Last active
January 29, 2021 08:26
Bluetooth LE HCI Python test class
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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