continuo fix

This commit is contained in:
Samuele Locatelli
2026-05-23 09:59:43 +02:00
parent 4b9f03c9d7
commit 62847732dd
4 changed files with 523 additions and 531 deletions
+475 -32
View File
@@ -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
/// </summary>
public DataQueue QueueRawTransf;// = new DataQueue("000", "QueueRawTransf", false);
public DataQueue QueueRawTransf;
/// <summary>
/// Coda delle richieste dal server (Task2Exe)
/// </summary>
public DataQueue QueueSrvReq;
// = new DataQueue("000", "QueueRawTransf", false);
/// <summary>
/// Coda delle risposte al server (Task2Exe)
/// </summary>
@@ -253,13 +260,14 @@ namespace IOB_UT_NEXT.Iob
/// <summary>
/// Coda valori LOG UTENTE (da non sottocampionare come samples)...
/// </summary>
public DataQueue QueueULog;// = new DataQueue("000", "QueueULog", false);
public DataQueue QueueULog;
/// <summary>
/// alias booleano false = R
/// </summary>
public bool R = false;
// = new DataQueue("000", "QueueULog", false);
/// <summary>
/// 32 byte input base (es strobe, 8 word da 32 bit di flags...)
/// </summary>
@@ -280,11 +288,6 @@ namespace IOB_UT_NEXT.Iob
/// </summary>
public Stopwatch sw = new Stopwatch();
/// <summary>
/// Oggetto gestione TempiCiclo e contapezzi
/// </summary>
public TCMan tcMan = new TCMan(0.5, 1.3, 5);
/// <summary>
/// Imposta veto lettura dati (es per DB a 2 sec)
/// </summary>
@@ -402,49 +405,407 @@ namespace IOB_UT_NEXT.Iob
#region Protected Fields
/// <summary>
/// Variabile numero errori vari (in lettura) --&gt; se supera soglia maxErroriCheck --&gt; disconnette
/// </summary>
protected static int numErroriCheck = 0;
/// <summary>
/// Valore di attesa (random) dopo ogni invio x evitare congestione send...
/// </summary>
protected static int urlRandWait = 0;
/// <summary>
/// Stato connessione con macchina gestita
/// </summary>
protected bool _connOk = false;
/// <summary>
/// valore booleano di check se sia in fase di COMUNICAZIONE ATTIVA con il PLC/NC
/// </summary>
protected bool adpCommAct;
/// <summary>
/// porta x adapter (x restart)
/// </summary>
protected int adpPortNum;
/// <summary>
/// DataOra ultimo avvio adapter x watchdog
/// </summary>
protected DateTime adpStartRun;
/// <summary>
/// Vettore 32 BIT valori in ingresso al filtro
/// </summary>
protected int B_input;
/// <summary>
/// Vettore 32 BIT valori in uscita dal filtro
/// </summary>
protected int B_output;
/// <summary>
/// Vettore 32 BIT valori precedenti
/// </summary>
protected int B_previous = -1;
/// <summary>
/// Cod grupo IOB x creazione PODL al volo
/// </summary>
protected string CodGruppoIob = "ND-00";
/// <summary>
/// Num errori check alive
/// </summary>
protected int currAliveErrors = 0;
/// <summary>
/// Dizionario valori impostati x produzione
/// </summary>
protected Dictionary<string, string> currProdData = new Dictionary<string, string>();
/// <summary>
/// num corrente errori read PLC
/// </summary>
protected int currReadErrors = 0;
/// <summary>
/// num errori send
/// </summary>
protected int currSendErrors = 0;
/// <summary>
/// Tempo di attesa in minuti x lettura contapezzi standard (da .ini / OptPar)
/// </summary>
protected double delayMinReadPzCount = 0;
/// <summary>
/// Fattore di demoltiplicazione dei DynData x ridurre campionamento
/// </summary>
protected int demFactDynData = 1;
/// <summary>
/// Disabilitazione gestione ODL (lettura e gestione)
/// </summary>
protected bool disableOdl = false;
/// <summary>
/// Boolean x indicare contapezzi disabilitato forzatamente da IOB
/// </summary>
protected bool disablePzCountByIob = false;
/// <summary>
/// Veto x esecuzione task AutoDossier
/// </summary>
protected DateTime dtVetoAutoDossier = DateTime.Now;
/// <summary>
/// Veto x lettura contapezzi (in caso di autoODL con attesa reset ad esempio...)
/// </summary>
protected DateTime dtVetoReadPzCount = DateTime.Now;
/// <summary>
/// DataOra x veto all'invio dataItem
/// </summary>
protected DateTime dtVetoSenDataItem = DateTime.Now;
/// <summary>
/// Veto x esecuzione Task2Exe troppo frequenti
/// </summary>
protected DateTime dtVetoTask2Exe = DateTime.Now;
/// <summary>
/// Determina se sia prevista gestione PODL (creazione/avvio/chiusura) come Soitaab
/// </summary>
protected bool EnabelPodlManFull = false;
/// <summary>
/// Abilita riscrittura memoria se trova differenze lettura/richiesti
/// </summary>
protected bool ENABLE_MEM_REWRITE = true;
/// <summary>
/// Abilitazione restart (da opt par...)
/// </summary>
protected bool enableCliRestart = false;
/// <summary>
/// Boolean x indicare contapezzi abilitato a livello di conf applicazione
/// </summary>
protected bool enablePzCountByApp = true;
/// <summary>
/// Abilitazione invio dataitem
/// </summary>
protected bool enableSendDataItem = true;
/// <summary>
/// Abilitazione gestione slow data
/// </summary>
protected bool enableSlowData = false;
//protected static Logger lg = LogManager.GetCurrentClassLogger();
/// <summary>
/// Abilitazione invio conf macchine
/// </summary>
protected bool enabSendMachineConf = true;
/// <summary>
/// dizionario (opzionale) xz decodifica file da importare
/// </summary>
protected Dictionary<string, int> FileDecod = new Dictionary<string, int>();
/// <summary>
/// DeadBand x riduzione dati FluxLog (se 0 non gestita)
/// </summary>
protected double fluxLogRedDeadBand = 0;
/// <summary>
/// Determina se sia gestita riduzione dati FluxLog
/// </summary>
protected bool fluxLogReduce = false;
/// <summary>
/// Dizionario dei valori FluxLog ultimi verificati x veto
/// </summary>
protected Dictionary<string, double> fluxLogReduceLast = new Dictionary<string, double>();
/// <summary>
/// Dizionario dei valori FluxLog ultimi tipo STRING verificati x veto
/// </summary>
protected Dictionary<string, string> fluxLogReduceLastString = new Dictionary<string, string>();
/// <summary>
/// Dizionario dei veto send x ogni variabile quando non variata
/// </summary>
protected Dictionary<string, DateTime> fluxLogReduceVeto = new Dictionary<string, DateTime>();
/// <summary>
/// Finestra in minuti x invio dati FluxLog quando invariati
/// </summary>
protected int fluxLogResendPeriod = 60;
/// <summary>
/// indica che è richiesto forzatamente reset contapezzi
/// </summary>
protected bool forcePzReset = false;
/// <summary>
/// indica che è richiesto forzatamente reset contapezzi
/// </summary>
protected DateTime forcePzResetUntil = DateTime.Now.AddMinutes(-1);
/// <summary>
/// DEADBAND globale se impostata (es x gestire variazioni minime valori FluxLog da inviare...)
/// </summary>
protected float GLOBAL_DBAND = 0;
/// <summary>
/// Determina se siano gestite le ricette
/// </summary>
protected bool hasRecipe = false;
/// <summary>
/// Array dei contatori x segnali blinking
/// </summary>
protected int[] i_counters;
/// <summary>
/// Indica impianto IN SETUP (fino a quando SMETTE di esserlo...)
/// </summary>
protected bool inSetup = false;
/// <summary>
/// ultimo tentativo connessione...
/// </summary>
protected DateTime lastConnectTry;
/// <summary>
/// Ultimo LOG registrazione avvio (x ridurre log notturni...)
/// </summary>
protected DateTime lastLogStartup = DateTime.Today.AddHours(-1);
/// <summary>
/// Dizionario ULTIMI valori impostati x produzione
/// </summary>
protected Dictionary<string, string> lastProdData = new Dictionary<string, string>();
/// <summary>
/// Ultimo invio contapezzi (x invio delayed)
/// </summary>
protected DateTime lastPzCountSend;
/// <summary>
/// Dizionario ultimi valori (string) delle TSS
/// </summary>
protected Dictionary<string, string> LastTSS = new Dictionary<string, string>();
/// <summary>
/// Dizionario ultimi valori (string) delle TSS
/// </summary>
protected Dictionary<string, DateTime> LastTSSSend = new Dictionary<string, DateTime>();
/// <summary>
/// Dizionario ultimi valori (double) delle TSVC
/// </summary>
protected Dictionary<string, double> LastTSVC = new Dictionary<string, double>();
/// <summary>
/// Ultima registrazione warning x ODL mancante (x scrivere solo ogni 15 secondi)
/// </summary>
protected DateTime lastWarnODL;
/// <summary>
/// ultima data-ora invio parametri write x ribadire status
/// </summary>
protected DateTime lastWriteParamsUpsert = DateTime.Now;
/// <summary>
/// Separatore linea (tipicamente x commenti)
/// </summary>
protected string lineSep = "--------------------------";
/// <summary>
/// Elenco parametri calcolati da inviare alla macchina (es ricetta con traduzione, RAMA/TFT)
/// </summary>
protected List<objItem> list2Write = new List<objItem>();
/// <summary>
/// Elenco delle eventuali condizioni di veto conditions attive
/// </summary>
protected List<string> ListVetoCond = new List<string>();
/// <summary>
/// Num massimo di errori in funzionalità check alive
/// </summary>
protected int maxAliveErrors = utils.CRI("maxAliveErrors");
/// <summary>
/// Soglia massima errori prima della disconnessione automatica in check
/// </summary>
protected int maxErroriCheck = utils.CRI("maxErroriCheck");
/// <summary>
/// Quantità massima per singola ricetta (per determinare num ricette da inviare)
/// </summary>
protected int maxQtyPerFile = 0;
/// <summary>
/// Dimensione coda di ping x valutazione
/// </summary>
protected int maxQueuePing = 11;
/// <summary>
/// Num massimo di errori di rete read (dal PLC)
/// </summary>
protected int maxReadErrors = utils.CRI("maxReadErrors");
/// <summary>
/// Periodo massimo (in sec) per letture dati in mancanza di eventi di aggiornamento
/// </summary>
protected int MaxSecReload = 120;
/// <summary>
/// Num massimodi errori di rete send al server
/// </summary>
protected int maxSendErrors = utils.CRI("maxSendErrors");
/// <summary>
/// Numero massimo di tentativi x test ping preliminare
/// </summary>
protected int maxTryPing = 1;
protected string mem2trace = "";
/// <summary>
/// Tempo minimo ammissibile di risposta (es x errori ModBus che risponde troppo in fretta) in millisec
/// </summary>
protected int minRespTimeMs = 5;
protected int minVetoSendDataItem = 60;
/// <summary>
/// indica se serva refresh parametri e quindi PLC...
/// </summary>
protected bool needRefresh = true;
/// <summary>
/// Indica se usare la parte numerica di un articolo come codice INT
/// </summary>
protected bool numArtCharTrim = false;
/// <summary>
/// Timeout x ping al server
/// </summary>
protected int pingServerMsTimeout = utils.CRI("PingMsTimeout");
/// <summary>
/// DataOra avvio Programma x check avvio
/// </summary>
protected DateTime prgStarted = DateTime.Now;
/// <summary>
/// Ritardo minimo x invio contapezzi
/// </summary>
protected int pzCountDelay = 2500;
/// <summary>
/// Indica se resettare allarmi all'avvio e inviare il reset appena parte adapter
/// </summary>
protected bool resetAlarmOnStart = false;
/// <summary>
/// Periodo di campionamento x refresh info
/// </summary>
protected int samplePeriod = 1000;
/// <summary>
/// MsSample Period base x campionamenti tpo OCP-UA
/// </summary>
protected int samplePeriodBase = 600;
/// <summary>
/// Dizionario di VC da trattare come TimeSeries (con conf decodificata + processing successivo...)
/// </summary>
protected Dictionary<string, VCData> TSVC_Data = new Dictionary<string, VCData>();
/// <summary>
/// Indica se usare archivio locale ricette vs scarico http/REST
/// </summary>
protected bool useLocalRecipe = true;
/// <summary>
/// Dizionario di VARIABILI da trattare come eventi (da inviare quando cambiano oppure a
/// scadenza periodo...)
/// </summary>
protected Dictionary<string, EVData> VarArray = new Dictionary<string, EVData>();
/// <summary>
/// Dizionario dei divieti di invio x ogni counter gestito
/// </summary>
protected Dictionary<string, DateTime> VetoCounterSend = new Dictionary<string, DateTime>();
/// <summary>
/// Veto per registrazione completa log di startup (minuti)
/// </summary>
protected int vetoLogStartupDuration = 60;
/// <summary>
/// Durata in secondi del divieto accodamento segnali IN alla fase di startup
/// </summary>
protected int vetoQueueIn = 10;
/// <summary>
/// Periodo di veto prima di invio nuova conferma dei valori write correnti, default ogni 5 min
/// </summary>
protected double vetoSendWriteUpsert = 1;
/// <summary>
/// Periodo wathdog di default (2 sec se non specificato)
/// </summary>
protected int watchDogPeriod = 2;
#endregion Protected Fields
#region Protected Properties
@@ -463,6 +824,88 @@ namespace IOB_UT_NEXT.Iob
#region Protected Methods
/// <summary>
/// Decodifica file MAP (caso <paramref name="ByteNum" />.bit)
/// </summary>
/// <param name="linea"></param>
/// <param name="separator"></param>
/// <param name="ByteNum">indirizzo Byte: indirizzo di partenza memoria</param>
/// <param name="memSize">dimensione singolo slot in byte</param>
/// <param name="BitNum">indirizzo bit: numero riga x calcolo indice bit</param>
/// <returns></returns>
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;
}
}
/// <summary>
/// Decodifica file MAP generico
/// </summary>
/// <param name="linea"></param>
/// <param name="separator"></param>
/// <param name="memPre"></param>
/// <param name="baseAddr"></param>
/// <param name="memSize"></param>
/// <returns></returns>
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;
}
/// <summary>
/// Verifica se ci sia veto log attivo e gestisce casistiche
/// </summary>
@@ -560,6 +1003,21 @@ namespace IOB_UT_NEXT.Iob
/// </summary>
protected string GetWeekStatsKey() => redisMan.redHash($"IOB:Status:{IOBConfFull.General.FilenameIOB}:WeekStats");
/// <summary>
/// Deserializza una stringa JSON in un oggetto.
/// </summary>
protected T JsonDeserialize<T>(string json) => DataSerializer.Deserialize<T>(json);
/// <summary>
/// Serializza un oggetto in formato JSON.
/// </summary>
protected string JsonSerialize<T>(T obj) => DataSerializer.Serialize(obj);
/// <summary>
/// Serializza un oggetto in formato JSON con opzioni serializzazione.
/// </summary>
protected string JsonSerialize<T>(T obj, Formatting reqFormat) => DataSerializer.Serialize(obj, reqFormat);
/// <summary>
/// Imposta un valore nel hash dello stato dell'IOB.
/// </summary>
@@ -590,36 +1048,17 @@ namespace IOB_UT_NEXT.Iob
QueueULog = new DataQueue(codIob, "QueueULog", false, redisMan);
}
#endregion Protected Methods
#region Protected Serialization Helpers
/// <summary>
/// Serializza un oggetto in formato JSON.
/// Deserializza una stringa XML in un oggetto.
/// </summary>
protected string JsonSerialize<T>(T obj) => IOB_UT_NEXT.Services.Data.DataSerializer.Serialize(obj);
/// <summary>
/// Serializza un oggetto in formato JSON con opzioni serializzazione.
/// </summary>
protected string JsonSerialize<T>(T obj, Formatting reqFormat) => IOB_UT_NEXT.Services.Data.DataSerializer.Serialize(obj, reqFormat);
/// <summary>
/// Deserializza una stringa JSON in un oggetto.
/// </summary>
protected T JsonDeserialize<T>(string json) => IOB_UT_NEXT.Services.Data.DataSerializer.Deserialize<T>(json);
protected T XmlDeserialize<T>(string xml) => XmlDataSerializer.Deserialize<T>(xml);
/// <summary>
/// Serializza un oggetto in formato XML.
/// </summary>
protected string XmlSerialize<T>(T obj) => IOB_UT_NEXT.Services.Data.XmlDataSerializer.Serialize(obj);
protected string XmlSerialize<T>(T obj) => XmlDataSerializer.Serialize(obj);
/// <summary>
/// Deserializza una stringa XML in un oggetto.
/// </summary>
protected T XmlDeserialize<T>(string xml) => IOB_UT_NEXT.Services.Data.XmlDataSerializer.Deserialize<T>(xml);
#endregion Protected Serialization Helpers
#endregion Protected Methods
#region Private Fields
@@ -628,7 +1067,11 @@ namespace IOB_UT_NEXT.Iob
/// </summary>
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
}
@@ -57,6 +57,14 @@ namespace IOB_UT_NEXT.Services.Machine
set => _tcMan.pzCountPLC = value;
}
/// <summary>
/// Abilitazione allarme in caso di TC superiore a soglia
/// </summary>
public bool AlarmDelayTC
{
get => _tcMan.alarmDelayTC;
}
/// <summary>
/// Legge un valore dalla memoria condivisa (MemMap) ricevuta dal PLC.
/// </summary>
+18 -471
View File
@@ -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
/// <summary>
/// Valore medio del TC rilevato x verifica derive sul delta variazione contapezzi
/// </summary>
public double plcAvgTc => tcMan.avgTC > 0 ? tcMan.avgTC : 1;
/// <summary>
/// DataOra dell'ultima lettura variabile contapezzi da CNC
/// </summary>
public DateTime plcLastPzRead => tcMan.lastObservedData;
#endif
/// <summary>
/// Contapezzi attuale
/// </summary>
@@ -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
/// <summary>
/// Variabile numero errori vari (in lettura) --&gt; se supera soglia maxErroriCheck --&gt; disconnette
/// </summary>
protected static int numErroriCheck = 0;
protected bool _connOk = false;
/// <summary>
/// valore booleano di check se sia in fase di COMUNICAZIONE ATTIVA con il PLC/NC
/// </summary>
protected bool adpCommAct;
/// <summary>
/// porta x adapter (x restart)
/// </summary>
protected int adpPortNum;
/// <summary>
/// DataOra ultimo avvio adapter x watchdog
/// </summary>
protected DateTime adpStartRun;
/// <summary>
/// Vettore 32 BIT valori in ingresso al filtro
/// </summary>
protected int B_input;
/// <summary>
/// Vettore 32 BIT valori in uscita dal filtro
/// </summary>
protected int B_output;
/// <summary>
/// Vettore 32 BIT valori precedenti
/// </summary>
protected int B_previous = -1;
/// <summary>
/// Cod grupo IOB x creazione PODL al volo
/// </summary>
protected string CodGruppoIob = "ND-00";
/// <summary>
/// Num errori check alive
/// </summary>
protected int currAliveErrors = 0;
/// <summary>
/// Dizionario valori impostati x produzione
/// </summary>
protected Dictionary<string, string> currProdData = new Dictionary<string, string>();
/// <summary>
/// num corrente errori read PLC
/// </summary>
protected int currReadErrors = 0;
/// <summary>
/// num errori send
/// </summary>
protected int currSendErrors = 0;
/// <summary>
/// Tempo di attesa in minuti x lettura contapezzi standard (da .ini / OptPar)
/// </summary>
protected double delayMinReadPzCount = 0;
/// <summary>
/// Fattore di demoltiplicazione dei DynData x ridurre campionamento
/// </summary>
protected int demFactDynData = 1;
/// <summary>
/// Boolean x indicare contapezzi disabilitato forzatamente da IOB
/// </summary>
protected bool disablePzCountByIob = false;
/// <summary>
/// Veto x esecuzione task AutoDossier
/// </summary>
protected DateTime dtVetoAutoDossier = DateTime.Now;
/// <summary>
/// Veto x esecuzione Task2Exe troppo frequenti
/// </summary>
protected DateTime dtVetoTask2Exe = DateTime.Now;
/// <summary>
/// Veto x lettura contapezzi (in caso di autoODL con attesa reset ad esempio...)
/// </summary>
protected DateTime dtVetoReadPzCount = DateTime.Now;
/// <summary>
/// Determina se sia prevista gestione PODL (creazione/avvio/chiusura) come Soitaab
/// </summary>
protected bool EnabelPodlManFull = false;
/// <summary>
/// Abilita riscrittura memoria se trova differenze lettura/richiesti
/// </summary>
protected bool ENABLE_MEM_REWRITE = true;
/// <summary>
/// Abilitazione restart (da opt par...)
/// </summary>
protected bool enableCliRestart = false;
/// <summary>
/// Abilitazione invio dataitem
/// </summary>
protected bool enableSendDataItem = true;
protected int minVetoSendDataItem = 60;
/// <summary>
/// DataOra x veto all'invio dataItem
/// </summary>
protected DateTime dtVetoSenDataItem = DateTime.Now;
/// <summary>
/// Boolean x indicare contapezzi abilitato a livello di conf applicazione
/// </summary>
protected bool enablePzCountByApp = true;
/// <summary>
/// Abilitazione gestione slow data
/// </summary>
protected bool enableSlowData = false;
/// <summary>
/// dizionario (opzionale) xz decodifica file da importare
/// </summary>
protected Dictionary<string, int> FileDecod = new Dictionary<string, int>();
/// <summary>
/// DeadBand x riduzione dati FluxLog (se 0 non gestita)
/// </summary>
protected double fluxLogRedDeadBand = 0;
/// <summary>
/// Determina se sia gestita riduzione dati FluxLog
/// </summary>
protected bool fluxLogReduce = false;
/// <summary>
/// Dizionario dei valori FluxLog ultimi verificati x veto
/// </summary>
protected Dictionary<string, double> fluxLogReduceLast = new Dictionary<string, double>();
/// <summary>
/// Dizionario dei valori FluxLog ultimi tipo STRING verificati x veto
/// </summary>
protected Dictionary<string, string> fluxLogReduceLastString = new Dictionary<string, string>();
/// <summary>
/// Dizionario dei veto send x ogni variabile quando non variata
/// </summary>
protected Dictionary<string, DateTime> fluxLogReduceVeto = new Dictionary<string, DateTime>();
/// <summary>
/// Finestra in minuti x invio dati FluxLog quando invariati
/// </summary>
protected int fluxLogResendPeriod = 60;
/// <summary>
/// indica che è richiesto forzatamente reset contapezzi
/// </summary>
protected bool forcePzReset = false;
/// <summary>
/// indica che è richiesto forzatamente reset contapezzi
/// </summary>
protected DateTime forcePzResetUntil = DateTime.Now.AddMinutes(-1);
/// <summary>
/// DEADBAND globale se impostata (es x gestire variazioni minime valori FluxLog da inviare...)
/// </summary>
protected float GLOBAL_DBAND = 0;
/// <summary>
/// Determina se siano gestite le ricette
/// </summary>
protected bool hasRecipe = false;
/// <summary>
/// Array dei contatori x segnali blinking
/// </summary>
protected int[] i_counters;
/// <summary>
/// Indica impianto IN SETUP (fino a quando SMETTE di esserlo...)
/// </summary>
protected bool inSetup = false;
/// <summary>
/// ultimo tentativo connessione...
/// </summary>
protected DateTime lastConnectTry;
/// <summary>
/// Dizionario ULTIMI valori impostati x produzione
/// </summary>
protected Dictionary<string, string> lastProdData = new Dictionary<string, string>();
/// <summary>
/// Ultimo invio contapezzi (x invio delayed)
/// </summary>
protected DateTime lastPzCountSend;
/// <summary>
/// Dizionario ultimi valori (string) delle TSS
/// </summary>
protected Dictionary<string, string> LastTSS = new Dictionary<string, string>();
/// <summary>
/// Dizionario ultimi valori (string) delle TSS
/// </summary>
protected Dictionary<string, DateTime> LastTSSSend = new Dictionary<string, DateTime>();
/// <summary>
/// Dizionario ultimi valori (double) delle TSVC
/// </summary>
protected Dictionary<string, double> LastTSVC = new Dictionary<string, double>();
/// <summary>
/// Ultima registrazione warning x ODL mancante (x scrivere solo ogni 15 secondi)
/// </summary>
protected DateTime lastWarnODL;
/// <summary>
/// ultima data-ora invio parametri write x ribadire status
/// </summary>
protected DateTime lastWriteParamsUpsert = DateTime.Now;
/// <summary>
/// Separatore linea (tipicamente x commenti)
/// </summary>
protected string lineSep = "--------------------------";
/// <summary>
/// Elenco parametri calcolati da inviare alla macchina (es ricetta con traduzione, RAMA/TFT)
/// </summary>
protected List<objItem> list2Write = new List<objItem>();
/// <summary>
/// Elenco delle eventuali condizioni di veto conditions attive
/// </summary>
protected List<string> ListVetoCond = new List<string>();
/// <summary>
/// Num massimo di errori in funzionalità check alive
/// </summary>
protected int maxAliveErrors = utils.CRI("maxAliveErrors");
/// <summary>
/// Soglia massima errori prima della disconnessione automatica in check
/// </summary>
protected int maxErroriCheck = utils.CRI("maxErroriCheck");
/// <summary>
/// Quantità massima per singola ricetta (per determinare num ricette da inviare)
/// </summary>
protected int maxQtyPerFile = 0;
/// <summary>
/// Num massimo di errori di rete read (dal PLC)
/// </summary>
protected int maxReadErrors = utils.CRI("maxReadErrors");
/// <summary>
/// Periodo massimo (in sec) per letture dati in mancanza di eventi di aggiornamento
/// </summary>
protected int MaxSecReload = 120;
/// <summary>
/// Num massimodi errori di rete send al server
/// </summary>
protected int maxSendErrors = utils.CRI("maxSendErrors");
/// <summary>
/// Numero massimo di tentativi x test ping preliminare
/// </summary>
protected int maxTryPing = 1;
protected string mem2trace = "";
/// <summary>
/// indica se serva refresh parametri e quindi PLC...
/// </summary>
protected bool needRefresh = true;
/// <summary>
/// Indica se usare la parte numerica di un articolo come codice INT
/// </summary>
protected bool numArtCharTrim = false;
/// <summary>
/// Timeout x ping al server
/// </summary>
protected int pingServerMsTimeout = utils.CRI("PingMsTimeout");
/// <summary>
/// DataOra avvio Programma x check avvio
/// </summary>
protected DateTime prgStarted = DateTime.Now;
/// <summary>
/// Ritardo minimo x invio contapezzi
/// </summary>
protected int pzCountDelay = 2500;
/// <summary>
/// Periodo di campionamento x refresh info
/// </summary>
protected int samplePeriod = 1000;
/// <summary>
/// MsSample Period base x campionamenti tpo OCP-UA
/// </summary>
protected int samplePeriodBase = 600;
/// <summary>
/// Dizionario di VC da trattare come TimeSeries (con conf decodificata + processing successivo...)
/// </summary>
protected Dictionary<string, VCData> TSVC_Data = new Dictionary<string, VCData>();
/// <summary>
/// Indica se usare archivio locale ricette vs scarico http/REST
/// </summary>
protected bool useLocalRecipe = true;
/// <summary>
/// Dizionario di VARIABILI da trattare come eventi (da inviare quando cambiano oppure a
/// scadenza periodo...)
/// </summary>
protected Dictionary<string, EVData> VarArray = new Dictionary<string, EVData>();
/// <summary>
/// Dizionario dei divieti di invio x ogni counter gestito
/// </summary>
protected Dictionary<string, DateTime> VetoCounterSend = new Dictionary<string, DateTime>();
/// <summary>
/// Durata in secondi del divieto accodamento segnali IN alla fase di startup
/// </summary>
protected int vetoQueueIn = 10;
/// <summary>
/// Periodo di veto prima di invio nuova conferma dei valori write correnti, default ogni 5 min
/// </summary>
protected double vetoSendWriteUpsert = 1;
/// <summary>
/// Periodo wathdog di default (2 sec se non specificato)
/// </summary>
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
/// <summary>
/// Decodifica file MAP (caso <paramref name="ByteNum" />.bit)
/// </summary>
/// <param name="linea"></param>
/// <param name="separator"></param>
/// <param name="ByteNum">indirizzo Byte: indirizzo di partenza memoria</param>
/// <param name="memSize">dimensione singolo slot in byte</param>
/// <param name="BitNum">indirizzo bit: numero riga x calcolo indice bit</param>
/// <returns></returns>
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;
}
}
/// <summary>
/// Decodifica file MAP generico
/// </summary>
/// <param name="linea"></param>
/// <param name="separator"></param>
/// <param name="memPre"></param>
/// <param name="baseAddr"></param>
/// <param name="memSize"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 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
};
/// <summary>
/// Oggetto logger della classe
+22 -28
View File
@@ -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<string> alarmMessages = new List<string>();
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<List<AnagArticoli>>(rawListArt);
okArt = listaArt.Count > 0;
listaArt = JsonDeserialize<List<AnagArticoli>>(rawListArt);
okArt = listaArt.Count > 0;
}
catch (Exception exc)
{
@@ -1776,8 +1770,8 @@ namespace IOB_WIN_FORM.Iob
{
try
{
listaDoss = JsonDeserialize<List<DossiersModel>>(rawListDOSS);
okDoss = listaDoss.Count > 0;
listaDoss = JsonDeserialize<List<DossiersModel>>(rawListDOSS);
okDoss = listaDoss.Count > 0;
}
catch (Exception exc)
{
@@ -1792,8 +1786,8 @@ namespace IOB_WIN_FORM.Iob
{
try
{
listaPODL = JsonDeserialize<List<PODLModel>>(rawListPODL);
okPodl = listaPODL.Count > 0;
listaPODL = JsonDeserialize<List<PODLModel>>(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<DossierFluxLogDTO>(selDoss.Valore);
DossierFluxLogDTO resultSet = JsonDeserialize<DossierFluxLogDTO>(selDoss.Valore);
List<FluxLog> listFluxLog = resultSet.ODL;
// preparo elenco parametri da inviare...
@@ -2167,7 +2161,7 @@ namespace IOB_WIN_FORM.Iob
/// <param name="dataItems"></param>
private void sendDataItemsList(List<machDataItem> dataItems)
{
string rawData = JsonSerialize(dataItems);
string rawData = JsonSerialize(dataItems);
HttpService.CallUrlPost($"{urlSaveDataItems}", rawData);
}