using IOB_UT_NEXT; using MapoSDK; using MTConnect.Clients; using Newtonsoft.Json; using System; using System.Threading.Tasks; using Opc.Ua; using Opc.Ua.Configuration; using System.Collections.Generic; using System.IO; using System.Net.NetworkInformation; using System.Threading; using System.Windows.Forms; using System.Linq; namespace IOB_WIN_NEXT { public class IobOpcUa : IobGeneric { #region Private Fields /// /// Struttura dove vengono memorizzati i dataitem ed i rispettivi valori x processing /// private Dictionary dataItemMem = new Dictionary(); /// /// Elenco degli items da monitorare come risultato del browse iniziale /// private Dictionary selectedItemList = new Dictionary(); #endregion Private Fields #region Protected Fields /// /// Abilitazione restart (da opt par...) /// protected bool enableCliRestart = false; /// /// Gestione filtraggio dati /// protected bool enableDataFilter = false; /// /// Determina se ha effettuata lettura items in memoria x confronto... /// protected bool hasReadItems = false; /// /// Ultimo current received x gestione update periodico... /// protected DateTime lastCurrent = DateTime.Now; /// /// Variabile numero errori controllo --> se supera soglia 20 --> disconnette /// protected int numErroriCheck = 0; /// /// Oggetto MAIN x connessione MTC /// protected UAClient UA_ref; /// /// Veto controllo status x log... /// protected DateTime vetoCheckStatus = DateTime.Now; #endregion Protected Fields #region Public Constructors /// /// Estende l'init della classe base, impiegando il pacchetto Nuget OPC-UA foundation /// https://github.com/OPCFoundation/UA-.NETStandard /// /// /// public IobOpcUa(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf) { // gestione invio ritardato contapezzi pzCountDelay = utils.CRI("pzCountDelay"); // gestione data filtering... if (!string.IsNullOrEmpty(getOptPar("ENABLE_DATA_FILTER"))) { bool.TryParse(getOptPar("ENABLE_DATA_FILTER"), out enableDataFilter); } // gestione restart OpcUa client... if (!string.IsNullOrEmpty(getOptPar("ENABLE_CLI_RESTART"))) { bool.TryParse(getOptPar("ENABLE_CLI_RESTART"), out enableCliRestart); } // init datetime counters DateTime adesso = DateTime.Now; lastPzCountSend = adesso; lastWarnODL = adesso; lastCurrent = adesso; // ora leggo il file di conf specifico.... string jsonFileName = getOptPar("OPC_PARAM_CONF"); if (!string.IsNullOrEmpty(jsonFileName)) { // leggo il file... loadOpcUaConf(jsonFileName); } } #endregion Public Constructors #region Protected Properties /// /// Verifico se abbia ALMENO un errore... /// protected bool hasError { get { return checkMultiCondition(opcUaParams.condError.checkList, opcUaParams.condError.checkMode); } } /// /// Indica se abbia emergenza ARMATA (cond normale) /// protected bool hasEStopArmed { get { return checkMultiCondition(opcUaParams.condEStop.checkList, opcUaParams.condError.checkMode); } } /// /// Indica se abbia stato POWER ON (multicondizione) /// protected bool hasPowerOn { get { return checkMultiCondition(opcUaParams.condPowerOn.checkList, opcUaParams.condPowerOn.checkMode); } } /// /// Indica se abbia stato MANUAL (condizioni varie, es stopped) /// protected bool isManual { get { return checkMultiCondition(opcUaParams.condManual.checkList, opcUaParams.condManual.checkMode); } } /// /// Indica se abbia stato READY (condizioni varie, es ausiliari OK) /// protected bool isReady { get { return checkMultiCondition(opcUaParams.condReady.checkList, opcUaParams.condReady.checkMode); } } /// /// Indica se sia in stato WarmUp / CoolDown (riscaldamento/raffreddamento) /// protected bool isWarmUpCoolDown { get { return checkMultiCondition(opcUaParams.condWarmUpCoolDown.checkList, opcUaParams.condWarmUpCoolDown.checkMode); } } /// /// Indica se sia in stato Warning /// protected bool isWarning { get { return checkMultiCondition(opcUaParams.condWarning.checkList, opcUaParams.condWarning.checkMode); } } /// /// Indica se sia in stato Ssetup /// protected bool isSetup { get { return checkMultiCondition(opcUaParams.condSetup.checkList, opcUaParams.condSetup.checkMode); } } /// /// Indica se abbia stato READY (condizioni varie, es ausiliari OK) /// protected bool isWorking { get { return checkMultiCondition(opcUaParams.condWork, boolCheckMode.AND); } } /// /// Parametri specifici MTC /// protected OpcUaParamConf opcUaParams { get; set; } /// /// URL x salvataggio elenco dataItems OpcUa /// protected string urlSaveDataItems { get { string answ = ""; try { string machineName = Environment.MachineName; answ = $@"{cIobConf.serverData.TRANSP}://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDALIVE}/saveDataItems/{cIobConf.codIOB}"; } catch (Exception exc) { lgError(exc, "Errore in composizione urlSaveDataItems"); } return answ; } } #endregion Protected Properties #region Private Methods /// /// Verifica ed invia variazioni /// /// /// /// private void checkAndSend(Opc.Ua.Client.MonitoredItem MonIt, string NotifyValue, bool forceSend) { if (MonIt != null) { if (!string.IsNullOrEmpty(NotifyValue)) { string sVal = ""; string descr = ""; DateTime locTStamp = DateTime.Now; descr = itemTranslation("OPC", MonIt.DisplayName); sVal = $"Change: {locTStamp.ToString()} | descr: {descr} | Id: {MonIt.StartNodeId} | | Val: {NotifyValue}"; if (isVerboseLog) { lgInfo(sVal); } // verifico se salvare bool changed = checkSaveValue(MonIt, NotifyValue); // cerco se non sia un dato filtrato in FLUXLOG... bool isFiltered = opcUaParams.fluxLogVeto.Contains(MonIt.DisplayName); if (isFiltered) { if (isVerboseLog) { lgInfo($"NON ACCODATO sample per {MonIt.DisplayName} poiché trovato VETO in fluxLogVeto", false); } } else { if (changed || forceSend) { accodaFLog(sVal, qEncodeFLog(descr, $"{NotifyValue}")); } else { if (isVerboseLog) { lgInfo($"NON ACCODATO sample per {MonIt.DisplayName} poiché verifica variazione ha dato esito negativo", false); } } } } else { lgError($"checkAndSend ERROR | MonIt: {MonIt.DisplayName} | NotifyValue Null!!!"); } } else { lgError("checkAndSend ERROR: MonIt null"); } } /// /// Vera connessione ad OpcUa /// /// private async Task doConnect() { IOutput console = new ConsoleOutput(); short esitoLink = 0; // reset memoria dataItem.. dataItemMem = new Dictionary(); // predisposizione conf oggetto di comunicazione MTC int port = 4840; int.TryParse(cIobConf.cncPort, out port); // ora avvio try { lgInfo("Start init OpcUa Client"); // Define the UA Client application ApplicationInstance application = new ApplicationInstance(); application.ApplicationName = "Steamware IOB-WIN Client"; application.ApplicationType = ApplicationType.Client; // load the application configuration. string confPath = $"{Application.StartupPath}\\DATA\\CONF\\IobOpcUaClient.Config.xml"; await application.LoadApplicationConfiguration(confPath, silent: false).ConfigureAwait(false); // check the application certificate. await application.CheckApplicationInstanceCertificate(silent: false, minimumKeySize: 0).ConfigureAwait(false); lgInfo($"Chiamata UAClient con configurazione standard: {application.ApplicationConfiguration.ApplicationName}"); UA_ref = new UAClient(application.ApplicationConfiguration, console, ClientBase.ValidateResponse); lgInfo($"Chiamata apertura OpcUa Client: {cIobConf.cncIpAddr}:{port}"); UA_ref.ServerUrl = $"opc.tcp://{cIobConf.cncIpAddr}:{port}"; var task = Task.Run(async () => { return await UA_ref.ConnectAsync().ConfigureAwait(false); }); bool connected = task.Result; if (connected) { // faccio un primo browse dei dati... Dictionary nodeIdNameList = new Dictionary(); if (!string.IsNullOrEmpty(opcUaParams.BrowseFullVal)) { UA_ref.Browse(opcUaParams.BrowseFullVal, opcUaParams.filterItemsNodeId, ref nodeIdNameList); } else { UA_ref.Browse(opcUaParams.BrowseNSIndex, opcUaParams.BrowseValue, opcUaParams.filterItemsNodeId, ref nodeIdNameList); } // loggo elenco degli item sottocrivibili... lgInfo("---------- AVAILABLE FOR SUBSCRIBE ----------"); foreach (var item in nodeIdNameList) { lgInfo(item.Key); } lgInfo("---------- END LIST ----------"); // se ho un insieme non vuoto degli item sottoscritti carico solo quelli if (opcUaParams.subscribedItems != null && opcUaParams.subscribedItems.Count > 0) { // cerco e aggiungo SOLO quelle indicati foreach (var currItem in opcUaParams.subscribedItems) { var foundItems = nodeIdNameList.Where(x => x.Key.Contains(currItem)).ToList(); if (foundItems != null && foundItems.Count > 0) { foreach (var fItem in foundItems) { // verifico di NON duplicare... if (!selectedItemList.ContainsKey(fItem.Key)) { selectedItemList.Add(fItem.Key, fItem.Value); } } } else { lgInfo($"subscribedItems non trovato: {currItem}"); } } lgInfo($"Aggiunti {selectedItemList.Count} items!"); } // altrimenti tutti! else { selectedItemList = nodeIdNameList; } // loggo elenco degli item sottocrivibili... lgInfo("---------- SUBSCRIBED NODES ----------"); foreach (var item in selectedItemList) { lgInfo(item.Key); } lgInfo("---------- END LIST ----------"); // sottoscrivo a rilevazione cambio dati solo l'incrocio degli insiemi List subscribedItems = UA_ref.SubscribeToDataChanges(selectedItemList); // aggiungo come DataItems int dSamplePeriod = 0; int threshDBand = 0; string uuid = ""; foreach (var item in subscribedItems) { OpcUaDataItemExt newItem = formatDataItem(ref dSamplePeriod, ref threshDBand, ref uuid, item); // controllo non sia già stato aggiunto if (dataItemMem.ContainsKey(uuid)) { lgInfo($"Item ALREADY subscribed: {uuid} | NOT re-adding"); } else { dataItemMem.Add(uuid, newItem); lgInfo($"Item subscribed: {uuid}"); string currVal = UA_ref.ReadNode(item.StartNodeId); checkAndSend(item, currVal, true); } } // gestione eventi change UA_ref.eh_MonItChange += UA_ref_eh_MonItChange; lgInfo("eh_MonItChange event registered"); } esitoLink = 1; // fix tempi! DateTime adesso = DateTime.Now; lastPzCountSend = adesso; lastWarnODL = adesso; lastCurrent = adesso; } catch (Exception exc) { lgError($"Eccezione in doConnect{Environment.NewLine}{exc}"); } return esitoLink; } /// /// Formatta un dataitem x salvataggio in memoria locale /// /// /// /// /// /// private OpcUaDataItemExt formatDataItem(ref int dSamplePeriod, ref int threshDBand, ref string uuid, Opc.Ua.Client.MonitoredItem dataItem) { OpcUaDataItemExt currDataItem; // calcolo parametri uuid = $"{dataItem.DisplayName}"; // SOLO SE è abilitato il datafiltering... if (enableDataFilter) { threshDBand = 1; // controllo SE ho conf x deadband... if (opcUaParams.paramsEndThresh.Count > 0) { // ciclo su tutti i parametri indicati... foreach (var item in opcUaParams.paramsEndThresh) { if (uuid.EndsWith(item.Key)) { threshDBand = item.Value; } } } } else { threshDBand = 0; } dSamplePeriod = 60; // salvo oggetto x "uso interno" currDataItem = new OpcUaDataItemExt(dataItem) { uid = uuid, thresholdDeadBand = threshDBand, samplePeriod = dSamplePeriod }; return currDataItem; } /// /// Effettua invio a MP/IO dell'elenco serializzato dei dataItems /// /// private void sendDataItemsList(List dataItems) { string rawData = JsonConvert.SerializeObject(dataItems); utils.callUrlNow($"{urlSaveDataItems}", rawData); } /// /// Evento rilevazione modifica valori --> chiamo checkSend /// /// /// private void UA_ref_eh_MonItChange(object sender, opcUaMonitItemChange e) { checkAndSend(e.CurrMonitoredItem, $"{e.CurrNotify.Value}", false); // se abilitato watchdog... if (opcUaParams.WatchDog.IsEnabled) { // se fosse watchdog --> processo il mio... if (e.CurrMonitoredItem.DisplayName == opcUaParams.WatchDog.MemConfRead) { try { WatchDog++; WatchDog = WatchDog > opcUaParams.WatchDog.MaxVal ? 0 : WatchDog; WriteValue commWriteVal = new WriteValue(); commWriteVal.NodeId = new NodeId(opcUaParams.WatchDog.MemConfWrite); commWriteVal.AttributeId = Attributes.Value; commWriteVal.Value = new DataValue(); commWriteVal.Value.Value = WatchDog; List nodes2Write = new List(); nodes2Write.Add(commWriteVal); UA_ref.WriteNodes(nodes2Write); } catch (Exception exc) { lgError($"Eccezione in gestione WatchDog, valore attuale {WatchDog}{Environment.NewLine}{exc}"); } } } lastCurrent = DateTime.Now; } protected int WatchDog = 0; #endregion Private Methods #region Protected Methods /// /// Verifica un DataItem e se il valore corrisponde a quello indicato come "true value" restituisce true /// /// /// /// protected bool checkDataItem(string itemName, string trueVal) { bool answ = false; OpcUaDataItemExt currValue = null; try { currValue = dataItemMem[itemName]; answ = (currValue.value.Equals(trueVal)); } catch { lgError($"Errore in decodifica valore per {itemName} rispetto a {trueVal} | recuperato {currValue} / {currValue.value}"); } return answ; } /// /// Verifica condizione "multipla" secondo setup json /// /// /// protected bool checkMultiCondition(List checkList, boolCheckMode checkMode) { bool answ = false; int numCondOk = 0; int numCond = 0; if (checkList != null && checkList.Count > 0) { numCond = checkList.Count; // cerco nell'elenco delle condizioni che indicano lavora se sono ok faccio +1 conteggio...... foreach (var item in checkList) { if (getDataItemValue(item.keyName) == item.targetValue) { numCondOk++; } } } if (checkMode == boolCheckMode.AND) { answ = (numCond == numCondOk); } else if (checkMode == boolCheckMode.OR) { answ = numCondOk > 0; } return answ; } /// /// Verifica / Salva valore e restitusice SE sia variato (e quindi da inviare...) /// /// /// protected bool checkSaveValue(Opc.Ua.Client.MonitoredItem dataItem, string NotifyValue) { bool answ = !enableDataFilter; double oldVal = 0; double newVal = 0; if (dataItem != null) { if (!string.IsNullOrEmpty(NotifyValue)) { if (isVerboseLog) { lgInfo($"Richiesta checkSaveSample per {dataItem.DisplayName} | id: {dataItem.StartNodeId} | Valore: {NotifyValue}"); } // verifico in memoria se ho l'oggetto condition ed il suo valore.. string uuid = $"{dataItem.DisplayName}"; DateTime adesso = DateTime.Now; if (dataItemMem.ContainsKey(uuid)) { OpcUaDataItemExt currDataItemMem = dataItemMem[uuid]; // controllo SE SIA scaduto il tempo massimo... if (Math.Abs(dataItemMem[uuid].valueTimestamp.Subtract(adesso).TotalSeconds) > currDataItemMem.samplePeriod) { answ = true; } else { // ALTRIMENTI controllo SE diverso if (dataItemMem[uuid].value != $"{NotifyValue}") { if (isVerboseLog) { lgInfo($"Val uuid: {dataItemMem[uuid].value} | NotifyValue: {NotifyValue}"); } // controllo SE ho DeadBand... if (dataItemMem[uuid].thresholdDeadBand > 0) { // recupero i valori e testo DeadBand... bool isNum01 = double.TryParse(dataItemMem[uuid].value.Replace(".", ","), out oldVal); bool isNum02 = double.TryParse($"{NotifyValue}".Replace(".", ","), out newVal); // test deadband! if (!(isNum01 && isNum02)) { answ = true; } else { if (Math.Abs(newVal - oldVal) > dataItemMem[uuid].thresholdDeadBand) { // indico da salvare.. answ = true; } } if (isVerboseLog) { lgInfo($"Test deadband: oldVal: {oldVal} | newVal: {newVal}"); } } } } if (answ) { // salvo! dataItemMem[uuid].value = $"{NotifyValue}"; dataItemMem[uuid].valueTimestamp = adesso; } } else { // registro non trovato da aggiungere... lgInfo($"DataItem non trovato in checkSaveSample: {dataItem.DisplayName}"); // provo a creare oggetto in memoria... try { List elencoDataItems = new List(); int dSamplePeriod = 0; int threshDBand = 0; uuid = ""; var currDataItem = formatDataItem(ref dSamplePeriod, ref threshDBand, ref uuid, dataItem); // sistemo valore/periodo currDataItem.value = $"{NotifyValue}"; currDataItem.valueTimestamp = adesso; // aggiungo dataItemMem.Add(uuid, currDataItem); // salvo oggetto x registrazione su server MP-IO var currMapoDataItem = new machDataItem() { uuid = uuid, Category = DataItemCategory.EVENT, Name = dataItem.DisplayName, Type = $"{dataItem.NodeClass}", SubType = $"{dataItem.StartNodeId}" }; // aggiungo elencoDataItems.Add(currMapoDataItem); // invio il dataItem serializzato... sendDataItemsList(elencoDataItems); } catch (Exception exc) { lgError($"Eccezione in checkSaveSample{Environment.NewLine}{exc}"); } } } else { lgError("Attenzione: checkSaveItem con Notify null!"); } } else { lgError("Attenzione: checkSaveItem con MonIt null!"); } return answ; } /// /// Effettua decodifica aree memoria alla bitmap usata x MAPO /// protected virtual void decodeToBaseBitmap() { DateTime adesso = DateTime.Now; // init a zero... B_input = 0; /* ----------------------------------------------------- * STATE MACHINE 60 STD / SIMULA *------------------------------------------------------ * bitmap MAPO * B0: POWER_ON * B1: RUN * B2: pzCount * B3: allarme * B4: manuale * B5: SlowTC (NON gestito qui) * B6: warm-up / cool-down * B7: emergenza ---------------------------------------------------- */ // se valido il check ping lo eseguo... altrimenti lo do x buono bool checkPing = !opcUaParams.pingAsPowerOn; string currRun = ""; if (!checkPing) { checkPing = (testPingMachine == IPStatus.Success); } // bit 0 (poweron) imposto a 1 SE pingo + PowerOn=="ON"... bool powerOnOk = checkPing && hasPowerOn; // lascio attivo sulla abse solo il poweron (da verificare il resto #if false // procedo SOLO SE mi da ping OK... if (checkPing) { B_input = powerOnOk ? 1 : 0; // variabili RUN... currRun = getDataItemValue(opcUaParams.keyRunMode); // salvo running come = working... isRunning = isWorking; // se ho emergenza premuta --> emergenza! if (hasEStopArmed) { B_input += (1 << 7); } // se ho emergenza premuta --> emergenza! if (isWarmUpCoolDown) { B_input += (1 << 6); } // se ho almeno 1 allarme E NON SONO IN AUTO --> ALARM! if (hasError) { B_input += (1 << 3); } if (isWorking) { // RUN = LAVORA! B_input += (1 << 1); } else if (powerOnOk && (!isReady || isManual)) { // se NON ready --> manual B_input += (1 << 4); } } #endif // controllo se sono poweroff e se non ho dati buoni da > 2 minuti --> disconnetto if (adesso.Subtract(lastCurrent).TotalMinutes > 2) { tryDisconnect(); } // solo se non ho veto check int vFactor = 2; if (vetoCheckStatus < adesso) { lgInfo($"Stato variabili checkPing: {testPingMachine}"); // imposto veto per vetoSeconds... vetoCheckStatus = adesso.AddSeconds(vetoSeconds * vFactor); } // log opzionale! if (verboseLog) { lgInfo($"Trasformazione checkPing: {checkPing} | hasPowerOn: {hasPowerOn} | B_input: {B_input} | currRun = {currRun}"); } } /// /// Effettua traduzione ITEM da LUT parametrica (key: tipo+id) del file di conf, se non trovo uso key /// /// /// /// protected string itemTranslation(string tipo, string id) { string answ = ""; string lemma = id; if (!string.IsNullOrEmpty(tipo)) { lemma = $"{tipo}_{id}"; } // cerco nel dizionario delle traduzioni SE esiste un valore e prendo quello, altrimenti uso il lemma... if (opcUaParams.itemTranslation.ContainsKey(lemma)) { answ = opcUaParams.itemTranslation[lemma]; } else { answ = lemma; } return answ; } /// /// Effettua lettura file di conf specifico OPC-UA da oggetto serializzato json /// Nome file da cui leggere i parametri json /// protected void loadOpcUaConf(string fileName) { string jsonFullPath = $"{Application.StartupPath}/DATA/CONF/{fileName}"; lgInfo($"Apertura file {jsonFullPath}"); using (StreamReader reader = new StreamReader(jsonFullPath)) { string jsonData = reader.ReadToEnd().Replace("\n", "").Replace("\r", ""); if (!string.IsNullOrEmpty(jsonData)) { lgInfo($"File json composto da {jsonData.Length} caratteri"); try { opcUaParams = JsonConvert.DeserializeObject(jsonData); lgInfo($"Decodifica aree OpcUaParamConf: trovati {opcUaParams.paramsEndThresh.Count} valori paramsEndThresh"); // sistemo se ci sono dati memMap... memMap = new plcMemMap(); if (opcUaParams.mMapWrite != null) { memMap.mMapWrite = opcUaParams.mMapWrite; } if (opcUaParams.mMapRead != null) { memMap.mMapRead = opcUaParams.mMapRead; } setupMemMap(); } catch (Exception exc) { lgError($"Eccezione in decodifica conf json OPC-UA:{Environment.NewLine}{exc}"); } } else { lgError("Errore in loadOpcUaConf: file json vuoto!"); } } //reader.Dispose(); } #endregion Protected Methods #region Public Methods /// /// Processo i task richiesti e li elimino dalla coda 1:1 /// /// public override Dictionary executeTasks(Dictionary task2exe) { // uso metodo base x ora return base.executeTasks(task2exe); } /// /// Recupera uno specifico dataItem /// /// /// public string getDataItemValue(string diKey) { string answ = ""; if (string.IsNullOrEmpty(diKey)) { lgError("Attenzione: richiesta chaive vuota in getDataItemValue"); } else { DateTime adesso = DateTime.Now; if (dataItemMem.Count == 0) { numErroriCheck++; if (vetoCheckStatus < adesso) { lgError($"Errore in getDataItemValue per {diKey} | dataItemMem NON contiene valori"); // imposto veto per vetoSeconds... vetoCheckStatus = adesso.AddSeconds(vetoSeconds * 2); } } else { if (!dataItemMem.ContainsKey(diKey)) { if (vetoCheckStatus < adesso) { lgError($"Errore in getDataItemValue per {diKey} | dataItemMem non contiene la chiave richiesta ma altri {dataItemMem.Count} valori"); // imposto veto per vetoSeconds... vetoCheckStatus = adesso.AddSeconds(vetoSeconds * 2); } numErroriCheck++; } else { try { var currDataItem = dataItemMem[diKey]; answ = currDataItem.value; } catch (Exception exc) { lgError($"Errore in getDataItemValue per {diKey} | dataItemMem contiene {dataItemMem.Count} valori {Environment.NewLine}{exc}"); if (dataItemMem != null) { lgError($"dataItemMem contiene {dataItemMem.Count} valori"); int maxNum = 5; foreach (var item in dataItemMem) { maxNum--; if (maxNum < 0) { break; } lgInfo($"{item.Key} --> {item.Value.DisplayName} = {item.Value.value}"); } } } } } // se supero soglia errori lettura --> disconnetto e resetto if (numErroriCheck > 100) { lgInfo($"numErroriCheck: {numErroriCheck} --> richiesta disconnessione adapter con tryDisconnect"); numErroriCheck = 0; tryDisconnect(); } } return answ; } /// /// Recupero dati dinamici... /// public override Dictionary getDynData() { Dictionary outVal = new Dictionary(); return outVal; } /// /// Effettua vero processing contapezzi /// public override void processContapezzi() { if (utils.CRB("enableContapezzi")) { // da ridefinire la gestione base del contapezzi OPC-UA... } } /// /// Effettua lettura semafori principale /// Parametri da aggiornare x display in form /// public override void readSemafori(ref newDisplayData currDispData) { base.readSemafori(ref currDispData); try { if (verboseLog) { lgInfo("inizio read semafori"); } currDispData.semIn = Semaforo.SV; // decodifica e gestione decodeToBaseBitmap(); reportRawInput(ref currDispData); } catch (Exception exc) { currDispData.semIn = Semaforo.SR; lgError($"Eccezione in readSemafori:{Environment.NewLine}{exc}"); } } /// /// Effettua reset del contapezzi, NON POSSIBILE in questa versione /// /// public override bool resetcontapezziPLC() { bool answ = false; return answ; } /// /// Effettua IMPOSTAZIONE FORZATA del contapezzi, NON POSSIBILE in questa versione /// /// public override bool setcontapezziPLC(int newPzCount) { bool answ = false; return answ; } /// /// Override connessione /// public override void tryConnect() { if (!connectionOk) { // controllo che il ping sia stato tentato almeno pingTestSec fa... if (DateTime.Now.Subtract(lastPING).TotalSeconds > utils.CRI("pingTestSec")) { if (verboseLog || periodicLog) { lgInfo("OpcUa: ConnKO - tryConnect"); } // in primis salvo data ping... lastPING = DateTime.Now; // se passa il ping faccio il resto... if (testPingMachine == IPStatus.Success) { string szStatusConnection = ""; try { // ora provo connessione... parentForm.commPlcActive = true; var task = Task.Run(async () => { return await doConnect().ConfigureAwait(false); }); short esitoLink = task.Result; // use returned result from async method here lgInfo($"szStatusConnection OpcUa, esitoLink: {esitoLink}"); parentForm.commPlcActive = false; connectionOk = true; // refresh stato allarmi!!! if (connectionOk) { if (adpRunning) { lgInfo("Connessione OK"); } } else { lgError("Impossibile procedere, connessione mancante..."); } } catch (Exception exc) { lgFatal($"Errore nella connessione all'adapter OpcUa: {szStatusConnection}{Environment.NewLine}{exc}"); connectionOk = false; lgInfo($"Eccezione in TryConnect, Adapter OpcUa NON running, pausa di {utils.CRI("waitRecMSec")} msec prima di ulteriori tentativi di riconnessione"); } } else { // loggo no risposta ping ... connectionOk = false; if (verboseLog || periodicLog) { lgInfo($"Attenzione: OpcUa controllo PING fallito per IP {cIobConf.cncIpAddr}"); } } } } else { needRefresh = true; } // se non è ancora connesso faccio procesisng memoria caso disconnesso... if (!connectionOk) { // processo semafori ed invio... processMemoryDiscon(); } } /// /// Override disconnessione /// public override void tryDisconnect() { if (connectionOk) { if (UA_ref != null) { string szStatusConnection = ""; try { UA_ref.Disconnect(); connectionOk = false; lgInfo(szStatusConnection); lgInfo("Effettuata disconnessione adapter OpcUa!"); } catch (Exception exc) { lgFatal(exc, "Errore nella disconnessione dall'adapter OpcUa"); } } else { lgError("IMPOSSIBILE effettuare disconnessione OpcUa: UA_ref non disponibile..."); } } else { lgError("IMPOSSIBILE effettuare disconnessione OpcUa: Connessione non disponibile..."); } } #endregion Public Methods } }