Error message

  • Warning: count(): Parameter must be an array or an object that implements Countable in theme_table() (line 1998 of /data/sigrok.org/apache/blog/includes/theme.inc).
  • Warning: count(): Parameter must be an array or an object that implements Countable in theme_table() (line 2061 of /data/sigrok.org/apache/blog/includes/theme.inc).
  • Deprecated function: implode(): Passing glue string after array is deprecated. Swap the parameters in drupal_get_feeds() (line 394 of /data/sigrok.org/apache/blog/includes/common.inc).

A matter of parsing

Supporting a new piece of hardware in sigrok entails writing a driver for libsigrok. As a bare minimum, the driver consists of a C source file with a struct sr_dev_driver in it. That struct contains the name of the driver and a set of callbacks libsigrok will do when that driver is used — things like initializing the device, starting acquisition and so on. libsigrok provides an internal API which drivers can use to send data across the "session bus" — something which the frontend application listens on.

However, writing code is the last thing you do. When you get started, first make a page on the wiki for that device. Check out the page for a similar device, and copy its source over. This will get the page structure and categories down. Take some pictures of the device, particularly of the insides. It may well help you with the driver later on. Some guidelines for taking good PCB pictures are here.

Next, take a look at the protocol. Generally this involves running a copy of Windows in a VM (Virtualbox or VMware will do nicely) on a Linux host. When you use the device through the vendor-provided Windows software, you can sniff the USB (or whatever) traffic on the Linux host. There are many techniques to reverse engineering protocols, but essentially it involves staring at hexdumps until you understand the connection between what the vendor software sends to the device, and what the device does in response.

Whatever you find out about the protocol, document it! You want to be able to pick up where you left off, even if there's a couple of weeks between working on this. By all means, use the wiki page you created as a working document — it's not just a place to put finished protocol docs. If you get stuck, somebody else might see something in your notes that you missed.

For some devices you might even skip the VM + Windows step. Some low-end multimeters and other measurement devices don't really communicate with the vendor software: they just send data out periodically — usually a few times per second — and don't even have an input channel on which to take commands. These are generally devices with a keypad or similar controls, and a display. By simply listening to what it puts out, verifying this against what you see on the display, and putting the device through its various modes and options with the controls, you have everything you need to grok the protocol.

Once you're satisfied you've got the whole protocol documented, it's time for the driver. Creating the driver's various source files and integrating it into the build is quite a bit of work, and requires a lot of fiddling around with autotools. So to make things easier, we have a tool to do all this for you. It's called, unsurprisingly, "new-driver", and can be found in the sigrok-util repository.

Clone the repository, and run it from the source directory:

$ git clone git://sigrok.org/sigrok-util
$ cd sigrok-util/source

Let's say your device is called the "Magic Widget S15". Invoke new-driver like this:

$ ./new-driver Magic Widget S15

This will show some output as it works, and leave behind a single file when it's done: 0001-magic-widget-s15-Initial-driver-skeleton.patch

Apply this to your libsigrok tree:

$ cd /path/to/libsigrok
$ git am /path/to/0001-magic-widget-s15-Initial-driver-skeleton.patch

That's it! The configure script will now know about your new driver, and doing the usual configure/make steps will build it. You'll find it in your source tree in the hardware directory:

$ ls -l hardware/magic-widget-s15
total 16
-rw-rw-r-- 1 bert bert 3692 Nov 13 02:49 api.c
-rw-rw-r-- 1 bert bert 1035 Nov 13 02:49 Makefile.am
-rw-rw-r-- 1 bert bert 1157 Nov 13 02:49 protocol.c
-rw-rw-r-- 1 bert bert 1919 Nov 13 02:49 protocol.h

The file api.c contains the struct sr_dev_driver which registers it with libsigrok. An overview of the struct and the callbacks it contains is on the hardware driver API page. All the callbacks have a stub function in api.c, with a TODO comment marking the spot where you come in. Take a look at another driver for a similar device to see how various callbacks might be implemented. The protocol.h file is included from both C files, and contains mostly the device context struct. This is specific to your driver, not shared across libsigrok. The protocol.c file is where you implement the protocol parser for your device. It has a single stub function defined:

SR_PRIV int magic_widget_s15_receive_data(int fd, int revents, void *cb_data)

This function gets called whenever your device sent some data. The stub grabs your device context, which will have a device handle you can use to read the data and send libsigrok the results.

Everything else is just a matter of parsing.