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
}
}