using MapoSDK; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using System.Collections.Generic; namespace IOB_UT_NEXT { /// /// Classe gestione configurazione parametri di base x allarmi /// public class BaseAlarmConf { #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) /// public int blinkDownVal { get; set; } = 4; /// /// valore di partenza x un segnale di blink in caso di inizio variazione (fronte salita) /// public int blinkUpVal { get; set; } = 3; /// /// Descrizione area allarmi /// public string description { get; set; } = ""; /// /// Indice nell'area di memoria (da valore iniziale = 0) /// public int index { get; set; } = 0; /// /// Nome "assoluto" della posizione nell'area di memoria (anche diverso da indice) /// public string memAddr { get; set; } = ""; /// /// Elenco allarmi configurati x la bitmap /// public List messages { get; set; } = new List(); /// /// Size in byte /// public int size { get; set; } = 0; /// /// Tipo di dato /// [JsonConverter(typeof(StringEnumConverter))] public plcDataType tipoMem { get; set; } = plcDataType.Boolean; /// /// Tipo del blocco allarmi configurato /// [JsonConverter(typeof(StringEnumConverter))] public AlarmBlockType blockType { get; set; } = AlarmBlockType.Bitmap; /// /// Livello del blocco memoria /// [JsonConverter(typeof(StringEnumConverter))] public AlarmLevel blockLevel { get; set; } = AlarmLevel.Alarm; /// /// Elenco KEY codici allarme attivabili /// public List activeKeys { get; set; } = new List(); /// /// Elenco VALUE codici allarme attivabili /// public List activeValues { get; set; } = new List(); #endregion Public Properties #region Public Methods /// /// Calcola il filtro da condizione blink (ovvero maschera per valori indicati blinking) /// /// /// public uint blinkFilter(int num) { uint answ = 0; int idx = 16 * num; for (int i = 0; i < 16; i++) { if (alarmsBlinkCounter[idx + i] > 0) { answ += (uint)1 << i; } } return answ; } /// /// Effettua update dei contatori blink per gestire i segnali alternati sul fronte di salita/discesa /// /// /// public void checkBlinkCounter(int num, uint newStatus) { // calcola la maschera di variazione da valore precedente var variations = newStatus ^ alarmsState[num]; // ciclo sui 16 bit... for (int i = 0; i < 16; i++) { // controllo se è variato if ((variations & (1 << i)) == (1 << i)) { // se il valore nuovo è 1 --> è in fronte salita if ((newStatus & (1 << i)) == (1 << i)) { // cambio SOLO SE il valore blink è zero... if (alarmsBlinkCounter[num * 16 + i] == 0) { alarmsBlinkCounter[num * 16 + i] = blinkUpVal; } } // altrimenti se è fronte discesa else { // cambio SOLO SE il valore blink è zero... if (alarmsBlinkCounter[num * 16 + i] == 0) { alarmsBlinkCounter[num * 16 + i] = blinkDownVal; } } } } // decremento contatori blink int idx = 0; foreach (var item in alarmsBlinkCounter) { alarmsBlinkCounter[idx] = item > 0 ? item - 1 : item; idx++; } } /// /// Confronta un valore di stato allarme con lo stato precedentemente salvato considerando blink/veto /// /// Numero/indice del banco di allarme (uint16) /// Valore (bitmap) allarmi come uint16 /// public bool isChanged(int num, uint newValue) { // per prima cosa controllo valori RAW bool answ = !alarmsState[num].Equals(newValue); if (answ) { // controllo valori filtrati con ## (sottraendo BITMASK dai valori di filtro) answ = ((alarmsState[num] & alarmsMask[num]) != (newValue & alarmsMask[num])); // se fossero ancora differenti controllo ulteriore mask dato il counter dei blink: if (answ) { var blinkFilt = blinkFilter(num); answ = ((alarmsState[num] & (alarmsMask[num] & ~blinkFilt)) != (newValue & (alarmsMask[num] & ~blinkFilt))); //answ = ((alarmsState[num] & (alarmsMask[num] | blinkFilt)) != (newValue & (alarmsMask[num] | blinkFilt))); } } return answ; } /// /// Inizializzazione classe con valori calcolati: attenzione si aspetta banchi da 32 bit... /// ATTENZIONE: eseguita solo se blockType == bitmap /// public void setupData() { // verifico si tratti di un tipo allarmi a bitmap... altrimenti salto if (blockType == AlarmBlockType.Bitmap) { // inizializzo vettore valore allarmi x banco int8 x iniziare alarmsState = new uint[size]; alarmsMask = new uint[size]; int bitSize = 8; // 16/32 bit if (size > 1) { // inizializzo vettore valore allarmi x banco int16 alarmsState = new uint[size / 2]; alarmsMask = new uint[size / 2]; bitSize = 16; } // una volta inizializzata la classe di base sistemo vettori allarmi disabilitati ed il // contatore blink dei fronti di discesa alarmsBlinkCounter = new int[messages.Count]; //verifico i contatori di blink da eventuale conf... int idx = 0; int bank = 0; foreach (var item in messages) { if (item.StartsWith("##")) { alarmsBlinkCounter[idx] = -999; } else { alarmsBlinkCounter[idx] = 1; alarmsMask[bank] += (uint)1 << idx; } idx++; // sistemo bank/indice if (idx > bitSize - 1) { bank++; idx = 0; } } } } /// /// Effettua il caricamento dello status da un valore precedente (es da cache REDIS) /// ATTENZIONE: eseguita solo se blockType == bitmap e size corrisponde a quella della mem allarmi /// /// public void loadPrev(uint[] lastState) { // verifico si tratti di un tipo allarmi a bitmap... altrimenti salto if (blockType == AlarmBlockType.Bitmap) { if (lastState.Length == alarmsState.Length) { alarmsState = lastState; } } } /// /// Imposta il valore dello status attuale allarme impostando eventuale valore blink x le variazioni /// /// /// public void updStatusVal(int num, uint newStatus) { // salvo nuovo valore alarmsState[num] = newStatus; } /// /// Tipologia del blocco allarmi configurato /// public enum AlarmBlockType { /// /// Modalità standard a bitmap /// Bitmap, /// /// Modalità elenco dei valori attivi (es OPC-UA BLM/Adige) /// ActiveList } /// /// Livello Allarme /// public enum AlarmLevel { /// /// Messaggio (non bloccante) /// Message = 0, /// /// Avviso (non bloccante) /// Warning = 100, /// /// Allarme (bloccante) /// Alarm = 200, /// /// Allarme di massimo livello /// Emergency = 300 } #endregion Public Methods } /// /// Classe gestione configurazione parametri di base x configurazione estesa (es MTConnect, /// OPC-UA, ...) /// public class BaseParamConf { #region Public Properties /// /// Struttura dati x check condizione LAVORA / Green /// public List condWork { get; set; } = new List(); /// /// Struttura dati x check condizione Manual /// public diCheckCondSetup condManual { get; set; } = new diCheckCondSetup(); /// /// Struttura dati x check condizione EXTRA di controllo x singoli BIT /// public Dictionary bitSpecCond { get; set; } = new Dictionary(); /// /// 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), ricerca SECCA /// public List fluxLogVeto { get; set; } = new List(); /// /// Elenco items FILTRATI da invio come dynData --> FluxLog (events o samples), ricerca testo come contains in displayName /// public List fluxLogVetoContains { get; set; } = new List(); /// /// Indica se il controllo di ping sia OK (x controllo prima della connessione) /// public bool forcePingOk { get; set; } = false; /// /// Array degli elementi di traduzione item /// public Dictionary itemTranslation { get; set; } = new Dictionary(); /// /// Indica se decodificare valori dall'area mMapRead da valori byte[] delle variabili sottoscritte /// public bool mMapReadFromRawByte { get; set; } = false; /// /// Indica se decodificare valori dall'area mMapWrite da valori byte[] delle variabili sottoscritte /// public bool mMapWriteFromRawByte { get; set; } = false; /// /// Indica se inviare i dati sottoscritti che sono "raw" o meno... /// public bool sendSubscribItemsRaw { get; set; } = true; /// /// Separatore configurazione area OPC e subObj in caso di memorie struct speciali /// public char kvDelim { get; set; } = '#'; /// /// Separatore definizione aree memoria speciali /// public char memDelim { get; set; } = '.'; /// /// Nome variabile x EmergencyStop /// public string keyEStop { get; set; } = ""; /// /// Nome variabile x ExeMode /// public string keyExeMode { get; set; } = ""; /// /// Nome variabile x pezzi FATTI /// public string keyPartCount { get; set; } = ""; #if true /// /// Indica se sia una macchina MULTI (con varie Tavole/Pallet) /// public bool isMulti { get; set; } = false; /// /// Dizionario variabili x pezzi FATTI se multi tavola /// public Dictionary keyPartCountTav { get; set; } = null; #endif /// /// Nome variabile x Codice Articolo /// public string keyPartId { get; set; } = ""; /// /// Nome variabile x pezzi RICHIESTI /// public string keyPartReq { get; set; } = ""; /// /// Nome variabile x NOME PROGRAMMA /// public string keyProgName { get; set; } = ""; /// /// Nome variabile x RunMode /// public string keyRunMode { get; set; } = ""; /// /// Aree di memoria lettura /// public Dictionary mMapRead { get; set; } = new Dictionary(); /// /// Aree di memoria scrittura /// public Dictionary mMapWrite { get; set; } = new Dictionary(); /// /// Dictionary dei nomi da cercare come "endsWith" a cui applicare la soglia indicata /// public Dictionary paramsEndThresh { get; set; } = new Dictionary(); /// /// Dictionary dei nomi da cercare come "contains" a cui applicare la soglia indicata /// public Dictionary paramsContainsThresh { get; set; } = new Dictionary(); /// /// Indica se il ping sia un criterio valido x determinare powerON impianto /// public bool pingAsPowerOn { get; set; } = true; /// /// Indica se venga richiesta invio del run mode /// public bool runModeSend { get; set; } = false; /// /// Indica se venga richiesta traduzione del run mode /// public bool runModeTrad { get; set; } = false; /// /// Lista ulteriori configurazioni KeyValuePair /// public Dictionary optKVP { get; set; } = new Dictionary(); #endregion Public Properties } /// /// Oggetto x processing valori (elenco valori e modalità) /// public class calcConf { #region Public Properties public calcMode calcMode { get; set; } = calcMode.None; public List listVal { get; set; } = new List(); #endregion Public Properties } /// /// Classe per rappresentare oggetti chiave/valore target x controlo condizioni multiple /// public class diCheckCondition { #region Public Properties /// /// Nome variabile /// public string keyName { get; set; } = ""; /// /// Se >=0 indica ordine bit x decodifica di byte[] raw /// public int bitNum { get; set; } = -1; /// /// valore target per esito richiesto /// public string targetValue { get; set; } = ""; #endregion Public Properties } /// /// Classe per rappresentare una lista di oggetti chiave/valore target x controlo condizioni /// multiple + indicazione modalità di controllo (AND/OR/...) /// public class diCheckCondSetup { #region Public Properties /// /// Elenco condizioni /// public List checkList { get; set; } = new List(); /// /// Modalità verifica condizioni /// 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) /// 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 /// public List writeParAction { get; set; } = new List(); #endregion Public Properties } /// /// COnfigurazione blocchi x accesso memoria ottimizzato /// public class MemBlockConf { #region Public Properties public Dictionary ReadBlocks { get; set; } = new Dictionary(); #endregion Public Properties } /// /// Classe gestione configurazione parametri specifici MTC da BaseParamConf /// public class MtcParamConf : BaseParamConf { #region Public Properties /// /// Struttura dati x check condizione PowerOn /// public diCheckCondition condPowerOn { get; set; } = new diCheckCondition(); /// /// Intervallo standard x SAMPLE data in ms /// public int clientSampleIntMs { get; set; } = 500; /// /// Timeout standard x richieste in ms /// public int reqTOutMs { get; set; } = 1500; /// /// Intervallo riconnessione standard in caso di mancanza risposta in ms /// public int reconnectIntMs { get; set; } = 1500; /// /// Indica se usare il metodo di sottoscrizione alle variazioni in modalità observations /// public bool doSubsObserv { get; set; } = false; /// /// Indica se usare il metodo di sottoscrizione alle variazioni sample /// public bool doSubsSample { get; set; } = true; #endregion Public Properties } /// /// Parametri speciali configurazione ModBusTCP /// public class ModBusTcpParamConf { #region Public Fields /// /// Indirizzo di base degli Holding Register /// public int holdRegBaseAddr { get; set; } = 40001; /// /// Indirizzo IP del PLC /// public string ipAdrr { get; set; } = "127.0.0.1"; /// /// Base area x lettura /// public string memAddrRead { get; set; } = "40001"; /// /// Base area x scrittura /// public string memAddrWrite { get; set; } = "41001"; /// /// Size memoria lettura /// public int memSizeRead { get; set; } = 0; /// /// Size memoria scrittura /// public int memSizeWrite { get; set; } = 0; /// /// Timeout ping /// public int pingMsTimeout { get; set; } = 500; /// /// Porta di comunicazione /// public int port { get; set; } = 502; /// /// Indica se usare baseAddress calcolati o da config /// public bool useCalcBaseAddr { get; set; } = true; /// /// Delta valore lettura base MBus /// public int deltaBase { get; set; } = 0; /// /// Indice della LUT corrente /// public int indexLutCorr { get; set; } = 0; /// /// Gestione opzionale memoria estesa: non 0...10'000 ma 0...xFFFF=65536 /// public bool modbusExtReg { get; set; } = false; #endregion Public Fields } /// /// Classe gestione configurazione parametri specifici OPC-UA da BaseParamConf /// public class OpcUaParamConf : BaseParamConf { #region Public Properties /// /// Elenco Variabili (e valori da impostare) x indicare di resettare contatore lotto e /// quindi riavviare produzione (es: impostando valore a 1...) /// public Dictionary actResetCounter { get; set; } = new Dictionary(); /// /// Elenco Variabili (e valori da impostare) x indicare di effettuare impostazione nuovo /// programma/ricetta (es: impostando valore a 1...) /// public Dictionary actSetRecipe { get; set; } = new Dictionary(); /// /// Elenco Variabili (e valori da impostare) x indicare di fermare la produzione (es: /// impostando valore a 1...) /// public Dictionary actStopProd { get; set; } = new Dictionary(); /// /// Identificativo nodo iniziale /// public string BrowseFullVal { get; set; } = "ns=2;s=Scalar_Static"; /// /// Elenco di nodi da sottoscrivere direttamente al posto dell'albero derivante dal BrowseFullVal /// public List BrowseNodeList { get; set; } = new List(); /// /// Indice NS da cui fare il browse dei file /// public ushort BrowseNSIndex { get; set; } = 4; /// /// ID del nodo da cui partire x il browse di identificazione nodi iniziale /// public uint BrowseValue { get; set; } = 5001; /// /// Lista valori calcolati/derivati da processare /// public Dictionary calcValues { get; set; } = new Dictionary(); /// /// Numero minimo di secondi di durata di uno status /// public int minSecStatusDuration { get; set; } = 1; /// /// Numero minimo di secondi di attesa finale (es prima di chiedere chiusura ODL) /// public int minSecFinalWait { get; set; } = 30; /// /// Struttura dati x check condizione Contapezzi Abilitato (se vuoto = sempre abilitato) /// public diCheckCondSetup condCountEnabled { get; set; } = new diCheckCondSetup(); /// /// Struttura dati x check condizione Errore /// public diCheckCondSetup condError { get; set; } = new diCheckCondSetup(); /// /// Struttura dati x check condizione Emergenza /// public diCheckCondSetup condEStop { get; set; } = new diCheckCondSetup(); /// /// Struttura dati x check condizione PowerOn /// public diCheckCondSetup condPowerOn { get; set; } = new diCheckCondSetup(); /// /// Struttura dati x check condizione READY /// 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 Tavola 1 attiva /// public diCheckCondSetup condActTav1 { get; set; } = new diCheckCondSetup(); /// /// Struttura dati x check condizione Tavola 2 attiva /// public diCheckCondSetup condActTav2 { get; set; } = new diCheckCondSetup(); /// /// Struttura dati x check condizione WarmUp - CoolDown /// public diCheckCondSetup condWarmUpCoolDown { get; set; } = new diCheckCondSetup(); /// /// Struttura dati x check condizione Warning /// public diCheckCondSetup condWarning { get; set; } = new diCheckCondSetup(); /// /// Struttura dati x check condizione Errore /// 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(); /// /// Elenco item flux da FILTRARE per chiave tradotta/VALORE /// es: Cimolai / Baglietto, RunModeVal NON VOGLIO inviare quando il valore è 0 /// public Dictionary> fluxLogKeyValVeto { get; set; } = new Dictionary>(); public UserIdent Identity { get; set; } = new UserIdent(); /// /// Aree di memoria lettura /// public new Dictionary mMapRead { get; set; } = new Dictionary(); /// /// Aree di memoria scrittura /// public new Dictionary mMapWrite { get; set; } = new Dictionary(); /// /// Elenco item RAW sottoscritti e relative configurazioni di decodifica da byte[] /// public Dictionary rawSubscribedItemsConf { get; set; } = new Dictionary(); /// /// Conf gestione setup macchina /// public MachineSetupConf SetupConf { get; set; } = new MachineSetupConf(); /// /// 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(); /// /// Indica che si utilizza (per LUT e gestione conf) il NodeId completo, default false (solo il DisplayName) /// public bool UseFullId { get; set; } = false; /// /// Numero massimo di letture null prima di disconnettere il client /// public int maxNullRead { get; set; } = 1000; /// /// Base del namespace da mascherare in invio OPC /// public string BaseIdMask { get; set; } = ""; /// /// Abilita la gestione dei popup x inviare /// public bool EnablePopup { get; set; } = false; public Dictionary DictOpcNameReplace { get; set; } = new Dictionary(); #endregion Public Properties } /// /// Classe gestione configurazione parametri specifici Rest Client da BaseParamConf /// public class RestParamConf : BaseParamConf { /// /// Timeout chiamate REST /// public int timeOutSec { get; set; } = 60; /// /// API di base x chiamate REST, eventuali variabili van indicate come [[nomevar]] /// public string apiUrl { get; set; } = ""; /// /// Periodo minimo di campionamento in ms x lettura dati frequenti stato/semafori... /// public int samplePeriod { get; set; } = 1000; /// /// Numero di errori dopo cui fare una vera disconnesisone con report poweroff della macchina /// public int connErrorMax { get; set; } = 5; /// /// Elenco delle chiamate x ID / struttura /// public Dictionary CallList { get; set; } = new Dictionary(); public class CallStruc { /// /// ID univoco chiamata per poterla recuperare /// public int Idx { get; set; } = 0; /// /// Metodo chiamata /// public RestSharp.Method Method { get; set; } = RestSharp.Method.Get; /// /// Url chiamata /// public string Url { get; set; } = ""; /// /// Nome x invio a MES /// public string Name { get; set; } = ""; /// /// Nome x salvataggio valore output in ProdData da poter richiamare /// public string OutVarName { get; set; } = ""; /// /// Intervallo di campionamento (minimo) da rispettare x evitare flood chiamate /// public int SamplePeriod { get; set; } = 5000; /// /// Elenco chiamate richieste se non fosse trovata/valida una variabile /// public List ListPrevCall { get; set; } = new List(); } } public class UserIdent { #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 } }