Tuesday, 20 December 2016

RPi: fixing Volumio to support Bluetooth

Volumio 2.0 (2.031/Nov 23 2016 build) on the RPi3 works as advertised but the build does seem to come with some annoyances if you want to use it in conjunction with other standard items. Here we will address how to fix bluetooth handling and to overcome the few other issues that bugged me and really should be fixed/part of the standard build.

So, I'm running volumio and then installed Kodi along side since it was a waste to simply have the RPi spinning; this way I can choose to watch my media via Kodi OR listen to music via volumio. However trying to add a simple bluetooth keyboard to the Volumio build is a pain. The first thing you will notice is that there appears to be NO bluetooth controller available; nothing seen by hciconfig or bluetoothctl (once you install it). But we know that the RPi3 has an embedded bluetooth chip sitting along the Broadcom wifi chip.

Ok, so Volumio is supposed to be a headless music streamer - so fine, the developers have decided to not included tools that don't fit the system's intended use and we look around google and we have to install some standard pkgs:
  • bluez
  • bluez-firmware
  • pi-bluetooth

The first problem that we find is that pi-bluetooth is not available and from the out-of-the-box repos, we find the following are installed:
bluez         5.23-2+b1
bluez-firmware 1.2-3
and we reboot and try hcitool again. Nothing. We also try force loading kernel modules bluetooth btbcm hidp hci_uart but still no bluetooth controller is available. Now we start digging...

The current version of Volumio is based on the Debian Jessie releae; it ships with a 4.4.9-v7+ kernel that was built in May 6 2016 (current Volumio version released 6months later) with its default repositories located at http://archive.raspbian.org/raspbian.

Trying to determine if the RPi3 bluetooth chip is defective we try another RPi distribution, this time RetroPie (4.1, from Nov 2016). Booting RetroPie and looking for the RPi's bluetooth controller we find:
$ hciconfig -a hci0: Type: BR/EDR Bus: UART BD Address: B8:27:EB:69:09:C7 ACL MTU: 1021:8 SCO MTU: 64:1 UP RUNNING PSCAN RX bytes:1004 acl:0 sco:0 events:46 errors:0 TX bytes:1549 acl:0 sco:0 commands:46 errors:0 Features: 0xbf 0xfe 0xcf 0xfe 0xdb 0xff 0x7b 0x87 Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3 Link policy: RSWITCH SNIFF Link mode: SLAVE ACCEPT Name: 'retropie' Class: 0x000000 Service Classes: Unspecified Device Class: Miscellaneous, HCI Version: 4.1 (0x7) Revision: 0xb6 LMP Version: 4.1 (0x7) Subversion: 0x2209 Manufacturer: Broadcom Corporation (15)

This means the RPi BT controller is available and working so we confirm this by adding/pairing our bluetooth keyboard
$ bluetoothctl
[NEW] Controller B8:27:EB:69:09:C7 RetroPie [default]
[bluetooth]# power on
[bluetooth]# pairable on
[bluetooth]# scan on
turn on bluetooth keyboard and wait for it to be found
[bluetooth]# scan off
[bluetooth]# agent on
[bluetooth]# pair    MAC address of keyboard
will issue a pin code to enter on keyboard
[bluetooth]# trust   MAC address of keyboard
[bluetooth]# connect MAC address of keyboard

At this point we are now connected to the bluetooth keyboard and we can see input on the screen as we type. Now to determine the differences between RetroPie and Volumio pkgs via dpkg-query -W pkgname.
bluez         5.23-2+rpi2
bluez-firmware  1.2-3+rpi1
pi-bluetooth    0.1.1

