Skip to content

Instantly share code, notes, and snippets.

@WayneKeenan
Last active January 29, 2021 08:26
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save WayneKeenan/bcaabcc6e7f2cd7cd38fbd2b0b916782 to your computer and use it in GitHub Desktop.
Save WayneKeenan/bcaabcc6e7f2cd7cd38fbd2b0b916782 to your computer and use it in GitHub Desktop.
Bluetooth LE HCI Python test class
import socket
import fcntl
from ioctl_helper import _IOW, _IOR
import struct
import array
from subprocess import call
from time import sleep
from os import popen
# ---------------------------------------------------
# HCI Constants (https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/lib/hci.h)
# HCI ioctl Commands:
HCIDEVUP = 0x400448c9 # 201
HCIDEVDOWN = 0x400448ca # 202
HCIGETDEVINFO = 0x7ffbb72d #_IOR(ord('H'), 211, 4)
HCISETSCAN = 0x400448dd #221
# hex values take from: import bluetooth._bluetooth as bluez, installed by: sudo apt-get install python-bluetooth
# TODO: replace magic hex with Linux IOCTL code helper, see: http://code.activestate.com/recipes/578225-linux-ioctl-numbers-in-python/
# HCI Parameters
SCAN_DISABLED = 0x00
SCAN_INQUIRY = 0x01
SCAN_PAGE = 0x02
# C HCI examples: https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/tools/hciconfig.c
# ---------------------------------------------------
# HCI Data structures for IOCTL buffers (subset, see hci.h):
"""
struct hci_dev_req {
uint16_t dev_id;
uint32_t dev_opt;
};
struct hci_dev_list_req {
uint16_t dev_num;
struct hci_dev_req dev_req[0]; /* hci_dev_req structures */
};
struct hci_dev_info {
uint16_t dev_id;
char name[8];
bdaddr_t bdaddr;
uint32_t flags;
uint8_t type;
uint8_t features[8];
uint32_t pkt_type;
uint32_t link_policy;
uint32_t link_mode;
uint16_t acl_mtu;
uint16_t acl_pkts;
uint16_t sco_mtu;
uint16_t sco_pkts;
struct hci_dev_stats stat;
};
"""
# Python struct data format specifiers (see: https://docs.python.org/3.0/library/struct.html)
# H unsigned short integer
# I unsigned int integer
# ---------------------------------------------------
class BluetoothHCI:
def __init__(self, dev_id=0):
self.dev_id = 0
self._socket_open()
def _socket_open(self):
self.sock = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_HCI)
self.sock.bind((self.dev_id,))
def up(self):
buffer = struct.pack("I", self.dev_id)
fcntl.ioctl(self.sock.fileno(), HCIDEVUP, 0)
def get_dev_info():
#zero_filled = [0 for _ in range(256)]
#buffer = struct.pack('I%sb' % len(zero_filled), dev_id, *zero_filled)
buffer = struct.pack("HbBIBBIIIHHHH10I", self.dev_id, *((0,) * 22))
fcntl.ioctl(self.sock.fileno(), HCIGETDEVINFO, buffer)
# simple hex dump:
print( [hex(ord(c)) for c in buffer])
def set_scan(self):
buffer = struct.pack("HI", self.dev_id, SCAN_INQUIRY)
fcntl.ioctl(self.sock.fileno(), HCISETSCAN, buffer)
def down(self):
buffer = struct.pack("I", self.dev_id)
fcntl.ioctl(self.sock.fileno(), HCIDEVDOWN, 0)
def _socket_close(self):
self.sock.close()
if __name__ == "__main__":
ble_hci = BluetoothHCI(0)
ble_hci.down()
print(popen("hciconfig").read())
sleep(3)
ble_hci.up()
print(popen("hciconfig").read())
sleep(3)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment