Files
Mapo-IOB-WIN/IOB-WIN-SIEMENS/IobSiemens/Siemens.cs
T
2025-01-10 16:47:50 +01:00

1816 lines
76 KiB
C#

using IOB_UT_NEXT;
using MapoSDK;
using Newtonsoft.Json;
using S7.Net;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading;
namespace IOB_WIN_SIEMENS.IobSiemens
{
public class Siemens : Iob.GenericNext, IDisposable
{
/* --------------------------------------------------------------------------------
* Controlli SIEMENS tramite libreria S7.net
* - basasto su SIEMENS
* - S7 testato vers 300 e 1200
* - attenzione conf rack/slot x varie serie controlli
* - necessità apertura metodi pu/get
*
* -------------------------------------------------------------------------------- */
#region Public Fields
/// <summary>
/// Byte dimensione buffer dati memoria (da file map)
/// </summary>
public int numByte = 0;
#endregion Public Fields
#region Public Constructors
/// <summary>
/// Classe base con i metodi x Siemens
/// </summary>
/// <param name="caller"></param>
/// <param name="adpConf"></param>
public Siemens(AdapterFormNext caller, IobConfiguration IOBConf) : base(caller, IOBConf)
{
memMap = new plcMemMapExt();
writePre = true;
if (IOBConf.optPar.ContainsKey("WRITE_PRE"))
{
bool.TryParse(IOBConf.optPar["WRITE_PRE"], out writePre);
lgInfo($"Override Write pre da conf: {IOBConf.optPar["WRITE_PRE"]} --> {writePre}");
}
if (IOBConf != null)
{
// gestione invio ritardato contapezzi
pzCountDelay = utils.CRI("pzCountDelay");
lastPzCountSend = DateTime.Now;
lastWarnODL = DateTime.Now;
// inizializzo parametri...
parametri = new connParamS7()
{
ipAdrr = "127.0.0.1",
tipoCpu = CpuType.S7200,
slot = 0,
rack = 0,
pingMsTimeout = IOBConf.pingMsTimeout,
memAddrRead = "DB1.DBB0",
memAddrWrite = "DB2.DBB0",
memSizeRead = 0,
memSizeWrite = 0
};
setParamPlc();
// salvo info su conf IOB...
string iobConfSer = "";
try
{
iobConfSer = JsonConvert.SerializeObject(IOBConf, Formatting.Indented);
}
catch
{ }
// finito!
lgInfoStartup($"Init IOB, con {iobConfSer}");
}
else
{
lgError("Impossibile avviare, IOBConf nullo/non valido!");
}
}
#endregion Public Constructors
#region Public Methods
/// <summary>
/// Converte direttamente un valore Int su un oggetto byte[4]
/// </summary>
/// <param name="valore">valore da scrivere</param>
public byte[] dintToByte(string valore)
{
byte[] answ = new byte[4];
try
{
int valInt = 0;
int.TryParse(valore, out valInt);
byte[] strByte = S7.Net.Types.DInt.ToByteArray(valInt);
int byteLen = 4;
Buffer.BlockCopy(strByte, 0, answ, 0, byteLen);
}
catch (Exception exc)
{
lgError($"Errore in gestione scrittura DINT {valore} in byte{Environment.NewLine}{exc}");
}
return answ;
}
/// <summary>
/// Metodo dispose x il currPLC contenuto
/// </summary>
public void Dispose()
{
currPLC.Dispose();
}
/// <summary>
/// Converte direttamente un valore UInt32 su un oggetto byte[4]
/// </summary>
/// <param name="valore">valore da scrivere</param>
public byte[] dwordToByte(string valore)
{
byte[] answ = new byte[4];
try
{
ushort valInt = 0;
ushort.TryParse(valore, out valInt);
byte[] strByte = S7.Net.Types.DWord.ToByteArray(valInt);
int byteLen = 4;
Buffer.BlockCopy(strByte, 0, answ, 0, byteLen);
}
catch (Exception exc)
{
lgError($"Errore in gestione scrittura DINT {valore} in byte{Environment.NewLine}{exc}");
}
return answ;
}
/// <summary>
/// Recupero dati dinamici...
/// </summary>
public override Dictionary<string, string> getDynData()
{
// valore non presente in vers default... se gestito fare override
Dictionary<string, string> outVal = new Dictionary<string, string>();
if (utils.CRB("enableTSVC"))
{
// processing SOLO SE ho in memoria abbastanza dati...
if (RawInput.Length < parametri.memSizeRead)
{
lgError($"Impossibile processare getDynData x Siemens PLC, vettore memoria troppo piccolo: {RawInput.Length} byte / {parametri.memSizeRead} byte presenti/richiesti)");
}
else
{
try
{
// processo x ogni valore configurato...
if (memMap.mMapRead.Count > 0)
{
// inizializzo i valori
bool valBool = false;
double valore = 0;
string valString = "";
// procedo x ogni valore configurato......
foreach (var item in memMap.mMapRead)
{
// in primis DEVO determinare di quale TIPO di valore ho bisogno...
switch (item.Value.tipoMem)
{
case plcDataType.Boolean:
valBool = S7.Net.Types.Boolean.GetValue(RawInput[item.Value.index], item.Value.size);
break;
case plcDataType.Int:
valore = ((double)S7.Net.Types.Int.FromByteArray(RawInput.Skip(item.Value.index).Take(item.Value.size).ToArray())) / item.Value.factor;
saveValue(ref outVal, item.Key, valore);
break;
case plcDataType.DInt:
valore = ((double)S7.Net.Types.DInt.FromByteArray(RawInput.Skip(item.Value.index).Take(item.Value.size).ToArray())) / item.Value.factor;
saveValue(ref outVal, item.Key, valore);
break;
case plcDataType.Word:
valore = ((double)S7.Net.Types.Word.FromByteArray(RawInput.Skip(item.Value.index).Take(item.Value.size).ToArray())) / item.Value.factor;
saveValue(ref outVal, item.Key, valore);
break;
case plcDataType.DWord:
valore = ((double)S7.Net.Types.DWord.FromByteArray(RawInput.Skip(item.Value.index).Take(item.Value.size).ToArray())) / item.Value.factor;
saveValue(ref outVal, item.Key, valore);
break;
case plcDataType.Real:
valore = S7.Net.Types.Double.FromByteArray(RawInput.Skip(item.Value.index).Take(item.Value.size).ToArray()) / item.Value.factor;
saveValue(ref outVal, item.Key, valore);
break;
case plcDataType.String:
valString = S7.Net.Types.String.FromByteArray(RawInput.Skip(item.Value.index).Take(item.Value.size).ToArray());
saveValueString(ref outVal, item.Key, valString);
break;
case plcDataType.Byte:
case plcDataType.BitMap:
byte[] byteState = RawInput.Skip(item.Value.index).Take(item.Value.size).ToArray();
// calcolo valore string come unione delle bitmap attive...
valString = getBitmapState(item.Value, byteState);
// se vuoto segno "OK"
valString = string.IsNullOrEmpty(valString) ? "OK" : valString;
saveValueString(ref outVal, item.Key, valString);
break;
default:
break;
}
}
}
else
{
lgInfo($"getDynData: {memMap.mMapRead.Count} record in mMapRead");
}
}
catch (Exception exc)
{
lgError(exc, "Errore in getDynData x Siemens PLC");
}
}
}
else
{
lgInfo($"Non processo getDynData: enableTSVC = false");
}
if (periodicLog || outVal.Count > 0)
{
lgInfo($"Esito getDynData: {outVal.Count} valori VALIDI in outVal");
}
return outVal;
}
/// <summary>
/// Recupero programma in lavorazione
/// </summary>
/// <returns></returns>
public override string getPrgName()
{
// valore non presente in vers default... se gestito fare override
string prgName = "";
return prgName;
}
/// <summary>
/// Recupero programma in lavorazione come Dictionary FANUC...
/// - SYSINFO: (prima KEY globale) TUTTI i valori separati da # (x fare check modifica)
/// - altre stringhe: ogni singolo parametro / valore
/// </summary>
/// <returns></returns>
public override Dictionary<string, string> getSysInfo()
{
// valore non presente in vers default... se gestito fare override
Dictionary<string, string> outVal = new Dictionary<string, string>();
return outVal;
}
/// <summary>
/// Converte direttamente un valore Short su un oggetto byte[2]
/// </summary>
/// <param name="valore">valore da scrivere</param>
public byte[] intToByte(string valore)
{
byte[] answ = new byte[2];
try
{
short valInt = 0;
short.TryParse(valore, out valInt);
byte[] strByte = S7.Net.Types.Int.ToByteArray(valInt);
int byteLen = 2;
Buffer.BlockCopy(strByte, 0, answ, 0, byteLen);
}
catch (Exception exc)
{
lgError($"Errore in gestione scrittura INT {valore} in byte{Environment.NewLine}{exc}");
}
return answ;
}
/// <summary>
/// Effettua vero processing contapezzi
/// </summary>
public override void processContapezzi()
{
bool disableByIob = (getOptPar("DISABLE_PZCOUNT") == "TRUE");
if (utils.CRB("enableContapezzi") && !disableByIob)
{
try
{
// verifico quale modalità sia richiesta: STD (6711) oppure BIT (Custom, con
// indicazione area)
if (cIobConf.optPar.Count > 0)
{
int pzCountBuoni = -1;
int pzCountQCtrl = -1;
int pzCountAll = 0;
string memAddrPzCount = "";
string strOutValPzBuoni = "";
string memAddrPzQCtrl = "";
string strOutValPzQCtrl = "";
if (!string.IsNullOrEmpty(getOptPar("PZCOUNT_MODE")))
{
memAddrPzCount = getOptPar("PZCOUNT_MODE");
strOutValPzBuoni = readCountVal(ref memAddrPzCount);
// verifico valori letti
if (!string.IsNullOrEmpty(strOutValPzBuoni))
{
// salvo...
Int32.TryParse(strOutValPzBuoni, out pzCountBuoni);
// e sommo (SE sono > -1)
if (pzCountBuoni >= 0)
{
pzCountAll += pzCountBuoni;
}
}
}
if (!string.IsNullOrEmpty(getOptPar("PZQCTRL_MODE")))
{
memAddrPzQCtrl = getOptPar("PZQCTRL_MODE");
strOutValPzQCtrl = readCountVal(ref memAddrPzQCtrl);
// verifico valori letti
if (!string.IsNullOrEmpty(strOutValPzQCtrl))
{
// salvo...
Int32.TryParse(strOutValPzQCtrl, out pzCountQCtrl);
// e sommo (SE sono > -1)
if (pzCountQCtrl >= 0)
{
pzCountAll += pzCountQCtrl;
}
}
}
// proseguo SOLO SE ho un pzCount > 0...
if (pzCountAll >= 0)
{
// verifico il NUOVO contapezzi PRIMA di accettare ogni incremento...
int deltaPzCount = pzCountAll - contapezziPLC;
double maxDelta = DateTime.Now.Subtract(plcLastPzRead).TotalMinutes / (plcAvgTc / 60);
// se incremento superiore del doppio atteso --> segnalo errore e NON accetto
if (deltaPzCount > maxDelta * (maxPzDeltaPerc / 100))
{
lgError($"[DELTA CHECK]: intremento contapezziPLC troppo elevato: lettura {pzCountAll} | contapezzi attuale: {contapezziPLC} | ultima lettura PLC: {plcLastPzRead} | TCiclo medio: {plcAvgTc}s | incremento accettato ");
}
else
{
contapezziPLC = (pzCountAll >= 0 ? pzCountAll : contapezziPLC);
if (isVerboseLog)
{
lgInfo($"[2] pzBuoni: {strOutValPzBuoni} | pzCQ: {strOutValPzQCtrl}");
lgInfo($"[3] contapezziPLC: {contapezziPLC}");
}
}
}
}
}
catch (Exception exc)
{
lgError(exc, "Errore in contapezzi SIEMENS");
}
}
}
/// <summary>
/// Esegue processing MODE (e nel contempo recupera altri dati dell'area G)
/// </summary>
public override void processMode()
{
// valore non presente in vers default... se gestito fare override
if (utils.CRB("enableMode"))
{
}
}
/// <summary>
/// Effettua lettura semafori principale
/// <paramref name="currDispData">Parametri da aggiornare x display in form</paramref>
/// </summary>
public override void readSemafori(ref newDisplayData currDispData)
{
base.readSemafori(ref currDispData);
try
{
currDispData.semIn = Semaforo.SV;
if (verboseLog)
{
lgInfo("inizio read semafori");
}
// leggo TUTTI i byte configurati...
byte[] MemBlock = new byte[parametri.memSizeRead];
bool fatto = S7ReadBB(ref MemBlock);
Buffer.BlockCopy(MemBlock, 0, RawInput, 0, parametri.memSizeRead);
if (verboseLog)
{
lgInfo(string.Format("RawInput[0]: {0}", utils.binaryForm(RawInput[0])));
}
// salvo il solo BYTE dell'input decifrando il semaforo...
decodeToBaseBitmap();
decodeOtherData();
// riporto bitmap...
reportRawInput(ref currDispData);
}
catch
{
currDispData.semIn = Semaforo.SR;
}
}
/// <summary>
/// wrapper chiamata LETTURA in blocco MULTI BYTE dell'area read DI DEFAULT...
/// </summary>
/// <param name="MATRICE valori letti"></param>
/// <returns></returns>
public bool S7ReadBB(ref byte[] Value)
{
return S7ReadBB(ref Value, parametri.memAddrRead, parametri.memSizeRead);
}
/// <summary>
/// wrapper chiamata LETTURA in blocco MULTI BYTE...
/// </summary>
/// <param name="Value">MATRICE valori letti</param>
/// <param name="memAddrRead">Area memoria da leggere...</param>
/// <param name="numByte">Numero byte da leggere</param>
/// <returns></returns>
public bool S7ReadBB(ref byte[] Value, string memAddrRead, int numByte)
{
bool answ = false;
if (Value != null)
{
sw.Restart();
parentForm.commPlcActive = true;
if (testCncConn())
{
// decodifico memoria...
memAreaSiemens memoria = new memAreaSiemens(memAddrRead);
Byte[] memByteRead = currPLC.ReadBytes(DataType.DataBlock, memoria.DbNum, memoria.indiceMem, numByte);
// copio in value, sennò do errore...
if (memByteRead.Length == Value.Length)
{
Value = memByteRead;
answ = true;
}
else
{
lgError($"Mismatch dimensione array memoria: indirizzo: {memAddrRead} | passato array di {Value.Length} byte, letti da S7 {memByteRead.Length} byte");
numErroriCheck++;
}
// loggo lettura...
if (verboseLog)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine(lineSep);
sb.AppendLine($"READ BLOCK MEM BYTE: {parametri.memAddrRead} --> {numByte} byte");
sb.AppendLine($"Contenuto area memoria acquisita:");
string byteVal = "";
for (int i = 0; i < memByteRead.Length; i++)
{
byteVal = Convert.ToString(memByteRead[i], 2).PadLeft(8, '0');
sb.AppendLine($"B{i:000}: {byteVal} | {memByteRead[i]}");
}
sb.AppendLine(lineSep);
lgInfo(sb.ToString());
}
}
else
{
connectionOk = false;
}
parentForm.commPlcActive = false;
sw.Stop();
if (utils.CRB("recTime"))
{
TimingData.addResult(cIobConf.codIOB, string.Format("{0}|{1}", parametri.memAddrRead, numByte), sw.ElapsedTicks);
}
}
// se supero soglia errori lettura --> disconnetto e resetto
if (numErroriCheck > maxErroriCheck)
{
lgInfo($"numErroriCheck: {numErroriCheck} --> richiesta disconnessione adapter con tryDisconnect");
numErroriCheck = 0;
tryDisconnect();
}
return answ;
}
/// <summary>
/// wrapper chiamata LETTURA in blocco MULTI BYTE... default size a parametri.memSizeRead
/// </summary>
/// <param name="MATRICE valori letti"></param>
/// <param name="memAddrRead">Area memoria da leggere...</param>
/// <returns></returns>
public bool S7ReadBB(ref byte[] Value, string memAddrRead)
{
bool answ = false;
answ = S7ReadBB(ref Value, memAddrRead, parametri.memSizeRead);
return answ;
}
/// <summary>
/// wrapper chiamata SCRITTURA in blocco MULTI BYTE, DI DEFAULT su area configurata x
/// scrittura CONTINUA...
/// </summary>
/// <param name="MATRICE valori scritti"></param>
/// <returns></returns>
public bool S7WriteBB(ref byte[] Value)
{
return S7WriteBB(ref Value, parametri.memAddrWrite);
}
/// <summary>
/// Override scrittura in area DBB
/// </summary>
/// <param name="Value"></param>
/// <param name="memAddrWrite"></param>
/// <returns></returns>
public bool S7WriteBB(ref byte[] Value, string memAddrWrite)
{
bool answ = false;
if (Value == null)
{
lgError($"Errore in S7WriteBB: Value = null");
}
else
{
if (string.IsNullOrEmpty(memAddrWrite))
{
lgError($"Errore in S7WriteBB: memAddrWrite = vuoto");
}
else
{
sw.Restart();
if (testCncConn())
{
try
{
// decodifico memoria...
memAreaSiemens memoria = new memAreaSiemens(memAddrWrite);
int numByte = Value.Length;
ErrorCode errorCode = currPLC.WriteBytes(DataType.DataBlock, memoria.DbNum, memoria.indiceMem, Value);
switch (errorCode)
{
case ErrorCode.NoError:
answ = true;
maybeLogWrite(memAddrWrite, $"S7WriteBB-01 Effettuata correttamente scrittura su PLC: MEMORIA {memAddrWrite} | numByte: {Value.Length} | ValOriginale: {BitConverter.ToString(Value)}");
break;
case ErrorCode.WrongCPU_Type:
case ErrorCode.ConnectionError:
case ErrorCode.IPAddressNotAvailable:
case ErrorCode.WrongVarFormat:
case ErrorCode.WrongNumberReceivedBytes:
case ErrorCode.SendData:
case ErrorCode.ReadData:
case ErrorCode.WriteData:
lgError($"Errore in S7WriteBB su {memAddrWrite}: {errorCode.ToString()} | numByte: {Value.Length}| {Value.ValToBinString()}");
answ = false;
break;
default:
break;
}
}
catch (Exception exc)
{
lgError($"Eccezione in S7WriteBB | memAddrWrite {memAddrWrite} | numByte: {Value.Length}{Environment.NewLine}{exc}");
}
}
sw.Stop();
}
}
return answ;
}
/// <summary>
/// Override scrittura in area DBB
/// </summary>
/// <param name="Value">Valore byte[] da scrivere</param>
/// <param name="DbNum">Numero del DB (es 700 per DB700)</param>
/// <param name="IndiceMem">Indice interno al datablock del byte da cui partire</param>
/// <returns></returns>
public bool S7WriteBB(ref byte[] Value, int DbNum, int IndiceMem)
{
bool answ = false;
if (Value == null)
{
lgError($"Errore in S7WriteBB: Value è null");
}
else
{
if (DbNum < 0 || IndiceMem < 0)
{
lgError($"Errore in S7WriteBB | DbNum: {DbNum} | IndiceMem: {IndiceMem}");
}
else
{
sw.Restart();
if (testCncConn())
{
try
{
int numByte = Value.Length;
ErrorCode errorCode = currPLC.WriteBytes(DataType.DataBlock, DbNum, IndiceMem, Value);
switch (errorCode)
{
case ErrorCode.NoError:
lgInfo($"S7WriteBB-02 Effettuata correttamente scrittura su PLC: DB {DbNum}.{IndiceMem} | numByte: {Value.Length}| {Value.ValToBinString()}");
break;
case ErrorCode.WrongCPU_Type:
case ErrorCode.ConnectionError:
case ErrorCode.IPAddressNotAvailable:
case ErrorCode.WrongVarFormat:
case ErrorCode.WrongNumberReceivedBytes:
case ErrorCode.SendData:
case ErrorCode.ReadData:
case ErrorCode.WriteData:
lgError($"Errore in S7WriteBB su DB {DbNum}.{IndiceMem}: {errorCode.ToString()} | numByte: {Value.Length}| {Value.ValToBinString()}");
break;
default:
break;
}
answ = true;
}
catch (Exception exc)
{
lgError($"Eccezione in S7WriteBB: DbNum {DbNum}, IndiceMem: {IndiceMem}, numByte: {Value.Length}{Environment.NewLine}{exc}");
}
}
sw.Stop();
}
}
return answ;
}
/// <summary>
/// Salvo in memblock il valore DInt indicato con formattazione siemens
/// </summary>
/// <param name="MemBlock">Blocco memoria come byte[] dove scrivere</param>
/// <param name="startPos">Posizione inizio scrittura</param>
/// <param name="valore">Valore da scrivere</param>
public void saveDIntOnMemBlock(ref byte[] MemBlock, int startPos, string valore)
{
try
{
lgInfo($"saveDIntOnMemBlock: MemBlock size: {MemBlock.Length} | startPos: {startPos} | valore: {valore}");
int valInt = 0;
int.TryParse(valore, out valInt);
byte[] strByte = S7.Net.Types.DInt.ToByteArray(valInt);
int byteLen = 4;
Buffer.BlockCopy(strByte, 0, MemBlock, startPos, byteLen);
//var verifica = S7.Net.Types.String.FromByteArray(MemBlock);
}
catch (Exception exc)
{
lgError($"Errore in gestione scrittura DINT {valore} alla posizione {startPos} byte{Environment.NewLine}{exc}");
}
}
/// <summary>
/// Salvo in memblock il valore DInt indicato con formattazione siemens
/// </summary>
/// <param name="MemBlock">Blocco memoria come byte[] dove scrivere</param>
/// <param name="stringKey">Valore da scrivere</param>
/// <param name="startPos">Posizione inizio scrittura</param>
public void saveDIntOnMemBlock(ref byte[] MemBlock, string stringKey, int startPos)
{
if (currProdData.ContainsKey(stringKey))
{
try
{
string valore = currProdData[stringKey];
lgInfo($"saveDIntOnMemBlock: MemBlock size: {MemBlock.Length} | startPos: {startPos} | key: {stringKey} | valore: {valore}");
saveDIntOnMemBlock(ref MemBlock, startPos, valore);
}
catch (Exception exc)
{
lgError($"Errore in gestione scrittura DINT {stringKey}{Environment.NewLine}{exc}");
}
}
}
/// <summary>
/// Salvo in memblock il valore DInt indicato con formattazione siemens
/// </summary>
/// <param name="MemBlock">Blocco memoria come byte[] dove scrivere</param>
/// <param name="startPos">Posizione inizio scrittura</param>
/// <param name="valore">Valore da scrivere</param>
public void saveDWordOnMemBlock(ref byte[] MemBlock, int startPos, string valore)
{
try
{
lgInfo($"saveDWordOnMemBlock: MemBlock size: {MemBlock.Length} | startPos: {startPos} | valore: {valore}");
byte[] stringPar = new byte[4];
int valInt = 0;
int.TryParse(valore, out valInt);
byte[] strByte = S7.Net.Types.DInt.ToByteArray(valInt);
int byteLen = 4;
Buffer.BlockCopy(strByte, 0, MemBlock, startPos, byteLen);
//var verifica = S7.Net.Types.String.FromByteArray(MemBlock);
}
catch (Exception exc)
{
lgError($"Errore in gestione scrittura DWord {valore} alla posizione {startPos} byte{Environment.NewLine}{exc}");
}
}
/// <summary>
/// Salvo in memblock il valore DInt indicato con formattazione siemens
/// </summary>
/// <param name="MemBlock">Blocco memoria come byte[] dove scrivere</param>
/// <param name="stringKey">Valore da scrivere</param>
/// <param name="startPos">Posizione inizio scrittura</param>
public void saveDWordOnMemBlock(ref byte[] MemBlock, string stringKey, int startPos)
{
if (currProdData.ContainsKey(stringKey))
{
try
{
string valore = currProdData[stringKey];
lgInfo($"saveDWordOnMemBlock: MemBlock size: {MemBlock.Length} | startPos: {startPos} | key: {stringKey} | valore: {valore}");
saveDIntOnMemBlock(ref MemBlock, startPos, valore);
}
catch (Exception exc)
{
lgError($"Errore in gestione scrittura DINT {stringKey}{Environment.NewLine}{exc}");
}
}
}
/// <summary>
/// Salvo in memblock il valore Int indicato con formattazione siemens
/// </summary>
/// <param name="MemBlock">Blocco memoria come byte[] dove scrivere</param>
/// <param name="startPos">Posizione inizio scrittura</param>
/// <param name="valore">valore da scrivere</param>
public void saveIntOnMemBlock(ref byte[] MemBlock, int startPos, string valore)
{
try
{
lgInfo($"saveIntOnMemBlock: MemBlock size: {MemBlock.Length} | startPos: {startPos} | valore: {valore}");
short valInt = 0;
short.TryParse(valore, out valInt);
byte[] strByte = S7.Net.Types.Int.ToByteArray(valInt);
int byteLen = 2;
Buffer.BlockCopy(strByte, 0, MemBlock, startPos, byteLen);
//var verifica = S7.Net.Types.String.FromByteArray(MemBlock);
}
catch (Exception exc)
{
lgError($"Errore in gestione scrittura INT {valore} alla posizione {startPos} byte{Environment.NewLine}{exc}");
}
}
/// <summary>
/// Salvo in memblock il valore Int indicato con formattazione siemens
/// </summary>
/// <param name="MemBlock">Blocco memoria come byte[] dove scrivere</param>
/// <param name="stringKey">Nome del parametro da recuperare da prodData x scrivere</param>
/// <param name="startPos">Posizione inizio scrittura</param>
public void saveIntOnMemBlock(ref byte[] MemBlock, string stringKey, int startPos)
{
if (currProdData.ContainsKey(stringKey))
{
try
{
string valore = currProdData[stringKey];
lgInfo($"saveIntOnMemBlock: MemBlock size: {MemBlock.Length} | startPos: {startPos} | key: {stringKey} | valore: {valore}");
saveIntOnMemBlock(ref MemBlock, startPos, valore);
}
catch (Exception exc)
{
lgError($"Errore in gestione scrittura INT {stringKey}{Environment.NewLine}{exc}");
}
}
}
/// <summary>
/// Salvo in memblock il valore stringa indicato con formattazione siemens
/// </summary>
/// <param name="MemBlock">Blocco memoria come byte[] dove scrivere</param>
/// <param name="startPos">Posizione inizio scrittura</param>
/// <param name="valore">Valore scrivere</param>
public void saveRealOnMemBlock(ref byte[] MemBlock, int startPos, string valore)
{
try
{
byte[] stringPar = new byte[2];
lgInfo($"saveRealOnMemBlock: MemBlock size: {MemBlock.Length} | startPos: {startPos} | valore: {valore}");
double valReal = 0;
double.TryParse(valore, out valReal);
byte[] strByte = S7.Net.Types.Double.ToByteArray(valReal);
int byteLen = 4;
Buffer.BlockCopy(strByte, 0, MemBlock, startPos, byteLen);
//var verifica = S7.Net.Types.String.FromByteArray(MemBlock);
}
catch (Exception exc)
{
lgError($"Errore in gestione scrittura REAL {valore} alla posizione {startPos} byte{Environment.NewLine}{exc}");
}
}
/// <summary>
/// Salvo in memblock il valore stringa indicato con formattazione siemens
/// </summary>
/// <param name="MemBlock">Blocco memoria come byte[] dove scrivere</param>
/// <param name="stringKey">Valore scrivere</param>
/// <param name="startPos">Posizione inizio scrittura</param>
public void saveRealOnMemBlock(ref byte[] MemBlock, string stringKey, int startPos)
{
if (currProdData.ContainsKey(stringKey))
{
try
{
string valore = currProdData[stringKey];
lgInfo($"saveRealOnMemBlock: MemBlock size: {MemBlock.Length} | startPos: {startPos} | key: {stringKey} | valore: {valore}");
saveRealOnMemBlock(ref MemBlock, startPos, valore);
}
catch (Exception exc)
{
lgError($"Errore in gestione scrittura REAL {stringKey}{Environment.NewLine}{exc}");
}
}
}
/// <summary>
/// Salvo in memblock il valore stringa indicato con formattazione siemens
/// </summary>
/// <param name="MemBlock">Blocco memoria come byte[] dove scrivere</param>
/// <param name="startPos">Posizione inizio scrittura</param>
/// <param name="totLen">
/// Lunghezza max stringa (se ci sono 2 byte iniziali verrà ridotta di 2)
/// </param>
/// <param name="valore">valore da scrivere</param>
public void saveStringOnMemBlock(ref byte[] MemBlock, int startPos, int totLen, string valore)
{
if (MemBlock != null)
{
// loggare valore? fornire un output con memBlock e NON ref?
try
{
lgInfo($"saveStringOnMemBlock: MemBlock size: {MemBlock.Length} | startPos: {startPos} | totLen: {totLen} | valore: {valore}");
byte[] stringPar = new byte[2];
byte[] strByte = S7.Net.Types.String.ToByteArray(valore);
// eventuale decremento val lungh totale...
totLen = writePre ? totLen - 2 : totLen;
int byteLen = strByte.Length <= totLen ? strByte.Length : totLen;
int shiftStrByte = writePre ? 2 : 0;
if (writePre)
{
// MAX LUN
stringPar[1] = (byte)totLen;
// LUNGH STRING
stringPar[0] = (byte)byteLen;
Buffer.BlockCopy(stringPar, 0, MemBlock, startPos, shiftStrByte);
}
Buffer.BlockCopy(strByte, 0, MemBlock, startPos + shiftStrByte, byteLen);
}
catch (Exception exc)
{
lgError($"Errore in gestione scrittura {valore} alla posizione {startPos} per {totLen} byte{Environment.NewLine}{exc}");
}
}
else
{
lgError("Errore: MemBlock nullo");
}
}
/// <summary>
/// Salvo in memblock il valore stringa indicato con formattazione siemens
/// </summary>
/// <param name="MemBlock">Blocco memoria come byte[] dove scrivere</param>
/// <param name="stringKey">Nome del parametro da recuperare da prodData x scrivere</param>
/// <param name="startPos">Posizione inizio scrittura</param>
/// <param name="totLen">
/// Lunghezza max stringa (se ci sono 2 byte iniziali verrà ridotta di 2)
/// </param>
public void saveStringOnMemBlock(ref byte[] MemBlock, string stringKey, int startPos, int totLen)
{
if (currProdData.ContainsKey(stringKey))
{
try
{
string valore = currProdData[stringKey];
saveStringOnMemBlock(ref MemBlock, startPos, totLen, valore);
}
catch (Exception exc)
{
lgError($"Errore in gestione scrittura x key {stringKey}{Environment.NewLine}{exc}");
}
}
}
/// <summary>
/// Salvo in memblock il valore DInt indicato con formattazione siemens
/// </summary>
/// <param name="MemBlock">Blocco memoria come byte[] dove scrivere</param>
/// <param name="startPos">Posizione inizio scrittura</param>
/// <param name="valore">Valore da scrivere</param>
public void saveWordOnMemBlock(ref byte[] MemBlock, int startPos, string valore)
{
try
{
lgInfo($"saveWordOnMemBlock: MemBlock size: {MemBlock.Length} | startPos: {startPos} | valore: {valore}");
byte[] stringPar = new byte[4];
int valInt = 0;
int.TryParse(valore, out valInt);
byte[] strByte = S7.Net.Types.DInt.ToByteArray(valInt);
int byteLen = 4;
Buffer.BlockCopy(strByte, 0, MemBlock, startPos, byteLen);
//var verifica = S7.Net.Types.String.FromByteArray(MemBlock);
}
catch (Exception exc)
{
lgError($"Errore in gestione scrittura Word {valore} alla posizione {startPos} byte{Environment.NewLine}{exc}");
}
}
/// <summary>
/// Salvo in memblock il valore DInt indicato con formattazione siemens
/// </summary>
/// <param name="MemBlock">Blocco memoria come byte[] dove scrivere</param>
/// <param name="stringKey">Valore da scrivere</param>
/// <param name="startPos">Posizione inizio scrittura</param>
public void saveWordOnMemBlock(ref byte[] MemBlock, string stringKey, int startPos)
{
if (currProdData.ContainsKey(stringKey))
{
try
{
string valore = currProdData[stringKey];
lgInfo($"saveWordOnMemBlock: MemBlock size: {MemBlock.Length} | startPos: {startPos} | key: {stringKey} | valore: {valore}");
saveDIntOnMemBlock(ref MemBlock, startPos, valore);
}
catch (Exception exc)
{
lgError($"Errore in gestione scrittura DINT {stringKey}{Environment.NewLine}{exc}");
}
}
}
/// <summary>
/// Converte direttamente un valore stringa su un oggetto byte[] (senza limitazioni di dimensione)
/// </summary>
/// <param name="valore"></param>
/// <param name="maxLenght">Dimensione massima ammessa per la stringa</param>
/// <returns></returns>
public byte[] stringToByte(string valore, int maxLenght)
{
byte[] answ = new byte[1];
byte[] stringPar = new byte[2];
byte[] strByte = S7.Net.Types.String.ToByteArray(valore);
int shiftStrByte = writePre ? 2 : 0;
int byteLen = strByte.Length <= maxLenght ? strByte.Length : maxLenght;
if (writePre)
{
// MAX LUN
stringPar[1] = (byte)maxLenght;
// LUNGH STRING
stringPar[0] = (byte)byteLen;
Buffer.BlockCopy(stringPar, 0, answ, 0, shiftStrByte);
}
Buffer.BlockCopy(strByte, 0, answ, shiftStrByte, byteLen);
return answ;
}
/// <summary>
/// Override connessione
/// </summary>
public override void tryConnect()
{
bool doLog = (verboseLog || periodicLog);
lgInfoStartup("SIEMENS: tryConnect step 01");
if (!connectionOk)
{
// SE è necessario refresh...
if (needRefresh)
{
lgInfoStartup("SIEMENS: tryConnect step 02");
// reimporto parametri PLC se necessario...
setParamPlc();
}
lgInfoStartup("SIEMENS: tryConnect step 03");
// controllo che il ping sia stato tentato almeno pingTestSec fa...
if (DateTime.Now.Subtract(lastPING).TotalSeconds > utils.CRI("pingTestSec"))
{
if (doLog)
{
lgInfoStartup("SIEMENS: ConnKO - tryConnect");
}
lgInfoStartup("SIEMENS: 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.Open();
szStatusConnection = "OPEN";
parentForm.commPlcActive = false;
connectionOk = true;
lgInfoStartup($"StatusConnection: {szStatusConnection}");
// refresh stato allarmi!!!
if (connectionOk)
{
queueInEnabCurr = true;
if (adpRunning)
{
lgInfo($"Connessione OK: {connectionOk} | adpRunning: {adpRunning}");
}
}
else
{
lgError("Impossibile procedere, connessione mancante...");
}
}
catch (Exception exc)
{
lgFatal($"Errore in TryConnect adapter SIEMENS | szStatusConnection {szStatusConnection}{Environment.NewLine}{exc}");
connectionOk = false;
needRefresh = true;
}
}
else
{
// loggo no risposta ping ...
connectionOk = false;
if (doLog)
{
lgInfo($"Attenzione: SIEMENS controllo PING fallito per IP {cIobConf.cncPingAddr}");
}
}
}
}
// 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.Close();
connectionOk = false;
queueInEnabCurr = false;
lgInfo(szStatusConnection);
lgInfo("Effettuata disconnessione adapter SIEMENS!");
}
catch (Exception exc)
{
lgFatal(exc, "Errore nella disconnessione dall'adapter SIEMENS");
}
}
else
{
lgError("IMPOSSIBILE effettuare disconnessione SIEMENS: Connessione non disponibile...");
}
}
/// <summary>
/// Converte direttamente un valore UInt16 su un oggetto byte[2]
/// </summary>
/// <param name="valore">valore da scrivere</param>
public byte[] wordToByte(string valore)
{
byte[] answ = new byte[2];
try
{
ushort valInt = 0;
ushort.TryParse(valore, out valInt);
byte[] strByte = S7.Net.Types.Word.ToByteArray(valInt);
int byteLen = 2;
Buffer.BlockCopy(strByte, 0, answ, 0, byteLen);
}
catch (Exception exc)
{
lgError($"Errore in gestione scrittura INT {valore} in byte{Environment.NewLine}{exc}");
}
return answ;
}
#endregion Public Methods
#region Protected Fields
/// <summary>
/// Oggetto PLC da ri-utilizzare...
/// </summary>
protected Plc currPLC;
/// <summary>
/// Ultimo controllo ping x evitare ping flood...
/// </summary>
protected DateTime lastPingConn = DateTime.Now.AddMinutes(-10);
/// <summary>
/// Esito ultimo ping
/// </summary>
protected bool lastPingOk = false;
/// <summary>
/// Lungh massima stringhe
/// </summary>
protected int maxStrChar = 20;
/// <summary>
/// parametri di connessione
/// </summary>
protected connParamS7 parametri;
/// <summary>
/// Oggetto cronometro x test vari...
/// </summary>
protected Stopwatch sw = new Stopwatch();
/// <summary>
/// indica se scrivere i primi byte x string siemens x indicare lung max e corrente
/// </summary>
protected bool writePre = true;
#endregion Protected Fields
#region Protected Properties
/// <summary>
/// Dizionario delle ultime operazioni di scrittura per OGNI memoria (in modo che fa log
/// ogni x sec...)
/// </summary>
protected Dictionary<string, DateTime> lastMemWrite { get; set; } = new Dictionary<string, DateTime>();
#endregion Protected Properties
#region Protected Methods
/// <summary>
/// decodifica da bitmap il CURRENT MODE del controllo
/// </summary>
/// <param name="currModeBitmap"></param>
/// <returns></returns>
protected virtual string decodeCurrMode(byte currModeBitmap)
{
string answ = "";
if (verboseLog)
{
lgInfo(string.Format("CURR_MODE raw data: {0}", utils.binaryForm(currModeBitmap)));
}
// decodifica del MODO... B21
/*
* CURR MODE diviso in BIT:
* B0 (01) = AUTO
* B1 (02) = MDI
* B2 (04) = JOG
* B3 (08) = TeachIN (associato a MDI --> 10)
* B4 (16) = Repos (associato a JOG --> 20)
* B5 (32) = RefPoint (associato a Jog --> 36)
* B6 (64) = Incr1 (associato a Jog --> 68)
* B7 (128) = Incr10 (associato a Jog --> -124 / 132 se UInt)
* */
// modi principali
if (currModeBitmap.SelectBit(0))
{
answ = "AUTO";
}
else if (currModeBitmap.SelectBit(1))
{
answ = "MDI";
}
else if (currModeBitmap.SelectBit(2))
{
answ = "JOG";
}
// modi accessori
if (currModeBitmap.SelectBit(3))
{
answ += " | TEACH-IN";
}
if (currModeBitmap.SelectBit(4))
{
answ += " | REPOS";
}
if (currModeBitmap.SelectBit(5))
{
answ += " | REF-POINT";
}
if (currModeBitmap.SelectBit(6))
{
answ += " | INCR-1";
}
if (currModeBitmap.SelectBit(7))
{
answ += " | INCR-10";
}
return answ;
}
/// <summary>
/// Decodifica il resto dell'area x i dati accessori (allarmi, ...)
/// </summary>
protected virtual void decodeOtherData()
{
if (verboseLog)
{
}
}
/// <summary>
/// Effettua decodifica aree memoria alla bitmap usata x MAPO
/// </summary>
protected virtual void decodeToBaseBitmap()
{
// init a zero...
B_input = 0;
}
/// <summary>
/// Restituisce path completo file da chiave configurazione
/// </summary>
/// <param name="keyFile">chiave conf x file richiesto</param>
/// <returns></returns>
protected string filePath(string keyFile)
{
string answ = "";
try
{
answ = $"{utils.confDir}\\{utils.CRS(keyFile)}";
}
catch (Exception exc)
{
lgError(exc, "Eccezione in recupero filePath");
}
return answ;
}
/// <summary>
/// Verifica presenza allarmi (tra quelli configurati)
/// </summary>
protected override bool hasAlarms()
{
bool answ = false;
int numErrors = 0;
uint currStatus = 0;
if (alarmMaps != null)
{
// leggo a ciclo le aree degli allarmi CONFIGURATI, se ne trovo --> segnalo allarme...
foreach (var item in alarmMaps)
{
// banchi in WORD (2 byte) --> scompongo
for (int i = 0; i < item.size / 2; i++)
{
currStatus = S7.Net.Types.Counter.FromByteArray(RawInput.Skip(item.index + 2 * i).Take(2).ToArray());
// verifica e decremento blink...
item.checkBlinkCounter(i, (uint)currStatus);
// 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, currStatus))
{
if (currStatus > 0)
{
numErrors++;
}
// 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;
}
/// <summary>
/// Override metodo x scrittura parametri su PLC
/// </summary>
/// <param name="updatedPar"></param>
protected override void plcWriteParams(ref List<objItem> updatedPar)
{
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($"Preparo scrittura{Environment.NewLine}---------------MemBlock data---------------{Environment.NewLine}{BitConverter.ToString(MemBlock)}{Environment.NewLine}--------------- END data ---------------");
if (!string.IsNullOrEmpty(memAddrWrite))
{
// scrivo su siemens
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}");
}
}
}
}
/// <summary>
/// Imposto parametri PLC
/// </summary>
protected override void setParamPlc()
{
// Creo oggetto connessione NC
parentForm.commPlcActive = true;
lgInfoStartup("Start init Adapter SIEMENS all'IP {0} | CPU: {1} | R/S: {2}/{3} | --> IOB {4}", cIobConf.cncIpAddr, cIobConf.cpuType, cIobConf.rack, cIobConf.slot, cIobConf.codIOB);
// SE è necessario refresh...
if (needRefresh)
{
lgInfoStartup("Refreshing connection...");
if (parametri != null)
{
try
{
parametri.slot = cIobConf.slot;
parametri.rack = cIobConf.rack;
parametri.tipoCpu = (CpuType)Enum.Parse(typeof(CpuType), cIobConf.cpuType);
parametri.ipAdrr = cIobConf.cncIpAddr;
// 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);
// 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");
}
// ora tento avvio PLC... SE PING OK...
IPStatus esitoPing = testPingMachine;
if (esitoPing == IPStatus.Success)
{
needRefresh = false;
try
{
currPLC = new Plc(parametri.tipoCpu, parametri.ipAdrr, parametri.rack, parametri.slot);
// disconnetto e connetto...
if (isVerboseLog)
{
lgInfo("SIEMENS: tryDisconnect");
}
tryDisconnect();
// lo ripeto x evitare che ci sia un loop... e tryConnect richiami la
// procedura corrente...
needRefresh = false;
lgInfoStartup("SIEMENS: tryConnect");
lastConnectTry = DateTime.Now;
tryConnect();
lgInfoStartup("End init Adapter SIEMENS");
if (isVerboseLog)
{
lgInfo("S7+ CONNESSIONE AVVENUTA");
}
}
catch (Exception exc)
{
lgError(exc, "Errore in INIT PLC S7+");
}
}
else
{
lgError($"IOB SIEMENS | 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))
{
lgDebug("SIEMENS: 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"))
{
lgDebug("Init contapezzi SIEMENS: pzCntReload(true)");
pzCntReload(true);
// refresh associazione Macchina - IOB
SendM2IOB();
// invio altri dati accessori...
SendMachineConf();
// 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;
lgDebug("Parametro mancante PZCOUNT_MODE");
}
}
catch (Exception exc)
{
lgError(exc, "Errore in contapezzi SIEMENS");
}
}
}
else
{
lgError("Parametri null!");
}
}
}
/// <summary>
/// Test connessione CNC
/// </summary>
/// <returns></returns>
protected bool testCncConn()
{
bool answ = false;
// 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.IsConnected)
{
currPLC.Open();
}
if (!currPLC.IsAvailable)
{
lgError($"PLC Siemens NON disponibile:{currPLC.LastErrorCode} | {currPLC.LastErrorString}");
currPLC.ClearLastError();
}
else
{
if (!currPLC.IsConnected)
{
lgError($"PLC Siemens NON connesso:{currPLC.LastErrorCode} | {currPLC.LastErrorString}");
currPLC.ClearLastError();
parentForm.updateComStats("NO connection");
}
else
{
// tutto ok
parentForm.updateComStats("Connection OK");
answ = true;
}
}
}
// salvo stato ping
lastPingOk = answ;
lastPingConn = adesso;
}
return answ;
}
#endregion Protected Methods
#region Private Methods
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;
}
/// <summary>
/// Verifica SE sia il caso di fare il log della memoria indicata
/// </summary>
/// <param name="memAddrWrite"></param>
/// <param name="logValue"></param>
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 ultima scrittura 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)
{
// 2022.03.16 portato a livello TRACE x evitare log troppo verboso
lgTrace(logValue);
lastMemWrite[memAddrWrite] = adesso;
}
}
/// <summary>
/// Effettua lettura del contatore e restitusice la stringa grezza del dato
/// </summary>
/// <param name="memAddrPzCount"></param>
/// <returns></returns>
private string readCountVal(ref string memAddrPzCount)
{
object outputVal = new object();
string strOutVal;
// cerco i pezzi contati STANDARD
if (memAddrPzCount.StartsWith("STD"))
{
// inizio verifica area memoria/parametro levando prima parte codice
memAddrPzCount = memAddrPzCount.Replace("STD.", "");
// verifico se si tratta di lettura area DB... formato tipo STD.DB700.DBB22.W
if (memAddrPzCount.StartsWith("DB"))
{
memAreaSiemens areaCounter = new memAreaSiemens(memAddrPzCount);
if (isVerboseLog)
{
lgInfo("DB [0] area memoria: {1}.{2}.{3}", memAddrPzCount, areaCounter.DbNum, areaCounter.indiceMem, areaCounter.tipoMem);
}
// copio da blocco già letto... con switch x tipo dati --> tipo lettura... e
// salvo ultimo conteggio rilevato
switch (areaCounter.tipoMem)
{
case "B":
byte valB = RawInput[areaCounter.indiceMem];
outputVal = valB;
break;
case "W":
ushort valW = S7.Net.Types.Word.FromByteArray(RawInput.Skip(areaCounter.indiceMem).Take(2).ToArray());
outputVal = valW;
break;
case "DW":
uint valDW = S7.Net.Types.DWord.FromByteArray(RawInput.Skip(areaCounter.indiceMem).Take(4).ToArray());
outputVal = valDW;
break;
case "DI":
int valSDW = S7.Net.Types.DInt.FromByteArray(RawInput.Skip(areaCounter.indiceMem).Take(4).ToArray());
outputVal = valSDW;
break;
case "RE":
double valRe = S7.Net.Types.Double.FromByteArray(RawInput.Skip(areaCounter.indiceMem).Take(4).ToArray());
outputVal = valRe;
break;
default:
break;
}
}
}
else if (memAddrPzCount.StartsWith("SPEC"))
{
// inizio verifica area memoria/parametro levando prima parte codice
memAddrPzCount = memAddrPzCount.Replace("SPEC.", "");
// verifico se si tratta di lettura area DB... formato tipo SPEC.DB700.DBB22.W
if (memAddrPzCount.StartsWith("DB"))
{
memAreaSiemens areaCounter = new memAreaSiemens(memAddrPzCount);
if (isVerboseLog)
{
lgInfo("SPEC [0] area memoria: {1}.{2}.{3}", memAddrPzCount, areaCounter.DbNum, areaCounter.indiceMem, areaCounter.tipoMem);
}
// leggo i dati SPECIFICI...
byte[] MemBlockPZ = new byte[8];
bool fatto = false;
// copio da blocco LEGGENDO con switch x tipo dati --> tipo lettura... e salvo
// ultimo conteggio rilevato
switch (areaCounter.tipoMem)
{
case "B":
MemBlockPZ = new byte[1];
fatto = S7ReadBB(ref MemBlockPZ, memAddrPzCount, 1);
outputVal = MemBlockPZ[0];
break;
case "W":
MemBlockPZ = new byte[2];
fatto = S7ReadBB(ref MemBlockPZ, memAddrPzCount, 2);
ushort valW = S7.Net.Types.Word.FromByteArray(MemBlockPZ.ToArray());
outputVal = valW;
break;
case "DW":
MemBlockPZ = new byte[4];
fatto = S7ReadBB(ref MemBlockPZ, memAddrPzCount, 4);
uint valDW = S7.Net.Types.DWord.FromByteArray(MemBlockPZ.ToArray());
outputVal = valDW;
break;
case "DI":
MemBlockPZ = new byte[4];
fatto = S7ReadBB(ref MemBlockPZ, memAddrPzCount, 4);
int valSDW = S7.Net.Types.DInt.FromByteArray(MemBlockPZ.ToArray());
outputVal = valSDW;
break;
case "RE":
MemBlockPZ = new byte[4];
fatto = S7ReadBB(ref MemBlockPZ, memAddrPzCount, 4);
double valRe = S7.Net.Types.Double.FromByteArray(MemBlockPZ.ToArray());
outputVal = valRe;
break;
default:
break;
}
}
}
strOutVal = $"{outputVal}";
return strOutVal;
}
#endregion Private Methods
}
}