From 1a2e5639d8ce5b089c98a9b7e9a0fe2f8e631fb2 Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Sat, 28 May 2022 12:27:27 +0200 Subject: [PATCH 01/13] Update (temporaneo) x gestione IcoelDb --- IOB-UT-NEXT/IOB-UT-NEXT.csproj | 4 ++-- IOB-UT-NEXT/packages.config | 2 +- IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_002.ini | 2 ++ IOB-WIN-NEXT/IobGeneric.cs | 2 +- IOB-WIN-NEXT/IobIcoelDb.cs | 11 +++++++---- IOB-WIN-NEXT/IobIcoelSoap.cs | 5 +++-- IOB-WIN-NEXT/packages.config | 2 +- 7 files changed, 17 insertions(+), 11 deletions(-) diff --git a/IOB-UT-NEXT/IOB-UT-NEXT.csproj b/IOB-UT-NEXT/IOB-UT-NEXT.csproj index 8dbe51fe..f9425e43 100644 --- a/IOB-UT-NEXT/IOB-UT-NEXT.csproj +++ b/IOB-UT-NEXT/IOB-UT-NEXT.csproj @@ -59,8 +59,8 @@ ..\packages\SharpZipLib.1.3.1\lib\net45\ICSharpCode.SharpZipLib.dll - - ..\packages\MapoSDK.6.14.2204.2616\lib\MapoSDK.dll + + ..\packages\MapoSDK.6.14.2205.2808\lib\MapoSDK.dll ..\packages\Microsoft.Bcl.AsyncInterfaces.6.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll diff --git a/IOB-UT-NEXT/packages.config b/IOB-UT-NEXT/packages.config index 70e045e6..26591de3 100644 --- a/IOB-UT-NEXT/packages.config +++ b/IOB-UT-NEXT/packages.config @@ -1,6 +1,6 @@  - + diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_002.ini b/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_002.ini index 92c2eae4..9e0105e8 100644 --- a/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_002.ini +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_002.ini @@ -67,6 +67,8 @@ ENABLE_DATA_FILTER=TRUE ENABLE_CLI_RESTART=TRUE VETO_SIG_IN=TRUE +; clock base (da 10ms) +timerIntMs=50 ; conf parametri memoria READ/WRITE PARAM_CONF=GIACO_ICOEL_002.json diff --git a/IOB-WIN-NEXT/IobGeneric.cs b/IOB-WIN-NEXT/IobGeneric.cs index 6a63763d..2ab1227f 100644 --- a/IOB-WIN-NEXT/IobGeneric.cs +++ b/IOB-WIN-NEXT/IobGeneric.cs @@ -3509,7 +3509,7 @@ namespace IOB_WIN_NEXT /// /// /// - public void accodaRawData(IOB_UT_NEXT.rawTransfType mesType, object mesContent) + public void accodaRawData(rawTransfType mesType, object mesContent) { /*-------------------------------- * nuova gestione coda dictionary diff --git a/IOB-WIN-NEXT/IobIcoelDb.cs b/IOB-WIN-NEXT/IobIcoelDb.cs index 3da0998c..1ec0d9dc 100644 --- a/IOB-WIN-NEXT/IobIcoelDb.cs +++ b/IOB-WIN-NEXT/IobIcoelDb.cs @@ -31,10 +31,13 @@ namespace IOB_WIN_NEXT * - init obj comunicazione da conf e nuget * - lanciare sync e verifica stato sync */ - string connEntrataFrontiera = utils.CRS("EntrataFrontiera"); - string connTrackerLotti = utils.CRS("TrackerLotti"); - string connExportIcoel = utils.CRS("ExportIcoel"); - string connSyncState = utils.CRS("SyncState"); + + string connEntrataFrontiera = getOptPar("EntrataFrontiera"); + string connTrackerLotti = getOptPar("TrackerLotti"); + string connExportIcoel = getOptPar("ExportIcoel"); + string SyncStateDb = getOptPar("SyncStateDb"); + + string connSyncState = $"data source={syncStateDb};initial catalog=MoonPro_ISF;persist security info=True;user id=egalware;password=egalware2022;MultipleActiveResultSets=True;App=IOB-WIN-NEXT" dbProxy = new DbProxy(connEntrataFrontiera, connTrackerLotti, connExportIcoel, connSyncState); diff --git a/IOB-WIN-NEXT/IobIcoelSoap.cs b/IOB-WIN-NEXT/IobIcoelSoap.cs index ab5dedd1..af042828 100644 --- a/IOB-WIN-NEXT/IobIcoelSoap.cs +++ b/IOB-WIN-NEXT/IobIcoelSoap.cs @@ -65,8 +65,9 @@ namespace IOB_WIN_NEXT #if false // accodo invio! string rawBatch = JsonConvert.SerializeObject(currBatch); -#endif accodaRawData(IOB_UT_NEXT.rawTransfType.IcoelBatch, currBatch); +#endif + accodaRawData(rawTransfType.IcoelBatch, currBatch); } } else @@ -157,7 +158,7 @@ namespace IOB_WIN_NEXT string rawBatch = JsonConvert.SerializeObject(currBatch); accodaRawData(IOB_UT_NEXT.rawTransfType.IcoelBatch, rawBatch); #endif - accodaRawData(IOB_UT_NEXT.rawTransfType.IcoelBatch, currBatch); + accodaRawData(rawTransfType.IcoelBatch, currBatch); currBatchList = currBatch; } } diff --git a/IOB-WIN-NEXT/packages.config b/IOB-WIN-NEXT/packages.config index e0471635..f9c592cd 100644 --- a/IOB-WIN-NEXT/packages.config +++ b/IOB-WIN-NEXT/packages.config @@ -5,7 +5,7 @@ - + From aa8bf8861f6579eb561941de72b0fcf8ea6494fc Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Sat, 28 May 2022 12:43:38 +0200 Subject: [PATCH 02/13] Modifica x demoltiplica freq controlli dynData x icoel SOAP --- IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_002.ini | 1 + IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_003.ini | 4 + IOB-WIN-NEXT/IOB-WIN-NEXT.csproj | 6 +- IOB-WIN-NEXT/IobGeneric.cs | 6958 ++++++++++---------- IOB-WIN-NEXT/IobIcoelDb.cs | 177 +- IOB-WIN-NEXT/packages.config | 2 +- 6 files changed, 3598 insertions(+), 3550 deletions(-) diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_002.ini b/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_002.ini index 9e0105e8..ce3224ff 100644 --- a/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_002.ini +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_002.ini @@ -63,6 +63,7 @@ MIN_SEND_PZC_BLOCK=0 MAX_SEND_PZC_BLOCK=100 ENABLE_DYN_DATA=TRUE FORCE_DYN_DATA=TRUE +DEM_FACT_DYN_DATA=6 ENABLE_DATA_FILTER=TRUE ENABLE_CLI_RESTART=TRUE VETO_SIG_IN=TRUE diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_003.ini b/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_003.ini index decae0b2..88a328a2 100644 --- a/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_003.ini +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_003.ini @@ -63,9 +63,13 @@ MIN_SEND_PZC_BLOCK=0 MAX_SEND_PZC_BLOCK=100 ENABLE_DYN_DATA=TRUE FORCE_DYN_DATA=TRUE +DEM_FACT_DYN_DATA=5 ENABLE_DATA_FILTER=TRUE ENABLE_CLI_RESTART=TRUE VETO_SIG_IN=TRUE +SyncStateDb=localhost\sqlexpress +SyncStateUser=egalware +SyncStatePwd=egalware2022 ; clock base (da 10ms) timerIntMs=10 diff --git a/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj b/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj index 60a702f1..a229b9bf 100644 --- a/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj +++ b/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj @@ -87,10 +87,10 @@ ..\packages\EasyModbusTCP.5.6.0\lib\net40\EasyModbus.dll - ..\packages\EgwProxy.Icoel.3.6.2205.2617\lib\EgwProxy.Icoel.dll + ..\packages\EgwProxy.Icoel.3.6.2205.2812\lib\EgwProxy.Icoel.dll - ..\packages\EgwProxy.Icoel.3.6.2205.2617\lib\EgwProxy.Icoel.DataLayer.dll + ..\packages\EgwProxy.Icoel.3.6.2205.2812\lib\EgwProxy.Icoel.DataLayer.dll ..\packages\EgwProxy.MultiCncLib.3.6.2205.2319\lib\EgwProxy.MultiCncLib.dll @@ -316,6 +316,8 @@ PreserveNewest + + Always diff --git a/IOB-WIN-NEXT/IobGeneric.cs b/IOB-WIN-NEXT/IobGeneric.cs index 2ab1227f..8c0c5ddc 100644 --- a/IOB-WIN-NEXT/IobGeneric.cs +++ b/IOB-WIN-NEXT/IobGeneric.cs @@ -22,173 +22,6 @@ namespace IOB_WIN_NEXT { public class IobGeneric { - #region Protected Fields - - /// - /// wrapper di log - /// - protected static Logger lg; - - protected bool _connOk = false; - - /// - /// 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; - - /// - /// Num errori check alive - /// - protected int currAliveErrors = 0; - - /// - /// Variabile numero errori vari (in lettura) --> se supera soglia maxErroriCheck --> disconnette - /// - protected int numErroriCheck = 0; - - /// - /// Soglia massima errori priam di disconnesisone automatica - /// - protected int maxErroriCheck = 100; - - /// - /// Dizionario valori impostati x produzione - /// - protected Dictionary currProdData = new Dictionary(); - - /// - /// num corrente errori read PLC - /// - protected int currReadErrors = 0; - - /// - /// num errori send - /// - protected int currSendErrors = 0; - - /// - /// Periodo wathdog di default (2 sec se non specificato) - /// - protected int watchDogPeriod = 2; - - /// - /// 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; - - /// - /// Dizionario ULTIMI valori impostati x produzione - /// - protected Dictionary lastProdData = new Dictionary(); - - /// - /// Ultimo invio contapezzi (x invio delayed) - /// - protected DateTime lastPzCountSend; - - - /// - /// Ultimo LOG registrazione avvio (x ridurre log notturni...) - /// - protected DateTime lastLogStartup = DateTime.Today.AddHours(-1); - - /// - /// Veto per registrazione completa log di startup (minuti) - /// - protected int vetoLogStartupDuration = 60; - - /// - /// 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; - - /// - /// Num massimo di errori in funzionalità check alive - /// - protected int maxAliveErrors = utils.CRI("maxAliveErrors"); - - /// - /// Num massimo di errori di rete read (dal PLC) - /// - protected int maxReadErrors = utils.CRI("maxReadErrors"); - - /// - /// Num massimodi errori di rete send al server - /// - protected int maxSendErrors = utils.CRI("maxSendErrors"); - - /// - /// 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 /// @@ -196,11 +29,6 @@ namespace IOB_WIN_NEXT /// public bool adpRunning = false; - /// - /// Valore di attesa (random) dopo ogni invio x evitare congestione send... - /// - protected static int urlRandWait = 0; - /// /// valore booleano di check se l'adapter STIA SALVANDO /// @@ -362,7 +190,8 @@ namespace IOB_WIN_NEXT public Dictionary persistenceLayer; /// - /// Determina se utilizzare blocchi di memoria IOT contigui (e quindi processing "monoblocco" semplificato"= + /// Determina se utilizzare blocchi di memoria IOT contigui (e quindi processing + /// "monoblocco" semplificato"= /// public bool procIotMem = false; @@ -387,7 +216,7 @@ namespace IOB_WIN_NEXT public ConcurrentQueue QueueMessages = new ConcurrentQueue(); /// - /// Oggetto della coda degli elementi di tipo RawTransf (e non ancora trasmessi) + /// Oggetto della coda degli elementi di tipo RawTransf (e non ancora trasmessi) /// NB: sono salvati serializzati come stringhe /// public ConcurrentQueue QueueRawTransf = new ConcurrentQueue(); @@ -497,387 +326,6 @@ namespace IOB_WIN_NEXT #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); - IobOnline = answ; - } - 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; - // se disabilitato salto... - if (pingDisabled) - { - answ = IPStatus.Success; - } - else - { - IPAddress address; - PingReply reply; - var rand = new Random(); - int pingTOut = 500; - using (Ping pingSender = new Ping()) - { - address = IPAddress.Loopback; - int maxRetry = maxPingRetry + 1; - int numRetry = 1; - string ipAddr = cIobConf.serverData.MPIP.Replace($"{cIobConf.serverData.TRANSP}://", ""); - // fix se fosse ip + porta... - if (ipAddr.IndexOf(":") >= 0) - { - ipAddr = ipAddr.Substring(0, ipAddr.IndexOf(":")); - } - IPAddress.TryParse(ipAddr, out address); - // se null --> provo DNS... - if (address == null) - { - var rawAddresses = Dns.GetHostAddresses(ipAddr); - if (rawAddresses.Length > 0) - { - address = rawAddresses[0]; - } - } - try - { - // se != null --> uso address... - if (address != null) - { - pingTOut = rand.Next(200, 400); - reply = pingSender.Send(address, pingTOut); - } - else - { - pingTOut = rand.Next(300, 600); - reply = pingSender.Send(cIobConf.cncIpAddr, pingTOut); - } - } - catch (Exception exc) - { - pingTOut = rand.Next(100, 200); - reply = pingSender.Send(IPAddress.Loopback, pingTOut); - lgError($"ping to loopback addres per eccezione:{Environment.NewLine}{exc}"); - } - // se ho timeout riprovo... - while (reply.Status != IPStatus.Success && numRetry < maxRetry) - { - Thread.Sleep(rand.Next(50, 200)); - pingTOut = pingServerMsTimeout * numRetry / 2; - reply = pingSender.Send(address, pingTOut); - numRetry++; - if (reply.Status == IPStatus.Success) - { - lgInfo("Server PING OK!"); - break; - } - else - { - lgInfo($"Server Ping KO | reply: {reply.Status} --> retry | TimeOut: {pingTOut}"); - } - } - } - 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; - } - } - - /// - /// Indica il counter della key richiesta attiva - /// - gestito tramite Redis - /// - a scadenza 25h - /// - incrementato ogni invio di auto ODL - /// - protected int countKeyRichiesta - { - get - { - // calcolo key odierna - int answ = redisMan.getKReqCount(dailyKey); - return answ; - } - set - { - // calcolo key odierna - redisMan.setKReqCount(dailyKey, value); - } - } - - protected string dailyKey - { - get - { - return DateTime.Today.ToString("yyMMdd"); - } - } - - /// - /// Variabile di appoggio GLOBALE x indicare che si può forzare reset contapezzi con macchina in RUN - /// - protected bool forceResetInRun { get; set; } = false; - - /// - /// Variabile di appoggio GLOBALE x indicare macchina RUN (es x gestione su reset pezzi) - /// - protected bool isRunning { get; set; } = false; - - /// - /// 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"); - /// - /// Coda massima ammessa per FLog (se <=0 disattivata...) - /// - protected int maxQueueRawTransf { get; set; } = utils.CRI("maxQueueRawTransf"); - - /// - /// Valore MINIMO limite x decidere invio di dati come array Json - /// - protected int minJsonData { get; set; } = utils.CRI("minJsonData"); - - protected string nextKeyRich - { - get - { - return $"{dailyKey}{countKeyRichiesta:00}"; - } - } - - /// - /// 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; } - - /// - /// Indica se sia stato resettato un contapezzi - /// - protected bool pzCountResetted { get; set; } = false; - - /// - /// 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; - } - } - - /// - /// Indica se vada inviata la key richiesta con lo split/autoODL - /// - protected bool sendKeyRichiesta { get; set; } = false; - - /// - /// 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; - int pingMsTimeout = cIobConf.pingMsTimeout; - IPAddress.TryParse(cIobConf.cncIpAddr, out address); - try - { - // se != null --> uso address... - if (address != null) - { - reply = pingSender.Send(address, pingMsTimeout); - } - else - { - reply = pingSender.Send(cIobConf.cncIpAddr, pingMsTimeout); - } - } - catch - { - reply = pingSender.Send(IPAddress.Loopback, 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 /// @@ -1112,23 +560,23 @@ namespace IOB_WIN_NEXT /// public int counterFLog { get; set; } - /// - /// Contatore x invio dati SignalIN - /// - public int counterSigIN { get; set; } - /// /// Contatore x invio dati RawTransf /// public int counterRawTransf { get; set; } + /// + /// Contatore x invio dati SignalIN + /// + public int counterSigIN { get; set; } + /// /// Contatore x invio dati UserLog /// public int counterULog { get; set; } /// - /// Verifica se sia in modalità DEMO --> da tipo IOB SIMULA... + /// Verifica se sia in modalità DEMO --> da tipo IOB SIMULA... /// public bool DemoIn { @@ -1227,7 +675,8 @@ namespace IOB_WIN_NEXT public string lastUrl { get; set; } /// - /// Valore massimo accettato x incremento pezzi letti dal PLC (valore moltiplicato per 100... 200% --> 200) + /// Valore massimo accettato x incremento pezzi letti dal PLC (valore moltiplicato per + /// 100... 200% --> 200) /// public int maxPzDeltaPerc { @@ -1722,813 +1171,2847 @@ namespace IOB_WIN_NEXT #endregion Public Properties - #region Private Methods + #region Public Methods /// - /// Verifica e se necessario comprime directory log... + /// Effettua chiamata URL e restituisce risultato /// - private void checkShrinkDir() + /// + /// invio in modalità async (NON GARANTITO ordine...) + /// + public static string callUrl(string URL, bool doAsync) { - 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; - } - - /// - /// 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) + string answ = ""; + // Chiamata ASINCRONA + if (doAsync) { - B_output = B_input; + //Task resp = utils.callUrlAsync(URL); + //answ = resp.Result; + answ = utils.callUrlAsync(URL); + if (urlRandWait > 0) + { + Random rnd = new Random(); + Thread.Sleep(rnd.Next(urlRandWait / 10, urlRandWait)); + } + } + // chiamata SOLO NORMALE SINCRONA... + else + { + answ = utils.callUrl(URL); + if (urlRandWait > 0) + { + Random rnd = new Random(); + Thread.Sleep(rnd.Next(urlRandWait / 10, urlRandWait)); + } + } + return answ; + } + + /// + /// Effettua chiamata URL e restituisce risultato + /// + /// + /// + /// invio in modalità async (NON GARANTITO ordine...) + /// + public static string callUrlWithPayload(string URL, string payload, bool doAsync) + { + string answ = ""; + // Chiamata ASINCRONA + if (doAsync) + { + answ = utils.callUrlAsync(URL, payload); + if (urlRandWait > 0) + { + Random rnd = new Random(); + Thread.Sleep(rnd.Next(urlRandWait / 10, urlRandWait)); + } + } + // chiamata SOLO NORMALE SINCRONA... + else + { + answ = utils.callUrl(URL, payload); + if (urlRandWait > 0) + { + Random rnd = new Random(); + Thread.Sleep(rnd.Next(urlRandWait / 10, urlRandWait)); + } + } + return answ; + } + + /// + /// processa dataLayer e se necessario salva/mostra + /// + public static void checkSavePersDataLayer() + { + } + + public static string GetMACAddress() + { + NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces(); + String sMacAddress = string.Empty; + foreach (NetworkInterface adapter in nics) + { + if (string.IsNullOrEmpty(sMacAddress))// only return MAC Address from first card + { + IPInterfaceProperties properties = adapter.GetIPProperties(); + //sMacAddress = adapter.GetPhysicalAddress().ToString(); + sMacAddress = string.Join(":", (from z in adapter.GetPhysicalAddress().GetAddressBytes() select z.ToString("X2")).ToArray()); + } + } + return sMacAddress; + } + + public static void resetDebugConsole() + { + } + + /// + /// Reset dei webclients + /// + public static void resetWebClients() + { + 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 da coda FLog per superamento maxLengh: {currVal}"); + } + } + } + // loggo! + lgTrace(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 RawData + log + /// + /// + /// + public void accodaRawData(rawTransfType mesType, object mesContent) + { + /*-------------------------------- + * nuova gestione coda dictionary + * fixme todo da fare !!! + * + * - conterrà una lista di oggetti baseRawTransf + * - i dati vanno poi "scodati" dal + vecchio ed inviati a MP/IO + * - mostra un sunto delle info da inviare + * - accodamento vero e proprio + * - verifica (opzionale) coda massima x gestire roundRobin ultimi eventi + * - trace della coda + * - counter invio??? valutare se c'è dataora e poi sono da salvare su MongoDb / Redis + * + * */ + + // serializzo il valore... + BaseRawTransf newVal = new BaseRawTransf(DateTime.Now, mesContent, mesType); + string encodedVal = JsonConvert.SerializeObject(newVal); + // --> accodo (valore già formattato)! + QueueRawTransf.Enqueue(encodedVal); + // se abilitato controllo coda Max (superiore a 0...) + if (maxQueueRawTransf > 0) + { + // se ho una coda superiore a max ammesso + if (QueueRawTransf.Count > maxQueueRawTransf) + { + // elimino valori iniziali fino a tornare al max ammesso... + while (QueueRawTransf.Count > maxQueueRawTransf) + { + string currVal = ""; + QueueRawTransf.TryDequeue(out currVal); + lgInfo($"Eliminazione da coda RawTransf per superamento maxLengh: {currVal}"); + } + } + } + // loggo! + lgTrace(string.Format("[QUEUE-RTRANSF] {0}", encodedVal)); + counterRawTransf++; + if (counterRawTransf > 9999) + { + counterRawTransf = 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); + // verifico veto a invio status macchina + string keyName = "VETO_SIG_IN"; + if (getOptPar(keyName).ToUpper() == "TRUE") + { + lgTrace($"Filtrato accodamento valore da conf IOB | {keyName} | [QUEUE-IN] {qEncodeIN}"); } 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; + // --> accodo (valore già formattato)! + QueueIN.Enqueue(qEncodeIN); + // loggo! + lgTrace(string.Format("[QUEUE-IN] {0}", qEncodeIN)); + } + // aggiorno counters ed eventuale reset + nReadFilt++; + if (nReadFilt > int.MaxValue - 1) + { + nReadFilt = 0; // per evitare buffer overflow... + } - // 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++) + counterSigIN++; + if (counterSigIN > 9999) + { + counterSigIN = 0; + } + } + + /// + /// Accumula in coda i valori USER LOG e logga... + /// + /// VALORE RAW (x display) + /// VALORE già processato con qEncodeULog(...) + public void accodaUserLog(string val, string encodedVal) + { + // mostro dati variati letti... + displayOtherData(val); + // accodo IN PRIMIS al FluxLog --> accodo (valore già formattato)! + QueueULog.Enqueue(encodedVal); + + // loggo! + lgInfo(string.Format("[QUEUE-USER-LOG] {0}", encodedVal)); + counterULog++; + if (counterULog > 9999) + { + counterFLog = 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) + { + // controllo se memMap != null... + if (memMap != null) { - // SE 1... impostiamo contatori al MAX - if (bitsUp[i] == 1) + bool taskOk = false; + string taskVal = ""; + // cerco task specifici: se ho startSetup --> imposto bit DBB701.DBB0.4 + foreach (var item in task2exe) { - // se era zero indico START blink... - if (i_counters[i] == 0) + taskOk = false; + taskVal = ""; + // converto richiesta in enum... + taskType tName = taskType.nihil; + Enum.TryParse(item.Key, out tName); + // controllo sulla KEY... + switch (tName) { - lgTrace("START BLINK: B{0}", i); + 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 != null && memMap.mMapWrite != null) + { + 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}"; + } + } + else + { + taskVal = $"NO MemMap found, SET task: {item.Key} --> {item.Value}"; + } + // salvo in currProd.. + saveProdData(new KeyValuePair(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 setParameter --> 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; } - // imposto comunque contatore al cambio fronte... - i_counters[i] = cIobConf.MAX_COUNTER_BLINK; + // aggiungo task! + taskDone.Add(item.Key, taskVal); } } - - // 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++) + else { - // se era a zero (invertito...) - if (bitsDown[i] == 1) + lgError($"Attenzione! memMap è nullo, non posso eseguire task2exe!"); + } + } + + return taskDone; + } + + /// + /// Effettua verifica delle memorie WRITE, se ci siano variazioni da riportare verso il PLC + /// Da impiegare ad esempio in caso di chiamate complesse (ad 2 aree di memoria condivise + /// sul PLC; coem commessa + articolo EWON) + /// + /// + /// 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) { - // SE è in corso il conteggio... - if (i_counters[i] > 0) + if (item.Key.StartsWith(keyStartSearch)) { - // decremento! - i_counters[i] -= 1; - // se è zero NON faccio nulla, altrimenti SOMMO... - if (i_counters[i] > 0) - { - B_output += 1 << i; - } - else - { - lgTrace("END BLINK: B{0}", i); - } + answ.Add(item.Key, item.Value); } } } } + return answ; } /// - /// Imposta eventuali altri valori default + /// forza reset ODL /// - private void fixDefaultPar() + public void forceResetOdl() { - // 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; - } - - string s_maxErrCheck = getOptPar("MAX_ERR_CHECK"); - if (!string.IsNullOrEmpty(s_maxErrCheck)) - { - int numErr = 50; - int.TryParse(s_maxErrCheck, out numErr); - maxErroriCheck = numErr; - } - - string s_watchDogPer = getOptPar("WATCHDOG_PERIOD"); - if (!string.IsNullOrEmpty(s_watchDogPer)) - { - int numPer = 3; - int.TryParse(s_watchDogPer, out numPer); - watchDogPeriod = numPer; - } + lgInfo("Registrato richiesta forzatura reset ODL"); + pzCountResetted = true; } /// - /// recupera valore salvato in persistence layer (se non c'è crea...) + /// Effettua chiamata x split ODL /// - /// /// - private string getStoredVal(string keyVal) + public bool forceSplitOdl() { - string value = ""; - try + bool fatto = false; + if (vetoSplit < DateTime.Now) { - if (persistenceLayer != null) + lgInfo("Richiesto forceSplitOdl"); + // imposto veto x 1 minuto ad altre chiamate... + vetoSplit = DateTime.Now.AddMinutes(1); + // eseguo SOLO SE sono online... + if (MPOnline && IobOnline) { - if (!persistenceLayer.TryGetValue(keyVal, out value)) + string fullUrl = ""; + string rawSplit = ""; + string IOB_MULTI_CNAME = ""; + string[] elencoMulti = null; + + try { - persistenceLayer.Add(keyVal, "0"); + /*************************************************** + * Descrizione procedura (OK X SIMULATORI...) + * + * - chiamata su MP/IO + * - verifica che su DB sia abilitato AUTO ODL + * - il server inserisce un evento fine prod HW 1 minuto prima e inizio setup HW + * - viene duplicato e chiuso ODL corrente + * - viene fatto partire ODL nuovo ADESSO + * - num pezzi come ODL precedente (o da media 3 ODL precedenti) + * - conferme pezzi & co... gestione NULL (NON SERVONO si tratta di impianti SENZA gestione vera ODL) + * - reset contapezzi PLC locale... + * + * + * + * DA VALUTARE (x macchine tipo linea con + impianti... es valvital) SE + * - creare una gestione ALTERNATIVA sul server che preveda impianto LEADER e impianti follower (RIGIDAMENTE CONFIGURATI) + * - ogni volta che si fa setup LEADER --> si ripete su impianti FOLLOWER (eventi!!!) + * - viene fatto reset contapezzi sui follower (+ altre operazioni opzionali, ES imposstazione nome commessa, quantità, articolo...) + * - viene fatto reset + nuovo ODL (con stessi articoli e quantità) su follower, SENZA avere gestione x ODL di un codice esterno (quindi registra TUTTO ma NON RITORNERA' dati non avendo link verso esterno) + * - serve NUOVA TABELLA delle macchine LEADER | FOLLOWER (1:n) e gestione da MP/IO + * + * ***************************************************/ + + if (isMulti) + { + // devo chiamare cambio ODL x OGNI tavola: mi servono i parametri opzionali... + IOB_MULTI_CNAME = getOptPar("IOB_MULTI_CNAME"); + elencoMulti = IOB_MULTI_CNAME.Split(','); + } + // se normale splitto! + if (!isMulti) + { + // invio chiamata URL x reset ODL su macchina + rawSplit = callUrl(urlForceSplit, false); + fatto = (rawSplit != "KO") ? true : false; + } + // se multi gestisco il bit delle tavole... + else + { + foreach (string item in elencoMulti) + { + // invio chiamata URL x reset ODL su macchina, ATTENZIONE scriviamo + // | al posto di "#" che in URL sarebbe filtrato... + fullUrl = $"{urlForceSplit}&multi={item}"; + rawSplit = callUrl(fullUrl, false); + lgDebug($"Esecuzione forceSplit | URL: {fullUrl} | esito: {rawSplit}"); + } + fatto = (rawSplit == "OK") ? true : false; + } + } + catch (Exception exc) + { + lgError($"Eccezione in forceSplitOdl{Environment.NewLine}{exc}"); + } + // se fatto --> resetto contapezzi!!! + if (fatto) + { + contapezziPLC = 0; + contapezziIOB = 0; } } + else + { + lgError("Richiesto forceSplitOdl ma MP/IOB offline --> NON eseguito"); + } } - catch (Exception exc) + else { - lgError(string.Format("Eccezione in getStoredVal: {0}{1}", Environment.NewLine, exc)); + lgError("Richiesto forceSplitOdl ma veto attivo --> NON eseguito"); } - return value; + return fatto; } /// - /// recupera valore salvato in persistence layer (se non c'è crea...) come double + /// effettua recupero dati ed invio valori modificati... /// - /// - /// - 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() + /// + public void getAndSend(gatherCycle ciclo) { // 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) + // IN OGNI CASO a prima di tutto EFFETTUO GESTIONE INVII dati da code!!! + try { - accodaSigIN(ref currDispData); + 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(); + processMem2Write(); + } + else if (ciclo == gatherCycle.LF) + { + processCustomTaskLF(); + 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... + lgTrace("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) + { + lgDebug("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($"Veto Time Elapsed | lastConnectTry: {lastConnectTry} | waitRecMSec {waitRecMSec} ms) | NOW tryConnect"); + lastConnectTry = DateTime.Now; + tryConnect(); + } + } + currDispData.semIn = Semaforo.SR; + processDisconnectedTask(); } raiseRefresh(currDispData); } - private void processMem2Write() + /// + /// Recupera eventuali allarmi CNC... + /// + public virtual Dictionary getCncAlarms() { - List updatedPar = new List(); - // ciclo tutti gli oggetti write x vedere se modificati... - foreach (var item in currProdData) + Dictionary outVal = new Dictionary(); + return outVal; + } + + /// + /// Restituisce info DINAMICHE + /// + /// + public virtual Dictionary getDynData() + { + Dictionary outVal = new Dictionary(); + return outVal; + } + + /// + /// Cerca se esiste il parametro opzionale e lo restituisce + /// + /// + /// + public string getOptPar(string key) + { + string answ = ""; + if (cIobConf.optPar.Count > 0) { - bool needWrite = false; - // li cerco su last... se non ci sono o modificati --> salvo da scrivere e copio - if (lastProdData.ContainsKey(item.Key)) + // controllo SE HO il parametro + if (cIobConf.optPar.ContainsKey(key)) { - // verifico se variato... - if (!item.Value.Equals(lastProdData[item.Key])) - { - needWrite = true; - lastProdData[item.Key] = item.Value; - } - } - // aggiungo - else - { - needWrite = true; - lastProdData.Add(item.Key, item.Value); - } - // se devo scrivere --> riporto - if (needWrite) - { - if (memMap.mMapWrite.ContainsKey(item.Key)) - { - // preparo obj da scrivere - objItem newWrite = new objItem() - { - uid = item.Key, - name = item.Key, - reqValue = memMap.mMapWrite[item.Key].value, - lastRequest = DateTime.Now, - writable = true - }; - updatedPar.Add(newWrite); - } + answ = cIobConf.optPar[key]; } } - // se ho da scrivere... scrivo TUTTI! - if (updatedPar.Count > 0) + return answ; + } + + /// + /// Restituisce info OVERRIDES + /// + /// + public virtual Dictionary getOverrides() + { + Dictionary outVal = new Dictionary(); + return outVal; + } + + /// + /// Restituisce programma in esecuzione + /// + public virtual string getPrgName() + { + return ""; + } + + /// + /// Restituisce info sistema + /// + /// + public virtual Dictionary getSysInfo() + { + Dictionary outVal = new Dictionary(); + return outVal; + } + + /// + /// 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 = -999999; + // cerco VC... + if (TSVC_Data.ContainsKey(VCName)) { - // scrivo valore! - lgInfo("Chiamata di plcWriteParams da processMem2Write"); - plcWriteParams(ref updatedPar); - // invio su cloud parametri! - string rawData = JsonConvert.SerializeObject(updatedPar); - utils.callUrl($"{urlUpdateWriteParams}", rawData); - lgInfo($"Notificato a server scrittura {updatedPar.Count} parametri"); + try + { + switch (TSVC_Data[VCName].Funzione) + { + case VC_func.POINT: + // prendo PRIMO + answ = TSVC_Data[VCName].dataArray.FirstOrDefault(); + break; + + case VC_func.AVG: + answ = TSVC_Data[VCName].dataArray.Average(); + break; + + case VC_func.MEDIAN: + answ = TSVC_Data[VCName].dataArray.Median(); + break; + + case VC_func.MIN: + answ = TSVC_Data[VCName].dataArray.Min(); + break; + + case VC_func.MAX: + default: + answ = TSVC_Data[VCName].dataArray.Max(); + break; + } + } + catch + { } + // 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 + /// + /// Tipo di URL (eventi / FLog) + /// elenco di valori da coda string salvata + /// + public string jsonPayload(urlType tipoUrl, List elencoValori) + { + string answ = ""; + if (elencoValori != null) + { + string[] valori; + int counter = 0; + DateTime dtEve = DateTime.Now; + switch (tipoUrl) + { + case urlType.FLog: + flogData currFlData = new flogData(); + flogJsonPayload fullFlObj = new flogJsonPayload(); + fullFlObj.fluxData = new List(); + // inizio processando ogni valore + foreach (var item in elencoValori) + { + valori = qDecodeIN(item); + CultureInfo provider = CultureInfo.InvariantCulture; + DateTime.TryParseExact(valori[0], "yyyyMMddHHmmssfff", provider, DateTimeStyles.AssumeLocal, out dtEve); + int.TryParse(valori[3], out counter); + currFlData = new flogData() + { + flux = valori[1], + valore = valori[2], + dtEve = dtEve, + dtCurr = DateTime.Now, + cnt = counter + }; + fullFlObj.fluxData.Add(currFlData); + } + // conversione finale + try + { + answ = JsonConvert.SerializeObject(fullFlObj); + } + catch (Exception exc) + { + lgError($"FLog Errore in costruzione jsonPayload:{Environment.NewLine}{exc}"); + } + break; + + case urlType.SignIN: + evData currSigData = new evData(); + evJsonPayload fullEvObj = new evJsonPayload(); + fullEvObj.eventList = new List(); + // inizio processando ogni valore + foreach (var item in elencoValori) + { + valori = qDecodeIN(item); + CultureInfo provider = CultureInfo.InvariantCulture; + DateTime.TryParseExact(valori[0], "yyyyMMddHHmmssfff", provider, DateTimeStyles.AssumeLocal, out dtEve); + int.TryParse(valori[2], out counter); + currSigData = new evData() + { + valore = valori[1], + dtEve = dtEve, + dtCurr = DateTime.Now, + cnt = counter + }; + fullEvObj.eventList.Add(currSigData); + } + // conversione finale + try + { + answ = JsonConvert.SerializeObject(fullEvObj); + } + catch (Exception exc) + { + lgError($"SignIN Errore in costruzione jsonPayload:{Environment.NewLine}{exc}"); + } + break; + + case urlType.RawTransf: + BaseRawTransf currRTData = new BaseRawTransf(); +#if false + rawTransfJsonPayload fullRTObj = new rawTransfJsonPayload(); + fullRTObj.rawTransfData = new List(); + // inizio processando ogni valore + foreach (var item in elencoValori) + { + try + { + currRTData = JsonConvert.DeserializeObject(item); + } + catch (Exception exc) + { + lgError($"Eccezione in deserializzazione BaseRawTransf:{Environment.NewLine}{exc}"); + } + fullRTObj.rawTransfData.Add(currRTData); + } + // conversione finale + try + { + answ = JsonConvert.SerializeObject(fullRTObj); + } + catch (Exception exc) + { + lgError($"RawTransf Errore in costruzione jsonPayload:{Environment.NewLine}{exc}"); + } +#endif + + // provo una serializzazione "brutale", ovvero aggiungo alla stringa il + // valore di testa... + string rawResult = ""; + foreach (var item in elencoValori) + { + rawResult += $"{item},"; + } + if (rawResult.Length > 0) + { + rawResult = rawResult.Substring(0, rawResult.Length - 1); + } + answ = "{" + $"\"rawTransfData\":[{rawResult}]" + "}"; + + break; + + case urlType.ULog: + int numVal = 0; + int matrOp = 0; + ulogData currUlData = new ulogData(); + ulogJsonPayload fullUlObj = new ulogJsonPayload(); + fullUlObj.fluxData = new List(); + // inizio processando ogni valore + foreach (var item in elencoValori) + { + valori = qDecodeIN(item); + CultureInfo provider = CultureInfo.InvariantCulture; + DateTime.TryParseExact(valori[0], "yyyyMMddHHmmssfff", provider, DateTimeStyles.AssumeLocal, out dtEve); + int.TryParse(valori[3], out matrOp); + int.TryParse(valori[5], out numVal); + int.TryParse(valori[6], out counter); + currUlData = new ulogData() + { + flux = valori[1], + valore = valori[2], + dtEve = dtEve, + dtCurr = DateTime.Now, + cnt = counter, + matrOpr = matrOp, + label = valori[4], + valNum = numVal + }; + fullUlObj.fluxData.Add(currUlData); + } + // conversione finale + try + { + answ = JsonConvert.SerializeObject(fullUlObj); + } + catch (Exception exc) + { + lgError($"ULog Errore in costruzione jsonPayload:{Environment.NewLine}{exc}"); + } + break; + + default: + break; + } + } + 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)); } } /// - /// Effettua gestioen programma: legge e mostra su display... + /// Processa un monitoredItem, e ritorna boolean SE richiede invio (cambio o scadenza) /// - private void processProgram() + /// + /// + /// + public bool monItem2Send(string newVal, DynDataItem item) { - string currPrgName = ""; - // se abilitata lettura prgName - if (enablePrgName) + bool answ = false; + if (item != null) { - if (connectionOk) + // controllo in base al tipo di function... + switch (item.func) { - currPrgName = getPrgName(); + 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 + /// + public void processAutoOdl() + { + bool fatto = false; + if (!string.IsNullOrEmpty(getOptPar("AUTO_CHANGE_ODL"))) + { + lgTrace("Richiesta processAutoOdl"); + string IOB_MULTI_CNAME = ""; + string[] elencoMulti = null; + string fullUrl = ""; + if (isMulti) + { + // devo chiamare cambio ODL x OGNI tavola: mi servono i parametri opzionali... + IOB_MULTI_CNAME = getOptPar("IOB_MULTI_CNAME"); + elencoMulti = IOB_MULTI_CNAME.Split(','); + } + // controllo SIA abilitato... + bool doProc = false; + DateTime adesso = DateTime.Now; + bool.TryParse(getOptPar("AUTO_CHANGE_ODL"), out doProc); + if (doProc) + { + lgTrace("AUTO_CHANGE_ODL abilitato"); + bool callChangeODL = false; + // modalità change ODL + string CHANGE_ODL_MODE = "TIME"; + if (!string.IsNullOrEmpty(getOptPar("CHANGE_ODL_MODE"))) + { + CHANGE_ODL_MODE = getOptPar("CHANGE_ODL_MODE"); + } + if (CHANGE_ODL_MODE == "PZCOUNT_RESET") + { + /* verifico se sia "armato" il reset cambio ODL, DEVO essere : + * - NON in produzione + * - contapezzi ACT < contapezzi LAST + * */ + lgTrace("processAutoOdl: caso PZCOUNT_RESET"); + if ((!isRunning || forceResetInRun) && pzCountResetted) + { + callChangeODL = true; + lgInfo("Attivato cambio ODL da PZCOUNT_RESET"); + } + else + { + lgInfo($"isRunning: {isRunning} | pzCountResetted: {pzCountResetted} | forceResetInRun: {forceResetInRun} | contapezziIOB: {contapezziIOB} | contapezziPLC: {contapezziPLC}"); + } + } + else if (CHANGE_ODL_MODE == "TIME") + { + // carico i parametri di configurazione x reset ODL... + string CHANGE_ODL_HOURS = getOptPar("CHANGE_ODL_HOURS"); + string CHANGE_ODL_IDLE_MIN = getOptPar("CHANGE_ODL_IDLE_MIN"); + if (!string.IsNullOrEmpty(CHANGE_ODL_HOURS) && !string.IsNullOrEmpty(CHANGE_ODL_IDLE_MIN)) + { + int minOdlDurHours = -1; + int minPlcIdelMin = -1; + int.TryParse(CHANGE_ODL_HOURS, out minOdlDurHours); + int.TryParse(CHANGE_ODL_IDLE_MIN, out minPlcIdelMin); + // controllo parametri validi + if (minOdlDurHours > 0 && minPlcIdelMin >= 0) + { + // leggo da server inizio ODL... se non multi 1 solo... + DateTime inizioOdl = DateTime.Now; + string rawDataInizio = ""; + if (!isMulti) + { + rawDataInizio = callUrl(urlInizioOdlIob, false); + DateTime.TryParse(rawDataInizio, out inizioOdl); + } + else + { + DateTime tmpData = DateTime.Now; + // prendo il + vecchio... + foreach (var item in elencoMulti) + { + fullUrl = $"{urlInizioOdlIob}|{item}"; + rawDataInizio = callUrl(fullUrl, false); + DateTime.TryParse(rawDataInizio, out tmpData); + inizioOdl = (tmpData < inizioOdl) ? tmpData : inizioOdl; + } + } + // verifico se sia scaduto... + if (inizioOdl.AddHours(minOdlDurHours) < adesso) + { + string rawIdle = ""; + int idlePeriod = 0; + if (!isMulti) + { + // controllo SE sono fermo (spento o in manuale) per il + // periodo minimo richiesto... + rawIdle = callUrl(urlIdleTime, false); + int.TryParse(rawIdle, out idlePeriod); + } + else + { + int tmpIdle = 0; + // prendo il + grande... + foreach (var item in elencoMulti) + { + fullUrl = $"{urlIdleTime}|{item}"; + rawIdle = callUrl(fullUrl, false); + int.TryParse(rawIdle, out tmpIdle); + idlePeriod = tmpIdle > idlePeriod ? tmpIdle : idlePeriod; + } + } + if (idlePeriod >= minPlcIdelMin) + { + callChangeODL = true; + } + } + } + } + } + + // vero processing... + if (callChangeODL) + { + lgTrace("Chiamata: processAutoOdl --> forceSplitODL"); + fatto = forceSplitOdl(); + pzCountResetted = false; + lgInfo("Esecuzione processAutoOdl completata --> pzCountResetted = false"); + } } else { - lgError("Errore connessione mancante x getPrgName"); + lgTrace("AUTO_CHANGE_ODL DISABILITATO"); + } + } + // loggo se fatto + if (fatto) + { + lgTrace("Effettuato processAutoOdl"); + } + } + + /// + /// Effettua processing degli allarmi CNC SE disponibili + /// + public void processCncAlarms() + { + if (utils.CRB("enableAlarms")) + { + Dictionary currAlarms = new Dictionary(); + if (connectionOk) + { + currAlarms = getCncAlarms(); + } + else + { + lgError("Errore connessione mancante x getCncAlarms"); + } + // verifico SE sia cambiato il programma... + if (currAlarms.Count > 0) + { + try + { + string sVal = ""; + if (lastAlarm != currAlarms["CNC_ALARM"]) + { + // salvo! + lastAlarm = currAlarms["CNC_ALARM"]; + // per ogni valore del dizionario mostro ed accodo! + foreach (var item in currAlarms) + { + sVal = string.Format("[CNC_ALARM]{0}|{1}", item.Key, item.Value); + // chiamo accodamento... + accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); + } + } + // accodo ALTRI allarmi NON CNC... + foreach (var item in currAlarms.Where(X => X.Key != "CNC_ALARM")) + { + sVal = $"{item.Key} | {item.Value}"; + accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); + } + } + catch (Exception exc) + { + lgError("Eccezione in processCncAlarms{0}{1}", Environment.NewLine, exc); + } + } + } + } + + /// + /// Effettua processing contapezzi (ed eventualmente alza il bit di contapezzo...) + /// + public virtual void processContapezzi() + { } + + /// + /// Effettua processing CUSTOM x l'IOB corrente (ed invia ad IO) (task svolto tipicamente + /// ogni 5 sec se base timer 10ms, vedere app.config) + /// + public virtual void processCustomTaskLF() + { } + + /// + /// Task periodici SE disconnesso + /// + public virtual void processDisconnectedTask() + { + } + + /// + /// Effettua processing del recupero dei valori dinamici: + /// es: speed (RPM, feedrate) degli assi, valori pressioni, temeprature + /// + public void processDynData() + { + bool enableByApp = utils.CRB("enableDynData"); + bool enableByIob = (getOptPar("ENABLE_DYN_DATA") == "TRUE"); + bool forceSendByIob = (getOptPar("FORCE_DYN_DATA") == "TRUE"); + Dictionary currDynData = new Dictionary(); + + if (enableByApp || enableByIob) + { + // verifico se ho fattore demoltiplica... + if (demFactDynData > 1) + { + lgTrace($"Non eseguo processDynData: fatt veto {demFactDynData}"); + // ricudo... + demFactDynData--; + } + else + { + lgInfo("Inizio processDynData"); + // sistemo il valore di demoltiplica a default + fixDemFactDynData(); + // proseguo + if (connectionOk) + { + currDynData = getDynData(); + try + { + string sVal = ""; + // se richiesto send diretto... + if (forceSendByIob) + { + // per ogni valore del dizionario mostro ed accodo! + foreach (var item in currDynData) + { + sVal = string.Format("[DYNDATA]{0}|{1}", item.Key, item.Value); + // chiamo accodamento... + accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); + } + } + // altrimenti verifico SE sia cambiato il valore dei DynData... + else if (lastDynDataCtrlVal != currDynData["DYNDATA"]) + { + // salvo! + lastDynDataCtrlVal = currDynData["DYNDATA"]; + // per ogni valore del dizionario mostro ed accodo! + foreach (var item in currDynData) + { + sVal = string.Format("[DYNDATA]{0}|{1}", item.Key, item.Value); + // chiamo accodamento... + accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); + } + } + // salvo array... + lastDynData = currDynData; + } + catch (Exception exc) + { + lgError(exc, "Eccezione in processDynData"); + } + } + else + { + lgError("Errore connessione mancante x getDynData"); + } + } + } + } + + /// + /// Processa gestione memoria x invio dati QUANDO IOB è disconnesso da CNC... + /// + public void processMemoryDiscon() + { + // init obj display + newDisplayData currDispData = new newDisplayData(); + // controllo contatore invio "keepalive"... invio solo a scadenza + if (DateTime.Now.Subtract(lastDisconnCheck).TotalSeconds > utils.CRI("disconMaxSec")) + { + // resetto tutti i vlaori BYTE IN/PREV/OUT... così invio macchina spenta... + B_input = 0; + B_output = 0; + B_previous = 0; + accodaSigIN(ref currDispData); + // update controllo + lastDisconnCheck = DateTime.Now; + } + raiseRefresh(currDispData); + } + + /// + /// Effettua processing mode/status (EDIT/MDI/...) + /// + public virtual void processMode() + { } + + /// + /// Effettua processing ALTRI contatori/parametri (ed invia ad IO) + /// + public virtual void processOtherCounters() + { } + + /// + /// Effettua processing del recupero delle OVERRIDE (spindle, feedrate, rapid) + /// + public virtual void processOverride() + { + bool enableByApp = utils.CRB("enableOverrides"); + bool enableByIob = (getOptPar("ENABLE_OVERRIDES") == "TRUE"); + Dictionary currOverride = new Dictionary(); + if (enableByApp || enableByIob) + { + lgInfo("Inizio processOverride"); + if (connectionOk) + { + currOverride = getOverrides(); + } + else + { + lgError("Errore connessione mancante x getOverrides"); + } + + // SE sono connesso... + if (connectionOk) + { + // se HO dei valori override... + if (currOverride.Count > 0) + { + // verifico SE sia cambiato il programma... + if (lastOverrideFS != currOverride["FEED_OVER"] || lastOverrideRapid != currOverride["RAPID_OVER"]) + { + // salvo! + lastOverrideFS = currOverride["FEED_OVER"]; + lastOverrideRapid = currOverride["RAPID_OVER"]; + // per ogni valore del dizionario mostro ed accodo! + string sVal = ""; + foreach (var item in currOverride) + { + sVal = string.Format("[OVERRIDES]{0}|{1}", item.Key, item.Value); + // chiamo accodamento... + accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); + } + } + } + } + } + } + + /// + /// 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 S01: {task2exe.Count} task ricevuti:"); + int idTask = 0; + foreach (var item in task2exe) + { + idTask++; + lgInfo($"[{idTask:00}] - {item.Key} --> {item.Value}"); + } + // chiamo procedura esecutiva (diversa x ogni IOB) + taskDone = executeTasks(task2exe); + lgInfo($"Task2Exe S02: eseguiti {taskDone.Count} task"); + // 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 + /// + public virtual void processVHF() + { + } + + /// + /// Classe fittizia in caso di processing watchdog data + /// + public virtual void processWhatchDog() + { + } + + /// + /// 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); + lgTrace("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; + lgError($"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; + lgError($"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 { - 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)); + // se server NON pronto... + contapezziIOB = contapezziPLC; + lgError("Errore server NON pronto in pzCntReload"); } } /// - /// Processo lettura dati sysinfo + /// Fornisce il valore di flusso e valore in formato valido x messa in coda nel formato + /// dtEve#flusso#valore#cont Flusso datiValore da salvare /// - private void processSysInfo() + public string qEncodeFLog(string flusso, string valore) { - if (utils.CRB("enableSysInfo")) + string answ = ""; + try { - Dictionary currSysInfo = new Dictionary(); + answ = $"{DateTime.Now:yyyyMMddHHmmssfff}#{flusso}#{valore}#{counterULog}"; + } + 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 + /// registratoFlusso datiValore da salvare + /// + public string qEncodeFLog(DateTime eventDT, string flusso, string valore) + { + string answ = ""; + try + { + answ = $"{eventDT:yyyyMMddHHmmssfff}#{flusso}#{valore}#{counterFLog}"; + } + catch + { } + return answ; + } + + /// + /// Fornisce il valore di UserLog e valore in formato valido x messa in coda nel formato: + /// dtEve#flusso#value#cont#matrOpr#label#valNum Flusso dati + /// (RC/RS/DI)Valore da inviare + /// (valStringMatricola operatoreValore etichetta: causale scarto / tagCodeValore numerico: esitoOk (0/1) / nuo scarti + /// + public string qEncodeULog(string flusso, string valore, int matrOpr, string label, int valNum) + { + string answ = ""; + try + { + answ = $"{DateTime.Now:yyyyMMddHHmmssfff}#{flusso}#{valore}#{matrOpr}#{label}#{valNum}#{counterULog}"; + } + catch + { } + return answ; + } + + /// + /// Effettua lettura dati Parametri da aggiornare x display in form + /// + public virtual void readAllData(ref newDisplayData currDispData) + { + if (currDispData == null) + { + currDispData = new newDisplayData(); + } + try + { + if (DemoIn) + { + // segnalo che sono in Demo + currDispData.semIn = Semaforo.SV; + } if (connectionOk) { - currSysInfo = getSysInfo(); + readSemafori(ref currDispData); } else { - lgError("Errore connessione mancante x getSysInfo"); + lgError("Errore connessione mancante x readSemafori"); } - // 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); + nReadIN++; + // aggiorno valore mostrato... + displayRawData(ref currDispData); + } + catch + { + currDispData.semIn = Semaforo.SR; + } + raiseRefresh(currDispData); } /// - /// Imposto alcuni valori di default + /// Effettua lettura semafori principale Parametri da + /// aggiornare x display in form /// - /// indica se sia richeisto di SVUOTARE le code delel info - private void setDefaults(bool resetQueue) + public virtual void readSemafori(ref newDisplayData currDispData) { - numSim = utils.CRI("numSim"); - lastPrgName = ""; - nReadIN = 0; - nReadFilt = 0; - nSendOut = 0; - currMode = 0; - lastAlarm = ""; - doStartMemDump = utils.CRB("doStartMemDump"); - doSampleMemory = utils.CRB("doSampleMemory"); - // fix url wait random... - urlRandWait = utils.CRI("urlRandWait"); - - // svuoto code se richiesto - if (resetQueue) - { - QueueAlarm = new ConcurrentQueue(); - QueueIN = new ConcurrentQueue(); - QueueFLog = new ConcurrentQueue(); - QueueMessages = new ConcurrentQueue(); - QueueRawTransf = new ConcurrentQueue(); - QueueULog = new ConcurrentQueue(); - } - // imposto contatori blink a zero... - i_counters = new int[32]; - lastPeriodicLog = DateTime.Now; - // fix parametri generali... - enablePrgName = true; + lastReadPLC = DateTime.Now; } - private void svuotaCodaContapezzi() + /// + /// Aggiunge ai dati da inviare alla parentform i valori di RawInput rilevati (32bit) + /// 2021.08.27: filtrati secondo i valori setup start/size RawDataInput + /// + public virtual void reportRawInput(ref newDisplayData currDispData) { - // permetto al max 2 tentativi infruttuosi... - int maxTry = 2; - int oldContapezzi = contapezziIOB; - // se ho contapezzi OLTRE limite... - while ((MPOnline) && (contapezziPLC > contapezziIOB + minSendPzCountBlock)) + // processo eventualmente aggiungendo ad elementi esistenti... + if (currDispData == null) { - lgInfo($"Ciclo svuotaCodaContapezzi --> contapezziPLC: {contapezziPLC} | contapezziIOB: {contapezziIOB}"); - if (!isMulti) + 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}"); + // Do x scontato siano VALIDI i valori di RawDataInputStart / size --> filtro... + var filtRawData = new byte[RawDataInputSize]; + Array.Copy(RawInput, RawDataInputStart, filtRawData, 0, RawDataInputSize); + int i = RawDataInputStart; + foreach (var item in filtRawData) { - pzCntReload(true); + sb.Append($"B{i:00} --> {baseUtils.binaryForm(item)} = {(short)item}{Environment.NewLine}"); + i++; } - // provo invio - trySendPzCountBlock(); - // verifica per evitare loop infinito invio fallito - if (oldContapezzi == contapezziIOB) + 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 + /// + /// tipo di DUMP + public virtual void saveMemDump(dumpType tipo) + { + } + + /// + /// 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); + } + } + + /// + /// Effettua salvataggio in LUT del valore ricevuto + /// + /// + /// + /// + /// + public virtual void saveValue(ref Dictionary outVal, double valore, string chiave) + { + //check obj preliminare + if (outVal == null) + { + outVal = new Dictionary(); + } + bool scaduto = stackVal_TSVC(chiave, valore); + // recupero VC + valore = getVal_TSVC(chiave, scaduto); + if (scaduto) + { + // limite a 3 digit x valore float + outVal.Add(chiave, $"{valore:N3}"); + } + LastTSVC[chiave] = valore; + } + + /// + /// Invio la variazione dello stato allarmi (se avvenuta) + /// + /// COD memoria allarmi + /// Indice memoria allarmi + /// ultimo stato rilevato + /// stato corrente + /// Lista allarmi validi per l'area + /// + public bool sendAlarmVariations(string memAddr, int index, uint lastStatus, uint currStatus, List AlarmList) + { + bool fatto = false; + if (lastStatus != currStatus) + { + List ActiveAlarmList = new List(); + // invio GET del MemoryAddress, del banco e del valore currStatus + lastUrl = $"{urlSendAlarm}?memAddr={memAddr}&index={index}&currStatus={currStatus}"; + if (currStatus == 0) { - maxTry--; + ActiveAlarmList.Add("ALL OK"); } else { - maxTry = 2; - oldContapezzi = contapezziIOB; + // calcolo quali allarmi mostrare dato currStatus ed elenco allarmi + string bitMap = Convert.ToString(currStatus, 2); + int bitLen = bitMap.Length; + // ciclo x associare tutti gli allarmi + for (int i = 0; i < bitLen; i++) + { + // se è 1 --> aggiungo! + if (bitMap[bitLen - i - 1] == '1') + { + // se sono entro limiti + if (AlarmList.Count >= i) + { + ActiveAlarmList.Add($"{i:000}-{AlarmList.ElementAt(i)}"); + } + //else + //{ + // ActiveAlarmList.Add($"Unknown Bit.{i}"); + //} + } + } } - // verifico maxTry: se li ho esauriti esco! - if (maxTry <= 0) + + string rawData = JsonConvert.SerializeObject(ActiveAlarmList); + + //string resp = utils.callUrlNow(lastUrl, rawData); + string resp = utils.callUrlAsync(lastUrl, rawData); + if (!string.IsNullOrEmpty(resp)) { - return; + if (resp.ToUpper() == "OK") + { + // segnalo fatto + fatto = true; + } + } + else + { + lgError($"Errore in invio richiesta registrazione allarme: URL: {lastUrl}{Environment.NewLine}Payload:{Environment.NewLine}{rawData}"); } - // aspetto x dare tempo calcolo - Thread.Sleep(400); } + return fatto; } /// - /// Processo la coda FLog... + /// Invia una LISTA di valori /// - private void svuotaCodaFLog() + /// + /// + public void sendDataBlock(urlType tipoUrl, List listQueueVal) { - // controllo se è passato oltre watchdog e non ho inviato nulla --> RE-INVIO (ultimo inviato)!!!! - if (DateTime.Now.Subtract(lastWatchDog).TotalSeconds > utils.CRI("watchdogMaxSec")) + // init obj display + newDisplayData currDispData = new newDisplayData(); + if (listQueueVal != null) { - 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++) + try { - // SE ho qualcosa in coda... - if (QueueFLog.Count > 0) + // recupero e formatto URL dati da coda... + lastUrl = urlDataBlock(tipoUrl); + // in base al tipo di dato compongo il payload Json da inviare + string payload = jsonPayload(tipoUrl, listQueueVal); + // async a true SE FLog + bool doAsync = tipoUrl == urlType.FLog ? true : false; + // se NON sono in demo effettuo invio! + if (!DemoOut) { - string currVal = ""; - if (MPOnline) + // SE server alive... + if (checkServerAlive) { - if (IobOnline) + // chiamo URL! + string answ = callUrlWithPayload(lastUrl, payload, doAsync); + // attesa opzionale se configurata + + // loggo! + lgInfo($"[SEND payload] TipoURL: {tipoUrl} | {listQueueVal.Count} records --> {answ}"); + // se "OK" verde, altrimenti errore --> ROSSO + if (answ.Contains("OK")) { - // se ho + di 2 elementi in coda --> uso invio JSON in blocco... - if (QueueFLog.Count > 1) + currDispData.semOut = Semaforo.SV; + // se oltre 1 min NON era online --> check pezzi! + if (DateTime.Now.Subtract(lastIobOnline).TotalMinutes > 1 && !isMulti) { - 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); - lastWatchDog = DateTime.Now; - } - else - { - // invio in blocco - listaValori = QueueFLog.ToList(); - // invio - sendDataBlock(urlType.FLog, listaValori); - // svuoto! - QueueFLog = new ConcurrentQueue(); - lastWatchDog = DateTime.Now; - } - } - else - { - // INVIO SINGOLO...!!! - QueueFLog.TryDequeue(out currVal); - sendToMoonPro(urlType.FLog, currVal); - lastWatchDog = DateTime.Now; + lgInfo($"sendDataBlock --> offline timeout ({lastIobOnline}) --> pzCntReload(true)"); + pzCntReload(true); } + lastIobOnline = DateTime.Now; } else { - break; + currDispData.semOut = Semaforo.SR; } } else { - break; + lgInfo($"[SERVER KO] {listQueueVal.Count}"); } } else { - break; + currDispData.semOut = Semaforo.SV; + // loggo! + lgInfo($"{listQueueVal.Count} records --> [SIM]"); } + nSendOut += listQueueVal.Count; + // riporto cosa inviato + currDispData.newUrlCallData = lastUrl; + // aggiorno data ultimo watchdog... + lastWatchDog = DateTime.Now; } - } - } - - /// - /// Processo la coda RawTransf... - /// - private void svuotaCodaRawTransf() - { - // verifico SE la coda abbia dei valori... - if (QueueRawTransf.Count > 0) - { - // invio pacchetto di dati (max da conf) - for (int i = 0; i < nMaxSend; i++) + catch { - // SE ho qualcosa in coda... - if (QueueRawTransf.Count > 0) - { - string currVal = ""; - if (MPOnline) - { - if (IobOnline) - { - List listaValori = new List(); - // se ho + di maxJsonData elementi --> invio un set di dati alla volta - if (QueueRawTransf.Count > maxJsonData) - { - // prendoi primi maxJsonDataValori - for (int j = 0; j < maxJsonData; j++) - { - QueueRawTransf.TryDequeue(out currVal); - listaValori.Add(currVal); - } - sendDataBlock(urlType.RawTransf, listaValori); - } - else - { - // invio in blocco - listaValori = QueueRawTransf.ToList(); - // invio - sendDataBlock(urlType.RawTransf, listaValori); - // svuoto! - QueueRawTransf = new ConcurrentQueue(); - } - } - else - { - break; - } - } - else - { - break; - } - } - else - { - break; - } + currDispData.semOut = Semaforo.SR; } } + raiseRefresh(currDispData); } /// - /// Processo la coda UserLog... + /// Effettua invio a MoonPro del valore richiesto /// - private void svuotaCodaULog() - { - // verifico SE la coda abbia dei valori... - if (QueueULog.Count > 0) - { - // invio pacchetto di dati (max da conf) - for (int i = 0; i < nMaxSend; i++) - { - // SE ho qualcosa in coda... - if (QueueULog.Count > 0) - { - string currVal = ""; - if (MPOnline) - { - if (IobOnline) - { - List listaValori = new List(); - // se ho + di maxJsonData elementi --> invio un set di dati alla volta - if (QueueULog.Count > maxJsonData) - { - // prendoi primi maxJsonDataValori - for (int j = 0; j < maxJsonData; j++) - { - QueueULog.TryDequeue(out currVal); - listaValori.Add(currVal); - } - sendDataBlock(urlType.ULog, listaValori); - } - else - { - // invio in blocco - listaValori = QueueULog.ToList(); - // invio - sendDataBlock(urlType.ULog, listaValori); - // svuoto! - QueueULog = new ConcurrentQueue(); - } - } - else - { - break; - } - } - else - { - break; - } - } - else - { - break; - } - } - } - } - - /// - /// Cerca di inviare su un altro thread i vari dati accumulati... - /// - private void trySendValues() + /// + /// + /// Valore da trasmettere: es + /// INPUT: lo status rilevato in HEX + /// FLog: il valore da trasmettere per il flusso indicato + /// + public void sendToMoonPro(urlType tipoUrl, string queueVal) { // init obj display newDisplayData currDispData = new newDisplayData(); try { - // verifico se risponde il server... - if (checkServerAlive) + // recupero e formatto URL dati da coda... + switch (tipoUrl) { - bool iobOk = false; - if (utils.CRB("sendDataByThread")) + case urlType.FLog: + lastUrl = urlFLog(queueVal); + break; + + case urlType.SignIN: + lastUrl = urlInput(queueVal); + break; + + default: + lastUrl = ""; + break; + } + // se NON sono in demo effettuo invio! + if (!DemoOut) + { + // SE server alive... + if (checkServerAlive) { - Task taskCheck = Task.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")) + // chiamo URL! + string answ = callUrl(lastUrl, false); + // loggo! + lgDebug(string.Format("[SEND] {0} -> {1}", queueVal, answ)); + // se oltre 1 min NON era online --> check pezzi! + if (DateTime.Now.Subtract(lastIobOnline).TotalMinutes > 1 && !isMulti) { - // invio con thread separato... - Task taskSigIN = Task.Run(() => svuotaCodaSignIN()); - Task taskFLog = Task.Run(() => svuotaCodaFLog()); - Task taskRawTransf = Task.Run(() => svuotaCodaRawTransf()); - Task taskULog = Task.Run(() => svuotaCodaULog()); + lgInfo($"sendToMoonPro --> offline timeout ({lastIobOnline}) --> pzCntReload(true)"); + pzCntReload(true); + } + // se richiesto effettuo refresh contapezzi + if (needRefreshPzCount && !isMulti) + { + pzCntReload(true); + needRefreshPzCount = false; + } + lastIobOnline = DateTime.Now; + // se "OK" verde, altrimenti errore --> ROSSO + if (answ == "OK") + { + currDispData.semOut = Semaforo.SV; } else { - // 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(); - // coda RawTransf - svuotaCodaRawTransf(); - // coda UserLog - svuotaCodaULog(); - // refresh - raiseRefresh(currDispData); + currDispData.semOut = Semaforo.SR; } - // se arrivo è tutto ok... - currSendErrors = 0; } else { - // mostro VETO-SEND x invio... GIALLO - currDispData.semOut = Semaforo.SG; - if (periodicLog) - { - lgInfo("IOB - VETO SEND"); - } + lgError(string.Format("[SERVER KO] {0}", queueVal)); } } else { - // mostro SERVER KO x invio... ROSSO - currDispData.semOut = Semaforo.SR; - if (periodicLog) - { - lgError("IOB - SERVER NOT READY"); - } + currDispData.semOut = Semaforo.SV; + // loggo! + lgDebug(string.Format("{0} -> [SIM]", queueVal)); } + nSendOut++; + currDispData.newUrlCallData = lastUrl; + // aggiorno data ultimo watchdog... + lastWatchDog = DateTime.Now; } - catch (Exception exc) + catch { - lgError($"Errore in fase trySendValues | currSendErrors: {currSendErrors}{Environment.NewLine}{exc}"); currDispData.semOut = Semaforo.SR; } raiseRefresh(currDispData); } /// - /// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce + /// Metodo generico di IMPOSTAZIONE FORZATA del contapezzi... /// - /// - /// - /// - /// Nuovo valore incrementato - private double updateValDoubleByIncr(int i, double delta, string searchString) + /// Pezzi richiesti + /// + public virtual bool setcontapezziPLC(int newPzCount) { - // 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; + return false; } /// - /// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce + /// Processing di Variabili Campionarie x TimeSeries, accoda valori x la VC (se esiste) e + /// restituisce bool val se SCADUTO periodo controllo /// - /// - /// - /// - /// Nuovo valore incrementato - private long updateValLongByIncr(int i, long delta, string searchString) + /// Nome della VC + /// Valore (nuovo) delal VC + /// + public bool stackVal_TSVC(string VCName, double VCVal) { - // 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; + 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; } /// - /// Aggiorna un valore del dizionario in SOSTITUZIONE + /// Avvia l'adapter sulla porta richiesta /// - /// - /// - /// - /// Nuovo valore incrementato - private void updateValString(int i, string newVal, string searchString) + /// indica se sia richeisto di SVUOTARE le code delel info + public virtual void startAdapter(bool resetQueue) { - // stringa da cercare.. - string keyVal = string.Format(searchString, i + 1); - // salvo in ram! - persistenceLayer[keyVal] = newVal; + DateTime adesso = DateTime.Now; ; + DateTime scaduto = adesso.AddMinutes(-10); + lgInfo("Starting adapter..."); + maxJsonData = utils.CRI("maxJsonData"); + maxJsonDataEv = utils.CRI("maxJsonDataEv"); + parentForm.commPlcActive = false; + adpRunning = true; + dtAvvioAdp = adesso; + lastWatchDog = scaduto; + lastPING = scaduto; + lastReadPLC = scaduto; + lastDisconnCheck = scaduto; + TimingData.resetData(); + // aggiungo altri defaults + setDefaults(resetQueue); + adpTryRestart = true; + lgDebug("startAdapter completed"); } /// - /// Aggiorna un valore del dizionario in SOSTITUZIONE e lo restituisce + /// ferma l'adapter... /// - /// - /// - /// - /// Nuovo valore incrementato - private void updateValUInt(int i, uint newVal, string searchString) + /// + /// 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) { - // stringa da cercare.. - string keyVal = string.Format(searchString, i + 1); - // salvo in ram! - persistenceLayer[keyVal] = newVal.ToString(); + if (forceDequeue) + { + // svuoto le code dei valori letti e non ancora trasmessi... + parentForm.displayTaskAndLog("[CLOSING] Svuotamento FORZATO coda segnali..."); + while (QueueIN.Count > 0) + { + // INVIO COMUNQUE...!!! + string valore = ""; + QueueIN.TryDequeue(out valore); + sendToMoonPro(urlType.SignIN, valore); + } + parentForm.displayTaskAndLog("[CLOSING] 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); + } + } + + // svuoto coda ULog + while (QueueULog.Count > 0) + { + List listaValori = new List(); + // se ho + di maxJsonData elementi --> invio un set di dati alla volta + if (QueueULog.Count > maxJsonData) + { + string currVal = ""; + // prendoi primi maxJsonDataValori + for (int i = 0; i < maxJsonData; i++) + { + QueueULog.TryDequeue(out currVal); + listaValori.Add(currVal); + } + sendDataBlock(urlType.ULog, listaValori); + } + else + { + // invio in blocco + listaValori = QueueULog.ToList(); + // invio + sendDataBlock(urlType.ULog, listaValori); + // svuoto! + QueueULog = new ConcurrentQueue(); + } + } + } + parentForm.displayTaskAndLog("[STOP] Stopping adapter..."); + adpTryRestart = false; + + parentForm.displayTaskAndLog("[STOP] 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; } /// - /// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce + /// Processo la coda SignalIN... /// - /// - /// - /// - /// Nuovo valore incrementato - private uint updateValUIntByIncr(int i, uint delta, string searchString) + public void svuotaCodaSignIN() { - // 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; + // 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; + } + } + } } - #endregion Private Methods + /// + /// Metodo base connessione... + /// + public virtual void tryConnect() + { + dtAvvioAdp = DateTime.Now; + } + + /// + /// 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 + lgError($"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 + { + lgError("Impossibile trySendPzCountBlock: IobOnline è false"); + } + } + else + { + lgError("Impossibile trySendPzCountBlock: MPOnline è false"); + } + } + + /// + /// Inserimento/aggiornamento chiavi/valore in currProdData + /// + /// + /// + public void upsertKey(string chiave, string valore) + { + if (currProdData.ContainsKey(chiave)) + { + currProdData[chiave] = valore; + } + else + { + currProdData.Add(chiave, valore); + } + } + + /// + /// Formatta URL x invio in DataBlock Json dei dati FLog / eventi + /// + /// + /// + public string urlDataBlock(urlType tipoUrl) + { + // verifico la parte di link "tipoComando" + string tipoComando = ""; + switch (tipoUrl) + { + case urlType.FLog: + tipoComando = cIobConf.serverData.CMDFLOG_JSON; + break; + + case urlType.SignIN: + tipoComando = cIobConf.serverData.CMDBASE_JSON; + break; + + case urlType.RawTransf: + tipoComando = cIobConf.serverData.CMDRAWTRANSF_JSON; + break; + + case urlType.ULog: + tipoComando = cIobConf.serverData.CMDULOG_JSON; + break; + + default: + break; + } + // URL base x input + string answ = $@"{cIobConf.serverData.TRANSP}://{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 = $@"{cIobConf.serverData.TRANSP}://{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 = $@"{cIobConf.serverData.TRANSP}://{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; + } + + /// + /// Fornisce URL di tipo UserLog + /// + /// valore salvato in coda nel formato dtEve#flux#valore#counter + /// + public string urlULog(string queueVal) + { + // URL base x input + string answ = $@"{cIobConf.serverData.TRANSP}://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDULOG}"; + // 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 Public Methods + + #region Protected Fields + + /// + /// wrapper di log + /// + protected static Logger lg; + + /// + /// Valore di attesa (random) dopo ogni invio x evitare congestione send... + /// + protected static int urlRandWait = 0; + + protected bool _connOk = false; + + /// + /// 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; + + /// + /// Num errori check alive + /// + protected int currAliveErrors = 0; + + /// + /// Dizionario valori impostati x produzione + /// + protected Dictionary currProdData = new Dictionary(); + + /// + /// num corrente errori read PLC + /// + protected int currReadErrors = 0; + + /// + /// num errori send + /// + protected int currSendErrors = 0; + + /// + /// Fattore di demoltiplicazione dei DynData x ridurre campionamento + /// + protected int demFactDynData = 1; + + /// + /// 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 LOG registrazione avvio (x ridurre log notturni...) + /// + protected DateTime lastLogStartup = DateTime.Today.AddHours(-1); + + /// + /// Dizionario ULTIMI valori impostati x produzione + /// + protected Dictionary lastProdData = new Dictionary(); + + /// + /// 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; + + /// + /// Num massimo di errori in funzionalità check alive + /// + protected int maxAliveErrors = utils.CRI("maxAliveErrors"); + + /// + /// Soglia massima errori priam di disconnesisone automatica + /// + protected int maxErroriCheck = 100; + + /// + /// Num massimo di errori di rete read (dal PLC) + /// + protected int maxReadErrors = utils.CRI("maxReadErrors"); + + /// + /// Num massimodi errori di rete send al server + /// + protected int maxSendErrors = utils.CRI("maxSendErrors"); + + /// + /// indica se serva refresh parametri e quindi PLC... + /// + protected bool needRefresh = true; + + /// + /// Variabile numero errori vari (in lettura) --> se supera soglia maxErroriCheck --> disconnette + /// + protected int numErroriCheck = 0; + + /// + /// 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(); + + /// + /// Veto per registrazione completa log di startup (minuti) + /// + protected int vetoLogStartupDuration = 60; + + /// + /// Periodo wathdog di default (2 sec se non specificato) + /// + protected int watchDogPeriod = 2; + + #endregion Protected Fields + + #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; + } + } + + /// + /// Indica il counter della key richiesta attiva + /// - gestito tramite Redis + /// - a scadenza 25h + /// - incrementato ogni invio di auto ODL + /// + protected int countKeyRichiesta + { + get + { + // calcolo key odierna + int answ = redisMan.getKReqCount(dailyKey); + return answ; + } + set + { + // calcolo key odierna + redisMan.setKReqCount(dailyKey, value); + } + } + + protected string dailyKey + { + get + { + return DateTime.Today.ToString("yyMMdd"); + } + } + + /// + /// Variabile di appoggio GLOBALE x indicare che si può forzare reset contapezzi con + /// macchina in RUN + /// + protected bool forceResetInRun { get; set; } = false; + + /// + /// Variabile di appoggio GLOBALE x indicare macchina RUN (es x gestione su reset pezzi) + /// + protected bool isRunning { get; set; } = false; + + /// + /// 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"); + + /// Coda massima ammessa per FLog (se <=0 disattivata...) + protected int maxQueueRawTransf { get; set; } = utils.CRI("maxQueueRawTransf"); + + /// + /// Valore MINIMO limite x decidere invio di dati come array Json + /// + protected int minJsonData { get; set; } = utils.CRI("minJsonData"); + + protected string nextKeyRich + { + get + { + return $"{dailyKey}{countKeyRichiesta:00}"; + } + } + + /// + /// 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; } + + /// + /// Indica se sia stato resettato un contapezzi + /// + protected bool pzCountResetted { get; set; } = false; + + /// + /// 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; + } + } + + /// + /// Indica se vada inviata la key richiesta con lo split/autoODL + /// + protected bool sendKeyRichiesta { get; set; } = false; + + /// + /// 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; + int pingMsTimeout = cIobConf.pingMsTimeout; + IPAddress.TryParse(cIobConf.cncIpAddr, out address); + try + { + // se != null --> uso address... + if (address != null) + { + reply = pingSender.Send(address, pingMsTimeout); + } + else + { + reply = pingSender.Send(cIobConf.cncIpAddr, pingMsTimeout); + } + } + catch + { + reply = pingSender.Send(IPAddress.Loopback, 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 Protected Methods /// - /// Decodifica file MAP (caso .bit) + /// Decodifica file MAP (caso .bit) /// /// /// @@ -2590,10 +4073,7 @@ namespace IOB_WIN_NEXT } /// - /// Decodifica valore della coda IN nel formato - /// answ[0]=dtEve - /// answ[1]=valore - /// answ[2]=counter + /// Decodifica valore della coda IN nel formato answ[0]=dtEve answ[1]=valore answ[2]=counter /// /// dtEve + '#' + value + '#' + cont /// @@ -2638,8 +4118,8 @@ namespace IOB_WIN_NEXT /// - formato Json /// - array di KVP / Dictionary /// - formato definito da API x MP/IO/: - /// - KEY: task - /// - VALUE: array JSon KVP + /// - KEY: task + /// - VALUE: array JSon KVP /// protected string getTask2exe() { @@ -2779,6 +4259,19 @@ namespace IOB_WIN_NEXT 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); + } + protected void lgInfoStartup(string message, bool sendToForm = true) { lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB; @@ -2799,17 +4292,6 @@ namespace IOB_WIN_NEXT } } - /// - /// 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); - } /// /// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere... /// @@ -2934,8 +4416,7 @@ namespace IOB_WIN_NEXT } /// - /// Lettura memorie conf speciali (json) - /// ...SE inserito in [OPTPAR] come PARAM_CONF=nome.json + /// Lettura memorie conf speciali (json) ...SE inserito in [OPTPAR] come PARAM_CONF=nome.json /// protected virtual void loadMemConf() { @@ -3343,2236 +4824,696 @@ namespace IOB_WIN_NEXT #endregion Protected Methods - #region Public Methods + #region Private Properties /// - /// Effettua chiamata URL e restituisce risultato + /// Verifica se la IOB sia ENABLED (da server o Demo) /// - /// - /// invio in modalità async (NON GARANTITO ordine...) - /// - public static string callUrl(string URL, bool doAsync) + private bool checkIobEnabled { - string answ = ""; - // Chiamata ASINCRONA - if (doAsync) + get { - //Task resp = utils.callUrlAsync(URL); - //answ = resp.Result; - answ = utils.callUrlAsync(URL); - if (urlRandWait > 0) + bool answ = false; + // controllo se ho veto al check... + if (dtVetoCheckIOB < DateTime.Now) { - Random rnd = new Random(); - Thread.Sleep(rnd.Next(urlRandWait / 10, urlRandWait)); - } - } - // chiamata SOLO NORMALE SINCRONA... - else - { - answ = utils.callUrl(URL); - if (urlRandWait > 0) - { - Random rnd = new Random(); - Thread.Sleep(rnd.Next(urlRandWait / 10, urlRandWait)); - } - } - return answ; - } - - /// - /// Effettua chiamata URL e restituisce risultato - /// - /// - /// - /// invio in modalità async (NON GARANTITO ordine...) - /// - public static string callUrlWithPayload(string URL, string payload, bool doAsync) - { - string answ = ""; - // Chiamata ASINCRONA - if (doAsync) - { - answ = utils.callUrlAsync(URL, payload); - if (urlRandWait > 0) - { - Random rnd = new Random(); - Thread.Sleep(rnd.Next(urlRandWait / 10, urlRandWait)); - } - } - // chiamata SOLO NORMALE SINCRONA... - else - { - answ = utils.callUrl(URL, payload); - if (urlRandWait > 0) - { - Random rnd = new Random(); - Thread.Sleep(rnd.Next(urlRandWait / 10, urlRandWait)); - } - } - return answ; - } - - /// - /// processa dataLayer e se necessario salva/mostra - /// - public static void checkSavePersDataLayer() - { - } - - public static string GetMACAddress() - { - NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces(); - String sMacAddress = string.Empty; - foreach (NetworkInterface adapter in nics) - { - if (string.IsNullOrEmpty(sMacAddress))// only return MAC Address from first card - { - IPInterfaceProperties properties = adapter.GetIPProperties(); - //sMacAddress = adapter.GetPhysicalAddress().ToString(); - sMacAddress = string.Join(":", (from z in adapter.GetPhysicalAddress().GetAddressBytes() select z.ToString("X2")).ToArray()); - } - } - return sMacAddress; - } - - public static void resetDebugConsole() - { - } - - /// - /// Reset dei webclients - /// - public static void resetWebClients() - { - 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) + if (DemoOut) { - string currVal = ""; - QueueFLog.TryDequeue(out currVal); - lgInfo($"Eliminazione da coda FLog per superamento maxLengh: {currVal}"); - } - } - } - // loggo! - lgTrace(string.Format("[QUEUE-FLOG] {0}", encodedVal)); - counterFLog++; - if (counterFLog > 9999) - { - counterFLog = 0; - } - } - - /// - /// Accumula in coda i valori RawData + log - /// - /// - /// - public void accodaRawData(rawTransfType mesType, object mesContent) - { - /*-------------------------------- - * nuova gestione coda dictionary - * fixme todo da fare !!! - * - * - conterrà una lista di oggetti baseRawTransf - * - i dati vanno poi "scodati" dal + vecchio ed inviati a MP/IO - * - mostra un sunto delle info da inviare - * - accodamento vero e proprio - * - verifica (opzionale) coda massima x gestire roundRobin ultimi eventi - * - trace della coda - * - counter invio??? valutare se c'è dataora e poi sono da salvare su MongoDb / Redis - * - * */ - - // serializzo il valore... - BaseRawTransf newVal = new BaseRawTransf(DateTime.Now, mesContent, mesType); - string encodedVal = JsonConvert.SerializeObject(newVal); - // --> accodo (valore già formattato)! - QueueRawTransf.Enqueue(encodedVal); - // se abilitato controllo coda Max (superiore a 0...) - if (maxQueueRawTransf > 0) - { - // se ho una coda superiore a max ammesso - if (QueueRawTransf.Count > maxQueueRawTransf) - { - // elimino valori iniziali fino a tornare al max ammesso... - while (QueueRawTransf.Count > maxQueueRawTransf) - { - string currVal = ""; - QueueRawTransf.TryDequeue(out currVal); - lgInfo($"Eliminazione da coda RawTransf per superamento maxLengh: {currVal}"); - } - } - } - // loggo! - lgTrace(string.Format("[QUEUE-RTRANSF] {0}", encodedVal)); - counterRawTransf++; - if (counterRawTransf > 9999) - { - counterRawTransf = 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); - // verifico veto a invio status macchina - string keyName = "VETO_SIG_IN"; - if (getOptPar(keyName).ToUpper() == "TRUE") - { - lgTrace($"Filtrato accodamento valore da conf IOB | {keyName} | [QUEUE-IN] {qEncodeIN}"); - } - else - { - // --> accodo (valore già formattato)! - QueueIN.Enqueue(qEncodeIN); - // loggo! - lgTrace(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; - } - } - - /// - /// Accumula in coda i valori USER LOG e logga... - /// - /// VALORE RAW (x display) - /// VALORE già processato con qEncodeULog(...) - public void accodaUserLog(string val, string encodedVal) - { - // mostro dati variati letti... - displayOtherData(val); - // accodo IN PRIMIS al FluxLog --> accodo (valore già formattato)! - QueueULog.Enqueue(encodedVal); - - // loggo! - lgInfo(string.Format("[QUEUE-USER-LOG] {0}", encodedVal)); - counterULog++; - if (counterULog > 9999) - { - counterFLog = 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) - { - // controllo se memMap != null... - if (memMap != 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 != null && memMap.mMapWrite != null) - { - 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}"; - } - } - else - { - taskVal = $"NO MemMap found, SET task: {item.Key} --> {item.Value}"; - } - // salvo in currProd.. - saveProdData(new KeyValuePair(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 setParameter --> 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); - } - } - else - { - lgError($"Attenzione! memMap è nullo, non posso eseguire task2exe!"); - } - } - - return taskDone; - } - - /// - /// Effettua verifica delle memorie WRITE, se ci siano variazioni da riportare verso il PLC - /// Da impiegare ad esempio in caso di chiamate complesse (ad 2 aree di memoria condivise sul PLC; coem commessa + articolo EWON) - /// - /// - /// 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; - } - - /// - /// forza reset ODL - /// - public void forceResetOdl() - { - lgInfo("Registrato richiesta forzatura reset ODL"); - pzCountResetted = true; - } - - /// - /// Effettua chiamata x split ODL - /// - /// - public bool forceSplitOdl() - { - bool fatto = false; - if (vetoSplit < DateTime.Now) - { - lgInfo("Richiesto forceSplitOdl"); - // imposto veto x 1 minuto ad altre chiamate... - vetoSplit = DateTime.Now.AddMinutes(1); - // eseguo SOLO SE sono online... - if (MPOnline && IobOnline) - { - string fullUrl = ""; - string rawSplit = ""; - string IOB_MULTI_CNAME = ""; - string[] elencoMulti = null; - - try - { - /*************************************************** - * Descrizione procedura (OK X SIMULATORI...) - * - * - chiamata su MP/IO - * - verifica che su DB sia abilitato AUTO ODL - * - il server inserisce un evento fine prod HW 1 minuto prima e inizio setup HW - * - viene duplicato e chiuso ODL corrente - * - viene fatto partire ODL nuovo ADESSO - * - num pezzi come ODL precedente (o da media 3 ODL precedenti) - * - conferme pezzi & co... gestione NULL (NON SERVONO si tratta di impianti SENZA gestione vera ODL) - * - reset contapezzi PLC locale... - * - * - * - * DA VALUTARE (x macchine tipo linea con + impianti... es valvital) SE - * - creare una gestione ALTERNATIVA sul server che preveda impianto LEADER e impianti follower (RIGIDAMENTE CONFIGURATI) - * - ogni volta che si fa setup LEADER --> si ripete su impianti FOLLOWER (eventi!!!) - * - viene fatto reset contapezzi sui follower (+ altre operazioni opzionali, ES imposstazione nome commessa, quantità, articolo...) - * - viene fatto reset + nuovo ODL (con stessi articoli e quantità) su follower, SENZA avere gestione x ODL di un codice esterno (quindi registra TUTTO ma NON RITORNERA' dati non avendo link verso esterno) - * - serve NUOVA TABELLA delle macchine LEADER | FOLLOWER (1:n) e gestione da MP/IO - * - * ***************************************************/ - - if (isMulti) - { - // devo chiamare cambio ODL x OGNI tavola: mi servono i parametri opzionali... - IOB_MULTI_CNAME = getOptPar("IOB_MULTI_CNAME"); - elencoMulti = IOB_MULTI_CNAME.Split(','); - } - // se normale splitto! - if (!isMulti) - { - // invio chiamata URL x reset ODL su macchina - rawSplit = callUrl(urlForceSplit, false); - fatto = (rawSplit != "KO") ? true : false; - } - // se multi gestisco il bit delle tavole... - else - { - foreach (string item in elencoMulti) - { - // invio chiamata URL x reset ODL su macchina, ATTENZIONE scriviamo | al posto di "#" che in URL sarebbe filtrato... - fullUrl = $"{urlForceSplit}&multi={item}"; - rawSplit = callUrl(fullUrl, false); - lgDebug($"Esecuzione forceSplit | URL: {fullUrl} | esito: {rawSplit}"); - } - fatto = (rawSplit == "OK") ? true : false; - } - } - catch (Exception exc) - { - lgError($"Eccezione in forceSplitOdl{Environment.NewLine}{exc}"); - } - // se fatto --> resetto contapezzi!!! - if (fatto) - { - contapezziPLC = 0; - contapezziIOB = 0; - } - } - else - { - lgError("Richiesto forceSplitOdl ma MP/IOB offline --> NON eseguito"); - } - } - else - { - lgError("Richiesto forceSplitOdl ma veto attivo --> NON eseguito"); - } - return fatto; - } - - /// - /// 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(); - processMem2Write(); - } - else if (ciclo == gatherCycle.LF) - { - processCustomTaskLF(); - 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... - lgTrace("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; + answ = (QueueIN.Count + QueueFLog.Count >= nMaxSend); + IobOnline = answ; } else { - if (periodicLog) - { - lgDebug("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($"Veto Time Elapsed | lastConnectTry: {lastConnectTry} | waitRecMSec {waitRecMSec} ms) | NOW tryConnect"); - lastConnectTry = DateTime.Now; - tryConnect(); - } - } - currDispData.semIn = Semaforo.SR; - processDisconnectedTask(); - } - raiseRefresh(currDispData); - } - - /// - /// Effettua processing CUSTOM x l'IOB corrente (ed invia ad IO) - /// (task svolto tipicamente ogni 5 sec se base timer 10ms, vedere app.config) - /// - public virtual void processCustomTaskLF() - { } - - /// - /// Recupera eventuali allarmi CNC... - /// - public virtual Dictionary getCncAlarms() - { - Dictionary outVal = new Dictionary(); - return outVal; - } - - /// - /// Restituisce info DINAMICHE - /// - /// - public virtual Dictionary getDynData() - { - Dictionary outVal = new Dictionary(); - return outVal; - } - - /// - /// 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 - /// - /// - public virtual Dictionary getOverrides() - { - Dictionary outVal = new Dictionary(); - return outVal; - } - - /// - /// Restituisce programma in esecuzione - /// - public virtual string getPrgName() - { - return ""; - } - - /// - /// Restituisce info sistema - /// - /// - public virtual Dictionary getSysInfo() - { - Dictionary outVal = new Dictionary(); - return outVal; - } - - /// - /// 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 = -999999; - // cerco VC... - if (TSVC_Data.ContainsKey(VCName)) - { - try - { - switch (TSVC_Data[VCName].Funzione) - { - case VC_func.POINT: - // prendo PRIMO - answ = TSVC_Data[VCName].dataArray.FirstOrDefault(); - break; - - case VC_func.AVG: - answ = TSVC_Data[VCName].dataArray.Average(); - break; - - case VC_func.MEDIAN: - answ = TSVC_Data[VCName].dataArray.Median(); - break; - - case VC_func.MIN: - answ = TSVC_Data[VCName].dataArray.Min(); - break; - - case VC_func.MAX: - default: - answ = TSVC_Data[VCName].dataArray.Max(); - break; - } - } - catch - { } - // 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 - /// - /// Tipo di URL (eventi / FLog) - /// elenco di valori da coda string salvata - /// - public string jsonPayload(urlType tipoUrl, List elencoValori) - { - string answ = ""; - if (elencoValori != null) - { - string[] valori; - int counter = 0; - DateTime dtEve = DateTime.Now; - switch (tipoUrl) - { - case urlType.FLog: - flogData currFlData = new flogData(); - flogJsonPayload fullFlObj = new flogJsonPayload(); - fullFlObj.fluxData = new List(); - // inizio processando ogni valore - foreach (var item in elencoValori) - { - valori = qDecodeIN(item); - CultureInfo provider = CultureInfo.InvariantCulture; - DateTime.TryParseExact(valori[0], "yyyyMMddHHmmssfff", provider, DateTimeStyles.AssumeLocal, out dtEve); - int.TryParse(valori[3], out counter); - currFlData = new flogData() - { - flux = valori[1], - valore = valori[2], - dtEve = dtEve, - dtCurr = DateTime.Now, - cnt = counter - }; - fullFlObj.fluxData.Add(currFlData); - } - // conversione finale try { - answ = JsonConvert.SerializeObject(fullFlObj); - } - catch (Exception exc) - { - lgError($"FLog Errore in costruzione jsonPayload:{Environment.NewLine}{exc}"); - } - break; - - case urlType.SignIN: - evData currSigData = new evData(); - evJsonPayload fullEvObj = new evJsonPayload(); - fullEvObj.eventList = new List(); - // inizio processando ogni valore - foreach (var item in elencoValori) - { - valori = qDecodeIN(item); - CultureInfo provider = CultureInfo.InvariantCulture; - DateTime.TryParseExact(valori[0], "yyyyMMddHHmmssfff", provider, DateTimeStyles.AssumeLocal, out dtEve); - int.TryParse(valori[2], out counter); - currSigData = new evData() + // 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) { - valore = valori[1], - dtEve = dtEve, - dtCurr = DateTime.Now, - cnt = counter - }; - fullEvObj.eventList.Add(currSigData); - } - // conversione finale - try - { - answ = JsonConvert.SerializeObject(fullEvObj); - } - catch (Exception exc) - { - lgError($"SignIN Errore in costruzione jsonPayload:{Environment.NewLine}{exc}"); - } - break; - - case urlType.RawTransf: - BaseRawTransf currRTData = new BaseRawTransf(); -#if false - rawTransfJsonPayload fullRTObj = new rawTransfJsonPayload(); - fullRTObj.rawTransfData = new List(); - // inizio processando ogni valore - foreach (var item in elencoValori) - { - try - { - currRTData = JsonConvert.DeserializeObject(item); + Thread.Sleep(rand.Next(250, 500)); + callResp = callUrl(urlIobEnabled, true); + answ = (callResp == "OK"); + maxTry--; } - catch (Exception exc) + // se NON OK riprovo ANCORA 1 volta... + if (!answ) { - lgError($"Eccezione in deserializzazione BaseRawTransf:{Environment.NewLine}{exc}"); + resetWebClients(); + Thread.Sleep(rand.Next(250, 1000)); + callResp = callUrl(urlIobEnabled, false); + answ = (callResp == "OK"); } - fullRTObj.rawTransfData.Add(currRTData); - } - // conversione finale - try - { - answ = JsonConvert.SerializeObject(fullRTObj); - } - catch (Exception exc) - { - lgError($"RawTransf Errore in costruzione jsonPayload:{Environment.NewLine}{exc}"); - } -#endif - - // provo una serializzazione "brutale", ovvero aggiungo alla stringa il valore di testa... - string rawResult = ""; - foreach (var item in elencoValori) - { - rawResult += $"{item},"; - } - if (rawResult.Length > 0) - { - rawResult = rawResult.Substring(0, rawResult.Length - 1); - } - answ = "{" + $"\"rawTransfData\":[{rawResult}]" + "}"; - - break; - - case urlType.ULog: - int numVal = 0; - int matrOp = 0; - ulogData currUlData = new ulogData(); - ulogJsonPayload fullUlObj = new ulogJsonPayload(); - fullUlObj.fluxData = new List(); - // inizio processando ogni valore - foreach (var item in elencoValori) - { - valori = qDecodeIN(item); - CultureInfo provider = CultureInfo.InvariantCulture; - DateTime.TryParseExact(valori[0], "yyyyMMddHHmmssfff", provider, DateTimeStyles.AssumeLocal, out dtEve); - int.TryParse(valori[3], out matrOp); - int.TryParse(valori[5], out numVal); - int.TryParse(valori[6], out counter); - currUlData = new ulogData() + // altri 2 + maxTry = 2; + while (maxTry > 0 && !answ) { - flux = valori[1], - valore = valori[2], - dtEve = dtEve, - dtCurr = DateTime.Now, - cnt = counter, - matrOpr = matrOp, - label = valori[4], - valNum = numVal - }; - fullUlObj.fluxData.Add(currUlData); - } - // conversione finale - try - { - answ = JsonConvert.SerializeObject(fullUlObj); - } - catch (Exception exc) - { - lgError($"ULog Errore in costruzione jsonPayload:{Environment.NewLine}{exc}"); - } - break; - - default: - break; - } - } - 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 - /// - public void processAutoOdl() - { - bool fatto = false; - if (!string.IsNullOrEmpty(getOptPar("AUTO_CHANGE_ODL"))) - { - lgTrace("Richiesta processAutoOdl"); - string IOB_MULTI_CNAME = ""; - string[] elencoMulti = null; - string fullUrl = ""; - if (isMulti) - { - // devo chiamare cambio ODL x OGNI tavola: mi servono i parametri opzionali... - IOB_MULTI_CNAME = getOptPar("IOB_MULTI_CNAME"); - elencoMulti = IOB_MULTI_CNAME.Split(','); - } - // controllo SIA abilitato... - bool doProc = false; - DateTime adesso = DateTime.Now; - bool.TryParse(getOptPar("AUTO_CHANGE_ODL"), out doProc); - if (doProc) - { - lgTrace("AUTO_CHANGE_ODL abilitato"); - bool callChangeODL = false; - // modalità change ODL - string CHANGE_ODL_MODE = "TIME"; - if (!string.IsNullOrEmpty(getOptPar("CHANGE_ODL_MODE"))) - { - CHANGE_ODL_MODE = getOptPar("CHANGE_ODL_MODE"); - } - if (CHANGE_ODL_MODE == "PZCOUNT_RESET") - { - /* verifico se sia "armato" il reset cambio ODL, DEVO essere : - * - NON in produzione - * - contapezzi ACT < contapezzi LAST - * */ - lgTrace("processAutoOdl: caso PZCOUNT_RESET"); - if ((!isRunning || forceResetInRun) && pzCountResetted) - { - callChangeODL = true; - lgInfo("Attivato cambio ODL da PZCOUNT_RESET"); - } - else - { - lgInfo($"isRunning: {isRunning} | pzCountResetted: {pzCountResetted} | forceResetInRun: {forceResetInRun} | contapezziIOB: {contapezziIOB} | contapezziPLC: {contapezziPLC}"); - } - } - else if (CHANGE_ODL_MODE == "TIME") - { - // carico i parametri di configurazione x reset ODL... - string CHANGE_ODL_HOURS = getOptPar("CHANGE_ODL_HOURS"); - string CHANGE_ODL_IDLE_MIN = getOptPar("CHANGE_ODL_IDLE_MIN"); - if (!string.IsNullOrEmpty(CHANGE_ODL_HOURS) && !string.IsNullOrEmpty(CHANGE_ODL_IDLE_MIN)) - { - int minOdlDurHours = -1; - int minPlcIdelMin = -1; - int.TryParse(CHANGE_ODL_HOURS, out minOdlDurHours); - int.TryParse(CHANGE_ODL_IDLE_MIN, out minPlcIdelMin); - // controllo parametri validi - if (minOdlDurHours > 0 && minPlcIdelMin >= 0) - { - // leggo da server inizio ODL... se non multi 1 solo... - DateTime inizioOdl = DateTime.Now; - string rawDataInizio = ""; - if (!isMulti) - { - rawDataInizio = callUrl(urlInizioOdlIob, false); - DateTime.TryParse(rawDataInizio, out inizioOdl); - } - else - { - DateTime tmpData = DateTime.Now; - // prendo il + vecchio... - foreach (var item in elencoMulti) - { - fullUrl = $"{urlInizioOdlIob}|{item}"; - rawDataInizio = callUrl(fullUrl, false); - DateTime.TryParse(rawDataInizio, out tmpData); - inizioOdl = (tmpData < inizioOdl) ? tmpData : inizioOdl; - } - } - // verifico se sia scaduto... - if (inizioOdl.AddHours(minOdlDurHours) < adesso) - { - string rawIdle = ""; - int idlePeriod = 0; - if (!isMulti) - { - // controllo SE sono fermo (spento o in manuale) per il periodo minimo richiesto... - rawIdle = callUrl(urlIdleTime, false); - int.TryParse(rawIdle, out idlePeriod); - } - else - { - int tmpIdle = 0; - // prendo il + grande... - foreach (var item in elencoMulti) - { - fullUrl = $"{urlIdleTime}|{item}"; - rawIdle = callUrl(fullUrl, false); - int.TryParse(rawIdle, out tmpIdle); - idlePeriod = tmpIdle > idlePeriod ? tmpIdle : idlePeriod; - } - } - if (idlePeriod >= minPlcIdelMin) - { - callChangeODL = true; - } - } + Thread.Sleep(rand.Next(250, 500)); + callResp = callUrl(urlIobEnabled, false); + answ = (callResp == "OK"); + maxTry--; } - } - } - - // vero processing... - if (callChangeODL) - { - lgTrace("Chiamata: processAutoOdl --> forceSplitODL"); - fatto = forceSplitOdl(); - pzCountResetted = false; - lgInfo("Esecuzione processAutoOdl completata --> pzCountResetted = false"); - } - } - else - { - lgTrace("AUTO_CHANGE_ODL DISABILITATO"); - } - } - // loggo se fatto - if (fatto) - { - lgTrace("Effettuato processAutoOdl"); - } - } - - /// - /// Effettua processing degli allarmi CNC SE disponibili - /// - public void processCncAlarms() - { - if (utils.CRB("enableAlarms")) - { - Dictionary currAlarms = new Dictionary(); - if (connectionOk) - { - currAlarms = getCncAlarms(); - } - else - { - lgError("Errore connessione mancante x getCncAlarms"); - } - // verifico SE sia cambiato il programma... - if (currAlarms.Count > 0) - { - try - { - string sVal = ""; - if (lastAlarm != currAlarms["CNC_ALARM"]) - { - // salvo! - lastAlarm = currAlarms["CNC_ALARM"]; - // per ogni valore del dizionario mostro ed accodo! - foreach (var item in currAlarms) + // salvo status... + IobOnline = answ; + // se online imposto veto check a 5 x tempo reinvio... + if (answ) { - sVal = string.Format("[CNC_ALARM]{0}|{1}", item.Key, item.Value); - // chiamo accodamento... - accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); - } - } - // accodo ALTRI allarmi NON CNC... - foreach (var item in currAlarms.Where(X => X.Key != "CNC_ALARM")) - { - sVal = $"{item.Key} | {item.Value}"; - accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); - } - } - catch (Exception exc) - { - lgError("Eccezione in processCncAlarms{0}{1}", Environment.NewLine, exc); - } - } - } - } - - /// - /// Effettua processing contapezzi (ed eventualmente alza il bit di contapezzo...) - /// - public virtual void processContapezzi() - { } - - /// - /// Task periodici SE disconnesso - /// - public virtual void processDisconnectedTask() - { - } - - /// - /// Effettua processing del recupero dei valori dinamici: - /// es: speed (RPM, feedrate) degli assi, valori pressioni, temeprature - /// - public void processDynData() - { - bool enableByApp = utils.CRB("enableDynData"); - bool enableByIob = (getOptPar("ENABLE_DYN_DATA") == "TRUE"); - bool forceSendByIob = (getOptPar("FORCE_DYN_DATA") == "TRUE"); - Dictionary currDynData = new Dictionary(); - - if (enableByApp || enableByIob) - { - lgInfo("Inizio processDynData"); - if (connectionOk) - { - currDynData = getDynData(); - try - { - string sVal = ""; - // se richiesto send diretto... - if (forceSendByIob) - { - // per ogni valore del dizionario mostro ed accodo! - foreach (var item in currDynData) - { - sVal = string.Format("[DYNDATA]{0}|{1}", item.Key, item.Value); - // chiamo accodamento... - accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); - } - } - // altrimenti verifico SE sia cambiato il valore dei DynData... - else if (lastDynDataCtrlVal != currDynData["DYNDATA"]) - { - // salvo! - lastDynDataCtrlVal = currDynData["DYNDATA"]; - // per ogni valore del dizionario mostro ed accodo! - foreach (var item in currDynData) - { - sVal = string.Format("[DYNDATA]{0}|{1}", item.Key, item.Value); - // chiamo accodamento... - accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); - } - } - // salvo array... - lastDynData = currDynData; - } - catch (Exception exc) - { - lgError(exc, "Eccezione in processDynData"); - } - } - else - { - lgError("Errore connessione mancante x getDynData"); - } - } - } - - /// - /// Processa gestione memoria x invio dati QUANDO IOB è disconnesso da CNC... - /// - public void processMemoryDiscon() - { - // init obj display - newDisplayData currDispData = new newDisplayData(); - // controllo contatore invio "keepalive"... invio solo a scadenza - if (DateTime.Now.Subtract(lastDisconnCheck).TotalSeconds > utils.CRI("disconMaxSec")) - { - // resetto tutti i vlaori BYTE IN/PREV/OUT... così invio macchina spenta... - B_input = 0; - B_output = 0; - B_previous = 0; - accodaSigIN(ref currDispData); - // update controllo - lastDisconnCheck = DateTime.Now; - } - raiseRefresh(currDispData); - } - - /// - /// Effettua processing mode/status (EDIT/MDI/...) - /// - public virtual void processMode() - { } - - /// - /// Effettua processing ALTRI contatori/parametri (ed invia ad IO) - /// - public virtual void processOtherCounters() - { } - - /// - /// Effettua processing del recupero delle OVERRIDE (spindle, feedrate, rapid) - /// - public virtual void processOverride() - { - bool enableByApp = utils.CRB("enableOverrides"); - bool enableByIob = (getOptPar("ENABLE_OVERRIDES") == "TRUE"); - Dictionary currOverride = new Dictionary(); - if (enableByApp || enableByIob) - { - lgInfo("Inizio processOverride"); - if (connectionOk) - { - currOverride = getOverrides(); - } - else - { - lgError("Errore connessione mancante x getOverrides"); - } - - // SE sono connesso... - if (connectionOk) - { - // se HO dei valori override... - if (currOverride.Count > 0) - { - // verifico SE sia cambiato il programma... - if (lastOverrideFS != currOverride["FEED_OVER"] || lastOverrideRapid != currOverride["RAPID_OVER"]) - { - // salvo! - lastOverrideFS = currOverride["FEED_OVER"]; - lastOverrideRapid = currOverride["RAPID_OVER"]; - // per ogni valore del dizionario mostro ed accodo! - string sVal = ""; - foreach (var item in currOverride) - { - sVal = string.Format("[OVERRIDES]{0}|{1}", item.Key, item.Value); - // chiamo accodamento... - accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); - } - } - } - } - } - } - - /// - /// 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 S01: {task2exe.Count} task ricevuti:"); - int idTask = 0; - foreach (var item in task2exe) - { - idTask++; - lgInfo($"[{idTask:00}] - {item.Key} --> {item.Value}"); - } - // chiamo procedura esecutiva (diversa x ogni IOB) - taskDone = executeTasks(task2exe); - lgInfo($"Task2Exe S02: eseguiti {taskDone.Count} task"); - // 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 - /// - public virtual void processVHF() - { - } - - /// - /// Classe fittizia in caso di processing watchdog data - /// - public virtual void processWhatchDog() - { - } - - /// - /// 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); - lgTrace("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; - lgError($"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; - lgError($"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#flusso#valore#cont - /// Flusso dati - /// Valore da salvare - /// - public string qEncodeFLog(string flusso, string valore) - { - string answ = ""; - try - { - answ = $"{DateTime.Now:yyyyMMddHHmmssfff}#{flusso}#{valore}#{counterULog}"; - } - 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 = $"{eventDT:yyyyMMddHHmmssfff}#{flusso}#{valore}#{counterFLog}"; - } - catch - { } - return answ; - } - - /// - /// Fornisce il valore di UserLog e valore in formato valido x messa in coda nel formato: - /// dtEve#flusso#value#cont#matrOpr#label#valNum - /// Flusso dati (RC/RS/DI) - /// Valore da inviare (valString - /// Matricola operatore - /// Valore etichetta: causale scarto / tagCode - /// Valore numerico: esitoOk (0/1) / nuo scarti - /// - public string qEncodeULog(string flusso, string valore, int matrOpr, string label, int valNum) - { - string answ = ""; - try - { - answ = $"{DateTime.Now:yyyyMMddHHmmssfff}#{flusso}#{valore}#{matrOpr}#{label}#{valNum}#{counterULog}"; - } - catch - { } - return answ; - } - - /// - /// Effettua lettura dati - /// Parametri da aggiornare x display in form - /// - public virtual void readAllData(ref newDisplayData currDispData) - { - if (currDispData == null) - { - currDispData = new newDisplayData(); - } - try - { - if (DemoIn) - { - // segnalo che sono in Demo - currDispData.semIn = Semaforo.SV; - } - if (connectionOk) - { - readSemafori(ref currDispData); - } - else - { - lgError("Errore connessione mancante x readSemafori"); - } - - nReadIN++; - // aggiorno valore mostrato... - displayRawData(ref currDispData); - } - catch - { - currDispData.semIn = Semaforo.SR; - } - raiseRefresh(currDispData); - } - - /// - /// Effettua lettura semafori principale - /// Parametri da aggiornare x display in form - /// - public virtual void readSemafori(ref newDisplayData currDispData) - { - lastReadPLC = DateTime.Now; - } - - /// - /// Aggiunge ai dati da inviare alla parentform i valori di RawInput rilevati (32bit) - /// 2021.08.27: filtrati secondo i valori setup start/size RawDataInput - /// - 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}"); - // Do x scontato siano VALIDI i valori di RawDataInputStart / size --> filtro... - var filtRawData = new byte[RawDataInputSize]; - Array.Copy(RawInput, RawDataInputStart, filtRawData, 0, RawDataInputSize); - int i = RawDataInputStart; - foreach (var item in filtRawData) - { - 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 - /// - /// tipo di DUMP - public virtual void saveMemDump(dumpType tipo) - { - } - - /// - /// 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); - } - } - - /// - /// Effettua salvataggio in LUT del valore ricevuto - /// - /// - /// - /// - /// - public virtual void saveValue(ref Dictionary outVal, double valore, string chiave) - { - //check obj preliminare - if (outVal == null) - { - outVal = new Dictionary(); - } - bool scaduto = stackVal_TSVC(chiave, valore); - // recupero VC - valore = getVal_TSVC(chiave, scaduto); - if (scaduto) - { - // limite a 3 digit x valore float - outVal.Add(chiave, $"{valore:N3}"); - } - LastTSVC[chiave] = valore; - } - - /// - /// Invio la variazione dello stato allarmi (se avvenuta) - /// - /// COD memoria allarmi - /// Indice memoria allarmi - /// ultimo stato rilevato - /// stato corrente - /// Lista allarmi validi per l'area - /// - public bool sendAlarmVariations(string memAddr, int index, uint lastStatus, uint currStatus, List AlarmList) - { - bool fatto = false; - if (lastStatus != currStatus) - { - List ActiveAlarmList = new List(); - // invio GET del MemoryAddress, del banco e del valore currStatus - lastUrl = $"{urlSendAlarm}?memAddr={memAddr}&index={index}&currStatus={currStatus}"; - if (currStatus == 0) - { - ActiveAlarmList.Add("ALL OK"); - } - else - { - // calcolo quali allarmi mostrare dato currStatus ed elenco allarmi - string bitMap = Convert.ToString(currStatus, 2); - int bitLen = bitMap.Length; - // ciclo x associare tutti gli allarmi - for (int i = 0; i < bitLen; i++) - { - // se è 1 --> aggiungo! - if (bitMap[bitLen - i - 1] == '1') - { - // se sono entro limiti - if (AlarmList.Count >= i) - { - ActiveAlarmList.Add($"{i:000}-{AlarmList.ElementAt(i)}"); - } - //else - //{ - // ActiveAlarmList.Add($"Unknown Bit.{i}"); - //} - } - } - } - - string rawData = JsonConvert.SerializeObject(ActiveAlarmList); - - //string resp = utils.callUrlNow(lastUrl, rawData); - string resp = utils.callUrlAsync(lastUrl, rawData); - if (!string.IsNullOrEmpty(resp)) - { - if (resp.ToUpper() == "OK") - { - // segnalo fatto - fatto = true; - } - } - else - { - lgError($"Errore in invio richiesta registrazione allarme: URL: {lastUrl}{Environment.NewLine}Payload:{Environment.NewLine}{rawData}"); - } - } - return fatto; - } - - /// - /// Invia una LISTA di valori - /// - /// - /// - public void sendDataBlock(urlType tipoUrl, List listQueueVal) - { - // init obj display - newDisplayData currDispData = new newDisplayData(); - if (listQueueVal != null) - { - try - { - // recupero e formatto URL dati da coda... - lastUrl = urlDataBlock(tipoUrl); - // in base al tipo di dato compongo il payload Json da inviare - string payload = jsonPayload(tipoUrl, listQueueVal); - // async a true SE FLog - bool doAsync = tipoUrl == urlType.FLog ? true : false; - // se NON sono in demo effettuo invio! - if (!DemoOut) - { - // SE server alive... - if (checkServerAlive) - { - // chiamo URL! - string answ = callUrlWithPayload(lastUrl, payload, doAsync); - // attesa opzionale se configurata - - // loggo! - lgInfo($"[SEND payload] TipoURL: {tipoUrl} | {listQueueVal.Count} records --> {answ}"); - // se "OK" verde, altrimenti errore --> ROSSO - if (answ.Contains("OK")) - { - currDispData.semOut = Semaforo.SV; - // se oltre 1 min NON era online --> check pezzi! - if (DateTime.Now.Subtract(lastIobOnline).TotalMinutes > 1 && !isMulti) - { - lgInfo($"sendDataBlock --> offline timeout ({lastIobOnline}) --> pzCntReload(true)"); - pzCntReload(true); - } lastIobOnline = DateTime.Now; } + 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; + // se disabilitato salto... + if (pingDisabled) + { + answ = IPStatus.Success; + } + else + { + IPAddress address; + PingReply reply; + var rand = new Random(); + int pingTOut = 500; + using (Ping pingSender = new Ping()) + { + address = IPAddress.Loopback; + int maxRetry = maxPingRetry + 1; + int numRetry = 1; + string ipAddr = cIobConf.serverData.MPIP.Replace($"{cIobConf.serverData.TRANSP}://", ""); + // fix se fosse ip + porta... + if (ipAddr.IndexOf(":") >= 0) + { + ipAddr = ipAddr.Substring(0, ipAddr.IndexOf(":")); + } + IPAddress.TryParse(ipAddr, out address); + // se null --> provo DNS... + if (address == null) + { + var rawAddresses = Dns.GetHostAddresses(ipAddr); + if (rawAddresses.Length > 0) + { + address = rawAddresses[0]; + } + } + try + { + // se != null --> uso address... + if (address != null) + { + pingTOut = rand.Next(200, 400); + reply = pingSender.Send(address, pingTOut); + } else { - currDispData.semOut = Semaforo.SR; + pingTOut = rand.Next(300, 600); + reply = pingSender.Send(cIobConf.cncIpAddr, pingTOut); } } - else + catch (Exception exc) { - lgInfo($"[SERVER KO] {listQueueVal.Count}"); + pingTOut = rand.Next(100, 200); + reply = pingSender.Send(IPAddress.Loopback, pingTOut); + lgError($"ping to loopback addres per eccezione:{Environment.NewLine}{exc}"); + } + // se ho timeout riprovo... + while (reply.Status != IPStatus.Success && numRetry < maxRetry) + { + Thread.Sleep(rand.Next(50, 200)); + pingTOut = pingServerMsTimeout * numRetry / 2; + reply = pingSender.Send(address, pingTOut); + numRetry++; + if (reply.Status == IPStatus.Success) + { + lgInfo("Server PING OK!"); + break; + } + else + { + lgInfo($"Server Ping KO | reply: {reply.Status} --> retry | TimeOut: {pingTOut}"); + } } } - else - { - currDispData.semOut = Semaforo.SV; - // loggo! - lgInfo($"{listQueueVal.Count} records --> [SIM]"); - } - nSendOut += listQueueVal.Count; - // riporto cosa inviato - currDispData.newUrlCallData = lastUrl; - // aggiorno data ultimo watchdog... - lastWatchDog = DateTime.Now; - } - catch - { - currDispData.semOut = Semaforo.SR; + answ = reply.Status; } + return answ; } - raiseRefresh(currDispData); + } + + #endregion Private Properties + + #region Private Methods + + /// + /// 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); } /// - /// Effettua invio a MoonPro del valore richiesto + /// Mostra i dati grezzi letti in esadecimale Parametri da + /// aggiornare x display in form /// - /// - /// Valore da trasmettere: es - /// INPUT: lo status rilevato in HEX - /// FLog: il valore da trasmettere per il flusso indicato - public void sendToMoonPro(urlType tipoUrl, string queueVal) + private void displayRawData(ref newDisplayData currDispData) { - // init obj display - newDisplayData currDispData = new newDisplayData(); + // mostro update... + string newString = string.Format("{0:X}", B_input); + currDispData.newInData = newString; + } + + /// + /// 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) + { + lgTrace("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 + { + lgTrace("END BLINK: B{0}", i); + } + } + } + } + } + } + + /// + /// 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; + } + + string s_maxErrCheck = getOptPar("MAX_ERR_CHECK"); + if (!string.IsNullOrEmpty(s_maxErrCheck)) + { + int numErr = 50; + int.TryParse(s_maxErrCheck, out numErr); + maxErroriCheck = numErr; + } + + string s_watchDogPer = getOptPar("WATCHDOG_PERIOD"); + if (!string.IsNullOrEmpty(s_watchDogPer)) + { + int numPer = 3; + int.TryParse(s_watchDogPer, out numPer); + watchDogPeriod = numPer; + } + } + + /// + /// recupera valore salvato in persistence layer (se non c'è crea...) + /// + /// + /// + private string getStoredVal(string keyVal) + { + string value = ""; try { - // recupero e formatto URL dati da coda... - switch (tipoUrl) + if (persistenceLayer != null) { - case urlType.FLog: - lastUrl = urlFLog(queueVal); - break; - - case urlType.SignIN: - lastUrl = urlInput(queueVal); - break; - - default: - lastUrl = ""; - break; - } - // se NON sono in demo effettuo invio! - if (!DemoOut) - { - // SE server alive... - if (checkServerAlive) + if (!persistenceLayer.TryGetValue(keyVal, out value)) { - // chiamo URL! - string answ = callUrl(lastUrl, false); - // loggo! - lgDebug(string.Format("[SEND] {0} -> {1}", queueVal, answ)); - // se oltre 1 min NON era online --> check pezzi! - if (DateTime.Now.Subtract(lastIobOnline).TotalMinutes > 1 && !isMulti) - { - lgInfo($"sendToMoonPro --> offline timeout ({lastIobOnline}) --> pzCntReload(true)"); - pzCntReload(true); - } - // se richiesto effettuo refresh contapezzi - if (needRefreshPzCount && !isMulti) - { - pzCntReload(true); - needRefreshPzCount = false; - } - lastIobOnline = DateTime.Now; - // se "OK" verde, altrimenti errore --> ROSSO - if (answ == "OK") - { - currDispData.semOut = Semaforo.SV; - } - else - { - currDispData.semOut = Semaforo.SR; - } - } - else - { - lgError(string.Format("[SERVER KO] {0}", queueVal)); + persistenceLayer.Add(keyVal, "0"); } } - else - { - currDispData.semOut = Semaforo.SV; - // loggo! - lgDebug(string.Format("{0} -> [SIM]", queueVal)); - } - nSendOut++; - currDispData.newUrlCallData = lastUrl; - // aggiorno data ultimo watchdog... - lastWatchDog = DateTime.Now; } - catch + catch (Exception exc) { - currDispData.semOut = Semaforo.SR; + lgError(string.Format("Eccezione in getStoredVal: {0}{1}", Environment.NewLine, exc)); } - raiseRefresh(currDispData); + return value; } /// - /// Metodo generico di IMPOSTAZIONE FORZATA del contapezzi... + /// recupera valore salvato in persistence layer (se non c'è crea...) come double /// - /// Pezzi richiesti + /// /// - public virtual bool setcontapezziPLC(int newPzCount) + private double getStoredValDouble(string keyVal) { - 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)) + double answ = 0; + try { - TSVC_Data[VCName].dataArray.Add(VCVal); - // ora verifico scadenza... - if (TSVC_Data[VCName].DTStart.AddSeconds(TSVC_Data[VCName].Period) < DateTime.Now) - { - answ = true; - } + 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; } /// - /// Avvia l'adapter sulla porta richiesta + /// recupera valore salvato in persistence layer (se non c'è crea...) come INT /// - /// indica se sia richeisto di SVUOTARE le code delel info - public virtual void startAdapter(bool resetQueue) + /// + /// + private long getStoredValLong(string keyVal) { - DateTime adesso = DateTime.Now; ; - DateTime scaduto = adesso.AddMinutes(-10); - lgInfo("Starting adapter..."); - maxJsonData = utils.CRI("maxJsonData"); - maxJsonDataEv = utils.CRI("maxJsonDataEv"); - parentForm.commPlcActive = false; - adpRunning = true; - dtAvvioAdp = adesso; - lastWatchDog = scaduto; - lastPING = scaduto; - lastReadPLC = scaduto; - lastDisconnCheck = scaduto; - TimingData.resetData(); - // aggiungo altri defaults - setDefaults(resetQueue); - adpTryRestart = true; - lgDebug("startAdapter completed"); + 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; } /// - /// ferma l'adapter... + /// recupera valore salvato in persistence layer (se non c'è crea...) come UINT /// - /// 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) + /// + /// + private uint getStoredValUInt(string keyVal) { - if (forceDequeue) + uint answ = 0; + try { - // svuoto le code dei valori letti e non ancora trasmessi... - parentForm.displayTaskAndLog("[CLOSING] Svuotamento FORZATO coda segnali..."); - while (QueueIN.Count > 0) + 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); + } + + private void processMem2Write() + { + List updatedPar = new List(); + // ciclo tutti gli oggetti write x vedere se modificati... + foreach (var item in currProdData) + { + bool needWrite = false; + // li cerco su last... se non ci sono o modificati --> salvo da scrivere e copio + if (lastProdData.ContainsKey(item.Key)) { - // INVIO COMUNQUE...!!! - string valore = ""; - QueueIN.TryDequeue(out valore); - sendToMoonPro(urlType.SignIN, valore); - } - parentForm.displayTaskAndLog("[CLOSING] Svuotamento FORZATO coda FluxLOG..."); - // se ho + di 2 elementi in coda --> uso invio JSON in blocco... - if (QueueFLog.Count > minJsonData) - { - while (QueueFLog.Count > 0) + // verifico se variato... + if (!item.Value.Equals(lastProdData[item.Key])) { - 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(); - } + needWrite = true; + lastProdData[item.Key] = item.Value; } - // HO FINITO invio di FLog... } + // aggiungo else { - string currVal = ""; - while (QueueFLog.Count > 0) - { - // INVIO COMUNQUE...!!! - QueueFLog.TryDequeue(out currVal); - sendToMoonPro(urlType.FLog, currVal); - } + needWrite = true; + lastProdData.Add(item.Key, item.Value); } - - // svuoto coda ULog - while (QueueULog.Count > 0) + // se devo scrivere --> riporto + if (needWrite) { - List listaValori = new List(); - // se ho + di maxJsonData elementi --> invio un set di dati alla volta - if (QueueULog.Count > maxJsonData) + if (memMap.mMapWrite.ContainsKey(item.Key)) { - string currVal = ""; - // prendoi primi maxJsonDataValori - for (int i = 0; i < maxJsonData; i++) + // preparo obj da scrivere + objItem newWrite = new objItem() { - QueueULog.TryDequeue(out currVal); - listaValori.Add(currVal); - } - sendDataBlock(urlType.ULog, listaValori); - } - else - { - // invio in blocco - listaValori = QueueULog.ToList(); - // invio - sendDataBlock(urlType.ULog, listaValori); - // svuoto! - QueueULog = new ConcurrentQueue(); + uid = item.Key, + name = item.Key, + reqValue = memMap.mMapWrite[item.Key].value, + lastRequest = DateTime.Now, + writable = true + }; + updatedPar.Add(newWrite); } } } - parentForm.displayTaskAndLog("[STOP] Stopping adapter..."); - adpTryRestart = false; - - parentForm.displayTaskAndLog("[STOP] 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; + // se ho da scrivere... scrivo TUTTI! + if (updatedPar.Count > 0) + { + // scrivo valore! + lgInfo("Chiamata di plcWriteParams da processMem2Write"); + plcWriteParams(ref updatedPar); + // invio su cloud parametri! + string rawData = JsonConvert.SerializeObject(updatedPar); + utils.callUrl($"{urlUpdateWriteParams}", rawData); + lgInfo($"Notificato a server scrittura {updatedPar.Count} parametri"); + } } /// - /// Processo la coda SignalIN... + /// Effettua gestioen programma: legge e mostra su display... /// - public void svuotaCodaSignIN() + 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"); + // fix url wait random... + urlRandWait = utils.CRI("urlRandWait"); + // fix fattore demoltiplica dynData + fixDemFactDynData(); + + // svuoto code se richiesto + if (resetQueue) + { + QueueAlarm = new ConcurrentQueue(); + QueueIN = new ConcurrentQueue(); + QueueFLog = new ConcurrentQueue(); + QueueMessages = new ConcurrentQueue(); + QueueRawTransf = new ConcurrentQueue(); + QueueULog = new ConcurrentQueue(); + } + // imposto contatori blink a zero... + i_counters = new int[32]; + lastPeriodicLog = DateTime.Now; + // fix parametri generali... + enablePrgName = true; + } + + /// + /// Legge da conf il valore di demoltiplica lettura dynData (se presente) o ignora e pone a 1... + /// + private void fixDemFactDynData() + { + var rawDemFact = getOptPar("DEM_FACT_DYN_DATA"); + if (string.IsNullOrEmpty(rawDemFact)) + { + demFactDynData = 1; + } + else + { + int.TryParse(rawDemFact, out demFactDynData); + } + } + + 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 (QueueIN.Count > 0) + if (QueueFLog.Count > 0) { // invio pacchetto di dati (max da conf) for (int i = 0; i < nMaxSend; i++) { - if (QueueIN.Count > 0) + // SE ho qualcosa in coda... + if (QueueFLog.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) + if (QueueFLog.Count > 1) { List listaValori = new List(); // se ho + di maxJsonData elementi --> invio un set di dati alla volta - if (QueueIN.Count > maxJsonDataEv) + if (QueueFLog.Count > maxJsonData) { // prendoi primi maxJsonDataValori - for (int j = 0; j < maxJsonDataEv; j++) + for (int j = 0; j < maxJsonData; j++) { - QueueIN.TryDequeue(out currVal); + QueueFLog.TryDequeue(out currVal); listaValori.Add(currVal); } - sendDataBlock(urlType.SignIN, listaValori); + sendDataBlock(urlType.FLog, listaValori); + lastWatchDog = DateTime.Now; } else { // invio in blocco - listaValori = QueueIN.ToList(); + listaValori = QueueFLog.ToList(); // invio - sendDataBlock(urlType.SignIN, listaValori); + sendDataBlock(urlType.FLog, listaValori); // svuoto! - QueueIN = new ConcurrentQueue(); + QueueFLog = new ConcurrentQueue(); + lastWatchDog = DateTime.Now; } } 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; + QueueFLog.TryDequeue(out currVal); + sendToMoonPro(urlType.FLog, currVal); + lastWatchDog = DateTime.Now; } } else @@ -5594,197 +5535,302 @@ namespace IOB_WIN_NEXT } /// - /// Metodo base connessione... + /// Processo la coda RawTransf... /// - public virtual void tryConnect() + private void svuotaCodaRawTransf() { - dtAvvioAdp = DateTime.Now; - } - - /// - /// 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) + // verifico SE la coda abbia dei valori... + if (QueueRawTransf.Count > 0) { - // SOLO SE online la macchina... - if (IobOnline) + // invio pacchetto di dati (max da conf) + for (int i = 0; i < nMaxSend; i++) { - int numIncr = 0; - int qtyAdded = 0; - // verifico se la funzione SIA abilitata - if (enableSendPzCountBlock) + // SE ho qualcosa in coda... + if (QueueRawTransf.Count > 0) { - int delta = contapezziPLC - contapezziIOB; - // se è abilitata verifico differenza: se ho DELTA > minSendPzCountBlock --> invio un blocco <= maxSendPzCountBlock - if (delta > minSendPzCountBlock) + string currVal = ""; + if (MPOnline) { - // 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)) + if (IobOnline) { - // dalla risposta (come numero) capisco SE ha aggiunto i pezzi (e quanti) - int.TryParse(resp, out qtyAdded); - if (qtyAdded > 0) + List listaValori = new List(); + // se ho + di maxJsonData elementi --> invio un set di dati alla volta + if (QueueRawTransf.Count > maxJsonData) { - // 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()) + // prendoi primi maxJsonDataValori + for (int j = 0; j < maxJsonData; j++) { - // errore salvataggio contapezzi - lgError($"trySendPzCountBlock: errore salvataggio contapezzi: contapezziIOB {contapezziIOB} | risposta: {retVal}"); + QueueRawTransf.TryDequeue(out currVal); + listaValori.Add(currVal); } + sendDataBlock(urlType.RawTransf, listaValori); } else { - lgError($"Richiesto incremento {numIncr} ma NON registrato su server MP-IO"); + // invio in blocco + listaValori = QueueRawTransf.ToList(); + // invio + sendDataBlock(urlType.RawTransf, listaValori); + // svuoto! + QueueRawTransf = new ConcurrentQueue(); } } - currDispData.newUrlCallData = lastUrl; + else + { + break; + } + } + else + { + break; + } + } + else + { + break; + } + } + } + } + + /// + /// Processo la coda UserLog... + /// + private void svuotaCodaULog() + { + // verifico SE la coda abbia dei valori... + if (QueueULog.Count > 0) + { + // invio pacchetto di dati (max da conf) + for (int i = 0; i < nMaxSend; i++) + { + // SE ho qualcosa in coda... + if (QueueULog.Count > 0) + { + string currVal = ""; + if (MPOnline) + { + if (IobOnline) + { + List listaValori = new List(); + // se ho + di maxJsonData elementi --> invio un set di dati alla volta + if (QueueULog.Count > maxJsonData) + { + // prendoi primi maxJsonDataValori + for (int j = 0; j < maxJsonData; j++) + { + QueueULog.TryDequeue(out currVal); + listaValori.Add(currVal); + } + sendDataBlock(urlType.ULog, listaValori); + } + else + { + // invio in blocco + listaValori = QueueULog.ToList(); + // invio + sendDataBlock(urlType.ULog, listaValori); + // svuoto! + QueueULog = new ConcurrentQueue(); + } + } + 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 = Task.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 = Task.Run(() => svuotaCodaSignIN()); + Task taskFLog = Task.Run(() => svuotaCodaFLog()); + Task taskRawTransf = Task.Run(() => svuotaCodaRawTransf()); + Task taskULog = Task.Run(() => svuotaCodaULog()); + } + else + { + // gestione queue SignalIN (invio, display) + svuotaCodaSignIN(); currDispData.counter = contapezziIOB; - currDispData.semOut = Semaforo.SV; raiseRefresh(currDispData); + // provo a svuotare coda contapezzi + svuotaCodaContapezzi(); + currDispData.counter = contapezziIOB; + raiseRefresh(currDispData); + // gestione queue FluxLog (invio, display) + svuotaCodaFLog(); + // coda RawTransf + svuotaCodaRawTransf(); + // coda UserLog + svuotaCodaULog(); + // refresh + raiseRefresh(currDispData); + } + // se arrivo è tutto ok... + currSendErrors = 0; + } + else + { + // mostro VETO-SEND x invio... GIALLO + currDispData.semOut = Semaforo.SG; + if (periodicLog) + { + lgInfo("IOB - VETO SEND"); } } } else { - lgError("Impossibile trySendPzCountBlock: IobOnline è false"); + // mostro SERVER KO x invio... ROSSO + currDispData.semOut = Semaforo.SR; + if (periodicLog) + { + lgError("IOB - SERVER NOT READY"); + } } } - else + catch (Exception exc) { - lgError("Impossibile trySendPzCountBlock: MPOnline è false"); + lgError($"Errore in fase trySendValues | currSendErrors: {currSendErrors}{Environment.NewLine}{exc}"); + currDispData.semOut = Semaforo.SR; } + raiseRefresh(currDispData); } /// - /// Inserimento/aggiornamento chiavi/valore in currProdData + /// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce /// - /// - /// - public void upsertKey(string chiave, string valore) + /// + /// + /// + /// Nuovo valore incrementato + private double updateValDoubleByIncr(int i, double delta, string searchString) { - if (currProdData.ContainsKey(chiave)) - { - currProdData[chiave] = valore; - } - else - { - currProdData.Add(chiave, valore); - } + // 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; } /// - /// Formatta URL x invio in DataBlock Json dei dati FLog / eventi + /// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce /// - /// - /// - public string urlDataBlock(urlType tipoUrl) + /// + /// + /// + /// Nuovo valore incrementato + private long updateValLongByIncr(int i, long delta, string searchString) { - // verifico la parte di link "tipoComando" - string tipoComando = ""; - switch (tipoUrl) - { - case urlType.FLog: - tipoComando = cIobConf.serverData.CMDFLOG_JSON; - break; - - case urlType.SignIN: - tipoComando = cIobConf.serverData.CMDBASE_JSON; - break; - - case urlType.RawTransf: - tipoComando = cIobConf.serverData.CMDRAWTRANSF_JSON; - break; - - case urlType.ULog: - tipoComando = cIobConf.serverData.CMDULOG_JSON; - break; - - default: - break; - } - // URL base x input - string answ = $@"{cIobConf.serverData.TRANSP}://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{tipoComando}{cIobConf.codIOB}"; - return answ; + // 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; } /// - /// Fornisce URL di tipo FluxLog + /// Aggiorna un valore del dizionario in SOSTITUZIONE /// - /// valore salvato in coda nel formato dtEve#flux#valore#counter - /// - public string urlFLog(string queueVal) + /// + /// + /// + /// Nuovo valore incrementato + private void updateValString(int i, string newVal, string searchString) { - // URL base x input - string answ = $@"{cIobConf.serverData.TRANSP}://{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; + // stringa da cercare.. + string keyVal = string.Format(searchString, i + 1); + // salvo in ram! + persistenceLayer[keyVal] = newVal; } /// - /// Fornisce URL INPUT per i parametri richiesti + /// Aggiorna un valore del dizionario in SOSTITUZIONE e lo restituisce /// - /// valore salvato in coda formato dtEve#valore#counter - /// - public string urlInput(string queueVal) + /// + /// + /// + /// Nuovo valore incrementato + private void updateValUInt(int i, uint newVal, string searchString) { - // URL base x input - string answ = $@"{cIobConf.serverData.TRANSP}://{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; + // stringa da cercare.. + string keyVal = string.Format(searchString, i + 1); + // salvo in ram! + persistenceLayer[keyVal] = newVal.ToString(); } /// - /// Fornisce URL di tipo UserLog + /// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce /// - /// valore salvato in coda nel formato dtEve#flux#valore#counter - /// - public string urlULog(string queueVal) + /// + /// + /// + /// Nuovo valore incrementato + private uint updateValUIntByIncr(int i, uint delta, string searchString) { - // URL base x input - string answ = $@"{cIobConf.serverData.TRANSP}://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDULOG}"; - // 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; + // 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 Public Methods + #endregion Private Methods } /// @@ -5792,15 +5838,6 @@ namespace IOB_WIN_NEXT /// public class iobRefreshedEventArgs : EventArgs { - #region Private Fields - - /// - /// classe obj privata - /// - private readonly newDisplayData _newDisplayData; - - #endregion Private Fields - #region Public Constructors /// @@ -5825,5 +5862,14 @@ namespace IOB_WIN_NEXT } #endregion Public Properties + + #region Private Fields + + /// + /// classe obj privata + /// + private readonly newDisplayData _newDisplayData; + + #endregion Private Fields } } \ No newline at end of file diff --git a/IOB-WIN-NEXT/IobIcoelDb.cs b/IOB-WIN-NEXT/IobIcoelDb.cs index 1ec0d9dc..16781097 100644 --- a/IOB-WIN-NEXT/IobIcoelDb.cs +++ b/IOB-WIN-NEXT/IobIcoelDb.cs @@ -3,21 +3,22 @@ using IOB_UT_NEXT; using MapoSDK; using System; using System.Collections.Generic; -using System.Linq; using System.Net.NetworkInformation; -using System.Text; -using System.Threading.Tasks; namespace IOB_WIN_NEXT -{ /// - /// Adapter specializzato per ICOEL e le chiamate tramite DB per i dati - /// - accettazione lotti prodotto (frontiera / entrata ciliegie) - /// - export (totale per prodotti) - /// - tracciabilità (confezioni - /// +{ + /// + /// Adapter specializzato per ICOEL e le chiamate tramite DB per i dati + /// - accettazione lotti prodotto (frontiera / entrata ciliegie) + /// - export (totale per prodotti) + /// - tracciabilità (confezioni + /// public class IobIcoelDb : IobGeneric { + + #region Public Constructors + /// /// Costruttore dell'IOB Icoel DB /// @@ -32,84 +33,17 @@ namespace IOB_WIN_NEXT * - lanciare sync e verifica stato sync */ - string connEntrataFrontiera = getOptPar("EntrataFrontiera"); - string connTrackerLotti = getOptPar("TrackerLotti"); - string connExportIcoel = getOptPar("ExportIcoel"); string SyncStateDb = getOptPar("SyncStateDb"); + string SyncStateUser = getOptPar("SyncStateUser"); + string SyncStatePwd = getOptPar("SyncStatePwd"); - string connSyncState = $"data source={syncStateDb};initial catalog=MoonPro_ISF;persist security info=True;user id=egalware;password=egalware2022;MultipleActiveResultSets=True;App=IOB-WIN-NEXT" + string connSyncState = $"data source={SyncStateDb};initial catalog=MoonPro_ISF;persist security info=True;user id={SyncStateUser};password={SyncStatePwd};MultipleActiveResultSets=True;App=IOB-WIN-NEXT"; - dbProxy = new DbProxy(connEntrataFrontiera, connTrackerLotti, connExportIcoel, connSyncState); + dbProxy = new DbProxy(connSyncState); lastPING = DateTime.Now.AddHours(-1); } - #region Public Constructors - - - /// - /// Effettua lettura semafori principale - /// Parametri da aggiornare x display in form - /// - public override void readSemafori(ref newDisplayData currDispData) - { - if (connectionOk) - { - B_input = 1; - currDispData.semIn = Semaforo.SV; -#if false - if (currBatchList == null) - { - // se nullo --> provo a leggere! - - var currBatch = IcoelSizer.GetCurrentBatch(); - if (currBatch != null) - { - currBatchList = currBatch; - // accodo invio! - string rawBatch = JsonConvert.SerializeObject(currBatch); - accodaRawData(IOB_UT_NEXT.rawTransfType.IcoelBatch, currBatch); - } - } - else - { - // se ho batch NON chiusi (data = minValue) allora lavora - if (currBatchList[1].EndTime == DateTime.MinValue || currBatchList[1].EndTime == DateTime.MinValue) - { - B_input = 3; - } - } -#endif - } - else - { - B_input = 0; - currDispData.semIn = Semaforo.SR; - } - } - - /// - /// Recupero dati dinamici... - /// - public override Dictionary getDynData() - { - // valore non presente in vers default... se gestito fare override - Dictionary outVal = new Dictionary(); - - // mettere conteggio dei record trasferiti?!? -#if false - // recupero da libreria il dizionario dei performance parameters... - var perfParamDict = IcoelSizer.GetPerfMeters(); - foreach (var item in perfParamDict) - { - saveValue(ref outVal, item.Value, item.Key); - } - -#endif - lastReadPLC = DateTime.Now; - return outVal; - } - #endregion Public Constructors #region Public Methods @@ -135,6 +69,28 @@ namespace IOB_WIN_NEXT return base.executeTasks(task2exe); } + /// + /// Recupero dati dinamici... + /// + public override Dictionary getDynData() + { + // valore non presente in vers default... se gestito fare override + Dictionary outVal = new Dictionary(); + + // mettere conteggio dei record trasferiti?!? +#if false + // recupero da libreria il dizionario dei performance parameters... + var perfParamDict = IcoelSizer.GetPerfMeters(); + foreach (var item in perfParamDict) + { + saveValue(ref outVal, item.Value, item.Key); + } + +#endif + lastReadPLC = DateTime.Now; + return outVal; + } + /// /// Effettua processing CUSTOM x Icoel: /// - recupera elenco batch delle 2 linee @@ -147,7 +103,7 @@ namespace IOB_WIN_NEXT // fare processing DB secondo il seguente scehma: /* - * + * EgwProxy.Icoel.DbProxy dbProxy = new DbProxy(ReadSetting("EntrataFrontiera"), ReadSetting("TrackerLotti"), ReadSetting("ExportIcoel"), ReadSetting("SyncState")); Console.WriteLine(); Console.WriteLine("--- SyncState ---"); @@ -184,8 +140,8 @@ namespace IOB_WIN_NEXT // processo needRedo = testNeedRedo(elencoSyncState); } - * - * + * + * * */ #if false @@ -213,6 +169,47 @@ namespace IOB_WIN_NEXT lastReadPLC = DateTime.Now; } + /// + /// Effettua lettura semafori principale Parametri da + /// aggiornare x display in form + /// + public override void readSemafori(ref newDisplayData currDispData) + { + if (connectionOk) + { + B_input = 1; + currDispData.semIn = Semaforo.SV; +#if false + if (currBatchList == null) + { + // se nullo --> provo a leggere! + + var currBatch = IcoelSizer.GetCurrentBatch(); + if (currBatch != null) + { + currBatchList = currBatch; + // accodo invio! + string rawBatch = JsonConvert.SerializeObject(currBatch); + accodaRawData(IOB_UT_NEXT.rawTransfType.IcoelBatch, currBatch); + } + } + else + { + // se ho batch NON chiusi (data = minValue) allora lavora + if (currBatchList[1].EndTime == DateTime.MinValue || currBatchList[1].EndTime == DateTime.MinValue) + { + B_input = 3; + } + } +#endif + } + else + { + B_input = 0; + currDispData.semIn = Semaforo.SR; + } + } + /// /// Override connessione /// @@ -245,7 +242,7 @@ namespace IOB_WIN_NEXT lgInfo($"szStatusConnection IcoelSoap, recuperato elenco di {batchList.Count} batch"); parentForm.commPlcActive = false; connectionOk = true; - } + } #endif // refresh stato connessione!!! if (connectionOk) @@ -292,15 +289,15 @@ namespace IOB_WIN_NEXT #endregion Public Methods - #region Protected Properties - #if false /// /// elenco dei BAtch correntemente caricati x testing variazione /// - protected Dictionary currBatchList { get; set; } + protected Dictionary currBatchList { get; set; } #endif + #region Protected Properties + protected EgwProxy.Icoel.DbProxy dbProxy { get; set; } #endregion Protected Properties @@ -320,14 +317,12 @@ namespace IOB_WIN_NEXT { var varietyData = IcoelSizer.GetLayoutForVarietyList(varList); // invio dai al server IO - - } + } #endif lastReadPLC = DateTime.Now; } #endregion Protected Methods - } -} +} \ No newline at end of file diff --git a/IOB-WIN-NEXT/packages.config b/IOB-WIN-NEXT/packages.config index f9c592cd..473827f5 100644 --- a/IOB-WIN-NEXT/packages.config +++ b/IOB-WIN-NEXT/packages.config @@ -2,7 +2,7 @@ - + From d2931a363aa18abcc3f677a3498477e6ab44d526 Mon Sep 17 00:00:00 2001 From: "S.E.Locatelli" Date: Sat, 28 May 2022 14:15:50 +0200 Subject: [PATCH 03/13] Aggiunta trace soap x chiamate servizio, cambio parametri periodi --- IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_002.ini | 2 +- IOB-WIN-NEXT/IobIcoelSoap.cs | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_002.ini b/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_002.ini index ce3224ff..5e6b3216 100644 --- a/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_002.ini +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_002.ini @@ -63,7 +63,7 @@ MIN_SEND_PZC_BLOCK=0 MAX_SEND_PZC_BLOCK=100 ENABLE_DYN_DATA=TRUE FORCE_DYN_DATA=TRUE -DEM_FACT_DYN_DATA=6 +DEM_FACT_DYN_DATA=3 ENABLE_DATA_FILTER=TRUE ENABLE_CLI_RESTART=TRUE VETO_SIG_IN=TRUE diff --git a/IOB-WIN-NEXT/IobIcoelSoap.cs b/IOB-WIN-NEXT/IobIcoelSoap.cs index af042828..0918507a 100644 --- a/IOB-WIN-NEXT/IobIcoelSoap.cs +++ b/IOB-WIN-NEXT/IobIcoelSoap.cs @@ -57,8 +57,8 @@ namespace IOB_WIN_NEXT if (currBatchList == null) { // se nullo --> provo a leggere! - var currBatch = IcoelSizer.GetCurrentBatch(); + lgTrace("SOAP: effettuata chiamata IcoelSizer.GetCurrentBatch()"); if (currBatch != null) { currBatchList = currBatch; @@ -95,6 +95,7 @@ namespace IOB_WIN_NEXT Dictionary outVal = new Dictionary(); // recupero da libreria il dizionario dei performance parameters... var perfParamDict = IcoelSizer.GetPerfMeters(); + lgTrace("SOAP: effettuata chiamata IcoelSizer.GetPerfMeters()"); foreach (var item in perfParamDict) { saveValue(ref outVal, item.Value, item.Key); @@ -138,6 +139,7 @@ namespace IOB_WIN_NEXT { lgInfo($"Richiesto processCustomTaskLF"); var currBatch = IcoelSizer.GetCurrentBatch(); + lgTrace("SOAP: effettuata chiamata IcoelSizer.GetCurrentBatch()"); if (currBatch != null) { // verifico se i batch siano variati... e quindi da inviare... @@ -192,6 +194,7 @@ namespace IOB_WIN_NEXT parentForm.commPlcActive = true; // recupero elenco batch... se != vuoto -_> connesso! var batchList = IcoelSizer.GetCurrentBatch(); + lgTrace("SOAP: effettuata chiamata IcoelSizer.GetCurrentBatch()"); if (batchList != null && batchList.Count > 0) { lgInfo($"szStatusConnection IcoelSoap, recuperato elenco di {batchList.Count} batch"); @@ -264,9 +267,11 @@ namespace IOB_WIN_NEXT ///determina se recuperare SOLO varietà attive o tutte bool soloAttive = false; var varList = IcoelSizer.GetVarietyList(soloAttive); + lgTrace("SOAP: effettuata chiamata IcoelSizer.GetVarietyList()"); if (varList != null && varList.Length > 0) { var varietyData = IcoelSizer.GetLayoutForVarietyList(varList); + lgTrace("SOAP: effettuata chiamata IcoelSizer.GetLayoutForVarietyList()"); // invio dai al server IO } From 25112bddd7779332760b0714f9302065e8b19ce0 Mon Sep 17 00:00:00 2001 From: "S.E.Locatelli" Date: Sat, 28 May 2022 14:46:57 +0200 Subject: [PATCH 04/13] Modifiche IcoelDb: sembra ok (a patto di includere EntityFramework in IOB-WIN-NEXT --- IOB-WIN-NEXT/App.config | 335 +++++++++++---------- IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_003.ini | 4 +- IOB-WIN-NEXT/DATA/CONF/MAIN.ini | 3 +- IOB-WIN-NEXT/IOB-WIN-NEXT.csproj | 19 +- IOB-WIN-NEXT/IobIcoelDb.cs | 32 +- IOB-WIN-NEXT/packages.config | 1 + 6 files changed, 222 insertions(+), 172 deletions(-) diff --git a/IOB-WIN-NEXT/App.config b/IOB-WIN-NEXT/App.config index a3743cb8..3985bdbf 100644 --- a/IOB-WIN-NEXT/App.config +++ b/IOB-WIN-NEXT/App.config @@ -1,165 +1,174 @@  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_003.ini b/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_003.ini index 88a328a2..1e4925d1 100644 --- a/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_003.ini +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_003.ini @@ -10,8 +10,8 @@ VENDOR=ICOEL MODEL=Impianto Ciliegie Turi [CNC] -IP=192.168.137.50 -PORT=8001 +IP=192.168.137.11 +PORT=1443 GETPRGNAME=false [SERVER] diff --git a/IOB-WIN-NEXT/DATA/CONF/MAIN.ini b/IOB-WIN-NEXT/DATA/CONF/MAIN.ini index cb0aa7c3..9722b51a 100644 --- a/IOB-WIN-NEXT/DATA/CONF/MAIN.ini +++ b/IOB-WIN-NEXT/DATA/CONF/MAIN.ini @@ -79,6 +79,7 @@ CLI_INST=SteamWareSim ;STARTLIST=VL25 ;STARTLIST=SIMUL_03 ;STARTLIST=GIACO_CEDAX_01 -STARTLIST=GIACO_ICOEL_002 +;STARTLIST=GIACO_ICOEL_002 +STARTLIST=GIACO_ICOEL_003 MAXCNC=10 \ No newline at end of file diff --git a/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj b/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj index a229b9bf..3b78adc6 100644 --- a/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj +++ b/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj @@ -1,5 +1,6 @@  + @@ -101,6 +102,12 @@ ..\packages\EgwProxy.OsaiCncLib.3.6.2205.2015\lib\EgwProxy.OsaiCncLib.XmlSerializers.dll + + ..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.dll + + + ..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.SqlServer.dll + False ExtLib\krcc.dll @@ -147,6 +154,7 @@ ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll + @@ -316,8 +324,12 @@ PreserveNewest - - + + PreserveNewest + + + PreserveNewest + Always @@ -919,9 +931,12 @@ + + + \ No newline at end of file diff --git a/IOB-WIN-NEXT/IobIcoelDb.cs b/IOB-WIN-NEXT/IobIcoelDb.cs index 16781097..60024f53 100644 --- a/IOB-WIN-NEXT/IobIcoelDb.cs +++ b/IOB-WIN-NEXT/IobIcoelDb.cs @@ -3,6 +3,7 @@ using IOB_UT_NEXT; using MapoSDK; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Net.NetworkInformation; namespace IOB_WIN_NEXT @@ -39,6 +40,7 @@ namespace IOB_WIN_NEXT string connSyncState = $"data source={SyncStateDb};initial catalog=MoonPro_ISF;persist security info=True;user id={SyncStateUser};password={SyncStatePwd};MultipleActiveResultSets=True;App=IOB-WIN-NEXT"; + // eccezione: NON TROVA EntityFramework 6.0.0 o successivo... why?!? dbProxy = new DbProxy(connSyncState); lastPING = DateTime.Now.AddHours(-1); @@ -100,13 +102,26 @@ namespace IOB_WIN_NEXT { lgInfo($"Richiesto processCustomTaskLF"); - // fare processing DB secondo il seguente scehma: + var elencoSyncStatePre = dbProxy.DataController.SyncStateGetAll(); + Stopwatch sw = new Stopwatch(); + sw.Start(); + var elencoSyncState = dbProxy.DataController.SyncStateDoImportAll(); + sw.Stop(); + lgInfo($"DB: esecuzione task dbProxy.DataController.SyncStateGetAll() in {sw.ElapsedMilliseconds} ms"); + + if (elencoSyncState != null) + { + foreach (var item in elencoSyncState) + { + lgTrace($"TAB: {item.TableName} | IdxIN / IdxLocal {item.LastIdxIn} / {item.LastIdx} | NumIn / NumLocal {item.NumRecIn} / {item.NumRec}"); + // verifico se serva redo.. + } + } + + // fare processing DB secondo il seguente schema: /* * - EgwProxy.Icoel.DbProxy dbProxy = new DbProxy(ReadSetting("EntrataFrontiera"), ReadSetting("TrackerLotti"), ReadSetting("ExportIcoel"), ReadSetting("SyncState")); - Console.WriteLine(); - Console.WriteLine("--- SyncState ---"); bool needRedo = true; var elencoSyncState = dbProxy.DataController.SyncStateGetAll(); while (needRedo) @@ -179,6 +194,11 @@ namespace IOB_WIN_NEXT { B_input = 1; currDispData.semIn = Semaforo.SV; + + if (dbProxy != null) + { + B_input = 3; + } #if false if (currBatchList == null) { @@ -234,6 +254,10 @@ namespace IOB_WIN_NEXT { // ora provo connessione... parentForm.commPlcActive = true; + if (dbProxy != null) + { + connectionOk = true; + } #if false // recupero elenco batch... se != vuoto -_> connesso! var batchList = IcoelSizer.GetCurrentBatch(); diff --git a/IOB-WIN-NEXT/packages.config b/IOB-WIN-NEXT/packages.config index 473827f5..37aef99b 100644 --- a/IOB-WIN-NEXT/packages.config +++ b/IOB-WIN-NEXT/packages.config @@ -5,6 +5,7 @@ + From 233bfeeee7c9c99db52f56faeb63651598229b18 Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Mon, 30 May 2022 12:19:56 +0200 Subject: [PATCH 05/13] Update con inclusione nuovo tipo task syncDb --- IOB-WIN-NEXT/IOB-WIN-NEXT.csproj | 4 +-- IOB-WIN-NEXT/IobGeneric.cs | 11 ++------ IOB-WIN-NEXT/IobIcoelDb.cs | 46 +++++++++++++++++++++++--------- IOB-WIN-NEXT/packages.config | 2 +- 4 files changed, 39 insertions(+), 24 deletions(-) diff --git a/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj b/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj index a229b9bf..5772b53a 100644 --- a/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj +++ b/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj @@ -105,8 +105,8 @@ False ExtLib\krcc.dll - - ..\packages\MapoSDK.6.14.2205.2808\lib\MapoSDK.dll + + ..\packages\MapoSDK.6.14.2205.3011\lib\MapoSDK.dll ..\packages\MathNet.Numerics.4.15.0\lib\net461\MathNet.Numerics.dll diff --git a/IOB-WIN-NEXT/IobGeneric.cs b/IOB-WIN-NEXT/IobGeneric.cs index 8c0c5ddc..e613ba05 100644 --- a/IOB-WIN-NEXT/IobGeneric.cs +++ b/IOB-WIN-NEXT/IobGeneric.cs @@ -1501,13 +1501,6 @@ namespace IOB_WIN_NEXT // 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: @@ -1583,8 +1576,8 @@ namespace IOB_WIN_NEXT break; default: - taskVal = "SKIPPED | NO EXEC"; - lgInfo($"Chiamata default senza processing: taskOk: {taskOk} | taskVal: {taskVal}"); + taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC"; + lgInfo($"Chiamata senza processing: taskOk: {taskOk} | taskVal: {taskVal}"); break; } // aggiungo task! diff --git a/IOB-WIN-NEXT/IobIcoelDb.cs b/IOB-WIN-NEXT/IobIcoelDb.cs index 16781097..b30a41e8 100644 --- a/IOB-WIN-NEXT/IobIcoelDb.cs +++ b/IOB-WIN-NEXT/IobIcoelDb.cs @@ -55,18 +55,40 @@ namespace IOB_WIN_NEXT /// public override Dictionary executeTasks(Dictionary task2exe) { - /*--------------------------------------- - * fixme todo fare !!! - * gestione execute task SPECIFICI x il sizer: - * - recupero anagrafice variety/layout (attivi) - * - recupero grower - * - invio batch da accodare - * - recupero dati da sizer (OVE disponibili) - * - recupero batch corrente (modalità force/resync?) - * - *---------------------------------------*/ - return base.executeTasks(task2exe); + // unico task ammissibile: fare un SYNC forzato... + Dictionary taskDone = new Dictionary(); + if (task2exe != null) + { + // controllo se memMap != null... + if (memMap != 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.syncDbData: + break; + default: + taskVal = $"IobIcoelDb | taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC"; + lgInfo($"IobIcoelDb | chiamata senza processing: taskOk: {taskOk} | taskVal: {taskVal}"); + break; + } + + } + } + } + + return taskDone; } /// @@ -77,7 +99,7 @@ namespace IOB_WIN_NEXT // valore non presente in vers default... se gestito fare override Dictionary outVal = new Dictionary(); - // mettere conteggio dei record trasferiti?!? + // recupero da variabile appoggio dati del DB locale conteggio record trasferiti #if false // recupero da libreria il dizionario dei performance parameters... var perfParamDict = IcoelSizer.GetPerfMeters(); diff --git a/IOB-WIN-NEXT/packages.config b/IOB-WIN-NEXT/packages.config index 473827f5..697ab200 100644 --- a/IOB-WIN-NEXT/packages.config +++ b/IOB-WIN-NEXT/packages.config @@ -5,7 +5,7 @@ - + From 9b8a314a628cf8e9afabae3c2537c07dfe5395ed Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Mon, 30 May 2022 15:19:16 +0200 Subject: [PATCH 06/13] Fix gestione sync DB Icoel --- IOB-WIN-NEXT/IobGeneric.cs | 33 +++--- IOB-WIN-NEXT/IobIcoelDb.cs | 197 ++++++++--------------------------- IOB-WIN-NEXT/IobIcoelSoap.cs | 127 +++++++++++----------- 3 files changed, 122 insertions(+), 235 deletions(-) diff --git a/IOB-WIN-NEXT/IobGeneric.cs b/IOB-WIN-NEXT/IobGeneric.cs index e613ba05..66840aeb 100644 --- a/IOB-WIN-NEXT/IobGeneric.cs +++ b/IOB-WIN-NEXT/IobGeneric.cs @@ -1501,7 +1501,6 @@ namespace IOB_WIN_NEXT // controllo sulla KEY... switch (tName) { - case taskType.setArt: case taskType.setComm: case taskType.setProg: @@ -5123,6 +5122,22 @@ namespace IOB_WIN_NEXT } } + /// + /// Legge da conf il valore di demoltiplica lettura dynData (se presente) o ignora e pone a 1... + /// + private void fixDemFactDynData() + { + var rawDemFact = getOptPar("DEM_FACT_DYN_DATA"); + if (string.IsNullOrEmpty(rawDemFact)) + { + demFactDynData = 1; + } + else + { + int.TryParse(rawDemFact, out demFactDynData); + } + } + /// /// recupera valore salvato in persistence layer (se non c'è crea...) /// @@ -5395,22 +5410,6 @@ namespace IOB_WIN_NEXT enablePrgName = true; } - /// - /// Legge da conf il valore di demoltiplica lettura dynData (se presente) o ignora e pone a 1... - /// - private void fixDemFactDynData() - { - var rawDemFact = getOptPar("DEM_FACT_DYN_DATA"); - if (string.IsNullOrEmpty(rawDemFact)) - { - demFactDynData = 1; - } - else - { - int.TryParse(rawDemFact, out demFactDynData); - } - } - private void svuotaCodaContapezzi() { // permetto al max 2 tentativi infruttuosi... diff --git a/IOB-WIN-NEXT/IobIcoelDb.cs b/IOB-WIN-NEXT/IobIcoelDb.cs index 436dbb56..5532c618 100644 --- a/IOB-WIN-NEXT/IobIcoelDb.cs +++ b/IOB-WIN-NEXT/IobIcoelDb.cs @@ -17,7 +17,6 @@ namespace IOB_WIN_NEXT public class IobIcoelDb : IobGeneric { - #region Public Constructors /// @@ -57,7 +56,6 @@ namespace IOB_WIN_NEXT /// public override Dictionary executeTasks(Dictionary task2exe) { - // unico task ammissibile: fare un SYNC forzato... Dictionary taskDone = new Dictionary(); if (task2exe != null) @@ -79,17 +77,21 @@ namespace IOB_WIN_NEXT switch (tName) { case taskType.syncDbData: + lgInfo($"executeTasks --> syncDbData"); + // effettua sync + refreshElencoStati(); + break; + default: taskVal = $"IobIcoelDb | taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC"; lgInfo($"IobIcoelDb | chiamata senza processing: taskOk: {taskOk} | taskVal: {taskVal}"); break; } - } } } - + lastReadPLC = DateTime.Now; return taskDone; } @@ -100,17 +102,15 @@ namespace IOB_WIN_NEXT { // valore non presente in vers default... se gestito fare override Dictionary outVal = new Dictionary(); - - // recupero da variabile appoggio dati del DB locale conteggio record trasferiti -#if false - // recupero da libreria il dizionario dei performance parameters... - var perfParamDict = IcoelSizer.GetPerfMeters(); - foreach (var item in perfParamDict) + // recupero da DB locale stato sync attuale + var elencoSyncStateCurr = dbProxy.DataController.SyncStateGetAll(); + foreach (var item in elencoSyncStateCurr) { - saveValue(ref outVal, item.Value, item.Key); + saveValue(ref outVal, item.NumRec, $"{item.TableName}_NumRec"); + saveValue(ref outVal, item.NumRecIn, $"{item.TableName}_NumRecIn"); + saveValue(ref outVal, item.LastIdx, $"{item.TableName}_LastIdx"); + saveValue(ref outVal, item.LastIdxIn, $"{item.TableName}_LastIdxIn"); } - -#endif lastReadPLC = DateTime.Now; return outVal; } @@ -123,86 +123,8 @@ namespace IOB_WIN_NEXT public override void processCustomTaskLF() { lgInfo($"Richiesto processCustomTaskLF"); - - - var elencoSyncStatePre = dbProxy.DataController.SyncStateGetAll(); - Stopwatch sw = new Stopwatch(); - sw.Start(); - var elencoSyncState = dbProxy.DataController.SyncStateDoImportAll(); - sw.Stop(); - lgInfo($"DB: esecuzione task dbProxy.DataController.SyncStateGetAll() in {sw.ElapsedMilliseconds} ms"); - - if (elencoSyncState != null) - { - foreach (var item in elencoSyncState) - { - lgTrace($"TAB: {item.TableName} | IdxIN / IdxLocal {item.LastIdxIn} / {item.LastIdx} | NumIn / NumLocal {item.NumRecIn} / {item.NumRec}"); - // verifico se serva redo.. - } - } - - // fare processing DB secondo il seguente schema: - /* - * - bool needRedo = true; - var elencoSyncState = dbProxy.DataController.SyncStateGetAll(); - while (needRedo) - { - Console.WriteLine(" --- PRE --- "); - if (elencoSyncState != null) - { - foreach (var item in elencoSyncState) - { - Console.WriteLine($"TAB: {item.TableName} | IdxIN / IdxLocal {item.LastIdxIn} / {item.LastIdx} | NumIn / NumLocal {item.NumRecIn} / {item.NumRec}"); - // verifico se serva redo.. - } - } - Console.WriteLine(); - Console.WriteLine("Premere un tasto x continuare..."); - Console.ReadKey(); - Stopwatch sw = new Stopwatch(); - sw.Start(); - elencoSyncState = dbProxy.DataController.SyncStateDoImportAll(); - sw.Stop(); - Console.WriteLine($" process time: {sw.ElapsedMilliseconds} ms "); - Console.WriteLine(" --- POST --- "); - if (elencoSyncState != null) - { - foreach (var item in elencoSyncState) - { - Console.WriteLine($"TAB: {item.TableName} | IdxIN / IdxLocal {item.LastIdxIn} / {item.LastIdx} | NumIn / NumLocal {item.NumRecIn} / {item.NumRec}"); - // verifico se serva redo.. - } - } - // processo - needRedo = testNeedRedo(elencoSyncState); - } - * - * - * */ - -#if false - var currBatch = IcoelSizer.GetCurrentBatch(); - if (currBatch != null) - { - // verifico se i batch siano variati... e quindi da inviare... - bool doSend = (currBatchList == null || currBatchList.Count == 0); - if (currBatch.Count > 0 && !doSend) - { - foreach (var item in currBatch) - { - // se variato ID è cambiato - doSend = doSend || (currBatchList[item.Key].Id != item.Value.Id); - } - } - // se devo inviare impacchetto dati - if (doSend) - { - accodaRawData(IOB_UT_NEXT.rawTransfType.IcoelBatch, currBatch); - currBatchList = currBatch; - } - } -#endif + // effettua sync + refreshElencoStati(); lastReadPLC = DateTime.Now; } @@ -217,33 +139,10 @@ namespace IOB_WIN_NEXT B_input = 1; currDispData.semIn = Semaforo.SV; - if (dbProxy != null) + if (dbProxy != null && elencoSyncState != null && elencoSyncState.Count > 0) { B_input = 3; } -#if false - if (currBatchList == null) - { - // se nullo --> provo a leggere! - - var currBatch = IcoelSizer.GetCurrentBatch(); - if (currBatch != null) - { - currBatchList = currBatch; - // accodo invio! - string rawBatch = JsonConvert.SerializeObject(currBatch); - accodaRawData(IOB_UT_NEXT.rawTransfType.IcoelBatch, currBatch); - } - } - else - { - // se ho batch NON chiusi (data = minValue) allora lavora - if (currBatchList[1].EndTime == DateTime.MinValue || currBatchList[1].EndTime == DateTime.MinValue) - { - B_input = 3; - } - } -#endif } else { @@ -278,18 +177,14 @@ namespace IOB_WIN_NEXT parentForm.commPlcActive = true; if (dbProxy != null) { - connectionOk = true; + elencoSyncState = dbProxy.DataController.SyncStateDoImportAll(); + + if (elencoSyncState != null && elencoSyncState.Count > 0) + { + parentForm.commPlcActive = false; + connectionOk = true; + } } -#if false - // recupero elenco batch... se != vuoto -_> connesso! - var batchList = IcoelSizer.GetCurrentBatch(); - if (batchList != null && batchList.Count > 0) - { - lgInfo($"szStatusConnection IcoelSoap, recuperato elenco di {batchList.Count} batch"); - parentForm.commPlcActive = false; - connectionOk = true; - } -#endif // refresh stato connessione!!! if (connectionOk) { @@ -335,40 +230,36 @@ namespace IOB_WIN_NEXT #endregion Public Methods -#if false - /// - /// elenco dei BAtch correntemente caricati x testing variazione - /// - protected Dictionary currBatchList { get; set; } -#endif - #region Protected Properties - protected EgwProxy.Icoel.DbProxy dbProxy { get; set; } + protected EgwProxy.Icoel.DbProxy dbProxy { get; set; } = null; + + /// + /// Stato di sync delle tab gestite + /// + protected List elencoSyncState { get; set; } = new List(); #endregion Protected Properties - #region Protected Methods + #region Private Methods - /// - /// recupera le variety ed i rispettivi layout e li invia al sistema MP/IO - /// - protected void refreshVarietyData() + private void refreshElencoStati() { -#if false - ///determina se recuperare SOLO varietà attive o tutte - bool soloAttive = false; - var varList = IcoelSizer.GetVarietyList(soloAttive); - if (varList != null && varList.Length > 0) - { - var varietyData = IcoelSizer.GetLayoutForVarietyList(varList); - // invio dai al server IO - } -#endif + Stopwatch sw = new Stopwatch(); + sw.Start(); + elencoSyncState = dbProxy.DataController.SyncStateDoImportAll(); + sw.Stop(); + lgInfo($"DB: esecuzione task dbProxy.DataController.SyncStateGetAll() in {sw.ElapsedMilliseconds} ms"); - lastReadPLC = DateTime.Now; + if (elencoSyncState != null) + { + foreach (var item in elencoSyncState) + { + lgTrace($"TAB: {item.TableName} | IdxIN / IdxLocal {item.LastIdxIn} / {item.LastIdx} | NumIn / NumLocal {item.NumRecIn} / {item.NumRec}"); + } + } } - #endregion Protected Methods + #endregion Private Methods } } \ No newline at end of file diff --git a/IOB-WIN-NEXT/IobIcoelSoap.cs b/IOB-WIN-NEXT/IobIcoelSoap.cs index 0918507a..399c294c 100644 --- a/IOB-WIN-NEXT/IobIcoelSoap.cs +++ b/IOB-WIN-NEXT/IobIcoelSoap.cs @@ -2,10 +2,8 @@ using EgwProxy.Icoel.SizerService; using IOB_UT_NEXT; using MapoSDK; -using Newtonsoft.Json; using System; using System.Collections.Generic; -using System.Linq; using System.Net.NetworkInformation; namespace IOB_WIN_NEXT @@ -44,67 +42,6 @@ namespace IOB_WIN_NEXT lastPING = DateTime.Now.AddHours(-1); } - /// - /// Effettua lettura semafori principale - /// Parametri da aggiornare x display in form - /// - public override void readSemafori(ref newDisplayData currDispData) - { - if (connectionOk) - { - B_input = 1; - currDispData.semIn = Semaforo.SV; - if (currBatchList == null) - { - // se nullo --> provo a leggere! - var currBatch = IcoelSizer.GetCurrentBatch(); - lgTrace("SOAP: effettuata chiamata IcoelSizer.GetCurrentBatch()"); - if (currBatch != null) - { - currBatchList = currBatch; -#if false - // accodo invio! - string rawBatch = JsonConvert.SerializeObject(currBatch); - accodaRawData(IOB_UT_NEXT.rawTransfType.IcoelBatch, currBatch); -#endif - accodaRawData(rawTransfType.IcoelBatch, currBatch); - } - } - else - { - // se ho batch NON chiusi (data = minValue) allora lavora - if (currBatchList[1].EndTime == DateTime.MinValue || currBatchList[1].EndTime == DateTime.MinValue) - { - B_input = 3; - } - } - } - else - { - B_input = 0; - currDispData.semIn = Semaforo.SR; - } - } - - /// - /// Recupero dati dinamici... - /// - public override Dictionary getDynData() - { - // valore non presente in vers default... se gestito fare override - Dictionary outVal = new Dictionary(); - // recupero da libreria il dizionario dei performance parameters... - var perfParamDict = IcoelSizer.GetPerfMeters(); - lgTrace("SOAP: effettuata chiamata IcoelSizer.GetPerfMeters()"); - foreach (var item in perfParamDict) - { - saveValue(ref outVal, item.Value, item.Key); - } - - lastReadPLC = DateTime.Now; - return outVal; - } - #endregion Public Constructors #region Public Methods @@ -130,6 +67,25 @@ namespace IOB_WIN_NEXT return base.executeTasks(task2exe); } + /// + /// Recupero dati dinamici... + /// + public override Dictionary getDynData() + { + // valore non presente in vers default... se gestito fare override + Dictionary outVal = new Dictionary(); + // recupero da libreria il dizionario dei performance parameters... + var perfParamDict = IcoelSizer.GetPerfMeters(); + lgTrace("SOAP: effettuata chiamata IcoelSizer.GetPerfMeters()"); + foreach (var item in perfParamDict) + { + saveValue(ref outVal, item.Value, item.Key); + } + + lastReadPLC = DateTime.Now; + return outVal; + } + /// /// Effettua processing CUSTOM x Icoel: /// - recupera elenco batch delle 2 linee @@ -158,7 +114,7 @@ namespace IOB_WIN_NEXT #if false // accodo per invio... string rawBatch = JsonConvert.SerializeObject(currBatch); - accodaRawData(IOB_UT_NEXT.rawTransfType.IcoelBatch, rawBatch); + accodaRawData(IOB_UT_NEXT.rawTransfType.IcoelBatch, rawBatch); #endif accodaRawData(rawTransfType.IcoelBatch, currBatch); currBatchList = currBatch; @@ -168,6 +124,48 @@ namespace IOB_WIN_NEXT lastReadPLC = DateTime.Now; } + /// + /// Effettua lettura semafori principale Parametri da + /// aggiornare x display in form + /// + public override void readSemafori(ref newDisplayData currDispData) + { + if (connectionOk) + { + B_input = 1; + currDispData.semIn = Semaforo.SV; + if (currBatchList == null) + { + // se nullo --> provo a leggere! + var currBatch = IcoelSizer.GetCurrentBatch(); + lgTrace("SOAP: effettuata chiamata IcoelSizer.GetCurrentBatch()"); + if (currBatch != null) + { + currBatchList = currBatch; +#if false + // accodo invio! + string rawBatch = JsonConvert.SerializeObject(currBatch); + accodaRawData(IOB_UT_NEXT.rawTransfType.IcoelBatch, currBatch); +#endif + accodaRawData(rawTransfType.IcoelBatch, currBatch); + } + } + else + { + // se ho batch NON chiusi (data = minValue) allora lavora + if (currBatchList[1].EndTime == DateTime.MinValue || currBatchList[1].EndTime == DateTime.MinValue) + { + B_input = 3; + } + } + } + else + { + B_input = 0; + currDispData.semIn = Semaforo.SR; + } + } + /// /// Override connessione /// @@ -273,7 +271,6 @@ namespace IOB_WIN_NEXT var varietyData = IcoelSizer.GetLayoutForVarietyList(varList); lgTrace("SOAP: effettuata chiamata IcoelSizer.GetLayoutForVarietyList()"); // invio dai al server IO - } lastReadPLC = DateTime.Now; From 4f58ea28462b8b00494afb73313b87d0c9d27407 Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Mon, 30 May 2022 15:25:20 +0200 Subject: [PATCH 07/13] fix doppio package --- IOB-WIN-NEXT/packages.config | 1 - 1 file changed, 1 deletion(-) diff --git a/IOB-WIN-NEXT/packages.config b/IOB-WIN-NEXT/packages.config index f2672e05..43bf02c1 100644 --- a/IOB-WIN-NEXT/packages.config +++ b/IOB-WIN-NEXT/packages.config @@ -6,7 +6,6 @@ - From aae3504a5bf68290d258ff7bbfc6598c644ad655 Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Mon, 30 May 2022 15:25:56 +0200 Subject: [PATCH 08/13] Fix pack duplicati --- IOB-UT-NEXT/BinaryFormatter.cs | 31 ++++++++------- IOB-UT-NEXT/Enums.cs | 56 +-------------------------- IOB-UT-NEXT/Objects.cs | 70 +++------------------------------- IOB-UT-NEXT/baseUtils.cs | 63 ++++++++++++++---------------- 4 files changed, 49 insertions(+), 171 deletions(-) diff --git a/IOB-UT-NEXT/BinaryFormatter.cs b/IOB-UT-NEXT/BinaryFormatter.cs index a91b074e..0619bf95 100644 --- a/IOB-UT-NEXT/BinaryFormatter.cs +++ b/IOB-UT-NEXT/BinaryFormatter.cs @@ -6,20 +6,6 @@ namespace IOB_UT_NEXT { public class BinaryUtils : IFormatProvider, ICustomFormatter { - #region Private Methods - - private string HandleOtherFormats(string format, object arg) - { - if (arg is IFormattable) - return ((IFormattable)arg).ToString(format, CultureInfo.CurrentCulture); - else if (arg != null) - return arg.ToString(); - else - return String.Empty; - } - - #endregion Private Methods - #region Public Methods // Format number in binary (B), octal (O), or hexadecimal (H). @@ -29,8 +15,7 @@ namespace IOB_UT_NEXT int baseNumber; // Handle null or empty format string, string with precision specifier. string thisFmt = String.Empty; - // Extract first character of format string (precision specifiers - // are not supported). + // Extract first character of format string (precision specifiers are not supported). if (!String.IsNullOrEmpty(format)) thisFmt = format.Length > 1 ? format.Substring(0, 1) : format; @@ -140,5 +125,19 @@ namespace IOB_UT_NEXT } #endregion Public Methods + + #region Private Methods + + private string HandleOtherFormats(string format, object arg) + { + if (arg is IFormattable) + return ((IFormattable)arg).ToString(format, CultureInfo.CurrentCulture); + else if (arg != null) + return arg.ToString(); + else + return String.Empty; + } + + #endregion Private Methods } } \ No newline at end of file diff --git a/IOB-UT-NEXT/Enums.cs b/IOB-UT-NEXT/Enums.cs index 8a07e576..63f0993c 100644 --- a/IOB-UT-NEXT/Enums.cs +++ b/IOB-UT-NEXT/Enums.cs @@ -1,6 +1,4 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; -using System; +using System; namespace IOB_UT_NEXT { @@ -470,35 +468,6 @@ namespace IOB_UT_NEXT WPS } -#if false - /// - /// Enumerazione tipi di semaforo - /// - public enum Semaforo - { - /// - /// Stato non definito - /// - ND, - /// - /// Verde - /// - SV, - /// - /// Giallo - /// - SG, - /// - /// Rosso - /// - SR, - /// - /// Grigio/Spento - /// - SS - } -#endif - /// /// Enumerazione tipi di tipi di URL x invio /// @@ -524,27 +493,4 @@ namespace IOB_UT_NEXT /// ULog } - -#if false - /// - /// Tipologia dato Raw Transfer (derivare da MapoSdk e togliere qui) - /// - /// serializzazione Native - /// [JsonConverter(typeof(JsonStringEnumConverter))] - /// serializzazione Newtonsoft json - /// [JsonConverter(typeof(StringEnumConverter))] - [JsonConverter(typeof(StringEnumConverter))] - public enum rawTransfType - { - ND = 0, - /// - /// Icoel: Batch info - /// - IcoelBatch, - /// - /// Icoel: Variety + layout info relative - /// - IcoelVarInfo - } -#endif } \ No newline at end of file diff --git a/IOB-UT-NEXT/Objects.cs b/IOB-UT-NEXT/Objects.cs index 7ee9ae69..5b893604 100644 --- a/IOB-UT-NEXT/Objects.cs +++ b/IOB-UT-NEXT/Objects.cs @@ -117,70 +117,6 @@ namespace IOB_UT_NEXT #endregion Public Methods } -#if false - /// - /// Classe di base per trasferimento informazioni di tipo RawTransfer - /// FixMe Todo Fare !!!: elimnare usando SDK MAPO - /// - public class BaseRawTransf - { - #region Public Properties - - /// - /// Data-Ora riferimento (x ordinamento fifo) - /// - public DateTime dataRif { get; set; } = DateTime.Now; - - /// - /// Messaggio in modalità raw/stringa - /// - public object mesContent { get; set; } = ""; - - /// - /// Tipo di messaggio trasmesso - /// - public rawTransfType mesType { get; set; } = rawTransfType.ND; - - /// - /// Costruttore senza parametri - /// - public BaseRawTransf() - { - this.dataRif = DateTime.Now; - this.mesContent = ""; - this.mesType = rawTransfType.ND; - } - - /// - /// Costruttore oggetto - /// - /// - /// - /// - public BaseRawTransf(DateTime dataRif, object mesContent, rawTransfType mesType) - { - this.dataRif = dataRif; - this.mesContent = mesContent; - this.mesType = mesType; - } - - #endregion Public Properties - } - - /// - /// Array valori tipo BaseRawTransf inviati come JSon - /// FixMe Todo Fare !!!: elimnare usando SDK MAPO - /// - public class rawTransfJsonPayload - { - #region Public Properties - - public List rawTransfData { get; set; } - - #endregion Public Properties - } -#endif - /// /// Cache a tempo valori INT /// @@ -343,6 +279,8 @@ namespace IOB_UT_NEXT #endregion Public Properties + #region Public Methods + /// /// Override metodo di equality /// @@ -371,7 +309,7 @@ namespace IOB_UT_NEXT return false; if (queueRawTransfLen != item.queueRawTransfLen) return false; - if (queueUlLen!= item.queueUlLen) + if (queueUlLen != item.queueUlLen) return false; return true; @@ -381,6 +319,8 @@ namespace IOB_UT_NEXT { return base.GetHashCode(); } + + #endregion Public Methods } /// diff --git a/IOB-UT-NEXT/baseUtils.cs b/IOB-UT-NEXT/baseUtils.cs index 7f074349..1dc6a419 100644 --- a/IOB-UT-NEXT/baseUtils.cs +++ b/IOB-UT-NEXT/baseUtils.cs @@ -1,4 +1,3 @@ -using MapoSDK; using NLog; using System; using System.Collections; @@ -49,35 +48,6 @@ namespace IOB_UT_NEXT #endregion Public Fields -#if false - { - get - { - return redisMan.servStatus.dtVetoPing; - } - set - { - var currData = redisMan.servStatus; - currData.dtVetoPing = value; - redisMan.servStatus = currData; - } - } -#endif - - #region Protected Properties - - /// - /// Oggetto WebClient BASE da riutilizzare - /// - protected static WebClientWT client { get; set; } - - /// - /// Oggetto WebClient con PAYLOAD da riutilizzare - /// - protected static WebClientWT clientPayload { get; set; } - - #endregion Protected Properties - #region Public Properties /// @@ -117,6 +87,7 @@ namespace IOB_UT_NEXT { } return answ; } + /// /// formatta un numero in forma binaria 0/1 /// @@ -409,7 +380,9 @@ namespace IOB_UT_NEXT /// number will be formatted as a 32-character binary number in two's compliment. /// /// self-explanatory - /// if binary number contains fewer characters leading zeros are added + /// + /// if binary number contains fewer characters leading zeros are added + /// /// string as described above public static string IntToBinStr(int theNumber, int minimumDigits) { @@ -420,7 +393,9 @@ namespace IOB_UT_NEXT /// verifica se un dato bit sia alzato (come flag di strobe) /// /// valore da testare - /// valore cercato, può essere un singolo valore o un insieme in modalità AND + /// + /// valore cercato, può essere un singolo valore o un insieme in modalità AND + /// /// public static bool IsSetAll(StFlag32 value, StFlag32 flag) { @@ -431,7 +406,9 @@ namespace IOB_UT_NEXT /// verifica se un dato bit sia alzato (come flag di strobe) /// /// valore da testare - /// valore cercato, può essere un singolo valore o un insieme in modalità OR + /// + /// valore cercato, può essere un singolo valore o un insieme in modalità OR + /// /// public static bool IsSetAny(StFlag32 value, StFlag32 flag) { @@ -586,7 +563,8 @@ namespace IOB_UT_NEXT } /// - /// provvede a verificare la dim della cartella dei log e cancella i + vecchi fino a restare a dim inferiori a _logMaxMb + /// provvede a verificare la dim della cartella dei log e cancella i + vecchi fino a restare + /// a dim inferiori a _logMaxMb /// public static void shrinkDir(string dirPath) { @@ -616,7 +594,8 @@ namespace IOB_UT_NEXT // inizio con eliminare file + vecchi della data indicata... int maxLogDays = CRI("maxLogDays"); fileMover.obj.deleteOlderThan(maxLogDays); - // ora controllo SE sia superata la dim max della directory --> in tal caso cancello dal + vecchio... + // ora controllo SE sia superata la dim max della directory --> in tal caso cancello dal + // + vecchio... dirSizeMb = fileMover.obj.totalMb(); int maxLogDirSize = CRI("maxLogDirSize"); int maxTry = 100; @@ -723,6 +702,20 @@ namespace IOB_UT_NEXT } #endregion Public Methods + + #region Protected Properties + + /// + /// Oggetto WebClient BASE da riutilizzare + /// + protected static WebClientWT client { get; set; } + + /// + /// Oggetto WebClient con PAYLOAD da riutilizzare + /// + protected static WebClientWT clientPayload { get; set; } + + #endregion Protected Properties } /// From c6ea2fc22d798822d79c13e2d171eea3feedf173 Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Mon, 30 May 2022 15:32:09 +0200 Subject: [PATCH 09/13] Refresh e refactor vario codice --- IOB-UT-NEXT/Eurom63.cs | 14 +- IOB-UT-NEXT/IOB-UT-NEXT.csproj | 1 - IOB-UT-NEXT/IniFile.cs | 91 ++++++++--- IOB-UT-NEXT/Logging.cs | 7 +- IOB-UT-NEXT/RedisMan.cs | 219 +++++++++++++------------- IOB-UT-NEXT/TCMan.cs | 91 ++++++----- IOB-UT-NEXT/ToMapo.cs | 273 +++++++++++++++++---------------- IOB-UT-NEXT/val.cs | 6 - 8 files changed, 373 insertions(+), 329 deletions(-) delete mode 100644 IOB-UT-NEXT/val.cs diff --git a/IOB-UT-NEXT/Eurom63.cs b/IOB-UT-NEXT/Eurom63.cs index d601eabe..0ffba8c9 100644 --- a/IOB-UT-NEXT/Eurom63.cs +++ b/IOB-UT-NEXT/Eurom63.cs @@ -1,8 +1,5 @@ using System; using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; namespace IOB_UT_NEXT { @@ -39,7 +36,8 @@ namespace IOB_UT_NEXT TimeSet, /// - /// Verificato il canale di comunicazione è OK, fatta pulizia con AbortAll, NON ci sono report attivi + /// Verificato il canale di comunicazione è OK, fatta pulizia con AbortAll, NON ci sono + /// report attivi /// ChannelOk, @@ -135,7 +133,8 @@ namespace IOB_UT_NEXT public int PzPallet { get; set; } = 1; /// - /// Indica se sia possibile impostare i pezzi pallet dal server, ed in tal caso moltiplica i pezzi letti dalla macchina per il valore pzPallet (vedi sopra) + /// Indica se sia possibile impostare i pezzi pallet dal server, ed in tal caso + /// moltiplica i pezzi letti dalla macchina per il valore pzPallet (vedi sopra) /// public bool SetPzPalletFromSrv { get; set; } = false; @@ -170,7 +169,8 @@ namespace IOB_UT_NEXT public List FileList { get; set; } = new List(); /// - /// Numero MAX di esecuzioni da mantenere in HIST prima di eliminare i + vecchi (fare folder HIST\SESSnnnn) + /// Numero MAX di esecuzioni da mantenere in HIST prima di eliminare i + vecchi (fare + /// folder HIST\SESSnnnn) /// public int Max2Keep { get; set; } = 50; @@ -190,7 +190,7 @@ namespace IOB_UT_NEXT public string RespOk { get; set; } = "PROCESSED"; /// - /// Seconds before do a new retry (default = 0 --> no veto) + /// Seconds before do a new retry (default = 0 --> no veto) /// public double RetrySec { get; set; } = 0; diff --git a/IOB-UT-NEXT/IOB-UT-NEXT.csproj b/IOB-UT-NEXT/IOB-UT-NEXT.csproj index f9425e43..14903e11 100644 --- a/IOB-UT-NEXT/IOB-UT-NEXT.csproj +++ b/IOB-UT-NEXT/IOB-UT-NEXT.csproj @@ -134,7 +134,6 @@ - diff --git a/IOB-UT-NEXT/IniFile.cs b/IOB-UT-NEXT/IniFile.cs index 1ea22447..a23f2453 100644 --- a/IOB-UT-NEXT/IniFile.cs +++ b/IOB-UT-NEXT/IniFile.cs @@ -1,7 +1,7 @@ using System; +using System.Globalization; using System.Runtime.InteropServices; using System.Text; -using System.Globalization; namespace IOB_UT_NEXT { @@ -16,9 +16,6 @@ namespace IOB_UT_NEXT #endregion Public Fields - // INI filename - - // import windows dll functions #region Public Constructors @@ -33,25 +30,6 @@ namespace IOB_UT_NEXT #endregion Public Constructors - #region Private Methods - - [DllImport("kernel32")] - private static extern int GetPrivateProfileInt(string section, string key, int def, string filePath); - - [DllImport("kernel32")] - private static extern int GetPrivateProfileSection(string section, IntPtr retVal, uint size, string filePath); - - [DllImport("kernel32")] - private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath); - - [DllImport("kernel32")] - private static extern bool WritePrivateProfileSection(string section, string value, string filePath); - - [DllImport("kernel32", CharSet = CharSet.Auto, BestFitMapping = false)] - private static extern long WritePrivateProfileString(string section, string key, string val, string filePath); - - #endregion Private Methods - #region Public Methods /// @@ -149,7 +127,9 @@ namespace IOB_UT_NEXT /// /// /// Section name - /// restituisce delle stringhe keys=values da suddividere appunto come key/val successivamente + /// + /// restituisce delle stringhe keys=values da suddividere appunto come key/val successivamente + /// public string[] ReadSection(string Section) { const int bufferSize = 2048; // max is 32767 @@ -270,5 +250,68 @@ namespace IOB_UT_NEXT } #endregion Public Methods + + #region Private Methods + + + // INI filename + + /// + /// GetPrivateProfileInt: import windows dll functions + /// + /// + /// + /// + /// + /// + [DllImport("kernel32")] + private static extern int GetPrivateProfileInt(string section, string key, int def, string filePath); + + /// + /// GetPrivateProfileSection: import windows dll functions + /// + /// + /// + /// + /// + /// + [DllImport("kernel32")] + private static extern int GetPrivateProfileSection(string section, IntPtr retVal, uint size, string filePath); + + /// + /// GetPrivateProfileString: import windows dll functions + /// + /// + /// + /// + /// + /// + /// + /// + [DllImport("kernel32")] + private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath); + + /// + /// WritePrivateProfileSection: import windows dll functions + /// + /// + /// + /// + /// + [DllImport("kernel32")] + private static extern bool WritePrivateProfileSection(string section, string value, string filePath); + + /// + /// WritePrivateProfileString: import windows dll functions + /// + /// + /// + /// + /// + /// + [DllImport("kernel32", CharSet = CharSet.Auto, BestFitMapping = false)] + private static extern long WritePrivateProfileString(string section, string key, string val, string filePath); + + #endregion Private Methods } } \ No newline at end of file diff --git a/IOB-UT-NEXT/Logging.cs b/IOB-UT-NEXT/Logging.cs index ab425119..795dfd44 100644 --- a/IOB-UT-NEXT/Logging.cs +++ b/IOB-UT-NEXT/Logging.cs @@ -1,15 +1,10 @@ using NLog; using NLog.Config; using NLog.Targets; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace IOB_UT_NEXT {/// - /// Classe helper x LOG basata su NLog - /// + /// Classe helper x LOG basata su NLog public static class Logging { #region Public Constructors diff --git a/IOB-UT-NEXT/RedisMan.cs b/IOB-UT-NEXT/RedisMan.cs index 5bda2a2e..73f0cb7a 100644 --- a/IOB-UT-NEXT/RedisMan.cs +++ b/IOB-UT-NEXT/RedisMan.cs @@ -2,68 +2,12 @@ using StackExchange.Redis; using System; using System.Collections.Generic; -using System.Linq; using System.Text; namespace IOB_UT_NEXT { public class RedisIobCache { - #region Private Fields - - /// - /// Connessione lazy a redis... - /// - private Lazy lazyConnection = new Lazy(() => - { - string RedisConn = baseUtils.CRS("RedisConn"); - if (string.IsNullOrEmpty(RedisConn)) - { - RedisConn = "localhost,abortConnect=false,ssl=false"; - } - - return ConnectionMultiplexer.Connect(RedisConn); - }); - - /// - /// Connessione lazy a redis... - /// - private Lazy lazyConnectionAdmin = new Lazy(() => - { - string RedisConnAdmin = baseUtils.CRS("RedisConnAdmin"); - if (string.IsNullOrEmpty(RedisConnAdmin)) - { - RedisConnAdmin = "localhost,abortConnect=false,ssl=false,allowAdmin=true"; - } - - return ConnectionMultiplexer.Connect(RedisConnAdmin); - }); - - #endregion Private Fields - - #region Protected Fields - - /// - /// Cod IOB - /// - protected string currCodIob = "000"; - /// - /// Tipo IOB - /// - protected string currIobType = "ND"; - - /// - /// Hash redis x dati IOB - /// - protected string redIobKey = ""; - - /// - /// Hash redis x dati server - /// - protected string redServKey = ""; - - #endregion Protected Fields - #region Public Constructors /// @@ -97,7 +41,7 @@ namespace IOB_UT_NEXT IobWinStatus newIobStatus = new IobWinStatus() { CodIob = currCodIob, - IobType= currIobType, + IobType = currIobType, online = false }; // salvo in area REDIS @@ -137,15 +81,6 @@ namespace IOB_UT_NEXT #endregion Public Enums - #region Private Properties - - /// - /// Oggetto currentDb locale - /// - private IDatabase _currDB { get; set; } - - #endregion Private Properties - #region Public Properties /// @@ -216,7 +151,7 @@ namespace IOB_UT_NEXT answ = new IobWinStatus() { CodIob = currCodIob, - IobType=currIobType, + IobType = currIobType, online = false }; // salvo serializzando... @@ -298,39 +233,6 @@ namespace IOB_UT_NEXT #endregion Public Properties - #region Private Methods - - /// - /// Effettua comaprazione x CHIAVE in KVP ASC - /// - /// - /// - /// - private int CompareKey(KeyValuePair x, KeyValuePair y) - { - return x.Key.CompareTo(y.Key); - } - - /// - /// Effettua comaprazione x CHIAVE in KVP DESC - /// - /// - /// - /// - private int CompareKeyDesc(KeyValuePair x, KeyValuePair y) - { - return y.Key.CompareTo(x.Key); - } - - private void initHashKeys() - { - // init dati di base... - redServKey = redHash($"MP"); - redIobKey = redHash($"IOB:{currCodIob}"); - } - - #endregion Private Methods - #region Public Methods /// @@ -477,8 +379,7 @@ namespace IOB_UT_NEXT public int redCountKey(string keyPattern) { int answ = 0; - // cerco se ci sia valore in redis... - // se vuoto = ALL... + // cerco se ci sia valore in redis... se vuoto = ALL... keyPattern = string.IsNullOrEmpty(keyPattern) ? "**" : keyPattern; try { @@ -528,8 +429,7 @@ namespace IOB_UT_NEXT public bool redFlushKey(string keyPattern) { bool answ = false; - // cerco se ci sia valore in redis... - // se vuoto = ALL... + // cerco se ci sia valore in redis... se vuoto = ALL... keyPattern = string.IsNullOrEmpty(keyPattern) ? "**" : keyPattern; try { @@ -702,7 +602,8 @@ namespace IOB_UT_NEXT } /// - /// Nome della variabile HASH da utilizzare (dato CodModulo / Server / DB impiegato da funzionalita' DbConfig) + keyName richiesto... + /// Nome della variabile HASH da utilizzare (dato CodModulo / Server / DB impiegato da + /// funzionalita' DbConfig) + keyName richiesto... /// public string redHash(string keyName) { @@ -834,7 +735,9 @@ namespace IOB_UT_NEXT /// /// chiave /// valori - /// scadenza preimpostata hash (secondi) | defaoult = -1 (non scade) + /// + /// scadenza preimpostata hash (secondi) | defaoult = -1 (non scade) + /// /// public bool redSaveHash(string hashKey, KeyValuePair[] hashFields, double expireSeconds = -1) { @@ -891,7 +794,9 @@ namespace IOB_UT_NEXT /// /// chiave /// valori - /// scadenza preimpostata hash (secondi) | defaoult = -1 (non scade) + /// + /// scadenza preimpostata hash (secondi) | defaoult = -1 (non scade) + /// /// public bool redSaveHashDict(string hashKey, Dictionary hashFields, double expireSeconds = -1) { @@ -1058,7 +963,7 @@ namespace IOB_UT_NEXT } /// - /// Salva un set KVP (Key Value Pair) in RedisCache + /// Salva un set KVP (Key Value Pair) in RedisCache /// /// Set KVP chiave-valore da salvare /// @@ -1123,5 +1028,103 @@ namespace IOB_UT_NEXT } #endregion Public Methods + + #region Protected Fields + + /// + /// Cod IOB + /// + protected string currCodIob = "000"; + + /// + /// Tipo IOB + /// + protected string currIobType = "ND"; + + /// + /// Hash redis x dati IOB + /// + protected string redIobKey = ""; + + /// + /// Hash redis x dati server + /// + protected string redServKey = ""; + + #endregion Protected Fields + + #region Private Fields + + /// + /// Connessione lazy a redis... + /// + private Lazy lazyConnection = new Lazy(() => + { + string RedisConn = baseUtils.CRS("RedisConn"); + if (string.IsNullOrEmpty(RedisConn)) + { + RedisConn = "localhost,abortConnect=false,ssl=false"; + } + + return ConnectionMultiplexer.Connect(RedisConn); + }); + + /// + /// Connessione lazy a redis... + /// + private Lazy lazyConnectionAdmin = new Lazy(() => + { + string RedisConnAdmin = baseUtils.CRS("RedisConnAdmin"); + if (string.IsNullOrEmpty(RedisConnAdmin)) + { + RedisConnAdmin = "localhost,abortConnect=false,ssl=false,allowAdmin=true"; + } + + return ConnectionMultiplexer.Connect(RedisConnAdmin); + }); + + #endregion Private Fields + + #region Private Properties + + /// + /// Oggetto currentDb locale + /// + private IDatabase _currDB { get; set; } + + #endregion Private Properties + + #region Private Methods + + /// + /// Effettua comaprazione x CHIAVE in KVP ASC + /// + /// + /// + /// + private int CompareKey(KeyValuePair x, KeyValuePair y) + { + return x.Key.CompareTo(y.Key); + } + + /// + /// Effettua comaprazione x CHIAVE in KVP DESC + /// + /// + /// + /// + private int CompareKeyDesc(KeyValuePair x, KeyValuePair y) + { + return y.Key.CompareTo(x.Key); + } + + private void initHashKeys() + { + // init dati di base... + redServKey = redHash($"MP"); + redIobKey = redHash($"IOB:{currCodIob}"); + } + + #endregion Private Methods } } \ No newline at end of file diff --git a/IOB-UT-NEXT/TCMan.cs b/IOB-UT-NEXT/TCMan.cs index 0a8c1937..c513a8c0 100644 --- a/IOB-UT-NEXT/TCMan.cs +++ b/IOB-UT-NEXT/TCMan.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace IOB_UT_NEXT { @@ -27,50 +24,6 @@ namespace IOB_UT_NEXT #endregion Public Constructors - #region Protected Properties - - /// - /// Fattore lambda (innovazione) per calcolo EWMA valore TCiclo corrente - /// - protected double _lambda { get; set; } = 0.4; - - /// - /// Ultimo TCiclo osservato in SECONDI - /// - protected double _lastTC { get; set; } = 0; - - /// - /// ULTIMO Contapezzi IOB VALIDO - /// - protected int _lastValidPzCountIOB { get; set; } = 0; - - /// - /// ULTIMO Contapezzi PLC VALIDO - /// - protected int _lastValidPzCountPLC { get; set; } = 0; - - /// - /// Fattore massimo ammesso di delay x il TCiclo - /// - protected double _maxDelayFactor { get; set; } = 1.2; - - /// - /// Incremento amssimo pezzi per cui fare calcolo del tempociclo attuale - /// - protected double _maxIncrPz { get; set; } = 2; - - /// - /// Contapezzi IOB - /// - protected int _pzCountIOB { get; set; } = 0; - - /// - /// Contapezzi PLC - /// - protected int _pzCountPLC { get; set; } = 0; - - #endregion Protected Properties - #region Public Properties /// @@ -171,5 +124,49 @@ namespace IOB_UT_NEXT } #endregion Public Properties + + #region Protected Properties + + /// + /// Fattore lambda (innovazione) per calcolo EWMA valore TCiclo corrente + /// + protected double _lambda { get; set; } = 0.4; + + /// + /// Ultimo TCiclo osservato in SECONDI + /// + protected double _lastTC { get; set; } = 0; + + /// + /// ULTIMO Contapezzi IOB VALIDO + /// + protected int _lastValidPzCountIOB { get; set; } = 0; + + /// + /// ULTIMO Contapezzi PLC VALIDO + /// + protected int _lastValidPzCountPLC { get; set; } = 0; + + /// + /// Fattore massimo ammesso di delay x il TCiclo + /// + protected double _maxDelayFactor { get; set; } = 1.2; + + /// + /// Incremento amssimo pezzi per cui fare calcolo del tempociclo attuale + /// + protected double _maxIncrPz { get; set; } = 2; + + /// + /// Contapezzi IOB + /// + protected int _pzCountIOB { get; set; } = 0; + + /// + /// Contapezzi PLC + /// + protected int _pzCountPLC { get; set; } = 0; + + #endregion Protected Properties } } \ No newline at end of file diff --git a/IOB-UT-NEXT/ToMapo.cs b/IOB-UT-NEXT/ToMapo.cs index f91154da..56a1011b 100644 --- a/IOB-UT-NEXT/ToMapo.cs +++ b/IOB-UT-NEXT/ToMapo.cs @@ -1,11 +1,7 @@ using MapoSDK; using Newtonsoft.Json; using Newtonsoft.Json.Converters; -using System; -using System.Collections; using System.Collections.Generic; -using System.Linq; -using System.Text; namespace IOB_UT_NEXT { @@ -14,7 +10,23 @@ namespace IOB_UT_NEXT /// public class BaseAlarmConf { - #region Public Fields + #region Public Properties + + /// + /// Elenco dei contatori blink x gestione caso fronte salita/discesa segnale che blinka + /// + public int[] alarmsBlinkCounter { get; set; } + + /// + /// BitMask 16bit (1 = valido, 0 = filtro) degli allarmi silenziati/disabilitati (se + /// iniziano per ##) come valore da sottrarre x check + /// + public uint[] alarmsMask { get; set; } + + /// + /// Array dei valori allarme correnti + /// + public uint[] alarmsState { get; set; } /// /// valore di partenza x un segnale di blink in caso di fine variazione (fronte discesa) @@ -26,25 +38,6 @@ namespace IOB_UT_NEXT /// public int blinkUpVal { get; set; } = 3; - #endregion Public Fields - - #region Public Properties - - /// - /// Elenco dei contatori blink x gestione caso fronte salita/discesa segnale che blinka - /// - public int[] alarmsBlinkCounter { get; set; } - - /// - /// BitMask 16bit (1 = valido, 0 = filtro) degli allarmi silenziati/disabilitati (se iniziano per ##) come valore da sottrarre x check - /// - public uint[] alarmsMask { get; set; } - - /// - /// Array dei valori allarme correnti - /// - public uint[] alarmsState { get; set; } - /// /// Descrizione area allarmi /// @@ -177,7 +170,8 @@ namespace IOB_UT_NEXT alarmsState = new uint[size / 2]; alarmsMask = new uint[size / 2]; - // una volta inizializzata la classe di base sistemo vettori allarmi disabilitati ed il contatore blink dei fronti di discesa + // una volta inizializzata la classe di base sistemo vettori allarmi disabilitati ed il + // contatore blink dei fronti di discesa alarmsBlinkCounter = new int[messages.Count]; int idx = 0; int bank = 0; @@ -217,7 +211,8 @@ namespace IOB_UT_NEXT } /// - /// Classe gestione configurazione parametri di base x configuraizone estesa (es MTConnect, OPC-UA, ...) + /// Classe gestione configurazione parametri di base x configuraizone estesa (es MTConnect, + /// OPC-UA, ...) /// public class BaseParamConf { @@ -229,14 +224,13 @@ namespace IOB_UT_NEXT public List condWork { get; set; } = new List(); /// - /// Indica se l'emergenza armata va riportata verso Mapo come bit a TRUE - /// True --> armata = 1 / triggered = 0 - /// False --> triggered = 1 / armata = 0 + /// Indica se l'emergenza armata va riportata verso Mapo come bit a TRUE True --> armata + /// = 1 / triggered = 0 False --> triggered = 1 / armata = 0 /// public bool emergencyArmedTrue { get; set; } = true; /// - /// Elenco items FILTRATI da invio come dynData --> FluxLog (events o samples) + /// Elenco items FILTRATI da invio come dynData --> FluxLog (events o samples) /// public List fluxLogVeto { get; set; } = new List(); @@ -309,7 +303,8 @@ namespace IOB_UT_NEXT } /// - /// Classe per rappresentare una lista di oggetti chiave/valore target x controlo condizioni multiple + indicazione modalità di controllo (AND/OR/...) + /// Classe per rappresentare una lista di oggetti chiave/valore target x controlo condizioni + /// multiple + indicazione modalità di controllo (AND/OR/...) /// public class diCheckCondSetup { @@ -326,13 +321,75 @@ namespace IOB_UT_NEXT public boolCheckMode checkMode { get; set; } = boolCheckMode.AND; /// - /// indica se il check vada NEGATO (esempio se cerco la condizione opposta, esempio num allarmi 0 --> se true NEGO la condizione HO ALLARMI) + /// indica se il check vada NEGATO (esempio se cerco la condizione opposta, esempio num + /// allarmi 0 --> se true NEGO la condizione HO ALLARMI) /// public bool negateValue { get; set; } = false; #endregion Public Properties } + /// + /// Classe x definizione delle azioni in fase di setup macchina + /// + public class MachineSetupAction + { + #region Public Properties + + /// + /// Indica se vada disabilitato il contapezzi quando la condizione NotEqual sia soddisfatta + /// + public bool DisablePzCountNotEqual { get; set; } = false; + + /// + /// Parametro target dell'azione + /// + public string TargetParam { get; set; } = ""; + + /// + /// parametro da impostare SE il check da esito EQUAL + /// + public int TargetValEqual { get; set; } = 0; + + /// + /// parametro da impostare SE il check da esito NOT EQUAL + /// + public int TargetValNotEqual { get; set; } = 1; + + #endregion Public Properties + } + + /// + /// Definizione parametri di setup incrociato... + /// + public class MachineSetupConf + { + #region Public Properties + + /// + /// Dizionario dei parametri di corrispondenza tra variabili MES e variabili Macchina MES = + /// scritte dal MES Macchina = scritte da macchina + /// + public Dictionary checkParList { get; set; } = new Dictionary(); + + /// + /// Abilitazione gestione Setup Avanzato (= scrittura) + /// + public bool EnableAdvSetup { get; set; } = false; + + /// + /// Modalità gestione setup + /// + public MachineSetupMode SetupMode { get; set; } = MachineSetupMode.ND; + + /// Dizionario dei parametri da scrivere quando si rilevano differenze tra i + /// parametri MES/Macchina string (key) --> memoria da scrivere tuple --> valori da scrivere quando uguali o diversi + public List writeParAction { get; set; } = new List(); + + #endregion Public Properties + } + /// /// COnfigurazione blocchi x accesso memoria ottimizzato /// @@ -360,84 +417,6 @@ namespace IOB_UT_NEXT #endregion Public Properties } - /// - /// Definizione parametri watchdog - /// - public class WatchDogConf - { - /// - /// Abilitazione WatchDog - /// - public bool IsEnabled { get; set; } = false; - /// - /// Conf memoria x lettura WatchDog (ToMes), se !="" è gestito - /// - public string MemConfRead { get; set; } = ""; - /// - /// Conf memoria x scrittura WatchDog (FromMes), se !="" è gestito - /// - public string MemConfWrite { get; set; } = ""; - /// - /// Valore max contatore prima di resettare - /// - public int MaxVal { get; set; } = 9999; - } - - /// - /// Definizione parametri di setup incrociato... - /// - public class MachineSetupConf - { - /// - /// Modalità gestione setup - /// - public MachineSetupMode SetupMode { get; set; } = MachineSetupMode.ND; - - /// - /// Abilitazione gestione Setup Avanzato (= scrittura) - /// - public bool EnableAdvSetup { get; set; } = false; - - /// - /// Dizionario dei parametri di corrispondenza tra variabili MES e variabili Macchina - /// MES = scritte dal MES - /// Macchina = scritte da macchina - /// - public Dictionary checkParList { get; set; } = new Dictionary(); - - /// - /// Dizionario dei parametri da scrivere quando si rilevano differenze tra i parametri MES/Macchina - /// string (key) --> memoria da scrivere - /// tuple --> valori da scrivere quando uguali o diversi - /// - public List writeParAction { get; set; } = new List(); - } - - /// - /// Classe x definizione delle azioni in fase di setup macchina - /// - public class MachineSetupAction - { - /// - /// Parametro target dell'azione - /// - public string TargetParam { get; set; } = ""; - - /// - /// parametro da impostare SE il check da esito EQUAL - /// - public int TargetValEqual { get; set; } = 0; - /// - /// parametro da impostare SE il check da esito NOT EQUAL - /// - public int TargetValNotEqual { get; set; } = 1; - - /// - /// Indica se vada disabilitato il contapezzi quando la condizione NotEqual sia soddisfatta - /// - public bool DisablePzCountNotEqual { get; set; } = false; - } - /// /// Classe gestione configurazione parametri specifici OPC-UA da BaseParamConf /// @@ -470,12 +449,6 @@ namespace IOB_UT_NEXT /// public diCheckCondSetup condError { get; set; } = new diCheckCondSetup(); - - /// - /// Struttura dati x check condizione Errore - /// - public diCheckCondSetup condWorkOpc { get; set; } = new diCheckCondSetup(); - /// /// Struttura dati x check condizione Emergenza /// @@ -496,6 +469,11 @@ namespace IOB_UT_NEXT /// public diCheckCondSetup condReady { get; set; } = new diCheckCondSetup(); + /// + /// Struttura dati x check condizione Setup + /// + public diCheckCondSetup condSetup { get; set; } = new diCheckCondSetup(); + /// /// Struttura dati x check condizione WarmUp - CoolDown /// @@ -505,16 +483,19 @@ namespace IOB_UT_NEXT /// Struttura dati x check condizione Warning ///
public diCheckCondSetup condWarning { get; set; } = new diCheckCondSetup(); + /// - /// Struttura dati x check condizione Setup + /// Struttura dati x check condizione Errore /// - public diCheckCondSetup condSetup { get; set; } = new diCheckCondSetup(); + public diCheckCondSetup condWorkOpc { get; set; } = new diCheckCondSetup(); /// /// Elenco dei NodeId da ignorare intesi come interi rami (se vuoto NON filtro) /// public List filterItemsNodeId { get; set; } = new List(); + public UserIdent Identity { get; set; } = new UserIdent(); + /// /// Aree di memoria lettura /// @@ -525,34 +506,66 @@ namespace IOB_UT_NEXT ///
public Dictionary mMapWrite { get; set; } = new Dictionary(); - /// - /// Elenco dei SOLI item sottoscritti (se vuoto TUTTI) - /// - public List subscribedItems { get; set; } = new List(); - /// /// Elenco item RAW sottoscritti e relative configurazioni di decodifica da byte[] /// public Dictionary rawSubscribedItemsConf { get; set; } = new Dictionary(); - /// - /// Conf Gestione WatchDog - /// - public WatchDogConf WatchDog { get; set; } = new WatchDogConf(); - /// /// Conf gestione setup macchina /// public MachineSetupConf SetupConf { get; set; } = new MachineSetupConf(); - public UserIdent Identity { get; set; } = new UserIdent(); + /// + /// Elenco dei SOLI item sottoscritti (se vuoto TUTTI) + /// + public List subscribedItems { get; set; } = new List(); + + /// + /// Conf Gestione WatchDog + /// + public WatchDogConf WatchDog { get; set; } = new WatchDogConf(); #endregion Public Properties } public class UserIdent { - public string UserName { get; set; } = ""; + #region Public Properties + public string Passwd { get; set; } = ""; + public string UserName { get; set; } = ""; + + #endregion Public Properties + } + + /// + /// Definizione parametri watchdog + /// + public class WatchDogConf + { + #region Public Properties + + /// + /// Abilitazione WatchDog + /// + public bool IsEnabled { get; set; } = false; + + /// + /// Valore max contatore prima di resettare + /// + public int MaxVal { get; set; } = 9999; + + /// + /// Conf memoria x lettura WatchDog (ToMes), se !="" è gestito + /// + public string MemConfRead { get; set; } = ""; + + /// + /// Conf memoria x scrittura WatchDog (FromMes), se !="" è gestito + /// + public string MemConfWrite { get; set; } = ""; + + #endregion Public Properties } } \ No newline at end of file diff --git a/IOB-UT-NEXT/val.cs b/IOB-UT-NEXT/val.cs deleted file mode 100644 index 94029a5c..00000000 --- a/IOB-UT-NEXT/val.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace IOB_UT_NEXT -{ - internal class val - { - } -} \ No newline at end of file From d0190024549ae22d869c892c9cf047fe3387915f Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Tue, 31 May 2022 18:00:12 +0200 Subject: [PATCH 10/13] Update Adapters ICOEL --- IOB-WIN-NEXT/IobIcoelDb.cs | 5 +++- IOB-WIN-NEXT/IobIcoelSoap.cs | 42 +++++++++++++++++++++--------- IOB-WIN-NEXT/IobOpcUaOmronIcoel.cs | 3 ++- 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/IOB-WIN-NEXT/IobIcoelDb.cs b/IOB-WIN-NEXT/IobIcoelDb.cs index 5532c618..3bb11b86 100644 --- a/IOB-WIN-NEXT/IobIcoelDb.cs +++ b/IOB-WIN-NEXT/IobIcoelDb.cs @@ -141,8 +141,11 @@ namespace IOB_WIN_NEXT if (dbProxy != null && elencoSyncState != null && elencoSyncState.Count > 0) { - B_input = 3; + B_input += (1 << 1); } + + // accodo NON emergenza + B_input += (1 << 7); } else { diff --git a/IOB-WIN-NEXT/IobIcoelSoap.cs b/IOB-WIN-NEXT/IobIcoelSoap.cs index 399c294c..19e35d1b 100644 --- a/IOB-WIN-NEXT/IobIcoelSoap.cs +++ b/IOB-WIN-NEXT/IobIcoelSoap.cs @@ -67,6 +67,11 @@ namespace IOB_WIN_NEXT return base.executeTasks(task2exe); } + /// + /// Dizionario parametri correnti + /// + protected Dictionary perfParamDict { get; set; } = new Dictionary(); + /// /// Recupero dati dinamici... /// @@ -75,7 +80,7 @@ namespace IOB_WIN_NEXT // valore non presente in vers default... se gestito fare override Dictionary outVal = new Dictionary(); // recupero da libreria il dizionario dei performance parameters... - var perfParamDict = IcoelSizer.GetPerfMeters(); + perfParamDict = IcoelSizer.GetPerfMeters(); lgTrace("SOAP: effettuata chiamata IcoelSizer.GetPerfMeters()"); foreach (var item in perfParamDict) { @@ -111,11 +116,6 @@ namespace IOB_WIN_NEXT // se devo inviare impacchetto dati if (doSend) { -#if false - // accodo per invio... - string rawBatch = JsonConvert.SerializeObject(currBatch); - accodaRawData(IOB_UT_NEXT.rawTransfType.IcoelBatch, rawBatch); -#endif accodaRawData(rawTransfType.IcoelBatch, currBatch); currBatchList = currBatch; } @@ -142,22 +142,39 @@ namespace IOB_WIN_NEXT if (currBatch != null) { currBatchList = currBatch; -#if false - // accodo invio! - string rawBatch = JsonConvert.SerializeObject(currBatch); - accodaRawData(IOB_UT_NEXT.rawTransfType.IcoelBatch, currBatch); -#endif accodaRawData(rawTransfType.IcoelBatch, currBatch); } } else { + //se i perf parameters mi danno valire > 0 x quantità frutta... + if (perfParamDict != null && perfParamDict.Count > 0) + { + if (perfParamDict.ContainsKey("VelFruttiMinuto")) + { + if (perfParamDict["VelFruttiMinuto"] > 0) + { + B_input += (1 << 1); + } + // metto manuale + else + { + B_input += (1 << 4); + } + } + } + + //usato altro criterio x stato verde da vel frutti minuto +#if false // se ho batch NON chiusi (data = minValue) allora lavora if (currBatchList[1].EndTime == DateTime.MinValue || currBatchList[1].EndTime == DateTime.MinValue) { B_input = 3; - } + } +#endif } + // accodo NON emergenza + B_input += (1 << 7); } else { @@ -270,7 +287,6 @@ namespace IOB_WIN_NEXT { var varietyData = IcoelSizer.GetLayoutForVarietyList(varList); lgTrace("SOAP: effettuata chiamata IcoelSizer.GetLayoutForVarietyList()"); - // invio dai al server IO } lastReadPLC = DateTime.Now; diff --git a/IOB-WIN-NEXT/IobOpcUaOmronIcoel.cs b/IOB-WIN-NEXT/IobOpcUaOmronIcoel.cs index 91803e95..bc31f488 100644 --- a/IOB-WIN-NEXT/IobOpcUaOmronIcoel.cs +++ b/IOB-WIN-NEXT/IobOpcUaOmronIcoel.cs @@ -415,7 +415,7 @@ namespace IOB_WIN_NEXT B_input = powerOnOk ? 1 : 0; // decodifico da currData - if (currData.Varie.InEmergenza) + if (!currData.Varie.InEmergenza) { B_input += (1 << 7); } @@ -427,6 +427,7 @@ namespace IOB_WIN_NEXT { B_input += (1 << 3); } + } // controllo se sono poweroff e se non ho dati buoni da > 2 minuti --> disconnetto From 435b13d58cd8fc83f4d9d9a6b350a3bd5d7fcb02 Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Wed, 1 Jun 2022 16:51:45 +0200 Subject: [PATCH 11/13] Aggiunta un altra metrica da SOAP client --- EgwProxy.Icoel/Compac/ComClient.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/EgwProxy.Icoel/Compac/ComClient.cs b/EgwProxy.Icoel/Compac/ComClient.cs index 587f5dd6..3f5ee6e6 100644 --- a/EgwProxy.Icoel/Compac/ComClient.cs +++ b/EgwProxy.Icoel/Compac/ComClient.cs @@ -182,18 +182,20 @@ namespace EgwProxy.Icoel.Compac internal Dictionary GetPerfMeters() { Dictionary answ = new Dictionary(); - // indicata in tonnOra + // velocità processo indicata in tonnellate /oOra double velTonnOra = SSClient.GetMachineTonnesPH(); // velocità espressa in frutti/minuto double velFruttiMinuto = SSClient.GetMachineTotalFPM(); // percentuale riempimento carrellini double percRiemp = SSClient.GetMachineCupfill(); - //// indicata in carrelli/minuto - //int[] velCarrMinuto = SSClient.GetMachineRodsPM(); + // Numero confezioni/ora + double numPackOra = SSClient.GetMachinePacksPH(); + // accodo i valori ricavati - answ.Add("VelTonnOra", velTonnOra); - answ.Add("VelFruttiMinuto", velFruttiMinuto); + answ.Add("NumPacksOra", numPackOra); answ.Add("PercRiemp", percRiemp); + answ.Add("VelFruttiMinuto", velFruttiMinuto); + answ.Add("VelTonnOra", velTonnOra); return answ; } From 5adee48d512aa5a3a73a60dd69138f3dd4b36690 Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Wed, 1 Jun 2022 16:52:10 +0200 Subject: [PATCH 12/13] Aggiunto recupero CurrData da DB + update SyncStateModel --- .../Controllers/DbController.cs | 208 ++++-------------- .../DatabaseModels/CurrDataModel.cs | 19 ++ .../DatabaseModels/SyncStateModel.cs | 2 + .../EgwProxy.Icoel.DataLayer.csproj | 1 + .../SyncStateDbContext.cs | 7 +- 5 files changed, 72 insertions(+), 165 deletions(-) create mode 100644 EgwProxy.Icoel.DataLayer/DatabaseModels/CurrDataModel.cs diff --git a/EgwProxy.Icoel.DataLayer/Controllers/DbController.cs b/EgwProxy.Icoel.DataLayer/Controllers/DbController.cs index 0727fdb5..98ab5ffd 100644 --- a/EgwProxy.Icoel.DataLayer/Controllers/DbController.cs +++ b/EgwProxy.Icoel.DataLayer/Controllers/DbController.cs @@ -2,8 +2,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; /*------------------------------------------------ * Aggiunto fix come da link seguente: @@ -14,6 +12,7 @@ using System.Threading.Tasks; * using SqlProviderServices= System.Data.Entity.SqlServer.SqlProviderServices; * */ + namespace EgwProxy.Icoel.DataLayer.Controllers { /// @@ -26,29 +25,9 @@ namespace EgwProxy.Icoel.DataLayer.Controllers private static ExportDbContext dbExportCtx; private static TrackerDbContext dbTrackerCtx; #endif - private static SyncStateDbContext dbSyncStateCtx; - private static NLog.Logger Log = LogManager.GetCurrentClassLogger(); -#if false - /// - /// Avvio dell'oggetto gestione DB con le 3 stringhe di connessione specifiche - /// - /// Connesisone Db frontiera Entrata Merce - /// Connessione DB Tracker - /// Connessione DB IcoelExport - /// Connessione DB locale di SYNC - public DbController(string connEntrata, string connTracker, string connExport, string connSyncState) - { - dbEntrataCtx = new EntrataDbContext(connEntrata); - Log.Info("Avviata classe EntrataDbContext"); - dbExportCtx = new ExportDbContext(connExport); - Log.Info("Avviata classe ExportDbContext"); - dbTrackerCtx = new TrackerDbContext(connTracker); - Log.Info("Avviata classe dbTrackerCtx"); - dbSyncStateCtx = new SyncStateDbContext(connSyncState); - Log.Info("Avviata classe dbSyncStateCtx"); - } -#endif + #region Public Constructors + /// /// Avvio dell'oggetto gestione DB con stringa di connessione specifica /// @@ -59,6 +38,25 @@ namespace EgwProxy.Icoel.DataLayer.Controllers Log.Info("Avviata classe dbSyncStateCtx"); } + #endregion Public Constructors + + #region Public Methods + + /// + /// Recupera la tab di CurrData corrente + /// + /// + public List CurrDataGetAll() + { + List dbResult = new List(); + + dbResult = dbSyncStateCtx + .DbSetCurrData + .ToList(); + + return dbResult; + } + /// /// Dispose classe /// @@ -73,94 +71,6 @@ namespace EgwProxy.Icoel.DataLayer.Controllers dbSyncStateCtx.Dispose(); } -#if false - /// - /// Elenco record Entrata Merce (Frontiera) - /// - /// idx da cui partire a recuperare - /// - public List EntrateGetFromIdx(int minIdx = 0) - { - List dbResult = new List(); - dbResult = dbEntrataCtx - .DbSetEntrataMerce - .Where(x => (x.ID_CHIAVE >= minIdx)) - .OrderBy(x => x.ID_CHIAVE) - .ToList(); - - return dbResult; - } - - /// - /// Elenco ultimi record Entrata Merce (Frontiera) - /// - /// numero records da recuperare - /// - public List EntrateGetLast(int numRec = 100) - { - List dbResult = new List(); - dbResult = dbEntrataCtx - .DbSetEntrataMerce - .OrderByDescending(x => x.ID_CHIAVE) - .Take(numRec) - .ToList(); - - return dbResult; - } - - /// - /// Elenco record ProductsTotal (da Icoel Export Products) - /// - /// idx da cui partire a recuperare - /// - public List ExportProductsGetFromIdx(int minIdx = 0) - { - List dbResult = new List(); - dbResult = dbExportCtx - .DbSetProductsTotals - .Where(x => (x.SizerBatchId >= minIdx)) - .OrderBy(x => x.SizerBatchId) - .ToList(); - - return dbResult; - } - - /// - /// Elenco ultimi record ProductsTotal (da Icoel Export Products) - /// - /// numero records da recuperare - /// - public List ExportProductsGetLast(int numRec = 0) - { - List dbResult = new List(); - dbResult = dbExportCtx - .DbSetProductsTotals - .OrderByDescending(x => x.SizerBatchId) - .ThenByDescending(x => x.Index) - .Take(numRec) - .ToList(); - - return dbResult; - } -#endif - - /// - /// Esegue una volta la stored di ImportAll (x recupero dati da DB esterni) e poi - /// restitusice in output la tab di SyncState x verificare lo stato - /// - /// - public List SyncStateDoImportAll() - { - List dbResult = new List(); - - dbResult = dbSyncStateCtx - .Database - .SqlQuery("EXEC stp_ImportAll") - .ToList(); - - return dbResult; - } - /// /// Esegue una volta la stored di ImportAll (x recupero dati da DB esterni) e poi /// restitusice in output la tab di SyncState x verificare lo stato @@ -178,6 +88,23 @@ namespace EgwProxy.Icoel.DataLayer.Controllers return dbResult; } + /// + /// Esegue una volta la stored di ImportAll (x recupero dati da DB esterni) e poi + /// restitusice in output la tab di SyncState x verificare lo stato + /// + /// + public List SyncStateDoImportAll() + { + List dbResult = new List(); + + dbResult = dbSyncStateCtx + .Database + .SqlQuery("EXEC stp_ImportAll") + .ToList(); + + return dbResult; + } + /// /// recupera la tab di SyncState corrente /// @@ -193,60 +120,13 @@ namespace EgwProxy.Icoel.DataLayer.Controllers return dbResult; } -#if false - /// - /// Elenco record DettConfezioni (da Icoel TrackerLotti) - /// - /// idx da cui partire a recuperare - /// - public List TrackConfezioniGetFromIdx(int minIdx = 0) - { - List dbResult = new List(); - dbResult = dbTrackerCtx - .DbSetConfezioni - .Where(x => (x.Pack_Id >= minIdx)) - .OrderBy(x => x.Pack_Id) - .ToList(); + #endregion Public Methods - return dbResult; - } + #region Private Fields - /// - /// Elenco ultimi record DettaglioConfezioni (da Icoel TrackerLotti) - /// - /// numero records da recuperare - /// - public List TrackConfezioniGetLast(int numRec = 0) - { - List dbResult = new List(); - dbResult = dbTrackerCtx - .DbSetConfezioni - .OrderByDescending(x => x.Pack_Id) - .Take(numRec) - .ToList(); + private static SyncStateDbContext dbSyncStateCtx; + private static NLog.Logger Log = LogManager.GetCurrentClassLogger(); - return dbResult; - } - - /// - /// Elenco dettaglio conferimento x PackId (da Icoel TrackerLotti) - /// ATTENZIONE: in caso di mancata associazione lotto ingresso con lavorazione corrente la - /// vista restituisce nuovo (possibile lavorare senza lotto ingresso e senza tracking) - /// - /// idx da cui partire a recuperare - /// - public List TrackPackConfDetailByIdx(long packId = 0) - { - List dbResult = new List(); - dbResult = dbTrackerCtx - .DbSetConferimento - .Where(x => (x.PackId == packId)) - .OrderBy(x => x.NUMERO_LOTTO) - .ThenByDescending(x => x.QUANTITA_ENTRATA) - .ToList(); - - return dbResult; - } -#endif + #endregion Private Fields } } \ No newline at end of file diff --git a/EgwProxy.Icoel.DataLayer/DatabaseModels/CurrDataModel.cs b/EgwProxy.Icoel.DataLayer/DatabaseModels/CurrDataModel.cs new file mode 100644 index 00000000..f6fb6573 --- /dev/null +++ b/EgwProxy.Icoel.DataLayer/DatabaseModels/CurrDataModel.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Data.Entity.Spatial; + +namespace EgwProxy.Icoel.DataLayer.DatabaseModels +{ + + [Table("CurrData")] + public partial class CurrDataModel + { + [Key] + [StringLength(50)] + public string Topic { get; set; } + + public decimal CurrVal { get; set; } = 0; + } +} diff --git a/EgwProxy.Icoel.DataLayer/DatabaseModels/SyncStateModel.cs b/EgwProxy.Icoel.DataLayer/DatabaseModels/SyncStateModel.cs index 477c3fc5..b37fa326 100644 --- a/EgwProxy.Icoel.DataLayer/DatabaseModels/SyncStateModel.cs +++ b/EgwProxy.Icoel.DataLayer/DatabaseModels/SyncStateModel.cs @@ -25,5 +25,7 @@ namespace EgwProxy.Icoel.DataLayer.DatabaseModels public long NumRecIn { get; set; } public long NumRecOut { get; set; } + + public DateTime LastUpdate { get; set; } = DateTime.Today; } } diff --git a/EgwProxy.Icoel.DataLayer/EgwProxy.Icoel.DataLayer.csproj b/EgwProxy.Icoel.DataLayer/EgwProxy.Icoel.DataLayer.csproj index c1aaa5c3..ffb54d76 100644 --- a/EgwProxy.Icoel.DataLayer/EgwProxy.Icoel.DataLayer.csproj +++ b/EgwProxy.Icoel.DataLayer/EgwProxy.Icoel.DataLayer.csproj @@ -65,6 +65,7 @@ + diff --git a/EgwProxy.Icoel.DataLayer/SyncStateDbContext.cs b/EgwProxy.Icoel.DataLayer/SyncStateDbContext.cs index 1e811380..fd401841 100644 --- a/EgwProxy.Icoel.DataLayer/SyncStateDbContext.cs +++ b/EgwProxy.Icoel.DataLayer/SyncStateDbContext.cs @@ -32,10 +32,15 @@ namespace EgwProxy.Icoel.DataLayer } /// - /// DbSet dai dati stato sync DB esterni <--> locale + /// DbSet dei dati stato sync DB esterni <--> locale /// public virtual DbSet DbSetSyncState { get; set; } + /// + /// DbSet CurrData + /// + public virtual DbSet DbSetCurrData { get; set; } + protected override void OnModelCreating(DbModelBuilder modelBuilder) { } From f2559b759e704df9014fa8ed6968c3af6e3bb4c4 Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Wed, 1 Jun 2022 16:52:23 +0200 Subject: [PATCH 13/13] refresh ini conf ICOEL --- IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_002.ini | 1 - IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_003.ini | 1 - 2 files changed, 2 deletions(-) diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_002.ini b/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_002.ini index 5e6b3216..5f2471f1 100644 --- a/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_002.ini +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_002.ini @@ -66,7 +66,6 @@ FORCE_DYN_DATA=TRUE DEM_FACT_DYN_DATA=3 ENABLE_DATA_FILTER=TRUE ENABLE_CLI_RESTART=TRUE -VETO_SIG_IN=TRUE ; clock base (da 10ms) timerIntMs=50 diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_003.ini b/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_003.ini index 1e4925d1..470b6385 100644 --- a/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_003.ini +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_003.ini @@ -66,7 +66,6 @@ FORCE_DYN_DATA=TRUE DEM_FACT_DYN_DATA=5 ENABLE_DATA_FILTER=TRUE ENABLE_CLI_RESTART=TRUE -VETO_SIG_IN=TRUE SyncStateDb=localhost\sqlexpress SyncStateUser=egalware SyncStatePwd=egalware2022