Thursday, December 26, 2013

TI SensorTag, Bluetooth Low Energy (BLE) and Linux

I've  been interested in wireless sensing of temperature and relative humidity. All the options I found previously were at least one of the following:

  • expensive, as in >€100
  • outdated, e.g. still using IEEE 802.11b
  • large
  • power-hungry
Then, I found the TI SensorTag. Texas Instruments calls it a development kit and uses it to promote its CC2541 Bluetooth Low Energy (BLE) chip. The whole board is small enough to fit into a box of matches, yet hosts temperature, humidity, 3d accelerometers and gyros, IR temperature and probably other sensors that I forgot.


Mike Saunby kindly reported on how to access this device using linux and the BlueZ utilities. He also provides a python script to retrieve the sensor's values in a scripty fashion and convert them to values meaningful to humans.

Pretty sweet! So I ordered two. And it works. My flat was built in the beginning of the last century, and using a Digitus DN-30210 Bluetooth dongle (Broadcom 20702), the lack of concrete allows a range of about 15m, with two "walls" in between. Great!

The only trouble was that the SensorTag would advertise (and wait for incoming connections) exactly 180 seconds, then shut down. This is a real problem if you're trying to use them for long-term data capture. You'd have to keep the connection alive permanently, and if it ever drops for more than 3 minutes (server restart, bugs etc.) you're disconnected. That might be ok at home, but not in remote locations. It's just not robust.

I read a lot about BLE, central devices, peripheral devices, masters and slaves, advertising and whatnot, but I could never find out whether it's possible in principle to connect to the SensorTag when it's NOT advertising. After all, I thought advertising is just to let others know you exist and what MAC you have, but accepting connections might still be possible without it. I still don't know, but I guess not.

TI does distribute the source-code for the firmware running on the SensorTag (it's one of the sample projects in their BLE stack, which is only partly open source). To get rid of the 180-second-timeout, I'd have to recompile this sample project without the timeout and flash it onto the SensorTag.

To flash new firmware, you'd either use the Texas Instruments CC Debugger ($49, international shipping is free), or, maybe, you can use an iOS-App from TI to flash the firmware wirelessly (TI calls this OAD, over-the-air download). Because I don't have Apple hardware and am scared of flashing firmware without cables, I ordered the debugger.

TI's toolchain for building software for the CC2541 is called "IAR Embedded Workbench for 8051", currently at version 8.30 (you need a recent version to work with v1.40 of the BLE stack). This software is closed, proprietary, and hideously expensive. Like, 4-figure expensive. And they guard it well.

You can download a "free" version that is limited to a 4kb code size. Nice, but quite useless, as the SensorTag's firmware boils down to around 400kb.

The other option is evaluating a full-featured version for 30 days. My evaluation period started yesterday night at 3 am.

So, after installing IAR Embedded Workbench and unzipping TI's BLE stack, you need to open
$TI_BLE_Stack\Projects\ble\common\cc2540\ti_51ew_cc2540b.xcl
in an editor and find the line
-Z(DATA)VREG+_NR_OF_VIRTUAL_REGISTERS=08-7F
 replace it with
-Z(DATA)VREG=08-7F
Now you can open
$TI_BLE_Stack\Projects\ble\SensorTag\CC2541DB\SensorTag.eww
 in IAR. In SensorTag.c, find the line
// General discoverable mode advertises indefinitely
#define DEFAULT_DISCOVERABLE_MODE             GAP_ADTYPE_FLAGS_LIMITED
 and replace it with
#define DEFAULT_DISCOVERABLE_MODE             GAP_ADTYPE_FLAGS_GENERAL
This line makes sure that advertising doesn't stop anymore. I have no idea how long the CR2032 battery will last if you keep advertising at the default rate of 10Hz forever, so I changed the advertising interval. Find the line
// What is the advertising interval when device is discoverable (units of 625us, 160=100ms)
#define DEFAULT_ADVERTISING_INTERVAL          160
and replace it with
#define DEFAULT_ADVERTISING_INTERVAL          16384
which means that advertising happens every 10.24 seconds. I read somewhere in TI's forums that this is the maximum value (and while I wonder what they use those other two bits for, I haven't tried going above 2^14).

