// UNCLASSIFIED /*------------------------------------------------------------------------- RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON COMPANY. THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT. UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. -------------------------------------------------------------------------*/ using System; using System.Collections.Generic; using System.IO; using NLog; using Raytheon.Common; namespace BitMeasurementManagerLib { /// /// Handles received messages from the UUT /// internal class BitMsgHandler : MsgDevice { #region PublicClassMembers public enum ErrorCodes { NO_ERROR = 0, UNKNOWN_MSG_ID = 1 }; #endregion #region PrivateClassMembers private static object _syncObj = new Object(); private BinaryWriter _binWriter; private StreamWriter _asciiWriter; private MeasurementManagerLib.BitMeasurementManager.MessageReceivedDelegate _callback; private SortedDictionary _callbackControl; private readonly BitMessageIDs _messageIds; private readonly bool _shallWeLogOutgoingBinData; private readonly bool _shallWeLogOutgoingAsciiData; private readonly bool _shallWeLogIncomingBinData; private readonly bool _shallWeLogIncomingAsciiData; private readonly uint _bitmask; private readonly string _crcFieldName; private readonly ILogger _logger; #endregion #region PublicFuctions /// /// The constructor /// /// Host callback for received messages /// The size of the internal parsing buffer /// THe binary file log name /// The ascii file log name /// /// /// /// unsafe public BitMsgHandler(BitMessageIDs messageIds, MeasurementManagerLib.BitMeasurementManager.MessageReceivedDelegate callback, uint bufferSize, string binLogFileName, string asciiLogFileName, bool shallWeLogOutgoingBinData, bool shallWeLogOutgoingAsciiData, bool shallWeLogIncomingBinData, bool shallWeLogIncomingAsciiData, uint crcBitmask, string crcFieldName, bool shallWePerformVerboseParserLogging) : base(new BitMsgParser(messageIds, shallWePerformVerboseParserLogging), bufferSize) { _logger = LogManager.GetCurrentClassLogger(); _messageIds = messageIds; // hold onto the callback _callback = callback; _shallWeLogOutgoingBinData = shallWeLogOutgoingBinData; _shallWeLogOutgoingAsciiData = shallWeLogOutgoingAsciiData; _shallWeLogIncomingBinData = shallWeLogIncomingBinData; _shallWeLogIncomingAsciiData = shallWeLogIncomingAsciiData; _bitmask = crcBitmask; _crcFieldName = crcFieldName; // set all messages to not issue a callback. Host can change it as necessary _callbackControl = new SortedDictionary(); List msgIds = messageIds.GetAllIds(); foreach (uint id in msgIds) { _callbackControl[id] = false; } _binWriter = null; _asciiWriter = null; SetLogFileNames(binLogFileName, asciiLogFileName); // set the callback base.SetCompleteMessageCallback(this.OnCompleteMessage); } /// /// The finalizer /// ~BitMsgHandler() { Dispose(false); } /// /// Add data to the buffer. For this Handler, we are just going to log out the data /// /// The data to add /// The number of bytes in the data buffer public override void AddData(byte[] data, uint numBytes) { // log out raw data and add to buffer for processing lock (_syncObj) { WriteIncomingDataToLog(data, (int)numBytes); AddToBuffer(data, numBytes); } } /// /// Clear all data from the buffer. We are just logging out data, no buffer to clear /// public void ClearData() { ClearBuffer(); } /// /// /// public void CloseDataFiles() { lock (_syncObj) { if (_binWriter != null) { _binWriter.Close(); _binWriter.Dispose(); _binWriter = null; } if (_asciiWriter != null) { _asciiWriter.Close(); _asciiWriter.Dispose(); _asciiWriter = null; } } } /// /// The callback function for when a complete message is received. We are just logging out data, no messages to handle. /// /// The id of the message received /// The data for the message received /// the number of bytes in pData /// The parser error code unsafe public void OnCompleteMessage(uint msgId, IntPtr pData, uint numBytes, uint errorCode) { try { if (_messageIds.ContainsId(msgId) == false) { _logger.Warn("BitMsgHandler::OnCompleteMessage() - detected unknown msg id: " + msgId.ToString()); } else { // create the msg and parse it BitConfigurableMessage msg = BitConfigurableMessageFactory.Instance().RetreiveMessage(msgId); msg.Parse(pData); int callbackValue = 0; // check for crc errors if (_bitmask != 0x00000000) { uint rawStatus = msg.GetDataItemByName(_crcFieldName); var maskedStatus = rawStatus & _bitmask; if (maskedStatus != 0) { _logger.Warn($"Message Status register indicates that a CRC error may have occurred. Raw status read: 0x{rawStatus:X8}. Masked status value: 0x{maskedStatus:X8}"); callbackValue = -1; } } // get the ascii msg string asciiMessage = msg.ToString(); // log it WriteIncomingDataToLog(asciiMessage); // add the message to the buffer in case the host wants it BitMsgRxBuffer.Instance().AddMsg(msg, false); // issue callback if requested uint id = msg.GetMessageId(); if (_callbackControl[id] == true) { _callback(id, msg.GetEntireMsgLength(), callbackValue); } // some debugging _logger.Debug("added message " + msgId.ToString("X8") + " to buffer "); } } catch { } } /// /// Subscribe a callback to a specific msg /// /// The msg to subscribe to /// true to get the callbacks, false to not get them public void SetCallbackControl(uint msgId, bool shallWeIssueCallback) { _callbackControl[msgId] = shallWeIssueCallback; } /// /// Set the data file log names. Closes the previous file and opens a new one /// /// The binary file log name /// The ascii file log name public void SetLogFileNames(string binFileName, string asciiFileName) { lock (_syncObj) { if (_binWriter != null) { _binWriter.Close(); } _binWriter = new BinaryWriter(File.Open(binFileName, FileMode.Create)); if (_asciiWriter != null) { _asciiWriter.Close(); } _asciiWriter = new StreamWriter(File.Open(asciiFileName, FileMode.Create)); } } /// /// Stops the message handler /// public void QuitHandler() { base.QuitThread(); } /// /// Write bin data to a file /// /// The data to write /// The number of bytes to write public void WriteIncomingDataToLog(byte[] data, int numBytes) { lock (_syncObj) { if (_binWriter == null && _shallWeLogIncomingBinData == true) { throw new Exception("Trying to log bin data before the log file is open"); } else if (_shallWeLogIncomingBinData == true) { // write the data out and flush it for immediate viewing _binWriter.Write(data, 0, (int)numBytes); _binWriter.Flush(); } } } /// /// Write ascii data to a log file. Prepends a timestamp to the data /// /// The data to write public void WriteIncomingDataToLog(string data) { lock (_syncObj) { if (_asciiWriter == null && _shallWeLogIncomingAsciiData == true) { throw new Exception("Trying to log ascii data before the log file is open"); } else if (_shallWeLogIncomingAsciiData == true) { string timestamp = "Time: " + Util.GetTimeString(); string dataToLog = timestamp + "\r\n" + data; _asciiWriter.WriteLine(dataToLog); _asciiWriter.Flush(); } } } /// /// Write bin data to a file /// /// The data to write /// The number of bytes to write public void WriteOutgoingDataToLog(byte[] data, int numBytes) { lock (_syncObj) { if (_binWriter == null && _shallWeLogOutgoingBinData == true) { throw new Exception("Trying to log bin data before the log file is open"); } else if (_shallWeLogOutgoingBinData == true) { _binWriter.Write(data, 0, numBytes); _binWriter.Flush(); } } } /// /// Write ascii data to a log file. Prepends a timestamp to the data /// /// The data to write public void WriteOutgoingDataToLog(string data) { lock (_syncObj) { if (_asciiWriter == null && _shallWeLogOutgoingAsciiData == true) { throw new Exception("Trying to log ascii data before the log file is open"); } else if (_shallWeLogOutgoingAsciiData == true) { string timestamp = "Time: " + Util.GetTimeString(); string dataToLog = timestamp + "\r\n" + data; _asciiWriter.WriteLine(dataToLog); _asciiWriter.Flush(); } } } /// /// /// /// protected override void Dispose(bool disposing) { if (disposing) { // call the parent dispose first base.Dispose(disposing); // now dispose of our resources if (_binWriter != null) { _binWriter.Dispose(); } if (_asciiWriter != null) { _asciiWriter.Dispose(); } } } #endregion } }