using System; using System.Collections.Generic; using System.Linq; using System.Text; using DTS.Common.DASResource; using DTS.Common.Enums.DASFactory; using DTS.Common.ICommunication; using DTS.Common.Interface.DASFactory; using DTS.Common.Utilities; namespace DTS.DASLib.Command.SLICE { /* from firmware * typedef struct _tFirmwareFileHeader { // file format: totalLen = firmwaresize + 108B header. uint16_t magicNum; // 2 2 marker: 0x1234 uint16_t headerCRC16; // 2 4 crc16 for header uint32_t fileLen; // 4 8 firmwaresize in originaltxt format + header size uint16_t formatType; // 2 10 0 = text. other TBD. uint16_t fileCRC16; // 2 12 crc16 for firmware in txt format. uint16_t binCRC16; // 2 14 TBD crc16 for extracted bin format. uint16_t reserved[7]; // 14 28 TBD. uint8_t data[80]; // 80 108 any note from host. Filename for example... } tFirmwareFileHeader; */ public struct SliceProFirmwareImageHeader { // file format: totalLen = firmwaresize + 108B header. public ushort magicNum; // 2 2 marker: 0x1234 public ushort headerCRC16; // 2 4 crc16 for header public uint fileLen; // 4 8 firmwaresize in originaltxt format + header size public ushort formatType; // 2 10 0 = text. other TBD. public ushort fileCRC16; // 2 12 crc16 for firmware in txt format. public ushort binCRC16; // 2 14 TBD crc16 for extracted bin format. public ushort[] reserved; // 14 28 TBD. public byte[] data; // 80 108 any note from host. Filename for example... } public abstract class InformationCommands : CommandBase { protected enum Commands { Reserved = 0x00, QueryStackContents = 0x01, QueryProtocolVersion = 0x02, QueryGroup = 0x03, SetGroup = 0x04, QueryFirmwareVersion = 0x05, QuerySerialNumber = 0x06, SetSerialNumber = 0x07, QueryType = 0x08, QueryOneWireID = 0x09, QueryOneWireEEPROM = 0x0A, SetOneWireEEPROM = 0x0B, QueryMSP430FirmwareVersion = 0x0C, SetFileData = 0x0D, QueryFileData = 0x0E, QueryFirmwareBuildVersion = 0x0F, QueryStackSensorIDs = 0x10, // new command after protocol 136 to query all sensor IDs on stack. SetStackInfoData = 0x11, // TBD. Not yet implemented. set 64-byte data block to infoB page. QueryStackInfoData = 0x12, // TBD. Not yet implemented. query 64-byte data block from infoB page. QueryFirmwareBuildID = 0x13, // TBD. Now supporting via system attribute. query build information from slice. QueryBaseSystemTime = 0x14, // query current system time: sec.min.hr.days.weekdays.years (from 20xx) SetBaseSystemTime = 0x15, // set current system time: sec.min.hr.days.weekdays.years (from 20xx) QueryTempLogFile = 0x16, }; //100 is now the max, per 14531 Implement TMATS support for S6A stream on boot protected const int MAX_FILE_ID = 100; // user = 10, firmware = 20, max internally = 65. 10; protected const int MAX_FILE_LENGTH = 400; public const int MAX_FILE_LENGTH_ID100 = 16000; protected const int MAX_FILE_READ_LENGTH = 1024; protected abstract Commands _Command { get; } protected InformationCommands(Common.Interface.DASFactory.ICommunication sock) : base(sock) { command.Type = CommandPacket.CommandType.Information; command.SetCommand((byte)_Command, _Command.ToString()); } protected InformationCommands(Common.Interface.DASFactory.ICommunication sock, int TimeoutMillisec) : base(sock, TimeoutMillisec) { command.Type = CommandPacket.CommandType.Information; command.SetCommand((byte)_Command, _Command.ToString()); } } public class QueryStackContents : InformationCommands { const int SliceDescriptorSize = 24; const int AddressPosition = 0; const int GroupPosition = 1; const int TypePosition = 2; const int SerialNumberPosition = 3; const int FirmwareVersionPosition = 19; public int SliceCount { get; private set; } = 0; public string[] SerialNumber { get; private set; } public string[] FirmwareVersion { get; private set; } public byte[] SliceType { get; private set; } public byte[] SliceAddress { get; private set; } public byte[] SliceGroup { get; private set; } protected override Commands _Command => Commands.QueryStackContents; public QueryStackContents(Common.Interface.DASFactory.ICommunication sock) : base(sock) { } public QueryStackContents(Common.Interface.DASFactory.ICommunication sock, int TimeoutMillisec) : base(sock, TimeoutMillisec) { } protected override CommandReceiveAction WholePackage() { // we have a whole package if (response.Status == DFConstantsAndEnums.CommandStatus.StatusNoError) { SliceCount = response.ParameterLength / SliceDescriptorSize; SerialNumber = new string[SliceCount]; FirmwareVersion = new string[SliceCount]; SliceType = new byte[SliceCount]; SliceAddress = new byte[SliceCount]; SliceGroup = new byte[SliceCount]; for (int i = 0; i < SliceCount; i++) { response.GetParameter(SliceDescriptorSize * i + AddressPosition, out SliceAddress[i]); response.GetParameter(SliceDescriptorSize * i + GroupPosition, out SliceGroup[i]); response.GetParameter(SliceDescriptorSize * i + TypePosition, out SliceType[i]); response.GetParameter(SliceDescriptorSize * i + SerialNumberPosition, out SerialNumber[i]); response.GetParameter(SliceDescriptorSize * i + FirmwareVersionPosition, out FirmwareVersion[i]); } } else { SliceCount = 0; } return CommandReceiveAction.StopReceiving; } public override void ResponseToString(ref List> lines) { base.ResponseToString(ref lines); lines.Add(new List() { $"SliceCount: {SliceCount}", $"Connection: {recorder.ConnectString}" }); for (int i = 0; i < SliceCount; i++) { var line = new List(); line.Add($"Serial Number: {(SerialNumber != null && SerialNumber.Length > 0 ? SerialNumber[i] : "")}, "); line.Add($"Firmware version: {(FirmwareVersion != null && FirmwareVersion.Length > 0 ? FirmwareVersion[i] : "")}, "); line.Add($"Type: {(SliceType != null ? ((ChannelTypes)SliceType[i]).ToString() : "")}, "); line.Add($"Address: {(SliceAddress != null ? SliceAddress[i].ToString() : "")}, "); line.Add($"Group: {(SliceGroup != null ? SliceGroup[i].ToString() : "")}"); lines.Add(line); } } } public class QueryProtocolVersion : InformationCommands { private byte _versionbyte = 0; public byte Version => _versionbyte; protected override Commands _Command => Commands.QueryProtocolVersion; public QueryProtocolVersion(Common.Interface.DASFactory.ICommunication sock) : base(sock) { } public QueryProtocolVersion(Common.Interface.DASFactory.ICommunication sock, int TimeoutMillisec) : base(sock, TimeoutMillisec) { } protected override CommandReceiveAction WholePackage() { // we have a whole package if (response.Status == DFConstantsAndEnums.CommandStatus.StatusNoError) { response.GetParameter(0, out _versionbyte); } return CommandReceiveAction.StopReceiving; } public override void ResponseToString(ref List> lines) { base.ResponseToString(ref lines); lines.Add(new List() { $"Version: {Version}" }); } } public class QueryFirmwareVersion : InformationCommands { string _versionstring = string.Empty; public string Version => _versionstring; protected override Commands _Command => Commands.QueryFirmwareVersion; public QueryFirmwareVersion(Common.Interface.DASFactory.ICommunication sock) : base(sock) { } public QueryFirmwareVersion(Common.Interface.DASFactory.ICommunication sock, int TimeoutMillisec) : base(sock, TimeoutMillisec) { } protected override CommandReceiveAction WholePackage() { // we have a whole package if (response.Status == DFConstantsAndEnums.CommandStatus.StatusNoError) { response.GetParameter(0, out _versionstring); } return CommandReceiveAction.StopReceiving; } public override void ResponseToString(ref List> lines) { base.ResponseToString(ref lines); lines.Add(new List() { Version }); } } public class QuerySerialNumber : InformationCommands { private string _serialnumber = string.Empty; public string SerialNumber => _serialnumber; protected override Commands _Command => Commands.QuerySerialNumber; public QuerySerialNumber(Common.Interface.DASFactory.ICommunication sock) : base(sock) { } public QuerySerialNumber(Common.Interface.DASFactory.ICommunication sock, int TimeoutMillisec) : base(sock, TimeoutMillisec) { } protected override CommandReceiveAction WholePackage() { // we have a whole package if (response.Status == DFConstantsAndEnums.CommandStatus.StatusNoError) { response.GetParameter(0, out _serialnumber); } return CommandReceiveAction.StopReceiving; } public override void ResponseToString(ref List> lines) { base.ResponseToString(ref lines); lines.Add(new List() { $"SerialNumber: {SerialNumber}" }); } } public class SetSerialNumber : InformationCommands { private string _sn = string.Empty; protected override Commands _Command => Commands.SetSerialNumber; public string SerialNumber { get => _sn; set { _sn = value; command.Parameter = new byte[value.Length + 1]; command.SetParameter(0, value.ToCharArray()); } } public SetSerialNumber(Common.Interface.DASFactory.ICommunication sock) : base(sock) { } public SetSerialNumber(Common.Interface.DASFactory.ICommunication sock, int TimeoutMillisec) : base(sock, TimeoutMillisec) { } public override void CommandToString(ref List> lines) { base.CommandToString(ref lines); lines.Add(new List() { $"SerialNumber: {SerialNumber}" }); } } public class QueryOneWireID : InformationCommands { private const int StackChannelPosition = 0; private const int OneWireIDLength = 8; protected override Commands _Command => Commands.QueryOneWireID; public List IDs { get; private set; } = new List(); private byte _stackchannel; public byte StackChannel { get => _stackchannel; set { _stackchannel = value; command.SetParameter(StackChannelPosition, _stackchannel); } } private bool _bSupportsIdTypes = false; public enum IdTypes { Default = 0x0, Bridge = 0x1, IEPE = 0x2 }; private IdTypes _idType = IdTypes.Default; public IdTypes IdType { get => _idType; set { if (_bSupportsIdTypes) { _idType = value; command.SetParameter(1, (byte)value); } } } public QueryOneWireID(Common.Interface.DASFactory.ICommunication sock) : base(sock) { if (sock.IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.SLICE2_OneWireID)) { command.Parameter = new byte[2]; _bSupportsIdTypes = true; } else { command.Parameter = new byte[1]; } } public QueryOneWireID(Common.Interface.DASFactory.ICommunication sock, int TimeoutMillisec) : base(sock, TimeoutMillisec) { if (sock.IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.SLICE2_OneWireID)) { command.Parameter = new byte[2]; _bSupportsIdTypes = true; } else { command.Parameter = new byte[1]; } } protected override CommandReceiveAction WholePackage() { // we have a whole package if (response.Status == DFConstantsAndEnums.CommandStatus.StatusNoError) { int numberOfIDs = response.ParameterLength / OneWireIDLength; IDs = new List(); for (int i = 0; i < numberOfIDs; i++) { var id = new byte[OneWireIDLength]; var reversedId = new byte[OneWireIDLength]; Buffer.BlockCopy(response.Parameter, OneWireIDLength * i, reversedId, 0, OneWireIDLength); for (int currentByte = reversedId.Length - 1; currentByte >= 0; currentByte--) { id[OneWireIDLength - currentByte - 1] = reversedId[currentByte]; } IDs.Add(id); } } return CommandReceiveAction.StopReceiving; } public override void CommandToString(ref List> lines) { base.CommandToString(ref lines); lines.Add(new List() { $"Stack Channel: {StackChannel}" }); } public override void ResponseToString(ref List> lines) { base.ResponseToString(ref lines); lines.Add(new List() { $"Number of IDs: {IDs.Count}" }); var ids = new List(); for (int i = 0; null != IDs && i < IDs.Count; i++) { if (0 == i) { ids.Add($"IDS: {HexEncoding.ToString(IDs[i])}"); } else { ids.Add(HexEncoding.ToString(IDs[i])); } } if (ids.Count > 0) { lines.Add(ids); } } } public class QueryMSP430FirmwareVersion : InformationCommands { private string _versionstring = string.Empty; public string Version => _versionstring; protected override Commands _Command => Commands.QueryMSP430FirmwareVersion; public QueryMSP430FirmwareVersion(Common.Interface.DASFactory.ICommunication sock) : base(sock) { } public QueryMSP430FirmwareVersion(Common.Interface.DASFactory.ICommunication sock, int TimeoutMillisec) : base(sock, TimeoutMillisec) { } protected override CommandReceiveAction WholePackage() { // we have a whole package if (response.Status == DFConstantsAndEnums.CommandStatus.StatusNoError) { response.GetParameter(0, out _versionstring); } return CommandReceiveAction.StopReceiving; } public override void ResponseToString(ref List> lines) { base.ResponseToString(ref lines); lines.Add(new List() { Version }); } } /// /// Command ID 0x0D – Information FILE Data Set /// STU shall accept data from USER and save to file ID indicated in message. /// public class SetFileData : InformationCommands { protected override Commands _Command => Commands.SetFileData; #region Private Variables private ushort _fileID; //Byte 0-1: 16-bit file ID ranges from 1-10. private uint _startByteCount; private byte[] _data; private static byte PARAM_NUM = 6; #endregion #region Command Parameters public ushort FileID { get => _fileID; set { if (MAX_FILE_ID < value) { throw new NotSupportedException($"FileId: {value.ToString()} > {MAX_FILE_ID.ToString()}"); } _fileID = value; command.SetParameter(0, _fileID); } } public uint StartByteCount { get => _startByteCount; set { _startByteCount = value; command.SetParameter(2, _startByteCount); } } /// /// This is the TMT file ID, per 14531 Implement TMATS support for S6A stream on boot /// public const ushort TMT_FILE_ID = 100; public byte[] Data { get => _data; set { if (null == value) { return; } var maxLength = MAX_FILE_LENGTH; if (FileID == TMT_FILE_ID) { maxLength = MAX_FILE_LENGTH_ID100; if (recorder is ITMATSStreamingDevice tmatsStreamer) { maxLength = tmatsStreamer.GetMaxFileLengthTMATS(); } } if (maxLength < value.Length) { throw new ArgumentOutOfRangeException($"File length: {value.Length} > {maxLength.ToString()}"); } _data = value; //if (this.command.Parameter.Length < value.Length+ PARAM_NUM) //{ var newparameter = new byte[value.Length + PARAM_NUM]; Buffer.BlockCopy(command.Parameter, 0, newparameter, 0, PARAM_NUM); Size = value.Length; command.Parameter = newparameter; Buffer.BlockCopy(_data, 0, command.Parameter, PARAM_NUM, _data.Length); //} } } public int Size { get; private set; } public int MaximumFileStreamBytes => MAX_FILE_LENGTH; #endregion #region Command Functions public SetFileData(Common.Interface.DASFactory.ICommunication sock) : base(sock) { command.Parameter = new byte[PARAM_NUM]; MinimumProtocolVersion = sock.GetMinProto(DFConstantsAndEnums.ProtocolLimitedCommands.FileData); _data = null; _fileID = 0; _startByteCount = 0; command.ShouldLog = false; } public SetFileData(Common.Interface.DASFactory.ICommunication sock, int TimeoutMillisec) : base(sock, TimeoutMillisec) { command.Parameter = new byte[PARAM_NUM]; MinimumProtocolVersion = sock.GetMinProto(DFConstantsAndEnums.ProtocolLimitedCommands.FileData); _data = null; _fileID = 0; _startByteCount = 0; command.ShouldLog = false; } #endregion #region Log Functions public override void CommandToString(ref List> lines) { base.CommandToString(ref lines); lines.Add(new List() { $"Store ID: {FileID}, Start Byte: {StartByteCount}, End Byte: {Size + StartByteCount}" }); } public void LogResponse() { LogCommand(false); } #endregion } /// /// Command ID 0x0E – Information FILE Data Query /// STU shall respond with data requested by host similar to download process. /// public class QueryFileData : InformationCommands { protected override Commands _Command => Commands.QueryFileData; #region Private Variables private ushort _fileID; //Byte 0-1: 16-bit file ID ranges from 1-10. private uint _startByteCount; //Byte 2-5: 32-bit StartBytecount which ranges from 0 to EndBytecount private uint _endByteCount; //Byte 6-9: 32-bit EndBytecount. #endregion #region Command Parameters public ushort FileID { get => _fileID; set { if (MAX_FILE_ID < value) { throw new ArgumentOutOfRangeException($"FileId {value.ToString()} > {MAX_FILE_ID.ToString()}"); } _fileID = value; command.SetParameter(0, _fileID); } } public uint StartByteCount { get => _startByteCount; set { _startByteCount = value; command.SetParameter(2, _startByteCount); } } public uint EndByteCount { get => _endByteCount; set { _endByteCount = value; command.SetParameter(6, _endByteCount); } } #endregion #region Command Variables public uint BytesDownloaded { get; set; } public byte[] Data { get; private set; } public int MaximumFileStreamBytes => MAX_FILE_LENGTH; public int MaxFileReadStreamBytes => MAX_FILE_READ_LENGTH; #endregion #region Command Functions public QueryFileData(Common.Interface.DASFactory.ICommunication sock) : base(sock) { command.Parameter = new byte[10]; MinimumProtocolVersion = sock.GetMinProto(DFConstantsAndEnums.ProtocolLimitedCommands.FileData); Data = null; _fileID = 0; _startByteCount = 0; _endByteCount = 0; command.ShouldLog = false; } public QueryFileData(Common.Interface.DASFactory.ICommunication sock, int TimeoutMillisec) : base(sock, TimeoutMillisec) { command.Parameter = new byte[10]; MinimumProtocolVersion = sock.GetMinProto(DFConstantsAndEnums.ProtocolLimitedCommands.FileData); Data = null; _fileID = 0; _startByteCount = 0; _endByteCount = 0; command.ShouldLog = false; } protected override CommandReceiveAction WholePackage() { if (response.Status != DFConstantsAndEnums.CommandStatus.StatusNoError) { return CommandReceiveAction.StopReceiving; } BytesDownloaded = (uint)(response.Parameter.Length); Data = new byte[BytesDownloaded]; for (int i = 0; (uint)i < BytesDownloaded; i++) { response.GetParameter(i, out Data[i]); } return CommandReceiveAction.StopReceiving; } public override void SyncExecute() { // Do a little parameter checking if (_startByteCount > _endByteCount) { // "QueryEventData.SyncExecute: First Sample cannot be greater than Last Sample" throw new ApplicationException(Strings.QueryEventData_SyncExecute_Err1); } base.SyncExecute(); } #endregion #region Log Functions public override void CommandToString(ref List> lines) { base.CommandToString(ref lines); lines.Add(new List() { $"Store ID: {FileID}, Start Byte: {StartByteCount}, End Byte: {EndByteCount}" }); } public override void ResponseToString(ref List> lines) { base.ResponseToString(ref lines); lines.Add(new List() { $"Store ID: {FileID}, BytesDownloaded: {BytesDownloaded}" }); } public void LogResponse() { LogCommand(false); } #endregion } public class QueryStackSensorIDs : InformationCommands { private const byte StackChannelPosition = 0; private const byte ParameterLength = 1; private const byte ChannelDataLength = 10; private const byte IDLength = 8; private const byte TypeIndex = 9; private const byte ChannelIndex = 10; protected override Commands _Command => Commands.QueryStackSensorIDs; public List IDs { get; private set; } = new List(); public List Types { get; private set; } = new List(); public List Channels { get; private set; } = new List(); private byte _stackchannel; public byte StackChannel { get => _stackchannel; set { _stackchannel = value; command.SetParameter(StackChannelPosition, _stackchannel); } } public QueryStackSensorIDs(Common.Interface.DASFactory.ICommunication sock) : base(sock) { command.Parameter = new byte[ParameterLength]; MinimumProtocolVersion = sock.GetMinProto(DFConstantsAndEnums.ProtocolLimitedCommands.StackSensors); } public QueryStackSensorIDs(Common.Interface.DASFactory.ICommunication sock, int TimeoutMillisec) : base(sock, TimeoutMillisec) { command.Parameter = new byte[ParameterLength]; MinimumProtocolVersion = sock.GetMinProto(DFConstantsAndEnums.ProtocolLimitedCommands.StackSensors); } public void Exec() { SyncExecute(); } protected override CommandReceiveAction WholePackage() { // we have a whole package if (response.Status == DFConstantsAndEnums.CommandStatus.StatusNoError) { int numberOfIDs = response.ParameterLength / ChannelDataLength; IDs = new List(); Types = new List(); Channels = new List(); for (int i = 0; i < numberOfIDs; i++) { var data = new byte[ChannelDataLength]; var reversed_data = new byte[ChannelDataLength]; var id = new byte[IDLength]; var type = new byte(); var channel = new byte(); Buffer.BlockCopy(response.Parameter, ChannelDataLength * i, reversed_data, 0, ChannelDataLength); for (int currentByte = reversed_data.Length - 1; currentByte >= 0; currentByte--) { data[ChannelDataLength - currentByte - 1] = reversed_data[currentByte]; } for (int currentByte = 0; currentByte < data.Length; currentByte++) { if (currentByte < IDLength) { id[currentByte] = data[currentByte]; } else if (currentByte < TypeIndex) { type = data[currentByte]; } else { channel = data[currentByte]; } } IDs.Add(id); Types.Add(type); Channels.Add(channel); } } return CommandReceiveAction.StopReceiving; } public override void CommandToString(ref List> lines) { base.CommandToString(ref lines); lines.Add(new List() { $"Stack Channel: {StackChannel}" }); } public override void ResponseToString(ref List> lines) { base.ResponseToString(ref lines); lines.Add(new List() { $"Number of Stack Channels: {Channels.Count}" }); var info = new List(); for (int i = 0; null != IDs && i < IDs.Count; i++) { info.Add($"Channel: {Channels[i].ToString()}, Type {Types[i].ToString()}, IDS: {HexEncoding.ToString(IDs[i])}"); } if (info.Count > 0) { lines.Add(info); } } } public class QueryBaseSystemTime : InformationCommands { public byte[] Calendar { get; } = new byte[7]; private DateTime _systemTime = DateTime.MinValue; public DateTime SystemTime { get { if (_systemTime == DateTime.MinValue) { var cal = new byte[7]; for (int i = 0; i < cal.Length; i++) { cal[i] = Calendar[i]; } // convert from BCD to binary uint dec, dec2; for (int i = 0; i < 7; i++) { dec = (uint)cal[i] & 0x0f; dec2 = (uint)cal[i] >> 4; dec2 = dec2 * 10; dec = dec + dec2; cal[i] = (byte)dec; } _systemTime = new DateTime(cal[6] + 2000, // year cal[5], // month cal[3], // day cal[2], // hh cal[1], // mm cal[0]); // ss } return _systemTime; } } protected override Commands _Command => Commands.QueryBaseSystemTime; public QueryBaseSystemTime(Common.Interface.DASFactory.ICommunication sock) : base(sock) { MinimumProtocolVersion = sock.GetMinProto(DFConstantsAndEnums.ProtocolLimitedCommands.BaseSystemTime); } public QueryBaseSystemTime(Common.Interface.DASFactory.ICommunication sock, int TimeoutMillisec) : base(sock, TimeoutMillisec) { MinimumProtocolVersion = sock.GetMinProto(DFConstantsAndEnums.ProtocolLimitedCommands.BaseSystemTime); } protected override CommandReceiveAction WholePackage() { // we have a whole package if (response.Status == DFConstantsAndEnums.CommandStatus.StatusNoError) { for (int i = 0; i < 7; i++) { response.GetParameter(i, out Calendar[i]); } } return CommandReceiveAction.StopReceiving; } public override void ResponseToString(ref List> lines) { base.ResponseToString(ref lines); lines.Add(new List() { $"System Time: {SystemTime}" }); } } public class SetBaseSystemTime : InformationCommands { private DateTime _systemTime = new DateTime(); protected override Commands _Command => Commands.SetBaseSystemTime; public DateTime SystemTime { get => _systemTime; set { var timestream = new byte[7]; timestream[0] = (byte)value.Second; timestream[1] = (byte)value.Minute; timestream[2] = (byte)value.Hour; timestream[3] = (byte)value.Day; timestream[4] = (byte)value.DayOfWeek; timestream[5] = (byte)value.Month; timestream[6] = (byte)(value.Year - 2000); // convert binary to BCD uint bcd, bcd2; for (int i = 0; i < 7; i++) { bcd = ((uint)timestream[i]) / 10; bcd2 = ((uint)timestream[i]) % 10; bcd = (bcd << 4) + bcd2; timestream[i] = (byte)bcd; } command.Parameter = timestream; _systemTime = value; } } public SetBaseSystemTime(Common.Interface.DASFactory.ICommunication sock) : base(sock) { MinimumProtocolVersion = sock.GetMinProto(DFConstantsAndEnums.ProtocolLimitedCommands.BaseSystemTime); } public SetBaseSystemTime(Common.Interface.DASFactory.ICommunication sock, int TimeoutMillisec) : base(sock, TimeoutMillisec) { MinimumProtocolVersion = sock.GetMinProto(DFConstantsAndEnums.ProtocolLimitedCommands.BaseSystemTime); } public override void CommandToString(ref List> lines) { base.CommandToString(ref lines); lines.Add(new List() { $"System Time: {SystemTime}" }); } } /* * cmdInfo_queryTempLogfile - query tempurature logfile in S6DB * * @param * uint8_t cmd. No param or param value = 0. Readonly. 1 = readclear. * uint8_t u8-rsv; // for future subcommand. * uint32_t time offset from the current time in second. * uint32_t timeROI in second. * for example: * u8 cmd = 0. * u8 rsv. Maybe sampleByteSize; * u32 timeOffset = 0. Start from last sample taken. * u32 timeDurationSec = 120. Asking for sample in last two hours. * * @return Response status with logging data in payload. * Data structure in payload. * - u32 timeOffset; // confirmed with software command. * // samplePeriodInSec can be tracked with system attr. * // channelMask can be tracked with system attribute. * - Repeated structure of following: * { * . uint32_t RTC Timestamp-Second. * . float32_t temp1; * . float32_t temp2; * } * * Note: Default of 2 ADC channel. * 48hr*60min/hr **/ public class QueryTempLogFile : InformationCommands { //private const byte ParameterLength = 1; uint _timeOffsetSec = 0; uint _timeDurationSec = 48 * 60 * 60; // full log byte _readClear = 0; byte _rsvCmd = 0; public uint TimeOffsetFromNowSec { get => _timeOffsetSec; set { _timeOffsetSec = value; command.SetParameter(2, _timeOffsetSec); } } public uint TimeDurationSec { get => _timeDurationSec; set { _timeDurationSec = value; command.SetParameter(6, _timeDurationSec); } } public byte ReadClear { get => _readClear; set { _readClear = value; command.SetParameter(0, _readClear); } } public byte ReadRsvCmd { get => _rsvCmd; set { _rsvCmd = value; command.SetParameter(1, _rsvCmd); } } protected override Commands _Command => Commands.QueryTempLogFile; public QueryTempLogFile(Common.Interface.DASFactory.ICommunication sock) : base(sock) { command.Parameter = new byte[10]; MinimumProtocolVersion = sock.GetMinProto(DFConstantsAndEnums.ProtocolLimitedCommands.QueryTempLogFile); } public QueryTempLogFile(Common.Interface.DASFactory.ICommunication sock, int TimeoutMillisec) : base(sock, TimeoutMillisec) { command.Parameter = new byte[10]; MinimumProtocolVersion = sock.GetMinProto(DFConstantsAndEnums.ProtocolLimitedCommands.QueryTempLogFile); } public static DateTime UnixTimeStampToDateTime(uint unixTimeStamp) { // Unix timestamp is seconds past epoch DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); dtDateTime = dtDateTime.AddSeconds(unixTimeStamp).ToLocalTime(); return dtDateTime; } public List> TempData = new List>(); protected override CommandReceiveAction WholePackage() { // we have a whole package if (response.Status != DFConstantsAndEnums.CommandStatus.StatusNoError || response.ParameterLength == 0) return CommandReceiveAction.StopReceiving; response.GetParameter(2, out int dataOffset); var sampleCount = (response.ParameterLength - 6) / 12; uint curTicks; float channel1Sample; float channel2Sample; for (int i = 6; i < response.ParameterLength - 6; i += 12) { response.GetParameter(i + 0, out curTicks); response.GetParameter(i + 4, out channel1Sample); response.GetParameter(i + 8, out channel2Sample); TempData.Add(new Tuple(UnixTimeStampToDateTime(curTicks).ToLocalTime(), channel1Sample, channel2Sample, curTicks)); } TempData = TempData.OrderBy(a => a.Item1).ToList(); // check to see if any dates are bogus var badDates = TempData.Where(x => x.Item1.Year < 1990).Select(x => x.Item1).ToList(); if (badDates.Count == 1) { // fix the single date TempData[0] = TempDataReplaceDate(TempData[0], DateTime.Now - new TimeSpan(0, 1, 0)); } else if (badDates.Count > 1) { // we need to extrapolate from a known good time stamp var goodDate = DateTime.Now; // lets see how far back our data should go var lastBadSpan = badDates[badDates.Count - 1] - badDates[badDates.Count - 2]; var badDateTimeSpan = badDates.Last() - badDates[0] + lastBadSpan; if (TempData.Exists(x => x.Item1.Year > 1990)) { // if we have a good date, use it to seed the bad date extrapolation goodDate = TempData.Where(x => x.Item1.Year > 1990).Select(x => x.Item1).ToList()[0]; } // Fix the first data point TempData[0] = TempDataReplaceDate(TempData[0], goodDate - badDateTimeSpan); // Fix all the data points in between for (int i = 1; i < TempData.Select(x => x.Item1).ToList().IndexOf(badDates.Last()); i++) { TempData[i] = TempDataReplaceDate(TempData[i], TempData[i - 1].Item1 + (TempData[i + 1].Item1 - TempData[i].Item1)); } // fix the last data point var indesxOfLastBadDate = TempData.Select(x => x.Item1).ToList().IndexOf(badDates.Last()); TempData[indesxOfLastBadDate] = TempDataReplaceDate(TempData[indesxOfLastBadDate], goodDate - lastBadSpan); } return CommandReceiveAction.StopReceiving; } public override void ResponseToString(ref List> lines) { base.ResponseToString(ref lines); lines.Add(new List() { $"QueryTempLogFile: From:{TimeOffsetFromNowSec}s Duration:{TimeDurationSec}s Samples Returned: {TempData.Count}" }); } /// /// Only replaces the new date and returns the rest of the tuple for the temp log point /// /// /// /// private Tuple TempDataReplaceDate(Tuple origTuple, DateTime dateTime) { return new Tuple(dateTime, origTuple.Item2, origTuple.Item3, origTuple.Item4); } } public class QueryEeprom : InformationCommands { private byte _eeprom_id = 0; private ushort _data_offset = 0; private ushort _data_length = 0; private byte[] _data; public byte ID { set { _eeprom_id = value; command.SetParameter(0, value); } get => _eeprom_id; } public ushort Data_Offset { get => _data_offset; set { _data_offset = value; command.SetParameter(1, _data_offset); } } public ushort DataLength { get => _data_length; set { _data_length = value; command.SetParameter(3, _data_length); } } public byte[] Data { set => _data = value; get => _data; } protected override Commands _Command => Commands.QueryOneWireEEPROM; public QueryEeprom(Common.Interface.DASFactory.ICommunication sock) : base(sock) { command.Parameter = new byte[5]; } public QueryEeprom(Common.Interface.DASFactory.ICommunication sock, int TimeoutMillisec) : base(sock, TimeoutMillisec) { command.Parameter = new byte[5]; } protected override CommandReceiveAction WholePackage() { if (response.Status == DFConstantsAndEnums.CommandStatus.StatusNoError) { response.GetParameter(0, out _eeprom_id); response.GetParameter(1, out _data_offset); response.GetParameter(3, out _data_length); _data = new byte[_data_length]; for (int i = 0; i < _data_length; i++) { response.GetParameter(5 + i, out _data[i]); } } return CommandReceiveAction.StopReceiving; } public override void ResponseToString(ref List> lines) { base.ResponseToString(ref lines); lines.Add(new List() { string.Format("Data: {0}", Encoding.UTF8.GetString(_data)) }); } } public class SetEeprom : InformationCommands { private byte _eeprom_id = 0; private ushort _data_offset = 0; private ushort _data_length = 0; private string _data = string.Empty; protected override Commands _Command => Commands.SetOneWireEEPROM; public byte ID { set => _eeprom_id = value; get => _eeprom_id; } public ushort Data_Offset { get => _data_offset; set => _data_offset = value; } public ushort DataLength { get => _data_length; set => _data_length = value; } public string Data { set => _data = value; get => _data; } public void SetEEPROM() { command.Parameter = new byte[6 + _data_length]; for (int i = 0; i < _data_length; i++) { command.SetParameter(5 + i, _data[i]); } command.SetParameter(0, _eeprom_id); command.SetParameter(1, _data_offset); command.SetParameter(3, _data_length); } public SetEeprom(Common.Interface.DASFactory.ICommunication sock) : base(sock) { } public SetEeprom(Common.Interface.DASFactory.ICommunication sock, int TimeoutMillisec) : base(sock, TimeoutMillisec) { } public override void CommandToString(ref List> lines) { base.CommandToString(ref lines); lines.Add(new List() { string.Format("Data: {0}", _data) }); } } }