Monday, 22 October 2012

TomTom Bluetooth Remote & Raspberry Pi

A while back I bought a TomTom Bluetooth remote control (here's a good review) with a view to using it with a Linux home theatre computer (HTPC) running XBMC or similar. As far as the computer is concerned, it is just a Bluetooth keyboard.

TomTom Bluetooth remote control

While most of the information below should apply to any Debian/Ubuntu system, this time I was using the Debain variant Raspbian on a Raspberry Pi. Since the Raspberry Pi has an HDMI connector I may keep one connected to our TV, but this could also work out nicely for controlling a Raspberry Pi running the GPS software Navit in the car. Time to get Bluetooth on the Pi with a USB dongle!

I tried this with two Bluetooth dongles, a tiny Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode) (USB ID 0a12:0001), and a noticeable larger Belkin Components F8T013 Bluetooth Adapter (USB ID 050d:0013). Both worked fine (eventually).

From having played with this before, I know that the TomTom Remote pretends to be a normal Bluetooth Keyboard (only it happens to have just ten keys). The only catch is this means you can't type in a Bluetooth pairing code, instead like a Bluetooth mouse, the PIN is preset to 0000.

$ sudo apt-get install bluetooth bluez

That takes a long time, and seems to install a whole bunch of apparently unrelated printer and scanner stuff. Once it is done, check if it recognises your Bluetooth dongle and everything seems OK so far:

$ /etc/init.d/bluetooth status
[ ok ] bluetooth is running.


TomTom Bluetooth pairing

Now let's do a Bluetooth scan, and at this point put batteries in the TomTom Remote if you haven't already (or take them out for 30 seconds or so to reset it if needed), or press any key to wake it up. Then start scanning - although it never seems to show up until just after the flashing blue LED stops:

$ hcitool scan --refresh
Scanning ...
00:13:6C:BC:E1:CD TomTom Remote

Possibly helpful snippets of information via hcitools:

$ hcitool name 00:13:6C:BC:E1:CD
TomTom Remote

and:

$ hcitool inq
Inquiring ...
        00:13:6C:BC:E1:CD       clock offset: 0x369c    class: 0x000540

Also potentially of interest, although until I'd sorted out the pairing properly most of the time it just gave "Can't create connection: Input/output error" failures:

$ sudo hcitool info 00:13:6C:BC:E1:CD
Requesting information ...
        BD Address:  00:13:6C:BC:E1:CD
        Device Name: TomTom Remote
        LMP Version: 2.0 (0x3) LMP Subversion: 0x10b7
        Manufacturer: Cambridge Silicon Radio (10)
        Features: 0xff 0xff 0x8f 0xfe 0x9b 0xf9 0x00 0x80
                <3-slot packets> <5-slot packets> <encryption> <slot offset> 
                <timing accuracy> <role switch> <hold mode> <sniff mode> 
                <park state> <RSSI> <channel quality> <SCO link> <HV2 packets> 
                <HV3 packets> <u-law log> <A-law log> <CVSD> <paging scheme> 
                <power control> <transparent SCO> <broadcast encrypt> 
                <EDR ACL 2 Mbps> <EDR ACL 3 Mbps> <enhanced iscan> 
                <interlaced iscan> <interlaced pscan> <inquiry with RSSI> 
                <extended SCO> <EV4 packets> <EV5 packets> <AFH cap. slave> 
                <AFH class. slave> <3-slot EDR ACL> <5-slot EDR ACL> 
                <AFH cap. master> <AFH class. master> <EDR eSCO 2 Mbps> 
                <EDR eSCO 3 Mbps> <3-slot EDR eSCO> <extended features>

My first attempts to pair from the command line were frustrating. I gave up, plugged the Raspberry Pi into my TV, and used the GUI bluetooth tool which was very simple. So having confirmed it could be done, I tried once more at the command line only.

Tip - a brute force way to remove all existing Bluetooth pairings etc back to a clean slate is to remove these files, and then reboot:

