A Minimal Arduino Library for Processing Serial Commands

Here’s some nice music to listen to while you read this long and boring article:

Note: there have been updates to this library to include support for SoftwareSerial since this post was originally published.  The github version is the most current.

For lots of software projects, I end up writing stupid little utility libraries so I don’t have to keep re-writing crap over and over. Hence my earlier SerLCD and ADT7310 libraries I’ve published here. Here’s another dinky little thing I wrote because I was unsatisfied with the alternatives. Frequently I write code that has to interact with a host computer. The Arduino boards have a very nice, very easy to use USB-to-Serial connection on them, so you just have to write your host program to send serial bytes and you can communicate with the arduino board. Frequently what I end up needing is the arduino to respond to some commands sent from the host computer. Things like “turn off that relay” or “process this” or “move this motor to this position and stop” or “holy shit the building is burning down everybody run”. If you RTFM, the arduino libraries tell you to use the “Messenger” library for doing serial command processing (which I did, a long time ago). Unfortunately, as you then follow the trail, you are suggested in the modern age to instead of Messenger to use CmdMessenger. Stupid documentation in a Wiki. There are also things like Firmata and Bitlash, but they’re really more extensive than just having your arduino program talk to your host program. There’s nothing really wrong with CmdMessenger. It works fine. I just don’t like it. I don’t like that it depends on two other libraries (Arduino Streaming Library and Arduino Base64 Library ). I also don’t exactly see why you need base64 except to run the demo code. I also don’t like the messenging format. The commands back and forth end up just being enum’s of the commands you’ve added handlers for, so the commands all look… strange. From the example in the CmdMessenger library:

// Try typing these command messages in the serial monitor!
//
// 4,hi,heh,ho!;
// 5;
// 5,dGhlIGJlYXJzIGFyZSBhbGxyaWdodA==;
// 5,dGhvc2UgbmFzdHkgY29udHJvbCA7OyBjaGFyYWN0ZXJzICws==;
// 2;
// 6;

(The actual commands shouldn’t make any sense unless you’ve looked at what the demo code does, I just repeat it here to show the formats). All the commands become “number,something,something, …” and the number depends on what order you’ve added the handlers, so you have to do your own bookkeeping to know which number belongs to the enum of the command handlers. There’s nothing wrong with this. If you’re writing code on a host computer, the host just wants consistent format. Frequently when I’m testing I sit with the serial monitor window open and fire down commands myself. There are also times when debugging that it’s nice to just look at the commands and understand what the hell is going on. So I finally got fed up and wrote my own SerialCommand library. I based a lot of the conceptual idea off how Dreamcat4 organizes CmdMessenger. You initialize a SerialCommand object by pushing pointers to functions and associating them with a received string. The string is case-sensitive. e.g. –

// Setup callbacks for SerialCommand commands
SCmd.addCommand("ON",LED_on);       // Turns LED on
SCmd.addCommand("OFF",LED_off);        // Turns LED off
SCmd.addCommand("HELLO",SayHello);     // Echos the string argument back
SCmd.addCommand("P";,process_command);  // Converts two arguments to integers and echos them back
SCmd.addDefaultHandler(unrecognized);  // Handler for command that isn't matched  (says "What?")

The second parameter is just the function to call when that command is received:

void LED_on()
{
  Serial.println("LED on");
  digitalWrite(arduinoLED,HIGH);
}

A SerialCommand object maintains a char[] buffer, that fills with characters from the Serial() stream. When the terminator character is received (in my case, the carriage return, or ‘\r’), it then scans the buffer looking for the first word in the buffer to be the command (delimiter defaults to the space character, but you can configure that in the library). The buffer is of fixed size (configurable), and just wraps around if you overwrite the end, so it doesn’t crash but might give unintended results if you try to receive a command larger than the buffer. There is a .clearBuffer() routine, which you can use to zero out the buffer to be sure. The buffer also zeros out when a command gets recognized and processed. In the handler, you can call the .next() function to parse out the next token. It comes out as a pointer to a char string, so you can use atoi() or whatever to convert to a numeric format or do further parsing. You can keep calling next() until it returns NULL, meaning no more arguments.

void SayHello()
{
  char *arg;
  arg = SCmd.next();    // Get the next argument from the SerialCommand object buffer
  if (arg != NULL)      // As long as it existed, take it
  {
    Serial.print("Hello ");
    Serial.println(arg);
  }
  else {
    Serial.println("Hello, whoever you are");
  }
}

Essentially the whole library is just an interface to a string buffer and the strtok_r() command. It doesn’t do a lot, but it does what I want. Maybe you’d like it, but I doubt it. You can download the library here or from my repository on github. My github version is the most current one. It includes a stupid demo program. You won’t like it, it won’t do what you want, you won’t like my coding style, and if you do end up using it you’ll tell your boss you wrote it yourself and strip out my attribution and LGPL license, but hey. It works for me, that’s why I wrote it. You’ll probably like CmdMessenger a lot better. As well, it was pointed out to me by Stephen Lake that Stefan Rado (github user kroimon) has made a modified version available on github, which you might find more appealing. As usual, unzip it and drop the folder into your libraries folder (e.g. My Documents\Arduino\libraries, on Windows). In the tradition of useless sample output, here’s some useless sample output: and because apparently you’re not allowed to post about arduino on the intarweb without including a picture of an arduino, here’s arduino Mega running the SerialCommand demo program. Not like you can actually tell, but hey.