using IOB_UT_NEXT; using MapoSDK; using MTConnect.Clients; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Net.NetworkInformation; using System.Threading; using System.Windows.Forms; using MTConnectDevices = MTConnect.MTConnectDevices; using MTConnectStreams = MTConnect.MTConnectStreams; namespace IOB_WIN_NEXT { public class IobMTC : IobGeneric { #region Private Fields /// /// Struttura dove vengono memorizzati i dataitem ed i rispettivi valori x processing /// private Dictionary dataItemMem = new Dictionary(); #endregion Private Fields #region Protected Fields /// /// Gestione filtraggio dati /// protected bool enableDataFilter = false; /// /// Abilitazione restart (da opt par...) /// protected bool enableMtcRestart = 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; /// /// Oggetto MAIN x connessione MTC /// protected MTConnectClient MTC_ref; /// /// Veto controllos tatus x log... /// protected DateTime vetoCheckStatus = DateTime.Now; #endregion Protected Fields #region Public Constructors /// /// Estende l'init della classe base, impiegando il pacchetto Nuget TrackHound /// https://github.com/TrakHound/MTConnect.NET /// /// /// public IobMTC(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 MTC client... if (!string.IsNullOrEmpty(getOptPar("ENABLE_MTC_RESTART"))) { bool.TryParse(getOptPar("ENABLE_MTC_RESTART"), out enableMtcRestart); } // init datetime counters DateTime adesso = DateTime.Now; lastPzCountSend = adesso; lastWarnODL = adesso; lastCurrent = adesso; // ora leggo il file di conf specifico.... string jsonFileName = getOptPar("MTC_PARAM_CONF"); if (!string.IsNullOrEmpty(jsonFileName)) { // leggo il file... loadMtcConf(jsonFileName); } } #endregion Public Constructors #region Protected Properties /// /// Verifico se abbia ALMENO un errore... /// protected bool hasError { get { bool answ = false; // controllo TUTTE le conditions... foreach (var item in dataItemMem) { // se NON HO GIA' allarmi attivi... if (!answ) { // se è una condition... if (item.Value.Category == MTConnect.DataItemCategory.CONDITION) { // se ha valore !="" --> allarmi attivi if (!string.IsNullOrEmpty(item.Value.value)) { answ = true; } } } } return answ; } } /// /// Indica se abbia emergenza premuta /// protected bool hasEStopTriggered { get { bool answ = false; try { if (!string.IsNullOrEmpty(mtcParams.keyEStop)) { string currEStop = getDataItemValue(mtcParams.keyEStop); answ = (currEStop == "TRIGGERED"); } } catch { } return answ; } } /// /// Parametri specifici MTC /// protected MtcParamConf mtcParams { get; set; } /// /// URL x salvataggio elenco dataItems MTC /// 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(MTConnectStreams.Document document, bool forceSend) { if (document != null) { foreach (var deviceStream in document.DeviceStreams) { string sVal = ""; string descr = ""; DateTime locTStamp = DateTime.Now; // check su Conditions try { // check su dataItems (conditions + events + samples) foreach (var dataItem in deviceStream.Conditions) { descr = itemTranslation("C", dataItem.DataItemId); locTStamp = dataItem.Timestamp.ToLocalTime(); sVal = $"CONDITION: {locTStamp.ToString()} | Id: {dataItem.DataItemId} | | Name: {dataItem.Name} | descr: {descr} | Val: {dataItem.CDATA}"; // condition verboso SEMPRE! lgInfo(sVal); DateTime tStamp = dataItem.Timestamp; var time2 = tStamp.ToLocalTime(); // verifico se salvare bool changed = checkSaveItem(dataItem); if (changed || forceSend) { // accodare ed invia nella coda ALARMS (che POI salva in document MongoDB anche ultimi x minuti di FluxLog...) accodaAlarmLog(sVal, qEncodeFLog(time2, descr, dataItem.CDATA)); } } } catch (Exception exc) { lgError($"Eccezione in decodifica Conditions x StreamSuccesfull{Environment.NewLine}{exc}", false); } // check su events try { // check su dataItems (conditions + events + samples) foreach (var dataItem in deviceStream.Events) { descr = itemTranslation("E", dataItem.DataItemId); locTStamp = dataItem.Timestamp.ToLocalTime(); sVal = $"EVENT: {locTStamp.ToString()} | descr: {descr} | Id: {dataItem.DataItemId} | Name: {dataItem.Name} | Val: {dataItem.CDATA}"; if (isVerboseLog) { lgInfo(sVal); } DateTime tStamp = dataItem.Timestamp; var time2 = tStamp.ToLocalTime(); // verifico se salvare bool changed = checkSaveItem(dataItem); // cerco se non sia un dato filtrato in FLUXLOG... bool isFiltered = mtcParams.fluxLogVeto.Contains(dataItem.DataItemId); if (isFiltered) { if (isVerboseLog) { lgTrace($"NON ACCODATO sample per {dataItem.DataItemId} - trovato VETO in fluxLogVeto", false); } } else { if (changed || forceSend) { accodaFLog(sVal, qEncodeFLog(time2, descr, dataItem.CDATA)); } } } } catch (Exception exc) { lgError($"Eccezione in decodifica Events x StreamSuccesfull{Environment.NewLine}{exc}", false); } // check su samples try { // check su dataItems (conditions + events + samples) foreach (var dataItem in deviceStream.Samples) { descr = itemTranslation("S", dataItem.DataItemId); locTStamp = dataItem.Timestamp.ToLocalTime(); sVal = $"SAMPLE: {locTStamp.ToString()} | descr: {descr} | Id: {dataItem.DataItemId} | | Name: {dataItem.Name} | Val: {dataItem.CDATA}"; if (isVerboseLog) { lgInfo(sVal); } DateTime tStamp = dataItem.Timestamp; var time2 = tStamp.ToLocalTime(); // verifico se salvare bool changed = checkSaveSample(dataItem); // cerco se non sia un dato filtrato in FLUXLOG... bool isFiltered = mtcParams.fluxLogVeto.Contains(dataItem.DataItemId); if (isFiltered) { if (isVerboseLog) { lgTrace($"NON ACCODATO sample per {dataItem.DataItemId} - trovato VETO in fluxLogVeto", false); } } else { if (changed || forceSend) { accodaFLog(sVal, qEncodeFLog(time2, descr, dataItem.CDATA)); } else { if (isVerboseLog) { lgTrace($"NON ACCODATO sample per {dataItem.DataItemId} - verifica variazione SAMPLE ha dato esito negativo", false); } } } } } catch (Exception exc) { lgError($"Eccezione in decodifica Samples x StreamSuccesfull{Environment.NewLine}{exc}"); } } } else { lgError("StreamsSuccessful ERROR: document è null"); } } /// /// Effettua decodifica aree memoria alla bitmap usata x MAPO /// private void decodeToBaseBitmap() { // init a zero... B_input = 0; /* ----------------------------------------------------- * bitmap MAPO * B0: POWER_ON * B1: RUN * B2: pzCount * B3: allarme * B4: manuale * B5: emergenza (dipende da state machine se riportare 1 = armata/premuta, vedere conf mtcParams.emergencyArmedTrue) ----------------------------------------------------- */ // Controllo booleano PING e POWERON... string currPowerOn = getDataItemValue(mtcParams.condPowerOn.keyName); // se valido il check ping lo eseguo... altrimenti lo do x buono bool isPingOk = (testPingMachine == IPStatus.Success); // verifico da target value richiesto... bool checkPowerOn = (currPowerOn == mtcParams.condPowerOn.targetValue); // bit 0 (poweron) imposto a 1 SE pingo o PowerOn=="ON"... B_input = ((isPingOk && mtcParams.pingAsPowerOn) || checkPowerOn) ? 1 : 0; // variabili RUN... string currRun = getDataItemValue(mtcParams.keyRunMode); // controllo RUN MODE preliminare... CABLATO - è GENERALE x MTC if (currRun == "AUTOMATIC" || currRun == "SEMI_AUTO" || currRun == "SEMI_AUTOMATIC") { int numCond = mtcParams.condWork.Count; int numCondOk = 0; // cerco nell'elenco delle condizioni che indicano lavora se sono ok faccio +1 conteggio...... foreach (var item in mtcParams.condWork) { if (getDataItemValue(item.keyName) == item.targetValue) { numCondOk++; } } // se tutte condizioni rispettate --> lavora! if (numCond == numCondOk) { // RUN = LAVORA! B_input += (1 << 1); } } // se ho almeno 1 allarme E NON SONO IN AUTO --> ALARM! else if (hasError) { B_input += (1 << 3); } else { // se ho run mode != auto --> manual B_input += (1 << 4); } // emergenza armata da riportare con bit True/ 1 if (mtcParams.emergencyArmedTrue) { //se NON premuta lazo il bit if (!hasEStopTriggered) { B_input += (1 << 5); } } // emergenza armata da riportare come False/0 (!mtcParams.emergencyArmedTrue) else { // se premuta alzo il bit... if (hasEStopTriggered) { B_input += (1 << 5); } } DateTime adesso = DateTime.Now; int vFactor = 1; // controllo SE HO dati per fare verifiche... if (string.IsNullOrEmpty(currRun)) { // se ho parametro x gestione reset... if (enableMtcRestart) { // controllo se ho ricevuto il current da OLTRE 1 minuto... if (lastCurrent.AddMinutes(3) < adesso) { lastCurrent = adesso; // stop... lgInfo("Fermato MTC_ref per mancanza dati current"); MTC_ref.Stop(); Thread.Sleep(1000); // restart lgInfo("Riavviato MTC_ref per mancanza dati current"); MTC_ref.Start(); } } } else { vFactor = 6; } // solo se non ho veto check if (vetoCheckStatus < adesso) { lgInfo($"Stato variabili: currRun: {currRun}"); // imposto veto per vetoSeconds... vetoCheckStatus = adesso.AddSeconds(vetoSeconds * vFactor); } // log opzionale! if (verboseLog) { lgInfo($"Trasformazione B_input: {B_input} | currRun = {currRun}"); } } /// /// Vera connessione ad MTC /// /// private short doConnect() { short esitoLink = 0; // reset memoria dataItem.. dataItemMem = new Dictionary(); // predisposizione conf oggetto di comunicazione MTC short port = 5000; short.TryParse(cIobConf.cncPort, out port); // test probe! try { var probe = new Probe($"http://{cIobConf.cncIpAddr}:{port}").Execute(); // se valido loggo! if (probe != null) { lgInfo($"Effettuata correttamente PROBE per device MTC all'URL {probe.Url} | vers: {probe.Version} | send: {probe.Header.Sender}"); lgInfo($"---------------- Elenco Devices ----------------"); // loggo devices principali... logDevicesList(probe.Devices); } } catch (Exception exc) { lgError($"Eccezione durante test probe:{Environment.NewLine}{exc}"); } // attendo 1 sec... Thread.Sleep(1000); // ora avvio try { lgInfo($"Chiamata apertura MTC Client: {cIobConf.cncIpAddr}:{port}"); MTC_ref = new MTConnectClient($"http://{cIobConf.cncIpAddr}:{port}"); // Subscribe to the Event handlers to receive the MTConnect documents MTC_ref.ProbeReceived += DevicesSuccessful; MTC_ref.CurrentReceived += CurrentSuccessful; MTC_ref.SampleReceived += StreamsSuccessful; // attendo 1 sec... Thread.Sleep(1000); MTC_ref.Start(); esitoLink = 1; // fix tempi! DateTime adesso = DateTime.Now; lastPzCountSend = adesso; lastWarnODL = adesso; lastCurrent = adesso; } catch { } return esitoLink; } /// /// Formatta un dataitem da uno stream SAMPLE /// /// /// /// /// /// private MtcDataItemExt formatDataItem(ref int dSamplePeriod, ref int threshDBand, ref string uuid, MTConnectStreams.Sample DISample) { // creo il nuovo dataitem da sample... MTConnectDevices.DataItem newDataItem = new MTConnectDevices.DataItem() { Category = DISample.Category, Id = DISample.DataItemId, Name = DISample.Name, SampleRate = DISample.SampleRate, Statistic = DISample.Statistic, SubType = DISample.SubType, Type = DISample.Type }; return formatDataItem(ref dSamplePeriod, ref threshDBand, ref uuid, newDataItem); } /// /// Formatta un dataitem da uno stream GENERICO /// /// /// /// /// /// private MtcDataItemExt formatDataItem(ref int dSamplePeriod, ref int threshDBand, ref string uuid, MTConnectStreams.DataItem DIGen) { // creo il nuovo dataitem da sample... MTConnectDevices.DataItem newDataItem = new MTConnectDevices.DataItem() { Category = DIGen.Category, Id = DIGen.DataItemId, Name = DIGen.Name, SubType = DIGen.SubType, Type = DIGen.Type }; return formatDataItem(ref dSamplePeriod, ref threshDBand, ref uuid, newDataItem); } /// /// Formatta un dataitem x salvataggio in memoria locale /// /// /// /// /// /// private MtcDataItemExt formatDataItem(ref int dSamplePeriod, ref int threshDBand, ref string uuid, MTConnectDevices.DataItem dataItem) { MtcDataItemExt currDataItem; // uuid e parametri secondo categoria... switch (dataItem.Category) { case MTConnect.DataItemCategory.CONDITION: uuid = $"C_{dataItem.Id}"; threshDBand = 0; dSamplePeriod = 0; break; case MTConnect.DataItemCategory.EVENT: uuid = $"E_{dataItem.Id}"; threshDBand = 0; dSamplePeriod = 0; break; case MTConnect.DataItemCategory.SAMPLE: uuid = $"S_{dataItem.Id}"; // SOLO SE è abilitato il datafiltering... if (enableDataFilter) { threshDBand = 1; // controllo SE ho conf x deadband... if (mtcParams.paramsEndThresh.Count > 0) { // ciclo su tutti i parametri indicati... foreach (var item in mtcParams.paramsEndThresh) { if (dataItem.Id.EndsWith(item.Key)) { threshDBand = item.Value; } } } } else { threshDBand = 0; } dSamplePeriod = 60; break; default: break; } // salvo oggetto x "uso interno" currDataItem = new MtcDataItemExt() { Id = dataItem.Id, Category = dataItem.Category, Constraints = dataItem.Constraints, CoordinateSystem = dataItem.CoordinateSystem, Name = dataItem.Name, NativeScale = dataItem.NativeScale, NativeUnits = dataItem.NativeUnits, SampleRate = dataItem.SampleRate, Representation = dataItem.Representation, SignificantDigits = dataItem.SignificantDigits, Source = dataItem.Source, Statistic = dataItem.Statistic, SubType = dataItem.SubType, Type = dataItem.Type, TypePath = dataItem.TypePath, Units = dataItem.Units, XPath = dataItem.XPath, uid = uuid, thresholdDeadBand = threshDBand, samplePeriod = dSamplePeriod }; // log x capire COME ho chiamato alcune cosette... if (dataItem.Id.Contains("EXE_MODE") || dataItem.Id.Contains("RUN_MODE") || dataItem.Id.Contains("POWER") || dataItem.Id.EndsWith("_Status")) { lgInfo($"DEBUG DATA | dataItem.Id : {dataItem.Id}"); } return currDataItem; } /// /// Effettua lettura file di conf specifico MTC da oggetto serializzato json /// Nome file da cui leggere i parametri json /// private void loadMtcConf(string fileName) { string jsonFullPath = $"{Application.StartupPath}/DATA/CONF/{fileName}"; lgInfo($"Apertura file {jsonFullPath}"); 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 { mtcParams = JsonConvert.DeserializeObject(jsonData); lgInfo($"Decodifica aree MtcParamConf: trovati {mtcParams.paramsEndThresh.Count} valori paramsEndThresh"); } catch (Exception exc) { lgError($"Eccezione in decodifica conf json MTC:{Environment.NewLine}{exc}"); } } else { lgError("Errore in loadMtcConf: file json vuoto!"); } reader.Dispose(); } /// /// Effettua invio a MP/IO dell'elenco serializzato dei dataItems /// /// private void sendDataItemsList(List dataItems) { string rawData = JsonConvert.SerializeObject(dataItems); utils.callUrlNow($"{urlSaveDataItems}", rawData); } #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; MtcDataItemExt 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 / Salva valore generico (NON SAMPLE) /// /// /// protected bool checkSaveItem(MTConnectStreams.DataItem newValue) { bool answ = !enableDataFilter; if (newValue != null) { if (isVerboseLog) { lgInfo($"Richiesta checkSaveItem per {newValue} | id: {newValue.DataItemId} | CDATA: {newValue.CDATA}"); } // verifico in memoria se ho l'oggetto condition ed il suo valore.. if (dataItemMem.ContainsKey(newValue.DataItemId)) { // salvo sempre! dataItemMem[newValue.DataItemId].value = newValue.CDATA; dataItemMem[newValue.DataItemId].valueTimestamp = newValue.Timestamp; answ = true; } else { // registro non trovato da aggiungere... lgInfo($"DataItem non trovato in checkSaveItem: {newValue.DataItemId}"); try { // provo a creare oggetot in memoria... List elencoDataItems = new List(); int dSamplePeriod = 0; int threshDBand = 0; string uuid = ""; var currDataItem = formatDataItem(ref dSamplePeriod, ref threshDBand, ref uuid, newValue); // aggiungo dataItemMem.Add(newValue.DataItemId, currDataItem); // salvo oggetto x registrazione su server MP-IO var currMapoDataItem = new machDataItem() { uuid = newValue.DataItemId, Category = (DataItemCategory)newValue.Category, Name = newValue.Name, Type = newValue.Type, SubType = newValue.SubType, //Units = newValue.Units }; // 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 newValue null!"); } return answ; } /// /// Verifica / Salva valore SAMPLE e restitusice SE sia variato (e quindi da inviare...) /// /// /// protected bool checkSaveSample(MTConnectStreams.Sample newValue) { bool answ = !enableDataFilter; double oldVal = 0; double newVal = 0; if (newValue != null) { lgTrace($"Richiesta checkSaveSample per {newValue} | id: {newValue.DataItemId} | CDATA: {newValue.CDATA}"); // verifico in memoria se ho l'oggetto condition ed il suo valore.. if (dataItemMem.ContainsKey(newValue.DataItemId)) { MtcDataItemExt currDataItemMem = dataItemMem[newValue.DataItemId]; // controllo SE SIA scaduto il tempo massimo... if (Math.Abs(dataItemMem[newValue.DataItemId].valueTimestamp.Subtract(newValue.Timestamp).TotalSeconds) > currDataItemMem.samplePeriod) { answ = true; } else { // ALTRIMENTI controllo SE diverso if (dataItemMem[newValue.DataItemId].value != newValue.CDATA) { // controllo SE ho DeadBand... if (dataItemMem[newValue.DataItemId].thresholdDeadBand > 0) { if (isVerboseLog) { lgInfo($"Test deadband: oldVal: {oldVal} | newVal: {newVal}"); } // recupero i valori e testo DeadBand... double.TryParse(dataItemMem[newValue.DataItemId].value.Replace(".", ","), out oldVal); double.TryParse(newValue.CDATA.Replace(".", ","), out newVal); // test deadband! if (Math.Abs(newVal - oldVal) > dataItemMem[newValue.DataItemId].thresholdDeadBand) { // indico da salvare.. answ = true; } } } } if (answ) { // salvo! dataItemMem[newValue.DataItemId].value = newValue.CDATA; dataItemMem[newValue.DataItemId].valueTimestamp = newValue.Timestamp; } } else { // registro non trovato da aggiungere... lgInfo($"DataItem non trovato in checkSaveSample: {newValue.DataItemId}"); // provo a creare oggetto in memoria... try { List elencoDataItems = new List(); int dSamplePeriod = 0; int threshDBand = 0; string uuid = ""; var currDataItem = formatDataItem(ref dSamplePeriod, ref threshDBand, ref uuid, newValue); // aggiungo dataItemMem.Add(newValue.DataItemId, currDataItem); // salvo oggetto x registrazione su server MP-IO var currMapoDataItem = new machDataItem() { uuid = newValue.DataItemId, Category = (DataItemCategory)newValue.Category, Name = newValue.Name, Type = newValue.Type, SubType = newValue.SubType, //Units = newValue.Units }; // 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 newValue null!"); } return answ; } /// /// Effettuata discovery iniziale valori CURRENT /// /// /// protected void CurrentSuccessful(MTConnectStreams.Document document) { if (document != null) { lgInfo($"DiscoverySuccessful: discovery per {document.Url}"); if (document.DeviceStreams != null) { lgInfo($"DiscoverySuccessful: trovati {document.DeviceStreams.Count} streams"); } checkAndSend(document, true); } else { lgError("StreamsSuccessful ERROR: document è null"); } } /// /// Evento lanciato alla corretta ricezione del PROBE /// /// protected void DevicesSuccessful(MTConnectDevices.Document document) { lgInfo("STEP 01 DevicesSuccessful reached!"); MtcDataItemExt currDataItem = null; machDataItem currMapoDataItem = null; List elencoDataItems = new List(); int dSamplePeriod = 0; int threshDBand = 0; string uuid = ""; if (document != null) { foreach (var device in document.Devices) { List dataItems = device.GetDataItems(); lgInfo($"Inizio STEP 02 per caricare {dataItems.Count} dataItems"); foreach (var dataItem in dataItems) { try { currDataItem = formatDataItem(ref dSamplePeriod, ref threshDBand, ref uuid, dataItem); // aggiungo se non c'è... if (!dataItemMem.ContainsKey(dataItem.Id)) { dataItemMem.Add(dataItem.Id, currDataItem); } // salvo oggetto x registrazione su server MP-IO currMapoDataItem = new machDataItem() { uuid = dataItem.Id, Category = (DataItemCategory)dataItem.Category, Name = dataItem.Name, Type = dataItem.Type, SubType = dataItem.SubType, Units = dataItem.Units }; // aggiungo se non ci fosse if (!elencoDataItems.Contains(currMapoDataItem)) { elencoDataItems.Add(currMapoDataItem); } } catch (Exception exc) { lgError($"Eccezione in DevicesSuccessful / DataItem:{Environment.NewLine}{exc}"); } } } // invio IN BLOCCO il dataItem serializzati... if (elencoDataItems.Count > 0) { lgInfo($"STEP 04 invio dati di {elencoDataItems.Count} records"); sendDataItemsList(elencoDataItems); } hasReadItems = true; lgInfo($"STEP 05: memorizzati {dataItemMem.Count} oggetti in memoria"); } else { lgError("STEP 06 error: document null!"); } } /// /// 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 = $"{tipo}_{id}"; // cerco nel dizionario delle traduzioni SE esiste un valore e prendo quello, altrimenti uso il lemma... if (mtcParams.itemTranslation.ContainsKey(lemma)) { answ = mtcParams.itemTranslation[lemma]; } else { answ = lemma; } return answ; } /// /// Effettua log di un elenco componenti /// /// protected void logComponentsList(List elencoComponenti) { if (elencoComponenti != null) { foreach (var item in elencoComponenti) { lgInfo($"Component data | ID: {item.Id} | Name: {item.Name} | Type: {item.Type} | # items: {item.DataItems.Count}"); // se ho sottocomponenti richiamo... if (item.SubComponents != null) { if (item.SubComponents.Components.Count > 0) { logComponentsList(item.SubComponents.Components); } } if (item.DataItems.Count > 0) { logDataItemList(item.DataItems); } } } } /// /// Log elenco DataItems /// /// protected void logDataItemList(List elencoItems) { if (elencoItems != null) { // loggo devices principali... foreach (var item in elencoItems) { lgInfo($"Device data | ID: {item.Id} | Name: {item.Name} | Category: {item.Category} | # Type: {item.Type}"); } } } /// /// Effettua log di un devices (ed eventualmente dei sub-devices... /// /// protected void logDevicesList(List elencoDevices) { if (elencoDevices != null) { // loggo devices principali... foreach (var item in elencoDevices) { lgInfo($"Device data | ID: {item.Id} | Name: {item.Name} | UUID: {item.Uuid} | # items: {item.DataItems.Count}"); // se ho subItems descrivo pure loro... if (item.DataItems.Count > 0) { logDataItemList(item.DataItems); } if (item.Components.Components.Count > 0) { logComponentsList(item.Components.Components); } } } } /// /// Ricevuta modifica come stream da campionamenti ricevuti /// /// protected void StreamsSuccessful(MTConnectStreams.Document document) { checkAndSend(document, false); } #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 = ""; try { var currDataItem = dataItemMem[diKey]; answ = currDataItem.value; } catch (Exception exc) { Logging.Instance.Error($"Errore in getDataItemValue per {diKey}{Environment.NewLine}{exc}"); } 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")) { // cerco parametro contapezzi... string currPzCount = getDataItemValue(mtcParams.keyPartCount); if (isVerboseLog) { lgInfo($"contapezzi: {mtcParams.keyPartCount} --> {currPzCount}"); } // se ho un contapezzi... processo... if (!string.IsNullOrEmpty(currPzCount)) { int newVal = -1; Int32.TryParse(currPzCount, out newVal); contapezziPLC = newVal > -1 ? newVal : contapezziPLC; } } } /// /// 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 per MTC (read only) /// /// public override bool resetcontapezziPLC() { bool answ = false; return answ; } /// /// Effettua IMPOSTAZIONE FORZATA del contapezzi, NON POSSIBILE per MTC (read only) /// /// 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("MTC: 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; short esitoLink = doConnect(); lgInfo($"szStatusConnection MTC, 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 MTC: {szStatusConnection}{Environment.NewLine}{exc}"); connectionOk = false; lgInfo($"Eccezione in TryConnect, Adapter MTC 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: MTC 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) { string szStatusConnection = ""; try { MTC_ref.Stop(); connectionOk = false; lgInfo(szStatusConnection); lgInfo("Effettuata disconnessione adapter MTC!"); } catch (Exception exc) { lgFatal(exc, "Errore nella disconnessione dall'adapter MTC"); } } else { lgError("IMPOSSIBILE effettuare disconnessione MTC: Connessione non disponibile..."); } } #endregion Public Methods } }