We take a copy of all the RetroPie files belonging to the bluetooth related packages after examining dpkg-query -L and transfer them to Volumio - we don't care that we are overwritting files since bluetooth on Volumio doesn't work anyway.
  • bluez-firmware-1.2-3_rpi1.tar
    -rw-r--r-- root/root    114688 2016-02-25 03:23 lib/firmware/BCM2033-FW.bin
    -rw-r--r-- root/root      3245 2016-02-25 03:23 lib/firmware/BCM2033-MD.hex
    -rw-r--r-- root/root     35976 2016-02-25 03:23 lib/firmware/BCM43430A1.hcd
    -rw-r--r-- root/root      4588 2016-02-25 03:23 lib/firmware/STLC2500_R4_00_03.ptc
    -rw-r--r-- root/root       281 2016-02-25 03:23 lib/firmware/STLC2500_R4_00_06.ssf
    -rw-r--r-- root/root       292 2016-02-25 03:23 lib/firmware/STLC2500_R4_02_02_WLAN.ssf
    -rw-r--r-- root/root       508 2016-02-25 03:23 lib/firmware/STLC2500_R4_02_04.ptc
  • bluez-5,23-2_rpi2.tar
    -rw-r--r-- root/root      1518 2016-05-27 10:46 lib/udev/rules.d/97-hid2hci.rules
    -rw-r--r-- root/root       113 2014-07-28 00:27 lib/udev/rules.d/50-bluetooth-hci-auto-poweron.rules
    -rwxr-xr-x root/root      9732 2016-05-27 10:46 lib/udev/hid2hci
    -rw-r--r-- root/root       338 2016-05-27 10:46 lib/systemd/system/bluetooth.service
    -rwxr-xr-x root/root      2948 2014-08-18 12:05 etc/init.d/bluetooth
    -rw-r--r-- root/root      1453 2016-05-27 10:46 etc/dbus-1/system.d/bluetooth.conf
    -rw-r--r-- root/root       845 2014-07-28 14:36 etc/default/bluetooth
    -rw-r--r-- root/root      2323 2014-05-19 08:51 etc/bluetooth/main.conf
    -rw-r--r-- root/root       120 2012-12-24 17:46 etc/bluetooth/network.conf
    -rw-r--r-- root/root       397 2014-05-19 08:51 etc/bluetooth/input.conf
    -rw-r--r-- root/root       258 2012-12-24 17:46 etc/bluetooth/proximity.conf
    -rwxr-xr-x root/root    152112 2016-05-27 10:46 bin/hciconfig
    -rwxr-xr-x root/root    792812 2016-05-27 10:46 usr/lib/bluetooth/bluetoothd
    -rw-r--r-- root/root        95 2016-05-27 10:46 usr/share/dbus-1/system-services/org.bluez.service
    -rw-r--r-- root/root       880 2016-05-27 10:46 usr/share/man/man8/bluetoothd.8.gz
    -rw-r--r-- root/root      1093 2016-05-27 10:46 usr/share/man/man1/ciptool.1.gz
    -rw-r--r-- root/root      1590 2016-05-27 10:46 usr/share/man/man1/hcitool.1.gz
    -rw-r--r-- root/root      1577 2016-05-27 10:46 usr/share/man/man1/hciattach.1.gz
    -rw-r--r-- root/root       445 2016-05-27 10:46 usr/share/man/man1/btmon.1.gz
    -rw-r--r-- root/root       856 2016-05-27 10:46 usr/share/man/man1/l2ping.1.gz
    -rw-r--r-- root/root       754 2016-05-27 10:46 usr/share/man/man1/hid2hci.1.gz
    -rw-r--r-- root/root      1477 2016-05-27 10:46 usr/share/man/man1/rfcomm.1.gz
    -rw-r--r-- root/root      1934 2016-05-27 10:46 usr/share/man/man1/hciconfig.1.gz
    -rw-r--r-- root/root       795 2016-05-27 10:46 usr/share/man/man1/l2test.1.gz
    -rw-r--r-- root/root       349 2016-05-27 10:46 usr/share/man/man1/bluetoothctl.1.gz
    -rw-r--r-- root/root      1171 2016-05-27 10:46 usr/share/man/man1/bccmd.1.gz
    -rw-r--r-- root/root       672 2016-05-27 10:46 usr/share/man/man1/rctest.1.gz
    -rw-r--r-- root/root      1556 2016-05-27 10:46 usr/share/man/man1/sdptool.1.gz
    -rw-r--r-- root/root      2689 2013-11-26 16:16 usr/share/doc/bluez/NEWS.Debian.gz
    -rw-r--r-- root/root      4356 2013-11-26 16:16 usr/share/doc/bluez/copyright
    -rw-r--r-- root/root      8516 2016-05-27 10:34 usr/share/doc/bluez/changelog.Debian.gz
    -rw-r--r-- root/root      1656 2014-07-25 19:48 usr/share/doc/bluez/README.Debian.gz
    -rw-r--r-- root/root     21638 2014-09-07 23:23 usr/share/doc/bluez/changelog.gz
    -rwxr-xr-x root/root    365000 2016-05-27 10:46 usr/bin/btmon
    -rwxr-xr-x root/root    152132 2016-05-27 10:46 usr/bin/bccmd
    -rwxr-xr-x root/root     96052 2016-05-27 10:46 usr/bin/hciattach
    -rwxr-xr-x root/root     70320 2016-05-27 10:46 usr/bin/rfcomm
    -rwxr-xr-x root/root     78300 2016-05-27 10:46 usr/bin/l2test
    -rwxr-xr-x root/root     96116 2016-05-27 10:46 usr/bin/hcitool
    -rwxr-xr-x root/root     79480 2016-05-27 10:46 usr/bin/bluetoothctl
    -rwxr-xr-x root/root    103560 2016-05-27 10:46 usr/bin/rctest
    -rwxr-xr-x root/root     61792 2016-05-27 10:46 usr/bin/l2ping
    -rwxr-xr-x root/root    156536 2016-05-27 10:46 usr/bin/sdptool
    -rwxr-xr-x root/root     99540 2016-05-27 10:46 usr/bin/ciptool
    -rwxr-xr-x root/root    157556 2016-05-27 10:46 usr/bin/gatttool
    lrwxrwxrwx root/root         0 2016-05-27 10:46 usr/sbin/bluetoothd -> ../lib/bluetooth/bluetoothd
  • pi-bluetooth-0.1.1.tar
    -rw-r--r-- root/root       311 2016-05-10 20:38 lib/systemd/system/hciuart.service
