Files
Mapo-IOB-WIN/IOB-UT-NEXT/Iob/BaseObj.cs
T
Samuele Locatelli 0fe998a908 Update SIEMENS xComeca
- controllo DynData validi
- controllo update grafico su thread indipendente in lettura memoria
- refresh
2026-01-20 11:19:11 +01:00

649 lines
20 KiB
C#

using IOB_UT_NEXT.Config;
using NLog;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.NetworkInformation;
using System.Threading;
using System.Threading.Tasks;
using static IOB_UT_NEXT.BaseAlarmConf;
namespace IOB_UT_NEXT.Iob
{
/// <summary>
/// Classe di base per IOB
/// </summary>
public class BaseObj
{
#region Public Fields
/// <summary>
/// valore booleano di check se sia stato AVVIATO l'adapter (Running)
/// </summary>
public bool adpRunning = false;
/// <summary>
/// valore booleano di check se l'adapter STIA SALVANDO
/// </summary>
public bool adpSaving = false;
/// <summary>
/// valore booleano (richiesta di riavvio automatico)
/// </summary>
public bool adpTryRestart;
/// <summary>
/// Livello minimo allarmi da considerare x invio
/// </summary>
public AlarmLevel alarmLevelMin = AlarmLevel.Alarm;
/// <summary>
/// Struttura allarmi mappati
/// </summary>
public List<BaseAlarmConf> alarmMaps = new List<BaseAlarmConf>();
/// <summary>
/// Tipo di allarmi gestiti
/// rif: BaseAlarmConf.AlarmBlockType.[Bitmap/ActiveList]
/// </summary>
public AlarmBlockType alarmType = AlarmBlockType.Bitmap;
#if false
/// <summary>
/// Conf adapter corrente
/// </summary>
public IobConfiguration cIobConf;
#endif
/// <summary>
/// Conteggio ATTUALE ore macchina IN LAVORO
/// </summary>
public double contOreMaccLav;
/// <summary>
/// Conteggio ATTUALE ore macchina ON
/// </summary>
public double contOreMaccOn;
/// <summary>
/// contatore x simulazione valori input
/// </summary>
public int countSim = 0;
/// <summary>
/// ODL attualmente sulla macchina
/// </summary>
public Int32 currIdxODL = 0;
/// <summary>
/// Modo corrente (da classe ENUM)
/// </summary>
public CNC_MODE currMode;
/// <summary>
/// ODL corrente caricato sulla macchina (stringa, da chiamata MP/IO)
/// </summary>
public string currODL = "";
/// <summary>
/// Indica se sia richiesto campionamento memoria PERIODICO
/// </summary>
public bool doSampleMemory;
/// <summary>
/// Indica se si debba leggere e fare DUMP delle aree di memoria (1 volta solo all'avvio x debug...)
/// </summary>
public bool doStartMemDump;
/// <summary>
/// Data/ora ultimo avvio adapter
/// </summary>
public DateTime dtAvvioAdp = DateTime.Now;
/// <summary>
/// Data/ora ultimo spegnimento adapter
/// </summary>
public DateTime dtStopAdp = DateTime.Now;
/// <summary>
/// Indicazione VETO check status IOB x evitare loop troppo stretti...
/// </summary>
public DateTime dtVetoCheckIOB = DateTime.Now.AddDays(-1);
/// <summary>
/// Indicazione VETO check sync ricette x evitare loop troppo stretti...
/// </summary>
public DateTime dtVetoCheckSyncRecipe = DateTime.Now.AddHours(-1);
/// <summary>
/// Abilitazione lettura PrgName
/// </summary>
public bool enablePrgName = true;
/// <summary>
/// Abilitazione invio pezzi "in blocco" per recupero contapezzi
/// </summary>
public bool enableSendPzCountBlock = false;
/// <summary>
/// Determina se sia encessario convertire valori little/big endian (SIEMENS=true, OSAI=FALSE)
/// </summary>
public bool hasBigEndian = false;
/// <summary>
/// Configurazione gerarchica completa (v 4.x.x.x)
/// </summary>
public IobConfTree IOBConfFull;
/// <summary>
/// dataOra ultima verifica CNC disconnesso...
/// </summary>
public DateTime lastDisconnCheck;
/// <summary>
/// Data/ora ultima volta che IOB è stato dichiarato online
/// </summary>
public DateTime lastIobOnline = DateTime.Now.AddHours(-1);
/// <summary>
/// dataOra ultimo log periodico...
/// </summary>
public DateTime lastPeriodicLog;
/// <summary>
/// dataOra ultimo PING inviato verso il PLC...
/// </summary>
public DateTime lastPING = DateTime.Now.AddHours(-1);
/// <summary>
/// DataOra ultima lettura da PLC
/// </summary>
public DateTime lastReadPLC;
/// <summary>
/// ULtimo valore inviato (in caso di disconnessione lo reinvia x garantire watchdog...)
/// </summary>
public string lastSignInVal = "";
/// <summary>
/// DateTime Ultimo valore simulazione generato
/// </summary>
public DateTime lastSim;
/// <summary>
/// dataOra ultimo segnale inviato al SERVER...
/// </summary>
public DateTime lastWatchDog;
/// <summary>
/// dataOra ultimo segnale inviato a macchina/PLC...
/// </summary>
public DateTime lastWatchDogPLC = DateTime.Now;
/// <summary>
/// Massimo numero di px da inviare in blocco
/// </summary>
public int maxSendPzCountBlock = 10;
/// <summary>
/// Struttura memoria PLC x lettura/scrittura da JSON file
/// </summary>
public plcMemMapExt memMap;
/// <summary>
/// Minimo numero di px da inviare in blocco
/// </summary>
public int minSendPzCountBlock = 1;
/// <summary>
/// Variabile booleana che indica se sia necessario fare refresh del contapezzi
/// </summary>
public bool needRefreshPzCount = true;
/// <summary>
/// Coda degli esiti di ping x calcolo stato macchina
/// </summary>
public DataQueue QueuePing;
/// <summary>
/// Determina se utilizzare blocchi di memoria IOT contigui (e quindi processing
/// "monoblocco" semplificato"=
/// </summary>
public bool procIotMem = false;
/// <summary>
/// Coda valori ALLARMI ove gestiti...
/// </summary>
public DataQueue QueueAlarm;// = new DataQueue("000", "QueueAlarm", false);
/// <summary>
/// Oggetto della coda degli elementi letti di tipo FluxLog (e non ancora trasmessi)
/// </summary>
public DataQueue QueueFLog;// = new DataQueue("000", "QueueFLog", false);
/// <summary>
/// Oggetto della coda degli elementi letti (e non ancora trasmessi)
/// </summary>
public DataQueue QueueIN;// = new DataQueue("000", "QueueIN", false);
/// <summary>
/// Coda valori MESSAGGI/EVENTI (da non sottocampionare come samples)...
/// </summary>
public DataQueue QueueMessages;// = new DataQueue("000", "QueueMessages", false);
/// <summary>
/// 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);
/// <summary>
/// Coda valori LOG UTENTE (da non sottocampionare come samples)...
/// </summary>
public DataQueue QueueULog;// = new DataQueue("000", "QueueULog", false);
/// <summary>
/// alias booleano false = R
/// </summary>
public bool R = false;
/// <summary>
/// 32 byte input base (es strobe, 8 word da 32 bit di flags...)
/// </summary>
public byte[] RawInput = new byte[32];
/// <summary>
/// 32 byte output base (es ack, 8 word da 32 bit di flags...)
/// </summary>
public byte[] RawOutput = new byte[32];
/// <summary>
/// Oggetto connessione REDIS
/// </summary>
public RedisIobCache redisMan;
/// <summary>
/// Oggetto cronometro x campionamento durate chiamate
/// </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>
public DateTime vetoDataRead = DateTime.Now;
/// <summary>
/// Imposta veto SYNC dati (es per DB 2 DB a 10 sec)
/// </summary>
public DateTime vetoDataSync = DateTime.Now;
/// <summary>
/// Veto (in sec) a nuovi ping (x IOB PING, FTP...)
/// </summary>
public int vetoPingSec = 1;
/// <summary>
/// Imposta veto chiamata split (durante chiamata, per 60 sec)
/// </summary>
public DateTime vetoSplit = DateTime.Now.AddMinutes(1);
/// <summary>
/// alias booleano true = W
/// </summary>
public bool W = true;
#endregion Public Fields
#region Public Properties
/// <summary>
/// Verifica se sia in modalità DEMO avanzata (campionamento da set di valori ammessi...)
/// </summary>
public static bool DemoInSample
{
get
{
return baseUtils.CRB("DemoInSample");
}
}
/// <summary>
/// Verifica se sia in modalità DEMO x dati OUTPUT
/// </summary>
public static bool DemoOut
{
get
{
return utils.CRB("DemoOut");
}
}
/// <summary>
/// Indicazione VETO PING a server sino alla data-ora indicata
/// </summary>
public static DateTime dtVetoPing
{
get
{
return utils.dtVetoPing;
}
set
{
utils.dtVetoPing = value;
}
}
/// <summary>
/// Indicazione VETO accodamento valori INGRESSI/EVENTI sino alla data-ora indicata
/// </summary>
public static DateTime dtVetoQueueIN
{
get
{
return utils.dtVetoQueueIN;
}
set
{
utils.dtVetoQueueIN = value;
}
}
/// <summary>
/// Indicazione VETO invio a server sino alla data-ora indicata
/// </summary>
public static DateTime dtVetoSend
{
get
{
return utils.dtVetoSend;
}
set
{
utils.dtVetoSend = value;
}
}
/// <summary>
/// Verifica se sia abilitato test lettura blocchi memoria all'avvio
/// </summary>
public static bool EnableTest
{
get
{
return baseUtils.CRB("enableTest");
}
}
/// <summary>
/// stato Online/Offline del server MP IO (su REDIS)
/// </summary>
public static bool MPOnline
{
get
{
return utils.MPIO_Online;
}
set
{
utils.MPIO_Online = value;
}
}
#endregion Public Properties
#region Public Methods
/// <summary>
/// Effettua chiamata URL e restituisce risultato
/// </summary>
/// <param name="URL"></param>
/// <param name="doAsync">invio in modalità async (NON GARANTITO ordine...)</param>
/// <returns></returns>
public static async Task<string> callUrl(string URL, bool doAsync)
{
string answ = "";
if (doAsync)
{
answ = await utils.callUrlAsync(URL);
}
else
{
answ = await Task.Run(() => utils.callUrl(URL));
}
if (urlRandWait > 0)
{
// NON blocca il thread, libera risorse per le altre 20 istanze
await Task.Delay(rnd.Next(urlRandWait / 10, urlRandWait));
}
return answ;
}
/// <summary>
/// Effettua chiamata URL e restituisce risultato
/// </summary>
/// <param name="URL"></param>
/// <param name="payload"></param>
/// <param name="doAsync">invio in modalità async (NON GARANTITO ordine...)</param>
/// <returns></returns>
public static async Task<string> callUrlWithPayloadAsync(string URL, string payload, bool doAsync)
{
string answ = "";
if (doAsync)
{
answ = await utils.callUrlAsync(URL, payload);
}
else
{
answ = await Task.Run(() => utils.callUrl(URL, payload));
}
if (urlRandWait > 0)
{
// NON blocca il thread, libera risorse per le altre 20 istanze
await Task.Delay(rnd.Next(urlRandWait / 10, urlRandWait));
}
return answ;
}
/// <summary>
/// processa dataLayer e se necessario salva/mostra
/// </summary>
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()
{
}
/// <summary>
/// Reset dei webclients
/// </summary>
public static void resetWebClients()
{
utils.resetWebClients();
}
#endregion Public Methods
#region Protected Fields
/// <summary>
/// Valore di attesa (random) dopo ogni invio x evitare congestione send...
/// </summary>
protected static int urlRandWait = 0;
/// <summary>
/// Disabilitazione gestione ODL (lettura e gestione)
/// </summary>
protected bool disableOdl = false;
//protected static Logger lg = LogManager.GetCurrentClassLogger();
/// <summary>
/// Abilitazione invio conf macchine
/// </summary>
protected bool enabSendMachineConf = true;
/// <summary>
/// Ultimo LOG registrazione avvio (x ridurre log notturni...)
/// </summary>
protected DateTime lastLogStartup = DateTime.Today.AddHours(-1);
/// <summary>
/// Dimensione coda di ping x valutazione
/// </summary>
protected int maxQueuePing = 11;
/// <summary>
/// Tempo minimo ammissibile di risposta (es x errori ModBus che risponde troppo in fretta) in millisec
/// </summary>
protected int minRespTimeMs = 5;
/// <summary>
/// Indica se resettare allarmi all'avvio e inviare il reset appena parte adapter
/// </summary>
protected bool resetAlarmOnStart = false;
/// <summary>
/// Veto per registrazione completa log di startup (minuti)
/// </summary>
protected int vetoLogStartupDuration = 60;
#endregion Protected Fields
#region Protected Properties
/// <summary>
/// Dizionario condizioni di veto log x ogni tipo di messaggio (periodo differente secondo livello)
/// </summary>
protected Dictionary<string, DateTime> VetoLog { get; set; } = new Dictionary<string, DateTime>();
/// <summary>
/// Dizionario conteggio numero volte che si fa veto log x ogni tipo di messaggio
/// </summary>
protected Dictionary<string, int> VetoLogCount { get; set; } = new Dictionary<string, int>();
#endregion Protected Properties
#region Protected Methods
/// <summary>
/// Verifica se ci sia veto log attivo e gestisce casistiche
/// </summary>
/// <param name="vetoSec"></param>
/// <param name="message"></param>
/// <returns></returns>
protected bool checkLogVeto(int vetoSec, ref string message)
{
// verifico SE si debba fare log, altrimenti metto in coda...
bool doVeto = true;
try
{
DateTime adesso = DateTime.Now;
if (VetoLog.ContainsKey(message))
{
// conteggio num veto a +1...
if (VetoLogCount.ContainsKey(message))
{
VetoLogCount[message]++;
}
else
{
VetoLogCount.Add(message, 1);
}
// controllo scadenza, quando superata soglia aggiorno messaggio con {n} x {messaggio}
if (adesso.Subtract(VetoLog[message]).TotalSeconds > vetoSec)
{
doVeto = false;
string newMessage = $"{VetoLogCount[message]} x {message}";
VetoLog.Remove(message);
VetoLogCount.Remove(message);
message = newMessage;
}
}
else
{
// primo --> loggo
doVeto = false;
VetoLog.Add(message, adesso.AddSeconds(vetoSec));
if (VetoLogCount.ContainsKey(message))
{
VetoLogCount[message]++;
}
else
{
VetoLogCount.Add(message, 0);
}
}
}
catch (Exception exc)
{
lg.Error($"Eccezione in checkLogVeto: reset contatori VetoLog/VetoLogCount | message: {message}");
lg.Error($"Raised Exc:{Environment.NewLine}{exc}");
doVeto = false;
// svuoto tutti i log veto...
VetoLog = new Dictionary<string, DateTime>();
VetoLogCount = new Dictionary<string, int>();
lg.Error($"Effettuato reset contatori VetoLog/VetoLogCount");
}
// restituisco esito!
return doVeto;
}
/// <summary>
/// Setup di tutti gli oggetti Queue, ma solo alcuni hanno coda REDIS (quelli senza sono "sacrificabili"
/// </summary>
protected void SetupQueue()
{
string codIob = IOBConfFull.General.FilenameIOB;
bool useRedis = IOBConfFull.General.EnabRedisQue;
QueueAlarm = new DataQueue(codIob, "QueueAlarm", false, redisMan);
// valutare se portare di nuovo in redis...
QueueIN = new DataQueue(codIob, "QueueIN", useRedis, redisMan);
// fix a NON redis
QueueFLog = new DataQueue(codIob, "QueueFLog", false, redisMan);
//QueueFLog = new DataQueue(codIob, "QueueFLog", useRedis, redisMan);
QueueMessages = new DataQueue(codIob, "QueueMessages", false, redisMan);
QueueRawTransf = new DataQueue(codIob, "QueueRawTransf", false, redisMan);
QueueULog = new DataQueue(codIob, "QueueULog", false, redisMan);
QueuePing = new DataQueue(codIob, "QueuePing", false, redisMan);
}
#endregion Protected Methods
#region Private Fields
/// <summary>
/// wrapper di log
/// </summary>
private static readonly Logger lg = LogManager.GetCurrentClassLogger();
private static Random rnd = new Random();
#endregion Private Fields
}
}