/// <summary>
        /// Get the elapsed times, in ms, between the RTC time of each frame of historic data and the Start Time of the plot.
        /// </summary>
        /// <param name="startTime">The start time of the plot.</param>
        /// <param name="historicDataManager">Reference to the historic data that is to be plotted.</param>
        /// <returns>An array containing the elapsed time, in ms, since the specified start time of the plot for each frame of historic data.</returns>
        public long[] GetElapsedTimes(DateTime startTime, IHistoricDataManager historicDataManager)
        {
            long[] elapsedTime   = new long[historicDataManager.FramesToDisplay.Count];
            long   timeFromStart = 0;

            // Round down to the nearest data interval.
            long adjust;

            for (int frame = 0; frame < m_HistoricDataManager.FramesToDisplay.Count; frame++)
            {
                timeFromStart      = (long)m_HistoricDataManager.FramesToDisplay[frame].CurrentDateTime.Subtract(startTime).TotalMilliseconds;
                adjust             = timeFromStart % 10;
                timeFromStart     -= adjust;
                elapsedTime[frame] = (timeFromStart >= 0) ? timeFromStart : 0;
            }
            return(elapsedTime);
        }
        /// <summary>
        /// Clean up the resources used by the form.
        /// </summary>
        /// <param name="disposing">True to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
        protected override void Cleanup(bool disposing)
        {
            try
            {
                if (disposing)
                {
                    // Method called by consumer code. Call the Dispose method of any managed data members that implement the dispose method.
                    // Cleanup managed objects by calling their Dispose() methods.
                    if (components != null)
                    {
                        components.Dispose();
                    }

                    if (m_TimerPlay != null)
                    {
                        m_TimerPlay.Dispose();
                    }
                }

                // Whether called by consumer code or the garbage collector free all unmanaged resources and set the value of managed data 
                // members to null.
                m_TimerPlay = null;
                m_HistoricDataManager = null;

                #region - [Detach the event handler methods.] -
                this.Shown -= new System.EventHandler(this.FormDataStreamReplay_Shown);
                #endregion - [Detach the event handler methods.] -
            }
            catch (Exception)
            {
                // Don't do anything, just ensure that an exception isn't thrown.
            }

            base.Cleanup(disposing);
        }
        /// <summary>
        /// Initializes a new instance of the class.
        /// </summary>
        /// <param name="historicDataManager">Reference to the <c>HistoricDataManager</c> object containing the data frames that are to be displayed.</param>
        /// <param name="watchFile">The saved watch data file.</param>
        public FormDataStreamReplay(IHistoricDataManager historicDataManager, WatchFile_t watchFile ) : base(watchFile.DataStream.Workset)
        {
            InitializeComponent();

            WatchFile = watchFile;
            m_Workset = WatchFile.DataStream.Workset;
            m_HistoricDataManager = historicDataManager;

            // Instantiate the class that helps manage the user controls.
            m_WatchControlLayout = new WatchControlLayout(this, m_HistoricDataManager);

            #region - [Function Keys] -
            // Escape - Exit
            // F1 - Help
            // F2 - Print
            // F3 - Save (Not  Used)
            // F4 - YTPlot
            // F5 - Trip
            // F6 - First
            // F7 - Previous
            // F8 - Next
            // F9 - Last
            // F11 - Play
            // F12 - Header Information
            DisplayFunctionKey(F3, Resources.FunctionKeyTextSave, Resources.FunctionKeyToolTipSave, Resources.Save);
            F3.Enabled = false;
            DisplayFunctionKey(F4, Resources.FunctionKeyTextYTPlot, Resources.FunctionKeyToolTipYTPlot, Resources.YTPlot);

            // Only display the trip function key if the historic data is a fault log or simulated fault log.
            if ((m_HistoricDataManager.LogType == LogType.DataStream) || (m_HistoricDataManager.LogType == LogType.SimulatedDataStream))
            {
                DisplayFunctionKey(F5, Resources.FunctionKeyTextTrip, Resources.FunctionKeyToolTipTrip, Resources.Trip);
            }

            DisplayFunctionKey(F6, Resources.FunctionKeyTextFirst, Resources.FunctionKeyToolTipFirst, Resources.MoveFirst);
            DisplayFunctionKey(F7, Resources.FunctionKeyTextPrevious, Resources.FunctionKeyToolTipPrevious, Resources.MovePrevious);
            DisplayFunctionKey(F8, Resources.FunctionKeyTextNext, Resources.FunctionKeyToolTipNext, Resources.MoveNext);
            DisplayFunctionKey(F9, Resources.FunctionKeyTextLast, Resources.FunctionKeyToolTipLast, Resources.MoveLast);
            DisplayFunctionKey(F11, Resources.FunctionKeyTextPlay, Resources.FunctionKeyToolTipPlay, Resources.Play);
            DisplayFunctionKey(F12, Resources.FunctionKeyTextInfo, Resources.FunctionKeyToolTipInfo, Resources.FileInformation);
            #endregion - [Function Keys] -

            #region - [InformationLabels/Legend] -
            // InformationLabel 1  - Date
            // InformationLabel 2  - Start Time
            // InformationLabel 3  - Stop Time
            // InformationLabel 4  - Duration
            // InformationLabel 5  - Time
            // InformationLabel 6  - Frame
            DisplayLabel(InformationLabel1, Resources.InformationLegendDate, Color.MintCream);
            DisplayLabel(InformationLabel2, Resources.InformationLegendStartTime, Color.PaleGreen);
            DisplayLabel(InformationLabel3, Resources.InformationLegendStopTime, Color.LightCoral);
            DisplayLabel(InformationLabel4, Resources.InformationLegendDuration, Color.Khaki);
            DisplayLabel(InformationLabel5, Resources.InformationLegendRTC, Color.FromKnownColor(KnownColor.GradientInactiveCaption));
            DisplayLabel(InformationLabel6, Resources.InformationLegendFrame, Color.FromKnownColor(KnownColor.Info));
            #endregion - [InformationLabels/Legend] -

            #region - [Title] -
            Text =  Resources.TitleReplay + CommonConstants.Colon + WatchFile.Filename;
            #endregion - [Title] -

            #region - [Play Timer] -
            m_TimerPlay = new System.Windows.Forms.Timer();
            m_TimerPlay.Tick += new EventHandler(DisplayNextFrame);
            m_TimerPlay.Interval = IntervalTimerPlayInitialValue;
            m_TimerPlay.Enabled = true;
            m_TimerPlay.Stop();
            #endregion - [Play Timer] -
            
            UpdateStatusLabels();

            // Update the tab with the name of the workset.
            m_TabControl.TabPages[m_TabControl.SelectedIndex].Text = m_Workset.Name;

            // Display the values associated with the first frame.
            m_Index = 0;

            // Frame.
            InformationLabel6.Text = m_Index.ToString();

            // Don't allow the user to attempt to modify watch variable data values from this form.
            VariableControl.ReadOnly = true;
        }
