using MTC; using System; using System.Collections.Generic; namespace SCMA.AdapterCom { /// /// Gateway di comunicazione secondo diversi standard, partendo da oggetti BASE MTC /// public class Gateway { #region oggetti base /// /// Protocollo attivo per la comunicazione dell'adapter /// public gwProtocol protocollo; /// /// STOBE allarmi: /// 1024 bit di strobe degli allarmi attivi (32 word da 4byte/32 bit di flags...) /// public byte[] AlarmFlags; /// /// Oggetto elenco allarmi /// public allarme[] elencoAllarmi; /// /// Porta comunicazione standard oggetto /// public int port; /// /// Stringa di configurazione globale /// public string connConfig; /// /// Flag per indicare se l'obj stia ancora girando /// private bool myRunning = false; /// /// Indicatore public di oggetto running running. /// public bool Running { get { return myRunning; } } /// /// la parte di "mark & sweep" (segnala ed invia) è iniziata e stiamo tracciando le conditions. /// bool myBegun = false; /// /// Elenco di TUTTI i NODI ITEMS gestiti dal gateway (item/variabile)... /// public Dictionary itemNodes = new Dictionary(); /// /// Elenco di TUTTI i NODI CONDITIONS gestiti dal gateway (allarme/condizione)... /// public Dictionary conditionNodes = new Dictionary(); #endregion #region gestione globale oggetto /// /// init classe come output su LOGFILE /// public Gateway() { port = 0; connConfig = ""; protocollo = gwProtocol.LOGFILE; } /// /// Inizia la raccolta dati per confronto modifica da precedente... /// public virtual void beginDataCollect() { myBegun = true; foreach (object di in itemNodes) { // inizializza ogni oggetto (in particolare di tipo alarm/conditions x check variazione) //di.Begin(); } } /// /// Fa la verifica di cosa sia cambiato ed invia /// public virtual void sendChanged() { if (myBegun) { foreach (object di in itemNodes) { //di.Prepare(); } } #if false // Separate out the data items into those that are on one line and those // need separate lines. List together = new List(); List separate = new List(); foreach (object di in trackItems) { List list = di.ItemList(); if (di.NewLine) separate.AddRange(list); else together.AddRange(list); } // Compone all the same line data items onto one line. string line; if (timestamp == null) { DateTime now = DateTime.UtcNow; timestamp = now.ToString("yyyy-MM-dd\\THH:mm:ss.fffffffK"); } if (together.Count > 0) { line = timestamp; foreach (SimpleDataItem di in together) line += "|" + di.ToString(); line += "\n"; SendToAll(line); } // Now write out all the separate lines if (separate.Count > 0) { foreach (SimpleDataItem di in separate) { line = timestamp; line += "|" + di.ToString() + "\n"; SendToAll(line); } } // Flush the output FlushAll(); #endif // Cleanup foreach (object di in itemNodes) { // pulizia oggetti //di.Cleanup(); } myBegun = false; } /// /// Imposta TUTTI i data items unavailable /// public virtual void setAllUnavailable() { foreach (object di in itemNodes) { //// imposta a unavailable //di.Unavailable(); } } /// /// AVVIA processo lettura CNC e invio dati a client /// public virtual void start() { #if false if (!mRunning) { mListener = new TcpListener(IPAddress.Any, mPort); mListener.Start(); mListenThread = new Thread(new ThreadStart(ListenForClients)); mListenThread.Start(); } #endif } /// /// FERMA processo lettura CNC e invio dati a client /// public virtual void stop() { #if false if (mRunning) { mRunning = false; mListener.Stop(); foreach (Object obj in mClients) { Stream client = (Stream)obj; client.Close(); } mClients.Clear(); // Wait 5 seconds for the thread to exit. mListenThread.Join(2000); // Wait for all client threads to exit. mActiveClients.Wait(2000); } #endif } #endregion #region gestione nodi (dataItems / conditions) /// /// Aggiunge un generico item all'elenco di quelli tracciati INDICANDO IL TYPE /// /// /// public virtual void addItemNodeByType(string key, itemType tipo) { if (!itemNodes.ContainsKey(key)) { itemNode currItem = new itemNode(tipo, availStatus.UNAVAILABLE.ToString()); #if false // di base salvo tipo/valore come KVP nell'item... Dictionary currObj = new Dictionary(); currObj.Add(tipo, "UNAVAILABLE"); #endif itemNodes.Add(key, currItem); } } /// /// Aggiunge un generico item all'elenco di quelli tracciati INDICANDO IL TYPE ed il valore iniziale /// /// /// public virtual void addItemNodeAndSet(string key, itemType tipo, object value) { addItemNodeByType(key, tipo); updateItemNodeValue(key, value); } /// /// Aggiunge un generico item all'elenco di quelli tracciati (NON STRONGLY TYPED!!! occhio!!!) /// /// /// public virtual void addItemNode(string key, object value) { // se non c'è già elemento lo aggiungo... if (!itemNodes.ContainsKey(key)) { // default: event... itemNode currItem = new itemNode(itemType.Event, value); itemNodes.Add(key, currItem); } } public virtual void addItemNode(object value) { if (!itemNodes.ContainsKey(value.ToString())) { // default: event... itemNode currItem = new itemNode(itemType.Event, value); itemNodes.Add(value.ToString(), currItem); } } /// /// Rimuove TUTTI i data items tracciati /// public virtual void removeAllItemNodes() { itemNodes.Clear(); } /// /// Rimuove un item dall'elenco di quelli tracciati /// /// public virtual void removeItemNode(string key) { itemNodes.Remove(key); } /// /// RESTITUISCE un item da KEY /// /// public virtual object getItemNode(string key) { return itemNodes[key].cObject; } /// /// AGGIORNA un generico item all'elenco di quelli tracciati (NON STRONGLY TYPED!!! occhio!!!) /// /// /// public virtual void updateItemNodeValue(string key, object value) { itemNodes[key].cObject = value; } /// /// AGGIORNA un generico item all'elenco di quelli tracciati (NON STRONGLY TYPED!!! occhio!!!) /// /// /// /// public virtual void updateItemNodeCodeValue(string key, string code, object value) { itemNodes[key].cObject = value; } /// /// Aggiunge un generico item all'elenco di quelli tracciati (NON STRONGLY TYPED!!! occhio!!!) /// /// /// public virtual void addConditionNode(string key, object value) { // se non c'è già elemento lo aggiungo... if (!conditionNodes.ContainsKey(key)) { // default: event... itemNode currItem = new itemNode(itemType.Condition, value); conditionNodes.Add(key, currItem); } } /// /// Rimuove TUTTI i CONDITION NODES tracciati /// public virtual void removeAllConditionNodes() { conditionNodes.Clear(); } /// /// Rimuove un CONDITION NODE dall'elenco di quelli tracciati /// /// chaive public virtual void removeConditionNode(string key) { conditionNodes.Remove(key); } #endregion #region gestione allarmi /// /// processo il vettore LOCALE degli allarmi /// public virtual void processAlarm() { if (AlarmFlags != null) { // variabili helper StFlag32 AlarmBlock = 0; allarme currAllarm; // controllo TUTTI i bit della variabile COMPLETA degli status allarmi: se ce ne sono di alzati DEVO processare... for (int i = 0; i < AlarmFlags.Length / 4; i++) { // leggo 32bit alla volta... AlarmBlock = (StFlag32)BitConverter.ToUInt32(AlarmFlags, i * 4); for (int j = 0; j < 32; j++) { // converto! e aggiungo allarmi sollevati al corretto controller allarmi... if (AlarmBlock.HasFlag((StFlag32)Math.Pow(2, j))) { // recupero allarme da oggetto in memoria... currAllarm = elencoAllarmi[i * 32 + j]; addAlarm(currAllarm); } } } } } /// /// SETUP oggetti gestione allarmi /// public virtual void addAlarmNodes() { // minimo sempre PLC/CNC addConditionNode("CNC", "CNC"); addConditionNode("PLC", "PLC"); } /// /// INIT allarmi a normal /// public virtual void initAlarms() { } /// /// INIT di un SINGOLO NODO di allarme a normal /// /// public virtual void initAlarm(itemNode alarmNode) { } /// /// Aggiunta SINGOLO allarme su GENERICO (global) nodo /// /// Allarme da riportare al nodo public virtual void addAlarm(allarme currAllarm) { #if false // in base al tipo di allarme decodifico condizione... Condition.Level livello = Condition.Level.NORMAL; switch (currAllarm.livello) { case "WARNING": livello = Condition.Level.WARNING; break; case "FAULT": default: livello = Condition.Level.FAULT; break; } // in base al gruppo decido dove assegnare come CONDITION... switch (currAllarm.gruppo) { case "PLC": mAlarmPLC.Add(livello, currAllarm.descrizione, currAllarm.codNum, "", ""); break; case "CNC": default: mAlarmCNC.Add(livello, currAllarm.descrizione, currAllarm.codNum, "", ""); break; } #endif } /// /// Aggiunta SINGOLO allarme su SPECIFICO nodo /// /// Generico nodo di tipo condition /// Allarme da riportare al nodo public virtual void addAlarm(itemNode alarmNode, allarme currAllarm) { #if false // in base al tipo di allarme decodifico condizione... Condition.Level livello = Condition.Level.NORMAL; switch (currAllarm.livello) { case "WARNING": livello = Condition.Level.WARNING; break; case "FAULT": default: livello = Condition.Level.FAULT; break; } // in base al gruppo decido dove assegnare come CONDITION... switch (currAllarm.gruppo) { case "PLC": mAlarmPLC.Add(livello, currAllarm.descrizione, currAllarm.codNum, "", ""); break; case "CNC": default: mAlarmCNC.Add(livello, currAllarm.descrizione, currAllarm.codNum, "", ""); break; } #endif } /// /// RESTITUISCE un nodo CONDITION da KEY /// /// public virtual object getAlarmNode(string key) { return conditionNodes[key]; } #endregion } /// /// Classe item node (tipo/obj) /// public class itemNode { /// /// Tipo oggetto (per cast) /// public itemType cType; /// /// Object specifico /// public object cObject; /// /// costruttore /// public itemNode() { } /// /// costruttore /// /// /// public itemNode(itemType _tipo, object _obj) { cType = _tipo; cObject = _obj; } } /// /// Tipologia protocolli di comunicazione ammessi /// public enum gwProtocol { /// /// NESSUN protocollo reale --> FILE DUMP sul log... /// LOGFILE, /// /// Protocollo di comunicazione MTConnect /// MTC, /// /// Protocollo di comunicazione SCM.OPC.UA.REDIS.SERVER /// SOURS } /// /// Tipologia di ITEM /// public enum itemType { /// /// CONDIZION = ALLARME /// Condition, /// /// Evento = point in time data /// Event, /// /// Messaggio generico /// Message, /// /// Campionamento continuo /// Sample } /// /// Varibili STATO ATTIVO (es attuatori, sistemi...) /// public enum actStatus { /// /// Stato inattivo /// INACTIVE = 0, /// /// Stato Attivo /// ACTIVE } /// /// Varibili STATO OnOff /// public enum onOffStatus { /// /// Stato OFF /// OFF = 0, /// /// Stato ON /// ON } /// /// Varibili STATO per EMERGENZA /// public enum emStatus { /// /// Stato ARMATO /// ARMED = 0, /// /// Stato EMERGENZA PREMUTA /// TRIGGERED } /// /// Varibili STATO per AVAIL /// public enum availStatus { /// /// Stato DISPONIBILE /// AVAILABLE = 0, /// /// Stato NON disponibile /// UNAVAILABLE } /// /// Varibili STATO per AVAIL /// public enum pathType { /// /// Stato LAVORO /// LAVORO = 0, /// /// Stato ASSERV /// ASSERV } }