コード例 #1
0
        /// <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);
        }
コード例 #2
0
        /// <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);
        }
コード例 #3
0
        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);
        }
コード例 #4
0
        /// <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);
        }
コード例 #5
0
        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);
        }
コード例 #6
0
        /// <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
コード例 #7
0
        /// <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);
        }