Purpose

Propose a simple way to communicate 2 ways between PC and Arduino. I want also to abstract from low level stuff focus on the high level. I also don't want to care about serial communication tricks and caveats, how to make sure packet has arrived, etc... so let's write this once and for all.
This works with fixed size packets.
Current version
0.4
Current version release date
25/05/2010
Current version release
  • Acknowledgement
  • Send receive problem fixed
  • C# reception is multithreaded and no collision between ack packets and notification packets
  • Works fine (^o^)v
  • Works only with the hardware serial
  • Better handling of message reception without Exception raised (C#)
Current version bin/src
ARDUINO Source
C# .Net Source
TODO and future
Currently since communication is done in "text", the character \0 is forbidden. This is a shameful limitation that involves tricky and time wasting workarounds. Let's remove this. Also it's related to the fact I use bytes here and there, int is better (funny byte bug in arduino for() )

General idea

A Package

Communication is done by sending packages on the serial port. You can ask for a receipt acknowledgement, the library will take care of retrying a few times if missed. You just make the packet and post it. You can focus on what your software/piece of electronic is supposed to do and not waste time again and again with serial communication stuffs.
Each packet is sent with a header "$*" and the it goes until end of message/fixed length.

Package is defined as follow:
//Content member max length
#define CONTENT_LENGTH 56
//length WITHOUT the header 2 chars
#define FULL_PACKET_LENGTH CONTENT_LENGTH + 4
 
//Each packet is sent with that signature $*ITEContent....
//A packet is 64 in length, internal serial buffer is 128 according documentation, which is a maximum if you dont
//want to loose too much packet I assume.
typedef struct {
  char ID; //default undefined
  char Type;
  char SubType;
  char ExpectAcknowledge;
  char Content[CONTENT_LENGTH];
} ARCPOPacket;

IMPORTANT NOTA BENE : none of this field should worth 0 ! Serial communication interprets it as a "hey, it's finished, nothing more to read". Don't know why, maybe it's me, but to avoid this, make sure to put something else that 0 everywhere.

Field description:
  • ID : a unique ID, used for you or for the Acknowledgement. Making it unique (mod 256) doesnt hurt
  • Type : free
  • SubType : free
  • ExpectAcknowledge : shall the library make sure it was sent and received or do you feel lucky?
  • Content : free, put some text, values whatever. Don't put 0, it's the end of communication.
    • Nota Bene : The Content does not have to be CONTENT_LENGTH chars. It can be less, it's ok.

Arduino side

Easy classes and library to include, that can read/write a packet and send to the pc without much trouble.
#include "ARCPO_Lib.h"
 
void ProcessPacket (ARCPOPacket& pPacket) {
  switch (pPacket.Type){
    case PACKET_TYPE_TEXT:
      ProcessPacketText (pPacket);
      break;
    case PACKET_TYPE_TIME:
      ProcessPacketTime (pPacket);
      break;
    default:
      //nothing
      break;
  }
}
 
//Make a packet and send. Set every member to something != 0 !!
void SampleSendPacket(){
  ARCPOPacket vP;
  vP.ID = 1;
  vP.Type = 98;
  vP.SubType = 128;
  strcpy(vP.Content, "hello monde");
 
  writePacket (vP);
}
 
void setup() {
  Serial.begin(9600);
}
 
void loop() {
  ARCPOPacket vPacket;
 
  vPacket = readPacket();
 
  if (readPacketSuccess()){
    ProcessPacket (vPacket);
  }
 
  delay(50);
}


PC side

C# multithreaded message reception plus integrated acknowledgement of sent messages.
Just instanciate a ARCPO_Connector for sending. If you want to received messages also, attache the PacketReceived event and then (in that order please) set PollMessages to true.
private ARCPO_Connector mConnector = null;
 
private void Form1_Load(object sender, EventArgs e)
{
    mConnector = new ARCPO_Connector(9600, "COM8");
 
    this.mConnector.PacketReceived += new EventHandler<ARCPO_ReceivedEventArgs>(Connector_PacketReceived);
    this.mConnector.PollMessages = true;
}
 
private void Connector_PacketReceived(object sender, ARCPO_ReceivedEventArgs e) {
    textBox1.Text += ">>RECEIVED unexpected message " + e.Packet.mID + " : ";
    textBox1.Text += e.Packet.ContentString;
    textBox1.Text += "\r\n";
}
 
private void SendPacket(string pContent, byte pType, byte pSubType)
{
    ARCPO_Packet vP = new ARCPO_Packet();
    int vPacketId = mPacketCounter;
    vP.mType = pType;
    vP.mID = (byte)(mPacketCounter++ % 256);
    vP.mSubType = pSubType;
    vP.mExpectAcknowledge = ckbAck.Checked; ;
    vP.ContentString = pContent;
 
    mConnector.SendPacket(vP);
}