The first thing we notice is the service provided by the pi-bluetooth package which sets up an UART device.

On the Volumio system, we execute this code from the console
# we replace /dev/serial1 with /dev/ttyAMA0
$ /usr/bin/hciattach /dev/ttyAMA0 bcm43xx 921600 noflow -
Flash firmware /lib/firmware/BCM43430A1.hcd
Set Controller UART speed to 921600 bit/s
Device setup complete
At this point we are now able to see our bluetooth controller via hciconfig. Note that the attach command above automatically loads firmware from /lib/firmware - the first time I ran the hciattach I had not extracted the firmware files from RetroPie and whilst the command completed the bluetooth controller listed seen by the sytem had no MAC address and did not function.
$ hciconfig -a hci0: Type: BR/EDR Bus: UART BD Address: B8:27:EB:69:09:C7 ACL MTU: 1021:8 SCO MTU: 64:1 UP RUNNING RX bytes:154237 acl:8055 sco:0 events:66 errors:0 TX bytes:1812 acl:10 sco:0 commands:51 errors:0 Features: 0xbf 0xfe 0xcf 0xfe 0xdb 0xff 0x7b 0x87 Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3 Link policy: RSWITCH SNIFF Link mode: SLAVE ACCEPT Name: 'volumio' Class: 0x000000 Service Classes: Unspecified Device Class: Miscellaneous, HCI Version: 4.1 (0x7) Revision: 0xb6 LMP Version: 4.1 (0x7) Subversion: 0x2209 Manufacturer: Broadcom Corporation (15)
Note that this differs slightly to the RetroPie config where PSCAN is enabled - this is the page scan function that periodically pings for devices that wish to connect.

