528 lines
20 KiB
C#
528 lines
20 KiB
C#
|
|
using DTS.Common.Utilities.Logging;
|
|||
|
|
using System;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.Diagnostics;
|
|||
|
|
using System.IO;
|
|||
|
|
using System.Linq;
|
|||
|
|
using System.Net;
|
|||
|
|
using System.Text;
|
|||
|
|
using System.Threading;
|
|||
|
|
|
|||
|
|
namespace DTS.DASLib.Command.TDAS
|
|||
|
|
{
|
|||
|
|
/*
|
|||
|
|
* typedef struct _md {
|
|||
|
|
int delim; delimiter pattern
|
|||
|
|
int key; key to mem state
|
|||
|
|
long itemSize; mem size that this MDB controls
|
|||
|
|
long dataSize; length of valid data buffer
|
|||
|
|
unsigned int nCrc; buffer crc
|
|||
|
|
void *flink; forward link to next buffer
|
|||
|
|
struct _md *next; used for doubly-linked list
|
|||
|
|
struct _md *prev; of all mds
|
|||
|
|
void *this; this buffer of size itemSize
|
|||
|
|
void *freeList; a free list of objects
|
|||
|
|
long nInst; number of memory blocks created
|
|||
|
|
long nActive; number still out there somewhere
|
|||
|
|
long nFree; length of free list
|
|||
|
|
}*/
|
|||
|
|
//note in CVI longs are the same size as ints, or 4 bytes
|
|||
|
|
internal class MDB_BLOCK
|
|||
|
|
{
|
|||
|
|
public enum MDB_Fields
|
|||
|
|
{
|
|||
|
|
delim = 0,
|
|||
|
|
key,
|
|||
|
|
itemSize,
|
|||
|
|
dataSize,
|
|||
|
|
nCrc,
|
|||
|
|
flink,
|
|||
|
|
next,
|
|||
|
|
prev,
|
|||
|
|
ptrThis,
|
|||
|
|
freeList,
|
|||
|
|
nInst,
|
|||
|
|
nActive,
|
|||
|
|
nFree
|
|||
|
|
}
|
|||
|
|
public int GetField(MDB_Fields field)
|
|||
|
|
{
|
|||
|
|
return IPAddress.NetworkToHostOrder(BitConverter.ToInt32(_mdb, 4 * (int)field));
|
|||
|
|
}
|
|||
|
|
private byte[] _mdb;
|
|||
|
|
public const int MDB_BLOCK_SIZE = 52;
|
|||
|
|
public const int DMA_SIZE = 1024;
|
|||
|
|
public const int DMA_BLOCK_SIZE = MDB_BLOCK_SIZE + DMA_SIZE;
|
|||
|
|
public const int MEM_KEY_START = 100;
|
|||
|
|
public static readonly byte[] DelimBytes = { 0xFE, 0x01, 0xFD, 0x02 };
|
|||
|
|
public static readonly int DelimPattern = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(DelimBytes, 0));
|
|||
|
|
public static readonly string DelimString = BitConverter.ToString(DelimBytes);
|
|||
|
|
public MDB_BLOCK(byte[] packet)
|
|||
|
|
{
|
|||
|
|
_mdb = packet;
|
|||
|
|
}
|
|||
|
|
public bool HasData => (null != _mdb && GetField(MDB_Fields.dataSize) > 0);
|
|||
|
|
|
|||
|
|
public short[] GetData()
|
|||
|
|
{
|
|||
|
|
var data = new List<short>();
|
|||
|
|
for (var i = 0; i < GetField(MDB_Fields.dataSize) / 2; i++)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
var value = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(_mdb, MDB_BLOCK_SIZE + i * 2));
|
|||
|
|
data.Add(value);
|
|||
|
|
}
|
|||
|
|
catch (Exception) { Trace.WriteLine("failed to convert " + i); }
|
|||
|
|
}
|
|||
|
|
return data.ToArray();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
public class TDASCommandPacketBase : CommandPacketBase
|
|||
|
|
{
|
|||
|
|
public bool RackCommand
|
|||
|
|
{
|
|||
|
|
get => _commandStrings[0].RackCommand;
|
|||
|
|
set => _commandStrings[0].RackCommand = value;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public bool SingleModuleCommand
|
|||
|
|
{
|
|||
|
|
get { return _commandStrings[0].SingleModuleCommand; }
|
|||
|
|
set { _commandStrings[0].SingleModuleCommand = value; }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public string RackSerialNumber
|
|||
|
|
{
|
|||
|
|
get { return _commandStrings[0].RackSerialNumber; }
|
|||
|
|
set { _commandStrings[0].RackSerialNumber = value; }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
private char _moduleIndex = ' ';
|
|||
|
|
public int ModuleIndex
|
|||
|
|
{
|
|||
|
|
get => int.Parse(new string(_moduleIndex, 1));
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
if (value > 9) { throw new Exception("ModuleIndex must be <10 for this command" + ModuleIndex); }
|
|||
|
|
_moduleIndex = value.ToString()[0];
|
|||
|
|
RackCommand = false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public bool AllModule { get; set; }
|
|||
|
|
|
|||
|
|
|
|||
|
|
public bool RebuildBytes { get; set; }
|
|||
|
|
|
|||
|
|
public bool ExpectsData
|
|||
|
|
{
|
|||
|
|
get => _commandStrings[0].ExpectsData;
|
|||
|
|
set => _commandStrings[0].ExpectsData = value;
|
|||
|
|
}
|
|||
|
|
public bool ExpectsMultipleLines
|
|||
|
|
{
|
|||
|
|
get => _commandStrings[0].ExpectsMultipleLines;
|
|||
|
|
set => _commandStrings[0].ExpectsMultipleLines = value;
|
|||
|
|
}
|
|||
|
|
public int LinesExpected
|
|||
|
|
{
|
|||
|
|
get => _commandStrings[0].LinesExpected;
|
|||
|
|
set => _commandStrings[0].LinesExpected = value;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private const int MAX_CMD = 1;
|
|||
|
|
private const int MAX_CMD_SIZE = 512;
|
|||
|
|
public const int CDB_SIZE = 536;
|
|||
|
|
|
|||
|
|
private readonly byte _cdbId;
|
|||
|
|
private readonly byte _cdbQueue;
|
|||
|
|
public byte CharWait { get; set; }
|
|||
|
|
|
|||
|
|
public int ReplyWait { get; set; }
|
|||
|
|
|
|||
|
|
private readonly byte[] _reserved;
|
|||
|
|
private readonly int _rackId;
|
|||
|
|
private readonly byte[] _memoryAddress = GENERIC_MEMORY_ADDRESS;
|
|||
|
|
private readonly List<CommandString> _commandStrings = new List<CommandString>();
|
|||
|
|
private readonly byte[] _responseBytes;
|
|||
|
|
private static readonly byte[] GENERIC_MEMORY_ADDRESS = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
|||
|
|
|
|||
|
|
public override byte[] ToBytes()
|
|||
|
|
{
|
|||
|
|
if (null != _responseBytes) { return _responseBytes; }
|
|||
|
|
|
|||
|
|
var ms = new MemoryStream(CDB_SIZE);
|
|||
|
|
|
|||
|
|
ms.WriteByte(_cdbId);
|
|||
|
|
ms.WriteByte(_cdbQueue);
|
|||
|
|
ms.WriteByte(Convert.ToByte(_commandStrings.Count));
|
|||
|
|
ms.WriteByte(CharWait);
|
|||
|
|
ms.Write(BitConverter.GetBytes(ReplyWait), 0, 4);
|
|||
|
|
ms.Write(_reserved, 0, _reserved.Length);
|
|||
|
|
ms.Write(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(_rackId)), 0, 4);
|
|||
|
|
ms.Write(_memoryAddress, 0, _memoryAddress.Length);
|
|||
|
|
|
|||
|
|
if (RackCommand)
|
|||
|
|
{
|
|||
|
|
ms.Write(new byte[] { 0x31, 0x30, 0x30, 0x30 }, 0, 4);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
if (AllModule) { ms.WriteByte(Convert.ToByte('*')); }
|
|||
|
|
if (_moduleIndex != ' ')
|
|||
|
|
{
|
|||
|
|
ms.WriteByte(Convert.ToByte(Convert.ToByte(_moduleIndex)));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
foreach (var cs in _commandStrings)
|
|||
|
|
{
|
|||
|
|
if (RebuildBytes) { cs.RebuildBytes(); }
|
|||
|
|
ms.Write(cs.GetBytes(), 0, cs.Length);
|
|||
|
|
}
|
|||
|
|
//17716 eliminate extra characters filling out outgoing TDAS coms
|
|||
|
|
//if (ms.Length < CDB_SIZE)
|
|||
|
|
//{
|
|||
|
|
// ms.Write(new byte[CDB_SIZE - (int)ms.Length], 0, CDB_SIZE - (int)ms.Length);
|
|||
|
|
//}
|
|||
|
|
return ms.ToArray();
|
|||
|
|
}
|
|||
|
|
public override object ConvertByteToCommandType(byte b)
|
|||
|
|
{
|
|||
|
|
throw new NotSupportedException("TDASCommandPacketBase::ConvertByteToCommandType not supported");
|
|||
|
|
}
|
|||
|
|
private int _expectedBytes;
|
|||
|
|
private int _bytesSoFar;
|
|||
|
|
public bool UseMDBMode { get; set; }
|
|||
|
|
|
|||
|
|
public bool MonitorDataMode { get; set; }
|
|||
|
|
|
|||
|
|
private readonly List<MDB_BLOCK> _data = new List<MDB_BLOCK>();
|
|||
|
|
private int _curOffset;
|
|||
|
|
|
|||
|
|
public int GetExpectedBytes()
|
|||
|
|
{
|
|||
|
|
return _expectedBytes;
|
|||
|
|
}
|
|||
|
|
public short[] GetData()
|
|||
|
|
{
|
|||
|
|
List<short> data = new List<short>();
|
|||
|
|
//we have to skip the first one for some odd reason?
|
|||
|
|
for (int i = 1; i < _data.Count; i++)
|
|||
|
|
{
|
|||
|
|
MDB_BLOCK mdb = _data[i];
|
|||
|
|
if (mdb.HasData)
|
|||
|
|
{
|
|||
|
|
data.AddRange(mdb.GetData());
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return data.ToArray();
|
|||
|
|
}
|
|||
|
|
public bool RealtimeCommand { get; set; }
|
|||
|
|
public override PacketState VerifyPacket(byte[] Bytes)
|
|||
|
|
{
|
|||
|
|
if (!ExpectsData && Bytes.Length > 0)
|
|||
|
|
{
|
|||
|
|
Thread.Sleep(100); //cut from 500 to 100 for performance reasons
|
|||
|
|
APILogger.Log($"VerifyPacket [{SequenceNumber}], returning OK as we don't expect data and have greater than 0 length ({Bytes.Length})");
|
|||
|
|
return PacketState.OK;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (UseMDBMode)
|
|||
|
|
{
|
|||
|
|
if (0 == _curOffset)
|
|||
|
|
{
|
|||
|
|
int index = -1;
|
|||
|
|
string s = BitConverter.ToString(Bytes);
|
|||
|
|
try { index = s.IndexOf(MDB_BLOCK.DelimString, 1); }
|
|||
|
|
catch (Exception) { }
|
|||
|
|
if (index < 0)
|
|||
|
|
{
|
|||
|
|
return PacketState.TooShort;
|
|||
|
|
}
|
|||
|
|
if (index > 0)
|
|||
|
|
{
|
|||
|
|
//need to advance to the start of the block
|
|||
|
|
for (var i = 1; i < Bytes.Length - MDB_BLOCK.DelimBytes.Length; i++)
|
|||
|
|
{
|
|||
|
|
if (Bytes[i] != MDB_BLOCK.DelimBytes[0] || Bytes[i + 1] != MDB_BLOCK.DelimBytes[1] ||
|
|||
|
|
Bytes[i + 2] != MDB_BLOCK.DelimBytes[2] ||
|
|||
|
|
Bytes[i + 3] != MDB_BLOCK.DelimBytes[3]) continue;
|
|||
|
|
_curOffset = i;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
while (Bytes.Length - _curOffset >= MDB_BLOCK.DMA_BLOCK_SIZE)
|
|||
|
|
{
|
|||
|
|
byte[] block;
|
|||
|
|
using (var ms = new MemoryStream())
|
|||
|
|
{
|
|||
|
|
//need to advance to the start of the block
|
|||
|
|
for (var i = _curOffset; i < Bytes.Length - MDB_BLOCK.DelimBytes.Length; i++)
|
|||
|
|
{
|
|||
|
|
if (Bytes[i] != MDB_BLOCK.DelimBytes[0] || Bytes[i + 1] != MDB_BLOCK.DelimBytes[1] ||
|
|||
|
|
Bytes[i + 2] != MDB_BLOCK.DelimBytes[2] ||
|
|||
|
|
Bytes[i + 3] != MDB_BLOCK.DelimBytes[3]) continue;
|
|||
|
|
_curOffset = i;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//scan forward from _curOffset till we see the
|
|||
|
|
ms.Write(Bytes, _curOffset, MDB_BLOCK.DMA_BLOCK_SIZE);
|
|||
|
|
_curOffset += MDB_BLOCK.DMA_BLOCK_SIZE;
|
|||
|
|
block = ms.ToArray();
|
|||
|
|
}
|
|||
|
|
var mdb = new MDB_BLOCK(block);
|
|||
|
|
|
|||
|
|
_data.Add(mdb);
|
|||
|
|
if (mdb.GetField(MDB_BLOCK.MDB_Fields.delim) == MDB_BLOCK.DelimPattern)
|
|||
|
|
{
|
|||
|
|
if (mdb.GetField(MDB_BLOCK.MDB_Fields.key) == MDB_BLOCK.MEM_KEY_START)
|
|||
|
|
{
|
|||
|
|
var s = Encoding.ASCII.GetString(block, MDB_BLOCK.MDB_BLOCK_SIZE + 5, 10);
|
|||
|
|
var tokens = s.Split(' ');
|
|||
|
|
_expectedBytes = Convert.ToInt32(tokens[0]);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
_bytesSoFar += mdb.GetField(MDB_BLOCK.MDB_Fields.dataSize);
|
|||
|
|
if (_bytesSoFar >= _expectedBytes && 0 != _expectedBytes)
|
|||
|
|
{
|
|||
|
|
return PacketState.OK;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
return PacketState.OK;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return PacketState.TooShort;
|
|||
|
|
}
|
|||
|
|
{
|
|||
|
|
string s = Encoding.ASCII.GetString(Bytes);
|
|||
|
|
//Could be a multi-line response where we've grabbed the newline as the first characters.
|
|||
|
|
if (s.Length > 2 && s.IndexOf("\r\n") >= 0)
|
|||
|
|
{
|
|||
|
|
if (!s.EndsWith("\r\n") && ExpectsMultipleLines)
|
|||
|
|
{
|
|||
|
|
APILogger.Log($"TDASCommandPacketBase:VerifyPacket [{SequenceNumber}], returning too short {s}");
|
|||
|
|
return PacketState.TooShort;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!ExpectsMultipleLines)
|
|||
|
|
{
|
|||
|
|
APILogger.Log($"TDASCommandPacketBase:VerifyPacket [{SequenceNumber}], returning OK, not expecting multiple lines: {s}");
|
|||
|
|
return PacketState.OK;
|
|||
|
|
}
|
|||
|
|
var lines = s.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
|
|||
|
|
|
|||
|
|
//G5 returns ~ and if we see that we know we still have more lines coming
|
|||
|
|
//TDAS PRO does not, but we do have an expectation of a certain number of lines
|
|||
|
|
|
|||
|
|
if (lines[lines.Length - 1].Contains('~'))
|
|||
|
|
{
|
|||
|
|
APILogger.Log($"[{SequenceNumber}] returning packet too short (contains ~) {s}");
|
|||
|
|
return PacketState.TooShort;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (lines.Length < LinesExpected)
|
|||
|
|
{
|
|||
|
|
APILogger.Log(
|
|||
|
|
$"[{SequenceNumber}] Lines less than expected, returning too short {lines.Length}<{LinesExpected} for {s}");
|
|||
|
|
return PacketState.TooShort;
|
|||
|
|
}
|
|||
|
|
//if command has a required response and we haven't seen it yet,
|
|||
|
|
//consider us as having not received the full response yet.
|
|||
|
|
//18127 Test Channel Run Broadcast can complete before response is received and processed
|
|||
|
|
if (null != _commandStrings && 1 == _commandStrings.Count &&
|
|||
|
|
!string.IsNullOrEmpty(_commandStrings[0].RequiredResponseString))
|
|||
|
|
{
|
|||
|
|
if (!s.Contains(_commandStrings[0].RequiredResponseString))
|
|||
|
|
{
|
|||
|
|
return PacketState.TooShort;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return PacketState.OK;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
APILogger.Log($"[{SequenceNumber}] Returning too short - {s} - didn't find CR-EOL");
|
|||
|
|
return PacketState.TooShort;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
private static ushort _globalSequenceNumber;
|
|||
|
|
private static readonly object GLOBAL_SEQUENCE_NUMBER_LOCK = new object();
|
|||
|
|
public override void GetNextSequenceNumber()
|
|||
|
|
{
|
|||
|
|
lock (GLOBAL_SEQUENCE_NUMBER_LOCK)
|
|||
|
|
{
|
|||
|
|
SequenceNumber = _globalSequenceNumber;
|
|||
|
|
_globalSequenceNumber++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
public override void ComputeCRCs()
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
private void AddCommand(CommandString commandString)
|
|||
|
|
{
|
|||
|
|
if (_commandStrings.Count + 1 > MAX_CMD)
|
|||
|
|
{
|
|||
|
|
throw new CommandPacketException(CommandPacketException.ERROR_CODES.TOO_MANY_COMMANDS, CommandPacketException.ERROR_CODES.TOO_MANY_COMMANDS.ToString());
|
|||
|
|
}
|
|||
|
|
int totalBytes = commandString.Length;
|
|||
|
|
foreach (CommandString cs in _commandStrings) { totalBytes += cs.Length; }
|
|||
|
|
if (totalBytes > MAX_CMD_SIZE)
|
|||
|
|
{
|
|||
|
|
throw new CommandPacketException(CommandPacketException.ERROR_CODES.TOO_MANY_BYTES, CommandPacketException.ERROR_CODES.TOO_MANY_BYTES.ToString());
|
|||
|
|
}
|
|||
|
|
_commandStrings.Add(commandString);
|
|||
|
|
SetCommand(0x00, commandString.GetCommandDescription());
|
|||
|
|
Type = "TDAS";
|
|||
|
|
}
|
|||
|
|
public TDASCommandPacketBase(CommandString cs)
|
|||
|
|
{
|
|||
|
|
GetNextSequenceNumber();
|
|||
|
|
_cdbId = 1;
|
|||
|
|
_cdbQueue = Convert.ToByte(false);
|
|||
|
|
//support.dtsweb.com/hc/requests/7294
|
|||
|
|
//this is used to avoid flooding buffer, but was too large, TDC is using 1ms and presumably when we copied
|
|||
|
|
//tdc we must have used an older version
|
|||
|
|
CharWait = 0x01;
|
|||
|
|
ReplyWait = 30;
|
|||
|
|
_reserved = new byte[] { 0x00, 0x00, 0x00, 0x00 };
|
|||
|
|
_rackId = 1006;
|
|||
|
|
AddCommand(cs);
|
|||
|
|
}
|
|||
|
|
public TDASCommandPacketBase(byte[] buffer, CommandPacketBase command)
|
|||
|
|
{
|
|||
|
|
if (null != command)
|
|||
|
|
{
|
|||
|
|
SequenceNumber = command.SequenceNumber;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var s = Encoding.ASCII.GetString(buffer);
|
|||
|
|
if (s.Contains("1000ARM"))
|
|||
|
|
{
|
|||
|
|
APILogger.Log($"Sequence [{SequenceNumber}] complete response", s);
|
|||
|
|
}
|
|||
|
|
_responseBytes = buffer;
|
|||
|
|
SetCommand(0x00, "");
|
|||
|
|
Type = "TDAS";
|
|||
|
|
}
|
|||
|
|
public string GetCommandString(int index)
|
|||
|
|
{
|
|||
|
|
return _commandStrings[index].GetCommandPortion();
|
|||
|
|
}
|
|||
|
|
public CommandString GetCommandStringObject(int index) { return _commandStrings[index]; }
|
|||
|
|
public string ToCommandString()
|
|||
|
|
{
|
|||
|
|
byte[] bytes = ToBytes();
|
|||
|
|
return Encoding.ASCII.GetString(bytes, 24, bytes.Length - 24).Replace("\r\n", string.Empty).Replace("\0", string.Empty);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
public abstract class CommandString
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// defines a required string to find in the response
|
|||
|
|
/// if string is not found response is not complete yet
|
|||
|
|
/// override to require a response
|
|||
|
|
/// 18127 Test Channel Run Broadcast can complete before response is received and processed
|
|||
|
|
/// </summary>
|
|||
|
|
public virtual string RequiredResponseString { get; set; } = string.Empty;
|
|||
|
|
|
|||
|
|
public bool ExpectsData { get; set; } = true;
|
|||
|
|
|
|||
|
|
public bool ExpectsMultipleLines { get; set; }
|
|||
|
|
|
|||
|
|
public int LinesExpected { get; set; }
|
|||
|
|
|
|||
|
|
public virtual byte[] GetParameters()
|
|||
|
|
{
|
|||
|
|
return new byte[] { };
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private bool _bRackCommand = true;
|
|||
|
|
public bool RackCommand
|
|||
|
|
{
|
|||
|
|
get { return _bRackCommand; }
|
|||
|
|
set { _bRackCommand = value; }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private bool _bSingleModuleCommand = false;
|
|||
|
|
public bool SingleModuleCommand
|
|||
|
|
{
|
|||
|
|
get { return _bSingleModuleCommand; }
|
|||
|
|
set { _bSingleModuleCommand = value; }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private string _RackSerialNumber = string.Empty;
|
|||
|
|
public string RackSerialNumber
|
|||
|
|
{
|
|||
|
|
get { return _RackSerialNumber; }
|
|||
|
|
set { _RackSerialNumber = value; }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
protected abstract string _CommandString { get; }
|
|||
|
|
public virtual string GetCommandPortion() { return _CommandString; }
|
|||
|
|
protected abstract string _CommandDescription { get; }
|
|||
|
|
public string GetCommandDescription() { return _CommandDescription; }
|
|||
|
|
private byte[] _bytes;
|
|||
|
|
public int Length
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
if (null == _bytes)
|
|||
|
|
{
|
|||
|
|
_bytes = GetBytes();
|
|||
|
|
}
|
|||
|
|
return _bytes.Length;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void RebuildBytes() { _bytes = null; }
|
|||
|
|
|
|||
|
|
public byte[] GetBytes()
|
|||
|
|
{
|
|||
|
|
if (null != _bytes) return _bytes;
|
|||
|
|
var ms = new MemoryStream();
|
|||
|
|
|
|||
|
|
ms.Write(Encoding.ASCII.GetBytes(_CommandString), 0, _CommandString.Length);
|
|||
|
|
|
|||
|
|
byte[] parameters = GetParameters();
|
|||
|
|
if (parameters.Length > 0) { ms.Write(parameters, 0, parameters.Length); }
|
|||
|
|
|
|||
|
|
ms.Write(new byte[] { 0x0d, 0x0a }, 0, 2);
|
|||
|
|
_bytes = ms.ToArray();
|
|||
|
|
return _bytes;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
public class CommandPacketException : Exception
|
|||
|
|
{
|
|||
|
|
public enum ERROR_CODES
|
|||
|
|
{
|
|||
|
|
TOO_MANY_COMMANDS = 0,
|
|||
|
|
TOO_MANY_BYTES = 1,
|
|||
|
|
UNKNOWN = 2
|
|||
|
|
}
|
|||
|
|
public CommandPacketException(ERROR_CODES errorCode, string description)
|
|||
|
|
: base(description)
|
|||
|
|
{
|
|||
|
|
Data["ErrorCode"] = errorCode;
|
|||
|
|
}
|
|||
|
|
public ERROR_CODES ErrorCode
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
if (!Data.Contains("ErrorCode")) { return ERROR_CODES.UNKNOWN; }
|
|||
|
|
return (ERROR_CODES)Data["ErrorCode"];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|