You can also change the name that shows up when scanning for devices (default "SensorTag").

Now right-click on the project and select make. It should build fine and create
$TI_BLE_Stack\Projects\ble\SensorTag\CC2541DB\CC2541DK-Sensor\Exe\SensorTag.hex
In my case, that ended up like this:
md5sum aa086082c665d82e701fe2d061f710c0  SensorTag.hex
You can then try your luck using the OAD-iOS thingy, or use TI's SmartRF Flash Programmer to flash it to the SensorTag. I wrote the firmware to the primary location and didn't change that IEEE address (I think it's the bluetooth MAC, but I'm not sure).


And it works! The green LED flashes shortly every 10.24 seconds instead of 10Hz. And it has been doing that for a full 14 hours by now. I can connect using Mike's bluez-magic, fetch some values, disconnect and it will still advertise forever.

How long the battery lasts, I don't know. As soon as it stops flashing, I'll amend this post.

Dear TI, thank you very much for this great, cheap little device. But pleeeeeaaase, having to download proprietary compilers feels like the nineties. How about something that I can use GCC or LLVM with?

Dear OpenWRT, could you please package a more recent version of bluez than 3.36? Google told me a few people have tried it before, but it seems this never made it into trunk. I'd love to have my router query two or three SensorTags and populate some mysql-table!

Saturday, December 21, 2013

TechnoTrend TT-connect CT2-4650 CI working with Ubuntu 13.10

This is a short note for everybody wondering whether the TechnoTrend TT-connect CT2-4650 CI DVB-C receiver works with linux.

I just got the USB device delivered today. Drivers needed to be downloaded from TechnoTrend and installed, but that worked quickly and flawlessly. It took me a while to search/remember how to generate initial tuning data (w_scan) and then scan, but now everything works just fine. Haven't tried anything CI-related, though.

Great work, TechnoTrend!

Monday, December 16, 2013

Initialize (partition, format, copy) multiple USB sticks using linux and udev

Here's a set of scripts that allows you to fill hundreds of USB sticks with the same data. We used that for distributing proceedings of a conference, but I guess it might be helpful for others, too.

It should work on pretty much any recent linux distribution, as it only requires UDEV to work.

