diff --git a/IOB-WIN/IOB-WIN.csproj b/IOB-WIN/IOB-WIN.csproj index e5525b54..c1bab42b 100644 --- a/IOB-WIN/IOB-WIN.csproj +++ b/IOB-WIN/IOB-WIN.csproj @@ -254,6 +254,12 @@ Always + + Always + + + Always + Always diff --git a/IOB-WIN/IobMTC.cs b/IOB-WIN/IobMTC.cs index 5f20bc02..bf27530b 100644 --- a/IOB-WIN/IobMTC.cs +++ b/IOB-WIN/IobMTC.cs @@ -13,1139 +13,1166 @@ using MTConnectStreams = MTConnect.MTConnectStreams; namespace IOB_WIN { - public class IobMTC : IobGeneric - { - #region area comune (non modificare) + public class IobMTC : IobGeneric + { + #region area comune (non modificare) - /// - /// LookUpTable di decodifica da CNC a segnali tipo bitmap MAPO - /// - Dictionary signLUT = new Dictionary(); - /// - /// Struttura dove vengono memorizzati i dataitem ed i rispettivi valori x processing - /// - Dictionary dataItemMem = new Dictionary(); - /// - /// Oggetto MAIN x connessione MTC - /// - protected MTConnectClient MTC_ref; - /// - /// Gestione filtraggio dati - /// - protected bool enableDataFilter = false; - /// - /// Determina se ha effettuata lettura items in memoria x confronto... - /// - protected bool hasReadItems = false; - /// - /// Veto controllos tatus x log... - /// - protected DateTime vetoCheckStatus = DateTime.Now; - /// - /// Ultimo current received x gestione update periodico... - /// - protected DateTime lastCurrent = DateTime.Now; - /// - /// Abilitazione restart (da opt par...) - /// - protected bool enableMtcRestart = false; - /// - /// URL x salvataggio elenco dataItems MTC - /// - protected string urlSaveDataItems - { - get - { - string answ = ""; - try + /// + /// 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; + + /// + /// Struttura dove vengono memorizzati i dataitem ed i rispettivi valori x processing + /// + private Dictionary dataItemMem = new Dictionary(); + + /// + /// LookUpTable di decodifica da CNC a segnali tipo bitmap MAPO + /// + private Dictionary signLUT = new Dictionary(); + + /// + /// 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) { - string machineName = Environment.MachineName; - answ = $@"http://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDALIVE}/saveDataItems/{cIobConf.codIOB}"; - } - catch (Exception exc) - { - lgError(exc, "Errore in composizione urlSaveDataItems"); - } - return answ; - } - } - /// - /// Parametri specifici MTC - /// - protected MtcParamConf mtcParams { get; set; } - /// - /// 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); - } - } - /// - /// 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(); - } - /// - /// 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); - } - /// - /// Effettua reset del contapezzi, NON POSSIBILE per MTC (read only) - /// - /// - public override bool resetContapezziCNC() - { - bool answ = false; - return answ; - } - /// - /// Effettua IMPOSTAZIONE FORZATA del contapezzi, NON POSSIBILE per MTC (read only) - /// - /// - public override bool setContapezziCNC(int newPzCount) - { - bool answ = false; - return answ; - } - /// - /// 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); - } - } - } - } - /// - /// 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) + // gestione invio ritardato contapezzi + pzCountDelay = utils.CRI("pzCountDelay"); + // gestione data filtering... + if (!string.IsNullOrEmpty(getOptPar("ENABLE_DATA_FILTER"))) { - logComponentsList(item.SubComponents.Components); + bool.TryParse(getOptPar("ENABLE_DATA_FILTER"), out enableDataFilter); } - } - 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}"); - } - } - } - /// - /// 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; - } - /// - /// 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"); - } - } - /// - /// Ricevuta modifica come stream da campionamenti ricevuti - /// - /// - protected void StreamsSuccessful(MTConnectStreams.Document document) - { - checkAndSend(document, false); - } - /// - /// 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) - { -#if false - string sVal = $"STEP 03 | Category: {dataItem.Category} | Type: {dataItem.Type} | Id: {dataItem.Id} | Name: {dataItem.Name}"; - lgInfo(sVal); -#endif - try + // gestione restart MTC client... + if (!string.IsNullOrEmpty(getOptPar("ENABLE_MTC_RESTART"))) { - 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); - } + bool.TryParse(getOptPar("ENABLE_MTC_RESTART"), out enableMtcRestart); } - 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!"); - } - } - /// - /// 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 invio a MP/IO dell'elenco serializzato dei dataItems - /// - /// - private void sendDataItemsList(List dataItems) - { - string rawData = JsonConvert.SerializeObject(dataItems); - utils.callUrlNow($"{urlSaveDataItems}", rawData); - } - /// - /// 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; - } - /// - /// 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) - { - if (isVerboseLog) - { - lgInfo($"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; - } - /// - /// 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}"; - // condizion 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); - 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); - if (changed || forceSend) - { - accodaFLog(sVal, qEncodeFLog(time2, descr, dataItem.CDATA)); - } - else - { - if (isVerboseLog) - { - lgInfo($"NON ACCODATO sample poiché 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"); - } - } - /// - /// 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..."); - } - } - /// - /// 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(); - } - } - /// - /// 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; - } - - #endregion - - #region Metodi specifici (da verificare/completare in implementazione) - - /// - /// Effettua vero processing contapezzi - /// - public override void processContapezzi() - { - if (utils.CRB("enableContapezzi")) - { - // cerco parametro contapezzi... - string currPzCount = getDataItemValue(mtcParams.keyPartCount); -#if false - string currPzReq = getDataItemValue(mtcParams.keyPartReq); - string currPartId = getDataItemValue(mtcParams.keyPartId); - string currProg = getDataItemValue(mtcParams.keyProgName); -#endif - - // se ho un contapezzi... processo... - if (!string.IsNullOrEmpty(currPzCount)) - { - int newVal = -1; - Int32.TryParse(currPzCount, out newVal); - lastCountCNC = newVal > -1 ? newVal : lastCountCNC; - } - } - } - /// - /// 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}"); - } - } - /// - /// 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; - } - } - /// - /// 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 - ----------------------------------------------------- */ - - // Controllo booleano PING e POWERON... - string currPowerOn = getDataItemValue(mtcParams.condPowerOn.keyName); - // se valido il check ping lo eseguo... altrimenti lo do x buono - bool checkPing = !mtcParams.pingAsPowerOn; - if (!checkPing) - { - checkPing = (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 = (checkPing || checkPowerOn) ? 1 : 0; - - - // variabili RUN... - string currRun = getDataItemValue(mtcParams.keyRunMode); - - // controllo RUN MODE preliminare... CABLATO poiché è 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); - } - - - 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) - { + // init datetime counters + DateTime adesso = DateTime.Now; + lastPzCountSend = adesso; + lastWarnODL = 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(); - } + // ora leggo il file di conf specifico.... + string jsonFileName = getOptPar("MTC_PARAM_CONF"); + if (!string.IsNullOrEmpty(jsonFileName)) + { + // leggo il file... + loadMtcConf(jsonFileName); + } } - } - 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}"); - } + /// + /// 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 = $@"http://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDALIVE}/saveDataItems/{cIobConf.codIOB}"; + } + catch (Exception exc) + { + lgError(exc, "Errore in composizione urlSaveDataItems"); + } + return answ; + } + } + + /// + /// 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; + } + + /// + /// Effettua reset del contapezzi, NON POSSIBILE per MTC (read only) + /// + /// + public override bool resetContapezziCNC() + { + bool answ = false; + return answ; + } + + /// + /// Effettua IMPOSTAZIONE FORZATA del contapezzi, NON POSSIBILE per MTC (read only) + /// + /// + public override bool setContapezziCNC(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..."); + } + } + + /// + /// 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) + { + if (isVerboseLog) + { + lgInfo($"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); + } + + /// + /// 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}"; + // condizion 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); + 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); + if (changed || forceSend) + { + accodaFLog(sVal, qEncodeFLog(time2, descr, dataItem.CDATA)); + } + else + { + if (isVerboseLog) + { + lgInfo($"NON ACCODATO sample poiché 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"); + } + } + + /// + /// 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 area comune (non modificare) + + #region Metodi specifici (da verificare/completare in implementazione) + + /// + /// 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; + } + } + + /// + /// Recupero dati dinamici... + /// + public override Dictionary getDynData() + { + // valore non presente in vers default... se gestito fare override + 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); + + // se ho un contapezzi... processo... + if (!string.IsNullOrEmpty(currPzCount)) + { + int newVal = -1; + Int32.TryParse(currPzCount, out newVal); + lastCountCNC = newVal > -1 ? newVal : lastCountCNC; + } + } + } + + /// + /// 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}"); + } + } + + /// + /// 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; + } + + /// + /// 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 + ----------------------------------------------------- */ + + // Controllo booleano PING e POWERON... + string currPowerOn = getDataItemValue(mtcParams.condPowerOn.keyName); + // se valido il check ping lo eseguo... altrimenti lo do x buono + bool checkPing = !mtcParams.pingAsPowerOn; + if (!checkPing) + { + checkPing = (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 = (checkPing || checkPowerOn) ? 1 : 0; + + // variabili RUN... + string currRun = getDataItemValue(mtcParams.keyRunMode); + + // controllo RUN MODE preliminare... CABLATO poiché è 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); + } + + 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}"); + } + } + + #endregion Metodi specifici (da verificare/completare in implementazione) } - /// - /// 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; - } - - /// - /// Recupero dati dinamici... - /// - public override Dictionary getDynData() - { - // valore non presente in vers default... se gestito fare override - Dictionary outVal = new Dictionary(); - return outVal; - } - - #endregion - - } -} +} \ No newline at end of file diff --git a/IOB-WIN/IobSiemensLasco.cs b/IOB-WIN/IobSiemensLasco.cs index 695836d6..6a272a22 100644 --- a/IOB-WIN/IobSiemensLasco.cs +++ b/IOB-WIN/IobSiemensLasco.cs @@ -7,540 +7,547 @@ using System.Text.RegularExpressions; namespace IOB_WIN { - /// - /// Controllo Siemens specifico x impianti Lasco (Pressa bilancere Valvital) - /// - public class IobSiemensLasco : IobSiemens - { - /* -------------------------------------------------------------------------------- - * Controlli SIEMENS LASCO (Pressa principale in VALVITAL) - * - basasto su SIEMENS - * - S7 vers 1500 - * - * STRUTTURA MEMORIA DB1001 READ: 68 byte lettura, DB1002 68 byte byte scrittura, vedere doc allegato - * G:\Drive condivisi\30_Clienti\Valvital\Comunicazione PLC\LASCO - * - * !!!RISCRIVERE!!! - * - parametri processo - * - DBD00: Watchdog INT SAET Alive ( 1-9999 ) - * - * - DB60.DBD6: pressione camera filtrante (salvataggio del MAX ogni minuto) | var testVal = S7.Net.Types.Double.FromByteArray(memByteRead.Skip(0).Take(4).ToArray()); - * - DB60.DBD10: pressione linea utenze (salvataggio del MAX ogni minuto) - * - DB60.DBD14: temperatura acqua pulita (salvataggio del MAX ogni minuto) - * - * - BIT di stato - * - DBX2.1: READY TO RUN in AUTOMATICO - * - DBX2.3: Macchina in LAVORAZIONE - * - DBX2.4: WARNING Differenza tra Part Code MES - Saet (blu) - * - DBX2.5: se 1 --> LAMPADA ROSSA (allarmi almeno 1 attivo) - * - * PartCounter DINT 4.0 Conteggio Parziale di pezzi "OK" prodotti dalla macchina - * NumberCode String [12] 8.0 Valore numerico associato alla ricetta di produzione attualmente utilizzata dalla macchina - * NewCode INT 22.0 "1= Avvenuta ricezione del segnale ""richiesta nuovo ordine di produzione (NEW CODE)"" - * ricevuto dal server,impostabile su 1 solo quando la macchina NON è in produzione attiva" - * Potenza utilizzata ST.1 REAL 24 Potenza utilizzata dalla stazione di riscaldo 1 [kW] - * Potenza utilizzata ST.2 REAL 28 Potenza utilizzata dalla stazione di riscaldo 2 [kW] - * Potenza utilizzata ST.3 REAL 32 Potenza utilizzata dalla stazione di riscaldo 3 [kW] - * Potenza utilizzata ST.4 REAL 36 Potenza utilizzata dalla stazione di riscaldo 4 [kW] - * Lettura Pirometro ST.1 REAL 40 Lettura Pirometro della stazione di riscaldo 1 [°C] - * Lettura Pirometro ST.2 REAL 44 Lettura Pirometro della stazione di riscaldo 2 [°C] - * Lettura Pirometro ST.3 REAL 48 Lettura Pirometro della stazione di riscaldo 3 [°C] - * Lettura Pirometro ST.4 REAL 52 Lettura Pirometro della stazione di riscaldo 4 [°C] - * Temperatura Acqua Raff Conv. ST.1 REAL 56 Temperarura Acqua di Raffreddamento Convertitore Stazione di Riscaldo 1 [°C] - * Temperatura Acqua Raff Conv. ST.2 REAL 60 Temperarura Acqua di Raffreddamento Convertitore Stazione di Riscaldo 2 [°C] - * Temperatura Acqua Raff Conv. ST.3 REAL 64 Temperarura Acqua di Raffreddamento Convertitore Stazione di Riscaldo 3 [°C] - * Temperatura Acqua Raff Conv. ST.4 REAL 68 Temperarura Acqua di Raffreddamento Convertitore Stazione di Riscaldo 4 [°C] - * Part_Status ST.1 INT 72 Stato Pezzo Stazione di Riscaldo 1 (0=Assente 1=Grezzo 10=OK 11=NOK) - * Part_Status ST.2 INT 74 Stato Pezzo Stazione di Riscaldo 2 (0=Assente 1=Grezzo 10=OK 11=NOK) - * Part_Status ST.3 INT 76 Stato Pezzo Stazione di Riscaldo 3 (0=Assente 1=Grezzo 10=OK 11=NOK) - * Part_Status ST.4 INT 78 Stato Pezzo Stazione di Riscaldo 4 (0=Assente 1=Grezzo 10=OK 11=NOK) - * Reserve_12 REAL 80 Riserva - * Reserve_13 REAL 84 Riserva - * Reserve_14 REAL 88 Riserva - - * -------------------------------------------------------------------------------- */ - - protected DateTime lastPLCWatchDog; - protected int counterMes2Plc = 0; - protected int counterPlc2Mes = 0; - protected int counterPlc2MesWrote = 0; - - protected bool useNewSend = false; - /// - /// Classe base con i metodi x Siemens + /// Controllo Siemens specifico x impianti Lasco (Pressa bilancere Valvital) /// - /// - /// - public IobSiemensLasco(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf) + public class IobSiemensLasco : IobSiemens { - lgInfo("NEW IOB SIEMENS versione LASCO"); - lastPLCWatchDog = DateTime.Now.AddMinutes(-1); - useNewSend = string.IsNullOrWhiteSpace(getOptPar("USE_NEW_EXE_TASK")) ? false : true; - // imposto i parametri speciali x calcolo... - var chiaviTSVC = findOptPar("TSVC"); - if (chiaviTSVC.Count > 0) - { - lgInfo($"Trovate {chiaviTSVC.Count} chiavi TSVC"); - string[] codVal; - VCData currConf; - int periodo = 0; - VC_func funz = VC_func.POINT; - // accodo nella conf... - foreach (var item in chiaviTSVC) + /* -------------------------------------------------------------------------------- + * Controlli SIEMENS LASCO (Pressa principale in VALVITAL) + * - basasto su SIEMENS + * - S7 vers 1500 + * + * STRUTTURA MEMORIA DB1001 READ: 68 byte lettura, DB1002 68 byte byte scrittura, vedere doc allegato + * G:\Drive condivisi\30_Clienti\Valvital\Comunicazione PLC\LASCO + * + * !!!RISCRIVERE!!! + * - parametri processo + * - DBD00: Watchdog INT SAET Alive ( 1-9999 ) + * + * - DB60.DBD6: pressione camera filtrante (salvataggio del MAX ogni minuto) | var testVal = S7.Net.Types.Double.FromByteArray(memByteRead.Skip(0).Take(4).ToArray()); + * - DB60.DBD10: pressione linea utenze (salvataggio del MAX ogni minuto) + * - DB60.DBD14: temperatura acqua pulita (salvataggio del MAX ogni minuto) + * + * - BIT di stato + * - DBX2.1: READY TO RUN in AUTOMATICO + * - DBX2.3: Macchina in LAVORAZIONE + * - DBX2.4: WARNING Differenza tra Part Code MES - Saet (blu) + * - DBX2.5: se 1 --> LAMPADA ROSSA (allarmi almeno 1 attivo) + * + * PartCounter DINT 4.0 Conteggio Parziale di pezzi "OK" prodotti dalla macchina + * NumberCode String [12] 8.0 Valore numerico associato alla ricetta di produzione attualmente utilizzata dalla macchina + * NewCode INT 22.0 "1= Avvenuta ricezione del segnale ""richiesta nuovo ordine di produzione (NEW CODE)"" + * ricevuto dal server,impostabile su 1 solo quando la macchina NON è in produzione attiva" + * Potenza utilizzata ST.1 REAL 24 Potenza utilizzata dalla stazione di riscaldo 1 [kW] + * Potenza utilizzata ST.2 REAL 28 Potenza utilizzata dalla stazione di riscaldo 2 [kW] + * Potenza utilizzata ST.3 REAL 32 Potenza utilizzata dalla stazione di riscaldo 3 [kW] + * Potenza utilizzata ST.4 REAL 36 Potenza utilizzata dalla stazione di riscaldo 4 [kW] + * Lettura Pirometro ST.1 REAL 40 Lettura Pirometro della stazione di riscaldo 1 [°C] + * Lettura Pirometro ST.2 REAL 44 Lettura Pirometro della stazione di riscaldo 2 [°C] + * Lettura Pirometro ST.3 REAL 48 Lettura Pirometro della stazione di riscaldo 3 [°C] + * Lettura Pirometro ST.4 REAL 52 Lettura Pirometro della stazione di riscaldo 4 [°C] + * Temperatura Acqua Raff Conv. ST.1 REAL 56 Temperarura Acqua di Raffreddamento Convertitore Stazione di Riscaldo 1 [°C] + * Temperatura Acqua Raff Conv. ST.2 REAL 60 Temperarura Acqua di Raffreddamento Convertitore Stazione di Riscaldo 2 [°C] + * Temperatura Acqua Raff Conv. ST.3 REAL 64 Temperarura Acqua di Raffreddamento Convertitore Stazione di Riscaldo 3 [°C] + * Temperatura Acqua Raff Conv. ST.4 REAL 68 Temperarura Acqua di Raffreddamento Convertitore Stazione di Riscaldo 4 [°C] + * Part_Status ST.1 INT 72 Stato Pezzo Stazione di Riscaldo 1 (0=Assente 1=Grezzo 10=OK 11=NOK) + * Part_Status ST.2 INT 74 Stato Pezzo Stazione di Riscaldo 2 (0=Assente 1=Grezzo 10=OK 11=NOK) + * Part_Status ST.3 INT 76 Stato Pezzo Stazione di Riscaldo 3 (0=Assente 1=Grezzo 10=OK 11=NOK) + * Part_Status ST.4 INT 78 Stato Pezzo Stazione di Riscaldo 4 (0=Assente 1=Grezzo 10=OK 11=NOK) + * Reserve_12 REAL 80 Riserva + * Reserve_13 REAL 84 Riserva + * Reserve_14 REAL 88 Riserva + + * -------------------------------------------------------------------------------- */ + + protected int counterMes2Plc = 0; + protected int counterPlc2Mes = 0; + protected int counterPlc2MesWrote = 0; + protected DateTime lastPLCWatchDog; + protected bool useNewSend = false; + + /// + /// Classe base con i metodi x Siemens + /// + /// + /// + public IobSiemensLasco(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf) { - codVal = item.Value.Split(':'); - Enum.TryParse(codVal[0], out funz); - int.TryParse(codVal[1], out periodo); - currConf = new VCData() - { - Funzione = funz, - Period = periodo, - DTStart = DateTime.Now.AddHours(-1), - dataArray = new List() - }; - TSVC_Data.Add(item.Key.Replace("TSVC_", ""), currConf); - } - // documento... - foreach (var item in TSVC_Data) - { - lgInfo($"TSVC: {item.Key} | periodo: {item.Value.Period} | funz: {item.Value.Funzione}"); - // salvo i valori PREC... - LastTSVC.Add(item.Key, 0); - } - } - } - - #region Metodi specifici (da verificare/completare in implementazione) - - /// - /// Effettua processing del recupero delle OVERRIDE (spindle, feedrate, rapid) - /// - public override void processOverride() - { - } - - public override void processWhatchDog() - { - // scrive nel primo byte, ultimo bit, il watchdog, mentre scrive nel primo 1 = setup, 0 = run - // scrivo 1 volta al secondo il contatore incrementale su area apposita - DateTime adesso = DateTime.Now; - if (adesso.Subtract(lastPLCWatchDog).TotalSeconds > 1) - { - // incremento - counterMes2Plc++; - // se > 1 --> 0 (balla solo 0..1) - if (counterMes2Plc > 1) counterMes2Plc = 0; - // salvo su DB - Dictionary task2exe = new Dictionary(); - Dictionary taskDone = new Dictionary(); - task2exe.Add("sendWatchDogMes2Plc", counterMes2Plc.ToString()); - taskDone = executeTasks(task2exe); - // salvo watchdog PLC - lastPLCWatchDog = adesso; - } - } - - /// - /// Processo i task richiesti e li elimino dalla coda 1:1 - /// - /// - public override Dictionary executeTasks(Dictionary task2exe) - { - // Verificare il protocollo: dovrebeb togliere SOLO i task eseguiti... - Dictionary taskDone = new Dictionary(); - bool taskOk = false; - string taskVal = ""; - string memAddrWrite = ""; - if (task2exe != null) - { - // inizio VUOTO - byte[] MemBlock = new byte[parametri.memSizeWrite]; - - // controllo su OPT_PAR se usare nuovo metodo exe task... - if (useNewSend) - { - // cerco task specifici - foreach (var item in task2exe) - { - taskOk = false; - taskVal = ""; - // converto richiesta in enum... - taskType tName = taskType.nihil; - Enum.TryParse(item.Key, out tName); - // controllo sulla KEY - switch (tName) + lgInfo("NEW IOB SIEMENS versione LASCO"); + lastPLCWatchDog = DateTime.Now.AddMinutes(-1); + useNewSend = string.IsNullOrWhiteSpace(getOptPar("USE_NEW_EXE_TASK")) ? false : true; + // imposto i parametri speciali x calcolo... + var chiaviTSVC = findOptPar("TSVC"); + if (chiaviTSVC.Count > 0) { - case taskType.nihil: - case taskType.fixStopSetup: - case taskType.forceResetPzCount: - case taskType.forceSetPzCount: - case taskType.setProg: - taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC"; - break; - case taskType.setArt: - case taskType.setComm: - case taskType.setPzComm: - saveProdData(item); - int byteSize = 0; - // recupero dati da memMap... altrimenti NULLA - if (memMap.mMapWrite.ContainsKey(item.Key)) + lgInfo($"Trovate {chiaviTSVC.Count} chiavi TSVC"); + string[] codVal; + VCData currConf; + int periodo = 0; + VC_func funz = VC_func.POINT; + // accodo nella conf... + foreach (var item in chiaviTSVC) { - dataConf currMem = memMap.mMapWrite[item.Key]; - byteSize = currMem.size; - memAddrWrite = currMem.memAddr; - MemBlock = new byte[byteSize]; - if (currMem.tipoMem == plcDataType.String) - { - saveStringOnMemBlock(ref MemBlock, item.Key, 0, byteSize); - } - else if (currMem.tipoMem == plcDataType.DInt) - { - int valDInt = 0; - int.TryParse(item.Value, out valDInt); - MemBlock = S7.Net.Types.DInt.ToByteArray(valDInt); - } - else if (currMem.tipoMem == plcDataType.Int) - { - short valDInt = 0; - short.TryParse(item.Value, out valDInt); - MemBlock = S7.Net.Types.Int.ToByteArray(valDInt); - } + codVal = item.Value.Split(':'); + Enum.TryParse(codVal[0], out funz); + int.TryParse(codVal[1], out periodo); + currConf = new VCData() + { + Funzione = funz, + Period = periodo, + DTStart = DateTime.Now.AddHours(-1), + dataArray = new List() + }; + TSVC_Data.Add(item.Key.Replace("TSVC_", ""), currConf); } - taskVal = item.Value; - break; - case taskType.sendWatchDogMes2Plc: - // processo scrittura BIT su DB150.DBX4.0 - MemBlock = new byte[1]; - memAddrWrite = "DB1002.DBB0"; - // compogo in byte... primo bit è setup/run, ultimo è watchdog - int valore = inSetup ? 1 : 0; - valore += (byte)(counterMes2Plc << 7); - MemBlock[0] = (byte)valore; - taskVal = $"VALUE DB1002.92 --> {valore} | counter interno {counterMes2Plc}"; - break; - case taskType.setParameter: - // richiedo da URL i parametri WRITE da popolare - lgInfo("Chiamata processMemWriteRequests"); - taskVal = processMemWriteRequests(); - // se restituiscce "" faccio altra prova... - if (string.IsNullOrEmpty(taskVal)) + // documento... + foreach (var item in TSVC_Data) { - // i parametri me li aspetto come stringa composta paramName|paramvalue - if (item.Value.Contains("|")) - { - string[] paramsJob = item.Value.Split('|'); - taskVal = $"REQUEST SET PARAMETERS: {paramsJob[0]} --> {paramsJob[1]}"; - } - else - { - taskVal = $"WRONG REQUEST FOR SET PARAMETERS: {item.Value} doesnt contain pipe for splitting key/value"; - } + lgInfo($"TSVC: {item.Key} | periodo: {item.Value.Period} | funz: {item.Value.Funzione}"); + // salvo i valori PREC... + LastTSVC.Add(item.Key, 0); } - break; - case taskType.startSetup: - // salvo che SONO IN SETUP! - inSetup = true; - break; - case taskType.stopSetup: - // salvo che SONO FUORI DAL SETUP! - inSetup = false; - break; - default: - taskVal = "SKIPPED | NO EXEC"; - break; } - // aggiungo task! - taskDone.Add(item.Key, taskVal); - // scrivo comunque! - taskOk = S7WriteBB(ref MemBlock, memAddrWrite); - if (!taskOk) + } + + #region Metodi specifici (da verificare/completare in implementazione) + + /// + /// Processo i task richiesti e li elimino dalla coda 1:1 + /// + /// + public override Dictionary executeTasks(Dictionary task2exe) + { + // Verificare il protocollo: dovrebeb togliere SOLO i task eseguiti... + Dictionary taskDone = new Dictionary(); + bool taskOk = false; + string taskVal = ""; + string memAddrWrite = ""; + if (task2exe != null) { - lgError($"Errore in S7WriteBB durante executeTasks: {item.Key} | {item.Value}"); - } - } - } - else - { - // cerco task specifici: se ho startSetup --> imposto bit DBB701.DBB0.4 - foreach (var item in task2exe) - { - taskOk = false; - taskVal = ""; - // converto richiesta in enum... - taskType tName = taskType.nihil; - Enum.TryParse(item.Key, out tName); - // controllo sulla KEY - switch (tName) - { - case taskType.nihil: - case taskType.fixStopSetup: - case taskType.forceResetPzCount: - case taskType.forceSetPzCount: - case taskType.startSetup: - case taskType.stopSetup: - taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC"; - break; - case taskType.setArt: - case taskType.setComm: - case taskType.setProg: - saveProdData(item); - taskVal = item.Value; - break; - case taskType.sendWatchDogMes2Plc: - // compogo in byte... primo bit è setup/run, ultimo è watchdog - int valore = inSetup ? 1 : 0; - valore += (byte)(counterMes2Plc << 7); - MemBlock[0] = (byte)valore; - taskVal = $"VALUE DB1002.92 --> {counterMes2Plc}"; - break; + // inizio VUOTO + byte[] MemBlock = new byte[parametri.memSizeWrite]; - case taskType.setParameter: - // richiedo da URL i parametri WRITE da popolare - lgInfo("Chiamata processMemWriteRequests"); - taskVal = processMemWriteRequests(); - // se restituiscce "" faccio altra prova... - if (string.IsNullOrEmpty(taskVal)) + // controllo su OPT_PAR se usare nuovo metodo exe task... + if (useNewSend) { - // i parametri me li aspetto come stringa composta paramName|paramvalue - if (item.Value.Contains("|")) - { - string[] paramsJob = item.Value.Split('|'); - taskVal = $"REQUEST SET PARAMETERS: {paramsJob[0]} --> {paramsJob[1]}"; - } - else - { - taskVal = $"WRONG REQUEST FOR SET PARAMETERS: {item.Value} doesnt contain pipe for splitting key/value"; - } + // cerco task specifici + foreach (var item in task2exe) + { + taskOk = false; + taskVal = ""; + // converto richiesta in enum... + taskType tName = taskType.nihil; + Enum.TryParse(item.Key, out tName); + // controllo sulla KEY + switch (tName) + { + case taskType.nihil: + case taskType.fixStopSetup: + case taskType.forceResetPzCount: + case taskType.forceSetPzCount: + case taskType.setProg: + taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC"; + break; + + case taskType.setArt: + case taskType.setComm: + case taskType.setPzComm: + saveProdData(item); + int byteSize = 0; + // recupero dati da memMap... altrimenti NULLA + if (memMap.mMapWrite.ContainsKey(item.Key)) + { + dataConf currMem = memMap.mMapWrite[item.Key]; + byteSize = currMem.size; + memAddrWrite = currMem.memAddr; + MemBlock = new byte[byteSize]; + if (currMem.tipoMem == plcDataType.String) + { + saveStringOnMemBlock(ref MemBlock, item.Key, 0, byteSize); + } + else if (currMem.tipoMem == plcDataType.DInt) + { + int valDInt = 0; + int.TryParse(item.Value, out valDInt); + MemBlock = S7.Net.Types.DInt.ToByteArray(valDInt); + } + else if (currMem.tipoMem == plcDataType.Int) + { + short valDInt = 0; + short.TryParse(item.Value, out valDInt); + MemBlock = S7.Net.Types.Int.ToByteArray(valDInt); + } + } + taskVal = item.Value; + break; + + case taskType.sendWatchDogMes2Plc: + // processo scrittura BIT su DB150.DBX4.0 + MemBlock = new byte[1]; + memAddrWrite = "DB1002.DBB0"; + // compogo in byte... primo bit è setup/run, ultimo è watchdog + int valore = inSetup ? 1 : 0; + valore += (byte)(counterMes2Plc << 7); + MemBlock[0] = (byte)valore; + taskVal = $"VALUE DB1002.92 --> {valore} | counter interno {counterMes2Plc}"; + break; + + case taskType.setParameter: + // richiedo da URL i parametri WRITE da popolare + lgInfo("Chiamata processMemWriteRequests"); + taskVal = processMemWriteRequests(); + // se restituiscce "" faccio altra prova... + if (string.IsNullOrEmpty(taskVal)) + { + // i parametri me li aspetto come stringa composta paramName|paramvalue + if (item.Value.Contains("|")) + { + string[] paramsJob = item.Value.Split('|'); + taskVal = $"REQUEST SET PARAMETERS: {paramsJob[0]} --> {paramsJob[1]}"; + } + else + { + taskVal = $"WRONG REQUEST FOR SET PARAMETERS: {item.Value} doesnt contain pipe for splitting key/value"; + } + } + break; + + case taskType.startSetup: + // salvo che SONO IN SETUP! + inSetup = true; + break; + + case taskType.stopSetup: + // salvo che SONO FUORI DAL SETUP! + inSetup = false; + break; + + default: + taskVal = "SKIPPED | NO EXEC"; + break; + } + // aggiungo task! + taskDone.Add(item.Key, taskVal); + // scrivo comunque! + taskOk = S7WriteBB(ref MemBlock, memAddrWrite); + if (!taskOk) + { + lgError($"Errore in S7WriteBB durante executeTasks: {item.Key} | {item.Value}"); + } + } + } + else + { + // cerco task specifici: se ho startSetup --> imposto bit DBB701.DBB0.4 + foreach (var item in task2exe) + { + taskOk = false; + taskVal = ""; + // converto richiesta in enum... + taskType tName = taskType.nihil; + Enum.TryParse(item.Key, out tName); + // controllo sulla KEY + switch (tName) + { + case taskType.nihil: + case taskType.fixStopSetup: + case taskType.forceResetPzCount: + case taskType.forceSetPzCount: + case taskType.startSetup: + case taskType.stopSetup: + taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC"; + break; + + case taskType.setArt: + case taskType.setComm: + case taskType.setProg: + saveProdData(item); + taskVal = item.Value; + break; + + case taskType.sendWatchDogMes2Plc: + // compogo in byte... primo bit è setup/run, ultimo è watchdog + int valore = inSetup ? 1 : 0; + valore += (byte)(counterMes2Plc << 7); + MemBlock[0] = (byte)valore; + taskVal = $"VALUE DB1002.92 --> {counterMes2Plc}"; + break; + + case taskType.setParameter: + // richiedo da URL i parametri WRITE da popolare + lgInfo("Chiamata processMemWriteRequests"); + taskVal = processMemWriteRequests(); + // se restituiscce "" faccio altra prova... + if (string.IsNullOrEmpty(taskVal)) + { + // i parametri me li aspetto come stringa composta paramName|paramvalue + if (item.Value.Contains("|")) + { + string[] paramsJob = item.Value.Split('|'); + taskVal = $"REQUEST SET PARAMETERS: {paramsJob[0]} --> {paramsJob[1]}"; + } + else + { + taskVal = $"WRONG REQUEST FOR SET PARAMETERS: {item.Value} doesnt contain pipe for splitting key/value"; + } + } + break; + + default: + taskVal = "SKIPPED | NO EXEC"; + break; + } + // aggiungo task! + taskDone.Add(item.Key, taskVal); + } + // controllo SE HO da scrivere articolo/commessa/programma + saveStringOnMemBlock(ref MemBlock, "setArt", 2, 22); + saveStringOnMemBlock(ref MemBlock, "setComm", 24, 22); + saveStringOnMemBlock(ref MemBlock, "setProg", 46, 22); + + // scrivo comunque! + taskOk = S7WriteBB(ref MemBlock); } - break; - default: - taskVal = "SKIPPED | NO EXEC"; - break; } - // aggiungo task! - taskDone.Add(item.Key, taskVal); - } - // controllo SE HO da scrivere articolo/commessa/programma - saveStringOnMemBlock(ref MemBlock, "setArt", 2, 22); - saveStringOnMemBlock(ref MemBlock, "setComm", 24, 22); - saveStringOnMemBlock(ref MemBlock, "setProg", 46, 22); - - // scrivo comunque! - taskOk = S7WriteBB(ref MemBlock); + return taskDone; } - } - return taskDone; - } - - /// - /// Recupero dati dinamici in formato dictionary - /// - /// - public override Dictionary getDynData() - { - Dictionary outVal = new Dictionary(); - // processing - try - { - // le 3 posizioni sono in 1/10 mm x cui vanno divise x 10... x avere MM - double RamPosition = S7.Net.Types.Int.FromByteArray(RawInput.Skip(18).Take(2).ToArray()) / 10; - double LowerEjectorPosition = S7.Net.Types.Int.FromByteArray(RawInput.Skip(20).Take(2).ToArray()) / 10; - double UpperTool = S7.Net.Types.Int.FromByteArray(RawInput.Skip(22).Take(2).ToArray()) / 10; - // temp in °C - int TempMainMotorU = S7.Net.Types.Int.FromByteArray(RawInput.Skip(24).Take(2).ToArray()); - int TempMainMotorV = S7.Net.Types.Int.FromByteArray(RawInput.Skip(26).Take(2).ToArray()); - int TempMainMotorW = S7.Net.Types.Int.FromByteArray(RawInput.Skip(28).Take(2).ToArray()); - int TempSpindleNut = S7.Net.Types.Int.FromByteArray(RawInput.Skip(30).Take(2).ToArray()); - int TempMotoModule = S7.Net.Types.Int.FromByteArray(RawInput.Skip(32).Take(2).ToArray()); - int TempOilCirculation = S7.Net.Types.Int.FromByteArray(RawInput.Skip(34).Take(2).ToArray()); - int TempHydraulicUnit = S7.Net.Types.Int.FromByteArray(RawInput.Skip(36).Take(2).ToArray()); - // press in BAR - int PressHydraulicPump = S7.Net.Types.Int.FromByteArray(RawInput.Skip(38).Take(2).ToArray()); - int PressHydraulicAccumulator = S7.Net.Types.Int.FromByteArray(RawInput.Skip(40).Take(2).ToArray()); - int PressCounterforceOil = S7.Net.Types.Int.FromByteArray(RawInput.Skip(42).Take(2).ToArray()); - int PressCounterforceGas = S7.Net.Types.Int.FromByteArray(RawInput.Skip(44).Take(2).ToArray()); - // forze in kN (10^3 Newton) - int ForcePressureActual = S7.Net.Types.DInt.FromByteArray(RawInput.Skip(46).Take(4).ToArray()); - int ForceOnBushing = S7.Net.Types.Int.FromByteArray(RawInput.Skip(50).Take(2).ToArray()); - - if (utils.CRB("enableTSVC")) + /// + /// Recupero dati dinamici in formato dictionary + /// + /// + public override Dictionary getDynData() { - bool[] scaduti = new bool[16]; - // salvo in stack le VC rilevate - scaduti[0] = stackVal_TSVC("RamPosition", RamPosition); - scaduti[1] = stackVal_TSVC("LowerEjectorPosition", LowerEjectorPosition); - scaduti[2] = stackVal_TSVC("UpperTool", UpperTool); - scaduti[3] = stackVal_TSVC("TempMainMotorU", TempMainMotorU); - scaduti[4] = stackVal_TSVC("TempMainMotorV", TempMainMotorV); - scaduti[5] = stackVal_TSVC("TempMainMotorW", TempMainMotorW); - scaduti[6] = stackVal_TSVC("TempSpindleNut", TempSpindleNut); - scaduti[7] = stackVal_TSVC("TempMotoModule", TempMotoModule); - scaduti[8] = stackVal_TSVC("TempOilCirculation", TempOilCirculation); - scaduti[9] = stackVal_TSVC("TempHydraulicUnit", TempHydraulicUnit); - scaduti[10] = stackVal_TSVC("PressHydraulicPump", PressHydraulicPump); - scaduti[11] = stackVal_TSVC("PressHydraulicAccumulator", PressHydraulicAccumulator); - scaduti[12] = stackVal_TSVC("PressCounterforceOil", PressCounterforceOil); - scaduti[13] = stackVal_TSVC("PressCounterforceGas", PressCounterforceGas); - scaduti[14] = stackVal_TSVC("ForcePressureActual", ForcePressureActual); - scaduti[15] = stackVal_TSVC("ForceOnBushing", ForceOnBushing); + Dictionary outVal = new Dictionary(); + // processing + try + { + // le 3 posizioni sono in 1/10 mm x cui vanno divise x 10... x avere MM + double RamPosition = S7.Net.Types.Int.FromByteArray(RawInput.Skip(18).Take(2).ToArray()) / 10; + double LowerEjectorPosition = S7.Net.Types.Int.FromByteArray(RawInput.Skip(20).Take(2).ToArray()) / 10; + double UpperTool = S7.Net.Types.Int.FromByteArray(RawInput.Skip(22).Take(2).ToArray()) / 10; + // temp in °C + int TempMainMotorU = S7.Net.Types.Int.FromByteArray(RawInput.Skip(24).Take(2).ToArray()); + int TempMainMotorV = S7.Net.Types.Int.FromByteArray(RawInput.Skip(26).Take(2).ToArray()); + int TempMainMotorW = S7.Net.Types.Int.FromByteArray(RawInput.Skip(28).Take(2).ToArray()); + int TempSpindleNut = S7.Net.Types.Int.FromByteArray(RawInput.Skip(30).Take(2).ToArray()); + int TempMotoModule = S7.Net.Types.Int.FromByteArray(RawInput.Skip(32).Take(2).ToArray()); + int TempOilCirculation = S7.Net.Types.Int.FromByteArray(RawInput.Skip(34).Take(2).ToArray()); + int TempHydraulicUnit = S7.Net.Types.Int.FromByteArray(RawInput.Skip(36).Take(2).ToArray()); + // press in BAR + int PressHydraulicPump = S7.Net.Types.Int.FromByteArray(RawInput.Skip(38).Take(2).ToArray()); + int PressHydraulicAccumulator = S7.Net.Types.Int.FromByteArray(RawInput.Skip(40).Take(2).ToArray()); + int PressCounterforceOil = S7.Net.Types.Int.FromByteArray(RawInput.Skip(42).Take(2).ToArray()); + int PressCounterforceGas = S7.Net.Types.Int.FromByteArray(RawInput.Skip(44).Take(2).ToArray()); + // forze in kN (10^3 Newton) + int ForcePressureActual = S7.Net.Types.DInt.FromByteArray(RawInput.Skip(46).Take(4).ToArray()); + int ForceOnBushing = S7.Net.Types.Int.FromByteArray(RawInput.Skip(50).Take(2).ToArray()); - // verifico SE devo riportare dati VC - if (baseUtils.CountTrue(scaduti) > 0) - { - RamPosition = getVal_TSVC_int("RamPosition", scaduti[0]); - LowerEjectorPosition = getVal_TSVC_int("LowerEjectorPosition", scaduti[1]); - UpperTool = getVal_TSVC_int("UpperTool", scaduti[2]); - TempMainMotorU = getVal_TSVC_int("TempMainMotorU", scaduti[3]); - TempMainMotorV = getVal_TSVC_int("TempMainMotorV", scaduti[4]); - TempMainMotorW = getVal_TSVC_int("TempMainMotorW", scaduti[5]); - TempSpindleNut = getVal_TSVC_int("TempSpindleNut", scaduti[6]); - TempMotoModule = getVal_TSVC_int("TempMotoModule", scaduti[7]); - TempOilCirculation = getVal_TSVC_int("TempOilCirculation", scaduti[8]); - TempHydraulicUnit = getVal_TSVC_int("TempHydraulicUnit", scaduti[9]); - PressHydraulicPump = getVal_TSVC_int("PressHydraulicPump", scaduti[10]); - PressHydraulicAccumulator = getVal_TSVC_int("PressHydraulicAccumulator", scaduti[11]); - PressCounterforceOil = getVal_TSVC_int("PressCounterforceOil", scaduti[12]); - PressCounterforceGas = getVal_TSVC_int("PressCounterforceGas", scaduti[13]); - ForcePressureActual = getVal_TSVC_int("ForcePressureActual", scaduti[14]); - ForceOnBushing = getVal_TSVC_int("ForceOnBushing", scaduti[15]); - //outVal.Add("DYNDATA", $"RamPosition {RamPosition:N2} | TempMainMotorV {TempMainMotorV:N2} | TempOilCirculation {TempOilCirculation:N2} | PressCounterforceGas {PressCounterforceGas}"); - outVal.Add("RamPosition", $"{RamPosition:N1}"); - outVal.Add("LowerEjectorPosition", $"{LowerEjectorPosition:N1}"); - outVal.Add("UpperTool", $"{UpperTool:N1}"); - outVal.Add("TempMainMotorU", $"{TempMainMotorU}"); - outVal.Add("TempMainMotorV", $"{TempMainMotorV}"); - outVal.Add("TempMainMotorW", $"{TempMainMotorW}"); - outVal.Add("TempSpindleNut", $"{TempSpindleNut}"); - outVal.Add("TempMotoModule", $"{TempMotoModule}"); - outVal.Add("TempOilCirculation", $"{TempOilCirculation}"); - outVal.Add("TempHydraulicUnit", $"{TempHydraulicUnit}"); - outVal.Add("PressHydraulicPump", $"{PressHydraulicPump}"); - outVal.Add("PressHydraulicAccumulator", $"{PressHydraulicAccumulator}"); - outVal.Add("PressCounterforceOil", $"{PressCounterforceOil}"); - outVal.Add("PressCounterforceGas", $"{PressCounterforceGas}"); - outVal.Add("ForcePressureActual", $"{ForcePressureActual}"); - outVal.Add("ForceOnBushing", $"{ForceOnBushing}"); + if (utils.CRB("enableTSVC")) + { + bool[] scaduti = new bool[16]; + // salvo in stack le VC rilevate + scaduti[0] = stackVal_TSVC("RamPosition", RamPosition); + scaduti[1] = stackVal_TSVC("LowerEjectorPosition", LowerEjectorPosition); + scaduti[2] = stackVal_TSVC("UpperTool", UpperTool); + scaduti[3] = stackVal_TSVC("TempMainMotorU", TempMainMotorU); + scaduti[4] = stackVal_TSVC("TempMainMotorV", TempMainMotorV); + scaduti[5] = stackVal_TSVC("TempMainMotorW", TempMainMotorW); + scaduti[6] = stackVal_TSVC("TempSpindleNut", TempSpindleNut); + scaduti[7] = stackVal_TSVC("TempMotoModule", TempMotoModule); + scaduti[8] = stackVal_TSVC("TempOilCirculation", TempOilCirculation); + scaduti[9] = stackVal_TSVC("TempHydraulicUnit", TempHydraulicUnit); + scaduti[10] = stackVal_TSVC("PressHydraulicPump", PressHydraulicPump); + scaduti[11] = stackVal_TSVC("PressHydraulicAccumulator", PressHydraulicAccumulator); + scaduti[12] = stackVal_TSVC("PressCounterforceOil", PressCounterforceOil); + scaduti[13] = stackVal_TSVC("PressCounterforceGas", PressCounterforceGas); + scaduti[14] = stackVal_TSVC("ForcePressureActual", ForcePressureActual); + scaduti[15] = stackVal_TSVC("ForceOnBushing", ForceOnBushing); - // salvo! - LastTSVC["RamPosition"] = RamPosition; - LastTSVC["LowerEjectorPosition"] = LowerEjectorPosition; - LastTSVC["UpperTool"] = UpperTool; - LastTSVC["TempMainMotorU"] = TempMainMotorU; - LastTSVC["TempMainMotorV"] = TempMainMotorV; - LastTSVC["TempMainMotorW"] = TempMainMotorW; - LastTSVC["TempSpindleNut"] = TempSpindleNut; - LastTSVC["TempMotoModule"] = TempMotoModule; - LastTSVC["TempOilCirculation"] = TempOilCirculation; - LastTSVC["TempHydraulicUnit"] = TempHydraulicUnit; - LastTSVC["PressHydraulicPump"] = PressHydraulicPump; - LastTSVC["PressHydraulicAccumulator"] = PressHydraulicAccumulator; - LastTSVC["PressCounterforceOil"] = PressCounterforceOil; - LastTSVC["PressCounterforceGas"] = PressCounterforceGas; - LastTSVC["ForcePressureActual"] = ForcePressureActual; - LastTSVC["ForceOnBushing"] = ForceOnBushing; - } - else - { - outVal.Add("DYNDATA", $"RamPosition {LastTSVC["RamPosition"]:N1} | ForcePressureActual {LastTSVC["ForcePressureActual"]} | ForceOnBushing {LastTSVC["ForceOnBushing"]}"); - } + // verifico SE devo riportare dati VC + if (baseUtils.CountTrue(scaduti) > 0) + { + RamPosition = getVal_TSVC_int("RamPosition", scaduti[0]); + LowerEjectorPosition = getVal_TSVC_int("LowerEjectorPosition", scaduti[1]); + UpperTool = getVal_TSVC_int("UpperTool", scaduti[2]); + TempMainMotorU = getVal_TSVC_int("TempMainMotorU", scaduti[3]); + TempMainMotorV = getVal_TSVC_int("TempMainMotorV", scaduti[4]); + TempMainMotorW = getVal_TSVC_int("TempMainMotorW", scaduti[5]); + TempSpindleNut = getVal_TSVC_int("TempSpindleNut", scaduti[6]); + TempMotoModule = getVal_TSVC_int("TempMotoModule", scaduti[7]); + TempOilCirculation = getVal_TSVC_int("TempOilCirculation", scaduti[8]); + TempHydraulicUnit = getVal_TSVC_int("TempHydraulicUnit", scaduti[9]); + PressHydraulicPump = getVal_TSVC_int("PressHydraulicPump", scaduti[10]); + PressHydraulicAccumulator = getVal_TSVC_int("PressHydraulicAccumulator", scaduti[11]); + PressCounterforceOil = getVal_TSVC_int("PressCounterforceOil", scaduti[12]); + PressCounterforceGas = getVal_TSVC_int("PressCounterforceGas", scaduti[13]); + ForcePressureActual = getVal_TSVC_int("ForcePressureActual", scaduti[14]); + ForceOnBushing = getVal_TSVC_int("ForceOnBushing", scaduti[15]); + //outVal.Add("DYNDATA", $"RamPosition {RamPosition:N2} | TempMainMotorV {TempMainMotorV:N2} | TempOilCirculation {TempOilCirculation:N2} | PressCounterforceGas {PressCounterforceGas}"); + outVal.Add("RamPosition", $"{RamPosition:N1}"); + outVal.Add("LowerEjectorPosition", $"{LowerEjectorPosition:N1}"); + outVal.Add("UpperTool", $"{UpperTool:N1}"); + outVal.Add("TempMainMotorU", $"{TempMainMotorU}"); + outVal.Add("TempMainMotorV", $"{TempMainMotorV}"); + outVal.Add("TempMainMotorW", $"{TempMainMotorW}"); + outVal.Add("TempSpindleNut", $"{TempSpindleNut}"); + outVal.Add("TempMotoModule", $"{TempMotoModule}"); + outVal.Add("TempOilCirculation", $"{TempOilCirculation}"); + outVal.Add("TempHydraulicUnit", $"{TempHydraulicUnit}"); + outVal.Add("PressHydraulicPump", $"{PressHydraulicPump}"); + outVal.Add("PressHydraulicAccumulator", $"{PressHydraulicAccumulator}"); + outVal.Add("PressCounterforceOil", $"{PressCounterforceOil}"); + outVal.Add("PressCounterforceGas", $"{PressCounterforceGas}"); + outVal.Add("ForcePressureActual", $"{ForcePressureActual}"); + outVal.Add("ForceOnBushing", $"{ForceOnBushing}"); + + // salvo! + LastTSVC["RamPosition"] = RamPosition; + LastTSVC["LowerEjectorPosition"] = LowerEjectorPosition; + LastTSVC["UpperTool"] = UpperTool; + LastTSVC["TempMainMotorU"] = TempMainMotorU; + LastTSVC["TempMainMotorV"] = TempMainMotorV; + LastTSVC["TempMainMotorW"] = TempMainMotorW; + LastTSVC["TempSpindleNut"] = TempSpindleNut; + LastTSVC["TempMotoModule"] = TempMotoModule; + LastTSVC["TempOilCirculation"] = TempOilCirculation; + LastTSVC["TempHydraulicUnit"] = TempHydraulicUnit; + LastTSVC["PressHydraulicPump"] = PressHydraulicPump; + LastTSVC["PressHydraulicAccumulator"] = PressHydraulicAccumulator; + LastTSVC["PressCounterforceOil"] = PressCounterforceOil; + LastTSVC["PressCounterforceGas"] = PressCounterforceGas; + LastTSVC["ForcePressureActual"] = ForcePressureActual; + LastTSVC["ForceOnBushing"] = ForceOnBushing; + } + else + { + outVal.Add("DYNDATA", $"RamPosition {LastTSVC["RamPosition"]:N1} | ForcePressureActual {LastTSVC["ForcePressureActual"]} | ForceOnBushing {LastTSVC["ForceOnBushing"]}"); + } + } + else + { + outVal.Add("DYNDATA", $"RamPosition {LastTSVC["RamPosition"]:N1} | ForcePressureActual {LastTSVC["ForcePressureActual"]} | ForceOnBushing {LastTSVC["ForceOnBushing"]}"); + } + } + catch (Exception exc) + { + lgError(exc, "Errore in getDynData x Siemens Aprochim"); + } + return outVal; } - else + + public override string getPrgName() { - outVal.Add("DYNDATA", $"RamPosition {LastTSVC["RamPosition"]:N1} | ForcePressureActual {LastTSVC["ForcePressureActual"]} | ForceOnBushing {LastTSVC["ForceOnBushing"]}"); + string answ = ""; + try + { + string rawProdCode = S7.Net.Types.String.FromByteArray(RawInput.Skip(54).Take(12).ToArray()); + // primi due char sono \f e \n avanzamento carta e nuova linea... + answ = Regex.Replace(rawProdCode, @"\t|\n|\r|\f", ""); + } + catch (Exception exc) + { + lgError($"Errore in decodifica product code{Environment.NewLine}{exc}"); + } + return answ; } - } - catch (Exception exc) - { - lgError(exc, "Errore in getDynData x Siemens Aprochim"); - } - return outVal; + + /// + /// Effettua processing del recupero delle OVERRIDE (spindle, feedrate, rapid) + /// + public override void processOverride() + { + } + + public override void processWhatchDog() + { + // scrive nel primo byte, ultimo bit, il watchdog, mentre scrive nel primo 1 = setup, 0 = run + // scrivo 1 volta al secondo il contatore incrementale su area apposita + DateTime adesso = DateTime.Now; + if (adesso.Subtract(lastPLCWatchDog).TotalSeconds > 1) + { + // incremento + counterMes2Plc++; + // se > 1 --> 0 (balla solo 0..1) + if (counterMes2Plc > 1) counterMes2Plc = 0; + // salvo su DB + Dictionary task2exe = new Dictionary(); + Dictionary taskDone = new Dictionary(); + task2exe.Add("sendWatchDogMes2Plc", counterMes2Plc.ToString()); + taskDone = executeTasks(task2exe); + // salvo watchdog PLC + lastPLCWatchDog = adesso; + } + } + + /// + /// Effettua decodifica aree memoria alla bitmap usata x MAPO + /// + protected override void decodeToBaseBitmap() + { + // init a zero... + B_input = 0; + + /* ----------------------------------------------------- + * bitmap MAPO STANDARD + * B0: POWER_ON + * B1: RUN + * B2: pzCount + * B3: allarme + * B4: manuale + * B5: emergenza + * + * + * - BIT di stato + * - DBX0.0: RUN STATE + * - DBX0.1: CYCLE + * - DBX0.2: MANUAL MODE + * - DBX0.3: GENERAL ALARM + * - DBX0.4: ESTOP (1=OK, 0 = emergency) + * - DBX0.5: SAFETY DOORS + ----------------------------------------------------- */ + + byte mainData = RawInput[0]; + + int byteSignals = 0; + // bit 0 (poweron) imposto a 1 SE connected... + if (currPLC.IsConnected) + { + byteSignals += (1 << 0); + } + if ((mainData & (1 << 0)) == 1) + { + byteSignals += (1 << 1); + } + + // EMERGENZA + if ((mainData & (1 << 5)) == 1) + { + byteSignals += (1 << 5); + } + // ALLARME + if ((mainData & (1 << 3)) == 1) + { + byteSignals += (1 << 3); + } + + // MANUALE ... + if ((mainData & (1 << 2)) == 1) + { + byteSignals += (1 << 4); + } + + // salvo! + B_input = byteSignals; + + // log opzionale! + if (verboseLog) + { + lgInfo(string.Format($"Trasformazione dati: RawInput:{RawInput[3]} --> B_input: {B_input}")); + } + } + + #endregion Metodi specifici (da verificare/completare in implementazione) } - - /// - /// Effettua decodifica aree memoria alla bitmap usata x MAPO - /// - protected override void decodeToBaseBitmap() - { - // init a zero... - B_input = 0; - - /* ----------------------------------------------------- - * bitmap MAPO STANDARD - * B0: POWER_ON - * B1: RUN - * B2: pzCount - * B3: allarme - * B4: manuale - * B5: emergenza - * - * - * - BIT di stato - * - DBX0.0: RUN STATE - * - DBX0.1: CYCLE - * - DBX0.2: MANUAL MODE - * - DBX0.3: GENERAL ALARM - * - DBX0.4: ESTOP (1=OK, 0 = emergency) - * - DBX0.5: SAFETY DOORS - ----------------------------------------------------- */ - - byte mainData = RawInput[0]; - - int byteSignals = 0; - // bit 0 (poweron) imposto a 1 SE connected... - if (currPLC.IsConnected) - { - byteSignals += (1 << 0); - } - if ((mainData & (1 << 0)) == 1) - { - byteSignals += (1 << 1); - } - - // EMERGENZA - if ((mainData & (1 << 5)) == 1) - { - byteSignals += (1 << 5); - } - // ALLARME - if ((mainData & (1 << 3)) == 1) - { - byteSignals += (1 << 3); - } - - // MANUALE ... - if ((mainData & (1 << 2)) == 1) - { - byteSignals += (1 << 4); - } - - // salvo! - B_input = byteSignals; - - // log opzionale! - if (verboseLog) - { - lgInfo(string.Format($"Trasformazione dati: RawInput:{RawInput[3]} --> B_input: {B_input}")); - } - } - - public override string getPrgName() - { - string answ = ""; - try - { - string rawProdCode = S7.Net.Types.String.FromByteArray(RawInput.Skip(54).Take(12).ToArray()); - // primi due char sono \f e \n avanzamento carta e nuova linea... - answ = Regex.Replace(rawProdCode, @"\t|\n|\r|\f", ""); - } - catch (Exception exc) - { - lgError($"Errore in decodifica product code{Environment.NewLine}{exc}"); - } - return answ; - } - - #endregion - } -} +} \ No newline at end of file diff --git a/IOB-WIN/IobSiemensSaet.cs b/IOB-WIN/IobSiemensSaet.cs index 9f59f653..4bc73024 100644 --- a/IOB-WIN/IobSiemensSaet.cs +++ b/IOB-WIN/IobSiemensSaet.cs @@ -170,17 +170,19 @@ namespace IOB_WIN break; case taskType.startSetup: - // processo scrittura BIT x richeista nuovo ordine a FINE setup + // processo scrittura BIT x richiesta nuovo ordine a FINE setup MemBlock = new byte[1]; MemBlock[0] = (byte)1; memAddrWrite = "DB1275.DBB94"; + lgInfo("Chiamata startSetup"); break; case taskType.stopSetup: - // processo scrittura BIT x richeista nuovo ordine a FINE setup + // processo scrittura BIT x richiesta nuovo ordine a FINE setup MemBlock = new byte[1]; MemBlock[0] = (byte)0; memAddrWrite = "DB1275.DBB94"; + lgInfo("Chiamata stopSetup"); break; default: @@ -243,6 +245,7 @@ namespace IOB_WIN * B2: pzCount * B3: allarme * B4: manuale + * B5: anomalia * * * - BIT di stato @@ -268,7 +271,13 @@ namespace IOB_WIN } // controllo il bit ALLARME - if (((mainData & (1 << 1)) == 0) || ((mainData & (1 << 5)) != 0)) + if ((mainData & (1 << 1)) == 0) + { + byteSignals += (1 << 3); + } + + // controllo il bit ANOMALIA + if ((mainData & (1 << 5)) != 0) { byteSignals += (1 << 3); }