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

551 lines
21 KiB
C#

using IOB_UT_NEXT;
using MapoSDK;
using System;
using System.Collections.Generic;
using System.Linq;
namespace IOB_WIN_SIEMENS.IobSiemens
{
public class SiemensTorri : Siemens
{
/* --------------------------------------------------------------------------------
* Controlli SIEMENS TORRI
* - basasto su SIEMENS
* - S7 vers 1200
*
* mod: 2019.01.19: aggiunta gestione segnale test/accensione/spegnimento (DB700.B1.4) --> mod StateMachine!
* mod: 2019.04.06: aggiunta indicazione (IOB--> PLC) di stato setup su DB701.B0.4
* mod: 2024.12.05: gestione allarmi da file ext come base Siemens e opzione ENABLE_ALARM_LEGACY
* -------------------------------------------------------------------------------- */
#region Public Constructors
/// <summary>
/// estende l'init della classe base con i metodi x Siemens specifici x Torri
/// </summary>
/// <param name="caller"></param>
/// <param name="adpConf"></param>
public SiemensTorri(AdapterFormNext caller, IobConfiguration IOBConf) : base(caller, IOBConf)
{
// gestione restart OpcUa client...
if (!string.IsNullOrEmpty(getOptPar("ENABLE_ALARM_LEGACY")))
{
bool.TryParse(getOptPar("ENABLE_ALARM_LEGACY"), out enableAlarmLegacy);
}
//
lgInfo("NEW IOB SIEMENS versione TORRI avviato | vers 2024");
}
#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)
{
// Verificare il protocollo: dovrebeb togliere SOLO i task eseguiti...
Dictionary<string, string> taskDone = new Dictionary<string, string>();
bool taskOk = false;
string taskVal = "";
// inizio con 1 byte VUOTO
byte[] MemBlock = new byte[1];
if (task2exe != null)
{
// cerco task specifici: se ho startSetup --> imposto bit DBB701.DBB0.4
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.setArt:
case taskType.setComm:
case taskType.setProg:
case taskType.sendWatchDogMes2Plc:
taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC";
lgInfo($"Chiamata senza processing: taskOk: {taskOk} | taskVal: {taskVal}");
break;
case taskType.fixStopSetup:
MemBlock[0] = 0;
taskVal = "VALUE DB701.0.4 --> 0";
lgInfo($"Chiamata fixStopSetup: taskOk: {taskOk} | taskVal: {taskVal}");
break;
case taskType.startSetup:
MemBlock[0] += (1 << 4);
taskVal = "VALUE DB701.0.4 --> 1";
lgInfo($"Chiamata startSetup: taskOk: {taskOk} | taskVal: {taskVal}");
break;
case taskType.stopSetup:
MemBlock[0] = 0;
taskVal = "VALUE DB701.0.4 --> 0";
lgInfo($"Chiamata stopSetup: taskOk: {taskOk} | taskVal: {taskVal}");
break;
default:
taskVal = "SKIPPED | NO EXEC";
lgInfo($"Chiamata default senza processing: taskOk: {taskOk} | taskVal: {taskVal}");
break;
}
taskDone.Add(item.Key, taskVal);
}
// scrivo comunque!
bool fatto = S7WriteBB(ref MemBlock);
}
return taskDone;
}
/// <summary>
/// Recupera ULTIMO allarme...
/// </summary>
/// <returns></returns>
public override Dictionary<string, string> getCncAlarms()
{
// parto da ultimo vettore allarmi rilevato
Dictionary<string, string> outVal = lastReadAlarms;
// se ho altro --> accodo
try
{
string almMsg = string.Format("{0} | {1}", currPLC.LastErrorCode.ToString(), currPLC.LastErrorString);
outVal.Add("CNC_ALARM", almMsg);
}
catch (Exception exc)
{
lgError(exc, "Errore in getCncAlarms");
}
// resetto vettore allarmi
lastReadAlarms = new Dictionary<string, string>();
return outVal;
}
/// <summary>
/// Recupero dati dinamici...
/// </summary>
public override Dictionary<string, string> getDynData()
{
Dictionary<string, string> outVal = new Dictionary<string, string>();
#if false
inizio = DateTime.Now;
EgwProxy.MultiCncLib.Focas1.ODBDY2_1 answ = FANUC_ref.getAllDynData();
if (utils.CRB("recTime")) TimingData.addResult(string.Format("PROC-DYN-DATA"), DateTime.Now.Subtract(inizio).Ticks);
try
{
string actf = answ.actf.ToString();
string acts = answ.acts.ToString();
//string numAlarm = answ.alarm.ToString();
// preparo i singoli valori dell'array...
//outVal.Add("DYNDATA", string.Format("{0}#{1}#{2}", actf, acts, numAlarm));
outVal.Add("DYNDATA", string.Format("FEED {0}#SPEED_RPM {1}", actf, acts));
if (utils.CRB("SendFeedSpeed"))
{
outVal.Add("FEED", actf);
outVal.Add("SPEED_RPM", acts);
//outVal.Add("NUM_ALARM", numAlarm);
}
if (utils.CRB("SendAxPos"))
{
// salvo le posizioni...
EgwProxy.MultiCncLib.Focas1.FAXIS posAx = answ.pos;
int[] currPosAbs = posAx.absolute;
int i = 0;
foreach (var item in currPosAbs)
{
i++;
outVal.Add(string.Format("POS_{0:00}", i), item.ToString());
}
}
}
catch (Exception exc)
{
lgError(exc, "Errore in getDynData");
}
#endif
return outVal;
}
/// <summary>
/// Recupero dati override in formato dictionary
/// </summary>
/// <returns></returns>
public override Dictionary<string, string> getOverrides()
{
Dictionary<string, string> outVal = new Dictionary<string, string>();
uint valDW = 0;
// !!!FARE!!! recuperare da conf memoria, ora HARD CODED
outVal.Add("FEED_OVER", RawInput[19].ToString());
outVal.Add("RAPID_OVER", RawInput[20].ToString());
outVal.Add("CURR_MODE", decodeCurrMode(RawInput[21]));
// recupero RPM pezzo/mola !!!FARE!!! cambio nome da config, qui sono 01:conduttrice e
// 02:operatrice (3013), mentre sono pezzo/mola nella V100
valDW = S7.Net.Types.DWord.FromByteArray(RawInput.Skip(24).Take(4).ToArray());
outVal.Add("RPM_01", valDW.ToString());
valDW = S7.Net.Types.DWord.FromByteArray(RawInput.Skip(28).Take(4).ToArray());
outVal.Add("RPM_02", valDW.ToString());
return outVal;
}
/// <summary>
/// Recupero programma in lavorazione
/// </summary>
/// <returns></returns>
public override string getPrgName()
{
string prgName = "";
#if false
// recupero NUOVO prgName...
try
{
// recupero nome programma MAIN
prgName = utils.purgedChar2String(FANUC_ref.getPrgNameMain());
// trimmo path del programma, ovvero "CNCMEMUSERPATH1"
prgName = prgName.Replace(utils.CRS("basePrgMemPath"), "");
}
catch (Exception exc)
{
lgError(string.Format("Eccezione in recupero PRG NAME MAIN:{0}{1}", Environment.NewLine, exc));
}
#endif
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()
{
Dictionary<string, string> outVal = new Dictionary<string, string>();
try
{
outVal.Add("CPU", currPLC.CPU.ToString());
outVal.Add("MAX_PDU", currPLC.MaxPDUSize.ToString());
outVal.Add("RACK", currPLC.Rack.ToString());
outVal.Add("SLOT", currPLC.Slot.ToString());
}
catch (Exception exc)
{
lgError(exc, "Errore in getSysInfo");
}
return outVal;
}
/// <summary>
/// Esegue processing MODE (e nel contempo recupera altri dati dell'area G)
/// </summary>
public override void processMode()
{
if (utils.CRB("enableMode"))
{
#if false
try
{
inizio = DateTime.Now;
// leggo tutto da 0 a 43...
int memIndex = 0;
FanucMemRW(R, FANUC.MemType.G, memIndex, ref MemBlockG);
if (utils.CRB("recTime")) TimingData.addResult(string.Format("R{0}-G-AREA", MemBlockG.Length), DateTime.Now.Subtract(inizio).Ticks);
// verifico modo con valore corrente, se cambia aggiorno...
CNC_MODE newMode = decodeG43(MemBlockG[43]);
if (newMode != currMode)
{
// aggiorno!
currMode = newMode;
// conversione NUM MODE in descrizione da ENUM
string descrMode = Enum.GetName(typeof(CNC_MODE), currMode);
// accodo x invio
string sVal = string.Format("[CNC_MODE]{0}", descrMode);
// chiamo accodamento...
accodaFLog(sVal, qEncodeFLog("CNC_MODE", descrMode));
}
}
catch (Exception exc)
{
lgError(exc, "Errore in process Mode G43");
}
#endif
}
}
/// <summary>
/// Override salvataggio valori in memoria...
/// </summary>
/// <param name="tipo">tipo di DUMP</param>
public override void saveMemDump(dumpType tipo)
{
}
#endregion Public Methods
#region Protected Fields
protected Dictionary<string, string> lastReadAlarms = new Dictionary<string, string>();
#endregion Protected Fields
#region Protected Methods
/// <summary>
/// Decodifica il resto dell'area TORRI x i dati accessori (allarmi, ...)
/// </summary>
protected override void decodeOtherData()
{
if (verboseLog)
{
}
}
/// <summary>
/// Effettua decodifica aree memoria alla bitmap usata x MAPO
/// </summary>
protected override void decodeToBaseBitmap()
{
// init a zero...
B_input = 0;
// TORRI: leggo i primi 8 bit hard coded...
int byteSem = RawInput[0];
// azzero powerOn...
byteSem &= ~(1 << 0);
// bit 0 (powerOn) imposto a 1 SE connected...
if (currPLC.IsConnected)
{
byteSem += (1 << 0);
}
// azzero i bit NON gestiti (2-5-6-7)
byteSem &= ~(1 << 2);
byteSem &= ~(1 << 5);
byteSem &= ~(1 << 6);
byteSem &= ~(1 << 7);
// leggo bit DB700.B1.4 e lo porto al bit 5 --> ciclo test/accensione/spegnimento
if ((RawInput[1] & (1 << 4)) != 0) //se RawInput[1] & 16-- > 5° bit-- > TEST
{
byteSem += (1 << 5);
}
// salvo infine variabile bit x invio
B_input = byteSem;
// se ho il bit di allarme
if ((RawInput[0] & (1 << 3)) != 0)
{
checkAlarms();
}
// procedo SOLO SE è enabled IOB
if (IobOnline)
{
try
{
currODL = utils.callUrl(urlGetCurrODL);
// solo SE HO un ODL...
if (string.IsNullOrEmpty(currODL) || currODL == "0")
{
if (periodicLog)
{
lgInfo($"SiemensTorri | Lettura ODL andata a vuoto: currODL: {currODL}");
}
}
else
{
// se variato o scaduto timeout log...
if (periodicLog || (currIdxODL.ToString() != currODL))
{
lgInfo($"SiemensTorri | Lettura ODL, currODL: {currODL} --> currIdxODL prec: {currIdxODL}");
}
// provo a salvare nuovo ODL
int.TryParse(currODL, out currIdxODL);
}
}
catch (Exception exc)
{
if (DateTime.Now.Subtract(lastWarnODL).TotalSeconds > 15)
{
lgError(exc, $"Errore in fase di chiamata URL x ODL corrente | URL chiamato: {urlGetCurrODL}");
lastWarnODL = DateTime.Now;
}
}
}
else
{
// imposto currODL a vuoto!
currODL = "";
if (periodicLog)
{
lgInfo($"Fanuc | Lettura ODL non effettuata: IobOnline: {IobOnline} | currODL impostato a vuoto");
}
}
if (!string.IsNullOrEmpty(currODL) && currODL != "0")
{
// ora processo il contapezzi...
string retVal = "";
// controllo se è passato intervallo minimo tra 2 controlli/elaborazioni x
// distanziare invio e ridurre letture
if (DateTime.Now >= lastPzCountSend.AddMilliseconds(pzCountDelay))
{
// Salvo il contapezzi della macchina
retVal = utils.callUrlNow(urlSetPzCountMAC + contapezziPLC.ToString());
// verifica se tutto OK, ovvero conferma i pezzi inviati
if (retVal != contapezziPLC.ToString())
{
// errore salvataggio contapezzi
lgInfo($"Errore salvataggio Contapezzi PLC SIEMENST-TORRI: {contapezziPLC} | contapezziIOB {contapezziIOB} | Valore tornato: {retVal}");
// rileggo il counter pezzi da server
pzCntReload(true);
}
// se sono differenti MOSTRO...
if (contapezziPLC != contapezziIOB)
{
// registro contapezzi
lgInfo($"Differenza Contapezzi: contapezziPLC: {contapezziPLC} | contapezziIOB: {contapezziIOB}");
}
if ((contapezziPLC > contapezziIOB))
{
// salvo nuovo contapezzi (incremento di 1...) + richiesta refresh conteggio
contapezziIOB++;
needRefreshPzCount = true;
// salvo in semaforo!
B_input += 1 << 2;
// registro contapezzi
lgInfo($"contapezziPLC SIEMENST-TORRI: {contapezziPLC} | contapezziIOB {contapezziIOB}");
}
// Salvo il contapezzi della macchina
retVal = utils.callUrlNow(urlSetPzCount + contapezziIOB.ToString());
// verifica se tutto OK, ovvero conferma i pezzi inviati
if (retVal != contapezziIOB.ToString())
{
// errore salvataggio contapezzi
lgInfo($"Errore salvataggio contapezziPLC SIEMENST-TORRI: {contapezziPLC} | contapezziIOB {contapezziIOB} | Valore tornato: {retVal}");
// rileggo il counter pezzi da server
pzCntReload(true);
}
// verifico se variato contapezzi... e se passato ritardo minimo...
if ((contapezziPLC - contapezziIOB) > minSendPzCountBlock)
{
trySendPzCountBlock("");
}
// invio a server contapezzi (aggiornato)
retVal = utils.callUrlNow(urlSetPzCount + contapezziIOB.ToString());
// verifica se tutto OK
if (retVal != contapezziIOB.ToString())
{
// errore salvataggio contapezzi
lgInfo($"Errore salvataggio Contapezzi SIEMENS-TORRI: contapezziPLC {contapezziPLC} | contapezziIOB {contapezziIOB} | risposta: {retVal}");
// rileggo il counter pezzi da server
pzCntReload(true);
}
// resetto timer...
lastPzCountSend = DateTime.Now;
}
}
else
{
if (DateTime.Now >= lastPzCountSend.AddMilliseconds(pzCountDelay))
{
lgInfo($"Attenzione: mancanza ODL non procedo con gestione contapezzi. contapezziPLC SIEMENST-TORRI: {contapezziPLC} | contapezziIOB: {contapezziIOB}");
// resetto timer...
lastPzCountSend = DateTime.Now;
}
}
// log opzionale!
if (verboseLog)
{
lgInfo("Trasformazione B_input: {B_input}");
}
}
#endregion Protected Methods
#region Private Fields
/// <summary>
/// gestione allarmi classica torri come eventi FluxLog
/// </summary>
private bool enableAlarmLegacy = false;
#endregion Private Fields
#region Private Methods
private int checkAlarmBank(string memAddrAlarms)
{
int trovato = 0;
uint valDW = 0;
var MemBlockPZ = new byte[4];
bool fatto = S7ReadBB(ref MemBlockPZ, memAddrAlarms, 4);
if (fatto)
{
valDW = S7.Net.Types.DWord.FromByteArray(MemBlockPZ.ToArray());
// se <> 0 --> log e accodo a dynData
if (valDW != 0)
{
string key = $"MTH_ALARM_{memAddrAlarms}_{valDW}";
var biteVal = baseUtils.binaryForm(valDW);
lgInfo($"Stato allarmi rilevati: {key} | {valDW} | {biteVal}");
// accodo a dictionary
string almMsg = $"{DateTime.Now} | val {valDW} | {biteVal}";
// se non ci fosse aggiungo
if (!lastReadAlarms.ContainsKey(key))
{
lastReadAlarms.Add(key, almMsg);
}
trovato++;
}
}
return trovato;
}
private void checkAlarms()
{
int trovati = 0;
// SE ho la gestione legacy allarmi sennò nulla...
if (enableAlarmLegacy)
{
// test gestione da conf alarmMap...
if (alarmMaps != null && alarmMaps.Count > 0)
{
foreach (var item in alarmMaps)
{
// da rivedere procedura x usare metodi di gestione allarmi con check differenze + invio alarmLog...
trovati += checkAlarmBank(item.memAddr);
}
}
// legacy... tolto!
#if false
else
{
// leggo i banchi allarmi : cablato D700.DBDW2 --> D700 DBDW14, sono 4 banchi a 32 bit
// da verificare
// ciclo nei 4 banchi...
trovati += checkAlarmBank("DB700.DBDW2");
trovati += checkAlarmBank("DB700.DBDW6");
trovati += checkAlarmBank("DB700.DBDW10");
trovati += checkAlarmBank("DB700.DBDW14");
}
#endif
}
}
#endregion Private Methods
}
}