House automation tooling - Part 2 - Getting Serial
21 March 2022
The war in Ukraine is ongoing.
Last post I prepared Clozure CL on an iBook with MacOS X 10.4 (Tiger) including getting quicklisp ready. quicklisp is not absolutely necessary, but it helps. Otherwise all libraries that you want to use you have to download and load manually in the REPL.
In this post I'd want to check feasability and prepare the serial communication.
This iBook as well as more modern computers don't have a Sub-D serial port adapter anymore. However, the device (the boiler) this software should communicate with has a 9 pin Sub-D connector. So we need a USB to serial adapter. There are a number of them available. But we also need drivers for this version of Mac OS. This one, a Keyspan (USA19HS) works with this version of Mac OSX and drivers are available.
OK, in order to 'simulate' the boiler we use an Amiga 1200, which still has a serial port and a nice software called 'Term' which allows to act as a serial peer for development. The application 'Term' has an Amiga Rexx (ARexx) scripting interface which allows to script behavior in Term. In the end this could be handy to create a half-automated test environment for system tests.
(Since the Amiga has a 25 pin Sub-D interface but the Keyspan adapter has a 9 pin interface I had to build a 25<->9 pin converter. Of course I could have bought it but I like doing some soldering work from time to time.)
The Common Lisp serial interface library
There are two CL libraries based on FFI (Foreign Function Interface) that would work. I've experimented with both.
In my opinion cl-libserialport offers a few more features and I'd settle on it. I.e. it allows to specify a termination character for the read operation where when received the read will automatically return.
cl-libserialport is not on quicklisp, so in order to still load it in the REPL via quicklisp we have to clone it to
With all the additional work for cl-libserialport (which is actually not that much and a one-time effort) I hope it pays off by being easier to work with.
Prototyping some code
The boiler serial protocol will require to send commands to the boiler, and receive sensor data. One of the commands is a 'start-record' command which instructs the boiler to start sending data repeatedly every x seconds until it received a 'stop-record' command. Since it is not possible to send and receive on the serial device at the same time we have to somehow serialize the send and receive of data. One way to do this is to use a queue. We enqueue send and read commands and when dequeued the command is executed. Now, this cries for an actor. Fortunately there is a good actor library for Common Lisp called cl-gserver which we can utilize for this and hack together some prove of concept. (Though if I read correctly then libserialport internally uses semaphores to manage concurrent access to the device resource. Nontheless I'd like to use an actor.)
For this we have to implement to initialize the serial interface, set the right baud value and such. Then we want to write/send and read/receive data.
The initialization, opening the serial device can look like this:
The opened serial device will be stored in
Now write and read will look like this:
The read function utilizes the termination character because I know already that the boiler data uses start and end characters
Now let's see how the actor can look like in a simple way that can work for this example:
The last part creates the actor-system and a
To initialize the serial device we do:
To write to the serial device we do:
Having done that we see in the 'Term' application the string "Hello World". So this works.
The read has a speciality: sending
When I type something in the 'Term' program the REPL will print the read data:
So this seems to work. I need to think about the next step now. Since I'd like to develop outside-in with a double test loop the next thing to do is figure out a use-case and create a test for it that basically sets the bounds of what should be developed in smaller increments.