Merge remote-tracking branch 'origin/develop' into RemoteDebug

This commit is contained in:
Samuele E. Locatelli
2022-09-07 11:12:51 +02:00
6 changed files with 767 additions and 682 deletions
+18 -14
View File
@@ -424,6 +424,24 @@ namespace IOB_UT_NEXT
{
#region Public Properties
/// <summary>
/// Elenco Variabili (e valori da impostare) x indicare di resettare contatore lotto e
/// quindi riavviare produzione (es: impostando valore a 1...)
/// </summary>
public Dictionary<string, string> actResetCounter { get; set; } = new Dictionary<string, string>();
/// <summary>
/// Elenco Variabili (e valori da impostare) x indicare di effettuare impostazione nuovo
/// programma/ricetta (es: impostando valore a 1...)
/// </summary>
public Dictionary<string, string> actSetRecipe { get; set; } = new Dictionary<string, string>();
/// <summary>
/// Elenco Variabili (e valori da impostare) x indicare di fermare la produzione (es:
/// impostando valore a 1...)
/// </summary>
public Dictionary<string, string> actStopProd { get; set; } = new Dictionary<string, string>();
/// <summary>
/// Identificativo nodo iniziale
/// </summary>
@@ -526,20 +544,6 @@ namespace IOB_UT_NEXT
/// </summary>
public WatchDogConf WatchDog { get; set; } = new WatchDogConf();
/// <summary>
/// Elenco Variabili (e valori da impostare) x indicare di fermare la produzione (es: impostando valore a 1...)
/// </summary>
public Dictionary<string, string> actStopProd { get; set; } = new Dictionary<string, string>();
/// <summary>
/// Elenco Variabili (e valori da impostare) x indicare di effettuare impostazione nuovo programma/ricetta (es: impostando valore a 1...)
/// </summary>
public Dictionary<string, string> actSetRecipe { get; set; } = new Dictionary<string, string>();
/// <summary>
/// Elenco Variabili (e valori da impostare) x indicare di resettare contatore lotto e quindi riavviare produzione (es: impostando valore a 1...)
/// </summary>
public Dictionary<string, string> actResetCounter { get; set; } = new Dictionary<string, string>();
#endregion Public Properties
}
+75
View File
@@ -0,0 +1,75 @@
;Configurazione IOB-WIN
[IOB]
CNCTYPE=FANUC
[MACHINE]
VENDOR=COLCOM
MODEL=DMG-MORI
[CNC]
; TEST FANUC!
IP=192.168.100.78
PORT=8193
GETPRGNAME=true
[SERVER]
MPIP=192.168.111.104
MPURL=/MP/IO
CMDBASE=/IOB/input/
CMDFLOG=/IOB/flog/
CMDALIVE=/IOB
CMDENABLED=/IOB/enabled/
CMDADV1=?valore=
CMDREBO=/sendReboot.aspx?idxMacchina=
[MEMORY]
; Red: Y12.4 | Yellow: Y51.1 (porta chiusa, da NEGARE) | Green Y12.6 | Alarm Y 51.4 | Blu Y12.7
;BIT0=CONN
BIT1=Y12.6
BIT2=PZCOUNT.PAR.6711
BIT3=Y12.4
BIT4=Y12.7
;BIT5=Y11.2
BIT5=X18.3
BIT6=X11.3
AREAD_START=0
AREAD_SIZE=9999
AREAG_SIZE=48
AREAR_START=0
AREAR_SIZE=64
AREAX_START=0
AREAX_SIZE=64
AREAY_START=0
AREAY_SIZE=64
PAR_START=6711
PAR_SIZE=3
[BLINK]
;MAX_COUNTER_BLINK = 30
MAX_COUNTER_BLINK = 15
;bit0 = 0
;bit1 = 0
;bit2 = 1
;bit3 = 1
;bit4 = 1
;bit5 = 0
;bit6 = 0
;bit7 = 0
BLINK_FILT=0
;BLINK_FILT=28
[OPTPAR]
;PZCOUNT_MODE=STD|BIT
PZCOUNT_MODE=STD.PAR.6711
PZGTOT_MODE=STD.PAR.6712
;PZREQ_MODE=STD.PAR.6713
ENABLE_PZ_RESET=TRUE
ENABLE_PZ_RESET_stopSetup=TRUE
;gestione invio pezzi in blocco
ENABLE_SEND_PZC_BLOCK=TRUE
MIN_SEND_PZC_BLOCK=0
MAX_SEND_PZC_BLOCK=100
[BRANCH]
NAME=master
+1 -1
View File
@@ -15,7 +15,7 @@ namespace IOB_WIN_NEXT
/// <summary>
/// LookUpTable di decodifica da CNC a segnali tipo bitmap MAPO
/// </summary>
private Dictionary<string, string> signLUT = new Dictionary<string, string>();
internal Dictionary<string, string> signLUT = new Dictionary<string, string>();
#endregion Private Fields
+110 -111
View File
@@ -3,31 +3,17 @@ using Newtonsoft.Json;
using Opc.Ua;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
namespace IOB_WIN_NEXT
{
public class IobOpcUaSiemens : IobOpcUa
{
#region Protected Fields
/// <summary>
/// Modalità cambio ODL
/// </summary>
protected string CHANGE_ODL_MODE = "";
protected bool testDone = false;
#endregion Protected Fields
#region Public Constructors
/// <summary>
/// Estende l'init della classe base, impiegando il pacchetto Nuget OPC-UA foundation con la gestione specifica per Siemens OPC-UA (es OPC, Cereria Finassi)
/// https://github.com/OPCFoundation/UA-.NETStandard
/// Estende l'init della classe base, impiegando il pacchetto Nuget OPC-UA foundation con la
/// gestione specifica per Siemens OPC-UA (es OPC, Cereria Finassi) https://github.com/OPCFoundation/UA-.NETStandard
/// </summary>
/// <param name="caller"></param>
/// <param name="IOBConf"></param>
@@ -44,6 +30,113 @@ namespace IOB_WIN_NEXT
#endregion Public Constructors
#region Public Methods
/// <summary>
/// Processo i task richiesti e li elimino dalla coda 1:1
/// </summary>
/// <param name="task2exe"></param>
public override Dictionary<string, string> executeTasks(Dictionary<string, string> task2exe)
{
// uso metodo base x ora
return base.executeTasks(task2exe);
}
/// <summary>
/// Effettua vero processing contapezzi
/// </summary>
public override void processContapezzi()
{
if (utils.CRB("enableContapezzi"))
{
// check condizione validazione
if (checkMultiCondition(opcUaParams.condCountEnabled) || opcUaParams.condCountEnabled.checkList.Count == 0)
{
// cerco parametro contapezzi...
string currPzCount = getDataItemValue(opcUaParams.keyPartCount);
// se ho un contapezzi... processo...
if (!string.IsNullOrEmpty(currPzCount))
{
int newVal = -1;
bool fatto = Int32.TryParse(currPzCount, out newVal);
if (fatto)
{
// gestione decremento contapezzi: viene "messo via" solo SE c'è un
// effettivo decremento contapezzi...
if (newVal < contapezziPLC)
{
pzCountResetted = true;
// incremento contatore richiesta
countKeyRichiesta = countKeyRichiesta + 1;
// log
lgInfo("Contapezzi resettato (PLC) --> pzCountResetted = true");
}
// salvo nuovo valore contapezziPLC
contapezziPLC = newVal > -1 ? newVal : contapezziPLC;
}
else
{
lgError($"Errore in decodifica valore contapezzi, valore rilevato: {currPzCount}");
}
}
else
{
lgError("Errore in decodifica valore contapezzi, valore vuoto!");
}
}
if (CHANGE_ODL_MODE == "PZCOUNT_RESET")
{
// controllo comunque, se è ZERO il contapezzi, e sul server è maggiore il
// valore x ODL e NON abilitato il trigger reset --> abilito trigger...
if (!pzCountResetted && contapezziPLC == 0 && contapezziIOB > 0)
{
pzCountResetted = true;
// incremento contatore richiesta
countKeyRichiesta = countKeyRichiesta + 1;
// log
lgInfo("Contapezzi resettato (PLC==0 e IOB>PLC) --> pzCountResetted = true");
}
}
}
}
/// <summary>
/// Effettua reset del contapezzi, NON POSSIBILE in questa versione
/// </summary>
/// <returns></returns>
public override bool resetcontapezziPLC()
{
bool answ = false;
return answ;
}
/// <summary>
/// Effettua IMPOSTAZIONE FORZATA del contapezzi, NON POSSIBILE in questa versione
/// </summary>
/// <returns></returns>
public override bool setcontapezziPLC(int newPzCount)
{
bool answ = false;
return answ;
}
#endregion Public Methods
#region Protected Fields
/// <summary>
/// Modalità cambio ODL
/// </summary>
protected string CHANGE_ODL_MODE = "";
protected bool testDone = false;
#endregion Protected Fields
#region Protected Methods
/// <summary>
@@ -138,7 +231,7 @@ namespace IOB_WIN_NEXT
List<WriteValue> nodes2Write = new List<WriteValue>();
nodes2Write.Add(commWriteVal);
UA_ref.WriteNodes(nodes2Write);
}
catch (Exception exc)
@@ -272,99 +365,5 @@ namespace IOB_WIN_NEXT
}
#endregion Protected Methods
#region Public Methods
/// <summary>
/// Processo i task richiesti e li elimino dalla coda 1:1
/// </summary>
/// <param name="task2exe"></param>
public override Dictionary<string, string> executeTasks(Dictionary<string, string> task2exe)
{
// uso metodo base x ora
return base.executeTasks(task2exe);
}
/// <summary>
/// Effettua vero processing contapezzi
/// </summary>
public override void processContapezzi()
{
if (utils.CRB("enableContapezzi"))
{
// check condizione validazione
if (checkMultiCondition(opcUaParams.condCountEnabled) || opcUaParams.condCountEnabled.checkList.Count == 0)
{
// cerco parametro contapezzi...
string currPzCount = getDataItemValue(opcUaParams.keyPartCount);
// se ho un contapezzi... processo...
if (!string.IsNullOrEmpty(currPzCount))
{
int newVal = -1;
bool fatto = Int32.TryParse(currPzCount, out newVal);
if (fatto)
{
// gestione decremento contapezzi: viene "messo via" solo SE c'è un effettivo decremento contapezzi...
if (newVal < contapezziPLC)
{
pzCountResetted = true;
// incremento contatore richiesta
countKeyRichiesta = countKeyRichiesta + 1;
// log
lgInfo("Contapezzi resettato (PLC) --> pzCountResetted = true");
}
// salvo nuovo valore contapezziPLC
contapezziPLC = newVal > -1 ? newVal : contapezziPLC;
}
else
{
lgError($"Errore in decodifica valore contapezzi, valore rilevato: {currPzCount}");
}
}
else
{
lgError("Errore in decodifica valore contapezzi, valore vuoto!");
}
}
if (CHANGE_ODL_MODE == "PZCOUNT_RESET")
{
// controllo comunque, se è ZERO il contapezzi, e sul server è maggiore il valore x ODL e NON abilitato il trigger reset --> abilito trigger...
if (!pzCountResetted && contapezziPLC == 0 && contapezziIOB > 0)
{
pzCountResetted = true;
// incremento contatore richiesta
countKeyRichiesta = countKeyRichiesta + 1;
// log
lgInfo("Contapezzi resettato (PLC==0 e IOB>PLC) --> pzCountResetted = true");
}
}
}
}
/// <summary>
/// Effettua reset del contapezzi, NON POSSIBILE in questa versione
/// </summary>
/// <returns></returns>
public override bool resetcontapezziPLC()
{
bool answ = false;
return answ;
}
/// <summary>
/// Effettua IMPOSTAZIONE FORZATA del contapezzi, NON POSSIBILE in questa versione
/// </summary>
/// <returns></returns>
public override bool setcontapezziPLC(int newPzCount)
{
bool answ = false;
return answ;
}
#endregion Public Methods
}
}
+93 -98
View File
@@ -1,27 +1,17 @@
using MapoSDK;
using Newtonsoft.Json;
using Opc.Ua;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
namespace IOB_WIN_NEXT
{
public class IobOpcUaSiemensOMP : IobOpcUaSiemens
{
#region Protected Fields
#endregion Protected Fields
#region Public Constructors
/// <summary>
/// Estende l'init della classe base, impiegando il pacchetto Nuget OPC-UA foundation con la gestione specifica per EWON (es Monti, Tenditalia)
/// https://github.com/OPCFoundation/UA-.NETStandard
/// Estende l'init della classe base, impiegando il pacchetto Nuget OPC-UA foundation con la
/// gestione specifica per EWON (es Monti, Tenditalia) https://github.com/OPCFoundation/UA-.NETStandard
/// </summary>
/// <param name="caller"></param>
/// <param name="IOBConf"></param>
@@ -37,89 +27,9 @@ namespace IOB_WIN_NEXT
sendKeyRichiesta = true;
}
public override bool resetcontapezziPLC()
{
bool answ = false;
try
{
List<WriteValue> nodes2Write = new List<WriteValue>();
foreach (var item in opcUaParams.actResetCounter)
{
WriteValue commWriteVal = new WriteValue();
commWriteVal.NodeId = new NodeId(item.Key);
commWriteVal.AttributeId = Attributes.Value;
commWriteVal.Value = new DataValue();
commWriteVal.Value.Value = item.Value;
nodes2Write.Add(commWriteVal);
}
// vera scrittura
UA_ref.WriteNodes(nodes2Write);
answ = true;
}
catch
{ }
return answ;
}
/// <summary>
/// Azioni specifiche x indicare fine lotto di produzione
/// </summary>
/// <returns></returns>
private bool setFineLotto()
{
bool answ = false;
try
{
List<WriteValue> nodes2Write = new List<WriteValue>();
foreach (var item in opcUaParams.actStopProd)
{
WriteValue commWriteVal = new WriteValue();
commWriteVal.NodeId = new NodeId(item.Key);
commWriteVal.AttributeId = Attributes.Value;
commWriteVal.Value = new DataValue();
commWriteVal.Value.Value = item.Value;
nodes2Write.Add(commWriteVal);
}
// vera scrittura
UA_ref.WriteNodes(nodes2Write);
answ = true;
}
catch
{ }
return answ;
}
/// <summary>
/// Azioni specifiche x iniziare produzione (impostazione ricetta)
/// </summary>
/// <returns></returns>
private bool setInizioProd()
{
bool answ = false;
try
{
List<WriteValue> nodes2Write = new List<WriteValue>();
foreach (var item in opcUaParams.actSetRecipe)
{
WriteValue commWriteVal = new WriteValue();
commWriteVal.NodeId = new NodeId(item.Key);
commWriteVal.AttributeId = Attributes.Value;
commWriteVal.Value = new DataValue();
commWriteVal.Value.Value = item.Value;
nodes2Write.Add(commWriteVal);
}
// vera scrittura
UA_ref.WriteNodes(nodes2Write);
answ = true;
}
catch
{ }
return answ;
}
#endregion Public Constructors
#region Public Methods
/// <summary>
/// Processo i task richiesti e li elimino dalla coda 1:1
@@ -130,9 +40,8 @@ namespace IOB_WIN_NEXT
// uso metodo base x salvare esito scrittura
var writeResult = base.executeTasks(task2exe);
// aggiungo comportamento custom:
// se ho impostato nome ricetta (programma) --> imposto richiesta caricamento
// se ho richiesto reset o fine lavoro --> imposto azzeramento
// aggiungo comportamento custom: se ho impostato nome ricetta (programma) --> imposto
// richiesta caricamento se ho richiesto reset o fine lavoro --> imposto azzeramento
// esco restituendo risutlato scrittura iniziali
if (task2exe != null)
{
@@ -202,7 +111,93 @@ namespace IOB_WIN_NEXT
return writeResult;
}
#endregion Public Constructors
public override bool resetcontapezziPLC()
{
bool answ = false;
try
{
List<WriteValue> nodes2Write = new List<WriteValue>();
foreach (var item in opcUaParams.actResetCounter)
{
WriteValue commWriteVal = new WriteValue();
commWriteVal.NodeId = new NodeId(item.Key);
commWriteVal.AttributeId = Attributes.Value;
commWriteVal.Value = new DataValue();
commWriteVal.Value.Value = item.Value;
nodes2Write.Add(commWriteVal);
}
// vera scrittura
UA_ref.WriteNodes(nodes2Write);
answ = true;
}
catch
{ }
return answ;
}
#endregion Public Methods
#region Private Methods
/// <summary>
/// Azioni specifiche x indicare fine lotto di produzione
/// </summary>
/// <returns></returns>
private bool setFineLotto()
{
bool answ = false;
try
{
List<WriteValue> nodes2Write = new List<WriteValue>();
foreach (var item in opcUaParams.actStopProd)
{
WriteValue commWriteVal = new WriteValue();
commWriteVal.NodeId = new NodeId(item.Key);
commWriteVal.AttributeId = Attributes.Value;
commWriteVal.Value = new DataValue();
commWriteVal.Value.Value = item.Value;
nodes2Write.Add(commWriteVal);
}
// vera scrittura
UA_ref.WriteNodes(nodes2Write);
answ = true;
}
catch
{ }
return answ;
}
/// <summary>
/// Azioni specifiche x iniziare produzione (impostazione ricetta)
/// </summary>
/// <returns></returns>
private bool setInizioProd()
{
bool answ = false;
try
{
List<WriteValue> nodes2Write = new List<WriteValue>();
foreach (var item in opcUaParams.actSetRecipe)
{
WriteValue commWriteVal = new WriteValue();
commWriteVal.NodeId = new NodeId(item.Key);
commWriteVal.AttributeId = Attributes.Value;
commWriteVal.Value = new DataValue();
commWriteVal.Value.Value = item.Value;
nodes2Write.Add(commWriteVal);
}
// vera scrittura
UA_ref.WriteNodes(nodes2Write);
answ = true;
}
catch
{ }
return answ;
}
#endregion Private Methods
}
}
+470 -458
View File
@@ -8,112 +8,6 @@ namespace IOB_WIN_NEXT
{
public class IobSimula : IobGeneric
{
#region Protected Fields
/// <summary>
/// Parametri simulazione oscillazione bit 2
/// </summary>
protected simPar bit2;
/// <summary>
/// Parametri simulazione oscillazione bit 3
/// </summary>
protected simPar bit3;
/// <summary>
/// Parametri simulazione oscillazione bit 4
/// </summary>
protected simPar bit4;
/// <summary>
/// Parametri simulazione oscillazione bit 5
/// </summary>
protected simPar bit5;
/// <summary>
/// Parametri simulazione oscillazione bit 6
/// </summary>
protected simPar bit6;
/// <summary>
/// Parametri simulazione oscillazione bit 7
/// </summary>
protected simPar bit7;
/// <summary>
/// pallet corrente
/// </summary>
protected int cP = 1;
protected bool disableSimStatus = false;
/// <summary>
/// ultimo controllo decremento eventi
/// </summary>
protected DateTime lastEvCheck;
/// <summary>
/// Ultimo istante in cui sono stati generati dati di simulazione
/// </summary>
protected DateTime lastSimData;
/// <summary>
/// Ultimo istante in cui sono stati ridotti dati simulazione duration
/// </summary>
protected DateTime lastRedDuration;
/// <summary>
/// Matricola OPR simulato
/// </summary>
protected int matrOpr = 1;
/// <summary>
/// Durata minima ODL x reset quando pezzi iob > pezzi macchina...
/// </summary>
protected int minDurataODL = 480;
/// <summary>
/// pallet successivo (next)
/// </summary>
protected int nP = 1;
/// <summary>
/// periodo base del simulatore (in millisecondi)
/// </summary>
protected int periodoMSec = 1000;
/// <summary>
/// variabile di appoggio x stato segnale contapezzo
/// </summary>
protected bool sigPzCount = false;
/// <summary>
/// Simulazione registrazione dichiarazioni utente
/// </summary>
protected simPar simDich;
/// <summary>
/// BOOL: indica se simulare powerOn/Off (bit 0 e 1) compresi WarmUp e CoolDown
/// </summary>
protected bool simPowerOnOff;
/// <summary>
/// Simulazione effettuazione controlli utente
/// </summary>
protected simPar simRC;
/// <summary>
/// Simulazione registro scarti utente
/// </summary>
protected simPar simRS;
/// <summary>
/// Tempo di MINIMO attesa x simulazione parametri
/// </summary>
protected int waitSimPar = utils.CRI("waitSimPar");
#endregion Protected Fields
#region Public Fields
/// <summary>
@@ -200,18 +94,454 @@ namespace IOB_WIN_NEXT
#endregion Public Constructors
#region Private Methods
#region Public Methods
/// <summary>
/// Decodifica il resto dell'area x i dati accessori (allarmi, ...)
/// Processo i task richiesti e li elimino dalla coda 1:1 (in realtà SOLO forceSetPzCount x ora)
/// </summary>
private void decodeOtherData()
/// <param name="task2exe"></param>
public override Dictionary<string, string> executeTasks(Dictionary<string, string> task2exe)
{
// Verificare il protocollo: dovrebeb togliere SOLO i task eseguiti...
Dictionary<string, string> taskDone = new Dictionary<string, string>();
// controlo SE sia disabilitata simulazione principale
if (!disableSimStatus)
{
string taskVal = "";
// verifico non sia null
if (task2exe != null)
{
// cerco task specifici
foreach (var item in task2exe)
{
taskVal = "";
// converto richiesta in enum...
taskType tName = taskType.nihil;
Enum.TryParse(item.Key, out tName);
// controllo sulla KEY
switch (tName)
{
case taskType.setArt:
case taskType.setComm:
case taskType.setProg:
case taskType.setPzComm:
memMap.mMapWrite[item.Key].value = item.Value;
taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | UPDATED memMap.mMapWrite";
break;
case taskType.setParameter:
// richiedo da URL i parametri WRITE da popolare
lgInfo("Chiamata processMemWriteRequests");
taskVal = processMemWriteRequests();
// se restituiscce "" faccio altra prova...
if (string.IsNullOrEmpty(taskVal))
{
// i parametri me li aspetto come stringa composta paramName|paramvalue
if (item.Value.Contains("|"))
{
string[] paramsJob = item.Value.Split('|');
taskVal = $"REQUEST SET PARAMETERS: {paramsJob[0]} --> {paramsJob[1]}";
}
else
{
taskVal = $"WRONG REQUEST FOR SET PARAMETERS: {item.Value} doesnt contain pipe for splitting key/value";
}
}
break;
case taskType.nihil:
case taskType.fixStopSetup:
case taskType.forceResetPzCount:
case taskType.sendWatchDogMes2Plc:
case taskType.startSetup:
case taskType.stopSetup:
taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC";
break;
case taskType.forceSetPzCount:
// forzo sul SIM il valore pzCount dell'IOB...
int newPzCount = contapezziPLC;
bool fatto = int.TryParse(item.Value, out newPzCount);
if (fatto)
{
// verifico SE sia ammesso il cambio ...
int deltaPzCount = newPzCount - 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 {newPzCount} | contapezzi attuale: {contapezziPLC} | ultima lettura PLC: {plcLastPzRead} | TCiclo medio: {plcAvgTc}s | incremento accettato ");
}
else
{
contapezziPLC = newPzCount;
taskVal = $"Set new contapezziPLC: {contapezziPLC}";
}
}
break;
default:
taskVal = "SKIPPED | NO EXEC";
break;
}
// aggiungo task!
taskDone.Add(item.Key, taskVal);
}
}
}
return taskDone;
}
/// <summary>
/// Recupera e processa allarmi CNC...
/// </summary>
public override Dictionary<string, string> getCncAlarms()
{
Dictionary<string, string> outVal = new Dictionary<string, string>();
return outVal;
}
/// <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>();
// verificare periodo SIM parametri... se passato li invio altrimenti NO... FIX a 20 sec
if (lastSimData.AddSeconds(waitSimPar) < DateTime.Now)
{
Random rnd = new Random();
// controllo conf memorie json (se ci sono...)
try
{
if (memMap.mMapWrite.Count > 0)
{
foreach (var item in memMap.mMapWrite)
{
outVal.Add(item.Key, item.Value.value);
}
}
if (memMap.mMapRead.Count > 0)
{
foreach (var item in memMap.mMapRead)
{
// se il TIPO di valore è livello --> simulo variazione da MAX --> min,
// con un delta in CALO pari a factor * (80-120)%
if (item.Value.name == "SIM_LEVEL")
{
// verifico last value
float lastVal = 0;
float.TryParse(item.Value.value, out lastVal);
if (lastVal == 0)
{
lastVal = item.Value.maxVal - (float)item.Value.factor;
}
// decremento casuale...
float newVal = lastVal - ((float)item.Value.factor * rnd.Next(40, 120) / 100);
// se inferiore a minimo --> massimo!
if (newVal < item.Value.minVal)
{
newVal = item.Value.maxVal;
}
// salvo il suo VALUE...
item.Value.value = $"{newVal}";
outVal.Add(item.Key, $"{newVal}");
}
// altrimenti siulazione random walk...
else
{
if (item.Value.factor == 1)
{
// uso factor come valore MAX ammesso
int randVal = rnd.Next(item.Value.minVal, item.Value.maxVal);
outVal.Add(item.Key, randVal.ToString());
}
else
{
// uso factor come fattore di divisione x simulare decimali
float randVal = ((float)rnd.Next(item.Value.minVal, item.Value.maxVal)) / (float)item.Value.factor;
outVal.Add(item.Key, randVal.ToString());
}
}
}
}
}
catch
{ }
lastSimData = DateTime.Now;
}
return outVal;
}
/// <summary>
/// Recupero programma in lavorazione
/// </summary>
/// <returns></returns>
public override string getPrgName()
{
// NOME DEL SIM!
string prgName = $"PROG_{cIobConf.codIOB}";
return prgName;
}
/// <summary> Recupero info sistema generiche <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>();
outVal.Add("MACHINE", "IOB_SIM");
return outVal;
}
/// <summary>
/// Effettua vero processing contapezzi
/// </summary>
public override void processContapezzi()
{
}
private Random rnd = new Random();
private int currSimAlarmCode = 0;
private List<string> alarmMessages = new List<string>();
/// <summary>
/// Processo contatori eventi...
/// </summary>
public override void processVHF()
{
if (lastEvCheck.AddMilliseconds(periodoMSec) < DateTime.Now)
{
// decremento contatore ultimo evento
try
{
if (bit2 != null)
bit2.wait--;
if (bit3 != null)
bit3.wait--;
if (bit4 != null)
bit4.wait--;
if (bit5 != null)
bit5.wait--;
if (simDich != null)
simDich.wait--;
if (simRC != null)
simRC.wait--;
if (simRS != null)
simRS.wait--;
}
catch
{ }
lastEvCheck = DateTime.Now;
}
}
/// <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);
// controlo SE sia disabilitata simulazione principale
if (!disableSimStatus)
{
// decodifica e gestione
decodeToBaseBitmap();
decodeOtherData();
reportRawInput(ref currDispData);
}
}
/// <summary>
/// Effettua reset del contapezzi
/// </summary>
/// <returns></returns>
public override bool resetcontapezziPLC()
{
bool answ = false;
// ...SE abilitato da conf IOB
if (cIobConf.optPar.Count > 0 && getOptPar("ENABLE_PZ_RESET") == "TRUE")
{
// fingo di aver fatto...
answ = true;
}
return answ;
}
public override void tryConnect()
{
base.tryConnect();
connectionOk = true;
}
public override void tryDisconnect()
{
base.tryDisconnect();
connectionOk = false;
}
#endregion Public Methods
#region Protected Fields
/// <summary>
/// Parametri simulazione oscillazione bit 2
/// </summary>
protected simPar bit2;
/// <summary>
/// Parametri simulazione oscillazione bit 3
/// </summary>
protected simPar bit3;
/// <summary>
/// Parametri simulazione oscillazione bit 4
/// </summary>
protected simPar bit4;
/// <summary>
/// Parametri simulazione oscillazione bit 5
/// </summary>
protected simPar bit5;
/// <summary>
/// Parametri simulazione oscillazione bit 6
/// </summary>
protected simPar bit6;
/// <summary>
/// Parametri simulazione oscillazione bit 7
/// </summary>
protected simPar bit7;
/// <summary>
/// pallet corrente
/// </summary>
protected int cP = 1;
protected bool disableSimStatus = false;
/// <summary>
/// ultimo controllo decremento eventi
/// </summary>
protected DateTime lastEvCheck;
/// <summary>
/// Ultimo istante in cui sono stati ridotti dati simulazione duration
/// </summary>
protected DateTime lastRedDuration;
/// <summary>
/// Ultimo istante in cui sono stati generati dati di simulazione
/// </summary>
protected DateTime lastSimData;
/// <summary>
/// Matricola OPR simulato
/// </summary>
protected int matrOpr = 1;
/// <summary>
/// Durata minima ODL x reset quando pezzi iob &gt; pezzi macchina...
/// </summary>
protected int minDurataODL = 480;
/// <summary>
/// pallet successivo (next)
/// </summary>
protected int nP = 1;
/// <summary>
/// periodo base del simulatore (in millisecondi)
/// </summary>
protected int periodoMSec = 1000;
/// <summary>
/// variabile di appoggio x stato segnale contapezzo
/// </summary>
protected bool sigPzCount = false;
/// <summary>
/// Simulazione registrazione dichiarazioni utente
/// </summary>
protected simPar simDich;
/// <summary>
/// BOOL: indica se simulare powerOn/Off (bit 0 e 1) compresi WarmUp e CoolDown
/// </summary>
protected bool simPowerOnOff;
/// <summary>
/// Simulazione effettuazione controlli utente
/// </summary>
protected simPar simRC;
/// <summary>
/// Simulazione registro scarti utente
/// </summary>
protected simPar simRS;
/// <summary>
/// Tempo di MINIMO attesa x simulazione parametri
/// </summary>
protected int waitSimPar = utils.CRI("waitSimPar");
#endregion Protected Fields
#region Protected Methods
/// <summary>
/// Salvo valori 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 = "";
string serObj = "";
if (updatedPar != null)
{
// controllo i parametri... ne gestisco 4...
foreach (var item in updatedPar)
{
try
{
memAddrWrite = "";
// 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}---------------");
lgInfo($"---------------MemBlock data---------------{Environment.NewLine}{BitConverter.ToString(MemBlock)}{Environment.NewLine}--------------- END data ---------------");
}
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>
/// Decremento duration del bit indicato secondo stesse regole di ritardo dei bit di wait
@@ -226,21 +556,27 @@ namespace IOB_WIN_NEXT
case 2:
bit2.duration--;
break;
case 3:
bit3.duration--;
break;
case 4:
bit4.duration--;
break;
case 5:
bit5.duration--;
break;
case 6:
bit6.duration--;
break;
case 7:
bit7.duration--;
break;
default:
break;
}
@@ -248,6 +584,27 @@ namespace IOB_WIN_NEXT
}
}
#endregion Protected Methods
#region Private Fields
private List<string> alarmMessages = new List<string>();
private int currSimAlarmCode = 0;
private Random rnd = new Random();
#endregion Private Fields
#region Private Methods
/// <summary>
/// Decodifica il resto dell'area x i dati accessori (allarmi, ...)
/// </summary>
private void decodeOtherData()
{
}
/// <summary>
/// Effettua decodifica aree memoria alla bitmap usata x MAPO
/// </summary>
@@ -655,7 +1012,7 @@ namespace IOB_WIN_NEXT
}
/// <summary>
/// provo a chiamare split ODL
/// provo a chiamare split ODL
/// </summary>
private void trySplitOdl()
{
@@ -674,351 +1031,6 @@ namespace IOB_WIN_NEXT
}
#endregion Private Methods
#region Protected Methods
/// <summary>
/// Salvo valori 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 = "";
string serObj = "";
if (updatedPar != null)
{
// controllo i parametri... ne gestisco 4...
foreach (var item in updatedPar)
{
try
{
memAddrWrite = "";
// 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}---------------");
lgInfo($"---------------MemBlock data---------------{Environment.NewLine}{BitConverter.ToString(MemBlock)}{Environment.NewLine}--------------- END data ---------------");
}
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}");
}
}
}
}
#endregion Protected Methods
#region Public Methods
/// <summary>
/// Processo i task richiesti e li elimino dalla coda 1:1 (in realtà SOLO forceSetPzCount x ora)
/// </summary>
/// <param name="task2exe"></param>
public override Dictionary<string, string> executeTasks(Dictionary<string, string> task2exe)
{
// Verificare il protocollo: dovrebeb togliere SOLO i task eseguiti...
Dictionary<string, string> taskDone = new Dictionary<string, string>();
// controlo SE sia disabilitata simulazione principale
if (!disableSimStatus)
{
string taskVal = "";
// verifico non sia null
if (task2exe != null)
{
// cerco task specifici
foreach (var item in task2exe)
{
taskVal = "";
// converto richiesta in enum...
taskType tName = taskType.nihil;
Enum.TryParse(item.Key, out tName);
// controllo sulla KEY
switch (tName)
{
case taskType.setArt:
case taskType.setComm:
case taskType.setProg:
case taskType.setPzComm:
memMap.mMapWrite[item.Key].value = item.Value;
taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | UPDATED memMap.mMapWrite";
break;
case taskType.setParameter:
// richiedo da URL i parametri WRITE da popolare
lgInfo("Chiamata processMemWriteRequests");
taskVal = processMemWriteRequests();
// se restituiscce "" faccio altra prova...
if (string.IsNullOrEmpty(taskVal))
{
// i parametri me li aspetto come stringa composta paramName|paramvalue
if (item.Value.Contains("|"))
{
string[] paramsJob = item.Value.Split('|');
taskVal = $"REQUEST SET PARAMETERS: {paramsJob[0]} --> {paramsJob[1]}";
}
else
{
taskVal = $"WRONG REQUEST FOR SET PARAMETERS: {item.Value} doesnt contain pipe for splitting key/value";
}
}
break;
case taskType.nihil:
case taskType.fixStopSetup:
case taskType.forceResetPzCount:
case taskType.sendWatchDogMes2Plc:
case taskType.startSetup:
case taskType.stopSetup:
taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC";
break;
case taskType.forceSetPzCount:
// forzo sul SIM il valore pzCount dell'IOB...
int newPzCount = contapezziPLC;
bool fatto = int.TryParse(item.Value, out newPzCount);
if (fatto)
{
// verifico SE sia ammesso il cambio ...
int deltaPzCount = newPzCount - 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 {newPzCount} | contapezzi attuale: {contapezziPLC} | ultima lettura PLC: {plcLastPzRead} | TCiclo medio: {plcAvgTc}s | incremento accettato ");
}
else
{
contapezziPLC = newPzCount;
taskVal = $"Set new contapezziPLC: {contapezziPLC}";
}
}
break;
default:
taskVal = "SKIPPED | NO EXEC";
break;
}
// aggiungo task!
taskDone.Add(item.Key, taskVal);
}
}
}
return taskDone;
}
/// <summary>
/// Recupera e processa allarmi CNC...
/// </summary>
public override Dictionary<string, string> getCncAlarms()
{
Dictionary<string, string> outVal = new Dictionary<string, string>();
return outVal;
}
/// <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>();
// verificare periodo SIM parametri... se passato li invio altrimenti NO... FIX a 20 sec
if (lastSimData.AddSeconds(waitSimPar) < DateTime.Now)
{
Random rnd = new Random();
// controllo conf memorie json (se ci sono...)
try
{
if (memMap.mMapWrite.Count > 0)
{
foreach (var item in memMap.mMapWrite)
{
outVal.Add(item.Key, item.Value.value);
}
}
if (memMap.mMapRead.Count > 0)
{
foreach (var item in memMap.mMapRead)
{
// se il TIPO di valore è livello --> simulo variazione da MAX --> min, con un delta in CALO pari a factor * (80-120)%
if (item.Value.name == "SIM_LEVEL")
{
// verifico last value
float lastVal = 0;
float.TryParse(item.Value.value, out lastVal);
if (lastVal == 0)
{
lastVal = item.Value.maxVal - (float)item.Value.factor;
}
// decremento casuale...
float newVal = lastVal - ((float)item.Value.factor * rnd.Next(40, 120) / 100);
// se inferiore a minimo --> massimo!
if (newVal < item.Value.minVal)
{
newVal = item.Value.maxVal;
}
// salvo il suo VALUE...
item.Value.value = $"{newVal}";
outVal.Add(item.Key, $"{newVal}");
}
// altrimenti siulazione random walk...
else
{
if (item.Value.factor == 1)
{
// uso factor come valore MAX ammesso
int randVal = rnd.Next(item.Value.minVal, item.Value.maxVal);
outVal.Add(item.Key, randVal.ToString());
}
else
{
// uso factor come fattore di divisione x simulare decimali
float randVal = ((float)rnd.Next(item.Value.minVal, item.Value.maxVal)) / (float)item.Value.factor;
outVal.Add(item.Key, randVal.ToString());
}
}
}
}
}
catch
{ }
lastSimData = DateTime.Now;
}
return outVal;
}
/// <summary>
/// Recupero programma in lavorazione
/// </summary>
/// <returns></returns>
public override string getPrgName()
{
// NOME DEL SIM!
string prgName = $"PROG_{cIobConf.codIOB}";
return prgName;
}
/// <summary>
/// Recupero info sistema generiche
/// <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>();
outVal.Add("MACHINE", "IOB_SIM");
return outVal;
}
/// <summary>
/// Effettua vero processing contapezzi
/// </summary>
public override void processContapezzi()
{
}
/// <summary>
/// Processo contatori eventi...
/// </summary>
public override void processVHF()
{
if (lastEvCheck.AddMilliseconds(periodoMSec) < DateTime.Now)
{
// decremento contatore ultimo evento
try
{
if (bit2 != null)
bit2.wait--;
if (bit3 != null)
bit3.wait--;
if (bit4 != null)
bit4.wait--;
if (bit5 != null)
bit5.wait--;
if (simDich != null)
simDich.wait--;
if (simRC != null)
simRC.wait--;
if (simRS != null)
simRS.wait--;
}
catch
{ }
lastEvCheck = DateTime.Now;
}
}
/// <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);
// controlo SE sia disabilitata simulazione principale
if (!disableSimStatus)
{
// decodifica e gestione
decodeToBaseBitmap();
decodeOtherData();
reportRawInput(ref currDispData);
}
}
/// <summary>
/// Effettua reset del contapezzi
/// </summary>
/// <returns></returns>
public override bool resetcontapezziPLC()
{
bool answ = false;
// ...SE abilitato da conf IOB
if (cIobConf.optPar.Count > 0 && getOptPar("ENABLE_PZ_RESET") == "TRUE")
{
// fingo di aver fatto...
answ = true;
}
return answ;
}
public override void tryConnect()
{
base.tryConnect();
connectionOk = true;
}
public override void tryDisconnect()
{
base.tryDisconnect();
connectionOk = false;
}
#endregion Public Methods
}
/// <summary>