From 95c4aca30569b624340f71e38b50f25515f239ab Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Thu, 10 Nov 2022 17:16:35 +0100 Subject: [PATCH] ModbusTcp: - aggiunta gestione decodifica bitConditions - test x Imax Jetco --- IOB-UT-NEXT/BitConditionCheck.cs | 89 ++++++++++++++ IOB-UT-NEXT/IOB-UT-NEXT.csproj | 2 + IOB-UT-NEXT/plcMemMapExt.cs | 14 +++ IOB-WIN-NEXT/DATA/CONF/3026.json | 63 +++++----- IOB-WIN-NEXT/IobGeneric.cs | 49 +++++++- IOB-WIN-NEXT/IobModbusTCP.cs | 2 +- IOB-WIN-NEXT/IobModbusTCPImaxAeromec.cs | 148 ++++++++++++++---------- IOB-WIN-NEXT/IobModbusTCPZetapack.cs | 42 ++++--- IOB-WIN-NEXT/IobOpcUa.cs | 3 +- IOB-WIN-NEXT/IobSiemens.cs | 2 +- 10 files changed, 303 insertions(+), 111 deletions(-) create mode 100644 IOB-UT-NEXT/BitConditionCheck.cs create mode 100644 IOB-UT-NEXT/plcMemMapExt.cs diff --git a/IOB-UT-NEXT/BitConditionCheck.cs b/IOB-UT-NEXT/BitConditionCheck.cs new file mode 100644 index 00000000..94899773 --- /dev/null +++ b/IOB-UT-NEXT/BitConditionCheck.cs @@ -0,0 +1,89 @@ +namespace IOB_UT_NEXT +{ + public class BitConditionCheck + { + #region Public Constructors + + /// + /// Inizializza un oggetto da usare per testing bit condition + /// + /// Nome della chiave registrata + /// Configuraizone nel formato BaseAddr.BitNum=ValOk + public BitConditionCheck(string keyName, string rawConf) + { + Logging.Instance.Info($"Init BitConditionCheck | {keyName} | {rawConf}"); + KeyName = keyName; + RawVal = rawConf; + string sVal = ""; + int valDecoded = 0; + // check preliminare + if (rawConf.Contains(".") && rawConf.Contains("=")) + { + // splitto per "="... + var splitCond = rawConf.Split('='); + sVal = splitCond[1]; + int.TryParse(sVal, out valDecoded); + ValOk = valDecoded; + // il restante splitto per "." + var splitMem = splitCond[0].Split('.'); + // BaseAddr + sVal = splitMem[0]; + int.TryParse(sVal, out valDecoded); + BaseAddr = valDecoded; + // BitNum + sVal = splitMem[1]; + int.TryParse(sVal, out valDecoded); + BitNum = valDecoded; + } + } + + /// + /// Inizializza un oggetto fake/empty + /// + public BitConditionCheck() + { + Logging.Instance.Info("Init empty BitConditionCheck"); + } + + /// + /// Inizializza un oggetto solo per key + /// + /// Nome della chiave registrata + public BitConditionCheck(string keyName) + { + Logging.Instance.Info($"Init BitConditionCheck | {keyName}"); + KeyName = keyName; + } + + #endregion Public Constructors + + #region Public Properties + + /// + /// Indirizzo base x memoria da testare come bit condition + /// + public int BaseAddr { get; set; } = 0; + + /// + /// Numero bit da impiegare + /// + public int BitNum { get; set; } = 0; + + /// + /// Valore chiave + /// + public string KeyName { get; set; } = ""; + + /// + /// Valore raw decodificato + /// + public string RawVal { get; set; } = ""; + + /// + /// Valore target che porta a condizione OK = true + /// + public int ValOk { get; set; } = 0; + + #endregion Public Properties + } +} \ No newline at end of file diff --git a/IOB-UT-NEXT/IOB-UT-NEXT.csproj b/IOB-UT-NEXT/IOB-UT-NEXT.csproj index 2507531e..e74a2d2f 100644 --- a/IOB-UT-NEXT/IOB-UT-NEXT.csproj +++ b/IOB-UT-NEXT/IOB-UT-NEXT.csproj @@ -141,10 +141,12 @@ + + diff --git a/IOB-UT-NEXT/plcMemMapExt.cs b/IOB-UT-NEXT/plcMemMapExt.cs new file mode 100644 index 00000000..3b582347 --- /dev/null +++ b/IOB-UT-NEXT/plcMemMapExt.cs @@ -0,0 +1,14 @@ +using MapoSDK; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IOB_UT_NEXT +{ + public class plcMemMapExt : plcMemMap + { + public Dictionary optMemPar { get; set; } = new Dictionary(); + } +} diff --git a/IOB-WIN-NEXT/DATA/CONF/3026.json b/IOB-WIN-NEXT/DATA/CONF/3026.json index 6488f32b..2ecd5729 100644 --- a/IOB-WIN-NEXT/DATA/CONF/3026.json +++ b/IOB-WIN-NEXT/DATA/CONF/3026.json @@ -1,36 +1,36 @@ { "mMapWrite": { - + }, "mMapRead": { - "StatusWord": { - "name": "StatusWord", - "description": "Word di Status", - "memAddr": "40002", - "tipoMem": "Int", - "index": 2, - "size": 1, - "func": "POINT", - "period": 90, - "factor": 1, - "minVal": 0, - "maxVal": 65536, - "unit": "BMap" - }, - "StatusDetWord": { - "name": "StatusDetWord", - "description": "Word di Status", - "memAddr": "40005", - "tipoMem": "Int", - "index": 5, - "size": 1, - "func": "POINT", - "period": 90, - "factor": 1, - "minVal": 0, - "maxVal": 65536, - "unit": "BMap" - }, + //"StatusWord": { + // "name": "StatusWord", + // "description": "Word di Status", + // "memAddr": "40002", + // "tipoMem": "Int", + // "index": 2, + // "size": 1, + // "func": "POINT", + // "period": 90, + // "factor": 1, + // "minVal": 0, + // "maxVal": 65536, + // "unit": "BMap" + //}, + //"StatusDetWord": { + // "name": "StatusDetWord", + // "description": "Word di Status", + // "memAddr": "40005", + // "tipoMem": "Int", + // "index": 5, + // "size": 1, + // "func": "POINT", + // "period": 90, + // "factor": 1, + // "minVal": 0, + // "maxVal": 65536, + // "unit": "BMap" + //}, "FreqInverter": { "name": "FreqInverter", "description": "Frequenza Inverter", @@ -101,5 +101,10 @@ "maxVal": 999999999, "unit": "A" } + }, + "optMemPar": { + "AutoBitCond": "40002.14=1", + "EStopBitCond": "40002.9=0", + "WorkBitCond": "40002.0=1" } } \ No newline at end of file diff --git a/IOB-WIN-NEXT/IobGeneric.cs b/IOB-WIN-NEXT/IobGeneric.cs index 138aadbe..917d5d04 100644 --- a/IOB-WIN-NEXT/IobGeneric.cs +++ b/IOB-WIN-NEXT/IobGeneric.cs @@ -174,7 +174,7 @@ namespace IOB_WIN_NEXT /// /// Struttura memoria PLC x lettura/scrittura da JSON file /// - public plcMemMap memMap; + public plcMemMapExt memMap; /// /// Minimo numero di px da inviare in blocco @@ -5191,8 +5191,9 @@ namespace IOB_WIN_NEXT lgInfoStartup($"File json PARAMETRI composto da {jsonData.Length} caratteri"); try { - memMap = JsonConvert.DeserializeObject(jsonData); + memMap = JsonConvert.DeserializeObject(jsonData); setupMemMap(); + setupOptMemPar(); } catch (Exception exc) { @@ -5246,6 +5247,47 @@ namespace IOB_WIN_NEXT lgInfoStartup("DONE loadMemConf"); } + /// + /// Dizionario condizioni di check (opzionali) da usare x valori controllo bitmap (es ModBUs TCP Imax) + /// + protected Dictionary OptCheckConditions { get; set; } = new Dictionary(); + + protected virtual void setupOptMemPar() + { + // verifica se siano necessari configuraizoni speciali dalla optMemPar (es per ricerca condizioni status bolleane come ModbusTCP...) + if (memMap.optMemPar != null && memMap.optMemPar.Count > 0) + { + // cerco condizioni speciali x Auto, Estop, Work.. devono essere *BitCond + var listPar2add = memMap.optMemPar.Where(x => x.Key.EndsWith("BitCond")).ToList(); + if (listPar2add != null && listPar2add.Count > 0) + { + foreach (var item in listPar2add) + { + addCheckCondition(item.Key, item.Value); + } + } + } + } + + /// + /// Aggiunge in setup memoria la checkCondition ricevuta già "decodificata" + /// + /// Chiave da aggiungere + /// Valore da decodificare e poi aggiungere + private void addCheckCondition(string ompKey, string ompVal) + { + var newCond = new BitConditionCheck(ompVal); + // cerco x aggiornare o aggiungere... + if (OptCheckConditions.ContainsKey(ompKey)) + { + OptCheckConditions[ompKey] = newCond; + } + else + { + OptCheckConditions.Add(ompKey, newCond); + } + } + /// /// Metodo da overridare x scrivere DAVVERO i parametri sul PLC /// @@ -6689,6 +6731,9 @@ namespace IOB_WIN_NEXT } #endregion Private Methods + + + } /// diff --git a/IOB-WIN-NEXT/IobModbusTCP.cs b/IOB-WIN-NEXT/IobModbusTCP.cs index 21a5f25c..1bedd686 100644 --- a/IOB-WIN-NEXT/IobModbusTCP.cs +++ b/IOB-WIN-NEXT/IobModbusTCP.cs @@ -27,7 +27,7 @@ namespace IOB_WIN_NEXT { lgInfo("NEW IOB ModBus TCP"); DateTime adesso = DateTime.Now; - memMap = new plcMemMap(); + memMap = new plcMemMapExt(); if (IOBConf != null) { // gestione invio ritardato contapezzi diff --git a/IOB-WIN-NEXT/IobModbusTCPImaxAeromec.cs b/IOB-WIN-NEXT/IobModbusTCPImaxAeromec.cs index 563e88e3..5dce5300 100644 --- a/IOB-WIN-NEXT/IobModbusTCPImaxAeromec.cs +++ b/IOB-WIN-NEXT/IobModbusTCPImaxAeromec.cs @@ -43,51 +43,8 @@ namespace IOB_WIN_NEXT #endregion Public Constructors - #region Protected Methods + #region Protected Properties - /// - /// Restituisce status di emergenza - /// - protected bool EStop - { - get - { - bool answ = false; - int currStatus = 0; - // hard coded - int statusReg = 40002; - // deve avere allarmi (è un allarme EStop) - if (hasAlarms()) - { - int[] listInt = new int[2]; - listInt = HoldingRegisterLUT[statusReg]; - currStatus = ModbusClient.ConvertRegistersToInt(listInt); - // hard coded il 9° bit a zero - answ = ((currStatus & (1 << 9)) == 0); - } - return answ; - } - } - - /// - /// Restituisce status di LAVORA, hard coded - /// - protected bool Work - { - get - { - bool answ = false; - int currStatus = 0; - // hard coded - int statusReg = 40002; - int[] listInt = new int[2]; - listInt = HoldingRegisterLUT[statusReg]; - currStatus = ModbusClient.ConvertRegistersToInt(listInt); - // hard coded il 5° bit - answ = ((currStatus & (1 << 0)) > 0); - return answ; - } - } /// /// Restituisce status di AUTOmatico, hard coded /// @@ -95,6 +52,8 @@ namespace IOB_WIN_NEXT { get { + return testCondition("WorkBitCond"); +#if false bool answ = false; int currStatus = 0; // hard coded @@ -105,9 +64,49 @@ namespace IOB_WIN_NEXT // hard coded il 5° bit answ = ((currStatus & (1 << 14)) > 0); return answ; +#endif } } + /// + /// Restituisce status di ESTOP triggered (triggered = premuta, altrimenti armed) + /// + protected bool EStopTriggered + { + get + { + return testCondition("EStopBitCond"); + } + } + + /// + /// Restituisce status di LAVORA, hard coded + /// + protected bool Work + { + get + { + return testCondition("WorkBitCond"); +#if false + + bool answ = false; + int currStatus = 0; + // hard coded + int statusReg = 40002; + int[] listInt = new int[2]; + listInt = HoldingRegisterLUT[statusReg]; + currStatus = ModbusClient.ConvertRegistersToInt(listInt); + // hard coded il 5° bit + answ = ((currStatus & (1 << 0)) > 0); + return answ; +#endif + } + } + + #endregion Protected Properties + + #region Protected Methods + /// /// Effettua decodifica aree memoria alla bitmap usata x MAPO /// @@ -137,26 +136,32 @@ namespace IOB_WIN_NEXT { byteSignals += (1 << 0); } - // processo dagli stati + gravi... - if (!EStop) + if (HoldingRegisterLUT != null && HoldingRegisterLUT.Count > 0) { - byteSignals += (1 << 7); - } + // se emergenza NON premuta (triggered) indico OK (armata...) + if (!EStopTriggered) + { + byteSignals += (1 << 7); + } - // processo dagli stati + gravi... - if (hasAlarms()) - { - byteSignals += (1 << 3); + // processo dagli stati + gravi... + if (hasAlarms()) + { + byteSignals += (1 << 3); + } + if (Work) + { + byteSignals += (1 << 1); + } + if (!Auto) + { + byteSignals += (1 << 4); + } } - if (Work) + else { - byteSignals += (1 << 1); + lgInfo("HoldingRegisterLUT vuoto!"); } - if (!Auto) - { - byteSignals += (1 << 4); - } - // salvo! B_input = byteSignals; @@ -190,6 +195,31 @@ namespace IOB_WIN_NEXT lgTrace("-------------------- Completato test lettura {baseAddr} --------------------"); } + /// + /// Testa la condition modbus da LUT + configurazione + /// + /// + /// + private bool testCondition(string cKey) + { + bool answ = false; + if (OptCheckConditions.ContainsKey(cKey)) + { + int currStatus = 0; + int[] listInt = new int[2]; + listInt = HoldingRegisterLUT[OptCheckConditions[cKey].BaseAddr]; + currStatus = ModbusClient.ConvertRegistersToInt(listInt); + // hard coded il 9° bit a zero + answ = ((currStatus & (1 << OptCheckConditions[cKey].BitNum)) == OptCheckConditions[cKey].ValOk); + lgTrace($"testCondition for {cKey} | BaseAddr: {OptCheckConditions[cKey].BaseAddr} | BitNum: {OptCheckConditions[cKey].BitNum} | ValOk: {OptCheckConditions[cKey].ValOk}"); + } + else + { + lgTrace($"testCondition error: {cKey} not found"); + } + return answ; + } + private void testRead() { foreach (var item in memSetR) diff --git a/IOB-WIN-NEXT/IobModbusTCPZetapack.cs b/IOB-WIN-NEXT/IobModbusTCPZetapack.cs index 99699781..754ca2ac 100644 --- a/IOB-WIN-NEXT/IobModbusTCPZetapack.cs +++ b/IOB-WIN-NEXT/IobModbusTCPZetapack.cs @@ -55,7 +55,7 @@ namespace IOB_WIN_NEXT bool answ = false; int currStatus = 0; // hard coded - int statusReg = 40003; + int statusReg = 40002; // deve avere allarmi (è un allarme EStop) if (hasAlarms()) { @@ -79,7 +79,7 @@ namespace IOB_WIN_NEXT bool answ = false; int currStatus = 0; // hard coded - int statusReg = 40003; + int statusReg = 40002; int[] listInt = new int[2]; listInt = HoldingRegisterLUT[statusReg]; currStatus = ModbusClient.ConvertRegistersToInt(listInt); @@ -98,7 +98,7 @@ namespace IOB_WIN_NEXT bool answ = false; int currStatus = 0; // hard coded - int statusReg = 40003; + int statusReg = 40002; int[] listInt = new int[2]; listInt = HoldingRegisterLUT[statusReg]; currStatus = ModbusClient.ConvertRegistersToInt(listInt); @@ -137,26 +137,32 @@ namespace IOB_WIN_NEXT { byteSignals += (1 << 0); } - // processo dagli stati + gravi... - if (!EStop) + if (HoldingRegisterLUT != null && HoldingRegisterLUT.Count > 0) { - byteSignals += (1 << 7); - } + // processo dagli stati + gravi... + if (!EStop) + { + byteSignals += (1 << 7); + } - // processo dagli stati + gravi... - if (hasAlarms()) - { - byteSignals += (1 << 3); + // processo dagli stati + gravi... + if (hasAlarms()) + { + byteSignals += (1 << 3); + } + if (Work) + { + byteSignals += (1 << 1); + } + if (!Auto) + { + byteSignals += (1 << 4); + } } - if (Work) + else { - byteSignals += (1 << 1); + lgInfo("HoldingRegisterLUT vuoto!"); } - if (!Auto) - { - byteSignals += (1 << 4); - } - // salvo! B_input = byteSignals; diff --git a/IOB-WIN-NEXT/IobOpcUa.cs b/IOB-WIN-NEXT/IobOpcUa.cs index 1b6369a6..122d0268 100644 --- a/IOB-WIN-NEXT/IobOpcUa.cs +++ b/IOB-WIN-NEXT/IobOpcUa.cs @@ -1176,7 +1176,7 @@ namespace IOB_WIN_NEXT opcUaParams = JsonConvert.DeserializeObject(jsonData); lgDebug($"Decodifica aree OpcUaParamConf: trovati {opcUaParams.paramsEndThresh.Count} valori paramsEndThresh"); // sistemo se ci sono dati memMap... - memMap = new plcMemMap(); + memMap = new plcMemMapExt(); if (opcUaParams.mMapWrite != null) { memMap.mMapWrite = opcUaParams.mMapWrite; @@ -1186,6 +1186,7 @@ namespace IOB_WIN_NEXT memMap.mMapRead = opcUaParams.mMapRead; } setupMemMap(); + setupOptMemPar(); } catch (Exception exc) { diff --git a/IOB-WIN-NEXT/IobSiemens.cs b/IOB-WIN-NEXT/IobSiemens.cs index 103901c6..7b061e4e 100644 --- a/IOB-WIN-NEXT/IobSiemens.cs +++ b/IOB-WIN-NEXT/IobSiemens.cs @@ -79,7 +79,7 @@ namespace IOB_WIN_NEXT /// public IobSiemens(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf) { - memMap = new plcMemMap(); + memMap = new plcMemMapExt(); writePre = true; if (IOBConf.optPar.ContainsKey("WRITE_PRE")) {