using CndexLinkDotNet; using IOB_UT; using MapoSDK; using System; using System.Collections.Generic; using System.Net; using System.Net.NetworkInformation; using EgwProxy.OsaiCncLib; namespace IOB_WIN { public class IobOSAI : IobGeneric { #region Private Fields /// /// LookUpTable di decodifica da CNC a segnali tipo bitmap MAPO /// private Dictionary signLUT = new Dictionary(); #endregion Private Fields #region Protected Fields /// /// Struttura dati principale in continuo update... /// protected Cndex.GETINFO1DATA oData; /// /// Oggetto MAIN x connessione OSAI /// protected ComCNOsai OSAI_ref; #endregion Protected Fields #region Public Fields /// /// Vettore degli allarmi CNC attivi /// public Dictionary allarmiCNC = new Dictionary(); /// /// Stato corrente (da classe ENUM) /// public CNC_STATUS_OSAI currStatus; #endregion Public Fields #region Public Constructors /// /// estende l'init della classe base... /// /// /// public IobOSAI(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf) { // gestione invio ritardato contapezzi pzCountDelay = utils.CRI("pzCountDelay"); lastPzCountSend = DateTime.Now; lastWarnODL = DateTime.Now; if (IOBConf != null) { // inizializzo correttamente aree memoria secondo CONF - iniFileName if (!string.IsNullOrEmpty(IOBConf.iniFileName)) { IniFile fIni = new IniFile(IOBConf.iniFileName); // fix enable prgName enablePrgName = fIni.ReadBoolean("CNC", "GETPRGNAME", true); // effettuo lettura della conf sigLUT... cercando 1:1 i bit... string currBit = ""; string memArea = ""; for (int i = 0; i < 8; i++) { currBit = string.Format("BIT{0}", i); memArea = fIni.ReadString("MEMORY", currBit, ""); // se trovo un valore... if (!string.IsNullOrEmpty(memArea)) { signLUT.Add(currBit, memArea); } } } } // è little endian (NON serve conversione) hasBigEndian = false; lgInfo("Start init Adapter OSAI, tipo all'IP/NOME {0}, variante {1} per IOB {2}", IOBConf.cncIpAddr, IOBConf.tipoIob, IOBConf.codIOB); // Creo oggetto x gestione connessione/comunicazione NC: secondo il tipo creo CNDEX o OPEN parentForm.commPlcActive = true; if (IOBConf.tipoIob == tipoAdapter.OSAI_OPEN) { OSAI_ref = new Open_Series(IOBConf.cncIpAddr, false); } else if (IOBConf.tipoIob == tipoAdapter.OSAI_VB6) { OSAI_ref = new ComCNOSAIVB6(IOBConf.cncIpAddr, false); } else { OSAI_ref = new ComCNOsai(IOBConf.cncIpAddr, false); } parentForm.commPlcActive = false; if (isVerboseLog) { lgInfo(string.Format("INIT OSAI_ref da EgwProxy.MultiCncLib come {0}", IOBConf.tipoIob)); } // disconnetto e connetto... if (isVerboseLog) { lgInfo("OSAI: tryDisconnect"); } tryDisconnect(); lgInfo("OSAI: tryConnect"); tryConnect(); // recupero machine status e mode da cui decodificare info sul PLC... byte machineStatus = OSAI_ref.GetMachineStatus(); byte modeSelected = OSAI_ref.GetModeSelected(); lgInfo(string.Format("Lettura preliminare: machineStatus={0} | modeSelected={1}", machineStatus, modeSelected)); // possiamo leggere tutto da qui che contiene status, mode e last_nc_error oData = new Cndex.GETINFO1DATA(); var ncInfo = OSAI_ref.NcInfo1(ref oData); lgInfo(string.Format("Lettura START completa NCINFO1DATA{0} lastNcError={1}{0}status={2}{0}substatus={9}{0}mode_select={3}{0}main_progr_name={4}{0}speed_ov={5}{0}progr_speed={6}{0}real_speed={7}{0}real_feed={8}{0}", Environment.NewLine, oData.last_nc_error, oData.status, oData.mode_select, oData.main_progr_name, oData.speed_ov, oData.progr_speed, oData.real_speed, oData.real_feed, oData.substatus)); // inizio il calcolo dello status semaforico short bitStatus = 0; if (OSAI_ref.Connected) { bitStatus += 1; } if (utils.CRB("enableContapezzi")) { lgInfo("OSAI: inizio gestione contapezzi"); try { // verifico quale modalità sia richiesta: STD (6711) oppure BIT (Custom, con indicazione area) if (cIobConf.optPar.Count > 0 && !string.IsNullOrEmpty(getOptPar("PZCOUNT_MODE"))) { if (getOptPar("PZCOUNT_MODE").StartsWith("OVAR")) { lgInfo("Init contapezzi OSAI: pzCntReload(true)"); pzCntReload(true); // refresh associazione Macchina - IOB sendM2IOB(); // per adesso imposto lettura dal CNC == contapezzi (poi farà vera lettura...) contapezziPLC = contapezziIOB; } else { contapezziIOB = 0; lgInfo("Contapezzi STD disabilitato: modalità {0}", getOptPar("PZCOUNT_MODE")); } } else { contapezziIOB = 0; lgInfo("Parametro mancante PZCOUNT_MODE"); } } catch (Exception exc) { lgError(exc, "Errore in contapezzi OSAI"); } } // finisco INIT ADAPTER lgInfo("End init Adapter OSAI"); } #endregion Public Constructors #region Private Methods /// /// Effettua decodifica aree memoria alla bitmap usata x MAPO /// private void decodeToBitmap() { // init a zero... B_input = 0; // SE SI E' CONNESSO al CNC allora è 1=powerON... if (OSAI_ref.Connected) { B_input += 1 << 0; } // decodifico impiegando dictionary... cercando il TIPO di memoria & co... string bKey = ""; string bVal = ""; for (int i = 0; i < 8; i++) { bKey = string.Format("BIT{0}", i); // cerco se ci sia in LUT if (signLUT.ContainsKey(bKey)) { // recupero nome variabile... bVal = signLUT[bKey]; // se l'area è PZCOUNT... processo PUNTUALMENTE il CONTAPEZZI... if (bVal.StartsWith("PZCOUNT")) { // 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(string.Format("Osai | Lettura ODL andata a vuoto: currODL: {0}", currODL)); } } else { lgInfo(string.Format("Osai | Lettura ODL, currODL: {0} --> currIdxODL prec: {1}", currODL, 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: {0}", urlGetCurrODL); lastWarnODL = DateTime.Now; } } } else { // imposto currODL a vuoto! currODL = ""; if (periodicLog) { lgInfo($"OSAI | Lettura ODL non effettuata: IobOnline: {IobOnline} | currODL impostato a vuoto"); } } if (!string.IsNullOrEmpty(currODL) && currODL != "0") { // controllo se è passato intervallo minimo tra 2 controlli/elaborazioni x distanziare invio e ridurre letture if (DateTime.Now >= lastPzCountSend.AddMilliseconds(pzCountDelay)) { // se sono differenti MOSTRO... if (contapezziPLC != contapezziIOB) { // registro contapezzi lgInfo($"Differenza Contapezzi: contapezziPLC: {contapezziPLC} | contapezziIOB {contapezziIOB}"); } // verifico se variato contapezzi in area STD PAR6711... e se passato ritardo minimo... 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 OSAI: {contapezziPLC} | contapezziIOB {contapezziIOB}"); } // invio a server contapezzi (aggiornato) string retVal = utils.callUrl(urlSetPzCount + contapezziIOB.ToString()); // verifica se tutto OK if (retVal.Trim() != $"{contapezziIOB}") { // errore salvataggio contapezzi lgInfo($"Errore salvataggio Contapezzi OSAI: urlSetPzCount: {urlSetPzCount} | 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 OSAI: {contapezziPLC} | contapezziIOB {contapezziIOB}"); // resetto timer... lastPzCountSend = DateTime.Now; } } } // controllo le condizioni x costruire il bit1 RUN! if (oData.mode_select == 2 && oData.status == 2) { B_input += 1 << 1; } // errore su bit3 if (oData.mode_select == 6) { B_input += 1 << 3; } // auto su bit4 if (oData.mode_select != 2) { B_input += 1 << 4; } // emergenza su bit5 if (oData.mode_select == 9) { B_input += 1 << 5; } } } // log opzionale! if (verboseLog) { lgInfo(string.Format("Trasformazione B_input: {0}", B_input)); } } #endregion Private Methods #region Protected Methods /// /// Decodifica del MODE selezionato /// /// /// protected static CNC_MODE decodeModeOsai(int mode) { CNC_MODE answ = CNC_MODE.ND; switch (mode) { case 1: answ = CNC_MODE.MDI; break; case 2: answ = CNC_MODE.AUTO; break; case 3: answ = CNC_MODE.SEMI; break; case 4: answ = CNC_MODE.JOG_MAN; break; case 5: answ = CNC_MODE.JOG_INC; break; case 6: answ = CNC_MODE.PROFILE; break; case 7: answ = CNC_MODE.HOME; break; case 8: answ = CNC_MODE.HANDLE_INC; break; default: break; } return answ; } #endregion Protected Methods #region Public Methods /// /// Recupera e processa allarmi CNC... /// public override Dictionary getCncAlarms() { Dictionary outVal = new Dictionary(); // se ho allarmi li accodo... if (oData.last_nc_error != 0) { try { outVal.Add("CNC_ALARM", (oData.last_nc_error).ToString()); } catch (Exception exc) { lg.Error(exc, "Eccezione in getCncAlarms"); } } return outVal; } /// /// Recupero dati dinamici... /// public override Dictionary getDynData() { Dictionary outVal = new Dictionary(); stopwatch.Restart(); try { string actf = oData.real_feed.ToString(); string acts = oData.real_speed.ToString(); 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); outVal.Add("ACT_TOOL", oData.actual_tool.ToString()); } if (utils.CRB("SendAxPos")) { // salvo info assi... outVal.Add("AX_SEL", oData.ax_sel.ToString()); outVal.Add("NUM_AX_SEL", oData.num_ax_sel.ToString()); } } catch (Exception exc) { lgError(exc, "Errore in getDynData"); } stopwatch.Stop(); return outVal; } /// /// Recupero dati override (da area G che è già stata letta...) /// /// public override Dictionary getOverrides() { Dictionary outVal = new Dictionary(); outVal.Add("FEED_OVER", (oData.feed_ov).ToString()); outVal.Add("RAPID_OVER", (oData.rapid_override).ToString()); return outVal; } /// /// Recupero programma in lavorazione /// /// public override string getPrgName() { string prgName = ""; // recupero NUOVO prgName... try { // recupero nome programma MAIN prgName = System.Text.Encoding.Default.GetString(oData.main_progr_name); // trimmo path del programma, ovvero "CNCMEMUSERPATH1" prgName = prgName.Replace(utils.CRS("basePrgMemPath"), ""); lgInfo("Current PROG: {0}", prgName); } catch (Exception exc) { lgError(string.Format("Eccezione in recupero PRG NAME MAIN:{0}{1}", Environment.NewLine, exc)); connectionOk = false; } return prgName; } /// /// Effettua vero processing contapezzi appoggiato ad area specifica da CONF /// public override void processContapezzi() { if (utils.CRB("enableContapezzi")) { try { // verifico quale modalità sia richiesta: STD (6711) oppure BIT (Custom, con indicazione area) if (cIobConf.optPar.Count > 0 && !string.IsNullOrEmpty(getOptPar("PZCOUNT_MODE"))) { string memAddr = getOptPar("PZCOUNT_MODE"); if (memAddr.StartsWith("STD")) { // inizio verifica area memoria/parametro levando prima parte codice memAddr = memAddr.Replace("STD.", ""); // var di appoggio int cntAddr = 0; // verifico se si tratta di lettura MEMORIA... formato tipo STD.MEM.6711 if (memAddr.StartsWith("MEM.")) { // recupero parametro... int.TryParse(memAddr.Replace("MEM.", ""), out cntAddr); if (cntAddr == 0) { cntAddr = 29; } // processo parametro contapezzi (lavorati) stopwatch.Restart(); // vera lettura area memoria... int resVal = 0; // lettura variabili (es contapezzi) resVal = (int)OSAI_ref.ReadVarSN((short)cntAddr); if (utils.CRB("recTime")) { TimingData.addResult(cIobConf.codIOB, string.Format("R{0}-MEM", 2), stopwatch.ElapsedTicks); } // aggiungo in visualizzazione SE variata... if (resVal != contapezziPLC) { string mCount = string.Format("MEM{0}", cntAddr); string sVal = string.Format("[PZCOUNT]{0}|{1}", mCount, resVal); // chiamo accodamento... accodaFLog(sVal, qEncodeFLog(mCount, resVal.ToString())); } // salvo ultimo conteggio rilevato contapezziPLC = resVal; } stopwatch.Stop(); } } } catch (Exception exc) { lgError(exc, "Errore in contapezzi CNC"); connectionOk = false; } } } /// /// Esegue processing MODE (e nel contempo recupera altri dati dell'area G) /// public override void processMode() { if (utils.CRB("enableMode")) { try { // verifico modo con valore corrente, se cambia aggiorno... CNC_MODE newMode = decodeModeOsai(oData.mode_select); 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, string.Format("Errore in process Mode OSAI: {0}{1}", Environment.NewLine, exc)); connectionOk = false; stopwatch.Stop(); } } // lo status lo processo SEMPRE try { // verifico modo con valore corrente, se cambia aggiorno... CNC_STATUS_OSAI newStatus = (CNC_STATUS_OSAI)(oData.status); if (newStatus != currStatus) { // aggiorno! currStatus = newStatus; // accodo x invio string sVal = string.Format("[CNC_STATUS]{0}", currStatus.ToString()); // chiamo accodamento... accodaFLog(sVal, qEncodeFLog("CNC_STATUS", currStatus.ToString())); } } catch (Exception exc) { lgError(exc, string.Format("Errore in process Mode OSAI: {0}{1}", Environment.NewLine, exc)); connectionOk = false; stopwatch.Stop(); } } /// /// Effettua lettura semafori principale /// Parametri da aggiornare x display in form /// public override void readSemafori(ref newDisplayData currDispData) { base.readSemafori(ref currDispData); try { if (verboseLog) { lgInfo("inizio read semafori"); } currDispData.semIn = Semaforo.SV; stopwatch.Restart(); // possiamo leggere tutto da qui che contiene tutto: status, mode, last_nc_error var ncInfo = OSAI_ref.NcInfo1(ref oData); // time rec if (utils.CRB("recTime")) { TimingData.addResult(cIobConf.codIOB, "GETINFO1DATA", stopwatch.ElapsedTicks); } stopwatch.Stop(); // salvo il solo BYTE dell'input decifrando il semaforo... decodeToBitmap(); } catch (Exception exc) { lgError(string.Format("Eccezione in readSemafori:{0}{1}", Environment.NewLine, exc)); connectionOk = false; currDispData.semIn = Semaforo.SR; } } /// /// Override connessione /// public override void tryConnect() { if (!connectionOk) { // controllo che il ping sia stato tentato almeno pingTestSec fa... if (DateTime.Now.Subtract(lastPING).TotalSeconds > utils.CRI("pingTestSec")) { if (verboseLog || periodicLog) { lgInfo("OSAI: ConnKO - tryConnect"); } // PING SOLO x OPEN!!! bool needPing = (cIobConf.tipoIob == tipoAdapter.OSAI_OPEN); bool pingOk = false; Ping pingSender = new Ping(); PingReply reply = pingSender.Send("127.0.0.1", 100); // se serve PING... if (needPing) { // in primis salvo data ping... lastPING = DateTime.Now; // ora PING!!! IPAddress address = IPAddress.Loopback; IPAddress.TryParse(cIobConf.cncIpAddr, out address); reply = pingSender.Send(address, 100); pingOk = reply.Status == IPStatus.Success; } // se passa il ping faccio il resto... if (pingOk || !needPing) { string szStatusConnection = ""; try { // ora provo connessione... parentForm.commPlcActive = true; bool fatto = OSAI_ref.OpenSession(); if (!fatto) { // log errore! lgInfo("Impossibile effettuare apertura sessione: " + OSAI_ref.ErrMsg); } parentForm.commPlcActive = false; lgInfo("szStatusConnection: " + szStatusConnection); connectionOk = true; // refresh stato allarmi!!! if (connectionOk) { AvvioAdp = DateTime.Now; if (adpRunning) { lgInfo("Connessione OK"); } } else { lgError("Impossibile procedere, connessione mancante..."); } } catch (Exception exc) { lgFatal(string.Format("Errore nella connessione all'adapter OSAI: {0}{1}{2}", szStatusConnection, Environment.NewLine, exc)); connectionOk = false; lgInfo(string.Format("Eccezione in TryConnect, Adapter NON running, pausa di {0} msec prima di ulteriori tentativi di riconnessione", utils.CRI("waitRecMSec"))); } } else { // loggo no risposta ping ... connectionOk = false; if (needPing) { if (verboseLog || periodicLog) { lgInfo(string.Format("Attenzione: controllo PING fallito per IP {0} - {1}", cIobConf.cncIpAddr, reply.Status)); } } } } } // se non è ancora connesso faccio procesisng memoria caso disconnesso... if (!connectionOk) { // processo semafori ed invio... processMemoryDiscon(); } } /// /// Override disconnessione /// public override void tryDisconnect() { if (connectionOk) { string szStatusConnection = ""; try { OSAI_ref.CloseSession(); connectionOk = false; // resetto timing! TimingData.resetData(); lgInfo(szStatusConnection); lgInfo("Effettuata disconnessione adapter OSAI!"); } catch (Exception exc) { lgFatal(exc, "Errore nella disconnessione dall'adapter OSAI"); } } else { lgError("IMPOSSIBILE effettuare disconnessione: Connessione non disponibile..."); } } #endregion Public Methods } }