using System; using System.Collections.Generic; namespace OpcUAServerSample { using IToolS.Components.Communication; using IToolS.Components.IOServers; static class Program { static void Main() { IToolS.Components.ComponentBase.RaiseEventsOnMainThread = false; Group group = new Group() { GroupName = "group1" }; Variable variable1 = new Variable() { VariableName = "variable1", Area = "HR", Address = "0" }; Variable variable2 = new Variable() { VariableName = "variable2", Area = "HR", Address = "1" }; variable1.Changed += variableChanged; variable2.Changed += variableChanged; IOServer ioserver1 = new IOServer() { Name = "Simulation" }; IOServer ioserver2 = new IOServer() { Name = "OpcUAServer" }; Client client = new Client() { ClientName = "client1", Group = group, IOServer = ioserver1 }; group.Add(variable1); group.Add(variable2); group.IOServer = ioserver2; client.Start(); group.StartIOServer(); Console.WriteLine("Press ENTER to exit"); Console.ReadLine(); client.Stop(); client.StopIOServer(); group.StopIOServer(); } private static void variableChanged(object sender, IToolS.Data.ChangedEventArgs e) { Variable variable = (Variable)sender; Console.WriteLine("{0} value: {1}", variable.VariableName, e.NewValue); } } }
How to create a page alarm management with IToolS
Per impostare la comunicazione con un dispositivo Allen Bradley è necessario impostare la proprietà "Name" dell'ioserver a "ABEthernetIP"
Le variabili sono lette e scritte per nome, è quindi necessario inserire nella proprietà "Address" della variable il nome della variabile che si vuole gestire.
I tipi di dato gestiti sono:
La lettura dei tag viene effettuate per nome e non per indirizzamento e dimensione come per altri driver (ad esempio Modbus, Siemens, Omron, ecc...) quindi per qualsiasi tag può essere utilizzato il tipo "Variant". È auspicabile utilizzare tipi di dato non "Variant" nel caso in cui il valore letto dal dispositivo debba poi essere convertito, scalato o soggetto a qualche trasformazione.
Il campo area non è utilizzato.
Sono implementate le letture e scrittura multiple.
La porta socket da utilizzare per la comunicazione è la: 44818
Il server permettere l’invocazione dei metodi del client da remoto mediante la tecnologia WCF, sul quale sono esposti due endpoint:
Le operazioni disponibili sono:
// IToolSVCClr.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <vcclr.h> void OnChanged(System::Object^ sender, IToolS::Data::ChangedEventArgs ^e) { System::Console::WriteLine(System::String::Format("New value {0}", e->NewValue)); } int _tmain(int argc, _TCHAR* argv[]) { gcroot<IToolS::Lite::Communication::Variable^> variable = gcnew IToolS::Lite::Communication::Variable(); gcroot<IToolS::Lite::Communication::Client^> client = gcnew IToolS::Lite::Communication::Client(); gcroot<IToolS::Lite::Communication::Group^> group = gcnew IToolS::Lite::Communication::Group(); gcroot<IToolS::Lite::IOServers::IOServer^> ioserver = gcnew IToolS::Lite::IOServers::IOServer(); variable->VariableName = "var"; variable->Address = "10"; variable->Changed += gcnew IToolS::Data::ChangedEventHandler(OnChanged); group->Add(variable); ioserver->Name = "Simulation"; client->Group = group; client->IOServer = ioserver; client->Start(); System::Console::WriteLine("Press ENTER to exit"); System::Console::ReadLine(); client->Stop(); client->StopIOServer(); return 0; }
Nel campo address e' necessario inserire l'indirizzo che di trova nel file APPLI.SYB:
<file>=K5SYB.V1 <proj>=LOGIC <crc>=1534836188 <vers>=4 <date>=1371717010 <ctsize>=1 <ctretoffset>=1 <ctretsize>=0 0x01000001(0)[0]=bBOOL 0x0c000001(0)[0]=iINT16 ...
Sopra e' riportato una stralcio del file APPLI.SYB dove e' presente la dichiarazione di due variabili:
0x01000001(0)[0]=bBOOL 0x0c000001(0)[0]=iINT16
Se vogliamo ad esempio interrogare la variabile "bBOOL", nel campo address dobbiamo inserire "01000001". Alla partenza il driver in base al valore inserito in Address si calcola l'indirizzo reale e il tipo di dato associato, in fase di progettazione non e' quindi necessario impostare la proprieta' "VariableType" in quanto e' il driver che in base al valore presente nel campo "Address" estrae il tipo e lo imposta.
using System; using System.Collections.Generic; using System.Text; namespace TestStratonNG { class Program { static void Main(string[] args) { IToolS.Components.ComponentBase.RaiseEventsOnMainThread = false; IToolS.Components.Communication.Variable s_variable1 =
new IToolS.Components.Communication.Variable(); IToolS.Components.Communication.Group s_group1 =
new IToolS.Components.Communication.Group(); IToolS.Components.IOServers.IOServer s_ioServer1 =
new IToolS.Components.IOServers.IOServer(); IToolS.Components.Communication.Client s_client1 =
new IToolS.Components.Communication.Client(); s_ioServer1.Name = "StratonNG"; s_ioServer1.NetConfig.Port = 1100; s_ioServer1.NetConfig.Address = "172.17.250.183"; s_variable1.VariableName = "sSTRING"; s_variable1.Address = "08000001"; s_variable1.Changed += s_variable1_Changed; s_group1.Items.Add(s_variable1); s_client1.Group = s_group1; s_client1.IOServer = s_ioServer1; s_client1.Start(); Console.WriteLine("Press ENTER to exit"); Console.ReadLine(); } static void s_variable1_Changed(object sender, IToolS.Data.ChangedEventArgs e) { Console.WriteLine(String.Format("Variable: {0} type: {1} value: {2}",
((IToolS.Components.Communication.Variable)sender).VariableName,
((IToolS.Components.Communication.Variable)sender).VariableType, e.NewValue)); } } }
//... for (int i = 0; i < 5; ++i) { Console.WriteLine("Cycle: {0}", i); DateTime time = DateTime.Now; IToolS.Data.ClientResult result = client.ReadSync(new IToolS.Components.Communication.Variable[] { variable1, variable2, variable3, variable4, variable5, variable6, variable7, variable8, variable9, variable10 }); Console.WriteLine("Time: {0}", (DateTime.Now - time).TotalMilliseconds); foreach (IToolS.IOServers.IORequest request in result.Requests) { Console.WriteLine("Request: {0}", request.Result.ToString()); } } //...
using System; using System.Collections.Generic; using System.IO; namespace IToolS.Web.i18Next { using Newtonsoft.Json.Linq; public class Translator { String _path; Dictionary<String, JObject> _dictionary; private Translator() { _dictionary = new Dictionary<string, JObject>(); } public Translator(String path, String jsonFileName = "translation.json") : this() { _path = path; foreach (var folder in Directory.GetDirectories(path)) { String directoryName = new DirectoryInfo(folder).Name; String jsonFile = Path.Combine(path, directoryName, jsonFileName); if (File.Exists(jsonFile)) { JObject jObject = JObject.Parse(File.ReadAllText(jsonFile)); _dictionary[directoryName] = jObject; } } } public String Translate(String culture, String text) { if (String.IsNullOrEmpty(text)) return text; if (!_dictionary.ContainsKey(culture)) return text; String[] fields = text.Split('.'); JToken jToken = _dictionary[culture]; for (int i = 0; i < fields.Length; i++) { jToken = jToken[fields[i]]; if (jToken == null) return text; if (i == fields.Length - 1) return jToken.ToString(); } return text; } } }