For reference, here's the background research I did on kernel APIs ---
So it seems Linux gives us a number of ways of actually talking to the kernel, with various pros and cons. The basic difference is the value set in the
addr.hci_channel field when calling bind() after creating a BTPROTO_HCI socket.
HCI_CHANNEL_RAW
This is the 'traditional' option, which is what both
python-hcipy and
bluepy.device are using at the minute. These let you send controller commands as defined in the Bluetooth spec (e.g. Set Scan Parameters) and ACL data to the device (e.g. GATT commands). Seems you can either do this via ioctl (
hcipy) or reading/writing socket data (
bluepy.device).
HCI_CHANNEL_CONTROL
This is used by BlueZ code when issuing 'management' commands. It's documented at e.g.
https://github.com/pauloborges/bluez/blob/master/doc/mgmt-api.txtIt seems this has a Linux-specific command set which doesn't match up to anything in the Bluetooth spec. There's some background to why this was added at
http://www.bluez.org/the-management-interface/
HCI_CHANNEL_USER
This is best described here:
https://www.spinics.net/lists/linux-bluetooth/msg37345.htmlSeems like this allows controller commands to be sent (like HCI_CHANNEL_RAW) but the kernel gives you exclusive access.
There might be advantages to using the newer HCI_CHANNEL_CONTROL and HCI_CHANNEL_USER methods, but there's a big problem that current Python's
socket module doesn't let you get at it. The relevant code is in
makesockaddr() in CPython's
socketmodule.c - see
https://github.com/python/cpython/blob/master/Modules/socketmodule.c#L1276. - it only ever seems to set the
dev and
bdaddr members, leaving the
hci_channel field set to 0 (HCI_CHANNEL_RAW).
We could conceivably submit a patch to a future version of CPython to fix this, or build our small own extension module with a better
bind(), or try something slightly crazy using CTypes to load and call directly into the C library. None of these seem particularly appealing at the minute, so we might be best sticking with HCI_CHANNEL_RAW.