/// <summary> /// Determines current charging status of the docked instrument. /// </summary> /// <returns> /// The returned DockingStationEvent is always null. /// </returns> /// <exception cref="InstrumentNotDockedException"> /// If instrument is undocked /// </exception> /// <exception cref="InstrumentPingFailedException"> /// Failure to turn on the instrument. /// </exception> public DockingStationEvent Execute() { if (Configuration.DockingStation.Type != DeviceType.MX4 && Configuration.DockingStation.Type != DeviceType.MX6) { return(null); } if (!Controller.IsDocked()) { throw new InstrumentNotDockedException(); } Log.Debug(this.Name + ".Execute"); using (InstrumentController instrumentController = SwitchService.CreateInstrumentController()) { // Turn on the instrument, the ask it for it's charging status try { // Note that we deliberately do NOT use batch mode. We're only trying to read a very // few number of messages. So it's not worth the effort and time it takes to negotiate // faster baud rate and establish a batched connection to the instrument. It's much // quicker to just read the few registers at the slow baud rate. instrumentController.Initialize(InstrumentController.Mode.NoLid /* lid not necessary */); InstrumentSerialNumber = instrumentController.GetSerialNumber(); BatteryCode = instrumentController.GetBatteryCode(); InstrumentChargePhase = instrumentController.GetChargePhase(); Log.Warning(string.Format("{0}: BatteryCode={1}, ChargePhase=\"{2}\"", this.Name, BatteryCode, InstrumentChargePhase)); } catch (InstrumentPingFailedException ipef) // Couldn't turn on the instrument? { // will get a ping failure if undocked. if (!Controller.IsDocked()) { throw new InstrumentNotDockedException(); } Log.Error(this.Name, ipef); throw; } catch (CommunicationAbortedException cae) // thrown by driver when instrument is undocked. { Log.Error(this.Name, cae); throw new InstrumentNotDockedException(); } } return(null); }
/// <summary> /// Executes an instrument discovery operation. /// </summary> /// <returns>Docking station event</returns> public DockingStationEvent Execute() { InstrumentNothingEvent instrumentNothingEvent; using (InstrumentController instrumentController = SwitchService.CreateInstrumentController()) { // Create the return event. instrumentNothingEvent = new InstrumentNothingEvent(this); // Open the serial port connection needed to communicate with the instrument. instrumentController.Initialize(); } return(instrumentNothingEvent); }
private InstrumentNothingEvent DiscoverInstrument() { // Create the return event. InstrumentNothingEvent instrumentNothingEvent = new InstrumentNothingEvent(this); InstrumentController instrumentController = SwitchService.CreateInstrumentController(); try { // Open the serial port connection needed to communicate with the instrument. instrumentController.Initialize(InstrumentController.Mode.Batch); // MX4 is the default instrument controller created for MX4 docking stations. if (instrumentController is MX4) { // VPRO instrument controller may need created instead depending on type of docked instrument. if (instrumentController.GetInstrumentType() == DeviceType.VPRO) { // Clean up MX4 controller. instrumentController.Dispose(); // Create and initialize VPRO controller. instrumentController = new VPRO(); instrumentController.Initialize(InstrumentController.Mode.Batch); } } // If we make it through InstrumentController.Initialize without throwing, then // we assume the instrument is now on, or at least it's IrDA is. InstrumentOff = false; Stopwatch sw = new Stopwatch(); sw.Start(); // TxRxRetries value is returned by modbuslibrary.dll. It continally increments the value and never resets it back to zero. // So, before reading data from the instrument, we get the current value. Farther below, when we're finished reading, we get // the value again, and subtract this starting value to determine how many retries occurred during this particular discovery. // Getting this starting value also lets us subtract out any of the retries occurring during initializing above. int startTxRxRetries = instrumentController.Driver.TxRxRetries; // Retrieve the docked instrument. instrumentNothingEvent.DockedInstrument = instrumentController.DiscoverDockedInstrument(true); // INS-8228 RHP v7.6, Service accounts need to perform auto-upgrade on instruments even in error/fail state Master.Instance.SwitchService.IsInstrumentInSystemAlarm = instrumentController.IsInstrumentInSystemAlarm; sw.Stop(); int txRxCount = instrumentController.Driver.TxRxCount; double txRxCountPerSecond = (double)txRxCount / (sw.ElapsedMilliseconds / 1000.0); int txRxRetries = instrumentController.Driver.TxRxRetries - startTxRxRetries; Log.Debug(string.Format("Modbus statistics: stopwatch={0}ms, TxRx={1} ({2}/s), retries={3}", sw.ElapsedMilliseconds, txRxCount, txRxCountPerSecond.ToString("f0"), txRxRetries)); } catch (InstrumentSystemAlarmException) // SGF Nov-23-2009 DSW-355 (DS2 v7.6) { // If the user docked an instrument in system alarm, then just rethrow up to the service // that invoked this discovery and let it deal with it. throw; } catch (HardwareConfigurationException) { // If user failed to reconfigure the docking station hardware, then just rethrow up to the service // that invoked this discovery and let it deal with it. throw; } catch (Exception e) { Log.Error(this.GetType().ToString() + ".Execute.DiscoverDockedInstrument", e); // ******************************************************************** // See INS-6671 and INS-6682 as to why the second discover was removed. // ******************************************************************** throw; } // end-catch finally { instrumentController.Dispose(); } return(instrumentNothingEvent); }
/// <summary> /// Executes a turn off instrument operation. /// </summary> /// <returns>A InstrumentTurnOffEvent, which contains the TurnOffAction /// indicating what exactly the Execute() decided to do. /// </returns> /// <exception cref="InstrumentNotDockedException">If an instrument is not docked.</exception> public DockingStationEvent Execute() { string funcName = Name + ".Execute"; Log.Debug(funcName + ", Reason=" + _reason); InstrumentTurnOffEvent _returnEvent = new InstrumentTurnOffEvent(this); #if DEBUG // When debugging, don't turn off the GBPROs since they annoyingly take too long to turn back on. if (Configuration.DockingStation.Type == DeviceType.GBPRO) { _returnEvent.TurnOffAction = TurnOffAction.None; Log.Info(string.Format("{0}.Execute doing nothing due to DEBUG directive", Name)); return(_returnEvent); } #endif _returnEvent.TurnOffAction = GetTurnOffAction(); if (_returnEvent.TurnOffAction == TurnOffAction.NotSupported) { Log.Warning(string.Format("{0}: Docked {1}'s cannot be turned off.", funcName, Configuration.DockingStation.Type)); return(_returnEvent); } else if (_returnEvent.TurnOffAction == TurnOffAction.None) { Log.Warning(string.Format("{0}: Docked {1} should already be off.", funcName, Configuration.DockingStation.Type)); return(_returnEvent); } else { if (!Controller.IsDocked()) { throw new InstrumentNotDockedException(); } using (InstrumentController instrumentController = SwitchService.CreateInstrumentController()) { // Note that we specify NoPing. This causes the instrument controller to *not* call the // driver's connect method. instrumentController.Initialize(InstrumentController.Mode.NoPing); try { if (_returnEvent.TurnOffAction == TurnOffAction.Shutdown) { // Even the instruments which cannot shutdown will have this called // so their sensors get turned off. instrumentController.TurnOff(); } else if (_returnEvent.TurnOffAction == TurnOffAction.TurnOffSensors) { if (instrumentController.GetOperatingMode() == OperatingMode.WarmingUp) { // MX6 instrument does not support going to Charging mode when it is currently WarmingUp. // So we need to try again later after the instrument has transitioned to Running. _returnEvent.TurnOffAction = TurnOffAction.Postponed; Log.Debug(funcName + ", WAITING FOR WARM UP TO COMPLETE. TURN OFF POSTPONED."); } else { // This should only need to be called for MX6 rechargeable instruments. instrumentController.TurnOnSensors(false, false); } } } catch (CommunicationException ce) { Log.Debug(funcName + " caught CommunicationException: " + (Log.Level >= LogLevel.Trace ? ce.ToString() : ce.Message)); Log.Debug(funcName + " FAILED. Instrument might already be in OFF state."); } } } return(_returnEvent); }
public DockingStationEvent Execute() { string funcMsg = Name + ".Execute"; Log.Debug(funcMsg); // create return event InstrumentDisableReplacedEvent returnEvent = new InstrumentDisableReplacedEvent(this); returnEvent.DetectedReplacedSerialNumber = this.ReplacedSerialNumber; try { // record docking station and docked instrument on return event, // instrument serial number will be stored in the event journal returnEvent.DockingStation = Configuration.DockingStation; returnEvent.DockedInstrument = (ISC.iNet.DS.DomainModel.Instrument)Master.Instance.SwitchService.Instrument.Clone(); // check that the instrument is still docked if (!Controller.IsDocked()) { throw new InstrumentUndockedDuringDisableReplacedException(); } // establish communication with the docked instrument, verify it has the expected // serial number, and then disable it using (IFactoryController factoryController = SwitchService.CreateFactoryInstrumentController()) { factoryController.InstrumentController.Initialize(InstrumentController.Mode.Batch); returnEvent.SerialNumberBefore = factoryController.InstrumentController.GetSerialNumber(); // ensure the docked instrument serial number, the instrument serial number that will be saved to the event journal, and the detected // replaced instrument serial number all match before continuing if (returnEvent.SerialNumberBefore == this.ReplacedSerialNumber && returnEvent.DockedInstrument.SerialNumber == this.ReplacedSerialNumber) { Log.Warning(string.Format("DISABLING REPLACED INSTRUMENT: {0}", returnEvent.SerialNumberBefore)); factoryController.DisableReplacedInstrument(); Log.Warning(string.Format("INSTRUMENT DISABLED")); // set flag on switch service to stop anything else from happening until the disabled instrument is undocked Master.Instance.SwitchService.IsInstrumentReplaced = true; returnEvent.Passed = true; returnEvent.SerialNumberAfter = factoryController.InstrumentController.GetSerialNumber(); } } } catch (InstrumentUndockedDuringDisableReplacedException) { throw; } catch (Exception ex) { Log.Error(string.Format("{0} - Caught Exception", funcMsg), ex); // check that the instrument is still docked if (!Master.Instance.SwitchService.IsDocked()) { throw new InstrumentUndockedDuringDisableReplacedException(); } } finally { // log operation results Log.Debug(string.Format("WAS INSTRUMENT DISABLED: {0} - Detected Replaced S/N: {1} - S/N (before): {2} - S/N (after): {3}", returnEvent.Passed, returnEvent.DetectedReplacedSerialNumber, returnEvent.SerialNumberBefore, returnEvent.SerialNumberAfter)); } return(returnEvent); }
/// <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
/// <summary> /// Executes an instrument settings update operation. /// </summary> /// <returns>Docking station event</returns> public DockingStationEvent Execute() { Stopwatch stopwatch = Log.TimingBegin("INSTRUMENT SETTINGS UPDATE"); // Check for a docked instrument. if (!Master.Instance.ControllerWrapper.IsDocked()) { throw new InstrumentNotDockedException(); } string serialNumber = Master.Instance.SwitchService.Instrument.SerialNumber; DeviceType instrumentType = Master.Instance.SwitchService.Instrument.Type; if (serialNumber == string.Empty || instrumentType == DeviceType.Unknown) { throw new InstrumentNotDockedException(); } // Create the return event. _instrumentSettingsUpdateEvent = new InstrumentSettingsUpdateEvent(this); // Retrieve the docking station's information. _instrumentSettingsUpdateEvent.DockingStation = Master.Instance.ControllerWrapper.GetDockingStation(); _instrumentSettingsUpdateEvent.DockedTime = Master.Instance.SwitchService.DockedTime; // Get the settings from the database to update the instrument with. Instrument settings = new InstrumentDataAccess().FindApplicableSettings(serialNumber, instrumentType); // If no instrument settings found, then there's nothing more we can do. // since we can't update the instrument's settings if we have no settings. if (settings == null) { string errMsg = string.Format("Unable to find instrument settings for S/N \"{0}\"", serialNumber); _instrumentSettingsUpdateEvent.Errors.Add(new DockingStationError(errMsg, DockingStationErrorLevel.Warning)); return(_instrumentSettingsUpdateEvent); } // The settings loaded only apply to the discovered instrument. // We don't know if the settings loaded are the defaults are not // so we just set the type to what we searched for above. settings.Type = instrumentType; // Merge the loaded settings with our Instrument. using (_instCtrlr = SwitchService.CreateInstrumentController()) { // Open the serial port connection needed to communicate with the instrument. _instCtrlr.Initialize(InstrumentController.Mode.Batch); // After an instrument settings read, we need to send a command to the instrument // to have it clear its base unit log. Only SafeCore needs this command. _instCtrlr.ClearBaseUnits(); // Update the docked instrument. _instrumentSettingsUpdateEvent.DockedInstrument = UpdateInstrument(settings, serialNumber); // Settings RefId will contain the ID of the settings used during the Update Event. Otherwise, will be Nullid. // We place it into the event's Instrument in order to upload it to iNet. _instrumentSettingsUpdateEvent.DockedInstrument.RefId = settings.RefId; if (_instrumentSettingsUpdateEvent.DockingStation.ClearPeaksUponDocking) { _instCtrlr.ClearInstrumentSensorPeaks(_instrumentSettingsUpdateEvent.DockedInstrument.InstalledComponents); } } // end-using Log.TimingEnd("INSTRUMENT SETTINGS UPDATE", stopwatch); return(_instrumentSettingsUpdateEvent); }