def write_inquiry_mode(sock, mode): """returns 0 on success, -1 on failure""" # save current filter old_filter = sock.getsockopt( bluez.SOL_HCI, bluez.HCI_FILTER, 14) # Setup socket filter to receive only events related to the # write_inquiry_mode command flt = bluez.hci_filter_new() opcode = bluez.cmd_opcode_pack(bluez.OGF_HOST_CTL, bluez.OCF_WRITE_INQUIRY_MODE) bluez.hci_filter_set_ptype(flt, bluez.HCI_EVENT_PKT) bluez.hci_filter_set_event(flt, bluez.EVT_CMD_COMPLETE); bluez.hci_filter_set_opcode(flt, opcode) sock.setsockopt( bluez.SOL_HCI, bluez.HCI_FILTER, flt ) # send the command! bluez.hci_send_cmd(sock, bluez.OGF_HOST_CTL, bluez.OCF_WRITE_INQUIRY_MODE, struct.pack("B", mode) ) pkt = sock.recv(255) status = struct.unpack("xxxxxxB", pkt)[0] # restore old filter sock.setsockopt( bluez.SOL_HCI, bluez.HCI_FILTER, old_filter ) if status != 0: return -1 return 0
def read_inquiry_scan_activity(sock): """returns the current inquiry scan interval and window, or -1 on failure""" # save current filter old_filter = sock.getsockopt( bluez.SOL_HCI, bluez.HCI_FILTER, 14) # Setup socket filter to receive only events related to the # read_inquiry_mode command flt = bluez.hci_filter_new() opcode = bluez.cmd_opcode_pack(bluez.OGF_HOST_CTL, bluez.OCF_READ_INQ_ACTIVITY) bluez.hci_filter_set_ptype(flt, bluez.HCI_EVENT_PKT) bluez.hci_filter_set_event(flt, bluez.EVT_CMD_COMPLETE); bluez.hci_filter_set_opcode(flt, opcode) sock.setsockopt( bluez.SOL_HCI, bluez.HCI_FILTER, flt ) # first read the current inquiry mode. bluez.hci_send_cmd(sock, bluez.OGF_HOST_CTL, bluez.OCF_READ_INQ_ACTIVITY ) pkt = sock.recv(255) status,interval,window = struct.unpack("!xxxxxxBHH", pkt) interval = bluez.btohs(interval) interval = (interval >> 8) | ( (interval & 0xFF) << 8 ) window = (window >> 8) | ( (window & 0xFF) << 8 ) if status != 0: mode = -1 # restore old filter sock.setsockopt( bluez.SOL_HCI, bluez.HCI_FILTER, old_filter ) return interval, window
def read_inquiry_mode(sock): """returns the current mode, or -1 on failure""" # save current filter old_filter = sock.getsockopt( bluez.SOL_HCI, bluez.HCI_FILTER, 14) # Setup socket filter to receive only events related to the # read_inquiry_mode command flt = bluez.hci_filter_new() opcode = bluez.cmd_opcode_pack(bluez.OGF_HOST_CTL, bluez.OCF_READ_INQUIRY_MODE) bluez.hci_filter_set_ptype(flt, bluez.HCI_EVENT_PKT) bluez.hci_filter_set_event(flt, bluez.EVT_CMD_COMPLETE); bluez.hci_filter_set_opcode(flt, opcode) sock.setsockopt( bluez.SOL_HCI, bluez.HCI_FILTER, flt ) # first read the current inquiry mode. bluez.hci_send_cmd(sock, bluez.OGF_HOST_CTL, bluez.OCF_READ_INQUIRY_MODE ) pkt = sock.recv(255) status,mode = struct.unpack("xxxxxxBB", pkt) if status != 0: mode = -1 # restore old filter sock.setsockopt( bluez.SOL_HCI, bluez.HCI_FILTER, old_filter ) return mode
def _check_command_support(self, octet, mask): """ Checks if a certain command is supported by the Bluetooth sensor. @param octet The octet of the command. @param mask The bitmask of the command. Both as defined in the Bluetooth specification v4.0 pp. 447 (pdf 693). """ # save current filter old_filter = self.sock.getsockopt(bluez.SOL_HCI, bluez.HCI_FILTER, 14) # Setup socket filter to receive only events related to the # read_inquiry_mode command flt = bluez.hci_filter_new() opcode = bluez.cmd_opcode_pack(0x04, 0x0002) bluez.hci_filter_set_ptype(flt, bluez.HCI_EVENT_PKT) bluez.hci_filter_set_event(flt, bluez.EVT_CMD_COMPLETE); bluez.hci_filter_set_opcode(flt, opcode) self.sock.setsockopt(bluez.SOL_HCI, bluez.HCI_FILTER, flt) # Send the Read Local Supported Commands command bluez.hci_send_cmd(self.sock, 0x04, 0x0002) pkt = self.sock.recv(65) status = struct.unpack("65B", pkt) status = status[6:] # restore old filter self.sock.setsockopt(bluez.SOL_HCI, bluez.HCI_FILTER, old_filter) # Check if the requested bit is set. if len(status) >= octet+1: return status[octet+1] & mask == mask return False
def find_local_bdaddr(self): dev_id = 0 hci_sock = _bt.hci_open_dev(dev_id) old_filter = hci_sock.getsockopt( _bt.SOL_HCI, _bt.HCI_FILTER, 14) flt = _bt.hci_filter_new() opcode = _bt.cmd_opcode_pack(_bt.OGF_INFO_PARAM, _bt.OCF_READ_BD_ADDR) _bt.hci_filter_set_ptype(flt, _bt.HCI_EVENT_PKT) _bt.hci_filter_set_event(flt, _bt.EVT_CMD_COMPLETE); _bt.hci_filter_set_opcode(flt, opcode) hci_sock.setsockopt(_bt.SOL_HCI, _bt.HCI_FILTER, flt) _bt.hci_send_cmd(hci_sock, _bt.OGF_INFO_PARAM, _bt.OCF_READ_BD_ADDR) pkt = hci_sock.recv(255) status,raw_bdaddr = struct.unpack("xxxxxxB6s", pkt) assert status == 0 t = [ "%X" % ord(b) for b in raw_bdaddr ] t.reverse() bdaddr = ":".join(t) # restore old filter hci_sock.setsockopt( _bt.SOL_HCI, _bt.HCI_FILTER, old_filter ) return bdaddr
def _write_inquiry_tx_power(self, power): """ Returns 0 on success, error status code or -1 on failure. """ if not self._check_command_support(18, 0b10): return -1 # save current filter old_filter = self.sock.getsockopt(bluez.SOL_HCI, bluez.HCI_FILTER, 14) # Setup socket filter to receive only events related to the # read_inquiry_mode command flt = bluez.hci_filter_new() opcode = bluez.cmd_opcode_pack(bluez.OGF_HOST_CTL, 0x0059) bluez.hci_filter_set_ptype(flt, bluez.HCI_EVENT_PKT) bluez.hci_filter_set_event(flt, bluez.EVT_CMD_COMPLETE); bluez.hci_filter_set_opcode(flt, opcode) self.sock.setsockopt(bluez.SOL_HCI, bluez.HCI_FILTER, flt) # first read the current inquiry mode. bluez.hci_send_cmd(self.sock, bluez.OGF_HOST_CTL, 0x0059, struct.pack("b", power)) pkt = self.sock.recv(255) status = struct.unpack("xxxxxxB", pkt)[0] # restore old filter self.sock.setsockopt(bluez.SOL_HCI, bluez.HCI_FILTER, old_filter) return status
def hci_le_set_scan_parameters(sock): SCAN_TYPE = 0x01 INTERVAL = 0x10 WINDOW = 0x10 OWN_TYPE = 0x00 FILTER = 0x00 # all advertisements, not just whitelisted devices cmd_pkt = struct.pack("<BBBBBBB", SCAN_TYPE, 0x0, INTERVAL, 0x0, WINDOW, OWN_TYPE, FILTER) bluez.hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_SET_SCAN_PARAMETERS, cmd_pkt) old_filter = sock.getsockopt(bluez.SOL_HCI, bluez.HCI_FILTER, 14) filtr = bluez.hci_filter_new() bluez.hci_filter_all_events(filtr) bluez.hci_filter_set_ptype(filtr, bluez.HCI_EVENT_PKT) bluez.hci_filter_set_event(filtr, LE_META_EVENT) sock.setsockopt(bluez.SOL_HCI, bluez.HCI_FILTER, filtr)
def get_localAdapter(self, deviceNr): "Return name and address of a local adapter" name = None address = None sock = bt.hci_open_dev(deviceNr) if sock.getsockid() >= 0: sock.settimeout(3) # Save original filter orig_filter = sock.getsockopt(bt.SOL_HCI, bt.HCI_FILTER, 14) # Create new filter new_filter = orig_filter new_filter = bt.hci_filter_new() bt.hci_filter_set_ptype(new_filter, bt.HCI_EVENT_PKT) bt.hci_filter_set_event(new_filter, bt.EVT_CMD_COMPLETE) # CMD Read local name opcode = bt.cmd_opcode_pack(bt.OGF_HOST_CTL, bt.OCF_READ_LOCAL_NAME) bt.hci_filter_set_opcode(new_filter, opcode) sock.setsockopt(bt.SOL_HCI, bt.HCI_FILTER, new_filter) bt.hci_send_cmd(sock, bt.OGF_HOST_CTL, bt.OCF_READ_LOCAL_NAME) try: data = sock.recv(255) name = data[7:] name = name[:name.find('\0')] except bluetooth._bluetooth.timeout: print 'bluetooth timeout during local device scan for name' # CMD Read local address opcode = bt.cmd_opcode_pack(bt.OGF_INFO_PARAM, bt.OCF_READ_BD_ADDR) bt.hci_filter_set_opcode(new_filter, opcode) sock.setsockopt(bt.SOL_HCI, bt.HCI_FILTER, new_filter) bt.hci_send_cmd(sock, bt.OGF_INFO_PARAM, bt.OCF_READ_BD_ADDR) try: data = sock.recv(255) status, raw_bdaddr = struct.unpack('xxxxxxB6s', data) address = ['%02X' % ord(b) for b in raw_bdaddr] address.reverse() address = ':'.join(address) except bluetooth._bluetooth.timeout: print 'bluetooth timeout during local device scan for address' # Restore original filter sock.setsockopt(bt.SOL_HCI, bt.HCI_FILTER, orig_filter) sock.close() return name, address
def read_remote_version_information(self, cmd_params: dict) -> dict: ''' cmd_params -- { 'Connection_Handle': 0x0000 } ''' dd = hci_open_dev(self.devid) bin_cmd_params = cmd_params['Connection_Handle'].to_bytes(2, 'little') flt = hci_filter_new() hci_filter_set_ptype(flt, HCI_EVENT_PKT) hci_filter_set_event(flt, EVT_READ_REMOTE_VERSION_COMPLETE) dd.setsockopt(SOL_HCI, HCI_FILTER, flt) hci_send_cmd(dd, OGF_LINK_CTL, OCF_READ_REMOTE_VERSION, bin_cmd_params) while True: event_params = dd.recv(3 + \ EVT_READ_REMOTE_VERSION_COMPLETE_SIZE)[3:] status, conn_handle, ver, manufacturer_name, subver = \ struct.unpack('<BHBHH', event_params) event_params = { 'Status': status, 'Connection_Handle': conn_handle, 'Version': ver, 'Manufacturer_Name': manufacturer_name, 'Subversion': subver } if event_params['Connection_Handle'] == cmd_params[ 'Connection_Handle']: break hci_close_dev(dd.fileno()) return event_params
def read_local_bdaddr(): hci_sock = _bt.hci_open_dev(0) old_filter = hci_sock.getsockopt(_bt.SOL_HCI, _bt.HCI_FILTER, 14) flt = _bt.hci_filter_new() opcode = _bt.cmd_opcode_pack(_bt.OGF_INFO_PARAM, _bt.OCF_READ_BD_ADDR) _bt.hci_filter_set_ptype(flt, _bt.HCI_EVENT_PKT) _bt.hci_filter_set_event(flt, _bt.EVT_CMD_COMPLETE) _bt.hci_filter_set_opcode(flt, opcode) hci_sock.setsockopt(_bt.SOL_HCI, _bt.HCI_FILTER, flt) _bt.hci_send_cmd(hci_sock, _bt.OGF_INFO_PARAM, _bt.OCF_READ_BD_ADDR) pkt = hci_sock.recv(255) status, raw_bdaddr = struct.unpack("xxxxxxB6s", pkt) assert status == 0 t = ["%02X" % ord(b) for b in raw_bdaddr] t.reverse() bdaddr = ":".join(t) # restore old filter hci_sock.setsockopt(_bt.SOL_HCI, _bt.HCI_FILTER, old_filter) return bdaddr
def read_extended_page_timeout(self): dd = hci_open_dev(self.devid) flt = hci_filter_new() hci_filter_set_ptype(flt, HCI_EVENT_PKT) hci_filter_set_event(flt, EVT_CMD_COMPLETE) hci_filter_set_opcode( flt, cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_EXT_PAGE_TIMEOUT)) dd.setsockopt(SOL_HCI, HCI_FILTER, flt) hci_send_cmd(dd, OGF_HOST_CTL, OCF_READ_EXT_PAGE_TIMEOUT) event_params = dd.recv(3 + EVT_CMD_COMPLETE_SIZE + 3)[3:] num_hci_cmd_pkts, cmd_opcode, status, \ ext_page_timeout = struct.unpack('<BHBH', event_params) event_params = { 'Num_HCI_Command_Packets': num_hci_cmd_pkts, 'Command_Opcode': cmd_opcode, 'Status': status, 'Extended_Page_Timeout': ext_page_timeout } hci_close_dev(dd.fileno()) return event_params
def read_class_of_device(self) -> dict: dd = hci_open_dev(self.devid) flt = hci_filter_new() hci_filter_set_ptype(flt, HCI_EVENT_PKT) hci_filter_set_event(flt, EVT_CMD_COMPLETE) hci_filter_set_opcode( flt, cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_CLASS_OF_DEV)) dd.setsockopt(SOL_HCI, HCI_FILTER, flt) hci_send_cmd(dd, OGF_HOST_CTL, OCF_READ_CLASS_OF_DEV) event_params = dd.recv(3 + HCI_MAX_EVENT_SIZE)[3:] num_hci_cmd_pkts, cmd_opcode, status, cod = struct.unpack( '<BHB3s', event_params) event_params = { 'Num_HCI_Command_Packets': num_hci_cmd_pkts, 'Command_Opcode': cmd_opcode, 'Status': status, 'Class_Of_Device': cod[::-1] } hci_close_dev(dd.fileno()) return event_params
def write_page_timeout(self, cmd_params={'Page_Timeout': 0x2000}) -> dict: dd = hci_open_dev(self.devid) bin_cmd_params = cmd_params['Page_Timeout'].to_bytes(2, 'little') flt = hci_filter_new() hci_filter_set_ptype(flt, HCI_EVENT_PKT) hci_filter_set_event(flt, EVT_CMD_COMPLETE) hci_filter_set_opcode( flt, cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_PAGE_TIMEOUT)) dd.setsockopt(SOL_HCI, HCI_FILTER, flt) hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_PAGE_TIMEOUT, bin_cmd_params) event_params = dd.recv(3 + EVT_CMD_COMPLETE_SIZE + 3)[3:] num_hci_cmd_pkts, cmd_opcode, status = struct.unpack( '<BHB', event_params) event_params = { 'Num_HCI_Command_Packets': num_hci_cmd_pkts, 'Command_Opcode': cmd_opcode, 'Status': status } hci_close_dev(dd.fileno()) return event_params
def write_inquiry_mode(self, cmd_params={'Inquiry_Mode': 0x00}) -> dict: dd = hci_open_dev(self.devid) bin_cmd_params = cmd_params['Inquiry_Mode'].to_bytes(1, 'little') flt = hci_filter_new() hci_filter_set_ptype(flt, HCI_EVENT_PKT) hci_filter_set_event(flt, EVT_CMD_COMPLETE) hci_filter_set_opcode( flt, cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_INQUIRY_MODE)) dd.setsockopt(SOL_HCI, HCI_FILTER, flt) hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_INQUIRY_MODE, bin_cmd_params) event_params = dd.recv(3 + EVT_CMD_COMPLETE_SIZE + 1)[3:] num_hci_cmd_pkts, cmd_opcode, status = struct.unpack( '<BHB', event_params) event_params = { 'Num_HCI_Command_Packets': num_hci_cmd_pkts, 'Command_Opcode': cmd_opcode, 'Status': status } hci_close_dev(dd.fileno()) return event_params
def read_local_name(self) -> dict: dd = hci_open_dev(self.devid) flt = hci_filter_new() hci_filter_set_ptype(flt, HCI_EVENT_PKT) hci_filter_set_event(flt, EVT_CMD_COMPLETE) hci_filter_set_opcode( flt, cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_LOCAL_NAME)) dd.setsockopt(SOL_HCI, HCI_FILTER, flt) hci_send_cmd(dd, OGF_HOST_CTL, OCF_READ_LOCAL_NAME) event_params = dd.recv(3 + EVT_CMD_COMPLETE_SIZE + 249)[3:] num_hci_cmd_pkts, cmd_opcode, status, local_name = struct.unpack( '<BHB248s', event_params) event_params = { 'Num_HCI_Command_Packets': num_hci_cmd_pkts, 'Command_Opcode': cmd_opcode, 'Status': status, 'Local_Name': local_name.decode() } hci_close_dev(dd.fileno()) return event_params
def parse_le_advertising_events(sock, mac_addr=None, packet_length=None, handler=None, debug=False): """ Parse and report LE advertisements. This is a blocking call, an infinite loop is started and the given handler will be called each time a new LE advertisement packet is detected and corresponds to the given filters. .. note:: The :func:`.start_le_advertising` function must be called before calling this function. :param sock: A bluetooth HCI socket (retrieved using the ``hci_open_dev`` PyBluez function). :param mac_addr: list of filtered mac address representations (uppercase, with ':' separators). If not specified, the LE advertisement of any device will be reported. Example: mac_addr=('00:2A:5F:FF:25:11', 'DA:FF:12:33:66:12') :type mac_addr: ``list`` of ``string`` :param packet_length: Filter a specific length of LE advertisement packet. :type packet_length: ``int`` :param handler: Handler that will be called each time a LE advertisement packet is available (in accordance with the ``mac_addr`` and ``packet_length`` filters). :type handler: ``callable`` taking 4 parameters: mac (``str``), adv_type (``int``), data (``bytes``) and rssi (``int``) :param debug: Enable debug prints. :type debug: ``bool`` """ if not debug and handler is None: raise ValueError("You must either enable debug or give a handler !") old_filter = sock.getsockopt(bluez.SOL_HCI, bluez.HCI_FILTER, 14) flt = bluez.hci_filter_new() bluez.hci_filter_set_ptype(flt, bluez.HCI_EVENT_PKT) # bluez.hci_filter_all_events(flt) bluez.hci_filter_set_event(flt, LE_META_EVENT) sock.setsockopt(bluez.SOL_HCI, bluez.HCI_FILTER, flt) print("socket filter set to ptype=HCI_EVENT_PKT event=LE_META_EVENT") print("Listening ...") try: while True: pkt = full_pkt = sock.recv(255) ptype, event, plen = struct.unpack("BBB", pkt[:3]) if event != LE_META_EVENT: # Should never occur because we filtered with this type of event print("Not a LE_META_EVENT !") continue sub_event, = struct.unpack("B", pkt[3:4]) if sub_event != EVT_LE_ADVERTISING_REPORT: if debug: print("Not a EVT_LE_ADVERTISING_REPORT !") continue pkt = pkt[4:] adv_type = struct.unpack("b", pkt[1:2])[0] mac_addr_str = bluez.ba2str(pkt[3:9]) if packet_length and plen != packet_length: # ignore this packet if debug: print( "packet with non-matching length: mac=%s adv_type=%02x plen=%s" % (mac_addr_str, adv_type, plen)) print(raw_packet_to_str(pkt)) continue data = pkt[9:-1] rssi = struct.unpack("b", full_pkt[len(full_pkt) - 1:len(full_pkt)])[0] if mac_addr and mac_addr_str not in mac_addr: if debug: print( "packet with non-matching mac %s adv_type=%02x data=%s RSSI=%s" % (mac_addr_str, adv_type, raw_packet_to_str(data), rssi)) continue if debug: print( "LE advertisement: mac=%s adv_type=%02x data=%s RSSI=%d" % (mac_addr_str, adv_type, raw_packet_to_str(data), rssi)) if handler is not None: try: handler(mac_addr_str, adv_type, data, rssi) except Exception as e: print( 'Exception when calling handler with a BLE advertising event: %r' % (e, )) import traceback traceback.print_exc() except KeyboardInterrupt: print("\nRestore previous socket filter") sock.setsockopt(bluez.SOL_HCI, bluez.HCI_FILTER, old_filter) raise