At this point, we have a working bluetooth stack on Volumio and are able to run the commands to pair the bluetooth keyboard. To make all of these items permanent we want to enable the hciuart service but we have to modify the RetroPie script first since it relies on another service which is unavailable on Volumio and it also relies on a non-existant device
Description=Configure Bluetooth Modems connected by UART

#ExecStart=/usr/bin/hciattach /dev/serial1 bcm43xx 921600 noflow -
ExecStart=/usr/bin/hciattach /dev/ttyAMA0 bcm43xx 921600 noflow -

Once the minor modifications are made, the service can be started successfully and enabled permanently via systemctl daemon-reload && systemctl enable hciuart. Upon reboot, the system comes up and will automatically pair to your previously paired/trusted keyboard once the keyboard is switched on/made discoverable after Volumio boots.

Keymap Annoyances

As mentioned the Volumio build seems to miss a number of standard utils which poses no problems for the standard user. However once you add a keyboard into the mix and log on the console we notice a few items that we will fix to save our sanity.

When logging on the console, you will notice that the keyboard map is off - to remap for a UK keyboard, we need to install keyboard-configuration and console-setup for good measure. With these pkgs (and dpkg-reconfigure keyboard-configuration or dpkg-reconfigure console-setup) we can select the most appropriate keyboard map. I had to reconfigure this after the pkg installation since the first time seemed to cause the " and ' keys to only appear after another key was pressed.

Other Annoyances

Back to the standard/intended uses of Volumio, I have been using an external USB hdd attached to the RPi as the source of my music. This works for because I happened to have a spare 2.5" hdd and USB enclosure and also it means that I do not have to rely on another machine (a NAS for example) to serve my music. However, the Volumio build does NOT ship with hdparm which means that even with no use, the hdd does not spindown.

Adding and configuring hdparm for the trivial case is easy since we can add:
# /etc/rc.local
#!/bin/sh -e

# enable apm and spindown after 2mins of inactvy
/sbin/hdparm -B 127 -S 24 /dev/sda
exit 0
This gets executed after every boot but it does not take into account hotplugging another USB hdd or in fact other USB hdds attached. An advanced way to handle this would be to add a udev rule to manage this so the correct hdparm commands will run when the kernel finds the appropriate devices.
# /etc/udev/rules.d/50-hdparm-rules
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="1", RUN+="/sbin/hdparm -B 127 -S 24 /dev/%k"

Finally, you want to serve files from the RPi to Windows machines on your network using SMB/CIFS. However to make this less of a pain for casual Windows users, it's best to set this up to require no additional usernames and passwords. To share the directory /export/public where files as owned by the user pi as readonly without passwords:
$ apt-get install samba # /etc/samba/smb.conf [global] # this is the only important item - ensure the workgroup name is the same as the one used by Windows hosts workgroup = WORKGROUP usershare allow guests = yes [public] comment = Public path = "/export/public" writeable = no guest ok = yes create mask = 0644 directory mask = 0755 force user = pi # verify config items all ok $ testparm # restart the services $ for i in smbd nmbd ; do systemctl enable $i && systemctl restart $i
Now on your Windows machine, you can simply use the hostname in the explorer window and you should see it autocomplete the rest of the path. This is where having a static hostname for the RPi is going to beneficial.


Whilst we acknowledge that most Volumio users may NOT need/want to log into their RPi on the console and via a bluetooth keyboard these updates listed here are relatively trivial for any intermediate user. It therefore seems a shame that the Volumio build does not include the bluetooth utils and firmware (it may only require the firmware files along with the hciuart service) as part of the standard build but hopefully the instructions set out here will help anyone wishing to setup their bluetooth keyboards with Volumio.

No comments:

Post a Comment