Files
Mapo-IOB-WIN/IOB-WIN-NEXT/IobSiemensSaet.cs
T
2022-03-18 13:36:11 +01:00

342 lines
15 KiB
C#

using MapoSDK;
using System;
using System.Collections.Generic;
using System.Linq;
namespace IOB_WIN_NEXT
{
/// <summary>
/// Controllo Siemens specifico x impianti SAET
/// </summary>
public class IobSiemensSaet : IobSiemens
{
/* --------------------------------------------------------------------------------
* Controlli SIEMENS SAET (impianti ad induzione in VALVITAL)
* - basasto su SIEMENS
* - S7 vers 1500
*
* STRUTTURA MEMORIA DB1275: primi 92 byte lettura, poi 56 byte scrittura, vedere doc allegato
* G:\Drive condivisi\30_Clienti\Valvital\Comunicazione PLC\SAET (forno e tempra)
*
* Si intende tutto con DB1275.DBxx
*
* - parametri processo
* - DBD00: Watchdog INT SAET Alive ( 1-9999 )
*
* - DB60.DBD6: pressione camera filtrante (salvataggio del MAX ogni minuto) | var testVal = S7.Net.Types.Double.FromByteArray(memByteRead.Skip(0).Take(4).ToArray());
* - DB60.DBD10: pressione linea utenze (salvataggio del MAX ogni minuto)
* - DB60.DBD14: temperatura acqua pulita (salvataggio del MAX ogni minuto)
*
* - BIT di stato
* - DBX2.1: READY TO RUN in AUTOMATICO
* - DBX2.3: Macchina in LAVORAZIONE
* - DBX2.4: WARNING Differenza tra Part Code MES - Saet (blu)
* - DBX2.5: se 1 --> LAMPADA ROSSA (allarmi almeno 1 attivo)
*
* PartCounter DINT 4.0 Conteggio Parziale di pezzi "OK" prodotti dalla macchina
* NumberCode String [12] 8.0 Valore numerico associato alla ricetta di produzione attualmente utilizzata dalla macchina
* NewCode INT 22.0 "1= Avvenuta ricezione del segnale ""richiesta nuovo ordine di produzione (NEW CODE)""
* ricevuto dal server,impostabile su 1 solo quando la macchina NON è in produzione attiva"
* Potenza utilizzata ST.1 REAL 24 Potenza utilizzata dalla stazione di riscaldo 1 [kW]
* Potenza utilizzata ST.2 REAL 28 Potenza utilizzata dalla stazione di riscaldo 2 [kW]
* Potenza utilizzata ST.3 REAL 32 Potenza utilizzata dalla stazione di riscaldo 3 [kW]
* Potenza utilizzata ST.4 REAL 36 Potenza utilizzata dalla stazione di riscaldo 4 [kW]
* Lettura Pirometro ST.1 REAL 40 Lettura Pirometro della stazione di riscaldo 1 [°C]
* Lettura Pirometro ST.2 REAL 44 Lettura Pirometro della stazione di riscaldo 2 [°C]
* Lettura Pirometro ST.3 REAL 48 Lettura Pirometro della stazione di riscaldo 3 [°C]
* Lettura Pirometro ST.4 REAL 52 Lettura Pirometro della stazione di riscaldo 4 [°C]
* Temperatura Acqua Raff Conv. ST.1 REAL 56 Temperarura Acqua di Raffreddamento Convertitore Stazione di Riscaldo 1 [°C]
* Temperatura Acqua Raff Conv. ST.2 REAL 60 Temperarura Acqua di Raffreddamento Convertitore Stazione di Riscaldo 2 [°C]
* Temperatura Acqua Raff Conv. ST.3 REAL 64 Temperarura Acqua di Raffreddamento Convertitore Stazione di Riscaldo 3 [°C]
* Temperatura Acqua Raff Conv. ST.4 REAL 68 Temperarura Acqua di Raffreddamento Convertitore Stazione di Riscaldo 4 [°C]
* Part_Status ST.1 INT 72 Stato Pezzo Stazione di Riscaldo 1 (0=Assente 1=Grezzo 10=OK 11=NOK)
* Part_Status ST.2 INT 74 Stato Pezzo Stazione di Riscaldo 2 (0=Assente 1=Grezzo 10=OK 11=NOK)
* Part_Status ST.3 INT 76 Stato Pezzo Stazione di Riscaldo 3 (0=Assente 1=Grezzo 10=OK 11=NOK)
* Part_Status ST.4 INT 78 Stato Pezzo Stazione di Riscaldo 4 (0=Assente 1=Grezzo 10=OK 11=NOK)
* Reserve_12 REAL 80 Riserva
* Reserve_13 REAL 84 Riserva
* Reserve_14 REAL 88 Riserva
* -------------------------------------------------------------------------------- */
#region Protected Fields
protected int counterMes2Plc = 0;
protected int counterPlc2Mes = 0;
protected int counterPlc2MesWrote = 0;
protected DateTime lastPLCWatchDog;
#endregion Protected Fields
#region Public Constructors
/// <summary>
/// Classe base con i metodi x Siemens
/// </summary>
/// <param name="caller"></param>
/// <param name="adpConf"></param>
public IobSiemensSaet(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf)
{
lgInfo("NEW IOB SIEMENS versione SAET");
lastPLCWatchDog = DateTime.Now.AddMinutes(-1);
}
#endregion Public Constructors
#region Protected Methods
/// <summary>
/// Effettua decodifica aree memoria alla bitmap usata x MAPO
/// </summary>
protected override void decodeToBaseBitmap()
{
// init a zero...
B_input = 0;
/* -----------------------------------------------------
* bitmap MAPO STANDARD
* B0: POWER_ON
* B1: RUN
* B2: pzCount
* B3: allarme
* B4: manuale
* B5: anomalia
*
*
* - BIT di stato
* - DBX2.0: macchina accesa
* - DBX2.1: CICLO AUTO = NON HO ANOMALIE/ALLARMI (0 --> allarme)
* - DBX2.2: contapezzi
* - DBX2.3: MACCHINA IN CICLO AUTO = LAVORA
* - DBX2.4: ERRORE tra part code MES/SAET (blu)
* - DBX2.5: Anomalia presente (rosso)
----------------------------------------------------- */
byte mainData = RawInput[2];
int byteSignals = 0;
// bit 0 (poweron) imposto a 1 SE connected...
if (currPLC.IsConnected)
{
byteSignals += (1 << 0);
}
if ((mainData & (1 << 3)) != 0)
{
byteSignals += (1 << 1);
}
// controllo il bit ALLARME
if ((mainData & (1 << 1)) == 0)
{
byteSignals += (1 << 3);
}
// controllo il bit ANOMALIA
if ((mainData & (1 << 5)) != 0)
{
byteSignals += (1 << 3);
}
// considero NON auto come manuale...
if ((mainData & (1 << 3)) == 0)
{
byteSignals += (1 << 4);
}
// salvo!
B_input = byteSignals;
// processo il watchdog!
counterPlc2Mes = S7.Net.Types.Int.FromByteArray(RawInput.Skip(0).Take(2).ToArray());
// ogni 60 registro...
if (Math.Abs(counterPlc2Mes - counterPlc2MesWrote) > 60)
{
lgInfo($"WatchDog da PLC: {counterPlc2Mes}");
counterPlc2MesWrote = counterPlc2Mes;
}
// log opzionale!
if (verboseLog)
{
lgInfo($"Trasformazione dati: RawInput:{RawInput[3]} --> B_input: {B_input}");
}
}
#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)
{
// Verificare il protocollo: dovrebeb togliere SOLO i task eseguiti...
Dictionary<string, string> taskDone = new Dictionary<string, string>();
bool taskOk = false;
string taskVal = "";
// verifico non sia null
if (task2exe != null)
{
// inizio con 1 byte di default
byte[] MemBlock = new byte[1];
string memAddrWrite = "";
// cerco task specifici
foreach (var item in task2exe)
{
taskOk = false;
taskVal = "";
// converto richiesta in enum...
taskType tName = taskType.nihil;
Enum.TryParse(item.Key, out tName);
// controllo sulla KEY
switch (tName)
{
case taskType.nihil:
case taskType.forceResetPzCount:
case taskType.forceSetPzCount:
case taskType.setProg:
taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC";
break;
case taskType.setArt:
saveProdData(item);
MemBlock = new byte[34];
saveStringOnMemBlock(ref MemBlock, "setArt", 0, 32);
memAddrWrite = "DB1275.DBB96";
taskVal = item.Value;
break;
case taskType.setComm:
saveProdData(item);
MemBlock = new byte[14];
saveStringOnMemBlock(ref MemBlock, "setComm", 0, 12);
memAddrWrite = "DB1275.DBB130";
taskVal = item.Value;
break;
case taskType.setPzComm:
// imposto i valori...
MemBlock = new byte[4];
int numPz = 0;
int.TryParse(item.Value, out numPz);
MemBlock = S7.Net.Types.DInt.ToByteArray(numPz);
memAddrWrite = "DB1275.DBB144";
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.sendWatchDogMes2Plc:
MemBlock = new byte[2];
MemBlock[1] = (byte)counterMes2Plc;
MemBlock[0] = (byte)(counterMes2Plc >> 8);
memAddrWrite = "DB1275.DBB92";
taskVal = $"VALUE DB1275.92 --> {counterMes2Plc}";
break;
case taskType.endProd:
case taskType.startSetup:
// processo scrittura BIT x richiesta nuovo ordine a INIZIO setup --> è DINT!
MemBlock = new byte[2];
MemBlock[0] = (byte)1;
MemBlock[1] = (byte)1;
memAddrWrite = "DB1275.DBB94";
lgInfo($"Chiamata startSetup | memAddrWrite: {memAddrWrite} | MemBlock: {MemBlock}");
break;
case taskType.fixStopSetup:
case taskType.stopSetup:
// processo scrittura BIT x richiesta nuovo ordine a FINE setup
MemBlock = new byte[2];
MemBlock[0] = (byte)0;
MemBlock[1] = (byte)0;
memAddrWrite = "DB1275.DBB94";
lgInfo($"Chiamata stopSetup | memAddrWrite: {memAddrWrite} | MemBlock: {MemBlock}");
break;
default:
taskVal = "SKIPPED | NO EXEC";
break;
}
// verifico se posso aggiornare valori in memoria...
if (memMap != null && memMap.mMapWrite != null)
{
if (memMap.mMapWrite.ContainsKey(item.Key))
{
dataConf currMem = memMap.mMapWrite[item.Key];
string addr = currMem.memAddr;
taskVal = $"SET task: {item.Key} --> {item.Value} | mem: {currMem.memAddr} - {currMem.size} byte";
// salvo il nuovo valore nella memoria... così prox invio lo trasmetterà
memMap.mMapWrite[item.Key].value = item.Value;
}
else
{
taskVal = $"NO DATA MEM, SET task: {item.Key} --> {item.Value}";
}
}
else
{
taskVal = $"NO MemMap found, SET task: {item.Key} --> {item.Value}";
}
// aggiungo task!
taskDone.Add(item.Key, taskVal);
// scrivo comunque!
taskOk = S7WriteBB(ref MemBlock, memAddrWrite);
if (!taskOk)
{
lgError($"Errore in S7WriteBB durante executeTasks: {item.Key} | {item.Value}");
}
}
}
return taskDone;
}
/// <summary>
/// Effettua processing del recupero delle OVERRIDE (spindle, feedrate, rapid)
/// </summary>
public override void processOverride()
{
}
public override void processWhatchDog()
{
// scrivo 1 volta ogni n secondi il contatore incrementale su area apposita
DateTime adesso = DateTime.Now;
if (adesso.Subtract(lastPLCWatchDog).TotalSeconds > watchDogPeriod)
{
// incremento
counterMes2Plc++;
// se > 9999 --> 0
if (counterMes2Plc > 9999) counterMes2Plc = 0;
// salvo su DB
Dictionary<string, string> task2exe = new Dictionary<string, string>();
Dictionary<string, string> taskDone = new Dictionary<string, string>();
task2exe.Add("sendWatchDogMes2Plc", counterMes2Plc.ToString());
taskDone = executeTasks(task2exe);
// salvo watchdog PLC
lastPLCWatchDog = adesso;
}
}
#endregion Public Methods
}
}