using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using NLog; using MTC; namespace MTC_ADB { using MTConnect; using System.Configuration; using System.Data.Common; using System.Diagnostics; using System.Globalization; using System.IO; using System.Threading; using System.Windows.Forms; public class AdapterGeneric { /// /// wrapper di log /// public static Logger lg; /// /// valore booleano di check se sia in fase di COMUNICAZIONE ATTIVA con il DB /// protected bool adpCommAct; /// /// valore booleano di check se sia stato AVVIATO l'adapter (Running) /// public bool adpRunning; /// /// valore booleano di check se l'adapter STIA SALVANDO /// public bool adpSaving; /// /// valore booleano (richiesta di riavvio automatico) /// public bool adpTryRestart; /// /// ultimo ID letto /// protected uint lastId = 0; /// /// 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; /// /// adapter globale /// public Adapter mAdapter = new Adapter(); /// /// Form chiamante /// protected MainForm parentForm; /// /// Numero tentativi di riconnesiosne prima di chiamare "fermaAdapter" nel parent... /// protected int numRetryConnDb = 10; /// /// Tipo server DB /// public string ServerType = "ND"; /// /// Indirizzo server DB /// public string ServerAddress = ""; /// /// Nome DB /// public string DbName = ""; /// /// User connessione /// protected string DbUser = ""; /// /// Pwd connessione /// protected string DbPwd = ""; /// /// Oggetto connessione al DB /// protected DbConnection DbConn; /// /// testo della query da eseguire... /// public string Query { get; set; } /// /// Singola istanza valore tipo DbTimeseries /// public class DbTS { /// /// Vettore della serie storica /// public Sample mSampleData; /// /// Classe gestione dati POWER /// /// Nome (univoco) variabile da pubblicare public DbTS(string ident) { mSampleData = new Sample(ident); } } #region DataItems Globali /// /// Disponibilità (del DB) /// public Event mAvail = new Event("AVAIL"); /// /// Status (ADP Running = ON / stopped INACTIVE) /// public Event mStatus = new Event("STATUS"); /// /// Orologio /// public Sample mClock = new Sample("CLOCK"); /// /// Messaggi (generico) /// public MTConnect.Message mMessage = new MTConnect.Message("MESSAGE"); /// /// vettore dati da lettura DB /// public DbTS[] vettDbData; #endregion public event EventHandler eh_refreshed; /// /// inizializzo l'oggetto /// /// /// public AdapterGeneric(MainForm caller) { lg = LogManager.GetCurrentClassLogger(); lg.Info("Avvio AdapterGeneric"); // salvo al form chiamante parentForm = caller; numRetryConnDb = utils.CRI("numRetryConnDb"); adpRunning = false; adpSaving = false; // item base mAdapter.AddDataItem(mAvail); mAdapter.AddDataItem(mStatus); mAdapter.AddDataItem(mClock); mAdapter.AddDataItem(mMessage); mAvail.Value = "ND"; mStatus.Value = "ND"; mClock.Value = string.Format("{0:yyyy-MM-dd} {0:HH:mm:ss}", DateTime.Now); mMessage.Code = "ND"; mMessage.Value = "INIT"; createDbConn(); // aggiunto 1 valore x la gestione timeseries... vettDbData = new DbTS[1]; for (int i = 0; i < vettDbData.Length; i++) { vettDbData[i] = new DbTS(string.Format("DbVal_E_{0:00}", i + 1)); mAdapter.AddDataItem(vettDbData[i].mSampleData); } // concluso! lg.Info("Istanziata classe ADB"); } /// /// Inizializzazione oggetti connessione al DB... /// private void createDbConn() { DbProviderFactory factory = DbProviderFactories.GetFactory("MySql.Data.MySqlClient"); DbConn = factory.CreateConnection(); } /// /// Lettura conf DB /// public void loadServerConf() { // disconnetto e riconnetto SE fosse già connesso... if (!connectionOk) { ServerType = utils.CRS("ServerType"); ServerAddress = utils.CRS("ServerAddress"); DbName = utils.CRS("DbName"); DbUser = utils.CRS("DbUser"); DbPwd = utils.CRS("DbPwd"); DbConn.ConnectionString = string.Format("SERVER={0};database={1};uid={2};password={3}", ServerAddress, DbName, DbUser, DbPwd); } } /// /// Caricamento altri file necessari epr adapter all'avvio /// protected virtual void loadOtherFile() { } #region metodi adapter public void loadPersData() { // nuova lettura valori da file persistenza... lastId = getStoredValUInt("LAST_ID"); } /// /// Avvia l'adapter sulla porta richiesta /// /// public virtual void startAdapter(int port) { lg.Info("Starting adapter..."); adpRunning = true; dtAvvioAdp = DateTime.Now; // inizializzo vettori di utility.. loadOtherFile(); // salvo porta! mAdapter.Port = port; // avvio! mAdapter.Start(); // setto status a ON mStatus.Value = "ON"; // resetto running flag... adpCommAct = false; //mAlarmGeneral.Normal(); adpTryRestart = true; parentForm.displayTaskAndWait("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.displayTaskAndWait("Stopping adapter..."); adpTryRestart = false; mStatus.Value = "INACTIVE"; // faccio una chiamata extra ad ogni metodo di check... gaterAndSend(gatherCycle.HF); gaterAndSend(gatherCycle.MF); gaterAndSend(gatherCycle.LF); gaterAndSend(gatherCycle.VLF); parentForm.displayTaskAndWait("Stopping adapter - last periodic data read..."); // chiudo la connessione all'adapter... tryDisconnect(); // Stop everything... try { mAdapter.Stop(); } catch (Exception exc) { lg.Error(exc, "Eccezione in chiusura Adapter"); } dtStopAdp = DateTime.Now; adpTryRestart = tryRestart; adpRunning = false; // chiudo! parentForm.resetProgBar(); parentForm.displayTaskAndWait("Adapter Stopped."); } /// /// effettua recupero dati ed invio valori modificati... /// /// public void gaterAndSend(gatherCycle ciclo) { // controllo connessione/connettività if (connectionOk) { // controllo non sia già in esecuzione... if (!adpCommAct) { // provo ad avviare try { // avvio fase raccolta dati mAdapter.Begin(); // imposto flag adapter running.. adpCommAct = true; adpStartRun = DateTime.Now; } catch (Exception exc) { parentForm.displayTaskAndWait(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 { // ciclo HF (nulla) if (ciclo == gatherCycle.HF) { // gestisco dati stato adapter getGlobalData(); } else if (ciclo == gatherCycle.MF) { getMainData(); } // ciclo lento else if (ciclo == gatherCycle.LF) { // invio dati "lenti" getSlowChangingData(); } // ciclo lentissimo else if (ciclo == gatherCycle.VLF) { // eventuale log! if (utils.CRB("recTime")) logTimeResults(); } // INVIO dati variati! mAdapter.SendChanged(); } catch (Exception exc) { // segnalo eccezione e indico disconnesso... DbConn.Close(); numRetryConnDb--; if (numRetryConnDb < 0) { numRetryConnDb = utils.CRI("numRetryConnDb"); lg.Error(exc, string.Format("Errore in gestione ciclo principale ADP, richiesto reset completo{0}{1}", Environment.NewLine, exc)); mMessage.Code = "ERR-ADP-RESET"; mMessage.Value = "Effettuato Reset Adapter"; parentForm.fermaAdapter(true); } else { lg.Error(exc, string.Format("Errore in gestione ciclo principale ADP, tentativo reset{0}{1}", Environment.NewLine, exc)); mMessage.Code = "ERR-DB-RESET"; mMessage.Value = "Reset Connessione DB"; } } // tolgo flag running adpCommAct = false; } else { 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("ADP - Connessione non disponibile, provo a riconnettere"); mMessage.Code = "ERR-DB-CONN"; mMessage.Value = "Connessione DB non disponibile, tentativo riconnessione"; // provo a riconnettere SE abilitato tryRestart... if (adpTryRestart && !connectionOk) { lg.Info("ConnKO - tryConnect"); tryConnect(); } } if (eh_refreshed != null) { eh_refreshed(this, new EventArgs()); } } /// /// salvo e controllo dati globali... /// public virtual void getGlobalData() { string currAvail = ""; if (connectionOk) { currAvail = "AVAILABLE"; } else { currAvail = "DISCONNECTED"; } if (mAvail.Value.ToString() != currAvail) { mAvail.Value = currAvail; } } /// /// 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", item.codCall, item.numCall, item.avgMsec); 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 MEDIO del 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); } } /// /// Metodo base connessione... /// public virtual void tryConnect() { if (!connectionOk) { try { DbConn.Open(); mMessage.Code = "DB-CONN"; mMessage.Value = "DB Connesso"; } catch (Exception exc) { mMessage.Code = "DB-DISC"; mMessage.Value = "DB Disconnesso"; lg.Error(exc, string.Format("Errore apertura connessione DB: {0}{1}", Environment.NewLine, exc)); mAdapter.SendChanged(); } } else { lg.Info("Exit tryConnect (ADP connected)"); } } /// /// Metodo base disconnessione... /// public virtual void tryDisconnect() { try { // CHIUDO! DbConn.Close(); mMessage.Code = "DB-DISC"; mMessage.Value = "ADP - Disconnessione DB"; } catch (Exception exc) { lg.Error(exc, string.Format("Errore in tryDisconnect da DB: {0}{1}", Environment.NewLine, exc)); mMessage.Code = "ERR-DB-DISC"; mMessage.Value = "Errore durante disconnessione DB"; } } /// /// Salva verifica stato connessione OK /// /// public virtual bool connectionOk { get { return DbConn.State == System.Data.ConnectionState.Open; } } /// /// Restituisce conteggio record disponibili e lo restituisce /// /// public string numRecAvail { get { string answ = "NA"; if (connectionOk) { // recupero conteggio degli eventi... Query = string.Format("SELECT COUNT(id) AS num FROM tracelog WHERE resource = 'E' AND device=1 AND id > {0}", lastId); DbCommand qrycmd = DbConn.CreateCommand(); qrycmd.CommandText = Query; qrycmd.Connection = DbConn; using (DbDataReader reader = qrycmd.ExecuteReader()) { try { while (reader.Read()) { answ = reader["num"].ToString(); } // chiudo reader! reader.Close(); } catch (Exception exc) { lg.Error(exc, string.Format("Errore in recupero conteggio eventi: {0}{1}", Environment.NewLine, exc)); answ = "ERR"; mMessage.Code = "ERR-DB-COUNT"; mMessage.Value = "Errore conteggio dati da DB"; } } } return answ; } } /// /// Recupero dati principali (DB) /// public virtual void getMainData() { // recupero da DB ultimo valore NON inviato e se c'è lo invio... string valore = "-999"; bool valFound = false; if (connectionOk) { // recupero conteggio degli eventi... se in debug rileggo da inizio altrimenti SOLO ultimo valore... #if DEBUG Query = string.Format("SELECT id, value FROM tracelog WHERE resource = 'E' AND device=1 AND id > {0} ORDER BY id LIMIT 1", lastId); #else Query = string.Format("SELECT id, value FROM tracelog WHERE resource = 'E' AND device=1 AND id > {0} ORDER BY id DESC LIMIT 1", lastId); #endif DbCommand qrycmd = DbConn.CreateCommand(); qrycmd.CommandText = Query; qrycmd.Connection = DbConn; using (DbDataReader reader = qrycmd.ExecuteReader()) { try { while (reader.Read()) { valore = reader["value"].ToString(); lastId = Convert.ToUInt32(reader["id"].ToString()); valFound = true; } // chiudo reader! reader.Close(); } catch (Exception exc) { lg.Error(exc, string.Format("Errore in recupero dati da DB: {0}{1}", Environment.NewLine, exc)); valore = "-99"; mMessage.Code = "ERR-DB-READ"; mMessage.Value = "Errore recupero dati da DB"; } } if (valFound) { // salvo in sample SE trovato...! vettDbData[0].mSampleData.Value = valore; // salvo lastID... updateValUInt(0, lastId, "LAST_ID"); } } } /// /// dati "lenti" relativi al device /// public virtual void getSlowChangingData() { // dati da PC mClock.Value = string.Format("{0:yyyy-MM-dd} {0:HH:mm:ss}", DateTime.Now); } #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.TryGetValue(keyVal, out value)) { persistenceLayer.Add(keyVal, "0"); } } catch { } 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 { } 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 { } 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 { } 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(); } #endregion } }