using IOB_UT; using Newtonsoft.Json; using NLog; using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Net; using System.Net.NetworkInformation; namespace IOB_WIN { public class IobGeneric { #region variabili ed oggetti base /// /// Indicazione VETO invio a server sino alla data-ora indicata /// public static DateTime dtVetoPing = DateTime.Now; /// /// Contapezzi attuale /// protected Int32 contapezzi; /// /// Ultima lettura variabile contapezzi da CNC /// protected Int32 lastCountCNC; /// /// ODL attualmente sulla macchina /// public Int32 currIdxODL; /// /// Ultimo invio contapezzi (x invio delayed) /// protected DateTime lastPzCountSend; /// /// Ultima registrazione warning x ODL mancante (x scrivere solo ogni 15 secondi) /// protected DateTime lastWarnODL; /// /// Ritardo minimo x invio contapezzi /// protected int pzCountDelay; /// /// Abilitazione lettura PrgName /// public bool enablePrgName = true; /// /// Indica se si debba leggere e fare DUMP delle aree di memoria (1 volta solo all'avvio x debug...) /// public bool doStartMemDump; /// /// Indica se sia richiesto campionamento memoria PERIODICO /// public bool doSampleMemory; /// /// Evento Iob ha subito un refresh /// public event EventHandler eh_refreshed; /// /// Determina se sia encessario convertire valori little/big endian (SIEMENS=true, OSAI=FALSE) /// public bool hasBigEndian = false; /// /// alias booleano false = R /// public bool R = false; /// /// alias booleano true = W /// public bool W = true; /// /// wrapper di log /// protected static Logger lg; /// /// ULtimo valore inviato (in caso di disconnessione lo reinvia x garantire watchdog...) /// public string lastSignInVal = ""; /// /// dataOra ultimo log periodico... /// public DateTime lastPeriodicLog; /// /// dataOra ultimo segnale inviato... /// public DateTime lastWatchDog; /// /// dataOra ultima verifica CNC disconnesso... /// public DateTime lastDisconnCheck; /// /// dataOra ultimo PING inviato... /// public DateTime lastPING; /// /// Oggetto della coda degli elementi letti (e non ancora trasmessi) /// public Queue QueueIN = new Queue(); /// /// Oggetto della coda degli elementi letti di tipo FluxLog (e non ancora trasmessi) /// public Queue QueueFLog = new Queue(); /// /// Coda valori simulazione deterministica... /// public Queue QueueSIM = new Queue(); /// /// Coda valori letti x DEBUG... /// public Queue QueueDebug = new Queue(); /// /// valore booleano di check se sia in fase di COMUNICAZIONE ATTIVA con il PLC/NC /// protected bool adpCommAct; /// /// valore booleano di check se sia stato AVVIATO l'adapter (Running) /// public bool adpRunning = false; /// /// valore booleano di check se l'adapter STIA SALVANDO /// public bool adpSaving = false; /// /// valore booleano (richiesta di riavvio automatico) /// public bool adpTryRestart; /// /// Verifica se sia in modalità DEMO --> da tipo IOB SIMULA... /// public bool DemoIn { get { return (cIobConf.tipoIob == tipoAdapter.SIMULA);// baseUtils.CRB("DemoIn"); } } /// /// Verifica se sia in modalità DEMO avanzata (campionamento da set di valori ammessi...) /// public bool DemoInSample { get { return baseUtils.CRB("DemoInSample"); } } /// /// Numero simulazioni ammesse... /// protected int numSim { get; set; } /// /// Numero letture IN da avvio /// protected int nReadIN { get; set; } /// /// Numero letture IN da avvio /// protected int nReadFilt { get; set; } /// /// Numero invii OUT (svuotamento coda) /// protected int nSendOut { get; set; } /// /// Verifica se sia in modalità DEMO x dati OUTPUT /// public bool DemoOut { get { return utils.CRB("DemoOut"); } } /// /// Contatore x invio dati SignalIN /// public int counterSigIN { get; set; } /// /// Contatore x invio dati FluxLog /// public int counterFLog { get; set; } /// /// Ultimo URL /// public string lastUrl { get; set; } /// /// Ultimo programma letto /// public string lastPrgName { get; set; } /// /// Ultimo SysInfo letto /// public string lastSysInfo { get; set; } /// /// Ultimo DynData letto /// public string lastDynData { get; set; } /// /// Ultimo Alarm letto /// public string lastAlarm { get; set; } /// /// Ultimo Override set letto /// public string lastOverrideFS { get; set; } /// /// Ultimo Override set letto /// public string lastOverrideRapid { get; set; } /// /// Array dei contatori x segnali blinking /// protected int[] i_counters; /// /// Vettore 16 BIT valori precedenti /// protected int B_previous; /// /// Vettore 16 BIT valori in ingresso al filtro /// protected int B_input; /// /// Vettore 16 BIT valori in uscita dal filtro /// protected int B_output; /// /// 32 byte input base (es strobe, 8 word da 32 bit di flags...) /// public byte[] RawInput = new byte[32]; /// /// 32 byte output base (es ack, 8 word da 32 bit di flags...) /// public byte[] RawOutput = new byte[32]; /// /// Modo corrente (da classe ENUM) /// public CNC_MODE currMode; /// /// Verifica SE si debba fare log verboso (verboso + ogni tot letture IN) /// public bool verboseLog { get { bool answ = false; int logEvery = utils.CRI("logEvery"); if (logEvery < 1) { logEvery = 10; } answ = utils.CRB("verbose") && (nReadIN % logEvery == 0); return answ; } } /// /// Verifica SE si debba fare log periodico (ogni "verboseLogTOut" sec...) /// public bool periodicLog { get { bool answ = false; answ = (DateTime.Now.Subtract(lastPeriodicLog).TotalSeconds > utils.CRI("verboseLogTOut")); if (answ) { lastPeriodicLog = DateTime.Now; } return answ; } } /// /// Determina se utilizzare blocchi di memoria IOT contigui (e quindi processing "monoblocco" semplificato"= /// public bool procIotMem = false; /// /// porta x adapter (x restart) /// protected int adpPortNum; /// /// DataOra ultimo avvio adapter x watchdog /// protected DateTime adpStartRun; /// /// Data/ora ultimo avvio adapter /// public DateTime dtAvvioAdp = DateTime.Now; /// /// Data/ora ultimo spegnimento adapter /// public DateTime dtStopAdp = DateTime.Now; /// /// Oggetto cronometro x campionamento durate chiamate /// public Stopwatch stopwatch = new Stopwatch(); /// /// Conteggio ATTUALE ore macchina ON /// public double contOreMaccOn; /// /// Conteggio ATTUALE ore macchina IN LAVORO /// public double contOreMaccLav; /// /// stato Online/Offline della IOB /// public bool IobOnline; /// /// stato Online/Offline della IOB /// public bool MPOnline; /// /// Dizionario di VC da trattare come TimeSeries (con conf decodificata + processing successivo...) /// protected Dictionary TSVC_Data = new Dictionary(); #endregion /// /// Form chiamante /// protected AdapterForm parentForm; /// /// Conf adapter corrente /// public IobConfiguration cIobConf; /// /// indica se serva refresh parametri e quindi PLC... /// protected bool needRefresh = true; /// /// inizializzo l'oggetto sulla form SULLA BASE DEL FILE DI CONFIGURAZIONE letto /// /// /// public IobGeneric(AdapterForm caller, IobConfiguration IOBConf) { // configurazione... cIobConf = IOBConf; // aggiungo nel logger IDX Macchina lg = LogManager.GetCurrentClassLogger(); lgInfo("Avvio preliminare AdapterGeneric"); // aggiungo altri defaults setDefaults(true); // salvo il form chiamante parentForm = caller; // checkLogDir x shrink! checkShrinkDir(); // concluso! lgInfo("Istanziata classe preliminare IOBGeneric"); } /// /// Imposto alcuni valori di default /// /// indica se sia richeisto di SVUOTARE le code delel info private void setDefaults(bool resetQueue) { numSim = utils.CRI("numSim"); lastPrgName = ""; nReadIN = 0; nReadFilt = 0; nSendOut = 0; currMode = 0; lastAlarm = ""; doStartMemDump = utils.CRB("doStartMemDump"); doSampleMemory = utils.CRB("doSampleMemory"); // svuoto code se richiesto if (resetQueue) { QueueIN.Clear(); QueueFLog.Clear(); QueueSIM.Clear(); } // imposto contatori blink a zero... i_counters = new int[32]; lastPeriodicLog = DateTime.Now; // fix parametri generali... enablePrgName = true; } /// /// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere... /// /// protected void lgInfo(string message) { lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB; lg.Info(message); } /// /// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere... /// /// /// protected void lgInfo(string message, params object[] args) { lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB; lg.Info(message, args); } /// /// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere... /// /// protected void lgError(string message) { lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB; lg.Error(message); } /// /// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere... /// /// /// protected void lgError(string message, params object[] args) { lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB; lg.Error(message, args); } /// /// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere... /// /// /// /// protected void lgError(Exception exception, string message, params object[] args) { lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB; lg.Error(exception, message, args); } /// /// Effettua logging FATAL corretto impostanto anche la variabile IOB prima di scrivere... /// /// protected void lgFatal(string message) { lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB; lg.Fatal(message); } /// /// Effettua logging FATAL corretto impostanto anche la variabile IOB prima di scrivere... /// /// /// protected void lgFatal(string message, params object[] args) { lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB; lg.Fatal(message, args); } /// /// Effettua logging FATAL corretto impostanto anche la variabile IOB prima di scrivere... /// /// /// /// protected void lgFatal(Exception exception, string message, params object[] args) { lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB; lg.Fatal(exception, message, args); } #region metodi adapter /// /// Invia informazioni associazione IOB 2 machine /// protected void sendM2IOB() { if (checkServerAlive) { lgInfo("chiamata URL " + urlSetM2IOB); utils.callUrl(urlSetM2IOB); } } /// /// Chiede elenco dei task da eseguire /// - formato Json /// - array di KVP / Dictionary /// - formato definito da API x MP/IO/: /// - KEY: task /// - VALUE: array JSon KVP /// protected string getTask2exe() { string answ = ""; if (checkServerAlive) { string url2call = $"{urlGetTask2Exe}"; lgInfo("chiamata URL " + url2call); answ = utils.callUrl(url2call); } return answ; } /// /// Cancella dal server i task eseguiti /// protected string remTask2exe(string taskName) { string answ = ""; if (checkServerAlive) { string url2call = $"{urlRemTask2Exe}{taskName}"; lgInfo("chiamata URL " + url2call); answ = utils.callUrl(url2call); } return answ; } /// /// Invia al server IO i valori dei parametri opzionali (es counters) /// /// Nome parametro /// Valore parametro protected void sendOptVal(string paramName, string paramValue) { if (checkServerAlive) { string url2call = $"{urlSetOptVal}pName={paramName}&pValue={paramValue}"; lgInfo("chiamata URL " + url2call); utils.callUrl(url2call); } } /// /// Invia al server IO i valori dei parametri opzionali (es counters) /// /// Nome parametro /// Valore parametro INT protected void sendOptVal(string paramName, int paramValueInt) { // override! sendOptVal(paramName, paramValueInt.ToString()); } /// /// Effettua rilettura del contapezzi dal server MP/IO /// /// Forza rilettura da DB tempi ciclo rilevati protected void pzCntReload(bool forceCountRec) { // legge da IO server ULTIMO valore CONTPEZZI al riavvio... string currServerCount = ""; string lastIdxODL = ""; if (checkServerAlive) { // se ho valori in coda da trasmettere uso dati REDIS if (QueueIN.Count > 0 && !forceCountRec) { currServerCount = utils.callUrl(urlGetPzCount); lgInfo("Lettura contapezzi dall'url {0}", urlGetPzCount); } // altrimenti uso dati da TCiclo registrati... else { // leggo PRIMA ODL .... lastIdxODL = utils.callUrl(urlGetCurrODL); lgInfo("Lettura ODL dall'url {0} --> {1}", urlGetPzCountRec, lastIdxODL); // POI leggo i pezzi currServerCount = utils.callUrl(urlGetPzCountRec); lgInfo("Lettura contapezzi da TCiclo dall'url {0} --> num pz: {1}", urlGetPzCountRec, currServerCount); } // controllo: SE NON HO ODL... if (lastIdxODL == "" || lastIdxODL == "0") { // NON AGGIORNO contapezzi = lastCountCNC; lgInfo(string.Format("Errore lettura ODL: {0} - uso lastCountCNC --> {1}", lastIdxODL, contapezzi)); } else { if (currServerCount != "") { // se "-1" resto a ultimo... if (currServerCount != "-1") { int.TryParse(currServerCount, out contapezzi); lgInfo("Ricevuta conferma da server di {0} pezzi registrati per ODL", currServerCount); } else { // NON AGGIORNO contapezzi = lastCountCNC; lgInfo("Errore lettura contapezzi (-1) - uso lastCountCNC --> " + contapezzi); } } else { // registro che ho UN NUOVO ODL lgInfo(string.Format("Lettura ODL in pzCntReload, {0} --> {1}", currIdxODL, lastIdxODL)); // provo a salvare nuovo ODL int.TryParse(lastIdxODL, out currIdxODL); // segno contapezzi a zero... contapezzi = 0; lgInfo("RESET contapezzi (ZERO)"); } } } else { // se server NON pronto... contapezzi = lastCountCNC; lgError("Errore server NON pronto in pzCntReload"); } } /// /// Avvia l'adapter sulla porta richiesta /// /// indica se sia richeisto di SVUOTARE le code delel info public virtual void startAdapter(bool resetQueue) { lgInfo("Starting adapter..."); parentForm.commPlcActive = false; adpRunning = true; dtAvvioAdp = DateTime.Now; lastWatchDog = dtAvvioAdp; lastPING = dtAvvioAdp; lastDisconnCheck = dtAvvioAdp; TimingData.resetData(); // aggiungo altri defaults setDefaults(resetQueue); adpTryRestart = true; parentForm.displayTaskAndLog("Adapter Started!"); } /// /// ferma l'adapter... /// /// indica se si debba tentare di riavviare l'adapter (con caduta connessione viene fermato in automatico) /// indica se sia richeisto di SVUOTARE le code delel info public void stopAdapter(bool tryRestart, bool forceDequeue) { if (forceDequeue) { // svuoto le code dei valori letti e non ancora trasmessi... parentForm.displayTaskAndLog("Svuotamento FORZATO coda segnali..."); while (QueueIN.Count > 0) { // INVIO COMUNQUE...!!! sendToMoonPro(urlType.SignIN, QueueIN.Dequeue()); } parentForm.displayTaskAndLog("Svuotamento FORZATO coda FluxLOG..."); while (QueueFLog.Count > 0) { // INVIO COMUNQUE...!!! sendToMoonPro(urlType.FLog, QueueFLog.Dequeue()); } } parentForm.displayTaskAndLog("Stopping adapter..."); adpTryRestart = false; parentForm.displayTaskAndLog("Stopping adapter - last periodic data read..."); // chiudo la connessione all'adapter... tryDisconnect(); dtStopAdp = DateTime.Now; adpTryRestart = tryRestart; adpRunning = false; // chiudo! parentForm.displayTaskAndLog("Adapter Stopped."); parentForm.commPlcActive = false; } /// /// effettua recupero dati ed invio valori modificati... /// /// public void getAndSend(gatherCycle ciclo) { // IN OGNI CASO a prima di tutto EFFETTUO GESTIONE INVII dati da code!!! try { // gestione queue SignalIN (invio, display) svuotaCodaSignIN(); // gestione queue FluxLog (invio, display) svuotaCodaFLog(); } catch (Exception exc) { lgError(exc, "Errore in gestione svuotamento/invio preliminare code memoria"); } // controllo connessione/connettività if (connectionOk) { // controllo non sia già in esecuzione... if (!adpCommAct) { // provo ad avviare try { // imposto flag adapter running.. adpCommAct = true; adpStartRun = DateTime.Now; } catch (Exception exc) { parentForm.displayTaskAndLog(string.Format("Adapter NOT STARTED!!!{0}{1}", Environment.NewLine, exc)); adpCommAct = false; adpStartRun = DateTime.Now; } if (adpCommAct) { // try / catch generale altrimenti segno che è disconnesso... try { bool showDebugData = false; if (ciclo == gatherCycle.VHF) { processVHF(); } // processing dati memoria (lettura, filtraggio, enqueque) else if (ciclo == gatherCycle.HF) { processAllMemory(); processMode(); } else if (ciclo == gatherCycle.MF) { processServerRequests(); processOverride(); processContapezzi(); processCncAlarms(); processDynData(); } else if (ciclo == gatherCycle.LF) { processOtherCounters(); processProgram(); } else if (ciclo == gatherCycle.VLF) { if (utils.CRB("enableContapezzi")) { // rilettura contapezzi da server... SE ABILITATA pzCntReload(false); // refresh associazione Macchina - IOB sendM2IOB(); } // recupero dati SETUP (sysinfo) e li invio/mostro se variati... processSysInfo(); // checkLogDir x shrink! checkShrinkDir(); // eventuale log! if (utils.CRB("recTime")) { logTimeResults(); } } // mostra eventuali altri dati di processo... reportDataProc(); if (showDebugData) { // verifica se debba salvare e mostrare dati checkSavePersDataLayer(); } } catch (Exception exc) { // segnalo eccezione e indico disconnesso... lgError(exc, string.Format("Errore in gestione ciclo principale ADP, fermo adapter{0}{1}", Environment.NewLine, exc)); parentForm.fermaAdapter(true, false); } // tolgo flag running adpCommAct = false; } else { if (periodicLog) { lgInfo("ADP not running..."); } } } else { // log ADP running lgError("Non eseguo chiamata: ADP ancora in running"); // se è bloccato da oltre maxSec lo sblocco... if (DateTime.Now.Subtract(adpStartRun).TotalSeconds > utils.CRI("maxAdapterLockSec")) { // tolgo flag running adpCommAct = false; adpStartRun = DateTime.Now; } } } else { // provo a riconnettere SE abilitato tryRestart... if (adpTryRestart && !connectionOk) { tryConnect(); } } // segnalo refresh! if (eh_refreshed != null) { eh_refreshed(this, new EventArgs()); } } /// /// Effettua ciclo controllo richieste server /// public void processServerRequests() { Dictionary task2exe = new Dictionary(); Dictionary taskDone = new Dictionary(); // recupero elenco delle cose da fare string resp = getTask2exe(); if (resp != "") { try { task2exe = JsonConvert.DeserializeObject>(resp); // se ho da fare chiamo esecuzione.. if (task2exe.Count > 0) { // chiamo procedura esecutiva (diversa x ogni IOB) taskDone = executeTasks(task2exe); } // ora chiamo la cancellazione dei task eseguiti... foreach (var item in taskDone) { remTask2exe(item.Key); } } catch { } } } /// /// Esecuzione dei task richiesti e pulizia coda richieste eseguite /// /// public virtual Dictionary executeTasks(Dictionary task2exe) { // Verificare il protocollo: dovrebeb togliere SOLO i task eseguiti... Dictionary taskDone = new Dictionary(); bool taskOk = false; string taskVal = ""; // cerco task specifici: se ho startSetup --> imposto bit DBB701.DBB0.4 foreach (var item in task2exe) { taskOk = false; taskVal = ""; // controllo sulal KEY switch (item.Key) { case "startSetup": // reset contapezzi inizio setup taskOk = resetContapezziCNC(); taskVal = taskOk ? "RESET: SETUP START" : "PZ RESET DISABLED | NO EXEC"; break; case "stopSetup": // reset contapezzi fine setup taskOk = resetContapezziCNC(); taskVal = taskOk ? "RESET: SETUP END" : "PZ RESET DISABLED | NO EXEC"; break; default: // anche se non faccio nulla SEGNO con value = SKIPPED taskVal = "SKIPPED | NO EXEC"; break; } taskDone.Add(item.Key, taskVal); } return taskDone; } /// /// Metodo generico di reset contapezzi... /// /// public virtual bool resetContapezziCNC() { return false; } /// /// Verifica e se necessario comprime directory log... /// private void checkShrinkDir() { string path = string.Format("{0}logs\\{1}", AppDomain.CurrentDomain.BaseDirectory, cIobConf.codIOB); baseUtils.shrinkDir(path); } private void reportDataProc() { // update valori visualizzazione... parentForm.dataProcLabel = string.Format("RAW: {0} --> IN: {1} --> OUT: {2}", nReadIN, nReadFilt, nSendOut); } /// /// riporta il log di tutti i dati di results temporali registrati /// public void logTimeResults() { if (TimingData.results.Count > 0) { lgInfo("{0}--------------- START TIMING DATA ---------------", Environment.NewLine); int globNumCall = 0; TimeSpan globAvgMsec = new TimeSpan(0); foreach (TimeRec item in TimingData.results) { // loggo SOLO se del mio IOB corrente... if (item.classCall == cIobConf.codIOB) { lgInfo("{4}|Chiamate {0}: effettuate {1}, tempo medio {2:N2} msec | impegno canale {3:P3}", item.codCall, item.numCall, item.avgMsec, item.totMsec.TotalSeconds / DateTime.Now.Subtract(dtAvvioAdp).TotalSeconds, cIobConf.codIOB); globNumCall += item.numCall; globAvgMsec += item.totMsec; } } // riporto conteggio medio al secondo... lgInfo("{4}|Chiamate GLOBALI: {0}, periodo: {1:N2} minuti.cent, tempo medio {2:N2} msec | impegno canale {3:P3}", globNumCall, DateTime.Now.Subtract(dtAvvioAdp).TotalMinutes, globAvgMsec.TotalMilliseconds / globNumCall, globAvgMsec.TotalSeconds / DateTime.Now.Subtract(dtAvvioAdp).TotalSeconds, cIobConf.codIOB); lgInfo("{0}--------------- STOP TIMING DATA ---------------{0}", Environment.NewLine); // mostro in form statistiche globali! parentForm.updateComStats(string.Format("Periodo: {0:N2}min | {1} x {2:N2}ms | canale {3:P3}", DateTime.Now.Subtract(dtAvvioAdp).TotalMinutes, globNumCall, globAvgMsec.TotalMilliseconds / globNumCall, globAvgMsec.TotalSeconds / DateTime.Now.Subtract(dtAvvioAdp).TotalSeconds)); } } /// /// processa dataLayer e se necessario salva/mostra /// public void checkSavePersDataLayer() { } public void resetDebugConsole() { } /// /// Metodo base connessione... /// public virtual void tryConnect() { dtAvvioAdp = DateTime.Now; } /// /// Metodo base disconnessione... /// public virtual void tryDisconnect() { } protected bool _connOk = false; /// /// Salva verifica stato connessione OK /// /// public virtual bool connectionOk { get { return _connOk || DemoIn; } set { _connOk = value; } } /// /// test ping all'indirizzo impostato nei parametri /// /// protected IPStatus testPing() { IPStatus answ = IPStatus.Unknown; ; IPAddress address; PingReply reply; Ping pingSender = new Ping(); address = IPAddress.Loopback; IPAddress.TryParse(cIobConf.cncIpAddr, out address); int pingMsTimeout = cIobConf.pingMsTimeout; reply = pingSender.Send(address, pingMsTimeout); answ = reply.Status; return answ; } #endregion #region layer persistenza dati /// /// Dizionario di persistenza per i valori da salvare da/su file /// public Dictionary persistenceLayer; /// /// recupera valore salvato in persistence layer (se non c'è crea...) /// /// /// private string getStoredVal(string keyVal) { string value = ""; try { if (persistenceLayer != null) { if (!persistenceLayer.TryGetValue(keyVal, out value)) { persistenceLayer.Add(keyVal, "0"); } } } catch (Exception exc) { lgError(string.Format("Eccezione in getStoredVal: {0}{1}", Environment.NewLine, exc)); } return value; } /// /// recupera valore salvato in persistence layer (se non c'è crea...) come UINT /// /// /// private uint getStoredValUInt(string keyVal) { uint answ = 0; try { answ = Convert.ToUInt32(getStoredVal(keyVal)); } catch (Exception exc) { lgError(string.Format("Eccezione in getStoredValUInt: {0}{1}", Environment.NewLine, exc)); } // verifico che il valore sia minore di 9/10 del valore massimo... answ = (answ < (uint.MaxValue / 10 * 9)) ? answ : 0; return answ; } /// /// recupera valore salvato in persistence layer (se non c'è crea...) come INT /// /// /// private long getStoredValLong(string keyVal) { long answ = 0; try { answ = Convert.ToInt64(getStoredVal(keyVal)); } catch { } // verifico che il valore sia minore di 9/10 del valore massimo... answ = (answ < (long.MaxValue / 10 * 9)) ? answ : 0; return answ; } /// /// recupera valore salvato in persistence layer (se non c'è crea...) come double /// /// /// private double getStoredValDouble(string keyVal) { double answ = 0; try { answ = Convert.ToDouble(getStoredVal(keyVal)); } catch (Exception exc) { lgError(string.Format("Eccezione in getStoredValDouble: {0}{1}", Environment.NewLine, exc)); } answ = (answ < (double.MaxValue / 10 * 9)) ? answ : 0; return answ; } /// /// Aggiorna un valore del dizionario in SOSTITUZIONE /// /// /// /// /// Nuovo valore incrementato private void updateValString(int i, string newVal, string searchString) { // stringa da cercare.. string keyVal = string.Format(searchString, i + 1); // salvo in ram! persistenceLayer[keyVal] = newVal; } /// /// Aggiorna un valore del dizionario in SOSTITUZIONE e lo restituisce /// /// /// /// /// Nuovo valore incrementato private void updateValUInt(int i, uint newVal, string searchString) { // stringa da cercare.. string keyVal = string.Format(searchString, i + 1); // salvo in ram! persistenceLayer[keyVal] = newVal.ToString(); } /// /// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce /// /// /// /// /// Nuovo valore incrementato private uint updateValUIntByIncr(int i, uint delta, string searchString) { // stringa da cercare.. string keyVal = string.Format(searchString, i + 1); // recupero valore precedente... uint contAct = getStoredValUInt(keyVal); // nuovo valore... contAct += delta; // salvo in ram! persistenceLayer[keyVal] = contAct.ToString(); // rendo il valore! return contAct; } /// /// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce /// /// /// /// /// Nuovo valore incrementato private long updateValLongByIncr(int i, long delta, string searchString) { // stringa da cercare.. string keyVal = string.Format(searchString, i + 1); // recupero valore precedente... long contAct = getStoredValLong(keyVal); // nuovo valore... contAct += delta; // salvo in ram! persistenceLayer[keyVal] = contAct.ToString(); // rendo il valore! return contAct; } /// /// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce /// /// /// /// /// Nuovo valore incrementato private double updateValDoubleByIncr(int i, double delta, string searchString) { // stringa da cercare.. string keyVal = string.Format(searchString, i + 1); // recupero valore precedente... double contAct = getStoredValDouble(keyVal); // nuovo valore... contAct += delta; // salvo in ram! persistenceLayer[keyVal] = contAct.ToString(); // rendo il valore! return contAct; } #endregion #region area lettura configurazioni /// /// Legge il file di conf di una MAP di informazioni da gestire con lettura set memoria /// /// nome vettore memoria /// file origine /// dimensione (in byte) della memoria /// dimensione (in byte) della memoria protected void loadConfFile(ref otherData[] vettoreConf, string nomeFile, int memSize, ref int numVett) { otherData lastData = new otherData(); int totRighe = 0; string linea; totRighe = File.ReadLines(nomeFile).Count(); // creo un vettore della dimensione corretta... conta anche commenti tanto poi riduco... vettoreConf = new otherData[File.ReadLines(nomeFile).Count()]; // carica da file... StreamReader file = new StreamReader(nomeFile); // leggo 1 linea alla volta... int numRiga = 0; int bitNum = 0; int byteNum = 0; while ((linea = file.ReadLine()) != null) { // SE non è un commento... if (linea.Substring(0, 1) != "#") { // se finisce per BIT allora processo bit-a-bit... if (linea.EndsWith("BOOL")) { try { string[] memIdx = linea.Split(utils.CRC("testCharSep"))[0].Split('.'); // calcolo bit e byte number... int.TryParse(memIdx[0], out byteNum); if (memIdx.Length > 1) { int.TryParse(memIdx[1], out bitNum); } else { bitNum = 0; } } catch { byteNum = 0; bitNum = 0; } lastData = decodeBitData(linea, utils.CRC("testCharSep"), byteNum, 1, bitNum); vettoreConf[numRiga] = lastData; } else { lastData = decodeOtherData(linea, utils.CRC("testCharSep"), "", 1, memSize); vettoreConf[numRiga] = lastData; } numRiga++; } } // salvo lunghezza file... try { numVett = Convert.ToInt32(lastData.memAddr) + 1; } catch { numVett = numRiga + 1; } // chiudo file file.Close(); // ora trimmo vettore al solo numero VERO dei valori caricati... Array.Resize(ref vettoreConf, numRiga); if (utils.CRB("verbose")) { lgInfo(string.Format("Fine caricamento vettore di {0} variabili per file {1}", numRiga, nomeFile)); } } /// /// Decodifica file MAP generico /// /// /// /// /// /// /// protected otherData decodeOtherData(string linea, char separator, string memPre, int baseAddr, int memSize) { string[] valori = linea.Split(separator); int shift = 0; try { shift = Convert.ToInt32(valori[0]) - 1; } catch { } string memAddr = string.Format("{0}{1}", memPre, baseAddr + shift * memSize); return new otherData(valori[0], memAddr, valori[1].Trim(), valori[2].Trim()); } /// /// Decodifica file MAP (caso .bit) /// /// /// /// indirizzo Byte: indirizzo di partenza memoria /// dimensione singolo slot in byte /// indirizzo bit: numero riga x calcolo indice bit /// protected otherData decodeBitData(string linea, char separator, int ByteNum, int memSize, int BitNum) { string[] valori = linea.Split(separator); int shift = 0; try { shift = Convert.ToInt32(valori[0]) - 1; } catch { } int resto = 0; Math.DivRem(BitNum, 8, out resto); string memAddr = string.Format("{0}.{1}", ByteNum + shift * memSize, resto); return new otherData(valori[0], memAddr, valori[1].Trim(), valori[2].Trim()); } /// /// Cerca se esiste il parametro opzionale e lo restituisce /// /// /// public string getOptPar(string key) { string answ = ""; if (cIobConf.optPar.Count > 0) { // controllo SE salvare contapezzo if (cIobConf.optPar.ContainsKey(key)) { answ = cIobConf.optPar[key]; } } return answ; } /// /// Cerca parametri opzionali in modalità "like" del nome /// /// /// public Dictionary findOptPar(string keyStartSearch = "") { Dictionary answ = new Dictionary(); // controllo SE keySearch !="" if (keyStartSearch != "") { if (cIobConf.optPar.Count > 0) { // ciclo su tutti e cerco occorrenze che INIZINO... foreach (var item in cIobConf.optPar) { if (item.Key.StartsWith(keyStartSearch)) { answ.Add(item.Key, item.Value); } } } } return answ; } #endregion /// /// effettua ogni log period una rilettura di TUTTI gli allarmi... /// public virtual void forceAlarmCheck() { } #region IOB METHODS /// /// Valore del num max invii consecutivi da coda... /// protected int nMaxSend { get { int answ = 5; try { answ = utils.CRI("nMaxSend"); } catch { } return answ; } } /// /// DateTime Ultimo valore simulazione generato /// public DateTime lastSim; /// /// contatore x simulazione valori input /// public int countSim = 0; /// /// URL per check alive... /// public string urlAlive { get { return string.Format(@"http://{0}{1}{2}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE); } } /// /// URL per check alive... /// public string urlIobEnabled { get { return string.Format(@"http://{0}{1}{2}{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDENABLED, cIobConf.codIOB); } } /// /// URL per segnalazione reboot... /// public string urlReboot { get { string answ = ""; try { answ = string.Format(@"http://{0}{1}{2}{3}&mac={4}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDREBO, cIobConf.codIOB, GetMACAddress()); } catch { answ = string.Format(@"http://{0}{1}{2}{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDREBO, cIobConf.codIOB); } return answ; } } /// /// URL per salvataggio contapezzi... /// public string urlGetCurrODL { get { string answ = ""; try { answ = string.Format(@"http://{0}{1}{2}/getCurrODL/{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB); } catch (Exception exc) { lgError(exc, "Errore in composizione urlGetCurrODL"); } return answ; } } /// /// URL per salvataggio contapezzi... /// public string urlSetPzCount { get { string answ = ""; try { answ = string.Format(@"http://{0}{1}{2}/setCounter/{3}?counter=", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB); } catch (Exception exc) { lgError(exc, "Errore in composizione urlSetPzCount"); } return answ; } } /// /// URL per salvataggio VALORI opzionali... /// public string urlSetOptVal { get { string answ = ""; try { answ = string.Format(@"http://{0}{1}{2}/addOptPar/{3}?", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB); } catch (Exception exc) { lgError(exc, "Errore in composizione urlSetOptVal"); } return answ; } } /// /// URL per richiamo task da eseguire... /// public string urlGetTask2Exe { get { string answ = ""; try { answ = string.Format(@"http://{0}{1}{2}/getTask2Exe/{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB); } catch (Exception exc) { lgError(exc, "Errore in composizione urlGetTask2Exe"); } return answ; } } /// /// URL per richiamo task da eseguire... /// public string urlRemTask2Exe { get { string answ = ""; try { answ = string.Format(@"http://{0}{1}{2}/remTask2Exe/{3}?taskName=", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB); } catch (Exception exc) { lgError(exc, "Errore in composizione urlRemTask2Exe"); } return answ; } } /// /// URL per recupero contapezzi... /// public string urlGetPzCount { get { string answ = ""; try { answ = string.Format(@"http://{0}{1}{2}/getCounter/{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB); } catch (Exception exc) { lgError(exc, "Errore in composizione urlGetPzCount"); } return answ; } } /// /// URL per recupero contapezzi REGISTRATI da TC... /// public string urlGetPzCountRec { get { string answ = ""; try { answ = string.Format(@"http://{0}{1}{2}/getCounterTCRec/{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB); } catch (Exception exc) { lgError(exc, "Errore in composizione urlGetPzCountRec"); } return answ; } } /// /// URL per salvataggio dati associazione Machine 2 IOB... /// public string urlSetM2IOB { get { string answ = ""; try { string machineName = Environment.MachineName; answ = string.Format(@"http://{0}{1}{2}/setM2IOB/{3}?IOB_name={4}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB, machineName); } catch (Exception exc) { lgError(exc, "Errore in composizione urlSetM2IOB"); } return answ; } } public string GetMACAddress() { NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces(); String sMacAddress = string.Empty; foreach (NetworkInterface adapter in nics) { if (sMacAddress == String.Empty)// only return MAC Address from first card { IPInterfaceProperties properties = adapter.GetIPProperties(); //sMacAddress = adapter.GetPhysicalAddress().ToString(); sMacAddress = string.Join(":", (from z in adapter.GetPhysicalAddress().GetAddressBytes() select z.ToString("X2")).ToArray()); } } return sMacAddress; } /// /// Fornisce URL INPUT per i parametri richiesti /// /// valore salvato in coda formato dtEve#valore#counter /// public string urlInput(string queueVal) { // URL base x input string answ = string.Format(@"http://{0}{1}{2}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDBASE); // decodifica valore! string[] valori = qDecodeIN(queueVal); // aggiungo macchina e valore... answ += string.Format(@"{0}?valore={1}", cIobConf.codIOB, valori[1]); // aggiondo dataOra evento e corrente + contatore... answ += string.Format(@"&&dtEve={0}&&dtCurr={1:yyyyMMddHHmmssfff}&&cnt={2}", valori[0], DateTime.Now, valori[2]); return answ; } /// /// Fornisce URL di tipo FluxLog /// /// valore salvato in coda nel formato dtEve#flux#valore#counter /// public string urlFLog(string queueVal) { // URL base x input string answ = string.Format(@"http://{0}{1}{2}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDFLOG); // decodifica valore! string[] valori = qDecodeIN(queueVal); // aggiungo macchina e valore... answ += string.Format(@"{0}?flux={1}&&valore={2}", cIobConf.codIOB, valori[1], valori[2]); // aggiondo dataOra evento e corrente + contatore... answ += string.Format(@"&&dtEve={0}&&dtCurr={1:yyyyMMddHHmmssfff}&&cnt={2}", valori[0], DateTime.Now, valori[3]); return answ; } /// /// Effettua chiamata URL e restituisce risultato /// /// /// public string callUrl(string URL) { return utils.callUrl(URL); } /// /// test ping all'indirizzo impostato nei parametri /// /// private IPStatus testPingServer() { IPStatus answ = IPStatus.Unknown; ; IPAddress address; PingReply reply; Ping pingSender = new Ping(); address = IPAddress.Loopback; string ipAdrr = cIobConf.serverData.MPIP.Replace("http://", "").Replace("https://", ""); IPAddress.TryParse(ipAdrr, out address); int pingMsTimeout = utils.CRI("pingMsTimeout"); reply = pingSender.Send(address, pingMsTimeout); answ = reply.Status; return answ; } /// /// Verifica se il server sia ALIVE (tramite PING) /// public bool checkServerAlive { get { bool answ = false; // controllo se ho un VETO all'invio... if (dtVetoPing < DateTime.Now) { if (DemoOut) { answ = false; } else { IPStatus pingStatus = testPingServer(); // se passa il ping faccio il resto... if (pingStatus == IPStatus.Success) { try { // chiamo URL, se restituisce "OK" è alive! answ = (callUrl(urlAlive) == "OK"); } catch (Exception exc) { lgError("Errore in checkServerAlive:{0}{1}", Environment.NewLine, exc); } // verifico SE è variato stato online/offline... if (MPOnline != answ) { // se ORA sono online riporto... if (answ) { lgInfo("SERVER ONLINE"); parentForm.commSrvActive = 1; dtVetoPing = DateTime.Now.AddMinutes(-5); utils.dtVetoSend = DateTime.Now.AddMinutes(-5); } else { lgInfo("SERVER OFFLINE"); parentForm.commSrvActive = 0; } // salvo nuovo status... MPOnline = answ; } } else { lgInfo("SERVER NOT RESPONDING (PING)"); // imposto un veto per pauseSendMSec int pauseSendMSec = utils.CRI("pauseSendMSec"); // aggiungo NOISE... +/- 33% Random rnd = new Random(); int noise = rnd.Next(1, pauseSendMSec / 3); pauseSendMSec += noise - (pauseSendMSec / 6); // imposto veto dtVetoPing = DateTime.Now.AddMilliseconds(pauseSendMSec); } } } return answ; } } /// /// Verifica se la IOB sia ENABLED (da server o Demo) /// private bool checkIobEnabled { get { bool answ = false; if (DemoOut) { answ = (QueueIN.Count + QueueFLog.Count >= nMaxSend); } else { try { // chiamo URL, se restituisce "OK" è enabled! answ = (callUrl(urlIobEnabled) == "OK"); } catch { } } // verifico SE è variato stato online/offline... if (IobOnline != answ) { // se ORA sono online riporto... if (answ) { lgInfo("IOB ONLINE"); } else { lgInfo("IOB OFFLINE"); } // salvo nuovo status... IobOnline = answ; } // fix colore if (answ) { parentForm.commSrvActive = 2; } else { parentForm.commSrvActive = 1; } return answ; } } /// /// Processo la coda SignalIN... /// public void svuotaCodaSignIN() { // verifico SE la coda abbia dei valori... if (QueueIN.Count > 0) { // verifico se risponde il server... if (checkServerAlive) { // verifico SE posso inviare dati if (checkIobEnabled) { // invio pacchetto di dati (max da conf) for (int i = 0; i < nMaxSend; i++) { trySendQueuedVal(); } } else { // mostro VETO-SEND x invio... GIALLO parentForm.sOUT = Semaforo.SG; if (periodicLog) { lgInfo("IOB - VETO SEND"); } } } else { // mostro SERVER KO x invio... ROSSO parentForm.sOUT = Semaforo.SR; if (periodicLog) { lgInfo("IOB - SERVER NOT READY"); } } } } /// /// Invio del + vecchio valore in coda (se c'è) /// private void trySendQueuedVal() { // SE ho qualcosa in coda... if (QueueIN.Count > 0) { // recupero ed aggiorno ULTIMO valore... lastSignInVal = QueueIN.Dequeue(); // INVIO!!! sendToMoonPro(urlType.SignIN, lastSignInVal); } } /// /// Processo la coda FLog... /// private void svuotaCodaFLog() { //controllo se è passato oltre watchdog e non ho inviato nulla --> RE-INVIO (ultimo inviato)!!!! if (DateTime.Now.Subtract(lastWatchDog).TotalSeconds > utils.CRI("watchdogMaxSec")) { string wdStatus = "elapsed"; string sVal = string.Format("[WDST]{0}", wdStatus); // chiamo accodamento... accodaFLog(sVal, qEncodeFLog("WDST", wdStatus)); lastWatchDog = DateTime.Now; } // verifico SE la coda abbia dei valori... if (QueueFLog.Count > 0) { // verifico se risponde il server... if (checkServerAlive) { // verifico SE posso inviare dati if (checkIobEnabled) { // invio pacchetto di dati (max da conf) for (int i = 0; i < nMaxSend; i++) { // SE ho qualcosa in coda... if (QueueFLog.Count > 0) { // INVIO!!! sendToMoonPro(urlType.FLog, QueueFLog.Dequeue()); } } } else { // mostro VETO-SEND x invio... GIALLO parentForm.sOUT = Semaforo.SG; } } else { // mostro SERVER KO x invio... ROSSO parentForm.sOUT = Semaforo.SR; } } } /// /// Classe fittizia in caso di processing task in VHF /// public virtual void processVHF() { } /// /// Classe fittizia in caso di processing GLOBALE di tutto in 1 solo colpo... /// private void processAllMemory() { // in primis SALVO valori previous/precedenti B_previous = B_output; // poi faccio lettura NUOVI valori readAllData(); // eseguo il filtering dei valori (per i bit "blinking") filterData(); // effettuo confronto valori vecchi/nuovi... SE trovo variazione OPPURE se è passato + di un timeout di controllo... if (B_output != B_previous) { accodaSigIN(); } } /// /// Processa gestione memoria x invio dati QUANDO IOB è disconnesso da CNC... /// public void processMemoryDiscon() { // controllo contatore invio "keepalive"... invio solo a scadenza if (DateTime.Now.Subtract(lastDisconnCheck).TotalSeconds > utils.CRI("disconMaxSec")) { // resetto tutti i vlaori BYTE IN/PREV/OUT... così invio macchina spenta... B_input = 0; B_output = 0; B_previous = 0; accodaSigIN(); // update controllo lastDisconnCheck = DateTime.Now; } } /// /// Esegue filtraggio dati x bit blinking!!! /// private void filterData() { // effettuo filtraggio dei valori letti... inizializzo OUT! B_output = 0; // in primis verifico SE ci siano bit blinkng... se non ci sono OUT=IN... if (cIobConf.BLINK_FILT == 0) { B_output = B_input; } else { // incomincio con i valori NON blinking: questi "passano invariati", inizio a sommare nel valore OUT... B_output = B_input & ~cIobConf.BLINK_FILT; // calcolo il valore dei BIT che "passano la maschera" int iBlink = B_input & cIobConf.BLINK_FILT; // ...aggiungo i "bit che passano" B_output += iBlink; // calcolo QUALI valori (tra quelli blink) siano PASSATI da 0 a 1 --> init counters... BitArray bBlinkStart = new BitArray(new byte[] { Convert.ToByte(iBlink) }); int[] bitsUp = bBlinkStart.Cast().Select(bit => bit ? 1 : 0).ToArray(); for (int i = 0; i < bitsUp.Length; i++) { // SE 1... impostiamo contatori al MAX if (bitsUp[i] == 1) { // se era zero indico START blink... if (i_counters[i] == 0) { lgInfo("START BLINK: B{0}", i); } // imposto comunque contatore al cambio fronte... i_counters[i] = cIobConf.MAX_COUNTER_BLINK; } } // quelli che sono zero... LI RECUPERO E LI PROCESSO... int iZero = ~B_input & cIobConf.BLINK_FILT; BitArray bBlinkEnd = new BitArray(new byte[] { Convert.ToByte(iZero) }); int[] bitsDown = bBlinkEnd.Cast().Select(bit => bit ? 1 : 0).ToArray(); for (int i = 0; i < bitsDown.Length; i++) { // se era a zero (invertito...) if (bitsDown[i] == 1) { // SE è in corso il conteggio... if (i_counters[i] > 0) { // decremento! i_counters[i] -= 1; // se è zero NON faccio nulla, altrimenti SOMMO... if (i_counters[i] > 0) { B_output += 1 << i; } else { lgInfo("END BLINK: B{0}", i); } } } } } } /// /// Effettua lettura dati /// public virtual void readAllData() { if (DemoIn) { // segnalo che sono in Demo parentForm.sIN = Semaforo.SV; } if (connectionOk) { readSemafori(); } else { lgError("Errore connessione mancante x readSemafori"); } nReadIN++; // aggiorno valore mostrato... displayRawData(); } /// /// Effettua gestioen programma: legge e mostra su display... /// private void processProgram() { string currPrgName = ""; // se abilitata lettura prgName if (enablePrgName) { if (connectionOk) { currPrgName = getPrgName(); } else { lgError("Errore connessione mancante x getPrgName"); } } else { currPrgName = lastPrgName; } // verifico SE sia cambiato il programma... if (lastPrgName != currPrgName) { // salvo! lastPrgName = currPrgName; string sVal = string.Format("[PROG]{0}", currPrgName); // chiamo accodamento... accodaFLog(sVal, qEncodeFLog("PROG", currPrgName)); } } /// /// Processo lettura dati sysinfo /// private void processSysInfo() { if (utils.CRB("enableSysInfo")) { Dictionary currSysInfo = new Dictionary(); if (connectionOk) { currSysInfo = getSysInfo(); } else { lgError("Errore connessione mancante x getSysInfo"); } // verifico SE sia cambiato il programma... if (lastSysInfo != currSysInfo["SYSINFO"]) { // salvo! lastSysInfo = currSysInfo["SYSINFO"]; // per ogni valore del dizionario mostro ed accodo! string sVal = ""; foreach (var item in currSysInfo) { sVal = string.Format("[SYSINFO]{0}|{1}", item.Key, item.Value); // chiamo accodamento... accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); } } } } /// /// Restituisce info sistema /// /// public virtual Dictionary getSysInfo() { Dictionary outVal = new Dictionary(); return outVal; } /// /// Restituisce info DINAMICHE /// /// public virtual Dictionary getDynData() { Dictionary outVal = new Dictionary(); return outVal; } /// /// Restituisce info OVERRIDES /// /// public virtual Dictionary getOverrides() { Dictionary outVal = new Dictionary(); return outVal; } /// /// Recupera eventuali allarmi CNC... /// public virtual Dictionary getCncAlarms() { Dictionary outVal = new Dictionary(); return outVal; } /// /// Restituisce programma in esecuzione /// public virtual string getPrgName() { return ""; } /// /// Effettua lettura semafori principale /// public virtual void readSemafori() { } /// /// Effettua processing contapezzi (ed eventualmente alza il bit di contapezzo...) /// public virtual void processContapezzi() { } /// /// Effettua processing ALTRI contatori/parametri (ed invia ad IO) /// public virtual void processOtherCounters() { } /// /// Effettua processing mode/status (EDIT/MDI/...) /// public virtual void processMode() { } /// /// Effettua processing del recupero delle speed (RPM, feedrate) degli assi /// public void processDynData() { bool enableByApp = utils.CRB("enableDynData"); bool enableByIob = (getOptPar("ENABLE_DYN_DATA") == "TRUE"); Dictionary currDynData = new Dictionary(); if (enableByApp || enableByIob) { lgInfo("Inizio processDynData"); if (connectionOk) { currDynData = getDynData(); } else { lgError("Errore connessione mancante x getDynData"); } try { // verifico SE sia cambiato il programma... if (lastDynData != currDynData["DYNDATA"]) { // salvo! lastDynData = currDynData["DYNDATA"]; // per ogni valore del dizionario mostro ed accodo! string sVal = ""; foreach (var item in currDynData) { sVal = string.Format("[DYNDATA]{0}|{1}", item.Key, item.Value); // chiamo accodamento... accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); } } } catch (Exception exc) { lgError(exc, "Eccezione in processDynData"); } } } /// /// Processing di VC x TS, accoda valori x la VC (se esiste) e restituisce bool val se SCADUTO periodo controllo /// /// Nome della VC /// Valore (nuovo) delal VC /// public bool stackVal_TSVC(string VCName, double VCVal) { bool answ = false; // cerco VC... if (TSVC_Data.ContainsKey(VCName)) { TSVC_Data[VCName].dataArray.Add(VCVal); // ora verifico scadenza... if (TSVC_Data[VCName].DTStart.AddSeconds(TSVC_Data[VCName].Periodo) < DateTime.Now) { answ = true; } } return answ; } /// /// Recupera la VC x TS, svuotando lista e resettando periodo partenza /// /// Nome della VC /// Reimposta e resetta array VC /// public double getVal_TSVC(string VCName, bool doReset) { double answ = 0; // cerco VC... if (TSVC_Data.ContainsKey(VCName)) { // !!!FARE!!! vero calcolo... x ora FIX a MAX... foreach (var item in TSVC_Data[VCName].dataArray) { answ = item > answ ? item : answ; } // ora resetto... SE richiesto.. if (doReset) { TSVC_Data[VCName].dataArray = new List(); TSVC_Data[VCName].DTStart = DateTime.Now; } } return answ; } /// /// Effettua processing del recupero delle speed (RPM, feedrate) degli assi /// public void processCncAlarms() { if (utils.CRB("enableAlarms")) { Dictionary currAlarms = new Dictionary(); if (connectionOk) { currAlarms = getCncAlarms(); } else { lgError("Errore connessione mancante x getCncAlarms"); } // verifico SE sia cambiato il programma... if (currAlarms.Count > 0) { try { if (lastAlarm != currAlarms["CNC_ALARM"]) { // salvo! lastAlarm = currAlarms["CNC_ALARM"]; // per ogni valore del dizionario mostro ed accodo! string sVal = ""; foreach (var item in currAlarms) { sVal = string.Format("[CNC_ALARM]{0}|{1}", item.Key, item.Value); // chiamo accodamento... accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); } } } catch (Exception exc) { lgError("Eccezione in processCncAlarms{0}{1}", Environment.NewLine, exc); } } } } /// /// Effettua processing del recupero delle OVERRIDE (spindle, feedrate, rapid) /// public virtual void processOverride() { bool enableByApp = utils.CRB("enableOverrides"); bool enableByIob = (getOptPar("ENABLE_OVERRIDES") == "TRUE"); Dictionary currOverride = new Dictionary(); if (enableByApp || enableByIob) { lgInfo("Inizio processOverride"); if (connectionOk) { currOverride = getOverrides(); } else { lgError("Errore connessione mancante x getOverrides"); } // SE sono connesso... if (connectionOk) { // se HO dei valori override... if (currOverride.Count > 0) { // verifico SE sia cambiato il programma... if (lastOverrideFS != currOverride["FEED_OVER"] || lastOverrideRapid != currOverride["RAPID_OVER"]) { // salvo! lastOverrideFS = currOverride["FEED_OVER"]; lastOverrideRapid = currOverride["RAPID_OVER"]; // per ogni valore del dizionario mostro ed accodo! string sVal = ""; foreach (var item in currOverride) { sVal = string.Format("[OVERRIDES]{0}|{1}", item.Key, item.Value); // chiamo accodamento... accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); } } } } } } /// /// metodo dummy x salvataggio aree memoria conf x CN /// /// tipo di DUMP public virtual void saveMemDump(dumpType tipo) { } #endregion #region gestione code (accumulo, invio) /// /// Fornisce il valore letto da BITMAP in formato valido x messa in coda nel formato dtEve#value#cont /// protected string qEncodeIN { get { string answ = ""; try { answ = string.Format("{0:yyyyMMddHHmmssfff}#{1:X2}#{2}", DateTime.Now, B_output, counterSigIN); } catch { } return answ; } } /// /// Fornisce il valore di flusso e valore in formato valido x messa in coda nel formato dtEve#flux#value#cont /// public string qEncodeFLog(string flusso, string valore) { string answ = ""; try { answ = string.Format("{0:yyyyMMddHHmmssfff}#{1}#{2}#{3}", DateTime.Now, flusso, valore, counterFLog); } catch { } return answ; } /// /// Decodifica valore della coda IN nel formato /// answ[0]=dtEve /// answ[1]=valore /// answ[2]=counter /// /// dtEve + '#' + value + '#' + cont /// protected string[] qDecodeIN(string queueVal) { return queueVal.Split('#'); } /// /// Accumula in coda i valori Signal IN e logga... /// public void accodaSigIN() { // mostro dati variati letti... displayInData(); // --> accodo (valore già formattato)! QueueIN.Enqueue(qEncodeIN); // loggo! lgInfo(string.Format("[QUEUE-IN] {0}", qEncodeIN)); // aggiorno counters ed eventuale reset nReadFilt++; if (nReadFilt > int.MaxValue - 1) { nReadFilt = 0; // per evitare buffer overflow... } counterSigIN++; if (counterSigIN > 9999) { counterSigIN = 0; } } /// /// Accumula in coda i valori Signal IN e logga... /// /// VALORE RAW (x display) /// VALORE già processato con qEncodeFLog(...) public void accodaFLog(string val, string encodedVal) { // mostro dati variati letti... displayOtherData(val); // --> accodo (valore già formattato)! QueueFLog.Enqueue(encodedVal); // loggo! lgInfo(string.Format("[QUEUE-FLOG] {0}", encodedVal)); counterFLog++; if (counterFLog > 9999) { counterFLog = 0; } } /// /// Effettua invio a MoonPro del valore richiesto /// /// /// Valore da trasmettere: es /// INPUT: lo status rilevato in HEX /// FLog: il valore da trasmettere per il flusso indicato public void sendToMoonPro(urlType tipoUrl, string queueVal) { // recupero e formatto URL dati da coda... switch (tipoUrl) { case urlType.FLog: lastUrl = urlFLog(queueVal); break; case urlType.SignIN: lastUrl = urlInput(queueVal); break; default: lastUrl = ""; break; } // se NON sono in demo effettuo invio! if (!DemoOut) { // chiamo URL! string answ = callUrl(lastUrl); // loggo! lgInfo(string.Format("[SEND] {0} -> {1}", queueVal, answ)); // se "OK" verde, altrimenti errore --> ROSSO if (answ == "OK") { parentForm.sOUT = Semaforo.SV; } else { parentForm.sOUT = Semaforo.SR; } } else { parentForm.sOUT = Semaforo.SV; // loggo! lgInfo(string.Format("{0} -> [SIM]", queueVal)); } nSendOut++; // riporto cosa inviato displayOutData(); // aggiorno data ultimo watchdog... lastWatchDog = DateTime.Now; } #endregion #region gestione dataMonitor (update visualizzazione valori) /// /// Mostra i dati grezzi letti in esadecimale /// private void displayRawData() { // mostro update... string newString = string.Format("{0:X}", B_input); accodaRawData(newString); // salvo coda debug... QueueDebug.Enqueue(B_input); } /// /// Update visualizzaizone BIT in ingresso /// public void displayInData() { // mostro update... string newString = string.Format("{0:0000}|{1}", counterSigIN, utils.IntToBinStr(B_output, 8)); accodaSignaInlData(newString); } /// /// Mostra cosa ha/avrebbe inviato /// public void displayOutData() { accodaUrlData(lastUrl); } /// /// Mostra cosa ha/avrebbe inviato /// /// public void displayOtherData(string newData) { // mostro update... accodaOtherData(newData); } /// /// Accoda (visualizzando in cima allo stack) la nuova stringa di output per area OTHER DATA /// /// public void accodaRawData(string newLine) { // inserisco in cima allo stack, trimmo e aggiorno display parentForm.dataMonitor_0 = limitLine2show(string.Format("{0}{1}{2}", newLine, Environment.NewLine, parentForm.dataMonitor_0)); } /// /// Accoda (visualizzando in cima allo stack) la nuova stringa di output per area OTHER DATA /// /// public void accodaSignaInlData(string newLine) { // inserisco in cima allo stack, trimmo e aggiorno display parentForm.dataMonitor_1 = limitLine2show(string.Format("{0}{1}{2}", newLine, Environment.NewLine, parentForm.dataMonitor_1)); } /// /// Accoda (visualizzando in cima allo stack) la nuova stringa di output per area OTHER DATA /// /// public void accodaUrlData(string newLine) { // inserisco in cima allo stack, trimmo e aggiorno display parentForm.dataMonitor_2 = limitLine2show(string.Format("{0}{1}{2}", newLine, Environment.NewLine, parentForm.dataMonitor_2)); } /// /// Accoda (visualizzando in cima allo stack) la nuova stringa di output per area OTHER DATA /// /// public void accodaOtherData(string newLine) { // inserisco in cima allo stack, trimmo e aggiorno display parentForm.dataMonitor_3 = limitLine2show(string.Format("{0}{1}{2}", newLine, Environment.NewLine, parentForm.dataMonitor_3)); } /// /// Effettua un trim della stringa al numero max di linee da mostrare a video /// /// /// private string limitLine2show(string newString) { // se num righe superiore a limite trimmo... if (newString.Split('\n').Length > parentForm.nLine2show) { //int idx = newString.LastIndexOf('\r'); int idx = newString.LastIndexOf(Environment.NewLine); newString = newString.Substring(0, idx); } return newString; } #endregion } }