using IOB_UT; using NLog; using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Text; using System.Threading; using System.Threading.Tasks; namespace IOB_WIN { public class IobGeneric { /// /// 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 /// public static Logger lg; /// /// dataOra ultimo log periodico... /// public DateTime lastPeriodicLog; /// /// Oggetto della coda degli elementi letti (e non ancora trasmessi) /// public Queue QueueIN = 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; /// /// Ultimo valore watchdog rilevato /// public bool lastWatchDog = false; /// /// Verifica se sia in modalità DEMO x dati INPUT /// public bool DemoIn { get { return IOB_UT.baseUtils.CRB("DemoIn"); } } /// /// Verifica se sia in modalità DEMO avanzata (campionamento da set di valori ammessi...) /// public bool DemoInSample { get { return IOB_UT.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 /// public int counter { get; set; } /// /// Ultimo URL /// public string lastUrl { 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; // 16 byte di strobe (4 word da 32 bit di flags...) public byte[] RawInput = new byte[4]; /// /// 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; /// /// vettore gestione cronometraggi /// public DateTime inizio; /// /// 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; /// /// Form chiamante /// protected MainForm parentForm; /// /// Conf adapter corrente /// public IobConfiguration currIobConf; /// /// inizializzo l'oggetto sulla form SULLA BASE DEL FILE DI CONFIGURAZIONE letto /// /// /// public IobGeneric(MainForm caller, IobConfiguration IOBConf) { lg = LogManager.GetCurrentClassLogger(); lg.Info("Avvio preliminare AdapterGeneric"); // configurazione... currIobConf = IOBConf; // aggiungo altri defaults setDefaults(); // salvo il form chiamante parentForm = caller; // concluso! lg.Info("Istanziata classe preliminare IOBGeneric"); } /// /// Imposto alcuni valori di default /// private void setDefaults() { numSim = utils.CRI("numSim"); nReadIN = 0; nReadFilt = 0; nSendOut = 0; // svuoto code... QueueIN.Clear(); QueueSIM.Clear(); // imposto contatori blink a zero... i_counters = new int[32]; lastPeriodicLog = DateTime.Now; } #region metodi adapter /// /// lettura file di persistenza /// public void loadPersData() { } /// /// Avvia l'adapter sulla porta richiesta /// /// public virtual void startAdapter(int port) { lg.Info("Starting adapter..."); parentForm.commPlcActive = false; adpRunning = true; dtAvvioAdp = DateTime.Now; TimingData.resetData(); // aggiungo altri defaults setDefaults(); 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) public void stopAdapter(bool tryRestart) { parentForm.displayTaskAndLog("Svuotamento FORZATO coda invio..."); while (QueueIN.Count > 0) { // INVIO SE PERMESSO...!!! sendToMoonPro(QueueIN.Dequeue()); } //reportDataProc(); 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.resetProgBar(); parentForm.displayTaskAndLog("Adapter Stopped."); parentForm.commPlcActive = false; } /// /// effettua recupero dati ed invio valori modificati... /// /// public void getAndSend(gatherCycle ciclo) { lg.Info("START getAndSend"); // 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; lg.Info("STEP 01"); // processing dati memoria (lettura, filtraggio, enqueque) if (ciclo == gatherCycle.VHF) { } else if (ciclo == gatherCycle.HF) { processAllMemory(); } else if (ciclo == gatherCycle.MF) { parentForm.dataMonitor_3 = ""; readPrgName(); } else if (ciclo == gatherCycle.LF) { } else if (ciclo == gatherCycle.VLF) { // recupero dati SETUP (sysinfo e sysinfo_ex) // eventuale log! if (utils.CRB("recTime")) logTimeResults(); } lg.Info("STEP 02"); // gestione queue (invio, display) svuotaCoda(); reportDataProc(); if (showDebugData) { // verifica se debba salvare e mostrare dati checkSavePersDataLayer(); } lg.Info("STEP 03"); } catch (Exception exc) { // segnalo eccezione e indico disconnesso... lg.Error(exc, string.Format("Errore in gestione ciclo principale ADP, fermo adapter{0}{1}", Environment.NewLine, exc)); parentForm.fermaAdapter(true); } // tolgo flag running adpCommAct = false; } else { if (periodicLog) lg.Info("ADP not running..."); } } else { // log ADP running lg.Error("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 { // log connessione KO lg.Error("getAndSend - Connessione non disponibile, provo a riconnettere"); // provo a riconnettere SE abilitato tryRestart... if (adpTryRestart && !connectionOk) { lg.Info("ConnKO - tryConnect"); tryConnect(); } } if (eh_refreshed != null) { eh_refreshed(this, new EventArgs()); } lg.Info("STOP getAndSend"); } 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) { lg.Info("{0}--------------- START TIMING DATA ---------------", Environment.NewLine); int globNumCall = 0; TimeSpan globAvgMsec = new TimeSpan(0); foreach (TimeRec item in TimingData.results) { lg.Info("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); globNumCall += item.numCall; globAvgMsec += item.totMsec; } // riporto conteggio medio al secondo... lg.Info("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); lg.Info("{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() { } /// /// Metodo base disconnessione... /// public virtual void tryDisconnect() { } protected bool _connOk = false; /// /// Salva verifica stato connessione OK /// /// public virtual bool connectionOk { get { return _connOk; } set { _connOk = value; } } #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) { lg.Error(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) { lg.Error(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) { lg.Error(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 /// /// 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 = 5; /// /// 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(@"{0}{1}{2}", currIobConf.serverData.MPIP, currIobConf.serverData.MPURL, currIobConf.serverData.CMDALIVE); } } /// /// URL per check alive... /// public string urlIobEnabled { get { return string.Format(@"{0}{1}{2}{3}", currIobConf.serverData.MPIP, currIobConf.serverData.MPURL, currIobConf.serverData.CMDENABLED, currIobConf.codIOB); } } /// /// Fornisce URL INPUT per i parametri richiesti /// /// valore salvato in coda formatodtEve#valore#counter /// public string urlInput(string queueVal) { // URL base x input string answ = string.Format(@"{0}{1}{2}", currIobConf.serverData.MPIP, currIobConf.serverData.MPURL, currIobConf.serverData.CMDBASE); // decodifica valore! string[] valori = qDecodeIN(queueVal); // aggiungo macchina e valore... answ += string.Format(@"{0}?valore={1}", currIobConf.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; } /// /// Effettua chaimata URL e restituisce risultato /// /// /// public string callUrl(string URL) { string answ = ""; var client = new WebClient(); answ = client.DownloadString(URL); // restituisco valore! return answ; } /// /// Verifica se il server sia ALIVE /// private bool checkServerAlive { get { bool answ = false; if (DemoOut) { answ = true; } else { try { // chiamo URL, se restituisce "OK" è alive! answ = (callUrl(urlAlive) == "OK"); } catch { } // verifico SE è variato stato online/offline... if (MPOnline != answ) { // se ORA sono online riporto... if (answ) { lg.Info("SERVER ONLINE"); } else { lg.Info("SERVER OFFLINE"); } // salvo nuovo status... MPOnline = answ; } } return answ; } } /// /// Verifica se la IOB sia ENABLED (da server o Demo) /// private bool checkIobEnabled { get { bool answ = false; if (DemoOut) { answ = (QueueIN.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) { lg.Info("IOB ONLINE"); } else { lg.Info("IOB OFFLINE"); } // salvo nuovo status... IobOnline = answ; } return answ; } } /// /// Processo la coda... /// private void svuotaCoda() { // 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++) { // SE ho qualcosa in coda... if (QueueIN.Count > 0) { // INVIO!!! sendToMoonPro(QueueIN.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 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 if (B_output != B_previous) { // mostro dati variati letti... displayInData(); // --> accodo (valore già formattato)! QueueIN.Enqueue(qEncodeIN); nReadFilt++; // Gestione counter! counter++; // se supera 10k resetto... if (counter > 9999) counter = 0; } } /// /// 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 (currIobConf.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 & ~currIobConf.BLINK_FILT; // calcolo il valore dei BIT che "passano la maschera" int iBlink = B_input & currIobConf.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) { lg.Info("START BLINK: B{0}", i); } // imposto comunque contatore al cambio fronte... i_counters[i] = currIobConf.MAX_COUNTER_BLINK; } } // quelli che sono zero... LI RECUPERO E LI PROCESSO... int iZero = ~B_input & currIobConf.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 { lg.Info("END BLINK: B{0}", i); } } } } } } /// /// 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, (int)B_output, counter); } 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('#'); } /// /// Effettua lettura dati /// public virtual void readAllData() { if (!DemoIn) { if (connectionOk) { readSemafori(); } else { lg.Error("Errore connessione mancante x readSemafori"); } } else { // segnalo ceh sono in Demo parentForm.sIN = Semaforo.SS; // simulo letura simReadMem(); } nReadIN++; // aggiorno valore mostrato... displayRawData(); } /// /// lettura programma in esecuzione /// public virtual void readPrgName() { } /// /// Effettua lettura semafori principale /// public virtual void readSemafori() { } private void displayRawData() { // mostro update...... string newString = string.Format("{0}{1}{2}", (int)B_input, Environment.NewLine, parentForm.dataMonitor_0); // se num righe superiore a limite trimmo... if (newString.Split('\n').Length > parentForm.nLine2show) { int idx = newString.LastIndexOf(Environment.NewLine); newString = newString.Substring(0, idx); } parentForm.dataMonitor_0 = newString; // salvo coda debug... QueueDebug.Enqueue(B_input); } /// /// Effettua invio a MoonPro dello status rilevato in HEX /// public void sendToMoonPro(string queueVal) { // recupero e formatto URL dati da coda... lastUrl = urlInput(queueVal); // se NON sono in demo effettuo invio! if (!DemoOut) { // chiamo URL! string answ = callUrl(lastUrl); // loggo! lg.Info(string.Format("{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! lg.Info(string.Format("{0} -> [SIM]", queueVal)); } nSendOut++; // riporto cosa inviato displayOutData(); } /// /// Mostra cosa ha/avrebbe inviato /// public void displayOutData() { // mostro update...... string newString = string.Format("{0}{1}{2}", lastUrl, Environment.NewLine, parentForm.dataMonitor_2); // se num righe superiore a limite trimmo... if (newString.Split('\n').Length > parentForm.nLine2show) { int idx = newString.LastIndexOf(Environment.NewLine); newString = newString.Substring(0, idx); } parentForm.dataMonitor_2 = newString; } /// /// Update visualizzaizone BIT in ingresso /// public void displayInData() { // mostro update...... string newString = string.Format("{0:0000}|{1}{2}{3}", counter, utils.IntToBinStr((int)B_output, 8), Environment.NewLine, parentForm.dataMonitor_1); // se num righe superiore a limite trimmo... if (newString.Split('\n').Length > parentForm.nLine2show) { int idx = newString.LastIndexOf(Environment.NewLine); newString = newString.Substring(0, idx); } parentForm.dataMonitor_1 = newString; } public void simReadMem() { if (lastSim == null) { lastSim = DateTime.Now; } // simulazione complessa (basata su samples dei parametri effettivi...) if (utils.CRB("DemoInSample")) { if (numSim >= 0) { // verifico se la coda di simulazione sia piena altrimenti la RICARICO... if (QueueSIM.Count == 0) { leggiSimFile(); numSim--; } // processo la coda di simulazione (stacco ed accodo 1 valore...) B_input = QueueSIM.Dequeue(); countSim++; // ogni 5 loggo... if (countSim % 5 == 0) { lg.Info("Read {0} sim data", countSim); } } else { // fermo tutto! parentForm.sIN = Semaforo.SR; parentForm.fermaAdapter(false); } } // simulazione semplice (counter crescente) else { // se passato 1 sec genero NUOV num casuale e lo metto nel bit strobe... ogni 2 sec... if (DateTime.Now.Subtract(lastSim).TotalMilliseconds > 100) { countSim++; if (countSim > 255) countSim = 0; B_input = countSim; } } lastSim = DateTime.Now; } /// /// legge ed accoda file Sim in QueueSIM /// private void leggiSimFile() { int totRighe = 0; string fileName = utils.simDataFile; string linea; totRighe = File.ReadLines(fileName).Count(); lg.Info("File SIM: TROVATE {0} righe", totRighe); // ora conto righe effettive... totRighe = 0; // carica da file... StreamReader file = new StreamReader(fileName); // leggo 1 linea alla volta... int valore = 0; while ((linea = file.ReadLine()) != null) { // SE non è un commento... if (linea.Substring(0, 1) != ";") { //elencoAllarmi[rumRiga] = decodeAlarmLine(linea, ':'); Int32.TryParse(linea, out valore); QueueSIM.Enqueue(valore); totRighe++; } } // chiudo file file.Close(); lg.Info("File SIM: LETTE {0} righe", totRighe); } #endregion } }