/// <summary> /// /// </summary> /// <param name="args"></param> private void Run(string[] args) { Thread.CurrentThread.Name = "Master"; string applicationPath = Assembly.GetExecutingAssembly().GetName().CodeBase; Log.Info(Log.Dashes); Log.Info("STARTING " + applicationPath); foreach (string arg in args) { Log.Info(string.Format("arg: \"{0}\"", arg)); } Log.Debug(Thread.CurrentThread.Name + " ThreadId=" + Thread.CurrentThread.ManagedThreadId.ToString("x8")); Log.Info(Log.Dashes); // We want the Controller class to load now, so that it's static // constructor reads the config file. It's important to do this // before starting ANY of the service threads. Calling any // random property of the Controller class will cause the class to load. Controller.ApplicationPath = applicationPath; // Stop the pump and speaker on startup. This is primarily done because if // the debugger is stopped then restarted while the pump or speaker are on, then they're left on. // if we don't do this... Controller.TurnBuzzerOff(); Pump.Stop(); // Instantiate the console service immediately so that we can display // the "Starting" message ASAP. Note that we don't yet start the thread, // though, since we don't need (yet), to monitor for keypad input. LCD.Clear(); // This is the first time we're accessing the LCD class, so it's static constructor will be called here. LCD.SetLanguage(Configuration.DockingStation.Language); Controller.LastRebootTime = DateTime.UtcNow; Controller.FirmwareVersion = string.Format("{0}.{1}.{2}.{3}", Assembly.GetExecutingAssembly().GetName().Version.Major, Assembly.GetExecutingAssembly().GetName().Version.Minor, Assembly.GetExecutingAssembly().GetName().Version.Build, Assembly.GetExecutingAssembly().GetName().Version.Revision); _consoleService = new ConsoleService(this); Log.Debug(ConsoleService.Name + " has been created."); ConsoleService.Start(); // Calling InitializeState now will force the display to refresh and say "Starting" // right away. If we don't do this, it remains blank for a second or two. ConsoleService.InitializeState(); try { Configuration.ServiceMode = Controller.DetermineServiceMode(); } catch (Exception e) { Log.Error(e); } // Did something go wrong trying to read the configuration data from the flash memory? if (Configuration.HasConfigurationError && Configuration.DockingStation.IsSerialized()) { Controller.RunState |= Controller.State.ConfigError; } // Verify that we have a flash card. We can't do much of anything without one. bool haveFlashCard = FlashCard.WaitForMount(); if (haveFlashCard) { Log.Info("Found a mounted flash card"); } else { Log.Fatal("ERROR: FLASH CARD NOT FOUND."); Controller.RunState |= Controller.State.FlashCardError; } Log.Info(Log.Dashes); Log.Info("Firmware Version: " + Controller.FirmwareVersion); Log.Info(Log.Dashes); Controller.LogSystemInfo(); Log.Info(Log.Dashes); Controller.LogProcessorInfo(); Log.Info(Log.Dashes); Controller.LogMemory(); Log.Info(Log.Dashes); if (haveFlashCard) { FlashCard.Log(); Log.Info(Log.Dashes); } Log.Info("MAC Address: " + Controller.GetWiredNetworkAdapter().MacAddress); Log.Info(Log.Dashes); if (haveFlashCard) { DataAccess.DataAccess.StartInet(); DataAccess.DataAccess.StartInetQueue(); } // Before we can start the WebAppService, we need to initialize // the password used to login to it. // Note that for debug builds, we configure it to not use SLL. // There are two reasons for this... // 1) SSL slows done iNet DS Configurator, which is annoying // when we developers are constantly logging into it to use it. // 2) There is some sort of problem when Padarn is using SSL // that causes the Visual Studio debugger to lose its connections // to the device. #if DEBUG Configuration.ConfigureWebApp(Configuration.DockingStation.WebAppPassword, false); #else Configuration.ConfigureWebApp(Configuration.DockingStation.WebAppPassword, true); #endif if (Controller.RunState == Controller.State.OK) { InitializeWinsock(); } // AJAY: INS-8380 Service accounts need to perform auto-upgrade on instruments even in error/fail state - DSX // If service account is configured to override event priority in admin console, // this method reorders events that needs to be executed on docking station. if (Configuration.IsRepairAccount() && Configuration.DockingStation.UpgradeOnErrorFail) { ISC.iNet.DS.DomainModel.EventCode.SetEventPriorityForService(); } // Initialize, wire up and start all necessary services. // Note that this will be iterated every time any of the // services gets interrupted. // Create the services. Log.Debug("Creating services..."); _resourceService = new ResourceService(this); Log.Debug(ResourceService.Name + " has been created."); _reporterService = new ReporterService(this); Log.Debug(ReporterService.Name + " has been created."); _executerService = new ExecuterService(this); Log.Debug(ExecuterService.Name + " has been created."); _switchService = new SwitchService(this); Log.Debug(SwitchService.Name + " has been created."); _chargingService = new ChargingService(this); Log.Debug(ChargingService.Name + " has been created."); _webAppService = new WebAppService(this); Log.Debug(WebAppService.Name + " has been created."); _controllerWrapper = ControllerWrapper.Instance; _pumpWrapper = PumpManager.Instance; _lcdWrapper = LCDWrapper.Instance; _smartCardWrapper = SmartCardWrapper.Instance; // Start the services. Log.Debug("Starting service threads..."); if (Controller.RunState == Controller.State.OK) { ResourceService.Start(); } // Don't start the Switch, Charging, or Executer service if the DS has // not been serialized. Only the Configurator web app will be functional. if (Configuration.DockingStation.IsSerialized()) { ExecuterService.Start(); if (Controller.RunState == Controller.State.OK) { SwitchService.Start(); } if (Controller.RunState == Controller.State.OK) { ChargingService.Start(); } } else { // update the LCD ConsoleService.UpdateState(ConsoleState.NotSerialized); } if (Controller.RunState == Controller.State.OK) { ReporterService.Start(); } WebAppService.Start(); Log.Debug("Service threads started."); // the controller's static constructor will initialize the other logging settings, // but we always want to log all the initialization stuff above out the serial port Log.LogToSerialPort = Configuration.ServiceMode ? true : Configuration.DockingStation.LogToSerialPort; // always log in service mode // Determine if sequenceId passed in as argument. This is number that will be automatically // passed in as an argument to the process when Windows CE boots the device. If process // is manually started, then no sequence ID will be passed. If sequenceId is passed in, // then process MUST call SignalStarted when it feels that it's safely up and running // in order to continue with the proper boot sequence. if (args.Length > 0) { uint sequenceId = 0; try { sequenceId = UInt32.Parse(args[0]); } catch { Log.Debug("Invalid sequenceId (" + args[0] + ") found. SignalStarted not called."); } if (sequenceId > 0) { Log.Debug("SignalStarted(" + sequenceId + ")"); WinCeApi.SignalStarted(sequenceId); } } // INS-6183, 6/8/2015 - This watchdog is used in the below while-loop. The while-loop // periodically calls MonitorNetworkConnection(), which calls GetWiredNetworkAdapter(), // which calls GetNetworkAdapters(). GetNetworkAdapters() makes a call to OpenNetCF // SDF's GetAllNetworkInterfaces() to get the networking info from the OS. // Sometimes that call throws a Data Abort (unmanaged exception). Unmanaged exceptions // cannot be caught in .Net, so the exception is thrown outside and above the application, // which causes OS to display a message box informing of the Data Abort. The message box // waits for a user to press its OK button, so the thread that threw the Data Abort is // effectly hung waiting for somebody to press an OK button which is never going to happen. // The data abort may be thrown by a thread other this Master thread. But this watchdog // for the master thread should still work in that situation. This is because the // aforementioned GetNetworkAdapters has a "lock" block in it. If another thread calls // GetNetworkAdapters, it will a obtain a lock, then call into SDF's GetAllNetworkInterfaces. // If the data abort is then thrown, then GetNetworkAdapters will not have a chance to // release its lock. Then, next time master thread trys to call GetNetworkAdapters, it will // hang trying to obtain a lock, which it will never be able to do, so the watchdog timer // will eventually expire, causing a reboot, as desired. WatchDog watchDog = new WatchDog("MasterWatchDog", 60000, Log.LogToFile); // reboot if not refreshed in 60 seconds. watchDog.Start(); /////////////////////////////////////////////////////////////////////// // Used for smart card debugging. Please leave this code here for now. /////////////////////////////////////////////////////////////////////// // I2CTestThread i2cTest= new I2CTestThread(); // i2cTest.StartWork(); MonitorNetworkConnection(); Controller.LogMemoryUsage(); // Now that we've fired off the child worker threads, we have nothing more to do // except hang out and stay alive. Lower our priority and take a nap. //Thread.CurrentThread.Priority = ThreadPriority.BelowNormal; int sleepTime = 5000; int lastCheck = 0; while (true) { Thread.Sleep(sleepTime); lastCheck += sleepTime; if (lastCheck >= 300000) // 5 minutes { MonitorNetworkConnection(); //Logger.Debug( "Total Up Time: " + ( runTime / 1000 ) + " seconds" ); //Controller.LogMemoryUsage(); lastCheck = 0; } if (Controller.RunState != Controller.State.OK) { string errNum = ((int)Controller.RunState).ToString("x8"); // If a menu is active, skip the operation for now. (the only menu that should // possibly ever be active is the factory reset confirmation menu). if (!ConsoleService.IsMenuActive) { Log.Trace("SYSTEM ERROR ENCOUNTERED with error number " + errNum); if (errNum.Equals("00000001")) { ConsoleService.UpdateState(ConsoleState.ContactISCCode1011); } else if (errNum.Equals("00000002")) { ConsoleService.UpdateState(ConsoleState.ContactISCCode1012); } else if (errNum.Equals("00000004")) { ConsoleService.UpdateState(ConsoleState.ContactISCCode1014); } else if (errNum.Equals("00000008")) { ConsoleService.UpdateState(ConsoleState.ContactISCCode1018); } else if (errNum.Equals("00000010")) { ConsoleService.UpdateState(ConsoleState.ContactISCCode10110); } else { ConsoleService.UpdateState(ConsoleState.ContactISCCode10160); } } } if (lastCheck == 0 || lastCheck >= 10000) { watchDog.Refresh(); } } } // end-Run