I have to createcreated a C# library that can send commands to a device and process the command specific responses and broadcasts over a serial port (or other communications method). The library must also be able to handle request and response extensions held in other libraries as certain devices implement an extended command set, but it must be possible to choose whether these extended commands are utilised (I guess using reflection in the client app).
The library must also be able to handle request and response extensions held in other libraries as certain devices implement an extended command set, but it must be possible to choose whether these extended commands are utilised (I guess using reflection in the client app) however I have yet to find a good way to implement this bit yet.
I have created a class of type Packet that is able to create the packet and add its payload, calculate its checksum and write the packet to the stream and observe a packet router for receiving and processing responses.
I have to create a C# library that can send commands to a device and process the command specific responses and broadcasts over a serial port (or other communications method). The library must also be able to handle request and response extensions held in other libraries as certain devices implement an extended command set, but it must be possible to choose whether these extended commands are utilised (I guess using reflection in the client app).
I have created a class of type Packet that is able to create the packet and add its payload, calculate its checksum and write the packet to the stream.
I have created a C# library that can send commands to a device and process the command specific responses and broadcasts over a serial port (or other communications method).
The library must also be able to handle request and response extensions held in other libraries as certain devices implement an extended command set, but it must be possible to choose whether these extended commands are utilised (I guess using reflection in the client app) however I have yet to find a good way to implement this bit yet.
I have created a class of type Packet that is able to create the packet and add its payload, calculate its checksum write the packet to the stream and observe a packet router for receiving and processing responses.
- 31
- 1
- 3
public class Packet : IObserver<Packet>
{
//The following properties are used for returning a response
private IDisposable unsubscriber;
public bool ResponseReceived { get; private set; }
public double Timeout { get; set; }
private Packet ResponsePacket;
//The following properties are used for building a packet
internal PacketHeaderType Header { get; private set; } //This an enum of byte with possible values of 0-15
internal List<byte> Payload { get; private set; }
protected int PayloadLength { get { return Payload.Count; } }
protected byte HeaderByte { get { return (byte)((Convert.ToByte(Header) << 4) | PayloadLength); } } //we need to add the packet length to the lower nibble of the header before sending
public Packet(PacketHeaderType header, List<byte> payload)
{
this.Header = header;
this.Payload = new List<byte>(payload);
this.ResponseReceived = false;
this.Timeout = 5;
}
public Packet(PacketHeaderType headerByte)
{
this.Header = headerByte;
this.Payload = new List<byte>();
this.ResponseReceived = false;
this.Timeout = 5;
}
internal byte XorByte
{
get
{
Byte xorByte = Convert.ToByte(HeaderByte);
for (int i = 0; i < PayloadLength; i++)
xorByte ^= Payload.ToArray()[i];
return xorByte;
}
}
public async Task WriteAsync(Stream stream, bool returnResponse = false, bool flush = true, CancellationToken token = default(CancellationToken))
{
var buffer = new List<byte>();
buffer.Add(HeaderByte);
if (Payload != null && PayloadLength > 0)
{
buffer.AddRange(Payload);
}
buffer.Add(XorByte);
await stream.WriteAsync(buffer.ToArray(), 0, buffer.Count);
if (flush)
{
await stream.FlushAsync();
}
if (returnResponse)
{
var ts = new TimeSpan();
ts = TimeSpan.FromSeconds(Timeout);
while (DateTime.Now + ts < DateTime.Now && !ResponseReceived)
{
await Task.Delay(10);
}
}
}
private bool ValidResponse(Packet p)
{
return false;
}
public virtual void Subscribe(IObservable<Packet> provider)
{
if (provider != null)
unsubscriber = provider.Subscribe(this);
}
public virtual void OnCompleted()
{
this.Unsubscribe();
}
public virtual void OnError(Exception e)
{
Console.WriteLine("{0}: Cannot get packet from router.", this.ToString());
}
public virtual void OnNext(Packet value)
{
if (ValidResponse(value))
{
ResponsePacket = value;
ResponseReceived = true;
Unsubscribe();
}
}
public virtual void Unsubscribe()
{
unsubscriber.Dispose();
}
//This probably shouldn't be here as we now use it in the packet handler
public static async Task<Packet> ReadAsync(Stream stream, CancellationToken cancellationToken = default(CancellationToken))
{
//TODO: we should read the stream until we find a valid header!
var headerBuffer = new byte[1];
int bytesRead = await stream.ReadAsync(headerBuffer, 0, 1, cancellationToken);
if (bytesRead == 0)
{
return null;
}
var headerVal = (byte)(headerBuffer[0] >> 4);
var payloadLength = (headerBuffer[0] & 0x0F);
Packet packet = new Packet((PacketHeaderType)Enum.Parse(typeof(PacketHeaderType), headerVal.ToString()));
//TODO: we should handle unknown packets some how!
//if (Enum.IsDefined(typeof(XpressNetV3PacketType), headerVal))
var bytesRemaining = payloadLength;
var offset = 0;
if (payloadLength > 0)
{
var payloadBytes = new byte[payloadLength];
do
{
bytesRead = await stream.ReadAsync(payloadBytes, offset, bytesRemaining, cancellationToken);
if (bytesRead == 0)
{
throw new XpressNetProtocolViolationException("Unexpected end of stream");
}
bytesRemaining -= bytesRead;
offset += bytesRead;
} while (bytesRemaining > 0);
}
//check the xor matches
var xorByte = stream.ReadByte();
if (xorByte != packet.XorByte)
throw new XpressNetProtocolViolationException("Packet checksum is invalid");
return packet;
}
}
I have also created child classes that implement Type
packet for each of the valid commands (I don't think it is necessary to show them here...
FinallyI have created an IObservable message router in order for the packet to get a response:
public class PacketRouter : IObservable<Packet>
{
private List<IObserver<Packet>> observers = new List<IObserver<Packet>>();
public IDisposable Subscribe(IObserver<Packet> observer)
{
if (!observers.Contains(observer))
observers.Add(observer);
return new Unsubscriber(observers, observer);
}
private class Unsubscriber : IDisposable
{
private List<IObserver<Packet>> _observers;
private IObserver<Packet> _observer;
public Unsubscriber(List<IObserver<Packet>> observers, IObserver<Packet> observer)
{
this._observers = observers;
this._observer = observer;
}
public void Dispose()
{
if (_observer != null && _observers.Contains(_observer))
_observers.Remove(_observer);
}
}
public void SendPacket(Packet packet)
{
foreach (var observer in observers)
{
if (packet != null)
observer.OnError(new PacketUnknownException());
else
observer.OnNext(packet);
}
}
public void EndTransmission()
{
foreach (var observer in observers.ToArray())
if (observers.Contains(observer))
observer.OnCompleted();
observers.Clear();
}
}
public class PacketUnknownException : Exception
{
internal PacketUnknownException()
{
}
}
I have also created a class of type PacketHandler
that is able to read bytes from a stream and create it into a packet object. It also raises a broadcast event if the correct types of packets are discovered, otherwise it passes them to the messageRouter for handling by the library.
public class BroadcastMessageReceivedEventArgs : EventArgs
{
public Packet Packet { get; set; }
}
public static class PacketHandler
{
public static event EventHandler<BroadcastMessageReceivedEventArgs> BroadcastMessageReceived = delegate {};
public static void OnBroadcastMessageReceived(BroadcastMessageReceivedEventArgs e)
{
EventHandler<BroadcastMessageReceivedEventArgs> handler = BroadcastMessageReceived;
if (handler != null)
{
handler(null, e);
}
}
public static async Task<Packet> ReadPacketAsync(Stream stream, CancellationToken cancellationToken = default(CancellationToken))
{
var headerBuffer = new byte[1];
int bytesRead = await stream.ReadAsync(headerBuffer, 0, 1, cancellationToken);
if (bytesRead == 0)
{
return null;
}
var headerVal = (byte)(headerBuffer[0] >> 4);
var payloadLength = (headerBuffer[0] & 0x0F);
Packet packet = new Packet((PacketHeaderType)Enum.Parse(typeof(PacketHeaderType), headerVal.ToString()));
var bytesRemaining = payloadLength;
var offset = 0;
if (payloadLength > 0)
{
var payloadBytes = new byte[payloadLength];
do
{
bytesRead = await stream.ReadAsync(payloadBytes, offset, bytesRemaining, cancellationToken);
if (bytesRead == 0)
{
throw new XpressNetProtocolViolationException("Unexpected end of stream");
}
bytesRemaining -= bytesRead;
offset += bytesRead;
} while (bytesRemaining > 0);
}
//check the xor matches
var xorByte = stream.ReadByte();
if (xorByte != packet.XorByte)
throw new XpressNetProtocolViolationException("Packet checksum is invalid");
PacketReceived(packet);
return packet;
}
internal static void PacketReceived(Packet packet)
{
//TODO: Handle Broadcast Messages and AckResp
if ((packet.Header == PacketHeaderType.EmergencyStopAll) )
//|| (packet.Header == PacketHeaderType.CommandStationOperationResponse && packet.Payload.ElementAt(0) ))...
{
BroadcastMessageReceivedEventArgs bmr = new BroadcastMessageReceivedEventArgs();
bmr.Packet = packet;
OnBroadcastMessageReceived(bmr);
}
else
{
PacketRouter pump = new PacketRouter();
pump.SendPacket(packet);
}
}
}
public async string GetCmdStnSoftwareVersion()
{
var msgReq = new CmdStnSoftwareVersionReqMessage();
await var response msgReq.WriteAsync(sPort.BaseStream);
await var response =, msgReq.GetResponse(5true); //5 = timeout in seconds!
return String.Format("{0}.{1}", response.Major, response.Minor);
}
What I am stuck on isIs this a good pattern and/or example implementation for handling responses which is compatible with implementing the extension libraries. Can anyone provide input?
public class Packet
{
internal PacketHeaderType Header { get; private set; }
internal List<byte> Payload { get; private set; }
protected int PayloadLength { get { return Payload.Count; } }
protected byte HeaderByte { get { return (byte)((Convert.ToByte(Header) << 4) | PayloadLength); } } //we need to add the packet length to the lower nibble of the header before sending
public Packet(PacketHeaderType header, List<byte> payload)
{
this.Header = header;
this.Payload = new List<byte>(payload);
}
public Packet(PacketHeaderType headerByte)
{
this.Header = headerByte;
this.Payload = new List<byte>();
}
internal byte XorByte
{
get
{
Byte xorByte = Convert.ToByte(HeaderByte);
for (int i = 0; i < PayloadLength; i++)
xorByte ^= Payload.ToArray()[i];
return xorByte;
}
}
public async Task WriteAsync(Stream stream, bool flush = true, CancellationToken token = default(CancellationToken))
{
var buffer = new List<byte>();
buffer.Add(HeaderByte);
if (Payload != null && PayloadLength > 0)
{
buffer.AddRange(Payload);
}
buffer.Add(XorByte);
await stream.WriteAsync(buffer.ToArray(), 0, buffer.Count);
if (flush)
{
await stream.FlushAsync();
}
}
}
I have also created child classes that implement Type
packet for each of the valid commands.
Finally I have also created a class of type PacketHandler
that is able to read bytes from a stream and create it into a packet object.
public async string GetCmdStnSoftwareVersion()
{
var msgReq = new CmdStnSoftwareVersionReqMessage();
await msgReq.WriteAsync(sPort.BaseStream);
await var response = msgReq.GetResponse(5); //5 = timeout in seconds!
return String.Format("{0}.{1}", response.Major, response.Minor);
}
What I am stuck on is a good pattern and/or example implementation for handling responses which is compatible with implementing the extension libraries. Can anyone provide input?
public class Packet : IObserver<Packet>
{
//The following properties are used for returning a response
private IDisposable unsubscriber;
public bool ResponseReceived { get; private set; }
public double Timeout { get; set; }
private Packet ResponsePacket;
//The following properties are used for building a packet
internal PacketHeaderType Header { get; private set; } //This an enum of byte with possible values of 0-15
internal List<byte> Payload { get; private set; }
protected int PayloadLength { get { return Payload.Count; } }
protected byte HeaderByte { get { return (byte)((Convert.ToByte(Header) << 4) | PayloadLength); } } //we need to add the packet length to the lower nibble of the header before sending
public Packet(PacketHeaderType header, List<byte> payload)
{
this.Header = header;
this.Payload = new List<byte>(payload);
this.ResponseReceived = false;
this.Timeout = 5;
}
public Packet(PacketHeaderType headerByte)
{
this.Header = headerByte;
this.Payload = new List<byte>();
this.ResponseReceived = false;
this.Timeout = 5;
}
internal byte XorByte
{
get
{
Byte xorByte = Convert.ToByte(HeaderByte);
for (int i = 0; i < PayloadLength; i++)
xorByte ^= Payload.ToArray()[i];
return xorByte;
}
}
public async Task WriteAsync(Stream stream, bool returnResponse = false, bool flush = true, CancellationToken token = default(CancellationToken))
{
var buffer = new List<byte>();
buffer.Add(HeaderByte);
if (Payload != null && PayloadLength > 0)
{
buffer.AddRange(Payload);
}
buffer.Add(XorByte);
await stream.WriteAsync(buffer.ToArray(), 0, buffer.Count);
if (flush)
{
await stream.FlushAsync();
}
if (returnResponse)
{
var ts = new TimeSpan();
ts = TimeSpan.FromSeconds(Timeout);
while (DateTime.Now + ts < DateTime.Now && !ResponseReceived)
{
await Task.Delay(10);
}
}
}
private bool ValidResponse(Packet p)
{
return false;
}
public virtual void Subscribe(IObservable<Packet> provider)
{
if (provider != null)
unsubscriber = provider.Subscribe(this);
}
public virtual void OnCompleted()
{
this.Unsubscribe();
}
public virtual void OnError(Exception e)
{
Console.WriteLine("{0}: Cannot get packet from router.", this.ToString());
}
public virtual void OnNext(Packet value)
{
if (ValidResponse(value))
{
ResponsePacket = value;
ResponseReceived = true;
Unsubscribe();
}
}
public virtual void Unsubscribe()
{
unsubscriber.Dispose();
}
//This probably shouldn't be here as we now use it in the packet handler
public static async Task<Packet> ReadAsync(Stream stream, CancellationToken cancellationToken = default(CancellationToken))
{
//TODO: we should read the stream until we find a valid header!
var headerBuffer = new byte[1];
int bytesRead = await stream.ReadAsync(headerBuffer, 0, 1, cancellationToken);
if (bytesRead == 0)
{
return null;
}
var headerVal = (byte)(headerBuffer[0] >> 4);
var payloadLength = (headerBuffer[0] & 0x0F);
Packet packet = new Packet((PacketHeaderType)Enum.Parse(typeof(PacketHeaderType), headerVal.ToString()));
//TODO: we should handle unknown packets some how!
//if (Enum.IsDefined(typeof(XpressNetV3PacketType), headerVal))
var bytesRemaining = payloadLength;
var offset = 0;
if (payloadLength > 0)
{
var payloadBytes = new byte[payloadLength];
do
{
bytesRead = await stream.ReadAsync(payloadBytes, offset, bytesRemaining, cancellationToken);
if (bytesRead == 0)
{
throw new XpressNetProtocolViolationException("Unexpected end of stream");
}
bytesRemaining -= bytesRead;
offset += bytesRead;
} while (bytesRemaining > 0);
}
//check the xor matches
var xorByte = stream.ReadByte();
if (xorByte != packet.XorByte)
throw new XpressNetProtocolViolationException("Packet checksum is invalid");
return packet;
}
}
I have created child classes that implement Type
packet for each of the valid commands (I don't think it is necessary to show them here...
I have created an IObservable message router in order for the packet to get a response:
public class PacketRouter : IObservable<Packet>
{
private List<IObserver<Packet>> observers = new List<IObserver<Packet>>();
public IDisposable Subscribe(IObserver<Packet> observer)
{
if (!observers.Contains(observer))
observers.Add(observer);
return new Unsubscriber(observers, observer);
}
private class Unsubscriber : IDisposable
{
private List<IObserver<Packet>> _observers;
private IObserver<Packet> _observer;
public Unsubscriber(List<IObserver<Packet>> observers, IObserver<Packet> observer)
{
this._observers = observers;
this._observer = observer;
}
public void Dispose()
{
if (_observer != null && _observers.Contains(_observer))
_observers.Remove(_observer);
}
}
public void SendPacket(Packet packet)
{
foreach (var observer in observers)
{
if (packet != null)
observer.OnError(new PacketUnknownException());
else
observer.OnNext(packet);
}
}
public void EndTransmission()
{
foreach (var observer in observers.ToArray())
if (observers.Contains(observer))
observer.OnCompleted();
observers.Clear();
}
}
public class PacketUnknownException : Exception
{
internal PacketUnknownException()
{
}
}
I have also created a class of type PacketHandler
that is able to read bytes from a stream and create it into a packet object. It also raises a broadcast event if the correct types of packets are discovered, otherwise it passes them to the messageRouter for handling by the library.
public class BroadcastMessageReceivedEventArgs : EventArgs
{
public Packet Packet { get; set; }
}
public static class PacketHandler
{
public static event EventHandler<BroadcastMessageReceivedEventArgs> BroadcastMessageReceived = delegate {};
public static void OnBroadcastMessageReceived(BroadcastMessageReceivedEventArgs e)
{
EventHandler<BroadcastMessageReceivedEventArgs> handler = BroadcastMessageReceived;
if (handler != null)
{
handler(null, e);
}
}
public static async Task<Packet> ReadPacketAsync(Stream stream, CancellationToken cancellationToken = default(CancellationToken))
{
var headerBuffer = new byte[1];
int bytesRead = await stream.ReadAsync(headerBuffer, 0, 1, cancellationToken);
if (bytesRead == 0)
{
return null;
}
var headerVal = (byte)(headerBuffer[0] >> 4);
var payloadLength = (headerBuffer[0] & 0x0F);
Packet packet = new Packet((PacketHeaderType)Enum.Parse(typeof(PacketHeaderType), headerVal.ToString()));
var bytesRemaining = payloadLength;
var offset = 0;
if (payloadLength > 0)
{
var payloadBytes = new byte[payloadLength];
do
{
bytesRead = await stream.ReadAsync(payloadBytes, offset, bytesRemaining, cancellationToken);
if (bytesRead == 0)
{
throw new XpressNetProtocolViolationException("Unexpected end of stream");
}
bytesRemaining -= bytesRead;
offset += bytesRead;
} while (bytesRemaining > 0);
}
//check the xor matches
var xorByte = stream.ReadByte();
if (xorByte != packet.XorByte)
throw new XpressNetProtocolViolationException("Packet checksum is invalid");
PacketReceived(packet);
return packet;
}
internal static void PacketReceived(Packet packet)
{
//TODO: Handle Broadcast Messages and AckResp
if ((packet.Header == PacketHeaderType.EmergencyStopAll) )
//|| (packet.Header == PacketHeaderType.CommandStationOperationResponse && packet.Payload.ElementAt(0) ))...
{
BroadcastMessageReceivedEventArgs bmr = new BroadcastMessageReceivedEventArgs();
bmr.Packet = packet;
OnBroadcastMessageReceived(bmr);
}
else
{
PacketRouter pump = new PacketRouter();
pump.SendPacket(packet);
}
}
}
public async string GetCmdStnSoftwareVersion()
{
var msgReq = new CmdStnSoftwareVersionReqMessage();
await var response msgReq.WriteAsync(sPort.BaseStream, true);
return String.Format("{0}.{1}", response.Major, response.Minor);
}
Is this a good pattern and/or example implementation for handling responses which is compatible with implementing the extension libraries. Can anyone provide input?
OK,
I have to create a C# library that can send commands to a device and process the command specific responses and broadcasts over a serial port (or other communications method). The library must also be able to handle request and response extensions held in other libraries as certain devices implement an extended command set, but it must be possible to choose whether these extended commands are utilised (I guess using reflection in the client app).
I have created a class of type Packet that is able to create the packet and add its payload, calculate its checksum and write the packet to the stream.
I have also created child classes that implement TypeType
packet for each of the valid commands.
Finally
Finally I have also created a class of type PacketHandlerPacketHandler
that is able to read bytes from a stream and create it into a packet object.
OK,
I have to create a C# library that can send commands to a device and process the command specific responses and broadcasts over a serial port (or other communications method). The library must also be able to handle request and response extensions held in other libraries as certain devices implement an extended command set, but it must be possible to choose whether these extended commands are utilised (I guess using reflection in the client app). I have created a class of type Packet that is able to create the packet and add its payload, calculate its checksum and write the packet to the stream.
I have also created child classes that implement Type packet for each of the valid commands. Finally I have also created a class of type PacketHandler that is able to read bytes from a stream and create it into a packet object.
I have to create a C# library that can send commands to a device and process the command specific responses and broadcasts over a serial port (or other communications method). The library must also be able to handle request and response extensions held in other libraries as certain devices implement an extended command set, but it must be possible to choose whether these extended commands are utilised (I guess using reflection in the client app).
I have created a class of type Packet that is able to create the packet and add its payload, calculate its checksum and write the packet to the stream.
I have also created child classes that implement Type
packet for each of the valid commands.
Finally I have also created a class of type PacketHandler
that is able to read bytes from a stream and create it into a packet object.