Computing stuff tied to the physical world

Serial port encapsulation

In Software on Feb 19, 2010 at 00:01

This post continues to look a bit into the new JeeMon design.

Let’s focus on serial interfaces first, mostly USB. There’s a “Serial” module which does all the basics. On the Mac, if I want to open device /dev/tty.usbserial-A900ad5l, then the following call with do everything:

Serial connect usb-A900ad5l 57600
The name of the device would be different on Windows and Linux (COM5, or USB1), but that’s all.

By default, this creates a new Serial object, which logs all incoming text to stdout. To send a command out, we need to keep a handle to this object:

set conn [Serial connect usb-A900ad5l 57600]
$conn send "some text"
Nice, but not very exciting…

Let’s take it one step further. The “JeeSketch” module does the automation described in the previous post, i.e. detect the running sketch, associate it with a class, instantiate an object for it, and call the methods of that object whenever text lines come in over that serial port. Here’s a complete JeeMon custom “application.tcl” program:

Screen shot 2010-02-18 at 14.44.59.png

First, all the sketch drivers are made available with one or more “register” calls. This lets the appropriate classes take over for each new serial connection – depending on what sketch is running. That’s all it takes. Servicing such serial ports now becomes an event-driven background activity.

The listeners are defined in separate files, one for each type of sketch:

Screen shot 2010-02-18 at 15.05.58.png

The ookRelay/host.tcl file looks like this, for example:

Screen shot 2010-02-18 at 14.51.58.png

This structure makes it easy to manage stuff that belongs together. Projects can be exchanged (or archived, or revision-controlled), with all the pieces needed to use them in one place. And as far as I’m concerned, it won’t be limited to JeeNodes etc, or Tcl, or a specific platform. This has to remain general enough to hook up to any hardware and use with any language (via networking, files, and direct launching of executables/scripts). My goal for JeeMon is not to limit anyone’s options, but to create a simple switchboard between whatever is needed.

(I’m still mucking around with the organization and naming of code and files, as you can see)

Nice, but still not very practical…

The problem with the above is that it doesn’t deal with devices getting plugged in or unplugged. Well, unplugging is the easy bit – the above code will automatically clean up after itself on connection loss, so that part is covered.

Wouldn’t it be nice if we could just plug in new devices and get them to automatically start doing something?

I implemented such a mechanism in a recent revision of the code, but I’m hesitant to add it again – because it was Mac OS X specific, where USB devices connected via the FTDI driver include a unique code. On Windows and Linux, you just get COM<n> and USB<n> devices, where “n” seems to be related to the order and number of device insertions.

I haven’t looked into “libusb” yet. Should I? Will it help for Windows too? Do I need to start learning about USB enumeration? What OSS-compatible tools and libs are there?

Update – on Linux, it looks like /sys/bus/usb/devices/* has all the info needed to identify USB devices. So that only leaves Windows – good: at most one lib or dll to deal with.

  1. For windows see http://www.naughter.com/enumser.html FTDI has registry setting with the USB id’s and the assigned comport…

    I’m still looking for (native c/c++) code that handles timeouts gracefully. Someting like serial->socket where you have select/timeout support, not blocking the client when a newline is missing etc…

    • Thx for the pointer. What I see and can understand in that code is that it has a handful of different ways of trying to iterate and identify COM ports. While I understand the need, I’m not sure it is needed with Tcl, which has async I/O and can do that already (I think). The file opening itself is not so much an issue, it’s more about identifying which COM port is what.

      What I want is to react to USB device insertions, etc.

      Here’s one article about that: http://www.codemiles.com/download/file.php?id=719

  2. For Linux (Ubuntu), I have edited /etc/udev/rules.d/10-usbadapter.rules to give each device a unique name (symlink actually) depending on its FTDI serial number:

    e.g.: BUS==”usb”,SYSFS{serial}==”A9007CBS”,KERNEL==”ttyUSB*”,SYMLINK+=”JeeLink”

    -> My JeeLink is now always /dev/JeeLink

  3. USB insertions etc is nice, but complex…

    TinyOS motelist has some examples scanning the registry for USB/FTDIBUS (sub scan_registry). FTDI is in [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\FTDIBUS\VID_0403+PID_6001+yourserial]

    With http://www.patthoyts.tk/tclftd2xx.html you can use D2XX and FTDI’s suggested way of finding the comports…

    • Heh, see http://code.jeelabs.org/viewvc/svn/jeelabs/trunk/jeemon/kit/rigs/SysDep.tcl for what I’m trying out right now. It seems to work on Win2k, returning both the list of COM ports and the FTDI type and serial numbers of the attached devices.

      Indeed, tclftd2xx would be an option, but it’s FTDI-specific, and I’m hoping the registry is standardized enough across Windows platforms to use it. Will need to scan twice and make sure it returns the same results to avoid race conditions.

      If I can figure out the same info for Linux from /sys/* without libusb, then maybe the whole idea can be made to work. So that when you plug a device in, the corresponding code for it gets launched, automatically.

  4. Well… so much for that. The above approach doesn’t see the USB ports on Win7. Needs more work :(

    Oh wait, it works – had to install http://www.ftdichip.com/Drivers/CDM/CDM20600.exe – sample output: COM1 {ACPI\PNP0501\2} COM2 {ACPI\PNP0501\1} COM3 {FTDIBUS\VID_0403+PID_6001+A8007Up6A\0000} COM4 {FTDIBUS\VID_0403+PID_6001+A900ad5lA\0000}

    • Now I’m trying to figure out info on Linux – not much luck yet, trying to associate info about say /dev/USB0 with FTDI info such as a serial number. The other direction, as described by Marius, would work – but it’d be nice to go in the other way.

      Update – Hm. There’s probably enough info in “lsusb -v” output, but only when run as root.

      Even this info is available only as root:

      cat /proc/tty/driver/usbserial

      usbserinfo:1.0 driver:2.0

      There’s info at /sys/dev/char/189:145/ which has all the details, but it’s a symlink deep into pci drivers etc. Not easy to scan for and detect. 0: module:ftdi_sio name:”FTDI USB Serial Device” vendor:0403 product:6001 num_ports:1 port:1 path:usb-0000:02:02.0-1

      Ooh – this might be something: $ hal-find-by-capability –capability serial /org/freedesktop/Hal/devices/usb_device_403_6001_A900ad5l_if0_serial_usb_0 /org/freedesktop/Hal/devices/pnp_PNP0501_0_serial_platform_1 /org/freedesktop/Hal/devices/pnp_PNP0501_serial_platform_0

      Unfortunately, that tool will not always be present – it’s not on my install of Debian Lenny, for example – but then again, there I can see al the info in dmesg and in /proc/bus/usb/devices. What a mess…

      Yet another angle, as mentioned on http://wiki.debian.org/HowToIdentifyADevice/Serial – “find /sys/ -name ‘USB‘” seems to find all the devices on Ubuntu and Debian.

      … and /sys/class/tty/ has the symlink from ttyUSB<N> to the detailed device. Cool, now we’re getting somewhere!

    • should that not be currentcontrolset instead of 001… looks nice…

Comments are closed.