diff --git a/IOB-WIN-NEXT/DATA/CONF/FINASSI_HELPI_01.ini b/IOB-WIN-NEXT/DATA/CONF/FINASSI_HELPI_01.ini
index 0af3ab79..1dce7177 100644
--- a/IOB-WIN-NEXT/DATA/CONF/FINASSI_HELPI_01.ini
+++ b/IOB-WIN-NEXT/DATA/CONF/FINASSI_HELPI_01.ini
@@ -1,12 +1,12 @@
;Configurazione IOB-WIN
[IOB]
-;Impianto Cedax di Turi (test) - Giacovelli
-CNCTYPE=MODBUS_TCP_CEDAX
+;Impianto Helpi x impacchettatrice - Finassi
+CNCTYPE=MODBUS_TCP_HELPI
PING_MS_TIMEOUT=1000
[MACHINE]
-VENDOR=CEDAX
-MODEL=CEDAX
+VENDOR=HELPI
+MODEL=HELPI
[CNC]
IP=10.74.82.65
@@ -25,9 +25,9 @@ CMDREBO=/IOB/sendReboot?idxMacchina=
;CMDREBO=/sendReboot.aspx?idxMacchina=
[MEMORY]
-ADDR_READ=41001
-ADDR_WRITE=41021
-SIZE_READ=20
+ADDR_READ=41060
+ADDR_WRITE=41060
+SIZE_READ=0
SIZE_WRITE=0
HR_BASE_ADDR=40000
@@ -48,7 +48,7 @@ BLINK_FILT=0
[OPTPAR]
;PZCOUNT_MODE=STD.[PAR/MEM].info|BIT.indice
-PZCOUNT_MODE=STD.DB85.DBRE16
+PZCOUNT_MODE=STD.41100.UDINT32
DISABLE_PZCOUNT=TRUE
ENABLE_SEND_PZC_BLOCK=TRUE
MIN_SEND_PZC_BLOCK=0
@@ -63,13 +63,13 @@ DELTA_VAL=0.1
timerIntMs=10
; conf parametri memoria READ/WRITE
-PARAM_CONF=GIACO_CEDAX_01.json
+PARAM_CONF=FINASSI_HELPI_01.json
-NO_PING=TRUE
+NO_PING=FALSE
; conf blocchi memoria x READ
-MEM_BLOCK=GIACO_CEDAX_01_MBlock.json
+MEM_BLOCK=FINASSI_HELPI_01_MBlock.json
; conf aree allarme
-ALARM_CONF=GIACO_CEDAX_01_alarm.json
+ALARM_CONF=FINASSI_HELPI_01_alarm.json
[BRANCH]
NAME=master
\ No newline at end of file
diff --git a/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj b/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj
index 22f5e805..1a148125 100644
--- a/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj
+++ b/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj
@@ -260,6 +260,7 @@
+
Always
@@ -278,6 +279,18 @@
Always
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
Always
diff --git a/IOB-WIN-NEXT/IobModbusTCP.cs b/IOB-WIN-NEXT/IobModbusTCP.cs
index f079af54..4c1d8279 100644
--- a/IOB-WIN-NEXT/IobModbusTCP.cs
+++ b/IOB-WIN-NEXT/IobModbusTCP.cs
@@ -6,11 +6,8 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
-using System.Linq;
using System.Net.NetworkInformation;
-using System.Text;
using System.Threading;
-using System.Threading.Tasks;
using System.Windows.Forms;
namespace IOB_WIN_NEXT
@@ -23,61 +20,9 @@ namespace IOB_WIN_NEXT
public class IobModbusTCP : IobGeneric
{
- #region Private Fields
-
- ///
- /// Valore delta x gestione min/MAX e valore rilevato
- ///
- private double deltaVal = 0;
- ///
- /// Indirizzo di base x fare il calcolo di dove leggere in ModBus
- ///
- private int HoldRegBaseAddr = 40001;
-
- #endregion Private Fields
-
- #region Protected Fields
-
- protected ModbusClient currPLC;
-
- ///
- /// Copia locale dei valori in Holding Registry, come array chiave (int) valori int[] letti tramite ModBus, da convertire secondo tipo
- ///
- protected Dictionary HoldingRegisterLUT = new Dictionary();
-
- ///
- /// Ultimo controllo ping x evitare ping flood...
- ///
- protected DateTime lastPingConn = DateTime.Now.AddMinutes(-10);
-
- ///
- /// Esito ultimo ping
- ///
- protected bool lastPingOk = false;
-
- ///
- /// Setup blocchi memorie read (indirizzo inizio, size)
- ///
- protected Dictionary memSetR = new Dictionary();
-
- ///
- /// parametri di connessione
- ///
- protected connParamModBusTCP parametri;
-
- ///
- /// Oggetto cronometro x test vari...
- ///
- protected Stopwatch sw = new Stopwatch();
-
- #endregion Protected Fields
-
#region Public Constructors
- /// Classe base con i metodi x ModBusTCP
- ///
- ///
- ///
+ /// Classe base con i metodi x ModBusTCP
public IobModbusTCP(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf)
{
lgInfo("NEW IOB ModBus TCP");
@@ -122,766 +67,6 @@ namespace IOB_WIN_NEXT
#endregion Public Constructors
- #region Protected Properties
-
- protected bool hasAlarms
- {
- get
- {
- bool answ = false;
- int numErrors = 0;
- int currStatus = 0;
- int[] listInt = new int[2];
- if (alarmMaps != null)
- {
- // leggo a ciclo le aree degli allarmi CONFIGURATI, se ne trovo --> segnalo allarme...
- foreach (var item in alarmMaps)
- {
- // banchi in array Int16 --> scompongo
- for (int i = 0; i < item.size / 2; i++)
- {
- // verifico se usare LUT
- bool useLUT = memSetR != null && memSetR.Count > 0;
- if (useLUT)
- {
- int lutAddress = 40000 + item.index;
- if (HoldingRegisterLUT.ContainsKey(lutAddress))
- {
- try
- {
- listInt = HoldingRegisterLUT[lutAddress];
- }
- catch (Exception exc)
- {
- lgError($"Errore in lettura da HoldingRegisterLUT per indirizzo {lutAddress} | item {item.memAddr}{Environment.NewLine}{exc}");
- }
- }
- }
- else
- {
- listInt = readInputReg(item.index, item.size);
- }
- currStatus = ModbusClient.ConvertRegistersToInt(listInt);
-
- // aggiornamento blink counters dato nuovo valore
- item.checkBlinkCounter(i, (uint)currStatus);
-
- // calcolo indice errori
- if ((uint)(item.alarmsMask[i] & currStatus) > 0)
- {
- numErrors++;
- }
- // verifico SE sia variato... confronto allarmi filtrato stile blink per bit status:
- // - allarmi che iniziano per # IGNORATI
- // - altri allarmi con un countdown da MAX_COUNTER_BLINK a 0 per il fronte di discesa
- if (item.isChanged(i, (uint)currStatus))
- {
- // registro gli allarmi attivi e trasmetto...
- if (sendAlarmVariations(item.memAddr, i, item.alarmsState[i], (uint)(item.alarmsMask[i] & currStatus), item.messages))
- {
- // se inviato --> salvo stato da current...
- item.updStatusVal(i, (uint)(item.alarmsMask[i] & currStatus));
- }
- }
- }
- }
- }
- answ = numErrors > 0;
- return answ;
- }
- }
-
- ///
- /// Dizionario delle ultime operazioni di scrittura per OGNI memoria (in modo che fa log ogni x sec...)
- ///
- protected Dictionary lastMemWrite { get; set; } = new Dictionary();
-
- #endregion Protected Properties
-
- #region Private Methods
-
- ///
- /// converte valore in tipo desiderato
- ///
- ///
- ///
- ///
- ///
- private static double convertFromReg(int[] listInt, int size, plcDataType tipoMem)
- {
- double valore = 0;
- //verifico se sia INT o real x convertire...
- switch (tipoMem)
- {
- case plcDataType.Real:
- if (size == 4)
- {
- valore = ModbusClient.ConvertRegistersToDouble(listInt);
- }
- else if (size == 2)
- {
- valore = ModbusClient.ConvertRegistersToFloat(listInt);
- }
- break;
-
- // caso speciale x Cedax, che usa HighVal moltiplicato x 32768...
- case plcDataType.HLPInt:
- if (size == 4)
- {
- valore = ModbusClient.ConvertRegistersToLong(listInt);
- }
- else if (size == 2)
- {
- int fact = Int16.MaxValue + 1;
- valore = listInt[1] * fact + listInt[0];
- }
- break;
-
- case plcDataType.Int:
- default:
- if (size == 4)
- {
- valore = ModbusClient.ConvertRegistersToLong(listInt);
- }
- else if (size == 2)
- {
- valore = ModbusClient.ConvertRegistersToInt(listInt);
- }
- break;
- }
- return valore;
- }
-
- private static double getScaledDouble(dataConf currMem)
- {
- double valDouble;
- // prima faccio eventuale fattore di scala...
- double.TryParse(currMem.value, out valDouble);
- if (currMem.factor != 1)
- {
- valDouble = valDouble * (double)currMem.factor;
- }
-
- return valDouble;
- }
-
- private static int getScaledInt(dataConf currMem)
- {
- int valInt;
- // prima faccio eventuale fattore di scala...
- int.TryParse(currMem.value, out valInt);
- if (currMem.factor != 1)
- {
- valInt = (int)(valInt * currMem.factor);
- }
-
- return valInt;
- }
-
- private static uint getScaledUInt(dataConf currMem)
- {
- uint valUInt;
- // prima faccio eventuale fattore di scala...
- uint.TryParse(currMem.value, out valUInt);
- if (currMem.factor != 1)
- {
- valUInt = valUInt * (uint)currMem.factor;
- }
-
- return valUInt;
- }
-
- ///
- /// se si disconnette --> processo tentativo riconnessione..
- ///
- ///
- private void CurrPLC_ConnectedChanged(object sender)
- {
- if (!currPLC.Connected)
- {
- tryDisconnect();
- }
- }
-
- ///
- /// Recupero dati da singole letture
- ///
- /// Valori da processare
- /// Impiego della LookUpTable x diminuire accessi
- /// Dizionario valori in uscita
- /// Errori di lettura
- private Dictionary getDataDictionary(Dictionary memItemList, bool useLUT, ref Dictionary outVal)
- {
- Dictionary readErrorList = new Dictionary();
- // inizializzo i valori
- bool[] listBool = new bool[1];
- int[] listInt = new int[2];
- // procedo x ogni valore configurato...
- foreach (var item in memItemList)
- {
- // attesa 50 ms prima di procedere x evitare burst dati
- if (!useLUT)
- {
- Thread.Sleep(50);
- }
- double valore = 0;
- double valoreScal = 0;
- bool dataOk = false;
- // in primis DEVO determinare di quale TIPO di valore ho bisogno... dalla PRIMA cifra di memAddr...
- modBusAddrType memAddrType = getAddrType(item.Value.memAddr);
- // in base al tipo leggo array...
- switch (memAddrType)
- {
- case modBusAddrType.Coil:
- listBool = readCoil(item.Value.index, item.Value.size);
- valore = listBool[0] ? 1 : 0;
- break;
-
- case modBusAddrType.DiscreteInput:
- listBool = readDiscrInputs(item.Value.index, item.Value.size);
- valore = listBool[0] ? 1 : 0;
- break;
-
- case modBusAddrType.InputRegister:
- listInt = readInputReg(item.Value.index, item.Value.size);
- valore = convertFromReg(listInt, item.Value.size, item.Value.tipoMem);
-
- break;
-
- case modBusAddrType.HoldingRegister:
- if (useLUT)
- {
- int lutAddress = 40000 + item.Value.index;
- if (HoldingRegisterLUT.ContainsKey(lutAddress))
- {
- try
- {
- listInt = HoldingRegisterLUT[lutAddress];
- }
- catch (Exception exc)
- {
- lgError($"Errore in lettura da HoldingRegisterLUT per indirizzo {lutAddress} | item {item.Key}{Environment.NewLine}{exc}");
- }
- }
- }
- else
- {
- listInt = readHoldReg(item.Value.index - 1, item.Value.size);
- }
- valore = convertFromReg(listInt, item.Value.size, item.Value.tipoMem);
- break;
-
- default:
- break;
- }
- // verifica limite... con delta da impianto
- dataOk = (valore > (item.Value.minVal + deltaVal) && valore < (item.Value.maxVal - deltaVal));
- if (dataOk)
- {
- // moltiplico x fattore conversione...
- valoreScal = valore * item.Value.factor;
- saveValue(ref outVal, valoreScal, item.Key);
- lgDebug($"getDynData: valore ricevuto | {item.Key} | val: {valore} | valoreScal: {valoreScal}");
- }
- else
- {
- lgError($"getDynData: valore scartato x limiti min/max | {item.Key} | val: {valore} | valoreScal: {valoreScal} | min-max: {item.Value.minVal}-{item.Value.maxVal} | deltaVal: {deltaVal}");
- readErrorList.Add(item.Key, item.Value);
- lgDebug($"--> rimesso in coda lettura | parametro: {item.Key} | index: {item.Value.index} | size: {item.Value.size}");
- }
- }
-
- return readErrorList;
- }
-
- ///
- /// Verifica SE sia il caso di fare il log della memoria indicata
- ///
- ///
- ///
- private void maybeLogWrite(string memAddrWrite, string logValue)
- {
- bool doWrite = true;
- DateTime adesso = DateTime.Now;
- if (!lastMemWrite.ContainsKey(memAddrWrite))
- {
- lastMemWrite.Add(memAddrWrite, adesso.AddMinutes(-1));
- }
- // ora mi leggo valore ultimas crittura e confronto con adesso
- try
- {
- doWrite = (lastMemWrite[memAddrWrite].AddSeconds(vetoSeconds) < adesso);
- }
- catch (Exception exc)
- {
- lgError($"Eccezione in maybeLogWrite{Environment.NewLine}{exc}");
- }
- // se encessario --> LOG!
- if (doWrite)
- {
- lgInfo(logValue);
- lastMemWrite[memAddrWrite] = adesso;
- }
- }
-
- ///
- /// Effettua lettura blocco memoria indicato e lo salva in copia locale HoldingRegisterLUT
- ///
- /// Indirizzo di aprtenza
- /// NUm registri da leggere (max 120)
- private void readBlockHoldingReg(int startAddr, int numReg, int baseAddr)
- {
- bool allOk = false;
- if (currPLC.Connected)
- {
- allOk = true;
- // fix massima lunghezza pacchetto
- if (numReg > 120)
- {
- lgError($"Attenzione richiesta lettura blocco troppo grande: numReg {numReg} --> 120");
- numReg = 120;
- }
- // si lavora rispetto all'indirizzo base 40001
-
- int[] rawData = new int[2];
- try
- {
- stopwatch.Restart();
- rawData = currPLC.ReadHoldingRegisters(startAddr - baseAddr, numReg);
- stopwatch.Stop();
- lgTrace($"Lettura in blocco HoldingRegisters| startAddr: {startAddr} | numReg {numReg} | rawData.lenght: {rawData.Length} | {stopwatch.ElapsedMilliseconds}ms");
- // salvo in LUT la versione ESPLOSA 2 byte alla volta...
- if (rawData.Length > 0)
- {
- for (int i = 0; i < rawData.Length / 2; i++)
- {
- int[] thisSet = new int[2];
- if (rawData.Length >= (i + 1) * 2)
- {
- Array.Copy(rawData, i * 2, thisSet, 0, 2);
- // salvo nel registro...
- int currAddr = startAddr + i * 2;
- if (HoldingRegisterLUT.ContainsKey(currAddr))
- {
- HoldingRegisterLUT[currAddr] = thisSet;
- }
- else
- {
- HoldingRegisterLUT.Add(currAddr, thisSet);
- }
- }
- else
- {
- currReadErrors++;
- allOk = false;
- lgError($"Impossibile copiare dati, array di origine troppo corto: rawData.lenght: {rawData.Length} | base addr richiesto i*2: {i * 2} | errori currReadErrors: {currReadErrors}");
- }
- }
- }
- }
- catch (Exception exc)
- {
- currReadErrors++;
- allOk = false;
- lgError($"Eccezione in readBlockHoldingReg | currReadErrors: {currReadErrors}{Environment.NewLine}{exc}");
- }
- }
- else
- {
- lgError($"Attenzione, plc disconnesso... currReadErrors: {currReadErrors}");
- tryDisconnect();
- }
-
- // se tutto ok --> riduco contatore errori di 1...
- if (allOk)
- {
- currReadErrors = currReadErrors >= 1 ? currReadErrors-- : 0;
- }
- else
- {
- // se > max errori --> disconnetto
- if (currReadErrors > maxReadErrors)
- {
- lgError($"Superato limite errori Read ({currReadErrors}) --> tryDisconnect");
- currReadErrors = 0;
- tryDisconnect();
- }
- else
- {
- // altrimenti pausa forzata
- Thread.Sleep(300);
- }
- }
- }
-
- #endregion Private Methods
-
- #region Protected Methods
-
- ///
- /// Decodifica il resto dell'area x i dati accessori (allarmi, ...)
- ///
- protected virtual void decodeOtherData()
- {
- }
-
- ///
- /// Effettua decodifica aree memoria alla bitmap usata x MAPO/GWMS
- /// - per lo scopo specifico IN REALTA' non conta lo stato macchina.... ma lo inviamo lo stesso
- ///
- protected virtual void decodeToBaseBitmap()
- {
- // init a zero...
- B_input = 0;
- }
-
- ///
- /// Override metodo x scrittura parametri su PLC
- ///
- ///
- protected override void plcWriteParams(ref List updatedPar)
- {
- dataConf currMem = null;
- int byteSize = 0;
- int[] CurrVal = new int[1];
- string memAddrWrite = "";
- bool fatto = false;
- string serObj = "";
- if (updatedPar != null)
- {
- // controllo i parametri... ne gestisco 4...
- foreach (var item in updatedPar)
- {
- try
- {
- memAddrWrite = "";
- int valInt = 0;
- uint valUInt = 0;
- double valDouble = 0;
- // cerco in area memMapWrite...
- if (memMap.mMapWrite.ContainsKey(item.uid))
- {
- // recupero!
- currMem = memMap.mMapWrite[item.uid];
- byteSize = currMem.size;
- memAddrWrite = currMem.memAddr;
- CurrVal = new int[byteSize];
- // faccio preliminarmente upsertKey...
- upsertKey(currMem.name, currMem.value);
- serObj = JsonConvert.SerializeObject(item, Formatting.Indented);
- lgInfo($"Inizio processing plcWriteParams per {currMem.name} | valore richiesto {currMem.value}{Environment.NewLine}---------------UPDATED PARAM---------------{Environment.NewLine}{serObj}{Environment.NewLine}---------------");
- serObj = JsonConvert.SerializeObject(currMem, Formatting.Indented);
- lgInfo($"---------------MEMORY CONTENT---------------{Environment.NewLine}{serObj}{Environment.NewLine}---------------");
- switch (currMem.tipoMem)
- {
- case plcDataType.Boolean:
- break;
-
- case plcDataType.Int:
- valInt = getScaledInt(currMem);
- CurrVal = ModbusClient.ConvertIntToRegisters(valInt);
- fatto = writeInputReg(currMem.index, CurrVal);
- break;
-
- case plcDataType.DInt:
- valUInt = getScaledUInt(currMem);
- CurrVal = ModbusClient.ConvertLongToRegisters(valInt);
- fatto = writeInputReg(currMem.index, CurrVal);
- break;
-
- //case plcDataType.Word:
- // valUInt = getScaledUInt(currMem);
- // saveWordOnMemBlock(ref MemBlock, 0, valInt.ToString());
- // break;
-
- //case plcDataType.DWord:
- // valUInt = getScaledUInt(currMem);
- // saveDWordOnMemBlock(ref MemBlock, 0, valInt.ToString());
- // break;
-
- case plcDataType.Real:
- valDouble = getScaledDouble(currMem);
- CurrVal = ModbusClient.ConvertFloatToRegisters((float)valDouble, ModbusClient.RegisterOrder.HighLow);
- fatto = writeInputReg(currMem.index, CurrVal);
- break;
-
- //case plcDataType.String:
- // // se ho writePre --> "allungo" di 2 la dimensione della stringa x MemBlock...
- // if (writePre)
- // {
- // MemBlock = new byte[byteSize + 2];
- // }
- // saveStringOnMemBlock(ref MemBlock, 0, currMem.size, currMem.value);
- // break;
-
- default:
- break;
- }
- lgInfo($"---------------MemBlock data---------------{Environment.NewLine}CurrVal: {CurrVal}{Environment.NewLine}--------------- END data ---------------");
- if (!string.IsNullOrEmpty(memAddrWrite))
- {
- // se fatto --> aggiorno!
- if (fatto)
- {
- item.value = item.reqValue;
- item.reqValue = "";
- item.lastRead = DateTime.Now;
- item.UM = currMem.unit;
- }
- }
- else
- {
- lgError($"Errore: memAddrWrite vuoto!");
- }
- }
- else
- {
- lgError($"Errore uid non trovato in area write memory: {item.uid}, ci sono {memMap.mMapWrite.Count} in area write");
- }
- }
- catch (Exception exc)
- {
- lgError($"Eccezione in fase di plcWriteParams per item {item.uid} con valore {item.value}{Environment.NewLine}{exc}");
- }
- }
- }
- }
-
- ///
- /// Imposto parametri PLC
- ///
- protected override void setParamPlc()
- {
- DateTime adesso = DateTime.Now;
- // Creo oggetto connessione NC
- parentForm.commPlcActive = true;
- lgInfo($"Start init Adapter ModBus TCP all'IP {cIobConf.cncIpAddr} | port: {cIobConf.cncPort} | --> IOB {cIobConf.codIOB}");
- // SE è necessario refresh...
- if (needRefresh)
- {
- lgInfoStartup("Refreshing connection...");
- if (parametri != null)
- {
- try
- {
- parametri.ipAdrr = cIobConf.cncIpAddr;
- parametri.port = int.Parse(cIobConf.cncPort);
- // leggo file init...
- lgInfoStartup("Reading ini file...");
- IniFile fIni = new IniFile(cIobConf.iniFileName);
- // ora leggo valori speciali
- parametri.memAddrRead = fIni.ReadString("MEMORY", "ADDR_READ", "");
- parametri.memAddrWrite = fIni.ReadString("MEMORY", "ADDR_WRITE", "");
- parametri.memSizeRead = fIni.ReadInteger("MEMORY", "SIZE_READ", 0);
- parametri.memSizeWrite = fIni.ReadInteger("MEMORY", "SIZE_WRITE", 0);
- parametri.holdRegBaseAddr = fIni.ReadInteger("MEMORY", "HR_BASE_ADDR", 40001);
- // salvo vettori memoria...
- lgInfoStartup("Set RawInput dimensions...");
- RawInput = new byte[parametri.memSizeRead];
- RawOutput = new byte[parametri.memSizeWrite];
- // salvo parametri conn!
- lgInfoStartup(string.Format("Parametri memoria: memAddrRead: {0} | memAddrWrite: {1} | memSizeRead: {2} | memSizeWrite: {3}", parametri.memAddrRead, parametri.memAddrWrite, parametri.memSizeRead, parametri.memSizeWrite));
- }
- catch (Exception exc)
- {
- lgError(exc, "Errore in parse parametri da IOBConf");
- }
-
- // carico conf vettore memoria...
- loadMemConf();
- // avvio conf blocchi memoria
- setupMemBlocks();
- // aggiungo DELTA x calcolo min/MAX...
- string deltaValStr = getOptPar("DELTA_VAL");
- if (!string.IsNullOrEmpty(deltaValStr))
- {
- double.TryParse(deltaValStr.Replace(".", ","), out deltaVal);
- }
- bool enableByApp = utils.CRB("enableContapezzi");
- bool enableByIob = (getOptPar("ENABLE_PZCOUNT") == "TRUE");
- bool disableByIob = (getOptPar("DISABLE_PZCOUNT") == "TRUE");
- if ((enableByApp || enableByIob) && !(disableByIob))
- {
- lgInfoStartup("ModBus TCP: inizio gestione contapezzi");
- try
- {
- // verifico quale modalità sia richiesta: STD (6711) oppure BIT (Custom, con indicazione area)
- if (cIobConf.optPar.Count > 0 && !string.IsNullOrWhiteSpace(getOptPar("PZCOUNT_MODE")))
- {
- if (getOptPar("PZCOUNT_MODE").StartsWith("STD"))
- {
- lgInfoStartup("Init contapezzi ModBusTCP: pzCntReload(true)");
- pzCntReload(true);
- // refresh associazione Macchina - IOB
- sendM2IOB();
- // per adesso imposto lettura PLC == contapezzi (poi farà vera lettura...)
- contapezziPLC = contapezziIOB;
- }
- else
- {
- contapezziIOB = 0;
- lgDebug("Contapezzi STD disabilitato: modalità {0}", getOptPar("PZCOUNT_MODE"));
- }
- }
- else
- {
- contapezziIOB = 0;
- lgError("Parametro mancante PZCOUNT_MODE");
- }
- }
- catch (Exception exc)
- {
- lgError(exc, "Errore in contapezzi ModBusTCP");
- }
- }
-
- // ora tento avvio PLC... SE PING OK...
- lastPING = adesso;
- IPStatus esitoPing = testPingMachine;
- if (esitoPing == IPStatus.Success)
- {
- needRefresh = false;
- try
- {
- //Ip-Address and Port of Modbus-TCP-Server
- currPLC = new ModbusClient(parametri.ipAdrr, parametri.port);
- currPLC.ConnectionTimeout = 3000;
-
- currPLC.ConnectedChanged += CurrPLC_ConnectedChanged;
-
- // disconnetto e connetto...
- if (isVerboseLog)
- {
- lgInfoStartup("ModBus TCP: tryDisconnect");
- }
- tryDisconnect();
-
- // lo ripeto x evitare che ci sia un loop... e tryConnect richiami la procedura corrente...
- needRefresh = false;
- lgInfoStartup("ModBus TCP: tryConnect");
- tryConnect();
- lgInfoStartup("End init Adapter ModBusTCP");
- if (isVerboseLog)
- {
- lgInfo("ModBus TCP CONNESSIONE AVVENUTA");
- }
- }
- catch (Exception exc)
- {
- lgError(exc, "Errore in INIT ModBusTCP");
- }
- }
- else
- {
- lgError($"ModBusTCP IOB | Errore in ping: esito {esitoPing}");
- }
- parentForm.commPlcActive = false;
- }
- else
- {
- lgError("Parametri null!");
- }
- }
- }
-
- ///
- /// effettua il setup dei memblock da gestire (NON leggo intera memoria ma tanti blocchi...)
- ///
- protected void setupMemBlocks()
- {
- // se configurato -_> deserializzo
- string confFile = getOptPar("MEM_BLOCK");
- if (!string.IsNullOrEmpty(confFile))
- {
- string jsonFileName = $"{Application.StartupPath}/DATA/CONF/{confFile}";
- lgInfo($"Apertura file {jsonFileName}");
- using (StreamReader reader = new StreamReader(jsonFileName))
- {
- string jsonData = reader.ReadToEnd();
- if (!string.IsNullOrEmpty(jsonData))
- {
- lgInfo($"File json MemBlock composto da {jsonData.Length} caratteri");
- try
- {
- var currMem = JsonConvert.DeserializeObject(jsonData);
- memSetR = currMem.ReadBlocks;
- }
- catch (Exception exc)
- {
- lgError($"Errore in setupMemBlock{Environment.NewLine}{exc}");
- }
- }
- }
- }
- }
-
- ///
- /// Test connessione CNC
- ///
- ///
- protected bool testCncConn()
- {
- bool answ = currPLC.Connected;
- if (!answ)
- {
- // riduco i controlli ping.. li faccio solo ogni 5 ping period se precedente positivo...
- DateTime adesso = DateTime.Now;
- if (lastPingOk && adesso.Subtract(lastPingConn).TotalMilliseconds < 5 * parametri.pingMsTimeout)
- {
- answ = lastPingOk;
- }
- else
- {
- IPStatus pingStatus = testPingMachine;
-
- // se non ok riprovo 1 volta dopo attesa
- if (pingStatus != IPStatus.Success)
- {
- Thread.Sleep(2 * cIobConf.pingMsTimeout);
- pingStatus = testPingMachine;
- }
- // se non passa ancora errore!
- if (pingStatus != IPStatus.Success)
- {
- lgError($"Errore in testCncConn | reply Status {pingStatus} | IP: {parametri.ipAdrr} | T.Out: {parametri.pingMsTimeout}ms");
- }
- // se passa il ping faccio il resto...
- else
- {
- if (!currPLC.Connected)
- {
- currPLC.Connect();
- }
-
- if (!currPLC.Available(500))
- {
- lgError($"PLC ModBus NON disponibile: {currPLC.IPAddress} | {currPLC.Port}");
- }
- else
- {
- if (!currPLC.Connected)
- {
- lgError($"PLC ModBus NON connesso:{currPLC.IPAddress} | {currPLC.Port}");
- }
- else
- {
- // tutto ok
- parentForm.updateComStats("Connection OK");
- answ = true;
- }
- }
- }
- // salvo stato ping
- lastPingConn = adesso;
- }
- lastPingOk = answ;
- }
-
- return answ;
- }
-
- #endregion Protected Methods
-
#region Public Methods
///
@@ -962,8 +147,7 @@ namespace IOB_WIN_NEXT
}
///
- /// Decodifica tipo indirizzo dal codice
- /// vedere ad esempio https://www.fernhillsoftware.com/help/drivers/modbus/data-address-format.html
+ /// Decodifica tipo indirizzo dal codice vedere ad esempio https://www.fernhillsoftware.com/help/drivers/modbus/data-address-format.html
///
///
///
@@ -976,13 +160,12 @@ namespace IOB_WIN_NEXT
}
///
- /// Recupero dati dinamici...
- /// ATTENZIONE factor usato come FONDOSCALA
+ /// Recupero dati dinamici... ATTENZIONE factor usato come FONDOSCALA
///
/// Esempio:
- /// - RealVal : 0 - 28000
- /// - ReadVal : 0 - 100
- /// - Factor : 28000 / 100 = 280
+ /// - RealVal : 0 - 28000
+ /// - ReadVal : 0 - 100
+ /// - Factor : 28000 / 100 = 280
///
public override Dictionary getDynData()
{
@@ -1018,7 +201,8 @@ namespace IOB_WIN_NEXT
var memItemList = memMap.mMapRead;
readErrorList = getDataDictionary(memItemList, useLUT, ref outVal);
- // se qualcosa è andato storto riprovo a caricare SOLO gli errori... 1 sola volta
+ // se qualcosa è andato storto riprovo a caricare SOLO gli errori... 1
+ // sola volta
if (readErrorList.Count > 0)
{
lgDebug($"Attesa prima di rilettura | LUT: {useLUT}");
@@ -1138,8 +322,8 @@ namespace IOB_WIN_NEXT
}
///
- /// Effettua lettura semafori principale
- /// Parametri da aggiornare x display in form
+ /// Effettua lettura semafori principale Parametri da
+ /// aggiornare x display in form
///
public override void readSemafori(ref newDisplayData currDispData)
{
@@ -1351,5 +535,822 @@ namespace IOB_WIN_NEXT
}
#endregion Public Methods
+
+ #region Protected Fields
+
+ protected ModbusClient currPLC;
+
+ ///
+ /// Copia locale dei valori in Holding Registry, come array chiave (int) valori int[] letti
+ /// tramite ModBus, da convertire secondo tipo
+ ///
+ protected Dictionary HoldingRegisterLUT = new Dictionary();
+
+ ///
+ /// Ultimo controllo ping x evitare ping flood...
+ ///
+ protected DateTime lastPingConn = DateTime.Now.AddMinutes(-10);
+
+ ///
+ /// Esito ultimo ping
+ ///
+ protected bool lastPingOk = false;
+
+ ///
+ /// Setup blocchi memorie read (indirizzo inizio, size)
+ ///
+ protected Dictionary memSetR = new Dictionary();
+
+ ///
+ /// parametri di connessione
+ ///
+ protected connParamModBusTCP parametri;
+
+ ///
+ /// Oggetto cronometro x test vari...
+ ///
+ protected Stopwatch sw = new Stopwatch();
+
+ #endregion Protected Fields
+
+ #region Protected Properties
+
+ protected bool hasAlarms
+ {
+ get
+ {
+ bool answ = false;
+ int numErrors = 0;
+ int currStatus = 0;
+ int[] listInt = new int[2];
+ if (alarmMaps != null)
+ {
+ // leggo a ciclo le aree degli allarmi CONFIGURATI, se ne trovo --> segnalo allarme...
+ foreach (var item in alarmMaps)
+ {
+ // banchi in array Int16 --> scompongo
+ for (int i = 0; i < item.size / 2; i++)
+ {
+ // verifico se usare LUT
+ bool useLUT = memSetR != null && memSetR.Count > 0;
+ if (useLUT)
+ {
+ int lutAddress = 40000 + item.index;
+ if (HoldingRegisterLUT.ContainsKey(lutAddress))
+ {
+ try
+ {
+ listInt = HoldingRegisterLUT[lutAddress];
+ }
+ catch (Exception exc)
+ {
+ lgError($"Errore in lettura da HoldingRegisterLUT per indirizzo {lutAddress} | item {item.memAddr}{Environment.NewLine}{exc}");
+ }
+ }
+ }
+ else
+ {
+ listInt = readInputReg(item.index, item.size);
+ }
+ currStatus = ModbusClient.ConvertRegistersToInt(listInt);
+
+ // aggiornamento blink counters dato nuovo valore
+ item.checkBlinkCounter(i, (uint)currStatus);
+
+ // calcolo indice errori
+ if ((uint)(item.alarmsMask[i] & currStatus) > 0)
+ {
+ numErrors++;
+ }
+ // verifico SE sia variato... confronto allarmi filtrato stile blink per
+ // bit status:
+ // - allarmi che iniziano per # IGNORATI
+ // - altri allarmi con un countdown da MAX_COUNTER_BLINK a 0 per il
+ // fronte di discesa
+ if (item.isChanged(i, (uint)currStatus))
+ {
+ // registro gli allarmi attivi e trasmetto...
+ if (sendAlarmVariations(item.memAddr, i, item.alarmsState[i], (uint)(item.alarmsMask[i] & currStatus), item.messages))
+ {
+ // se inviato --> salvo stato da current...
+ item.updStatusVal(i, (uint)(item.alarmsMask[i] & currStatus));
+ }
+ }
+ }
+ }
+ }
+ answ = numErrors > 0;
+ return answ;
+ }
+ }
+
+ ///
+ /// Dizionario delle ultime operazioni di scrittura per OGNI memoria (in modo che fa log
+ /// ogni x sec...)
+ ///
+ protected Dictionary lastMemWrite { get; set; } = new Dictionary();
+
+ #endregion Protected Properties
+
+ #region Protected Methods
+
+ ///
+ /// Decodifica il resto dell'area x i dati accessori (allarmi, ...)
+ ///
+ protected virtual void decodeOtherData()
+ {
+ }
+
+ ///
+ /// Effettua decodifica aree memoria alla bitmap usata x MAPO/GWMS
+ /// - per macchine base (GWMS) IN REALTA' non gestito lo stato macchina.... previsto comunque
+ ///
+ protected virtual void decodeToBaseBitmap()
+ {
+ // init a zero...
+ B_input = 0;
+ }
+
+ ///
+ /// Override metodo x scrittura parametri su PLC
+ ///
+ ///
+ protected override void plcWriteParams(ref List updatedPar)
+ {
+ dataConf currMem = null;
+ int byteSize = 0;
+ int[] CurrVal = new int[1];
+ string memAddrWrite = "";
+ bool fatto = false;
+ string serObj = "";
+ if (updatedPar != null)
+ {
+ // controllo i parametri... ne gestisco 4...
+ foreach (var item in updatedPar)
+ {
+ try
+ {
+ memAddrWrite = "";
+ int valInt = 0;
+ uint valUInt = 0;
+ double valDouble = 0;
+ // cerco in area memMapWrite...
+ if (memMap.mMapWrite.ContainsKey(item.uid))
+ {
+ // recupero!
+ currMem = memMap.mMapWrite[item.uid];
+ byteSize = currMem.size;
+ memAddrWrite = currMem.memAddr;
+ CurrVal = new int[byteSize];
+ // faccio preliminarmente upsertKey...
+ upsertKey(currMem.name, currMem.value);
+ serObj = JsonConvert.SerializeObject(item, Formatting.Indented);
+ lgInfo($"Inizio processing plcWriteParams per {currMem.name} | valore richiesto {currMem.value}{Environment.NewLine}---------------UPDATED PARAM---------------{Environment.NewLine}{serObj}{Environment.NewLine}---------------");
+ serObj = JsonConvert.SerializeObject(currMem, Formatting.Indented);
+ lgInfo($"---------------MEMORY CONTENT---------------{Environment.NewLine}{serObj}{Environment.NewLine}---------------");
+ switch (currMem.tipoMem)
+ {
+ case plcDataType.Boolean:
+ break;
+
+ case plcDataType.Int:
+ valInt = getScaledInt(currMem);
+ CurrVal = ModbusClient.ConvertIntToRegisters(valInt);
+ fatto = writeInputReg(currMem.index, CurrVal);
+ break;
+
+ case plcDataType.DInt:
+ valUInt = getScaledUInt(currMem);
+ CurrVal = ModbusClient.ConvertLongToRegisters(valInt);
+ fatto = writeInputReg(currMem.index, CurrVal);
+ break;
+
+ //case plcDataType.Word:
+ // valUInt = getScaledUInt(currMem);
+ // saveWordOnMemBlock(ref MemBlock, 0, valInt.ToString());
+ // break;
+
+ //case plcDataType.DWord:
+ // valUInt = getScaledUInt(currMem);
+ // saveDWordOnMemBlock(ref MemBlock, 0, valInt.ToString());
+ // break;
+
+ case plcDataType.Real:
+ valDouble = getScaledDouble(currMem);
+ CurrVal = ModbusClient.ConvertFloatToRegisters((float)valDouble, ModbusClient.RegisterOrder.HighLow);
+ fatto = writeInputReg(currMem.index, CurrVal);
+ break;
+
+ //case plcDataType.String:
+ // // se ho writePre --> "allungo" di 2 la dimensione della stringa x MemBlock...
+ // if (writePre)
+ // {
+ // MemBlock = new byte[byteSize + 2];
+ // }
+ // saveStringOnMemBlock(ref MemBlock, 0, currMem.size, currMem.value);
+ // break;
+
+ default:
+ break;
+ }
+ lgInfo($"---------------MemBlock data---------------{Environment.NewLine}CurrVal: {CurrVal}{Environment.NewLine}--------------- END data ---------------");
+ if (!string.IsNullOrEmpty(memAddrWrite))
+ {
+ // se fatto --> aggiorno!
+ if (fatto)
+ {
+ item.value = item.reqValue;
+ item.reqValue = "";
+ item.lastRead = DateTime.Now;
+ item.UM = currMem.unit;
+ }
+ }
+ else
+ {
+ lgError($"Errore: memAddrWrite vuoto!");
+ }
+ }
+ else
+ {
+ lgError($"Errore uid non trovato in area write memory: {item.uid}, ci sono {memMap.mMapWrite.Count} in area write");
+ }
+ }
+ catch (Exception exc)
+ {
+ lgError($"Eccezione in fase di plcWriteParams per item {item.uid} con valore {item.value}{Environment.NewLine}{exc}");
+ }
+ }
+ }
+ }
+
+ ///
+ /// Imposto parametri PLC
+ ///
+ protected override void setParamPlc()
+ {
+ DateTime adesso = DateTime.Now;
+ // Creo oggetto connessione NC
+ parentForm.commPlcActive = true;
+ lgInfo($"Start init Adapter ModBus TCP all'IP {cIobConf.cncIpAddr} | port: {cIobConf.cncPort} | --> IOB {cIobConf.codIOB}");
+ // SE è necessario refresh...
+ if (needRefresh)
+ {
+ lgInfoStartup("Refreshing connection...");
+ if (parametri != null)
+ {
+ try
+ {
+ parametri.ipAdrr = cIobConf.cncIpAddr;
+ parametri.port = int.Parse(cIobConf.cncPort);
+ // leggo file init...
+ lgInfoStartup("Reading ini file...");
+ IniFile fIni = new IniFile(cIobConf.iniFileName);
+ // ora leggo valori speciali
+ parametri.memAddrRead = fIni.ReadString("MEMORY", "ADDR_READ", "");
+ parametri.memAddrWrite = fIni.ReadString("MEMORY", "ADDR_WRITE", "");
+ parametri.memSizeRead = fIni.ReadInteger("MEMORY", "SIZE_READ", 0);
+ parametri.memSizeWrite = fIni.ReadInteger("MEMORY", "SIZE_WRITE", 0);
+ parametri.holdRegBaseAddr = fIni.ReadInteger("MEMORY", "HR_BASE_ADDR", 40001);
+ // salvo vettori memoria...
+ lgInfoStartup("Set RawInput dimensions...");
+ RawInput = new byte[parametri.memSizeRead];
+ RawOutput = new byte[parametri.memSizeWrite];
+ // salvo parametri conn!
+ lgInfoStartup(string.Format("Parametri memoria: memAddrRead: {0} | memAddrWrite: {1} | memSizeRead: {2} | memSizeWrite: {3}", parametri.memAddrRead, parametri.memAddrWrite, parametri.memSizeRead, parametri.memSizeWrite));
+ }
+ catch (Exception exc)
+ {
+ lgError(exc, "Errore in parse parametri da IOBConf");
+ }
+
+ // carico conf vettore memoria...
+ loadMemConf();
+ // avvio conf blocchi memoria
+ setupMemBlocks();
+ // aggiungo DELTA x calcolo min/MAX...
+ string deltaValStr = getOptPar("DELTA_VAL");
+ if (!string.IsNullOrEmpty(deltaValStr))
+ {
+ double.TryParse(deltaValStr.Replace(".", ","), out deltaVal);
+ }
+ bool enableByApp = utils.CRB("enableContapezzi");
+ bool enableByIob = (getOptPar("ENABLE_PZCOUNT") == "TRUE");
+ bool disableByIob = (getOptPar("DISABLE_PZCOUNT") == "TRUE");
+ if ((enableByApp || enableByIob) && !(disableByIob))
+ {
+ lgInfoStartup("ModBus TCP: inizio gestione contapezzi");
+ try
+ {
+ // verifico quale modalità sia richiesta: STD (6711) oppure BIT (Custom,
+ // con indicazione area)
+ if (cIobConf.optPar.Count > 0 && !string.IsNullOrWhiteSpace(getOptPar("PZCOUNT_MODE")))
+ {
+ if (getOptPar("PZCOUNT_MODE").StartsWith("STD"))
+ {
+ lgInfoStartup("Init contapezzi ModBusTCP: pzCntReload(true)");
+ pzCntReload(true);
+ // refresh associazione Macchina - IOB
+ sendM2IOB();
+ // per adesso imposto lettura PLC == contapezzi (poi farà vera lettura...)
+ contapezziPLC = contapezziIOB;
+ }
+ else
+ {
+ contapezziIOB = 0;
+ lgDebug("Contapezzi STD disabilitato: modalità {0}", getOptPar("PZCOUNT_MODE"));
+ }
+ }
+ else
+ {
+ contapezziIOB = 0;
+ lgError("Parametro mancante PZCOUNT_MODE");
+ }
+ }
+ catch (Exception exc)
+ {
+ lgError(exc, "Errore in contapezzi ModBusTCP");
+ }
+ }
+
+ // ora tento avvio PLC... SE PING OK...
+ lastPING = adesso;
+ IPStatus esitoPing = testPingMachine;
+ if (esitoPing == IPStatus.Success)
+ {
+ needRefresh = false;
+ try
+ {
+ //Ip-Address and Port of Modbus-TCP-Server
+ currPLC = new ModbusClient(parametri.ipAdrr, parametri.port);
+ currPLC.ConnectionTimeout = 3000;
+
+ currPLC.ConnectedChanged += CurrPLC_ConnectedChanged;
+
+ // disconnetto e connetto...
+ if (isVerboseLog)
+ {
+ lgInfoStartup("ModBus TCP: tryDisconnect");
+ }
+ tryDisconnect();
+
+ // lo ripeto x evitare che ci sia un loop... e tryConnect richiami la
+ // procedura corrente...
+ needRefresh = false;
+ lgInfoStartup("ModBus TCP: tryConnect");
+ tryConnect();
+ lgInfoStartup("End init Adapter ModBusTCP");
+ if (isVerboseLog)
+ {
+ lgInfo("ModBus TCP CONNESSIONE AVVENUTA");
+ }
+ }
+ catch (Exception exc)
+ {
+ lgError(exc, "Errore in INIT ModBusTCP");
+ }
+ }
+ else
+ {
+ lgError($"ModBusTCP IOB | Errore in ping: esito {esitoPing}");
+ }
+ parentForm.commPlcActive = false;
+ }
+ else
+ {
+ lgError("Parametri null!");
+ }
+ }
+ }
+
+ ///
+ /// effettua il setup dei memblock da gestire (NON leggo intera memoria ma tanti blocchi...)
+ ///
+ protected void setupMemBlocks()
+ {
+ // se configurato -_> deserializzo
+ string confFile = getOptPar("MEM_BLOCK");
+ if (!string.IsNullOrEmpty(confFile))
+ {
+ string jsonFileName = $"{Application.StartupPath}/DATA/CONF/{confFile}";
+ lgInfo($"Apertura file {jsonFileName}");
+ using (StreamReader reader = new StreamReader(jsonFileName))
+ {
+ string jsonData = reader.ReadToEnd();
+ if (!string.IsNullOrEmpty(jsonData))
+ {
+ lgInfo($"File json MemBlock composto da {jsonData.Length} caratteri");
+ try
+ {
+ var currMem = JsonConvert.DeserializeObject(jsonData);
+ memSetR = currMem.ReadBlocks;
+ }
+ catch (Exception exc)
+ {
+ lgError($"Errore in setupMemBlock{Environment.NewLine}{exc}");
+ }
+ }
+ }
+ }
+ }
+
+ ///
+ /// Test connessione CNC
+ ///
+ ///
+ protected bool testCncConn()
+ {
+ bool answ = currPLC.Connected;
+ if (!answ)
+ {
+ // riduco i controlli ping.. li faccio solo ogni 5 ping period se precedente positivo...
+ DateTime adesso = DateTime.Now;
+ if (lastPingOk && adesso.Subtract(lastPingConn).TotalMilliseconds < 5 * parametri.pingMsTimeout)
+ {
+ answ = lastPingOk;
+ }
+ else
+ {
+ IPStatus pingStatus = testPingMachine;
+
+ // se non ok riprovo 1 volta dopo attesa
+ if (pingStatus != IPStatus.Success)
+ {
+ Thread.Sleep(2 * cIobConf.pingMsTimeout);
+ pingStatus = testPingMachine;
+ }
+ // se non passa ancora errore!
+ if (pingStatus != IPStatus.Success)
+ {
+ lgError($"Errore in testCncConn | reply Status {pingStatus} | IP: {parametri.ipAdrr} | T.Out: {parametri.pingMsTimeout}ms");
+ }
+ // se passa il ping faccio il resto...
+ else
+ {
+ if (!currPLC.Connected)
+ {
+ currPLC.Connect();
+ }
+
+ if (!currPLC.Available(500))
+ {
+ lgError($"PLC ModBus NON disponibile: {currPLC.IPAddress} | {currPLC.Port}");
+ }
+ else
+ {
+ if (!currPLC.Connected)
+ {
+ lgError($"PLC ModBus NON connesso:{currPLC.IPAddress} | {currPLC.Port}");
+ }
+ else
+ {
+ // tutto ok
+ parentForm.updateComStats("Connection OK");
+ answ = true;
+ }
+ }
+ }
+ // salvo stato ping
+ lastPingConn = adesso;
+ }
+ lastPingOk = answ;
+ }
+
+ return answ;
+ }
+
+ #endregion Protected Methods
+
+ #region Private Fields
+
+ ///
+ /// Valore delta x gestione min/MAX e valore rilevato
+ ///
+ private double deltaVal = 0;
+
+ ///
+ /// Indirizzo di base x fare il calcolo di dove leggere in ModBus
+ ///
+ private int HoldRegBaseAddr = 40001;
+
+ #endregion Private Fields
+
+ #region Private Methods
+
+ ///
+ /// converte valore in tipo desiderato
+ ///
+ ///
+ ///
+ ///
+ ///
+ private static double convertFromReg(int[] listInt, int size, plcDataType tipoMem)
+ {
+ double valore = 0;
+ //verifico se sia INT o real x convertire...
+ switch (tipoMem)
+ {
+ case plcDataType.Real:
+ if (size == 4)
+ {
+ valore = ModbusClient.ConvertRegistersToDouble(listInt);
+ }
+ else if (size == 2)
+ {
+ valore = ModbusClient.ConvertRegistersToFloat(listInt);
+ }
+ break;
+
+ // caso speciale x Cedax, che usa HighVal moltiplicato x 32768...
+ case plcDataType.HLPInt:
+ if (size == 4)
+ {
+ valore = ModbusClient.ConvertRegistersToLong(listInt);
+ }
+ else if (size == 2)
+ {
+ int fact = Int16.MaxValue + 1;
+ valore = listInt[1] * fact + listInt[0];
+ }
+ break;
+
+ case plcDataType.Int:
+ default:
+ if (size == 4)
+ {
+ valore = ModbusClient.ConvertRegistersToLong(listInt);
+ }
+ else if (size == 2)
+ {
+ valore = ModbusClient.ConvertRegistersToInt(listInt);
+ }
+ break;
+ }
+ return valore;
+ }
+
+ private static double getScaledDouble(dataConf currMem)
+ {
+ double valDouble;
+ // prima faccio eventuale fattore di scala...
+ double.TryParse(currMem.value, out valDouble);
+ if (currMem.factor != 1)
+ {
+ valDouble = valDouble * (double)currMem.factor;
+ }
+
+ return valDouble;
+ }
+
+ private static int getScaledInt(dataConf currMem)
+ {
+ int valInt;
+ // prima faccio eventuale fattore di scala...
+ int.TryParse(currMem.value, out valInt);
+ if (currMem.factor != 1)
+ {
+ valInt = (int)(valInt * currMem.factor);
+ }
+
+ return valInt;
+ }
+
+ private static uint getScaledUInt(dataConf currMem)
+ {
+ uint valUInt;
+ // prima faccio eventuale fattore di scala...
+ uint.TryParse(currMem.value, out valUInt);
+ if (currMem.factor != 1)
+ {
+ valUInt = valUInt * (uint)currMem.factor;
+ }
+
+ return valUInt;
+ }
+
+ ///
+ /// se si disconnette --> processo tentativo riconnessione..
+ ///
+ ///
+ private void CurrPLC_ConnectedChanged(object sender)
+ {
+ if (!currPLC.Connected)
+ {
+ tryDisconnect();
+ }
+ }
+
+ ///
+ /// Recupero dati da singole letture
+ ///
+ /// Valori da processare
+ /// Impiego della LookUpTable x diminuire accessi
+ /// Dizionario valori in uscita
+ /// Errori di lettura
+ private Dictionary getDataDictionary(Dictionary memItemList, bool useLUT, ref Dictionary outVal)
+ {
+ Dictionary readErrorList = new Dictionary();
+ // inizializzo i valori
+ bool[] listBool = new bool[1];
+ int[] listInt = new int[2];
+ // procedo x ogni valore configurato...
+ foreach (var item in memItemList)
+ {
+ // attesa 50 ms prima di procedere x evitare burst dati
+ if (!useLUT)
+ {
+ Thread.Sleep(50);
+ }
+ double valore = 0;
+ double valoreScal = 0;
+ bool dataOk = false;
+ // in primis DEVO determinare di quale TIPO di valore ho bisogno... dalla PRIMA
+ // cifra di memAddr...
+ modBusAddrType memAddrType = getAddrType(item.Value.memAddr);
+ // in base al tipo leggo array...
+ switch (memAddrType)
+ {
+ case modBusAddrType.Coil:
+ listBool = readCoil(item.Value.index, item.Value.size);
+ valore = listBool[0] ? 1 : 0;
+ break;
+
+ case modBusAddrType.DiscreteInput:
+ listBool = readDiscrInputs(item.Value.index, item.Value.size);
+ valore = listBool[0] ? 1 : 0;
+ break;
+
+ case modBusAddrType.InputRegister:
+ listInt = readInputReg(item.Value.index, item.Value.size);
+ valore = convertFromReg(listInt, item.Value.size, item.Value.tipoMem);
+
+ break;
+
+ case modBusAddrType.HoldingRegister:
+ if (useLUT)
+ {
+ int lutAddress = 40000 + item.Value.index;
+ if (HoldingRegisterLUT.ContainsKey(lutAddress))
+ {
+ try
+ {
+ listInt = HoldingRegisterLUT[lutAddress];
+ }
+ catch (Exception exc)
+ {
+ lgError($"Errore in lettura da HoldingRegisterLUT per indirizzo {lutAddress} | item {item.Key}{Environment.NewLine}{exc}");
+ }
+ }
+ }
+ else
+ {
+ listInt = readHoldReg(item.Value.index - 1, item.Value.size);
+ }
+ valore = convertFromReg(listInt, item.Value.size, item.Value.tipoMem);
+ break;
+
+ default:
+ break;
+ }
+ // verifica limite... con delta da impianto
+ dataOk = (valore > (item.Value.minVal + deltaVal) && valore < (item.Value.maxVal - deltaVal));
+ if (dataOk)
+ {
+ // moltiplico x fattore conversione...
+ valoreScal = valore * item.Value.factor;
+ saveValue(ref outVal, valoreScal, item.Key);
+ lgDebug($"getDynData: valore ricevuto | {item.Key} | val: {valore} | valoreScal: {valoreScal}");
+ }
+ else
+ {
+ lgError($"getDynData: valore scartato x limiti min/max | {item.Key} | val: {valore} | valoreScal: {valoreScal} | min-max: {item.Value.minVal}-{item.Value.maxVal} | deltaVal: {deltaVal}");
+ readErrorList.Add(item.Key, item.Value);
+ lgDebug($"--> rimesso in coda lettura | parametro: {item.Key} | index: {item.Value.index} | size: {item.Value.size}");
+ }
+ }
+
+ return readErrorList;
+ }
+
+ ///
+ /// Verifica SE sia il caso di fare il log della memoria indicata
+ ///
+ ///
+ ///
+ private void maybeLogWrite(string memAddrWrite, string logValue)
+ {
+ bool doWrite = true;
+ DateTime adesso = DateTime.Now;
+ if (!lastMemWrite.ContainsKey(memAddrWrite))
+ {
+ lastMemWrite.Add(memAddrWrite, adesso.AddMinutes(-1));
+ }
+ // ora mi leggo valore ultimas crittura e confronto con adesso
+ try
+ {
+ doWrite = (lastMemWrite[memAddrWrite].AddSeconds(vetoSeconds) < adesso);
+ }
+ catch (Exception exc)
+ {
+ lgError($"Eccezione in maybeLogWrite{Environment.NewLine}{exc}");
+ }
+ // se encessario --> LOG!
+ if (doWrite)
+ {
+ lgInfo(logValue);
+ lastMemWrite[memAddrWrite] = adesso;
+ }
+ }
+
+ ///
+ /// Effettua lettura blocco memoria indicato e lo salva in copia locale HoldingRegisterLUT
+ ///
+ /// Indirizzo di aprtenza
+ /// NUm registri da leggere (max 120)
+ private void readBlockHoldingReg(int startAddr, int numReg, int baseAddr)
+ {
+ bool allOk = false;
+ if (currPLC.Connected)
+ {
+ allOk = true;
+ // fix massima lunghezza pacchetto
+ if (numReg > 120)
+ {
+ lgError($"Attenzione richiesta lettura blocco troppo grande: numReg {numReg} --> 120");
+ numReg = 120;
+ }
+ // si lavora rispetto all'indirizzo base 40001
+
+ int[] rawData = new int[2];
+ try
+ {
+ stopwatch.Restart();
+ rawData = currPLC.ReadHoldingRegisters(startAddr - baseAddr, numReg);
+ stopwatch.Stop();
+ lgTrace($"Lettura in blocco HoldingRegisters| startAddr: {startAddr} | numReg {numReg} | rawData.lenght: {rawData.Length} | {stopwatch.ElapsedMilliseconds}ms");
+ // salvo in LUT la versione ESPLOSA 2 byte alla volta...
+ if (rawData.Length > 0)
+ {
+ for (int i = 0; i < rawData.Length / 2; i++)
+ {
+ int[] thisSet = new int[2];
+ if (rawData.Length >= (i + 1) * 2)
+ {
+ Array.Copy(rawData, i * 2, thisSet, 0, 2);
+ // salvo nel registro...
+ int currAddr = startAddr + i * 2;
+ if (HoldingRegisterLUT.ContainsKey(currAddr))
+ {
+ HoldingRegisterLUT[currAddr] = thisSet;
+ }
+ else
+ {
+ HoldingRegisterLUT.Add(currAddr, thisSet);
+ }
+ }
+ else
+ {
+ currReadErrors++;
+ allOk = false;
+ lgError($"Impossibile copiare dati, array di origine troppo corto: rawData.lenght: {rawData.Length} | base addr richiesto i*2: {i * 2} | errori currReadErrors: {currReadErrors}");
+ }
+ }
+ }
+ }
+ catch (Exception exc)
+ {
+ currReadErrors++;
+ allOk = false;
+ lgError($"Eccezione in readBlockHoldingReg | currReadErrors: {currReadErrors}{Environment.NewLine}{exc}");
+ }
+ }
+ else
+ {
+ lgError($"Attenzione, plc disconnesso... currReadErrors: {currReadErrors}");
+ tryDisconnect();
+ }
+
+ // se tutto ok --> riduco contatore errori di 1...
+ if (allOk)
+ {
+ currReadErrors = currReadErrors >= 1 ? currReadErrors-- : 0;
+ }
+ else
+ {
+ // se > max errori --> disconnetto
+ if (currReadErrors > maxReadErrors)
+ {
+ lgError($"Superato limite errori Read ({currReadErrors}) --> tryDisconnect");
+ currReadErrors = 0;
+ tryDisconnect();
+ }
+ else
+ {
+ // altrimenti pausa forzata
+ Thread.Sleep(300);
+ }
+ }
+ }
+
+ #endregion Private Methods
}
}
\ No newline at end of file
diff --git a/IOB-WIN-NEXT/IobModbusTCPHelpi.cs b/IOB-WIN-NEXT/IobModbusTCPHelpi.cs
index c3022111..40596d8c 100644
--- a/IOB-WIN-NEXT/IobModbusTCPHelpi.cs
+++ b/IOB-WIN-NEXT/IobModbusTCPHelpi.cs
@@ -185,7 +185,14 @@ namespace IOB_WIN_NEXT
get
{
int answ = 0;
-
+ // hard coded
+ int statusReg = 41108;
+ if (HoldingRegisterLUT.ContainsKey(statusReg))
+ {
+ int[] listInt = new int[2];
+ listInt = HoldingRegisterLUT[statusReg];
+ answ = ModbusClient.ConvertRegistersToInt(listInt);
+ }
return answ;
}
}
@@ -199,11 +206,13 @@ namespace IOB_WIN_NEXT
{
bool answ = false;
int currStatus = 0;
+ // hard coded
+ int statusReg = 41094;
// deve avere allarmi (è un allarme EStop)
if (hasAlarms)
{
int[] listInt = new int[2];
- listInt = HoldingRegisterLUT[41094];
+ listInt = HoldingRegisterLUT[statusReg];
currStatus = ModbusClient.ConvertRegistersToInt(listInt);
// hard coded il 5° bit
answ = ((currStatus & (1 << 4)) > 0);