1816 lines
76 KiB
C#
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
|
|
}
|
|
} |