From 62847732dda0dc0229236bda1a2cf9601b8eae73 Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Sat, 23 May 2026 09:59:43 +0200 Subject: [PATCH] continuo fix --- IOB-UT-NEXT/Iob/BaseObj.cs | 507 ++++++++++++++++-- .../Machine/MachineCommunicationService.cs | 8 + IOB-WIN-FORM/Iob/Generic.cs | 489 +---------------- IOB-WIN-FORM/Iob/Simula.cs | 50 +- 4 files changed, 523 insertions(+), 531 deletions(-) diff --git a/IOB-UT-NEXT/Iob/BaseObj.cs b/IOB-UT-NEXT/Iob/BaseObj.cs index 131bde02..38bfb956 100644 --- a/IOB-UT-NEXT/Iob/BaseObj.cs +++ b/IOB-UT-NEXT/Iob/BaseObj.cs @@ -1,16 +1,22 @@ using IOB_UT_NEXT.Config; using IOB_UT_NEXT.Config.Mem; +using IOB_UT_NEXT.Objects; using IOB_UT_NEXT.Services.Cache; using IOB_UT_NEXT.Services.Core; using IOB_UT_NEXT.Services.Data; using IOB_UT_NEXT.Services.Files; +using MapoSDK; using Newtonsoft.Json; using NLog; using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Linq; using System.Net.NetworkInformation; +using System.Runtime.Serialization.Formatters.Binary; +using System.Text.Json; +using System.Text.Json.Serialization; using static IOB_UT_NEXT.Config.BaseAlarmConf; namespace IOB_UT_NEXT.Iob @@ -238,13 +244,14 @@ namespace IOB_UT_NEXT.Iob /// Oggetto della coda degli elementi di tipo RawTransf (e non ancora trasmessi) /// NB: sono salvati serializzati come stringhe /// - public DataQueue QueueRawTransf;// = new DataQueue("000", "QueueRawTransf", false); + public DataQueue QueueRawTransf; /// /// Coda delle richieste dal server (Task2Exe) /// public DataQueue QueueSrvReq; + // = new DataQueue("000", "QueueRawTransf", false); /// /// Coda delle risposte al server (Task2Exe) /// @@ -253,13 +260,14 @@ namespace IOB_UT_NEXT.Iob /// /// Coda valori LOG UTENTE (da non sottocampionare come samples)... /// - public DataQueue QueueULog;// = new DataQueue("000", "QueueULog", false); + public DataQueue QueueULog; /// /// alias booleano false = R /// public bool R = false; + // = new DataQueue("000", "QueueULog", false); /// /// 32 byte input base (es strobe, 8 word da 32 bit di flags...) /// @@ -280,11 +288,6 @@ namespace IOB_UT_NEXT.Iob /// public Stopwatch sw = new Stopwatch(); - /// - /// Oggetto gestione TempiCiclo e contapezzi - /// - public TCMan tcMan = new TCMan(0.5, 1.3, 5); - /// /// Imposta veto lettura dati (es per DB a 2 sec) /// @@ -402,49 +405,407 @@ namespace IOB_UT_NEXT.Iob #region Protected Fields - + /// + /// Variabile numero errori vari (in lettura) --> se supera soglia maxErroriCheck --> disconnette + /// + protected static int numErroriCheck = 0; /// /// Valore di attesa (random) dopo ogni invio x evitare congestione send... /// protected static int urlRandWait = 0; + /// + /// Stato connessione con macchina gestita + /// + 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 = -1; + + /// + /// Cod grupo IOB x creazione PODL al volo + /// + protected string CodGruppoIob = "ND-00"; + + /// + /// 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; + + /// + /// Tempo di attesa in minuti x lettura contapezzi standard (da .ini / OptPar) + /// + protected double delayMinReadPzCount = 0; + + /// + /// Fattore di demoltiplicazione dei DynData x ridurre campionamento + /// + protected int demFactDynData = 1; + /// /// Disabilitazione gestione ODL (lettura e gestione) /// protected bool disableOdl = false; + /// + /// Boolean x indicare contapezzi disabilitato forzatamente da IOB + /// + protected bool disablePzCountByIob = false; + + /// + /// Veto x esecuzione task AutoDossier + /// + protected DateTime dtVetoAutoDossier = DateTime.Now; + + /// + /// Veto x lettura contapezzi (in caso di autoODL con attesa reset ad esempio...) + /// + protected DateTime dtVetoReadPzCount = DateTime.Now; + + /// + /// DataOra x veto all'invio dataItem + /// + protected DateTime dtVetoSenDataItem = DateTime.Now; + + /// + /// Veto x esecuzione Task2Exe troppo frequenti + /// + protected DateTime dtVetoTask2Exe = DateTime.Now; + + /// + /// Determina se sia prevista gestione PODL (creazione/avvio/chiusura) come Soitaab + /// + protected bool EnabelPodlManFull = false; + + /// + /// Abilita riscrittura memoria se trova differenze lettura/richiesti + /// + protected bool ENABLE_MEM_REWRITE = true; + + /// + /// Abilitazione restart (da opt par...) + /// + protected bool enableCliRestart = false; + + /// + /// Boolean x indicare contapezzi abilitato a livello di conf applicazione + /// + protected bool enablePzCountByApp = true; + + /// + /// Abilitazione invio dataitem + /// + protected bool enableSendDataItem = true; + + /// + /// Abilitazione gestione slow data + /// + protected bool enableSlowData = false; + //protected static Logger lg = LogManager.GetCurrentClassLogger(); /// /// Abilitazione invio conf macchine /// protected bool enabSendMachineConf = true; + /// + /// dizionario (opzionale) xz decodifica file da importare + /// + protected Dictionary FileDecod = new Dictionary(); + + /// + /// DeadBand x riduzione dati FluxLog (se 0 non gestita) + /// + protected double fluxLogRedDeadBand = 0; + + /// + /// Determina se sia gestita riduzione dati FluxLog + /// + protected bool fluxLogReduce = false; + + /// + /// Dizionario dei valori FluxLog ultimi verificati x veto + /// + protected Dictionary fluxLogReduceLast = new Dictionary(); + + /// + /// Dizionario dei valori FluxLog ultimi tipo STRING verificati x veto + /// + protected Dictionary fluxLogReduceLastString = new Dictionary(); + + /// + /// Dizionario dei veto send x ogni variabile quando non variata + /// + protected Dictionary fluxLogReduceVeto = new Dictionary(); + + /// + /// Finestra in minuti x invio dati FluxLog quando invariati + /// + protected int fluxLogResendPeriod = 60; + + /// + /// indica che è richiesto forzatamente reset contapezzi + /// + protected bool forcePzReset = false; + + /// + /// indica che è richiesto forzatamente reset contapezzi + /// + protected DateTime forcePzResetUntil = DateTime.Now.AddMinutes(-1); + + /// + /// DEADBAND globale se impostata (es x gestire variazioni minime valori FluxLog da inviare...) + /// + protected float GLOBAL_DBAND = 0; + + /// + /// Determina se siano gestite le ricette + /// + protected bool hasRecipe = false; + + /// + /// 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 (string) delle TSS + /// + protected Dictionary LastTSS = new Dictionary(); + + /// + /// Dizionario ultimi valori (string) delle TSS + /// + protected Dictionary LastTSSSend = new Dictionary(); + + /// + /// 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; + + /// + /// ultima data-ora invio parametri write x ribadire status + /// + protected DateTime lastWriteParamsUpsert = DateTime.Now; + + /// + /// Separatore linea (tipicamente x commenti) + /// + protected string lineSep = "--------------------------"; + + /// + /// Elenco parametri calcolati da inviare alla macchina (es ricetta con traduzione, RAMA/TFT) + /// + protected List list2Write = new List(); + + /// + /// Elenco delle eventuali condizioni di veto conditions attive + /// + protected List ListVetoCond = new List(); + + /// + /// Num massimo di errori in funzionalità check alive + /// + protected int maxAliveErrors = utils.CRI("maxAliveErrors"); + + /// + /// Soglia massima errori prima della disconnessione automatica in check + /// + protected int maxErroriCheck = utils.CRI("maxErroriCheck"); + + /// + /// Quantità massima per singola ricetta (per determinare num ricette da inviare) + /// + protected int maxQtyPerFile = 0; + /// /// Dimensione coda di ping x valutazione /// protected int maxQueuePing = 11; + /// + /// Num massimo di errori di rete read (dal PLC) + /// + protected int maxReadErrors = utils.CRI("maxReadErrors"); + + /// + /// Periodo massimo (in sec) per letture dati in mancanza di eventi di aggiornamento + /// + protected int MaxSecReload = 120; + + /// + /// Num massimodi errori di rete send al server + /// + protected int maxSendErrors = utils.CRI("maxSendErrors"); + + /// + /// Numero massimo di tentativi x test ping preliminare + /// + protected int maxTryPing = 1; + + protected string mem2trace = ""; + /// /// Tempo minimo ammissibile di risposta (es x errori ModBus che risponde troppo in fretta) in millisec /// protected int minRespTimeMs = 5; + protected int minVetoSendDataItem = 60; + + /// + /// indica se serva refresh parametri e quindi PLC... + /// + protected bool needRefresh = true; + + /// + /// Indica se usare la parte numerica di un articolo come codice INT + /// + protected bool numArtCharTrim = false; + + /// + /// Timeout x ping al server + /// + protected int pingServerMsTimeout = utils.CRI("PingMsTimeout"); + + /// + /// DataOra avvio Programma x check avvio + /// + protected DateTime prgStarted = DateTime.Now; + + /// + /// Ritardo minimo x invio contapezzi + /// + protected int pzCountDelay = 2500; + /// /// Indica se resettare allarmi all'avvio e inviare il reset appena parte adapter /// protected bool resetAlarmOnStart = false; + /// + /// Periodo di campionamento x refresh info + /// + protected int samplePeriod = 1000; + + /// + /// MsSample Period base x campionamenti tpo OCP-UA + /// + protected int samplePeriodBase = 600; + + /// + /// Dizionario di VC da trattare come TimeSeries (con conf decodificata + processing successivo...) + /// + protected Dictionary TSVC_Data = new Dictionary(); + + /// + /// Indica se usare archivio locale ricette vs scarico http/REST + /// + protected bool useLocalRecipe = true; + + /// + /// Dizionario di VARIABILI da trattare come eventi (da inviare quando cambiano oppure a + /// scadenza periodo...) + /// + protected Dictionary VarArray = new Dictionary(); + + /// + /// Dizionario dei divieti di invio x ogni counter gestito + /// + protected Dictionary VetoCounterSend = new Dictionary(); + /// /// Veto per registrazione completa log di startup (minuti) /// protected int vetoLogStartupDuration = 60; + /// + /// Durata in secondi del divieto accodamento segnali IN alla fase di startup + /// + protected int vetoQueueIn = 10; + + /// + /// Periodo di veto prima di invio nuova conferma dei valori write correnti, default ogni 5 min + /// + protected double vetoSendWriteUpsert = 1; + + /// + /// Periodo wathdog di default (2 sec se non specificato) + /// + protected int watchDogPeriod = 2; + #endregion Protected Fields #region Protected Properties @@ -463,6 +824,88 @@ namespace IOB_UT_NEXT.Iob #region Protected Methods + /// + /// Decodifica file MAP (caso .bit) + /// + /// + /// + /// indirizzo Byte: indirizzo di partenza memoria + /// dimensione singolo slot in byte + /// indirizzo bit: numero riga x calcolo indice bit + /// + protected static otherData decodeBitData(string linea, char separator, int ByteNum, int memSize, int BitNum) + { + if (linea != null) + { + string[] valori = linea.Split(separator); + int shift = 0; + try + { + shift = Convert.ToInt32(valori[0]) - 1; + } + catch + { } + int resto = 0; + Math.DivRem(BitNum, 8, out resto); + string memAddr = string.Format("{0}.{1}", ByteNum + shift * memSize, resto); + return new otherData(valori[0], memAddr, valori[1].Trim(), valori[2].Trim()); + } + else + { + return null; + } + } + + /// + /// Decodifica file MAP generico + /// + /// + /// + /// + /// + /// + /// + protected static otherData decodeOtherData(string linea, char separator, string memPre, int baseAddr, int memSize) + { + if (linea != null) + { + string[] valori = linea.Split(separator); + int shift = 0; + try + { + shift = Convert.ToInt32(valori[0]) - 1; + } + catch + { } + string memAddr = string.Format("{0}{1}", memPre, baseAddr + shift * memSize); + return new otherData(valori[0], memAddr, valori[1].Trim(), valori[2].Trim()); + } + else + { + return null; + } + } + + protected static long GetObjectSize(object genObj, bool isSerializable) + { + long result = 0; + if (isSerializable) + { + using (var stream = new MemoryStream()) + { + var formatter = new BinaryFormatter(); + formatter.Serialize(stream, genObj); + result = stream.Length; + } + } + else + { + string rawVal = System.Text.Json.JsonSerializer.Serialize(genObj, options); + result = rawVal.Length; + } + return result; + } + /// /// Verifica se ci sia veto log attivo e gestisce casistiche /// @@ -560,6 +1003,21 @@ namespace IOB_UT_NEXT.Iob /// protected string GetWeekStatsKey() => redisMan.redHash($"IOB:Status:{IOBConfFull.General.FilenameIOB}:WeekStats"); + /// + /// Deserializza una stringa JSON in un oggetto. + /// + protected T JsonDeserialize(string json) => DataSerializer.Deserialize(json); + + /// + /// Serializza un oggetto in formato JSON. + /// + protected string JsonSerialize(T obj) => DataSerializer.Serialize(obj); + + /// + /// Serializza un oggetto in formato JSON con opzioni serializzazione. + /// + protected string JsonSerialize(T obj, Formatting reqFormat) => DataSerializer.Serialize(obj, reqFormat); + /// /// Imposta un valore nel hash dello stato dell'IOB. /// @@ -590,36 +1048,17 @@ namespace IOB_UT_NEXT.Iob QueueULog = new DataQueue(codIob, "QueueULog", false, redisMan); } - #endregion Protected Methods - - #region Protected Serialization Helpers - /// - /// Serializza un oggetto in formato JSON. + /// Deserializza una stringa XML in un oggetto. /// - protected string JsonSerialize(T obj) => IOB_UT_NEXT.Services.Data.DataSerializer.Serialize(obj); - - /// - /// Serializza un oggetto in formato JSON con opzioni serializzazione. - /// - protected string JsonSerialize(T obj, Formatting reqFormat) => IOB_UT_NEXT.Services.Data.DataSerializer.Serialize(obj, reqFormat); - - /// - /// Deserializza una stringa JSON in un oggetto. - /// - protected T JsonDeserialize(string json) => IOB_UT_NEXT.Services.Data.DataSerializer.Deserialize(json); + protected T XmlDeserialize(string xml) => XmlDataSerializer.Deserialize(xml); /// /// Serializza un oggetto in formato XML. /// - protected string XmlSerialize(T obj) => IOB_UT_NEXT.Services.Data.XmlDataSerializer.Serialize(obj); + protected string XmlSerialize(T obj) => XmlDataSerializer.Serialize(obj); - /// - /// Deserializza una stringa XML in un oggetto. - /// - protected T XmlDeserialize(string xml) => IOB_UT_NEXT.Services.Data.XmlDataSerializer.Deserialize(xml); - - #endregion Protected Serialization Helpers + #endregion Protected Methods #region Private Fields @@ -628,7 +1067,11 @@ namespace IOB_UT_NEXT.Iob /// private static readonly Logger lg = LogManager.GetCurrentClassLogger(); - private static Random rnd = new Random(); + private static readonly JsonSerializerOptions options = new JsonSerializerOptions + { + ReferenceHandler = ReferenceHandler.IgnoreCycles, + WriteIndented = false // Optional: set to true for pretty-printing + }; #endregion Private Fields } diff --git a/IOB-UT-NEXT/Iob/Services/Machine/MachineCommunicationService.cs b/IOB-UT-NEXT/Iob/Services/Machine/MachineCommunicationService.cs index 5accac77..e04741d1 100644 --- a/IOB-UT-NEXT/Iob/Services/Machine/MachineCommunicationService.cs +++ b/IOB-UT-NEXT/Iob/Services/Machine/MachineCommunicationService.cs @@ -57,6 +57,14 @@ namespace IOB_UT_NEXT.Services.Machine set => _tcMan.pzCountPLC = value; } + /// + /// Abilitazione allarme in caso di TC superiore a soglia + /// + public bool AlarmDelayTC + { + get => _tcMan.alarmDelayTC; + } + /// /// Legge un valore dalla memoria condivisa (MemMap) ricevuta dal PLC. /// diff --git a/IOB-WIN-FORM/Iob/Generic.cs b/IOB-WIN-FORM/Iob/Generic.cs index a5a05a83..0a6ff827 100644 --- a/IOB-WIN-FORM/Iob/Generic.cs +++ b/IOB-WIN-FORM/Iob/Generic.cs @@ -41,13 +41,6 @@ namespace IOB_WIN_FORM.Iob { public partial class Generic : BaseObj { - #region Private Fields - - private CommunicationService commService; - private MachineCommunicationService machineCommService; - - #endregion Private Fields - #region Public Fields public int numPzReqOdl = 0; @@ -73,6 +66,9 @@ namespace IOB_WIN_FORM.Iob // init oggetto redis... redisMan = new RedisIobCache(IobConfNew.MapoMes.IpAddr, IobConfNew.General.FilenameIOB, $"{IobConfNew.General.IobType}", IobConfNew.General.MinDeltaSec); + // init oggetto TCMan + var tcMan = new TCMan(IobConfNew.TCDataConf.Lambda, IobConfNew.TCDataConf.MaxDelayFactor, IobConfNew.TCDataConf.MaxIncrPz); + // init communication services commService = new CommunicationService(IobConfNew, redisMan); machineCommService = new MachineCommunicationService(IobConfNew, tcMan, memMap); @@ -80,8 +76,6 @@ namespace IOB_WIN_FORM.Iob // init code SetupQueue(); - // initi oggetto TCMan - tcMan = new TCMan(IobConfNew.TCDataConf.Lambda, IobConfNew.TCDataConf.MaxDelayFactor, IobConfNew.TCDataConf.MaxIncrPz); lastConnectTry = DateTime.Now; @@ -288,18 +282,6 @@ namespace IOB_WIN_FORM.Iob } } -#if false - /// - /// Valore medio del TC rilevato x verifica derive sul delta variazione contapezzi - /// - public double plcAvgTc => tcMan.avgTC > 0 ? tcMan.avgTC : 1; - - /// - /// DataOra dell'ultima lettura variabile contapezzi da CNC - /// - public DateTime plcLastPzRead => tcMan.lastObservedData; - -#endif /// /// Contapezzi attuale /// @@ -1129,14 +1111,14 @@ namespace IOB_WIN_FORM.Iob case taskType.forceSetPzCount: // recupero dati da memMap... - if (machineCommService.WriteToMemMap(iKey, item.Value)) - { - taskVal = $"SET task: {iKey} --> {item.Value} | mem: [Updated via MachineComm]"; - } - else - { - taskVal = $"NO DATA MEM, SET task: {iKey} --> {item.Value}"; - } + if (machineCommService.WriteToMemMap(iKey, item.Value)) + { + taskVal = $"SET task: {iKey} --> {item.Value} | mem: [Updated via MachineComm]"; + } + else + { + taskVal = $"NO DATA MEM, SET task: {iKey} --> {item.Value}"; + } lgInfo($"Chiamata forceSetPzCount: taskVal: {taskVal}"); @@ -3834,362 +3816,11 @@ namespace IOB_WIN_FORM.Iob } #endregion Private Methods + #region Protected Fields - /// - /// Variabile numero errori vari (in lettura) --> se supera soglia maxErroriCheck --> disconnette - /// - protected static int numErroriCheck = 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 = -1; - - /// - /// Cod grupo IOB x creazione PODL al volo - /// - protected string CodGruppoIob = "ND-00"; - - /// - /// 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; - - /// - /// Tempo di attesa in minuti x lettura contapezzi standard (da .ini / OptPar) - /// - protected double delayMinReadPzCount = 0; - - /// - /// Fattore di demoltiplicazione dei DynData x ridurre campionamento - /// - protected int demFactDynData = 1; - - /// - /// Boolean x indicare contapezzi disabilitato forzatamente da IOB - /// - protected bool disablePzCountByIob = false; - - /// - /// Veto x esecuzione task AutoDossier - /// - protected DateTime dtVetoAutoDossier = DateTime.Now; - - /// - /// Veto x esecuzione Task2Exe troppo frequenti - /// - protected DateTime dtVetoTask2Exe = DateTime.Now; - - /// - /// Veto x lettura contapezzi (in caso di autoODL con attesa reset ad esempio...) - /// - protected DateTime dtVetoReadPzCount = DateTime.Now; - - /// - /// Determina se sia prevista gestione PODL (creazione/avvio/chiusura) come Soitaab - /// - protected bool EnabelPodlManFull = false; - - /// - /// Abilita riscrittura memoria se trova differenze lettura/richiesti - /// - protected bool ENABLE_MEM_REWRITE = true; - - /// - /// Abilitazione restart (da opt par...) - /// - protected bool enableCliRestart = false; - - /// - /// Abilitazione invio dataitem - /// - protected bool enableSendDataItem = true; - protected int minVetoSendDataItem = 60; - /// - /// DataOra x veto all'invio dataItem - /// - protected DateTime dtVetoSenDataItem = DateTime.Now; - - /// - /// Boolean x indicare contapezzi abilitato a livello di conf applicazione - /// - protected bool enablePzCountByApp = true; - - /// - /// Abilitazione gestione slow data - /// - protected bool enableSlowData = false; - - /// - /// dizionario (opzionale) xz decodifica file da importare - /// - protected Dictionary FileDecod = new Dictionary(); - - /// - /// DeadBand x riduzione dati FluxLog (se 0 non gestita) - /// - protected double fluxLogRedDeadBand = 0; - - /// - /// Determina se sia gestita riduzione dati FluxLog - /// - protected bool fluxLogReduce = false; - - /// - /// Dizionario dei valori FluxLog ultimi verificati x veto - /// - protected Dictionary fluxLogReduceLast = new Dictionary(); - - /// - /// Dizionario dei valori FluxLog ultimi tipo STRING verificati x veto - /// - protected Dictionary fluxLogReduceLastString = new Dictionary(); - - /// - /// Dizionario dei veto send x ogni variabile quando non variata - /// - protected Dictionary fluxLogReduceVeto = new Dictionary(); - - /// - /// Finestra in minuti x invio dati FluxLog quando invariati - /// - protected int fluxLogResendPeriod = 60; - - /// - /// indica che è richiesto forzatamente reset contapezzi - /// - protected bool forcePzReset = false; - - /// - /// indica che è richiesto forzatamente reset contapezzi - /// - protected DateTime forcePzResetUntil = DateTime.Now.AddMinutes(-1); - - /// - /// DEADBAND globale se impostata (es x gestire variazioni minime valori FluxLog da inviare...) - /// - protected float GLOBAL_DBAND = 0; - - /// - /// Determina se siano gestite le ricette - /// - protected bool hasRecipe = false; - - /// - /// 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; - - /// - /// Dizionario ultimi valori (string) delle TSS - /// - protected Dictionary LastTSS = new Dictionary(); - - /// - /// Dizionario ultimi valori (string) delle TSS - /// - protected Dictionary LastTSSSend = new Dictionary(); - - /// - /// 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; - - /// - /// ultima data-ora invio parametri write x ribadire status - /// - protected DateTime lastWriteParamsUpsert = DateTime.Now; - - /// - /// Separatore linea (tipicamente x commenti) - /// - protected string lineSep = "--------------------------"; - - /// - /// Elenco parametri calcolati da inviare alla macchina (es ricetta con traduzione, RAMA/TFT) - /// - protected List list2Write = new List(); - - /// - /// Elenco delle eventuali condizioni di veto conditions attive - /// - protected List ListVetoCond = new List(); - - /// - /// Num massimo di errori in funzionalità check alive - /// - protected int maxAliveErrors = utils.CRI("maxAliveErrors"); - - /// - /// Soglia massima errori prima della disconnessione automatica in check - /// - protected int maxErroriCheck = utils.CRI("maxErroriCheck"); - - /// - /// Quantità massima per singola ricetta (per determinare num ricette da inviare) - /// - protected int maxQtyPerFile = 0; - - /// - /// Num massimo di errori di rete read (dal PLC) - /// - protected int maxReadErrors = utils.CRI("maxReadErrors"); - - /// - /// Periodo massimo (in sec) per letture dati in mancanza di eventi di aggiornamento - /// - protected int MaxSecReload = 120; - - /// - /// Num massimodi errori di rete send al server - /// - protected int maxSendErrors = utils.CRI("maxSendErrors"); - - /// - /// Numero massimo di tentativi x test ping preliminare - /// - protected int maxTryPing = 1; - - protected string mem2trace = ""; - - /// - /// indica se serva refresh parametri e quindi PLC... - /// - protected bool needRefresh = true; - - /// - /// Indica se usare la parte numerica di un articolo come codice INT - /// - protected bool numArtCharTrim = false; - - /// - /// Timeout x ping al server - /// - protected int pingServerMsTimeout = utils.CRI("PingMsTimeout"); - - /// - /// DataOra avvio Programma x check avvio - /// - protected DateTime prgStarted = DateTime.Now; - - /// - /// Ritardo minimo x invio contapezzi - /// - protected int pzCountDelay = 2500; - - /// - /// Periodo di campionamento x refresh info - /// - protected int samplePeriod = 1000; - - /// - /// MsSample Period base x campionamenti tpo OCP-UA - /// - protected int samplePeriodBase = 600; - - /// - /// Dizionario di VC da trattare come TimeSeries (con conf decodificata + processing successivo...) - /// - protected Dictionary TSVC_Data = new Dictionary(); - - /// - /// Indica se usare archivio locale ricette vs scarico http/REST - /// - protected bool useLocalRecipe = true; - - /// - /// Dizionario di VARIABILI da trattare come eventi (da inviare quando cambiano oppure a - /// scadenza periodo...) - /// - protected Dictionary VarArray = new Dictionary(); - - /// - /// Dizionario dei divieti di invio x ogni counter gestito - /// - protected Dictionary VetoCounterSend = new Dictionary(); - - /// - /// Durata in secondi del divieto accodamento segnali IN alla fase di startup - /// - protected int vetoQueueIn = 10; - - /// - /// Periodo di veto prima di invio nuova conferma dei valori write correnti, default ogni 5 min - /// - protected double vetoSendWriteUpsert = 1; - - /// - /// Periodo wathdog di default (2 sec se non specificato) - /// - protected int watchDogPeriod = 2; + protected CommunicationService commService; + protected MachineCommunicationService machineCommService; #endregion Protected Fields @@ -4938,87 +4569,7 @@ namespace IOB_WIN_FORM.Iob #region Protected Methods - /// - /// Decodifica file MAP (caso .bit) - /// - /// - /// - /// indirizzo Byte: indirizzo di partenza memoria - /// dimensione singolo slot in byte - /// indirizzo bit: numero riga x calcolo indice bit - /// - protected static otherData decodeBitData(string linea, char separator, int ByteNum, int memSize, int BitNum) - { - if (linea != null) - { - string[] valori = linea.Split(separator); - int shift = 0; - try - { - shift = Convert.ToInt32(valori[0]) - 1; - } - catch - { } - int resto = 0; - Math.DivRem(BitNum, 8, out resto); - string memAddr = string.Format("{0}.{1}", ByteNum + shift * memSize, resto); - return new otherData(valori[0], memAddr, valori[1].Trim(), valori[2].Trim()); - } - else - { - return null; - } - } - /// - /// Decodifica file MAP generico - /// - /// - /// - /// - /// - /// - /// - protected static otherData decodeOtherData(string linea, char separator, string memPre, int baseAddr, int memSize) - { - if (linea != null) - { - string[] valori = linea.Split(separator); - int shift = 0; - try - { - shift = Convert.ToInt32(valori[0]) - 1; - } - catch - { } - string memAddr = string.Format("{0}{1}", memPre, baseAddr + shift * memSize); - return new otherData(valori[0], memAddr, valori[1].Trim(), valori[2].Trim()); - } - else - { - return null; - } - } - - protected static long GetObjectSize(object genObj, bool isSerializable) - { - long result = 0; - if (isSerializable) - { - using (var stream = new MemoryStream()) - { - var formatter = new BinaryFormatter(); - formatter.Serialize(stream, genObj); - result = stream.Length; - } - } - else - { - string rawVal = System.Text.Json.JsonSerializer.Serialize(genObj, options); - result = rawVal.Length; - } - return result; - } /// /// Decodifica valore della coda IN nel formato sendEnab[0]=dtEve sendEnab[1]=valore sendEnab[2]=counter @@ -6331,10 +5882,9 @@ namespace IOB_WIN_FORM.Iob { foreach (var item in writeList) { - // scrivo in memoria - if (memMap.mMapWrite.ContainsKey(item.uid)) + // scrivo in memoria tramite servizio + if (machineCommService.WriteToMemMap(item.uid, item.reqValue)) { - memMap.mMapWrite[item.uid].value = item.reqValue; currOut = $" | Parameter {item.uid} | {item.value} --> {item.reqValue}"; // sistemo valori item.value = item.reqValue; @@ -6344,6 +5894,7 @@ namespace IOB_WIN_FORM.Iob // salvo in lista da ritrasmettere updatedPar.Add(item); } + else { currOut = $" | Error: parameter {item.uid} not found"; @@ -8473,11 +8024,7 @@ namespace IOB_WIN_FORM.Iob #region Private Fields - private static readonly JsonSerializerOptions options = new JsonSerializerOptions - { - ReferenceHandler = ReferenceHandler.IgnoreCycles, - WriteIndented = false // Optional: set to true for pretty-printing - }; + /// /// Oggetto logger della classe diff --git a/IOB-WIN-FORM/Iob/Simula.cs b/IOB-WIN-FORM/Iob/Simula.cs index 0f70f550..f075c8c2 100644 --- a/IOB-WIN-FORM/Iob/Simula.cs +++ b/IOB-WIN-FORM/Iob/Simula.cs @@ -60,18 +60,13 @@ namespace IOB_WIN_FORM.Iob #endregion Public Fields - #region Private Fields for Dirty Check - private int lastSentPzCount = -1; - private DateTime lastBitmapDecodeTime = DateTime.MinValue; - #endregion - #region Public Constructors public Simula(AdapterForm caller, IobConfTree IobConfFull) : base(caller, IobConfFull) { // jitter di avvio per disallineare le istanze nella VM Random startRnd = new Random(); - int startDelay = startRnd.Next(0, 5000); + int startDelay = startRnd.Next(0, 5000); Thread.Sleep(startDelay); // gestione invio ritardato contapezzi @@ -95,13 +90,13 @@ namespace IOB_WIN_FORM.Iob { int basePeriod = 0; int.TryParse(IOBConfFull.OptParGet("PER_BASE"), out basePeriod); - + // Applicazione Jitter sui periodi per evitare sincronizzazione tra VM Random rnd = new Random(); // Aggiungiamo un rumore del +/- 15% e un jitter extra - double noiseFactor = 0.85 + (rnd.NextDouble() * 0.30); + double noiseFactor = 0.85 + (rnd.NextDouble() * 0.30); periodoMSec = (int)(basePeriod * noiseFactor); - + // Assicuriamo un minimo di jitter per evitare che periodi simili si allineino periodoMSec += rnd.Next(1, 500); } @@ -157,12 +152,12 @@ namespace IOB_WIN_FORM.Iob // carica conf try { - // Invece di bloccare il costruttore con .GetAwaiter().GetResult(), + // Invece di bloccare il costruttore con .GetAwaiter().GetResult(), // avviamo il carico in modo "fire-and-forget" controllato. // Questo evita il context switch pesante durante l'inizializzazione. _ = Task.Run(async () => { - try + try { await Simula_Load(adesso); } @@ -973,10 +968,10 @@ namespace IOB_WIN_FORM.Iob item.reqValue = ""; MemBlock = new byte[byteSize]; - serObj = JsonSerialize(item, Formatting.Indented); - lgInfo($"Inizio processing plcWriteParams per {currMem.name} | valore richiesto {currMem.value}{Environment.NewLine}---------------UPDATED PARAM---------------{Environment.NewLine}{serObj}{Environment.NewLine}---------------"); - serObj = JsonSerialize(currMem, Formatting.Indented); - lgInfo($"---------------MEMORY CONTENT---------------{Environment.NewLine}{serObj}{Environment.NewLine}---------------"); + serObj = JsonSerialize(item, Formatting.Indented); + lgInfo($"Inizio processing plcWriteParams per {currMem.name} | valore richiesto {currMem.value}{Environment.NewLine}---------------UPDATED PARAM---------------{Environment.NewLine}{serObj}{Environment.NewLine}---------------"); + serObj = JsonSerialize(currMem, Formatting.Indented); + lgInfo($"---------------MEMORY CONTENT---------------{Environment.NewLine}{serObj}{Environment.NewLine}---------------"); lgInfo($"---------------MemBlock data---------------{Environment.NewLine}{BitConverter.ToString(MemBlock)}{Environment.NewLine}--------------- END data ---------------"); // salvo @@ -1002,12 +997,12 @@ namespace IOB_WIN_FORM.Iob { try { - // Eseguiamo il lavoro in un Task per non bloccare il thread chiamante, + // Eseguiamo il lavoro in un Task per non bloccare il thread chiamante, // ma evitiamo il .GetAwaiter().GetResult() che causerebbe un blocco sincrono pesante. // In un ambiente WinForms, questo permette al thread di polling di non restare in attesa attiva. _ = Task.Run(async () => { - try + try { // Esecuzione dei task sincroni esistenti iobWriteLocalCSV(); @@ -1102,9 +1097,8 @@ namespace IOB_WIN_FORM.Iob #region Private Fields private List alarmMessages = new List(); - private int currSimAlarmCode = 0; - + private DateTime lastBitmapDecodeTime = DateTime.MinValue; private Random rnd = new Random(); #endregion Private Fields @@ -1475,7 +1469,7 @@ namespace IOB_WIN_FORM.Iob } } } - else if (bit5 != null && bit5.wait <= 0 || tcMan.alarmDelayTC) + else if (bit5 != null && bit5.wait <= 0 || machineCommService.AlarmDelayTC) { // segnalo BIT B_input += (1 << 5); @@ -1760,8 +1754,8 @@ namespace IOB_WIN_FORM.Iob { try { - listaArt = JsonDeserialize>(rawListArt); - okArt = listaArt.Count > 0; + listaArt = JsonDeserialize>(rawListArt); + okArt = listaArt.Count > 0; } catch (Exception exc) { @@ -1776,8 +1770,8 @@ namespace IOB_WIN_FORM.Iob { try { - listaDoss = JsonDeserialize>(rawListDOSS); - okDoss = listaDoss.Count > 0; + listaDoss = JsonDeserialize>(rawListDOSS); + okDoss = listaDoss.Count > 0; } catch (Exception exc) { @@ -1792,8 +1786,8 @@ namespace IOB_WIN_FORM.Iob { try { - listaPODL = JsonDeserialize>(rawListPODL); - okPodl = listaPODL.Count > 0; + listaPODL = JsonDeserialize>(rawListPODL); + okPodl = listaPODL.Count > 0; } catch (Exception exc) { @@ -1828,7 +1822,7 @@ namespace IOB_WIN_FORM.Iob if (selArt != null && selDoss != null) { // recupero il resultset dei valori FluxLog da caricare - DossierFluxLogDTO resultSet = JsonDeserialize(selDoss.Valore); + DossierFluxLogDTO resultSet = JsonDeserialize(selDoss.Valore); List listFluxLog = resultSet.ODL; // preparo elenco parametri da inviare... @@ -2167,7 +2161,7 @@ namespace IOB_WIN_FORM.Iob /// private void sendDataItemsList(List dataItems) { - string rawData = JsonSerialize(dataItems); + string rawData = JsonSerialize(dataItems); HttpService.CallUrlPost($"{urlSaveDataItems}", rawData); }