using System; namespace PixelHub { /// /// The type of message that you are sending. /// public enum MessageTypes { // No command. This is not a valid message type. None = -1, // Hard-resets the PixelBot. Useful if something has gone wrong, or to reset it's internal state. Reset = 0, // May be sent by either party. Indicates that one or the other doesn't like a message that was sent by the other party. Error = 1, // Sent by a PixelBot upon connection. HandshakeRequest = 5, // Sent by the server in response to a `HandshakeRequest`. HandshakeResponse = 6, // Instructs a PixelBot to perform a movement. Move = 11, // Sent by a pixelbot to indicate that the command sent by the server is ok, and that it will proceed to execute it. CommandOk = 12, // Sent by a pixelbot to indicate that it has completed executing the command sent previously. CommandComplete = 13, // Sent by a pixelbot to indicate that it has failed to complete the execution of a command it received previously. CommandFailed = 14, // Sent by the server to request information from a PixelBot. This could be from sensors, configuration, statistics, etc. InfoRequest = 20, // Sent by a PixelBot in response to an `InfoRequest` message. InfoResponse = 21 } /// /// Specifies a single command that is to be sent to a PixelBot. /// public abstract class PixelMessage { /// /// A random number generator. Useful for generating default message ids. /// private static Random rand = new Random(); /// /// The size of the pixel message header, in bytes. /// public static readonly int HeaderSize = 12; /// /// The protocol version that this message is written in. /// public readonly ushort ProtocolVersion = 1; /// /// The type of this message. /// /// The type of the message. public MessageTypes MessageType { get; private set; } = MessageTypes.None; /// /// The id of this message, or the message that this message is in direct response to. /// public uint MessageId; /// /// The length of the containing message. /// public uint MessageLength = 0; /// /// The header of the message. /// public byte[] Header { get { byte[] result = new byte[HeaderSize]; // Fetch all the components needed to build the message header and convert them to byte arrays byte[] rawProtocolVersion = BitConverter.GetBytes(ProtocolVersion); byte[] rawMessageType = BitConverter.GetBytes((ushort)MessageType); byte[] rawMessageId = BitConverter.GetBytes((ushort)MessageId); byte[] rawMessageLength = BitConverter.GetBytes(Payload.Length); // Copy the pieces into the correct places Buffer.BlockCopy(rawProtocolVersion, 0, result, 0, rawProtocolVersion.Length); Buffer.BlockCopy(rawMessageType, 0, result, 2, rawProtocolVersion.Length); Buffer.BlockCopy(rawMessageId, 0, result, 4, rawProtocolVersion.Length); Buffer.BlockCopy(rawMessageLength, 0, result, 8, rawProtocolVersion.Length); return result; } } /// /// The payload of the message. /// public abstract byte[] Payload { get; protected set; } public PixelMessage() { byte[] rawMessageId = new byte[sizeof(uint)]; rand.NextBytes(rawMessageId); MessageId = BitConverter.ToUInt32(rawMessageId, 0); } /// /// Returns this message in it's raw format that's sent and received over the wire. /// /// This message, as a byte array. public byte[] AsCompiledCommand() { byte[] message = new byte[HeaderSize + Payload.Length]; Buffer.BlockCopy(Header, 0, message, 0, HeaderSize); Buffer.BlockCopy(Payload, 0, message, HeaderSize, Payload.Length); return message; } } }