447 lines
12 KiB
C#
447 lines
12 KiB
C#
using MTC;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
|
|
namespace SCMA.AdapterCom
|
|
{
|
|
/// <summary>
|
|
/// Gateway di comunicazione secondo diversi standard, partendo da oggetti BASE MTC
|
|
/// </summary>
|
|
public class Gateway
|
|
{
|
|
|
|
#region oggetti base
|
|
|
|
/// <summary>
|
|
/// Protocollo attivo per la comunicazione dell'adapter
|
|
/// </summary>
|
|
public gwProtocol protocollo;
|
|
/// <summary>
|
|
/// STOBE allarmi:
|
|
/// 1024 bit di strobe degli allarmi attivi (32 word da 4byte/32 bit di flags...)
|
|
/// </summary>
|
|
public byte[] AlarmFlags;
|
|
/// <summary>
|
|
/// Oggetto elenco allarmi
|
|
/// </summary>
|
|
public allarme[] elencoAllarmi;
|
|
/// <summary>
|
|
/// Porta comunicazione standard oggetto
|
|
/// </summary>
|
|
public int port;
|
|
/// <summary>
|
|
/// Stringa di configurazione globale
|
|
/// </summary>
|
|
public string connConfig;
|
|
/// <summary>
|
|
/// Flag per indicare se l'obj stia ancora girando
|
|
/// </summary>
|
|
private bool myRunning = false;
|
|
/// <summary>
|
|
/// Indicatore public di oggetto running running.
|
|
/// </summary>
|
|
public bool Running { get { return myRunning; } }
|
|
/// <summary>
|
|
/// la parte di "mark & sweep" (segnala ed invia) è iniziata e stiamo tracciando le conditions.
|
|
/// </summary>
|
|
bool myBegun = false;
|
|
/// <summary>
|
|
/// Elenco di TUTTI i NODI ITEMS gestiti dal gateway (item/variabile)...
|
|
/// </summary>
|
|
public ArrayList itemNodes = new ArrayList();
|
|
/// <summary>
|
|
/// Elenco di TUTTI i NODI CONDITIONS gestiti dal gateway (allarme/condizione)...
|
|
/// </summary>
|
|
public Dictionary<string, object> conditionNodes = new Dictionary<string, object>();
|
|
|
|
#endregion
|
|
|
|
#region classi x nodi/item gestiti
|
|
|
|
/// <summary>
|
|
/// Singola pompa da vuoto, 0..n
|
|
/// </summary>
|
|
public class vacuumPump : element
|
|
{
|
|
/// <summary>
|
|
/// Stato: ACTIVE/INACTIVE
|
|
/// </summary>
|
|
public KeyValuePair<string, string> status;
|
|
/// <summary>
|
|
/// valore work time della pompa vuoto
|
|
/// </summary>
|
|
public KeyValuePair<string, string> workTime;
|
|
/// <summary>
|
|
/// Classe Vacuum Pump (pompa)
|
|
/// </summary>
|
|
/// <param name="baseElem">element base contenente parametri (da XML)</param>
|
|
public vacuumPump(element baseElem)
|
|
{
|
|
ident = baseElem.ident;
|
|
dataRefList = baseElem.dataRefList;
|
|
|
|
status = new KeyValuePair<string, string>(string.Format("{0}_Status", ident), "UNAVAILABLE");
|
|
workTime = new KeyValuePair<string, string>(string.Format("{0}_WrkTime", ident), "UNAVAILABLE");
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region metodi esposti (virtual)
|
|
|
|
/// <summary>
|
|
/// init classe come output su LOGFILE
|
|
/// </summary>
|
|
public Gateway()
|
|
{
|
|
port = 0;
|
|
connConfig = "";
|
|
protocollo = gwProtocol.LOGFILE;
|
|
}
|
|
|
|
#region gestione nodi (dataItems, conditions)
|
|
|
|
/// <summary>
|
|
/// Aggiunge un generico item all'elenco di quelli tracciati (NON STRONGLY TYPED!!! occhio!!!)
|
|
/// </summary>
|
|
/// <param name="newItem"></param>
|
|
public virtual void addItemNode(object newItem)
|
|
{
|
|
itemNodes.Add(newItem);
|
|
}
|
|
/// <summary>
|
|
/// Rimuove TUTTI i data items tracciati
|
|
/// </summary>
|
|
public virtual void removeAllItemNodes()
|
|
{
|
|
itemNodes.Clear();
|
|
}
|
|
/// <summary>
|
|
/// Rimuove un item dall'elenco di quelli tracciati
|
|
/// </summary>
|
|
/// <param name="anItem"></param>
|
|
public virtual void removeItemNode(object anItem)
|
|
{
|
|
int ind = itemNodes.IndexOf(anItem);
|
|
if (ind >= 0)
|
|
itemNodes.RemoveAt(ind);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Aggiunge un generico item all'elenco di quelli tracciati (NON STRONGLY TYPED!!! occhio!!!)
|
|
/// </summary>
|
|
/// <param name="key"></param>
|
|
/// <param name="value"></param>
|
|
public virtual void addConditionNode(string key, object value)
|
|
{
|
|
conditionNodes.Add(key, value);
|
|
}
|
|
/// <summary>
|
|
/// Rimuove TUTTI i CONDITION NODES tracciati
|
|
/// </summary>
|
|
public virtual void removeAllConditionNodes()
|
|
{
|
|
conditionNodes.Clear();
|
|
}
|
|
/// <summary>
|
|
/// Rimuove un CONDITION NODE dall'elenco di quelli tracciati
|
|
/// </summary>
|
|
/// <param name="key">chaive</param>
|
|
public virtual void removeConditionNode(string key)
|
|
{
|
|
conditionNodes.Remove(key);
|
|
}
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// Inizia la raccolta dati per confronto modifica da precedente...
|
|
/// </summary>
|
|
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();
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Fa la verifica di cosa sia cambiato ed invia
|
|
/// </summary>
|
|
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<SimpleDataItem> together = new List<SimpleDataItem>();
|
|
List<SimpleDataItem> separate = new List<SimpleDataItem>();
|
|
foreach (object di in trackItems)
|
|
{
|
|
List<SimpleDataItem> 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;
|
|
}
|
|
/// <summary>
|
|
/// Imposta TUTTI i data items unavailable
|
|
/// </summary>
|
|
public virtual void setAllUnavailable()
|
|
{
|
|
foreach (object di in itemNodes)
|
|
{
|
|
//// imposta a unavailable
|
|
//di.Unavailable();
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// AVVIA processo lettura CNC e invio dati a client
|
|
/// </summary>
|
|
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
|
|
}
|
|
/// <summary>
|
|
/// FERMA processo lettura CNC e invio dati a client
|
|
/// </summary>
|
|
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
|
|
}
|
|
|
|
|
|
#region gestione allarmi
|
|
|
|
/// <summary>
|
|
/// processo il vettore LOCALE degli allarmi
|
|
/// </summary>
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// SETUP oggetti gestione allarmi
|
|
/// </summary>
|
|
public virtual void addAlarmNodes()
|
|
{
|
|
// minimo sempre PLC/CNC
|
|
addConditionNode("CNC", "CNC");
|
|
addConditionNode("PLC", "PLC");
|
|
}
|
|
/// <summary>
|
|
/// INIT allarmi a normal
|
|
/// </summary>
|
|
public virtual void initAlarms()
|
|
{
|
|
}
|
|
/// <summary>
|
|
/// INIT di un SINGOLO NODO di allarme a normal
|
|
/// </summary>
|
|
/// <param name="alarmNode"></param>
|
|
public virtual void initAlarm(object alarmNode)
|
|
{
|
|
}
|
|
/// <summary>
|
|
/// Aggiunta SINGOLO allarme su GENERICO (global) nodo
|
|
/// </summary>
|
|
/// <param name="currAllarm">Allarme da riportare al nodo</param>
|
|
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
|
|
}
|
|
/// <summary>
|
|
/// Aggiunta SINGOLO allarme su SPECIFICO nodo
|
|
/// </summary>
|
|
/// <param name="alarmNode">Generico nodo di tipo condition</param>
|
|
/// <param name="currAllarm">Allarme da riportare al nodo</param>
|
|
public virtual void addAlarm(object 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
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
}
|
|
/// <summary>
|
|
/// Tipologia protocolli di comunicazione ammessi
|
|
/// </summary>
|
|
public enum gwProtocol
|
|
{
|
|
/// <summary>
|
|
/// NESSUN protocollo reale --> FILE DUMP sul log...
|
|
/// </summary>
|
|
LOGFILE,
|
|
/// <summary>
|
|
/// Protocollo di comunicazione MTConnect
|
|
/// </summary>
|
|
MTC,
|
|
/// <summary>
|
|
/// Protocollo di comunicazione SCM.OPC.UA.REDIS.SERVER
|
|
/// </summary>
|
|
SOURS
|
|
}
|
|
/// <summary>
|
|
/// Varibili STATO (es attuatori, sistemi...)
|
|
/// </summary>
|
|
public enum status
|
|
{
|
|
/// <summary>
|
|
/// Stato inattivo
|
|
/// </summary>
|
|
INACTIVE = 0,
|
|
/// <summary>
|
|
/// Stato Attivo
|
|
/// </summary>
|
|
ACTIVE
|
|
}
|
|
}
|