using IOB_UT_NEXT; using MapoSDK; using System; using System.Collections.Generic; using System.Linq; namespace IOB_WIN_NEXT { public class IobSiemensTorri : IobSiemens { /* -------------------------------------------------------------------------------- * 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 * -------------------------------------------------------------------------------- */ #region Protected Fields protected Dictionary lastReadAlarms = new Dictionary(); #endregion Protected Fields #region Public Constructors /// /// estende l'init della classe base con i metodi x Siemens specifici x Torri /// /// /// public IobSiemensTorri(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf) { // dovebbe fare init della classe base, VERIFICARE... lgInfo("NEW IOB SIEMENS versione TORRI"); } #endregion Public Constructors #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() { // leggo i banchi allarmi : cablato D700.DBDW2 --> D700 DBDW14, sono 4 banchi a 32 bit da verificare int trovati = 0; // ciclo nei 4 banchi... trovati += checkAlarmBank("DB700.DBDW2"); trovati += checkAlarmBank("DB700.DBDW6"); trovati += checkAlarmBank("DB700.DBDW10"); trovati += checkAlarmBank("DB700.DBDW14"); } #endregion Private Methods #region Protected Methods /// /// Decodifica il resto dell'area TORRI x i dati accessori (allarmi, ...) /// protected override void decodeOtherData() { if (verboseLog) { } } /// /// Effettua decodifica aree memoria alla bitmap usata x MAPO /// 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 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 = ""; // 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; } /// /// Recupera ULTIMO allarme... /// /// public override Dictionary getCncAlarms() { // parto da ultimo vettore allarmi rilevato Dictionary 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(); return outVal; } /// /// Recupero dati dinamici... /// public override Dictionary getDynData() { Dictionary outVal = new Dictionary(); #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; } /// /// Recupero dati override in formato dictionary /// /// public override Dictionary getOverrides() { Dictionary outVal = new Dictionary(); 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; } /// /// Recupero programma in lavorazione /// /// 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; } /// /// 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 /// /// public override Dictionary getSysInfo() { Dictionary outVal = new Dictionary(); 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; } /// /// Esegue processing MODE (e nel contempo recupera altri dati dell'area G) /// 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 } } /// /// Override salvataggio valori in memoria... /// /// tipo di DUMP public override void saveMemDump(dumpType tipo) { } #endregion Public Methods } }