diff --git a/IOB-WIN/IobGeneric.cs b/IOB-WIN/IobGeneric.cs
index 064ec765..0b7db10f 100644
--- a/IOB-WIN/IobGeneric.cs
+++ b/IOB-WIN/IobGeneric.cs
@@ -19,3600 +19,3365 @@ using System.Windows.Forms;
namespace IOB_WIN
{
- public class IobGeneric
- {
- #region variabili serializzate in REDIS
-
- ///
- /// Oggetto connessione REDIS
- ///
- public RedisIobCache redisMan;
-
- #endregion variabili serializzate in REDIS
-
- #region variabili ed oggetti base
-
- ///
- /// wrapper di log
- ///
- protected static Logger lg;
-
- ///
- /// valore booleano di check se sia in fase di COMUNICAZIONE ATTIVA con il PLC/NC
- ///
- protected bool adpCommAct;
-
- ///
- /// porta x adapter (x restart)
- ///
- protected int adpPortNum;
-
- ///
- /// DataOra ultimo avvio adapter x watchdog
- ///
- protected DateTime adpStartRun;
-
- ///
- /// Vettore 16 BIT valori in ingresso al filtro
- ///
- protected int B_input;
-
- ///
- /// Vettore 16 BIT valori in uscita dal filtro
- ///
- protected int B_output;
-
- ///
- /// Vettore 16 BIT valori precedenti
- ///
- protected int B_previous;
-
- ///
- /// Dizionario valori impostati x produzione
- ///
- protected Dictionary currProdData = new Dictionary();
-
- ///
- /// Array dei contatori x segnali blinking
- ///
- protected int[] i_counters;
-
- ///
- /// Indica impianto IN SETUP (fino a quando SMETTE di esserlo...)
- ///
- protected bool inSetup = false;
-
- ///
- /// Ultimo invio contapezzi (x invio delayed)
- ///
- protected DateTime lastPzCountSend;
-
- ///
- /// Dizionario ultimi valori (double) delle TSVC
- ///
- protected Dictionary LastTSVC = new Dictionary();
-
- ///
- /// Ultima registrazione warning x ODL mancante (x scrivere solo ogni 15 secondi)
- ///
- protected DateTime lastWarnODL;
-
- ///
- /// TImeout x ping al server
- ///
- protected int pingServerMsTimeout = utils.CRI("pingMsTimeout");
-
- ///
- /// Ritardo minimo x invio contapezzi
- ///
- protected int pzCountDelay;
-
- ///
- /// Dizionario di VC da trattare come TimeSeries (con conf decodificata + processing successivo...)
- ///
- protected Dictionary TSVC_Data = new Dictionary();
-
- ///
- /// Dizionario di VARIABILI da trattare come eventi (da inviare quando cambiano oppure a scadenza periodo...)
- ///
- protected Dictionary VarArray = new Dictionary();
-
- ///
- /// valore booleano di check se sia stato AVVIATO l'adapter (Running)
- ///
- public bool adpRunning = false;
-
- ///
- /// valore booleano di check se l'adapter STIA SALVANDO
- ///
- public bool adpSaving = false;
-
- ///
- /// valore booleano (richiesta di riavvio automatico)
- ///
- public bool adpTryRestart;
-
- ///
- /// Contapezzi attuale
- ///
- public Int32 contapezziIOB
+ public class IobGeneric
{
- get
- {
- return tcMan.pzCountIOB;
- }
- set
- {
- tcMan.pzCountIOB = value;
- }
- }
+ #region variabili serializzate in REDIS
- ///
- /// Ultima lettura variabile contapezzi da CNC
- ///
- public Int32 contapezziPLC
- {
- get
- {
- return tcMan.pzCountPLC;
- }
- set
- {
- tcMan.pzCountPLC = value;
- }
- }
+ ///
+ /// Oggetto connessione REDIS
+ ///
+ public RedisIobCache redisMan;
- ///
- /// Conteggio ATTUALE ore macchina IN LAVORO
- ///
- public double contOreMaccLav;
+ #endregion variabili serializzate in REDIS
- ///
- /// Conteggio ATTUALE ore macchina ON
- ///
- public double contOreMaccOn;
+ #region variabili ed oggetti base
- ///
- /// ODL attualmente sulla macchina
- ///
- public Int32 currIdxODL;
+ ///
+ /// valore booleano di check se sia stato AVVIATO l'adapter (Running)
+ ///
+ public bool adpRunning = false;
- ///
- /// Modo corrente (da classe ENUM)
- ///
- public CNC_MODE currMode;
+ ///
+ /// valore booleano di check se l'adapter STIA SALVANDO
+ ///
+ public bool adpSaving = false;
- ///
- /// Indica se sia richiesto campionamento memoria PERIODICO
- ///
- public bool doSampleMemory;
+ ///
+ /// valore booleano (richiesta di riavvio automatico)
+ ///
+ public bool adpTryRestart;
- ///
- /// Indica se si debba leggere e fare DUMP delle aree di memoria (1 volta solo all'avvio x debug...)
- ///
- public bool doStartMemDump;
+ ///
+ /// Conteggio ATTUALE ore macchina IN LAVORO
+ ///
+ public double contOreMaccLav;
- ///
- /// Data/ora ultimo avvio adapter
- ///
- public DateTime dtAvvioAdp = DateTime.Now;
+ ///
+ /// Conteggio ATTUALE ore macchina ON
+ ///
+ public double contOreMaccOn;
- ///
- /// Data/ora ultimo spegnimento adapter
- ///
- public DateTime dtStopAdp = DateTime.Now;
+ ///
+ /// ODL attualmente sulla macchina
+ ///
+ public Int32 currIdxODL;
- ///
- /// Indicazione VETO check status IOB x evitare loop troppo stretti...
- ///
- public DateTime dtVetoCheckIOB = DateTime.Now.AddDays(-1);
+ ///
+ /// Modo corrente (da classe ENUM)
+ ///
+ public CNC_MODE currMode;
- ///
- /// Abilitazione lettura PrgName
- ///
- public bool enablePrgName = true;
+ ///
+ /// Indica se sia richiesto campionamento memoria PERIODICO
+ ///
+ public bool doSampleMemory;
- ///
- /// Abilitazione invio pezzi "in blocco" per recupero contapezzi
- ///
- public bool enableSendPzCountBlock = false;
+ ///
+ /// Indica se si debba leggere e fare DUMP delle aree di memoria (1 volta solo all'avvio x debug...)
+ ///
+ public bool doStartMemDump;
- ///
- /// Determina se sia encessario convertire valori little/big endian (SIEMENS=true, OSAI=FALSE)
- ///
- public bool hasBigEndian = false;
+ ///
+ /// Data/ora ultimo avvio adapter
+ ///
+ public DateTime dtAvvioAdp = DateTime.Now;
- ///
- /// dataOra ultima verifica CNC disconnesso...
- ///
- public DateTime lastDisconnCheck;
+ ///
+ /// Data/ora ultimo spegnimento adapter
+ ///
+ public DateTime dtStopAdp = DateTime.Now;
- ///
- /// Data/ora ultima volta che IOB è stato dichairato online
- ///
- public DateTime lastIobOnline = DateTime.Now.AddHours(-1);
+ ///
+ /// Indicazione VETO check status IOB x evitare loop troppo stretti...
+ ///
+ public DateTime dtVetoCheckIOB = DateTime.Now.AddDays(-1);
- ///
- /// dataOra ultimo log periodico...
- ///
- public DateTime lastPeriodicLog;
+ ///
+ /// Abilitazione lettura PrgName
+ ///
+ public bool enablePrgName = true;
- ///
- /// dataOra ultimo PING inviato verso il PLC...
- ///
- public DateTime lastPING;
+ ///
+ /// Abilitazione invio pezzi "in blocco" per recupero contapezzi
+ ///
+ public bool enableSendPzCountBlock = false;
- ///
- /// DataOra ultima lettura da PLC
- ///
- public DateTime lastReadPLC;
+ ///
+ /// Determina se sia encessario convertire valori little/big endian (SIEMENS=true, OSAI=FALSE)
+ ///
+ public bool hasBigEndian = false;
- ///
- /// ULtimo valore inviato (in caso di disconnessione lo reinvia x garantire watchdog...)
- ///
- public string lastSignInVal = "";
+ ///
+ /// dataOra ultima verifica CNC disconnesso...
+ ///
+ public DateTime lastDisconnCheck;
- ///
- /// dataOra ultimo segnale inviato...
- ///
- public DateTime lastWatchDog;
+ ///
+ /// Data/ora ultima volta che IOB è stato dichairato online
+ ///
+ public DateTime lastIobOnline = DateTime.Now.AddHours(-1);
- ///
- /// Massimo numero di px da inviare in blocco
- ///
- public int maxSendPzCountBlock = 10;
+ ///
+ /// dataOra ultimo log periodico...
+ ///
+ public DateTime lastPeriodicLog;
- ///
- /// Minimo numero di px da inviare in blocco
- ///
- public int minSendPzCountBlock = 5;
+ ///
+ /// dataOra ultimo PING inviato verso il PLC...
+ ///
+ public DateTime lastPING;
- ///
- /// Variabile booleana che indica se sia necessario fare refresh del contapezzi
- ///
- public bool needRefreshPzCount = true;
+ ///
+ /// DataOra ultima lettura da PLC
+ ///
+ public DateTime lastReadPLC;
- ///
- /// Determina se utilizzare blocchi di memoria IOT contigui (e quindi processing "monoblocco" semplificato"=
- ///
- public bool procIotMem = false;
+ ///
+ /// ULtimo valore inviato (in caso di disconnessione lo reinvia x garantire watchdog...)
+ ///
+ public string lastSignInVal = "";
- ///
- /// Coda valori ALLARMI ove gestiti...
- ///
- public ConcurrentQueue QueueAlarm = new ConcurrentQueue();
+ ///
+ /// dataOra ultimo segnale inviato...
+ ///
+ public DateTime lastWatchDog;
- ///
- /// Oggetto della coda degli elementi letti di tipo FluxLog (e non ancora trasmessi)
- ///
- public ConcurrentQueue QueueFLog = new ConcurrentQueue();
+ ///
+ /// Massimo numero di px da inviare in blocco
+ ///
+ public int maxSendPzCountBlock = 10;
- ///
- /// Oggetto della coda degli elementi letti (e non ancora trasmessi)
- ///
- public ConcurrentQueue QueueIN = new ConcurrentQueue();
+ ///
+ /// Minimo numero di px da inviare in blocco
+ ///
+ public int minSendPzCountBlock = 5;
- ///
- /// Coda valori MESSAGGI/EVENTI (da non sottocampionare come samples)...
- ///
- public ConcurrentQueue QueueMessages = new ConcurrentQueue();
+ ///
+ /// Variabile booleana che indica se sia necessario fare refresh del contapezzi
+ ///
+ public bool needRefreshPzCount = true;
- ///
- /// alias booleano false = R
- ///
- public bool R = false;
+ ///
+ /// Determina se utilizzare blocchi di memoria IOT contigui (e quindi processing "monoblocco" semplificato"=
+ ///
+ public bool procIotMem = false;
- ///
- /// 32 byte input base (es strobe, 8 word da 32 bit di flags...)
- ///
- public byte[] RawInput = new byte[32];
+ ///
+ /// Coda valori ALLARMI ove gestiti...
+ ///
+ public ConcurrentQueue QueueAlarm = new ConcurrentQueue();
- ///
- /// 32 byte output base (es ack, 8 word da 32 bit di flags...)
- ///
- public byte[] RawOutput = new byte[32];
+ ///
+ /// Oggetto della coda degli elementi letti di tipo FluxLog (e non ancora trasmessi)
+ ///
+ public ConcurrentQueue QueueFLog = new ConcurrentQueue();
- ///
- /// Oggetto cronometro x campionamento durate chiamate
- ///
- public Stopwatch stopwatch = new Stopwatch();
+ ///
+ /// Oggetto della coda degli elementi letti (e non ancora trasmessi)
+ ///
+ public ConcurrentQueue QueueIN = new ConcurrentQueue();
- ///
- /// Oggetto gestione TempiCiclo e contapezzi
- ///
- public TCMan tcMan = new TCMan(0.5, 1.3, 5);
+ ///
+ /// Coda valori MESSAGGI/EVENTI (da non sottocampionare come samples)...
+ ///
+ public ConcurrentQueue QueueMessages = new ConcurrentQueue();
- ///
- /// Imposta veto chiamata split (durante chiamata, per 60 sec)
- ///
- public DateTime vetoSplit = DateTime.Now.AddMinutes(1);
+ ///
+ /// alias booleano false = R
+ ///
+ public bool R = false;
- ///
- /// alias booleano true = W
- ///
- public bool W = true;
+ ///
+ /// 32 byte input base (es strobe, 8 word da 32 bit di flags...)
+ ///
+ public byte[] RawInput = new byte[32];
- ///
- /// Evento Iob ha subito un refresh
- ///
- public event EventHandler eh_refreshed;
+ ///
+ /// 32 byte output base (es ack, 8 word da 32 bit di flags...)
+ ///
+ public byte[] RawOutput = new byte[32];
- ///
- /// Coda massima ammessa per FLog (se <=0 disattivata...)
- ///
- protected int maxQueueFLog { get; set; } = utils.CRI("maxQueueFLog");
+ ///
+ /// Oggetto cronometro x campionamento durate chiamate
+ ///
+ public Stopwatch stopwatch = new Stopwatch();
- ///
- /// Numero letture IN da avvio
- ///
- protected int nReadFilt { get; set; }
+ ///
+ /// Oggetto gestione TempiCiclo e contapezzi
+ ///
+ public TCMan tcMan = new TCMan(0.5, 1.3, 5);
- ///
- /// Numero letture IN da avvio
- ///
- protected int nReadIN { get; set; }
+ ///
+ /// Imposta veto chiamata split (durante chiamata, per 60 sec)
+ ///
+ public DateTime vetoSplit = DateTime.Now.AddMinutes(1);
- ///
- /// Numero invii OUT (svuotamento coda)
- ///
- protected int nSendOut { get; set; }
+ ///
+ /// alias booleano true = W
+ ///
+ public bool W = true;
- ///
- /// Numero simulazioni ammesse...
- ///
- protected int numSim { get; set; }
+ ///
+ /// wrapper di log
+ ///
+ protected static Logger lg;
- ///
- /// Verifica se sia in modalità DEMO avanzata (campionamento da set di valori ammessi...)
- ///
- public static bool DemoInSample
- {
- get
- {
- return baseUtils.CRB("DemoInSample");
- }
- }
+ ///
+ /// valore booleano di check se sia in fase di COMUNICAZIONE ATTIVA con il PLC/NC
+ ///
+ protected bool adpCommAct;
- ///
- /// Verifica se sia in modalità DEMO x dati OUTPUT
- ///
- public static bool DemoOut
- {
- get
- {
- return utils.CRB("DemoOut");
- }
- }
+ ///
+ /// porta x adapter (x restart)
+ ///
+ protected int adpPortNum;
- ///
- /// Indicazione VETO PING a server sino alla data-ora indicata
- ///
- public static DateTime dtVetoPing
- {
- get
- {
- return utils.dtVetoPing;
- }
- set
- {
- utils.dtVetoPing = value;
- }
- }
+ ///
+ /// DataOra ultimo avvio adapter x watchdog
+ ///
+ protected DateTime adpStartRun;
- ///
- /// Indicazione VETO invio a server sino alla data-ora indicata
- ///
- public static DateTime dtVetoSend
- {
- get
- {
- return utils.dtVetoSend;
- }
- set
- {
- utils.dtVetoSend = value;
- }
- }
+ ///
+ /// Vettore 32 BIT valori in ingresso al filtro
+ ///
+ protected int B_input;
- ///
- /// stato Online/Offline del server MP IO (su REDIS)
- ///
- public static bool MPOnline
- {
- get
- {
- return utils.MPIO_Online;
- }
- set
- {
- utils.MPIO_Online = value;
- }
- }
+ ///
+ /// Vettore 32 BIT valori in uscita dal filtro
+ ///
+ protected int B_output;
- ///
- /// Contatore x invio dati FluxLog
- ///
- public int counterFLog { get; set; }
+ ///
+ /// Vettore 32 BIT valori precedenti
+ ///
+ protected int B_previous;
- ///
- /// Contatore x invio dati SignalIN
- ///
- public int counterSigIN { get; set; }
+ ///
+ /// Dizionario valori impostati x produzione
+ ///
+ protected Dictionary currProdData = new Dictionary();
- ///
- /// Verifica se sia in modalità DEMO --> da tipo IOB SIMULA...
- ///
- public bool DemoIn
- {
- get
- {
- return (cIobConf.tipoIob == tipoAdapter.SIMULA);// baseUtils.CRB("DemoIn");
- }
- }
+ ///
+ /// Array dei contatori x segnali blinking
+ ///
+ protected int[] i_counters;
- ///
- /// stato Online/Offline della IOB
- ///
- public bool IobOnline
- {
- get
- {
- return utils.IOB_Online;
- }
- set
- {
- utils.IOB_Online = value;
- }
- }
+ ///
+ /// Indica impianto IN SETUP (fino a quando SMETTE di esserlo...)
+ ///
+ protected bool inSetup = false;
- ///
- /// Log verboso da configurazione (SOLO CHAIVE "verbose"...
- ///
- public bool isVerboseLog { get; set; } = utils.CRB("verbose");
+ ///
+ /// Ultimo invio contapezzi (x invio delayed)
+ ///
+ protected DateTime lastPzCountSend;
- ///
- /// Ultimo Alarm letto
- ///
- public string lastAlarm { get; set; }
+ ///
+ /// Dizionario ultimi valori (double) delle TSVC
+ ///
+ protected Dictionary LastTSVC = new Dictionary();
- ///
- /// Ultimo ARRAY DynData letto
- ///
- public Dictionary lastDynData { get; set; } = new Dictionary();
+ ///
+ /// Ultima registrazione warning x ODL mancante (x scrivere solo ogni 15 secondi)
+ ///
+ protected DateTime lastWarnODL;
- ///
- /// Ultimo DynData (sunto) letto
- ///
- public string lastDynDataCtrlVal { get; set; }
+ ///
+ /// TImeout x ping al server
+ ///
+ protected int pingServerMsTimeout = utils.CRI("pingMsTimeout");
- ///
- /// Ultimo Override set letto
- ///
- public string lastOverrideFS { get; set; }
+ ///
+ /// Ritardo minimo x invio contapezzi
+ ///
+ protected int pzCountDelay;
- ///
- /// Ultimo Override set letto
- ///
- public string lastOverrideRapid { get; set; }
+ ///
+ /// Dizionario di VC da trattare come TimeSeries (con conf decodificata + processing successivo...)
+ ///
+ protected Dictionary TSVC_Data = new Dictionary();
- ///
- /// Ultimo programma letto
- ///
- public string lastPrgName { get; set; }
+ ///
+ /// Dizionario di VARIABILI da trattare come eventi (da inviare quando cambiano oppure a scadenza periodo...)
+ ///
+ protected Dictionary VarArray = new Dictionary();
- ///
- /// Ultimo SysInfo letto
- ///
- public string lastSysInfo { get; set; }
+ ///
+ /// Evento Iob ha subito un refresh
+ ///
+ public event EventHandler eh_refreshed;
- ///
- /// Ultimo URL
- ///
- public string lastUrl { get; set; }
-
- ///
- /// Verifica SE si debba fare log periodico (ogni "verboseLogTOut" sec...)
- ///
- public bool periodicLog
- {
- get
- {
- bool answ = false;
- answ = (DateTime.Now.Subtract(lastPeriodicLog).TotalSeconds > utils.CRI("verboseLogTOut"));
- if (answ)
+ ///
+ /// Verifica se sia in modalità DEMO avanzata (campionamento da set di valori ammessi...)
+ ///
+ public static bool DemoInSample
{
- lastPeriodicLog = DateTime.Now;
- }
-
- return answ;
- }
- }
-
- ///
- /// Verifica SE si debba fare log verboso (verboso + ogni tot letture IN)
- ///
- public bool verboseLog
- {
- get
- {
- bool answ = false;
- int logEvery = utils.CRI("logEvery");
- if (logEvery < 1)
- {
- logEvery = 10;
- }
-
- answ = utils.CRB("verbose") && (nReadIN % logEvery == 0);
- return answ;
- }
- }
-
- ///
- /// Aggiunge ai dati da inviare alla parentform i valori di RawInput rilevati
- ///
- public virtual void reportRawInput(ref newDisplayData currDispData)
- {
- // processo eventualmente aggiungendo ad elementi esistenti...
- if (currDispData == null)
- {
- currDispData = new newDisplayData();
- }
- try
- {
- StringBuilder sb = new StringBuilder();
- sb.Append($"B_input --> {(short)B_input}{Environment.NewLine}");
- sb.Append($"{baseUtils.binaryForm(B_input)}{Environment.NewLine}");
- sb.Append($"{Environment.NewLine}");
- sb.Append($"----------- RAW Data Memory -----------{Environment.NewLine}");
- int i = 0;
- foreach (var item in RawInput)
- {
- sb.Append($"B{i:00} --> {baseUtils.binaryForm(item)} = {(short)item}{Environment.NewLine}");
- i++;
- }
- sb.Append("-------------------------------");
- currDispData.currBitmap = sb.ToString();
- }
- catch
- { }
- }
-
- ///
- /// Salva valori indicati in prod data
- ///
- /// Item KVP di cui salvare i dati in currProdData come chiave/valore
- ///
- public void saveProdData(KeyValuePair item)
- {
- // imposto i valori...
- if (currProdData.ContainsKey(item.Key))
- {
- currProdData[item.Key] = item.Value;
- }
- else
- {
- currProdData.Add(item.Key, item.Value);
- }
- }
-
- #endregion variabili ed oggetti base
-
- #region Protected Fields
-
- ///
- /// ultimo tentativo connessione...
- ///
- protected DateTime lastConnectTry;
-
- ///
- /// indica se serva refresh parametri e quindi PLC...
- ///
- protected bool needRefresh = true;
-
- ///
- /// Form chiamante
- ///
- protected AdapterForm parentForm;
-
- #endregion Protected Fields
-
- ///
- /// Conf adapter corrente
- ///
- public IobConfiguration cIobConf;
-
- ///
- /// Struttura memoria PLC x lettura/scrittura da JSON file
- ///
- public plcMemMap memMap;
-
- ///
- /// inizializzo l'oggetto sulla form SULLA BASE DEL FILE DI CONFIGURAZIONE letto
- ///
- ///
- ///
- public IobGeneric(AdapterForm caller, IobConfiguration IOBConf)
- {
- if (IOBConf != null)
- {
- // init oggetto redis...
- redisMan = new RedisIobCache(IOBConf.serverData.MPIP, IOBConf.codIOB);
-
- // initi oggetto TCMan
- tcMan = new TCMan(IOBConf.TCLambda, IOBConf.TCMaxDelayFactor, IOBConf.TCMaxIncrPz);
-
- // salvo il form chiamante
- parentForm = caller;
- // configurazione...
- cIobConf = IOBConf;
-
- lastConnectTry = DateTime.Now;
-
- // aggiungo nel logger IDX Macchina
- lg = LogManager.GetCurrentClassLogger();
-
- lgInfo("Avvio preliminare AdapterGeneric");
- // aggiungo altri defaults
- setDefaults(true);
-
- setParamPlc();
-
- // checkLogDir x shrink!
- checkShrinkDir();
-
- // concluso!
- lgInfo("Istanziata classe preliminare IOBGeneric");
- }
- else
- {
- lgError("Error: IobCOnf is null!");
- }
- }
-
- ///
- /// Valore limite MASSIMO di invio di dati come array Json
- ///
- protected int maxJsonData { get; set; } = utils.CRI("maxJsonData");
-
- ///
- /// Valore limite MASSIMO di invio di dati come array Json x EVENTI
- ///
- protected int maxJsonDataEv { get; set; } = utils.CRI("maxJsonDataEv");
-
- ///
- /// Valore MINIMO limite x decidere invio di dati come array Json
- ///
- protected int minJsonData { get; set; } = utils.CRI("minJsonData");
-
- ///
- /// Secondi standard x veto check status e log
- ///
- protected int vetoSeconds { get; set; } = utils.CRI("vetoSeconds");
-
- ///
- /// Imposta eventuali altri valori default
- ///
- private void fixDefaultPar()
- {
- // parametro max tentativi PING...
- string s_maxPingRetry = getOptPar("MAX_PING_RETRY");
- if (!string.IsNullOrEmpty(s_maxPingRetry))
- {
- int numRetry = 5;
- int.TryParse(s_maxPingRetry, out numRetry);
- maxPingRetry = numRetry;
- }
- }
-
- ///
- /// Imposto alcuni valori di default
- ///
- /// indica se sia richeisto di SVUOTARE le code delel info
- private void setDefaults(bool resetQueue)
- {
- numSim = utils.CRI("numSim");
- lastPrgName = "";
- nReadIN = 0;
- nReadFilt = 0;
- nSendOut = 0;
- currMode = 0;
- lastAlarm = "";
- doStartMemDump = utils.CRB("doStartMemDump");
- doSampleMemory = utils.CRB("doSampleMemory");
- // svuoto code se richiesto
- if (resetQueue)
- {
- QueueIN = new ConcurrentQueue();
- QueueFLog = new ConcurrentQueue();
- QueueAlarm = new ConcurrentQueue();
- QueueMessages = new ConcurrentQueue();
- }
- // imposto contatori blink a zero...
- i_counters = new int[32];
- lastPeriodicLog = DateTime.Now;
- // fix parametri generali...
- enablePrgName = true;
- }
-
- ///
- /// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere...
- ///
- ///
- protected void lgError(string message, bool sendToForm = true)
- {
- lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB;
- lg.Error(message);
- if (sendToForm)
- {
- sendToLogWatch("ERROR", message);
- }
- }
-
- ///
- /// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere...
- ///
- ///
- ///
- protected void lgError(string message, params object[] args)
- {
- lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB;
- lg.Error(message, args);
- sendToLogWatch("ERROR", message, args);
- }
-
- ///
- /// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere...
- ///
- ///
- ///
- ///
- protected void lgError(Exception exception, string message, params object[] args)
- {
- lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB;
- lg.Error(exception, message, args);
- sendToLogWatch("ERROR", message, exception, args);
- }
-
- ///
- /// Effettua logging FATAL corretto impostanto anche la variabile IOB prima di scrivere...
- ///
- ///
- protected void lgFatal(string message, bool sendToForm = true)
- {
- lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB;
- lg.Fatal(message);
- if (sendToForm)
- {
- sendToLogWatch("FATAL", message);
- }
- }
-
- ///
- /// Effettua logging FATAL corretto impostanto anche la variabile IOB prima di scrivere...
- ///
- ///
- ///
- protected void lgFatal(string message, params object[] args)
- {
- lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB;
- lg.Fatal(message, args);
- sendToLogWatch("FATAL", message, args);
- }
-
- ///
- /// Effettua logging FATAL corretto impostanto anche la variabile IOB prima di scrivere...
- ///
- ///
- ///
- ///
- protected void lgFatal(Exception exception, string message, params object[] args)
- {
- lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB;
- lg.Fatal(exception, message, args);
- sendToLogWatch("FATAL", message, exception, args);
- }
-
- ///
- /// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere...
- ///
- ///
- protected void lgInfo(string message, bool sendToForm = true)
- {
- lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB;
- lg.Info(message);
- if (sendToForm)
- {
- sendToLogWatch("INFO", message);
- }
- }
-
- ///
- /// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere...
- ///
- ///
- ///
- protected void lgInfo(string message, params object[] args)
- {
- lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB;
- lg.Info(message, args);
- sendToLogWatch("INFO", message, args);
- }
-
- ///
- /// Lettura memorie conf speciali (json)
- /// ...SE inserito in [OPTPAR] come PARAM_CONF=nome.json
- ///
- protected virtual void loadMemConf()
- {
- lgInfo("BEGIN loadMemConf");
- // variabili x gestione send contapezzi in blocco
- string currPar = getOptPar("ENABLE_SEND_PZC_BLOCK");
- if (!string.IsNullOrEmpty(currPar))
- {
- bool.TryParse(currPar, out enableSendPzCountBlock);
- // se abilitato leggo num pezzi da reinviare in blocco
- if (enableSendPzCountBlock)
- {
- int.TryParse(getOptPar("MAX_SEND_PZC_BLOCK"), out maxSendPzCountBlock);
- int.TryParse(getOptPar("MIN_SEND_PZC_BLOCK"), out minSendPzCountBlock);
- }
- }
- else
- {
- lgError("loadMemConf: parametro ENABLE_SEND_PZC_BLOCK non trovato, verificare anche MAX_SEND_PZC_BLOCK e MIN_SEND_PZC_BLOCK");
- }
- // inizializzo LUT decodifica
- string jsonConf = getOptPar("PARAM_CONF");
- if (!string.IsNullOrEmpty(jsonConf))
- {
- string jsonFileName = $"{Application.StartupPath}/DATA/CONF/{jsonConf}";
- lgInfo($"Apertura file {jsonFileName}");
- StreamReader reader = new StreamReader(jsonFileName);
- string jsonData = reader.ReadToEnd();
- if (!string.IsNullOrEmpty(jsonData))
- {
- lgInfo($"File json composto da {jsonData.Length} caratteri");
- try
- {
- memMap = JsonConvert.DeserializeObject(jsonData);
- lgInfo($"Decodifica aree memMap: trovati {memMap.mMapRead.Count} valori TSVC");
- lgInfo($"Decodifica aree memMap: trovati {memMap.mMapWrite.Count} parametri ");
- // se ho variabili read --> genero dati TSVC...
- if (memMap.mMapRead.Count > 0)
+ get
{
- TSVC_Data.Clear();
- LastTSVC.Clear();
- VCData currConf;
- int periodo = 0;
- VC_func funz = VC_func.POINT;
- // accodo nella conf...
- foreach (var item in memMap.mMapRead)
- {
- funz = item.Value.func;
- periodo = item.Value.period;
- currConf = new VCData()
+ return baseUtils.CRB("DemoInSample");
+ }
+ }
+
+ ///
+ /// Verifica se sia in modalità DEMO x dati OUTPUT
+ ///
+ public static bool DemoOut
+ {
+ get
+ {
+ return utils.CRB("DemoOut");
+ }
+ }
+
+ ///
+ /// Indicazione VETO PING a server sino alla data-ora indicata
+ ///
+ public static DateTime dtVetoPing
+ {
+ get
+ {
+ return utils.dtVetoPing;
+ }
+ set
+ {
+ utils.dtVetoPing = value;
+ }
+ }
+
+ ///
+ /// Indicazione VETO invio a server sino alla data-ora indicata
+ ///
+ public static DateTime dtVetoSend
+ {
+ get
+ {
+ return utils.dtVetoSend;
+ }
+ set
+ {
+ utils.dtVetoSend = value;
+ }
+ }
+
+ ///
+ /// stato Online/Offline del server MP IO (su REDIS)
+ ///
+ public static bool MPOnline
+ {
+ get
+ {
+ return utils.MPIO_Online;
+ }
+ set
+ {
+ utils.MPIO_Online = value;
+ }
+ }
+
+ ///
+ /// Contapezzi attuale
+ ///
+ public Int32 contapezziIOB
+ {
+ get
+ {
+ return tcMan.pzCountIOB;
+ }
+ set
+ {
+ tcMan.pzCountIOB = value;
+ }
+ }
+
+ ///
+ /// Ultima lettura variabile contapezzi da CNC
+ ///
+ public Int32 contapezziPLC
+ {
+ get
+ {
+ return tcMan.pzCountPLC;
+ }
+ set
+ {
+ tcMan.pzCountPLC = value;
+ }
+ }
+
+ ///
+ /// Contatore x invio dati FluxLog
+ ///
+ public int counterFLog { get; set; }
+
+ ///
+ /// Contatore x invio dati SignalIN
+ ///
+ public int counterSigIN { get; set; }
+
+ ///
+ /// Verifica se sia in modalità DEMO --> da tipo IOB SIMULA...
+ ///
+ public bool DemoIn
+ {
+ get
+ {
+ return (cIobConf.tipoIob == tipoAdapter.SIMULA);// baseUtils.CRB("DemoIn");
+ }
+ }
+
+ ///
+ /// stato Online/Offline della IOB
+ ///
+ public bool IobOnline
+ {
+ get
+ {
+ return utils.IOB_Online;
+ }
+ set
+ {
+ utils.IOB_Online = value;
+ }
+ }
+
+ ///
+ /// Log verboso da configurazione (SOLO CHAIVE "verbose"...
+ ///
+ public bool isVerboseLog { get; set; } = utils.CRB("verbose");
+
+ ///
+ /// Ultimo Alarm letto
+ ///
+ public string lastAlarm { get; set; }
+
+ ///
+ /// Ultimo ARRAY DynData letto
+ ///
+ public Dictionary lastDynData { get; set; } = new Dictionary();
+
+ ///
+ /// Ultimo DynData (sunto) letto
+ ///
+ public string lastDynDataCtrlVal { get; set; }
+
+ ///
+ /// Ultimo Override set letto
+ ///
+ public string lastOverrideFS { get; set; }
+
+ ///
+ /// Ultimo Override set letto
+ ///
+ public string lastOverrideRapid { get; set; }
+
+ ///
+ /// Ultimo programma letto
+ ///
+ public string lastPrgName { get; set; }
+
+ ///
+ /// Ultimo SysInfo letto
+ ///
+ public string lastSysInfo { get; set; }
+
+ ///
+ /// Ultimo URL
+ ///
+ public string lastUrl { get; set; }
+
+ ///
+ /// Verifica SE si debba fare log periodico (ogni "verboseLogTOut" sec...)
+ ///
+ public bool periodicLog
+ {
+ get
+ {
+ bool answ = false;
+ answ = (DateTime.Now.Subtract(lastPeriodicLog).TotalSeconds > utils.CRI("verboseLogTOut"));
+ if (answ)
{
- Funzione = funz,
- Period = periodo,
- DTStart = DateTime.Now.AddHours(-1),
- dataArray = new List()
- };
- TSVC_Data.Add(item.Key, currConf);
- }
- // documento...
- foreach (var item in TSVC_Data)
- {
- lgInfo($"TSVC: {item.Key} | periodo: {item.Value.Period} | funz: {item.Value.Funzione}");
- // salvo i valori PREC...
- LastTSVC.Add(item.Key, 0);
- }
- }
- // infine se obj memoria valido salvo in MP-IO x sue applicazioni
- if (memMap != null)
- {
- // invio su cloud conf memoria...
- string rawData = JsonConvert.SerializeObject(memMap);
- utils.callUrlNow($"{urlSaveMemMap}", rawData);
- // salvo ANCHE come parametri i valori...
- objItem currItem = new objItem();
- List allParam = new List();
- // valori WRITE
- foreach (var item in memMap.mMapWrite)
- {
- currItem = new objItem()
- {
- uid = item.Value.name,
- name = !string.IsNullOrEmpty(item.Value.description) ? item.Value.description : item.Value.name,
- writable = true
- };
- allParam.Add(currItem);
- }
- // valori READ
- foreach (var item in memMap.mMapRead)
- {
- currItem = new objItem()
- {
- uid = item.Value.name,
- name = !string.IsNullOrEmpty(item.Value.description) ? item.Value.description : item.Value.name,
- writable = false
- };
- allParam.Add(currItem);
- }
- // invio su cloud parametri!
- rawData = JsonConvert.SerializeObject(allParam);
- utils.callUrl($"{urlSaveAllParams}", rawData);
- }
- }
- catch (Exception exc)
- {
- lgError($"Eccezione in decodifica conf json{Environment.NewLine}{exc}");
- }
- }
- else
- {
- lgError("Errore in loadMemConf: file json vuoto!");
- }
- reader.Dispose();
- }
- else
- {
- lgInfo("loadMemConf: non trovata opzione PARAM_CONF in file INI");
- }
- // loggo
- lgInfo("DONE loadMemConf");
- }
-
- ///
- /// Invia messaggio a logWatcher
- ///
- ///
- ///
- protected void sendToLogWatch(string messType, string message)
- {
- newDisplayData currDispData = new newDisplayData();
- currDispData.newLiveLogData = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} | {messType} | {message}";
- parentForm.updateFormDisplay(currDispData);
- }
-
- ///
- /// Invia messaggio a logWatcher
- ///
- ///
- ///
- ///
- protected void sendToLogWatch(string messType, string message, params object[] args)
- {
- try
- {
- string expString = string.Format(message, args);
- newDisplayData currDispData = new newDisplayData();
- currDispData.newLiveLogData = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} | {messType} | {expString}";
- parentForm.updateFormDisplay(currDispData);
- }
- catch
- { }
- }
-
- ///
- /// Invia messaggio a logWatcher
- ///
- ///
- ///
- ///
- ///
- protected void sendToLogWatch(string messType, string message, Exception exception, params object[] args)
- {
- try
- {
- string expString = string.Format(message, args);
- newDisplayData currDispData = new newDisplayData();
- currDispData.newLiveLogData = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} | {messType} | {expString}{Environment.NewLine}{exception}";
- parentForm.updateFormDisplay(currDispData);
- }
- catch
- { }
- }
-
- ///
- /// Invia messaggio a logWatcher
- ///
- ///
- ///
- protected void sendToTaskWatch(string messType, string message)
- {
- parentForm.taskWatcher = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} | {messType} | {message}";
- }
-
- ///
- /// Impostazioni parametri PLC
- ///
- protected virtual void setParamPlc()
- {
- loadMemConf();
- fixDefaultPar();
- }
-
- #region metodi adapter
-
- protected bool _connOk = false;
-
- ///
- /// Max tentativi ping permessi (default: 5)
- ///
- protected int maxPingRetry { get; set; } = 5;
-
- ///
- /// test ping all'indirizzo PLC/CNC impostato nei parametri
- ///
- ///
- protected IPStatus testPingMachine
- {
- get
- {
- IPStatus answ = IPStatus.Unknown;
- // se disabilitato salto...
- if (pingDisabled)
- {
- answ = IPStatus.Success;
- }
- else
- {
- IPAddress address;
- PingReply reply;
- using (Ping pingSender = new Ping())
- {
- address = IPAddress.Loopback;
- IPAddress.TryParse(cIobConf.cncIpAddr, out address);
- int pingMsTimeout = cIobConf.pingMsTimeout;
- reply = pingSender.Send(address, pingMsTimeout);
- answ = reply.Status;
- }
- }
- return answ;
- }
- }
-
- ///
- /// Salva verifica stato connessione OK
- ///
- ///
- public virtual bool connectionOk
- {
- get
- {
- return _connOk || DemoIn;
- }
- set
- {
- _connOk = value;
- }
- }
-
- ///
- /// indica se ping disabilitato da optPar
- ///
- public bool pingDisabled
- {
- get
- {
- bool answ = false;
- bool.TryParse(getOptPar("NO_PING"), out answ);
- return answ;
- }
- }
-
- ///
- /// Verifica e se necessario comprime directory log...
- ///
- private void checkShrinkDir()
- {
- string path = string.Format("{0}logs\\{1}", AppDomain.CurrentDomain.BaseDirectory, cIobConf.codIOB);
- baseUtils.shrinkDir(path);
- }
-
- private void reportDataProc()
- {
- // update valori visualizzazione...
- parentForm.dataProcLabel = string.Format("RAW: {0} --> IN: {1} --> OUT: {2}", nReadIN, nReadFilt, nSendOut);
- }
-
- private void svuotaCodaContapezzi()
- {
- // permetto al max 2 tentativi infruttuosi...
- int maxTry = 2;
- int oldContapezzi = contapezziIOB;
- // se ho contapezzi OLTRE limite...
- while ((MPOnline) && (contapezziPLC > contapezziIOB + minSendPzCountBlock))
- {
- lgInfo($"Ciclo svuotaCodaContapezzi --> contapezziPLC: {contapezziPLC} | contapezziIOB: {contapezziIOB}");
- if (!isMulti)
- {
- pzCntReload(true);
- }
- // provo invio
- trySendPzCountBlock();
- // verifica per evitare loop infinito invio fallito
- if (oldContapezzi == contapezziIOB)
- {
- maxTry--;
- }
- else
- {
- maxTry = 2;
- oldContapezzi = contapezziIOB;
- }
- // verifico maxTry: se li ho esauriti esco!
- if (maxTry <= 0)
- {
- return;
- }
- // aspetto x dare tempo calcolo
- Thread.Sleep(400);
- }
- }
-
- ///
- /// Cerca di inviare su un altro thread i vari dati accumulati...
- ///
- private void trySendValues()
- {
- // init obj display
- newDisplayData currDispData = new newDisplayData();
- try
- {
- // verifico se risponde il server...
- if (checkServerAlive)
- {
- bool iobOk = false;
- if (utils.CRB("sendDataByThread"))
- {
- Task taskCheck = TaskEx.Run(() => iobOk = checkIobEnabled);
- }
- else
- {
- iobOk = checkIobEnabled;
- }
- // verifico SE posso inviare dati
- if (iobOk)
- {
- currDispData.semOut = Semaforo.SV;
- // verificare come gestire il task secondario senza interferenza (chiamate update su FORM da thread secondari danno errori)
- if (utils.CRB("sendDataByThread"))
- {
- // invio con thread separato...
- Task taskSigIN = TaskEx.Run(() => svuotaCodaSignIN());
- Task taskFlog = TaskEx.Run(() => svuotaCodaFLog());
- }
- else
- {
- // gestione queue SignalIN (invio, display)
- svuotaCodaSignIN();
- currDispData.counter = contapezziIOB;
- raiseRefresh(currDispData);
- // provo a svuotare coda contapezzi
- svuotaCodaContapezzi();
- currDispData.counter = contapezziIOB;
- raiseRefresh(currDispData);
- // gestione queue FluxLog (invio, display)
- svuotaCodaFLog();
- raiseRefresh(currDispData);
- }
- }
- else
- {
- // mostro VETO-SEND x invio... GIALLO
- currDispData.semOut = Semaforo.SG;
- if (periodicLog)
- {
- lgInfo("IOB - VETO SEND");
- }
- }
- }
- else
- {
- // mostro SERVER KO x invio... ROSSO
- currDispData.semOut = Semaforo.SR;
- if (periodicLog)
- {
- lgInfo("IOB - SERVER NOT READY");
- }
- }
- }
- catch (Exception exc)
- {
- lgError($"Errore in fase trySendValues{Environment.NewLine}{exc}");
- currDispData.semOut = Semaforo.SR;
- }
- raiseRefresh(currDispData);
- }
-
- ///
- /// Stringa raw dei parametri da scrivere...
- ///
- ///
- protected string getParams2write()
- {
- string answ = "";
- string url2call = $"{urlGetParams2Write}";
- if (verboseLog)
- {
- lgInfo("chiamata URL " + url2call);
- }
- answ = utils.callUrlNow(url2call);
- // se vuoto faccio seconda prova...
- if (string.IsNullOrEmpty(answ))
- {
- answ = utils.callUrlNow(url2call);
- }
- return answ;
- }
-
- ///
- /// Chiede elenco dei task da eseguire
- /// - formato Json
- /// - array di KVP / Dictionary
- /// - formato definito da API x MP/IO/:
- /// - KEY: task
- /// - VALUE: array JSon KVP
- ///
- protected string getTask2exe()
- {
- string answ = "";
- if (checkServerAlive)
- {
- string url2call = $"{urlGetTask2Exe}";
- if (verboseLog)
- {
- lgInfo("chiamata URL " + url2call);
- }
- answ = utils.callUrlNow(url2call);
- }
- return answ;
- }
-
- ///
- /// Metodo da overridare x scrivere DAVVERO i aprametri sul PLC
- ///
- ///
- protected virtual void plcWriteParams(List updatedPar)
- {
- // non faccio nulla di base...
- }
-
- ///
- /// Processa le richieste di scrittura memoria
- ///
- ///
- protected string processMemWriteRequests()
- {
- string answ = "";
- // li salvo nei parametri in memoria locale (ogni adapter DOVREBBE salvare POI sul VERO PLC)
- List writeList = new List();
- List updatedPar = new List();
- // recupero elenco delle cose da fare
- string resp = getParams2write();
- if (!string.IsNullOrEmpty(resp))
- {
- try
- {
- writeList = JsonConvert.DeserializeObject>(resp);
- // se ho da fare chiamo esecuzione..
- if (writeList.Count > 0)
- {
- foreach (var item in writeList)
- {
- // scrivo in memoria
- if (memMap.mMapWrite.ContainsKey(item.uid))
- {
- memMap.mMapWrite[item.uid].value = item.reqValue;
- // accodo in stringa taskVal...
- answ += $" | Parameter {item.uid} --> {item.reqValue}";
- // sistemo valori
- item.value = item.reqValue;
- lgInfo($"Effettuato update parametro: actVal = {item.value} | reqVal = {item.reqValue}");
- item.reqValue = "";
- // salvo in lista da ritrasmettere
- updatedPar.Add(item);
- }
- else
- {
- answ += $" | Error: parameter {item.uid} not found";
- }
- }
- // richiamo scrittura parametri su PLC
- plcWriteParams(updatedPar);
- // invio su cloud parametri!
- string rawData = JsonConvert.SerializeObject(updatedPar);
- utils.callUrl($"{urlUpdateWriteParams}", rawData);
- }
- }
- catch (Exception exc)
- {
- lgError($"Eccezione in processServerRequests:{Environment.NewLine}{exc}");
- }
- }
- else
- {
- lgError("Non è stata ricevuta risposta x task da eseguire");
- }
- return answ;
- }
-
- protected void raiseRefresh(newDisplayData currDispData)
- {
- if (currDispData.hasData)
- {
- // segnalo refresh!
- if (eh_refreshed != null)
- {
- eh_refreshed(this, new iobRefreshedEventArgs(currDispData));
- }
- }
- }
-
- ///
- /// Cancella dal server i task eseguiti
- ///
- ///
- ///
- ///
- protected string remTask2exe(string taskName, string esitoTask)
- {
- string answ = "";
- if (checkServerAlive)
- {
- string url2call = $"{urlRemTask2Exe}{taskName}";
- lgInfo($"Task2Exe | {esitoTask} | chiamata URL {url2call}");
- answ = utils.callUrlNow(url2call);
- }
- return answ;
- }
-
- ///
- /// Invia informazioni associazione IOB 2 machine
- ///
- protected void sendM2IOB()
- {
- if (checkServerAlive)
- {
- lgInfo("chiamata URL " + urlSetM2IOB);
- utils.callUrlNow(urlSetM2IOB);
- }
- }
-
- ///
- /// Invia al server IO i valori dei parametri opzionali (es counters)
- ///
- /// Nome parametro
- /// Valore parametro
- protected void sendOptVal(string paramName, string paramValue)
- {
- if (checkServerAlive)
- {
- string url2call = $"{urlSetOptVal}pName={paramName}&pValue={paramValue}";
- lgInfo("chiamata URL " + url2call);
- utils.callUrlNow(url2call);
- }
- }
-
- ///
- /// Invia al server IO i valori dei parametri opzionali (es counters)
- ///
- /// Nome parametro
- /// Valore parametro INT
- protected void sendOptVal(string paramName, int paramValueInt)
- {
- // override!
- sendOptVal(paramName, paramValueInt.ToString());
- }
-
- ///
- /// processa dataLayer e se necessario salva/mostra
- ///
- public static void checkSavePersDataLayer()
- {
- }
-
- public static void resetDebugConsole()
- {
- }
-
- ///
- /// Esecuzione dei task richiesti e pulizia coda richieste eseguite
- ///
- ///
- public virtual Dictionary executeTasks(Dictionary task2exe)
- {
- // Verificare il protocollo: dovrebbe togliere SOLO i task eseguiti...
- Dictionary taskDone = new Dictionary();
- if (task2exe != null)
- {
- bool taskOk = false;
- string taskVal = "";
- // cerco task specifici: se ho startSetup --> imposto bit DBB701.DBB0.4
- foreach (var item in task2exe)
- {
- taskOk = false;
- taskVal = "";
- // converto richiesta in enum...
- taskType tName = taskType.nihil;
- Enum.TryParse(item.Key, out tName);
- // controllo sulla KEY...
- switch (tName)
- {
- case taskType.nihil:
- case taskType.fixStopSetup:
- case taskType.forceSetPzCount:
- case taskType.sendWatchDogMes2Plc:
- taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC";
- lgInfo($"Chiamata senza processing: taskOk: {taskOk} | taskVal: {taskVal}");
- break;
-
- case taskType.setArt:
- case taskType.setComm:
- case taskType.setProg:
- case taskType.setPzComm:
- // recupero dati da memMap...
- if (memMap.mMapWrite.ContainsKey(item.Key))
- {
- dataConf currMem = memMap.mMapWrite[item.Key];
- string addr = currMem.memAddr;
- taskVal = $"SET task: {item.Key} --> {item.Value} | mem: {currMem.memAddr} - {currMem.size} byte";
- // salvo il nuovo valore nella memoria... così prox invio lo trasmetterà
- memMap.mMapWrite[item.Key].value = item.Value;
- }
- else
- {
- taskVal = $"NO DATA MEM, SET task: {item.Key} --> {item.Value}";
- }
- break;
-
- case taskType.forceResetPzCount:
- // reset contapezzi inizio setup
- taskOk = resetcontapezziPLC();
- taskVal = taskOk ? "RESET PZ COUNT OK" : "PZ RESET DISABLED | NO EXEC";
- lgInfo($"Chiamata forceResetPzCount: taskOk: {taskOk} | taskVal: {taskVal}");
- break;
-
- case taskType.startSetup:
- // reset contapezzi inizio setup
- taskOk = resetcontapezziPLC();
- taskVal = taskOk ? "RESET: SETUP START" : "PZ RESET DISABLED | NO EXEC";
- lgInfo($"Chiamata startSetup: taskOk: {taskOk} | taskVal: {taskVal}");
- break;
-
- case taskType.stopSetup:
- // reset contapezzi fine setup SE ESPLICITAMENTE IMPOSTATO
- if (cIobConf.optPar.Count > 0 && getOptPar("ENABLE_PZ_RESET_stopSetup") == "TRUE")
- {
- taskOk = resetcontapezziPLC();
- }
- taskVal = taskOk ? "RESET: SETUP END" : "PZ RESET DISABLED | NO EXEC";
- lgInfo($"Chiamata stopSetup: taskOk: {taskOk} | taskVal: {taskVal}");
- break;
-
- case taskType.setParameter:
- // richiedo da URL i parametri WRITE da popolare
- lgInfo("Chiamata processMemWriteRequests");
- taskVal = processMemWriteRequests();
- // se restituiscce "" faccio altra prova...
- if (string.IsNullOrEmpty(taskVal))
- {
- // i parametri me li aspetto come stringa composta paramName|paramvalue
- if (item.Value.Contains("|"))
- {
- string[] paramsJob = item.Value.Split('|');
- taskVal = $"REQUEST SET PARAMETERS: {paramsJob[0]} --> {paramsJob[1]}";
+ lastPeriodicLog = DateTime.Now;
}
- else
- {
- taskVal = $"WRONG REQUEST FOR SET PARAMETERS: {item.Value} doesnt contain pipe for splitting key/value";
- }
- }
- break;
- default:
- taskVal = "SKIPPED | NO EXEC";
- lgInfo($"Chiamata default senza processing: taskOk: {taskOk} | taskVal: {taskVal}");
- break;
- }
- // aggiungo task!
- taskDone.Add(item.Key, taskVal);
+ return answ;
+ }
}
- }
- return taskDone;
- }
- ///
- /// effettua recupero dati ed invio valori modificati...
- ///
- ///
- public void getAndSend(gatherCycle ciclo)
- {
- // init obj display
- newDisplayData currDispData = new newDisplayData();
- // IN OGNI CASO a prima di tutto EFFETTUO GESTIONE INVII dati da code!!!
- try
- {
- trySendValues();
- }
- catch (Exception exc)
- {
- lgError(exc, "Errore in gestione svuotamento/invio preliminare code memoria");
- currDispData.semOut = Semaforo.SR;
- }
- // controllo connessione/connettività
- if (connectionOk)
- {
- // controllo non sia già in esecuzione...
- if (!adpCommAct)
+ ///
+ /// Verifica SE si debba fare log verboso (verboso + ogni tot letture IN)
+ ///
+ public bool verboseLog
{
- // provo ad avviare
- try
- {
- // imposto flag adapter running..
- adpCommAct = true;
- adpStartRun = DateTime.Now;
- }
- catch (Exception exc)
- {
- string errore = $"Adapter NOT STARTED!!!{Environment.NewLine}{exc}";
- adpCommAct = false;
- adpStartRun = DateTime.Now;
- currDispData.newLiveLogData = errore;
- }
- if (adpCommAct)
- {
- // try / catch generale altrimenti segno che è disconnesso...
+ get
+ {
+ bool answ = false;
+ int logEvery = utils.CRI("logEvery");
+ if (logEvery < 1)
+ {
+ logEvery = 10;
+ }
+
+ answ = utils.CRB("verbose") && (nReadIN % logEvery == 0);
+ return answ;
+ }
+ }
+
+ ///
+ /// Coda massima ammessa per FLog (se <=0 disattivata...)
+ ///
+ protected int maxQueueFLog { get; set; } = utils.CRI("maxQueueFLog");
+
+ ///
+ /// Numero letture IN da avvio
+ ///
+ protected int nReadFilt { get; set; }
+
+ ///
+ /// Numero letture IN da avvio
+ ///
+ protected int nReadIN { get; set; }
+
+ ///
+ /// Numero invii OUT (svuotamento coda)
+ ///
+ protected int nSendOut { get; set; }
+
+ ///
+ /// Numero simulazioni ammesse...
+ ///
+ protected int numSim { get; set; }
+
+ ///
+ /// Aggiunge ai dati da inviare alla parentform i valori di RawInput rilevati
+ ///
+ public virtual void reportRawInput(ref newDisplayData currDispData)
+ {
+ // processo eventualmente aggiungendo ad elementi esistenti...
+ if (currDispData == null)
+ {
+ currDispData = new newDisplayData();
+ }
try
{
- bool showDebugData = false;
- if (ciclo == gatherCycle.VHF)
- {
- processVHF();
- }
- // processing dati memoria (lettura, filtraggio, enqueque)
- else if (ciclo == gatherCycle.HF)
- {
- processWhatchDog();
- processAllMemory();
- processMode();
- }
- else if (ciclo == gatherCycle.MF)
- {
- processServerRequests();
- processOverride();
- processContapezzi();
- processCncAlarms();
- processDynData();
- }
- else if (ciclo == gatherCycle.LF)
- {
- processOtherCounters();
- processProgram();
- // verifico se devo gestire cambio ODL in modo automatico
- processAutoOdl();
- }
- else if (ciclo == gatherCycle.VLF)
- {
- if (utils.CRB("enableContapezzi"))
+ StringBuilder sb = new StringBuilder();
+ sb.Append($"B_input --> {(short)B_input}{Environment.NewLine}");
+ sb.Append($"{baseUtils.binaryForm(B_input)}{Environment.NewLine}");
+ sb.Append($"{Environment.NewLine}");
+ sb.Append($"----------- RAW Data Memory -----------{Environment.NewLine}");
+ int i = 0;
+ foreach (var item in RawInput)
{
- // rilettura contapezzi da server...
- lgInfo("Ciclo VLF: pzCntReload(true)");
- if (!isMulti)
- {
- pzCntReload(true);
- }
- // refresh associazione Macchina - IOB
- sendM2IOB();
+ sb.Append($"B{i:00} --> {baseUtils.binaryForm(item)} = {(short)item}{Environment.NewLine}");
+ i++;
}
- // recupero dati SETUP (sysinfo) e li invio/mostro se variati...
- processSysInfo();
- // checkLogDir x shrink!
- checkShrinkDir();
- // eventuale log!
- if (utils.CRB("recTime"))
- {
- logTimeResults();
- }
- }
- // mostra eventuali altri dati di processo...
- reportDataProc();
- if (showDebugData)
- {
- // verifica se debba salvare e mostrare dati
- checkSavePersDataLayer();
- }
- }
- catch (Exception exc)
- {
- // segnalo eccezione e indico disconnesso...
- lgError(exc, string.Format("Errore in gestione ciclo principale ADP, fermo adapter{0}{1}", Environment.NewLine, exc));
- parentForm.fermaAdapter(true, false, true);
- }
- // tolgo flag running
- adpCommAct = false;
- }
- else
- {
- if (periodicLog)
- {
- lgInfo("ADP not running...");
- }
- }
- }
- else
- {
- // log ADP running
- lgError("Non eseguo chiamata: ADP ancora in running");
- // se è bloccato da oltre maxSec lo sblocco...
- if (DateTime.Now.Subtract(adpStartRun).TotalSeconds > utils.CRI("maxAdapterLockSec"))
- {
- // tolgo flag running
- adpCommAct = false;
- adpStartRun = DateTime.Now;
- }
- }
- }
- else
- {
- // provo a riconnettere SE abilitato tryRestart...
- if (adpTryRestart && !connectionOk)
- {
- // controllo se sia scaduto periodi di veto al tryConnect...
- int waitRecMSec = utils.CRI("waitRecMSec") * 2;
- DateTime dtVeto = lastConnectTry.AddMilliseconds(waitRecMSec);
- if (DateTime.Now > dtVeto)
- {
- lgInfo($"Retry Time Elapsed (waited for {waitRecMSec} ms)--> NOW tryConnect");
- lastConnectTry = DateTime.Now;
- tryConnect();
- }
- }
- currDispData.semIn = Semaforo.SR;
- }
- raiseRefresh(currDispData);
- }
-
- ///
- /// riporta il log di tutti i dati di results temporali registrati
- ///
- public void logTimeResults()
- {
- if (TimingData.results.Count > 0)
- {
- lgInfo("{0}--------------- START TIMING DATA ---------------", Environment.NewLine);
- int globNumCall = 0;
- TimeSpan globAvgMsec = new TimeSpan(0);
- foreach (TimeRec item in TimingData.results)
- {
- // loggo SOLO se del mio IOB corrente...
- if (item.classCall == cIobConf.codIOB)
- {
- lgInfo("{4}|Chiamate {0}: effettuate {1}, tempo medio {2:N2} msec | impegno canale {3:P3}", item.codCall, item.numCall, item.avgMsec, item.totMsec.TotalSeconds / DateTime.Now.Subtract(dtAvvioAdp).TotalSeconds, cIobConf.codIOB);
- globNumCall += item.numCall;
- globAvgMsec += item.totMsec;
- }
- }
- // riporto conteggio medio al secondo...
- lgInfo("{4}|Chiamate GLOBALI: {0}, periodo: {1:N2} minuti.cent, tempo medio {2:N2} msec | impegno canale {3:P3}", globNumCall, DateTime.Now.Subtract(dtAvvioAdp).TotalMinutes, globAvgMsec.TotalMilliseconds / globNumCall, globAvgMsec.TotalSeconds / DateTime.Now.Subtract(dtAvvioAdp).TotalSeconds, cIobConf.codIOB);
- lgInfo("{0}--------------- STOP TIMING DATA ---------------{0}", Environment.NewLine);
- // mostro in form statistiche globali!
- parentForm.updateComStats(string.Format("Periodo: {0:N2}min | {1} x {2:N2}ms | canale {3:P3}", DateTime.Now.Subtract(dtAvvioAdp).TotalMinutes, globNumCall, globAvgMsec.TotalMilliseconds / globNumCall, globAvgMsec.TotalSeconds / DateTime.Now.Subtract(dtAvvioAdp).TotalSeconds));
- }
- }
-
- ///
- /// Effettua ciclo controllo richieste server
- ///
- public void processServerRequests()
- {
- Dictionary task2exe = new Dictionary();
- Dictionary taskDone = new Dictionary();
- // recupero elenco delle cose da fare
- string resp = getTask2exe();
- if (!string.IsNullOrEmpty(resp))
- {
- try
- {
- task2exe = JsonConvert.DeserializeObject>(resp);
- // se ho da fare chiamo esecuzione..
- if (task2exe.Count > 0)
- {
- taskDone = processTask(task2exe);
- }
- }
- catch (Exception exc)
- {
- lgError($"Eccezione in processServerRequests:{Environment.NewLine}{exc}");
- }
- }
- }
-
- public Dictionary processTask(Dictionary task2exe)
- {
- Dictionary taskDone = new Dictionary();
- if (task2exe != null)
- {
- lgInfo($"Task2Exe: trovati {task2exe.Count} task da eseguire, procedo");
- // chiamo procedura esecutiva (diversa x ogni IOB)
- taskDone = executeTasks(task2exe);
- // loggo tutti i task done...
- foreach (var item in taskDone)
- {
- sendToTaskWatch(item.Key, item.Value);
- }
- // ora chiamo la cancellazione dei task eseguiti...
- foreach (var item in taskDone)
- {
- remTask2exe(item.Key, item.Value);
- }
- }
- return taskDone;
- }
-
- ///
- /// Effettua rilettura del contapezzi dal server MP/IO
- ///
- /// Forza rilettura da DB tempi ciclo rilevati
- public void pzCntReload(bool forceCountRec)
- {
- // legge da IO server ULTIMO valore CONTPEZZI al riavvio...
- string currServerCount = "";
- string lastIdxODL = "";
- if (checkServerAlive)
- {
- // leggo PRIMA ODL ....
- lastIdxODL = utils.callUrl(urlGetCurrODL);
- lgInfo("Lettura ODL dall'url {0} --> {1}", urlGetCurrODL, lastIdxODL);
- // se ho valori in coda da trasmettere uso dati REDIS
- if (forceCountRec)
- {
- // uso dati da TCiclo registrati...
- currServerCount = utils.callUrl(urlGetPzCountRec);
- lgInfo("Lettura contapezzi da TCiclo dall'url {0} --> num pz: {1}", urlGetPzCountRec, currServerCount);
- }
- else
- {
- // uso il contapezzi dichiarato dall'IOB stesso
- currServerCount = utils.callUrl(urlGetPzCount);
- lgInfo("Lettura contapezzi dall'url {0}", urlGetPzCount);
- }
- // controllo: SE NON HO ODL...
- if (string.IsNullOrEmpty(lastIdxODL) || lastIdxODL == "0")
- {
- // NON AGGIORNO
- contapezziIOB = contapezziPLC;
- lgInfo($"Errore lettura ODL (vuoto) resta tutto invariato contapezzi: {contapezziIOB} | contapezziPLC {contapezziPLC}");
- }
- else
- {
- if (!string.IsNullOrEmpty(currServerCount))
- {
- // se "-1" resto a ultimo...
- if (currServerCount != "-1")
- {
- int newVal = -1;
- Int32.TryParse(currServerCount, out newVal);
- contapezziIOB = newVal > -1 ? newVal : contapezziIOB;
- lgInfo("Ricevuta conferma da server di {0} pezzi registrati per ODL", currServerCount);
- }
- else
- {
- // NON AGGIORNO
- contapezziIOB = contapezziPLC;
- lgInfo($"Errore lettura contapezzi (-1) - uso contapezziPLC --> {contapezziPLC}");
- }
- }
- else
- {
- // registro che ho UN NUOVO ODL
- lgInfo($"Lettura ODL in pzCntReload, currIdxODL {currIdxODL} --> lastIdxODL {lastIdxODL}");
- // se ODL differente e NUOVO è zero --> resetto!
- if (currIdxODL.ToString() != lastIdxODL && lastIdxODL == "0")
- {
- // cambiato ODL quindi reset...
- contapezziIOB = 0;
- lgInfo("Nuovo ODL==0, RESET contapezzi (-->ZERO)");
- }
- // provo a salvare nuovo ODL
- int.TryParse(lastIdxODL, out currIdxODL);
- }
- }
- }
- else
- {
- // se server NON pronto...
- contapezziIOB = contapezziPLC;
- lgError("Errore server NON pronto in pzCntReload");
- }
- }
-
- ///
- /// Metodo generico di reset contapezzi...
- ///
- ///
- public virtual bool resetcontapezziPLC()
- {
- return false;
- }
-
- ///
- /// Metodo generico di IMPOSTAZIONE FORZATA del contapezzi...
- ///
- /// Pezzi richiesti
- ///
- public virtual bool setcontapezziPLC(int newPzCount)
- {
- return false;
- }
-
- ///
- /// Avvia l'adapter sulla porta richiesta
- ///
- /// indica se sia richeisto di SVUOTARE le code delel info
- public virtual void startAdapter(bool resetQueue)
- {
- lgInfo("Starting adapter...");
- maxJsonData = utils.CRI("maxJsonData");
- maxJsonDataEv = utils.CRI("maxJsonDataEv");
- parentForm.commPlcActive = false;
- adpRunning = true;
- dtAvvioAdp = DateTime.Now;
- lastWatchDog = dtAvvioAdp;
- lastPING = dtAvvioAdp;
- lastReadPLC = dtAvvioAdp.AddMinutes(-1);
- lastDisconnCheck = dtAvvioAdp;
- TimingData.resetData();
- // aggiungo altri defaults
- setDefaults(resetQueue);
- adpTryRestart = true;
- parentForm.displayTaskAndLog("Adapter Started!");
- }
-
- ///
- /// ferma l'adapter...
- ///
- /// indica se si debba tentare di riavviare l'adapter (con caduta connessione viene fermato in automatico)
- /// indica se sia richeisto di SVUOTARE le code delel info
- public virtual void stopAdapter(bool tryRestart, bool forceDequeue)
- {
- if (forceDequeue)
- {
- // svuoto le code dei valori letti e non ancora trasmessi...
- parentForm.displayTaskAndLog("Svuotamento FORZATO coda segnali...");
- while (QueueIN.Count > 0)
- {
- // INVIO COMUNQUE...!!!
- string valore = "";
- QueueIN.TryDequeue(out valore);
- sendToMoonPro(urlType.SignIN, valore);
- }
- parentForm.displayTaskAndLog("Svuotamento FORZATO coda FluxLOG...");
- // se ho + di 2 elementi in coda --> uso invio JSON in blocco...
- if (QueueFLog.Count > minJsonData)
- {
- while (QueueFLog.Count > 0)
- {
- List listaValori = new List();
- // se ho + di maxJsonData elementi --> invio un set di dati alla volta
- if (QueueFLog.Count > maxJsonData)
- {
- string currVal = "";
- // prendoi primi maxJsonDataValori
- for (int i = 0; i < maxJsonData; i++)
- {
- QueueFLog.TryDequeue(out currVal);
- listaValori.Add(currVal);
- }
- sendDataBlock(urlType.FLog, listaValori);
- }
- else
- {
- // invio in blocco
- listaValori = QueueFLog.ToList();
- // invio
- sendDataBlock(urlType.FLog, listaValori);
- // svuoto!
- QueueFLog = new ConcurrentQueue();
- }
- }
- // HO FINITO invio di FLog...
- }
- else
- {
- string currVal = "";
- while (QueueFLog.Count > 0)
- {
- // INVIO COMUNQUE...!!!
- QueueFLog.TryDequeue(out currVal);
- sendToMoonPro(urlType.FLog, currVal);
- }
- }
- }
- parentForm.displayTaskAndLog("Stopping adapter...");
- adpTryRestart = false;
-
- parentForm.displayTaskAndLog("Stopping adapter - last periodic data read...");
-
- // chiudo la connessione all'adapter...
- tryDisconnect();
- dtStopAdp = DateTime.Now;
- adpTryRestart = tryRestart;
- adpRunning = false;
- // chiudo!
- parentForm.displayTaskAndLog("Adapter Stopped.");
- parentForm.commPlcActive = false;
- }
-
- ///
- /// Metodo base connessione...
- ///
- public virtual void tryConnect()
- {
- dtAvvioAdp = DateTime.Now;
- }
-
- ///
- /// Metodo base disconnessione...
- ///
- public virtual void tryDisconnect()
- {
- }
-
- #endregion metodi adapter
-
- #region layer persistenza dati
-
- ///
- /// Dizionario di persistenza per i valori da salvare da/su file
- ///
- public Dictionary persistenceLayer;
-
- ///
- /// recupera valore salvato in persistence layer (se non c'è crea...)
- ///
- ///
- ///
- private string getStoredVal(string keyVal)
- {
- string value = "";
- try
- {
- if (persistenceLayer != null)
- {
- if (!persistenceLayer.TryGetValue(keyVal, out value))
- {
- persistenceLayer.Add(keyVal, "0");
- }
- }
- }
- catch (Exception exc)
- {
- lgError(string.Format("Eccezione in getStoredVal: {0}{1}", Environment.NewLine, exc));
- }
- return value;
- }
-
- ///
- /// recupera valore salvato in persistence layer (se non c'è crea...) come double
- ///
- ///
- ///
- private double getStoredValDouble(string keyVal)
- {
- double answ = 0;
- try
- {
- answ = Convert.ToDouble(getStoredVal(keyVal));
- }
- catch (Exception exc)
- {
- lgError(string.Format("Eccezione in getStoredValDouble: {0}{1}", Environment.NewLine, exc));
- }
- answ = (answ < (double.MaxValue / 10 * 9)) ? answ : 0;
- return answ;
- }
-
- ///
- /// recupera valore salvato in persistence layer (se non c'è crea...) come INT
- ///
- ///
- ///
- private long getStoredValLong(string keyVal)
- {
- long answ = 0;
- try
- {
- answ = Convert.ToInt64(getStoredVal(keyVal));
- }
- catch
- { }
- // verifico che il valore sia minore di 9/10 del valore massimo...
- answ = (answ < (long.MaxValue / 10 * 9)) ? answ : 0;
- return answ;
- }
-
- ///
- /// recupera valore salvato in persistence layer (se non c'è crea...) come UINT
- ///
- ///
- ///
- private uint getStoredValUInt(string keyVal)
- {
- uint answ = 0;
- try
- {
- answ = Convert.ToUInt32(getStoredVal(keyVal));
- }
- catch (Exception exc)
- {
- lgError(string.Format("Eccezione in getStoredValUInt: {0}{1}", Environment.NewLine, exc));
- }
- // verifico che il valore sia minore di 9/10 del valore massimo...
- answ = (answ < (uint.MaxValue / 10 * 9)) ? answ : 0;
- return answ;
- }
-
- ///
- /// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce
- ///
- ///
- ///
- ///
- /// Nuovo valore incrementato
- private double updateValDoubleByIncr(int i, double delta, string searchString)
- {
- // stringa da cercare..
- string keyVal = string.Format(searchString, i + 1);
- // recupero valore precedente...
- double contAct = getStoredValDouble(keyVal);
- // nuovo valore...
- contAct += delta;
- // salvo in ram!
- persistenceLayer[keyVal] = contAct.ToString();
- // rendo il valore!
- return contAct;
- }
-
- ///
- /// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce
- ///
- ///
- ///
- ///
- /// Nuovo valore incrementato
- private long updateValLongByIncr(int i, long delta, string searchString)
- {
- // stringa da cercare..
- string keyVal = string.Format(searchString, i + 1);
- // recupero valore precedente...
- long contAct = getStoredValLong(keyVal);
- // nuovo valore...
- contAct += delta;
- // salvo in ram!
- persistenceLayer[keyVal] = contAct.ToString();
- // rendo il valore!
- return contAct;
- }
-
- ///
- /// Aggiorna un valore del dizionario in SOSTITUZIONE
- ///
- ///
- ///
- ///
- /// Nuovo valore incrementato
- private void updateValString(int i, string newVal, string searchString)
- {
- // stringa da cercare..
- string keyVal = string.Format(searchString, i + 1);
- // salvo in ram!
- persistenceLayer[keyVal] = newVal;
- }
-
- ///
- /// Aggiorna un valore del dizionario in SOSTITUZIONE e lo restituisce
- ///
- ///
- ///
- ///
- /// Nuovo valore incrementato
- private void updateValUInt(int i, uint newVal, string searchString)
- {
- // stringa da cercare..
- string keyVal = string.Format(searchString, i + 1);
- // salvo in ram!
- persistenceLayer[keyVal] = newVal.ToString();
- }
-
- ///
- /// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce
- ///
- ///
- ///
- ///
- /// Nuovo valore incrementato
- private uint updateValUIntByIncr(int i, uint delta, string searchString)
- {
- // stringa da cercare..
- string keyVal = string.Format(searchString, i + 1);
- // recupero valore precedente...
- uint contAct = getStoredValUInt(keyVal);
- // nuovo valore...
- contAct += delta;
- // salvo in ram!
- persistenceLayer[keyVal] = contAct.ToString();
- // rendo il valore!
- return contAct;
- }
-
- #endregion layer persistenza dati
-
- #region area lettura configurazioni
-
- ///
- /// Decodifica file MAP (caso .bit)
- ///
- ///
- ///
- /// indirizzo Byte: indirizzo di partenza memoria
- /// dimensione singolo slot in byte
- /// indirizzo bit: numero riga x calcolo indice bit
- ///
- protected static otherData decodeBitData(string linea, char separator, int ByteNum, int memSize, int BitNum)
- {
- if (linea != null)
- {
- string[] valori = linea.Split(separator);
- int shift = 0;
- try
- {
- shift = Convert.ToInt32(valori[0]) - 1;
- }
- catch
- { }
- int resto = 0;
- Math.DivRem(BitNum, 8, out resto);
- string memAddr = string.Format("{0}.{1}", ByteNum + shift * memSize, resto);
- return new otherData(valori[0], memAddr, valori[1].Trim(), valori[2].Trim());
- }
- else
- {
- return null;
- }
- }
-
- ///
- /// Decodifica file MAP generico
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- protected static otherData decodeOtherData(string linea, char separator, string memPre, int baseAddr, int memSize)
- {
- if (linea != null)
- {
- string[] valori = linea.Split(separator);
- int shift = 0;
- try
- {
- shift = Convert.ToInt32(valori[0]) - 1;
- }
- catch
- { }
- string memAddr = string.Format("{0}{1}", memPre, baseAddr + shift * memSize);
- return new otherData(valori[0], memAddr, valori[1].Trim(), valori[2].Trim());
- }
- else
- {
- return null;
- }
- }
-
- ///
- /// Legge il file di conf di una MAP di informazioni da gestire con lettura set memoria
- ///
- /// nome vettore memoria
- /// file origine
- /// dimensione (in byte) della memoria
- /// dimensione (in byte) della memoria
- protected void loadConfFile(ref otherData[] vettoreConf, string nomeFile, int memSize, ref int numVett)
- {
- otherData lastData = new otherData();
- int totRighe = 0;
- string linea;
- totRighe = File.ReadLines(nomeFile).Count();
- // creo un vettore della dimensione corretta... conta anche commenti tanto poi riduco...
- vettoreConf = new otherData[File.ReadLines(nomeFile).Count()];
- // carica da file...
- StreamReader file = new StreamReader(nomeFile);
- // leggo 1 linea alla volta...
- int numRiga = 0;
- int bitNum = 0;
- int byteNum = 0;
- while ((linea = file.ReadLine()) != null)
- {
- // SE non è un commento...
- if (linea.Substring(0, 1) != "#")
- {
- // se finisce per BIT allora processo bit-a-bit...
- if (linea.EndsWith("BOOL"))
- {
- try
- {
- string[] memIdx = linea.Split(utils.CRC("testCharSep"))[0].Split('.');
- // calcolo bit e byte number...
- int.TryParse(memIdx[0], out byteNum);
- if (memIdx.Length > 1)
- {
- int.TryParse(memIdx[1], out bitNum);
- }
- else
- {
- bitNum = 0;
- }
- }
- catch
- {
- byteNum = 0;
- bitNum = 0;
- }
- lastData = decodeBitData(linea, utils.CRC("testCharSep"), byteNum, 1, bitNum);
- vettoreConf[numRiga] = lastData;
- }
- else
- {
- lastData = decodeOtherData(linea, utils.CRC("testCharSep"), "", 1, memSize);
- vettoreConf[numRiga] = lastData;
- }
- numRiga++;
- }
- }
- // salvo lunghezza file...
- try
- {
- numVett = Convert.ToInt32(lastData.memAddr) + 1;
- }
- catch
- {
- numVett = numRiga + 1;
- }
- // chiudo file
- file.Close();
- // ora trimmo vettore al solo numero VERO dei valori caricati...
- Array.Resize(ref vettoreConf, numRiga);
-
- if (isVerboseLog)
- {
- lgInfo(string.Format("Fine caricamento vettore di {0} variabili per file {1}", numRiga, nomeFile));
- }
- }
-
- ///
- /// Cerca parametri opzionali in modalità "like" del nome
- ///
- ///
- ///
- public Dictionary findOptPar(string keyStartSearch = "")
- {
- Dictionary answ = new Dictionary();
- // controllo SE keySearch !=""
- if (!string.IsNullOrWhiteSpace(keyStartSearch))
- {
- if (cIobConf.optPar.Count > 0)
- {
- // ciclo su tutti e cerco occorrenze che INIZINO...
- foreach (var item in cIobConf.optPar)
- {
- if (item.Key.StartsWith(keyStartSearch))
- {
- answ.Add(item.Key, item.Value);
- }
- }
- }
- }
- return answ;
- }
-
- ///
- /// Cerca se esiste il parametro opzionale e lo restituisce
- ///
- ///
- ///
- public string getOptPar(string key)
- {
- string answ = "";
- if (cIobConf.optPar.Count > 0)
- {
- // controllo SE HO il parametro
- if (cIobConf.optPar.ContainsKey(key))
- {
- answ = cIobConf.optPar[key];
- }
- }
- return answ;
- }
-
- #endregion area lettura configurazioni
-
- #region IOB METHODS
-
- ///
- /// contatore x simulazione valori input
- ///
- public int countSim = 0;
-
- ///
- /// DateTime Ultimo valore simulazione generato
- ///
- public DateTime lastSim;
-
- ///
- /// Verifica se la IOB sia ENABLED (da server o Demo)
- ///
- private bool checkIobEnabled
- {
- get
- {
- bool answ = false;
- // controllo se ho veto al check...
- if (dtVetoCheckIOB < DateTime.Now)
- {
- if (DemoOut)
- {
- answ = (QueueIN.Count + QueueFLog.Count >= nMaxSend);
- }
- else
- {
- try
- {
- // chiamo URL, se restituisce "OK" è enabled!
- string callResp = callUrl(urlIobEnabled, true);
- answ = (callResp == "OK");
- // attesa casuale se necessario
- var rand = new Random();
- // primi 2 test
- int maxTry = 2;
- while (maxTry > 0 && !answ)
- {
- Thread.Sleep(rand.Next(250, 500));
- callResp = callUrl(urlIobEnabled, true);
- answ = (callResp == "OK");
- maxTry--;
- }
- // se NON OK riprovo ANCORA 1 volta...
- if (!answ)
- {
- resetWebClients();
- Thread.Sleep(rand.Next(250, 1000));
- callResp = callUrl(urlIobEnabled, false);
- answ = (callResp == "OK");
- }
- // altri 2
- maxTry = 2;
- while (maxTry > 0 && !answ)
- {
- Thread.Sleep(rand.Next(250, 500));
- callResp = callUrl(urlIobEnabled, false);
- answ = (callResp == "OK");
- maxTry--;
- }
- // salvo status...
- IobOnline = answ;
- // se online imposto veto check a 5 x tempo reinvio...
- if (answ)
- {
- lastIobOnline = DateTime.Now;
- }
- dtVetoCheckIOB = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec * 5);
+ sb.Append("-------------------------------");
+ currDispData.currBitmap = sb.ToString();
}
catch
{ }
- }
- // verifico SE è variato stato online/offline...
- if (IobOnline != answ)
- {
- // se ORA sono online riporto...
- if (answ)
+ }
+
+ ///
+ /// Salva valori indicati in prod data
+ ///
+ /// Item KVP di cui salvare i dati in currProdData come chiave/valore
+ ///
+ public void saveProdData(KeyValuePair item)
+ {
+ // imposto i valori...
+ if (currProdData.ContainsKey(item.Key))
{
- lgInfo("IOB ONLINE for server MP/IO");
+ currProdData[item.Key] = item.Value;
}
else
{
- lgInfo("IOB OFFLINE for server MP/IO");
+ currProdData.Add(item.Key, item.Value);
}
- }
- // fix colore
- if (answ)
- {
- parentForm.commSrvActive = 2;
- }
- else
- {
- parentForm.commSrvActive = 1;
- }
}
- else
- {
- // altrimenti passo ultimo valore noto
- answ = IobOnline;
- }
- return answ;
- }
- }
- ///
- /// test ping all'indirizzo impostato nei parametri
- ///
- ///
- private IPStatus testPingServer
- {
- get
- {
- IPStatus answ = IPStatus.Unknown; ;
- IPAddress address;
- PingReply reply;
- using (Ping pingSender = new Ping())
+ #endregion variabili ed oggetti base
+
+ #region Protected Fields
+
+ ///
+ /// ultimo tentativo connessione...
+ ///
+ protected DateTime lastConnectTry;
+
+ ///
+ /// indica se serva refresh parametri e quindi PLC...
+ ///
+ protected bool needRefresh = true;
+
+ ///
+ /// Form chiamante
+ ///
+ protected AdapterForm parentForm;
+
+ #endregion Protected Fields
+
+ ///
+ /// Conf adapter corrente
+ ///
+ public IobConfiguration cIobConf;
+
+ ///
+ /// Struttura memoria PLC x lettura/scrittura da JSON file
+ ///
+ public plcMemMap memMap;
+
+ ///
+ /// inizializzo l'oggetto sulla form SULLA BASE DEL FILE DI CONFIGURAZIONE letto
+ ///
+ ///
+ ///
+ public IobGeneric(AdapterForm caller, IobConfiguration IOBConf)
{
- address = IPAddress.Loopback;
- int maxRetry = maxPingRetry + 1;
- int numRetry = 1; ;
- string ipAdrr = cIobConf.serverData.MPIP.Replace("http://", "").Replace("https://", "");
- IPAddress.TryParse(ipAdrr, out address);
- reply = pingSender.Send(address, pingServerMsTimeout);
- // se ho timeout riprovo...
- while (reply.Status != IPStatus.Success && numRetry < maxRetry)
- {
- lgInfo($"Ping KO | reply: {reply.Status} --> retry");
- reply = pingSender.Send(address, pingServerMsTimeout * numRetry / 2);
- numRetry++;
- if (reply.Status == IPStatus.Success)
+ if (IOBConf != null)
{
- lgInfo("PING OK!");
- break;
- }
- }
- }
- answ = reply.Status;
- return answ;
- }
- }
+ // init oggetto redis...
+ redisMan = new RedisIobCache(IOBConf.serverData.MPIP, IOBConf.codIOB);
- ///
- /// Valore del num max invii consecutivi da coda...
- ///
- protected static int nMaxSend
- {
- get
- {
- int answ = 5;
- try
- {
- answ = utils.CRI("nMaxSend");
- }
- catch
- { }
- return answ;
- }
- }
+ // initi oggetto TCMan
+ tcMan = new TCMan(IOBConf.TCLambda, IOBConf.TCMaxDelayFactor, IOBConf.TCMaxIncrPz);
- ///
- /// Verifica se il server sia ALIVE (tramite PING)
- ///
- public bool checkServerAlive
- {
- get
- {
- bool answ = false;
- // controllo se ho un VETO all'invio...
- if (dtVetoPing < DateTime.Now)
- {
- if (DemoOut)
- {
- answ = false;
- }
- else
- {
- IPStatus pingStatus = testPingServer;
- // se passa il ping faccio il resto...
- if (pingStatus == IPStatus.Success)
- {
- string callResp = "";
- try
- {
- // chiamo URL, se restituisce "OK" è alive!
- callResp = callUrl(urlAlive, false);
- answ = (callResp == "OK");
- }
- catch (Exception exc)
- {
- lgError("Errore in checkServerAlive:{0}{1}", Environment.NewLine, exc);
- }
- // attesa casuale se necessario
- var rand = new Random();
- // primi 3 test
- int maxTry = 3;
- while (maxTry > 0 && !answ)
- {
- try
- {
- Thread.Sleep(rand.Next(150, 500));
- callResp = callUrl(urlAlive, false);
- answ = (callResp == "OK");
- maxTry--;
- }
- catch
- { }
- }
- // se NON OK riprovo ANCORA 1 volta...
- if (!answ)
- {
- resetWebClients();
- Thread.Sleep(rand.Next(500, 1000));
- callResp = callUrl(urlAlive, false);
- answ = (callResp == "OK");
- }
- // altri 3
- maxTry = 3;
- while (maxTry > 0 && !answ)
- {
- try
- {
- Thread.Sleep(rand.Next(150, 500));
- callResp = callUrl(urlAlive, false);
- answ = (callResp == "OK");
- maxTry--;
- }
- catch
- { }
- }
- // verifico SE è variato stato online/offline...
- if (MPOnline != answ)
- {
- // se ORA sono online riporto...
- if (answ)
- {
- lgInfo("SERVER ONLINE in checkServerAlive");
- parentForm.commSrvActive = 1;
- dtVetoPing = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec);
- }
- else
- {
- lgInfo("SERVER OFFLINE in checkServerAlive");
- parentForm.commSrvActive = 0;
- }
- // salvo nuovo status...
- MPOnline = answ;
- }
- else
- {
- // allungo periodo controllo...
- dtVetoPing = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec * 3);
- }
+ // salvo il form chiamante
+ parentForm = caller;
+ // configurazione...
+ cIobConf = IOBConf;
+
+ lastConnectTry = DateTime.Now;
+
+ // aggiungo nel logger IDX Macchina
+ lg = LogManager.GetCurrentClassLogger();
+
+ lgInfo("Avvio preliminare AdapterGeneric");
+ // aggiungo altri defaults
+ setDefaults(true);
+
+ setParamPlc();
+
+ // checkLogDir x shrink!
+ checkShrinkDir();
+
+ // concluso!
+ lgInfo("Istanziata classe preliminare IOBGeneric");
}
else
{
- lgInfo($"SERVER NOT RESPONDING (PING at {cIobConf.serverData.MPIP})");
- MPOnline = false;
- // imposto veto a 10 volte reinvio dati standard...
- dtVetoPing = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec * 3);
- utils.dtVetoSend = dtVetoPing;
+ lgError("Error: IobCOnf is null!");
}
- }
}
- else
- {
- // altrimenti passo ultimo valore noto...
- answ = MPOnline;
- }
- return answ;
- }
- }
- ///
- /// Verifica se sia machcina multi = DoppioPallet da CONF
- ///
- public bool isMulti
- {
- get
- {
- bool answ = false;
- if (cIobConf.optPar.Count > 0)
- {
- // cerco con chaive reale IS_MULTI
- string keyName = "IS_MULTI";
- if (!cIobConf.optPar.ContainsKey(keyName))
- {
- // legacy: accetto anche SIM_MULTI...
- keyName = "SIM_MULTI";
- }
- // vera verifica su chaive...
- if (cIobConf.optPar.ContainsKey(keyName))
- {
- string SIM_MULTI = getOptPar(keyName);
- answ = SIM_MULTI == "1";
- }
- }
- return answ;
- }
- }
+ ///
+ /// Valore limite MASSIMO di invio di dati come array Json
+ ///
+ protected int maxJsonData { get; set; } = utils.CRI("maxJsonData");
- ///
- /// URL per INVIO IN BLOCCO di un INCREMENTO x contapezzi (quelli della macchina: PLC/CNC)...
- ///
- public string urlAddPzCount
- {
- get
- {
- string answ = "";
- try
- {
- answ = string.Format(@"http://{0}{1}{2}/savePzCountInc/{3}?qty=", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB);
- }
- catch (Exception exc)
- {
- lgError(exc, "Errore in composizione urlAddPzCount");
- }
- return answ;
- }
- }
+ ///
+ /// Valore limite MASSIMO di invio di dati come array Json x EVENTI
+ ///
+ protected int maxJsonDataEv { get; set; } = utils.CRI("maxJsonDataEv");
- ///
- /// URL per check alive...
- ///
- public string urlAlive
- {
- get
- {
- return string.Format(@"http://{0}{1}{2}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE);
- }
- }
+ ///
+ /// Valore MINIMO limite x decidere invio di dati come array Json
+ ///
+ protected int minJsonData { get; set; } = utils.CRI("minJsonData");
- ///
- /// URL per forzare split ODL...
- ///
- public string urlForceSplit
- {
- get
- {
- return string.Format(@"http://{0}{1}{2}{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMD_FORCLE_SPLIT_ODL, cIobConf.codIOB);
- }
- }
+ ///
+ /// Secondi standard x veto check status e log
+ ///
+ protected int vetoSeconds { get; set; } = utils.CRI("vetoSeconds");
- ///
- /// URL per salvataggio contapezzi...
- ///
- public string urlGetCurrODL
- {
- get
- {
- string answ = "";
- try
+ ///
+ /// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere...
+ ///
+ ///
+ protected void lgError(string message, bool sendToForm = true)
{
- answ = string.Format(@"http://{0}{1}{2}/getCurrODL/{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB);
- }
- catch (Exception exc)
- {
- lgError(exc, "Errore in composizione urlGetCurrODL");
- }
- return answ;
- }
- }
-
- ///
- /// URL per richiamo parametri da scrivere...
- ///
- public string urlGetParams2Write
- {
- get
- {
- string answ = "";
- try
- {
- answ = string.Format(@"http://{0}{1}{2}/getObjItems2Write/{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB);
- }
- catch (Exception exc)
- {
- lgError(exc, "Errore in composizione urlGetParams2Write");
- }
- return answ;
- }
- }
-
- ///
- /// URL per recupero contapezzi...
- ///
- public string urlGetPzCount
- {
- get
- {
- string answ = "";
- try
- {
- answ = $@"http://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDALIVE}/getCounter/{cIobConf.codIOB}";
- }
- catch (Exception exc)
- {
- lgError(exc, "Errore in composizione urlGetPzCount");
- }
- return answ;
- }
- }
-
- ///
- /// URL per recupero contapezzi REGISTRATI da TC...
- ///
- public string urlGetPzCountRec
- {
- get
- {
- string answ = "";
- try
- {
- answ = $@"http://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDALIVE}/getCounterTCRec/{cIobConf.codIOB}";
- }
- catch (Exception exc)
- {
- lgError(exc, "Errore in composizione urlGetPzCountRec");
- }
- return answ;
- }
- }
-
- ///
- /// URL per richiamo task da eseguire...
- ///
- public string urlGetTask2Exe
- {
- get
- {
- string answ = "";
- try
- {
- answ = string.Format(@"http://{0}{1}{2}/getTask2Exe/{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB);
- }
- catch (Exception exc)
- {
- lgError(exc, "Errore in composizione urlGetTask2Exe");
- }
- return answ;
- }
- }
-
- ///
- /// URL per recupero idle time IOB...
- ///
- public string urlIdleTime
- {
- get
- {
- return string.Format(@"http://{0}{1}{2}{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMD_IDLE_TIME, cIobConf.codIOB);
- }
- }
-
- ///
- /// URL per recupero inizio ODL...
- ///
- public string urlInizioOdlIob
- {
- get
- {
- return string.Format(@"http://{0}{1}{2}{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMD_ODL_STARTED, cIobConf.codIOB);
- }
- }
-
- ///
- /// URL per check se abilitato...
- ///
- public string urlIobEnabled
- {
- get
- {
- return string.Format(@"http://{0}{1}{2}{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDENABLED, cIobConf.codIOB);
- }
- }
-
- ///
- /// URL per segnalazione reboot...
- ///
- public string urlReboot
- {
- get
- {
- string answ = "";
- try
- {
- answ = string.Format(@"http://{0}{1}{2}{3}&mac={4}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDREBO, cIobConf.codIOB, GetMACAddress());
- }
- catch
- {
- answ = string.Format(@"http://{0}{1}{2}{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDREBO, cIobConf.codIOB);
- }
- return answ;
- }
- }
-
- ///
- /// URL per richiamo task da eseguire...
- ///
- public string urlRemTask2Exe
- {
- get
- {
- string answ = "";
- try
- {
- answ = string.Format(@"http://{0}{1}{2}/remTask2Exe/{3}?taskName=", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB);
- }
- catch (Exception exc)
- {
- lgError(exc, "Errore in composizione urlRemTask2Exe");
- }
- return answ;
- }
- }
-
- ///
- /// URL per salvataggio dati PARAMETRI IOB...
- ///
- public string urlSaveAllParams
- {
- get
- {
- string answ = "";
- try
- {
- string machineName = Environment.MachineName;
- string apiCall = "setObjItems";
- answ = string.Format(@"http://{0}{1}{2}/{3}/{4}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, apiCall, cIobConf.codIOB);
- }
- catch (Exception exc)
- {
- lgError(exc, "Errore in composizione urlSaveMemConf");
- }
- return answ;
- }
- }
-
- ///
- /// URL per salvataggio dati conf memoria IOB...
- ///
- public string urlSaveMemMap
- {
- get
- {
- string answ = "";
- try
- {
- string machineName = Environment.MachineName;
- answ = string.Format(@"http://{0}{1}{2}/saveConf/{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB);
- }
- catch (Exception exc)
- {
- lgError(exc, "Errore in composizione urlSaveMemConf");
- }
- return answ;
- }
- }
-
- ///
- /// URL per salvataggio dati associazione Machine 2 IOB...
- ///
- public string urlSetM2IOB
- {
- get
- {
- string answ = "";
- try
- {
- string machineName = Environment.MachineName;
- answ = string.Format(@"http://{0}{1}{2}/setM2IOB/{3}?IOB_name={4}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB, machineName);
- }
- catch (Exception exc)
- {
- lgError(exc, "Errore in composizione urlSetM2IOB");
- }
- return answ;
- }
- }
-
- ///
- /// URL per salvataggio VALORI opzionali...
- ///
- public string urlSetOptVal
- {
- get
- {
- string answ = "";
- try
- {
- answ = string.Format(@"http://{0}{1}{2}/addOptPar/{3}?", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB);
- }
- catch (Exception exc)
- {
- lgError(exc, "Errore in composizione urlSetOptVal");
- }
- return answ;
- }
- }
-
- ///
- /// URL per salvataggio contapezzi...
- ///
- public string urlSetPzCount
- {
- get
- {
- string answ = "";
- try
- {
- answ = $@"http://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDALIVE}/setCounter/{cIobConf.codIOB}?counter=";
- }
- catch (Exception exc)
- {
- lgError(exc, "Errore in composizione urlSetPzCount");
- }
- return answ;
- }
- }
-
- ///
- /// URL per salvataggio contapezzi (quelli della macchina: PLC/CNC)...
- ///
- public string urlSetPzCountMAC
- {
- get
- {
- string answ = "";
- try
- {
- answ = $@"http://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDALIVE}/setCounter/MAC_{cIobConf.codIOB}?counter=";
- }
- catch (Exception exc)
- {
- lgError(exc, "Errore in composizione urlSetPzCountMAC");
- }
- return answ;
- }
- }
-
- ///
- /// URL per salvataggio in UPSERT dei PARAMETRI IOB scritti...
- ///
- public string urlUpdateWriteParams
- {
- get
- {
- string answ = "";
- try
- {
- string machineName = Environment.MachineName;
- string apiCall = "upsertObjItems";
- answ = string.Format(@"http://{0}{1}{2}/{3}/{4}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, apiCall, cIobConf.codIOB);
- }
- catch (Exception exc)
- {
- lgError(exc, "Errore in composizione urlSaveMemConf");
- }
- return answ;
- }
- }
-
- ///
- /// Esegue filtraggio dati x bit blinking!!!
- ///
- private void filterData()
- {
- // effettuo filtraggio dei valori letti... inizializzo OUT!
- B_output = 0;
- // in primis verifico SE ci siano bit blinkng... se non ci sono OUT=IN...
- if (cIobConf.BLINK_FILT == 0)
- {
- B_output = B_input;
- }
- else
- {
- // incomincio con i valori NON blinking: questi "passano invariati", inizio a sommare nel valore OUT...
- B_output = B_input & ~cIobConf.BLINK_FILT;
- // calcolo il valore dei BIT che "passano la maschera"
- int iBlink = B_input & cIobConf.BLINK_FILT;
- // ...aggiungo i "bit che passano"
- B_output += iBlink;
-
- // calcolo QUALI valori (tra quelli blink) siano PASSATI da 0 a 1 --> init counters...
- BitArray bBlinkStart = new BitArray(new byte[] { Convert.ToByte(iBlink) });
- int[] bitsUp = bBlinkStart.Cast().Select(bit => bit ? 1 : 0).ToArray();
- for (int i = 0; i < bitsUp.Length; i++)
- {
- // SE 1... impostiamo contatori al MAX
- if (bitsUp[i] == 1)
- {
- // se era zero indico START blink...
- if (i_counters[i] == 0)
+ lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB;
+ lg.Error(message);
+ if (sendToForm)
{
- lgInfo("START BLINK: B{0}", i);
+ sendToLogWatch("ERROR", message);
}
- // imposto comunque contatore al cambio fronte...
- i_counters[i] = cIobConf.MAX_COUNTER_BLINK;
- }
}
- // quelli che sono zero... LI RECUPERO E LI PROCESSO...
- int iZero = ~B_input & cIobConf.BLINK_FILT;
- BitArray bBlinkEnd = new BitArray(new byte[] { Convert.ToByte(iZero) });
- int[] bitsDown = bBlinkEnd.Cast().Select(bit => bit ? 1 : 0).ToArray();
- for (int i = 0; i < bitsDown.Length; i++)
+ ///
+ /// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere...
+ ///
+ ///
+ ///
+ protected void lgError(string message, params object[] args)
{
- // se era a zero (invertito...)
- if (bitsDown[i] == 1)
- {
- // SE è in corso il conteggio...
- if (i_counters[i] > 0)
+ lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB;
+ lg.Error(message, args);
+ sendToLogWatch("ERROR", message, args);
+ }
+
+ ///
+ /// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere...
+ ///
+ ///
+ ///
+ ///
+ protected void lgError(Exception exception, string message, params object[] args)
+ {
+ lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB;
+ lg.Error(exception, message, args);
+ sendToLogWatch("ERROR", message, exception, args);
+ }
+
+ ///
+ /// Effettua logging FATAL corretto impostanto anche la variabile IOB prima di scrivere...
+ ///
+ ///
+ protected void lgFatal(string message, bool sendToForm = true)
+ {
+ lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB;
+ lg.Fatal(message);
+ if (sendToForm)
{
- // decremento!
- i_counters[i] -= 1;
- // se è zero NON faccio nulla, altrimenti SOMMO...
- if (i_counters[i] > 0)
- {
- B_output += 1 << i;
- }
- else
- {
- lgInfo("END BLINK: B{0}", i);
- }
+ sendToLogWatch("FATAL", message);
}
- }
}
- }
- }
- ///
- /// Classe fittizia in caso di processing GLOBALE di tutto in 1 solo colpo...
- ///
- private void processAllMemory()
- {
- // init obj display
- newDisplayData currDispData = new newDisplayData();
- // in primis SALVO valori previous/precedenti
- B_previous = B_output;
- // poi faccio lettura NUOVI valori
- readAllData(ref currDispData);
- // eseguo il filtering dei valori (per i bit "blinking")
- filterData();
- // effettuo confronto valori vecchi/nuovi... SE trovo variazione OPPURE se è passato + di un timeout di controllo...
- if (B_output != B_previous)
- {
- accodaSigIN(ref currDispData);
- }
- raiseRefresh(currDispData);
- }
-
- ///
- /// Effettua gestioen programma: legge e mostra su display...
- ///
- private void processProgram()
- {
- string currPrgName = "";
- // se abilitata lettura prgName
- if (enablePrgName)
- {
- if (connectionOk)
+ ///
+ /// Effettua logging FATAL corretto impostanto anche la variabile IOB prima di scrivere...
+ ///
+ ///
+ ///
+ protected void lgFatal(string message, params object[] args)
{
- currPrgName = getPrgName();
+ lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB;
+ lg.Fatal(message, args);
+ sendToLogWatch("FATAL", message, args);
}
- else
- {
- lgError("Errore connessione mancante x getPrgName");
- }
- }
- else
- {
- currPrgName = lastPrgName;
- }
- // verifico SE sia cambiato il programma...
- if (lastPrgName != currPrgName)
- {
- // salvo!
- lastPrgName = currPrgName;
- string sVal = string.Format("[PROG]{0}", currPrgName);
- // chiamo accodamento...
- accodaFLog(sVal, qEncodeFLog("PROG", currPrgName));
- }
- }
-
- ///
- /// Processo lettura dati sysinfo
- ///
- private void processSysInfo()
- {
- if (utils.CRB("enableSysInfo"))
- {
- Dictionary currSysInfo = new Dictionary();
-
- if (connectionOk)
+ ///
+ /// Effettua logging FATAL corretto impostanto anche la variabile IOB prima di scrivere...
+ ///
+ ///
+ ///
+ ///
+ protected void lgFatal(Exception exception, string message, params object[] args)
{
- currSysInfo = getSysInfo();
+ lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB;
+ lg.Fatal(exception, message, args);
+ sendToLogWatch("FATAL", message, exception, args);
}
- else
- {
- lgError("Errore connessione mancante x getSysInfo");
- }
- // verifico SE sia cambiato il programma...
- if (lastSysInfo != currSysInfo["SYSINFO"])
- {
- // salvo!
- lastSysInfo = currSysInfo["SYSINFO"];
- // per ogni valore del dizionario mostro ed accodo!
- string sVal = "";
- foreach (var item in currSysInfo)
- {
- sVal = string.Format("[SYSINFO]{0}|{1}", item.Key, item.Value);
- // chiamo accodamento...
- accodaFLog(sVal, qEncodeFLog(item.Key, item.Value));
- }
- }
- }
- }
- ///
- /// Processo la coda FLog...
- ///
- private void svuotaCodaFLog()
- {
- //controllo se è passato oltre watchdog e non ho inviato nulla --> RE-INVIO (ultimo inviato)!!!!
- if (DateTime.Now.Subtract(lastWatchDog).TotalSeconds > utils.CRI("watchdogMaxSec"))
- {
- string wdStatus = "elapsed";
- string sVal = string.Format("[WDST]{0}", wdStatus);
- // chiamo accodamento...
- accodaFLog(sVal, qEncodeFLog("WDST", wdStatus));
- lastWatchDog = DateTime.Now;
- }
- // verifico SE la coda abbia dei valori...
- if (QueueFLog.Count > 0)
- {
- // invio pacchetto di dati (max da conf)
- for (int i = 0; i < nMaxSend; i++)
+ ///
+ /// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere...
+ ///
+ ///
+ protected void lgInfo(string message, bool sendToForm = true)
{
- // SE ho qualcosa in coda...
- if (QueueFLog.Count > 0)
- {
- string currVal = "";
- if (MPOnline)
+ lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB;
+ lg.Info(message);
+ if (sendToForm)
{
- if (IobOnline)
- {
- // se ho + di 2 elementi in coda --> uso invio JSON in blocco...
- if (QueueFLog.Count > 1)
+ sendToLogWatch("INFO", message);
+ }
+ }
+
+ ///
+ /// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere...
+ ///
+ ///
+ ///
+ protected void lgInfo(string message, params object[] args)
+ {
+ lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB;
+ lg.Info(message, args);
+ sendToLogWatch("INFO", message, args);
+ }
+
+ ///
+ /// Lettura memorie conf speciali (json)
+ /// ...SE inserito in [OPTPAR] come PARAM_CONF=nome.json
+ ///
+ protected virtual void loadMemConf()
+ {
+ lgInfo("BEGIN loadMemConf");
+ // variabili x gestione send contapezzi in blocco
+ string currPar = getOptPar("ENABLE_SEND_PZC_BLOCK");
+ if (!string.IsNullOrEmpty(currPar))
+ {
+ bool.TryParse(currPar, out enableSendPzCountBlock);
+ // se abilitato leggo num pezzi da reinviare in blocco
+ if (enableSendPzCountBlock)
{
- List listaValori = new List();
- // se ho + di maxJsonData elementi --> invio un set di dati alla volta
- if (QueueFLog.Count > maxJsonData)
- {
- // prendoi primi maxJsonDataValori
- for (int j = 0; j < maxJsonData; j++)
+ int.TryParse(getOptPar("MAX_SEND_PZC_BLOCK"), out maxSendPzCountBlock);
+ int.TryParse(getOptPar("MIN_SEND_PZC_BLOCK"), out minSendPzCountBlock);
+ }
+ }
+ else
+ {
+ lgError("loadMemConf: parametro ENABLE_SEND_PZC_BLOCK non trovato, verificare anche MAX_SEND_PZC_BLOCK e MIN_SEND_PZC_BLOCK");
+ }
+ // inizializzo LUT decodifica
+ string jsonConf = getOptPar("PARAM_CONF");
+ if (!string.IsNullOrEmpty(jsonConf))
+ {
+ string jsonFileName = $"{Application.StartupPath}/DATA/CONF/{jsonConf}";
+ lgInfo($"Apertura file {jsonFileName}");
+ StreamReader reader = new StreamReader(jsonFileName);
+ string jsonData = reader.ReadToEnd();
+ if (!string.IsNullOrEmpty(jsonData))
+ {
+ lgInfo($"File json composto da {jsonData.Length} caratteri");
+ try
{
- QueueFLog.TryDequeue(out currVal);
- listaValori.Add(currVal);
+ memMap = JsonConvert.DeserializeObject(jsonData);
+ lgInfo($"Decodifica aree memMap: trovati {memMap.mMapRead.Count} valori TSVC");
+ lgInfo($"Decodifica aree memMap: trovati {memMap.mMapWrite.Count} parametri ");
+ // se ho variabili read --> genero dati TSVC...
+ if (memMap.mMapRead.Count > 0)
+ {
+ TSVC_Data.Clear();
+ LastTSVC.Clear();
+ VCData currConf;
+ int periodo = 0;
+ VC_func funz = VC_func.POINT;
+ // accodo nella conf...
+ foreach (var item in memMap.mMapRead)
+ {
+ funz = item.Value.func;
+ periodo = item.Value.period;
+ currConf = new VCData()
+ {
+ Funzione = funz,
+ Period = periodo,
+ DTStart = DateTime.Now.AddHours(-1),
+ dataArray = new List()
+ };
+ TSVC_Data.Add(item.Key, currConf);
+ }
+ // documento...
+ foreach (var item in TSVC_Data)
+ {
+ lgInfo($"TSVC: {item.Key} | periodo: {item.Value.Period} | funz: {item.Value.Funzione}");
+ // salvo i valori PREC...
+ LastTSVC.Add(item.Key, 0);
+ }
+ }
+ // infine se obj memoria valido salvo in MP-IO x sue applicazioni
+ if (memMap != null)
+ {
+ // invio su cloud conf memoria...
+ string rawData = JsonConvert.SerializeObject(memMap);
+ utils.callUrlNow($"{urlSaveMemMap}", rawData);
+ // salvo ANCHE come parametri i valori...
+ objItem currItem = new objItem();
+ List allParam = new List();
+ // valori WRITE
+ foreach (var item in memMap.mMapWrite)
+ {
+ currItem = new objItem()
+ {
+ uid = item.Value.name,
+ name = !string.IsNullOrEmpty(item.Value.description) ? item.Value.description : item.Value.name,
+ writable = true
+ };
+ allParam.Add(currItem);
+ }
+ // valori READ
+ foreach (var item in memMap.mMapRead)
+ {
+ currItem = new objItem()
+ {
+ uid = item.Value.name,
+ name = !string.IsNullOrEmpty(item.Value.description) ? item.Value.description : item.Value.name,
+ writable = false
+ };
+ allParam.Add(currItem);
+ }
+ // invio su cloud parametri!
+ rawData = JsonConvert.SerializeObject(allParam);
+ utils.callUrl($"{urlSaveAllParams}", rawData);
+ }
+ }
+ catch (Exception exc)
+ {
+ lgError($"Eccezione in decodifica conf json{Environment.NewLine}{exc}");
}
- sendDataBlock(urlType.FLog, listaValori);
- }
- else
- {
- // invio in blocco
- listaValori = QueueFLog.ToList();
- // invio
- sendDataBlock(urlType.FLog, listaValori);
- // svuoto!
- QueueFLog = new ConcurrentQueue();
- }
}
else
{
- // INVIO SINGOLO...!!!
- QueueFLog.TryDequeue(out currVal);
- sendToMoonPro(urlType.FLog, currVal);
+ lgError("Errore in loadMemConf: file json vuoto!");
}
- }
- else
- {
- break;
- }
+ reader.Dispose();
}
else
{
- break;
+ lgInfo("loadMemConf: non trovata opzione PARAM_CONF in file INI");
}
- }
- else
- {
- break;
- }
+ // loggo
+ lgInfo("DONE loadMemConf");
}
- }
- }
- ///
- /// Effettua chiamata URL e restituisce risultato
- ///
- ///
- /// invio in modalità async (NON GARANTITO ordine...)
- ///
- public static string callUrl(string URL, bool doAsync)
- {
- string answ = "";
- // Chiamata ASINCRONA
- if (doAsync)
- {
- //Task resp = utils.callUrlAsync(URL);
- //answ = resp.Result;
- answ = utils.callUrlAsync(URL);
- }
- // chiamata SOLO NORMALE SINCRONA...
- else
- {
- answ = utils.callUrl(URL);
- }
- return answ;
- }
-
- ///
- /// Effettua chiamata URL e restituisce risultato
- ///
- ///
- ///
- /// invio in modalità async (NON GARANTITO ordine...)
- ///
- public static string callUrlWithPayload(string URL, string payload, bool doAsync)
- {
- string answ = "";
- // Chiamata ASINCRONA
- if (doAsync)
- {
- answ = utils.callUrlAsync(URL, payload);
- }
- // chiamata SOLO NORMALE SINCRONA...
- else
- {
- answ = utils.callUrl(URL, payload);
- }
- return answ;
- }
-
- public static string GetMACAddress()
- {
- NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
- String sMacAddress = string.Empty;
- foreach (NetworkInterface adapter in nics)
- {
- if (string.IsNullOrEmpty(sMacAddress))// only return MAC Address from first card
+ ///
+ /// Invia messaggio a logWatcher
+ ///
+ ///
+ ///
+ protected void sendToLogWatch(string messType, string message)
{
- IPInterfaceProperties properties = adapter.GetIPProperties();
- //sMacAddress = adapter.GetPhysicalAddress().ToString();
- sMacAddress = string.Join(":", (from z in adapter.GetPhysicalAddress().GetAddressBytes() select z.ToString("X2")).ToArray());
+ newDisplayData currDispData = new newDisplayData();
+ currDispData.newLiveLogData = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} | {messType} | {message}";
+ parentForm.updateFormDisplay(currDispData);
}
- }
- return sMacAddress;
- }
- ///
- /// Reset dei webclients
- ///
- public static void resetWebClients()
- {
- utils.resetWebClients();
- }
-
- ///
- /// Effettua chaimata x split ODL
- ///
- ///
- public bool forceSplitOdl()
- {
- bool fatto = false;
- if (vetoSplit < DateTime.Now)
- {
- // imposto veto x 1 minuto ad altre chiamate...
- vetoSplit = DateTime.Now.AddMinutes(1);
- // eseguo SOLO SE sono online...
- if (MPOnline && IobOnline)
+ ///
+ /// Invia messaggio a logWatcher
+ ///
+ ///
+ ///
+ ///
+ protected void sendToLogWatch(string messType, string message, params object[] args)
{
- string fullUrl = "";
- string rawSplit = "";
- string IOB_MULTI_CNAME = "";
- string[] elencoMulti = null;
-
- try
- {
- /***************************************************
- * Descrizione procedura (OK X SIMULATORI...)
- *
- * - chiamata su MP/IO
- * - verifica che su DB sia abilitato AUTO ODL
- * - il server inserisce un evento fine prod HW 1 minuto prima e inizio setup HW
- * - viene duplicato e chiuso ODL corrente
- * - viene fatto partire ODL nuovo ADESSO
- * - num pezzi come ODL precedente (o da media 3 ODL precedenti)
- * - conferme pezzi & co... gestione NULL (NON SERVONO si tratta di impianti SENZA gestione vera ODL)
- * - reset contapezzi PLC locale...
- *
- *
- *
- * DA VALUTARE (x macchine tipo linea con + impianti... es valvital) SE
- * - creare una gestione ALTERNATIVA sul server che preveda impianto LEADER e impianti follower (RIGIDAMENTE CONFIGURATI)
- * - ogni volta che si fa setup LEADER --> si ripete su impianti FOLLOWER (eventi!!!)
- * - viene fatto reset contapezzi sui follower (+ altre operazioni opzionali, ES imposstazione nome commessa, quantità, articolo...)
- * - viene fatto reset + nuovo ODL (con stessi articoli e quantità) su follower, SENZA avere gestione x ODL di un codice esterno (quindi registra TUTTO ma NON RITORNERA' dati non avendo link verso esterno)
- * - serve NUOVA TABELLA delle macchine LEADER | FOLLOWER (1:n) e gestione da MP/IO
- *
- * ***************************************************/
-
- if (isMulti)
+ try
{
- // devo chiamare cambio ODL x OGNI tavola: mi servono i parametri opzionali...
- IOB_MULTI_CNAME = getOptPar("IOB_MULTI_CNAME");
- elencoMulti = IOB_MULTI_CNAME.Split(',');
+ string expString = string.Format(message, args);
+ newDisplayData currDispData = new newDisplayData();
+ currDispData.newLiveLogData = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} | {messType} | {expString}";
+ parentForm.updateFormDisplay(currDispData);
}
- // se normale splitto!
- if (!isMulti)
+ catch
+ { }
+ }
+
+ ///
+ /// Invia messaggio a logWatcher
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected void sendToLogWatch(string messType, string message, Exception exception, params object[] args)
+ {
+ try
{
- // invio chiamata URL x reset ODL su macchina
- rawSplit = callUrl(urlForceSplit, false);
- fatto = (rawSplit == "OK") ? true : false;
+ string expString = string.Format(message, args);
+ newDisplayData currDispData = new newDisplayData();
+ currDispData.newLiveLogData = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} | {messType} | {expString}{Environment.NewLine}{exception}";
+ parentForm.updateFormDisplay(currDispData);
}
- // se multi gestisco il bit delle tavole...
- else
+ catch
+ { }
+ }
+
+ ///
+ /// Invia messaggio a logWatcher
+ ///
+ ///
+ ///
+ protected void sendToTaskWatch(string messType, string message)
+ {
+ parentForm.taskWatcher = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} | {messType} | {message}";
+ }
+
+ ///
+ /// Impostazioni parametri PLC
+ ///
+ protected virtual void setParamPlc()
+ {
+ loadMemConf();
+ fixDefaultPar();
+ }
+
+ ///
+ /// Imposta eventuali altri valori default
+ ///
+ private void fixDefaultPar()
+ {
+ // parametro max tentativi PING...
+ string s_maxPingRetry = getOptPar("MAX_PING_RETRY");
+ if (!string.IsNullOrEmpty(s_maxPingRetry))
{
- foreach (string item in elencoMulti)
- {
- // invio chiamata URL x reset ODL su macchina, ATTENZIONE scriviamo | al posto di "#" che in URL sarebbe filtrato...
- fullUrl = $"{urlForceSplit}|{item}";
- rawSplit = callUrl(fullUrl, false);
- }
- fatto = (rawSplit == "OK") ? true : false;
+ int numRetry = 5;
+ int.TryParse(s_maxPingRetry, out numRetry);
+ maxPingRetry = numRetry;
}
- }
- catch (Exception exc)
- {
- lgError($"Eccezione in forceSplitOdl{Environment.NewLine}{exc}");
- }
- // se fatto --> resetto contapezzi!!!
- if (fatto)
- {
- contapezziPLC = 0;
- contapezziIOB = 0;
- }
}
- else
+
+ ///
+ /// Imposto alcuni valori di default
+ ///
+ /// indica se sia richeisto di SVUOTARE le code delel info
+ private void setDefaults(bool resetQueue)
{
- lgError("Richiesto forceSplitOdl ma MP/IOB offline --> NON eseguito");
- }
- }
- else
- {
- lgError("Richiesto forceSplitOdl ma veto attivo --> NON eseguito");
- }
- return fatto;
- }
-
- ///
- /// Recupera eventuali allarmi CNC...
- ///
- public virtual Dictionary getCncAlarms()
- {
- Dictionary outVal = new Dictionary();
- return outVal;
- }
-
- ///
- /// Restituisce info DINAMICHE
- ///
- ///
- public virtual Dictionary getDynData()
- {
- Dictionary outVal = new Dictionary();
- return outVal;
- }
-
- ///
- /// Restituisce info OVERRIDES
- ///
- ///
- public virtual Dictionary getOverrides()
- {
- Dictionary outVal = new Dictionary();
- return outVal;
- }
-
- ///
- /// Restituisce programma in esecuzione
- ///
- public virtual string getPrgName()
- {
- return "";
- }
-
- ///
- /// Restituisce info sistema
- ///
- ///
- public virtual Dictionary getSysInfo()
- {
- Dictionary outVal = new Dictionary();
- return outVal;
- }
-
- ///
- /// Restituisce un payload in formato json della lista di valori ricevuta
- ///
- /// Tipo di URL (eventi / FLog)
- /// elenco di valori da coda string salvata
- ///
- public string jsonPayload(urlType tipoUrl, List elencoValori)
- {
- string answ = "";
- if (elencoValori != null)
- {
- if (tipoUrl == urlType.FLog)
- {
- flogData currData = new flogData();
- flogJsonPayload fullObj = new flogJsonPayload();
- fullObj.fluxData = new List();
- string[] valori;
- int counter = 0;
- DateTime dtEve = DateTime.Now;
- // inizio processando ogni valore
- foreach (var item in elencoValori)
- {
- valori = qDecodeIN(item);
- //DateTime.TryParse(valori[0], out dtEve);
- CultureInfo provider = CultureInfo.InvariantCulture;
- DateTime.TryParseExact(valori[0], "yyyyMMddHHmmssfff", provider, DateTimeStyles.AssumeLocal, out dtEve);
- int.TryParse(valori[3], out counter);
- currData = new flogData()
+ numSim = utils.CRI("numSim");
+ lastPrgName = "";
+ nReadIN = 0;
+ nReadFilt = 0;
+ nSendOut = 0;
+ currMode = 0;
+ lastAlarm = "";
+ doStartMemDump = utils.CRB("doStartMemDump");
+ doSampleMemory = utils.CRB("doSampleMemory");
+ // svuoto code se richiesto
+ if (resetQueue)
{
- flux = valori[1],
- valore = valori[2],
- dtEve = dtEve,
- dtCurr = DateTime.Now,
- cnt = counter
- };
- fullObj.fluxData.Add(currData);
- }
- // conversione finale
- try
- {
- answ = JsonConvert.SerializeObject(fullObj);
- }
- catch (Exception exc)
- {
- lgError($"Errore in costruzione jsonPayload:{Environment.NewLine}{exc}");
- }
+ QueueIN = new ConcurrentQueue();
+ QueueFLog = new ConcurrentQueue();
+ QueueAlarm = new ConcurrentQueue();
+ QueueMessages = new ConcurrentQueue();
+ }
+ // imposto contatori blink a zero...
+ i_counters = new int[32];
+ lastPeriodicLog = DateTime.Now;
+ // fix parametri generali...
+ enablePrgName = true;
}
- else
- {
- evData currData = new evData();
- evJsonPayload fullObj = new evJsonPayload();
- fullObj.eventList = new List();
- string[] valori;
- int counter = 0;
- DateTime dtEve = DateTime.Now;
- // inizio processando ogni valore
- foreach (var item in elencoValori)
- {
- valori = qDecodeIN(item);
- //DateTime.TryParse(valori[0], out dtEve);
- CultureInfo provider = CultureInfo.InvariantCulture;
- DateTime.TryParseExact(valori[0], "yyyyMMddHHmmssfff", provider, DateTimeStyles.AssumeLocal, out dtEve);
- int.TryParse(valori[2], out counter);
- currData = new evData()
- {
- valore = valori[1],
- dtEve = dtEve,
- dtCurr = DateTime.Now,
- cnt = counter
- };
- fullObj.eventList.Add(currData);
- }
- // conversione finale
- try
- {
- answ = JsonConvert.SerializeObject(fullObj);
- }
- catch (Exception exc)
- {
- lgError($"Errore in costruzione jsonPayload:{Environment.NewLine}{exc}");
- }
- }
- }
- return answ;
- }
- ///
- /// Verifica e processing x gestione ODL automatica
- ///
- public void processAutoOdl()
- {
- bool fatto = false;
- if (!string.IsNullOrEmpty(getOptPar("AUTO_CHANGE_ODL")))
- {
- string IOB_MULTI_CNAME = "";
- string[] elencoMulti = null;
- string fullUrl = "";
- if (isMulti)
+ #region metodi adapter
+
+ protected bool _connOk = false;
+
+ ///
+ /// Salva verifica stato connessione OK
+ ///
+ ///
+ public virtual bool connectionOk
{
- // devo chiamare cambio ODL x OGNI tavola: mi servono i parametri opzionali...
- IOB_MULTI_CNAME = getOptPar("IOB_MULTI_CNAME");
- elencoMulti = IOB_MULTI_CNAME.Split(',');
- }
- // controllo SIA abilitato...
- bool doProc = false;
- DateTime adesso = DateTime.Now;
- bool.TryParse(getOptPar("AUTO_CHANGE_ODL"), out doProc);
- if (doProc)
- {
- // carico i parametri di configurazione x reset ODL...
- string CHANGE_ODL_HOURS = getOptPar("CHANGE_ODL_IDLE_MIN");
- string CHANGE_ODL_IDLE_MIN = getOptPar("CHANGE_ODL_IDLE_MIN");
- if (!string.IsNullOrEmpty(CHANGE_ODL_HOURS) && !string.IsNullOrEmpty(CHANGE_ODL_IDLE_MIN))
- {
- int minOdlDurHours = -1;
- int minPlcIdelMin = -1;
- int.TryParse(CHANGE_ODL_HOURS, out minOdlDurHours);
- int.TryParse(CHANGE_ODL_IDLE_MIN, out minPlcIdelMin);
- // controllo parametri validi
- if (minOdlDurHours > 0 && minPlcIdelMin > 0)
+ get
{
- // leggo da server inizio ODL... se non multi 1 solo...
- DateTime inizioOdl = DateTime.Now;
- string rawDataInizio = "";
- if (!isMulti)
- {
- rawDataInizio = callUrl(urlInizioOdlIob, false);
- DateTime.TryParse(rawDataInizio, out inizioOdl);
- }
- else
- {
- DateTime tmpData = DateTime.Now;
- // prendo il + vecchio...
- foreach (var item in elencoMulti)
+ return _connOk || DemoIn;
+ }
+ set
+ {
+ _connOk = value;
+ }
+ }
+
+ ///
+ /// indica se ping disabilitato da optPar
+ ///
+ public bool pingDisabled
+ {
+ get
+ {
+ bool answ = false;
+ bool.TryParse(getOptPar("NO_PING"), out answ);
+ return answ;
+ }
+ }
+
+ ///
+ /// Max tentativi ping permessi (default: 5)
+ ///
+ protected int maxPingRetry { get; set; } = 5;
+
+ ///
+ /// test ping all'indirizzo PLC/CNC impostato nei parametri
+ ///
+ ///
+ protected IPStatus testPingMachine
+ {
+ get
+ {
+ IPStatus answ = IPStatus.Unknown;
+ // se disabilitato salto...
+ if (pingDisabled)
{
- fullUrl = $"{urlInizioOdlIob}|{item}";
- rawDataInizio = callUrl(fullUrl, false);
- DateTime.TryParse(rawDataInizio, out tmpData);
- inizioOdl = (tmpData < inizioOdl) ? tmpData : inizioOdl;
+ answ = IPStatus.Success;
}
- }
- // verifico se sia scaduto...
- if (inizioOdl.AddHours(minOdlDurHours) < adesso)
- {
- string rawIdle = "";
- int idlePeriod = 0;
+ else
+ {
+ IPAddress address;
+ PingReply reply;
+ using (Ping pingSender = new Ping())
+ {
+ address = IPAddress.Loopback;
+ IPAddress.TryParse(cIobConf.cncIpAddr, out address);
+ int pingMsTimeout = cIobConf.pingMsTimeout;
+ reply = pingSender.Send(address, pingMsTimeout);
+ answ = reply.Status;
+ }
+ }
+ return answ;
+ }
+ }
+
+ ///
+ /// processa dataLayer e se necessario salva/mostra
+ ///
+ public static void checkSavePersDataLayer()
+ {
+ }
+
+ public static void resetDebugConsole()
+ {
+ }
+
+ ///
+ /// Esecuzione dei task richiesti e pulizia coda richieste eseguite
+ ///
+ ///
+ public virtual Dictionary executeTasks(Dictionary task2exe)
+ {
+ // Verificare il protocollo: dovrebbe togliere SOLO i task eseguiti...
+ Dictionary taskDone = new Dictionary();
+ if (task2exe != null)
+ {
+ bool taskOk = false;
+ string taskVal = "";
+ // cerco task specifici: se ho startSetup --> imposto bit DBB701.DBB0.4
+ foreach (var item in task2exe)
+ {
+ taskOk = false;
+ taskVal = "";
+ // converto richiesta in enum...
+ taskType tName = taskType.nihil;
+ Enum.TryParse(item.Key, out tName);
+ // controllo sulla KEY...
+ switch (tName)
+ {
+ case taskType.nihil:
+ case taskType.fixStopSetup:
+ case taskType.forceSetPzCount:
+ case taskType.sendWatchDogMes2Plc:
+ taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC";
+ lgInfo($"Chiamata senza processing: taskOk: {taskOk} | taskVal: {taskVal}");
+ break;
+
+ case taskType.setArt:
+ case taskType.setComm:
+ case taskType.setProg:
+ case taskType.setPzComm:
+ // recupero dati da memMap...
+ if (memMap.mMapWrite.ContainsKey(item.Key))
+ {
+ dataConf currMem = memMap.mMapWrite[item.Key];
+ string addr = currMem.memAddr;
+ taskVal = $"SET task: {item.Key} --> {item.Value} | mem: {currMem.memAddr} - {currMem.size} byte";
+ // salvo il nuovo valore nella memoria... così prox invio lo trasmetterà
+ memMap.mMapWrite[item.Key].value = item.Value;
+ }
+ else
+ {
+ taskVal = $"NO DATA MEM, SET task: {item.Key} --> {item.Value}";
+ }
+ break;
+
+ case taskType.forceResetPzCount:
+ // reset contapezzi inizio setup
+ taskOk = resetcontapezziPLC();
+ taskVal = taskOk ? "RESET PZ COUNT OK" : "PZ RESET DISABLED | NO EXEC";
+ lgInfo($"Chiamata forceResetPzCount: taskOk: {taskOk} | taskVal: {taskVal}");
+ break;
+
+ case taskType.startSetup:
+ // reset contapezzi inizio setup
+ taskOk = resetcontapezziPLC();
+ taskVal = taskOk ? "RESET: SETUP START" : "PZ RESET DISABLED | NO EXEC";
+ lgInfo($"Chiamata startSetup: taskOk: {taskOk} | taskVal: {taskVal}");
+ break;
+
+ case taskType.stopSetup:
+ // reset contapezzi fine setup SE ESPLICITAMENTE IMPOSTATO
+ if (cIobConf.optPar.Count > 0 && getOptPar("ENABLE_PZ_RESET_stopSetup") == "TRUE")
+ {
+ taskOk = resetcontapezziPLC();
+ }
+ taskVal = taskOk ? "RESET: SETUP END" : "PZ RESET DISABLED | NO EXEC";
+ lgInfo($"Chiamata stopSetup: taskOk: {taskOk} | taskVal: {taskVal}");
+ break;
+
+ case taskType.setParameter:
+ // richiedo da URL i parametri WRITE da popolare
+ lgInfo("Chiamata processMemWriteRequests");
+ taskVal = processMemWriteRequests();
+ // se restituiscce "" faccio altra prova...
+ if (string.IsNullOrEmpty(taskVal))
+ {
+ // i parametri me li aspetto come stringa composta paramName|paramvalue
+ if (item.Value.Contains("|"))
+ {
+ string[] paramsJob = item.Value.Split('|');
+ taskVal = $"REQUEST SET PARAMETERS: {paramsJob[0]} --> {paramsJob[1]}";
+ }
+ else
+ {
+ taskVal = $"WRONG REQUEST FOR SET PARAMETERS: {item.Value} doesnt contain pipe for splitting key/value";
+ }
+ }
+ break;
+
+ default:
+ taskVal = "SKIPPED | NO EXEC";
+ lgInfo($"Chiamata default senza processing: taskOk: {taskOk} | taskVal: {taskVal}");
+ break;
+ }
+ // aggiungo task!
+ taskDone.Add(item.Key, taskVal);
+ }
+ }
+ return taskDone;
+ }
+
+ ///
+ /// effettua recupero dati ed invio valori modificati...
+ ///
+ ///
+ public void getAndSend(gatherCycle ciclo)
+ {
+ // init obj display
+ newDisplayData currDispData = new newDisplayData();
+ // IN OGNI CASO a prima di tutto EFFETTUO GESTIONE INVII dati da code!!!
+ try
+ {
+ trySendValues();
+ }
+ catch (Exception exc)
+ {
+ lgError(exc, "Errore in gestione svuotamento/invio preliminare code memoria");
+ currDispData.semOut = Semaforo.SR;
+ }
+ // controllo connessione/connettività
+ if (connectionOk)
+ {
+ // controllo non sia già in esecuzione...
+ if (!adpCommAct)
+ {
+ // provo ad avviare
+ try
+ {
+ // imposto flag adapter running..
+ adpCommAct = true;
+ adpStartRun = DateTime.Now;
+ }
+ catch (Exception exc)
+ {
+ string errore = $"Adapter NOT STARTED!!!{Environment.NewLine}{exc}";
+ adpCommAct = false;
+ adpStartRun = DateTime.Now;
+ currDispData.newLiveLogData = errore;
+ }
+ if (adpCommAct)
+ {
+ // try / catch generale altrimenti segno che è disconnesso...
+ try
+ {
+ bool showDebugData = false;
+ if (ciclo == gatherCycle.VHF)
+ {
+ processVHF();
+ }
+ // processing dati memoria (lettura, filtraggio, enqueque)
+ else if (ciclo == gatherCycle.HF)
+ {
+ processWhatchDog();
+ processAllMemory();
+ processMode();
+ }
+ else if (ciclo == gatherCycle.MF)
+ {
+ processServerRequests();
+ processOverride();
+ processContapezzi();
+ processCncAlarms();
+ processDynData();
+ }
+ else if (ciclo == gatherCycle.LF)
+ {
+ processOtherCounters();
+ processProgram();
+ // verifico se devo gestire cambio ODL in modo automatico
+ processAutoOdl();
+ }
+ else if (ciclo == gatherCycle.VLF)
+ {
+ if (utils.CRB("enableContapezzi"))
+ {
+ // rilettura contapezzi da server...
+ lgInfo("Ciclo VLF: pzCntReload(true)");
+ if (!isMulti)
+ {
+ pzCntReload(true);
+ }
+ // refresh associazione Macchina - IOB
+ sendM2IOB();
+ }
+ // recupero dati SETUP (sysinfo) e li invio/mostro se variati...
+ processSysInfo();
+ // checkLogDir x shrink!
+ checkShrinkDir();
+ // eventuale log!
+ if (utils.CRB("recTime"))
+ {
+ logTimeResults();
+ }
+ }
+ // mostra eventuali altri dati di processo...
+ reportDataProc();
+ if (showDebugData)
+ {
+ // verifica se debba salvare e mostrare dati
+ checkSavePersDataLayer();
+ }
+ }
+ catch (Exception exc)
+ {
+ // segnalo eccezione e indico disconnesso...
+ lgError(exc, string.Format("Errore in gestione ciclo principale ADP, fermo adapter{0}{1}", Environment.NewLine, exc));
+ parentForm.fermaAdapter(true, false, true);
+ }
+ // tolgo flag running
+ adpCommAct = false;
+ }
+ else
+ {
+ if (periodicLog)
+ {
+ lgInfo("ADP not running...");
+ }
+ }
+ }
+ else
+ {
+ // log ADP running
+ lgError("Non eseguo chiamata: ADP ancora in running");
+ // se è bloccato da oltre maxSec lo sblocco...
+ if (DateTime.Now.Subtract(adpStartRun).TotalSeconds > utils.CRI("maxAdapterLockSec"))
+ {
+ // tolgo flag running
+ adpCommAct = false;
+ adpStartRun = DateTime.Now;
+ }
+ }
+ }
+ else
+ {
+ // provo a riconnettere SE abilitato tryRestart...
+ if (adpTryRestart && !connectionOk)
+ {
+ // controllo se sia scaduto periodi di veto al tryConnect...
+ int waitRecMSec = utils.CRI("waitRecMSec") * 2;
+ DateTime dtVeto = lastConnectTry.AddMilliseconds(waitRecMSec);
+ if (DateTime.Now > dtVeto)
+ {
+ lgInfo($"Retry Time Elapsed (waited for {waitRecMSec} ms)--> NOW tryConnect");
+ lastConnectTry = DateTime.Now;
+ tryConnect();
+ }
+ }
+ currDispData.semIn = Semaforo.SR;
+ }
+ raiseRefresh(currDispData);
+ }
+
+ ///
+ /// riporta il log di tutti i dati di results temporali registrati
+ ///
+ public void logTimeResults()
+ {
+ if (TimingData.results.Count > 0)
+ {
+ lgInfo("{0}--------------- START TIMING DATA ---------------", Environment.NewLine);
+ int globNumCall = 0;
+ TimeSpan globAvgMsec = new TimeSpan(0);
+ foreach (TimeRec item in TimingData.results)
+ {
+ // loggo SOLO se del mio IOB corrente...
+ if (item.classCall == cIobConf.codIOB)
+ {
+ lgInfo("{4}|Chiamate {0}: effettuate {1}, tempo medio {2:N2} msec | impegno canale {3:P3}", item.codCall, item.numCall, item.avgMsec, item.totMsec.TotalSeconds / DateTime.Now.Subtract(dtAvvioAdp).TotalSeconds, cIobConf.codIOB);
+ globNumCall += item.numCall;
+ globAvgMsec += item.totMsec;
+ }
+ }
+ // riporto conteggio medio al secondo...
+ lgInfo("{4}|Chiamate GLOBALI: {0}, periodo: {1:N2} minuti.cent, tempo medio {2:N2} msec | impegno canale {3:P3}", globNumCall, DateTime.Now.Subtract(dtAvvioAdp).TotalMinutes, globAvgMsec.TotalMilliseconds / globNumCall, globAvgMsec.TotalSeconds / DateTime.Now.Subtract(dtAvvioAdp).TotalSeconds, cIobConf.codIOB);
+ lgInfo("{0}--------------- STOP TIMING DATA ---------------{0}", Environment.NewLine);
+ // mostro in form statistiche globali!
+ parentForm.updateComStats(string.Format("Periodo: {0:N2}min | {1} x {2:N2}ms | canale {3:P3}", DateTime.Now.Subtract(dtAvvioAdp).TotalMinutes, globNumCall, globAvgMsec.TotalMilliseconds / globNumCall, globAvgMsec.TotalSeconds / DateTime.Now.Subtract(dtAvvioAdp).TotalSeconds));
+ }
+ }
+
+ ///
+ /// Effettua ciclo controllo richieste server
+ ///
+ public void processServerRequests()
+ {
+ Dictionary task2exe = new Dictionary();
+ Dictionary taskDone = new Dictionary();
+ // recupero elenco delle cose da fare
+ string resp = getTask2exe();
+ if (!string.IsNullOrEmpty(resp))
+ {
+ try
+ {
+ task2exe = JsonConvert.DeserializeObject>(resp);
+ // se ho da fare chiamo esecuzione..
+ if (task2exe.Count > 0)
+ {
+ taskDone = processTask(task2exe);
+ }
+ }
+ catch (Exception exc)
+ {
+ lgError($"Eccezione in processServerRequests:{Environment.NewLine}{exc}");
+ }
+ }
+ }
+
+ public Dictionary processTask(Dictionary task2exe)
+ {
+ Dictionary taskDone = new Dictionary();
+ if (task2exe != null)
+ {
+ lgInfo($"Task2Exe: trovati {task2exe.Count} task da eseguire, procedo");
+ // chiamo procedura esecutiva (diversa x ogni IOB)
+ taskDone = executeTasks(task2exe);
+ // loggo tutti i task done...
+ foreach (var item in taskDone)
+ {
+ sendToTaskWatch(item.Key, item.Value);
+ }
+ // ora chiamo la cancellazione dei task eseguiti...
+ foreach (var item in taskDone)
+ {
+ remTask2exe(item.Key, item.Value);
+ }
+ }
+ return taskDone;
+ }
+
+ ///
+ /// Effettua rilettura del contapezzi dal server MP/IO
+ ///
+ /// Forza rilettura da DB tempi ciclo rilevati
+ public void pzCntReload(bool forceCountRec)
+ {
+ // legge da IO server ULTIMO valore CONTPEZZI al riavvio...
+ string currServerCount = "";
+ string lastIdxODL = "";
+ if (checkServerAlive)
+ {
+ // leggo PRIMA ODL ....
+ lastIdxODL = utils.callUrl(urlGetCurrODL);
+ lgInfo("Lettura ODL dall'url {0} --> {1}", urlGetCurrODL, lastIdxODL);
+ // se ho valori in coda da trasmettere uso dati REDIS
+ if (forceCountRec)
+ {
+ // uso dati da TCiclo registrati...
+ currServerCount = utils.callUrl(urlGetPzCountRec);
+ lgInfo("Lettura contapezzi da TCiclo dall'url {0} --> num pz: {1}", urlGetPzCountRec, currServerCount);
+ }
+ else
+ {
+ // uso il contapezzi dichiarato dall'IOB stesso
+ currServerCount = utils.callUrl(urlGetPzCount);
+ lgInfo("Lettura contapezzi dall'url {0}", urlGetPzCount);
+ }
+ // controllo: SE NON HO ODL...
+ if (string.IsNullOrEmpty(lastIdxODL) || lastIdxODL == "0")
+ {
+ // NON AGGIORNO
+ contapezziIOB = contapezziPLC;
+ lgInfo($"Errore lettura ODL (vuoto) resta tutto invariato contapezzi: {contapezziIOB} | contapezziPLC {contapezziPLC}");
+ }
+ else
+ {
+ if (!string.IsNullOrEmpty(currServerCount))
+ {
+ // se "-1" resto a ultimo...
+ if (currServerCount != "-1")
+ {
+ int newVal = -1;
+ Int32.TryParse(currServerCount, out newVal);
+ contapezziIOB = newVal > -1 ? newVal : contapezziIOB;
+ lgInfo("Ricevuta conferma da server di {0} pezzi registrati per ODL", currServerCount);
+ }
+ else
+ {
+ // NON AGGIORNO
+ contapezziIOB = contapezziPLC;
+ lgInfo($"Errore lettura contapezzi (-1) - uso contapezziPLC --> {contapezziPLC}");
+ }
+ }
+ else
+ {
+ // registro che ho UN NUOVO ODL
+ lgInfo($"Lettura ODL in pzCntReload, currIdxODL {currIdxODL} --> lastIdxODL {lastIdxODL}");
+ // se ODL differente e NUOVO è zero --> resetto!
+ if (currIdxODL.ToString() != lastIdxODL && lastIdxODL == "0")
+ {
+ // cambiato ODL quindi reset...
+ contapezziIOB = 0;
+ lgInfo("Nuovo ODL==0, RESET contapezzi (-->ZERO)");
+ }
+ // provo a salvare nuovo ODL
+ int.TryParse(lastIdxODL, out currIdxODL);
+ }
+ }
+ }
+ else
+ {
+ // se server NON pronto...
+ contapezziIOB = contapezziPLC;
+ lgError("Errore server NON pronto in pzCntReload");
+ }
+ }
+
+ ///
+ /// Metodo generico di reset contapezzi...
+ ///
+ ///
+ public virtual bool resetcontapezziPLC()
+ {
+ return false;
+ }
+
+ ///
+ /// Metodo generico di IMPOSTAZIONE FORZATA del contapezzi...
+ ///
+ /// Pezzi richiesti
+ ///
+ public virtual bool setcontapezziPLC(int newPzCount)
+ {
+ return false;
+ }
+
+ ///
+ /// Avvia l'adapter sulla porta richiesta
+ ///
+ /// indica se sia richeisto di SVUOTARE le code delel info
+ public virtual void startAdapter(bool resetQueue)
+ {
+ lgInfo("Starting adapter...");
+ maxJsonData = utils.CRI("maxJsonData");
+ maxJsonDataEv = utils.CRI("maxJsonDataEv");
+ parentForm.commPlcActive = false;
+ adpRunning = true;
+ dtAvvioAdp = DateTime.Now;
+ lastWatchDog = dtAvvioAdp;
+ lastPING = dtAvvioAdp;
+ lastReadPLC = dtAvvioAdp.AddMinutes(-1);
+ lastDisconnCheck = dtAvvioAdp;
+ TimingData.resetData();
+ // aggiungo altri defaults
+ setDefaults(resetQueue);
+ adpTryRestart = true;
+ parentForm.displayTaskAndLog("Adapter Started!");
+ }
+
+ ///
+ /// ferma l'adapter...
+ ///
+ /// indica se si debba tentare di riavviare l'adapter (con caduta connessione viene fermato in automatico)
+ /// indica se sia richeisto di SVUOTARE le code delel info
+ public virtual void stopAdapter(bool tryRestart, bool forceDequeue)
+ {
+ if (forceDequeue)
+ {
+ // svuoto le code dei valori letti e non ancora trasmessi...
+ parentForm.displayTaskAndLog("Svuotamento FORZATO coda segnali...");
+ while (QueueIN.Count > 0)
+ {
+ // INVIO COMUNQUE...!!!
+ string valore = "";
+ QueueIN.TryDequeue(out valore);
+ sendToMoonPro(urlType.SignIN, valore);
+ }
+ parentForm.displayTaskAndLog("Svuotamento FORZATO coda FluxLOG...");
+ // se ho + di 2 elementi in coda --> uso invio JSON in blocco...
+ if (QueueFLog.Count > minJsonData)
+ {
+ while (QueueFLog.Count > 0)
+ {
+ List listaValori = new List();
+ // se ho + di maxJsonData elementi --> invio un set di dati alla volta
+ if (QueueFLog.Count > maxJsonData)
+ {
+ string currVal = "";
+ // prendoi primi maxJsonDataValori
+ for (int i = 0; i < maxJsonData; i++)
+ {
+ QueueFLog.TryDequeue(out currVal);
+ listaValori.Add(currVal);
+ }
+ sendDataBlock(urlType.FLog, listaValori);
+ }
+ else
+ {
+ // invio in blocco
+ listaValori = QueueFLog.ToList();
+ // invio
+ sendDataBlock(urlType.FLog, listaValori);
+ // svuoto!
+ QueueFLog = new ConcurrentQueue();
+ }
+ }
+ // HO FINITO invio di FLog...
+ }
+ else
+ {
+ string currVal = "";
+ while (QueueFLog.Count > 0)
+ {
+ // INVIO COMUNQUE...!!!
+ QueueFLog.TryDequeue(out currVal);
+ sendToMoonPro(urlType.FLog, currVal);
+ }
+ }
+ }
+ parentForm.displayTaskAndLog("Stopping adapter...");
+ adpTryRestart = false;
+
+ parentForm.displayTaskAndLog("Stopping adapter - last periodic data read...");
+
+ // chiudo la connessione all'adapter...
+ tryDisconnect();
+ dtStopAdp = DateTime.Now;
+ adpTryRestart = tryRestart;
+ adpRunning = false;
+ // chiudo!
+ parentForm.displayTaskAndLog("Adapter Stopped.");
+ parentForm.commPlcActive = false;
+ }
+
+ ///
+ /// Metodo base connessione...
+ ///
+ public virtual void tryConnect()
+ {
+ dtAvvioAdp = DateTime.Now;
+ }
+
+ ///
+ /// Metodo base disconnessione...
+ ///
+ public virtual void tryDisconnect()
+ {
+ }
+
+ ///
+ /// Stringa raw dei parametri da scrivere...
+ ///
+ ///
+ protected string getParams2write()
+ {
+ string answ = "";
+ string url2call = $"{urlGetParams2Write}";
+ if (verboseLog)
+ {
+ lgInfo("chiamata URL " + url2call);
+ }
+ answ = utils.callUrlNow(url2call);
+ // se vuoto faccio seconda prova...
+ if (string.IsNullOrEmpty(answ))
+ {
+ answ = utils.callUrlNow(url2call);
+ }
+ return answ;
+ }
+
+ ///
+ /// Chiede elenco dei task da eseguire
+ /// - formato Json
+ /// - array di KVP / Dictionary
+ /// - formato definito da API x MP/IO/:
+ /// - KEY: task
+ /// - VALUE: array JSon KVP
+ ///
+ protected string getTask2exe()
+ {
+ string answ = "";
+ if (checkServerAlive)
+ {
+ string url2call = $"{urlGetTask2Exe}";
+ if (verboseLog)
+ {
+ lgInfo("chiamata URL " + url2call);
+ }
+ answ = utils.callUrlNow(url2call);
+ }
+ return answ;
+ }
+
+ ///
+ /// Metodo da overridare x scrivere DAVVERO i aprametri sul PLC
+ ///
+ ///
+ protected virtual void plcWriteParams(List updatedPar)
+ {
+ // non faccio nulla di base...
+ }
+
+ ///
+ /// Processa le richieste di scrittura memoria
+ ///
+ ///
+ protected string processMemWriteRequests()
+ {
+ string answ = "";
+ // li salvo nei parametri in memoria locale (ogni adapter DOVREBBE salvare POI sul VERO PLC)
+ List writeList = new List();
+ List updatedPar = new List();
+ // recupero elenco delle cose da fare
+ string resp = getParams2write();
+ if (!string.IsNullOrEmpty(resp))
+ {
+ try
+ {
+ writeList = JsonConvert.DeserializeObject>(resp);
+ // se ho da fare chiamo esecuzione..
+ if (writeList.Count > 0)
+ {
+ foreach (var item in writeList)
+ {
+ // scrivo in memoria
+ if (memMap.mMapWrite.ContainsKey(item.uid))
+ {
+ memMap.mMapWrite[item.uid].value = item.reqValue;
+ // accodo in stringa taskVal...
+ answ += $" | Parameter {item.uid} --> {item.reqValue}";
+ // sistemo valori
+ item.value = item.reqValue;
+ lgInfo($"Effettuato update parametro: actVal = {item.value} | reqVal = {item.reqValue}");
+ item.reqValue = "";
+ // salvo in lista da ritrasmettere
+ updatedPar.Add(item);
+ }
+ else
+ {
+ answ += $" | Error: parameter {item.uid} not found";
+ }
+ }
+ // richiamo scrittura parametri su PLC
+ plcWriteParams(updatedPar);
+ // invio su cloud parametri!
+ string rawData = JsonConvert.SerializeObject(updatedPar);
+ utils.callUrl($"{urlUpdateWriteParams}", rawData);
+ }
+ }
+ catch (Exception exc)
+ {
+ lgError($"Eccezione in processServerRequests:{Environment.NewLine}{exc}");
+ }
+ }
+ else
+ {
+ lgError("Non è stata ricevuta risposta x task da eseguire");
+ }
+ return answ;
+ }
+
+ protected void raiseRefresh(newDisplayData currDispData)
+ {
+ if (currDispData.hasData)
+ {
+ // segnalo refresh!
+ if (eh_refreshed != null)
+ {
+ eh_refreshed(this, new iobRefreshedEventArgs(currDispData));
+ }
+ }
+ }
+
+ ///
+ /// Cancella dal server i task eseguiti
+ ///
+ ///
+ ///
+ ///
+ protected string remTask2exe(string taskName, string esitoTask)
+ {
+ string answ = "";
+ if (checkServerAlive)
+ {
+ string url2call = $"{urlRemTask2Exe}{taskName}";
+ lgInfo($"Task2Exe | {esitoTask} | chiamata URL {url2call}");
+ answ = utils.callUrlNow(url2call);
+ }
+ return answ;
+ }
+
+ ///
+ /// Invia informazioni associazione IOB 2 machine
+ ///
+ protected void sendM2IOB()
+ {
+ if (checkServerAlive)
+ {
+ lgInfo("chiamata URL " + urlSetM2IOB);
+ utils.callUrlNow(urlSetM2IOB);
+ }
+ }
+
+ ///
+ /// Invia al server IO i valori dei parametri opzionali (es counters)
+ ///
+ /// Nome parametro
+ /// Valore parametro
+ protected void sendOptVal(string paramName, string paramValue)
+ {
+ if (checkServerAlive)
+ {
+ string url2call = $"{urlSetOptVal}pName={paramName}&pValue={paramValue}";
+ lgInfo("chiamata URL " + url2call);
+ utils.callUrlNow(url2call);
+ }
+ }
+
+ ///
+ /// Invia al server IO i valori dei parametri opzionali (es counters)
+ ///
+ /// Nome parametro
+ /// Valore parametro INT
+ protected void sendOptVal(string paramName, int paramValueInt)
+ {
+ // override!
+ sendOptVal(paramName, paramValueInt.ToString());
+ }
+
+ ///
+ /// Verifica e se necessario comprime directory log...
+ ///
+ private void checkShrinkDir()
+ {
+ string path = string.Format("{0}logs\\{1}", AppDomain.CurrentDomain.BaseDirectory, cIobConf.codIOB);
+ baseUtils.shrinkDir(path);
+ }
+
+ private void reportDataProc()
+ {
+ // update valori visualizzazione...
+ parentForm.dataProcLabel = string.Format("RAW: {0} --> IN: {1} --> OUT: {2}", nReadIN, nReadFilt, nSendOut);
+ }
+
+ private void svuotaCodaContapezzi()
+ {
+ // permetto al max 2 tentativi infruttuosi...
+ int maxTry = 2;
+ int oldContapezzi = contapezziIOB;
+ // se ho contapezzi OLTRE limite...
+ while ((MPOnline) && (contapezziPLC > contapezziIOB + minSendPzCountBlock))
+ {
+ lgInfo($"Ciclo svuotaCodaContapezzi --> contapezziPLC: {contapezziPLC} | contapezziIOB: {contapezziIOB}");
if (!isMulti)
{
- // controllo SE sono fermo (spento o in manuale) per il periodo minimo richiesto...
- rawIdle = callUrl(urlIdleTime, false);
- int.TryParse(rawIdle, out idlePeriod);
+ pzCntReload(true);
+ }
+ // provo invio
+ trySendPzCountBlock();
+ // verifica per evitare loop infinito invio fallito
+ if (oldContapezzi == contapezziIOB)
+ {
+ maxTry--;
}
else
{
- int tmpIdle = 0;
- // prendo il + grande...
- foreach (var item in elencoMulti)
- {
- fullUrl = $"{urlIdleTime}|{item}";
- rawIdle = callUrl(fullUrl, false);
- int.TryParse(rawIdle, out tmpIdle);
- idlePeriod = tmpIdle > idlePeriod ? tmpIdle : idlePeriod;
- }
+ maxTry = 2;
+ oldContapezzi = contapezziIOB;
}
- if (idlePeriod >= minPlcIdelMin)
+ // verifico maxTry: se li ho esauriti esco!
+ if (maxTry <= 0)
{
+ return;
+ }
+ // aspetto x dare tempo calcolo
+ Thread.Sleep(400);
+ }
+ }
+
+ ///
+ /// Cerca di inviare su un altro thread i vari dati accumulati...
+ ///
+ private void trySendValues()
+ {
+ // init obj display
+ newDisplayData currDispData = new newDisplayData();
+ try
+ {
+ // verifico se risponde il server...
+ if (checkServerAlive)
+ {
+ bool iobOk = false;
+ if (utils.CRB("sendDataByThread"))
+ {
+ Task taskCheck = TaskEx.Run(() => iobOk = checkIobEnabled);
+ }
+ else
+ {
+ iobOk = checkIobEnabled;
+ }
+ // verifico SE posso inviare dati
+ if (iobOk)
+ {
+ currDispData.semOut = Semaforo.SV;
+ // verificare come gestire il task secondario senza interferenza (chiamate update su FORM da thread secondari danno errori)
+ if (utils.CRB("sendDataByThread"))
+ {
+ // invio con thread separato...
+ Task taskSigIN = TaskEx.Run(() => svuotaCodaSignIN());
+ Task taskFlog = TaskEx.Run(() => svuotaCodaFLog());
+ }
+ else
+ {
+ // gestione queue SignalIN (invio, display)
+ svuotaCodaSignIN();
+ currDispData.counter = contapezziIOB;
+ raiseRefresh(currDispData);
+ // provo a svuotare coda contapezzi
+ svuotaCodaContapezzi();
+ currDispData.counter = contapezziIOB;
+ raiseRefresh(currDispData);
+ // gestione queue FluxLog (invio, display)
+ svuotaCodaFLog();
+ raiseRefresh(currDispData);
+ }
+ }
+ else
+ {
+ // mostro VETO-SEND x invio... GIALLO
+ currDispData.semOut = Semaforo.SG;
+ if (periodicLog)
+ {
+ lgInfo("IOB - VETO SEND");
+ }
+ }
+ }
+ else
+ {
+ // mostro SERVER KO x invio... ROSSO
+ currDispData.semOut = Semaforo.SR;
+ if (periodicLog)
+ {
+ lgInfo("IOB - SERVER NOT READY");
+ }
+ }
+ }
+ catch (Exception exc)
+ {
+ lgError($"Errore in fase trySendValues{Environment.NewLine}{exc}");
+ currDispData.semOut = Semaforo.SR;
+ }
+ raiseRefresh(currDispData);
+ }
+
+ #endregion metodi adapter
+
+ #region layer persistenza dati
+
+ ///
+ /// Dizionario di persistenza per i valori da salvare da/su file
+ ///
+ public Dictionary persistenceLayer;
+
+ ///
+ /// recupera valore salvato in persistence layer (se non c'è crea...)
+ ///
+ ///
+ ///
+ private string getStoredVal(string keyVal)
+ {
+ string value = "";
+ try
+ {
+ if (persistenceLayer != null)
+ {
+ if (!persistenceLayer.TryGetValue(keyVal, out value))
+ {
+ persistenceLayer.Add(keyVal, "0");
+ }
+ }
+ }
+ catch (Exception exc)
+ {
+ lgError(string.Format("Eccezione in getStoredVal: {0}{1}", Environment.NewLine, exc));
+ }
+ return value;
+ }
+
+ ///
+ /// recupera valore salvato in persistence layer (se non c'è crea...) come double
+ ///
+ ///
+ ///
+ private double getStoredValDouble(string keyVal)
+ {
+ double answ = 0;
+ try
+ {
+ answ = Convert.ToDouble(getStoredVal(keyVal));
+ }
+ catch (Exception exc)
+ {
+ lgError(string.Format("Eccezione in getStoredValDouble: {0}{1}", Environment.NewLine, exc));
+ }
+ answ = (answ < (double.MaxValue / 10 * 9)) ? answ : 0;
+ return answ;
+ }
+
+ ///
+ /// recupera valore salvato in persistence layer (se non c'è crea...) come INT
+ ///
+ ///
+ ///
+ private long getStoredValLong(string keyVal)
+ {
+ long answ = 0;
+ try
+ {
+ answ = Convert.ToInt64(getStoredVal(keyVal));
+ }
+ catch
+ { }
+ // verifico che il valore sia minore di 9/10 del valore massimo...
+ answ = (answ < (long.MaxValue / 10 * 9)) ? answ : 0;
+ return answ;
+ }
+
+ ///
+ /// recupera valore salvato in persistence layer (se non c'è crea...) come UINT
+ ///
+ ///
+ ///
+ private uint getStoredValUInt(string keyVal)
+ {
+ uint answ = 0;
+ try
+ {
+ answ = Convert.ToUInt32(getStoredVal(keyVal));
+ }
+ catch (Exception exc)
+ {
+ lgError(string.Format("Eccezione in getStoredValUInt: {0}{1}", Environment.NewLine, exc));
+ }
+ // verifico che il valore sia minore di 9/10 del valore massimo...
+ answ = (answ < (uint.MaxValue / 10 * 9)) ? answ : 0;
+ return answ;
+ }
+
+ ///
+ /// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce
+ ///
+ ///
+ ///
+ ///
+ /// Nuovo valore incrementato
+ private double updateValDoubleByIncr(int i, double delta, string searchString)
+ {
+ // stringa da cercare..
+ string keyVal = string.Format(searchString, i + 1);
+ // recupero valore precedente...
+ double contAct = getStoredValDouble(keyVal);
+ // nuovo valore...
+ contAct += delta;
+ // salvo in ram!
+ persistenceLayer[keyVal] = contAct.ToString();
+ // rendo il valore!
+ return contAct;
+ }
+
+ ///
+ /// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce
+ ///
+ ///
+ ///
+ ///
+ /// Nuovo valore incrementato
+ private long updateValLongByIncr(int i, long delta, string searchString)
+ {
+ // stringa da cercare..
+ string keyVal = string.Format(searchString, i + 1);
+ // recupero valore precedente...
+ long contAct = getStoredValLong(keyVal);
+ // nuovo valore...
+ contAct += delta;
+ // salvo in ram!
+ persistenceLayer[keyVal] = contAct.ToString();
+ // rendo il valore!
+ return contAct;
+ }
+
+ ///
+ /// Aggiorna un valore del dizionario in SOSTITUZIONE
+ ///
+ ///
+ ///
+ ///
+ /// Nuovo valore incrementato
+ private void updateValString(int i, string newVal, string searchString)
+ {
+ // stringa da cercare..
+ string keyVal = string.Format(searchString, i + 1);
+ // salvo in ram!
+ persistenceLayer[keyVal] = newVal;
+ }
+
+ ///
+ /// Aggiorna un valore del dizionario in SOSTITUZIONE e lo restituisce
+ ///
+ ///
+ ///
+ ///
+ /// Nuovo valore incrementato
+ private void updateValUInt(int i, uint newVal, string searchString)
+ {
+ // stringa da cercare..
+ string keyVal = string.Format(searchString, i + 1);
+ // salvo in ram!
+ persistenceLayer[keyVal] = newVal.ToString();
+ }
+
+ ///
+ /// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce
+ ///
+ ///
+ ///
+ ///
+ /// Nuovo valore incrementato
+ private uint updateValUIntByIncr(int i, uint delta, string searchString)
+ {
+ // stringa da cercare..
+ string keyVal = string.Format(searchString, i + 1);
+ // recupero valore precedente...
+ uint contAct = getStoredValUInt(keyVal);
+ // nuovo valore...
+ contAct += delta;
+ // salvo in ram!
+ persistenceLayer[keyVal] = contAct.ToString();
+ // rendo il valore!
+ return contAct;
+ }
+
+ #endregion layer persistenza dati
+
+ #region area lettura configurazioni
+
+ ///
+ /// Cerca parametri opzionali in modalità "like" del nome
+ ///
+ ///
+ ///
+ public Dictionary findOptPar(string keyStartSearch = "")
+ {
+ Dictionary answ = new Dictionary();
+ // controllo SE keySearch !=""
+ if (!string.IsNullOrWhiteSpace(keyStartSearch))
+ {
+ if (cIobConf.optPar.Count > 0)
+ {
+ // ciclo su tutti e cerco occorrenze che INIZINO...
+ foreach (var item in cIobConf.optPar)
+ {
+ if (item.Key.StartsWith(keyStartSearch))
+ {
+ answ.Add(item.Key, item.Value);
+ }
+ }
+ }
+ }
+ return answ;
+ }
+
+ ///
+ /// Cerca se esiste il parametro opzionale e lo restituisce
+ ///
+ ///
+ ///
+ public string getOptPar(string key)
+ {
+ string answ = "";
+ if (cIobConf.optPar.Count > 0)
+ {
+ // controllo SE HO il parametro
+ if (cIobConf.optPar.ContainsKey(key))
+ {
+ answ = cIobConf.optPar[key];
+ }
+ }
+ return answ;
+ }
+
+ ///
+ /// Decodifica file MAP (caso .bit)
+ ///
+ ///
+ ///
+ /// indirizzo Byte: indirizzo di partenza memoria
+ /// dimensione singolo slot in byte
+ /// indirizzo bit: numero riga x calcolo indice bit
+ ///
+ protected static otherData decodeBitData(string linea, char separator, int ByteNum, int memSize, int BitNum)
+ {
+ if (linea != null)
+ {
+ string[] valori = linea.Split(separator);
+ int shift = 0;
+ try
+ {
+ shift = Convert.ToInt32(valori[0]) - 1;
+ }
+ catch
+ { }
+ int resto = 0;
+ Math.DivRem(BitNum, 8, out resto);
+ string memAddr = string.Format("{0}.{1}", ByteNum + shift * memSize, resto);
+ return new otherData(valori[0], memAddr, valori[1].Trim(), valori[2].Trim());
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ ///
+ /// Decodifica file MAP generico
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected static otherData decodeOtherData(string linea, char separator, string memPre, int baseAddr, int memSize)
+ {
+ if (linea != null)
+ {
+ string[] valori = linea.Split(separator);
+ int shift = 0;
+ try
+ {
+ shift = Convert.ToInt32(valori[0]) - 1;
+ }
+ catch
+ { }
+ string memAddr = string.Format("{0}{1}", memPre, baseAddr + shift * memSize);
+ return new otherData(valori[0], memAddr, valori[1].Trim(), valori[2].Trim());
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ ///
+ /// Legge il file di conf di una MAP di informazioni da gestire con lettura set memoria
+ ///
+ /// nome vettore memoria
+ /// file origine
+ /// dimensione (in byte) della memoria
+ /// dimensione (in byte) della memoria
+ protected void loadConfFile(ref otherData[] vettoreConf, string nomeFile, int memSize, ref int numVett)
+ {
+ otherData lastData = new otherData();
+ int totRighe = 0;
+ string linea;
+ totRighe = File.ReadLines(nomeFile).Count();
+ // creo un vettore della dimensione corretta... conta anche commenti tanto poi riduco...
+ vettoreConf = new otherData[File.ReadLines(nomeFile).Count()];
+ // carica da file...
+ StreamReader file = new StreamReader(nomeFile);
+ // leggo 1 linea alla volta...
+ int numRiga = 0;
+ int bitNum = 0;
+ int byteNum = 0;
+ while ((linea = file.ReadLine()) != null)
+ {
+ // SE non è un commento...
+ if (linea.Substring(0, 1) != "#")
+ {
+ // se finisce per BIT allora processo bit-a-bit...
+ if (linea.EndsWith("BOOL"))
+ {
+ try
+ {
+ string[] memIdx = linea.Split(utils.CRC("testCharSep"))[0].Split('.');
+ // calcolo bit e byte number...
+ int.TryParse(memIdx[0], out byteNum);
+ if (memIdx.Length > 1)
+ {
+ int.TryParse(memIdx[1], out bitNum);
+ }
+ else
+ {
+ bitNum = 0;
+ }
+ }
+ catch
+ {
+ byteNum = 0;
+ bitNum = 0;
+ }
+ lastData = decodeBitData(linea, utils.CRC("testCharSep"), byteNum, 1, bitNum);
+ vettoreConf[numRiga] = lastData;
+ }
+ else
+ {
+ lastData = decodeOtherData(linea, utils.CRC("testCharSep"), "", 1, memSize);
+ vettoreConf[numRiga] = lastData;
+ }
+ numRiga++;
+ }
+ }
+ // salvo lunghezza file...
+ try
+ {
+ numVett = Convert.ToInt32(lastData.memAddr) + 1;
+ }
+ catch
+ {
+ numVett = numRiga + 1;
+ }
+ // chiudo file
+ file.Close();
+ // ora trimmo vettore al solo numero VERO dei valori caricati...
+ Array.Resize(ref vettoreConf, numRiga);
+
+ if (isVerboseLog)
+ {
+ lgInfo(string.Format("Fine caricamento vettore di {0} variabili per file {1}", numRiga, nomeFile));
+ }
+ }
+
+ #endregion area lettura configurazioni
+
+ #region IOB METHODS
+
+ ///
+ /// contatore x simulazione valori input
+ ///
+ public int countSim = 0;
+
+ ///
+ /// DateTime Ultimo valore simulazione generato
+ ///
+ public DateTime lastSim;
+
+ ///
+ /// Verifica se il server sia ALIVE (tramite PING)
+ ///
+ public bool checkServerAlive
+ {
+ get
+ {
+ bool answ = false;
+ // controllo se ho un VETO all'invio...
+ if (dtVetoPing < DateTime.Now)
+ {
+ if (DemoOut)
+ {
+ answ = false;
+ }
+ else
+ {
+ IPStatus pingStatus = testPingServer;
+ // se passa il ping faccio il resto...
+ if (pingStatus == IPStatus.Success)
+ {
+ string callResp = "";
+ try
+ {
+ // chiamo URL, se restituisce "OK" è alive!
+ callResp = callUrl(urlAlive, false);
+ answ = (callResp == "OK");
+ }
+ catch (Exception exc)
+ {
+ lgError("Errore in checkServerAlive:{0}{1}", Environment.NewLine, exc);
+ }
+ // attesa casuale se necessario
+ var rand = new Random();
+ // primi 3 test
+ int maxTry = 3;
+ while (maxTry > 0 && !answ)
+ {
+ try
+ {
+ Thread.Sleep(rand.Next(150, 500));
+ callResp = callUrl(urlAlive, false);
+ answ = (callResp == "OK");
+ maxTry--;
+ }
+ catch
+ { }
+ }
+ // se NON OK riprovo ANCORA 1 volta...
+ if (!answ)
+ {
+ resetWebClients();
+ Thread.Sleep(rand.Next(500, 1000));
+ callResp = callUrl(urlAlive, false);
+ answ = (callResp == "OK");
+ }
+ // altri 3
+ maxTry = 3;
+ while (maxTry > 0 && !answ)
+ {
+ try
+ {
+ Thread.Sleep(rand.Next(150, 500));
+ callResp = callUrl(urlAlive, false);
+ answ = (callResp == "OK");
+ maxTry--;
+ }
+ catch
+ { }
+ }
+ // verifico SE è variato stato online/offline...
+ if (MPOnline != answ)
+ {
+ // se ORA sono online riporto...
+ if (answ)
+ {
+ lgInfo("SERVER ONLINE in checkServerAlive");
+ parentForm.commSrvActive = 1;
+ dtVetoPing = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec);
+ }
+ else
+ {
+ lgInfo("SERVER OFFLINE in checkServerAlive");
+ parentForm.commSrvActive = 0;
+ }
+ // salvo nuovo status...
+ MPOnline = answ;
+ }
+ else
+ {
+ // allungo periodo controllo...
+ dtVetoPing = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec * 3);
+ }
+ }
+ else
+ {
+ lgInfo($"SERVER NOT RESPONDING (PING at {cIobConf.serverData.MPIP})");
+ MPOnline = false;
+ // imposto veto a 10 volte reinvio dati standard...
+ dtVetoPing = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec * 3);
+ utils.dtVetoSend = dtVetoPing;
+ }
+ }
+ }
+ else
+ {
+ // altrimenti passo ultimo valore noto...
+ answ = MPOnline;
+ }
+ return answ;
+ }
+ }
+
+ ///
+ /// Verifica se sia machcina multi = DoppioPallet da CONF
+ ///
+ public bool isMulti
+ {
+ get
+ {
+ bool answ = false;
+ if (cIobConf.optPar.Count > 0)
+ {
+ // cerco con chaive reale IS_MULTI
+ string keyName = "IS_MULTI";
+ if (!cIobConf.optPar.ContainsKey(keyName))
+ {
+ // legacy: accetto anche SIM_MULTI...
+ keyName = "SIM_MULTI";
+ }
+ // vera verifica su chaive...
+ if (cIobConf.optPar.ContainsKey(keyName))
+ {
+ string SIM_MULTI = getOptPar(keyName);
+ answ = SIM_MULTI == "1";
+ }
+ }
+ return answ;
+ }
+ }
+
+ ///
+ /// URL per INVIO IN BLOCCO di un INCREMENTO x contapezzi (quelli della macchina: PLC/CNC)...
+ ///
+ public string urlAddPzCount
+ {
+ get
+ {
+ string answ = "";
+ try
+ {
+ answ = string.Format(@"http://{0}{1}{2}/savePzCountInc/{3}?qty=", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB);
+ }
+ catch (Exception exc)
+ {
+ lgError(exc, "Errore in composizione urlAddPzCount");
+ }
+ return answ;
+ }
+ }
+
+ ///
+ /// URL per check alive...
+ ///
+ public string urlAlive
+ {
+ get
+ {
+ return string.Format(@"http://{0}{1}{2}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE);
+ }
+ }
+
+ ///
+ /// URL per forzare split ODL...
+ ///
+ public string urlForceSplit
+ {
+ get
+ {
+ return string.Format(@"http://{0}{1}{2}{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMD_FORCLE_SPLIT_ODL, cIobConf.codIOB);
+ }
+ }
+
+ ///
+ /// URL per salvataggio contapezzi...
+ ///
+ public string urlGetCurrODL
+ {
+ get
+ {
+ string answ = "";
+ try
+ {
+ answ = string.Format(@"http://{0}{1}{2}/getCurrODL/{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB);
+ }
+ catch (Exception exc)
+ {
+ lgError(exc, "Errore in composizione urlGetCurrODL");
+ }
+ return answ;
+ }
+ }
+
+ ///
+ /// URL per richiamo parametri da scrivere...
+ ///
+ public string urlGetParams2Write
+ {
+ get
+ {
+ string answ = "";
+ try
+ {
+ answ = string.Format(@"http://{0}{1}{2}/getObjItems2Write/{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB);
+ }
+ catch (Exception exc)
+ {
+ lgError(exc, "Errore in composizione urlGetParams2Write");
+ }
+ return answ;
+ }
+ }
+
+ ///
+ /// URL per recupero contapezzi...
+ ///
+ public string urlGetPzCount
+ {
+ get
+ {
+ string answ = "";
+ try
+ {
+ answ = $@"http://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDALIVE}/getCounter/{cIobConf.codIOB}";
+ }
+ catch (Exception exc)
+ {
+ lgError(exc, "Errore in composizione urlGetPzCount");
+ }
+ return answ;
+ }
+ }
+
+ ///
+ /// URL per recupero contapezzi REGISTRATI da TC...
+ ///
+ public string urlGetPzCountRec
+ {
+ get
+ {
+ string answ = "";
+ try
+ {
+ answ = $@"http://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDALIVE}/getCounterTCRec/{cIobConf.codIOB}";
+ }
+ catch (Exception exc)
+ {
+ lgError(exc, "Errore in composizione urlGetPzCountRec");
+ }
+ return answ;
+ }
+ }
+
+ ///
+ /// URL per richiamo task da eseguire...
+ ///
+ public string urlGetTask2Exe
+ {
+ get
+ {
+ string answ = "";
+ try
+ {
+ answ = string.Format(@"http://{0}{1}{2}/getTask2Exe/{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB);
+ }
+ catch (Exception exc)
+ {
+ lgError(exc, "Errore in composizione urlGetTask2Exe");
+ }
+ return answ;
+ }
+ }
+
+ ///
+ /// URL per recupero idle time IOB...
+ ///
+ public string urlIdleTime
+ {
+ get
+ {
+ return string.Format(@"http://{0}{1}{2}{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMD_IDLE_TIME, cIobConf.codIOB);
+ }
+ }
+
+ ///
+ /// URL per recupero inizio ODL...
+ ///
+ public string urlInizioOdlIob
+ {
+ get
+ {
+ return string.Format(@"http://{0}{1}{2}{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMD_ODL_STARTED, cIobConf.codIOB);
+ }
+ }
+
+ ///
+ /// URL per check se abilitato...
+ ///
+ public string urlIobEnabled
+ {
+ get
+ {
+ return string.Format(@"http://{0}{1}{2}{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDENABLED, cIobConf.codIOB);
+ }
+ }
+
+ ///
+ /// URL per segnalazione reboot...
+ ///
+ public string urlReboot
+ {
+ get
+ {
+ string answ = "";
+ try
+ {
+ answ = string.Format(@"http://{0}{1}{2}{3}&mac={4}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDREBO, cIobConf.codIOB, GetMACAddress());
+ }
+ catch
+ {
+ answ = string.Format(@"http://{0}{1}{2}{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDREBO, cIobConf.codIOB);
+ }
+ return answ;
+ }
+ }
+
+ ///
+ /// URL per richiamo task da eseguire...
+ ///
+ public string urlRemTask2Exe
+ {
+ get
+ {
+ string answ = "";
+ try
+ {
+ answ = string.Format(@"http://{0}{1}{2}/remTask2Exe/{3}?taskName=", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB);
+ }
+ catch (Exception exc)
+ {
+ lgError(exc, "Errore in composizione urlRemTask2Exe");
+ }
+ return answ;
+ }
+ }
+
+ ///
+ /// URL per salvataggio dati PARAMETRI IOB...
+ ///
+ public string urlSaveAllParams
+ {
+ get
+ {
+ string answ = "";
+ try
+ {
+ string machineName = Environment.MachineName;
+ string apiCall = "setObjItems";
+ answ = string.Format(@"http://{0}{1}{2}/{3}/{4}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, apiCall, cIobConf.codIOB);
+ }
+ catch (Exception exc)
+ {
+ lgError(exc, "Errore in composizione urlSaveMemConf");
+ }
+ return answ;
+ }
+ }
+
+ ///
+ /// URL per salvataggio dati conf memoria IOB...
+ ///
+ public string urlSaveMemMap
+ {
+ get
+ {
+ string answ = "";
+ try
+ {
+ string machineName = Environment.MachineName;
+ answ = string.Format(@"http://{0}{1}{2}/saveConf/{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB);
+ }
+ catch (Exception exc)
+ {
+ lgError(exc, "Errore in composizione urlSaveMemConf");
+ }
+ return answ;
+ }
+ }
+
+ ///
+ /// URL per salvataggio dati associazione Machine 2 IOB...
+ ///
+ public string urlSetM2IOB
+ {
+ get
+ {
+ string answ = "";
+ try
+ {
+ string machineName = Environment.MachineName;
+ answ = string.Format(@"http://{0}{1}{2}/setM2IOB/{3}?IOB_name={4}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB, machineName);
+ }
+ catch (Exception exc)
+ {
+ lgError(exc, "Errore in composizione urlSetM2IOB");
+ }
+ return answ;
+ }
+ }
+
+ ///
+ /// URL per salvataggio VALORI opzionali...
+ ///
+ public string urlSetOptVal
+ {
+ get
+ {
+ string answ = "";
+ try
+ {
+ answ = string.Format(@"http://{0}{1}{2}/addOptPar/{3}?", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB);
+ }
+ catch (Exception exc)
+ {
+ lgError(exc, "Errore in composizione urlSetOptVal");
+ }
+ return answ;
+ }
+ }
+
+ ///
+ /// URL per salvataggio contapezzi...
+ ///
+ public string urlSetPzCount
+ {
+ get
+ {
+ string answ = "";
+ try
+ {
+ answ = $@"http://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDALIVE}/setCounter/{cIobConf.codIOB}?counter=";
+ }
+ catch (Exception exc)
+ {
+ lgError(exc, "Errore in composizione urlSetPzCount");
+ }
+ return answ;
+ }
+ }
+
+ ///
+ /// URL per salvataggio contapezzi (quelli della macchina: PLC/CNC)...
+ ///
+ public string urlSetPzCountMAC
+ {
+ get
+ {
+ string answ = "";
+ try
+ {
+ answ = $@"http://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDALIVE}/setCounter/MAC_{cIobConf.codIOB}?counter=";
+ }
+ catch (Exception exc)
+ {
+ lgError(exc, "Errore in composizione urlSetPzCountMAC");
+ }
+ return answ;
+ }
+ }
+
+ ///
+ /// URL per salvataggio in UPSERT dei PARAMETRI IOB scritti...
+ ///
+ public string urlUpdateWriteParams
+ {
+ get
+ {
+ string answ = "";
+ try
+ {
+ string machineName = Environment.MachineName;
+ string apiCall = "upsertObjItems";
+ answ = string.Format(@"http://{0}{1}{2}/{3}/{4}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, apiCall, cIobConf.codIOB);
+ }
+ catch (Exception exc)
+ {
+ lgError(exc, "Errore in composizione urlSaveMemConf");
+ }
+ return answ;
+ }
+ }
+
+ ///
+ /// Valore del num max invii consecutivi da coda...
+ ///
+ protected static int nMaxSend
+ {
+ get
+ {
+ int answ = 5;
+ try
+ {
+ answ = utils.CRI("nMaxSend");
+ }
+ catch
+ { }
+ return answ;
+ }
+ }
+
+ ///
+ /// Verifica se la IOB sia ENABLED (da server o Demo)
+ ///
+ private bool checkIobEnabled
+ {
+ get
+ {
+ bool answ = false;
+ // controllo se ho veto al check...
+ if (dtVetoCheckIOB < DateTime.Now)
+ {
+ if (DemoOut)
+ {
+ answ = (QueueIN.Count + QueueFLog.Count >= nMaxSend);
+ }
+ else
+ {
+ try
+ {
+ // chiamo URL, se restituisce "OK" è enabled!
+ string callResp = callUrl(urlIobEnabled, true);
+ answ = (callResp == "OK");
+ // attesa casuale se necessario
+ var rand = new Random();
+ // primi 2 test
+ int maxTry = 2;
+ while (maxTry > 0 && !answ)
+ {
+ Thread.Sleep(rand.Next(250, 500));
+ callResp = callUrl(urlIobEnabled, true);
+ answ = (callResp == "OK");
+ maxTry--;
+ }
+ // se NON OK riprovo ANCORA 1 volta...
+ if (!answ)
+ {
+ resetWebClients();
+ Thread.Sleep(rand.Next(250, 1000));
+ callResp = callUrl(urlIobEnabled, false);
+ answ = (callResp == "OK");
+ }
+ // altri 2
+ maxTry = 2;
+ while (maxTry > 0 && !answ)
+ {
+ Thread.Sleep(rand.Next(250, 500));
+ callResp = callUrl(urlIobEnabled, false);
+ answ = (callResp == "OK");
+ maxTry--;
+ }
+ // salvo status...
+ IobOnline = answ;
+ // se online imposto veto check a 5 x tempo reinvio...
+ if (answ)
+ {
+ lastIobOnline = DateTime.Now;
+ }
+ dtVetoCheckIOB = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec * 5);
+ }
+ catch
+ { }
+ }
+ // verifico SE è variato stato online/offline...
+ if (IobOnline != answ)
+ {
+ // se ORA sono online riporto...
+ if (answ)
+ {
+ lgInfo("IOB ONLINE for server MP/IO");
+ }
+ else
+ {
+ lgInfo("IOB OFFLINE for server MP/IO");
+ }
+ }
+ // fix colore
+ if (answ)
+ {
+ parentForm.commSrvActive = 2;
+ }
+ else
+ {
+ parentForm.commSrvActive = 1;
+ }
+ }
+ else
+ {
+ // altrimenti passo ultimo valore noto
+ answ = IobOnline;
+ }
+ return answ;
+ }
+ }
+
+ ///
+ /// test ping all'indirizzo impostato nei parametri
+ ///
+ ///
+ private IPStatus testPingServer
+ {
+ get
+ {
+ IPStatus answ = IPStatus.Unknown; ;
+ IPAddress address;
+ PingReply reply;
+ using (Ping pingSender = new Ping())
+ {
+ address = IPAddress.Loopback;
+ int maxRetry = maxPingRetry + 1;
+ int numRetry = 1; ;
+ string ipAdrr = cIobConf.serverData.MPIP.Replace("http://", "").Replace("https://", "");
+ IPAddress.TryParse(ipAdrr, out address);
+ reply = pingSender.Send(address, pingServerMsTimeout);
+ // se ho timeout riprovo...
+ while (reply.Status != IPStatus.Success && numRetry < maxRetry)
+ {
+ lgInfo($"Ping KO | reply: {reply.Status} --> retry");
+ reply = pingSender.Send(address, pingServerMsTimeout * numRetry / 2);
+ numRetry++;
+ if (reply.Status == IPStatus.Success)
+ {
+ lgInfo("PING OK!");
+ break;
+ }
+ }
+ }
+ answ = reply.Status;
+ return answ;
+ }
+ }
+
+ ///
+ /// Effettua chiamata URL e restituisce risultato
+ ///
+ ///
+ /// invio in modalità async (NON GARANTITO ordine...)
+ ///
+ public static string callUrl(string URL, bool doAsync)
+ {
+ string answ = "";
+ // Chiamata ASINCRONA
+ if (doAsync)
+ {
+ //Task resp = utils.callUrlAsync(URL);
+ //answ = resp.Result;
+ answ = utils.callUrlAsync(URL);
+ }
+ // chiamata SOLO NORMALE SINCRONA...
+ else
+ {
+ answ = utils.callUrl(URL);
+ }
+ return answ;
+ }
+
+ ///
+ /// Effettua chiamata URL e restituisce risultato
+ ///
+ ///
+ ///
+ /// invio in modalità async (NON GARANTITO ordine...)
+ ///
+ public static string callUrlWithPayload(string URL, string payload, bool doAsync)
+ {
+ string answ = "";
+ // Chiamata ASINCRONA
+ if (doAsync)
+ {
+ answ = utils.callUrlAsync(URL, payload);
+ }
+ // chiamata SOLO NORMALE SINCRONA...
+ else
+ {
+ answ = utils.callUrl(URL, payload);
+ }
+ return answ;
+ }
+
+ public static string GetMACAddress()
+ {
+ NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
+ String sMacAddress = string.Empty;
+ foreach (NetworkInterface adapter in nics)
+ {
+ if (string.IsNullOrEmpty(sMacAddress))// only return MAC Address from first card
+ {
+ IPInterfaceProperties properties = adapter.GetIPProperties();
+ //sMacAddress = adapter.GetPhysicalAddress().ToString();
+ sMacAddress = string.Join(":", (from z in adapter.GetPhysicalAddress().GetAddressBytes() select z.ToString("X2")).ToArray());
+ }
+ }
+ return sMacAddress;
+ }
+
+ ///
+ /// Reset dei webclients
+ ///
+ public static void resetWebClients()
+ {
+ utils.resetWebClients();
+ }
+
+ ///
+ /// Effettua chaimata x split ODL
+ ///
+ ///
+ public bool forceSplitOdl()
+ {
+ bool fatto = false;
+ if (vetoSplit < DateTime.Now)
+ {
+ // imposto veto x 1 minuto ad altre chiamate...
+ vetoSplit = DateTime.Now.AddMinutes(1);
+ // eseguo SOLO SE sono online...
+ if (MPOnline && IobOnline)
+ {
+ string fullUrl = "";
+ string rawSplit = "";
+ string IOB_MULTI_CNAME = "";
+ string[] elencoMulti = null;
+
+ try
+ {
+ /***************************************************
+ * Descrizione procedura (OK X SIMULATORI...)
+ *
+ * - chiamata su MP/IO
+ * - verifica che su DB sia abilitato AUTO ODL
+ * - il server inserisce un evento fine prod HW 1 minuto prima e inizio setup HW
+ * - viene duplicato e chiuso ODL corrente
+ * - viene fatto partire ODL nuovo ADESSO
+ * - num pezzi come ODL precedente (o da media 3 ODL precedenti)
+ * - conferme pezzi & co... gestione NULL (NON SERVONO si tratta di impianti SENZA gestione vera ODL)
+ * - reset contapezzi PLC locale...
+ *
+ *
+ *
+ * DA VALUTARE (x macchine tipo linea con + impianti... es valvital) SE
+ * - creare una gestione ALTERNATIVA sul server che preveda impianto LEADER e impianti follower (RIGIDAMENTE CONFIGURATI)
+ * - ogni volta che si fa setup LEADER --> si ripete su impianti FOLLOWER (eventi!!!)
+ * - viene fatto reset contapezzi sui follower (+ altre operazioni opzionali, ES imposstazione nome commessa, quantità, articolo...)
+ * - viene fatto reset + nuovo ODL (con stessi articoli e quantità) su follower, SENZA avere gestione x ODL di un codice esterno (quindi registra TUTTO ma NON RITORNERA' dati non avendo link verso esterno)
+ * - serve NUOVA TABELLA delle macchine LEADER | FOLLOWER (1:n) e gestione da MP/IO
+ *
+ * ***************************************************/
+
+ if (isMulti)
+ {
+ // devo chiamare cambio ODL x OGNI tavola: mi servono i parametri opzionali...
+ IOB_MULTI_CNAME = getOptPar("IOB_MULTI_CNAME");
+ elencoMulti = IOB_MULTI_CNAME.Split(',');
+ }
+ // se normale splitto!
+ if (!isMulti)
+ {
+ // invio chiamata URL x reset ODL su macchina
+ rawSplit = callUrl(urlForceSplit, false);
+ fatto = (rawSplit == "OK") ? true : false;
+ }
+ // se multi gestisco il bit delle tavole...
+ else
+ {
+ foreach (string item in elencoMulti)
+ {
+ // invio chiamata URL x reset ODL su macchina, ATTENZIONE scriviamo | al posto di "#" che in URL sarebbe filtrato...
+ fullUrl = $"{urlForceSplit}|{item}";
+ rawSplit = callUrl(fullUrl, false);
+ }
+ fatto = (rawSplit == "OK") ? true : false;
+ }
+ }
+ catch (Exception exc)
+ {
+ lgError($"Eccezione in forceSplitOdl{Environment.NewLine}{exc}");
+ }
+ // se fatto --> resetto contapezzi!!!
+ if (fatto)
+ {
+ contapezziPLC = 0;
+ contapezziIOB = 0;
+ }
+ }
+ else
+ {
+ lgError("Richiesto forceSplitOdl ma MP/IOB offline --> NON eseguito");
+ }
+ }
+ else
+ {
+ lgError("Richiesto forceSplitOdl ma veto attivo --> NON eseguito");
+ }
+ return fatto;
+ }
+
+ ///
+ /// Recupera eventuali allarmi CNC...
+ ///
+ public virtual Dictionary getCncAlarms()
+ {
+ Dictionary outVal = new Dictionary();
+ return outVal;
+ }
+
+ ///
+ /// Restituisce info DINAMICHE
+ ///
+ ///
+ public virtual Dictionary getDynData()
+ {
+ Dictionary outVal = new Dictionary();
+ return outVal;
+ }
+
+ ///
+ /// Restituisce info OVERRIDES
+ ///
+ ///
+ public virtual Dictionary getOverrides()
+ {
+ Dictionary outVal = new Dictionary();
+ return outVal;
+ }
+
+ ///
+ /// Restituisce programma in esecuzione
+ ///
+ public virtual string getPrgName()
+ {
+ return "";
+ }
+
+ ///
+ /// Restituisce info sistema
+ ///
+ ///
+ public virtual Dictionary getSysInfo()
+ {
+ Dictionary outVal = new Dictionary();
+ return outVal;
+ }
+
+ ///
+ /// Restituisce un payload in formato json della lista di valori ricevuta
+ ///
+ /// Tipo di URL (eventi / FLog)
+ /// elenco di valori da coda string salvata
+ ///
+ public string jsonPayload(urlType tipoUrl, List elencoValori)
+ {
+ string answ = "";
+ if (elencoValori != null)
+ {
+ if (tipoUrl == urlType.FLog)
+ {
+ flogData currData = new flogData();
+ flogJsonPayload fullObj = new flogJsonPayload();
+ fullObj.fluxData = new List();
+ string[] valori;
+ int counter = 0;
+ DateTime dtEve = DateTime.Now;
+ // inizio processando ogni valore
+ foreach (var item in elencoValori)
+ {
+ valori = qDecodeIN(item);
+ //DateTime.TryParse(valori[0], out dtEve);
+ CultureInfo provider = CultureInfo.InvariantCulture;
+ DateTime.TryParseExact(valori[0], "yyyyMMddHHmmssfff", provider, DateTimeStyles.AssumeLocal, out dtEve);
+ int.TryParse(valori[3], out counter);
+ currData = new flogData()
+ {
+ flux = valori[1],
+ valore = valori[2],
+ dtEve = dtEve,
+ dtCurr = DateTime.Now,
+ cnt = counter
+ };
+ fullObj.fluxData.Add(currData);
+ }
+ // conversione finale
+ try
+ {
+ answ = JsonConvert.SerializeObject(fullObj);
+ }
+ catch (Exception exc)
+ {
+ lgError($"Errore in costruzione jsonPayload:{Environment.NewLine}{exc}");
+ }
+ }
+ else
+ {
+ evData currData = new evData();
+ evJsonPayload fullObj = new evJsonPayload();
+ fullObj.eventList = new List();
+ string[] valori;
+ int counter = 0;
+ DateTime dtEve = DateTime.Now;
+ // inizio processando ogni valore
+ foreach (var item in elencoValori)
+ {
+ valori = qDecodeIN(item);
+ //DateTime.TryParse(valori[0], out dtEve);
+ CultureInfo provider = CultureInfo.InvariantCulture;
+ DateTime.TryParseExact(valori[0], "yyyyMMddHHmmssfff", provider, DateTimeStyles.AssumeLocal, out dtEve);
+ int.TryParse(valori[2], out counter);
+ currData = new evData()
+ {
+ valore = valori[1],
+ dtEve = dtEve,
+ dtCurr = DateTime.Now,
+ cnt = counter
+ };
+ fullObj.eventList.Add(currData);
+ }
+ // conversione finale
+ try
+ {
+ answ = JsonConvert.SerializeObject(fullObj);
+ }
+ catch (Exception exc)
+ {
+ lgError($"Errore in costruzione jsonPayload:{Environment.NewLine}{exc}");
+ }
+ }
+ }
+ return answ;
+ }
+
+ ///
+ /// Verifica e processing x gestione ODL automatica
+ ///
+ public void processAutoOdl()
+ {
+ bool fatto = false;
+ if (!string.IsNullOrEmpty(getOptPar("AUTO_CHANGE_ODL")))
+ {
+ string IOB_MULTI_CNAME = "";
+ string[] elencoMulti = null;
+ string fullUrl = "";
+ if (isMulti)
+ {
+ // devo chiamare cambio ODL x OGNI tavola: mi servono i parametri opzionali...
+ IOB_MULTI_CNAME = getOptPar("IOB_MULTI_CNAME");
+ elencoMulti = IOB_MULTI_CNAME.Split(',');
+ }
+ // controllo SIA abilitato...
+ bool doProc = false;
+ DateTime adesso = DateTime.Now;
+ bool.TryParse(getOptPar("AUTO_CHANGE_ODL"), out doProc);
+ if (doProc)
+ {
+ // carico i parametri di configurazione x reset ODL...
+ string CHANGE_ODL_HOURS = getOptPar("CHANGE_ODL_IDLE_MIN");
+ string CHANGE_ODL_IDLE_MIN = getOptPar("CHANGE_ODL_IDLE_MIN");
+ if (!string.IsNullOrEmpty(CHANGE_ODL_HOURS) && !string.IsNullOrEmpty(CHANGE_ODL_IDLE_MIN))
+ {
+ int minOdlDurHours = -1;
+ int minPlcIdelMin = -1;
+ int.TryParse(CHANGE_ODL_HOURS, out minOdlDurHours);
+ int.TryParse(CHANGE_ODL_IDLE_MIN, out minPlcIdelMin);
+ // controllo parametri validi
+ if (minOdlDurHours > 0 && minPlcIdelMin > 0)
+ {
+ // leggo da server inizio ODL... se non multi 1 solo...
+ DateTime inizioOdl = DateTime.Now;
+ string rawDataInizio = "";
+ if (!isMulti)
+ {
+ rawDataInizio = callUrl(urlInizioOdlIob, false);
+ DateTime.TryParse(rawDataInizio, out inizioOdl);
+ }
+ else
+ {
+ DateTime tmpData = DateTime.Now;
+ // prendo il + vecchio...
+ foreach (var item in elencoMulti)
+ {
+ fullUrl = $"{urlInizioOdlIob}|{item}";
+ rawDataInizio = callUrl(fullUrl, false);
+ DateTime.TryParse(rawDataInizio, out tmpData);
+ inizioOdl = (tmpData < inizioOdl) ? tmpData : inizioOdl;
+ }
+ }
+ // verifico se sia scaduto...
+ if (inizioOdl.AddHours(minOdlDurHours) < adesso)
+ {
+ string rawIdle = "";
+ int idlePeriod = 0;
+ if (!isMulti)
+ {
+ // controllo SE sono fermo (spento o in manuale) per il periodo minimo richiesto...
+ rawIdle = callUrl(urlIdleTime, false);
+ int.TryParse(rawIdle, out idlePeriod);
+ }
+ else
+ {
+ int tmpIdle = 0;
+ // prendo il + grande...
+ foreach (var item in elencoMulti)
+ {
+ fullUrl = $"{urlIdleTime}|{item}";
+ rawIdle = callUrl(fullUrl, false);
+ int.TryParse(rawIdle, out tmpIdle);
+ idlePeriod = tmpIdle > idlePeriod ? tmpIdle : idlePeriod;
+ }
+ }
+ if (idlePeriod >= minPlcIdelMin)
+ {
#if false
/***************************************************
* Descrizione procedura (OK X SIMULATORI...)
@@ -3656,1044 +3421,1279 @@ namespace IOB_WIN
fatto = (rawSplit == "OK") ? true : false;
}
#endif
- fatto = forceSplitOdl();
- lgInfo("Chiamata: processAutoOdl --> forceSplitODL");
+ fatto = forceSplitOdl();
+ lgInfo("Chiamata: processAutoOdl --> forceSplitODL");
+ }
+ }
+ }
+ }
}
- }
}
- }
- }
- }
- // loggo se fatto
- if (fatto)
- {
- lgInfo($"Effettuato processAutoOdl");
- }
- }
-
- ///
- /// Effettua processing degli allarmi CNC SE disponibili
- ///
- public void processCncAlarms()
- {
- if (utils.CRB("enableAlarms"))
- {
- Dictionary currAlarms = new Dictionary();
- if (connectionOk)
- {
- currAlarms = getCncAlarms();
- }
- else
- {
- lgError("Errore connessione mancante x getCncAlarms");
- }
- // verifico SE sia cambiato il programma...
- if (currAlarms.Count > 0)
- {
- try
- {
- if (lastAlarm != currAlarms["CNC_ALARM"])
+ // loggo se fatto
+ if (fatto)
{
- // salvo!
- lastAlarm = currAlarms["CNC_ALARM"];
- // per ogni valore del dizionario mostro ed accodo!
- string sVal = "";
- foreach (var item in currAlarms)
- {
- sVal = string.Format("[CNC_ALARM]{0}|{1}", item.Key, item.Value);
- // chiamo accodamento...
- accodaFLog(sVal, qEncodeFLog(item.Key, item.Value));
- }
+ lgInfo($"Effettuato processAutoOdl");
}
- }
- catch (Exception exc)
- {
- lgError("Eccezione in processCncAlarms{0}{1}", Environment.NewLine, exc);
- }
}
- }
- }
- ///
- /// Effettua processing contapezzi (ed eventualmente alza il bit di contapezzo...)
- ///
- public virtual void processContapezzi()
- { }
-
- ///
- /// Effettua processing del recupero delle speed (RPM, feedrate) degli assi
- ///
- public void processDynData()
- {
- bool enableByApp = utils.CRB("enableDynData");
- bool enableByIob = (getOptPar("ENABLE_DYN_DATA") == "TRUE");
- bool forceSendByIob = (getOptPar("FORCE_DYN_DATA") == "TRUE");
- Dictionary currDynData = new Dictionary();
-
- if (enableByApp || enableByIob)
- {
- lgInfo("Inizio processDynData");
- if (connectionOk)
+ ///
+ /// Effettua processing degli allarmi CNC SE disponibili
+ ///
+ public void processCncAlarms()
{
- currDynData = getDynData();
- }
- else
- {
- lgError("Errore connessione mancante x getDynData");
- }
- try
- {
- string sVal = "";
- // se richiesto send diretto...
- if (forceSendByIob)
- {
- // per ogni valore del dizionario mostro ed accodo!
- foreach (var item in currDynData)
+ if (utils.CRB("enableAlarms"))
{
- sVal = string.Format("[DYNDATA]{0}|{1}", item.Key, item.Value);
- // chiamo accodamento...
- accodaFLog(sVal, qEncodeFLog(item.Key, item.Value));
+ Dictionary currAlarms = new Dictionary();
+ if (connectionOk)
+ {
+ currAlarms = getCncAlarms();
+ }
+ else
+ {
+ lgError("Errore connessione mancante x getCncAlarms");
+ }
+ // verifico SE sia cambiato il programma...
+ if (currAlarms.Count > 0)
+ {
+ try
+ {
+ if (lastAlarm != currAlarms["CNC_ALARM"])
+ {
+ // salvo!
+ lastAlarm = currAlarms["CNC_ALARM"];
+ // per ogni valore del dizionario mostro ed accodo!
+ string sVal = "";
+ foreach (var item in currAlarms)
+ {
+ sVal = string.Format("[CNC_ALARM]{0}|{1}", item.Key, item.Value);
+ // chiamo accodamento...
+ accodaFLog(sVal, qEncodeFLog(item.Key, item.Value));
+ }
+ }
+ }
+ catch (Exception exc)
+ {
+ lgError("Eccezione in processCncAlarms{0}{1}", Environment.NewLine, exc);
+ }
+ }
}
- }
- // altrimenti verifico SE sia cambiato il valore dei DynData...
- else if (lastDynDataCtrlVal != currDynData["DYNDATA"])
- {
- // salvo!
- lastDynDataCtrlVal = currDynData["DYNDATA"];
- // per ogni valore del dizionario mostro ed accodo!
- foreach (var item in currDynData)
+ }
+
+ ///
+ /// Effettua processing contapezzi (ed eventualmente alza il bit di contapezzo...)
+ ///
+ public virtual void processContapezzi()
+ { }
+
+ ///
+ /// Effettua processing del recupero delle speed (RPM, feedrate) degli assi
+ ///
+ public void processDynData()
+ {
+ bool enableByApp = utils.CRB("enableDynData");
+ bool enableByIob = (getOptPar("ENABLE_DYN_DATA") == "TRUE");
+ bool forceSendByIob = (getOptPar("FORCE_DYN_DATA") == "TRUE");
+ Dictionary currDynData = new Dictionary();
+
+ if (enableByApp || enableByIob)
{
- sVal = string.Format("[DYNDATA]{0}|{1}", item.Key, item.Value);
- // chiamo accodamento...
- accodaFLog(sVal, qEncodeFLog(item.Key, item.Value));
+ lgInfo("Inizio processDynData");
+ if (connectionOk)
+ {
+ currDynData = getDynData();
+ }
+ else
+ {
+ lgError("Errore connessione mancante x getDynData");
+ }
+ try
+ {
+ string sVal = "";
+ // se richiesto send diretto...
+ if (forceSendByIob)
+ {
+ // per ogni valore del dizionario mostro ed accodo!
+ foreach (var item in currDynData)
+ {
+ sVal = string.Format("[DYNDATA]{0}|{1}", item.Key, item.Value);
+ // chiamo accodamento...
+ accodaFLog(sVal, qEncodeFLog(item.Key, item.Value));
+ }
+ }
+ // altrimenti verifico SE sia cambiato il valore dei DynData...
+ else if (lastDynDataCtrlVal != currDynData["DYNDATA"])
+ {
+ // salvo!
+ lastDynDataCtrlVal = currDynData["DYNDATA"];
+ // per ogni valore del dizionario mostro ed accodo!
+ foreach (var item in currDynData)
+ {
+ sVal = string.Format("[DYNDATA]{0}|{1}", item.Key, item.Value);
+ // chiamo accodamento...
+ accodaFLog(sVal, qEncodeFLog(item.Key, item.Value));
+ }
+ }
+ // salvo array...
+ lastDynData = currDynData;
+ }
+ catch (Exception exc)
+ {
+ lgError(exc, "Eccezione in processDynData");
+ }
}
- }
- // salvo array...
- lastDynData = currDynData;
- }
- catch (Exception exc)
- {
- lgError(exc, "Eccezione in processDynData");
- }
- }
- }
-
- ///
- /// Processa gestione memoria x invio dati QUANDO IOB è disconnesso da CNC...
- ///
- public void processMemoryDiscon()
- {
- // init obj display
- newDisplayData currDispData = new newDisplayData();
- // controllo contatore invio "keepalive"... invio solo a scadenza
- if (DateTime.Now.Subtract(lastDisconnCheck).TotalSeconds > utils.CRI("disconMaxSec"))
- {
- // resetto tutti i vlaori BYTE IN/PREV/OUT... così invio macchina spenta...
- B_input = 0;
- B_output = 0;
- B_previous = 0;
- accodaSigIN(ref currDispData);
- // update controllo
- lastDisconnCheck = DateTime.Now;
- }
- raiseRefresh(currDispData);
- }
-
- ///
- /// Effettua processing mode/status (EDIT/MDI/...)
- ///
- public virtual void processMode()
- { }
-
- ///
- /// Effettua processing ALTRI contatori/parametri (ed invia ad IO)
- ///
- public virtual void processOtherCounters()
- { }
-
- ///
- /// Effettua processing del recupero delle OVERRIDE (spindle, feedrate, rapid)
- ///
- public virtual void processOverride()
- {
- bool enableByApp = utils.CRB("enableOverrides");
- bool enableByIob = (getOptPar("ENABLE_OVERRIDES") == "TRUE");
- Dictionary currOverride = new Dictionary();
- if (enableByApp || enableByIob)
- {
- lgInfo("Inizio processOverride");
- if (connectionOk)
- {
- currOverride = getOverrides();
- }
- else
- {
- lgError("Errore connessione mancante x getOverrides");
}
- // SE sono connesso...
- if (connectionOk)
+ ///
+ /// Processa gestione memoria x invio dati QUANDO IOB è disconnesso da CNC...
+ ///
+ public void processMemoryDiscon()
{
- // se HO dei valori override...
- if (currOverride.Count > 0)
- {
- // verifico SE sia cambiato il programma...
- if (lastOverrideFS != currOverride["FEED_OVER"] || lastOverrideRapid != currOverride["RAPID_OVER"])
+ // init obj display
+ newDisplayData currDispData = new newDisplayData();
+ // controllo contatore invio "keepalive"... invio solo a scadenza
+ if (DateTime.Now.Subtract(lastDisconnCheck).TotalSeconds > utils.CRI("disconMaxSec"))
{
- // salvo!
- lastOverrideFS = currOverride["FEED_OVER"];
- lastOverrideRapid = currOverride["RAPID_OVER"];
- // per ogni valore del dizionario mostro ed accodo!
- string sVal = "";
- foreach (var item in currOverride)
- {
- sVal = string.Format("[OVERRIDES]{0}|{1}", item.Key, item.Value);
- // chiamo accodamento...
- accodaFLog(sVal, qEncodeFLog(item.Key, item.Value));
- }
+ // resetto tutti i vlaori BYTE IN/PREV/OUT... così invio macchina spenta...
+ B_input = 0;
+ B_output = 0;
+ B_previous = 0;
+ accodaSigIN(ref currDispData);
+ // update controllo
+ lastDisconnCheck = DateTime.Now;
}
- }
- }
- }
- }
-
- ///
- /// Classe fittizia in caso di processing task in VHF
- ///
- public virtual void processVHF()
- {
- }
-
- ///
- /// Classe fittizia in caso di processing watchdog data
- ///
- public virtual void processWhatchDog()
- {
- }
-
- ///
- /// Effettua lettura dati
- /// Parametri da aggiornare x display in form
- ///
- public virtual void readAllData(ref newDisplayData currDispData)
- {
- if (currDispData == null)
- {
- currDispData = new newDisplayData();
- }
- try
- {
- if (DemoIn)
- {
- // segnalo che sono in Demo
- currDispData.semIn = Semaforo.SV;
- }
- if (connectionOk)
- {
- readSemafori(ref currDispData);
- lastReadPLC = DateTime.Now;
- }
- else
- {
- lgError("Errore connessione mancante x readSemafori");
+ raiseRefresh(currDispData);
}
- nReadIN++;
- // aggiorno valore mostrato...
- displayRawData(ref currDispData);
- }
- catch
- {
- currDispData.semIn = Semaforo.SR;
- }
- raiseRefresh(currDispData);
- }
+ ///
+ /// Effettua processing mode/status (EDIT/MDI/...)
+ ///
+ public virtual void processMode()
+ { }
- ///
- /// Effettua lettura semafori principale
- /// Parametri da aggiornare x display in form
- ///
- public virtual void readSemafori(ref newDisplayData currDispData)
- {
- lastReadPLC = DateTime.Now;
- }
+ ///
+ /// Effettua processing ALTRI contatori/parametri (ed invia ad IO)
+ ///
+ public virtual void processOtherCounters()
+ { }
- ///
- /// metodo dummy x salvataggio aree memoria conf x CN
- ///
- /// tipo di DUMP
- public virtual void saveMemDump(dumpType tipo)
- {
- }
-
- ///
- /// Processo la coda SignalIN...
- ///
- public void svuotaCodaSignIN()
- {
- // verifico SE la coda abbia dei valori...
- if (QueueIN.Count > 0)
- {
- // invio pacchetto di dati (max da conf)
- for (int i = 0; i < nMaxSend; i++)
+ ///
+ /// Effettua processing del recupero delle OVERRIDE (spindle, feedrate, rapid)
+ ///
+ public virtual void processOverride()
{
- if (QueueIN.Count > 0)
- {
- string currVal = "";
- // se online provo
+ bool enableByApp = utils.CRB("enableOverrides");
+ bool enableByIob = (getOptPar("ENABLE_OVERRIDES") == "TRUE");
+ Dictionary currOverride = new Dictionary();
+ if (enableByApp || enableByIob)
+ {
+ lgInfo("Inizio processOverride");
+ if (connectionOk)
+ {
+ currOverride = getOverrides();
+ }
+ else
+ {
+ lgError("Errore connessione mancante x getOverrides");
+ }
+
+ // SE sono connesso...
+ if (connectionOk)
+ {
+ // se HO dei valori override...
+ if (currOverride.Count > 0)
+ {
+ // verifico SE sia cambiato il programma...
+ if (lastOverrideFS != currOverride["FEED_OVER"] || lastOverrideRapid != currOverride["RAPID_OVER"])
+ {
+ // salvo!
+ lastOverrideFS = currOverride["FEED_OVER"];
+ lastOverrideRapid = currOverride["RAPID_OVER"];
+ // per ogni valore del dizionario mostro ed accodo!
+ string sVal = "";
+ foreach (var item in currOverride)
+ {
+ sVal = string.Format("[OVERRIDES]{0}|{1}", item.Key, item.Value);
+ // chiamo accodamento...
+ accodaFLog(sVal, qEncodeFLog(item.Key, item.Value));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ ///
+ /// Classe fittizia in caso di processing task in VHF
+ ///
+ public virtual void processVHF()
+ {
+ }
+
+ ///
+ /// Classe fittizia in caso di processing watchdog data
+ ///
+ public virtual void processWhatchDog()
+ {
+ }
+
+ ///
+ /// Effettua lettura dati
+ /// Parametri da aggiornare x display in form
+ ///
+ public virtual void readAllData(ref newDisplayData currDispData)
+ {
+ if (currDispData == null)
+ {
+ currDispData = new newDisplayData();
+ }
+ try
+ {
+ if (DemoIn)
+ {
+ // segnalo che sono in Demo
+ currDispData.semIn = Semaforo.SV;
+ }
+ if (connectionOk)
+ {
+ readSemafori(ref currDispData);
+ lastReadPLC = DateTime.Now;
+ }
+ else
+ {
+ lgError("Errore connessione mancante x readSemafori");
+ }
+
+ nReadIN++;
+ // aggiorno valore mostrato...
+ displayRawData(ref currDispData);
+ }
+ catch
+ {
+ currDispData.semIn = Semaforo.SR;
+ }
+ raiseRefresh(currDispData);
+ }
+
+ ///
+ /// Effettua lettura semafori principale
+ /// Parametri da aggiornare x display in form
+ ///
+ public virtual void readSemafori(ref newDisplayData currDispData)
+ {
+ lastReadPLC = DateTime.Now;
+ }
+
+ ///
+ /// metodo dummy x salvataggio aree memoria conf x CN
+ ///
+ /// tipo di DUMP
+ public virtual void saveMemDump(dumpType tipo)
+ {
+ }
+
+ ///
+ /// Processo la coda SignalIN...
+ ///
+ public void svuotaCodaSignIN()
+ {
+ // verifico SE la coda abbia dei valori...
+ if (QueueIN.Count > 0)
+ {
+ // invio pacchetto di dati (max da conf)
+ for (int i = 0; i < nMaxSend; i++)
+ {
+ if (QueueIN.Count > 0)
+ {
+ string currVal = "";
+ // se online provo
+ if (MPOnline)
+ {
+ if (IobOnline)
+ {
+ // se ho + di 2 elementi in coda --> uso invio JSON in blocco...
+ if (QueueIN.Count > 1)
+ {
+ List listaValori = new List();
+ // se ho + di maxJsonData elementi --> invio un set di dati alla volta
+ if (QueueIN.Count > maxJsonDataEv)
+ {
+ // prendoi primi maxJsonDataValori
+ for (int j = 0; j < maxJsonDataEv; j++)
+ {
+ QueueIN.TryDequeue(out currVal);
+ listaValori.Add(currVal);
+ }
+ sendDataBlock(urlType.SignIN, listaValori);
+ }
+ else
+ {
+ // invio in blocco
+ listaValori = QueueIN.ToList();
+ // invio
+ sendDataBlock(urlType.SignIN, listaValori);
+ // svuoto!
+ QueueIN = new ConcurrentQueue();
+ }
+ }
+ else
+ {
+ // INVIO SINGOLO...!!!
+ QueueIN.TryDequeue(out currVal);
+ sendToMoonPro(urlType.SignIN, currVal);
+ }
+ // salvo come last signal in il currVal ultimo... SE !=""
+ if (!string.IsNullOrEmpty(currVal))
+ {
+ lastSignInVal = currVal;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ ///
+ /// Effettua verifica se abilitato invio pezzi in blocco e nel caso
+ /// - invio in blocco pezzi
+ /// - aggiornamento del contapezzi (passato come ref) x nuovo valore post invio
+ ///
+ public void trySendPzCountBlock()
+ {
+ // in primis HA SENSO procedere SOLO SE server MP è Online...
if (MPOnline)
{
- if (IobOnline)
- {
- // se ho + di 2 elementi in coda --> uso invio JSON in blocco...
- if (QueueIN.Count > 1)
+ // SOLO SE online la macchina...
+ if (IobOnline)
{
- List listaValori = new List();
- // se ho + di maxJsonData elementi --> invio un set di dati alla volta
- if (QueueIN.Count > maxJsonDataEv)
- {
- // prendoi primi maxJsonDataValori
- for (int j = 0; j < maxJsonDataEv; j++)
+ int numIncr = 0;
+ int qtyAdded = 0;
+ // verifico se la funzione SIA abilitata
+ if (enableSendPzCountBlock)
{
- QueueIN.TryDequeue(out currVal);
- listaValori.Add(currVal);
+ int delta = contapezziPLC - contapezziIOB;
+ // se è abilitata verifico differenza: se ho DELTA > minSendPzCountBlock --> invio un blocco <= maxSendPzCountBlock
+ if (delta > minSendPzCountBlock)
+ {
+ // init obj display
+ newDisplayData currDispData = new newDisplayData();
+ // resta indietro di ALMENO minSendPzCountBlock pezzi x recuperare 1:1...
+ numIncr = delta > maxSendPzCountBlock + minSendPzCountBlock ? maxSendPzCountBlock : delta - minSendPzCountBlock;
+ // invio il num max di pezzi ammesso in blocco!
+ lastUrl = $"{urlAddPzCount}{numIncr}";
+ string resp = utils.callUrlNow(lastUrl);
+ if (!string.IsNullOrEmpty(resp))
+ {
+ // dalla risposta (come numero) capisco SE ha aggiunto i pezzi (e quanti)
+ int.TryParse(resp, out qtyAdded);
+ if (qtyAdded > 0)
+ {
+ // aggiorno IL MIO contapezzi...
+ contapezziIOB += qtyAdded;
+ lgInfo($"Inviato incremento contapezzi: send: {numIncr} | resp: {qtyAdded} | contapezziIOB: {contapezziIOB}");
+ // invio conferma contapezzi..
+ string retVal = utils.callUrl($"{urlSetPzCount}{contapezziIOB}");
+ // verifica se tutto OK
+ if (retVal != contapezziIOB.ToString())
+ {
+ // errore salvataggio contapezzi
+ lgInfo($"trySendPzCountBlock: errore salvataggio contapezzi: contapezziIOB {contapezziIOB} | risposta: {retVal}");
+ }
+ }
+ else
+ {
+ lgError($"Richiesto incremento {numIncr} ma NON registrato su server MP-IO");
+ }
+ }
+ currDispData.newUrlCallData = lastUrl;
+ currDispData.counter = contapezziIOB;
+ currDispData.semOut = Semaforo.SV;
+ raiseRefresh(currDispData);
+ }
}
- sendDataBlock(urlType.SignIN, listaValori);
- }
- else
- {
- // invio in blocco
- listaValori = QueueIN.ToList();
- // invio
- sendDataBlock(urlType.SignIN, listaValori);
- // svuoto!
- QueueIN = new ConcurrentQueue();
- }
}
else
{
- // INVIO SINGOLO...!!!
- QueueIN.TryDequeue(out currVal);
- sendToMoonPro(urlType.SignIN, currVal);
+ lgInfo("Impossibile trySendPzCountBlock: IobOnline è false");
}
- // salvo come last signal in il currVal ultimo... SE !=""
- if (!string.IsNullOrEmpty(currVal))
- {
- lastSignInVal = currVal;
- }
- }
- else
- {
- break;
- }
}
else
{
- break;
+ lgInfo("Impossibile trySendPzCountBlock: MPOnline è false");
}
- }
- else
- {
- break;
- }
}
- }
- }
- ///
- /// Effettua verifica se abilitato invio pezzi in blocco e nel caso
- /// - invio in blocco pezzi
- /// - aggiornamento del contapezzi (passato come ref) x nuovo valore post invio
- ///
- public void trySendPzCountBlock()
- {
- // in primis HA SENSO procedere SOLO SE server MP è Online...
- if (MPOnline)
- {
- // SOLO SE online la macchina...
- if (IobOnline)
+ ///
+ /// Formatta URL x invio in DataBlock Json dei dati FLog / eventi
+ ///
+ ///
+ ///
+ public string urlDataBlock(urlType tipoUrl)
{
- int numIncr = 0;
- int qtyAdded = 0;
- // verifico se la funzione SIA abilitata
- if (enableSendPzCountBlock)
- {
- int delta = contapezziPLC - contapezziIOB;
- // se è abilitata verifico differenza: se ho DELTA > minSendPzCountBlock --> invio un blocco <= maxSendPzCountBlock
- if (delta > minSendPzCountBlock)
+ // verifico la parte di link "tipoComando"
+ string tipoComando = tipoUrl == urlType.FLog ? cIobConf.serverData.CMDFLOG_JSON : cIobConf.serverData.CMDBASE_JSON;
+ // URL base x input
+ string answ = string.Format(@"http://{0}{1}{2}{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, tipoComando, cIobConf.codIOB);
+ return answ;
+ }
+
+ ///
+ /// Fornisce URL di tipo FluxLog
+ ///
+ /// valore salvato in coda nel formato dtEve#flux#valore#counter
+ ///
+ public string urlFLog(string queueVal)
+ {
+ // URL base x input
+ string answ = string.Format(@"http://{0}{1}{2}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDFLOG);
+ // decodifica valore!
+ string[] valori = qDecodeIN(queueVal);
+ // aggiungo macchina e valore...
+ answ += string.Format(@"{0}?flux={1}&&valore={2}", cIobConf.codIOB, valori[1], valori[2]);
+ // aggiondo dataOra evento e corrente + contatore...
+ answ += string.Format(@"&&dtEve={0}&&dtCurr={1:yyyyMMddHHmmssfff}&&cnt={2}", valori[0], DateTime.Now, valori[3]);
+ return answ;
+ }
+
+ ///
+ /// Fornisce URL INPUT per i parametri richiesti
+ ///
+ /// valore salvato in coda formato dtEve#valore#counter
+ ///
+ public string urlInput(string queueVal)
+ {
+ // URL base x input
+ string answ = string.Format(@"http://{0}{1}{2}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDBASE);
+ // decodifica valore!
+ string[] valori = qDecodeIN(queueVal);
+ // aggiungo macchina e valore...
+ answ += string.Format(@"{0}?valore={1}", cIobConf.codIOB, valori[1]);
+ // aggiondo dataOra evento e corrente + contatore...
+ answ += string.Format(@"&&dtEve={0}&&dtCurr={1:yyyyMMddHHmmssfff}&&cnt={2}", valori[0], DateTime.Now, valori[2]);
+ return answ;
+ }
+
+ ///
+ /// Esegue filtraggio dati x bit blinking!!!
+ ///
+ private void filterData()
+ {
+ // effettuo filtraggio dei valori letti... inizializzo OUT!
+ B_output = 0;
+ // in primis verifico SE ci siano bit blinkng... se non ci sono OUT=IN...
+ if (cIobConf.BLINK_FILT == 0)
{
- // init obj display
- newDisplayData currDispData = new newDisplayData();
- // resta indietro di ALMENO minSendPzCountBlock pezzi x recuperare 1:1...
- numIncr = delta > maxSendPzCountBlock + minSendPzCountBlock ? maxSendPzCountBlock : delta - minSendPzCountBlock;
- // invio il num max di pezzi ammesso in blocco!
- lastUrl = $"{urlAddPzCount}{numIncr}";
- string resp = utils.callUrlNow(lastUrl);
- if (!string.IsNullOrEmpty(resp))
- {
- // dalla risposta (come numero) capisco SE ha aggiunto i pezzi (e quanti)
- int.TryParse(resp, out qtyAdded);
- if (qtyAdded > 0)
+ B_output = B_input;
+ }
+ else
+ {
+ // incomincio con i valori NON blinking: questi "passano invariati", inizio a sommare nel valore OUT...
+ B_output = B_input & ~cIobConf.BLINK_FILT;
+ // calcolo il valore dei BIT che "passano la maschera"
+ int iBlink = B_input & cIobConf.BLINK_FILT;
+ // ...aggiungo i "bit che passano"
+ B_output += iBlink;
+
+ // calcolo QUALI valori (tra quelli blink) siano PASSATI da 0 a 1 --> init counters...
+ BitArray bBlinkStart = new BitArray(new byte[] { Convert.ToByte(iBlink) });
+ int[] bitsUp = bBlinkStart.Cast().Select(bit => bit ? 1 : 0).ToArray();
+ for (int i = 0; i < bitsUp.Length; i++)
{
- // aggiorno IL MIO contapezzi...
- contapezziIOB += qtyAdded;
- lgInfo($"Inviato incremento contapezzi: send: {numIncr} | resp: {qtyAdded} | contapezziIOB: {contapezziIOB}");
- // invio conferma contapezzi..
- string retVal = utils.callUrl($"{urlSetPzCount}{contapezziIOB}");
- // verifica se tutto OK
- if (retVal != contapezziIOB.ToString())
- {
- // errore salvataggio contapezzi
- lgInfo($"trySendPzCountBlock: errore salvataggio contapezzi: contapezziIOB {contapezziIOB} | risposta: {retVal}");
- }
+ // SE 1... impostiamo contatori al MAX
+ if (bitsUp[i] == 1)
+ {
+ // se era zero indico START blink...
+ if (i_counters[i] == 0)
+ {
+ lgInfo("START BLINK: B{0}", i);
+ }
+ // imposto comunque contatore al cambio fronte...
+ i_counters[i] = cIobConf.MAX_COUNTER_BLINK;
+ }
+ }
+
+ // quelli che sono zero... LI RECUPERO E LI PROCESSO...
+ int iZero = ~B_input & cIobConf.BLINK_FILT;
+ BitArray bBlinkEnd = new BitArray(new byte[] { Convert.ToByte(iZero) });
+ int[] bitsDown = bBlinkEnd.Cast().Select(bit => bit ? 1 : 0).ToArray();
+ for (int i = 0; i < bitsDown.Length; i++)
+ {
+ // se era a zero (invertito...)
+ if (bitsDown[i] == 1)
+ {
+ // SE è in corso il conteggio...
+ if (i_counters[i] > 0)
+ {
+ // decremento!
+ i_counters[i] -= 1;
+ // se è zero NON faccio nulla, altrimenti SOMMO...
+ if (i_counters[i] > 0)
+ {
+ B_output += 1 << i;
+ }
+ else
+ {
+ lgInfo("END BLINK: B{0}", i);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ ///
+ /// Classe fittizia in caso di processing GLOBALE di tutto in 1 solo colpo...
+ ///
+ private void processAllMemory()
+ {
+ // init obj display
+ newDisplayData currDispData = new newDisplayData();
+ // in primis SALVO valori previous/precedenti
+ B_previous = B_output;
+ // poi faccio lettura NUOVI valori
+ readAllData(ref currDispData);
+ // eseguo il filtering dei valori (per i bit "blinking")
+ filterData();
+ // effettuo confronto valori vecchi/nuovi... SE trovo variazione OPPURE se è passato + di un timeout di controllo...
+ if (B_output != B_previous)
+ {
+ accodaSigIN(ref currDispData);
+ }
+ raiseRefresh(currDispData);
+ }
+
+ ///
+ /// Effettua gestioen programma: legge e mostra su display...
+ ///
+ private void processProgram()
+ {
+ string currPrgName = "";
+ // se abilitata lettura prgName
+ if (enablePrgName)
+ {
+ if (connectionOk)
+ {
+ currPrgName = getPrgName();
}
else
{
- lgError($"Richiesto incremento {numIncr} ma NON registrato su server MP-IO");
+ lgError("Errore connessione mancante x getPrgName");
}
- }
- currDispData.newUrlCallData = lastUrl;
- currDispData.counter = contapezziIOB;
- currDispData.semOut = Semaforo.SV;
- raiseRefresh(currDispData);
}
- }
- }
- else
- {
- lgInfo("Impossibile trySendPzCountBlock: IobOnline è false");
- }
- }
- else
- {
- lgInfo("Impossibile trySendPzCountBlock: MPOnline è false");
- }
- }
-
- ///
- /// Formatta URL x invio in DataBlock Json dei dati FLog / eventi
- ///
- ///
- ///
- public string urlDataBlock(urlType tipoUrl)
- {
- // verifico la parte di link "tipoComando"
- string tipoComando = tipoUrl == urlType.FLog ? cIobConf.serverData.CMDFLOG_JSON : cIobConf.serverData.CMDBASE_JSON;
- // URL base x input
- string answ = string.Format(@"http://{0}{1}{2}{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, tipoComando, cIobConf.codIOB);
- return answ;
- }
-
- ///
- /// Fornisce URL di tipo FluxLog
- ///
- /// valore salvato in coda nel formato dtEve#flux#valore#counter
- ///
- public string urlFLog(string queueVal)
- {
- // URL base x input
- string answ = string.Format(@"http://{0}{1}{2}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDFLOG);
- // decodifica valore!
- string[] valori = qDecodeIN(queueVal);
- // aggiungo macchina e valore...
- answ += string.Format(@"{0}?flux={1}&&valore={2}", cIobConf.codIOB, valori[1], valori[2]);
- // aggiondo dataOra evento e corrente + contatore...
- answ += string.Format(@"&&dtEve={0}&&dtCurr={1:yyyyMMddHHmmssfff}&&cnt={2}", valori[0], DateTime.Now, valori[3]);
- return answ;
- }
-
- ///
- /// Fornisce URL INPUT per i parametri richiesti
- ///
- /// valore salvato in coda formato dtEve#valore#counter
- ///
- public string urlInput(string queueVal)
- {
- // URL base x input
- string answ = string.Format(@"http://{0}{1}{2}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDBASE);
- // decodifica valore!
- string[] valori = qDecodeIN(queueVal);
- // aggiungo macchina e valore...
- answ += string.Format(@"{0}?valore={1}", cIobConf.codIOB, valori[1]);
- // aggiondo dataOra evento e corrente + contatore...
- answ += string.Format(@"&&dtEve={0}&&dtCurr={1:yyyyMMddHHmmssfff}&&cnt={2}", valori[0], DateTime.Now, valori[2]);
- return answ;
- }
-
- #endregion IOB METHODS
-
- #region gestione VC e postprocessing
-
- ///
- /// Recupera la VC x TS, svuotando lista e resettando periodo partenza
- ///
- /// Nome della VC
- /// Reimposta e resetta array VC
- ///
- public double getVal_TSVC(string VCName, bool doReset)
- {
- double answ = 0;
- // cerco VC...
- if (TSVC_Data.ContainsKey(VCName))
- {
- // !!!FARE!!! vero calcolo... x ora FIX a MAX...
- foreach (var item in TSVC_Data[VCName].dataArray)
- {
- answ = item > answ ? item : answ;
- }
- // ora resetto... SE richiesto...
- if (doReset)
- {
- TSVC_Data[VCName].dataArray = new List();
- TSVC_Data[VCName].DTStart = DateTime.Now;
- }
- }
- return answ;
- }
-
- ///
- /// Recupera la VC x TS, svuotando lista e resettando periodo partenza
- ///
- /// Nome della VC
- /// Reimposta e resetta array VC
- ///
- public int getVal_TSVC_int(string VCName, bool doReset)
- {
- int answ = 0;
- // cerco VC...
- if (TSVC_Data.ContainsKey(VCName))
- {
- // !!!FARE!!! vero calcolo... x ora FIX a MAX...
- foreach (var item in TSVC_Data[VCName].dataArray)
- {
- answ = (int)item > answ ? (int)item : answ;
- }
- // ora resetto... SE richiesto..
- if (doReset)
- {
- TSVC_Data[VCName].dataArray = new List();
- TSVC_Data[VCName].DTStart = DateTime.Now;
- }
- }
- return answ;
- }
-
- ///
- /// Processa un monitoredItem, e ritorna boolean SE richiede invio (cambio o scadenza)
- ///
- ///
- ///
- ///
- public bool monItem2Send(string newVal, DynDataItem item)
- {
- bool answ = false;
- if (item != null)
- {
- // controllo in base al tipo di function...
- switch (item.func)
- {
- case "SAMPLE":
- // controllo se scaduto sample period...
- if (item.DTScad < DateTime.Now)
+ else
{
- answ = true;
+ currPrgName = lastPrgName;
}
- break;
-
- case "CHANGE":
- default:
- // controllo se scaduto o se variato...
- if (newVal != item.actVal || item.DTScad < DateTime.Now)
+ // verifico SE sia cambiato il programma...
+ if (lastPrgName != currPrgName)
{
- // aggiorno scadenza e che vada inviato
- answ = true;
+ // salvo!
+ lastPrgName = currPrgName;
+ string sVal = string.Format("[PROG]{0}", currPrgName);
+
+ // chiamo accodamento...
+ accodaFLog(sVal, qEncodeFLog("PROG", currPrgName));
}
- break;
}
- }
- return answ;
- }
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public void saveValue(ref Dictionary outVal, double valore, string chiave)
- {
- //check obj preliminare
- if (outVal == null)
- {
- outVal = new Dictionary();
- }
- bool scaduto = stackVal_TSVC(chiave, valore);
- // recupero VC
- valore = getVal_TSVC(chiave, scaduto);
- if (scaduto)
- {
- outVal.Add(chiave, $"{valore}");
- }
- LastTSVC[chiave] = valore;
- }
-
- ///
- /// Processing di Variabili Campionarie x TimeSeries, accoda valori x la VC (se esiste) e restituisce bool val se SCADUTO periodo controllo
- ///
- /// Nome della VC
- /// Valore (nuovo) delal VC
- ///
- public bool stackVal_TSVC(string VCName, double VCVal)
- {
- bool answ = false;
- // cerco VC...
- if (TSVC_Data.ContainsKey(VCName))
- {
- TSVC_Data[VCName].dataArray.Add(VCVal);
- // ora verifico scadenza...
- if (TSVC_Data[VCName].DTStart.AddSeconds(TSVC_Data[VCName].Period) < DateTime.Now)
+ ///
+ /// Processo lettura dati sysinfo
+ ///
+ private void processSysInfo()
{
- answ = true;
- }
- }
- return answ;
- }
-
- #endregion gestione VC e postprocessing
-
- #region gestione code (accumulo, invio)
-
- ///
- /// Fornisce il valore letto da BITMAP in formato valido x messa in coda nel formato dtEve#value#cont
- ///
- protected string qEncodeIN
- {
- get
- {
- string answ = "";
- try
- {
- answ = string.Format("{0:yyyyMMddHHmmssfff}#{1:X2}#{2}", DateTime.Now, B_output, counterSigIN);
- }
- catch
- { }
- return answ;
- }
- }
-
- ///
- /// Decodifica valore della coda IN nel formato
- /// answ[0]=dtEve
- /// answ[1]=valore
- /// answ[2]=counter
- ///
- /// dtEve + '#' + value + '#' + cont
- ///
- protected static string[] qDecodeIN(string queueVal)
- {
- string[] answ = null;
- if (!string.IsNullOrEmpty(queueVal))
- {
- try
- {
- answ = queueVal.Split('#');
- }
- catch
- { }
- }
- return answ;
- }
-
- ///
- /// Accumula in coda i valori ALARM e logga...
- ///
- /// VALORE RAW (x display)
- /// VALORE già processato con qEncodeFLog(...)
- public void accodaAlarmLog(string val, string encodedVal)
- {
- // mostro dati variati letti...
- displayOtherData(val);
- // accodo IN PRIMIS al FluxLog --> accodo (valore già formattato)!
- QueueFLog.Enqueue(encodedVal);
- // accodo ANCHE alla coda allarmi che trasmetterò SOLO SE a scadenza impostata (10 sec?) ho allarmi perdurati...
-
- // loggo!
- lgInfo(string.Format("[QUEUE-ALARM-LOG] {0}", encodedVal));
- counterFLog++;
- if (counterFLog > 9999)
- {
- counterFLog = 0;
- }
- }
-
- ///
- /// Accumula in coda i valori Flux Log e logga...
- ///
- /// VALORE RAW (x display)
- /// VALORE già processato con qEncodeFLog(...)
- public void accodaFLog(string val, string encodedVal)
- {
- // mostro dati variati letti...
- displayOtherData(val);
- // --> accodo (valore già formattato)!
- QueueFLog.Enqueue(encodedVal);
- // se abilitato controllo coda FLog (superiore a 0...)
- if (maxQueueFLog > 0)
- {
- // se ho una coda superiore a max ammesso
- if (QueueFLog.Count > maxQueueFLog)
- {
- // elimino valori iniziali fino a tornare al max ammesso...
- while (QueueFLog.Count > maxQueueFLog)
- {
- string currVal = "";
- QueueFLog.TryDequeue(out currVal);
- lgInfo($"Eliminazione ca coda FLog per superamento maxLengh: {currVal}");
- }
- }
- }
- // loggo!
- lgInfo(string.Format("[QUEUE-FLOG] {0}", encodedVal));
- counterFLog++;
- if (counterFLog > 9999)
- {
- counterFLog = 0;
- }
- }
-
- ///
- /// Accumula in coda i valori Signal IN e logga...
- /// Parametri da aggiornare x display in form
- ///
- public void accodaSigIN(ref newDisplayData currDispData)
- {
- // mostro dati variati letti...
- displayInData(ref currDispData);
- // --> accodo (valore già formattato)!
- QueueIN.Enqueue(qEncodeIN);
- // loggo!
- lgInfo(string.Format("[QUEUE-IN] {0}", qEncodeIN));
- // aggiorno counters ed eventuale reset
- nReadFilt++;
- if (nReadFilt > int.MaxValue - 1)
- {
- nReadFilt = 0; // per evitare buffer overflow...
- }
-
- counterSigIN++;
- if (counterSigIN > 9999)
- {
- counterSigIN = 0;
- }
- }
-
- ///
- /// Fornisce il valore di flusso e valore in formato valido x messa in coda nel formato dtEve#flux#value#cont
- /// Flusso dati
- /// Valore da salvare
- ///
- public string qEncodeFLog(string flusso, string valore)
- {
- string answ = "";
- try
- {
- answ = string.Format("{0:yyyyMMddHHmmssfff}#{1}#{2}#{3}", DateTime.Now, flusso, valore, counterFLog);
- }
- catch
- { }
- return answ;
- }
-
- ///
- /// Fornisce il valore di flusso e valore in formato valido x messa in coda nel formato dtEve#flux#value#cont
- /// DataOra evento registrato
- /// Flusso dati
- /// Valore da salvare
- ///
- public string qEncodeFLog(DateTime eventDT, string flusso, string valore)
- {
- string answ = "";
- try
- {
- answ = string.Format("{0:yyyyMMddHHmmssfff}#{1}#{2}#{3}", eventDT, flusso, valore, counterFLog);
- }
- catch
- { }
- return answ;
- }
-
- ///
- /// Invia una LISTA di valori
- ///
- ///
- ///
- public void sendDataBlock(urlType tipoUrl, List listQueueVal)
- {
- // init obj display
- newDisplayData currDispData = new newDisplayData();
- if (listQueueVal != null)
- {
- try
- {
- // recupero e formatto URL dati da coda...
- lastUrl = urlDataBlock(tipoUrl);
- // in base al tipo di dato compongo il payload Json da inviare
- string payload = jsonPayload(tipoUrl, listQueueVal);
- // async a true SE FLog
- bool doAsync = tipoUrl == urlType.FLog ? true : false;
- // se NON sono in demo effettuo invio!
- if (!DemoOut)
- {
- // SE server alive...
- if (checkServerAlive)
+ if (utils.CRB("enableSysInfo"))
{
- // chiamo URL!
- string answ = callUrlWithPayload(lastUrl, payload, doAsync);
- // loggo!
- lgInfo($"[SEND payload] TipoURL: {tipoUrl} | {listQueueVal.Count} records --> {answ}");
- // se "OK" verde, altrimenti errore --> ROSSO
- if (answ.Contains("OK"))
- {
- currDispData.semOut = Semaforo.SV;
- // se oltre 1 min NON era online --> check pezzi!
- if (DateTime.Now.Subtract(lastIobOnline).TotalMinutes > 1 && !isMulti)
+ Dictionary currSysInfo = new Dictionary();
+
+ if (connectionOk)
{
- lgInfo($"sendDataBlock --> offline timeout ({lastIobOnline}) --> pzCntReload(true)");
- pzCntReload(true);
+ currSysInfo = getSysInfo();
+ }
+ else
+ {
+ lgError("Errore connessione mancante x getSysInfo");
+ }
+ // verifico SE sia cambiato il programma...
+ if (lastSysInfo != currSysInfo["SYSINFO"])
+ {
+ // salvo!
+ lastSysInfo = currSysInfo["SYSINFO"];
+ // per ogni valore del dizionario mostro ed accodo!
+ string sVal = "";
+ foreach (var item in currSysInfo)
+ {
+ sVal = string.Format("[SYSINFO]{0}|{1}", item.Key, item.Value);
+ // chiamo accodamento...
+ accodaFLog(sVal, qEncodeFLog(item.Key, item.Value));
+ }
}
- lastIobOnline = DateTime.Now;
- }
- else
- {
- currDispData.semOut = Semaforo.SR;
- }
}
- else
+ }
+
+ ///
+ /// Processo la coda FLog...
+ ///
+ private void svuotaCodaFLog()
+ {
+ //controllo se è passato oltre watchdog e non ho inviato nulla --> RE-INVIO (ultimo inviato)!!!!
+ if (DateTime.Now.Subtract(lastWatchDog).TotalSeconds > utils.CRI("watchdogMaxSec"))
{
- lgInfo($"[SERVER KO] {listQueueVal.Count}");
+ string wdStatus = "elapsed";
+ string sVal = string.Format("[WDST]{0}", wdStatus);
+ // chiamo accodamento...
+ accodaFLog(sVal, qEncodeFLog("WDST", wdStatus));
+ lastWatchDog = DateTime.Now;
}
- }
- else
- {
- currDispData.semOut = Semaforo.SV;
+ // verifico SE la coda abbia dei valori...
+ if (QueueFLog.Count > 0)
+ {
+ // invio pacchetto di dati (max da conf)
+ for (int i = 0; i < nMaxSend; i++)
+ {
+ // SE ho qualcosa in coda...
+ if (QueueFLog.Count > 0)
+ {
+ string currVal = "";
+ if (MPOnline)
+ {
+ if (IobOnline)
+ {
+ // se ho + di 2 elementi in coda --> uso invio JSON in blocco...
+ if (QueueFLog.Count > 1)
+ {
+ List listaValori = new List();
+ // se ho + di maxJsonData elementi --> invio un set di dati alla volta
+ if (QueueFLog.Count > maxJsonData)
+ {
+ // prendoi primi maxJsonDataValori
+ for (int j = 0; j < maxJsonData; j++)
+ {
+ QueueFLog.TryDequeue(out currVal);
+ listaValori.Add(currVal);
+ }
+ sendDataBlock(urlType.FLog, listaValori);
+ }
+ else
+ {
+ // invio in blocco
+ listaValori = QueueFLog.ToList();
+ // invio
+ sendDataBlock(urlType.FLog, listaValori);
+ // svuoto!
+ QueueFLog = new ConcurrentQueue();
+ }
+ }
+ else
+ {
+ // INVIO SINGOLO...!!!
+ QueueFLog.TryDequeue(out currVal);
+ sendToMoonPro(urlType.FLog, currVal);
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ #endregion IOB METHODS
+
+ #region gestione VC e postprocessing
+
+ ///
+ /// Recupera la VC x TS, svuotando lista e resettando periodo partenza
+ ///
+ /// Nome della VC
+ /// Reimposta e resetta array VC
+ ///
+ public double getVal_TSVC(string VCName, bool doReset)
+ {
+ double answ = 0;
+ // cerco VC...
+ if (TSVC_Data.ContainsKey(VCName))
+ {
+ // !!!FARE!!! vero calcolo... x ora FIX a MAX...
+ foreach (var item in TSVC_Data[VCName].dataArray)
+ {
+ answ = item > answ ? item : answ;
+ }
+ // ora resetto... SE richiesto...
+ if (doReset)
+ {
+ TSVC_Data[VCName].dataArray = new List();
+ TSVC_Data[VCName].DTStart = DateTime.Now;
+ }
+ }
+ return answ;
+ }
+
+ ///
+ /// Recupera la VC x TS, svuotando lista e resettando periodo partenza
+ ///
+ /// Nome della VC
+ /// Reimposta e resetta array VC
+ ///
+ public int getVal_TSVC_int(string VCName, bool doReset)
+ {
+ int answ = 0;
+ // cerco VC...
+ if (TSVC_Data.ContainsKey(VCName))
+ {
+ // !!!FARE!!! vero calcolo... x ora FIX a MAX...
+ foreach (var item in TSVC_Data[VCName].dataArray)
+ {
+ answ = (int)item > answ ? (int)item : answ;
+ }
+ // ora resetto... SE richiesto..
+ if (doReset)
+ {
+ TSVC_Data[VCName].dataArray = new List();
+ TSVC_Data[VCName].DTStart = DateTime.Now;
+ }
+ }
+ return answ;
+ }
+
+ ///
+ /// Processa un monitoredItem, e ritorna boolean SE richiede invio (cambio o scadenza)
+ ///
+ ///
+ ///
+ ///
+ public bool monItem2Send(string newVal, DynDataItem item)
+ {
+ bool answ = false;
+ if (item != null)
+ {
+ // controllo in base al tipo di function...
+ switch (item.func)
+ {
+ case "SAMPLE":
+ // controllo se scaduto sample period...
+ if (item.DTScad < DateTime.Now)
+ {
+ answ = true;
+ }
+ break;
+
+ case "CHANGE":
+ default:
+ // controllo se scaduto o se variato...
+ if (newVal != item.actVal || item.DTScad < DateTime.Now)
+ {
+ // aggiorno scadenza e che vada inviato
+ answ = true;
+ }
+ break;
+ }
+ }
+ return answ;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void saveValue(ref Dictionary outVal, double valore, string chiave)
+ {
+ //check obj preliminare
+ if (outVal == null)
+ {
+ outVal = new Dictionary();
+ }
+ bool scaduto = stackVal_TSVC(chiave, valore);
+ // recupero VC
+ valore = getVal_TSVC(chiave, scaduto);
+ if (scaduto)
+ {
+ outVal.Add(chiave, $"{valore}");
+ }
+ LastTSVC[chiave] = valore;
+ }
+
+ ///
+ /// Processing di Variabili Campionarie x TimeSeries, accoda valori x la VC (se esiste) e restituisce bool val se SCADUTO periodo controllo
+ ///
+ /// Nome della VC
+ /// Valore (nuovo) delal VC
+ ///
+ public bool stackVal_TSVC(string VCName, double VCVal)
+ {
+ bool answ = false;
+ // cerco VC...
+ if (TSVC_Data.ContainsKey(VCName))
+ {
+ TSVC_Data[VCName].dataArray.Add(VCVal);
+ // ora verifico scadenza...
+ if (TSVC_Data[VCName].DTStart.AddSeconds(TSVC_Data[VCName].Period) < DateTime.Now)
+ {
+ answ = true;
+ }
+ }
+ return answ;
+ }
+
+ #endregion gestione VC e postprocessing
+
+ #region gestione code (accumulo, invio)
+
+ ///
+ /// Fornisce il valore letto da BITMAP in formato valido x messa in coda nel formato dtEve#value#cont
+ ///
+ protected string qEncodeIN
+ {
+ get
+ {
+ string answ = "";
+ try
+ {
+ answ = string.Format("{0:yyyyMMddHHmmssfff}#{1:X2}#{2}", DateTime.Now, B_output, counterSigIN);
+ }
+ catch
+ { }
+ return answ;
+ }
+ }
+
+ ///
+ /// Accumula in coda i valori ALARM e logga...
+ ///
+ /// VALORE RAW (x display)
+ /// VALORE già processato con qEncodeFLog(...)
+ public void accodaAlarmLog(string val, string encodedVal)
+ {
+ // mostro dati variati letti...
+ displayOtherData(val);
+ // accodo IN PRIMIS al FluxLog --> accodo (valore già formattato)!
+ QueueFLog.Enqueue(encodedVal);
+ // accodo ANCHE alla coda allarmi che trasmetterò SOLO SE a scadenza impostata (10 sec?) ho allarmi perdurati...
+
// loggo!
- lgInfo($"{listQueueVal.Count} records --> [SIM]");
- }
- nSendOut += listQueueVal.Count;
- // riporto cosa inviato
- currDispData.newUrlCallData = lastUrl;
- // aggiorno data ultimo watchdog...
- lastWatchDog = DateTime.Now;
+ lgInfo(string.Format("[QUEUE-ALARM-LOG] {0}", encodedVal));
+ counterFLog++;
+ if (counterFLog > 9999)
+ {
+ counterFLog = 0;
+ }
}
- catch
- {
- currDispData.semOut = Semaforo.SR;
- }
- }
- raiseRefresh(currDispData);
- }
- ///
- /// Effettua invio a MoonPro del valore richiesto
- ///
- ///
- /// Valore da trasmettere: es
- /// INPUT: lo status rilevato in HEX
- /// FLog: il valore da trasmettere per il flusso indicato
- public void sendToMoonPro(urlType tipoUrl, string queueVal)
- {
- // init obj display
- newDisplayData currDispData = new newDisplayData();
- try
- {
- // recupero e formatto URL dati da coda...
- switch (tipoUrl)
+ ///
+ /// Accumula in coda i valori Flux Log e logga...
+ ///
+ /// VALORE RAW (x display)
+ /// VALORE già processato con qEncodeFLog(...)
+ public void accodaFLog(string val, string encodedVal)
{
- case urlType.FLog:
- lastUrl = urlFLog(queueVal);
- break;
-
- case urlType.SignIN:
- lastUrl = urlInput(queueVal);
- break;
-
- default:
- lastUrl = "";
- break;
- }
- // se NON sono in demo effettuo invio!
- if (!DemoOut)
- {
- // SE server alive...
- if (checkServerAlive)
- {
- // chiamo URL!
- string answ = callUrl(lastUrl, false);
+ // mostro dati variati letti...
+ displayOtherData(val);
+ // --> accodo (valore già formattato)!
+ QueueFLog.Enqueue(encodedVal);
+ // se abilitato controllo coda FLog (superiore a 0...)
+ if (maxQueueFLog > 0)
+ {
+ // se ho una coda superiore a max ammesso
+ if (QueueFLog.Count > maxQueueFLog)
+ {
+ // elimino valori iniziali fino a tornare al max ammesso...
+ while (QueueFLog.Count > maxQueueFLog)
+ {
+ string currVal = "";
+ QueueFLog.TryDequeue(out currVal);
+ lgInfo($"Eliminazione ca coda FLog per superamento maxLengh: {currVal}");
+ }
+ }
+ }
// loggo!
- lgInfo(string.Format("[SEND] {0} -> {1}", queueVal, answ));
- // se oltre 1 min NON era online --> check pezzi!
- if (DateTime.Now.Subtract(lastIobOnline).TotalMinutes > 1 && !isMulti)
+ lgInfo(string.Format("[QUEUE-FLOG] {0}", encodedVal));
+ counterFLog++;
+ if (counterFLog > 9999)
{
- lgInfo($"sendToMoonPro --> offline timeaout ({lastIobOnline}) --> pzCntReload(true)");
- pzCntReload(true);
+ counterFLog = 0;
}
- // se richiesto effettuo refresh contapezzi
- if (needRefreshPzCount && !isMulti)
- {
- pzCntReload(true);
- needRefreshPzCount = false;
- }
- lastIobOnline = DateTime.Now;
- // se "OK" verde, altrimenti errore --> ROSSO
- if (answ == "OK")
- {
- currDispData.semOut = Semaforo.SV;
- }
- else
- {
- currDispData.semOut = Semaforo.SR;
- }
- }
- else
- {
- lgInfo(string.Format("[SERVER KO] {0}", queueVal));
- }
}
- else
+
+ ///
+ /// Accumula in coda i valori Signal IN e logga...
+ /// Parametri da aggiornare x display in form
+ ///
+ public void accodaSigIN(ref newDisplayData currDispData)
{
- currDispData.semOut = Semaforo.SV;
- // loggo!
- lgInfo(string.Format("{0} -> [SIM]", queueVal));
+ // mostro dati variati letti...
+ displayInData(ref currDispData);
+ // --> accodo (valore già formattato)!
+ QueueIN.Enqueue(qEncodeIN);
+ // loggo!
+ lgInfo(string.Format("[QUEUE-IN] {0}", qEncodeIN));
+ // aggiorno counters ed eventuale reset
+ nReadFilt++;
+ if (nReadFilt > int.MaxValue - 1)
+ {
+ nReadFilt = 0; // per evitare buffer overflow...
+ }
+
+ counterSigIN++;
+ if (counterSigIN > 9999)
+ {
+ counterSigIN = 0;
+ }
}
- nSendOut++;
- // riporto cosa inviato
+
+ ///
+ /// Fornisce il valore di flusso e valore in formato valido x messa in coda nel formato dtEve#flux#value#cont
+ /// Flusso dati
+ /// Valore da salvare
+ ///
+ public string qEncodeFLog(string flusso, string valore)
+ {
+ string answ = "";
+ try
+ {
+ answ = string.Format("{0:yyyyMMddHHmmssfff}#{1}#{2}#{3}", DateTime.Now, flusso, valore, counterFLog);
+ }
+ catch
+ { }
+ return answ;
+ }
+
+ ///
+ /// Fornisce il valore di flusso e valore in formato valido x messa in coda nel formato dtEve#flux#value#cont
+ /// DataOra evento registrato
+ /// Flusso dati
+ /// Valore da salvare
+ ///
+ public string qEncodeFLog(DateTime eventDT, string flusso, string valore)
+ {
+ string answ = "";
+ try
+ {
+ answ = string.Format("{0:yyyyMMddHHmmssfff}#{1}#{2}#{3}", eventDT, flusso, valore, counterFLog);
+ }
+ catch
+ { }
+ return answ;
+ }
+
+ ///
+ /// Invia una LISTA di valori
+ ///
+ ///
+ ///
+ public void sendDataBlock(urlType tipoUrl, List listQueueVal)
+ {
+ // init obj display
+ newDisplayData currDispData = new newDisplayData();
+ if (listQueueVal != null)
+ {
+ try
+ {
+ // recupero e formatto URL dati da coda...
+ lastUrl = urlDataBlock(tipoUrl);
+ // in base al tipo di dato compongo il payload Json da inviare
+ string payload = jsonPayload(tipoUrl, listQueueVal);
+ // async a true SE FLog
+ bool doAsync = tipoUrl == urlType.FLog ? true : false;
+ // se NON sono in demo effettuo invio!
+ if (!DemoOut)
+ {
+ // SE server alive...
+ if (checkServerAlive)
+ {
+ // chiamo URL!
+ string answ = callUrlWithPayload(lastUrl, payload, doAsync);
+ // loggo!
+ lgInfo($"[SEND payload] TipoURL: {tipoUrl} | {listQueueVal.Count} records --> {answ}");
+ // se "OK" verde, altrimenti errore --> ROSSO
+ if (answ.Contains("OK"))
+ {
+ currDispData.semOut = Semaforo.SV;
+ // se oltre 1 min NON era online --> check pezzi!
+ if (DateTime.Now.Subtract(lastIobOnline).TotalMinutes > 1 && !isMulti)
+ {
+ lgInfo($"sendDataBlock --> offline timeout ({lastIobOnline}) --> pzCntReload(true)");
+ pzCntReload(true);
+ }
+ lastIobOnline = DateTime.Now;
+ }
+ else
+ {
+ currDispData.semOut = Semaforo.SR;
+ }
+ }
+ else
+ {
+ lgInfo($"[SERVER KO] {listQueueVal.Count}");
+ }
+ }
+ else
+ {
+ currDispData.semOut = Semaforo.SV;
+ // loggo!
+ lgInfo($"{listQueueVal.Count} records --> [SIM]");
+ }
+ nSendOut += listQueueVal.Count;
+ // riporto cosa inviato
+ currDispData.newUrlCallData = lastUrl;
+ // aggiorno data ultimo watchdog...
+ lastWatchDog = DateTime.Now;
+ }
+ catch
+ {
+ currDispData.semOut = Semaforo.SR;
+ }
+ }
+ raiseRefresh(currDispData);
+ }
+
+ ///
+ /// Effettua invio a MoonPro del valore richiesto
+ ///
+ ///
+ /// Valore da trasmettere: es
+ /// INPUT: lo status rilevato in HEX
+ /// FLog: il valore da trasmettere per il flusso indicato
+ public void sendToMoonPro(urlType tipoUrl, string queueVal)
+ {
+ // init obj display
+ newDisplayData currDispData = new newDisplayData();
+ try
+ {
+ // recupero e formatto URL dati da coda...
+ switch (tipoUrl)
+ {
+ case urlType.FLog:
+ lastUrl = urlFLog(queueVal);
+ break;
+
+ case urlType.SignIN:
+ lastUrl = urlInput(queueVal);
+ break;
+
+ default:
+ lastUrl = "";
+ break;
+ }
+ // se NON sono in demo effettuo invio!
+ if (!DemoOut)
+ {
+ // SE server alive...
+ if (checkServerAlive)
+ {
+ // chiamo URL!
+ string answ = callUrl(lastUrl, false);
+ // loggo!
+ lgInfo(string.Format("[SEND] {0} -> {1}", queueVal, answ));
+ // se oltre 1 min NON era online --> check pezzi!
+ if (DateTime.Now.Subtract(lastIobOnline).TotalMinutes > 1 && !isMulti)
+ {
+ lgInfo($"sendToMoonPro --> offline timeaout ({lastIobOnline}) --> pzCntReload(true)");
+ pzCntReload(true);
+ }
+ // se richiesto effettuo refresh contapezzi
+ if (needRefreshPzCount && !isMulti)
+ {
+ pzCntReload(true);
+ needRefreshPzCount = false;
+ }
+ lastIobOnline = DateTime.Now;
+ // se "OK" verde, altrimenti errore --> ROSSO
+ if (answ == "OK")
+ {
+ currDispData.semOut = Semaforo.SV;
+ }
+ else
+ {
+ currDispData.semOut = Semaforo.SR;
+ }
+ }
+ else
+ {
+ lgInfo(string.Format("[SERVER KO] {0}", queueVal));
+ }
+ }
+ else
+ {
+ currDispData.semOut = Semaforo.SV;
+ // loggo!
+ lgInfo(string.Format("{0} -> [SIM]", queueVal));
+ }
+ nSendOut++;
+ // riporto cosa inviato
#if false
displayOutData();
#endif
- currDispData.newUrlCallData = lastUrl;
- // aggiorno data ultimo watchdog...
- lastWatchDog = DateTime.Now;
- }
- catch
- {
- currDispData.semOut = Semaforo.SR;
- }
- raiseRefresh(currDispData);
- }
+ currDispData.newUrlCallData = lastUrl;
+ // aggiorno data ultimo watchdog...
+ lastWatchDog = DateTime.Now;
+ }
+ catch
+ {
+ currDispData.semOut = Semaforo.SR;
+ }
+ raiseRefresh(currDispData);
+ }
- #endregion gestione code (accumulo, invio)
+ ///
+ /// Decodifica valore della coda IN nel formato
+ /// answ[0]=dtEve
+ /// answ[1]=valore
+ /// answ[2]=counter
+ ///
+ /// dtEve + '#' + value + '#' + cont
+ ///
+ protected static string[] qDecodeIN(string queueVal)
+ {
+ string[] answ = null;
+ if (!string.IsNullOrEmpty(queueVal))
+ {
+ try
+ {
+ answ = queueVal.Split('#');
+ }
+ catch
+ { }
+ }
+ return answ;
+ }
- #region gestione dataMonitor (update visualizzazione valori)
+ #endregion gestione code (accumulo, invio)
- ///
- /// Mostra i dati grezzi letti in esadecimale
- /// Parametri da aggiornare x display in form
- ///
- private void displayRawData(ref newDisplayData currDispData)
- {
- // mostro update...
- string newString = string.Format("{0:X}", B_input);
- currDispData.newInData = newString;
+ #region gestione dataMonitor (update visualizzazione valori)
+
+ ///
+ /// Accoda (visualizzando in cima allo stack) la nuova stringa di output per area OTHER DATA
+ ///
+ ///
+ public void accodaOtherData(string newLine)
+ {
+ // inserisco in cima allo stack, trimmo e aggiorno display
+ string strOtherData = limitLine2show(string.Format("{0}{1}{2}", newLine, Environment.NewLine, parentForm.dataMonitor_3));
+ //parentForm.dataMonitor_3 = strOtherData;
+ parentForm.WriteTextSafe(strOtherData);
+ }
+
+ ///
+ /// Update visualizzaizone BIT in ingresso
+ /// Parametri da aggiornare x display in form
+ ///
+ public void displayInData(ref newDisplayData currDispData)
+ {
+ if (currDispData != null)
+ {
+ // mostro update...
+ string newString = string.Format("{0:0000}|{1}", counterSigIN, utils.IntToBinStr(B_output, 8));
+ currDispData.newSignalData = newString;
+ }
+ }
+
+ ///
+ /// Mostra cosa ha/avrebbe inviato
+ ///
+ ///
+ public void displayOtherData(string newData)
+ {
+ // mostro update...
+ accodaOtherData(newData);
+ }
+
+ ///
+ /// Effettua un trim della stringa al numero max di linee da mostrare a video
+ ///
+ ///
+ ///
+ public string limitLine2show(string newString)
+ {
+ // se num righe superiore a limite trimmo...
+ if (newString.Split('\n').Length > parentForm.nLine2show)
+ {
+ //int idx = newString.LastIndexOf('\r');
+ int idx = newString.LastIndexOf(Environment.NewLine);
+ newString = newString.Substring(0, idx);
+ }
+ return newString;
+ }
+
+ ///
+ /// Mostra i dati grezzi letti in esadecimale
+ /// Parametri da aggiornare x display in form
+ ///
+ private void displayRawData(ref newDisplayData currDispData)
+ {
+ // mostro update...
+ string newString = string.Format("{0:X}", B_input);
+ currDispData.newInData = newString;
#if false
// salvo coda debug...
QueueDebug.Enqueue(B_input);
#endif
+ }
+
+ #endregion gestione dataMonitor (update visualizzazione valori)
}
///
- /// Accoda (visualizzando in cima allo stack) la nuova stringa di output per area OTHER DATA
+ /// Evento per incapsulare dati x refresh pagina
///
- ///
- public void accodaOtherData(string newLine)
+ public class iobRefreshedEventArgs : EventArgs
{
- // inserisco in cima allo stack, trimmo e aggiorno display
- string strOtherData = limitLine2show(string.Format("{0}{1}{2}", newLine, Environment.NewLine, parentForm.dataMonitor_3));
- //parentForm.dataMonitor_3 = strOtherData;
- parentForm.WriteTextSafe(strOtherData);
+ #region Private Fields
+
+ ///
+ /// classe obj privata
+ ///
+ private readonly newDisplayData _newDisplayData;
+
+ #endregion Private Fields
+
+ #region Public Constructors
+
+ ///
+ /// salvataggio obj
+ ///
+ ///
+ public iobRefreshedEventArgs(newDisplayData newObject)
+ {
+ _newDisplayData = newObject;
+ }
+
+ #endregion Public Constructors
+
+ #region Public Properties
+
+ ///
+ /// Proprietà lettura displayData aggiornato
+ ///
+ public newDisplayData DisplayDataObject
+ {
+ get { return _newDisplayData; }
+ }
+
+ #endregion Public Properties
}
-
- ///
- /// Update visualizzaizone BIT in ingresso
- /// Parametri da aggiornare x display in form
- ///
- public void displayInData(ref newDisplayData currDispData)
- {
- if (currDispData != null)
- {
- // mostro update...
- string newString = string.Format("{0:0000}|{1}", counterSigIN, utils.IntToBinStr(B_output, 8));
- currDispData.newSignalData = newString;
- }
- }
-
- ///
- /// Mostra cosa ha/avrebbe inviato
- ///
- ///
- public void displayOtherData(string newData)
- {
- // mostro update...
- accodaOtherData(newData);
- }
-
- ///
- /// Effettua un trim della stringa al numero max di linee da mostrare a video
- ///
- ///
- ///
- public string limitLine2show(string newString)
- {
- // se num righe superiore a limite trimmo...
- if (newString.Split('\n').Length > parentForm.nLine2show)
- {
- //int idx = newString.LastIndexOf('\r');
- int idx = newString.LastIndexOf(Environment.NewLine);
- newString = newString.Substring(0, idx);
- }
- return newString;
- }
-
- #endregion gestione dataMonitor (update visualizzazione valori)
- }
-
- ///
- /// Evento per incapsulare dati x refresh pagina
- ///
- public class iobRefreshedEventArgs : EventArgs
- {
- #region Private Fields
-
- ///
- /// classe obj privata
- ///
- private readonly newDisplayData _newDisplayData;
-
- #endregion Private Fields
-
- #region Public Constructors
-
- ///
- /// salvataggio obj
- ///
- ///
- public iobRefreshedEventArgs(newDisplayData newObject)
- {
- _newDisplayData = newObject;
- }
-
- #endregion Public Constructors
-
- #region Public Properties
-
- ///
- /// Proprietà lettura displayData aggiornato
- ///
- public newDisplayData DisplayDataObject
- {
- get { return _newDisplayData; }
- }
-
- #endregion Public Properties
- }
}
\ No newline at end of file
diff --git a/IOB-WIN/IobSimula.cs b/IOB-WIN/IobSimula.cs
index 5e3f0fbc..e589e7bd 100644
--- a/IOB-WIN/IobSimula.cs
+++ b/IOB-WIN/IobSimula.cs
@@ -338,8 +338,6 @@ namespace IOB_WIN
// di base macchina in RUN
B_input = 3;
- // di base NON emergenza
- B_input += (1 << 7);
/*----------------------------------------
* Simulazione segnali con priorità:
@@ -429,6 +427,9 @@ namespace IOB_WIN
// questa parte la processo SOLO SE sono in run --> B_input == 3
if (B_input == 3)
{
+ // di base NON emergenza
+ B_input += (1 << 7);
+ // ora controllo il resto...
if (bit3.wait <= 0)
{
// segnalo BIT
diff --git a/Jenkinsfile b/Jenkinsfile
index 1b8f592d..ffe10d30 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -9,7 +9,7 @@ pipeline {
steps {
/* calcolo numero versione... diverso x branch MASTER/DEVELOP */
script {
- withEnv(['NEXT_BUILD_NUMBER=703']) {
+ withEnv(['NEXT_BUILD_NUMBER=704']) {
// env.versionNumber = VersionNumber(versionNumberString : '3.2.${BUILD_DATE_FORMATTED, "yyMM"}.${BUILDS_ALL_TIME}', projectStartDate : '2006-01-01', skipFailedBuilds: true)
env.versionNumber = VersionNumber(versionNumberString : '3.2.${BUILD_DATE_FORMATTED, "yyMM"}.${BUILDS_ALL_TIME}', projectStartDate : '2006-01-01', skipFailedBuilds: true, overrideBuildsAllTime: '${NEXT_BUILD_NUMBER}')
env.APP_NAME = 'MAPO-IOB-WIN'