diff --git a/CVCncLib/CVCncLib.dll b/CVCncLib/CVCncLib.dll
index 484da646..3e4e713e 100644
Binary files a/CVCncLib/CVCncLib.dll and b/CVCncLib/CVCncLib.dll differ
diff --git a/IOB-WIN/AdapterForm.cs b/IOB-WIN/AdapterForm.cs
index 1e0e8604..c19d2d92 100644
--- a/IOB-WIN/AdapterForm.cs
+++ b/IOB-WIN/AdapterForm.cs
@@ -15,7 +15,7 @@ namespace IOB_WIN
{
public partial class AdapterForm : Form
{
- #region inizializzazione contatori
+ #region Protected Fields
///
/// contatore veloce
@@ -27,6 +27,16 @@ namespace IOB_WIN
///
protected DateTime firstStart;
+ ///
+ /// Oggetto ultimo inviato stato IOB x REDIS
+ ///
+ protected IobWinStatus lastIobStatus = new IobWinStatus();
+
+ ///
+ /// Oggetto ultimo inviato stato MP-IO x REDIS
+ ///
+ protected ServerMpStatus lastSrvStatus = new ServerMpStatus();
+
///
/// ultimo tentativo riavvio...
///
@@ -52,9 +62,14 @@ namespace IOB_WIN
///
protected int verySlowCount;
- #endregion inizializzazione contatori
+ ///
+ /// Temnpo attesa std in MS
+ ///
+ protected int waitRecMSec = 30000;
- #region inizializzazione oggetti base
+ #endregion Protected Fields
+
+ #region Public Fields
///
/// oggetto logging
@@ -86,184 +101,9 @@ namespace IOB_WIN
///
public tipoAdapter tipoScelto = tipoAdapter.SIMULA;
- ///
- /// Oggetto ultimo inviato stato IOB x REDIS
- ///
- protected IobWinStatus lastIobStatus = new IobWinStatus();
+ #endregion Public Fields
- ///
- /// Oggetto ultimo inviato stato MP-IO x REDIS
- ///
- protected ServerMpStatus lastSrvStatus = new ServerMpStatus();
-
- ///
- /// Temnpo attesa std in MS
- ///
- protected int waitRecMSec = 30000;
-
- ///
- /// Codice IOB della macchina cui connettersi (x scegliere corretto file di conf...)
- ///
- protected string CurrIOB { get; set; }
-
- #endregion inizializzazione oggetti base
-
- #region utils ed helpers
-
- ///
- /// Log verboso da configurazione (SOLO CHAIVE "verbose"...
- ///
- public bool isVerboseLog { get; set; } = utils.CRB("verbose");
-
- ///
- /// Logwatcher (in modalità "accodamento in testa" ultimi messaggi...)
- ///
- public string logWatcher
- {
- get
- {
- return lblLogfile.Text;
- }
- set
- {
- try
- {
- logWatchString = limitLine2show($"{value}{Environment.NewLine}{logWatchString}");
- DateTime adesso = DateTime.Now;
- if (logWatchWriteVeto < adesso)
- {
- lblLogfile.Text = logWatchString;
- lblLogfile.Refresh();
- logWatchWriteVeto = adesso.AddMilliseconds(delayShowLogMs);
- }
- }
- catch (Exception exc)
- {
- lgError($"Errore in esecuzione logWatcher{Environment.NewLine}--> {value}");
- if (isVerboseLog)
- {
- lgError($"{exc}");
- }
- }
- }
- }
-
- ///
- /// Task watcher (in modalità "accodamento in testa" ultimi messaggi...)
- ///
- public string taskWatcher
- {
- get
- {
- return lblTaskLog.Text;
- }
- set
- {
- try
- {
- lblTaskLog.Text = limitLine2show($"{value}{Environment.NewLine}{lblTaskLog.Text}");
- lblTaskLog.Refresh();
- }
- catch (Exception exc)
- {
- lgError($"Errore in esecuzione taskWatcher{Environment.NewLine}--> {value}");
- if (isVerboseLog)
- {
- lgError($"{exc}");
- }
- }
- }
- }
-
- protected int delayShowLogMs { get; set; } = utils.CRI("delayShowLogMs");
-
- ///
- /// Stringa corrente di log...
- ///
- protected string logWatchString { get; set; } = "";
-
- ///
- /// Veto a NUOVE scritture in logWatch...
- ///
- protected DateTime logWatchWriteVeto { get; set; } = DateTime.Now;
-
- ///
- /// mostra un testo sulla status bar + LOG
- ///
- ///
- public void displayTaskAndLog(string txt2show)
- {
- lblStatus.Text = txt2show;
- lblStatus.Invalidate();
- lgInfo(txt2show);
- }
-
- ///
- /// Effettua un trim della stringa al numero max di linee da mostrare a video
- ///
- ///
- ///
- public string limitLine2show(string newString)
- {
- if (!string.IsNullOrEmpty(newString))
- {
- // se num righe superiore a limite trimmo...
- if (newString.Split('\n').Length > nLine2show)
- {
- //int idx = newString.LastIndexOf('\r');
- int idx = newString.LastIndexOf(Environment.NewLine);
- newString = newString.Substring(0, idx);
- }
- }
- return newString;
- }
-
- ///
- /// Mostra update delle statistiche di comunicazione (numero chiamate, tempo medio...)
- ///
- ///
- public void updateComStats(string txt2show)
- {
- lblComStats.Text = string.Format("{0} | ", txt2show);
- }
-
- ///
- /// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere...
- ///
- ///
- protected void lgError(string txt2log)
- {
- if (!string.IsNullOrEmpty(txt2log))
- {
- lg.Factory.Configuration.Variables["codIOB"] = this.CurrIOB;
- lg.Error(txt2log);
- // salvo anche in logwatcher... SE non si dimostra ricorsivo...
- if (!txt2log.Contains("logWatcher"))
- {
- newDisplayData currDispData = new newDisplayData();
- currDispData.newLiveLogData = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} | ERROR | {txt2log}";
- updateFormDisplay(currDispData);
- }
- }
- }
-
- ///
- /// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere...
- ///
- ///
- protected void lgInfo(string txt2log)
- {
- lg.Factory.Configuration.Variables["codIOB"] = this.CurrIOB;
- lg.Info(txt2log);
- // salvo anche in logwatcher...
- newDisplayData currDispData = new newDisplayData();
- currDispData.newLiveLogData = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} | INFO | {txt2log}";
- updateFormDisplay(currDispData);
- }
-
- #endregion utils ed helpers
-
- #region gestione form e visibilità
+ #region Public Constructors
///
/// Avvio MainForm
@@ -370,539 +210,13 @@ namespace IOB_WIN
displayTaskAndLog("Main Form OK");
}
- ///
- /// File configurazione default
- ///
- public string defConfFilePath
- {
- get
- {
- return string.Format(@"{0}\{1}.ini", utils.confDir, CurrIOB);
- }
- }
+ #endregion Public Constructors
- ///
- /// Init form (grafica) con helper x testi e varie
- ///
- protected void myGraphInitForm()
- {
- lblStatus.Text = "Loading";
-
- // aggiunta tooltip x send forzato
- ToolTip ttForceSend = new ToolTip();
-
- // imposto delay.
- ttForceSend.AutoPopDelay = 3000;
- ttForceSend.InitialDelay = 500;
- ttForceSend.ReshowDelay = 500;
- // sempre visibile (che sia o meno attiva la form).
- ttForceSend.ShowAlways = true;
-
- // imposto tooltip
- ttForceSend.SetToolTip(this.chkForceDequeue, "Forza invio eventi allo stop");
- }
-
- ///
- /// Fase chiusura Form
- ///
- ///
- ///
- private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
- {
- closeAdapter();
- }
-
- ///
- /// Completato resize form
- ///
- ///
- ///
- private void MainForm_Resize(object sender, EventArgs e)
- {
- }
-
- ///
- /// Mostrata form
- ///
- ///
- ///
- private void MainForm_Shown(object sender, EventArgs e)
- {
- displayTaskAndLog("Main Form SHOWN (Adapter)");
- }
-
- #endregion gestione form e visibilità
-
- #region gestione metodi specifici FORM
-
- ///
- /// Salva su file l'oggetto di persistenza dati
- ///
- ///
- public void savePersistLayer(string filePath)
- {
- // in primis check semaforo salvataggio...
- if (!iobObj.adpSaving)
- {
- // alzo semaforo salvataggio
- iobObj.adpSaving = true;
- // se HO dei dati...
- if (iobObj.persistenceLayer != null)
- {
- try
- {
- utils.WritePlain(iobObj.persistenceLayer, filePath);
- }
- catch (Exception exc)
- {
- lgError(string.Format("Errore salvataggio file{0}{1}", Environment.NewLine, exc));
- }
- }
- else
- {
- lgInfo("persistenceLayer null, non salvato...");
- }
- // abbasso semaforo salvataggio
- iobObj.adpSaving = false;
- }
- }
-
- private void checkFastTask()
- {
- // decremento...
- fastCount--;
- // se il counter è a zero eseguo...
- if (fastCount <= 0)
- {
- fastCount = utils.CRI("fastCount");
-
- // avvio fase raccolta dati e invio con adapter
- iobObj.getAndSend(gatherCycle.HF);
- }
- }
-
- private void checkNormTask()
- {
- // decremento...
- normCount--;
- // se il counter è a zero eseguo...
- if (normCount <= 0)
- {
- normCount = utils.CRI("normCount");
-
- // avvio fase raccolta dati e invio con adapter
- iobObj.getAndSend(gatherCycle.MF);
- }
- }
-
- private void checkSampleMem()
- {
- // decremento contatore...
- sampleMemCount--;
- if (sampleMemCount <= 0)
- {
- sampleMemCount = utils.CRI("sampleMemCount");
- // avvio fase raccolta dati e invio con adapter
- iobObj.saveMemDump(dumpType.SAMPLE);
- }
- }
-
- private void checkSendTask()
- {
- // avvio fase invio con adapter (code MST)
- iobObj.getAndSend(gatherCycle.VHF);
- }
-
- private void checkSlowTask()
- {
- slowCount--;
- if (slowCount <= 0)
- {
- slowCount = utils.CRI("slowCount");
-
- // avvio fase raccolta dati e invio con adapter
- iobObj.getAndSend(gatherCycle.LF);
- }
- }
-
- private void checkVerySlowData()
- {
- verySlowCount--;
- if (verySlowCount <= 0)
- {
- verySlowCount = utils.CRI("verySlowCount");
- // avvio fase raccolta dati e invio con adapter
- iobObj.getAndSend(gatherCycle.VLF);
- }
- }
-
- ///
- /// Chiusura adapter
- ///
- private void closeAdapter()
- {
- fermaTutto(true, false, true, false);
- }
-
- ///
- /// Ferma tutti i componenti adapter + update buttons
- ///
- /// indica se fermare il timer (gather) principale (solo se non si chiude)
- /// indica se tentare di riconnettersi
- /// indica se sia richeisto di SVUOTARE le code delel info
- /// indica se si debba aggiornare la form (no se si sta chiudendo...)
- private void fermaTutto(bool stopTimer, bool tryRestart, bool forceDequeue, bool updateForm)
- {
- iobObj.stopAdapter(tryRestart, forceDequeue);
- // salvo!
- savePersistLayer(utils.defPersLayerFile);
- savePersistLayer(utils.histPersLayerFile);
-
- stop.Enabled = false;
- start.Enabled = true;
- restart.Enabled = false;
-
- if (stopTimer)
- {
- gather.Enabled = false;
- iobObj.tryDisconnect();
- }
-
- newDisplayData currDispData = new newDisplayData();
- currDispData.semIn = Semaforo.SS;
- currDispData.semOut = Semaforo.SS;
- if (updateForm)
- {
- updateFormDisplay(currDispData);
- }
- }
-
- private void gather_Tick(object sender, EventArgs e)
- {
- bool doLog = false;
- if (iobObj != null)
- {
- if (iobObj.periodicLog)
- {
- doLog = true;
- }
- try
- {
- refreshFormData();
- // check esecuzione SendTask (VHF) COMUNQUE...
- checkSendTask();
- // eseguo cicli attivi SOLO se adapter è in EFFETTIVO running...
- if (iobObj.adpRunning)
- {
- if (iobObj.connectionOk)
- {
- // se richiesto faccio memory DUMP INIZIALE!
- if (iobObj.doStartMemDump)
- {
- lgInfo("Inizio dump memoria");
- iobObj.saveMemDump(dumpType.STARTUP);
- // fatto! non ripeto...
- iobObj.doStartMemDump = false;
- lgInfo("Finito dump memoria");
- }
- // controllo se sia abilitato sampleDump della meoria (periodico)
- if (iobObj.doSampleMemory)
- {
- checkSampleMem();
- }
- // check esecuzione FastTask
- checkFastTask();
- // check esecuzione NormTask
- checkNormTask();
- // check esecuzione SlowTask
- checkSlowTask();
- // check esecuzione AlarmSync
- checkVerySlowData();
- if (utils.CRI("waitEndCycle") > 0)
- {
- Thread.Sleep(utils.CRI("waitEndCycle"));
- }
- }
- else
- {
- DateTime dtVeto = lastStartTry.AddMilliseconds(waitRecMSec);
- if (iobObj.adpTryRestart && (DateTime.Now > dtVeto))
- {
- if (doLog)
- {
- lgInfo($"Retry Time Elapsed ({waitRecMSec} ms)--> tryConnect");
- }
- lastStartTry = DateTime.Now;
- iobObj.tryConnect();
- }
- }
- }
- else
- {
- if (doLog)
- {
- lgInfo("Adapter stopped");
- }
- // verifico SE debba tentare il riavvio, ovvero NON running ma adpTryRestart e non ho riprovato x oltre waitRecMSec
- DateTime dtVeto = lastStartTry.AddMilliseconds(waitRecMSec);
- if (iobObj.adpTryRestart && (DateTime.Now > dtVeto))
- {
- lastStartTry = DateTime.Now;
- avviaAdapter(chkForceDequeue.Checked);
- }
- }
- }
- catch (Exception exc)
- {
- lgError(string.Format("Eccezione in fase di gatherTick: {0}{1}", Environment.NewLine, exc));
- }
- }
- }
-
- ///
- /// Carica file ini della configurazione richiesta
- ///
- ///
- private void loadIniFile(string iniConfFile)
- {
- // out di cosa faccio...
- displayTaskAndLog(string.Format("Loading iniConfFile: {0}", iniConfFile));
- // leggo file
- IniFile fIni = new IniFile(iniConfFile);
-
- // leggo vendor e modello...
- curVendor = fIni.ReadString("MACHINE", "VENDOR", "ACME");
- curModel = fIni.ReadString("MACHINE", "MODEL", "NONE");
- // verifico tipo adapter
- try
- {
- tipoScelto = (tipoAdapter)Enum.Parse(typeof(tipoAdapter), fIni.ReadString("IOB", "CNCTYPE", "DEMO"));
- }
- catch (Exception exc)
- {
- lgError($"Eccezione in conversione tipo adapter: richiesto un tipo non codificato...{Environment.NewLine}{exc}");
- tipoScelto = tipoAdapter.ND;
- }
- // carivo vettore parametri opzionai
- Dictionary optParRead = new Dictionary();
- string[] optParRows = fIni.ReadSection("OPTPAR");
- if (optParRows.Length > 0)
- {
- try
- {
- string[] kvp;
- foreach (var item in optParRows)
- {
- kvp = item.Split('=');
- optParRead.Add(kvp[0], kvp[1]);
- }
- lgInfo($"Caricati {optParRead.Count} parametri opzionali da OPTPAR");
- }
- catch (Exception exc)
- {
- lgError(string.Format("EXCEPTION in fase di lettura OPTPAR: {0}{1}", Environment.NewLine, exc));
- }
- }
- // inizializzio conf IOB
- IOBConf = new IobConfiguration
- {
- pingMsTimeout = fIni.ReadInteger("IOB", "PING_MS_TIMEOUT", 500)
- ,
- vendor = curVendor
- ,
- model = curModel
- ,
- tipoIob = tipoScelto
- ,
- optPar = optParRead
- ,
- versIOB = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString()
- ,
- codIOB = CurrIOB
- ,
- cncIpAddr = fIni.ReadString("CNC", "IP", "::1")
- ,
- cncPort = fIni.ReadString("CNC", "PORT", "0")
- ,
- iniFileName = iniConfFile
- ,
- cpuType = fIni.ReadString("CNC", "CPUTYPE", "")
- ,
- rack = (short)fIni.ReadInteger("CNC", "RACK", 0)
- ,
- slot = (short)fIni.ReadInteger("CNC", "SLOT", 0)
- ,
- serverData = new serverMapo(fIni.ReadString("SERVER", "MPIP", "::1"), fIni.ReadString("SERVER", "MPURL", "/"), fIni.ReadString("SERVER", "CMDBASE", "/"), fIni.ReadString("SERVER", "CMDFLOG", "/"), fIni.ReadString("SERVER", "CMDALIVE", "/"), fIni.ReadString("SERVER", "CMDENABLED", "/"), fIni.ReadString("SERVER", "CMDREBO", "/"), fIni.ReadString("SERVER", "CMD_ODL_STARTED", "/IOB/getCurrOdlStart/"))
- ,
- MAX_COUNTER_BLINK = Convert.ToInt32(fIni.ReadString("BLINK", "MAX_COUNTER_BLINK", "1"))
- ,
- BLINK_FILT = Convert.ToInt32(fIni.ReadString("BLINK", "BLINK_FILT", "0"))
- ,
- TCMaxDelayFactor = Convert.ToDouble(fIni.ReadString("OPTPAR", "TC_MAX_TC_FACTOR", "1.2").Replace(".", ","))
- ,
- TCLambda = Convert.ToDouble(fIni.ReadString("OPTPAR", "TC_LAMBDA", "0.5").Replace(".", ","))
- ,
- TCMaxIncrPz = Convert.ToDouble(fIni.ReadString("OPTPAR", "TC_MAX_INCR", "5").Replace(".", ","))
- };
- lgInfo($"Creato IOBConf!");
-
- loadIobType();
- // avvio macchina con adapter specificato...
- if (utils.CRB("autoStartOnLoad"))
- {
- displayTaskAndLog("Auto Starting...");
- // avvio!
- avviaAdapter(chkForceDequeue.Checked);
- displayTaskAndLog("Auto Started!");
- }
- try
- {
- // segnalo reboot (programma)... metto in coda invio...
- //iobObj.sendToMoonPro(urlType.FLog, "IOB INI Loaded");
- //iobObj.QueueFLog.Enqueue(iobObj.qEncodeFLog("IOB-STATUS", "IOB INI Loaded"));
- }
- catch (Exception exc)
- {
- lgError(string.Format("EXCEPTION in fase di chiamata URL di segnalazione caricamento INI file:{0}{1}", Environment.NewLine, exc));
- }
- }
-
- private void refreshFormData()
- {
- // aggiorno visualizzazioni varie in form...
- evQueueLen = iobObj.QueueIN.Count;
- flQueueLen = iobObj.QueueFLog.Count;
- alQueueLen = iobObj.QueueAlarm.Count;
- msQueueLen = iobObj.QueueMessages.Count;
- // aggiorno labels counters...
- counterIob = $"pz IOB {iobObj.contapezziIOB}";
- counterMac = $"pz PLC {iobObj.contapezziPLC}";
- // verifico IOB status
- IobWinStatus currIobStatus = new IobWinStatus()
- {
- CodIob = iobObj.cIobConf.codIOB,
- queueEvLen = evQueueLen,
- queueFlLen = flQueueLen,
- queueAlLen = alQueueLen,
- queueMsLen = msQueueLen,
- counterIOB = iobObj.contapezziIOB,
- counterMAC = iobObj.contapezziPLC,
- lastUpdate = lastIobStatus.lastUpdate,
- online = utils.IOB_Online,
- lastDataIn = iobObj.lastReadPLC
- };
- // se diverso SALVO!
- if (lastIobStatus.online != currIobStatus.online || lastIobStatus.lastDataIn != currIobStatus.lastDataIn || lastIobStatus.counterIOB != currIobStatus.counterIOB || lastIobStatus.counterMAC != currIobStatus.counterMAC || lastIobStatus.queueEvLen != currIobStatus.queueEvLen || lastIobStatus.queueFlLen != currIobStatus.queueFlLen || lastIobStatus.queueAlLen != currIobStatus.queueAlLen || lastIobStatus.queueMsLen != currIobStatus.queueMsLen)
- {
- // aggiorno data
- currIobStatus.lastUpdate = DateTime.Now;
- // salvo su redis e in obj corrente
- iobObj.redisMan.iobStatus = currIobStatus;
- lastIobStatus = currIobStatus;
- }
- // se diverso SALVO MP IO status
- if (lastSrvStatus.online != utils.MPIO_Online)
- {
- // aggiorno
- ServerMpStatus currSrvStatus = iobObj.redisMan.servStatus;
- currSrvStatus.online = utils.MPIO_Online;
- currSrvStatus.lastUpdate = DateTime.Now;
- // salvo su redis e in obj corrente
- iobObj.redisMan.servStatus = currSrvStatus;
- lastSrvStatus = currSrvStatus;
- }
- }
-
- #endregion gestione metodi specifici FORM
-
- #region Area BackGroundWorker
-
- ///
- /// Effettua update form una volta ricevuto OBJ che contiene le varie innovazioni...
- ///
- ///
- public void updateFormDisplay(newDisplayData currDispData)
- {
- // ciclo x ogni oggetto x caricare le innovazioni...
- if (currDispData != null && currDispData.hasData)
- {
- // RealTime display
- if (!string.IsNullOrWhiteSpace(currDispData.newInData))
- {
- dataMonitor_0 = limitLine2show($"{currDispData.newInData}{Environment.NewLine}{dataMonitor_0}");
- }
- if (!string.IsNullOrWhiteSpace(currDispData.newSignalData))
- {
- dataMonitor_1 = limitLine2show($"{currDispData.newSignalData}{Environment.NewLine}{dataMonitor_1}");
- }
- if (!string.IsNullOrWhiteSpace(currDispData.newFLogData))
- {
- dataMonitor_3 = limitLine2show($"{currDispData.newFLogData}{Environment.NewLine}{dataMonitor_3}");
- }
- if (!string.IsNullOrWhiteSpace(currDispData.newUrlCallData))
- {
- dataMonitor_2 = limitLine2show($"{currDispData.newUrlCallData}{Environment.NewLine}{dataMonitor_2}");
- }
-
- // Bitmap lettura attuale
- if (currDispData.counter >= 0)
- {
- lblCounter.Text = currDispData.counter.ToString();
- }
- // Bitmap lettura attuale
- if (!string.IsNullOrWhiteSpace(currDispData.currBitmap))
- {
- lblBitmap.Text = currDispData.currBitmap;
- lblBitmap.Refresh();
- }
- // LiveLog
- if (!string.IsNullOrWhiteSpace(currDispData.newLiveLogData))
- {
- logWatcher = currDispData.newLiveLogData;
- }
- // semafori
- if (currDispData.semOut != Semaforo.ND)
- {
- //aggiorno comunque!
- sOUT = currDispData.semOut;
- }
- if (currDispData.semIn != Semaforo.ND)
- {
- //aggiorno comunque!
- sIN = currDispData.semIn;
- }
- }
- }
-
- protected override void Dispose(bool disposing)
- {
- if (disposing && (components != null))
- {
- components.Dispose();
- }
- base.Dispose(disposing);
- }
-
- #endregion Area BackGroundWorker
-
- #region Area gestione controlli threadSafe
+ #region Private Delegates
private delegate void SafeCallDelegate(string text);
- public void WriteTextSafe(string text)
- {
- if (lblOutMessage3.InvokeRequired)
- {
- var d = new SafeCallDelegate(WriteTextSafe);
- lblOutMessage3.Invoke(d, new object[] { text });
- }
- else
- {
- lblOutMessage3.Text = text;
- }
- }
-
- #endregion Area gestione controlli threadSafe
+ #endregion Private Delegates
#region Protected Properties
@@ -926,6 +240,23 @@ namespace IOB_WIN
///
protected Semaforo _sOUT { get; set; } = Semaforo.ND;
+ ///
+ /// Codice IOB della macchina cui connettersi (x scegliere corretto file di conf...)
+ ///
+ protected string CurrIOB { get; set; }
+
+ protected int delayShowLogMs { get; set; } = utils.CRI("delayShowLogMs");
+
+ ///
+ /// Stringa corrente di log...
+ ///
+ protected string logWatchString { get; set; } = "";
+
+ ///
+ /// Veto a NUOVE scritture in logWatch...
+ ///
+ protected DateTime logWatchWriteVeto { get; set; } = DateTime.Now;
+
protected int maxAlQueue { get; set; }
protected int maxEvQueue { get; set; }
@@ -952,6 +283,8 @@ namespace IOB_WIN
#endregion Protected Properties
+ #region Public Properties
+
public int alQueueLen
{
set
@@ -1130,6 +463,17 @@ namespace IOB_WIN
}
}
+ ///
+ /// File configurazione default
+ ///
+ public string defConfFilePath
+ {
+ get
+ {
+ return string.Format(@"{0}\{1}.ini", utils.confDir, CurrIOB);
+ }
+ }
+
public bool enableEditMes2Plc { get; set; }
public int evQueueLen
@@ -1182,6 +526,44 @@ namespace IOB_WIN
}
}
+ ///
+ /// Log verboso da configurazione (SOLO CHAIVE "verbose"...
+ ///
+ public bool isVerboseLog { get; set; } = utils.CRB("verbose");
+
+ ///
+ /// Logwatcher (in modalità "accodamento in testa" ultimi messaggi...)
+ ///
+ public string logWatcher
+ {
+ get
+ {
+ return lblLogfile.Text;
+ }
+ set
+ {
+ try
+ {
+ logWatchString = limitLine2show($"{value}{Environment.NewLine}{logWatchString}");
+ DateTime adesso = DateTime.Now;
+ if (logWatchWriteVeto < adesso)
+ {
+ lblLogfile.Text = logWatchString;
+ lblLogfile.Refresh();
+ logWatchWriteVeto = adesso.AddMilliseconds(delayShowLogMs);
+ }
+ }
+ catch (Exception exc)
+ {
+ lgError($"Errore in esecuzione logWatcher{Environment.NewLine}--> {value}");
+ if (isVerboseLog)
+ {
+ lgError($"{exc}");
+ }
+ }
+ }
+ }
+
public int msQueueLen
{
set
@@ -1241,8 +623,12 @@ namespace IOB_WIN
set
{
_sIN = value;
- bIN.BackColor = decSemaforo(value);
- bIN.Refresh();
+ var newColor = decSemaforo(value);
+ if (newColor != bIN.BackColor)
+ {
+ bIN.BackColor = newColor;
+ bIN.Refresh();
+ }
}
}
@@ -1258,107 +644,45 @@ namespace IOB_WIN
set
{
_sOUT = value;
- bOUT.BackColor = decSemaforo(value);
- bOUT.Refresh();
+ var newColor = decSemaforo(value);
+ if (newColor != bOUT.BackColor)
+ {
+ bOUT.BackColor = newColor;
+ bOUT.Refresh();
+ }
}
}
///
- /// Decodifica colore da valore semaforico
+ /// Task watcher (in modalità "accodamento in testa" ultimi messaggi...)
///
- ///
- ///
- public static Color decSemaforo(Semaforo valore)
+ public string taskWatcher
{
- Color colore = Color.LightGray;
- switch (valore)
+ get
{
- case Semaforo.SV:
- colore = Color.LightGreen;
- break;
-
- case Semaforo.SG:
- colore = Color.LightGoldenrodYellow;
- break;
-
- case Semaforo.SR:
- colore = Color.Red;
- break;
-
- case Semaforo.SS:
- colore = Color.DarkGray;
- break;
-
- default:
- colore = Color.LightGray;
- break;
+ return lblTaskLog.Text;
}
- return colore;
- }
-
- ///
- /// Avvio l'adapter
- ///
- /// indica se sia richeisto di SVUOTARE le code delel info
- public void avviaAdapter(bool resetQueue)
- {
- displayTaskAndLog("Adapter starting");
- // se NON sta girando...
- if (!iobObj.adpRunning)
+ set
{
- iobObj.startAdapter(resetQueue);
- displayTaskAndLog("Adapter started!");
-
- // fix buttons start/stop/dump
- start.Enabled = false;
- stop.Enabled = true;
- restart.Enabled = true;
-
- displayTaskAndLog("Start Timers");
- // inizializzo contatori fast/mid/slow
- fastCount = utils.CRI("fastCount");
- normCount = utils.CRI("normCount");
- slowCount = utils.CRI("slowCount");
- verySlowCount = utils.CRI("verySlowCount");
- displayTaskAndLog("Adapter Running...");
- // init max queue
- maxEvQueue = 1;
- maxFlQueue = 1;
-
try
{
- // segnalo reboot (programma)...
- iobObj.QueueFLog.Enqueue(iobObj.qEncodeFLog("IOB-STATUS", "IOB Started"));
+ lblTaskLog.Text = limitLine2show($"{value}{Environment.NewLine}{lblTaskLog.Text}");
+ lblTaskLog.Refresh();
}
catch (Exception exc)
{
- lgError(string.Format("EXCEPTION in fase di chiamata URL di segnalazione AVVIO IOB:{0}{1}", Environment.NewLine, exc));
+ lgError($"Errore in esecuzione taskWatcher{Environment.NewLine}--> {value}");
+ if (isVerboseLog)
+ {
+ lgError($"{exc}");
+ }
}
}
- else
- {
- displayTaskAndLog("Adapter STILL Running...");
- }
}
- ///
- /// Ferma l'adapter
- ///
- /// determina se si debba tentare riavvio automatico (per caduta connessione)
- /// indica se sia richeisto di SVUOTARE le code delel info
- /// indica se aggiornare la form prima di fermare
- public void fermaAdapter(bool tryRestart, bool forceDequeue, bool updateForm)
- {
- fermaTutto(false, tryRestart, forceDequeue, updateForm);
- }
+ #endregion Public Properties
- ///
- /// MOstra info su coda complessiva
- ///
- protected void showQueueData()
- {
- lblQueueLenTop.Text = totQueue == 0 ? "realtime" : $"ev: {qEvLen} | flog: {qFlLen} | tot: {totQueue}";
- }
+ #region Private Methods
private void BtnOpenLog_Click(object sender, EventArgs e)
{
@@ -1413,15 +737,125 @@ namespace IOB_WIN
}
}
+ private void checkFastTask()
+ {
+ // decremento...
+ fastCount--;
+ // se il counter è a zero eseguo...
+ if (fastCount <= 0)
+ {
+ fastCount = utils.CRI("fastCount");
+
+ // avvio fase raccolta dati e invio con adapter
+ iobObj.getAndSend(gatherCycle.HF);
+ }
+ }
+
+ private void checkNormTask()
+ {
+ // decremento...
+ normCount--;
+ // se il counter è a zero eseguo...
+ if (normCount <= 0)
+ {
+ normCount = utils.CRI("normCount");
+
+ // avvio fase raccolta dati e invio con adapter
+ iobObj.getAndSend(gatherCycle.MF);
+ }
+ }
+
+ private void checkSampleMem()
+ {
+ // decremento contatore...
+ sampleMemCount--;
+ if (sampleMemCount <= 0)
+ {
+ sampleMemCount = utils.CRI("sampleMemCount");
+ // avvio fase raccolta dati e invio con adapter
+ iobObj.saveMemDump(dumpType.SAMPLE);
+ }
+ }
+
+ private void checkSendTask()
+ {
+ // avvio fase invio con adapter (code MST)
+ iobObj.getAndSend(gatherCycle.VHF);
+ }
+
+ private void checkSlowTask()
+ {
+ slowCount--;
+ if (slowCount <= 0)
+ {
+ slowCount = utils.CRI("slowCount");
+
+ // avvio fase raccolta dati e invio con adapter
+ iobObj.getAndSend(gatherCycle.LF);
+ }
+ }
+
+ private void checkVerySlowData()
+ {
+ verySlowCount--;
+ if (verySlowCount <= 0)
+ {
+ verySlowCount = utils.CRI("verySlowCount");
+ // avvio fase raccolta dati e invio con adapter
+ iobObj.getAndSend(gatherCycle.VLF);
+ }
+ }
+
private void ChkEdit_CheckedChanged(object sender, EventArgs e)
{
toggleEditMes2Plc();
}
+ ///
+ /// Chiusura adapter
+ ///
+ private void closeAdapter()
+ {
+ fermaTutto(true, false, true, false);
+ }
+
private void displTimer_Tick(object sender, EventArgs e)
{
}
+ ///
+ /// Ferma tutti i componenti adapter + update buttons
+ ///
+ /// indica se fermare il timer (gather) principale (solo se non si chiude)
+ /// indica se tentare di riconnettersi
+ /// indica se sia richeisto di SVUOTARE le code delel info
+ /// indica se si debba aggiornare la form (no se si sta chiudendo...)
+ private void fermaTutto(bool stopTimer, bool tryRestart, bool forceDequeue, bool updateForm)
+ {
+ iobObj.stopAdapter(tryRestart, forceDequeue);
+ // salvo!
+ savePersistLayer(utils.defPersLayerFile);
+ savePersistLayer(utils.histPersLayerFile);
+
+ stop.Enabled = false;
+ start.Enabled = true;
+ restart.Enabled = false;
+
+ if (stopTimer)
+ {
+ gather.Enabled = false;
+ iobObj.tryDisconnect();
+ }
+
+ newDisplayData currDispData = new newDisplayData();
+ currDispData.semIn = Semaforo.SS;
+ currDispData.semOut = Semaforo.SS;
+ if (updateForm)
+ {
+ updateFormDisplay(currDispData);
+ }
+ }
+
private void fixComboParameters()
{
if (iobObj != null)
@@ -1444,6 +878,88 @@ namespace IOB_WIN
}
}
+ private void gather_Tick(object sender, EventArgs e)
+ {
+ bool doLog = false;
+ if (iobObj != null)
+ {
+ if (iobObj.periodicLog)
+ {
+ doLog = true;
+ }
+ try
+ {
+ refreshFormData();
+ // check esecuzione SendTask (VHF) COMUNQUE...
+ checkSendTask();
+ // eseguo cicli attivi SOLO se adapter è in EFFETTIVO running...
+ if (iobObj.adpRunning)
+ {
+ if (iobObj.connectionOk)
+ {
+ // se richiesto faccio memory DUMP INIZIALE!
+ if (iobObj.doStartMemDump)
+ {
+ lgInfo("Inizio dump memoria");
+ iobObj.saveMemDump(dumpType.STARTUP);
+ // fatto! non ripeto...
+ iobObj.doStartMemDump = false;
+ lgInfo("Finito dump memoria");
+ }
+ // controllo se sia abilitato sampleDump della meoria (periodico)
+ if (iobObj.doSampleMemory)
+ {
+ checkSampleMem();
+ }
+ // check esecuzione FastTask
+ checkFastTask();
+ // check esecuzione NormTask
+ checkNormTask();
+ // check esecuzione SlowTask
+ checkSlowTask();
+ // check esecuzione AlarmSync
+ checkVerySlowData();
+ if (utils.CRI("waitEndCycle") > 0)
+ {
+ Thread.Sleep(utils.CRI("waitEndCycle"));
+ }
+ }
+ else
+ {
+ DateTime dtVeto = lastStartTry.AddMilliseconds(waitRecMSec);
+ if (iobObj.adpTryRestart && (DateTime.Now > dtVeto))
+ {
+ if (doLog)
+ {
+ lgInfo($"Retry Time Elapsed ({waitRecMSec} ms)--> tryConnect");
+ }
+ lastStartTry = DateTime.Now;
+ iobObj.tryConnect();
+ }
+ }
+ }
+ else
+ {
+ if (doLog)
+ {
+ lgInfo("Adapter stopped");
+ }
+ // verifico SE debba tentare il riavvio, ovvero NON running ma adpTryRestart e non ho riprovato x oltre waitRecMSec
+ DateTime dtVeto = lastStartTry.AddMilliseconds(waitRecMSec);
+ if (iobObj.adpTryRestart && (DateTime.Now > dtVeto))
+ {
+ lastStartTry = DateTime.Now;
+ avviaAdapter(chkForceDequeue.Checked);
+ }
+ }
+ }
+ catch (Exception exc)
+ {
+ lgError(string.Format("Eccezione in fase di gatherTick: {0}{1}", Environment.NewLine, exc));
+ }
+ }
+ }
+
///
/// GEstione evento refresh
///
@@ -1455,6 +971,114 @@ namespace IOB_WIN
updateFormDisplay(e.DisplayDataObject);
}
+ ///
+ /// Carica file ini della configurazione richiesta
+ ///
+ ///
+ private void loadIniFile(string iniConfFile)
+ {
+ // out di cosa faccio...
+ displayTaskAndLog(string.Format("Loading iniConfFile: {0}", iniConfFile));
+ // leggo file
+ IniFile fIni = new IniFile(iniConfFile);
+
+ // leggo vendor e modello...
+ curVendor = fIni.ReadString("MACHINE", "VENDOR", "ACME");
+ curModel = fIni.ReadString("MACHINE", "MODEL", "NONE");
+ // verifico tipo adapter
+ try
+ {
+ tipoScelto = (tipoAdapter)Enum.Parse(typeof(tipoAdapter), fIni.ReadString("IOB", "CNCTYPE", "DEMO"));
+ }
+ catch (Exception exc)
+ {
+ lgError($"Eccezione in conversione tipo adapter: richiesto un tipo non codificato...{Environment.NewLine}{exc}");
+ tipoScelto = tipoAdapter.ND;
+ }
+ // carivo vettore parametri opzionai
+ Dictionary optParRead = new Dictionary();
+ string[] optParRows = fIni.ReadSection("OPTPAR");
+ if (optParRows.Length > 0)
+ {
+ try
+ {
+ string[] kvp;
+ foreach (var item in optParRows)
+ {
+ kvp = item.Split('=');
+ optParRead.Add(kvp[0], kvp[1]);
+ }
+ lgInfo($"Caricati {optParRead.Count} parametri opzionali da OPTPAR");
+ }
+ catch (Exception exc)
+ {
+ lgError(string.Format("EXCEPTION in fase di lettura OPTPAR: {0}{1}", Environment.NewLine, exc));
+ }
+ }
+ // inizializzio conf IOB
+ IOBConf = new IobConfiguration
+ {
+ pingMsTimeout = fIni.ReadInteger("IOB", "PING_MS_TIMEOUT", 500)
+ ,
+ vendor = curVendor
+ ,
+ model = curModel
+ ,
+ tipoIob = tipoScelto
+ ,
+ optPar = optParRead
+ ,
+ versIOB = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString()
+ ,
+ codIOB = CurrIOB
+ ,
+ cncIpAddr = fIni.ReadString("CNC", "IP", "::1")
+ ,
+ cncPort = fIni.ReadString("CNC", "PORT", "0")
+ ,
+ iniFileName = iniConfFile
+ ,
+ cpuType = fIni.ReadString("CNC", "CPUTYPE", "")
+ ,
+ rack = (short)fIni.ReadInteger("CNC", "RACK", 0)
+ ,
+ slot = (short)fIni.ReadInteger("CNC", "SLOT", 0)
+ ,
+ serverData = new serverMapo(fIni.ReadString("SERVER", "MPIP", "::1"), fIni.ReadString("SERVER", "MPURL", "/"), fIni.ReadString("SERVER", "CMDBASE", "/"), fIni.ReadString("SERVER", "CMDFLOG", "/"), fIni.ReadString("SERVER", "CMDALIVE", "/"), fIni.ReadString("SERVER", "CMDENABLED", "/"), fIni.ReadString("SERVER", "CMDREBO", "/"), fIni.ReadString("SERVER", "CMD_ODL_STARTED", "/IOB/getCurrOdlStart/"))
+ ,
+ MAX_COUNTER_BLINK = Convert.ToInt32(fIni.ReadString("BLINK", "MAX_COUNTER_BLINK", "1"))
+ ,
+ BLINK_FILT = Convert.ToInt32(fIni.ReadString("BLINK", "BLINK_FILT", "0"))
+ ,
+ TCMaxDelayFactor = Convert.ToDouble(fIni.ReadString("OPTPAR", "TC_MAX_TC_FACTOR", "1.2").Replace(".", ","))
+ ,
+ TCLambda = Convert.ToDouble(fIni.ReadString("OPTPAR", "TC_LAMBDA", "0.5").Replace(".", ","))
+ ,
+ TCMaxIncrPz = Convert.ToDouble(fIni.ReadString("OPTPAR", "TC_MAX_INCR", "5").Replace(".", ","))
+ };
+ lgInfo($"Creato IOBConf!");
+
+ loadIobType();
+ // avvio macchina con adapter specificato...
+ if (utils.CRB("autoStartOnLoad"))
+ {
+ displayTaskAndLog("Auto Starting...");
+ // avvio!
+ avviaAdapter(chkForceDequeue.Checked);
+ displayTaskAndLog("Auto Started!");
+ }
+ try
+ {
+ // segnalo reboot (programma)... metto in coda invio...
+ //iobObj.sendToMoonPro(urlType.FLog, "IOB INI Loaded");
+ //iobObj.QueueFLog.Enqueue(iobObj.qEncodeFLog("IOB-STATUS", "IOB INI Loaded"));
+ }
+ catch (Exception exc)
+ {
+ lgError(string.Format("EXCEPTION in fase di chiamata URL di segnalazione caricamento INI file:{0}{1}", Environment.NewLine, exc));
+ }
+ }
+
///
/// carica IOB richiesto
///
@@ -1583,6 +1207,35 @@ namespace IOB_WIN
displayTaskAndLog(string.Format("Caricata conf per adapter {0}", tipoScelto));
}
+ ///
+ /// Fase chiusura Form
+ ///
+ ///
+ ///
+ private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
+ {
+ closeAdapter();
+ }
+
+ ///
+ /// Completato resize form
+ ///
+ ///
+ ///
+ private void MainForm_Resize(object sender, EventArgs e)
+ {
+ }
+
+ ///
+ /// Mostrata form
+ ///
+ ///
+ ///
+ private void MainForm_Shown(object sender, EventArgs e)
+ {
+ displayTaskAndLog("Main Form SHOWN (Adapter)");
+ }
+
private void mLoadConf_Click(object sender, EventArgs e)
{
// mostro selettore file x leggere adapter..
@@ -1608,6 +1261,52 @@ namespace IOB_WIN
}
}
+ private void refreshFormData()
+ {
+ // aggiorno visualizzazioni varie in form...
+ evQueueLen = iobObj.QueueIN.Count;
+ flQueueLen = iobObj.QueueFLog.Count;
+ alQueueLen = iobObj.QueueAlarm.Count;
+ msQueueLen = iobObj.QueueMessages.Count;
+ // aggiorno labels counters...
+ counterIob = $"pz IOB {iobObj.contapezziIOB}";
+ counterMac = $"pz PLC {iobObj.contapezziPLC}";
+ // verifico IOB status
+ IobWinStatus currIobStatus = new IobWinStatus()
+ {
+ CodIob = iobObj.cIobConf.codIOB,
+ queueEvLen = evQueueLen,
+ queueFlLen = flQueueLen,
+ queueAlLen = alQueueLen,
+ queueMsLen = msQueueLen,
+ counterIOB = iobObj.contapezziIOB,
+ counterMAC = iobObj.contapezziPLC,
+ lastUpdate = lastIobStatus.lastUpdate,
+ online = utils.IOB_Online,
+ lastDataIn = iobObj.lastReadPLC
+ };
+ // se diverso SALVO!
+ if (lastIobStatus.online != currIobStatus.online || lastIobStatus.lastDataIn != currIobStatus.lastDataIn || lastIobStatus.counterIOB != currIobStatus.counterIOB || lastIobStatus.counterMAC != currIobStatus.counterMAC || lastIobStatus.queueEvLen != currIobStatus.queueEvLen || lastIobStatus.queueFlLen != currIobStatus.queueFlLen || lastIobStatus.queueAlLen != currIobStatus.queueAlLen || lastIobStatus.queueMsLen != currIobStatus.queueMsLen)
+ {
+ // aggiorno data
+ currIobStatus.lastUpdate = DateTime.Now;
+ // salvo su redis e in obj corrente
+ iobObj.redisMan.iobStatus = currIobStatus;
+ lastIobStatus = currIobStatus;
+ }
+ // se diverso SALVO MP IO status
+ if (lastSrvStatus.online != utils.MPIO_Online)
+ {
+ // aggiorno
+ ServerMpStatus currSrvStatus = iobObj.redisMan.servStatus;
+ currSrvStatus.online = utils.MPIO_Online;
+ currSrvStatus.lastUpdate = DateTime.Now;
+ // salvo su redis e in obj corrente
+ iobObj.redisMan.servStatus = currSrvStatus;
+ lastSrvStatus = currSrvStatus;
+ }
+ }
+
///
/// Button restart
///
@@ -1692,5 +1391,318 @@ namespace IOB_WIN
enableEditMes2Plc = !enableEditMes2Plc;
checkEditMes2Plc();
}
+
+ #endregion Private Methods
+
+ #region Protected Methods
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ ///
+ /// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere...
+ ///
+ ///
+ protected void lgError(string txt2log)
+ {
+ if (!string.IsNullOrEmpty(txt2log))
+ {
+ lg.Factory.Configuration.Variables["codIOB"] = this.CurrIOB;
+ lg.Error(txt2log);
+ // salvo anche in logwatcher... SE non si dimostra ricorsivo...
+ if (!txt2log.Contains("logWatcher"))
+ {
+ newDisplayData currDispData = new newDisplayData();
+ currDispData.newLiveLogData = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} | ERROR | {txt2log}";
+ updateFormDisplay(currDispData);
+ }
+ }
+ }
+
+ ///
+ /// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere...
+ ///
+ ///
+ protected void lgInfo(string txt2log)
+ {
+ lg.Factory.Configuration.Variables["codIOB"] = this.CurrIOB;
+ lg.Info(txt2log);
+ // salvo anche in logwatcher...
+ newDisplayData currDispData = new newDisplayData();
+ currDispData.newLiveLogData = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} | INFO | {txt2log}";
+ updateFormDisplay(currDispData);
+ }
+
+ ///
+ /// Init form (grafica) con helper x testi e varie
+ ///
+ protected void myGraphInitForm()
+ {
+ lblStatus.Text = "Loading";
+
+ // aggiunta tooltip x send forzato
+ ToolTip ttForceSend = new ToolTip();
+
+ // imposto delay.
+ ttForceSend.AutoPopDelay = 3000;
+ ttForceSend.InitialDelay = 500;
+ ttForceSend.ReshowDelay = 500;
+ // sempre visibile (che sia o meno attiva la form).
+ ttForceSend.ShowAlways = true;
+
+ // imposto tooltip
+ ttForceSend.SetToolTip(this.chkForceDequeue, "Forza invio eventi allo stop");
+ }
+
+ ///
+ /// MOstra info su coda complessiva
+ ///
+ protected void showQueueData()
+ {
+ lblQueueLenTop.Text = totQueue == 0 ? "realtime" : $"ev: {qEvLen} | flog: {qFlLen} | tot: {totQueue}";
+ }
+
+ #endregion Protected Methods
+
+ #region Public Methods
+
+ ///
+ /// Decodifica colore da valore semaforico
+ ///
+ ///
+ ///
+ public static Color decSemaforo(Semaforo valore)
+ {
+ Color colore = Color.LightGray;
+ switch (valore)
+ {
+ case Semaforo.SV:
+ colore = Color.LightGreen;
+ break;
+
+ case Semaforo.SG:
+ colore = Color.LightGoldenrodYellow;
+ break;
+
+ case Semaforo.SR:
+ colore = Color.Red;
+ break;
+
+ case Semaforo.SS:
+ colore = Color.DarkGray;
+ break;
+
+ default:
+ colore = Color.LightGray;
+ break;
+ }
+ return colore;
+ }
+
+ ///
+ /// Avvio l'adapter
+ ///
+ /// indica se sia richeisto di SVUOTARE le code delel info
+ public void avviaAdapter(bool resetQueue)
+ {
+ displayTaskAndLog("Adapter starting");
+ // se NON sta girando...
+ if (!iobObj.adpRunning)
+ {
+ iobObj.startAdapter(resetQueue);
+ displayTaskAndLog("Adapter started!");
+
+ // fix buttons start/stop/dump
+ start.Enabled = false;
+ stop.Enabled = true;
+ restart.Enabled = true;
+
+ displayTaskAndLog("Start Timers");
+ // inizializzo contatori fast/mid/slow
+ fastCount = utils.CRI("fastCount");
+ normCount = utils.CRI("normCount");
+ slowCount = utils.CRI("slowCount");
+ verySlowCount = utils.CRI("verySlowCount");
+ displayTaskAndLog("Adapter Running...");
+ // init max queue
+ maxEvQueue = 1;
+ maxFlQueue = 1;
+
+ try
+ {
+ // segnalo reboot (programma)...
+ iobObj.QueueFLog.Enqueue(iobObj.qEncodeFLog("IOB-STATUS", "IOB Started"));
+ }
+ catch (Exception exc)
+ {
+ lgError(string.Format("EXCEPTION in fase di chiamata URL di segnalazione AVVIO IOB:{0}{1}", Environment.NewLine, exc));
+ }
+ }
+ else
+ {
+ displayTaskAndLog("Adapter STILL Running...");
+ }
+ }
+
+ ///
+ /// mostra un testo sulla status bar + LOG
+ ///
+ ///
+ public void displayTaskAndLog(string txt2show)
+ {
+ lblStatus.Text = txt2show;
+ lblStatus.Invalidate();
+ lgInfo(txt2show);
+ }
+
+ ///
+ /// Ferma l'adapter
+ ///
+ /// determina se si debba tentare riavvio automatico (per caduta connessione)
+ /// indica se sia richeisto di SVUOTARE le code delel info
+ /// indica se aggiornare la form prima di fermare
+ public void fermaAdapter(bool tryRestart, bool forceDequeue, bool updateForm)
+ {
+ fermaTutto(false, tryRestart, forceDequeue, updateForm);
+ }
+
+ ///
+ /// Effettua un trim della stringa al numero max di linee da mostrare a video
+ ///
+ ///
+ ///
+ public string limitLine2show(string newString)
+ {
+ if (!string.IsNullOrEmpty(newString))
+ {
+ // se num righe superiore a limite trimmo...
+ if (newString.Split('\n').Length > nLine2show)
+ {
+ //int idx = newString.LastIndexOf('\r');
+ int idx = newString.LastIndexOf(Environment.NewLine);
+ newString = newString.Substring(0, idx);
+ }
+ }
+ return newString;
+ }
+
+ ///
+ /// Salva su file l'oggetto di persistenza dati
+ ///
+ ///
+ public void savePersistLayer(string filePath)
+ {
+ // in primis check semaforo salvataggio...
+ if (!iobObj.adpSaving)
+ {
+ // alzo semaforo salvataggio
+ iobObj.adpSaving = true;
+ // se HO dei dati...
+ if (iobObj.persistenceLayer != null)
+ {
+ try
+ {
+ utils.WritePlain(iobObj.persistenceLayer, filePath);
+ }
+ catch (Exception exc)
+ {
+ lgError(string.Format("Errore salvataggio file{0}{1}", Environment.NewLine, exc));
+ }
+ }
+ else
+ {
+ lgInfo("persistenceLayer null, non salvato...");
+ }
+ // abbasso semaforo salvataggio
+ iobObj.adpSaving = false;
+ }
+ }
+
+ ///
+ /// Mostra update delle statistiche di comunicazione (numero chiamate, tempo medio...)
+ ///
+ ///
+ public void updateComStats(string txt2show)
+ {
+ lblComStats.Text = string.Format("{0} | ", txt2show);
+ }
+
+ ///
+ /// Effettua update form una volta ricevuto OBJ che contiene le varie innovazioni...
+ ///
+ ///
+ public void updateFormDisplay(newDisplayData currDispData)
+ {
+ // ciclo x ogni oggetto x caricare le innovazioni...
+ if (currDispData != null && currDispData.hasData)
+ {
+ // RealTime display
+ if (!string.IsNullOrWhiteSpace(currDispData.newInData))
+ {
+ dataMonitor_0 = limitLine2show($"{currDispData.newInData}{Environment.NewLine}{dataMonitor_0}");
+ }
+ if (!string.IsNullOrWhiteSpace(currDispData.newSignalData))
+ {
+ dataMonitor_1 = limitLine2show($"{currDispData.newSignalData}{Environment.NewLine}{dataMonitor_1}");
+ }
+ if (!string.IsNullOrWhiteSpace(currDispData.newFLogData))
+ {
+ dataMonitor_3 = limitLine2show($"{currDispData.newFLogData}{Environment.NewLine}{dataMonitor_3}");
+ }
+ if (!string.IsNullOrWhiteSpace(currDispData.newUrlCallData))
+ {
+ dataMonitor_2 = limitLine2show($"{currDispData.newUrlCallData}{Environment.NewLine}{dataMonitor_2}");
+ }
+
+ // Bitmap lettura attuale
+ if (currDispData.counter >= 0)
+ {
+ lblCounter.Text = currDispData.counter.ToString();
+ }
+ // Bitmap lettura attuale
+ if (!string.IsNullOrWhiteSpace(currDispData.currBitmap))
+ {
+ lblBitmap.Text = currDispData.currBitmap;
+ lblBitmap.Refresh();
+ }
+ // LiveLog
+ if (!string.IsNullOrWhiteSpace(currDispData.newLiveLogData))
+ {
+ logWatcher = currDispData.newLiveLogData;
+ }
+ // semafori
+ if (currDispData.semOut != Semaforo.ND)
+ {
+ //aggiorno comunque!
+ sOUT = currDispData.semOut;
+ }
+ if (currDispData.semIn != Semaforo.ND)
+ {
+ //aggiorno comunque!
+ sIN = currDispData.semIn;
+ }
+ }
+ }
+
+ public void WriteTextSafe(string text)
+ {
+ if (lblOutMessage3.InvokeRequired)
+ {
+ var d = new SafeCallDelegate(WriteTextSafe);
+ lblOutMessage3.Invoke(d, new object[] { text });
+ }
+ else
+ {
+ lblOutMessage3.Text = text;
+ }
+ }
+
+ #endregion Public Methods
}
}
\ No newline at end of file
diff --git a/IOB-WIN/IobGeneric.cs b/IOB-WIN/IobGeneric.cs
index 0b7db10f..e2661221 100644
--- a/IOB-WIN/IobGeneric.cs
+++ b/IOB-WIN/IobGeneric.cs
@@ -21,16 +21,113 @@ namespace IOB_WIN
{
public class IobGeneric
{
- #region variabili serializzate in REDIS
+ #region Protected Fields
///
- /// Oggetto connessione REDIS
+ /// wrapper di log
///
- public RedisIobCache redisMan;
+ protected static Logger lg;
- #endregion variabili serializzate in REDIS
+ protected bool _connOk = false;
- #region variabili ed oggetti base
+ ///
+ /// 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 32 BIT valori in ingresso al filtro
+ ///
+ protected int B_input;
+
+ ///
+ /// Vettore 32 BIT valori in uscita dal filtro
+ ///
+ protected int B_output;
+
+ ///
+ /// Vettore 32 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 tentativo connessione...
+ ///
+ protected DateTime lastConnectTry;
+
+ ///
+ /// 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;
+
+ ///
+ /// indica se serva refresh parametri e quindi PLC...
+ ///
+ protected bool needRefresh = true;
+
+ ///
+ /// Form chiamante
+ ///
+ protected AdapterForm parentForm;
+
+ ///
+ /// 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();
+
+ #endregion Protected Fields
+
+ #region Public Fields
///
/// valore booleano di check se sia stato AVVIATO l'adapter (Running)
@@ -47,6 +144,11 @@ namespace IOB_WIN
///
public bool adpTryRestart;
+ ///
+ /// Conf adapter corrente
+ ///
+ public IobConfiguration cIobConf;
+
///
/// Conteggio ATTUALE ore macchina IN LAVORO
///
@@ -57,6 +159,11 @@ namespace IOB_WIN
///
public double contOreMaccOn;
+ ///
+ /// contatore x simulazione valori input
+ ///
+ public int countSim = 0;
+
///
/// ODL attualmente sulla macchina
///
@@ -137,6 +244,11 @@ namespace IOB_WIN
///
public string lastSignInVal = "";
+ ///
+ /// DateTime Ultimo valore simulazione generato
+ ///
+ public DateTime lastSim;
+
///
/// dataOra ultimo segnale inviato...
///
@@ -147,6 +259,11 @@ namespace IOB_WIN
///
public int maxSendPzCountBlock = 10;
+ ///
+ /// Struttura memoria PLC x lettura/scrittura da JSON file
+ ///
+ public plcMemMap memMap;
+
///
/// Minimo numero di px da inviare in blocco
///
@@ -157,6 +274,11 @@ namespace IOB_WIN
///
public bool needRefreshPzCount = true;
+ ///
+ /// Dizionario di persistenza per i valori da salvare da/su file
+ ///
+ public Dictionary persistenceLayer;
+
///
/// Determina se utilizzare blocchi di memoria IOT contigui (e quindi processing "monoblocco" semplificato"=
///
@@ -197,6 +319,11 @@ namespace IOB_WIN
///
public byte[] RawOutput = new byte[32];
+ ///
+ /// Oggetto connessione REDIS
+ ///
+ public RedisIobCache redisMan;
+
///
/// Oggetto cronometro x campionamento durate chiamate
///
@@ -217,96 +344,322 @@ namespace IOB_WIN
///
public bool W = true;
- ///
- /// wrapper di log
- ///
- protected static Logger lg;
+ #endregion Public Fields
+
+ #region Public Constructors
///
- /// valore booleano di check se sia in fase di COMUNICAZIONE ATTIVA con il PLC/NC
+ /// inizializzo l'oggetto sulla form SULLA BASE DEL FILE DI CONFIGURAZIONE letto
///
- protected bool adpCommAct;
+ ///
+ ///
+ public IobGeneric(AdapterForm caller, IobConfiguration IOBConf)
+ {
+ if (IOBConf != null)
+ {
+ // init oggetto redis...
+ redisMan = new RedisIobCache(IOBConf.serverData.MPIP, IOBConf.codIOB);
- ///
- /// porta x adapter (x restart)
- ///
- protected int adpPortNum;
+ // initi oggetto TCMan
+ tcMan = new TCMan(IOBConf.TCLambda, IOBConf.TCMaxDelayFactor, IOBConf.TCMaxIncrPz);
- ///
- /// DataOra ultimo avvio adapter x watchdog
- ///
- protected DateTime adpStartRun;
+ // salvo il form chiamante
+ parentForm = caller;
+ // configurazione...
+ cIobConf = IOBConf;
- ///
- /// Vettore 32 BIT valori in ingresso al filtro
- ///
- protected int B_input;
+ lastConnectTry = DateTime.Now;
- ///
- /// Vettore 32 BIT valori in uscita dal filtro
- ///
- protected int B_output;
+ // aggiungo nel logger IDX Macchina
+ lg = LogManager.GetCurrentClassLogger();
- ///
- /// Vettore 32 BIT valori precedenti
- ///
- protected int B_previous;
+ lgInfo("Avvio preliminare AdapterGeneric");
+ // aggiungo altri defaults
+ setDefaults(true);
- ///
- /// Dizionario valori impostati x produzione
- ///
- protected Dictionary currProdData = new Dictionary();
+ setParamPlc();
- ///
- /// Array dei contatori x segnali blinking
- ///
- protected int[] i_counters;
+ // checkLogDir x shrink!
+ checkShrinkDir();
- ///
- /// Indica impianto IN SETUP (fino a quando SMETTE di esserlo...)
- ///
- protected bool inSetup = false;
+ // concluso!
+ lgInfo("Istanziata classe preliminare IOBGeneric");
+ }
+ else
+ {
+ lgError("Error: IobCOnf is null!");
+ }
+ }
- ///
- /// Ultimo invio contapezzi (x invio delayed)
- ///
- protected DateTime lastPzCountSend;
+ #endregion Public Constructors
- ///
- /// 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();
+ #region Public Events
///
/// Evento Iob ha subito un refresh
///
public event EventHandler eh_refreshed;
+ #endregion Public Events
+
+ #region Private Properties
+
+ ///
+ /// 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;
+ }
+ }
+
+ #endregion Private Properties
+
+ #region Protected Properties
+
+ ///
+ /// Valore del num max invii consecutivi da coda...
+ ///
+ protected static int nMaxSend
+ {
+ get
+ {
+ int answ = 5;
+ try
+ {
+ answ = utils.CRI("nMaxSend");
+ }
+ catch
+ { }
+ return answ;
+ }
+ }
+
+ ///
+ /// 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");
+
+ ///
+ /// Max tentativi ping permessi (default: 5)
+ ///
+ protected int maxPingRetry { get; set; } = 5;
+
+ ///
+ /// Coda massima ammessa per FLog (se <=0 disattivata...)
+ ///
+ protected int maxQueueFLog { get; set; } = utils.CRI("maxQueueFLog");
+
+ ///
+ /// Valore MINIMO limite x decidere invio di dati come array Json
+ ///
+ protected int minJsonData { get; set; } = utils.CRI("minJsonData");
+
+ ///
+ /// 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; }
+
+ ///
+ /// 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;
+ }
+ }
+
+ ///
+ /// 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;
+ }
+ }
+
+ ///
+ /// Secondi standard x veto check status e log
+ ///
+ protected int vetoSeconds { get; set; } = utils.CRI("vetoSeconds");
+
+ #endregion Protected Properties
+
+ #region Public Properties
+
///
/// Verifica se sia in modalità DEMO avanzata (campionamento da set di valori ammessi...)
///
@@ -374,1983 +727,6 @@ namespace IOB_WIN
}
}
- ///
- /// 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)
- {
- 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;
- }
- }
-
- ///
- /// 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
- {
- 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");
-
- ///
- /// 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)
- {
- 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}");
- }
- }
- 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();
- }
-
- ///
- /// 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;
- }
-
- #region metodi adapter
-
- protected bool _connOk = false;
-
- ///
- /// 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;
- }
- }
-
- ///
- /// 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;
- }
- }
-
- ///
- /// 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)
- {
- 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);
- }
-
- #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)
///
@@ -2464,6 +840,88 @@ namespace IOB_WIN
}
}
+ ///
+ /// Salva verifica stato connessione OK
+ ///
+ ///
+ public virtual bool connectionOk
+ {
+ get
+ {
+ return _connOk || DemoIn;
+ }
+ set
+ {
+ _connOk = 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;
+ }
+ }
+
///
/// Verifica se sia machcina multi = DoppioPallet da CONF
///
@@ -2492,6 +950,82 @@ namespace IOB_WIN
}
}
+ ///
+ /// 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)
+ {
+ lastPeriodicLog = DateTime.Now;
+ }
+
+ return answ;
+ }
+ }
+
+ ///
+ /// indica se ping disabilitato da optPar
+ ///
+ public bool pingDisabled
+ {
+ get
+ {
+ bool answ = false;
+ bool.TryParse(getOptPar("NO_PING"), out answ);
+ return answ;
+ }
+ }
+
///
/// URL per INVIO IN BLOCCO di un INCREMENTO x contapezzi (quelli della macchina: PLC/CNC)...
///
@@ -2854,154 +1388,1279 @@ namespace IOB_WIN
}
///
- /// Valore del num max invii consecutivi da coda...
+ /// Verifica SE si debba fare log verboso (verboso + ogni tot letture IN)
///
- 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
+ public bool verboseLog
{
get
{
bool answ = false;
- // controllo se ho veto al check...
- if (dtVetoCheckIOB < DateTime.Now)
+ int logEvery = utils.CRI("logEvery");
+ if (logEvery < 1)
{
- 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;
+ logEvery = 10;
}
+
+ answ = utils.CRB("verbose") && (nReadIN % logEvery == 0);
return answ;
}
}
+ #endregion Public Properties
+
+ #region Private Methods
+
///
- /// test ping all'indirizzo impostato nei parametri
+ /// Verifica e se necessario comprime directory log...
///
- ///
- private IPStatus testPingServer
+ private void checkShrinkDir()
{
- get
+ string path = string.Format("{0}logs\\{1}", AppDomain.CurrentDomain.BaseDirectory, cIobConf.codIOB);
+ baseUtils.shrinkDir(path);
+ }
+
+ ///
+ /// 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
+ }
+
+ ///
+ /// 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)
{
- IPStatus answ = IPStatus.Unknown; ;
- IPAddress address;
- PingReply reply;
- using (Ping pingSender = new Ping())
+ 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++)
{
- 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)
+ // SE 1... impostiamo contatori al MAX
+ if (bitsUp[i] == 1)
{
- lgInfo($"Ping KO | reply: {reply.Status} --> retry");
- reply = pingSender.Send(address, pingServerMsTimeout * numRetry / 2);
- numRetry++;
- if (reply.Status == IPStatus.Success)
+ // se era zero indico START blink...
+ if (i_counters[i] == 0)
{
- lgInfo("PING OK!");
- break;
+ 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);
+ }
}
}
}
- answ = reply.Status;
- return answ;
}
}
+ ///
+ /// 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;
+ }
+ }
+
+ ///
+ /// 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;
+ }
+
+ ///
+ /// 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("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)
+ {
+ 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));
+ }
+ }
+ }
+ }
+
+ private void reportDataProc()
+ {
+ // update valori visualizzazione...
+ parentForm.dataProcLabel = string.Format("RAW: {0} --> IN: {1} --> OUT: {2}", nReadIN, nReadFilt, nSendOut);
+ }
+
+ ///
+ /// 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;
+ }
+
+ 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);
+ }
+ }
+
+ ///
+ /// 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++)
+ {
+ // 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;
+ }
+ }
+ }
+ }
+
+ ///
+ /// 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);
+ }
+
+ ///
+ /// 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 Private Methods
+
+ #region Protected Methods
+
+ ///
+ /// 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;
+ }
+ }
+
+ ///
+ /// 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;
+ }
+
+ ///
+ /// 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;
+ }
+
+ ///
+ /// 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);
+ }
+
+ ///
+ /// 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));
+ }
+ }
+
+ ///
+ /// 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)
+ {
+ 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}");
+ }
+ }
+ 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");
+ }
+
+ ///
+ /// 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 != null)
+ {
+ 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());
+ }
+
+ ///
+ /// 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();
+ }
+
+ #endregion Protected Methods
+
+ #region Public Methods
+
///
/// Effettua chiamata URL e restituisce risultato
///
@@ -3049,6 +2708,13 @@ namespace IOB_WIN
return answ;
}
+ ///
+ /// processa dataLayer e se necessario salva/mostra
+ ///
+ public static void checkSavePersDataLayer()
+ {
+ }
+
public static string GetMACAddress()
{
NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
@@ -3065,6 +2731,10 @@ namespace IOB_WIN
return sMacAddress;
}
+ public static void resetDebugConsole()
+ {
+ }
+
///
/// Reset dei webclients
///
@@ -3073,6 +2743,257 @@ namespace IOB_WIN
utils.resetWebClients();
}
+ ///
+ /// 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;
+ }
+ }
+
+ ///
+ /// 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);
+ }
+
+ ///
+ /// 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;
+ }
+ }
+
+ ///
+ /// 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);
+ }
+
+ ///
+ /// 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;
+ }
+
+ ///
+ /// 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;
+ }
+
///
/// Effettua chaimata x split ODL
///
@@ -3165,6 +3086,157 @@ namespace IOB_WIN
return fatto;
}
+ ///
+ /// 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);
+ }
+
///
/// Recupera eventuali allarmi CNC...
///
@@ -3184,6 +3256,25 @@ namespace IOB_WIN
return outVal;
}
+ ///
+ /// 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;
+ }
+
///
/// Restituisce info OVERRIDES
///
@@ -3212,6 +3303,60 @@ namespace IOB_WIN
return outVal;
}
+ ///
+ /// 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;
+ }
+
///
/// Restituisce un payload in formato json della lista di valori ricevuta
///
@@ -3298,6 +3443,87 @@ namespace IOB_WIN
return answ;
}
+ ///
+ /// 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;
+ }
+
+ ///
+ /// 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));
+ }
+ }
+
+ ///
+ /// 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;
+ }
+
///
/// Verifica e processing x gestione ODL automatica
///
@@ -3622,6 +3848,55 @@ namespace IOB_WIN
}
}
+ ///
+ /// 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;
+ }
+
///
/// Classe fittizia in caso di processing task in VHF
///
@@ -3636,6 +3911,118 @@ namespace IOB_WIN
{
}
+ ///
+ /// 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");
+ }
+ }
+
+ ///
+ /// 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;
+ }
+
///
/// Effettua lettura dati
/// Parametri da aggiornare x display in form
@@ -3683,6 +4070,45 @@ namespace IOB_WIN
lastReadPLC = DateTime.Now;
}
+ ///
+ /// 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
+ { }
+ }
+
+ ///
+ /// Metodo generico di reset contapezzi...
+ ///
+ ///
+ public virtual bool resetcontapezziPLC()
+ {
+ return false;
+ }
+
///
/// metodo dummy x salvataggio aree memoria conf x CN
///
@@ -3692,528 +4118,23 @@ namespace IOB_WIN
}
///
- /// Processo la coda SignalIN...
+ /// Salva valori indicati in prod data
///
- public void svuotaCodaSignIN()
+ /// Item KVP di cui salvare i dati in currProdData come chiave/valore
+ ///
+ public void saveProdData(KeyValuePair item)
{
- // verifico SE la coda abbia dei valori...
- if (QueueIN.Count > 0)
+ // imposto i valori...
+ if (currProdData.ContainsKey(item.Key))
{
- // 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)
- {
- // SOLO SE online la macchina...
- if (IobOnline)
- {
- 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)
- {
- // 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);
- }
- }
- }
- else
- {
- lgInfo("Impossibile trySendPzCountBlock: IobOnline è false");
- }
+ currProdData[item.Key] = item.Value;
}
else
{
- lgInfo("Impossibile trySendPzCountBlock: MPOnline è false");
+ currProdData.Add(item.Key, item.Value);
}
}
- ///
- /// 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;
- }
-
- ///
- /// 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)
- {
- 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("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)
- {
- 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));
- }
- }
- }
- }
-
- ///
- /// 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++)
- {
- // 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;
- }
-
///
///
///
@@ -4238,168 +4159,6 @@ namespace IOB_WIN
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(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
///
@@ -4560,101 +4319,345 @@ namespace IOB_WIN
}
///
- /// Decodifica valore della coda IN nel formato
- /// answ[0]=dtEve
- /// answ[1]=valore
- /// answ[2]=counter
+ /// Metodo generico di IMPOSTAZIONE FORZATA del contapezzi...
///
- /// dtEve + '#' + value + '#' + cont
+ /// Pezzi richiesti
///
- protected static string[] qDecodeIN(string queueVal)
+ public virtual bool setcontapezziPLC(int newPzCount)
{
- string[] answ = null;
- if (!string.IsNullOrEmpty(queueVal))
+ return false;
+ }
+
+ ///
+ /// 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))
{
- try
+ TSVC_Data[VCName].dataArray.Add(VCVal);
+ // ora verifico scadenza...
+ if (TSVC_Data[VCName].DTStart.AddSeconds(TSVC_Data[VCName].Period) < DateTime.Now)
{
- answ = queueVal.Split('#');
+ answ = true;
}
- catch
- { }
}
return answ;
}
- #endregion gestione code (accumulo, invio)
-
- #region gestione dataMonitor (update visualizzazione valori)
-
///
- /// Accoda (visualizzando in cima allo stack) la nuova stringa di output per area OTHER DATA
+ /// Avvia l'adapter sulla porta richiesta
///
- ///
- public void accodaOtherData(string newLine)
+ /// indica se sia richeisto di SVUOTARE le code delel info
+ public virtual void startAdapter(bool resetQueue)
{
- // 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);
+ 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!");
}
///
- /// Update visualizzaizone BIT in ingresso
- /// Parametri da aggiornare x display in form
+ /// ferma l'adapter...
///
- public void displayInData(ref newDisplayData currDispData)
+ /// 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 (currDispData != null)
+ if (forceDequeue)
{
- // mostro update...
- string newString = string.Format("{0:0000}|{1}", counterSigIN, utils.IntToBinStr(B_output, 8));
- currDispData.newSignalData = newString;
+ // 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;
+ }
+
+ ///
+ /// 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;
+ }
+ }
}
}
///
- /// Mostra cosa ha/avrebbe inviato
+ /// Metodo base connessione...
///
- ///
- public void displayOtherData(string newData)
+ public virtual void tryConnect()
{
- // mostro update...
- accodaOtherData(newData);
+ dtAvvioAdp = DateTime.Now;
}
///
- /// Effettua un trim della stringa al numero max di linee da mostrare a video
+ /// Metodo base disconnessione...
///
- ///
+ public virtual void tryDisconnect()
+ {
+ }
+
+ ///
+ /// 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)
+ {
+ 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)
+ {
+ // 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);
+ }
+ }
+ }
+ 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 limitLine2show(string newString)
+ public string urlDataBlock(urlType tipoUrl)
{
- // 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;
+ // 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;
}
///
- /// Mostra i dati grezzi letti in esadecimale
- /// Parametri da aggiornare x display in form
+ /// Fornisce URL di tipo FluxLog
///
- private void displayRawData(ref newDisplayData currDispData)
+ /// valore salvato in coda nel formato dtEve#flux#valore#counter
+ ///
+ public string urlFLog(string queueVal)
{
- // mostro update...
- string newString = string.Format("{0:X}", B_input);
- currDispData.newInData = newString;
-#if false
- // salvo coda debug...
- QueueDebug.Enqueue(B_input);
-#endif
+ // 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;
}
- #endregion gestione dataMonitor (update visualizzazione valori)
+ ///
+ /// 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 Public Methods
}
///
diff --git a/Jenkinsfile b/Jenkinsfile
index b519a38b..2254ae71 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -9,7 +9,7 @@ pipeline {
steps {
/* calcolo numero versione... diverso x branch MASTER/DEVELOP */
script {
- withEnv(['NEXT_BUILD_NUMBER=723']) {
+ withEnv(['NEXT_BUILD_NUMBER=724']) {
// env.versionNumber = VersionNumber(versionNumberString : '3.3.${BUILD_DATE_FORMATTED, "yyMM"}.${BUILDS_ALL_TIME}', projectStartDate : '2006-01-01', skipFailedBuilds: true)
env.versionNumber = VersionNumber(versionNumberString : '3.3.${BUILD_DATE_FORMATTED, "yyMM"}.${BUILDS_ALL_TIME}', projectStartDate : '2006-01-01', skipFailedBuilds: true, overrideBuildsAllTime: '${NEXT_BUILD_NUMBER}')
env.APP_NAME = 'MAPO-IOB-WIN'
diff --git a/gitSpread.bat b/gitSpread.bat
index 15fb39a3..11d43636 100644
--- a/gitSpread.bat
+++ b/gitSpread.bat
@@ -23,7 +23,7 @@ if %pushRemote% GTR 1 ( git push gitlab.steamware %baseBranch%:develop )
if %pushRemote% GTR 2 ( git push gitlab.steamware %baseBranch%:IOB-NET )
if %pushRemote% GTR 2 ( git push gitlab.steamware %baseBranch%:IOB/Euromap63 )
if %pushRemote% GTR 2 ( git push gitlab.steamware %baseBranch%:IOB/MTC )
-if %pushRemote% GTR 2 ( git push gitlab.steamware %baseBranch%:IobMan )
+if %pushRemote% GTR 1 ( git push gitlab.steamware %baseBranch%:IobMan )
if %pushRemote% GTR 1 ( git push gitlab.steamware %baseBranch%:master )
ECHO on
\ No newline at end of file