def decode_services(payload): services = [] for u in decode_field(payload, _ADV_TYPE_UUID16_COMPLETE): services.append(UUID(unpack("<h", u)[0])) for u in decode_field(payload, _ADV_TYPE_UUID32_COMPLETE): services.append(UUID(unpack("<d", u)[0])) for u in decode_field(payload, _ADV_TYPE_UUID128_COMPLETE): services.append(UUID(u)) return services
def _create_expected_services(): battery_service_uuid = UUID(0x180F) battery_level_characteristic = ( UUID(0x2A19), FLAG_NOTIFY | FLAG_READ, ) battery_service = ( battery_service_uuid, (battery_level_characteristic, ), ) return (battery_service, )
def __init__(self, device_name="Generic HID Device"): self._ble = bluetooth.BLE() self.adv = None self.device_state = DEVICE_STOPPED self.conn_handle = None self.state_change_callback = None print("Server created") self.device_name = device_name self.service_uuids = [UUID(0x180A), UUID(0x180F), UUID(0x1812)] # Service UUIDs: DIS, BAS, HIDS self.device_appearance = 960 # Generic HID Appearance self.battery_level = 100 self.DIS = ( # Device Information Service description UUID(0x180A), # Device Information ( (UUID(0x2A50), F_READ), # PnP ID ), ) self.BAS = ( # Battery Service description UUID(0x180F), # Device Information ( (UUID(0x2A19), F_READ_NOTIFY), # Battery level ), ) self.services = [self.DIS, self.BAS] # List of service descriptions, append HIDS self.HID_INPUT_REPORT = None
def __init__(self, name=b'ble_uart', appearance=0, rxbuf=100, role=0, slave_mac=None): self.role = role UART_SERVICE = Service(UUID('6E400001-B5A3-F393-E0A9-E50E24DCCA9E')) UART_TX = Characteristic(UUID('6E400003-B5A3-F393-E0A9-E50E24DCCA9E'), properties='-n') UART_RX = Characteristic(UUID('6E400002-B5A3-F393-E0A9-E50E24DCCA9E'), properties='-w') self._rx_cb = None connected = False if self.role == 0: profile = Profile() profile.add_services( UART_SERVICE.add_characteristics(UART_TX, UART_RX)) self.ble = Peripheral(name=name, profile=profile, resp_services=profile.services_uuid, appearance=appearance) self._rx_handle, self._tx_handle = UART_RX.value_handle, UART_TX.value_handle self.ble.ble.gatts_set_buffer(self._rx_handle, rxbuf, True) self.ble.write_callback(self._uart_cb_s) self.ble.advertise(True) else: self.ble = Centeral() while not connected: self.profile = self.ble.connect( name=name) if slave_mac is None else self.ble.connect( addr=slave_mac) if self.profile: connected = True # discovery rx,tx value_handle for service in self.profile: if service.uuid == UART_SERVICE.uuid: for characteristics in service: if characteristics.uuid == UART_TX.uuid: self._rx_handle = characteristics.value_handle elif characteristics.uuid == UART_RX.uuid: self._tx_handle = characteristics.value_handle self.ble.notify_callback(self._uart_cb_m) self.rx_buffer = bytearray()
def __init__(self, ble, services=[UUID(0x1812)], appearance=const(960), name="Generic HID Device"): self._ble = ble self._payload = self.advertising_payload(name=name, services=services, appearance=appearance) self.advertising = False print("Advertiser created")
def start(self): super(Keyboard, self).start() # Start super print("Registering services") # Register services and get read/write handles for all services handles = self._ble.gatts_register_services(self.services) # Write the values for the characteristics self.write_service_characteristics(handles) # Create an Advertiser # Only advertise the top level service, i.e., the HIDS self.adv = Advertiser(self._ble, [UUID(0x1812)], self.device_appearance, self.device_name) print("Server started")
def _irq(self, event, data): if self._debug: print("Event: {}, Data: {}".format(event, data)) if event == IRQ.IRQ_SCAN_RESULT: addr_type, addr, adv_type, rssi, adv_data = data if self._conn_info is None: name = decode_name(adv_data) if name == self._name_param or addr == self._addr_param: if adv_type in (AdvType.ADV_IND, AdvType.ADV_DIRECT_IND,): self.ble.gap_scan(None) # Note: The addr buffer is owned by modbluetooth, need to copy it. self._conn_info = (addr_type, bytes(addr), name, adv_type, rssi) else: raise BLEError("{} BLE Device is unconnectable!" .format(name)) elif event == IRQ.IRQ_SCAN_DONE: # find device if self._conn_info is not None: self.ble.gap_connect(self._conn_info[0], self._conn_info[1]) else: print("BLE: Not found device!") self._conn_status = 0xff elif event == IRQ.IRQ_PERIPHERAL_CONNECT: print("BLE: connect successful!") # Connect successful. conn_handle, addr_type, addr, = data self.connected_handle = conn_handle self._conn_status = 0x01 self.ble.gattc_discover_services(self.connected_handle) elif event == IRQ.IRQ_PERIPHERAL_DISCONNECT: # # Disconnect (either initiated by us or the remote end). conn_handle, _, _, = data if conn_handle == self.connected_handle: # If it was initiated by us, it'll already be reset. print("BLE: disconnected!") self._reset() elif event == IRQ.IRQ_GATTC_SERVICE_RESULT: # Connected device returned a service. conn_handle, start_handle, end_handle, uuid = data if conn_handle == self.connected_handle: service = Service(UUID(uuid)) service.value_handle = (start_handle, end_handle) self.profile.add_services(service) elif event == IRQ.IRQ_GATTC_SERVICE_DONE: # Called once service discovery is complete. # Note: Status will be zero on success, implementation-specific value otherwise. conn_handle, status = data if conn_handle == self.connected_handle: if status == 0: self._conn_status = 0x02 else: print("BLE: dicscovery services error.") self.disconnect() elif event == IRQ.IRQ_GATTC_CHARACTERISTIC_RESULT: # Connected device returned a characteristic. conn_handle, def_handle, value_handle, properties, uuid = data if conn_handle == self.connected_handle: characteristic = Characteristic(UUID(uuid)) characteristic._properties(properties) characteristic.value_handle = value_handle self.profile[self._service_num].add_characteristics(characteristic) elif event == IRQ.IRQ_GATTC_CHARACTERISTIC_DONE: # Called once service discovery is complete. # Note: Status will be zero on success, implementation-specific value otherwise. conn_handle, status = data self._dicov_charact_done = True elif event == IRQ.IRQ_GATTC_READ_RESULT: # A read completed successfully. conn_handle, value_handle, char_data = data if conn_handle == self.connected_handle: self._READ_DONE = True self._read_buf = char_data elif event == IRQ.IRQ_GATTC_WRITE_DONE: # A gattc_write() has completed. conn_handle, value_handle, status = data # if conn_handle == self.connected_handle and status == 0: # self._WRITE_DONE = True # else: # self._WRITE_DONE = False elif event == IRQ.IRQ_GATTC_NOTIFY: conn_handle, value_handle, notify_data = data if conn_handle == self.connected_handle: if self._notify_cb: self._notify_cb(value_handle, notify_data)
def __init__(self, name=b'mpy_hid', battery_level=100): # Human Interface Device humman_interface_service = Service(UUID(0x1812)) hid_information = Characteristic(UUID(0x2A4A), properties='-r') hid_control_point = Characteristic(UUID(0x2A4C), properties='-r') self._report_map = Characteristic(UUID(0x2A4B), properties='-r') # Report input: Report Reference self._report_mouse_char = Characteristic(UUID(0x2A4D), properties='-rn') self._report_keyboard_char = Characteristic(UUID(0x2A4D), properties='-rn') self._report_consumer_char = Characteristic(UUID(0x2A4D), properties='-rn') self._report_mouse_char.add_descriptors( Descriptor(UUID(0x2908), properties='-r')) self._report_keyboard_char.add_descriptors( Descriptor(UUID(0x2908), properties='-r')) self._report_consumer_char.add_descriptors( Descriptor(UUID(0x2908), properties='-r')) humman_interface_service.add_characteristics( hid_information, hid_control_point, self._report_map, self._report_mouse_char, self._report_keyboard_char, self._report_consumer_char) # Battery Service battery_service = Service(UUID(0x180F)) battery_service.add_characteristics( Characteristic(UUID(0x2A19), properties='-rn')) # gatt profile self.profile = Profile() self.profile.add_services(humman_interface_service, battery_service) # Instantiation ble peripheral self.hid_device = Peripheral(profile=self.profile, name=name, appearance=const(960), adv_services=self.profile.services_uuid) self._debug = self.hid_device._debug # write battery level self.battery_level = battery_level self._init_value() self.hid_device.advertise(True) self._report_mouse_buf = bytearray(4) self._report_kb_buf = bytearray(8) self._report_kb_modifier = memoryview(self._report_kb_buf)[0:1] self._report_kb_keys = memoryview(self._report_kb_buf)[2:] self._report_consumer_buf = bytearray(2)
def _create_advertising_payload(): return advertising_payload(name='micropython-esp32', services=[UUID(0x180F)], appearance=BATTERY_SERVICE_APPEARANCE)
def _create_battery_service(): battery_service_uuid = UUID(0x180F) battery_level_characteristic = ( UUID(0x2A19), FLAG_NOTIFY | FLAG_READ,) # type org.bluetooth.characteristic.battery_level, uint8 0-100 return battery_service_uuid, (battery_level_characteristic,),
def _irq(event, data): if event in ( _IRQ_CENTRAL_CONNECT, _IRQ_CENTRAL_DISCONNECT ): # A central has connected to this peripheral. # A central has disconnected from this peripheral. conn_handle, addr_type, addr = data data = conn_handle, addr_type, bytes(addr) _callback(event, data) elif event == _IRQ_PERIPHERAL_DISCONNECT: # A central has disconnected from this peripheral or connect timeout if data == (65535, 255, b'\x00\x00\x00\x00\x00\x00'): # connect timeout _event(event, None, None) else: conn_handle, addr_type, addr = data data = conn_handle, addr_type, bytes(addr) _callback(event, data) elif event == _IRQ_GATTS_WRITE: # A central has written to this characteristic or descriptor. # conn_handle, attr_handle = data _callback(event, data) elif event in (_IRQ_GATTC_NOTIFY, _IRQ_GATTC_INDICATE): # A peripheral has sent a notify request. # A peripheral has sent an indicate request. conn_handle, value_handle, notify_data = data data = conn_handle, value_handle, bytes(notify_data) _callback(event, data) elif event == _IRQ_SCAN_RESULT: # A single scan result. addr_type, addr, adv_type, rssi, adv_data = data data = addr_type, bytes(addr), adv_type, rssi, bytes(adv_data) _event(event, data, None) elif event == _IRQ_SCAN_DONE: # A single scan result. _event(event, None, None) elif event == _IRQ_PERIPHERAL_CONNECT: # A successful gap_connect(). conn_handle, addr_type, addr = data key = addr_type, bytes(addr) _event(event, conn_handle, key) elif event == _IRQ_GATTC_SERVICE_RESULT: # Called for each service found by gattc_discover_services(). conn_handle, start_handle, end_handle, uuid = data data = start_handle, end_handle, UUID(uuid) _event(event, data, conn_handle) elif event == _IRQ_GATTC_SERVICE_DONE: # Called once service discovery is complete. # Note: Status will be zero on success, implementation-specific value otherwise. conn_handle, status = data _event(event, status, conn_handle) elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT: # Called for each characteristic found by gattc_discover_services(). conn_handle, def_handle, value_handle, properties, uuid = data data = def_handle, value_handle, properties, UUID(uuid) _event(event, data, conn_handle) elif event == _IRQ_GATTC_CHARACTERISTIC_DONE: # Called once service discovery is complete. # Note: Status will be zero on success, implementation-specific value otherwise. conn_handle, status = data _event(event, status, conn_handle) elif event == _IRQ_GATTC_DESCRIPTOR_RESULT: # Called for each descriptor found by gattc_discover_descriptors(). conn_handle, dsc_handle, uuid = data data = dsc_handle, UUID(uuid) _event(event, data, conn_handle) elif event == _IRQ_GATTC_DESCRIPTOR_DONE: # Called once service discovery is complete. # Note: Status will be zero on success, implementation-specific value otherwise. conn_handle, status = data _event(event, status, conn_handle) elif event == _IRQ_GATTC_READ_RESULT: # A gattc_read() has completed. conn_handle, value_handle, char_data = data key = conn_handle, value_handle _event(event, bytes(char_data), key) elif event == _IRQ_GATTC_READ_DONE: # A gattc_read() has completed. # Note: The value_handle will be zero on btstack (but present on NimBLE). # Note: Status will be zero on success, implementation-specific value otherwise. # conn_handle, value_handle, status = data # key = conn_handle, value_handle # data = status return # TODO elif event == _IRQ_GATTC_WRITE_DONE: # A gattc_write() has completed. # Note: The value_handle will be zero on btstack (but present on NimBLE). # Note: Status will be zero on success, implementation-specific value otherwise. conn_handle, value_handle, status = data key = conn_handle, value_handle _event(event, status, key) else: return
from micropython import const from ujson import loads, dumps from op import AUTH_ERR, TOKEN, result from uasyncio import create_task, sleep from consumer import Consumer from sec import Sec from hw import log, ENCRYPTED_OUTPUT, ENCRYPTED_INPUT _IRQ_CENTRAL_CONNECT = const(1) _IRQ_CENTRAL_DISCONNECT = const(2) _IRQ_GATTS_WRITE = const(3) _FLAG_WRITE = const(0x0008) _FLAG_NOTIFY = const(0x0010) _UART_UUID = UUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E") _UART_TX = ( UUID("6E400003-B5A3-F393-E0A9-E50E24DCCA9E"), _FLAG_NOTIFY, ) _UART_RX = ( UUID("6E400002-B5A3-F393-E0A9-E50E24DCCA9E"), _FLAG_WRITE, ) _UART_SERVICE = ( _UART_UUID, (_UART_TX, _UART_RX), ) # org.bluetooth.characteristic.gap.appearance.xml _ADV_APPEARANCE_GENERIC_COMPUTER = const(128)
def __init__(self, name="Bluetooth Keyboard"): super(Keyboard, self).__init__(name) # Set up the general HID services in super self.device_appearance = 961 # Device appearance ID, 961 = keyboard self.HIDS = ( # Service description: describes the service and how we communicate UUID(0x1812), # Human Interface Device ( (UUID(0x2A4A), F_READ), # HID information (UUID(0x2A4B), F_READ), # HID report map (UUID(0x2A4C), F_WRITE), # HID control point (UUID(0x2A4D), F_READ_NOTIFY, ((UUID(0x2908), ATT_F_READ), )), # HID report / reference (UUID(0x2A4D), F_READ_WRITE, ((UUID(0x2908), ATT_F_READ), )), # HID report / reference (UUID(0x2A4E), F_READ_WRITE), # HID protocol mode ), ) # fmt: off self.HID_INPUT_REPORT = bytes( [ # Report Description: describes what we communicate 0x05, 0x01, # USAGE_PAGE (Generic Desktop) 0x09, 0x06, # USAGE (Keyboard) 0xa1, 0x01, # COLLECTION (Application) 0x85, 0x01, # REPORT_ID (1) 0x75, 0x01, # Report Size (1) 0x95, 0x08, # Report Count (8) 0x05, 0x07, # Usage Page (Key Codes) 0x19, 0xE0, # Usage Minimum (224) 0x29, 0xE7, # Usage Maximum (231) 0x15, 0x00, # Logical Minimum (0) 0x25, 0x01, # Logical Maximum (1) 0x81, 0x02, # Input (Data, Variable, Absolute); Modifier byte 0x95, 0x01, # Report Count (1) 0x75, 0x08, # Report Size (8) 0x81, 0x01, # Input (Constant); Reserved byte 0x95, 0x05, # Report Count (5) 0x75, 0x01, # Report Size (1) 0x05, 0x08, # Usage Page (LEDs) 0x19, 0x01, # Usage Minimum (1) 0x29, 0x05, # Usage Maximum (5) 0x91, 0x02, # Output (Data, Variable, Absolute); LED report 0x95, 0x01, # Report Count (1) 0x75, 0x03, # Report Size (3) 0x91, 0x01, # Output (Constant); LED report padding 0x95, 0x06, # Report Count (6) 0x75, 0x08, # Report Size (8) 0x15, 0x00, # Logical Minimum (0) 0x25, 0x65, # Logical Maximum (101) 0x05, 0x07, # Usage Page (Key Codes) 0x19, 0x00, # Usage Minimum (0) 0x29, 0x65, # Usage Maximum (101) 0x81, 0x00, # Input (Data, Array); Key array (6 bytes) 0xc0 # END_COLLECTION ]) # fmt: on # Define the initial keyboard state self.modifiers = 0 # 8 bits signifying Right GUI(Win/Command), Right ALT/Option, Right Shift, Right Control, Left GUI, Left ALT, Left Shift, Left Control self.keys = [0x00] * 6 # 6 keys to hold # Callback function for keyboard messages from central self.kb_callback = None self.services = [self.DIS, self.BAS, self.HIDS] # List of service descriptions
def __init__(self, name="Bluetooth Mouse"): super(Mouse, self).__init__(name) # Set up the general HID services in super self.device_appearance = 962 # Device appearance ID, 962 = mouse self.HIDS = ( # Service description: describes the service and how we communicate UUID(0x1812), # Human Interface Device ( (UUID(0x2A4A), F_READ), # HID information (UUID(0x2A4B), F_READ), # HID report map (UUID(0x2A4C), F_WRITE), # HID control point (UUID(0x2A4D), F_READ_NOTIFY, ((UUID(0x2908), ATT_F_READ), )), # HID report / reference (UUID(0x2A4E), F_READ_WRITE), # HID protocol mode ), ) # fmt: off self.HID_INPUT_REPORT = bytes( [ # Report Description: describes what we communicate 0x05, 0x01, # USAGE_PAGE (Generic Desktop) 0x09, 0x02, # USAGE (Mouse) 0xa1, 0x01, # COLLECTION (Application) 0x85, 0x01, # REPORT_ID (1) 0x09, 0x01, # USAGE (Pointer) 0xa1, 0x00, # COLLECTION (Physical) 0x05, 0x09, # Usage Page (Buttons) 0x19, 0x01, # Usage Minimum (1) 0x29, 0x03, # Usage Maximum (3) 0x15, 0x00, # Logical Minimum (0) 0x25, 0x01, # Logical Maximum (1) 0x95, 0x03, # Report Count (3) 0x75, 0x01, # Report Size (1) 0x81, 0x02, # Input(Data, Variable, Absolute); 3 button bits 0x95, 0x01, # Report Count(1) 0x75, 0x05, # Report Size(5) 0x81, 0x03, # Input(Constant); 5 bit padding 0x05, 0x01, # Usage Page (Generic Desktop) 0x09, 0x30, # Usage (X) 0x09, 0x31, # Usage (Y) 0x09, 0x38, # Usage (Wheel) 0x15, 0x81, # Logical Minimum (-127) 0x25, 0x7F, # Logical Maximum (127) 0x75, 0x08, # Report Size (8) 0x95, 0x03, # Report Count (3) 0x81, 0x06, # Input(Data, Variable, Relative); 3 position bytes (X,Y,Wheel) 0xc0, # END_COLLECTION 0xc0 # END_COLLECTION ]) # fmt: on # Define the initial mouse state self.x = 0 self.y = 0 self.w = 0 self.button1 = 0 self.button2 = 0 self.button3 = 0 self.services = [self.DIS, self.BAS, self.HIDS] # List of service descriptions
def __init__(self, name="Bluetooth Joystick"): super(Joystick, self).__init__(name) # Set up the general HID services in super self.device_appearance = 963 # Device appearance ID, 963 = joystick self.HIDS = ( # Service description: describes the service and how we communicate UUID(0x1812), # Human Interface Device ( (UUID(0x2A4A), F_READ), # HID information (UUID(0x2A4B), F_READ), # HID report map (UUID(0x2A4C), F_WRITE), # HID control point (UUID(0x2A4D), F_READ_NOTIFY, ((UUID(0x2908), ATT_F_READ), )), # HID report / reference (UUID(0x2A4E), F_READ_WRITE), # HID protocol mode ), ) # fmt: off self.HID_INPUT_REPORT = bytes( [ # Report Description: describes what we communicate 0x05, 0x01, # USAGE_PAGE (Generic Desktop) 0x09, 0x04, # USAGE (Joystick) 0xa1, 0x01, # COLLECTION (Application) 0x85, 0x01, # REPORT_ID (1) 0xa1, 0x00, # COLLECTION (Physical) 0x09, 0x30, # USAGE (X) 0x09, 0x31, # USAGE (Y) 0x15, 0x81, # LOGICAL_MINIMUM (-127) 0x25, 0x7f, # LOGICAL_MAXIMUM (127) 0x75, 0x08, # REPORT_SIZE (8) 0x95, 0x02, # REPORT_COUNT (2) 0x81, 0x02, # INPUT (Data,Var,Abs) 0x05, 0x09, # USAGE_PAGE (Button) 0x29, 0x08, # USAGE_MAXIMUM (Button 8) 0x19, 0x01, # USAGE_MINIMUM (Button 1) 0x95, 0x08, # REPORT_COUNT (8) 0x75, 0x01, # REPORT_SIZE (1) 0x25, 0x01, # LOGICAL_MAXIMUM (1) 0x15, 0x00, # LOGICAL_MINIMUM (0) 0x81, 0x02, # Input (Data, Variable, Absolute) 0xc0, # END_COLLECTION 0xc0 # END_COLLECTION ]) # fmt: on # Define the initial joystick state self.x = 0 self.y = 0 self.button1 = 0 self.button2 = 0 self.button3 = 0 self.button4 = 0 self.button5 = 0 self.button6 = 0 self.button7 = 0 self.button8 = 0 self.services = [self.DIS, self.BAS, self.HIDS] # List of service descriptions
def __init__(self, device_name="Generic HID Device"): self._ble = bluetooth.BLE() self.adv = None self.device_state = HumanInterfaceDevice.DEVICE_STOPPED self.conn_handle = None self.state_change_callback = None print("Server created") self.device_name = device_name self.service_uuids = [UUID(0x180A), UUID(0x180F), UUID(0x1812)] # Service UUIDs: DIS, BAS, HIDS self.device_appearance = 960 # Generic HID Appearance self.battery_level = 100 self.model_number = "1" self.serial_number = "1" self.firmware_revision = "1" self.hardware_revision = "1" self.software_revision = "1" self.manufacture_name = "Homebrew" self.pnp_manufacturer_source = 0x01 # Bluetooth uuid list self.pnp_manufacturer_uuid = 0xFE61 # 0xFEB2 for Microsoft, 0xFE61 for Logitech, 0xFD65 for Razer self.pnp_product_id = 0x01 # ID 1 self.pnp_product_version = 0x0123 # Version 1.2.3 self.DIS = ( # Device Information Service description UUID(0x180A), # Device Information ( (UUID(0x2A24), F_READ), # Model number string (UUID(0x2A25), F_READ), # Serial number string (UUID(0x2A26), F_READ), # Firmware revision string (UUID(0x2A27), F_READ), # Hardware revision string (UUID(0x2A28), F_READ), # Software revision string (UUID(0x2A29), F_READ), # Manufacturer name string (UUID(0x2A50), F_READ), # PnP ID ), ) self.BAS = ( # Battery Service description UUID(0x180F), # Device Information ( (UUID(0x2A19), F_READ_NOTIFY), # Battery level ), ) self.services = [self.DIS, self.BAS] # List of service descriptions, append HIDS self.HID_INPUT_REPORT = None