Ejemplo n.º 1
0
        /// <summary>
        /// Convert the data stream values retrieved from the VCU to a format that can be plotted by the <c>FormViewDataStream</c> class.
        /// </summary>
        /// <remarks>
        /// The value array retrieved by from the VCU is initially mapped to the WatchIdentifierList property of Column[0] of the workset, however, the WatchElement
        /// array associated with each frame must be mapped to the WatchElementList property of the workset.
        /// </remarks>
        /// <param name="startTime">The start time of the fault log.</param>
        /// <param name="sampleCount">The number of samples in the data stream.</param>
        /// <param name="frameIntervalMs">The interval, in ms, between consecutive data frames.</param>
        /// <param name="values">The point values corresponding to each variable.</param>
        /// <param name="dataTypes">The data types associated with each value.</param>
        /// <param name="workset">The workset that is to be used to define the output format.</param>
        /// <returns>The watch variable values in the format that can be plotted by the <c>FormViewDataStream</c> class.</returns>
        /// <exception cref="ArgumentException">Thrown if one or more of the the watch identifiers defined in the WatchElementList property of the workset does nor exist.</exception>
        private List <WatchFrame_t> ConvertToWatchFrameList(DateTime startTime, short sampleCount, short frameIntervalMs, int[] values, short[] dataTypes, Workset_t workset)
        {
            Debug.Assert(sampleCount > 1, "CommunicationEvent.ConvertToWatchFrameList() - [pointCount > 1]");
            Debug.Assert(frameIntervalMs > 0, "CommunicationEvent.ConvertToWatchFrameList() - [frameIntervalMs > 0");
            Debug.Assert(values != null, "CommunicationEvent.ConvertToWatchFrameList() - [values != null]");
            Debug.Assert(dataTypes != null, "CommunicationEvent.ConvertToWatchFrameList() - [dataTypes != null]");

            short watchCount = (short)workset.WatchElementList.Count;

            // Create a look-up array to translate the watch variable data retrieved from the VCU to the order defined by the WatchElementList property of the workset.
            short[]       translate = new short[watchCount];
            short         watchIdentifier, rowIndex, columnIndex;
            WatchVariable watchVariable;

            for (short watchElementIndex = 0; watchElementIndex < watchCount; watchElementIndex++)
            {
                watchIdentifier = workset.WatchElementList[watchElementIndex];
                try
                {
                    watchVariable = Lookup.WatchVariableTable.Items[watchIdentifier];
                    if (watchVariable == null)
                    {
                        throw new ArgumentException(Resources.MBTWatchVariableNotDefined);
                    }
                }
                catch (Exception)
                {
                    throw new ArgumentException(Resources.MBTWatchVariableNotDefined);
                }

                workset.GetWatchVariableLocation(watchVariable.OldIdentifier, out columnIndex, out rowIndex);
                Debug.Assert(((columnIndex != CommonConstants.NotFound) && (rowIndex != CommonConstants.NotFound)), "CommunicationEvent.ConvertToWatchFrameList() - [((columnIndex != 0) || (rowIndex != CommonConstants.NotFound))]");

                translate[watchElementIndex] = rowIndex;
            }

            // Translate the values of the watch variables retrieved from the VCU to a list of watch frames.
            List <WatchFrame_t> watchFrameList = new List <WatchFrame_t>();
            WatchFrame_t        watchFrame;
            WatchElement_t      watchElement;

            for (int frameIndex = 0; frameIndex < sampleCount; frameIndex++)
            {
                watchFrame = new WatchFrame_t();
                watchFrame.CurrentDateTime = startTime.AddMilliseconds(frameIndex * frameIntervalMs);
                watchFrame.WatchElements   = new WatchElement_t[watchCount];
                for (short watchElementIndex = 0; watchElementIndex < watchCount; watchElementIndex++)
                {
                    watchElement = new WatchElement_t();
                    watchElement.ElementIndex    = watchElementIndex;
                    watchElement.WatchIdentifier = workset.WatchElementList[watchElementIndex];
                    watchElement.DataType        = dataTypes[translate[watchElementIndex]];
                    watchElement.Value           = (double)values[(frameIndex * watchCount) + translate[watchElementIndex]];
                    watchFrame.WatchElements[watchElementIndex] = watchElement;
                }
                watchFrameList.Add(watchFrame);
            }
            return(watchFrameList);
        }
        /// <summary>
        /// Poll the target hardware for watch values and store the retrieve values in the log cyclic queue. If the <c>Record</c> property is asserted also store
        /// the watch values in the cyclic queue used to store recorded data.
        /// </summary>
        /// <remarks>Runs on the underlying thread.</remarks>
        public override void Run()
        {
            try
            {
                m_CommunicationFault = false;
                while (StopThread == false)
                {
                    if (Pause == false)
                    {
                        PauseFeedback = false;
                        m_PollScheduler.Wait(IntervalMsUpdate);
                        if (Pause == true)
                        {
                            m_Watchdog++;
                            continue;
                        }

                        WatchFrame_t watchFrame;
                        watchFrame = new WatchFrame_t();
                        watchFrame.CurrentDateTime = DateTime.Now;

                        // Get the watch values from the target.
                        try
                        {
                            m_Watchdog++;
                            watchFrame.WatchElements = m_CommunicationInterface.UpdateWatchElements(true);
                            m_ReadTimeoutCountdown   = ReadTimeoutCountdown;
                        }
                        catch (CommunicationException)
                        {
                            // Don't assert the communication fault flag until the countdown has elapsed.
                            if (m_ReadTimeoutCountdown <= 0)
                            {
                                // Assert the CommunicationFault property.
                                m_CommunicationFault = true;

                                // Close the communication Port.
                                m_CommunicationInterface.CloseCommunication(m_CommunicationInterface.CommunicationSetting.Protocol);

                                // Keep the watchdog ticking over so that the client can determine whether the port has locked.

                                //DAS TODO when a comm fault occurs this loop never exits and the thread runs forever and is
                                //not properly disposed. Will need to fix and other similar classes
                                do
                                {
                                    m_Watchdog++;
                                    Thread.Sleep(SleepMsRefreshWatchdog);
                                }while (m_CommunicationFault == true);
                            }
                            else
                            {
                                m_ReadTimeoutCountdown--;
                                continue;
                            }
                        }
                        m_CommunicationFault = false;

                        // Keep a count of the number of packets received. Used as a thread-safe way of blinking the packet received icon on the main window. This value
                        // is read by the display update method on the main thread and provided it has incremented since the timeout last expired it will blink the icon.
                        m_PacketCount++;

                        // If currently in record mode copy the data to the cyclic buffer.
                        if (Record == true)
                        {
                            #region - [Recording] -
                            // Lock the cyclic queue and write the new data to the queue.
                            lock (m_CyclicQueueRecord.SyncRoot)
                            {
                                m_CyclicQueueRecord.Enqueue(watchFrame);
                            }

                            #region - [AutoScale] -
                            double valueCurrent;
                            m_MutexAutoScaleWatchValues.WaitOne(DefaultMutexWaitDurationMs, false);
                            if (m_FirstRecordPass == true)
                            {
                                // Recording has just started, initialize both the maximum and minimum values to the current value.
                                for (short watchElementIndex = 0; watchElementIndex < watchFrame.WatchElements.Length; watchElementIndex++)
                                {
                                    valueCurrent = watchFrame.WatchElements[watchElementIndex].Value;
                                    m_AutoScaleWatchValues[watchElementIndex].MaximumRaw = valueCurrent;
                                    m_AutoScaleWatchValues[watchElementIndex].MinimumRaw = valueCurrent;
                                }
                                m_FirstRecordPass = false;
                            }
                            else
                            {
                                // Keep the maximum and minimum value for each watch element up to date.
                                for (short watchElementIndex = 0; watchElementIndex < watchFrame.WatchElements.Length; watchElementIndex++)
                                {
                                    valueCurrent = watchFrame.WatchElements[watchElementIndex].Value;
                                    if (valueCurrent > m_AutoScaleWatchValues[watchElementIndex].MaximumRaw)
                                    {
                                        m_AutoScaleWatchValues[watchElementIndex].MaximumRaw = valueCurrent;
                                    }
                                    else if (valueCurrent < m_AutoScaleWatchValues[watchElementIndex].MinimumRaw)
                                    {
                                        m_AutoScaleWatchValues[watchElementIndex].MinimumRaw = valueCurrent;
                                    }
                                }
                            }
                            m_MutexAutoScaleWatchValues.ReleaseMutex();
                            #endregion - [AutoScale] -

                            // Update the record count up to the size of the cyclic buffer. Used to keep track of progress.
                            if (m_RecordCount < m_CyclicQueueRecord.Size)
                            {
                                m_RecordCount++;
                            }

                            #region - [Queue Full] -
                            // ---------------------------
                            // Check if the queue is full.
                            // ---------------------------
                            if (m_CyclicQueueRecord.Count >= m_CyclicQueueRecord.Size)
                            {
                                // TODO - ThreadPollWatch.Run(). Implement code which archives the current log after 30 minutes of recording.

                                /*
                                 * // --------------------------------------------
                                 * // Still to be implemented.
                                 * // --------------------------------------------
                                 * lock (m_CyclicQueueRecord.SyncRoot)
                                 * {
                                 *  // ------------------------------
                                 *  // Save the current cyclic queue to disk.
                                 *  // ------------------------------
                                 *  // Creates a SORTED array whose size is equal to the number of entries in the cyclic queue.
                                 *  cyclicQueueRecordArray = m_CyclicQueueRecord.ToArray();
                                 *
                                 *  // Clear the cyclic buffer.
                                 *  m_CyclicQueueRecord.Clear();
                                 * }
                                 *
                                 *
                                 * // The save process must be carried out on a separate thread to enable data collection to continue without
                                 * // loosing packets.
                                 * m_ThreadSaveArrayToDisk = new Thread(SaveArrayToDisk);
                                 *
                                 * // The parameters to SaveArrayToDisk must be passed as an array of objects in this case.
                                 * //m_ThreadSaveArrayToDisk.Start(new object[] { m_FullyQualifiedFileMnemonic + "." + m_Page.ToString() + CommonConstants.ExtensionWatchFile, cyclicQueueRecordArray });
                                 * m_ThreadSaveArrayToDisk.Start(new object[] { m_FullyQualifiedFilename + CommonConstants.ExtensionWatchFile, cyclicQueueRecordArray, m_AutoScaleWatchValues });
                                 *
                                 * // Increment the page number.
                                 * m_Page++;
                                 *
                                 * // Reset the progress bar.
                                 * m_ApplicationProgressBarValue = 0;
                                 *
                                 * // Check if the maximum number of pages has been exceeded, if so, end the recording.
                                 * if (m_Page > Parameter.PageReferenceMax)
                                 * {
                                 *  // Do the processing on a separate thread.
                                 *  Thread threadEndRecording = new Thread(EndRecording);
                                 *  threadEndRecording.Start();
                                 * }
                                 */
                            }
                            #endregion - [Queue Full] -
                            #endregion - [Recording] -
                        }

                        // Record the data to the simulated fault log cyclic buffer.
                        lock (m_CyclicQueueLog.SyncRoot)
                        {
                            m_CyclicQueueLog.Enqueue(watchFrame);
                        }

                        // Write the new data to the lookup table.
                        m_CommunicationInterface.UpdateWatchVariableTable(watchFrame.WatchElements);
                    }
                    else
                    {
                        PauseFeedback = true;
                        m_Watchdog++;
                        Thread.Sleep(SleepMsCheckPause);
                    }
                }
            }
            finally
            {
                base.Run();
            }
        }