Files
Mapo-IOB-WIN/IOB-WIN-NEXT/IobModbusTCP.cs
T
Samuele Locatelli aa18a31360 Bozza TPC test HAM
2021-09-25 11:35:21 +02:00

496 lines
21 KiB
C#

using EasyModbus;
using IOB_UT_NEXT;
using MapoSDK;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
namespace IOB_WIN_NEXT
{
public class IobModbusTCP : IobGeneric
{
#region Protected Fields
protected ModbusClient currPLC;
/// <summary>
/// Setup blocchi memorie read (indirizzo inizio, size)
/// </summary>
protected Dictionary<int, int> memSetR = new Dictionary<int, int>();
/// <summary>
/// Setup blocchi memorie write (indirizzo inizio, size)
/// </summary>
protected Dictionary<int, int> memSetW = new Dictionary<int, int>();
/// <summary>
/// parametri di connessione
/// </summary>
protected connParamModBusTCP parametri;
#endregion Protected Fields
#region Public Constructors
/// Classe base con i metodi x ModBusTCP
/// </summary>
/// <param name="caller"></param>
/// <param name="adpConf"></param>
public IobModbusTCP(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf)
{
lgInfo("NEW IOB ModBus TCP");
setupMemBlocks();
memMap = new plcMemMap();
if (IOBConf != null)
{
// gestione invio ritardato contapezzi
pzCountDelay = utils.CRI("pzCountDelay");
lastPzCountSend = DateTime.Now;
lastWarnODL = DateTime.Now;
// inizializzo parametri...
parametri = new connParamModBusTCP()
{
ipAdrr = "127.0.0.1",
port = 502,
pingMsTimeout = IOBConf.pingMsTimeout,
memAddrRead = "40001",
memAddrWrite = "41001",
memSizeRead = 0,
memSizeWrite = 0
};
setParamPlc();
// salvo info su conf IOB...
string iobConfSer = "";
try
{
iobConfSer = JsonConvert.SerializeObject(IOBConf, Formatting.Indented);
}
catch
{ }
// finito!
lgInfo($"Init IOB, con {iobConfSer}");
}
else
{
lgError("Impossibile avviare, IOBConf nullo/non valido!");
}
// provo una lettura
testRead();
}
#endregion Public Constructors
#region Private Methods
/// <summary>
/// effettua il setup dei memblock da gestire (NON leggo intera memoria ma tanti blocchi...)
/// </summary>
private void setupMemBlocks()
{
// da calcolare... ora setup cablato...
memSetR.Add(1, 34);
}
private void testRead()
{
//Ip-Address and Port of Modbus-TCP-Server
currPLC = new ModbusClient(cIobConf.cncIpAddr, 502);
//Connect to Server
currPLC.Connect();
//modbusClient.WriteMultipleCoils(4, new bool[] { true, true, true, true, true, true, true, true, true, true }); //Write Coils starting with Address 5
//bool[] readCoils = modbusClient.ReadCoils(9, 10); //Read 10 Coils from Server, starting with address 10
int[] readHoldingRegisters = currPLC.ReadHoldingRegisters(0, 34); //Read 10 Holding Registers from Server, starting with Address 1
int[] readHR1000 = currPLC.ReadHoldingRegisters(0, 100); //Read 10 Holding Registers from Server, starting with Address 1
//// Console Output
//for (int i = 0; i < readCoils.Length; i++)
// Console.WriteLine("Value of Coil " + (9 + i + 1) + " " + readCoils[i].ToString());
for (int i = 0; i < readHoldingRegisters.Length; i++)
{
Console.WriteLine("Value of HoldingRegister " + (i + 1) + " " + readHoldingRegisters[i].ToString());
int[] thisSet = new int[2];
Array.Copy(readHoldingRegisters, i, thisSet, 0, 2);
Console.WriteLine("Convert val HoldingRegister " + (i + 1) + " " + ModbusClient.ConvertRegistersToFloat(thisSet));
}
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
#if false
//Disconnect from Server
currPLC.Disconnect();
#endif
}
#endregion Private Methods
#region Protected Methods
/// <summary>
/// Override metodo x scrittura parametri su PLC
/// </summary>
/// <param name="updatedPar"></param>
protected override void plcWriteParams(ref List<objItem> updatedPar)
{
#if false
dataConf currMem = null;
int byteSize = 0;
byte[] MemBlock = new byte[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;
// cerco in area memMapWrite...
if (memMap.mMapWrite.ContainsKey(item.uid))
{
// recupero!
currMem = memMap.mMapWrite[item.uid];
byteSize = currMem.size;
memAddrWrite = currMem.memAddr;
MemBlock = new byte[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);
saveIntOnMemBlock(ref MemBlock, 0, valInt.ToString());
break;
case plcDataType.DInt:
valInt = getScaledInt(currMem);
saveDIntOnMemBlock(ref MemBlock, 0, valInt.ToString());
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:
saveRealOnMemBlock(ref MemBlock, 0, currMem.value);
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}{BitConverter.ToString(MemBlock)}{Environment.NewLine}--------------- END data ---------------");
if (!string.IsNullOrEmpty(memAddrWrite))
{
// scrivo su ModBusTCP
fatto = S7WriteBB(ref MemBlock, memAddrWrite);
// se fatto --> aggiorno!
if (fatto)
{
item.value = item.reqValue;
item.reqValue = "";
item.lastRead = DateTime.Now;
}
// se configurato faccio verifica write...
if (getOptPar("WRITE_CHECK") == "TRUE")
{
byte[] MemBlockRead = new byte[MemBlock.Length];
S7ReadBB(ref MemBlockRead, memAddrWrite, MemBlock.Length);
// se non corrispondessero loggo!
if (!MemBlock.SequenceEqual(MemBlockRead))
{
lgError($"Errore: mancata corrispondenza tra dati scritti e letti:{Environment.NewLine}Write: {BitConverter.ToString(MemBlock)}{Environment.NewLine}read: {BitConverter.ToString(MemBlockRead)}");
}
else
{
lgInfo($"Scrittura corretta: {BitConverter.ToString(MemBlockRead)}");
}
}
}
else
{
lgInfo($"Errore: memAddrWrite vuoto!");
}
}
else
{
lgInfo($"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}");
}
}
}
#endif
}
/// <summary>
/// Imposto parametri PLC
/// </summary>
protected override void setParamPlc()
{
// 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)
{
lgInfo("Refreshing connection...");
if (parametri != null)
{
try
{
parametri.ipAdrr = cIobConf.cncIpAddr;
parametri.port = int.Parse(cIobConf.cncPort);
// leggo file init...
lgInfo("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);
// salvo vettori memoria...
lgInfo("Set RawInput dimensions...");
RawInput = new byte[parametri.memSizeRead];
RawOutput = new byte[parametri.memSizeWrite];
// salvo parametri conn!
lgInfo(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");
}
// ora tento avvio PLC... SE PING OK...
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);
// disconnetto e connetto...
if (isVerboseLog)
{
lgInfo("ModBusTCP: tryDisconnect");
}
tryDisconnect();
// lo ripeto x evitare che ci sia un loop... e tryConnect richiami la procedura corrente...
needRefresh = false;
lgInfo("ModBusTCP: tryConnect");
tryConnect();
lgInfo("End init Adapter ModBusTCP");
if (isVerboseLog)
{
lgInfo("ModBusTCP CONNESSIONE AVVENUTA");
}
}
catch (Exception exc)
{
lgError(exc, "Errore in INIT ModBusTCP");
}
}
else
{
lgError($"Errore in ping: esito {esitoPing}");
}
parentForm.commPlcActive = false;
// carico conf vettore memoria...
loadMemConf();
bool enableByApp = utils.CRB("enableContapezzi");
bool enableByIob = (getOptPar("ENABLE_PZCOUNT") == "TRUE");
bool disableByIob = (getOptPar("DISABLE_PZCOUNT") == "TRUE");
if ((enableByApp || enableByIob) && !(disableByIob))
{
lgInfo("ModBusTCP: 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"))
{
lgInfo("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;
lgInfo("Contapezzi STD disabilitato: modalità {0}", getOptPar("PZCOUNT_MODE"));
}
}
else
{
contapezziIOB = 0;
lgInfo("Parametro mancante PZCOUNT_MODE");
}
}
catch (Exception exc)
{
lgError(exc, "Errore in contapezzi ModBusTCP");
}
}
}
else
{
lgError("Parametri null!");
}
}
}
#endregion Protected Methods
#region Public Methods
/// <summary>
/// Override connessione
/// </summary>
public override void tryConnect()
{
bool doLog = (verboseLog || periodicLog);
lgInfo("ModBusTCP: tryConnect step 01");
if (!connectionOk)
{
// SE è necessario refresh...
if (needRefresh)
{
lgInfo("ModBusTCP: tryConnect step 02");
// reimporto parametri PLC se necessario...
setParamPlc();
}
lgInfo("ModBusTCP: tryConnect step 03");
// controllo che il ping sia stato tentato almeno pingTestSec fa...
if (DateTime.Now.Subtract(lastPING).TotalSeconds > utils.CRI("pingTestSec"))
{
if (doLog)
{
lgInfo("ModBusTCP: ConnKO - tryConnect");
}
lgInfo("ModBusTCP: tryConnect step 04");
// in primis salvo data ping...
lastPING = DateTime.Now;
// se passa il ping faccio il resto...
if (testPingMachine == IPStatus.Success)
{
string szStatusConnection = "ND";
try
{
// ora provo connessione...
parentForm.commPlcActive = true;
currPLC.Connect();
szStatusConnection = "OPEN";
parentForm.commPlcActive = false;
connectionOk = currPLC.Connected;
lgInfo($"StatusConnection: {szStatusConnection}");
// refresh stato allarmi!!!
if (connectionOk)
{
if (adpRunning)
{
lgInfo($"Connessione OK: {connectionOk} | adpRunning: {adpRunning}");
}
}
else
{
lgError("Impossibile procedere, connessione mancante...");
}
}
catch (Exception exc)
{
lgFatal($"Errore in TryConnect adapter ModBusTCP | szStatusConnection {szStatusConnection}{Environment.NewLine}{exc}");
connectionOk = false;
needRefresh = true;
}
}
else
{
// loggo no risposta ping ...
connectionOk = false;
if (doLog)
{
lgInfo($"Attenzione: ModBusTCP controllo PING fallito per IP {cIobConf.cncIpAddr}");
}
}
}
}
// se non è ancora connesso faccio procesisng memoria caso disconnesso...
if (!connectionOk)
{
// processo semafori ed invio...
processMemoryDiscon();
}
}
/// <summary>
/// Override disconnessione
/// </summary>
public override void tryDisconnect()
{
if (connectionOk)
{
string szStatusConnection = "";
try
{
currPLC.Disconnect();
connectionOk = false;
lgInfo(szStatusConnection);
lgInfo("Effettuata disconnessione adapter ModBusTCP!");
}
catch (Exception exc)
{
lgFatal(exc, "Errore nella disconnessione dall'adapter ModBusTCP");
}
}
else
{
lgError("IMPOSSIBILE effettuare disconnessione ModBusTCP: Connessione non disponibile...");
}
}
#endregion Public Methods
}
}