Serial communication between Arduino and PHP with a protocol

In my previous post I discussed basics of serial communication between Arduino and PHP. Theory behind it is very simple. It all comes down to writing to a file. Simplicity of the serial communication paradoxically might contribute to confusion and surprising results. Serial device is like a black hole when you think about it. You send data inside but there is no feedback. You don’t know has your message arrived or not. You don’t know is your transmission going to be divided into multiple chunks or will arrive at one peace. There is no guarantee no feedback. On top of that there are some differences between operating systems and Arduino peculiarities. All of that combined together can confuse for a few hours or even discourage from the project.

To solve most of the above problems you need a protocol. A formalised way to talk between peers. The simples idea would be to divide a packet into a header and the actual message. The header will always have the same size – two bytes and will carry an unsigned integer (2 bytes or 16 bits is Arduino’s integer size). The integer will contain length of a packet’s body.

packet
packet

This way both sides will always know how many bytes to read, when one transmission ends and when another one starts. There is one major drawback you have to be aware of. Incorrect header value (due to a bug somewhere) might break synchronisation and software will freeze. If such a risk is unaceptable you need an additional code to detect header corruption (perhaps checksums?) and resync.

When packet is transferred a receiver has to give a feedback to the sender. The feedback should indicate that data has been received. It should also allow to verify data consistence. This can be achieved by sending back an “ok” string follow by an integer with number of received bytes.

I created a generic library for Arduino called serialHelper. It encapsulates the above idea into a small and easy API. To install the library clone repository (or download archive) from GitHub and copy “SerialHelper” directory into your arduino-ide/libraries. If the IDE is on you will have to restart it.

If the library is correctly installed you should see SerialHelper in “File > Examples” navigation. Open Invert example (“File > Examples > SerialHelper > Invert”) and upload the sketch to your Arduino.

#include 

SerialHelper serialHelper(128, 0);

void setup() {
  Serial.begin(9600);
}

void invert(char *buff, int len) {
  int i, tmp;

  for( i = 0 ; i  0 ) {
    serialHelper.read();
    buff = serialHelper.getMessage();
    len = serialHelper.getMessageLength();

    invert(buff, len);
    serialHelper.write(buff, len);

  }
}

The sketch listens for a message, inverts it and returns it back. The only line which is worth a few words of explanation is the constructor.

SerialHelper serialHelper(128, 0);

That will create an instance of SerialHelper and will allocate 128 bytes for a buffer. What it really means is it doesn’t make any sense to send longer messages than 128 bytes. Actually the message can’t be longer that 125 bytes. Two first bytes are reserved for the header and the last byte is 0x00 to terminate a string. Excessive bytes will be omitted.

Once Arduino is ready for some “serial conversation” run terminal.php (which is attached to the library on GitHub). You might need to edit it first to define appropriate SERIAL_DEVICE. If you not sure what device path should you use run

$ sudo dmesg

straight after re-connecting Arduino’s USB. It should give you and idea what name your operating system chosen for the device.

<?php

define('SERIAL_DEVICE', '/dev/ttyACM0');

/**
 * Mac users will have to use something similar to this:
 * define('SERIAL_DEVICE', '/dev/cu.usbmodem1431');
 *
 */

function readMessage($fp) {
 $header = fread($fp, 2);
 $len = ord($header[0]) + (ord($header[1])<>8 ) & 0xFF );
 $msg .= $str;
 fwrite($fp, $msg, $len + 2 );
 $ret = readMessage($fp);

 if( substr($ret,0,2) != 'ok' ) {
  return false;
 }

 $_len = ord($ret[2]) + (ord($ret[3]) < ');
 if( $msg == 'exit' ) {
  break;
 }

 echo "* sending… ";

 if( sendMessage($fp, $msg) ) {
  echo "OKnn";
 }
 else {
  echo "FAILED!!!nn";
 }

 echo readMessage($fp) . "n";
}

fclose($fp);

The terminal waits for a user input and sends data thought the selected device. It uses the same protocol as serialHelper library.

If you are not using 10uF capacitor (from RST to GRD) remember that Arduino will restart on every fopen. If you send data immediately after terminal.php opens nothing will happen. Give it few seconds (5 should be enough) to let it boot. Now you are ready to have an exciting conversation with your Arduino!

I tested the library (on Ubuntu and on Mac) and it seams to be stable. If you want to try it with one of your projects I would love to hear how it went.

2 thoughts on “Serial communication between Arduino and PHP with a protocol

  1. Hi, great article. Can you explain this:

    > If you are not using 10uF capacitor (from RST to GRD) remember
    > that Arduino will restart on every fopen

    Why would the Arduino restart without the capacitor?

    Like

    1. Hi Fieg,

      By default every new serial connection restarts Arduino. This is how they put the board together by design.

      Inserting the mentioned capacitor between GND and RST makes the device “ignore” reset action (the button won’t also work). Why that exactly happens I can only guess but this is an official recommendation on the Arduino’s website.

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s