ClientAPI - .Net
SerialProtocol.cs
Go to the documentation of this file.
00001 using System;
00002 using System.IO;
00003 using System.Threading;
00004 
00005 namespace ebl_arduino
00006 {
00010     public abstract class SerialProtocol
00011     {
00015         public enum MessageTypes
00016         {
00020             DEBUG = 0x01,
00021 
00025             MESSAGE = 0x02,
00026 
00030             MESSAGE_ACKNOWLEDGE = 0x03,
00031 
00035             DISCOVERY_REQUEST = 0x04,
00036 
00040             DISCOVERY_RESPONSE = 0x05
00041         }
00042 
00046         public class AdvancedSerialMessage
00047         {
00051             public MessageTypes Type = MessageTypes.MESSAGE;
00052 
00056             public byte ID;
00057 
00061             public byte Size = 0;
00062 
00066             public byte[] Payload;
00067         }
00068 
00072         public enum ConnectionState
00073         {
00077             ReadingSTX,
00078 
00082             ReadingETX,
00083 
00087             ReadingHeader,
00088 
00092             ReadingPayload
00093         }
00094 
00098         public const int MESSAGE_HEADER_SIZE = 3;
00099 
00103         public const int MESSAGE_DELIMITER_SIZE = 1;
00104 
00108         public const int MESSAGE_MAX_PAYLOAD_SIZE = 32;
00109 
00113         public const int MESSAGE_SIZE = MESSAGE_MAX_PAYLOAD_SIZE + MESSAGE_HEADER_SIZE;
00114 
00118         public const byte STX = 0x02;
00119 
00123         public const byte ETX = 0x03;
00124 
00128         public delegate void MessageReceivedCallback(AdvancedSerialMessage Message);
00129 
00133         public event MessageReceivedCallback MessageReceived;
00134 
00138         protected Stream ConnectionStream;
00139 
00144         public abstract bool IsConnected();
00145 
00149         public abstract void Close();
00150 
00154         public int MessageTimeout = 2000;
00155 
00156         private AdvancedSerialMessage InputMessage = new AdvancedSerialMessage();
00157         private byte[] InputBuffer = new byte[MESSAGE_SIZE];
00158         private byte[] InputDelimiter = new byte[1];
00159         private ConnectionState State = ConnectionState.ReadingSTX;
00160         private int ReceivedBytes;
00161         private int RequestedBytes;
00162 
00167         public void Send(AdvancedSerialMessage Message)
00168         {
00169             this.Send(Message.Type, Message.ID, Message.Size, Message.Payload);
00170         }
00171 
00179         public void Send(MessageTypes Type, byte ID, byte Size, byte[] Payload)
00180         {
00181             if (Size >= 0 && Size <= MESSAGE_MAX_PAYLOAD_SIZE)
00182             {
00183                 this.ConnectionStream.WriteByte(STX);
00184                 this.ConnectionStream.WriteByte((byte)Type);
00185                 this.ConnectionStream.WriteByte(ID);
00186                 this.ConnectionStream.WriteByte(Size);
00187                 if (Size > 0) this.ConnectionStream.Write(Payload, 0, Size);
00188                 this.ConnectionStream.WriteByte(ETX);
00189 
00190                 //wait for confirmations
00191                 if (Type == MessageTypes.MESSAGE ||
00192                     Type == MessageTypes.DISCOVERY_REQUEST)
00193                 {
00194                     lock (this.ConnectionStream)
00195                     {
00196                         if (!Monitor.Wait(this.ConnectionStream, this.MessageTimeout))
00197                             throw new TimeoutException("Device not responding.");
00198                     }
00199                 }
00200             }
00201             else
00202             {
00203                 throw new TimeoutException("Accepted message's payload size between 0 and " + MESSAGE_MAX_PAYLOAD_SIZE + ".");
00204             }
00205         }
00206 
00211         public void Send(MessageTypes Type)
00212         {
00213             this.Send(Type, 0, 0, null);
00214         }
00215 
00219         public void Flush()
00220         {
00221             byte[] flushdata = new byte[MESSAGE_DELIMITER_SIZE+MESSAGE_SIZE+MESSAGE_DELIMITER_SIZE];
00222             for (int i = 0; i < flushdata.Length; i++)
00223             {
00224                 flushdata[i] = (byte)0x00;
00225             }
00226             this.ConnectionStream.Write(flushdata, 0, flushdata.Length);
00227             this.ConnectionStream.Flush();
00228         }
00229 
00233         protected void Receive()
00234         {
00235             this.ReceivedBytes = 0;
00236 
00237             if (this.DataReceivingCallback == null)
00238                 this.DataReceivingCallback = new AsyncCallback(DataReceiving);
00239 
00240             try
00241             {
00242                 switch (this.State)
00243                 {
00244                     case ConnectionState.ReadingSTX:
00245                     case ConnectionState.ReadingETX:
00246                         this.ConnectionStream.BeginRead(this.InputDelimiter, 0, MESSAGE_DELIMITER_SIZE, this.DataReceivingCallback, null);
00247                         this.RequestedBytes = MESSAGE_DELIMITER_SIZE;
00248                         break;
00249 
00250                     case ConnectionState.ReadingHeader:
00251                         this.ConnectionStream.BeginRead(this.InputBuffer, 0, MESSAGE_HEADER_SIZE, this.DataReceivingCallback, null);
00252                         this.RequestedBytes = MESSAGE_HEADER_SIZE;
00253                         break;
00254 
00255                     case ConnectionState.ReadingPayload:
00256                         this.ConnectionStream.BeginRead(this.InputBuffer, 0, this.InputMessage.Size, this.DataReceivingCallback, null);
00257                         this.RequestedBytes = this.InputMessage.Size;
00258                         break;
00259                 }
00260             }
00261             catch (Exception)
00262             {
00263                 this.Close();
00264             }
00265         }
00266 
00267         private AsyncCallback DataReceivingCallback;
00268         private void DataReceiving(IAsyncResult ar)
00269         {
00270             int ReceivedSize = 0;
00271             try
00272             {
00273                 ReceivedSize = this.ConnectionStream.EndRead(ar);
00274             }
00275             catch (Exception)
00276             {
00277                 this.Close();
00278                 return;
00279             }
00280 
00281             //verify if buffer was completelly received
00282             this.ReceivedBytes += ReceivedSize;
00283             if (this.ReceivedBytes < this.RequestedBytes)
00284             {
00285                 try
00286                 {
00287                     this.ConnectionStream.BeginRead(this.InputBuffer, ReceivedBytes, RequestedBytes - ReceivedBytes, this.DataReceivingCallback, null);
00288                 }
00289                 catch (Exception)
00290                 {
00291                     this.Close();
00292                 }
00293                 return;
00294             }
00295 
00296             switch (this.State)
00297             {
00298                 case ConnectionState.ReadingSTX:
00299                     if (this.InputDelimiter[0] == STX)
00300                     {
00301                         this.State = ConnectionState.ReadingHeader;
00302                     }
00303                     break;
00304 
00305                 case ConnectionState.ReadingHeader:
00306                     this.InputMessage.Type = (MessageTypes)this.InputBuffer[0];
00307                     this.InputMessage.Size = this.InputBuffer[1];
00308                     if (this.InputMessage.Size == 0)
00309                     {
00310                         //payload is empty
00311                         this.State = ConnectionState.ReadingETX;
00312                     }
00313                     else if (this.InputMessage.Size > 0 && this.InputMessage.Size <= MESSAGE_MAX_PAYLOAD_SIZE)
00314                     {
00315                         //read
00316                         this.State = ConnectionState.ReadingPayload;
00317                     }
00318                     else
00319                     {
00320                         //avoid wrong sized messages
00321                         this.State = ConnectionState.ReadingSTX;
00322                     }
00323                     break;
00324 
00325                 case ConnectionState.ReadingPayload:
00326                     Array.Copy(this.InputBuffer, this.InputMessage.Payload, this.InputMessage.Size);
00327                     this.State = ConnectionState.ReadingETX;
00328                     break;
00329 
00330                 case ConnectionState.ReadingETX:
00331                     if (this.InputDelimiter[0] == ETX)
00332                     {
00333                         if (this.InputMessage.Type == MessageTypes.DISCOVERY_RESPONSE ||
00334                             this.InputMessage.Type == MessageTypes.MESSAGE_ACKNOWLEDGE)
00335                         {
00336                             lock (this.ConnectionStream)
00337                             {
00338                                 Monitor.Pulse(this.ConnectionStream);
00339                             }
00340                         }
00341                         else if (this.InputMessage.Type == MessageTypes.MESSAGE)
00342                         {
00343                             this.Send(MessageTypes.MESSAGE_ACKNOWLEDGE);
00344                             this.MessageReceived(this.InputMessage);
00345                         }
00346                         else if (this.InputMessage.Type == MessageTypes.DISCOVERY_REQUEST)
00347                         {
00348                             this.Send(MessageTypes.DISCOVERY_RESPONSE);
00349                         }
00350                     }
00351 
00352                     this.State = ConnectionState.ReadingSTX;
00353                     break;
00354             }
00355 
00356             this.Receive();
00357         }
00358     }
00359 }
 All Classes Namespaces Files Functions Variables Enumerations Events