using AutoUpdaterDotNET; using IOB_UT; using MapoSDK; using Newtonsoft.Json; using NLog; using NLog.Config; using NLog.Targets; using System; using System.Collections.Generic; using System.Configuration; using System.Diagnostics; using System.Drawing; using System.Linq; using System.Net; using System.Net.NetworkInformation; using System.Threading; using System.Windows.Forms; namespace IOB_WIN { public partial class MainForm : Form { #region Protected Fields /// /// Ramo applicazione (x update) /// protected string branchName = "master"; /// /// chiamata x check alive di base /// protected string CMDALIVE = ""; /// /// chiamata x ricevere un codice IOB da gestire/acquisire /// protected string CMDIOB2CALL = ""; /// /// chiamata x invio comunicazioen reboot dell'IOBMAN /// protected string CMDREBO = ""; /// /// Data Avvio form /// protected DateTime formStartTime; /// /// Lista delle IOB da avviare /// protected List IOB2START; /// /// Num max di CNC da gestire /// protected int MAXCNC = 1; /// /// Modalità di avvio /// protected StartMode ModoAvvio = StartMode.STD; /// /// Indirizzo server /// protected string MPIP = ""; /// /// URL base applicazione /// protected string MPURL = ""; /// /// Parametri (opzionali) di avvio /// protected string[] myArgs; /// /// var x gestione reset progBar... arrivato a 3 faccio reset /// protected int resetProgBar = 0; /// /// Dizionario dei parametri di avvio (da elenco args...) /// protected Dictionary startParams = new Dictionary(); #endregion Protected Fields #region Public Fields /// /// oggetto logging /// public static Logger lg; /// /// Data ultimo controllo comunicazione /// public DateTime lastComCheck; /// /// Oggetto connessioen REDIS /// public RedisIobCache redisMan; #endregion Public Fields #region Public Constructors /// /// Init Main Form /// public MainForm(string[] args) { // salvo aprametri avvio... saveArgs(args); // continuo iNIT!!! InitializeComponent(); myInit(); if (args != null) { if (args.Length > 0) { lgInfo("Argomenti di avvio:"); foreach (var item in myArgs) { lgInfo(item); } } else { lgInfo("NESSUN Argomento di avvio trovato"); } } } #endregion Public Constructors #region Private Properties /// /// test ping all'indirizzo impostato nei parametri /// /// private IPStatus testPingServer { get { IPStatus answ = IPStatus.Unknown; IPAddress address; PingReply reply; Ping pingSender = new Ping(); address = IPAddress.Loopback; string ipAdrr = MPIP; IPAddress.TryParse(ipAdrr, out address); try { reply = pingSender.Send(address, 500); answ = reply.Status; } catch (Exception exc) { lgError($"testPingServer EXCEPTION in fase di ping{Environment.NewLine}{exc}"); } return answ; } } #endregion Private Properties #region Protected Properties /// /// IP del PC /// protected static string currIP { get { string answ = "127.0.0.1"; return answ; } } /// /// URL per recuperare i file dell'IOB su CLOUD (SENZA IOB) /// protected static string urlDownloadFileCloud { get { return @"http://seriate.steamware.net:8083/MP/IO/IOB/getFiles/"; } } /// /// URL per salvare i file dell'IOB su CLOUD (SENZA IOB) /// protected static string urlUploadFileCloud { get { return @"http://seriate.steamware.net:8083/MP/IO/IOB/uploadFile/"; } } /// /// URL stringa di UPDATE... /// protected string updateUrl { get { return string.Format("http://seriate.steamware.net:8083/SWS/MAPO/IOB-WIN/{0}/manifest.xml", branchName); } } /// /// URL per recuperare i file dell'IOB (SENZA IOB) /// protected string urlDownloadFile { get { string answ = ""; try { answ = string.Format(@"http://{0}{1}/IOB/getFiles/", MPIP, MPURL); } catch { } return answ; } } /// /// URL per chiedere quale sia la IOB da acquisire/gestire (se c'è...) /// protected string urlIob2call { get { string answ = ""; try { answ = string.Format(@"http://{0}{1}{2}{3}", MPIP, MPURL, CMDIOB2CALL, utils.GetIP()); } catch { } return answ; } } /// /// URL per segnalazione reboot... /// protected string urlReboot { get { string answ = ""; try { answ = string.Format(@"http://{0}{1}{2}{3}&mac={4}", MPIP, MPURL, CMDREBO, utils.GetIP(), utils.GetMACAddress()); } catch { answ = string.Format(@"http://{0}{1}{2}{3}", MPIP, MPURL, CMDREBO, utils.GetIP()); } return answ; } } /// /// URL per salvare i file dell'IOB (SENZA IOB) /// protected string urlUploadFile { get { string answ = ""; try { answ = string.Format(@"http://{0}{1}/IOB/uploadFile/", MPIP, MPURL); } catch { } return answ; } } #endregion Protected Properties #region Public Properties /// /// Visualizzazione stato di comunicazione attiva con PLC /// public bool commPlcActive { set { // se true --> comunica/verde, altrimenti grigio lblApp.ForeColor = value ? Color.SeaGreen : Color.Black; lblVers.ForeColor = value ? Color.SeaGreen : Color.DarkSlateGray; statusStrip1.Refresh(); } } /// /// Verifica il server: esiste IP, risponde a ping, risponde a pagina ALIVE /// public bool testServer { get { bool answ = false; if (!string.IsNullOrEmpty(MPIP)) { if (utils.dtVetoPing < DateTime.Now) { IPStatus pingStatus = testPingServer; // se passa il ping faccio il resto... if (pingStatus == IPStatus.Success) { try { // chiamo URL, se restituisce "OK" è alive! string callResp = utils.callUrl(urlAlive); answ = (callResp == "OK"); } catch (Exception exc) { lgError($"Errore in checkServerAlive:{Environment.NewLine}{exc}"); } // verifico SE è variato stato online/offline... if (utils.MPIO_Online != answ) { // se ORA sono online riporto... if (answ) { lgInfo("SERVER ONLINE"); utils.dtVetoPing = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec); } else { lgInfo("SERVER OFFLINE in MainForm:testServer"); } // salvo nuovo status... utils.MPIO_Online = answ; } else { // allungo periodo controllo... utils.dtVetoPing = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec * 3); } } else { lgInfo($"SERVER NOT RESPONDING (PING at {MPIP})"); utils.MPIO_Online = false; updateComStats(0, 0, false); // imposto veto a 10 volte reinvio dati standard... utils.dtVetoPing = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec * 10); utils.dtVetoSend = utils.dtVetoPing; } } else { // altrimenti passo ultimo valore noto... answ = utils.MPIO_Online; } } return answ; } } /// /// URL per check alive... /// public string urlAlive { get { return string.Format(@"http://{0}{1}/IOB", MPIP, MPURL); } } #endregion Public Properties #region Private Methods private void arrangeWindowsToolStripMenuItem_Click(object sender, EventArgs e) { // ferma tutti i child form... foreach (var ChildForm in this.MdiChildren) { try { //ChildForm.Show(); ChildForm.WindowState = FormWindowState.Normal; } catch { } } this.LayoutMdi(MdiLayout.TileHorizontal); } private void AutoUpdater_ApplicationExitEvent() { displayTaskAndLog("Chiusura Adapters"); Thread.Sleep(100); // chiudo tutto closeAllChild(); displayTaskAndLog("Chiusura Applicazione"); // attendo 1 sec... Thread.Sleep(1000); // ESCO! Application.Exit(); } /// /// Effettua verifiche varie comunicazione verso PLC e verso server /// private void checkCom() { // eseguo update se è passato almeno comCheckTOut secondi da ultimo check... if (DateTime.Now.Subtract(lastComCheck).TotalSeconds > utils.CRI("comCheckTOut")) { lastComCheck = DateTime.Now; // conta quanti child form di adapter verso PLC siano aperti !!!FARE!!! chiedere con un metodo che siano ATTIVI e contare quello... int numPLC = this.MdiChildren.Length; int numAttivi = 0; foreach (var item in this.MdiChildren) { try { var currForm = (AdapterForm)item; numAttivi += currForm.iobObj.IobOnline ? 1 : 0; } catch { } } // update stato! updateComStats(numPLC, numAttivi, testServer); } } /// /// Verifica stato windows (minimized/normal) e visibilità con tray... /// private void checkFormVisibility() { // se non può massimizzare imposto COMUNQUE a minimized... if (!utils.CRB("windowCanMax")) { WindowState = FormWindowState.Minimized; } // SOLO SE se sono in modo STD if (ModoAvvio == StartMode.STD) { // controllo cosa devo mostrare... if (WindowState == FormWindowState.Minimized) { notifyIcon1.Visible = false; sendToTray(); } else { notifyIcon1.Visible = false; } } else { notifyIcon1.Visible = false; } // fix child! this.LayoutMdi(MdiLayout.TileHorizontal); } /// /// FIx finestre restanti post chiusura di una finestra... /// /// /// private void Child_FormClosed(object sender, FormClosedEventArgs e) { this.LayoutMdi(MdiLayout.TileHorizontal); } /// /// Sistemazione finestre POST visualizzazione... /// /// /// private void Child_Shown(object sender, EventArgs e) { this.LayoutMdi(MdiLayout.TileHorizontal); } private void closeALLAdaptersToolStripMenuItem_Click(object sender, EventArgs e) { // chiudo tutte closeAllChild(); } /// /// Chiusura applicazione /// private void closeAllChild() { // ferma tutti i child form... foreach (var ChildForm in this.MdiChildren) { try { ChildForm.Close(); } catch { } } } /// /// crea menù tray x applicazione /// private void createTrayMenu() { // Fix testi menù tray... trayMenu.Items.Clear(); // SE permessa massimizzazione... if (utils.CRB("windowCanMax")) { trayMenu.Items.Add("Show IOB-WIN"); } // se è permesso tray close... if (utils.CRB("trayClose")) { trayMenu.Items.Add("Close IOB-WIN"); } } private void doConfDownload() { // ciclo su IOB configurati foreach (var currIob in IOB2START) { fileEmbed objFiles = new fileEmbed(); string rawData = ""; string url2call = ""; if (utils.CRB("ConfToCloud")) { // invio su cloud... url2call = $"{urlDownloadFileCloud}{currIob}"; } else { // invio in locale! url2call = $"{urlDownloadFile}{currIob}"; } rawData = utils.callUrlNow(url2call); if (!string.IsNullOrEmpty(rawData)) { // deserializzo objFiles = JsonConvert.DeserializeObject(rawData); if (objFiles != null) { // salvo! foreach (var item in objFiles.fileList) { fileMover.obj.salvaFileString(utils.confDir, item.fileName, item.content); } displayTaskAndLog("Download conf files aggiornati"); } else { displayTaskAndLog($"Error: invalid file data received, deserialized to null ({rawData})"); } } else { displayTaskAndLog("Error: no file data downloaded"); } } } private void downloadIOBConfToolStripMenuItem_Click(object sender, EventArgs e) { try { displayTaskAndLog("Attesa chiusura Adapters"); Thread.Sleep(100); // fermo gli IOB closeAllChild(); Thread.Sleep(100); // download da su server di TUTTI i file CONF delle IOB doConfDownload(); // riavvio gli IOB Thread.Sleep(100); startAdapters(); } catch (Exception exc) { lgError($"Eccezzione in download IOB conf files{Environment.NewLine}{exc}"); } } private void getIOBAssignmentsToolStripMenuItem_Click(object sender, EventArgs e) { // !!!FARE!!! // fa un check su server di quali IOB siano assegnate al PC (e modifica il file MAIN di avvio ripartendo...) } /// /// Carica file ini della configurazione richiesta /// /// private void loadIniFile(string iniConfFile) { displayTaskAndLog($"[STARTUP] Loading iniConfFile: {iniConfFile}"); IniFile fIni = new IniFile(iniConfFile); // salvo valori letti da INI file... branchName = fIni.ReadString("BRANCH", "NAME", "master"); MPIP = fIni.ReadString("SERVER", "MPIP", "ND"); MPURL = fIni.ReadString("SERVER", "MPURL", "/MP/IO"); CMDALIVE = fIni.ReadString("SERVER", "CMDALIVE", "/IOB"); CMDREBO = fIni.ReadString("SERVER", "CMDREBO", "/IOB/sendRebootGateway?GWIP="); CMDIOB2CALL = fIni.ReadString("SERVER", "CMDIOB2CALL", "/IOB/getIob2call?GWIP="); MAXCNC = fIni.ReadInteger("IOB", "MAXCNC", 1); string STARTLIST = fIni.ReadString("IOB", "STARTLIST", ""); // Gestione IOB da avviare IOB2START = new List(); // SE se sono in modo UPD --> nessuno if (ModoAvvio == StartMode.UPD) { IOB2START.Add("NONE"); } else { string[] elenco = null; // se modalità MAN CERCO se sostituire STARTLIST if (ModoAvvio == StartMode.MAN) { if (!string.IsNullOrEmpty(startParams["IOB"])) { STARTLIST = startParams["IOB"]; } } // se ho qualcosa... if (!string.IsNullOrEmpty(STARTLIST)) { elenco = STARTLIST.Split(','); // inserisco da elenco! foreach (var item in elenco) { IOB2START.Add(item); } } else { IOB2START.Add("NONE"); } } // init redis... string firstIob = "00"; if (IOB2START.Count > 0) { firstIob = IOB2START[0]; } redisMan = new RedisIobCache(MPIP, firstIob); } /// /// evento chiusura /// /// /// private void MainForm_FormClosing(object sender, FormClosingEventArgs e) { closeAllChild(); } /// /// evento resize /// /// /// private void MainForm_Resize(object sender, EventArgs e) { checkFormVisibility(); } /// /// evento visualizzazione /// /// /// private void MainForm_Shown(object sender, EventArgs e) { // SOLO SE se sono in modo STD if (ModoAvvio == StartMode.STD) { // avvio minimizzato se richiesto if (utils.CRB("startMinimized")) { // controllo e mando a tray... sendToTray(); } } displayTaskAndLog("Main Form SHOWN (MDI)"); } /// /// timer principale /// /// /// private void MainTimer_Tick(object sender, EventArgs e) { // inizio a riportare che sto funzionando.. advProgBar(); checkCom(); } /// /// Richeista verifica update /// /// /// private void mCheckUpdates_Click(object sender, EventArgs e) { lg.Info(string.Format("Avvio procedura controllo update:{0}branch: {1} | url: {2}", Environment.NewLine, branchName, updateUrl)); // avvio controllo AutoUpdater.ShowSkipButton = false; AutoUpdater.ShowRemindLaterButton = false; AutoUpdater.RunUpdateAsAdmin = utils.CRB("AUpdAsAdm"); AutoUpdater.ReportErrors = false; AutoUpdater.DownloadPath = @"C:\Steamware\src\"; AutoUpdater.ApplicationExitEvent += AutoUpdater_ApplicationExitEvent; AutoUpdater.Start(updateUrl); } private void minimizeALLToolStripMenuItem_Click(object sender, EventArgs e) { // ferma tutti i child form... foreach (var ChildForm in this.MdiChildren) { try { ChildForm.WindowState = FormWindowState.Minimized; } catch { } } } private void MShowMainLog_Click(object sender, EventArgs e) { try { string logPath = $"{System.AppDomain.CurrentDomain.BaseDirectory}logs\\MAIN\\{DateTime.Today:yyyy-MM-dd}.log"; Process.Start(logPath); } catch (Exception exc) { lgError($"Eccezione in show log (MAIN):{Environment.NewLine}{exc}"); } } /// /// doppio click su tray icon /// /// /// private void notifyIcon1_DoubleClick(object sender, EventArgs e) { // SOLO SE PERMESSO mostrare full... if (utils.CRB("windowCanMax")) { Show(); WindowState = FormWindowState.Normal; } } private void restartALLAdaptersToolStripMenuItem_Click(object sender, EventArgs e) { // chiudo closeAllChild(); Thread.Sleep(1000); // riapro startAdapters(); } private void sendIOBAssignmentsToolStripMenuItem_Click(object sender, EventArgs e) { // !!!FARE!!! // salva su server quali IOB siano gestite dal PC (da conf su MAIN...) } /// /// Gestisce "andata nel tray" della form /// private void sendToTray() { if (!notifyIcon1.Visible) { notifyIcon1.BalloonTipTitle = utils.CRS("appName"); notifyIcon1.BalloonTipText = string.Format("{0} running on tray", utils.CRS("appName")); notifyIcon1.Visible = true; notifyIcon1.ShowBalloonTip(100); } Hide(); } private void ShowLogToolStripMenuItem_Click(object sender, EventArgs e) { } /// /// Avvio gli adapters richeisti /// private void startAdapters() { // avvio child richiesti foreach (var item in IOB2START) { openChild(item); } // effettuo upload dei file di configurazione... uploadIobConfFile(); } /// /// click su menù contestuale in tray /// /// /// private void trayMenu_ItemClicked(object sender, ToolStripItemClickedEventArgs e) { if (e.ClickedItem.Text.StartsWith("Close")) { // stop child adapters... closeAllChild(); // chiudo! Close(); } else if (e.ClickedItem.Text.StartsWith("Show")) { if (utils.CRB("windowCanMax")) { Show(); WindowState = FormWindowState.Normal; } } } /// /// Effettua upload dei file di configurazione IOB /// private void uploadIobConfFile() { // upload su server i file CONF delle IOB attive... string answ = ""; smallFile currFile = null; string fileContent = ""; // ciclo su IOB configurati foreach (var currIob in IOB2START) { fileEmbed objFiles = new fileEmbed(); try { fileMover.obj.setDirectory(utils.confDir); var fileList = fileMover.obj.elencoFiles_FI(currIob + ".*"); foreach (var item in fileList) { fileContent = System.IO.File.ReadAllText($"{item.FullName}"); currFile = new smallFile() { fileName = item.Name, content = fileContent.Replace("\r\n", Environment.NewLine) }; objFiles.fileList.Add(currFile); } // serializzo string rawData = JsonConvert.SerializeObject(objFiles); if (utils.CRB("ConfToCloud")) { // invio su cloud... answ = utils.callUrl($"{urlUploadFileCloud}{currIob}", rawData); } else { // invio in locale! answ = utils.callUrl($"{urlUploadFile}{currIob}", rawData); } } catch (Exception exc) { lgError($"Eccezzione in upload IOB conf files{Environment.NewLine}{exc}"); } } } private void uploadIOBConfToolStripMenuItem_Click(object sender, EventArgs e) { uploadIobConfFile(); } #endregion Private Methods #region Protected Methods /// /// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere... /// /// protected static void lgError(string txt2log) { lg.Factory.Configuration.Variables["codIOB"] = "MAIN"; lg.Error(txt2log); } /// /// Effettua logging INFO corretto impostando anche la variabile IOB prima di scrivere... /// /// protected static void lgInfo(string txt2log) { lg.Factory.Configuration.Variables["codIOB"] = "MAIN"; lg.Info(txt2log); } /// /// CHiude le finestre child attive /// protected void closeActiveChild() { if (this.HasChildren) { try { this.ActiveMdiChild.Close(); this.LayoutMdi(MdiLayout.TileHorizontal); } catch { } } } protected void myInit() { DateTime adesso = DateTime.Now; resetProgBar = 0; formStartTime = adesso; lastComCheck = adesso.AddHours(-1); lblStatus.Text = "Loading"; // fix icon! notifyIcon1.Text = string.Format("IOB-WIN | {0}", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version); Icon = Icon.ExtractAssociatedIcon(utils.defIconFilePath); notifyIcon1.Icon = Icon.ExtractAssociatedIcon(utils.defIconFilePath); // fix versione! string nomeApp = $"{ConfigurationManager.AppSettings.Get("appName")} ({ModoAvvio})"; string versione = $" v.{System.Reflection.Assembly.GetExecutingAssembly().GetName().Version}"; lblApp.Text = nomeApp; lblVers.Text = versione; LogManager.ReconfigExistingLoggers(); lg = LogManager.GetCurrentClassLogger(); displayTaskAndLog("MainForm Starting"); // salvo versione SW! lgInfo("------ STARTUP DATA ------"); lgInfo($"App Mode : {nomeApp}"); lgInfo($"Versione : {versione}"); lgInfo("--------------------------"); // se abilitato autoload conf leggo file corretto... if (utils.CRB("autoLoadConf")) { try { loadIniFile(utils.mainConfFilePath); lgInfo("INI LOADED"); // avvio child come richiesto! startAdapters(); } catch (Exception exc) { displayTaskAndLog(string.Format("Eccezione in myInit: {0}", exc)); } } else { displayTaskAndLog("Waiting for config file selection"); } displayTaskAndLog("Program Running"); createTrayMenu(); displayTaskAndLog("Tray Menu OK"); // avvio minimizzato se richiesto if (utils.CRB("startMinimized")) { // imposto minimized se necessario! if (WindowState != FormWindowState.Minimized) { WindowState = FormWindowState.Minimized; } displayTaskAndLog("Minimized"); } try { IPStatus pingStatus = testPingServer; // se passa il ping faccio il resto... if (pingStatus == IPStatus.Success) { // segnalo reboot (programma)... utils.callUrl(urlReboot); } else { displayTaskAndLog("Server unreachable, cannot send urlReboot for MAIN FORM"); } } catch (Exception exc) { lgError(string.Format("MainForm myInit EXCEPTION in fase di chiamata URL di reboot:{0}{1}{2}", urlReboot, Environment.NewLine, exc)); } displayTaskAndLog("Main Form OK"); } /// /// Apre la finestra child con conf /// protected void openChild(string IOB) { if (IOB == null) { throw new ArgumentNullException(nameof(IOB)); } AdapterForm child = new AdapterForm(IOB); child.MdiParent = this; child.Text = IOB; child.Show(); child.Shown += Child_Shown; child.FormClosed += Child_FormClosed; } /// /// effettua salvataggio argomenti /// /// protected void saveArgs(string[] args) { if (args != null) { // salvo args di avvio (sono parametri tipo param1=val1 param2=test1,test2,test3 myArgs = args; if (myArgs.Length > 0) { // salvo dictionary! foreach (var item in myArgs) { var kvp = item.Split('='); startParams.Add(kvp[0], kvp[1]); } } // verifico gli args... if (startParams.ContainsKey("MODE")) { try { ModoAvvio = (StartMode)Enum.Parse(typeof(StartMode), startParams["MODE"]); } catch { } } } } #endregion Protected Methods #region Public Methods /// /// Avanza la barra di stato... /// public void advProgBar() { try { // aggiorno runtime... TimeSpan uptime = DateTime.Now.Subtract(formStartTime); tslRunTime.Text = string.Format("Running: {0}gg {1:00}:{2:00}:{3:00}", uptime.Days, uptime.Hours, uptime.Minutes, uptime.Seconds); if (MainProgrBar.Style != ProgressBarStyle.Marquee) { // se è arrivato a MAX resetto... MainProgrBar.PerformStep(); // verifico SE deve resettare progress bar if (resetProgBar > 10) { MainProgrBar.Value = 0; resetProgBar = 0; } // se arrivoa max imposto richiesta reset... if (MainProgrBar.Value == MainProgrBar.Maximum) { resetProgBar++; } // invalido x ridisegnare... MainProgrBar.Invalidate(); } } catch (Exception exc) { lgError($"Eccezione in advProgBar:{Environment.NewLine}{exc}"); } } /// /// mostra un testo sulla status bar + LOG /// /// public void displayTaskAndLog(string txt2show) { lblStatus.Text = txt2show; lblStatus.Invalidate(); lgInfo(txt2show); } /// /// Mostra update delle statistiche di comunicazione (num plc connessi, indirizzo server) con colore ad indicare anomalie... /// /// /// /// public void updateComStats(int numPLC, int numAttivi, bool serverOk) { // testo lblComStats.Text = $"{numAttivi}/{numPLC} PLC --> {MPIP} (MP/IO)"; // colore secondo valori... server !="ND" è ok, PLC > 0 è OK int score = 0; if (serverOk) { score++; } if (numPLC > 0 && numAttivi == numPLC) { score++; } switch (score) { case 0: lblComStats.ForeColor = Color.Red; break; case 1: lblComStats.ForeColor = Color.Orange; break; case 2: lblComStats.ForeColor = Color.Green; break; default: lblComStats.ForeColor = Color.Gray; break; } } #endregion Public Methods } }