$ sudo rm -rf /var/lib/bluetooth/*

What worked for me was following a combination of this Bluetooth pairing on Raspberry Pi guide and connecting Bluetooth from the command line, using the bluez to pair using PIN 0000, and mark the device as trusted:

$ echo "0000" | sudo bluez-simple-agent hci0 00:13:6C:BC:E1:CD
RequestPinCode (/org/bluez/1891/hci0/dev_00_13_6C_BC_E1_CD)
Enter PIN Code: Release
New device (/org/bluez/1891/hci0/dev_00_13_6C_BC_E1_CD)
$ sudo bluez-test-device trusted 00:13:6C:BC:E1:CD yes

At that point it seemed to be connected,

$ hcitool con
Connections:
> ACL 00:13:6C:BC:E1:CD handle 11 state 1 lm MASTER AUTH ENCRYPT

It was a great relief to find this still worked following a reboot as well.  To switch Bluetooth dongles, I removed the TomTom remote's batteries in order to reset it, and tried again - also successfully.


TomTom Remote remapping

As I was logged into the Raspberry Pi via ssh, key presses on the Bluetooth remote don't show up in my terminal window. Working directly with a keyboard and monitor might be easier. In fact I had no other keyboard attached - but I was able to check the key presses as follows. Note with other devices attached, /dev/input/event0 probably won't be the Bluetooth remote - but a higher number:

$ /lib/udev/keymap -i input/event0
Press ESC to finish, or Control-C if this device is not your primary keyboard
scan code: 0x70052   key code: up
scan code: 0x70050   key code: left
scan code: 0x70051   key code: down
scan code: 0x7004F   key code: right
scan code: 0x70028   key code: enter
scan code: 0x70042   key code: f9
scan code: 0x70043   key code: f10
scan code: 0x7002A   key code: backspace
scan code: 0x7002E   key code: equal
scan code: 0x70029   key code: esc

Here I pressed the ring of direction buttons (which act like the cursor keys) and their central button (which acts as enter), the minus and plus volume controls (which act as F9 and F10), then the three buttons from right to left (backspace, equals, escape). I did the escape button last as it quits the keymap application.

What each of the buttons does can be remapped - something I worked out under Ubuntu Linux a few years ago when I brought this remote. Initially I tried HAL but had success with udev rules. The aim of this is to only remap key presses from the TomTom remote, and not affect any other keyboards.

My remapping is defined in a new file /lib/udev/keymaps/tomtom-remote which gets loaded automatically using an entry in /lib/udev/rules.d/95-keymap.rules (so that only the TomTom remote keys are remapped - not any other keyboards):

/lib/udev/keymaps/tomtom-remote
#TomTom Remote (Bluetooth)
#Based on model 4M02.000
#
#Save this file as /lib/udev/keymaps/tomtom-remote and to enable it, add the
#following (as a single line) to http:///lib/udev/rules.d/95-keymap.rules near the
#start before the line: SUBSYSTEMS=="bluetooth", GOTO="keyboard_end"
#
#SUBSYSTEMS=="bluetooth", ATTRS{name}=="TomTom Remote",
#ATTRS{uniq}=="00:13:6C:*", RUN+="keymap $name tomtom-remote"
#
#Here are the ten key codes you can remap:
#
#The four cursor keys and enter, left alone:
#0x70028 enter
#0x7004F right
#0x70050 left
#0x70051 down
#0x70052 up
#
#The remaining five buttons are remapped here,
#you may want to change these (e.g. prev track,
#mute and next track):
#
0x70029 pageup # Left button, by default escape
0x7002E backspace # Middle button, by default equals
0x7002A pagedown # Right button, by default backspace
0x70042 volumedown # Volume down button, by default F9
0x70043 volumeup # Volume up button, by default F10
Start by creating this remapping file, then test it directly (using the appropriate event number for your system):

$ /lib/udev/keymap input/event0 /lib/udev/keymaps/tomtom-remote
Remapped scancode 0x70029 to 0x68 (prior: 0x01)
Remapped scancode 0x7002e to 0x0e (prior: 0x0d)
Remapped scancode 0x7002a to 0x6d (prior: 0x0e)
Remapped scancode 0x70042 to 0x72 (prior: 0x43)
Remapped scancode 0x70043 to 0x73 (prior: 0x44)

Now if I try all the keys on the remote again - following the same order as before:

$ /lib/udev/keymap -i input/event0
Press ESC to finish, or Control-C if this device is not your primary keyboard
scan code: 0x70052   key code: up
scan code: 0x70050   key code: left
scan code: 0x70051   key code: down
scan code: 0x7004F   key code: right
scan code: 0x70028   key code: enter
scan code: 0x70042   key code: volumedown
scan code: 0x70043   key code: volumeup
scan code: 0x7002A   key code: pagedown
scan code: 0x7002E   key code: backspace
scan code: 0x70029   key code: pageup
^C

This time as none of the keys send escape, I had to press control+c on the ssh terminal to end the test. As you can see the remapping works. Now, to make that happen automatically, we need to add a rule to /lib/udev/rules.d/95-keymap.rules as follows:

SUBSYSTEMS=="bluetooth", ATTRS{name}=="TomTom Remote", ATTRS{uniq}=="00:13:6C:*", RUN+="keymap $name tomtom-remote"

Place that new line just before this line (i.e. near the top of the file),

SUBSYSTEMS=="bluetooth", GOTO="keyboard_end"

What this does is filter for bluetooth keyboards with the name "TomTom Remote" and a MAC address belonging to the range assigned to TomTom. If you have more than one TomTom Remote and want to treat them differently, include the full MAC address (in my case, 00:13:6C:BC:E1:CD, as shown in the commands above).

Getting that working was quite fiddly, since after each change I had to reboot to retest. The file on the Ubuntu Desktop machine where I originally did this has been replaced during a system upgrade. My original notes were on this thread on the (defunct) Moovida Forums, the only trace of which I could find online was this blog post but sadly it lacked all the relevant details. [Moovida v1 was an interesting open source Linux friendly media center owned by Fluendo, and the key-mapping above worked nicely with it. Sadly in v2 they went closed source and focussed on Windows, and development on v1 stalled, and so I lost interest. Anyway, back to the present...]

Quite what the best remapping to use is depends on the primary application in mind of course - those three buttons in the middle of the remote appear to be used to match three context specific on-screen buttons in the original TomTom GUI. Right now I'm thinking of using either the GPS software Navit on the Raspberry Pi, or a media center connected to my TV.

On a related note, see this blog post for using this TomTom BlueTooth Remote with Android (also covering pairing and remapping the keys).

P.S. If you want to buy your own Bluetooth TomTom Remote on eBay, there are some grey and black variations and currently the prices seem to start at about £15. There is also a variant Renault TomTom Bluetooth remote in black where the volume buttons have been replaced with a Map 2D/3D toggle and a menu key - that would probably work too.

Watch out for the older cheaper TomTom remotes which are infra-red (IR) radio frequency (RF) only.

Update (October 2013):

I was hoping to try using the TomTom bluetooth remote to control XBMC running under OpenElec, but that wasn't so easy. Instead I've added an infrared sensor to my Raspberry Pi which was fairly simple to setup.

2 comments:

  1. I read most of your articles on Pi and linux, and would like to mention that you have been doing a great work on educating people by sharing your projects and knowledge... congratulations and keep up the good work!!!
    From Devinder Sethi, Canada.

    ReplyDelete
  2. Thanks for this.. I simply edited the keyboard.xml and put it in .xbmc/userdata/keymaps, so I didn't remap anything in linux, just in XBMC. (on the rPi) It works great, for me.. Thanks for helping me along!

    For reference, here's the keyboard XML I made, it just maps the three buttons above the volume (from left to right) to "back", "context menu" and "mute" and during video playback to "stop", "next subtitle" and "download subtitles", respectively. The directional buttons, enter and volume buttons work as expected out of the box.




    Mute
    Back
    ContextMenu




    runscript(script.xbmc.subtitles)
    Stop
    NextSubtitle


    ReplyDelete