using System; using System.Collections.Generic; using System.Text; using DTS.Common.Enums.DASFactory; using DTS.Common.Utilities.Logging; using DTS.Common.Utils; namespace DTS.DASLib.Command { /// /// this is the base for all slice command packets /// from here SliceDb and slice command packets will have different commands that can be /// run and a different command type enum containing the command types, however /// this class contains the common logic for addressing and packing the packet /// public abstract class SliceCommandPacketBase : CommandPacketBase { public const byte MAGIC_BYTE = 0xFA; protected const int HEADER_SIZE_BYTES = 12; protected const int DATA_CRC_SIZE_BYTES = 2; // Packet format -- all are 8 bits, but ParameterLength, SequenceNumber and HeaderCRC protected const int MagicBytePosition = 0; protected const int TypePosition = 1; protected const int CommandPosition = 2; protected const int StatusPosition = 3; protected const int DeviceGroupPosition = 4; protected const int DeviceIDPosition = 5; // Parameter length is 16 bits protected const int ParameterLengthPosition = 6; // Sequence number length is 16 bits protected const int SequenceNumberPosition = 8; // Header CRC is 16 bits protected const int HeaderCRCPosition = 10; public UInt16 ParameterLength; public byte DeviceGroup; public byte DeviceID; public UInt16 HeaderCRC; public byte[] Parameter; public UInt16 ParameterCRC; public SliceCommandPacketBase() { Parameter = new byte[0]; AlreadyRun = false; ShouldLog = true; GetNextSequenceNumber(); } public SliceCommandPacketBase(byte[] Bytes) { OriginalBytes = Bytes; ShouldLog = true; if (HEADER_SIZE_BYTES <= Bytes.Length && MAGIC_BYTE == Bytes[0]) { Type = ConvertByteToCommandType(Bytes[TypePosition]);//(CommandType)Bytes[TypePosition]; //Command = Bytes[CommandPosition]; SetCommand(Bytes[CommandPosition], Convert.ToString(Bytes[CommandPosition])); Status = (DFConstantsAndEnums.CommandStatus)Bytes[StatusPosition]; DeviceGroup = Bytes[DeviceGroupPosition]; DeviceID = Bytes[DeviceIDPosition]; ParameterLength = (ushort)(Bytes[ParameterLengthPosition + 0] | (Bytes[ParameterLengthPosition + 1] << 8)); SequenceNumber = (ushort)(Bytes[SequenceNumberPosition + 0] | (Bytes[SequenceNumberPosition + 1] << 8)); HeaderCRC = (ushort)(Bytes[HeaderCRCPosition + 0] | (Bytes[HeaderCRCPosition + 1] << 8)); Parameter = new byte[ParameterLength]; if (ParameterLength > 0 && Bytes.Length > HEADER_SIZE_BYTES) { try { Buffer.BlockCopy(Bytes, HEADER_SIZE_BYTES + DATA_CRC_SIZE_BYTES, Parameter, 0, ParameterLength); ParameterCRC = (UInt16)(Bytes[HEADER_SIZE_BYTES + 0] | Bytes[HEADER_SIZE_BYTES + 1] << 8); } catch (Exception ex) { APILogger.Log(ex); } } } } public override PacketState VerifyPacket(byte[] Bytes) { if (Bytes == null) return PacketState.Unknown; if (Bytes.Length < HEADER_SIZE_BYTES) return PacketState.TooShort; if (Bytes[MagicBytePosition] != MAGIC_BYTE) return PacketState.Unknown; object type = ConvertByteToCommandType(Bytes[TypePosition]); //CommandType type = (CommandType)Bytes[TypePosition]; byte command = Bytes[CommandPosition]; CommandStatus status = (CommandStatus)Bytes[StatusPosition]; byte deviceGroup = Bytes[DeviceGroupPosition]; byte deviceID = Bytes[DeviceIDPosition]; ushort parameterLength = (ushort)(Bytes[ParameterLengthPosition + 0] | (Bytes[ParameterLengthPosition + 1] << 8)); // TODO: Why isn't this checking the CRCs? //ushort headerCRC = (ushort)(Bytes[9] | (Bytes[8] << 8)); //ushort parameterCRC = (UInt16)(Bytes[10 + 1 + parameterLength] | Bytes[10 + 0 + parameterLength] << 8); // Note that the second condition (parameterLength==0) is already caught above and does not need to // be here. if ((parameterLength > 0 && Bytes.Length < parameterLength + HEADER_SIZE_BYTES + DATA_CRC_SIZE_BYTES) || (0 == parameterLength && Bytes.Length < HEADER_SIZE_BYTES)) { return PacketState.TooShort; } //if(Bytes.Length > parameterLength + 10 + 2) // return PacketState.TooLong; return PacketState.OK; } public override void ComputeCRCs() { HeaderCRC = 0xFFFF; // Compute the CRC of the first 8 bytes in the CommandPacket // This is a little more awkward than it should be but since the length field // is really two bytes, but packed into the 16-bit variable, we need to mask it // off and compute the CRC of the bytes in the correct order, etc. //Utility.Utility.Crc16Ccitt crccalc = new Utility.Utility.Crc16Ccitt(Utility.Utility.InitialCrcValue.Zeros); //crccalc.UpdateChecksum((ushort)0xFA); //crccalc.UpdateChecksum((ushort)Type); //crccalc.UpdateChecksum((ushort)Command); //crccalc.UpdateChecksum((ushort)Status); //crccalc.UpdateChecksum((ushort)DeviceGroup); //crccalc.UpdateChecksum((ushort)DeviceID); //crccalc.UpdateChecksum((ushort)(Parameter.Length & 0xFF)); //crccalc.UpdateChecksum((ushort)((Parameter.Length & 0xFF00) >> 8)); //HeaderCRC = crccalc.cur HeaderCRC = Utils.Math_DoCRCCCITTStep(0xFA, HeaderCRC); HeaderCRC = Utils.Math_DoCRCCCITTStep((ushort)((int)Type), HeaderCRC); HeaderCRC = Utils.Math_DoCRCCCITTStep(GetCommand(), HeaderCRC); HeaderCRC = Utils.Math_DoCRCCCITTStep((ushort)Status, HeaderCRC); HeaderCRC = Utils.Math_DoCRCCCITTStep(DeviceGroup, HeaderCRC); HeaderCRC = Utils.Math_DoCRCCCITTStep(DeviceID, HeaderCRC); HeaderCRC = Utils.Math_DoCRCCCITTStep((ushort)(Parameter.Length & 0xFF), HeaderCRC); HeaderCRC = Utils.Math_DoCRCCCITTStep((ushort)((Parameter.Length & 0xFF00) >> 8), HeaderCRC); HeaderCRC = Utils.Math_DoCRCCCITTStep((ushort)(SequenceNumber & 0xFF), HeaderCRC); HeaderCRC = Utils.Math_DoCRCCCITTStep((ushort)((SequenceNumber & 0xFF00) >> 8), HeaderCRC); // Compute the Parameter CRC ParameterCRC = 0xFFFF; // If length > 0, continue the computation over the data bytes if (Parameter.Length > 0) { for (int i = 0; i < Parameter.Length; i++) { ParameterCRC = Utils.Math_DoCRCCCITTStep(Parameter[i], ParameterCRC); } } } public void GetParameter(int Offset, out double Value) { ByteConvertor.Convert(Parameter, Offset, out Value); } public void GetParameter(int Offset, out UInt64 Value) { Value = 0 | (ulong)Parameter[Offset + 7] << 0 | (ulong)Parameter[Offset + 6] << 8 | (ulong)Parameter[Offset + 5] << 16 | (ulong)Parameter[Offset + 4] << 24 | (ulong)Parameter[Offset + 3] << 32 | (ulong)Parameter[Offset + 2] << 40 | (ulong)Parameter[Offset + 1] << 48 | (ulong)Parameter[Offset + 0] << 56; } public void GetParameter(int Offset, out Int64 Value) { Value = (long)Parameter[Offset + 7] << 0 | (long)Parameter[Offset + 6] << 8 | (long)Parameter[Offset + 5] << 16 | (long)Parameter[Offset + 4] << 24 | (long)Parameter[Offset + 3] << 32 | (long)Parameter[Offset + 2] << 40 | (long)Parameter[Offset + 1] << 48 | (long)Parameter[Offset + 0] << 56; } public void GetParameter(int Offset, out Int32 Value) { Value = Parameter[Offset + 3] | Parameter[Offset + 2] << 8 | Parameter[Offset + 1] << 16 | Parameter[Offset + 0] << 24; } public void GetParameter(int Offset, out UInt32 Value) { Value = (UInt32)(Parameter[Offset + 3] | Parameter[Offset + 2] << 8 | Parameter[Offset + 1] << 16 | Parameter[Offset + 0] << 24); } public void GetParameter(int Offset, out Int16 Value) { Value = (Int16)(Parameter[Offset + 1] | Parameter[Offset + 0] << 8); } public void GetParameter(int Offset, out UInt16 Value) { Value = (UInt16)(Parameter[Offset + 1] | Parameter[Offset + 0] << 8); } public void GetParameter(int Offset, out byte Value) { Value = Parameter[Offset]; } public void GetParameter(int Offset, out bool Value) { Value = (Parameter[Offset] == 0x01); } public void GetParameter(int Offset, out float Value) { Value = BitConverter.ToSingle(Parameter, Offset); } public void GetParameter(int Offset, out string Value) { StringBuilder sb = new StringBuilder(); int idx = Offset; while (idx < Parameter.Length && 0 != Parameter[idx]) { sb.Append((char)Parameter[idx++]); } Value = sb.ToString(); } public void SetParameter(int Offset, double Value) { byte[] rv = ByteConvertor.ToByteArray(Value); Buffer.BlockCopy(rv, 0, Parameter, Offset, rv.Length); } public void SetParameter(int Offset, Int64 Value) { Parameter[Offset + 7] = (byte)(((ulong)Value & 0x00000000000000FF) >> 0); Parameter[Offset + 6] = (byte)(((ulong)Value & 0x000000000000FF00) >> 8); Parameter[Offset + 5] = (byte)(((ulong)Value & 0x0000000000FF0000) >> 16); Parameter[Offset + 4] = (byte)(((ulong)Value & 0x00000000FF000000) >> 24); Parameter[Offset + 3] = (byte)(((ulong)Value & 0x000000FF00000000) >> 32); Parameter[Offset + 2] = (byte)(((ulong)Value & 0x0000FF0000000000) >> 40); Parameter[Offset + 1] = (byte)(((ulong)Value & 0x00FF000000000000) >> 48); Parameter[Offset + 0] = (byte)(((ulong)Value & 0xFF00000000000000) >> 56); } public void SetParameter(int Offset, UInt64 Value) { Parameter[Offset + 7] = (byte)((Value & 0x00000000000000FF) >> 0); Parameter[Offset + 6] = (byte)((Value & 0x000000000000FF00) >> 8); Parameter[Offset + 5] = (byte)((Value & 0x0000000000FF0000) >> 16); Parameter[Offset + 4] = (byte)((Value & 0x00000000FF000000) >> 24); Parameter[Offset + 3] = (byte)((Value & 0x000000FF00000000) >> 32); Parameter[Offset + 2] = (byte)((Value & 0x0000FF0000000000) >> 40); Parameter[Offset + 1] = (byte)((Value & 0x00FF000000000000) >> 48); Parameter[Offset + 0] = (byte)((Value & 0xFF00000000000000) >> 56); } public void SetParameter(int Offset, Int32 Value) { Parameter[Offset + 3] = (byte)((Value & 0x000000FF)); Parameter[Offset + 2] = (byte)((Value & 0x0000FF00) >> 8); Parameter[Offset + 1] = (byte)((Value & 0x00FF0000) >> 16); Parameter[Offset + 0] = (byte)((Value & 0xFF000000) >> 24); } public void SetParameter(int Offset, UInt32 Value) { Parameter[Offset + 3] = (byte)((Value & 0x000000FF)); Parameter[Offset + 2] = (byte)((Value & 0x0000FF00) >> 8); Parameter[Offset + 1] = (byte)((Value & 0x00FF0000) >> 16); Parameter[Offset + 0] = (byte)((Value & 0xFF000000) >> 24); } public void SetParameter(int Offset, Int16 Value) { Parameter[Offset + 1] = (byte)(Value & 0x00FF); Parameter[Offset + 0] = (byte)((Value & 0xFF00) >> 8); } public void SetParameter(int Offset, UInt16 Value) { Parameter[Offset + 1] = (byte)(Value & 0x00FF); Parameter[Offset + 0] = (byte)((Value & 0xFF00) >> 8); } public void SetParameter(int Offset, byte Value) { Parameter[Offset] = Value; } public void SetParameter(int Offset, bool Value) { Parameter[Offset] = (byte)(Value ? 0x01 : 0x00); } public void SetParameter(int Offset, byte[] Value) { Value.CopyTo(Parameter, Offset); } public void SetParameter(int Offset, string Value) { char[] original = Value.ToCharArray(); char[] withNullTermination = new char[original.Length + 1]; original.CopyTo(withNullTermination, 0); withNullTermination[withNullTermination.Length - 1] = '\0'; SetParameter(Offset, withNullTermination); } public void SetParameter(int Offset, char[] Value) { for (int i = 0; i < Value.Length; i++) { Parameter[Offset + i] = (byte)Value[i]; } Parameter[Parameter.Length - 1] = 0; } public void SetParameter(int Offset, char Value) { Parameter[Offset] = (byte)Value; } public void SetParameter(int Offset, float Value) { BitConverter.GetBytes(Value).CopyTo(Parameter, Offset); } public override byte[] ToBytes() { int Length; byte[] CommandBytes; Length = HEADER_SIZE_BYTES + Parameter.Length + (Parameter.Length > 0 ? DATA_CRC_SIZE_BYTES : 0); CommandBytes = new byte[Length]; CommandBytes[MagicBytePosition] = MAGIC_BYTE; CommandBytes[TypePosition] = (byte)((int)Type); CommandBytes[CommandPosition] = GetCommand(); CommandBytes[StatusPosition] = (byte)Status; CommandBytes[DeviceGroupPosition] = DeviceGroup; CommandBytes[DeviceIDPosition] = DeviceID; CommandBytes[ParameterLengthPosition + 0] = (byte)((Parameter.Length & 0xFF00) >> 8); CommandBytes[ParameterLengthPosition + 1] = (byte)(Parameter.Length & 0x00FF); CommandBytes[SequenceNumberPosition + 0] = (byte)((SequenceNumber & 0xFF00) >> 8); CommandBytes[SequenceNumberPosition + 1] = (byte)(SequenceNumber & 0x00FF); CommandBytes[HeaderCRCPosition + 0] = (byte)((HeaderCRC & 0xFF00) >> 8); CommandBytes[HeaderCRCPosition + 1] = (byte)(HeaderCRC & 0x00FF); for (int iIndex = 0; iIndex < Parameter.Length; iIndex++) { CommandBytes[iIndex + HEADER_SIZE_BYTES + DATA_CRC_SIZE_BYTES] = Parameter[iIndex]; } if (Parameter.Length > 0) { CommandBytes[HEADER_SIZE_BYTES + 0] = (byte)((ParameterCRC & 0xFF00) >> 8); CommandBytes[HEADER_SIZE_BYTES + 1] = (byte)(ParameterCRC & 0x00FF); } OriginalBytes = CommandBytes; return CommandBytes; } } }