示例#4
0
 /// <summary>
 /// Initializes a new instance of the class.
 /// </summary>
 /// <param name="form">Reference to the form which instantiated the class.</param>
 /// <param name="historicDataManager">Reference to the <c>HistoricDataManager</c> object associated with the calling form.</param>
 public WatchControlLayout(Form form, IHistoricDataManager historicDataManager)
     : this(form)
 {
     m_HistoricDataManager = historicDataManager;
 }
        /// <summary>
        /// Check whether there were any breaks in communication with the VCU and set the breakpoint values of each plotter controls accordingly. This allows the plot
        /// to be drawn using a transparent pen for periods where there was a break in transmission.
        /// </summary>
        /// <param name="controlCollection">Reference to the <c>TableLayoutControlCollection</c> containing the <c>IPlotterWatch</c> derived user controls.</param>
        /// <param name="startTime">The start time of the plot.</param>
        /// <param name="historicDataManager">Reference to the <c>HistoricDataManager</c> class containing the data that is to be plotted.</param>
        public void SetBreakpoints(TableLayoutControlCollection controlCollection, DateTime startTime, IHistoricDataManager historicDataManager)
        {
            // Skip, if the Dispose() method has been called.
            if (m_IsDisposed)
            {
                return;
            }

            // Skip, if there are no plotter controls associated with the TableLayoutPanel.
            if (controlCollection.Count == 0)
            {
                return;
            }

            // The time, in ms since the start of the plot, where a break in the sequence was detected.
            long breakpoint;

            // The DateTime corresponding to the previous entry, used to determine a break in the log sequence for running logs.
            DateTime previousEntryDateTime = new DateTime();

            // The interval between concurrent frames above which the plot is considered to have been interrupted i.e a new breakpoint has been triggered.
            TimeSpan breakpointTriggerInterval = new TimeSpan(0, 0, 0, 0, BreakpointTriggerIntervalAsMultiple * Parameter.IntervalWatchMs);

            long adjust;

            for (int frame = 0; frame < m_HistoricDataManager.FramesToDisplay.Count; frame++)
            {
                // Don't perform comparison on the first entry.
                if (frame != 0)
                {
                    if (historicDataManager.FramesToDisplay[frame].CurrentDateTime.Subtract(previousEntryDateTime) > breakpointTriggerInterval)
                    {
                        // Detected a break in the log sequence, record the previous entry as a breakpoint, round down to the nearest 10ms.
                        breakpoint  = (long)previousEntryDateTime.Subtract(startTime).TotalMilliseconds;
                        adjust      = breakpoint % BreakpointResolutionMs;
                        breakpoint -= adjust;

                        // Record the breakPoint for each plotter.
                        for (int index = 0; index < controlCollection.Count; index++)
                        {
                            // Skip, if the plotter user control has not been configured.
                            if ((controlCollection[index] as IPlotterWatch) == null)
                            {
                                continue;
                            }

                            (controlCollection[index] as IPlotterWatch).Channels[0].SetBreakPoint(breakpoint);
                        }
                    }
                }
                previousEntryDateTime = m_HistoricDataManager.FramesToDisplay[frame].CurrentDateTime;
            }
        }
        /// <summary>
        /// Plot the historic watch values stored within <paramref name="historicDataManager"/> using the <c>IPlotterWatch</c> derived plotter user controls associated
        /// with the specified <c>TableLayoutControlCollection</c>.
        /// </summary>
        /// <param name="controlCollection">Reference to the <c>TableLayoutControlCollection</c> containing the <c>IPlotterWatch</c> derived plotter controls used
        /// to plot the historic data.</param>
        /// <param name="historicDataManager">Reference to the <c>HistoricDataManager</c> class containing the data that is to be plotted.</param>
        /// <param name="elapsedTime">The elapsed time, in ms, since the start of the plot for each frame that is to be plotted.</param>
        public void PlotWatchValues(TableLayoutControlCollection controlCollection, IHistoricDataManager historicDataManager, long[] elapsedTime)
        {
            // Skip, if the Dispose() method has been called.
            if (m_IsDisposed)
            {
                return;
            }

            // Skip, if there are no plotter controls associated with the TableLayoutPanel.
            if (controlCollection.Count == 0)
            {
                return;
            }

            short         oldIdentifier, watchElementIndex;
            IPlotterWatch plotterWatch;
            WatchVariable watchVariable;

            for (int index = 0; index < controlCollection.Count; index++)
            {
                plotterWatch = controlCollection[index] as IPlotterWatch;

                // Skip, if the plotter user control has not been configured.
                if (plotterWatch == null)
                {
                    continue;
                }

                oldIdentifier = plotterWatch.Identifier;

                try
                {
                    watchVariable = Lookup.WatchVariableTableByOldIdentifier.Items[oldIdentifier];

                    // Check whether the watch variable exists.
                    if (watchVariable == null)
                    {
                        // No, skip this entry.
                        continue;
                    }
                }
                catch (Exception)
                {
                    continue;
                }

                // Get the watch element index associated with the old identifier identifier.
                watchElementIndex = m_HistoricDataManager.GetWatchElementIndex(oldIdentifier);

                // Check whether the old watch file contains watch values associated with this old identifier.
                if (watchElementIndex == CommonConstants.NotDefined)
                {
                    continue;
                }

                if (watchElementIndex > historicDataManager.Workset.CountMax)
                {
                    throw new ArgumentOutOfRangeException("watchElementIndex", "PlotterControlLayout.PlotWatchValues()");
                }

                plotterWatch.Start();

                if ((plotterWatch as IPlotterScalar) != null)
                {
                    double engineeringValue;
                    for (int frame = 0; frame < historicDataManager.FramesToDisplay.Count; frame++)
                    {
                        engineeringValue = watchVariable.ScaleFactor * historicDataManager.FramesToDisplay[frame].WatchElements[watchElementIndex].Value;
                        plotterWatch.Channels[0].SetYTValue((float)engineeringValue, elapsedTime[frame]);
                    }
                }
                else if ((plotterWatch as IPlotterEnumerator) != null)
                {
                    double engineeringValue;
                    for (int frame = 0; frame < historicDataManager.FramesToDisplay.Count; frame++)
                    {
                        engineeringValue = watchVariable.ScaleFactor * historicDataManager.FramesToDisplay[frame].WatchElements[watchElementIndex].Value;
                        plotterWatch.Channels[0].SetYTValue((float)engineeringValue, elapsedTime[frame]);
                    }
                }
                else if ((plotterWatch as IPlotterBitmask) != null)
                {
                    IPlotterBitmask plotterBitmask = plotterWatch as IPlotterBitmask;
                    byte            bit            = plotterBitmask.Bit;
                    ulong           bitmask        = (ulong)0x01 << bit;
                    bool            logicState;
                    for (int frame = 0; frame < historicDataManager.FramesToDisplay.Count; frame++)
                    {
                        if (((ulong)historicDataManager.FramesToDisplay[frame].WatchElements[watchElementIndex].Value & bitmask) == bitmask)
                        {
                            logicState = true;
                        }
                        else
                        {
                            logicState = false;
                        }

                        plotterBitmask.Channels[0].SetState(logicState, elapsedTime[frame]);
                    }
                }
                plotterWatch.Stop();
                plotterWatch.UpdateDisplay();
            }
        }
        /// <summary>
        /// Clean up the resources used by the form.
        /// </summary>
        /// <param name="disposing">True to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
        protected override void Cleanup(bool disposing)
        {
            try
            {

                // Method called by consumer code. Call the Dispose method of any managed data members that implement the dispose method.
                // Cleanup managed objects by calling their Dispose() methods.
                if (disposing)
                {
                    if (components != null)
                    {
                        components.Dispose();
                    }
                }
				
				// Whether called by consumer code or the garbage collector free all unmanaged resources and set the value of managed data 
                // members to null.
                m_PlotterControlLayout = null;
                m_HistoricDataManager = null;
                m_FormDataStreamReplay = null;

                #region - [Detach the event handler methods.] -
                this.Shown -= new EventHandler(this.FormDataStreamPlot_Shown);
                #endregion - [Detach the event handler methods.] -

                #region - [Component Designer Variables] -
                this.m_PanelSupplementalInformation = null;
                this.m_LabelSupplementalInformation = null;
                this.m_LegendSupplementalInformation = null;
                #endregion - [Component Designer Variables] -
            }
            catch (Exception)
            {
                // Don't do anything, just ensure that an exception isn't thrown.
            }
            finally
            {
                base.Cleanup(disposing);
            }
        }
        /// <summary>
        /// Initializes a new instance of the class.
        /// </summary>
        /// <param name="watchFile">The structure containing the data stream that is to be plotted.</param>
        public FormDataStreamPlot(WatchFile_t watchFile)
        {
            InitializeComponent();

            // Make the file accessible to all members methods.
            WatchFile = watchFile;
            Debug.Assert(watchFile.DataStream.FrameIntervalMs > 0, "FormDataStreamPlot.Ctor() - [watchFile.DataStream.FrameIntervalMs > 0");

            m_HistoricDataManager = new HistoricDataManager(WatchFile);

            // Instantiate the class that supports the plotting of historic data.
            m_PlotterControlLayout = new PlotterControlLayout(this, m_HistoricDataManager);

            #region - [UserControl Event Handlers] -
            m_PlotterControlLayout.RangeChanged += new EventHandler(RangeChanged);
            m_PlotterControlLayout.RangeReset += new EventHandler(RangeReset);
            m_PlotterControlLayout.ZoomSelected += new EventHandler(ZoomSelected);
            m_PlotterControlLayout.RemoveSelected += new EventHandler(RemoveSelected);
            #endregion - [Event Handlers] -

            ConfigureTabControl(m_TabControl, WatchFile);

            #region - [Function Keys] -
            // Escape - Exit
            // F1 - Help
            // F2 - Print
            // F4 - Replay
            // F5 - Configure Plot
			// F6 - MultiCursor
            DisplayFunctionKey(F4, Resources.FunctionKeyTextReplay, Resources.FunctionKeyToolTipReplay, Resources.Replay);
            DisplayFunctionKey(F5, Resources.FunctionKeyTextEdit, Resources.FunctionKeyToolTipEditPlotLayout, Resources.Modify);
			DisplayFunctionKey(F6, Resources.FunctionKeyTextMultiCursor, Resources.FunctionKeyToolTipMultiCursor, Resources.MultiCursor);
            #endregion - [Function Keys] -

            #region - [InformationLabels/Legend] -
            // InformationLabel 1  - Date
            // InformationLabel 2  - Start Time
            // InformationLabel 3  - Stop Time
            // InformationLabel 4  - Duration
            DisplayLabel(InformationLabel1, Resources.InformationLegendDate, Color.MintCream);
            DisplayLabel(InformationLabel2, Resources.InformationLegendStartTime, Color.LightGreen);
            DisplayLabel(InformationLabel3, Resources.InformationLegendStopTime, Color.Red);
            DisplayLabel(InformationLabel4, Resources.InformationLegendDuration, Color.Khaki);
            #endregion - [InformationLabels/Legend] -

            // Ensure that the single cursor option is used as the default.
            Plotter.MultiCursor = false;
        }
 /// <summary>
 /// Initializes a new instance of the class.
 /// </summary>
 /// <param name="form">Reference to the form which instantiated the class.</param>
 /// <param name="historicDataManager">Reference to the <c>HistoricDataManager</c> object associated with the calling form.</param>
 public WatchControlLayout(Form form, IHistoricDataManager historicDataManager)
     : this(form)
 {
     m_HistoricDataManager = historicDataManager;
 }
        /// <summary>
        /// Check whether there were any breaks in communication with the VCU and set the breakpoint values of each plotter controls accordingly. This allows the plot 
        /// to be drawn using a transparent pen for periods where there was a break in transmission.
        /// </summary>
        /// <param name="controlCollection">Reference to the <c>TableLayoutControlCollection</c> containing the <c>IPlotterWatch</c> derived user controls.</param>
        /// <param name="startTime">The start time of the plot.</param>
        /// <param name="historicDataManager">Reference to the <c>HistoricDataManager</c> class containing the data that is to be plotted.</param>
        public void SetBreakpoints(TableLayoutControlCollection controlCollection, DateTime startTime, IHistoricDataManager historicDataManager)
        {
            // Skip, if the Dispose() method has been called.
            if (m_IsDisposed)
            {
                return;
            }

            // Skip, if there are no plotter controls associated with the TableLayoutPanel.
            if (controlCollection.Count == 0)
            {
                return;
            }
            
            // The time, in ms since the start of the plot, where a break in the sequence was detected.
            long breakpoint;

            // The DateTime corresponding to the previous entry, used to determine a break in the log sequence for running logs.
            DateTime previousEntryDateTime = new DateTime();

            // The interval between concurrent frames above which the plot is considered to have been interrupted i.e a new breakpoint has been triggered.
            TimeSpan breakpointTriggerInterval = new TimeSpan(0, 0, 0, 0, BreakpointTriggerIntervalAsMultiple * Parameter.IntervalWatchMs);

            long adjust;
            for (int frame = 0; frame < m_HistoricDataManager.FramesToDisplay.Count; frame++)
            {
                // Don't perform comparison on the first entry.
                if (frame != 0)
                {
                    if (historicDataManager.FramesToDisplay[frame].CurrentDateTime.Subtract(previousEntryDateTime) > breakpointTriggerInterval)
                    {
                        // Detected a break in the log sequence, record the previous entry as a breakpoint, round down to the nearest 10ms.
                        breakpoint = (long)previousEntryDateTime.Subtract(startTime).TotalMilliseconds;
                        adjust = breakpoint % BreakpointResolutionMs;
                        breakpoint -= adjust;
                        
                        // Record the breakPoint for each plotter.
                        for (int index = 0; index < controlCollection.Count; index++)
                        {
                            // Skip, if the plotter user control has not been configured.
                            if ((controlCollection[index] as IPlotterWatch) == null)
                            {
                                continue;
                            }

                            (controlCollection[index] as IPlotterWatch).Channels[0].SetBreakPoint(breakpoint);
                        }
                    }
                }
                previousEntryDateTime = m_HistoricDataManager.FramesToDisplay[frame].CurrentDateTime;
            }
        }
        /// <summary>
        /// Plot the historic watch values stored within <paramref name="historicDataManager"/> using the <c>IPlotterWatch</c> derived plotter user controls associated
        /// with the specified <c>TableLayoutControlCollection</c>.
        /// </summary>
        /// <param name="controlCollection">Reference to the <c>TableLayoutControlCollection</c> containing the <c>IPlotterWatch</c> derived plotter controls used 
        /// to plot the historic data.</param>
        /// <param name="historicDataManager">Reference to the <c>HistoricDataManager</c> class containing the data that is to be plotted.</param>
        /// <param name="elapsedTime">The elapsed time, in ms, since the start of the plot for each frame that is to be plotted.</param>
        public void PlotWatchValues(TableLayoutControlCollection controlCollection, IHistoricDataManager historicDataManager, long[] elapsedTime)
        {
            // Skip, if the Dispose() method has been called.
            if (m_IsDisposed)
            {
                return;
            }

            // Skip, if there are no plotter controls associated with the TableLayoutPanel.
            if (controlCollection.Count == 0)
            {
                return;
            }

            short oldIdentifier, watchElementIndex;
            IPlotterWatch plotterWatch;
            WatchVariable watchVariable;
            for (int index = 0; index < controlCollection.Count; index++)
            {
                plotterWatch = controlCollection[index] as IPlotterWatch;

                // Skip, if the plotter user control has not been configured.
                if (plotterWatch == null)
                {
                    continue;
                }

                oldIdentifier = plotterWatch.Identifier;

                try
                {
                    watchVariable = Lookup.WatchVariableTableByOldIdentifier.Items[oldIdentifier];

                    // Check whether the watch variable exists.
                    if (watchVariable == null)
                    {
                        // No, skip this entry.
                        continue;
                    }
                }
                catch (Exception)
                {
                    continue;
                }

                // Get the watch element index associated with the old identifier identifier.
                watchElementIndex = m_HistoricDataManager.GetWatchElementIndex(oldIdentifier);

                // Check whether the old watch file contains watch values associated with this old identifier.
                if (watchElementIndex == CommonConstants.NotDefined)
                {
                    continue;
                }

                if (watchElementIndex > historicDataManager.Workset.CountMax)
                {
                    throw new ArgumentOutOfRangeException("watchElementIndex", "PlotterControlLayout.PlotWatchValues()");
                }

                plotterWatch.Start();

                if ((plotterWatch as IPlotterScalar) != null)
                {
                    double engineeringValue;
                    for (int frame = 0; frame < historicDataManager.FramesToDisplay.Count; frame++)
                    {
                        engineeringValue = watchVariable.ScaleFactor * historicDataManager.FramesToDisplay[frame].WatchElements[watchElementIndex].Value;
                        plotterWatch.Channels[0].SetYTValue((float)engineeringValue, elapsedTime[frame]);
                    }
                }
                else if ((plotterWatch as IPlotterEnumerator) != null)
                {
                    double engineeringValue;
                    for (int frame = 0; frame < historicDataManager.FramesToDisplay.Count; frame++)
                    {
                        engineeringValue = watchVariable.ScaleFactor * historicDataManager.FramesToDisplay[frame].WatchElements[watchElementIndex].Value;
                        plotterWatch.Channels[0].SetYTValue((float)engineeringValue, elapsedTime[frame]);
                    }
                }
                else if ((plotterWatch as IPlotterBitmask) != null)
                {
                    IPlotterBitmask plotterBitmask = plotterWatch as IPlotterBitmask;
                    byte bit = plotterBitmask.Bit;
                    ulong bitmask = (ulong)0x01 << bit;
                    bool logicState;
                    for (int frame = 0; frame < historicDataManager.FramesToDisplay.Count; frame++)
                    {
                        if (((ulong)historicDataManager.FramesToDisplay[frame].WatchElements[watchElementIndex].Value & bitmask) == bitmask)
                        {
                            logicState = true;
                        }
                        else
                        {
                            logicState = false;
                        }

                        plotterBitmask.Channels[0].SetState(logicState, elapsedTime[frame]);
                    }
                }
                plotterWatch.Stop();
                plotterWatch.UpdateDisplay();
            }
        }
        /// <summary>
        /// Get the elapsed times, in ms, between the RTC time of each frame of historic data and the Start Time of the plot.
        /// </summary>
        /// <param name="startTime">The start time of the plot.</param>
        /// <param name="historicDataManager">Reference to the historic data that is to be plotted.</param>
        /// <returns>An array containing the elapsed time, in ms, since the specified start time of the plot for each frame of historic data.</returns>
        public long[] GetElapsedTimes(DateTime startTime, IHistoricDataManager historicDataManager)
        {
            long[] elapsedTime = new long[historicDataManager.FramesToDisplay.Count];
            long timeFromStart = 0;

            // Round down to the nearest data interval.
            long adjust;
            for (int frame = 0; frame < m_HistoricDataManager.FramesToDisplay.Count; frame++)
            {
                timeFromStart = (long)m_HistoricDataManager.FramesToDisplay[frame].CurrentDateTime.Subtract(startTime).TotalMilliseconds;
                adjust = timeFromStart % 10;
                timeFromStart -= adjust;
                elapsedTime[frame] = (timeFromStart >= 0) ? timeFromStart : 0;
            }
            return elapsedTime;
        }