using IOB_UT_NEXT; using MapoSDK; using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; namespace IOB_WIN_NEXT { /// /// Controllo Siemens specifico x impianti Lasco (Pressa bilancere Valvital) /// public class IobSiemensLasco : IobSiemens { /* -------------------------------------------------------------------------------- * Controlli SIEMENS LASCO (Pressa principale in VALVITAL) * - basasto su SIEMENS * - S7 vers 1500 * * STRUTTURA MEMORIA DB1001 READ: 68 byte lettura, DB1002 68 byte byte scrittura, vedere doc allegato * F:\Drive condivisi\30_Clienti\Valvital\Comunicazione PLC\22 - LASCO Bilancere * * !!!RISCRIVERE!!! * - 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; protected bool useNewSend = false; #endregion Protected Fields #region Public Constructors /// /// Classe base con i metodi x Siemens /// /// /// public IobSiemensLasco(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf) { lgInfo("NEW IOB SIEMENS versione LASCO"); lastPLCWatchDog = DateTime.Now.AddMinutes(-1); useNewSend = string.IsNullOrWhiteSpace(getOptPar("USE_NEW_EXE_TASK")) ? false : true; // imposto i parametri speciali x calcolo... var chiaviTSVC = findOptPar("TSVC"); if (chiaviTSVC.Count > 0) { lgInfo($"Trovate {chiaviTSVC.Count} chiavi TSVC"); string[] codVal; VCData currConf; int periodo = 0; VC_func funz = VC_func.POINT; // accodo nella conf... foreach (var item in chiaviTSVC) { codVal = item.Value.Split(':'); Enum.TryParse(codVal[0], out funz); int.TryParse(codVal[1], out periodo); currConf = new VCData() { Funzione = funz, Period = periodo, DTStart = DateTime.Now.AddHours(-1), dataArray = new List() }; TSVC_Data.Add(item.Key.Replace("TSVC_", ""), currConf); } // documento... foreach (var item in TSVC_Data) { lgTrace($"TSVC: {item.Key} | periodo: {item.Value.Period} | funz: {item.Value.Funzione}"); // salvo i valori PREC... LastTSVC.Add(item.Key, 0); } } } #endregion Public Constructors #region Protected Methods /// /// Effettua decodifica aree memoria alla bitmap usata x MAPO /// 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: emergenza * * * - BIT di stato * - DBX0.0: RUN STATE * - DBX0.1: CYCLE * - DBX0.2: MANUAL MODE * - DBX0.3: GENERAL ALARM * - DBX0.4: ESTOP (1=OK, 0 = emergency) * - DBX0.5: SAFETY DOORS ----------------------------------------------------- */ byte mainData = RawInput[0]; int byteSignals = 0; // bit 0 (poweron) imposto a 1 SE connected... if (currPLC.IsConnected) { byteSignals += (1 << 0); } if ((mainData & (1 << 0)) == 1) { byteSignals += (1 << 1); } // EMERGENZA if ((mainData & (1 << 5)) == 1) { byteSignals += (1 << 5); } // ALLARME if ((mainData & (1 << 3)) == 1) { byteSignals += (1 << 3); } // MANUALE ... if ((mainData & (1 << 2)) == 1) { byteSignals += (1 << 4); } // salvo! B_input = byteSignals; // log opzionale! if (verboseLog) { lgInfo(string.Format($"Trasformazione dati: RawInput:{RawInput[3]} --> B_input: {B_input}")); } } #endregion Protected Methods #region Public Methods /// /// Processo i task richiesti e li elimino dalla coda 1:1 /// /// public override Dictionary executeTasks(Dictionary task2exe) { // Verificare il protocollo: dovrebeb togliere SOLO i task eseguiti... Dictionary taskDone = new Dictionary(); bool taskOk = false; string taskVal = ""; string memAddrWrite = ""; if (task2exe != null) { // inizio VUOTO byte[] MemBlock = new byte[parametri.memSizeWrite]; // controllo su OPT_PAR se usare nuovo metodo exe task... if (useNewSend) { // 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.fixStopSetup: 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: case taskType.setComm: case taskType.setPzComm: saveProdData(item); // 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}"; } int byteSize = 0; // recupero dati da memMap... altrimenti NULLA if (memMap.mMapWrite.ContainsKey(item.Key)) { dataConf currMem = memMap.mMapWrite[item.Key]; byteSize = currMem.size; memAddrWrite = currMem.memAddr; MemBlock = new byte[byteSize]; if (currMem.tipoMem == plcDataType.String) { saveStringOnMemBlock(ref MemBlock, item.Key, 0, byteSize); } else if (currMem.tipoMem == plcDataType.DInt) { int valDInt = 0; int.TryParse(item.Value, out valDInt); MemBlock = S7.Net.Types.DInt.ToByteArray(valDInt); } else if (currMem.tipoMem == plcDataType.Int) { short valDInt = 0; short.TryParse(item.Value, out valDInt); MemBlock = S7.Net.Types.Int.ToByteArray(valDInt); } } taskVal = item.Value; break; case taskType.sendWatchDogMes2Plc: // processo scrittura BIT su DB150.DBX4.0 MemBlock = new byte[1]; memAddrWrite = "DB1002.DBB0"; // compogo in byte... primo bit è setup/run, ultimo è watchdog int valore = inSetup ? 1 : 0; valore += (byte)(counterMes2Plc << 7); MemBlock[0] = (byte)valore; taskVal = $"VALUE DB1002.92 --> {valore} | counter interno {counterMes2Plc}"; 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.startSetup: // salvo che SONO IN SETUP! inSetup = true; break; case taskType.stopSetup: // salvo che SONO FUORI DAL SETUP! inSetup = false; break; default: taskVal = "SKIPPED | NO EXEC"; break; } // 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}"); } } } else { // 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.fixStopSetup: case taskType.forceResetPzCount: case taskType.forceSetPzCount: case taskType.startSetup: case taskType.stopSetup: taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC"; break; case taskType.setArt: case taskType.setComm: case taskType.setProg: saveProdData(item); taskVal = item.Value; break; case taskType.sendWatchDogMes2Plc: // compogo in byte... primo bit è setup/run, ultimo è watchdog int valore = inSetup ? 1 : 0; valore += (byte)(counterMes2Plc << 7); MemBlock[0] = (byte)valore; taskVal = $"VALUE DB1002.92 --> {counterMes2Plc}"; 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; default: taskVal = "SKIPPED | NO EXEC"; break; } // aggiungo task! taskDone.Add(item.Key, taskVal); } // controllo SE HO da scrivere articolo/commessa/programma saveStringOnMemBlock(ref MemBlock, "setArt", 2, 22); saveStringOnMemBlock(ref MemBlock, "setComm", 24, 22); saveStringOnMemBlock(ref MemBlock, "setProg", 46, 22); // scrivo comunque! taskOk = S7WriteBB(ref MemBlock); } } return taskDone; } /// /// Recupero dati dinamici in formato dictionary /// /// public override Dictionary getDynData() { Dictionary outVal = new Dictionary(); // processing try { // le 3 posizioni sono in 1/10 mm x cui vanno divise x 10... x avere MM double RamPosition = S7.Net.Types.Int.FromByteArray(RawInput.Skip(18).Take(2).ToArray()) / 10; double LowerEjectorPosition = S7.Net.Types.Int.FromByteArray(RawInput.Skip(20).Take(2).ToArray()) / 10; double UpperTool = S7.Net.Types.Int.FromByteArray(RawInput.Skip(22).Take(2).ToArray()) / 10; // temp in °C int TempMainMotorU = S7.Net.Types.Int.FromByteArray(RawInput.Skip(24).Take(2).ToArray()); int TempMainMotorV = S7.Net.Types.Int.FromByteArray(RawInput.Skip(26).Take(2).ToArray()); int TempMainMotorW = S7.Net.Types.Int.FromByteArray(RawInput.Skip(28).Take(2).ToArray()); int TempSpindleNut = S7.Net.Types.Int.FromByteArray(RawInput.Skip(30).Take(2).ToArray()); int TempMotoModule = S7.Net.Types.Int.FromByteArray(RawInput.Skip(32).Take(2).ToArray()); int TempOilCirculation = S7.Net.Types.Int.FromByteArray(RawInput.Skip(34).Take(2).ToArray()); int TempHydraulicUnit = S7.Net.Types.Int.FromByteArray(RawInput.Skip(36).Take(2).ToArray()); // press in BAR int PressHydraulicPump = S7.Net.Types.Int.FromByteArray(RawInput.Skip(38).Take(2).ToArray()); int PressHydraulicAccumulator = S7.Net.Types.Int.FromByteArray(RawInput.Skip(40).Take(2).ToArray()); int PressCounterforceOil = S7.Net.Types.Int.FromByteArray(RawInput.Skip(42).Take(2).ToArray()); int PressCounterforceGas = S7.Net.Types.Int.FromByteArray(RawInput.Skip(44).Take(2).ToArray()); // forze in kN (10^3 Newton) int ForcePressureActual = S7.Net.Types.DInt.FromByteArray(RawInput.Skip(46).Take(4).ToArray()); int ForceOnBushing = S7.Net.Types.Int.FromByteArray(RawInput.Skip(50).Take(2).ToArray()); if (utils.CRB("enableTSVC")) { bool[] scaduti = new bool[16]; // salvo in stack le VC rilevate scaduti[0] = stackVal_TSVC("RamPosition", RamPosition); scaduti[1] = stackVal_TSVC("LowerEjectorPosition", LowerEjectorPosition); scaduti[2] = stackVal_TSVC("UpperTool", UpperTool); scaduti[3] = stackVal_TSVC("TempMainMotorU", TempMainMotorU); scaduti[4] = stackVal_TSVC("TempMainMotorV", TempMainMotorV); scaduti[5] = stackVal_TSVC("TempMainMotorW", TempMainMotorW); scaduti[6] = stackVal_TSVC("TempSpindleNut", TempSpindleNut); scaduti[7] = stackVal_TSVC("TempMotoModule", TempMotoModule); scaduti[8] = stackVal_TSVC("TempOilCirculation", TempOilCirculation); scaduti[9] = stackVal_TSVC("TempHydraulicUnit", TempHydraulicUnit); scaduti[10] = stackVal_TSVC("PressHydraulicPump", PressHydraulicPump); scaduti[11] = stackVal_TSVC("PressHydraulicAccumulator", PressHydraulicAccumulator); scaduti[12] = stackVal_TSVC("PressCounterforceOil", PressCounterforceOil); scaduti[13] = stackVal_TSVC("PressCounterforceGas", PressCounterforceGas); scaduti[14] = stackVal_TSVC("ForcePressureActual", ForcePressureActual); scaduti[15] = stackVal_TSVC("ForceOnBushing", ForceOnBushing); // verifico SE devo riportare dati VC if (baseUtils.CountTrue(scaduti) > 0) { RamPosition = getVal_TSVC_int("RamPosition", scaduti[0]); LowerEjectorPosition = getVal_TSVC_int("LowerEjectorPosition", scaduti[1]); UpperTool = getVal_TSVC_int("UpperTool", scaduti[2]); TempMainMotorU = getVal_TSVC_int("TempMainMotorU", scaduti[3]); TempMainMotorV = getVal_TSVC_int("TempMainMotorV", scaduti[4]); TempMainMotorW = getVal_TSVC_int("TempMainMotorW", scaduti[5]); TempSpindleNut = getVal_TSVC_int("TempSpindleNut", scaduti[6]); TempMotoModule = getVal_TSVC_int("TempMotoModule", scaduti[7]); TempOilCirculation = getVal_TSVC_int("TempOilCirculation", scaduti[8]); TempHydraulicUnit = getVal_TSVC_int("TempHydraulicUnit", scaduti[9]); PressHydraulicPump = getVal_TSVC_int("PressHydraulicPump", scaduti[10]); PressHydraulicAccumulator = getVal_TSVC_int("PressHydraulicAccumulator", scaduti[11]); PressCounterforceOil = getVal_TSVC_int("PressCounterforceOil", scaduti[12]); PressCounterforceGas = getVal_TSVC_int("PressCounterforceGas", scaduti[13]); ForcePressureActual = getVal_TSVC_int("ForcePressureActual", scaduti[14]); ForceOnBushing = getVal_TSVC_int("ForceOnBushing", scaduti[15]); //outVal.Add("DYNDATA", $"RamPosition {RamPosition:N2} | TempMainMotorV {TempMainMotorV:N2} | TempOilCirculation {TempOilCirculation:N2} | PressCounterforceGas {PressCounterforceGas}"); outVal.Add("RamPosition", $"{RamPosition:N1}"); outVal.Add("LowerEjectorPosition", $"{LowerEjectorPosition:N1}"); outVal.Add("UpperTool", $"{UpperTool:N1}"); outVal.Add("TempMainMotorU", $"{TempMainMotorU}"); outVal.Add("TempMainMotorV", $"{TempMainMotorV}"); outVal.Add("TempMainMotorW", $"{TempMainMotorW}"); outVal.Add("TempSpindleNut", $"{TempSpindleNut}"); outVal.Add("TempMotoModule", $"{TempMotoModule}"); outVal.Add("TempOilCirculation", $"{TempOilCirculation}"); outVal.Add("TempHydraulicUnit", $"{TempHydraulicUnit}"); outVal.Add("PressHydraulicPump", $"{PressHydraulicPump}"); outVal.Add("PressHydraulicAccumulator", $"{PressHydraulicAccumulator}"); outVal.Add("PressCounterforceOil", $"{PressCounterforceOil}"); outVal.Add("PressCounterforceGas", $"{PressCounterforceGas}"); outVal.Add("ForcePressureActual", $"{ForcePressureActual}"); outVal.Add("ForceOnBushing", $"{ForceOnBushing}"); // salvo! LastTSVC["RamPosition"] = RamPosition; LastTSVC["LowerEjectorPosition"] = LowerEjectorPosition; LastTSVC["UpperTool"] = UpperTool; LastTSVC["TempMainMotorU"] = TempMainMotorU; LastTSVC["TempMainMotorV"] = TempMainMotorV; LastTSVC["TempMainMotorW"] = TempMainMotorW; LastTSVC["TempSpindleNut"] = TempSpindleNut; LastTSVC["TempMotoModule"] = TempMotoModule; LastTSVC["TempOilCirculation"] = TempOilCirculation; LastTSVC["TempHydraulicUnit"] = TempHydraulicUnit; LastTSVC["PressHydraulicPump"] = PressHydraulicPump; LastTSVC["PressHydraulicAccumulator"] = PressHydraulicAccumulator; LastTSVC["PressCounterforceOil"] = PressCounterforceOil; LastTSVC["PressCounterforceGas"] = PressCounterforceGas; LastTSVC["ForcePressureActual"] = ForcePressureActual; LastTSVC["ForceOnBushing"] = ForceOnBushing; } else { outVal.Add("DYNDATA", $"RamPosition {LastTSVC["RamPosition"]:N1} | ForcePressureActual {LastTSVC["ForcePressureActual"]} | ForceOnBushing {LastTSVC["ForceOnBushing"]}"); } } else { outVal.Add("DYNDATA", $"RamPosition {LastTSVC["RamPosition"]:N1} | ForcePressureActual {LastTSVC["ForcePressureActual"]} | ForceOnBushing {LastTSVC["ForceOnBushing"]}"); } } catch (Exception exc) { lgError(exc, "Errore in getDynData x Siemens Aprochim"); } return outVal; } public override string getPrgName() { string answ = ""; try { string rawProdCode = S7.Net.Types.String.FromByteArray(RawInput.Skip(54).Take(12).ToArray()); // primi due char sono \f e \n avanzamento carta e nuova linea... answ = Regex.Replace(rawProdCode, @"\t|\n|\r|\f", ""); } catch (Exception exc) { lgError($"Errore in decodifica product code{Environment.NewLine}{exc}"); } return answ; } /// /// Effettua processing del recupero delle OVERRIDE (spindle, feedrate, rapid) /// public override void processOverride() { } public override void processWhatchDog() { // scrive nel primo byte, ultimo bit, il watchdog, mentre scrive nel primo 1 = setup, 0 = run // scrivo 1 volta al secondo il contatore incrementale su area apposita DateTime adesso = DateTime.Now; if (adesso.Subtract(lastPLCWatchDog).TotalSeconds > watchDogPeriod) { // incremento counterMes2Plc++; // se > 1 --> 0 (balla solo 0..1) if (counterMes2Plc > 1) counterMes2Plc = 0; // salvo su DB Dictionary task2exe = new Dictionary(); Dictionary taskDone = new Dictionary(); task2exe.Add("sendWatchDogMes2Plc", counterMes2Plc.ToString()); taskDone = executeTasks(task2exe); // salvo watchdog PLC lastPLCWatchDog = adesso; } } #endregion Public Methods } }