First, create or edit /etc/udev/rules.d/10-local.rules and add
ATTRS{idVendor}=="VENDOR_ID_OF_USB_STICK", ATTRS{idProduct}=="PRODUCT_ID_OF_USB_STICK", ATTR{size}=="15810560", RUN+="/usr/bin/fill_usb_stick.sh %k"
Then create /usr/bin/fill_usb_stick.sh, which reads:
#!/bin/bash { # Convert /dev/sdb into sdb UNIQUENAME=$1 DEVICEFILE="/dev/$1" PARTITION="/dev/$11" if [[ "$ACTION" = "remove" ]] then echo "$(date +%Y%m%d-%H:%M:%S): $UNIQUENAME was removed." >> /tmp/log.txt exit 0 fi if [[ "$ACTION" != "add" ]] then exit 0 fi LOCKFILE="/tmp/lock_usb_$UNIQUENAME" test -e $LOCKFILE && echo "$(date +%Y%m%d-%H:%M:%S): $UNIQUENAME: already running, exiting" >> /tmp/log.txt && exit 1 touch $LOCKFILE if [[ "$UNIQUENAME" == "sda" ]] then echo "$(date +%Y%m%d-%H:%M:%S): $UNIQUENAME: Will not write to SDA, exiting" >> /tmp/log.txt exit 1 fi /usr/bin/logger "setting up usb stick $UNIQUENAME due to action $ACTION" echo "$(date +%Y%m%d-%H:%M:%S): $UNIQUENAME: creating new partition table, filesystem and proceedings on usb stick" >> /tmp/log.txt cat <> /tmp/log.txt # Create a FS on the first partition /sbin/mkfs.vfat -n MFI_2012 $PARTITION if [[ -d /mnt/$UNIQUENAME ]] ; then /bin/rmdir /mnt/$UNIQUENAME if [[ $? != 0 ]] ; then echo "$(date +%Y%m%d-%H:%M:%S): $UNIQUENAME: EEEEE could not delete /mnt/$UNIQUENAME before mounting, seems its not empty, exiting" >> /tmp/log.txt exit 1 fi fi /bin/mkdir -p /mnt/$UNIQUENAME #echo "$(date +%Y%m%d-%H:%M:%S): $UNIQUENAME: mounting usb stick to: /mnt/$UNIQUENAME" >> /tmp/log.txt /bin/mount $PARTITION /mnt/$UNIQUENAME if [[ $? != 0 ]] ; then echo "$(date +%Y%m%d-%H:%M:%S): $UNIQUENAME: EEEEE could not mount usb sticks new filesystem, exiting." >> /tmp/log.txt exit 1 fi #echo "$(date +%Y%m%d-%H:%M:%S): $UNIQUENAME: copying files to usb stick $UNIQUENAME" >> /tmp/log.txt /bin/cp -r /stuff/to/copy/on/stick/* /mnt/$UNIQUENAME/ if [[ $? != 0 ]] ; then echo "$(date +%Y%m%d-%H:%M:%S): $UNIQUENAME: EEEEE could not copy files, exiting." >> /tmp/log.txt && exit 1 exit 1 fi /bin/sleep 10 #/bin/umount $PARTITION || echo "$(date +%Y%m%d-%H:%M:%S): $UNIQUENAME: EEEEE could not remount usb stick, exiting." >> /tmp/log.txt ; exit 1 #echo "$(date +%Y%m%d-%H:%M:%S): $UNIQUENAME: remounting and checksumming usb stick $UNIQUENAME...." >> /tmp/log.txt /bin/mount -o remount $PARTITION /mnt/$UNIQUENAME if [[ $? != 0 ]] ; then echo "$(date +%Y%m%d-%H:%M:%S): $UNIQUENAME: EEEEE could not remount $PARTITION to /mnt/$UNIQUENAME, exiting" >> /tmp/log.txt && exit 1 exit 1 fi echo "$(date +%Y%m%d-%H:%M:%S): $UNIQUENAME: checksum of usb stick $UNIQUENAME is $(md5deep -rbs /mnt/$UNIQUENAME | sort | md5sum)" >> /tmp/log.txt /bin/sleep 10 /bin/umount $PARTITION if [[ $? != 0 ]] ; then echo "$(date +%Y%m%d-%H:%M:%S): $UNIQUENAME: EEEEE could not unmount usb stick, exiting." >> /tmp/log.txt exit 1 fi /bin/rmdir "/mnt/$UNIQUENAME" if [[ $? != 0 ]] ; then echo "$(date +%Y%m%d-%H:%M:%S): $UNIQUENAME: EEEEE could not delete /mnt/$UNIQUENAME after checksumming, seems its not empty, exiting." >> /tmp/log.txt exit 1 fi echo "$(date +%Y%m%d-%H:%M:%S): $UNIQUENAME: done." >> /tmp/log.txt /bin/rm $LOCKFILE /usr/bin/logger "done setting up USB stick $UNIQUENAME" } &

Now grab some USB hubs, plug in as many USB sticks as you can and see how things in /stuff/to/copy/on/stick/ are replicated to all the USB sticks.

Oh, you know what's most important? DISABLE THE SCRIPT WHEN YOU'RE DONE! I missed that part and ruined a colleague's USB-stick after he had started using it for stuff other than the conference's proceeedings :(