From 759929c24a9966b64075bedfb365f3dfc66ad681 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 25 Jun 2020 20:57:17 -0400 Subject: hci early wip; refactor supervisor bluetooth.c for nrf: tested --- py/circuitpy_defns.mk | 10 +++++++++- py/circuitpy_mpconfig.mk | 4 ++++ py/mkrules.mk | 5 ++--- 3 files changed, 15 insertions(+), 4 deletions(-) (limited to 'py') diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 74d8f548d..811de7866 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -411,7 +411,7 @@ SRC_SHARED_MODULE_ALL = \ SRC_SHARED_MODULE = $(filter $(SRC_PATTERNS), $(SRC_SHARED_MODULE_ALL)) # Use the native touchio if requested. This flag is set conditionally in, say, mpconfigport.h. -# The presence of common-hal/touchio/* # does not imply it's available for all chips in a port, +# The presence of common-hal/touchio/* does not imply it's available for all chips in a port, # so there is an explicit flag. For example, SAMD21 touchio is native, but SAMD51 is not. ifeq ($(CIRCUITPY_TOUCHIO_USE_NATIVE),1) SRC_COMMON_HAL_ALL += \ @@ -422,6 +422,14 @@ SRC_SHARED_MODULE_ALL += \ touchio/TouchIn.c \ touchio/__init__.c endif + +# If supporting _bleio via HCI, make devices/ble_hci/common-hal/_bleio be includable, +# and use C source files in devices/ble_hci/common-hal. +ifeq ($(CIRCUITPY_BLEIO_HCI),1) +INC += -I$(TOP)/devices/ble_hci +DEVICES_MODULES += $(TOP)/devices/ble_hci +endif + ifeq ($(CIRCUITPY_AUDIOMP3),1) SRC_MOD += $(addprefix lib/mp3/src/, \ bitstream.c \ diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 3459bff6d..239bb665e 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -79,6 +79,10 @@ CFLAGS += -DCIRCUITPY_BITBANGIO=$(CIRCUITPY_BITBANGIO) CIRCUITPY_BLEIO ?= 0 CFLAGS += -DCIRCUITPY_BLEIO=$(CIRCUITPY_BLEIO) +# _bleio can be supported on most any board via HCI +CIRCUITPY_BLEIO_HCI ?= 0 +CFLAGS += -DCIRCUITPY_BLEIO_HCI=$(CIRCUITPY_BLEIO_HCI) + CIRCUITPY_BOARD ?= 1 CFLAGS += -DCIRCUITPY_BOARD=$(CIRCUITPY_BOARD) diff --git a/py/mkrules.mk b/py/mkrules.mk index 13a73b90e..0b3ecc0e1 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -42,7 +42,7 @@ $(Q)$(CC) $(CFLAGS) -c -MD -o $@ $< $(RM) -f $(@:.o=.d) endef -vpath %.c . $(TOP) $(USER_C_MODULES) +vpath %.c . $(TOP) $(USER_C_MODULES) $(DEVICES_MODULES) $(BUILD)/%.o: %.c $(call compile_c) @@ -56,8 +56,7 @@ $(BUILD)/%.o: %.c QSTR_GEN_EXTRA_CFLAGS += -I$(BUILD)/tmp -vpath %.c . $(TOP) $(USER_C_MODULES) - +vpath %.c . $(TOP) $(USER_C_MODULES) $(DEVICES_MODULES) $(BUILD)/%.pp: %.c $(STEPECHO) "PreProcess $<" $(Q)$(CC) $(CFLAGS) -E -Wp,-C,-dD,-dI -o $@ $< -- cgit v1.2.3 From 1bc2e979eb9ca2f3cb0eed396cc35406eceea27a Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 26 Jun 2020 17:23:20 -0400 Subject: wip; compiles; much commented out --- devices/ble_hci/common-hal/_bleio/Adapter.c | 272 ++--- devices/ble_hci/common-hal/_bleio/Adapter.h | 14 +- devices/ble_hci/common-hal/_bleio/Attribute.c | 62 +- devices/ble_hci/common-hal/_bleio/Attribute.h | 9 +- devices/ble_hci/common-hal/_bleio/Characteristic.c | 255 ++-- .../common-hal/_bleio/CharacteristicBuffer.c | 98 +- devices/ble_hci/common-hal/_bleio/Connection.c | 1247 ++++++++++---------- devices/ble_hci/common-hal/_bleio/Connection.h | 1 - devices/ble_hci/common-hal/_bleio/PacketBuffer.c | 359 +++--- devices/ble_hci/common-hal/_bleio/Service.c | 136 +-- devices/ble_hci/common-hal/_bleio/UUID.c | 32 +- devices/ble_hci/common-hal/_bleio/UUID.h | 2 +- devices/ble_hci/common-hal/_bleio/__init__.c | 294 ++--- devices/ble_hci/common-hal/_bleio/__init__.h | 9 + devices/ble_hci/common-hal/_bleio/bonding.c | 306 ----- devices/ble_hci/common-hal/_bleio/bonding.h | 83 -- py/circuitpy_defns.mk | 12 + shared-bindings/_bleio/Adapter.c | 22 +- shared-bindings/_bleio/Adapter.h | 4 + 19 files changed, 1441 insertions(+), 1776 deletions(-) delete mode 100644 devices/ble_hci/common-hal/_bleio/bonding.c delete mode 100644 devices/ble_hci/common-hal/_bleio/bonding.h (limited to 'py') diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index 7e1bfe992..adfd12845 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.c +++ b/devices/ble_hci/common-hal/_bleio/Adapter.c @@ -31,9 +31,8 @@ #include #include -#include "bonding.h" - #include "py/gc.h" +#include "py/mphal.h" #include "py/objstr.h" #include "py/runtime.h" #include "supervisor/shared/safe_mode.h" @@ -74,111 +73,111 @@ bleio_connection_internal_t bleio_connections[BLEIO_TOTAL_CONNECTION_COUNT]; -STATIC bool adapter_on_ble_evt(ble_evt_t *ble_evt, void *self_in) { - // bleio_adapter_obj_t *self = (bleio_adapter_obj_t*)self_in; - - // // For debugging. - // // mp_printf(&mp_plat_print, "Adapter event: 0x%04x\n", ble_evt->header.evt_id); - - // switch (ble_evt->header.evt_id) { - // case BLE_GAP_EVT_CONNECTED: { - // // Find an empty connection. One must always be available because the SD has the same - // // total connection limit. - // bleio_connection_internal_t *connection; - // for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { - // connection = &bleio_connections[i]; - // if (connection->conn_handle == BLE_CONN_HANDLE_INVALID) { - // break; - // } - // } - - // // Central has connected. - // ble_gap_evt_connected_t* connected = &ble_evt->evt.gap_evt.params.connected; - - // connection->conn_handle = ble_evt->evt.gap_evt.conn_handle; - // connection->connection_obj = mp_const_none; - // connection->pair_status = PAIR_NOT_PAIRED; - // connection->mtu = 0; - - // ble_drv_add_event_handler_entry(&connection->handler_entry, connection_on_ble_evt, connection); - // self->connection_objs = NULL; - - // // Save the current connection parameters. - // memcpy(&connection->conn_params, &connected->conn_params, sizeof(ble_gap_conn_params_t)); - - // #if CIRCUITPY_VERBOSE_BLE - // ble_gap_conn_params_t *cp = &connected->conn_params; - // mp_printf(&mp_plat_print, "conn params: min_ci %d max_ci %d s_l %d sup_timeout %d\n", cp->min_conn_interval, cp->max_conn_interval, cp->slave_latency, cp->conn_sup_timeout); - // #endif - - // // See if connection interval set by Central is out of range. - // // If so, negotiate our preferred range. - // ble_gap_conn_params_t conn_params; - // sd_ble_gap_ppcp_get(&conn_params); - // if (conn_params.min_conn_interval < connected->conn_params.min_conn_interval || - // conn_params.min_conn_interval > connected->conn_params.max_conn_interval) { - // sd_ble_gap_conn_param_update(ble_evt->evt.gap_evt.conn_handle, &conn_params); - // } - // self->current_advertising_data = NULL; - // break; - // } - // case BLE_GAP_EVT_DISCONNECTED: { - // // Find the connection that was disconnected. - // bleio_connection_internal_t *connection; - // for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { - // connection = &bleio_connections[i]; - // if (connection->conn_handle == ble_evt->evt.gap_evt.conn_handle) { - // break; - // } - // } - // ble_drv_remove_event_handler(connection_on_ble_evt, connection); - // connection->conn_handle = BLE_CONN_HANDLE_INVALID; - // connection->pair_status = PAIR_NOT_PAIRED; - // if (connection->connection_obj != mp_const_none) { - // bleio_connection_obj_t* obj = connection->connection_obj; - // obj->connection = NULL; - // obj->disconnect_reason = ble_evt->evt.gap_evt.params.disconnected.reason; - // } - // self->connection_objs = NULL; - - // break; - // } +// STATIC bool adapter_on_ble_evt(ble_evt_t *ble_evt, void *self_in) { +// bleio_adapter_obj_t *self = (bleio_adapter_obj_t*)self_in; - // case BLE_GAP_EVT_ADV_SET_TERMINATED: - // self->current_advertising_data = NULL; - // break; +// // For debugging. +// // mp_printf(&mp_plat_print, "Adapter event: 0x%04x\n", ble_evt->header.evt_id); - // default: - // // For debugging. - // // mp_printf(&mp_plat_print, "Unhandled adapter event: 0x%04x\n", ble_evt->header.evt_id); - // return false; - // break; - // } - return true; -} +// switch (ble_evt->header.evt_id) { +// case BLE_GAP_EVT_CONNECTED: { +// // Find an empty connection. One must always be available because the SD has the same +// // total connection limit. +// bleio_connection_internal_t *connection; +// for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { +// connection = &bleio_connections[i]; +// if (connection->conn_handle == BLE_CONN_HANDLE_INVALID) { +// break; +// } +// } + +// // Central has connected. +// ble_gap_evt_connected_t* connected = &ble_evt->evt.gap_evt.params.connected; + +// connection->conn_handle = ble_evt->evt.gap_evt.conn_handle; +// connection->connection_obj = mp_const_none; +// connection->pair_status = PAIR_NOT_PAIRED; +// connection->mtu = 0; + +// ble_drv_add_event_handler_entry(&connection->handler_entry, connection_on_ble_evt, connection); +// self->connection_objs = NULL; + +// // Save the current connection parameters. +// memcpy(&connection->conn_params, &connected->conn_params, sizeof(ble_gap_conn_params_t)); + +// #if CIRCUITPY_VERBOSE_BLE +// ble_gap_conn_params_t *cp = &connected->conn_params; +// mp_printf(&mp_plat_print, "conn params: min_ci %d max_ci %d s_l %d sup_timeout %d\n", cp->min_conn_interval, cp->max_conn_interval, cp->slave_latency, cp->conn_sup_timeout); +// #endif + +// // See if connection interval set by Central is out of range. +// // If so, negotiate our preferred range. +// ble_gap_conn_params_t conn_params; +// sd_ble_gap_ppcp_get(&conn_params); +// if (conn_params.min_conn_interval < connected->conn_params.min_conn_interval || +// conn_params.min_conn_interval > connected->conn_params.max_conn_interval) { +// sd_ble_gap_conn_param_update(ble_evt->evt.gap_evt.conn_handle, &conn_params); +// } +// self->current_advertising_data = NULL; +// break; +// } +// case BLE_GAP_EVT_DISCONNECTED: { +// // Find the connection that was disconnected. +// bleio_connection_internal_t *connection; +// for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { +// connection = &bleio_connections[i]; +// if (connection->conn_handle == ble_evt->evt.gap_evt.conn_handle) { +// break; +// } +// } +// ble_drv_remove_event_handler(connection_on_ble_evt, connection); +// connection->conn_handle = BLE_CONN_HANDLE_INVALID; +// connection->pair_status = PAIR_NOT_PAIRED; +// if (connection->connection_obj != mp_const_none) { +// bleio_connection_obj_t* obj = connection->connection_obj; +// obj->connection = NULL; +// obj->disconnect_reason = ble_evt->evt.gap_evt.params.disconnected.reason; +// } +// self->connection_objs = NULL; + +// break; +// } + +// case BLE_GAP_EVT_ADV_SET_TERMINATED: +// self->current_advertising_data = NULL; +// break; + +// default: +// // For debugging. +// // mp_printf(&mp_plat_print, "Unhandled adapter event: 0x%04x\n", ble_evt->header.evt_id); +// return false; +// break; +// } +// return true; +// } -STATIC void get_address(bleio_adapter_obj_t *self, ble_gap_addr_t *address) { +// STATIC void get_address(bleio_adapter_obj_t *self, ble_gap_addr_t *address) { // check_nrf_error(sd_ble_gap_addr_get(address)); -} +// } char default_ble_name[] = { 'C', 'I', 'R', 'C', 'U', 'I', 'T', 'P', 'Y', 0, 0, 0, 0 , 0}; -STATIC void bleio_adapter_reset_name(bleio_adapter_obj_t *self) { - uint8_t len = sizeof(default_ble_name) - 1; +// STATIC void bleio_adapter_reset_name(bleio_adapter_obj_t *self) { +// // uint8_t len = sizeof(default_ble_name) - 1; - ble_gap_addr_t local_address; - get_address(self, &local_address); +// // ble_gap_addr_t local_address; +// // get_address(self, &local_address); - default_ble_name[len - 4] = nibble_to_hex_lower[local_address.addr[1] >> 4 & 0xf]; - default_ble_name[len - 3] = nibble_to_hex_lower[local_address.addr[1] & 0xf]; - default_ble_name[len - 2] = nibble_to_hex_lower[local_address.addr[0] >> 4 & 0xf]; - default_ble_name[len - 1] = nibble_to_hex_lower[local_address.addr[0] & 0xf]; - default_ble_name[len] = '\0'; // for now we add null for compatibility with C ASCIIZ strings +// // default_ble_name[len - 4] = nibble_to_hex_lower[local_address.addr[1] >> 4 & 0xf]; +// // default_ble_name[len - 3] = nibble_to_hex_lower[local_address.addr[1] & 0xf]; +// // default_ble_name[len - 2] = nibble_to_hex_lower[local_address.addr[0] >> 4 & 0xf]; +// // default_ble_name[len - 1] = nibble_to_hex_lower[local_address.addr[0] & 0xf]; +// // default_ble_name[len] = '\0'; // for now we add null for compatibility with C ASCIIZ strings - common_hal_bleio_adapter_set_name(self, (char*) default_ble_name); -} +// common_hal_bleio_adapter_set_name(self, (char*) default_ble_name); +// } -void common_hal_bleio_adapter_construct(bleio_adapter_obj_t *self, mcu_pin_obj_t *tx, mcu_pin_obj_t *rx, mcu_pin_obj_t *rts, mcu_pin_obj_t *cts, uint32_t baudrate, uint32_t buffer_size, mcu_pin_obj_t* spi_cs, mcu_pin_obj_t* gpio0, mcu_pin_obj_t *reset, bool reset_high) { +void common_hal_bleio_adapter_construct(bleio_adapter_obj_t *self, const mcu_pin_obj_t *tx, const mcu_pin_obj_t *rx, const mcu_pin_obj_t *rts, const mcu_pin_obj_t *cts, uint32_t baudrate, uint32_t buffer_size, const mcu_pin_obj_t* spi_cs, const mcu_pin_obj_t* gpio0, const mcu_pin_obj_t *reset, bool reset_high) { self->tx = tx; self->rx = rx; self->rts = rts; @@ -206,9 +205,9 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable // common_hal UART takes rts and cts, but is currently not implemented for many ports. // In addition, rts and cts may be pins that are not part of the serial peripheral // used for tx and rx, so use GPIO for them. - common_hal_busio_uart_construct(&self->hci_uart, tx, rx, NULL, NULL, NULL, false, - BLEIO_HCI_BAUDRATE, 8, PARITY_NONE, 1, 0.0f, - BLEIO_HCI_BUFFER_SIZE, NULL, false); + common_hal_busio_uart_construct(&self->hci_uart, self->tx, self->rx, NULL, NULL, NULL, false, + self->baudrate, 8, PARITY_NONE, 1, 0.0f, + self->buffer_size, NULL, false); // RTS is output, active high common_hal_digitalio_digitalinout_construct(&self->rts_digitalio, self->rts); @@ -220,9 +219,9 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable // SPI_CS and GPI0 are used to signal entering BLE mode. // SPI_CS should be low, and GPI0 should be high common_hal_digitalio_digitalinout_construct(&self->spi_cs_digitalio, self->spi_cs); - common_hal_digitalio_digitalinout_construct(&self->gpio0_digitalio, self->gpi0); + common_hal_digitalio_digitalinout_construct(&self->gpio0_digitalio, self->gpio0); common_hal_digitalio_digitalinout_switch_to_output(&self->spi_cs_digitalio, false, DRIVE_MODE_PUSH_PULL); - common_hal_digitalio_digitalinout_switch_to_output(&self->gpio0_digitalio, true DRIVE_MODE_PUSH_PULL); + common_hal_digitalio_digitalinout_switch_to_output(&self->gpio0_digitalio, true, DRIVE_MODE_PUSH_PULL); // RESET is output, start in non-reset state. common_hal_digitalio_digitalinout_construct(&self->reset_digitalio, self->reset); @@ -252,7 +251,7 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable common_hal_digitalio_digitalinout_deinit(&self->rts_digitalio); common_hal_digitalio_digitalinout_deinit(&self->cts_digitalio); common_hal_digitalio_digitalinout_deinit(&self->spi_cs_digitalio); - common_hal_digitalio_digitalinout_deinit(&self->gpi0_digitalio); + common_hal_digitalio_digitalinout_deinit(&self->gpio0_digitalio); common_hal_digitalio_digitalinout_deinit(&self->reset_digitalio); } @@ -263,13 +262,13 @@ bool common_hal_bleio_adapter_get_enabled(bleio_adapter_obj_t *self) { bleio_address_obj_t *common_hal_bleio_adapter_get_address(bleio_adapter_obj_t *self) { common_hal_bleio_adapter_set_enabled(self, true); - ble_gap_addr_t local_address; - get_address(self, &local_address); + // ble_gap_addr_t local_address; + // get_address(self, &local_address); bleio_address_obj_t *address = m_new_obj(bleio_address_obj_t); address->base.type = &bleio_address_type; - common_hal_bleio_address_construct(address, local_address.addr, local_address.addr_type); + // common_hal_bleio_address_construct(address, local_address.addr, local_address.addr_type); return address; } @@ -460,12 +459,12 @@ mp_obj_t common_hal_bleio_adapter_connect(bleio_adapter_obj_t *self, bleio_addre // sd_ble_gap_data_length_update(conn_handle, NULL, NULL); // Make the connection object and return it. - for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { - bleio_connection_internal_t *connection = &bleio_connections[i]; - if (connection->conn_handle == conn_handle) { - return bleio_connection_new_from_internal(connection); - } - } + // for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + // bleio_connection_internal_t *connection = &bleio_connections[i]; + // if (connection->conn_handle == conn_handle) { + // return bleio_connection_new_from_internal(connection); + // } + // } mp_raise_bleio_BluetoothError(translate("Failed to connect: internal error")); @@ -473,13 +472,13 @@ mp_obj_t common_hal_bleio_adapter_connect(bleio_adapter_obj_t *self, bleio_addre } // The nRF SD 6.1.0 can only do one concurrent advertisement so share the advertising handle. -uint8_t adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET; +//FIX uint8_t adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET; STATIC void check_data_fit(size_t data_len, bool connectable) { - if (data_len > BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_MAX_SUPPORTED || - (connectable && data_len > BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_CONNECTABLE_MAX_SUPPORTED)) { - mp_raise_ValueError(translate("Data too large for advertisement packet")); - } + //FIX if (data_len > BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_MAX_SUPPORTED || + // (connectable && data_len > BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_CONNECTABLE_MAX_SUPPORTED)) { + // mp_raise_ValueError(translate("Data too large for advertisement packet")); + // } } // STATIC bool advertising_on_ble_evt(ble_evt_t *ble_evt, void *self_in) { @@ -607,30 +606,31 @@ void common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, bool // the same data while cycling the MAC address -- otherwise, what's the // point of randomizing the MAC address? if (!timeout) { - if (anonymous) { - // The Nordic macro is in units of 10ms. Convert to seconds. - uint32_t adv_timeout_max_secs = UNITS_TO_SEC(BLE_GAP_ADV_TIMEOUT_LIMITED_MAX, UNIT_10_MS); - uint32_t rotate_timeout_max_secs = BLE_GAP_DEFAULT_PRIVATE_ADDR_CYCLE_INTERVAL_S; - timeout = MIN(adv_timeout_max_secs, rotate_timeout_max_secs); - } - else { - timeout = BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED; - } + //FIX if (anonymous) { + // // The Nordic macro is in units of 10ms. Convert to seconds. + // uint32_t adv_timeout_max_secs = UNITS_TO_SEC(BLE_GAP_ADV_TIMEOUT_LIMITED_MAX, UNIT_10_MS); + // uint32_t rotate_timeout_max_secs = BLE_GAP_DEFAULT_PRIVATE_ADDR_CYCLE_INTERVAL_S; + // timeout = MIN(adv_timeout_max_secs, rotate_timeout_max_secs); + // } + // else { + // timeout = BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED; + // } } else { - if (SEC_TO_UNITS(timeout, UNIT_10_MS) > BLE_GAP_ADV_TIMEOUT_LIMITED_MAX) { - mp_raise_bleio_BluetoothError(translate("Timeout is too long: Maximum timeout length is %d seconds"), - UNITS_TO_SEC(BLE_GAP_ADV_TIMEOUT_LIMITED_MAX, UNIT_10_MS)); - } + //FIX if (SEC_TO_UNITS(timeout, UNIT_10_MS) > BLE_GAP_ADV_TIMEOUT_LIMITED_MAX) { + // mp_raise_bleio_BluetoothError(translate("Timeout is too long: Maximum timeout length is %d seconds"), + // UNITS_TO_SEC(BLE_GAP_ADV_TIMEOUT_LIMITED_MAX, UNIT_10_MS)); + // } } // The advertising data buffers must not move, because the SoftDevice depends on them. // So make them long-lived and reuse them onwards. - if (self->advertising_data == NULL) { - self->advertising_data = (uint8_t *) gc_alloc(BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_MAX_SUPPORTED * sizeof(uint8_t), false, true); - } - if (self->scan_response_data == NULL) { - self->scan_response_data = (uint8_t *) gc_alloc(BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_MAX_SUPPORTED * sizeof(uint8_t), false, true); - } + //FIX GET CORRECT SIZE + // if (self->advertising_data == NULL) { + // self->advertising_data = (uint8_t *) gc_alloc(BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_MAX_SUPPORTED * sizeof(uint8_t), false, true); + // } + // if (self->scan_response_data == NULL) { + // self->scan_response_data = (uint8_t *) gc_alloc(BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_MAX_SUPPORTED * sizeof(uint8_t), false, true); + // } memcpy(self->advertising_data, advertising_data_bufinfo->buf, advertising_data_bufinfo->len); memcpy(self->scan_response_data, scan_response_data_bufinfo->buf, scan_response_data_bufinfo->len); @@ -690,7 +690,7 @@ mp_obj_t common_hal_bleio_adapter_get_connections(bleio_adapter_obj_t *self) { } void common_hal_bleio_adapter_erase_bonding(bleio_adapter_obj_t *self) { - bonding_erase_storage(); + //FIX bonding_erase_storage(); } void bleio_adapter_gc_collect(bleio_adapter_obj_t* adapter) { diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.h b/devices/ble_hci/common-hal/_bleio/Adapter.h index 9d4d5abf8..f045f920f 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.h +++ b/devices/ble_hci/common-hal/_bleio/Adapter.h @@ -52,15 +52,15 @@ typedef struct { bleio_scanresults_obj_t* scan_results; mp_obj_t name; mp_obj_tuple_t *connection_objs; - mcu_pin_obj_t* tx; - mcu_pin_obj_t* rx; - mcu_pin_obj_t* rts; - mcu_pin_obj_t* cts; + const mcu_pin_obj_t* tx; + const mcu_pin_obj_t* rx; + const mcu_pin_obj_t* rts; + const mcu_pin_obj_t* cts; uint32_t baudrate; uint16_t buffer_size; - mcu_pin_obj_t* spi_cs; - mcu_pin_obj_t* gpio0; - mcu_pin_obj_t* reset; + const mcu_pin_obj_t* spi_cs; + const mcu_pin_obj_t* gpio0; + const mcu_pin_obj_t* reset; bool reset_high; busio_uart_obj_t hci_uart; digitalio_digitalinout_obj_t rts_digitalio; diff --git a/devices/ble_hci/common-hal/_bleio/Attribute.c b/devices/ble_hci/common-hal/_bleio/Attribute.c index c55914b10..30a0ebcf0 100644 --- a/devices/ble_hci/common-hal/_bleio/Attribute.c +++ b/devices/ble_hci/common-hal/_bleio/Attribute.c @@ -27,34 +27,34 @@ #include "shared-bindings/_bleio/Attribute.h" // Convert a _bleio security mode to a ble_gap_conn_sec_mode_t setting. -void bleio_attribute_gatts_set_security_mode(ble_gap_conn_sec_mode_t *perm, bleio_attribute_security_mode_t security_mode) { - switch (security_mode) { - case SECURITY_MODE_NO_ACCESS: - BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(perm); - break; - - case SECURITY_MODE_OPEN: - BLE_GAP_CONN_SEC_MODE_SET_OPEN(perm); - break; - - case SECURITY_MODE_ENC_NO_MITM: - BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(perm); - break; - - case SECURITY_MODE_ENC_WITH_MITM: - BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(perm); - break; - - case SECURITY_MODE_LESC_ENC_WITH_MITM: - BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(perm); - break; - - case SECURITY_MODE_SIGNED_NO_MITM: - BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(perm); - break; - - case SECURITY_MODE_SIGNED_WITH_MITM: - BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(perm); - break; - } -} +// void bleio_attribute_gatts_set_security_mode(ble_gap_conn_sec_mode_t *perm, bleio_attribute_security_mode_t security_mode) { +// switch (security_mode) { +// case SECURITY_MODE_NO_ACCESS: +// BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(perm); +// break; + +// case SECURITY_MODE_OPEN: +// BLE_GAP_CONN_SEC_MODE_SET_OPEN(perm); +// break; + +// case SECURITY_MODE_ENC_NO_MITM: +// BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(perm); +// break; + +// case SECURITY_MODE_ENC_WITH_MITM: +// BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(perm); +// break; + +// case SECURITY_MODE_LESC_ENC_WITH_MITM: +// BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(perm); +// break; + +// case SECURITY_MODE_SIGNED_NO_MITM: +// BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(perm); +// break; + +// case SECURITY_MODE_SIGNED_WITH_MITM: +// BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(perm); +// break; +// } +// } diff --git a/devices/ble_hci/common-hal/_bleio/Attribute.h b/devices/ble_hci/common-hal/_bleio/Attribute.h index cd9c86ca3..f527bcf74 100644 --- a/devices/ble_hci/common-hal/_bleio/Attribute.h +++ b/devices/ble_hci/common-hal/_bleio/Attribute.h @@ -29,6 +29,13 @@ #include "shared-module/_bleio/Attribute.h" -extern void bleio_attribute_gatts_set_security_mode(ble_gap_conn_sec_mode_t *perm, bleio_attribute_security_mode_t security_mode); +// typedef struct +// { +// uint8_t sm : 4; /**< Security Mode (1 or 2), 0 for no permissions at all. */ +// uint8_t lv : 4; /**< Level (1, 2, 3 or 4), 0 for no permissions at all. */ + +// } ble_gap_conn_sec_mode_t; + +// extern void bleio_attribute_gatts_set_security_mode(ble_gap_conn_sec_mode_t *perm, bleio_attribute_security_mode_t security_mode); #endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_ATTRIBUTE_H diff --git a/devices/ble_hci/common-hal/_bleio/Characteristic.c b/devices/ble_hci/common-hal/_bleio/Characteristic.c index d507cecca..ff08bf15c 100644 --- a/devices/ble_hci/common-hal/_bleio/Characteristic.c +++ b/devices/ble_hci/common-hal/_bleio/Characteristic.c @@ -33,70 +33,70 @@ #include "shared-bindings/_bleio/Service.h" #include "common-hal/_bleio/Adapter.h" -#include "common-hal/_bleio/bonding.h" -STATIC uint16_t characteristic_get_cccd(uint16_t cccd_handle, uint16_t conn_handle) { - uint16_t cccd; - ble_gatts_value_t value = { - .p_value = (uint8_t*) &cccd, - .len = 2, - }; - - const uint32_t err_code = sd_ble_gatts_value_get(conn_handle, cccd_handle, &value); - - if (err_code == BLE_ERROR_GATTS_SYS_ATTR_MISSING) { - // CCCD is not set, so say that neither Notify nor Indicate is enabled. - cccd = 0; - } else { - check_nrf_error(err_code); - } - - return cccd; -} - - -STATIC void characteristic_gatts_notify_indicate(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo, uint16_t hvx_type) { - uint16_t hvx_len = bufinfo->len; - - ble_gatts_hvx_params_t hvx_params = { - .handle = handle, - .type = hvx_type, - .offset = 0, - .p_len = &hvx_len, - .p_data = bufinfo->buf, - }; - - while (1) { - const uint32_t err_code = sd_ble_gatts_hvx(conn_handle, &hvx_params); - if (err_code == NRF_SUCCESS) { - break; - } - // TX buffer is full - // We could wait for an event indicating the write is complete, but just retrying is easier. - if (err_code == NRF_ERROR_RESOURCES) { - RUN_BACKGROUND_TASKS; - continue; - } - - // Some real error has occurred. - check_nrf_error(err_code); - } -} +// STATIC uint16_t characteristic_get_cccd(uint16_t cccd_handle, uint16_t conn_handle) { +// uint16_t cccd; +// // ble_gatts_value_t value = { +// // .p_value = (uint8_t*) &cccd, +// // .len = 2, +// // }; + +// // const uint32_t err_code = sd_ble_gatts_value_get(conn_handle, cccd_handle, &value); + +// // if (err_code == BLE_ERROR_GATTS_SYS_ATTR_MISSING) { +// // // CCCD is not set, so say that neither Notify nor Indicate is enabled. +// // cccd = 0; +// // } else { +// // check_nrf_error(err_code); +// // } + +// return cccd; +// } + + +// STATIC void characteristic_gatts_notify_indicate(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo, uint16_t hvx_type) { +// uint16_t hvx_len = bufinfo->len; + +// ble_gatts_hvx_params_t hvx_params = { +// .handle = handle, +// .type = hvx_type, +// .offset = 0, +// .p_len = &hvx_len, +// .p_data = bufinfo->buf, +// }; + +// while (1) { +// const uint32_t err_code = sd_ble_gatts_hvx(conn_handle, &hvx_params); +// if (err_code == NRF_SUCCESS) { +// break; +// } +// // TX buffer is full +// // We could wait for an event indicating the write is complete, but just retrying is easier. +// if (err_code == NRF_ERROR_RESOURCES) { +// RUN_BACKGROUND_TASKS; +// continue; +// } + +// // Some real error has occurred. +// check_nrf_error(err_code); +// } +// } void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, bleio_service_obj_t *service, uint16_t handle, bleio_uuid_obj_t *uuid, bleio_characteristic_properties_t props, bleio_attribute_security_mode_t read_perm, bleio_attribute_security_mode_t write_perm, mp_int_t max_length, bool fixed_length, mp_buffer_info_t *initial_value_bufinfo) { self->service = service; self->uuid = uuid; - self->handle = BLE_GATT_HANDLE_INVALID; + //FIX self->handle = BLE_GATT_HANDLE_INVALID; self->props = props; self->read_perm = read_perm; self->write_perm = write_perm; self->descriptor_list = NULL; - const mp_int_t max_length_max = fixed_length ? BLE_GATTS_FIX_ATTR_LEN_MAX : BLE_GATTS_VAR_ATTR_LEN_MAX; - if (max_length < 0 || max_length > max_length_max) { - mp_raise_ValueError_varg(translate("max_length must be 0-%d when fixed_length is %s"), - max_length_max, fixed_length ? "True" : "False"); - } + //FIX + // const mp_int_t max_length_max = fixed_length ? BLE_GATTS_FIX_ATTR_LEN_MAX : BLE_GATTS_VAR_ATTR_LEN_MAX; + // if (max_length < 0 || max_length > max_length_max) { + // mp_raise_ValueError_varg(translate("max_length must be 0-%d when fixed_length is %s"), + // max_length_max, fixed_length ? "True" : "False"); + // } self->max_length = max_length; self->fixed_length = fixed_length; @@ -159,25 +159,26 @@ void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { bleio_connection_internal_t *connection = &bleio_connections[i]; uint16_t conn_handle = connection->conn_handle; - if (connection->conn_handle == BLE_CONN_HANDLE_INVALID) { + if (conn_handle == BLE_CONN_HANDLE_INVALID) { continue; } - uint16_t cccd = 0; - - const bool notify = self->props & CHAR_PROP_NOTIFY; - const bool indicate = self->props & CHAR_PROP_INDICATE; - if (notify | indicate) { - cccd = characteristic_get_cccd(self->cccd_handle, conn_handle); - } - - // It's possible that both notify and indicate are set. - if (notify && (cccd & BLE_GATT_HVX_NOTIFICATION)) { - characteristic_gatts_notify_indicate(self->handle, conn_handle, bufinfo, BLE_GATT_HVX_NOTIFICATION); - } - if (indicate && (cccd & BLE_GATT_HVX_INDICATION)) { - characteristic_gatts_notify_indicate(self->handle, conn_handle, bufinfo, BLE_GATT_HVX_INDICATION); - } + //FIX + // uint16_t cccd = 0; + + // const bool notify = self->props & CHAR_PROP_NOTIFY; + // const bool indicate = self->props & CHAR_PROP_INDICATE; + // if (notify | indicate) { + // cccd = characteristic_get_cccd(self->cccd_handle, conn_handle); + // } + + // // It's possible that both notify and indicate are set. + // if (notify && (cccd & BLE_GATT_HVX_NOTIFICATION)) { + // characteristic_gatts_notify_indicate(self->handle, conn_handle, bufinfo, BLE_GATT_HVX_NOTIFICATION); + // } + // if (indicate && (cccd & BLE_GATT_HVX_INDICATION)) { + // characteristic_gatts_notify_indicate(self->handle, conn_handle, bufinfo, BLE_GATT_HVX_INDICATION); + // } } } } @@ -192,34 +193,35 @@ bleio_characteristic_properties_t common_hal_bleio_characteristic_get_properties } void common_hal_bleio_characteristic_add_descriptor(bleio_characteristic_obj_t *self, bleio_descriptor_obj_t *descriptor) { - ble_uuid_t desc_uuid; - bleio_uuid_convert_to_nrf_ble_uuid(descriptor->uuid, &desc_uuid); - - ble_gatts_attr_md_t desc_attr_md = { - // Data passed is not in a permanent location and should be copied. - .vloc = BLE_GATTS_VLOC_STACK, - .vlen = !descriptor->fixed_length, - }; - - bleio_attribute_gatts_set_security_mode(&desc_attr_md.read_perm, descriptor->read_perm); - bleio_attribute_gatts_set_security_mode(&desc_attr_md.write_perm, descriptor->write_perm); - - mp_buffer_info_t desc_value_bufinfo; - mp_get_buffer_raise(descriptor->value, &desc_value_bufinfo, MP_BUFFER_READ); - - ble_gatts_attr_t desc_attr = { - .p_uuid = &desc_uuid, - .p_attr_md = &desc_attr_md, - .init_len = desc_value_bufinfo.len, - .p_value = desc_value_bufinfo.buf, - .init_offs = 0, - .max_len = descriptor->max_length, - }; - - check_nrf_error(sd_ble_gatts_descriptor_add(self->handle, &desc_attr, &descriptor->handle)); - - descriptor->next = self->descriptor_list; - self->descriptor_list = descriptor; + //FIX + // ble_uuid_t desc_uuid; + // bleio_uuid_convert_to_nrf_ble_uuid(descriptor->uuid, &desc_uuid); + + // ble_gatts_attr_md_t desc_attr_md = { + // // Data passed is not in a permanent location and should be copied. + // .vloc = BLE_GATTS_VLOC_STACK, + // .vlen = !descriptor->fixed_length, + // }; + + // bleio_attribute_gatts_set_security_mode(&desc_attr_md.read_perm, descriptor->read_perm); + // bleio_attribute_gatts_set_security_mode(&desc_attr_md.write_perm, descriptor->write_perm); + + // mp_buffer_info_t desc_value_bufinfo; + // mp_get_buffer_raise(descriptor->value, &desc_value_bufinfo, MP_BUFFER_READ); + + // ble_gatts_attr_t desc_attr = { + // .p_uuid = &desc_uuid, + // .p_attr_md = &desc_attr_md, + // .init_len = desc_value_bufinfo.len, + // .p_value = desc_value_bufinfo.buf, + // .init_offs = 0, + // .max_len = descriptor->max_length, + // }; + + // check_nrf_error(sd_ble_gatts_descriptor_add(self->handle, &desc_attr, &descriptor->handle)); + + // descriptor->next = self->descriptor_list; + // self->descriptor_list = descriptor; } void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, bool notify, bool indicate) { @@ -234,33 +236,34 @@ void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, const uint16_t conn_handle = bleio_connection_get_conn_handle(self->service->connection); common_hal_bleio_check_connected(conn_handle); - uint16_t cccd_value = - (notify ? BLE_GATT_HVX_NOTIFICATION : 0) | - (indicate ? BLE_GATT_HVX_INDICATION : 0); - - ble_gattc_write_params_t write_params = { - .write_op = BLE_GATT_OP_WRITE_REQ, - .handle = self->cccd_handle, - .p_value = (uint8_t *) &cccd_value, - .len = 2, - }; - - while (1) { - uint32_t err_code = sd_ble_gattc_write(conn_handle, &write_params); - if (err_code == NRF_SUCCESS) { - break; - } - - // Write with response will return NRF_ERROR_BUSY if the response has not been received. - // Write without reponse will return NRF_ERROR_RESOURCES if too many writes are pending. - if (err_code == NRF_ERROR_BUSY || err_code == NRF_ERROR_RESOURCES) { - // We could wait for an event indicating the write is complete, but just retrying is easier. - RUN_BACKGROUND_TASKS; - continue; - } - - // Some real error occurred. - check_nrf_error(err_code); - } + //FIX + // uint16_t cccd_value = + // (notify ? BLE_GATT_HVX_NOTIFICATION : 0) | + // (indicate ? BLE_GATT_HVX_INDICATION : 0); + + // ble_gattc_write_params_t write_params = { + // .write_op = BLE_GATT_OP_WRITE_REQ, + // .handle = self->cccd_handle, + // .p_value = (uint8_t *) &cccd_value, + // .len = 2, + // }; + + // while (1) { + // uint32_t err_code = sd_ble_gattc_write(conn_handle, &write_params); + // if (err_code == NRF_SUCCESS) { + // break; + // } + + // // Write with response will return NRF_ERROR_BUSY if the response has not been received. + // // Write without reponse will return NRF_ERROR_RESOURCES if too many writes are pending. + // if (err_code == NRF_ERROR_BUSY || err_code == NRF_ERROR_RESOURCES) { + // // We could wait for an event indicating the write is complete, but just retrying is easier. + // RUN_BACKGROUND_TASKS; + // continue; + // } + + // // Some real error occurred. + // check_nrf_error(err_code); + // } } diff --git a/devices/ble_hci/common-hal/_bleio/CharacteristicBuffer.c b/devices/ble_hci/common-hal/_bleio/CharacteristicBuffer.c index 6f848f858..c4eb6a19f 100644 --- a/devices/ble_hci/common-hal/_bleio/CharacteristicBuffer.c +++ b/devices/ble_hci/common-hal/_bleio/CharacteristicBuffer.c @@ -37,44 +37,44 @@ #include "common-hal/_bleio/CharacteristicBuffer.h" // Push all the data onto the ring buffer. When the buffer is full, new bytes will be dropped. -STATIC void write_to_ringbuf(bleio_characteristic_buffer_obj_t *self, uint8_t *data, uint16_t len) { - uint8_t is_nested_critical_region; - sd_nvic_critical_region_enter(&is_nested_critical_region); - ringbuf_put_n(&self->ringbuf, data, len); - sd_nvic_critical_region_exit(is_nested_critical_region); -} - -STATIC bool characteristic_buffer_on_ble_evt(ble_evt_t *ble_evt, void *param) { - bleio_characteristic_buffer_obj_t *self = (bleio_characteristic_buffer_obj_t *) param; - switch (ble_evt->header.evt_id) { - case BLE_GATTS_EVT_WRITE: { - // A client wrote to this server characteristic. - - ble_gatts_evt_write_t *evt_write = &ble_evt->evt.gatts_evt.params.write; - // Event handle must match the handle for my characteristic. - if (evt_write->handle == self->characteristic->handle) { - write_to_ringbuf(self, evt_write->data, evt_write->len); - } - break; - } - - case BLE_GATTC_EVT_HVX: { - // A remote service wrote to this characteristic. - - ble_gattc_evt_hvx_t* evt_hvx = &ble_evt->evt.gattc_evt.params.hvx; - // Must be a notification, and event handle must match the handle for my characteristic. - if (evt_hvx->type == BLE_GATT_HVX_NOTIFICATION && - evt_hvx->handle == self->characteristic->handle) { - write_to_ringbuf(self, evt_hvx->data, evt_hvx->len); - } - break; - } - default: - return false; - break; - } - return true; -} +// STATIC void write_to_ringbuf(bleio_characteristic_buffer_obj_t *self, uint8_t *data, uint16_t len) { +// uint8_t is_nested_critical_region; +// sd_nvic_critical_region_enter(&is_nested_critical_region); +// ringbuf_put_n(&self->ringbuf, data, len); +// sd_nvic_critical_region_exit(is_nested_critical_region); +// } + +// STATIC bool characteristic_buffer_on_ble_evt(ble_evt_t *ble_evt, void *param) { +// bleio_characteristic_buffer_obj_t *self = (bleio_characteristic_buffer_obj_t *) param; +// switch (ble_evt->header.evt_id) { +// case BLE_GATTS_EVT_WRITE: { +// // A client wrote to this server characteristic. + +// ble_gatts_evt_write_t *evt_write = &ble_evt->evt.gatts_evt.params.write; +// // Event handle must match the handle for my characteristic. +// if (evt_write->handle == self->characteristic->handle) { +// write_to_ringbuf(self, evt_write->data, evt_write->len); +// } +// break; +// } + +// case BLE_GATTC_EVT_HVX: { +// // A remote service wrote to this characteristic. + +// ble_gattc_evt_hvx_t* evt_hvx = &ble_evt->evt.gattc_evt.params.hvx; +// // Must be a notification, and event handle must match the handle for my characteristic. +// if (evt_hvx->type == BLE_GATT_HVX_NOTIFICATION && +// evt_hvx->handle == self->characteristic->handle) { +// write_to_ringbuf(self, evt_hvx->data, evt_hvx->len); +// } +// break; +// } +// default: +// return false; +// break; +// } +// return true; +// } // Assumes that timeout and buffer_size have been validated before call. void common_hal_bleio_characteristic_buffer_construct(bleio_characteristic_buffer_obj_t *self, @@ -88,7 +88,7 @@ void common_hal_bleio_characteristic_buffer_construct(bleio_characteristic_buffe // true means long-lived, so it won't be moved. ringbuf_alloc(&self->ringbuf, buffer_size, true); - ble_drv_add_event_handler(characteristic_buffer_on_ble_evt, self); + // FIX ble_drv_add_event_handler(characteristic_buffer_on_ble_evt, self); } @@ -105,31 +105,31 @@ uint32_t common_hal_bleio_characteristic_buffer_read(bleio_characteristic_buffer } // Copy received data. Lock out write interrupt handler while copying. - uint8_t is_nested_critical_region; - sd_nvic_critical_region_enter(&is_nested_critical_region); + // FIX uint8_t is_nested_critical_region; + // FIX sd_nvic_critical_region_enter(&is_nested_critical_region); uint32_t num_bytes_read = ringbuf_get_n(&self->ringbuf, data, len); // Writes now OK. - sd_nvic_critical_region_exit(is_nested_critical_region); + // FIX sd_nvic_critical_region_exit(is_nested_critical_region); return num_bytes_read; } uint32_t common_hal_bleio_characteristic_buffer_rx_characters_available(bleio_characteristic_buffer_obj_t *self) { - uint8_t is_nested_critical_region; - sd_nvic_critical_region_enter(&is_nested_critical_region); + //FIX uint8_t is_nested_critical_region; + //FIX sd_nvic_critical_region_enter(&is_nested_critical_region); uint16_t count = ringbuf_num_filled(&self->ringbuf); - sd_nvic_critical_region_exit(is_nested_critical_region); + //FIX sd_nvic_critical_region_exit(is_nested_critical_region); return count; } void common_hal_bleio_characteristic_buffer_clear_rx_buffer(bleio_characteristic_buffer_obj_t *self) { // prevent conflict with uart irq - uint8_t is_nested_critical_region; - sd_nvic_critical_region_enter(&is_nested_critical_region); + //FIX uint8_t is_nested_critical_region; + //FIX sd_nvic_critical_region_enter(&is_nested_critical_region); ringbuf_clear(&self->ringbuf); - sd_nvic_critical_region_exit(is_nested_critical_region); + //FIX sd_nvic_critical_region_exit(is_nested_critical_region); } bool common_hal_bleio_characteristic_buffer_deinited(bleio_characteristic_buffer_obj_t *self) { @@ -138,7 +138,7 @@ bool common_hal_bleio_characteristic_buffer_deinited(bleio_characteristic_buffer void common_hal_bleio_characteristic_buffer_deinit(bleio_characteristic_buffer_obj_t *self) { if (!common_hal_bleio_characteristic_buffer_deinited(self)) { - ble_drv_remove_event_handler(characteristic_buffer_on_ble_evt, self); + //FIX ble_drv_remove_event_handler(characteristic_buffer_on_ble_evt, self); } } diff --git a/devices/ble_hci/common-hal/_bleio/Connection.c b/devices/ble_hci/common-hal/_bleio/Connection.c index 6c63f4261..913f120fe 100644 --- a/devices/ble_hci/common-hal/_bleio/Connection.c +++ b/devices/ble_hci/common-hal/_bleio/Connection.c @@ -44,24 +44,22 @@ #include "shared-bindings/_bleio/UUID.h" #include "supervisor/shared/tick.h" -#include "common-hal/_bleio/bonding.h" - #define BLE_ADV_LENGTH_FIELD_SIZE 1 #define BLE_ADV_AD_TYPE_FIELD_SIZE 1 #define BLE_AD_TYPE_FLAGS_DATA_SIZE 1 -static const ble_gap_sec_params_t pairing_sec_params = { - .bond = 1, - .mitm = 0, - .lesc = 0, - .keypress = 0, - .oob = 0, - .io_caps = BLE_GAP_IO_CAPS_NONE, - .min_key_size = 7, - .max_key_size = 16, - .kdist_own = { .enc = 1, .id = 1}, - .kdist_peer = { .enc = 1, .id = 1}, -}; +// static const ble_gap_sec_params_t pairing_sec_params = { +// .bond = 1, +// .mitm = 0, +// .lesc = 0, +// .keypress = 0, +// .oob = 0, +// .io_caps = BLE_GAP_IO_CAPS_NONE, +// .min_key_size = 7, +// .max_key_size = 16, +// .kdist_own = { .enc = 1, .id = 1}, +// .kdist_peer = { .enc = 1, .id = 1}, +// }; #define CONNECTION_DEBUG (1) #if CONNECTION_DEBUG @@ -73,259 +71,259 @@ static const ble_gap_sec_params_t pairing_sec_params = { static volatile bool m_discovery_in_process; static volatile bool m_discovery_successful; -static bleio_service_obj_t *m_char_discovery_service; -static bleio_characteristic_obj_t *m_desc_discovery_characteristic; - -bool connection_on_ble_evt(ble_evt_t *ble_evt, void *self_in) { - bleio_connection_internal_t *self = (bleio_connection_internal_t*)self_in; - - if (BLE_GAP_EVT_BASE <= ble_evt->header.evt_id && ble_evt->header.evt_id <= BLE_GAP_EVT_LAST && - ble_evt->evt.gap_evt.conn_handle != self->conn_handle) { - return false; - } - if (BLE_GATTS_EVT_BASE <= ble_evt->header.evt_id && ble_evt->header.evt_id <= BLE_GATTS_EVT_LAST && - ble_evt->evt.gatts_evt.conn_handle != self->conn_handle) { - return false; - } - - switch (ble_evt->header.evt_id) { - case BLE_GAP_EVT_DISCONNECTED: - // Adapter.c does the work for this event. - break; - - case BLE_GAP_EVT_PHY_UPDATE_REQUEST: { - ble_gap_phys_t const phys = { - .rx_phys = BLE_GAP_PHY_AUTO, - .tx_phys = BLE_GAP_PHY_AUTO, - }; - sd_ble_gap_phy_update(ble_evt->evt.gap_evt.conn_handle, &phys); - break; - } - - case BLE_GAP_EVT_PHY_UPDATE: { // 0x22 - break; - } - - case BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST: - // SoftDevice will respond to a length update request. - sd_ble_gap_data_length_update(self->conn_handle, NULL, NULL); - break; - - case BLE_GAP_EVT_DATA_LENGTH_UPDATE: { // 0x24 - break; - } - - case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST: { - ble_gatts_evt_exchange_mtu_request_t *request = - &ble_evt->evt.gatts_evt.params.exchange_mtu_request; - - uint16_t new_mtu = BLE_GATTS_VAR_ATTR_LEN_MAX; - if (request->client_rx_mtu < new_mtu) { - new_mtu = request->client_rx_mtu; - } - if (new_mtu < BLE_GATT_ATT_MTU_DEFAULT) { - new_mtu = BLE_GATT_ATT_MTU_DEFAULT; - } - if (self->mtu > 0) { - new_mtu = self->mtu; - } - - self->mtu = new_mtu; - sd_ble_gatts_exchange_mtu_reply(self->conn_handle, new_mtu); - break; - } - - - case BLE_GATTC_EVT_EXCHANGE_MTU_RSP: { - ble_gattc_evt_exchange_mtu_rsp_t *response = - &ble_evt->evt.gattc_evt.params.exchange_mtu_rsp; - - self->mtu = response->server_rx_mtu; - break; - } - - case BLE_GATTS_EVT_WRITE: - // A client wrote a value. - // If we are bonded and it's a CCCD (UUID 0x2902), store the CCCD value. - if (self->conn_handle != BLE_CONN_HANDLE_INVALID && - self->pair_status == PAIR_PAIRED && - ble_evt->evt.gatts_evt.params.write.uuid.type == BLE_UUID_TYPE_BLE && - ble_evt->evt.gatts_evt.params.write.uuid.uuid == 0x2902) { - // - // Save sys_attr data (CCCD state) in bonding area at - // next opportunity, but also remember time of this - // request, so we can consolidate closely-spaced requests. - self->do_bond_cccds = true; - self->do_bond_cccds_request_time = supervisor_ticks_ms64(); - } - // Return false so other handlers get this event as well. - return false; - - case BLE_GATTS_EVT_SYS_ATTR_MISSING: - sd_ble_gatts_sys_attr_set(self->conn_handle, NULL, 0, 0); - break; - - #if CIRCUITPY_VERBOSE_BLE - // Use read authorization to snoop on all reads when doing verbose debugging. - case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST: { - - ble_gatts_evt_rw_authorize_request_t *request = - &ble_evt->evt.gatts_evt.params.authorize_request; - - mp_printf(&mp_plat_print, "Read %x offset %d ", request->request.read.handle, request->request.read.offset); - uint8_t value_bytes[22]; - ble_gatts_value_t value; - value.offset = request->request.read.offset; - value.len = 22; - value.p_value = value_bytes; - - sd_ble_gatts_value_get(self->conn_handle, request->request.read.handle, &value); - size_t len = value.len; - if (len > 22) { - len = 22; - } - for (uint8_t i = 0; i < len; i++) { - mp_printf(&mp_plat_print, " %02x", value_bytes[i]); - } - mp_printf(&mp_plat_print, "\n"); - ble_gatts_rw_authorize_reply_params_t reply; - reply.type = request->type; - reply.params.read.gatt_status = BLE_GATT_STATUS_SUCCESS; - reply.params.read.update = false; - reply.params.read.offset = request->request.read.offset; - sd_ble_gatts_rw_authorize_reply(self->conn_handle, &reply); - break; - } - #endif - - case BLE_GATTS_EVT_HVN_TX_COMPLETE: // Capture this for now. 0x55 - break; - case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: { - self->conn_params_updating = true; - ble_gap_evt_conn_param_update_request_t *request = - &ble_evt->evt.gap_evt.params.conn_param_update_request; - sd_ble_gap_conn_param_update(self->conn_handle, &request->conn_params); - break; - } - case BLE_GAP_EVT_CONN_PARAM_UPDATE: { // 0x12 - ble_gap_evt_conn_param_update_t *result = - &ble_evt->evt.gap_evt.params.conn_param_update; - - #if CIRCUITPY_VERBOSE_BLE - ble_gap_conn_params_t *cp = &ble_evt->evt.gap_evt.params.conn_param_update.conn_params; - mp_printf(&mp_plat_print, "conn params updated: min_ci %d max_ci %d s_l %d sup_timeout %d\n", cp->min_conn_interval, cp->max_conn_interval, cp->slave_latency, cp->conn_sup_timeout); - #endif - - memcpy(&self->conn_params, &result->conn_params, sizeof(ble_gap_conn_params_t)); - self->conn_params_updating = false; - break; - } - case BLE_GAP_EVT_SEC_PARAMS_REQUEST: { - // First time pairing. - // 1. Either we or peer initiate the process - // 2. Peer asks for security parameters using BLE_GAP_EVT_SEC_PARAMS_REQUEST. - // 3. Pair Key exchange ("just works" implemented now; TODO: out-of-band key pairing) - // 4. Connection is secured: BLE_GAP_EVT_CONN_SEC_UPDATE - // 5. Long-term Keys exchanged: BLE_GAP_EVT_AUTH_STATUS - - bonding_clear_keys(&self->bonding_keys); - self->ediv = EDIV_INVALID; - ble_gap_sec_keyset_t keyset = { - .keys_own = { - .p_enc_key = &self->bonding_keys.own_enc, - .p_id_key = NULL, - .p_sign_key = NULL, - .p_pk = NULL - }, - - .keys_peer = { - .p_enc_key = &self->bonding_keys.peer_enc, - .p_id_key = &self->bonding_keys.peer_id, - .p_sign_key = NULL, - .p_pk = NULL - } - }; - - sd_ble_gap_sec_params_reply(self->conn_handle, BLE_GAP_SEC_STATUS_SUCCESS, - self->is_central ? NULL : &pairing_sec_params, - &keyset); - break; - } - - case BLE_GAP_EVT_LESC_DHKEY_REQUEST: - // TODO for LESC pairing: - // sd_ble_gap_lesc_dhkey_reply(...); - break; - - case BLE_GAP_EVT_AUTH_STATUS: { // 0x19 - // Key exchange completed. - ble_gap_evt_auth_status_t* status = &ble_evt->evt.gap_evt.params.auth_status; - self->sec_status = status->auth_status; - if (status->auth_status == BLE_GAP_SEC_STATUS_SUCCESS) { - self->ediv = self->bonding_keys.own_enc.master_id.ediv; - self->pair_status = PAIR_PAIRED; - // Save keys in bonding area at next opportunity. - self->do_bond_keys = true; - } else { - // Inform busy-waiter pairing has failed. - self->pair_status = PAIR_NOT_PAIRED; - } - break; - } - - case BLE_GAP_EVT_SEC_INFO_REQUEST: { // 0x14 - // Peer asks for the stored keys. - // - load key and return if bonded previously. - // - Else return NULL --> Initiate key exchange - ble_gap_evt_sec_info_request_t* sec_info_request = &ble_evt->evt.gap_evt.params.sec_info_request; - (void) sec_info_request; - if ( bonding_load_keys(self->is_central, sec_info_request->master_id.ediv, &self->bonding_keys) ) { - sd_ble_gap_sec_info_reply( - self->conn_handle, - &self->bonding_keys.own_enc.enc_info, - &self->bonding_keys.peer_id.id_info, - NULL); - self->ediv = self->bonding_keys.own_enc.master_id.ediv; - } else { - // We don't have stored keys. Ask for keys. - sd_ble_gap_sec_info_reply(self->conn_handle, NULL, NULL, NULL); - } - break; - } - - case BLE_GAP_EVT_CONN_SEC_UPDATE: { // 0x1a - // We get this both on first-time pairing and on subsequent pairings using stored keys. - ble_gap_conn_sec_t* conn_sec = &ble_evt->evt.gap_evt.params.conn_sec_update.conn_sec; - if (conn_sec->sec_mode.sm <= 1 && conn_sec->sec_mode.lv <= 1) { - // Security setup did not succeed: - // mode 0, level 0 means no access - // mode 1, level 1 means open link - // mode >=1 and/or level >=1 means encryption is set up - self->pair_status = PAIR_NOT_PAIRED; - } else { - if (bonding_load_cccd_info(self->is_central, self->conn_handle, self->ediv)) { - // Did an sd_ble_gatts_sys_attr_set() with the stored sys_attr values. - } else { - // No matching bonding found, so use fresh system attributes. - sd_ble_gatts_sys_attr_set(self->conn_handle, NULL, 0, 0); - } - self->pair_status = PAIR_PAIRED; - } - break; - } - - default: - return false; - } - return true; -} +//FIX static bleio_service_obj_t *m_char_discovery_service; +//FIX static bleio_characteristic_obj_t *m_desc_discovery_characteristic; + +// bool connection_on_ble_evt(ble_evt_t *ble_evt, void *self_in) { +// bleio_connection_internal_t *self = (bleio_connection_internal_t*)self_in; + +// if (BLE_GAP_EVT_BASE <= ble_evt->header.evt_id && ble_evt->header.evt_id <= BLE_GAP_EVT_LAST && +// ble_evt->evt.gap_evt.conn_handle != self->conn_handle) { +// return false; +// } +// if (BLE_GATTS_EVT_BASE <= ble_evt->header.evt_id && ble_evt->header.evt_id <= BLE_GATTS_EVT_LAST && +// ble_evt->evt.gatts_evt.conn_handle != self->conn_handle) { +// return false; +// } + +// switch (ble_evt->header.evt_id) { +// case BLE_GAP_EVT_DISCONNECTED: +// // Adapter.c does the work for this event. +// break; + +// case BLE_GAP_EVT_PHY_UPDATE_REQUEST: { +// ble_gap_phys_t const phys = { +// .rx_phys = BLE_GAP_PHY_AUTO, +// .tx_phys = BLE_GAP_PHY_AUTO, +// }; +// sd_ble_gap_phy_update(ble_evt->evt.gap_evt.conn_handle, &phys); +// break; +// } + +// case BLE_GAP_EVT_PHY_UPDATE: { // 0x22 +// break; +// } + +// case BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST: +// // SoftDevice will respond to a length update request. +// sd_ble_gap_data_length_update(self->conn_handle, NULL, NULL); +// break; + +// case BLE_GAP_EVT_DATA_LENGTH_UPDATE: { // 0x24 +// break; +// } + +// case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST: { +// ble_gatts_evt_exchange_mtu_request_t *request = +// &ble_evt->evt.gatts_evt.params.exchange_mtu_request; + +// uint16_t new_mtu = BLE_GATTS_VAR_ATTR_LEN_MAX; +// if (request->client_rx_mtu < new_mtu) { +// new_mtu = request->client_rx_mtu; +// } +// if (new_mtu < BLE_GATT_ATT_MTU_DEFAULT) { +// new_mtu = BLE_GATT_ATT_MTU_DEFAULT; +// } +// if (self->mtu > 0) { +// new_mtu = self->mtu; +// } + +// self->mtu = new_mtu; +// sd_ble_gatts_exchange_mtu_reply(self->conn_handle, new_mtu); +// break; +// } + + +// case BLE_GATTC_EVT_EXCHANGE_MTU_RSP: { +// ble_gattc_evt_exchange_mtu_rsp_t *response = +// &ble_evt->evt.gattc_evt.params.exchange_mtu_rsp; + +// self->mtu = response->server_rx_mtu; +// break; +// } + +// case BLE_GATTS_EVT_WRITE: +// // A client wrote a value. +// // If we are bonded and it's a CCCD (UUID 0x2902), store the CCCD value. +// if (self->conn_handle != BLE_CONN_HANDLE_INVALID && +// self->pair_status == PAIR_PAIRED && +// ble_evt->evt.gatts_evt.params.write.uuid.type == BLE_UUID_TYPE_BLE && +// ble_evt->evt.gatts_evt.params.write.uuid.uuid == 0x2902) { +// // +// // Save sys_attr data (CCCD state) in bonding area at +// // next opportunity, but also remember time of this +// // request, so we can consolidate closely-spaced requests. +// self->do_bond_cccds = true; +// self->do_bond_cccds_request_time = supervisor_ticks_ms64(); +// } +// // Return false so other handlers get this event as well. +// return false; + +// case BLE_GATTS_EVT_SYS_ATTR_MISSING: +// sd_ble_gatts_sys_attr_set(self->conn_handle, NULL, 0, 0); +// break; + +// #if CIRCUITPY_VERBOSE_BLE +// // Use read authorization to snoop on all reads when doing verbose debugging. +// case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST: { + +// ble_gatts_evt_rw_authorize_request_t *request = +// &ble_evt->evt.gatts_evt.params.authorize_request; + +// mp_printf(&mp_plat_print, "Read %x offset %d ", request->request.read.handle, request->request.read.offset); +// uint8_t value_bytes[22]; +// ble_gatts_value_t value; +// value.offset = request->request.read.offset; +// value.len = 22; +// value.p_value = value_bytes; + +// sd_ble_gatts_value_get(self->conn_handle, request->request.read.handle, &value); +// size_t len = value.len; +// if (len > 22) { +// len = 22; +// } +// for (uint8_t i = 0; i < len; i++) { +// mp_printf(&mp_plat_print, " %02x", value_bytes[i]); +// } +// mp_printf(&mp_plat_print, "\n"); +// ble_gatts_rw_authorize_reply_params_t reply; +// reply.type = request->type; +// reply.params.read.gatt_status = BLE_GATT_STATUS_SUCCESS; +// reply.params.read.update = false; +// reply.params.read.offset = request->request.read.offset; +// sd_ble_gatts_rw_authorize_reply(self->conn_handle, &reply); +// break; +// } +// #endif + +// case BLE_GATTS_EVT_HVN_TX_COMPLETE: // Capture this for now. 0x55 +// break; +// case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: { +// self->conn_params_updating = true; +// ble_gap_evt_conn_param_update_request_t *request = +// &ble_evt->evt.gap_evt.params.conn_param_update_request; +// sd_ble_gap_conn_param_update(self->conn_handle, &request->conn_params); +// break; +// } +// case BLE_GAP_EVT_CONN_PARAM_UPDATE: { // 0x12 +// ble_gap_evt_conn_param_update_t *result = +// &ble_evt->evt.gap_evt.params.conn_param_update; + +// #if CIRCUITPY_VERBOSE_BLE +// ble_gap_conn_params_t *cp = &ble_evt->evt.gap_evt.params.conn_param_update.conn_params; +// mp_printf(&mp_plat_print, "conn params updated: min_ci %d max_ci %d s_l %d sup_timeout %d\n", cp->min_conn_interval, cp->max_conn_interval, cp->slave_latency, cp->conn_sup_timeout); +// #endif + +// memcpy(&self->conn_params, &result->conn_params, sizeof(ble_gap_conn_params_t)); +// self->conn_params_updating = false; +// break; +// } +// case BLE_GAP_EVT_SEC_PARAMS_REQUEST: { +// // First time pairing. +// // 1. Either we or peer initiate the process +// // 2. Peer asks for security parameters using BLE_GAP_EVT_SEC_PARAMS_REQUEST. +// // 3. Pair Key exchange ("just works" implemented now; TODO: out-of-band key pairing) +// // 4. Connection is secured: BLE_GAP_EVT_CONN_SEC_UPDATE +// // 5. Long-term Keys exchanged: BLE_GAP_EVT_AUTH_STATUS + +// bonding_clear_keys(&self->bonding_keys); +// self->ediv = EDIV_INVALID; +// ble_gap_sec_keyset_t keyset = { +// .keys_own = { +// .p_enc_key = &self->bonding_keys.own_enc, +// .p_id_key = NULL, +// .p_sign_key = NULL, +// .p_pk = NULL +// }, + +// .keys_peer = { +// .p_enc_key = &self->bonding_keys.peer_enc, +// .p_id_key = &self->bonding_keys.peer_id, +// .p_sign_key = NULL, +// .p_pk = NULL +// } +// }; + +// sd_ble_gap_sec_params_reply(self->conn_handle, BLE_GAP_SEC_STATUS_SUCCESS, +// self->is_central ? NULL : &pairing_sec_params, +// &keyset); +// break; +// } + +// case BLE_GAP_EVT_LESC_DHKEY_REQUEST: +// // TODO for LESC pairing: +// // sd_ble_gap_lesc_dhkey_reply(...); +// break; + +// case BLE_GAP_EVT_AUTH_STATUS: { // 0x19 +// // Key exchange completed. +// ble_gap_evt_auth_status_t* status = &ble_evt->evt.gap_evt.params.auth_status; +// self->sec_status = status->auth_status; +// if (status->auth_status == BLE_GAP_SEC_STATUS_SUCCESS) { +// self->ediv = self->bonding_keys.own_enc.master_id.ediv; +// self->pair_status = PAIR_PAIRED; +// // Save keys in bonding area at next opportunity. +// self->do_bond_keys = true; +// } else { +// // Inform busy-waiter pairing has failed. +// self->pair_status = PAIR_NOT_PAIRED; +// } +// break; +// } + +// case BLE_GAP_EVT_SEC_INFO_REQUEST: { // 0x14 +// // Peer asks for the stored keys. +// // - load key and return if bonded previously. +// // - Else return NULL --> Initiate key exchange +// ble_gap_evt_sec_info_request_t* sec_info_request = &ble_evt->evt.gap_evt.params.sec_info_request; +// (void) sec_info_request; +// if ( bonding_load_keys(self->is_central, sec_info_request->master_id.ediv, &self->bonding_keys) ) { +// sd_ble_gap_sec_info_reply( +// self->conn_handle, +// &self->bonding_keys.own_enc.enc_info, +// &self->bonding_keys.peer_id.id_info, +// NULL); +// self->ediv = self->bonding_keys.own_enc.master_id.ediv; +// } else { +// // We don't have stored keys. Ask for keys. +// sd_ble_gap_sec_info_reply(self->conn_handle, NULL, NULL, NULL); +// } +// break; +// } + +// case BLE_GAP_EVT_CONN_SEC_UPDATE: { // 0x1a +// // We get this both on first-time pairing and on subsequent pairings using stored keys. +// ble_gap_conn_sec_t* conn_sec = &ble_evt->evt.gap_evt.params.conn_sec_update.conn_sec; +// if (conn_sec->sec_mode.sm <= 1 && conn_sec->sec_mode.lv <= 1) { +// // Security setup did not succeed: +// // mode 0, level 0 means no access +// // mode 1, level 1 means open link +// // mode >=1 and/or level >=1 means encryption is set up +// self->pair_status = PAIR_NOT_PAIRED; +// } else { +// if (bonding_load_cccd_info(self->is_central, self->conn_handle, self->ediv)) { +// // Did an sd_ble_gatts_sys_attr_set() with the stored sys_attr values. +// } else { +// // No matching bonding found, so use fresh system attributes. +// sd_ble_gatts_sys_attr_set(self->conn_handle, NULL, 0, 0); +// } +// self->pair_status = PAIR_PAIRED; +// } +// break; +// } + +// default: +// return false; +// } +// return true; +// } void bleio_connection_clear(bleio_connection_internal_t *self) { self->remote_service_list = NULL; - self->conn_handle = BLE_CONN_HANDLE_INVALID; + //FIX self->conn_handle = BLE_CONN_HANDLE_INVALID; self->pair_status = PAIR_NOT_PAIRED; - bonding_clear_keys(&self->bonding_keys); + //FIX bonding_clear_keys(&self->bonding_keys); } bool common_hal_bleio_connection_get_paired(bleio_connection_obj_t *self) { @@ -339,17 +337,18 @@ bool common_hal_bleio_connection_get_connected(bleio_connection_obj_t *self) { if (self->connection == NULL) { return false; } - return self->connection->conn_handle != BLE_CONN_HANDLE_INVALID; + return false; + //FIX return self->connection->conn_handle != BLE_CONN_HANDLE_INVALID; } void common_hal_bleio_connection_disconnect(bleio_connection_internal_t *self) { - sd_ble_gap_disconnect(self->conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); + //FIX sd_ble_gap_disconnect(self->conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); } void common_hal_bleio_connection_pair(bleio_connection_internal_t *self, bool bond) { self->pair_status = PAIR_WAITING; - check_nrf_error(sd_ble_gap_authenticate(self->conn_handle, &pairing_sec_params)); + //FIX check_nrf_error(sd_ble_gap_authenticate(self->conn_handle, &pairing_sec_params)); while (self->pair_status == PAIR_WAITING && !mp_hal_is_interrupted()) { RUN_BACKGROUND_TASKS; @@ -364,369 +363,371 @@ mp_float_t common_hal_bleio_connection_get_connection_interval(bleio_connection_ while (self->conn_params_updating && !mp_hal_is_interrupted()) { RUN_BACKGROUND_TASKS; } - return 1.25f * self->conn_params.min_conn_interval; + //FIX return 1.25f * self->conn_params.min_conn_interval; + return 0.0f; } // Return the current negotiated MTU length, minus overhead. mp_int_t common_hal_bleio_connection_get_max_packet_length(bleio_connection_internal_t *self) { - return (self->mtu == 0 ? BLE_GATT_ATT_MTU_DEFAULT : self->mtu) - 3; + /// FIX return (self->mtu == 0 ? BLE_GATT_ATT_MTU_DEFAULT : self->mtu) - 3; + return 0; } void common_hal_bleio_connection_set_connection_interval(bleio_connection_internal_t *self, mp_float_t new_interval) { - self->conn_params_updating = true; - uint16_t interval = new_interval / 1.25f; - self->conn_params.min_conn_interval = interval; - self->conn_params.max_conn_interval = interval; - uint32_t status = NRF_ERROR_BUSY; - while (status == NRF_ERROR_BUSY) { - status = sd_ble_gap_conn_param_update(self->conn_handle, &self->conn_params); - RUN_BACKGROUND_TASKS; - } - check_nrf_error(status); + // self->conn_params_updating = true; + // uint16_t interval = new_interval / 1.25f; + // self->conn_params.min_conn_interval = interval; + // self->conn_params.max_conn_interval = interval; + // uint32_t status = NRF_ERROR_BUSY; + // while (status == NRF_ERROR_BUSY) { + // status = sd_ble_gap_conn_param_update(self->conn_handle, &self->conn_params); + // RUN_BACKGROUND_TASKS; + // } + // check_nrf_error(status); } // service_uuid may be NULL, to discover all services. -STATIC bool discover_next_services(bleio_connection_internal_t* connection, uint16_t start_handle, ble_uuid_t *service_uuid) { - m_discovery_successful = false; - m_discovery_in_process = true; - - uint32_t nrf_err = NRF_ERROR_BUSY; - while (nrf_err == NRF_ERROR_BUSY) { - nrf_err = sd_ble_gattc_primary_services_discover(connection->conn_handle, start_handle, service_uuid); - } - check_nrf_error(nrf_err); - - // Wait for a discovery event. - while (m_discovery_in_process) { - MICROPY_VM_HOOK_LOOP; - } - return m_discovery_successful; -} - -STATIC bool discover_next_characteristics(bleio_connection_internal_t* connection, bleio_service_obj_t *service, uint16_t start_handle) { - m_char_discovery_service = service; - - ble_gattc_handle_range_t handle_range; - handle_range.start_handle = start_handle; - handle_range.end_handle = service->end_handle; - - m_discovery_successful = false; - m_discovery_in_process = true; - - uint32_t err_code = sd_ble_gattc_characteristics_discover(connection->conn_handle, &handle_range); - if (err_code != NRF_SUCCESS) { - return false; - } - - // Wait for a discovery event. - while (m_discovery_in_process) { - MICROPY_VM_HOOK_LOOP; - } - return m_discovery_successful; -} - -STATIC bool discover_next_descriptors(bleio_connection_internal_t* connection, bleio_characteristic_obj_t *characteristic, uint16_t start_handle, uint16_t end_handle) { - m_desc_discovery_characteristic = characteristic; - - ble_gattc_handle_range_t handle_range; - handle_range.start_handle = start_handle; - handle_range.end_handle = end_handle; - - m_discovery_successful = false; - m_discovery_in_process = true; - - uint32_t err_code = sd_ble_gattc_descriptors_discover(connection->conn_handle, &handle_range); - if (err_code != NRF_SUCCESS) { - return false; - } - - // Wait for a discovery event. - while (m_discovery_in_process) { - MICROPY_VM_HOOK_LOOP; - } - return m_discovery_successful; -} - -STATIC void on_primary_srv_discovery_rsp(ble_gattc_evt_prim_srvc_disc_rsp_t *response, bleio_connection_internal_t* connection) { - bleio_service_obj_t* tail = connection->remote_service_list; - - for (size_t i = 0; i < response->count; ++i) { - ble_gattc_service_t *gattc_service = &response->services[i]; - - bleio_service_obj_t *service = m_new_obj(bleio_service_obj_t); - service->base.type = &bleio_service_type; - - // Initialize several fields at once. - bleio_service_from_connection(service, bleio_connection_new_from_internal(connection)); - - service->is_remote = true; - service->start_handle = gattc_service->handle_range.start_handle; - service->end_handle = gattc_service->handle_range.end_handle; - service->handle = gattc_service->handle_range.start_handle; - - if (gattc_service->uuid.type != BLE_UUID_TYPE_UNKNOWN) { - // Known service UUID. - bleio_uuid_obj_t *uuid = m_new_obj(bleio_uuid_obj_t); - uuid->base.type = &bleio_uuid_type; - bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_service->uuid); - service->uuid = uuid; - } else { - // The discovery response contained a 128-bit UUID that has not yet been registered with the - // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. - // For now, just set the UUID to NULL. - service->uuid = NULL; - } - - service->next = tail; - tail = service; - } - - connection->remote_service_list = tail; - - if (response->count > 0) { - m_discovery_successful = true; - } - m_discovery_in_process = false; -} - -STATIC void on_char_discovery_rsp(ble_gattc_evt_char_disc_rsp_t *response, bleio_connection_internal_t* connection) { - for (size_t i = 0; i < response->count; ++i) { - ble_gattc_char_t *gattc_char = &response->chars[i]; - - bleio_characteristic_obj_t *characteristic = m_new_obj(bleio_characteristic_obj_t); - characteristic->base.type = &bleio_characteristic_type; - - bleio_uuid_obj_t *uuid = NULL; - - if (gattc_char->uuid.type != BLE_UUID_TYPE_UNKNOWN) { - // Known characteristic UUID. - uuid = m_new_obj(bleio_uuid_obj_t); - uuid->base.type = &bleio_uuid_type; - bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_char->uuid); - } else { - // The discovery response contained a 128-bit UUID that has not yet been registered with the - // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. - // For now, just leave the UUID as NULL. - } - - bleio_characteristic_properties_t props = - (gattc_char->char_props.broadcast ? CHAR_PROP_BROADCAST : 0) | - (gattc_char->char_props.indicate ? CHAR_PROP_INDICATE : 0) | - (gattc_char->char_props.notify ? CHAR_PROP_NOTIFY : 0) | - (gattc_char->char_props.read ? CHAR_PROP_READ : 0) | - (gattc_char->char_props.write ? CHAR_PROP_WRITE : 0) | - (gattc_char->char_props.write_wo_resp ? CHAR_PROP_WRITE_NO_RESPONSE : 0); - - // Call common_hal_bleio_characteristic_construct() to initalize some fields and set up evt handler. - common_hal_bleio_characteristic_construct( - characteristic, m_char_discovery_service, gattc_char->handle_value, uuid, - props, SECURITY_MODE_OPEN, SECURITY_MODE_OPEN, - GATT_MAX_DATA_LENGTH, false, // max_length, fixed_length: values may not matter for gattc - NULL); - - mp_obj_list_append(m_char_discovery_service->characteristic_list, MP_OBJ_FROM_PTR(characteristic)); - } - - if (response->count > 0) { - m_discovery_successful = true; - } - m_discovery_in_process = false; -} - -STATIC void on_desc_discovery_rsp(ble_gattc_evt_desc_disc_rsp_t *response, bleio_connection_internal_t* connection) { - for (size_t i = 0; i < response->count; ++i) { - ble_gattc_desc_t *gattc_desc = &response->descs[i]; - - // Remember handles for certain well-known descriptors. - switch (gattc_desc->uuid.uuid) { - case BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG: - m_desc_discovery_characteristic->cccd_handle = gattc_desc->handle; - break; - - case BLE_UUID_DESCRIPTOR_SERVER_CHAR_CONFIG: - m_desc_discovery_characteristic->sccd_handle = gattc_desc->handle; - break; - - case BLE_UUID_DESCRIPTOR_CHAR_USER_DESC: - m_desc_discovery_characteristic->user_desc_handle = gattc_desc->handle; - break; - - default: - // TODO: sd_ble_gattc_descriptors_discover() can return things that are not descriptors, - // so ignore those. - // https://devzone.nordicsemi.com/f/nordic-q-a/49500/sd_ble_gattc_descriptors_discover-is-returning-attributes-that-are-not-descriptors - break; - } - - bleio_descriptor_obj_t *descriptor = m_new_obj(bleio_descriptor_obj_t); - descriptor->base.type = &bleio_descriptor_type; - - bleio_uuid_obj_t *uuid = NULL; - - if (gattc_desc->uuid.type != BLE_UUID_TYPE_UNKNOWN) { - // Known descriptor UUID. - uuid = m_new_obj(bleio_uuid_obj_t); - uuid->base.type = &bleio_uuid_type; - bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_desc->uuid); - } else { - // The discovery response contained a 128-bit UUID that has not yet been registered with the - // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. - // For now, just leave the UUID as NULL. - } - - common_hal_bleio_descriptor_construct( - descriptor, m_desc_discovery_characteristic, uuid, - SECURITY_MODE_OPEN, SECURITY_MODE_OPEN, - GATT_MAX_DATA_LENGTH, false, mp_const_empty_bytes); - descriptor->handle = gattc_desc->handle; - - mp_obj_list_append(m_desc_discovery_characteristic->descriptor_list, MP_OBJ_FROM_PTR(descriptor)); - } - - if (response->count > 0) { - m_discovery_successful = true; - } - m_discovery_in_process = false; -} - -STATIC bool discovery_on_ble_evt(ble_evt_t *ble_evt, mp_obj_t payload) { - bleio_connection_internal_t* connection = MP_OBJ_TO_PTR(payload); - switch (ble_evt->header.evt_id) { - case BLE_GAP_EVT_DISCONNECTED: - m_discovery_successful = false; - m_discovery_in_process = false; - break; - - case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP: - on_primary_srv_discovery_rsp(&ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp, connection); - break; - - case BLE_GATTC_EVT_CHAR_DISC_RSP: - on_char_discovery_rsp(&ble_evt->evt.gattc_evt.params.char_disc_rsp, connection); - break; - - case BLE_GATTC_EVT_DESC_DISC_RSP: - on_desc_discovery_rsp(&ble_evt->evt.gattc_evt.params.desc_disc_rsp, connection); - break; - - default: - // CONNECTION_DEBUG_PRINTF(&mp_plat_print, "Unhandled discovery event: 0x%04x\n", ble_evt->header.evt_id); - return false; - break; - } - return true; -} - -STATIC void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t service_uuids_whitelist) { - ble_drv_add_event_handler(discovery_on_ble_evt, self); - - // Start over with an empty list. - self->remote_service_list = NULL; - - if (service_uuids_whitelist == mp_const_none) { - // List of service UUID's not given, so discover all available services. - - uint16_t next_service_start_handle = BLE_GATT_HANDLE_START; - - while (discover_next_services(self, next_service_start_handle, MP_OBJ_NULL)) { - // discover_next_services() appends to remote_services_list. - - // Get the most recently discovered service, and then ask for services - // whose handles start after the last attribute handle inside that service. - const bleio_service_obj_t *service = self->remote_service_list; - next_service_start_handle = service->end_handle + 1; - } - } else { - mp_obj_iter_buf_t iter_buf; - mp_obj_t iterable = mp_getiter(service_uuids_whitelist, &iter_buf); - mp_obj_t uuid_obj; - while ((uuid_obj = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { - if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) { - mp_raise_TypeError(translate("non-UUID found in service_uuids_whitelist")); - } - bleio_uuid_obj_t *uuid = MP_OBJ_TO_PTR(uuid_obj); - - ble_uuid_t nrf_uuid; - bleio_uuid_convert_to_nrf_ble_uuid(uuid, &nrf_uuid); - - // Service might or might not be discovered; that's ok. Caller has to check - // Central.remote_services to find out. - // We only need to call this once for each service to discover. - discover_next_services(self, BLE_GATT_HANDLE_START, &nrf_uuid); - } - } - - - bleio_service_obj_t *service = self->remote_service_list; - while (service != NULL) { - // Skip the service if it had an unknown (unregistered) UUID. - if (service->uuid == NULL) { - service = service->next; - continue; - } - - uint16_t next_char_start_handle = service->start_handle; - - // Stop when we go past the end of the range of handles for this service or - // discovery call returns nothing. - // discover_next_characteristics() appends to the characteristic_list. - while (next_char_start_handle <= service->end_handle && - discover_next_characteristics(self, service, next_char_start_handle)) { - - - // Get the most recently discovered characteristic, and then ask for characteristics - // whose handles start after the last attribute handle inside that characteristic. - const bleio_characteristic_obj_t *characteristic = - MP_OBJ_TO_PTR(service->characteristic_list->items[service->characteristic_list->len - 1]); - - next_char_start_handle = characteristic->handle + 1; - } - - // Got characteristics for this service. Now discover descriptors for each characteristic. - size_t char_list_len = service->characteristic_list->len; - for (size_t char_idx = 0; char_idx < char_list_len; ++char_idx) { - bleio_characteristic_obj_t *characteristic = - MP_OBJ_TO_PTR(service->characteristic_list->items[char_idx]); - const bool last_characteristic = char_idx == char_list_len - 1; - bleio_characteristic_obj_t *next_characteristic = last_characteristic - ? NULL - : MP_OBJ_TO_PTR(service->characteristic_list->items[char_idx + 1]); - - // Skip the characteristic if it had an unknown (unregistered) UUID. - if (characteristic->uuid == NULL) { - continue; - } - - uint16_t next_desc_start_handle = characteristic->handle + 1; - - // Don't run past the end of this service or the beginning of the next characteristic. - uint16_t next_desc_end_handle = next_characteristic == NULL - ? service->end_handle - : next_characteristic->handle - 1; - - // Stop when we go past the end of the range of handles for this service or - // discovery call returns nothing. - // discover_next_descriptors() appends to the descriptor_list. - while (next_desc_start_handle <= service->end_handle && - next_desc_start_handle <= next_desc_end_handle && - discover_next_descriptors(self, characteristic, - next_desc_start_handle, next_desc_end_handle)) { - // Get the most recently discovered descriptor, and then ask for descriptors - // whose handles start after that descriptor's handle. - const bleio_descriptor_obj_t *descriptor = characteristic->descriptor_list; - next_desc_start_handle = descriptor->handle + 1; - } - } - service = service->next; - } - - // This event handler is no longer needed. - ble_drv_remove_event_handler(discovery_on_ble_evt, self); - -} +// STATIC bool discover_next_services(bleio_connection_internal_t* connection, uint16_t start_handle, ble_uuid_t *service_uuid) { +// m_discovery_successful = false; +// m_discovery_in_process = true; + +// uint32_t nrf_err = NRF_ERROR_BUSY; +// while (nrf_err == NRF_ERROR_BUSY) { +// nrf_err = sd_ble_gattc_primary_services_discover(connection->conn_handle, start_handle, service_uuid); +// } +// check_nrf_error(nrf_err); + +// // Wait for a discovery event. +// while (m_discovery_in_process) { +// MICROPY_VM_HOOK_LOOP; +// } +// return m_discovery_successful; +// } + +// STATIC bool discover_next_characteristics(bleio_connection_internal_t* connection, bleio_service_obj_t *service, uint16_t start_handle) { +// m_char_discovery_service = service; + +// ble_gattc_handle_range_t handle_range; +// handle_range.start_handle = start_handle; +// handle_range.end_handle = service->end_handle; + +// m_discovery_successful = false; +// m_discovery_in_process = true; + +// uint32_t err_code = sd_ble_gattc_characteristics_discover(connection->conn_handle, &handle_range); +// if (err_code != NRF_SUCCESS) { +// return false; +// } + +// // Wait for a discovery event. +// while (m_discovery_in_process) { +// MICROPY_VM_HOOK_LOOP; +// } +// return m_discovery_successful; +// } + +// STATIC bool discover_next_descriptors(bleio_connection_internal_t* connection, bleio_characteristic_obj_t *characteristic, uint16_t start_handle, uint16_t end_handle) { +// m_desc_discovery_characteristic = characteristic; + +// ble_gattc_handle_range_t handle_range; +// handle_range.start_handle = start_handle; +// handle_range.end_handle = end_handle; + +// m_discovery_successful = false; +// m_discovery_in_process = true; + +// uint32_t err_code = sd_ble_gattc_descriptors_discover(connection->conn_handle, &handle_range); +// if (err_code != NRF_SUCCESS) { +// return false; +// } + +// // Wait for a discovery event. +// while (m_discovery_in_process) { +// MICROPY_VM_HOOK_LOOP; +// } +// return m_discovery_successful; +// } + +// STATIC void on_primary_srv_discovery_rsp(ble_gattc_evt_prim_srvc_disc_rsp_t *response, bleio_connection_internal_t* connection) { +// bleio_service_obj_t* tail = connection->remote_service_list; + +// for (size_t i = 0; i < response->count; ++i) { +// ble_gattc_service_t *gattc_service = &response->services[i]; + +// bleio_service_obj_t *service = m_new_obj(bleio_service_obj_t); +// service->base.type = &bleio_service_type; + +// // Initialize several fields at once. +// bleio_service_from_connection(service, bleio_connection_new_from_internal(connection)); + +// service->is_remote = true; +// service->start_handle = gattc_service->handle_range.start_handle; +// service->end_handle = gattc_service->handle_range.end_handle; +// service->handle = gattc_service->handle_range.start_handle; + +// if (gattc_service->uuid.type != BLE_UUID_TYPE_UNKNOWN) { +// // Known service UUID. +// bleio_uuid_obj_t *uuid = m_new_obj(bleio_uuid_obj_t); +// uuid->base.type = &bleio_uuid_type; +// bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_service->uuid); +// service->uuid = uuid; +// } else { +// // The discovery response contained a 128-bit UUID that has not yet been registered with the +// // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. +// // For now, just set the UUID to NULL. +// service->uuid = NULL; +// } + +// service->next = tail; +// tail = service; +// } + +// connection->remote_service_list = tail; + +// if (response->count > 0) { +// m_discovery_successful = true; +// } +// m_discovery_in_process = false; +// } + +// STATIC void on_char_discovery_rsp(ble_gattc_evt_char_disc_rsp_t *response, bleio_connection_internal_t* connection) { +// for (size_t i = 0; i < response->count; ++i) { +// ble_gattc_char_t *gattc_char = &response->chars[i]; + +// bleio_characteristic_obj_t *characteristic = m_new_obj(bleio_characteristic_obj_t); +// characteristic->base.type = &bleio_characteristic_type; + +// bleio_uuid_obj_t *uuid = NULL; + +// if (gattc_char->uuid.type != BLE_UUID_TYPE_UNKNOWN) { +// // Known characteristic UUID. +// uuid = m_new_obj(bleio_uuid_obj_t); +// uuid->base.type = &bleio_uuid_type; +// bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_char->uuid); +// } else { +// // The discovery response contained a 128-bit UUID that has not yet been registered with the +// // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. +// // For now, just leave the UUID as NULL. +// } + +// bleio_characteristic_properties_t props = +// (gattc_char->char_props.broadcast ? CHAR_PROP_BROADCAST : 0) | +// (gattc_char->char_props.indicate ? CHAR_PROP_INDICATE : 0) | +// (gattc_char->char_props.notify ? CHAR_PROP_NOTIFY : 0) | +// (gattc_char->char_props.read ? CHAR_PROP_READ : 0) | +// (gattc_char->char_props.write ? CHAR_PROP_WRITE : 0) | +// (gattc_char->char_props.write_wo_resp ? CHAR_PROP_WRITE_NO_RESPONSE : 0); + +// // Call common_hal_bleio_characteristic_construct() to initalize some fields and set up evt handler. +// common_hal_bleio_characteristic_construct( +// characteristic, m_char_discovery_service, gattc_char->handle_value, uuid, +// props, SECURITY_MODE_OPEN, SECURITY_MODE_OPEN, +// GATT_MAX_DATA_LENGTH, false, // max_length, fixed_length: values may not matter for gattc +// NULL); + +// mp_obj_list_append(m_char_discovery_service->characteristic_list, MP_OBJ_FROM_PTR(characteristic)); +// } + +// if (response->count > 0) { +// m_discovery_successful = true; +// } +// m_discovery_in_process = false; +// } + +// STATIC void on_desc_discovery_rsp(ble_gattc_evt_desc_disc_rsp_t *response, bleio_connection_internal_t* connection) { +// for (size_t i = 0; i < response->count; ++i) { +// ble_gattc_desc_t *gattc_desc = &response->descs[i]; + +// // Remember handles for certain well-known descriptors. +// switch (gattc_desc->uuid.uuid) { +// case BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG: +// m_desc_discovery_characteristic->cccd_handle = gattc_desc->handle; +// break; + +// case BLE_UUID_DESCRIPTOR_SERVER_CHAR_CONFIG: +// m_desc_discovery_characteristic->sccd_handle = gattc_desc->handle; +// break; + +// case BLE_UUID_DESCRIPTOR_CHAR_USER_DESC: +// m_desc_discovery_characteristic->user_desc_handle = gattc_desc->handle; +// break; + +// default: +// // TODO: sd_ble_gattc_descriptors_discover() can return things that are not descriptors, +// // so ignore those. +// // https://devzone.nordicsemi.com/f/nordic-q-a/49500/sd_ble_gattc_descriptors_discover-is-returning-attributes-that-are-not-descriptors +// break; +// } + +// bleio_descriptor_obj_t *descriptor = m_new_obj(bleio_descriptor_obj_t); +// descriptor->base.type = &bleio_descriptor_type; + +// bleio_uuid_obj_t *uuid = NULL; + +// if (gattc_desc->uuid.type != BLE_UUID_TYPE_UNKNOWN) { +// // Known descriptor UUID. +// uuid = m_new_obj(bleio_uuid_obj_t); +// uuid->base.type = &bleio_uuid_type; +// bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_desc->uuid); +// } else { +// // The discovery response contained a 128-bit UUID that has not yet been registered with the +// // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. +// // For now, just leave the UUID as NULL. +// } + +// common_hal_bleio_descriptor_construct( +// descriptor, m_desc_discovery_characteristic, uuid, +// SECURITY_MODE_OPEN, SECURITY_MODE_OPEN, +// GATT_MAX_DATA_LENGTH, false, mp_const_empty_bytes); +// descriptor->handle = gattc_desc->handle; + +// mp_obj_list_append(m_desc_discovery_characteristic->descriptor_list, MP_OBJ_FROM_PTR(descriptor)); +// } + +// if (response->count > 0) { +// m_discovery_successful = true; +// } +// m_discovery_in_process = false; +// } + +// STATIC bool discovery_on_ble_evt(ble_evt_t *ble_evt, mp_obj_t payload) { +// bleio_connection_internal_t* connection = MP_OBJ_TO_PTR(payload); +// switch (ble_evt->header.evt_id) { +// case BLE_GAP_EVT_DISCONNECTED: +// m_discovery_successful = false; +// m_discovery_in_process = false; +// break; + +// case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP: +// on_primary_srv_discovery_rsp(&ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp, connection); +// break; + +// case BLE_GATTC_EVT_CHAR_DISC_RSP: +// on_char_discovery_rsp(&ble_evt->evt.gattc_evt.params.char_disc_rsp, connection); +// break; + +// case BLE_GATTC_EVT_DESC_DISC_RSP: +// on_desc_discovery_rsp(&ble_evt->evt.gattc_evt.params.desc_disc_rsp, connection); +// break; + +// default: +// // CONNECTION_DEBUG_PRINTF(&mp_plat_print, "Unhandled discovery event: 0x%04x\n", ble_evt->header.evt_id); +// return false; +// break; +// } +// return true; +// } + +// STATIC void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t service_uuids_whitelist) { +// ble_drv_add_event_handler(discovery_on_ble_evt, self); + +// // Start over with an empty list. +// self->remote_service_list = NULL; + +// if (service_uuids_whitelist == mp_const_none) { +// // List of service UUID's not given, so discover all available services. + +// uint16_t next_service_start_handle = BLE_GATT_HANDLE_START; + +// while (discover_next_services(self, next_service_start_handle, MP_OBJ_NULL)) { +// // discover_next_services() appends to remote_services_list. + +// // Get the most recently discovered service, and then ask for services +// // whose handles start after the last attribute handle inside that service. +// const bleio_service_obj_t *service = self->remote_service_list; +// next_service_start_handle = service->end_handle + 1; +// } +// } else { +// mp_obj_iter_buf_t iter_buf; +// mp_obj_t iterable = mp_getiter(service_uuids_whitelist, &iter_buf); +// mp_obj_t uuid_obj; +// while ((uuid_obj = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { +// if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) { +// mp_raise_TypeError(translate("non-UUID found in service_uuids_whitelist")); +// } +// bleio_uuid_obj_t *uuid = MP_OBJ_TO_PTR(uuid_obj); + +// ble_uuid_t nrf_uuid; +// bleio_uuid_convert_to_nrf_ble_uuid(uuid, &nrf_uuid); + +// // Service might or might not be discovered; that's ok. Caller has to check +// // Central.remote_services to find out. +// // We only need to call this once for each service to discover. +// discover_next_services(self, BLE_GATT_HANDLE_START, &nrf_uuid); +// } +// } + + +// bleio_service_obj_t *service = self->remote_service_list; +// while (service != NULL) { +// // Skip the service if it had an unknown (unregistered) UUID. +// if (service->uuid == NULL) { +// service = service->next; +// continue; +// } + +// uint16_t next_char_start_handle = service->start_handle; + +// // Stop when we go past the end of the range of handles for this service or +// // discovery call returns nothing. +// // discover_next_characteristics() appends to the characteristic_list. +// while (next_char_start_handle <= service->end_handle && +// discover_next_characteristics(self, service, next_char_start_handle)) { + + +// // Get the most recently discovered characteristic, and then ask for characteristics +// // whose handles start after the last attribute handle inside that characteristic. +// const bleio_characteristic_obj_t *characteristic = +// MP_OBJ_TO_PTR(service->characteristic_list->items[service->characteristic_list->len - 1]); + +// next_char_start_handle = characteristic->handle + 1; +// } + +// // Got characteristics for this service. Now discover descriptors for each characteristic. +// size_t char_list_len = service->characteristic_list->len; +// for (size_t char_idx = 0; char_idx < char_list_len; ++char_idx) { +// bleio_characteristic_obj_t *characteristic = +// MP_OBJ_TO_PTR(service->characteristic_list->items[char_idx]); +// const bool last_characteristic = char_idx == char_list_len - 1; +// bleio_characteristic_obj_t *next_characteristic = last_characteristic +// ? NULL +// : MP_OBJ_TO_PTR(service->characteristic_list->items[char_idx + 1]); + +// // Skip the characteristic if it had an unknown (unregistered) UUID. +// if (characteristic->uuid == NULL) { +// continue; +// } + +// uint16_t next_desc_start_handle = characteristic->handle + 1; + +// // Don't run past the end of this service or the beginning of the next characteristic. +// uint16_t next_desc_end_handle = next_characteristic == NULL +// ? service->end_handle +// : next_characteristic->handle - 1; + +// // Stop when we go past the end of the range of handles for this service or +// // discovery call returns nothing. +// // discover_next_descriptors() appends to the descriptor_list. +// while (next_desc_start_handle <= service->end_handle && +// next_desc_start_handle <= next_desc_end_handle && +// discover_next_descriptors(self, characteristic, +// next_desc_start_handle, next_desc_end_handle)) { +// // Get the most recently discovered descriptor, and then ask for descriptors +// // whose handles start after that descriptor's handle. +// const bleio_descriptor_obj_t *descriptor = characteristic->descriptor_list; +// next_desc_start_handle = descriptor->handle + 1; +// } +// } +// service = service->next; +// } + +// // This event handler is no longer needed. +// ble_drv_remove_event_handler(discovery_on_ble_evt, self); + +// } mp_obj_tuple_t *common_hal_bleio_connection_discover_remote_services(bleio_connection_obj_t *self, mp_obj_t service_uuids_whitelist) { - discover_remote_services(self->connection, service_uuids_whitelist); + //FIX discover_remote_services(self->connection, service_uuids_whitelist); bleio_connection_ensure_connected(self); // Convert to a tuple and then clear the list so the callee will take ownership. mp_obj_tuple_t *services_tuple = service_linked_list_to_tuple(self->connection->remote_service_list); @@ -756,13 +757,13 @@ mp_obj_t bleio_connection_new_from_internal(bleio_connection_internal_t* interna // Find the connection that uses the given conn_handle. Return NULL if not found. bleio_connection_internal_t *bleio_conn_handle_to_connection(uint16_t conn_handle) { - bleio_connection_internal_t *connection; - for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { - connection = &bleio_connections[i]; - if (connection->conn_handle == conn_handle) { - return connection; - } - } + //FIX bleio_connection_internal_t *connection; + // for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + // connection = &bleio_connections[i]; + // if (connection->conn_handle == conn_handle) { + // return connection; + // } + // } return NULL; } diff --git a/devices/ble_hci/common-hal/_bleio/Connection.h b/devices/ble_hci/common-hal/_bleio/Connection.h index 7ad91aa5c..bb0c140c5 100644 --- a/devices/ble_hci/common-hal/_bleio/Connection.h +++ b/devices/ble_hci/common-hal/_bleio/Connection.h @@ -34,7 +34,6 @@ #include "py/objlist.h" #include "common-hal/_bleio/__init__.h" -#include "common-hal/_bleio/bonding.h" #include "shared-module/_bleio/Address.h" #include "common-hal/_bleio/Service.h" diff --git a/devices/ble_hci/common-hal/_bleio/PacketBuffer.c b/devices/ble_hci/common-hal/_bleio/PacketBuffer.c index c3f41bc9d..65d413960 100644 --- a/devices/ble_hci/common-hal/_bleio/PacketBuffer.c +++ b/devices/ble_hci/common-hal/_bleio/PacketBuffer.c @@ -36,151 +36,152 @@ #include "shared-bindings/_bleio/PacketBuffer.h" #include "supervisor/shared/tick.h" -STATIC void write_to_ringbuf(bleio_packet_buffer_obj_t *self, uint8_t *data, uint16_t len) { - if (len + sizeof(uint16_t) > ringbuf_capacity(&self->ringbuf)) { - // This shouldn't happen. - return; - } - // Push all the data onto the ring buffer. - uint8_t is_nested_critical_region; - sd_nvic_critical_region_enter(&is_nested_critical_region); - // Make room for the new value by dropping the oldest packets first. - while (ringbuf_capacity(&self->ringbuf) - ringbuf_num_filled(&self->ringbuf) < len + sizeof(uint16_t)) { - uint16_t packet_length; - ringbuf_get_n(&self->ringbuf, (uint8_t*) &packet_length, sizeof(uint16_t)); - for (uint16_t i = 0; i < packet_length; i++) { - ringbuf_get(&self->ringbuf); - } - // set an overflow flag? - } - ringbuf_put_n(&self->ringbuf, (uint8_t*) &len, sizeof(uint16_t)); - ringbuf_put_n(&self->ringbuf, data, len); - sd_nvic_critical_region_exit(is_nested_critical_region); -} - -STATIC uint32_t queue_next_write(bleio_packet_buffer_obj_t *self) { - // Queue up the next outgoing buffer. We use two, one that has been passed to the SD for - // transmission (when packet_queued is true) and the other is `pending` and can still be - // modified. By primarily appending to the `pending` buffer we can reduce the protocol overhead - // of the lower level link and ATT layers. - self->packet_queued = false; - if (self->pending_size > 0) { - uint16_t conn_handle = self->conn_handle; - uint32_t err_code; - if (self->client) { - ble_gattc_write_params_t write_params = { - .write_op = self->write_type, - .handle = self->characteristic->handle, - .p_value = self->outgoing[self->pending_index], - .len = self->pending_size, - }; - - err_code = sd_ble_gattc_write(conn_handle, &write_params); - } else { - uint16_t hvx_len = self->pending_size; - - ble_gatts_hvx_params_t hvx_params = { - .handle = self->characteristic->handle, - .type = self->write_type, - .offset = 0, - .p_len = &hvx_len, - .p_data = self->outgoing[self->pending_index], - }; - err_code = sd_ble_gatts_hvx(conn_handle, &hvx_params); - } - if (err_code != NRF_SUCCESS) { - // On error, simply skip updating the pending buffers so that the next HVC or WRITE - // complete event triggers another attempt. - return err_code; - } - self->pending_size = 0; - self->pending_index = (self->pending_index + 1) % 2; - self->packet_queued = true; - } - return NRF_SUCCESS; -} - -STATIC bool packet_buffer_on_ble_client_evt(ble_evt_t *ble_evt, void *param) { - const uint16_t evt_id = ble_evt->header.evt_id; - // Check if this is a GATTC event so we can make sure the conn_handle is valid. - if (evt_id < BLE_GATTC_EVT_BASE || evt_id > BLE_GATTC_EVT_LAST) { - return false; - } - - uint16_t conn_handle = ble_evt->evt.gattc_evt.conn_handle; - bleio_packet_buffer_obj_t *self = (bleio_packet_buffer_obj_t *) param; - if (conn_handle != self->conn_handle) { - return false; - } - switch (evt_id) { - case BLE_GATTC_EVT_HVX: { - // A remote service wrote to this characteristic. - ble_gattc_evt_hvx_t* evt_hvx = &ble_evt->evt.gattc_evt.params.hvx; - // Must be a notification, and event handle must match the handle for my characteristic. - if (evt_hvx->handle == self->characteristic->handle) { - write_to_ringbuf(self, evt_hvx->data, evt_hvx->len); - if (evt_hvx->type == BLE_GATT_HVX_INDICATION) { - sd_ble_gattc_hv_confirm(conn_handle, evt_hvx->handle); - } - } - break; - } - case BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE: { - queue_next_write(self); - break; - } - case BLE_GATTC_EVT_WRITE_RSP: { - queue_next_write(self); - break; - } - default: - return false; - break; - } - return true; -} - -STATIC bool packet_buffer_on_ble_server_evt(ble_evt_t *ble_evt, void *param) { - bleio_packet_buffer_obj_t *self = (bleio_packet_buffer_obj_t *) param; - switch (ble_evt->header.evt_id) { - case BLE_GATTS_EVT_WRITE: { - uint16_t conn_handle = ble_evt->evt.gatts_evt.conn_handle; - // A client wrote to this server characteristic. - - ble_gatts_evt_write_t *evt_write = &ble_evt->evt.gatts_evt.params.write; - - // Event handle must match the handle for my characteristic. - if (evt_write->handle == self->characteristic->handle) { - if (self->conn_handle == BLE_CONN_HANDLE_INVALID) { - self->conn_handle = conn_handle; - } else if (self->conn_handle != conn_handle) { - return false; - } - write_to_ringbuf(self, evt_write->data, evt_write->len); - } else if (evt_write->handle == self->characteristic->cccd_handle) { - uint16_t cccd = *((uint16_t*) evt_write->data); - if (cccd & BLE_GATT_HVX_NOTIFICATION) { - self->conn_handle = conn_handle; - } else { - self->conn_handle = BLE_CONN_HANDLE_INVALID; - } - } - break; - } - case BLE_GAP_EVT_DISCONNECTED: { - if (self->conn_handle == ble_evt->evt.gap_evt.conn_handle) { - self->conn_handle = BLE_CONN_HANDLE_INVALID; - } - } - case BLE_GATTS_EVT_HVN_TX_COMPLETE: { - queue_next_write(self); - } - default: - return false; - break; - } - return true; -} +// STATIC void write_to_ringbuf(bleio_packet_buffer_obj_t *self, uint8_t *data, uint16_t len) { +// if (len + sizeof(uint16_t) > ringbuf_capacity(&self->ringbuf)) { +// // This shouldn't happen. +// return; +// } +// // Push all the data onto the ring buffer. +// //FIX uint8_t is_nested_critical_region; +// //FIX sd_nvic_critical_region_enter(&is_nested_critical_region); +// // Make room for the new value by dropping the oldest packets first. +// while (ringbuf_capacity(&self->ringbuf) - ringbuf_num_filled(&self->ringbuf) < len + sizeof(uint16_t)) { +// uint16_t packet_length; +// ringbuf_get_n(&self->ringbuf, (uint8_t*) &packet_length, sizeof(uint16_t)); +// for (uint16_t i = 0; i < packet_length; i++) { +// ringbuf_get(&self->ringbuf); +// } +// // set an overflow flag? +// } +// ringbuf_put_n(&self->ringbuf, (uint8_t*) &len, sizeof(uint16_t)); +// ringbuf_put_n(&self->ringbuf, data, len); +// //FIX sd_nvic_critical_region_exit(is_nested_critical_region); +// } + +//FIX +// STATIC uint32_t queue_next_write(bleio_packet_buffer_obj_t *self) { +// // Queue up the next outgoing buffer. We use two, one that has been passed to the SD for +// // transmission (when packet_queued is true) and the other is `pending` and can still be +// // modified. By primarily appending to the `pending` buffer we can reduce the protocol overhead +// // of the lower level link and ATT layers. +// self->packet_queued = false; +// if (self->pending_size > 0) { +// uint16_t conn_handle = self->conn_handle; +// uint32_t err_code; +// if (self->client) { +// ble_gattc_write_params_t write_params = { +// .write_op = self->write_type, +// .handle = self->characteristic->handle, +// .p_value = self->outgoing[self->pending_index], +// .len = self->pending_size, +// }; + +// err_code = sd_ble_gattc_write(conn_handle, &write_params); +// } else { +// uint16_t hvx_len = self->pending_size; + +// ble_gatts_hvx_params_t hvx_params = { +// .handle = self->characteristic->handle, +// .type = self->write_type, +// .offset = 0, +// .p_len = &hvx_len, +// .p_data = self->outgoing[self->pending_index], +// }; +// err_code = sd_ble_gatts_hvx(conn_handle, &hvx_params); +// } +// if (err_code != NRF_SUCCESS) { +// // On error, simply skip updating the pending buffers so that the next HVC or WRITE +// // complete event triggers another attempt. +// return err_code; +// } +// self->pending_size = 0; +// self->pending_index = (self->pending_index + 1) % 2; +// self->packet_queued = true; +// } +// return NRF_SUCCESS; +// } + +// STATIC bool packet_buffer_on_ble_client_evt(ble_evt_t *ble_evt, void *param) { +// const uint16_t evt_id = ble_evt->header.evt_id; +// // Check if this is a GATTC event so we can make sure the conn_handle is valid. +// if (evt_id < BLE_GATTC_EVT_BASE || evt_id > BLE_GATTC_EVT_LAST) { +// return false; +// } + +// uint16_t conn_handle = ble_evt->evt.gattc_evt.conn_handle; +// bleio_packet_buffer_obj_t *self = (bleio_packet_buffer_obj_t *) param; +// if (conn_handle != self->conn_handle) { +// return false; +// } +// switch (evt_id) { +// case BLE_GATTC_EVT_HVX: { +// // A remote service wrote to this characteristic. +// ble_gattc_evt_hvx_t* evt_hvx = &ble_evt->evt.gattc_evt.params.hvx; +// // Must be a notification, and event handle must match the handle for my characteristic. +// if (evt_hvx->handle == self->characteristic->handle) { +// write_to_ringbuf(self, evt_hvx->data, evt_hvx->len); +// if (evt_hvx->type == BLE_GATT_HVX_INDICATION) { +// sd_ble_gattc_hv_confirm(conn_handle, evt_hvx->handle); +// } +// } +// break; +// } +// case BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE: { +// queue_next_write(self); +// break; +// } +// case BLE_GATTC_EVT_WRITE_RSP: { +// queue_next_write(self); +// break; +// } +// default: +// return false; +// break; +// } +// return true; +// } + +// STATIC bool packet_buffer_on_ble_server_evt(ble_evt_t *ble_evt, void *param) { +// bleio_packet_buffer_obj_t *self = (bleio_packet_buffer_obj_t *) param; +// switch (ble_evt->header.evt_id) { +// case BLE_GATTS_EVT_WRITE: { +// uint16_t conn_handle = ble_evt->evt.gatts_evt.conn_handle; +// // A client wrote to this server characteristic. + +// ble_gatts_evt_write_t *evt_write = &ble_evt->evt.gatts_evt.params.write; + +// // Event handle must match the handle for my characteristic. +// if (evt_write->handle == self->characteristic->handle) { +// if (self->conn_handle == BLE_CONN_HANDLE_INVALID) { +// self->conn_handle = conn_handle; +// } else if (self->conn_handle != conn_handle) { +// return false; +// } +// write_to_ringbuf(self, evt_write->data, evt_write->len); +// } else if (evt_write->handle == self->characteristic->cccd_handle) { +// uint16_t cccd = *((uint16_t*) evt_write->data); +// if (cccd & BLE_GATT_HVX_NOTIFICATION) { +// self->conn_handle = conn_handle; +// } else { +// self->conn_handle = BLE_CONN_HANDLE_INVALID; +// } +// } +// break; +// } +// case BLE_GAP_EVT_DISCONNECTED: { +// if (self->conn_handle == ble_evt->evt.gap_evt.conn_handle) { +// self->conn_handle = BLE_CONN_HANDLE_INVALID; +// } +// } +// case BLE_GATTS_EVT_HVN_TX_COMPLETE: { +// queue_next_write(self); +// } +// default: +// return false; +// break; +// } +// return true; +// } void common_hal_bleio_packet_buffer_construct( bleio_packet_buffer_obj_t *self, bleio_characteristic_obj_t *characteristic, @@ -218,32 +219,32 @@ void common_hal_bleio_packet_buffer_construct( self->outgoing[1] = NULL; } - if (self->client) { - ble_drv_add_event_handler(packet_buffer_on_ble_client_evt, self); - if (incoming) { - // Prefer notify if both are available. - if (incoming & CHAR_PROP_NOTIFY) { - self->write_type = BLE_GATT_HVX_NOTIFICATION; - common_hal_bleio_characteristic_set_cccd(self->characteristic, true, false); - } else { - common_hal_bleio_characteristic_set_cccd(self->characteristic, false, true); - } - } - if (outgoing) { - self->write_type = BLE_GATT_OP_WRITE_REQ; - if (outgoing & CHAR_PROP_WRITE_NO_RESPONSE) { - self->write_type = BLE_GATT_OP_WRITE_CMD; - } - } - } else { - ble_drv_add_event_handler(packet_buffer_on_ble_server_evt, self); - if (outgoing) { - self->write_type = BLE_GATT_HVX_INDICATION; - if (outgoing & CHAR_PROP_NOTIFY) { - self->write_type = BLE_GATT_HVX_NOTIFICATION; - } - } - } + //FIX if (self->client) { + // ble_drv_add_event_handler(packet_buffer_on_ble_client_evt, self); + // if (incoming) { + // // Prefer notify if both are available. + // if (incoming & CHAR_PROP_NOTIFY) { + // self->write_type = BLE_GATT_HVX_NOTIFICATION; + // common_hal_bleio_characteristic_set_cccd(self->characteristic, true, false); + // } else { + // common_hal_bleio_characteristic_set_cccd(self->characteristic, false, true); + // } + // } + // if (outgoing) { + // self->write_type = BLE_GATT_OP_WRITE_REQ; + // if (outgoing & CHAR_PROP_WRITE_NO_RESPONSE) { + // self->write_type = BLE_GATT_OP_WRITE_CMD; + // } + // } + // } else { + // ble_drv_add_event_handler(packet_buffer_on_ble_server_evt, self); + // if (outgoing) { + // self->write_type = BLE_GATT_HVX_INDICATION; + // if (outgoing & CHAR_PROP_NOTIFY) { + // self->write_type = BLE_GATT_HVX_NOTIFICATION; + // } + // } + // } } mp_int_t common_hal_bleio_packet_buffer_readinto(bleio_packet_buffer_obj_t *self, uint8_t *data, size_t len) { @@ -252,8 +253,8 @@ mp_int_t common_hal_bleio_packet_buffer_readinto(bleio_packet_buffer_obj_t *self } // Copy received data. Lock out write interrupt handler while copying. - uint8_t is_nested_critical_region; - sd_nvic_critical_region_enter(&is_nested_critical_region); + //FIX uint8_t is_nested_critical_region; + //FIX sd_nvic_critical_region_enter(&is_nested_critical_region); // Get packet length, which is in first two bytes of packet. uint16_t packet_length; @@ -274,7 +275,7 @@ mp_int_t common_hal_bleio_packet_buffer_readinto(bleio_packet_buffer_obj_t *self } // Writes now OK. - sd_nvic_critical_region_exit(is_nested_critical_region); + //FIX sd_nvic_critical_region_exit(is_nested_critical_region); return ret; } @@ -306,8 +307,8 @@ mp_int_t common_hal_bleio_packet_buffer_write(bleio_packet_buffer_obj_t *self, u size_t num_bytes_written = 0; - uint8_t is_nested_critical_region; - sd_nvic_critical_region_enter(&is_nested_critical_region); + //FIX uint8_t is_nested_critical_region; + //FIX sd_nvic_critical_region_enter(&is_nested_critical_region); uint8_t* pending = self->outgoing[self->pending_index]; @@ -320,11 +321,11 @@ mp_int_t common_hal_bleio_packet_buffer_write(bleio_packet_buffer_obj_t *self, u self->pending_size += len; num_bytes_written += len; - sd_nvic_critical_region_exit(is_nested_critical_region); + //FIX sd_nvic_critical_region_exit(is_nested_critical_region); // If no writes are queued then sneak in this data. if (!self->packet_queued) { - queue_next_write(self); + //FIX queue_next_write(self); } return num_bytes_written; } @@ -397,6 +398,6 @@ bool common_hal_bleio_packet_buffer_deinited(bleio_packet_buffer_obj_t *self) { void common_hal_bleio_packet_buffer_deinit(bleio_packet_buffer_obj_t *self) { if (!common_hal_bleio_packet_buffer_deinited(self)) { - ble_drv_remove_event_handler(packet_buffer_on_ble_client_evt, self); + //FIX ble_drv_remove_event_handler(packet_buffer_on_ble_client_evt, self); } } diff --git a/devices/ble_hci/common-hal/_bleio/Service.c b/devices/ble_hci/common-hal/_bleio/Service.c index f194a95dd..1f9649b6c 100644 --- a/devices/ble_hci/common-hal/_bleio/Service.c +++ b/devices/ble_hci/common-hal/_bleio/Service.c @@ -40,22 +40,24 @@ uint32_t _common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uu self->connection = NULL; self->is_secondary = is_secondary; - ble_uuid_t nordic_uuid; - bleio_uuid_convert_to_nrf_ble_uuid(uuid, &nordic_uuid); + //FIX + // ble_uuid_t nordic_uuid; + // bleio_uuid_convert_to_nrf_ble_uuid(uuid, &nordic_uuid); - uint8_t service_type = BLE_GATTS_SRVC_TYPE_PRIMARY; - if (is_secondary) { - service_type = BLE_GATTS_SRVC_TYPE_SECONDARY; - } + // uint8_t service_type = BLE_GATTS_SRVC_TYPE_PRIMARY; + // if (is_secondary) { + // service_type = BLE_GATTS_SRVC_TYPE_SECONDARY; + // } vm_used_ble = true; - return sd_ble_gatts_service_add(service_type, &nordic_uuid, &self->handle); + //FIX return sd_ble_gatts_service_add(service_type, &nordic_uuid, &self->handle); + return 0; } void common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uuid_obj_t *uuid, bool is_secondary) { - check_nrf_error(_common_hal_bleio_service_construct(self, uuid, is_secondary, - mp_obj_new_list(0, NULL))); + //FIX check_nrf_error(_common_hal_bleio_service_construct(self, uuid, is_secondary, + // mp_obj_new_list(0, NULL))); } void bleio_service_from_connection(bleio_service_obj_t *self, mp_obj_t connection) { @@ -86,62 +88,62 @@ bool common_hal_bleio_service_get_is_secondary(bleio_service_obj_t *self) { void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *initial_value_bufinfo) { - ble_gatts_char_md_t char_md = { - .char_props.broadcast = (characteristic->props & CHAR_PROP_BROADCAST) ? 1 : 0, - .char_props.read = (characteristic->props & CHAR_PROP_READ) ? 1 : 0, - .char_props.write_wo_resp = (characteristic->props & CHAR_PROP_WRITE_NO_RESPONSE) ? 1 : 0, - .char_props.write = (characteristic->props & CHAR_PROP_WRITE) ? 1 : 0, - .char_props.notify = (characteristic->props & CHAR_PROP_NOTIFY) ? 1 : 0, - .char_props.indicate = (characteristic->props & CHAR_PROP_INDICATE) ? 1 : 0, - }; - - ble_gatts_attr_md_t cccd_md = { - .vloc = BLE_GATTS_VLOC_STACK, - }; - - ble_uuid_t char_uuid; - bleio_uuid_convert_to_nrf_ble_uuid(characteristic->uuid, &char_uuid); - - ble_gatts_attr_md_t char_attr_md = { - .vloc = BLE_GATTS_VLOC_STACK, - .vlen = !characteristic->fixed_length, - }; - - if (char_md.char_props.notify || char_md.char_props.indicate) { - BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); - // Make CCCD write permission match characteristic read permission. - bleio_attribute_gatts_set_security_mode(&cccd_md.write_perm, characteristic->read_perm); - - char_md.p_cccd_md = &cccd_md; - } - - bleio_attribute_gatts_set_security_mode(&char_attr_md.read_perm, characteristic->read_perm); - bleio_attribute_gatts_set_security_mode(&char_attr_md.write_perm, characteristic->write_perm); - #if CIRCUITPY_VERBOSE_BLE - // Turn on read authorization so that we receive an event to print on every read. - char_attr_md.rd_auth = true; - #endif - - ble_gatts_attr_t char_attr = { - .p_uuid = &char_uuid, - .p_attr_md = &char_attr_md, - .init_len = 0, - .p_value = NULL, - .init_offs = 0, - .max_len = characteristic->max_length, - }; - - ble_gatts_char_handles_t char_handles; - - check_nrf_error(sd_ble_gatts_characteristic_add(self->handle, &char_md, &char_attr, &char_handles)); - - characteristic->user_desc_handle = char_handles.user_desc_handle; - characteristic->cccd_handle = char_handles.cccd_handle; - characteristic->sccd_handle = char_handles.sccd_handle; - characteristic->handle = char_handles.value_handle; - #if CIRCUITPY_VERBOSE_BLE - mp_printf(&mp_plat_print, "Char handle %x user %x cccd %x sccd %x\n", characteristic->handle, characteristic->user_desc_handle, characteristic->cccd_handle, characteristic->sccd_handle); - #endif - - mp_obj_list_append(self->characteristic_list, MP_OBJ_FROM_PTR(characteristic)); + // ble_gatts_char_md_t char_md = { + // .char_props.broadcast = (characteristic->props & CHAR_PROP_BROADCAST) ? 1 : 0, + // .char_props.read = (characteristic->props & CHAR_PROP_READ) ? 1 : 0, + // .char_props.write_wo_resp = (characteristic->props & CHAR_PROP_WRITE_NO_RESPONSE) ? 1 : 0, + // .char_props.write = (characteristic->props & CHAR_PROP_WRITE) ? 1 : 0, + // .char_props.notify = (characteristic->props & CHAR_PROP_NOTIFY) ? 1 : 0, + // .char_props.indicate = (characteristic->props & CHAR_PROP_INDICATE) ? 1 : 0, + // }; + + // ble_gatts_attr_md_t cccd_md = { + // .vloc = BLE_GATTS_VLOC_STACK, + // }; + + // ble_uuid_t char_uuid; + // bleio_uuid_convert_to_nrf_ble_uuid(characteristic->uuid, &char_uuid); + + // ble_gatts_attr_md_t char_attr_md = { + // .vloc = BLE_GATTS_VLOC_STACK, + // .vlen = !characteristic->fixed_length, + // }; + + // if (char_md.char_props.notify || char_md.char_props.indicate) { + // BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); + // // Make CCCD write permission match characteristic read permission. + // bleio_attribute_gatts_set_security_mode(&cccd_md.write_perm, characteristic->read_perm); + + // char_md.p_cccd_md = &cccd_md; + // } + + // bleio_attribute_gatts_set_security_mode(&char_attr_md.read_perm, characteristic->read_perm); + // bleio_attribute_gatts_set_security_mode(&char_attr_md.write_perm, characteristic->write_perm); + // #if CIRCUITPY_VERBOSE_BLE + // // Turn on read authorization so that we receive an event to print on every read. + // char_attr_md.rd_auth = true; + // #endif + + // ble_gatts_attr_t char_attr = { + // .p_uuid = &char_uuid, + // .p_attr_md = &char_attr_md, + // .init_len = 0, + // .p_value = NULL, + // .init_offs = 0, + // .max_len = characteristic->max_length, + // }; + + // ble_gatts_char_handles_t char_handles; + + // check_nrf_error(sd_ble_gatts_characteristic_add(self->handle, &char_md, &char_attr, &char_handles)); + + // characteristic->user_desc_handle = char_handles.user_desc_handle; + // characteristic->cccd_handle = char_handles.cccd_handle; + // characteristic->sccd_handle = char_handles.sccd_handle; + // characteristic->handle = char_handles.value_handle; + // #if CIRCUITPY_VERBOSE_BLE + // mp_printf(&mp_plat_print, "Char handle %x user %x cccd %x sccd %x\n", characteristic->handle, characteristic->user_desc_handle, characteristic->cccd_handle, characteristic->sccd_handle); + // #endif + + // mp_obj_list_append(self->characteristic_list, MP_OBJ_FROM_PTR(characteristic)); } diff --git a/devices/ble_hci/common-hal/_bleio/UUID.c b/devices/ble_hci/common-hal/_bleio/UUID.c index 1c6c35e47..3f5fbe4fe 100644 --- a/devices/ble_hci/common-hal/_bleio/UUID.c +++ b/devices/ble_hci/common-hal/_bleio/UUID.c @@ -37,35 +37,36 @@ // If uuid128 is not NULL, it's a 128-bit (16-byte) UUID, with bytes 12 and 13 zero'd out, where // the 16-bit part goes. Those 16 bits are passed in uuid16. void common_hal_bleio_uuid_construct(bleio_uuid_obj_t *self, uint32_t uuid16, const uint8_t uuid128[]) { - self->nrf_ble_uuid.uuid = uuid16; - if (uuid128 == NULL) { - self->nrf_ble_uuid.type = BLE_UUID_TYPE_BLE; - } else { - ble_uuid128_t vs_uuid; - memcpy(vs_uuid.uuid128, uuid128, sizeof(vs_uuid.uuid128)); + //FIX self->nrf_ble_uuid.uuid = uuid16; + // if (uuid128 == NULL) { + // self->nrf_ble_uuid.type = BLE_UUID_TYPE_BLE; + // } else { + // ble_uuid128_t vs_uuid; + // memcpy(vs_uuid.uuid128, uuid128, sizeof(vs_uuid.uuid128)); - // Register this vendor-specific UUID. Bytes 12 and 13 will be zero. - check_nrf_error(sd_ble_uuid_vs_add(&vs_uuid, &self->nrf_ble_uuid.type)); - vm_used_ble = true; - } + // // Register this vendor-specific UUID. Bytes 12 and 13 will be zero. + // check_nrf_error(sd_ble_uuid_vs_add(&vs_uuid, &self->nrf_ble_uuid.type)); + // vm_used_ble = true; + // } } uint32_t common_hal_bleio_uuid_get_size(bleio_uuid_obj_t *self) { - // return self->nrf_ble_uuid.type == BLE_UUID_TYPE_BLE ? 16 : 128; + //FIX return self->nrf_ble_uuid.type == BLE_UUID_TYPE_BLE ? 16 : 128; + return 0; } uint32_t common_hal_bleio_uuid_get_uuid16(bleio_uuid_obj_t *self) { - // return self->nrf_ble_uuid.uuid; + //FIX return self->nrf_ble_uuid.uuid; return 0; } void common_hal_bleio_uuid_get_uuid128(bleio_uuid_obj_t *self, uint8_t uuid128[16]) { - uint8_t length; - // check_nrf_error(sd_ble_uuid_encode(&self->nrf_ble_uuid, &length, uuid128)); + //FIX uint8_t length; + //FIX check_nrf_error(sd_ble_uuid_encode(&self->nrf_ble_uuid, &length, uuid128)); } void common_hal_bleio_uuid_pack_into(bleio_uuid_obj_t *self, uint8_t* buf) { - // if (self->nrf_ble_uuid.type == BLE_UUID_TYPE_BLE) { + //FIX if (self->nrf_ble_uuid.type == BLE_UUID_TYPE_BLE) { // buf[0] = self->nrf_ble_uuid.uuid & 0xff; // buf[1] = self->nrf_ble_uuid.uuid >> 8; // } else { @@ -73,6 +74,7 @@ void common_hal_bleio_uuid_pack_into(bleio_uuid_obj_t *self, uint8_t* buf) { // } } +//FIX // void bleio_uuid_construct_from_nrf_ble_uuid(bleio_uuid_obj_t *self, ble_uuid_t *nrf_ble_uuid) { // if (nrf_ble_uuid->type == BLE_UUID_TYPE_UNKNOWN) { // mp_raise_bleio_BluetoothError(translate("Unexpected nrfx uuid type")); diff --git a/devices/ble_hci/common-hal/_bleio/UUID.h b/devices/ble_hci/common-hal/_bleio/UUID.h index 584a28960..4a72d38ac 100644 --- a/devices/ble_hci/common-hal/_bleio/UUID.h +++ b/devices/ble_hci/common-hal/_bleio/UUID.h @@ -33,7 +33,7 @@ typedef struct { mp_obj_base_t base; - // Use the native way of storing UUID's: + //FIX Use the native way of storing UUID's: // - ble_uuid_t.uuid is a 16-bit uuid. // - ble_uuid_t.type is BLE_UUID_TYPE_BLE if it's a 16-bit Bluetooth SIG UUID. // or is BLE_UUID_TYPE_VENDOR_BEGIN and higher, which indexes into a table of registered diff --git a/devices/ble_hci/common-hal/_bleio/__init__.c b/devices/ble_hci/common-hal/_bleio/__init__.c index e84bba662..a09c3a05c 100644 --- a/devices/ble_hci/common-hal/_bleio/__init__.c +++ b/devices/ble_hci/common-hal/_bleio/__init__.c @@ -40,52 +40,53 @@ #include "common-hal/_bleio/__init__.h" -void check_nrf_error(uint32_t err_code) { - if (err_code == NRF_SUCCESS) { - return; - } - switch (err_code) { - case NRF_ERROR_TIMEOUT: - mp_raise_msg(&mp_type_TimeoutError, NULL); - return; - case BLE_ERROR_INVALID_CONN_HANDLE: - mp_raise_bleio_ConnectionError(translate("Not connected")); - return; - default: - mp_raise_bleio_BluetoothError(translate("Unknown soft device error: %04x"), err_code); - break; - } -} - -void check_gatt_status(uint16_t gatt_status) { - if (gatt_status == BLE_GATT_STATUS_SUCCESS) { - return; - } - switch (gatt_status) { - case BLE_GATT_STATUS_ATTERR_INSUF_AUTHENTICATION: - mp_raise_bleio_SecurityError(translate("Insufficient authentication")); - return; - case BLE_GATT_STATUS_ATTERR_INSUF_ENCRYPTION: - mp_raise_bleio_SecurityError(translate("Insufficient encryption")); - return; - default: - mp_raise_bleio_BluetoothError(translate("Unknown gatt error: 0x%04x"), gatt_status); - } -} - -void check_sec_status(uint8_t sec_status) { - if (sec_status == BLE_GAP_SEC_STATUS_SUCCESS) { - return; - } - - switch (sec_status) { - case BLE_GAP_SEC_STATUS_UNSPECIFIED: - mp_raise_bleio_SecurityError(translate("Unspecified issue. Can be that the pairing prompt on the other device was declined or ignored.")); - return; - default: - mp_raise_bleio_SecurityError(translate("Unknown security error: 0x%04x"), sec_status); - } -} +//FIX to check HCI error +// void check_nrf_error(uint32_t err_code) { +// if (err_code == NRF_SUCCESS) { +// return; +// } +// switch (err_code) { +// case NRF_ERROR_TIMEOUT: +// mp_raise_msg(&mp_type_TimeoutError, NULL); +// return; +// case BLE_ERROR_INVALID_CONN_HANDLE: +// mp_raise_bleio_ConnectionError(translate("Not connected")); +// return; +// default: +// mp_raise_bleio_BluetoothError(translate("Unknown soft device error: %04x"), err_code); +// break; +// } +// } + +// void check_gatt_status(uint16_t gatt_status) { +// if (gatt_status == BLE_GATT_STATUS_SUCCESS) { +// return; +// } +// switch (gatt_status) { +// case BLE_GATT_STATUS_ATTERR_INSUF_AUTHENTICATION: +// mp_raise_bleio_SecurityError(translate("Insufficient authentication")); +// return; +// case BLE_GATT_STATUS_ATTERR_INSUF_ENCRYPTION: +// mp_raise_bleio_SecurityError(translate("Insufficient encryption")); +// return; +// default: +// mp_raise_bleio_BluetoothError(translate("Unknown gatt error: 0x%04x"), gatt_status); +// } +// } + +// void check_sec_status(uint8_t sec_status) { +// if (sec_status == BLE_GAP_SEC_STATUS_SUCCESS) { +// return; +// } + +// switch (sec_status) { +// case BLE_GAP_SEC_STATUS_UNSPECIFIED: +// mp_raise_bleio_SecurityError(translate("Unspecified issue. Can be that the pairing prompt on the other device was declined or ignored.")); +// return; +// default: +// mp_raise_bleio_SecurityError(translate("Unknown security error: 0x%04x"), sec_status); +// } +// } // Turn off BLE on a reset or reload. void bleio_reset() { @@ -98,7 +99,7 @@ void bleio_reset() { return; } common_hal_bleio_adapter_set_enabled(&common_hal_bleio_adapter_obj, false); - bonding_reset(); + //FIX bonding_reset(); supervisor_start_bluetooth(); } @@ -121,124 +122,127 @@ size_t common_hal_bleio_gatts_read(uint16_t handle, uint16_t conn_handle, uint8_ // conn_handle is ignored unless this is a system attribute. // If we're not connected, that's OK, because we can still read and write the local value. - ble_gatts_value_t gatts_value = { - .p_value = buf, - .len = len, - }; + //FIX ble_gatts_value_t gatts_value = { + // .p_value = buf, + // .len = len, + // }; - check_nrf_error(sd_ble_gatts_value_get(conn_handle, handle, &gatts_value)); + // check_nrf_error(sd_ble_gatts_value_get(conn_handle, handle, &gatts_value)); - return gatts_value.len; + // return gatts_value.len; + return 0; } void common_hal_bleio_gatts_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo) { // conn_handle is ignored unless this is a system attribute. // If we're not connected, that's OK, because we can still read and write the local value. - ble_gatts_value_t gatts_value = { - .p_value = bufinfo->buf, - .len = bufinfo->len, - }; + //FIX ble_gatts_value_t gatts_value = { + // .p_value = bufinfo->buf, + // .len = bufinfo->len, + // }; - check_nrf_error(sd_ble_gatts_value_set(conn_handle, handle, &gatts_value)); + // check_nrf_error(sd_ble_gatts_value_set(conn_handle, handle, &gatts_value)); } -typedef struct { - uint8_t* buf; - size_t len; - size_t final_len; - uint16_t conn_handle; - volatile uint16_t status; - volatile bool done; -} read_info_t; - -STATIC bool _on_gattc_read_rsp_evt(ble_evt_t *ble_evt, void *param) { - read_info_t* read = param; - switch (ble_evt->header.evt_id) { - - // More events may be handled later, so keep this as a switch. - - case BLE_GATTC_EVT_READ_RSP: { - ble_gattc_evt_t* evt = &ble_evt->evt.gattc_evt; - ble_gattc_evt_read_rsp_t *response = &evt->params.read_rsp; - if (read && evt->conn_handle == read->conn_handle) { - read->status = evt->gatt_status; - size_t len = MIN(read->len, response->len); - memcpy(read->buf, response->data, len); - read->final_len = len; - // Indicate to busy-wait loop that we've read the attribute value. - read->done = true; - } - break; - } - - default: - // For debugging. - // mp_printf(&mp_plat_print, "Unhandled characteristic event: 0x%04x\n", ble_evt->header.evt_id); - return false; - break; - } - return true; -} +//FIX +// typedef struct { +// uint8_t* buf; +// size_t len; +// size_t final_len; +// uint16_t conn_handle; +// volatile uint16_t status; +// volatile bool done; +// } read_info_t; + +// STATIC bool _on_gattc_read_rsp_evt(ble_evt_t *ble_evt, void *param) { +// read_info_t* read = param; +// switch (ble_evt->header.evt_id) { + +// // More events may be handled later, so keep this as a switch. + +// case BLE_GATTC_EVT_READ_RSP: { +// ble_gattc_evt_t* evt = &ble_evt->evt.gattc_evt; +// ble_gattc_evt_read_rsp_t *response = &evt->params.read_rsp; +// if (read && evt->conn_handle == read->conn_handle) { +// read->status = evt->gatt_status; +// size_t len = MIN(read->len, response->len); +// memcpy(read->buf, response->data, len); +// read->final_len = len; +// // Indicate to busy-wait loop that we've read the attribute value. +// read->done = true; +// } +// break; +// } + +// default: +// // For debugging. +// // mp_printf(&mp_plat_print, "Unhandled characteristic event: 0x%04x\n", ble_evt->header.evt_id); +// return false; +// break; +// } +// return true; +// } size_t common_hal_bleio_gattc_read(uint16_t handle, uint16_t conn_handle, uint8_t* buf, size_t len) { common_hal_bleio_check_connected(conn_handle); - read_info_t read_info; - read_info.buf = buf; - read_info.len = len; - read_info.final_len = 0; - read_info.conn_handle = conn_handle; - // Set to true by the event handler. - read_info.done = false; - ble_drv_add_event_handler(_on_gattc_read_rsp_evt, &read_info); - - uint32_t nrf_error = NRF_ERROR_BUSY; - while (nrf_error == NRF_ERROR_BUSY) { - nrf_error = sd_ble_gattc_read(conn_handle, handle, 0); - } - if (nrf_error != NRF_SUCCESS) { - ble_drv_remove_event_handler(_on_gattc_read_rsp_evt, &read_info); - check_nrf_error(nrf_error); - } - - while (!read_info.done) { - RUN_BACKGROUND_TASKS; - } - - ble_drv_remove_event_handler(_on_gattc_read_rsp_evt, &read_info); - check_gatt_status(read_info.status); - return read_info.final_len; + //FIX read_info_t read_info; + // read_info.buf = buf; + // read_info.len = len; + // read_info.final_len = 0; + // read_info.conn_handle = conn_handle; + // // Set to true by the event handler. + // read_info.done = false; + // ble_drv_add_event_handler(_on_gattc_read_rsp_evt, &read_info); + + // uint32_t nrf_error = NRF_ERROR_BUSY; + // while (nrf_error == NRF_ERROR_BUSY) { + // nrf_error = sd_ble_gattc_read(conn_handle, handle, 0); + // } + // if (nrf_error != NRF_SUCCESS) { + // ble_drv_remove_event_handler(_on_gattc_read_rsp_evt, &read_info); + // check_nrf_error(nrf_error); + // } + + // while (!read_info.done) { + // RUN_BACKGROUND_TASKS; + // } + + // ble_drv_remove_event_handler(_on_gattc_read_rsp_evt, &read_info); + // check_gatt_status(read_info.status); + // return read_info.final_len; + return 0; } void common_hal_bleio_gattc_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo, bool write_no_response) { common_hal_bleio_check_connected(conn_handle); - ble_gattc_write_params_t write_params = { - .write_op = write_no_response ? BLE_GATT_OP_WRITE_CMD: BLE_GATT_OP_WRITE_REQ, - .handle = handle, - .p_value = bufinfo->buf, - .len = bufinfo->len, - }; - - while (1) { - uint32_t err_code = sd_ble_gattc_write(conn_handle, &write_params); - if (err_code == NRF_SUCCESS) { - break; - } - - // Write with response will return NRF_ERROR_BUSY if the response has not been received. - // Write without reponse will return NRF_ERROR_RESOURCES if too many writes are pending. - if (err_code == NRF_ERROR_BUSY || err_code == NRF_ERROR_RESOURCES) { - // We could wait for an event indicating the write is complete, but just retrying is easier. - MICROPY_VM_HOOK_LOOP; - continue; - } - - // Some real error occurred. - check_nrf_error(err_code); - } - + //FIX + // ble_gattc_write_params_t write_params = { + // .write_op = write_no_response ? BLE_GATT_OP_WRITE_CMD: BLE_GATT_OP_WRITE_REQ, + // .handle = handle, + // .p_value = bufinfo->buf, + // .len = bufinfo->len, + // }; + + // while (1) { + // uint32_t err_code = sd_ble_gattc_write(conn_handle, &write_params); + // if (err_code == NRF_SUCCESS) { + // break; + // } + + // // Write with response will return NRF_ERROR_BUSY if the response has not been received. + // // Write without reponse will return NRF_ERROR_RESOURCES if too many writes are pending. + // if (err_code == NRF_ERROR_BUSY || err_code == NRF_ERROR_RESOURCES) { + // // We could wait for an event indicating the write is complete, but just retrying is easier. + // MICROPY_VM_HOOK_LOOP; + // continue; + // } + + // // Some real error occurred. + // check_nrf_error(err_code); + // } } void common_hal_bleio_gc_collect(void) { diff --git a/devices/ble_hci/common-hal/_bleio/__init__.h b/devices/ble_hci/common-hal/_bleio/__init__.h index 77548dac1..784dcefdc 100644 --- a/devices/ble_hci/common-hal/_bleio/__init__.h +++ b/devices/ble_hci/common-hal/_bleio/__init__.h @@ -27,6 +27,8 @@ #ifndef MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_INIT_H #define MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_INIT_H +#include + void bleio_reset(void); typedef struct { @@ -39,6 +41,13 @@ typedef struct { // 20 bytes max (23 - 3). #define GATT_MAX_DATA_LENGTH (BLE_GATT_ATT_MTU_DEFAULT - 3) +//FIX +#define BLE_GATT_HANDLE_INVALID 0x0000 +#define BLE_CONN_HANDLE_INVALID 0xFFFF +#define BLE_GATTS_FIX_ATTR_LEN_MAX (510) /**< Maximum length for fixed length Attribute Values. */ +#define BLE_GATTS_VAR_ATTR_LEN_MAX (512) /**< Maximum length for variable length Attribute Values. */ + + // These helpers raise the appropriate exceptions if the code doesn't equal success. void check_nrf_error(uint32_t err_code); void check_gatt_status(uint16_t gatt_status); diff --git a/devices/ble_hci/common-hal/_bleio/bonding.c b/devices/ble_hci/common-hal/_bleio/bonding.c deleted file mode 100644 index d03e418f7..000000000 --- a/devices/ble_hci/common-hal/_bleio/bonding.c +++ /dev/null @@ -1,306 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include -#include -#include - -#include "shared-bindings/_bleio/__init__.h" -#include "shared-bindings/_bleio/Adapter.h" -#include "shared-bindings/nvm/ByteArray.h" -#include "supervisor/shared/tick.h" - -#include "bonding.h" - -// Internal flash area reserved for bonding storage. -#define BONDING_PAGES_START_ADDR CIRCUITPY_BLE_CONFIG_START_ADDR -#define BONDING_PAGES_END_ADDR (CIRCUITPY_BLE_CONFIG_START_ADDR + CIRCUITPY_BLE_CONFIG_SIZE) - -// First and last four bytes are magic bytes for id and version. Data is in between. -// 'BD01' -const uint32_t BONDING_FLAG = ('1' | '0' << 8 | 'D' << 16 | 'B' << 24); - -#define BONDING_DATA_START_ADDR (BONDING_PAGES_START_ADDR + sizeof(BONDING_FLAG)) -#define BONDING_DATA_END_ADDR (BONDING_PAGES_END_ADDR - sizeof(BONDING_FLAG)) - -#define BONDING_START_FLAG_ADDR BONDING_PAGES_START_ADDR -#define BONDING_END_FLAG_ADDR BONDING_DATA_END_ADDR - -// Save both system and user service info. -#define SYS_ATTR_FLAGS (BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS | BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS) - -#if BONDING_DEBUG -void bonding_print_block(bonding_block_t *block) { - printf("at 0x%08lx: is_central: %1d, type: 0x%x, ediv: 0x%04x, data_length: %d\n", - (uint32_t) block, block->is_central, block->type, block->ediv, block->data_length); -} - -void bonding_print_keys(bonding_keys_t *keys) { - for (size_t i = 0; i < sizeof(bonding_keys_t); i ++) { - printf("%x", ((uint8_t*) keys)[i]); - } - printf("\n"); -} -#endif - -STATIC size_t compute_block_size(uint16_t data_length) { - // Round data size up to the nearest 32-bit address. - return sizeof(bonding_block_t) + ((data_length + 3) & ~0x3); -} - -void bonding_erase_storage(void) { - // Erase all pages in the bonding area. - for(uint32_t page_address = BONDING_PAGES_START_ADDR; - page_address < BONDING_PAGES_END_ADDR; - page_address += FLASH_PAGE_SIZE) { - // Argument is page number, not address. - sd_flash_page_erase_sync(page_address / FLASH_PAGE_SIZE); - } - // Write marker words at the beginning and the end of the bonding area. - uint32_t flag = BONDING_FLAG; - sd_flash_write_sync((uint32_t *) BONDING_START_FLAG_ADDR, &flag, 1); - sd_flash_write_sync((uint32_t *) BONDING_END_FLAG_ADDR, &flag, 1); -} - -// Given NULL to start or block address, return the address of the next valid block. -// The last block returned is the unused block at the end. -// Return NULL if we have run off the end of the bonding space. - -STATIC bonding_block_t *next_block(bonding_block_t *block) { - while (1) { - // Advance to next block. - if (block == NULL) { - return (bonding_block_t *) BONDING_DATA_START_ADDR; - } else if (block->type == BLOCK_UNUSED) { - // Already at last block (the unused block). - return NULL; - } - - // Advance to next block. - block = (bonding_block_t *) ((uint8_t *) block + compute_block_size(block->data_length)); - - if (block >= (bonding_block_t *) BONDING_DATA_END_ADDR) { - // Went past end of bonding space. - return NULL; - } - if (block->type != BLOCK_INVALID) { - // Found an empty or a valid block. - return block; - } - // Invalid block (was erased); try again. - } -} - -// Find the block with given is_central, type and ediv value. -// If type == BLOCK_UNUSED, ediv is ignored and the the sole unused block at the end is returned. -// If not found, return NULL. -STATIC bonding_block_t *find_existing_block(bool is_central, bonding_block_type_t type, uint16_t ediv) { - bonding_block_t *block = NULL; - while (1) { - block = next_block(block); - if (block == NULL) { - return NULL; - } - // If types match, and block is unused, just return it. - // Otherwise check that is_central and ediv match. - if (type == block->type) { - if (type == BLOCK_UNUSED || - (is_central == block->is_central && ediv == block->ediv)) { - return block; - } - } - } -} - -// Get an empty block large enough to store data_length data. -STATIC bonding_block_t* find_unused_block(uint16_t data_length) { - bonding_block_t *unused_block = find_existing_block(true, BLOCK_UNUSED, EDIV_INVALID); - // If no more room, erase all existing blocks and start over. - if (!unused_block || - (uint8_t *) unused_block + compute_block_size(data_length) >= (uint8_t *) BONDING_DATA_END_ADDR) { - bonding_erase_storage(); - unused_block = (bonding_block_t *) BONDING_DATA_START_ADDR; - } - return unused_block; -} - -// Set the header word to all 0's, to mark the block as invalid. -// We don't change data_length, so we can still skip over this block. -STATIC void invalidate_block(bonding_block_t *block) { - uint32_t zero = 0; - sd_flash_write_sync((uint32_t *) block, &zero, 1); -} - -// Write bonding block header. -STATIC void write_block_header(bonding_block_t *dest_block, bonding_block_t *source_block_header) { - sd_flash_write_sync((uint32_t *) dest_block, (uint32_t *) source_block_header, sizeof(bonding_block_t) / 4); -} - -// Write variable-length data at end of bonding block. -STATIC void write_block_data(bonding_block_t *dest_block, uint8_t *data, uint16_t data_length) { - // Minimize the number of writes. Datasheet says no more than two writes per word before erasing again. - - // Start writing after the current header. - uint32_t *flash_word_p = (uint32_t *) ((uint8_t *) dest_block + sizeof(bonding_block_t)); - while (1) { - uint32_t word = 0xffffffff; - memcpy(&word, data, data_length >= 4 ? 4 : data_length); - sd_flash_write_sync(flash_word_p, &word, 1); - if (data_length <= 4) { - break; - } - data_length -= 4; - data += 4; - // Increment by word size. - flash_word_p++; - } -} - -STATIC void write_sys_attr_block(bleio_connection_internal_t *connection) { - uint16_t length = 0; - // First find out how big a buffer we need, then fetch the data. - if(sd_ble_gatts_sys_attr_get(connection->conn_handle, NULL, &length, SYS_ATTR_FLAGS) != NRF_SUCCESS) { - return; - } - uint8_t sys_attr[length]; - if(sd_ble_gatts_sys_attr_get(connection->conn_handle, sys_attr, &length, SYS_ATTR_FLAGS) != NRF_SUCCESS) { - return; - } - - // Is there an existing sys_attr block that matches the current sys_attr data? - bonding_block_t *existing_block = - find_existing_block(connection->is_central, BLOCK_SYS_ATTR, connection->ediv); - if (existing_block) { - if (length == existing_block->data_length && - memcmp(sys_attr, existing_block->data, length) == 0) { - // Identical block found. No need to store again. - return; - } - // Data doesn't match. Invalidate block and store a new one. - invalidate_block(existing_block); - } - - bonding_block_t block_header = { - .is_central = connection->is_central, - .type = BLOCK_SYS_ATTR, - .ediv = connection->ediv, - .conn_handle = connection->conn_handle, - .data_length = length, - }; - bonding_block_t *new_block = find_unused_block(length); - write_block_header(new_block, &block_header); - write_block_data(new_block, sys_attr, length); - return; -} - -STATIC void write_keys_block(bleio_connection_internal_t *connection) { - uint16_t const ediv = connection->is_central - ? connection->bonding_keys.peer_enc.master_id.ediv - : connection->bonding_keys.own_enc.master_id.ediv; - - // Is there an existing keys block that matches? - bonding_block_t *existing_block = find_existing_block(connection->is_central, BLOCK_KEYS, ediv); - if (existing_block) { - if (existing_block->data_length == sizeof(bonding_keys_t) && - memcmp(existing_block->data, &connection->bonding_keys, sizeof(bonding_keys_t)) == 0) { - // Identical block found. No need to store again. - return; - } - // Data doesn't match. Invalidate block and store a new one. - invalidate_block(existing_block); - } - - bonding_block_t block_header = { - .is_central = connection->is_central, - .type = BLOCK_KEYS, - .ediv = ediv, - .conn_handle = connection->conn_handle, - .data_length = sizeof(bonding_keys_t), - }; - bonding_block_t *new_block = find_unused_block(sizeof(bonding_keys_t)); - write_block_header(new_block, &block_header); - write_block_data(new_block, (uint8_t *) &connection->bonding_keys, sizeof(bonding_keys_t)); -} - -void bonding_clear_keys(bonding_keys_t *bonding_keys) { - memset((uint8_t*) bonding_keys, 0, sizeof(bonding_keys_t)); -} - -void bonding_reset(void) { - if (BONDING_FLAG != *((uint32_t *) BONDING_START_FLAG_ADDR) || - BONDING_FLAG != *((uint32_t *) BONDING_END_FLAG_ADDR)) { - bonding_erase_storage(); - } -} - -// Write bonding blocks to flash. Requests have been queued during evt handlers. -void bonding_background(void) { - // A paired connection will request that its keys and CCCD values be stored. - // The CCCD store whenever a CCCD value is written. - for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { - bleio_connection_internal_t *connection = &bleio_connections[i]; - - // Wait at least one second before saving CCCD, to consolidate - // writes that involve multiple CCCDs. For instance, for HID, - // three CCCD's are set in short succession by the HID client. - if (connection->do_bond_cccds) { - uint64_t current_ticks_ms = supervisor_ticks_ms64(); - if (current_ticks_ms - connection->do_bond_cccds_request_time >= 1000) { - write_sys_attr_block(connection); - connection->do_bond_cccds = false; - } - } - - if (connection->do_bond_keys) { - write_keys_block(connection); - connection->do_bond_keys = false; - } - } -} - -bool bonding_load_cccd_info(bool is_central, uint16_t conn_handle, uint16_t ediv) { - bonding_block_t *block = find_existing_block(is_central, BLOCK_SYS_ATTR, ediv); - if (block == NULL) { - return false; - } - - return NRF_SUCCESS == - sd_ble_gatts_sys_attr_set(conn_handle, block->data, block->data_length, SYS_ATTR_FLAGS); -} - -bool bonding_load_keys(bool is_central, uint16_t ediv, bonding_keys_t *bonding_keys) { - bonding_block_t *block = find_existing_block(is_central, BLOCK_KEYS, ediv); - if (block == NULL) { - return false; - } - if (sizeof(bonding_keys_t) != block->data_length) { - // bonding_keys_t is a fixed length, so lengths should match. - return false; - } - - memcpy(bonding_keys, block->data, block->data_length); - return true; -} diff --git a/devices/ble_hci/common-hal/_bleio/bonding.h b/devices/ble_hci/common-hal/_bleio/bonding.h deleted file mode 100644 index 7fa66972d..000000000 --- a/devices/ble_hci/common-hal/_bleio/bonding.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_BONDING_H -#define MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_BONDING_H - -#include -#include -#include - -#include "common-hal/_bleio/__init__.h" - -#define EDIV_INVALID (0xffff) - -#define BONDING_DEBUG (1) -#if BONDING_DEBUG - #define BONDING_DEBUG_PRINTF(...) printf(__VA_ARGS__) - #define BONDING_DEBUG_PRINT_BLOCK(block) bonding_print_block(block) - #define BONDING_DEBUG_PRINT_KEYS(keys) bonding_print_keys(keys) -#else - #define BONDING_DEBUG_PRINTF(...) - #define BONDING_DEBUG_PRINT_BLOCK(block) - #define BONDING_DEBUG_PRINT_KEYS(keys) -#endif - -// Bonding data is stored in variable-length blocks consecutively in -// erased flash (all 1's). The blocks are 32-bit aligned, though the -// data may be any number of bytes. We hop through the blocks using -// the size field to find the next block. When we hit a word that is -// all 1's, we have reached the end of the blocks. We can write a new -// block there. - -typedef enum { - BLOCK_INVALID = 0, // Ignore this block - BLOCK_KEYS = 1, // Block contains bonding keys. - BLOCK_SYS_ATTR = 2, // Block contains sys_attr values (CCCD settings, etc.). - BLOCK_UNUSED = 0xff, // Initial erased value. -} bonding_block_type_t; - -typedef struct { - bool is_central: 1; // 1 if data is for a central role. - uint16_t reserved: 7; // Not currently used - bonding_block_type_t type: 8; // What kind of data is stored in. - uint16_t ediv; // ediv value; used as a lookup key. - uint16_t conn_handle; // Connection handle: used when a BLOCK_SYS_ATTR is queued to write. - // Not used as a key, etc. - uint16_t data_length; // Length of data in bytes, including ediv, not including padding. - // End of block header. 32-bit boundary here. - uint8_t data[]; // Rest of data in the block. Needs to be 32-bit aligned. - // Block is padded to 32-bit alignment. -} bonding_block_t; - -void bonding_background(void); -void bonding_erase_storage(void); -void bonding_reset(void); -void bonding_clear_keys(bonding_keys_t *bonding_keys); -bool bonding_load_cccd_info(bool is_central, uint16_t conn_handle, uint16_t ediv); -bool bonding_load_keys(bool is_central, uint16_t ediv, bonding_keys_t *bonding_keys); - -#endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_BONDING_H diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 811de7866..38ef37312 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -317,6 +317,13 @@ SRC_COMMON_HAL_ALL = \ watchdog/WatchDogTimer.c \ watchdog/__init__.c \ +ifeq ($(CIRCUITPY_BLEIO_HCI),1) +SRC_C +=\ + common_hal/_bleio/hci.c \ + +endif + + SRC_COMMON_HAL = $(filter $(SRC_PATTERNS), $(SRC_COMMON_HAL_ALL)) # These don't have corresponding files in each port but are still located in @@ -463,6 +470,11 @@ $(filter $(SRC_PATTERNS), \ displayio/display_core.c \ ) +SRC_COMMON_HAL_INTERNAL = \ +$(filter $(SRC_PATTERNS), \ + _bleio/ \ +) + ifeq ($(INTERNAL_LIBM),1) SRC_LIBM = \ $(addprefix lib/,\ diff --git a/shared-bindings/_bleio/Adapter.c b/shared-bindings/_bleio/Adapter.c index 0780e0a32..cf3b62ff1 100644 --- a/shared-bindings/_bleio/Adapter.c +++ b/shared-bindings/_bleio/Adapter.c @@ -90,10 +90,10 @@ STATIC mp_obj_t bleio_adapter_make_new(const mp_obj_type_t *type, size_t n_args, { MP_QSTR_cts, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 115200 } }, { MP_QSTR_buffer_size, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 256 } }, - { MP_QSTR_spi_cs, MP_ARG_KW_ONLY }| MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_gpio0, MP_ARG_KW_ONLY }| MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_reset, MP_ARG_KW_ONLY }| MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_reset_high, MP_ARG_KW_ONLY |MP_ARG_BOOL }, + { MP_QSTR_spi_cs, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_gpio0, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_reset, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_reset_high, MP_ARG_KW_ONLY | MP_ARG_BOOL }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -108,13 +108,23 @@ STATIC mp_obj_t bleio_adapter_make_new(const mp_obj_type_t *type, size_t n_args, const mcu_pin_obj_t *reset = validate_obj_is_free_pin(args[ARG_reset].u_obj); const bool reset_high = args[ARG_reset_high].u_bool; + if (args[ARG_baudrate].u_int <= 0) { + mp_raise_ValueError(translate("baudrate must be > 0")); + } + const uint32_t baudrate = args[ARG_baudrate].u_int; + + if (args[ARG_buffer_size].u_int <= 1) { + mp_raise_ValueError(translate("buffer_size must be >= 1")); + } + const uint32_t buffer_size = args[ARG_buffer_size].u_int; + common_hal_bleio_adapter_construct(&common_hal_bleio_adapter_obj, tx, rx, rts, cts, - args[ARG_baudrate], arg[ARG_buffer_size], + baudrate, buffer_size, spi_cs, gpio0, reset, reset_high); common_hal_bleio_adapter_set_enabled(&common_hal_bleio_adapter_obj, true); - return MP_OBJ_FROM_PTR(service); + return MP_OBJ_FROM_PTR(&common_hal_bleio_adapter_obj); } #endif //| diff --git a/shared-bindings/_bleio/Adapter.h b/shared-bindings/_bleio/Adapter.h index 39147b6eb..3f7cd5430 100644 --- a/shared-bindings/_bleio/Adapter.h +++ b/shared-bindings/_bleio/Adapter.h @@ -37,6 +37,10 @@ const mp_obj_type_t bleio_adapter_type; +#if CIRCUITPY_BLEIO_HCI +void common_hal_bleio_adapter_construct(bleio_adapter_obj_t *self, const mcu_pin_obj_t *tx, const mcu_pin_obj_t *rx, const mcu_pin_obj_t *rts, const mcu_pin_obj_t *cts, uint32_t baudrate, uint32_t buffer_size, const mcu_pin_obj_t* spi_cs, const mcu_pin_obj_t* gpio0, const mcu_pin_obj_t *reset, bool reset_high); +#endif + extern bool common_hal_bleio_adapter_get_advertising(bleio_adapter_obj_t *self); extern bool common_hal_bleio_adapter_get_enabled(bleio_adapter_obj_t *self); extern void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enabled); -- cgit v1.2.3 From 11cb3e3b4b18a12b56f926f342c65c0f7db93896 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 30 Jun 2020 23:19:40 -0400 Subject: hci skeleton done; not working yet --- devices/ble_hci/common-hal/_bleio/Adapter.c | 46 +- devices/ble_hci/common-hal/_bleio/Adapter.h | 12 +- devices/ble_hci/common-hal/_bleio/hci.c | 1015 +++++++++++++-------------- ports/atmel-samd/Makefile | 2 +- py/circuitpy_defns.mk | 4 +- shared-bindings/_bleio/Adapter.c | 14 +- shared-bindings/_bleio/__init__.c | 3 + 7 files changed, 567 insertions(+), 529 deletions(-) (limited to 'py') diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index c25bec5b8..5f5259f7e 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.c +++ b/devices/ble_hci/common-hal/_bleio/Adapter.c @@ -31,6 +31,8 @@ #include #include +#include "hci.h" + #include "py/gc.h" #include "py/mphal.h" #include "py/objstr.h" @@ -178,10 +180,10 @@ char default_ble_name[] = { 'C', 'I', 'R', 'C', 'U', 'I', 'T', 'P', 'Y', 0, 0, 0 // } void common_hal_bleio_adapter_hci_init(bleio_adapter_obj_t *self, const mcu_pin_obj_t *tx, const mcu_pin_obj_t *rx, const mcu_pin_obj_t *rts, const mcu_pin_obj_t *cts, uint32_t baudrate, uint32_t buffer_size) { - self->tx = tx; - self->rx = rx; - self->rts = rts; - self->cts = cts; + self->tx_pin = tx; + self->rx_pin = rx; + self->rts_pin = rts; + self->cts_pin = cts; self->baudrate = baudrate; self->buffer_size = buffer_size; self->enabled = false; @@ -195,6 +197,35 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable return; } + if (enabled) { + common_hal_busio_uart_construct( + &self->hci_uart, + self->tx_pin, // tx pin + self->rx_pin, // rx pin + NULL, // rts pin + NULL, // cts pin + NULL, // rs485 dir pin + false, // rs485 invert + 0, // timeout + self->baudrate, // baudrate + 8, // nbits + PARITY_NONE, // parity + 1, // stop bits + self->buffer_size, // buffer size + NULL, // buffer + false // sigint_enabled + ); + common_hal_digitalio_digitalinout_construct(&self->rts_digitalinout, self->rts_pin); + common_hal_digitalio_digitalinout_construct(&self->cts_digitalinout, self->cts_pin); + + hci_init(self); + } else { + common_hal_busio_uart_deinit(&self->hci_uart); + common_hal_digitalio_digitalinout_deinit(&self->rts_digitalinout); + common_hal_digitalio_digitalinout_deinit(&self->cts_digitalinout); + } + + //FIX enable/disable HCI adapter, but don't reset it, since we don't know how. self->enabled = enabled; } @@ -206,13 +237,14 @@ bool common_hal_bleio_adapter_get_enabled(bleio_adapter_obj_t *self) { bleio_address_obj_t *common_hal_bleio_adapter_get_address(bleio_adapter_obj_t *self) { common_hal_bleio_adapter_set_enabled(self, true); - // ble_gap_addr_t local_address; - // get_address(self, &local_address); + uint8_t addr[6]; + hci_readBdAddr(addr); bleio_address_obj_t *address = m_new_obj(bleio_address_obj_t); address->base.type = &bleio_address_type; - // common_hal_bleio_address_construct(address, local_address.addr, local_address.addr_type); + // 0 is the type designating a public address. + common_hal_bleio_address_construct(address, addr, 0); return address; } diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.h b/devices/ble_hci/common-hal/_bleio/Adapter.h index 38303062a..565963dc0 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.h +++ b/devices/ble_hci/common-hal/_bleio/Adapter.h @@ -52,15 +52,15 @@ typedef struct { bleio_scanresults_obj_t* scan_results; mp_obj_t name; mp_obj_tuple_t *connection_objs; - const mcu_pin_obj_t* tx; - const mcu_pin_obj_t* rx; - const mcu_pin_obj_t* rts; - const mcu_pin_obj_t* cts; + const mcu_pin_obj_t* tx_pin; + const mcu_pin_obj_t* rx_pin; + const mcu_pin_obj_t* rts_pin; + const mcu_pin_obj_t* cts_pin; uint32_t baudrate; uint16_t buffer_size; busio_uart_obj_t hci_uart; - digitalio_digitalinout_obj_t rts_digitalio; - digitalio_digitalinout_obj_t cts_digitalio; + digitalio_digitalinout_obj_t rts_digitalinout; + digitalio_digitalinout_obj_t cts_digitalinout; bool enabled; } bleio_adapter_obj_t; diff --git a/devices/ble_hci/common-hal/_bleio/hci.c b/devices/ble_hci/common-hal/_bleio/hci.c index 8ff69f202..7d4add9af 100644 --- a/devices/ble_hci/common-hal/_bleio/hci.c +++ b/devices/ble_hci/common-hal/_bleio/hci.c @@ -1,3 +1,6 @@ +/* + This file is part of the ArduinoBLE library. + Copyright (c) 2018 Arduino SA. All rights reserved. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -9,7 +12,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "HCI.h" +#include "hci.h" +#include + +#include "supervisor/shared/tick.h" + +#define ATT_CID 0x0004 #define HCI_COMMAND_PKT 0x01 #define HCI_ACLDATA_PKT 0x02 @@ -59,617 +67,608 @@ #define HCI_OE_USER_ENDED_CONNECTION 0x13 -HCIClass::HCIClass() : - _debug(NULL), - _recvIndex(0), - _pendingPkt(0) + +#define RECV_BUFFER_SIZE (3 + 255) +#define ACL_PKT_BUFFER_SIZE (255) + +STATIC bleio_adapter_obj_t *adapter; + +STATIC int recv_idx; +STATIC uint8_t recv_buffer[RECV_BUFFER_SIZE]; +STATIC uint16_t cmd_complete_opcode; +STATIC int cmd_complete_status; +STATIC uint8_t cmd_response_len; +STATIC uint8_t* cmd_response; + +STATIC uint8_t max_pkt; +STATIC uint8_t pending_pkt; + +//FIX STATIC uint8_t acl_pkt_buffer[255]; + +STATIC bool debug = true; + +typedef struct __attribute__ ((packed)) { + uint8_t evt; + uint8_t plen; +} HCIEventHdr; + +STATIC void dumpPkt(const char* prefix, uint8_t plen, uint8_t pdata[]) { + if (debug) { + mp_printf(&mp_plat_print, "%s", prefix); + + for (uint8_t i = 0; i < plen; i++) { + mp_printf(&mp_plat_print, "%02x", pdata[i]); + } + mp_printf(&mp_plat_print, "\n"); + } } -HCIClass::~HCIClass() + +STATIC void handleAclDataPkt(uint8_t plen, uint8_t pdata[]) { + // typedef struct __attribute__ ((packed)) { + // uint16_t handle; + // uint16_t dlen; + // uint16_t len; + // uint16_t cid; + // } HCIACLHdr; + + // HCIACLHdr *aclHdr = (HCIACLHdr*)pdata; + + // uint16_t aclFlags = (aclHdr->handle & 0xf000) >> 12; + + // if ((aclHdr->dlen - 4) != aclHdr->len) { + // // packet is fragmented + // if (aclFlags != 0x01) { + // // copy into ACL buffer + // memcpy(acl_pkt_buffer, &recv_buffer[1], sizeof(HCIACLHdr) + aclHdr->dlen - 4); + // } else { + // // copy next chunk into the buffer + // HCIACLHdr* aclBufferHeader = (HCIACLHdr*)acl_pkt_buffer; + + // memcpy(&acl_pkt_buffer[sizeof(HCIACLHdr) + aclBufferHeader->dlen - 4], &recv_buffer[1 + sizeof(aclHdr->handle) + sizeof(aclHdr->dlen)], aclHdr->dlen); + + // aclBufferHeader->dlen += aclHdr->dlen; + // aclHdr = aclBufferHeader; + // } + // } + + // if ((aclHdr->dlen - 4) != aclHdr->len) { + // // don't have the full packet yet + // return; + // } + + // if (aclHdr->cid == ATT_CID) { + // if (aclFlags == 0x01) { + // // use buffered packet + // ATT.handleData(aclHdr->handle & 0x0fff, aclHdr->len, &acl_pkt_buffer[sizeof(HCIACLHdr)]); + // } else { + // // use the recv buffer + // ATT.handleData(aclHdr->handle & 0x0fff, aclHdr->len, &recv_buffer[1 + sizeof(HCIACLHdr)]); + // } + // } else if (aclHdr->cid == SIGNALING_CID) { + // L2CAPSignaling.handleData(aclHdr->handle & 0x0fff, aclHdr->len, &recv_buffer[1 + sizeof(HCIACLHdr)]); + // } else { + // struct __attribute__ ((packed)) { + // uint8_t op; + // uint8_t id; + // uint16_t length; + // uint16_t reason; + // uint16_t localCid; + // uint16_t remoteCid; + // } l2capRejectCid= { 0x01, 0x00, 0x006, 0x0002, aclHdr->cid, 0x0000 }; + + // sendAclPkt(aclHdr->handle & 0x0fff, 0x0005, sizeof(l2capRejectCid), &l2capRejectCid); + // } } -int HCIClass::begin() +STATIC void handleNumCompPkts(uint16_t handle, uint16_t numPkts) { - _recvIndex = 0; - - return HCITransport.begin(); + if (numPkts && pending_pkt > numPkts) { + pending_pkt -= numPkts; + } else { + pending_pkt = 0; + } } -void HCIClass::end() +STATIC void handleEventPkt(uint8_t plen, uint8_t pdata[]) { - HCITransport.end(); + HCIEventHdr *eventHdr = (HCIEventHdr*)pdata; + + if (eventHdr->evt == EVT_DISCONN_COMPLETE) { + typedef struct __attribute__ ((packed)) { + uint8_t status; + uint16_t handle; + uint8_t reason; + } DisconnComplete; + + DisconnComplete *disconnComplete = (DisconnComplete*)&pdata[sizeof(HCIEventHdr)]; + (void) disconnComplete; + //FIX + // ATT.removeConnection(disconnComplete->handle, disconnComplete->reason); + // L2CAPSignaling.removeConnection(disconnComplete->handle, disconnComplete->reason); + + hci_leSetAdvertiseEnable(0x01); + } else if (eventHdr->evt == EVT_CMD_COMPLETE) { + typedef struct __attribute__ ((packed)) { + uint8_t ncmd; + uint16_t opcode; + uint8_t status; + } CmdComplete; + + CmdComplete *cmdCompleteHeader = (CmdComplete*)&pdata[sizeof(HCIEventHdr)]; + cmd_complete_opcode = cmdCompleteHeader->opcode; + cmd_complete_status = cmdCompleteHeader->status; + cmd_response_len = pdata[1] - sizeof(CmdComplete); + cmd_response = &pdata[sizeof(HCIEventHdr) + sizeof(CmdComplete)]; + + } else if (eventHdr->evt == EVT_CMD_STATUS) { + typedef struct __attribute__ ((packed)) { + uint8_t status; + uint8_t ncmd; + uint16_t opcode; + } CmdStatus; + + CmdStatus *cmdStatusHeader = (CmdStatus*)&pdata[sizeof(HCIEventHdr)]; + cmd_complete_opcode = cmdStatusHeader->opcode; + cmd_complete_status = cmdStatusHeader->status; + cmd_response_len = 0; + } else if (eventHdr->evt == EVT_NUM_COMP_PKTS) { + uint8_t numHandles = pdata[sizeof(HCIEventHdr)]; + uint8_t* data = &pdata[sizeof(HCIEventHdr) + sizeof(numHandles)]; + + for (uint8_t i = 0; i < numHandles; i++) { + handleNumCompPkts(data[0], data[1]); + + data += 2; + } + } else if (eventHdr->evt == EVT_LE_META_EVENT) { + typedef struct __attribute__ ((packed)) { + uint8_t subevent; + } LeMetaEventHeader; + + LeMetaEventHeader *leMetaHeader = (LeMetaEventHeader*)&pdata[sizeof(HCIEventHdr)]; + if (leMetaHeader->subevent == EVT_LE_CONN_COMPLETE) { + typedef struct __attribute__ ((packed)) { + uint8_t status; + uint16_t handle; + uint8_t role; + uint8_t peerBdaddrType; + uint8_t peerBdaddr[6]; + uint16_t interval; + uint16_t latency; + uint16_t supervisionTimeout; + uint8_t masterClockAccuracy; + } EvtLeConnectionComplete; + + EvtLeConnectionComplete *leConnectionComplete = (EvtLeConnectionComplete*)&pdata[sizeof(HCIEventHdr) + sizeof(LeMetaEventHeader)]; + + if (leConnectionComplete->status == 0x00) { + // ATT.addConnection(leConnectionComplete->handle, + // leConnectionComplete->role, + // leConnectionComplete->peerBdaddrType, + // leConnectionComplete->peerBdaddr, + // leConnectionComplete->interval, + // leConnectionComplete->latency, + // leConnectionComplete->supervisionTimeout, + // leConnectionComplete->masterClockAccuracy); + + // L2CAPSignaling.addConnection(leConnectionComplete->handle, + // leConnectionComplete->role, + // leConnectionComplete->peerBdaddrType, + // leConnectionComplete->peerBdaddr, + // leConnectionComplete->interval, + // leConnectionComplete->latency, + // leConnectionComplete->supervisionTimeout, + // leConnectionComplete->masterClockAccuracy); + } + } else if (leMetaHeader->subevent == EVT_LE_ADVERTISING_REPORT) { + typedef struct __attribute__ ((packed)) { + uint8_t status; + uint8_t type; + uint8_t peerBdaddrType; + uint8_t peerBdaddr[6]; + uint8_t eirLength; + uint8_t eirData[31]; + } EvtLeAdvertisingReport; + + EvtLeAdvertisingReport*leAdvertisingReport = (EvtLeAdvertisingReport*)&pdata[sizeof(HCIEventHdr) + sizeof(LeMetaEventHeader)]; + + if (leAdvertisingReport->status == 0x01) { + // last byte is RSSI + //FIX int8_t rssi = leAdvertisingReport->eirData[leAdvertisingReport->eirLength]; + + // GAP.handleLeAdvertisingReport(leAdvertisingReport->type, + // leAdvertisingReport->peerBdaddrType, + // leAdvertisingReport->peerBdaddr, + // leAdvertisingReport->eirLength, + // leAdvertisingReport->eirData, + // rssi); + + } + } + } } -void HCIClass::poll() -{ - poll(0); +void hci_init(bleio_adapter_obj_t *adapter_in) { + adapter = adapter_in; + recv_idx = 0; + pending_pkt = 0; } -void HCIClass::poll(unsigned long timeout) -{ -#if defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_METRO_M4_AIRLIFT_LITE) - digitalWrite(NINA_RTS, LOW); -#endif +void hci_poll(void) { + // Assert RTS low to say we're ready to read data. + common_hal_digitalio_digitalinout_set_value(&adapter->rts_digitalinout, false); + + int errcode = 0; + while (common_hal_busio_uart_rx_characters_available(&adapter->hci_uart)) { + // Read just one character. + common_hal_busio_uart_read(&adapter->hci_uart, recv_buffer + recv_idx, 1, &errcode); + recv_idx++; + + if (recv_buffer[0] == HCI_ACLDATA_PKT) { + if (recv_idx > 5 && recv_idx >= (5 + (recv_buffer[3] + (recv_buffer[4] << 8)))) { + if (debug) { + dumpPkt("HCI ACLDATA RX <- ", recv_idx, recv_buffer); + } + // Hold data while processing packet. + common_hal_digitalio_digitalinout_set_value(&adapter->rts_digitalinout, true); + size_t pktLen = recv_idx - 1; + recv_idx = 0; + + handleAclDataPkt(pktLen, &recv_buffer[1]); + + common_hal_digitalio_digitalinout_set_value(&adapter->rts_digitalinout, false); + } + } else if (recv_buffer[0] == HCI_EVENT_PKT) { + if (recv_idx > 3 && recv_idx >= (3 + recv_buffer[2])) { + if (debug) { + dumpPkt("HCI EVENT RX <- ", recv_idx, recv_buffer); + } + // Hold data while processing packet. + common_hal_digitalio_digitalinout_set_value(&adapter->rts_digitalinout, true); + // Received full event. Reset buffer and handle packet. + size_t pktLen = recv_idx - 1; + recv_idx = 0; + + handleEventPkt(pktLen, &recv_buffer[1]); + + common_hal_digitalio_digitalinout_set_value(&adapter->rts_digitalinout, false); + } + } else { + recv_idx = 0; + } + } - if (timeout) { - HCITransport.wait(timeout); - } + common_hal_digitalio_digitalinout_set_value(&adapter->rts_digitalinout, true); +} - while (HCITransport.available()) { - byte b = HCITransport.read(); - _recvBuffer[_recvIndex++] = b; +int hci_sendCommand(uint8_t ogf, uint16_t ocf, uint8_t plen, void* parameters) +{ + uint16_t opcode = ogf << 10 | ocf; - if (_recvBuffer[0] == HCI_ACLDATA_PKT) { - if (_recvIndex > 5 && _recvIndex >= (5 + (_recvBuffer[3] + (_recvBuffer[4] << 8)))) { - if (_debug) { - dumpPkt("HCI ACLDATA RX <- ", _recvIndex, _recvBuffer); - } -#if defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_METRO_M4_AIRLIFT_LITE) - digitalWrite(NINA_RTS, HIGH); -#endif - int pktLen = _recvIndex - 1; - _recvIndex = 0; + struct __attribute__ ((packed)) { + uint8_t pktType; + uint16_t opcode; + uint8_t plen; + } pktHdr = {HCI_COMMAND_PKT, opcode, plen}; - handleAclDataPkt(pktLen, &_recvBuffer[1]); + uint8_t txBuffer[sizeof(pktHdr) + plen]; + memcpy(txBuffer, &pktHdr, sizeof(pktHdr)); + memcpy(&txBuffer[sizeof(pktHdr)], parameters, plen); -#if defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_METRO_M4_AIRLIFT_LITE) - digitalWrite(NINA_RTS, LOW); -#endif - } - } else if (_recvBuffer[0] == HCI_EVENT_PKT) { - if (_recvIndex > 3 && _recvIndex >= (3 + _recvBuffer[2])) { - if (_debug) { - dumpPkt("HCI EVENT RX <- ", _recvIndex, _recvBuffer); - } -#if defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_METRO_M4_AIRLIFT_LITE) - digitalWrite(NINA_RTS, HIGH); -#endif - // received full event - int pktLen = _recvIndex - 1; - _recvIndex = 0; + if (debug) { + dumpPkt("HCI COMMAND TX -> ", sizeof(pktHdr) + plen, txBuffer); + } - handleEventPkt(pktLen, &_recvBuffer[1]); + int errcode = 0; + common_hal_busio_uart_write(&adapter->hci_uart, txBuffer, sizeof(pktHdr) + plen, &errcode); + if (errcode) { + return -1; + } -#if defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_METRO_M4_AIRLIFT_LITE) - digitalWrite(NINA_RTS, LOW); -#endif - } - } else { - _recvIndex = 0; + cmd_complete_opcode = 0xffff; + cmd_complete_status = -1; - if (_debug) { - _debug->println(b, HEX); - } + // Wait up to one second for a response. + for (uint64_t start = supervisor_ticks_ms64(); + cmd_complete_opcode != opcode && supervisor_ticks_ms64() < (start + 5000); + ) { + hci_poll(); } - } -#if defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_METRO_M4_AIRLIFT_LITE) - digitalWrite(NINA_RTS, HIGH); -#endif + return cmd_complete_status; } -int HCIClass::reset() -{ - return sendCommand(OGF_HOST_CTL << 10 | OCF_RESET); +int hci_reset(void) { + return hci_sendCommand(OGF_HOST_CTL, OCF_RESET, 0, NULL); } -int HCIClass::readLocalVersion(uint8_t& hciVer, uint16_t& hciRev, uint8_t& lmpVer, uint16_t& manufacturer, uint16_t& lmpSubVer) -{ - int result = sendCommand(OGF_INFO_PARAM << 10 | OCF_READ_LOCAL_VERSION); - - if (result == 0) { - struct __attribute__ ((packed)) HCILocalVersion { - uint8_t hciVer; - uint16_t hciRev; - uint8_t lmpVer; - uint16_t manufacturer; - uint16_t lmpSubVer; - } *localVersion = (HCILocalVersion*)_cmdResponse; - - hciVer = localVersion->hciVer; - hciRev = localVersion->hciRev; - lmpVer = localVersion->lmpVer; - manufacturer = localVersion->manufacturer; - lmpSubVer = localVersion->lmpSubVer; - } - - return result; +int hci_readLocalVersion(uint8_t *hciVer, uint16_t *hciRev, uint8_t *lmpVer, uint16_t *manufacturer, uint16_t *lmpSubVer) { + int result = hci_sendCommand(OGF_INFO_PARAM, OCF_READ_LOCAL_VERSION, 0, NULL); + + if (result == 0) { + typedef struct __attribute__ ((packed)) { + uint8_t hciVer; + uint16_t hciRev; + uint8_t lmpVer; + uint16_t manufacturer; + uint16_t lmpSubVer; + } HCILocalVersion; + + HCILocalVersion *localVersion = (HCILocalVersion*)cmd_response; + *hciVer = localVersion->hciVer; + *hciRev = localVersion->hciRev; + *lmpVer = localVersion->lmpVer; + *manufacturer = localVersion->manufacturer; + *lmpSubVer = localVersion->lmpSubVer; + } + + return result; } -int HCIClass::readBdAddr(uint8_t addr[6]) -{ - int result = sendCommand(OGF_INFO_PARAM << 10 | OCF_READ_BD_ADDR); +int hci_readBdAddr(uint8_t addr[6]) { + int result = hci_sendCommand(OGF_INFO_PARAM, OCF_READ_BD_ADDR, 0, NULL); - if (result == 0) { - memcpy(addr, _cmdResponse, 6); - } + if (result == 0) { + memcpy(addr, cmd_response, 6); + } - return result; + return result; } -int HCIClass::readRssi(uint16_t handle) -{ - int result = sendCommand(OGF_STATUS_PARAM << 10 | OCF_READ_RSSI, sizeof(handle), &handle); - int rssi = 127; +int hci_readRssi(uint16_t handle) { + int result = hci_sendCommand(OGF_STATUS_PARAM, OCF_READ_RSSI, sizeof(handle), &handle); + int rssi = 127; - if (result == 0) { - struct __attribute__ ((packed)) HCIReadRssi { - uint16_t handle; - int8_t rssi; - } *readRssi = (HCIReadRssi*)_cmdResponse; + if (result == 0) { + typedef struct __attribute__ ((packed)) { + uint16_t handle; + int8_t rssi; + } HCIReadRssi; - if (readRssi->handle == handle) { - rssi = readRssi->rssi; + HCIReadRssi *readRssi = (HCIReadRssi*)cmd_response; + if (readRssi->handle == handle) { + rssi = readRssi->rssi; + } } - } - return rssi; + return rssi; } -int HCIClass::setEventMask(uint64_t eventMask) -{ - return sendCommand(OGF_HOST_CTL << 10 | OCF_SET_EVENT_MASK, sizeof(eventMask), &eventMask); +int hci_setEventMask(uint64_t eventMask) { + return hci_sendCommand(OGF_HOST_CTL, OCF_SET_EVENT_MASK, sizeof(eventMask), &eventMask); } -int HCIClass::readLeBufferSize(uint16_t& pktLen, uint8_t& maxPkt) +int hci_readLeBufferSize(uint16_t *pktLen, uint8_t *maxPkt) { - int result = sendCommand(OGF_LE_CTL << 10 | OCF_LE_READ_BUFFER_SIZE); + int result = hci_sendCommand(OGF_LE_CTL, OCF_LE_READ_BUFFER_SIZE, 0, NULL); - if (result == 0) { - struct __attribute__ ((packed)) HCILeBufferSize { - uint16_t pktLen; - uint8_t maxPkt; - } *leBufferSize = (HCILeBufferSize*)_cmdResponse; + if (result == 0) { + typedef struct __attribute__ ((packed)) { + uint16_t pktLen; + uint8_t maxPkt; + } HCILeBufferSize; - pktLen = leBufferSize->pktLen; - _maxPkt = maxPkt = leBufferSize->maxPkt; + HCILeBufferSize *leBufferSize = (HCILeBufferSize*)cmd_response; + *pktLen = leBufferSize->pktLen; + *maxPkt = leBufferSize->maxPkt; #ifndef __AVR__ - ATT.setMaxMtu(pktLen - 9); // max pkt len - ACL header size + // FIX (needed?) ATT.setMaxMtu(pktLen - 9); // max pkt len - ACL header size #endif - } + } - return result; + return result; } -int HCIClass::leSetRandomAddress(uint8_t addr[6]) +int hci_leSetRandomAddress(uint8_t addr[6]) { - return sendCommand(OGF_LE_CTL << 10 | OCF_LE_SET_RANDOM_ADDRESS, 6, addr); + return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_RANDOM_ADDRESS, 6, addr); } -int HCIClass::leSetAdvertisingParameters(uint16_t minInterval, uint16_t maxInterval, +int hci_leSetAdvertisingParameters(uint16_t minInterval, uint16_t maxInterval, uint8_t advType, uint8_t ownBdaddrType, uint8_t directBdaddrType, uint8_t directBdaddr[6], uint8_t chanMap, uint8_t filter) { - struct __attribute__ ((packed)) HCILeAdvertisingParameters { - uint16_t minInterval; - uint16_t maxInterval; - uint8_t advType; - uint8_t ownBdaddrType; - uint8_t directBdaddrType; - uint8_t directBdaddr[6]; - uint8_t chanMap; - uint8_t filter; - } leAdvertisingParamters; - - leAdvertisingParamters.minInterval = minInterval; - leAdvertisingParamters.maxInterval = maxInterval; - leAdvertisingParamters.advType = advType; - leAdvertisingParamters.ownBdaddrType = ownBdaddrType; - leAdvertisingParamters.directBdaddrType = directBdaddrType; - memcpy(leAdvertisingParamters.directBdaddr, directBdaddr, 6); - leAdvertisingParamters.chanMap = chanMap; - leAdvertisingParamters.filter = filter; - - return sendCommand(OGF_LE_CTL << 10 | OCF_LE_SET_ADVERTISING_PARAMETERS, sizeof(leAdvertisingParamters), &leAdvertisingParamters); + struct __attribute__ ((packed)) HCILeAdvertisingParameters { + uint16_t minInterval; + uint16_t maxInterval; + uint8_t advType; + uint8_t ownBdaddrType; + uint8_t directBdaddrType; + uint8_t directBdaddr[6]; + uint8_t chanMap; + uint8_t filter; + } leAdvertisingParamters; + + leAdvertisingParamters.minInterval = minInterval; + leAdvertisingParamters.maxInterval = maxInterval; + leAdvertisingParamters.advType = advType; + leAdvertisingParamters.ownBdaddrType = ownBdaddrType; + leAdvertisingParamters.directBdaddrType = directBdaddrType; + memcpy(leAdvertisingParamters.directBdaddr, directBdaddr, 6); + leAdvertisingParamters.chanMap = chanMap; + leAdvertisingParamters.filter = filter; + + return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_ADVERTISING_PARAMETERS, sizeof(leAdvertisingParamters), &leAdvertisingParamters); } -int HCIClass::leSetAdvertisingData(uint8_t length, uint8_t data[]) +int hci_leSetAdvertisingData(uint8_t length, uint8_t data[]) { - struct __attribute__ ((packed)) HCILeAdvertisingData { - uint8_t length; - uint8_t data[31]; - } leAdvertisingData; + struct __attribute__ ((packed)) HCILeAdvertisingData { + uint8_t length; + uint8_t data[31]; + } leAdvertisingData; - memset(&leAdvertisingData, 0, sizeof(leAdvertisingData)); - leAdvertisingData.length = length; - memcpy(leAdvertisingData.data, data, length); + memset(&leAdvertisingData, 0, sizeof(leAdvertisingData)); + leAdvertisingData.length = length; + memcpy(leAdvertisingData.data, data, length); - return sendCommand(OGF_LE_CTL << 10 | OCF_LE_SET_ADVERTISING_DATA, sizeof(leAdvertisingData), &leAdvertisingData); + return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_ADVERTISING_DATA, sizeof(leAdvertisingData), &leAdvertisingData); } -int HCIClass::leSetScanResponseData(uint8_t length, uint8_t data[]) +int hci_leSetScanResponseData(uint8_t length, uint8_t data[]) { - struct __attribute__ ((packed)) HCILeScanResponseData { - uint8_t length; - uint8_t data[31]; - } leScanResponseData; - - memset(&leScanResponseData, 0, sizeof(leScanResponseData)); - leScanResponseData.length = length; - memcpy(leScanResponseData.data, data, length); - - return sendCommand(OGF_LE_CTL << 10 | OCF_LE_SET_SCAN_RESPONSE_DATA, sizeof(leScanResponseData), &leScanResponseData); -} + struct __attribute__ ((packed)) HCILeScanResponseData { + uint8_t length; + uint8_t data[31]; + } leScanResponseData; -int HCIClass::leSetAdvertiseEnable(uint8_t enable) -{ - return sendCommand(OGF_LE_CTL << 10 | OCF_LE_SET_ADVERTISE_ENABLE, sizeof(enable), &enable); -} + memset(&leScanResponseData, 0, sizeof(leScanResponseData)); + leScanResponseData.length = length; + memcpy(leScanResponseData.data, data, length); -int HCIClass::leSetScanParameters(uint8_t type, uint16_t interval, uint16_t window, - uint8_t ownBdaddrType, uint8_t filter) -{ - struct __attribute__ ((packed)) HCILeSetScanParameters { - uint8_t type; - uint16_t interval; - uint16_t window; - uint8_t ownBdaddrType; - uint8_t filter; - } leScanParameters; - - leScanParameters.type = type; - leScanParameters.interval = interval; - leScanParameters.window = window; - leScanParameters.ownBdaddrType = ownBdaddrType; - leScanParameters.filter = filter; - - return sendCommand(OGF_LE_CTL << 10 | OCF_LE_SET_SCAN_PARAMETERS, sizeof(leScanParameters), &leScanParameters); + return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_SCAN_RESPONSE_DATA, sizeof(leScanResponseData), &leScanResponseData); } -int HCIClass::leSetScanEnable(uint8_t enabled, uint8_t duplicates) +int hci_leSetAdvertiseEnable(uint8_t enable) { - struct __attribute__ ((packed)) HCILeSetScanEnableData { - uint8_t enabled; - uint8_t duplicates; - } leScanEnableData; - - leScanEnableData.enabled = enabled; - leScanEnableData.duplicates = duplicates; - - return sendCommand(OGF_LE_CTL << 10 | OCF_LE_SET_SCAN_ENABLE, sizeof(leScanEnableData), &leScanEnableData); + return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_ADVERTISE_ENABLE, sizeof(enable), &enable); } -int HCIClass::leCreateConn(uint16_t interval, uint16_t window, uint8_t initiatorFilter, - uint8_t peerBdaddrType, uint8_t peerBdaddr[6], uint8_t ownBdaddrType, - uint16_t minInterval, uint16_t maxInterval, uint16_t latency, - uint16_t supervisionTimeout, uint16_t minCeLength, uint16_t maxCeLength) +int hci_leSetScanParameters(uint8_t type, uint16_t interval, uint16_t window, + uint8_t ownBdaddrType, uint8_t filter) { - struct __attribute__ ((packed)) HCILeCreateConnData { - uint16_t interval; - uint16_t window; - uint8_t initiatorFilter; - uint8_t peerBdaddrType; - uint8_t peerBdaddr[6]; - uint8_t ownBdaddrType; - uint16_t minInterval; - uint16_t maxInterval; - uint16_t latency; - uint16_t supervisionTimeout; - uint16_t minCeLength; - uint16_t maxCeLength; - } leCreateConnData; - - leCreateConnData.interval = interval; - leCreateConnData.window = window; - leCreateConnData.initiatorFilter = initiatorFilter; - leCreateConnData.peerBdaddrType = peerBdaddrType; - memcpy(leCreateConnData.peerBdaddr, peerBdaddr, sizeof(leCreateConnData.peerBdaddr)); - leCreateConnData.ownBdaddrType = ownBdaddrType; - leCreateConnData.minInterval = minInterval; - leCreateConnData.maxInterval = maxInterval; - leCreateConnData.latency = latency; - leCreateConnData.supervisionTimeout = supervisionTimeout; - leCreateConnData.minCeLength = minCeLength; - leCreateConnData.maxCeLength = maxCeLength; - - return sendCommand(OGF_LE_CTL << 10 | OCF_LE_CREATE_CONN, sizeof(leCreateConnData), &leCreateConnData); + struct __attribute__ ((packed)) HCILeSetScanParameters { + uint8_t type; + uint16_t interval; + uint16_t window; + uint8_t ownBdaddrType; + uint8_t filter; + } leScanParameters; + + leScanParameters.type = type; + leScanParameters.interval = interval; + leScanParameters.window = window; + leScanParameters.ownBdaddrType = ownBdaddrType; + leScanParameters.filter = filter; + + return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_SCAN_PARAMETERS, sizeof(leScanParameters), &leScanParameters); } -int HCIClass::leCancelConn() +int hci_leSetScanEnable(uint8_t enabled, uint8_t duplicates) { - return sendCommand(OGF_LE_CTL << 10 | OCF_LE_CANCEL_CONN, 0, NULL); -} + struct __attribute__ ((packed)) HCILeSetScanEnableData { + uint8_t enabled; + uint8_t duplicates; + } leScanEnableData; -int HCIClass::leConnUpdate(uint16_t handle, uint16_t minInterval, uint16_t maxInterval, - uint16_t latency, uint16_t supervisionTimeout) -{ - struct __attribute__ ((packed)) HCILeConnUpdateData { - uint16_t handle; - uint16_t minInterval; - uint16_t maxInterval; - uint16_t latency; - uint16_t supervisionTimeout; - uint16_t minCeLength; - uint16_t maxCeLength; - } leConnUpdateData; - - leConnUpdateData.handle = handle; - leConnUpdateData.minInterval = minInterval; - leConnUpdateData.maxInterval = maxInterval; - leConnUpdateData.latency = latency; - leConnUpdateData.supervisionTimeout = supervisionTimeout; - leConnUpdateData.minCeLength = 0x0004; - leConnUpdateData.maxCeLength = 0x0006; - - return sendCommand(OGF_LE_CTL << 10 | OCF_LE_CONN_UPDATE, sizeof(leConnUpdateData), &leConnUpdateData); -} + leScanEnableData.enabled = enabled; + leScanEnableData.duplicates = duplicates; -int HCIClass::sendAclPkt(uint16_t handle, uint8_t cid, uint8_t plen, void* data) -{ - while (_pendingPkt >= _maxPkt) { - poll(); - } - - struct __attribute__ ((packed)) HCIACLHdr { - uint8_t pktType; - uint16_t handle; - uint16_t dlen; - uint16_t plen; - uint16_t cid; - } aclHdr = { HCI_ACLDATA_PKT, handle, uint8_t(plen + 4), plen, cid }; - - uint8_t txBuffer[sizeof(aclHdr) + plen]; - memcpy(txBuffer, &aclHdr, sizeof(aclHdr)); - memcpy(&txBuffer[sizeof(aclHdr)], data, plen); - - if (_debug) { - dumpPkt("HCI ACLDATA TX -> ", sizeof(aclHdr) + plen, txBuffer); - } - - _pendingPkt++; - HCITransport.write(txBuffer, sizeof(aclHdr) + plen); - - return 0; + return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_SCAN_ENABLE, sizeof(leScanEnableData), &leScanEnableData); } -int HCIClass::disconnect(uint16_t handle) +int hci_leCreateConn(uint16_t interval, uint16_t window, uint8_t initiatorFilter, + uint8_t peerBdaddrType, uint8_t peerBdaddr[6], uint8_t ownBdaddrType, + uint16_t minInterval, uint16_t maxInterval, uint16_t latency, + uint16_t supervisionTimeout, uint16_t minCeLength, uint16_t maxCeLength) { - struct __attribute__ ((packed)) HCIDisconnectData { - uint16_t handle; - uint8_t reason; - } disconnectData = { handle, HCI_OE_USER_ENDED_CONNECTION }; - - return sendCommand(OGF_LINK_CTL << 10 | OCF_DISCONNECT, sizeof(disconnectData), &disconnectData); + struct __attribute__ ((packed)) HCILeCreateConnData { + uint16_t interval; + uint16_t window; + uint8_t initiatorFilter; + uint8_t peerBdaddrType; + uint8_t peerBdaddr[6]; + uint8_t ownBdaddrType; + uint16_t minInterval; + uint16_t maxInterval; + uint16_t latency; + uint16_t supervisionTimeout; + uint16_t minCeLength; + uint16_t maxCeLength; + } leCreateConnData; + + leCreateConnData.interval = interval; + leCreateConnData.window = window; + leCreateConnData.initiatorFilter = initiatorFilter; + leCreateConnData.peerBdaddrType = peerBdaddrType; + memcpy(leCreateConnData.peerBdaddr, peerBdaddr, sizeof(leCreateConnData.peerBdaddr)); + leCreateConnData.ownBdaddrType = ownBdaddrType; + leCreateConnData.minInterval = minInterval; + leCreateConnData.maxInterval = maxInterval; + leCreateConnData.latency = latency; + leCreateConnData.supervisionTimeout = supervisionTimeout; + leCreateConnData.minCeLength = minCeLength; + leCreateConnData.maxCeLength = maxCeLength; + + return hci_sendCommand(OGF_LE_CTL, OCF_LE_CREATE_CONN, sizeof(leCreateConnData), &leCreateConnData); } -void HCIClass::debug(Stream& stream) +int hci_leCancelConn() { - _debug = &stream; + return hci_sendCommand(OGF_LE_CTL, OCF_LE_CANCEL_CONN, 0, NULL); } -void HCIClass::noDebug() +int hci_leConnUpdate(uint16_t handle, uint16_t minInterval, uint16_t maxInterval, + uint16_t latency, uint16_t supervisionTimeout) { - _debug = NULL; + struct __attribute__ ((packed)) HCILeConnUpdateData { + uint16_t handle; + uint16_t minInterval; + uint16_t maxInterval; + uint16_t latency; + uint16_t supervisionTimeout; + uint16_t minCeLength; + uint16_t maxCeLength; + } leConnUpdateData; + + leConnUpdateData.handle = handle; + leConnUpdateData.minInterval = minInterval; + leConnUpdateData.maxInterval = maxInterval; + leConnUpdateData.latency = latency; + leConnUpdateData.supervisionTimeout = supervisionTimeout; + leConnUpdateData.minCeLength = 0x0004; + leConnUpdateData.maxCeLength = 0x0006; + + return hci_sendCommand(OGF_LE_CTL, OCF_LE_CONN_UPDATE, sizeof(leConnUpdateData), &leConnUpdateData); } -int HCIClass::sendCommand(uint16_t opcode, uint8_t plen, void* parameters) -{ - struct __attribute__ ((packed)) { - uint8_t pktType; - uint16_t opcode; - uint8_t plen; - } pktHdr = {HCI_COMMAND_PKT, opcode, plen}; - - uint8_t txBuffer[sizeof(pktHdr) + plen]; - memcpy(txBuffer, &pktHdr, sizeof(pktHdr)); - memcpy(&txBuffer[sizeof(pktHdr)], parameters, plen); - - if (_debug) { - dumpPkt("HCI COMMAND TX -> ", sizeof(pktHdr) + plen, txBuffer); - } - - HCITransport.write(txBuffer, sizeof(pktHdr) + plen); - - _cmdCompleteOpcode = 0xffff; - _cmdCompleteStatus = -1; - - for (unsigned long start = millis(); _cmdCompleteOpcode != opcode && millis() < (start + 1000);) { - poll(); - } +int hci_sendAclPkt(uint16_t handle, uint8_t cid, uint8_t plen, void* data) { + while (pending_pkt >= max_pkt) { + hci_poll(); + } - return _cmdCompleteStatus; -} + typedef struct __attribute__ ((packed)) { + uint8_t pktType; + uint16_t handle; + uint16_t dlen; + uint16_t plen; + uint16_t cid; + } HCIACLHdr; -void HCIClass::handleAclDataPkt(uint8_t /*plen*/, uint8_t pdata[]) -{ - struct __attribute__ ((packed)) HCIACLHdr { - uint16_t handle; - uint16_t dlen; - uint16_t len; - uint16_t cid; - } *aclHdr = (HCIACLHdr*)pdata; - - uint16_t aclFlags = (aclHdr->handle & 0xf000) >> 12; - - if ((aclHdr->dlen - 4) != aclHdr->len) { - // packet is fragmented - if (aclFlags != 0x01) { - // copy into ACL buffer - memcpy(_aclPktBuffer, &_recvBuffer[1], sizeof(HCIACLHdr) + aclHdr->dlen - 4); - } else { - // copy next chunk into the buffer - HCIACLHdr* aclBufferHeader = (HCIACLHdr*)_aclPktBuffer; + HCIACLHdr aclHdr = { HCI_ACLDATA_PKT, handle, (uint8_t)(plen + 4), plen, cid }; - memcpy(&_aclPktBuffer[sizeof(HCIACLHdr) + aclBufferHeader->dlen - 4], &_recvBuffer[1 + sizeof(aclHdr->handle) + sizeof(aclHdr->dlen)], aclHdr->dlen); + uint8_t txBuffer[sizeof(aclHdr) + plen]; + memcpy(txBuffer, &aclHdr, sizeof(aclHdr)); + memcpy(&txBuffer[sizeof(aclHdr)], data, plen); - aclBufferHeader->dlen += aclHdr->dlen; - aclHdr = aclBufferHeader; + if (debug) { + dumpPkt("HCI ACLDATA TX -> ", sizeof(aclHdr) + plen, txBuffer); } - } - if ((aclHdr->dlen - 4) != aclHdr->len) { - // don't have the full packet yet - return; - } + pending_pkt++; - if (aclHdr->cid == ATT_CID) { - if (aclFlags == 0x01) { - // use buffered packet - ATT.handleData(aclHdr->handle & 0x0fff, aclHdr->len, &_aclPktBuffer[sizeof(HCIACLHdr)]); - } else { - // use the recv buffer - ATT.handleData(aclHdr->handle & 0x0fff, aclHdr->len, &_recvBuffer[1 + sizeof(HCIACLHdr)]); + int errcode = 0; + common_hal_busio_uart_write(&adapter->hci_uart, txBuffer, sizeof(aclHdr) + plen, &errcode); + if (errcode) { + return -1; } - } else if (aclHdr->cid == SIGNALING_CID) { - L2CAPSignaling.handleData(aclHdr->handle & 0x0fff, aclHdr->len, &_recvBuffer[1 + sizeof(HCIACLHdr)]); - } else { - struct __attribute__ ((packed)) { - uint8_t op; - uint8_t id; - uint16_t length; - uint16_t reason; - uint16_t localCid; - uint16_t remoteCid; - } l2capRejectCid= { 0x01, 0x00, 0x006, 0x0002, aclHdr->cid, 0x0000 }; - - sendAclPkt(aclHdr->handle & 0x0fff, 0x0005, sizeof(l2capRejectCid), &l2capRejectCid); - } -} -void HCIClass::handleNumCompPkts(uint16_t /*handle*/, uint16_t numPkts) -{ - if (numPkts && _pendingPkt > numPkts) { - _pendingPkt -= numPkts; - } else { - _pendingPkt = 0; - } + return 0; } -void HCIClass::handleEventPkt(uint8_t /*plen*/, uint8_t pdata[]) +int hci_disconnect(uint16_t handle) { - struct __attribute__ ((packed)) HCIEventHdr { - uint8_t evt; - uint8_t plen; - } *eventHdr = (HCIEventHdr*)pdata; - - if (eventHdr->evt == EVT_DISCONN_COMPLETE) { - struct __attribute__ ((packed)) DisconnComplete { - uint8_t status; - uint16_t handle; - uint8_t reason; - } *disconnComplete = (DisconnComplete*)&pdata[sizeof(HCIEventHdr)]; - - ATT.removeConnection(disconnComplete->handle, disconnComplete->reason); - L2CAPSignaling.removeConnection(disconnComplete->handle, disconnComplete->reason); - - HCI.leSetAdvertiseEnable(0x01); - } else if (eventHdr->evt == EVT_CMD_COMPLETE) { - struct __attribute__ ((packed)) CmdComplete { - uint8_t ncmd; - uint16_t opcode; - uint8_t status; - } *cmdCompleteHeader = (CmdComplete*)&pdata[sizeof(HCIEventHdr)]; - - _cmdCompleteOpcode = cmdCompleteHeader->opcode; - _cmdCompleteStatus = cmdCompleteHeader->status; - _cmdResponseLen = pdata[1] - sizeof(CmdComplete); - _cmdResponse = &pdata[sizeof(HCIEventHdr) + sizeof(CmdComplete)]; - - } else if (eventHdr->evt == EVT_CMD_STATUS) { - struct __attribute__ ((packed)) CmdStatus { - uint8_t status; - uint8_t ncmd; - uint16_t opcode; - } *cmdStatusHeader = (CmdStatus*)&pdata[sizeof(HCIEventHdr)]; - - _cmdCompleteOpcode = cmdStatusHeader->opcode; - _cmdCompleteStatus = cmdStatusHeader->status; - _cmdResponseLen = 0; - } else if (eventHdr->evt == EVT_NUM_COMP_PKTS) { - uint8_t numHandles = pdata[sizeof(HCIEventHdr)]; - uint16_t* data = (uint16_t*)&pdata[sizeof(HCIEventHdr) + sizeof(numHandles)]; - - for (uint8_t i = 0; i < numHandles; i++) { - handleNumCompPkts(data[0], data[1]); - - data += 2; - } - } else if (eventHdr->evt == EVT_LE_META_EVENT) { - struct __attribute__ ((packed)) LeMetaEventHeader { - uint8_t subevent; - } *leMetaHeader = (LeMetaEventHeader*)&pdata[sizeof(HCIEventHdr)]; - - if (leMetaHeader->subevent == EVT_LE_CONN_COMPLETE) { - struct __attribute__ ((packed)) EvtLeConnectionComplete { - uint8_t status; + struct __attribute__ ((packed)) HCIDisconnectData { uint16_t handle; - uint8_t role; - uint8_t peerBdaddrType; - uint8_t peerBdaddr[6]; - uint16_t interval; - uint16_t latency; - uint16_t supervisionTimeout; - uint8_t masterClockAccuracy; - } *leConnectionComplete = (EvtLeConnectionComplete*)&pdata[sizeof(HCIEventHdr) + sizeof(LeMetaEventHeader)]; - - if (leConnectionComplete->status == 0x00) { - ATT.addConnection(leConnectionComplete->handle, - leConnectionComplete->role, - leConnectionComplete->peerBdaddrType, - leConnectionComplete->peerBdaddr, - leConnectionComplete->interval, - leConnectionComplete->latency, - leConnectionComplete->supervisionTimeout, - leConnectionComplete->masterClockAccuracy); - - L2CAPSignaling.addConnection(leConnectionComplete->handle, - leConnectionComplete->role, - leConnectionComplete->peerBdaddrType, - leConnectionComplete->peerBdaddr, - leConnectionComplete->interval, - leConnectionComplete->latency, - leConnectionComplete->supervisionTimeout, - leConnectionComplete->masterClockAccuracy); - } - } else if (leMetaHeader->subevent == EVT_LE_ADVERTISING_REPORT) { - struct __attribute__ ((packed)) EvtLeAdvertisingReport { - uint8_t status; - uint8_t type; - uint8_t peerBdaddrType; - uint8_t peerBdaddr[6]; - uint8_t eirLength; - uint8_t eirData[31]; - } *leAdvertisingReport = (EvtLeAdvertisingReport*)&pdata[sizeof(HCIEventHdr) + sizeof(LeMetaEventHeader)]; - - if (leAdvertisingReport->status == 0x01) { - // last byte is RSSI - int8_t rssi = leAdvertisingReport->eirData[leAdvertisingReport->eirLength]; - - GAP.handleLeAdvertisingReport(leAdvertisingReport->type, - leAdvertisingReport->peerBdaddrType, - leAdvertisingReport->peerBdaddr, - leAdvertisingReport->eirLength, - leAdvertisingReport->eirData, - rssi); - - } - } - } -} - -void HCIClass::dumpPkt(const char* prefix, uint8_t plen, uint8_t pdata[]) -{ - if (_debug) { - _debug->print(prefix); - - for (uint8_t i = 0; i < plen; i++) { - byte b = pdata[i]; - - if (b < 16) { - _debug->print("0"); - } - - _debug->print(b, HEX); - } + uint8_t reason; + } disconnectData = { handle, HCI_OE_USER_ENDED_CONNECTION }; - _debug->println(); - _debug->flush(); - } + return hci_sendCommand(OGF_LINK_CTL, OCF_DISCONNECT, sizeof(disconnectData), &disconnectData); } -` diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile index 5f901a199..cce89a7ac 100644 --- a/ports/atmel-samd/Makefile +++ b/ports/atmel-samd/Makefile @@ -248,7 +248,7 @@ endif SRC_ASF := $(addprefix asf4/$(CHIP_FAMILY)/, $(SRC_ASF)) -SRC_C = \ +SRC_C += \ audio_dma.c \ background.c \ bindings/samd/Clock.c \ diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 38ef37312..b30159c7c 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -318,8 +318,8 @@ SRC_COMMON_HAL_ALL = \ watchdog/__init__.c \ ifeq ($(CIRCUITPY_BLEIO_HCI),1) -SRC_C +=\ - common_hal/_bleio/hci.c \ +SRC_C += \ + common-hal/_bleio/hci.c \ endif diff --git a/shared-bindings/_bleio/Adapter.c b/shared-bindings/_bleio/Adapter.c index 911fa6d35..1b991ac6d 100644 --- a/shared-bindings/_bleio/Adapter.c +++ b/shared-bindings/_bleio/Adapter.c @@ -64,20 +64,20 @@ //| advertisements and it can advertise its own data. Furthermore, Adapters can accept incoming //| connections and also initiate connections.""" //| - -//| def __init__(self, *, tx: Pin, rx: Pin, rts: Pin, cts: Pin, baudrate: int = 115200, buffer_size: int = 256): //| You cannot create an instance of `_bleio.Adapter`. //| Use `_bleio.adapter` to access the sole instance available.""" //| -//| On boards that do not have native BLE. You can use HCI co-processor. + +//| def hci_init(self, *, tx: Pin, rx: Pin, rts: Pin, cts: Pin, baudrate: int = 115200, buffer_size: int = 256): +//| On boards that do not have native BLE, you can an use HCI co-processor. //| Call `_bleio.adapter.hci_init()` passing it the pins used to communicate //| with the co-processor, such as an Adafruit AirLift. //| The co-processor must have been reset and put into BLE mode beforehand //| by the appropriate pin manipulation. //| The `tx`, `rx`, `rts`, and `cs` pins are used to communicate with the HCI co-processor in HCI mode. //| -#if CIRCUITPY_BLEIO_HCI mp_obj_t bleio_adapter_hci_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +#if CIRCUITPY_BLEIO_HCI bleio_adapter_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); if (self->enabled) { @@ -114,10 +114,14 @@ mp_obj_t bleio_adapter_hci_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_m common_hal_bleio_adapter_hci_init(&common_hal_bleio_adapter_obj, tx, rx, rts, cts, baudrate, buffer_size); + + return mp_const_none; +#else + mp_raise_RuntimeError(translate("hci_init not available")); return mp_const_none; +#endif // CIRCUITPY_BLEIO_HCI } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_adapter_hci_init_obj, 1, bleio_adapter_hci_init); -#endif // CIRCUITPY_BLEIO_HCI //| //| enabled: Any = ... diff --git a/shared-bindings/_bleio/__init__.c b/shared-bindings/_bleio/__init__.c index 90b185f79..29405ecad 100644 --- a/shared-bindings/_bleio/__init__.c +++ b/shared-bindings/_bleio/__init__.c @@ -112,7 +112,10 @@ NORETURN void mp_raise_bleio_SecurityError(const compressed_string_t* fmt, ...) // Called when _bleio is imported. STATIC mp_obj_t bleio___init__(void) { +#if !CIRCUITPY_BLEIO_HCI + // HCI cannot be enabled on import, because we need to setup the HCI adapter first. common_hal_bleio_adapter_set_enabled(&common_hal_bleio_adapter_obj, true); +#endif return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_0(bleio___init___obj, bleio___init__); -- cgit v1.2.3 From a5ab2829eb90f15d0b78678cd2f2aadd18160fed Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 8 Jul 2020 09:33:41 -0400 Subject: use zephyr include files; wip: compiles --- devices/ble_hci/common-hal/_bleio/Adapter.c | 51 +- devices/ble_hci/common-hal/_bleio/Adapter.h | 6 +- devices/ble_hci/common-hal/_bleio/hci.c | 674 -------- devices/ble_hci/common-hal/_bleio/hci_api.c | 646 +++++++ devices/ble_hci/common-hal/_bleio/hci_api.h | 69 + .../ble_hci/common-hal/_bleio/hci_include/#hci.h# | 1775 ++++++++++++++++++++ .../common-hal/_bleio/hci_include/README.md | 2 + .../ble_hci/common-hal/_bleio/hci_include/addr.h | 100 ++ .../ble_hci/common-hal/_bleio/hci_include/hci.h | 1764 +++++++++++++++++++ .../common-hal/_bleio/hci_include/hci_err.h | 92 + .../common-hal/_bleio/hci_include/hci_raw.h | 152 ++ .../ble_hci/common-hal/_bleio/hci_include/hci_vs.h | 379 +++++ py/circuitpy_defns.mk | 2 +- shared-bindings/_bleio/Adapter.c | 39 +- shared-bindings/_bleio/Adapter.h | 2 +- shared-bindings/time/__init__.c | 5 +- 16 files changed, 5005 insertions(+), 753 deletions(-) delete mode 100644 devices/ble_hci/common-hal/_bleio/hci.c create mode 100644 devices/ble_hci/common-hal/_bleio/hci_api.c create mode 100644 devices/ble_hci/common-hal/_bleio/hci_api.h create mode 100644 devices/ble_hci/common-hal/_bleio/hci_include/#hci.h# create mode 100644 devices/ble_hci/common-hal/_bleio/hci_include/README.md create mode 100644 devices/ble_hci/common-hal/_bleio/hci_include/addr.h create mode 100644 devices/ble_hci/common-hal/_bleio/hci_include/hci.h create mode 100644 devices/ble_hci/common-hal/_bleio/hci_include/hci_err.h create mode 100644 devices/ble_hci/common-hal/_bleio/hci_include/hci_raw.h create mode 100644 devices/ble_hci/common-hal/_bleio/hci_include/hci_vs.h (limited to 'py') diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index 5f5259f7e..9dbeca68f 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.c +++ b/devices/ble_hci/common-hal/_bleio/Adapter.c @@ -31,7 +31,7 @@ #include #include -#include "hci.h" +#include "hci_api.h" #include "py/gc.h" #include "py/mphal.h" @@ -179,13 +179,10 @@ char default_ble_name[] = { 'C', 'I', 'R', 'C', 'U', 'I', 'T', 'P', 'Y', 0, 0, 0 // common_hal_bleio_adapter_set_name(self, (char*) default_ble_name); // } -void common_hal_bleio_adapter_hci_init(bleio_adapter_obj_t *self, const mcu_pin_obj_t *tx, const mcu_pin_obj_t *rx, const mcu_pin_obj_t *rts, const mcu_pin_obj_t *cts, uint32_t baudrate, uint32_t buffer_size) { - self->tx_pin = tx; - self->rx_pin = rx; +void common_hal_bleio_adapter_hci_init(bleio_adapter_obj_t *self, busio_uart_obj_t *uart, const mcu_pin_obj_t *rts, const mcu_pin_obj_t *cts) { + self->hci_uart = uart; self->rts_pin = rts; self->cts_pin = cts; - self->baudrate = baudrate; - self->buffer_size = buffer_size; self->enabled = false; } @@ -198,34 +195,15 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable } if (enabled) { - common_hal_busio_uart_construct( - &self->hci_uart, - self->tx_pin, // tx pin - self->rx_pin, // rx pin - NULL, // rts pin - NULL, // cts pin - NULL, // rs485 dir pin - false, // rs485 invert - 0, // timeout - self->baudrate, // baudrate - 8, // nbits - PARITY_NONE, // parity - 1, // stop bits - self->buffer_size, // buffer size - NULL, // buffer - false // sigint_enabled - ); common_hal_digitalio_digitalinout_construct(&self->rts_digitalinout, self->rts_pin); common_hal_digitalio_digitalinout_construct(&self->cts_digitalinout, self->cts_pin); hci_init(self); } else { - common_hal_busio_uart_deinit(&self->hci_uart); common_hal_digitalio_digitalinout_deinit(&self->rts_digitalinout); common_hal_digitalio_digitalinout_deinit(&self->cts_digitalinout); } - //FIX enable/disable HCI adapter, but don't reset it, since we don't know how. self->enabled = enabled; } @@ -235,35 +213,22 @@ bool common_hal_bleio_adapter_get_enabled(bleio_adapter_obj_t *self) { } bleio_address_obj_t *common_hal_bleio_adapter_get_address(bleio_adapter_obj_t *self) { - common_hal_bleio_adapter_set_enabled(self, true); - - uint8_t addr[6]; - hci_readBdAddr(addr); + bt_addr_le_t addr; + hci_read_bd_addr(&addr.a); bleio_address_obj_t *address = m_new_obj(bleio_address_obj_t); address->base.type = &bleio_address_type; - // 0 is the type designating a public address. - common_hal_bleio_address_construct(address, addr, 0); + common_hal_bleio_address_construct(address, addr.a.val, addr.type); return address; } mp_obj_str_t* common_hal_bleio_adapter_get_name(bleio_adapter_obj_t *self) { - uint16_t len = 0; -// sd_ble_gap_device_name_get(NULL, &len); - uint8_t buf[len]; -// uint32_t err_code = sd_ble_gap_device_name_get(buf, &len); -// if (err_code != NRF_SUCCESS) { -// return NULL; -// } - return mp_obj_new_str((char*) buf, len); + return self->name; } void common_hal_bleio_adapter_set_name(bleio_adapter_obj_t *self, const char* name) { - // ble_gap_conn_sec_mode_t sec; - // sec.lv = 0; - // sec.sm = 0; - // sd_ble_gap_device_name_set(&sec, (const uint8_t*) name, strlen(name)); + self->name = mp_obj_new_str(name, strlen(name)); } // STATIC bool scan_on_ble_evt(ble_evt_t *ble_evt, void *scan_results_in) { diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.h b/devices/ble_hci/common-hal/_bleio/Adapter.h index 565963dc0..73b9fed0b 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.h +++ b/devices/ble_hci/common-hal/_bleio/Adapter.h @@ -52,13 +52,9 @@ typedef struct { bleio_scanresults_obj_t* scan_results; mp_obj_t name; mp_obj_tuple_t *connection_objs; - const mcu_pin_obj_t* tx_pin; - const mcu_pin_obj_t* rx_pin; + busio_uart_obj_t* hci_uart; const mcu_pin_obj_t* rts_pin; const mcu_pin_obj_t* cts_pin; - uint32_t baudrate; - uint16_t buffer_size; - busio_uart_obj_t hci_uart; digitalio_digitalinout_obj_t rts_digitalinout; digitalio_digitalinout_obj_t cts_digitalinout; bool enabled; diff --git a/devices/ble_hci/common-hal/_bleio/hci.c b/devices/ble_hci/common-hal/_bleio/hci.c deleted file mode 100644 index 7d4add9af..000000000 --- a/devices/ble_hci/common-hal/_bleio/hci.c +++ /dev/null @@ -1,674 +0,0 @@ -/* - This file is part of the ArduinoBLE library. - Copyright (c) 2018 Arduino SA. All rights reserved. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include "hci.h" -#include - -#include "supervisor/shared/tick.h" - -#define ATT_CID 0x0004 - -#define HCI_COMMAND_PKT 0x01 -#define HCI_ACLDATA_PKT 0x02 -#define HCI_EVENT_PKT 0x04 - -#define EVT_DISCONN_COMPLETE 0x05 -#define EVT_CMD_COMPLETE 0xe -#define EVT_CMD_STATUS 0x0f -#define EVT_NUM_COMP_PKTS 0x13 -#define EVT_LE_META_EVENT 0x3e - -#define EVT_LE_CONN_COMPLETE 0x01 -#define EVT_LE_ADVERTISING_REPORT 0x02 - -#define OGF_LINK_CTL 0x01 -#define OGF_HOST_CTL 0x03 -#define OGF_INFO_PARAM 0x04 -#define OGF_STATUS_PARAM 0x05 -#define OGF_LE_CTL 0x08 - -// OGF_LINK_CTL -#define OCF_DISCONNECT 0x0006 - -// OGF_HOST_CTL -#define OCF_SET_EVENT_MASK 0x0001 -#define OCF_RESET 0x0003 - -// OGF_INFO_PARAM -#define OCF_READ_LOCAL_VERSION 0x0001 -#define OCF_READ_BD_ADDR 0x0009 - -// OGF_STATUS_PARAM -#define OCF_READ_RSSI 0x0005 - -// OGF_LE_CTL -#define OCF_LE_READ_BUFFER_SIZE 0x0002 -#define OCF_LE_SET_RANDOM_ADDRESS 0x0005 -#define OCF_LE_SET_ADVERTISING_PARAMETERS 0x0006 -#define OCF_LE_SET_ADVERTISING_DATA 0x0008 -#define OCF_LE_SET_SCAN_RESPONSE_DATA 0x0009 -#define OCF_LE_SET_ADVERTISE_ENABLE 0x000a -#define OCF_LE_SET_SCAN_PARAMETERS 0x000b -#define OCF_LE_SET_SCAN_ENABLE 0x000c -#define OCF_LE_CREATE_CONN 0x000d -#define OCF_LE_CANCEL_CONN 0x000e -#define OCF_LE_CONN_UPDATE 0x0013 - -#define HCI_OE_USER_ENDED_CONNECTION 0x13 - - -#define RECV_BUFFER_SIZE (3 + 255) -#define ACL_PKT_BUFFER_SIZE (255) - -STATIC bleio_adapter_obj_t *adapter; - -STATIC int recv_idx; -STATIC uint8_t recv_buffer[RECV_BUFFER_SIZE]; -STATIC uint16_t cmd_complete_opcode; -STATIC int cmd_complete_status; -STATIC uint8_t cmd_response_len; -STATIC uint8_t* cmd_response; - -STATIC uint8_t max_pkt; -STATIC uint8_t pending_pkt; - -//FIX STATIC uint8_t acl_pkt_buffer[255]; - -STATIC bool debug = true; - -typedef struct __attribute__ ((packed)) { - uint8_t evt; - uint8_t plen; -} HCIEventHdr; - -STATIC void dumpPkt(const char* prefix, uint8_t plen, uint8_t pdata[]) -{ - if (debug) { - mp_printf(&mp_plat_print, "%s", prefix); - - for (uint8_t i = 0; i < plen; i++) { - mp_printf(&mp_plat_print, "%02x", pdata[i]); - } - mp_printf(&mp_plat_print, "\n"); - } -} - - -STATIC void handleAclDataPkt(uint8_t plen, uint8_t pdata[]) -{ - // typedef struct __attribute__ ((packed)) { - // uint16_t handle; - // uint16_t dlen; - // uint16_t len; - // uint16_t cid; - // } HCIACLHdr; - - // HCIACLHdr *aclHdr = (HCIACLHdr*)pdata; - - // uint16_t aclFlags = (aclHdr->handle & 0xf000) >> 12; - - // if ((aclHdr->dlen - 4) != aclHdr->len) { - // // packet is fragmented - // if (aclFlags != 0x01) { - // // copy into ACL buffer - // memcpy(acl_pkt_buffer, &recv_buffer[1], sizeof(HCIACLHdr) + aclHdr->dlen - 4); - // } else { - // // copy next chunk into the buffer - // HCIACLHdr* aclBufferHeader = (HCIACLHdr*)acl_pkt_buffer; - - // memcpy(&acl_pkt_buffer[sizeof(HCIACLHdr) + aclBufferHeader->dlen - 4], &recv_buffer[1 + sizeof(aclHdr->handle) + sizeof(aclHdr->dlen)], aclHdr->dlen); - - // aclBufferHeader->dlen += aclHdr->dlen; - // aclHdr = aclBufferHeader; - // } - // } - - // if ((aclHdr->dlen - 4) != aclHdr->len) { - // // don't have the full packet yet - // return; - // } - - // if (aclHdr->cid == ATT_CID) { - // if (aclFlags == 0x01) { - // // use buffered packet - // ATT.handleData(aclHdr->handle & 0x0fff, aclHdr->len, &acl_pkt_buffer[sizeof(HCIACLHdr)]); - // } else { - // // use the recv buffer - // ATT.handleData(aclHdr->handle & 0x0fff, aclHdr->len, &recv_buffer[1 + sizeof(HCIACLHdr)]); - // } - // } else if (aclHdr->cid == SIGNALING_CID) { - // L2CAPSignaling.handleData(aclHdr->handle & 0x0fff, aclHdr->len, &recv_buffer[1 + sizeof(HCIACLHdr)]); - // } else { - // struct __attribute__ ((packed)) { - // uint8_t op; - // uint8_t id; - // uint16_t length; - // uint16_t reason; - // uint16_t localCid; - // uint16_t remoteCid; - // } l2capRejectCid= { 0x01, 0x00, 0x006, 0x0002, aclHdr->cid, 0x0000 }; - - // sendAclPkt(aclHdr->handle & 0x0fff, 0x0005, sizeof(l2capRejectCid), &l2capRejectCid); - // } -} - -STATIC void handleNumCompPkts(uint16_t handle, uint16_t numPkts) -{ - if (numPkts && pending_pkt > numPkts) { - pending_pkt -= numPkts; - } else { - pending_pkt = 0; - } -} - -STATIC void handleEventPkt(uint8_t plen, uint8_t pdata[]) -{ - HCIEventHdr *eventHdr = (HCIEventHdr*)pdata; - - if (eventHdr->evt == EVT_DISCONN_COMPLETE) { - typedef struct __attribute__ ((packed)) { - uint8_t status; - uint16_t handle; - uint8_t reason; - } DisconnComplete; - - DisconnComplete *disconnComplete = (DisconnComplete*)&pdata[sizeof(HCIEventHdr)]; - (void) disconnComplete; - //FIX - // ATT.removeConnection(disconnComplete->handle, disconnComplete->reason); - // L2CAPSignaling.removeConnection(disconnComplete->handle, disconnComplete->reason); - - hci_leSetAdvertiseEnable(0x01); - } else if (eventHdr->evt == EVT_CMD_COMPLETE) { - typedef struct __attribute__ ((packed)) { - uint8_t ncmd; - uint16_t opcode; - uint8_t status; - } CmdComplete; - - CmdComplete *cmdCompleteHeader = (CmdComplete*)&pdata[sizeof(HCIEventHdr)]; - cmd_complete_opcode = cmdCompleteHeader->opcode; - cmd_complete_status = cmdCompleteHeader->status; - cmd_response_len = pdata[1] - sizeof(CmdComplete); - cmd_response = &pdata[sizeof(HCIEventHdr) + sizeof(CmdComplete)]; - - } else if (eventHdr->evt == EVT_CMD_STATUS) { - typedef struct __attribute__ ((packed)) { - uint8_t status; - uint8_t ncmd; - uint16_t opcode; - } CmdStatus; - - CmdStatus *cmdStatusHeader = (CmdStatus*)&pdata[sizeof(HCIEventHdr)]; - cmd_complete_opcode = cmdStatusHeader->opcode; - cmd_complete_status = cmdStatusHeader->status; - cmd_response_len = 0; - } else if (eventHdr->evt == EVT_NUM_COMP_PKTS) { - uint8_t numHandles = pdata[sizeof(HCIEventHdr)]; - uint8_t* data = &pdata[sizeof(HCIEventHdr) + sizeof(numHandles)]; - - for (uint8_t i = 0; i < numHandles; i++) { - handleNumCompPkts(data[0], data[1]); - - data += 2; - } - } else if (eventHdr->evt == EVT_LE_META_EVENT) { - typedef struct __attribute__ ((packed)) { - uint8_t subevent; - } LeMetaEventHeader; - - LeMetaEventHeader *leMetaHeader = (LeMetaEventHeader*)&pdata[sizeof(HCIEventHdr)]; - if (leMetaHeader->subevent == EVT_LE_CONN_COMPLETE) { - typedef struct __attribute__ ((packed)) { - uint8_t status; - uint16_t handle; - uint8_t role; - uint8_t peerBdaddrType; - uint8_t peerBdaddr[6]; - uint16_t interval; - uint16_t latency; - uint16_t supervisionTimeout; - uint8_t masterClockAccuracy; - } EvtLeConnectionComplete; - - EvtLeConnectionComplete *leConnectionComplete = (EvtLeConnectionComplete*)&pdata[sizeof(HCIEventHdr) + sizeof(LeMetaEventHeader)]; - - if (leConnectionComplete->status == 0x00) { - // ATT.addConnection(leConnectionComplete->handle, - // leConnectionComplete->role, - // leConnectionComplete->peerBdaddrType, - // leConnectionComplete->peerBdaddr, - // leConnectionComplete->interval, - // leConnectionComplete->latency, - // leConnectionComplete->supervisionTimeout, - // leConnectionComplete->masterClockAccuracy); - - // L2CAPSignaling.addConnection(leConnectionComplete->handle, - // leConnectionComplete->role, - // leConnectionComplete->peerBdaddrType, - // leConnectionComplete->peerBdaddr, - // leConnectionComplete->interval, - // leConnectionComplete->latency, - // leConnectionComplete->supervisionTimeout, - // leConnectionComplete->masterClockAccuracy); - } - } else if (leMetaHeader->subevent == EVT_LE_ADVERTISING_REPORT) { - typedef struct __attribute__ ((packed)) { - uint8_t status; - uint8_t type; - uint8_t peerBdaddrType; - uint8_t peerBdaddr[6]; - uint8_t eirLength; - uint8_t eirData[31]; - } EvtLeAdvertisingReport; - - EvtLeAdvertisingReport*leAdvertisingReport = (EvtLeAdvertisingReport*)&pdata[sizeof(HCIEventHdr) + sizeof(LeMetaEventHeader)]; - - if (leAdvertisingReport->status == 0x01) { - // last byte is RSSI - //FIX int8_t rssi = leAdvertisingReport->eirData[leAdvertisingReport->eirLength]; - - // GAP.handleLeAdvertisingReport(leAdvertisingReport->type, - // leAdvertisingReport->peerBdaddrType, - // leAdvertisingReport->peerBdaddr, - // leAdvertisingReport->eirLength, - // leAdvertisingReport->eirData, - // rssi); - - } - } - } -} - -void hci_init(bleio_adapter_obj_t *adapter_in) { - adapter = adapter_in; - recv_idx = 0; - pending_pkt = 0; -} - -void hci_poll(void) { - // Assert RTS low to say we're ready to read data. - common_hal_digitalio_digitalinout_set_value(&adapter->rts_digitalinout, false); - - int errcode = 0; - while (common_hal_busio_uart_rx_characters_available(&adapter->hci_uart)) { - // Read just one character. - common_hal_busio_uart_read(&adapter->hci_uart, recv_buffer + recv_idx, 1, &errcode); - recv_idx++; - - if (recv_buffer[0] == HCI_ACLDATA_PKT) { - if (recv_idx > 5 && recv_idx >= (5 + (recv_buffer[3] + (recv_buffer[4] << 8)))) { - if (debug) { - dumpPkt("HCI ACLDATA RX <- ", recv_idx, recv_buffer); - } - // Hold data while processing packet. - common_hal_digitalio_digitalinout_set_value(&adapter->rts_digitalinout, true); - size_t pktLen = recv_idx - 1; - recv_idx = 0; - - handleAclDataPkt(pktLen, &recv_buffer[1]); - - common_hal_digitalio_digitalinout_set_value(&adapter->rts_digitalinout, false); - } - } else if (recv_buffer[0] == HCI_EVENT_PKT) { - if (recv_idx > 3 && recv_idx >= (3 + recv_buffer[2])) { - if (debug) { - dumpPkt("HCI EVENT RX <- ", recv_idx, recv_buffer); - } - // Hold data while processing packet. - common_hal_digitalio_digitalinout_set_value(&adapter->rts_digitalinout, true); - // Received full event. Reset buffer and handle packet. - size_t pktLen = recv_idx - 1; - recv_idx = 0; - - handleEventPkt(pktLen, &recv_buffer[1]); - - common_hal_digitalio_digitalinout_set_value(&adapter->rts_digitalinout, false); - } - } else { - recv_idx = 0; - } - } - - common_hal_digitalio_digitalinout_set_value(&adapter->rts_digitalinout, true); -} - - -int hci_sendCommand(uint8_t ogf, uint16_t ocf, uint8_t plen, void* parameters) -{ - uint16_t opcode = ogf << 10 | ocf; - - struct __attribute__ ((packed)) { - uint8_t pktType; - uint16_t opcode; - uint8_t plen; - } pktHdr = {HCI_COMMAND_PKT, opcode, plen}; - - uint8_t txBuffer[sizeof(pktHdr) + plen]; - memcpy(txBuffer, &pktHdr, sizeof(pktHdr)); - memcpy(&txBuffer[sizeof(pktHdr)], parameters, plen); - - if (debug) { - dumpPkt("HCI COMMAND TX -> ", sizeof(pktHdr) + plen, txBuffer); - } - - int errcode = 0; - common_hal_busio_uart_write(&adapter->hci_uart, txBuffer, sizeof(pktHdr) + plen, &errcode); - if (errcode) { - return -1; - } - - cmd_complete_opcode = 0xffff; - cmd_complete_status = -1; - - // Wait up to one second for a response. - for (uint64_t start = supervisor_ticks_ms64(); - cmd_complete_opcode != opcode && supervisor_ticks_ms64() < (start + 5000); - ) { - hci_poll(); - } - - return cmd_complete_status; -} - -int hci_reset(void) { - return hci_sendCommand(OGF_HOST_CTL, OCF_RESET, 0, NULL); -} - -int hci_readLocalVersion(uint8_t *hciVer, uint16_t *hciRev, uint8_t *lmpVer, uint16_t *manufacturer, uint16_t *lmpSubVer) { - int result = hci_sendCommand(OGF_INFO_PARAM, OCF_READ_LOCAL_VERSION, 0, NULL); - - if (result == 0) { - typedef struct __attribute__ ((packed)) { - uint8_t hciVer; - uint16_t hciRev; - uint8_t lmpVer; - uint16_t manufacturer; - uint16_t lmpSubVer; - } HCILocalVersion; - - HCILocalVersion *localVersion = (HCILocalVersion*)cmd_response; - *hciVer = localVersion->hciVer; - *hciRev = localVersion->hciRev; - *lmpVer = localVersion->lmpVer; - *manufacturer = localVersion->manufacturer; - *lmpSubVer = localVersion->lmpSubVer; - } - - return result; -} - -int hci_readBdAddr(uint8_t addr[6]) { - int result = hci_sendCommand(OGF_INFO_PARAM, OCF_READ_BD_ADDR, 0, NULL); - - if (result == 0) { - memcpy(addr, cmd_response, 6); - } - - return result; -} - -int hci_readRssi(uint16_t handle) { - int result = hci_sendCommand(OGF_STATUS_PARAM, OCF_READ_RSSI, sizeof(handle), &handle); - int rssi = 127; - - if (result == 0) { - typedef struct __attribute__ ((packed)) { - uint16_t handle; - int8_t rssi; - } HCIReadRssi; - - HCIReadRssi *readRssi = (HCIReadRssi*)cmd_response; - if (readRssi->handle == handle) { - rssi = readRssi->rssi; - } - } - - return rssi; -} - -int hci_setEventMask(uint64_t eventMask) { - return hci_sendCommand(OGF_HOST_CTL, OCF_SET_EVENT_MASK, sizeof(eventMask), &eventMask); -} - -int hci_readLeBufferSize(uint16_t *pktLen, uint8_t *maxPkt) -{ - int result = hci_sendCommand(OGF_LE_CTL, OCF_LE_READ_BUFFER_SIZE, 0, NULL); - - if (result == 0) { - typedef struct __attribute__ ((packed)) { - uint16_t pktLen; - uint8_t maxPkt; - } HCILeBufferSize; - - HCILeBufferSize *leBufferSize = (HCILeBufferSize*)cmd_response; - *pktLen = leBufferSize->pktLen; - *maxPkt = leBufferSize->maxPkt; - -#ifndef __AVR__ - // FIX (needed?) ATT.setMaxMtu(pktLen - 9); // max pkt len - ACL header size -#endif - } - - return result; -} - -int hci_leSetRandomAddress(uint8_t addr[6]) -{ - return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_RANDOM_ADDRESS, 6, addr); -} - -int hci_leSetAdvertisingParameters(uint16_t minInterval, uint16_t maxInterval, - uint8_t advType, uint8_t ownBdaddrType, - uint8_t directBdaddrType, uint8_t directBdaddr[6], - uint8_t chanMap, - uint8_t filter) -{ - struct __attribute__ ((packed)) HCILeAdvertisingParameters { - uint16_t minInterval; - uint16_t maxInterval; - uint8_t advType; - uint8_t ownBdaddrType; - uint8_t directBdaddrType; - uint8_t directBdaddr[6]; - uint8_t chanMap; - uint8_t filter; - } leAdvertisingParamters; - - leAdvertisingParamters.minInterval = minInterval; - leAdvertisingParamters.maxInterval = maxInterval; - leAdvertisingParamters.advType = advType; - leAdvertisingParamters.ownBdaddrType = ownBdaddrType; - leAdvertisingParamters.directBdaddrType = directBdaddrType; - memcpy(leAdvertisingParamters.directBdaddr, directBdaddr, 6); - leAdvertisingParamters.chanMap = chanMap; - leAdvertisingParamters.filter = filter; - - return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_ADVERTISING_PARAMETERS, sizeof(leAdvertisingParamters), &leAdvertisingParamters); -} - -int hci_leSetAdvertisingData(uint8_t length, uint8_t data[]) -{ - struct __attribute__ ((packed)) HCILeAdvertisingData { - uint8_t length; - uint8_t data[31]; - } leAdvertisingData; - - memset(&leAdvertisingData, 0, sizeof(leAdvertisingData)); - leAdvertisingData.length = length; - memcpy(leAdvertisingData.data, data, length); - - return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_ADVERTISING_DATA, sizeof(leAdvertisingData), &leAdvertisingData); -} - -int hci_leSetScanResponseData(uint8_t length, uint8_t data[]) -{ - struct __attribute__ ((packed)) HCILeScanResponseData { - uint8_t length; - uint8_t data[31]; - } leScanResponseData; - - memset(&leScanResponseData, 0, sizeof(leScanResponseData)); - leScanResponseData.length = length; - memcpy(leScanResponseData.data, data, length); - - return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_SCAN_RESPONSE_DATA, sizeof(leScanResponseData), &leScanResponseData); -} - -int hci_leSetAdvertiseEnable(uint8_t enable) -{ - return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_ADVERTISE_ENABLE, sizeof(enable), &enable); -} - -int hci_leSetScanParameters(uint8_t type, uint16_t interval, uint16_t window, - uint8_t ownBdaddrType, uint8_t filter) -{ - struct __attribute__ ((packed)) HCILeSetScanParameters { - uint8_t type; - uint16_t interval; - uint16_t window; - uint8_t ownBdaddrType; - uint8_t filter; - } leScanParameters; - - leScanParameters.type = type; - leScanParameters.interval = interval; - leScanParameters.window = window; - leScanParameters.ownBdaddrType = ownBdaddrType; - leScanParameters.filter = filter; - - return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_SCAN_PARAMETERS, sizeof(leScanParameters), &leScanParameters); -} - -int hci_leSetScanEnable(uint8_t enabled, uint8_t duplicates) -{ - struct __attribute__ ((packed)) HCILeSetScanEnableData { - uint8_t enabled; - uint8_t duplicates; - } leScanEnableData; - - leScanEnableData.enabled = enabled; - leScanEnableData.duplicates = duplicates; - - return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_SCAN_ENABLE, sizeof(leScanEnableData), &leScanEnableData); -} - -int hci_leCreateConn(uint16_t interval, uint16_t window, uint8_t initiatorFilter, - uint8_t peerBdaddrType, uint8_t peerBdaddr[6], uint8_t ownBdaddrType, - uint16_t minInterval, uint16_t maxInterval, uint16_t latency, - uint16_t supervisionTimeout, uint16_t minCeLength, uint16_t maxCeLength) -{ - struct __attribute__ ((packed)) HCILeCreateConnData { - uint16_t interval; - uint16_t window; - uint8_t initiatorFilter; - uint8_t peerBdaddrType; - uint8_t peerBdaddr[6]; - uint8_t ownBdaddrType; - uint16_t minInterval; - uint16_t maxInterval; - uint16_t latency; - uint16_t supervisionTimeout; - uint16_t minCeLength; - uint16_t maxCeLength; - } leCreateConnData; - - leCreateConnData.interval = interval; - leCreateConnData.window = window; - leCreateConnData.initiatorFilter = initiatorFilter; - leCreateConnData.peerBdaddrType = peerBdaddrType; - memcpy(leCreateConnData.peerBdaddr, peerBdaddr, sizeof(leCreateConnData.peerBdaddr)); - leCreateConnData.ownBdaddrType = ownBdaddrType; - leCreateConnData.minInterval = minInterval; - leCreateConnData.maxInterval = maxInterval; - leCreateConnData.latency = latency; - leCreateConnData.supervisionTimeout = supervisionTimeout; - leCreateConnData.minCeLength = minCeLength; - leCreateConnData.maxCeLength = maxCeLength; - - return hci_sendCommand(OGF_LE_CTL, OCF_LE_CREATE_CONN, sizeof(leCreateConnData), &leCreateConnData); -} - -int hci_leCancelConn() -{ - return hci_sendCommand(OGF_LE_CTL, OCF_LE_CANCEL_CONN, 0, NULL); -} - -int hci_leConnUpdate(uint16_t handle, uint16_t minInterval, uint16_t maxInterval, - uint16_t latency, uint16_t supervisionTimeout) -{ - struct __attribute__ ((packed)) HCILeConnUpdateData { - uint16_t handle; - uint16_t minInterval; - uint16_t maxInterval; - uint16_t latency; - uint16_t supervisionTimeout; - uint16_t minCeLength; - uint16_t maxCeLength; - } leConnUpdateData; - - leConnUpdateData.handle = handle; - leConnUpdateData.minInterval = minInterval; - leConnUpdateData.maxInterval = maxInterval; - leConnUpdateData.latency = latency; - leConnUpdateData.supervisionTimeout = supervisionTimeout; - leConnUpdateData.minCeLength = 0x0004; - leConnUpdateData.maxCeLength = 0x0006; - - return hci_sendCommand(OGF_LE_CTL, OCF_LE_CONN_UPDATE, sizeof(leConnUpdateData), &leConnUpdateData); -} - -int hci_sendAclPkt(uint16_t handle, uint8_t cid, uint8_t plen, void* data) { - while (pending_pkt >= max_pkt) { - hci_poll(); - } - - typedef struct __attribute__ ((packed)) { - uint8_t pktType; - uint16_t handle; - uint16_t dlen; - uint16_t plen; - uint16_t cid; - } HCIACLHdr; - - HCIACLHdr aclHdr = { HCI_ACLDATA_PKT, handle, (uint8_t)(plen + 4), plen, cid }; - - uint8_t txBuffer[sizeof(aclHdr) + plen]; - memcpy(txBuffer, &aclHdr, sizeof(aclHdr)); - memcpy(&txBuffer[sizeof(aclHdr)], data, plen); - - if (debug) { - dumpPkt("HCI ACLDATA TX -> ", sizeof(aclHdr) + plen, txBuffer); - } - - pending_pkt++; - - int errcode = 0; - common_hal_busio_uart_write(&adapter->hci_uart, txBuffer, sizeof(aclHdr) + plen, &errcode); - if (errcode) { - return -1; - } - - return 0; -} - -int hci_disconnect(uint16_t handle) -{ - struct __attribute__ ((packed)) HCIDisconnectData { - uint16_t handle; - uint8_t reason; - } disconnectData = { handle, HCI_OE_USER_ENDED_CONNECTION }; - - return hci_sendCommand(OGF_LINK_CTL, OCF_DISCONNECT, sizeof(disconnectData), &disconnectData); -} diff --git a/devices/ble_hci/common-hal/_bleio/hci_api.c b/devices/ble_hci/common-hal/_bleio/hci_api.c new file mode 100644 index 000000000..180ab6f5e --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/hci_api.c @@ -0,0 +1,646 @@ +/* + This file is part of the ArduinoBLE library. + Copyright (c) 2018 Arduino SA. All rights reserved. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "hci_api.h" + +// Zephyr include files to define HCI communication values and structs. +#include "hci_include/hci.h" +#include "hci_include/hci_err.h" + +#include + +#include "supervisor/shared/tick.h" + +// HCI H4 protocol packet types: first byte in the packet. +#define H4_CMD 0x01 +#define H4_ACL 0x02 +#define H4_SCO 0x03 +#define H4_EVT 0x04 + +//FIX replace +#define ATT_CID 0x0004 + +#define RX_BUFFER_SIZE (3 + 255) +#define ACL_PKT_BUFFER_SIZE (255) + +#define CTS_TIMEOUT_MSECS (1000) +#define RESPONSE_TIMEOUT_MSECS (1000) + +STATIC bleio_adapter_obj_t *adapter; + +STATIC uint8_t rx_buffer[RX_BUFFER_SIZE]; +STATIC size_t rx_idx; + +STATIC size_t num_command_packets_allowed; +STATIC size_t max_pkt; +STATIC size_t pending_pkt; + +// Results from parsing a command response packet. +STATIC bool cmd_response_received; +STATIC uint16_t cmd_response_opcode; +STATIC uint8_t cmd_response_status; +STATIC size_t cmd_response_len; +STATIC uint8_t* cmd_response_data; + +//FIX STATIC uint8_t acl_pkt_buffer[ACL_PKT_BUFFER_SIZE]; + +STATIC bool debug = true; + +// These are the headers of the full packets that are sent over the serial interface. +// They all have a one-byte type-field at the front, one of the H4_xxx packet types. + +typedef struct __attribute__ ((packed)) { + uint8_t pkt_type; + uint16_t opcode; + uint8_t param_len; +} h4_hci_cmd_hdr_t; + +typedef struct __attribute__ ((packed)) { + uint8_t pkt_type; + uint16_t handle; + uint16_t total_data_len; + uint16_t acl_data_len; + uint16_t cid; +} h4_hci_acl_hdr_t; + +typedef struct __attribute__ ((packed)) { + uint8_t pkt_type; + uint8_t evt; + uint8_t param_len; +} h4_hci_evt_hdr_t; + + + +STATIC void dump_pkt(const char* prefix, uint8_t pkt_len, uint8_t pkt_data[]) { + if (debug) { + mp_printf(&mp_plat_print, "%s", prefix); + for (uint8_t i = 0; i < pkt_len; i++) { + mp_printf(&mp_plat_print, "%02x", pkt_data[i]); + } + mp_printf(&mp_plat_print, "\n"); + } +} + +STATIC void process_acl_data_pkt(uint8_t pkt_len, uint8_t pkt_data[]) { + //FIX pkt_len is +1 than before, because it includes the pkt_type. + // h4_hci_acl_hdr_t *aclHdr = (h4_hci_acl_hdr_t*)pkt_data; + + // uint16_t aclFlags = (aclHdr->handle & 0xf000) >> 12; + + // if ((aclHdr->data_len - 4) != aclHdr->len) { + // // packet is fragmented + // if (aclFlags != 0x01) { + // // copy into ACL buffer + // memcpy(acl_pkt_buffer, &rx_buffer[1], sizeof(HCIACLHdr) + aclHdr->data_len - 4); + // } else { + // // copy next chunk into the buffer + // HCIACLHdr* aclBufferHeader = (HCIACLHdr*)acl_pkt_buffer; + + // memcpy(&acl_pkt_buffer[sizeof(HCIACLHdr) + aclBufferHeader->data_len - 4], &rx_buffer[1 + sizeof(aclHdr->handle) + sizeof(aclHdr->data_len)], aclHdr->data_len); + + // aclBufferHeader->data_len += aclHdr->data_len; + // aclHdr = aclBufferHeader; + // } + // } + + // if ((aclHdr->data_len - 4) != aclHdr->len) { + // // don't have the full packet yet + // return; + // } + + // if (aclHdr->cid == ATT_CID) { + // if (aclFlags == 0x01) { + // // use buffered packet + // ATT.handleData(aclHdr->handle & 0x0fff, aclHdr->len, &acl_pkt_buffer[sizeof(HCIACLHdr)]); + // } else { + // // use the rx buffer + // ATT.handleData(aclHdr->handle & 0x0fff, aclHdr->len, &rx_buffer[1 + sizeof(HCIACLHdr)]); + // } + // } else if (aclHdr->cid == SIGNALING_CID) { + // L2CAPSignaling.handleData(aclHdr->handle & 0x0fff, aclHdr->len, &rx_buffer[1 + sizeof(HCIACLHdr)]); + // } else { + // struct __attribute__ ((packed)) { + // uint8_t op; + // uint8_t id; + // uint16_t length; + // uint16_t reason; + // uint16_t localCid; + // uint16_t remoteCid; + // } l2capRejectCid= { 0x01, 0x00, 0x006, 0x0002, aclHdr->cid, 0x0000 }; + + // sendAclPkt(aclHdr->handle & 0x0fff, 0x0005, sizeof(l2capRejectCid), &l2capRejectCid); + // } +} + +// Process number of completed packets. Reduce number of pending packets by reported +// number of completed. +STATIC void process_num_comp_pkts(uint16_t handle, uint16_t num_pkts) { + if (num_pkts && pending_pkt > num_pkts) { + pending_pkt -= num_pkts; + } else { + pending_pkt = 0; + } +} + +STATIC void process_evt_pkt(size_t pkt_len, uint8_t pkt[]) +{ + h4_hci_evt_hdr_t *evt_hdr = (h4_hci_evt_hdr_t*) pkt; + // The data itself, after the header. + uint8_t *evt_data = pkt + sizeof(h4_hci_evt_hdr_t); + + switch (evt_hdr->evt) { + case BT_HCI_EVT_DISCONN_COMPLETE: { + struct bt_hci_evt_disconn_complete *disconn_complete = (struct bt_hci_evt_disconn_complete*) evt_data; + (void) disconn_complete; + //FIX + // ATT.removeConnection(disconn_complete->handle, disconn_complete->reason); + // L2CAPSignaling.removeConnection(disconn_complete->handle, disconn_complete->reason); + hci_le_set_advertise_enable(0x01); + break; + } + + case BT_HCI_EVT_CMD_COMPLETE: { + + struct cmd_complete_with_status { + struct bt_hci_evt_cmd_complete cmd_complete; + struct bt_hci_evt_cc_status cc_status; + } __packed; + + struct cmd_complete_with_status *evt = (struct cmd_complete_with_status *) evt_data; + + num_command_packets_allowed = evt->cmd_complete.ncmd; + + cmd_response_received = true; + cmd_response_opcode = evt->cmd_complete.opcode; + cmd_response_status = evt->cc_status.status; + // All the bytes following status. + cmd_response_data = &evt_data[sizeof(struct cmd_complete_with_status)]; + cmd_response_len = evt_hdr->param_len - sizeof(struct cmd_complete_with_status); + + break; + } + + case BT_HCI_EVT_CMD_STATUS: { + struct bt_hci_evt_cmd_status *evt = (struct bt_hci_evt_cmd_status *) evt_data; + + num_command_packets_allowed = evt->ncmd; + + cmd_response_received = true; + cmd_response_opcode = evt->opcode; + cmd_response_status = evt->status; + cmd_response_data = NULL; + cmd_response_len = 0; + + break; + } + + case BT_HCI_EVT_NUM_COMPLETED_PACKETS: { + struct bt_hci_evt_num_completed_packets *evt = (struct bt_hci_evt_num_completed_packets *) evt_data; + + // Start at zero-th pair: (conn handle, num completed packets). + struct bt_hci_handle_count *handle_and_count = &(evt->h[0]); + for (uint8_t i = 0; i < evt->num_handles; i++) { + process_num_comp_pkts(handle_and_count->handle, handle_and_count->count); + handle_and_count++; + } + break; + } + + case BT_HCI_EVT_LE_META_EVENT: { + struct bt_hci_evt_le_meta_event *meta_evt = (struct bt_hci_evt_le_meta_event *) evt_data; + // Start of the encapsulated LE event. + uint8_t *le_evt = evt_data + sizeof (struct bt_hci_evt_le_meta_event); + + if (meta_evt->subevent == BT_HCI_EVT_LE_CONN_COMPLETE) { + struct bt_hci_evt_le_conn_complete *le_conn_complete = + (struct bt_hci_evt_le_conn_complete *) le_evt; + + if (le_conn_complete->status == 0x00) { + // ATT.addConnection(le_conn_complete->handle, + // le_conn_complete->role, + // le_conn_complete->peer_addr //FIX struct + // le_conn_complete->interval, + // le_conn_complete->latency, + // le_conn_complete->supv_timeout + // le_conn_complete->clock_accuracy); + + // L2CAPSignaling.addConnection(le_conn_complete->handle, + // le_conn_complete->role, + // le_conn_complete->peer_addr, //FIX struct + // le_conn_complete->interval, + // le_conn_complete->latency, + // le_conn_complete->supv_timeout, + // le_conn_complete->clock_accuracy); + } + } else if (meta_evt->subevent == BT_HCI_EVT_LE_ADVERTISING_REPORT) { + struct bt_hci_evt_le_advertising_info *le_advertising_info = + (struct bt_hci_evt_le_advertising_info *) le_evt; + if (le_advertising_info->evt_type == BT_HCI_ADV_DIRECT_IND) { //FIX handle kind of advertising + // last byte is RSSI + // GAP.handleLeAdvertisingReport(leAdvertisingReport->type, + // leAdvertisingReport->peerBdaddrType, + // leAdvertisingReport->peerBdaddr, + // leAdvertisingReport->eirLength, + // leAdvertisingReport->eirData, + // rssi); //FIX, don't separate + + } + } + break; + } + + default: + break; + } +} + +void hci_init(bleio_adapter_obj_t *adapter_in) { + adapter = adapter_in; + rx_idx = 0; + pending_pkt = 0; +} + +hci_result_t hci_poll_for_incoming_pkt(void) { + // Assert RTS low to say we're ready to read data. + common_hal_digitalio_digitalinout_set_value(&adapter->rts_digitalinout, false); + + int errcode = 0; + bool packet_is_complete = false; + + // Read bytes until we run out, or accumulate a complete packet. + while (common_hal_busio_uart_rx_characters_available(adapter->hci_uart)) { + common_hal_busio_uart_read(adapter->hci_uart, rx_buffer + rx_idx, 1, &errcode); + if (!errcode) { + return HCI_READ_ERROR; + } + rx_idx++; + + switch (rx_buffer[0]) { + case H4_ACL: + if (rx_idx > sizeof(h4_hci_acl_hdr_t) && + rx_idx >= sizeof(h4_hci_acl_hdr_t) + ((h4_hci_acl_hdr_t *) rx_buffer)->total_data_len) { + packet_is_complete = true; + } + break; + + case H4_EVT: + if (rx_idx > sizeof(h4_hci_evt_hdr_t) && + rx_idx >= sizeof(h4_hci_evt_hdr_t) + ((h4_hci_evt_hdr_t *) rx_buffer)->param_len) { + packet_is_complete = true; + } + break; + + default: + // Unknown or bad packet type. Start over. + rx_idx = 0; + break; + } + } + + if (!packet_is_complete) { + return HCI_OK; + } + + // Stop incoming data while processing packet. + common_hal_digitalio_digitalinout_set_value(&adapter->rts_digitalinout, true); + size_t pkt_len = rx_idx; + rx_idx = 0; + + switch (rx_buffer[0]) { + case H4_ACL: + if (debug) { + dump_pkt("HCI EVENT RX <- ", rx_idx, rx_buffer); + } + + process_acl_data_pkt(pkt_len, rx_buffer); + break; + + case H4_EVT: + if (debug) { + dump_pkt("HCI ACLDATA RX <- ", rx_idx, rx_buffer); + } + + process_evt_pkt(pkt_len, rx_buffer); + break; + + default: + break; + } + + common_hal_digitalio_digitalinout_set_value(&adapter->rts_digitalinout, true); + + return HCI_OK; +} + + +// Returns +STATIC hci_result_t write_pkt(uint8_t *buffer, size_t len) { + // Wait for CTS to go low before writing to HCI adapter. + uint64_t start = supervisor_ticks_ms64(); + while (common_hal_digitalio_digitalinout_get_value(&adapter->cts_digitalinout)) { + RUN_BACKGROUND_TASKS; + if (supervisor_ticks_ms64() - start > CTS_TIMEOUT_MSECS) { + return HCI_WRITE_TIMEOUT; + } + } + + int errcode = 0; + common_hal_busio_uart_write(adapter->hci_uart, buffer, len, &errcode); + if (errcode) { + return HCI_WRITE_ERROR; + } + + return HCI_OK; +} + +STATIC hci_result_t send_command(uint16_t opcode, uint8_t params_len, void* params) { + uint8_t tx_buffer[sizeof(h4_hci_cmd_hdr_t) + params_len]; + + // cmd header is at the beginning of tx_buffer + h4_hci_cmd_hdr_t *cmd_hdr = (h4_hci_cmd_hdr_t *) tx_buffer; + cmd_hdr->pkt_type = H4_CMD; + cmd_hdr->opcode = opcode; + cmd_hdr->param_len = params_len; + + // Copy the params data into the space after the header. + memcpy(&tx_buffer[sizeof(h4_hci_cmd_hdr_t)], params, params_len); + + if (debug) { + dump_pkt("HCI COMMAND TX -> ", sizeof(tx_buffer), tx_buffer); + } + + int result = write_pkt(tx_buffer, sizeof(h4_hci_cmd_hdr_t) + params_len); + if (result != HCI_OK) { + return result; + } + + cmd_response_received = false; + + // Wait for a response. Note that other packets may be received that are not + // command responses. + uint64_t start = supervisor_ticks_ms64(); + while (1) { + result = hci_poll_for_incoming_pkt(); + if (result != HCI_OK) { + // I/O error. + return result; + } + + if (cmd_response_received && cmd_response_opcode == opcode) { + // If this is definitely a response to the command that was sent, + // return the status value, which will will be + // BT_HCI_ERR_SUCCESS (0x00) if the command succeeded, + // or a BT_HCI_ERR_x value (> 0x00) if there ws a problem. + return cmd_response_status; + } + + if (supervisor_ticks_ms64() - start > RESPONSE_TIMEOUT_MSECS) { + return HCI_READ_TIMEOUT; + } + RUN_BACKGROUND_TASKS; + } + + // No I/O error, but no response sent back in time. + return HCI_NO_RESPONSE; +} + +//FIX remove unused +STATIC int __attribute__((unused)) send_acl_pkt(uint16_t handle, uint8_t cid, void* data, uint8_t data_len) { + int result; + while (pending_pkt >= max_pkt) { + result = hci_poll_for_incoming_pkt(); + if (result != HCI_OK) { + return result; + } + } + + // data_len does not include cid. + const size_t cid_len = sizeof(((h4_hci_acl_hdr_t *)0)->cid); + // buf_len is size of entire packet including header. + const size_t buf_len = sizeof(h4_hci_acl_hdr_t) + cid_len + data_len; + uint8_t tx_buffer[buf_len]; + + h4_hci_acl_hdr_t *acl_hdr = (h4_hci_acl_hdr_t *) tx_buffer; + acl_hdr->pkt_type = H4_ACL; + acl_hdr->handle = handle; + acl_hdr->total_data_len = (uint8_t)(cid_len + data_len); + acl_hdr->acl_data_len = (uint8_t) data_len; + acl_hdr->cid = cid; + + memcpy(&tx_buffer[sizeof(h4_hci_acl_hdr_t)], data, data_len); + + if (debug) { + dump_pkt("HCI ACLDATA TX -> ", buf_len, tx_buffer); + } + + pending_pkt++; + + int errcode = 0; + common_hal_busio_uart_write(adapter->hci_uart, tx_buffer, buf_len, &errcode); + if (errcode) { + return HCI_WRITE_ERROR; + } + + return HCI_OK; +} + +hci_result_t hci_reset(void) { + return send_command(BT_HCI_OP_RESET, 0, NULL); +} + +hci_result_t hci_read_local_version(uint8_t *hci_version, uint16_t *hci_revision, uint8_t *lmp_version, uint16_t *manufacturer, uint16_t *lmp_subversion) { + hci_result_t result = send_command(BT_HCI_OP_READ_LOCAL_VERSION_INFO, 0, NULL); + if (result == HCI_OK) { + struct bt_hci_rp_read_local_version_info *response = + (struct bt_hci_rp_read_local_version_info *) cmd_response_data; + *hci_version = response->hci_version; + *hci_revision = response->hci_revision; + *lmp_version = response->lmp_version; + *manufacturer = response->manufacturer; + *lmp_subversion = response->lmp_subversion; + } + + return result; +} + +hci_result_t hci_read_bd_addr(bt_addr_t *addr) { + int result = send_command(BT_HCI_OP_READ_BD_ADDR, 0, NULL); + if (result == HCI_OK) { + struct bt_hci_rp_read_bd_addr *response = (struct bt_hci_rp_read_bd_addr *) cmd_response_data; + memcpy(addr->val, response->bdaddr.val, sizeof(bt_addr_t)); + } + + return result; +} + +hci_result_t hci_read_rssi(uint16_t handle, int *rssi) { + int result = send_command(BT_HCI_OP_READ_RSSI, sizeof(handle), &handle); + if (result == HCI_OK) { + struct bt_hci_rp_read_rssi *response = (struct bt_hci_rp_read_rssi *) cmd_response_data; + if (response->handle != handle) { + // Handle doesn't match. + return HCI_NO_RESPONSE; + } + + *rssi = response->rssi; + } + + return result; +} + +hci_result_t hci_set_evt_mask(uint64_t event_mask) { + return send_command(BT_HCI_OP_SET_EVENT_MASK, sizeof(event_mask), &event_mask); +} + +hci_result_t hci_read_le_buffer_size(uint16_t *le_max_len, uint8_t *le_max_num) { + int result = send_command(BT_HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL); + if (result == HCI_OK) { + struct bt_hci_rp_le_read_buffer_size *response = + (struct bt_hci_rp_le_read_buffer_size *) cmd_response_data; + *le_max_len = response->le_max_len; + *le_max_num = response->le_max_num; + } + + return result; +} + +hci_result_t hci_le_set_random_address(uint8_t addr[6]) { + return send_command(BT_HCI_OP_LE_SET_RANDOM_ADDRESS, 6, addr); +} + +hci_result_t hci_le_set_advertising_parameters(uint16_t min_interval, uint16_t max_interval, uint8_t type, uint8_t own_addr_type, bt_addr_le_t *direct_addr, uint8_t channel_map, uint8_t filter_policy) { + struct bt_hci_cp_le_set_adv_param params = { + .min_interval = min_interval, + .max_interval = max_interval, + .type = type, + .own_addr_type = own_addr_type, + // .direct_addr set below. + .channel_map = channel_map, + .filter_policy = filter_policy, + }; + params.direct_addr.type = direct_addr->type; + memcpy(params.direct_addr.a.val, direct_addr->a.val, sizeof(params.direct_addr.a.val)); + + return send_command(BT_HCI_OP_LE_SET_ADV_PARAM, sizeof(params), ¶ms); +} + +hci_result_t hci_le_read_maximum_advertising_data_length(int *max_adv_data_len) { + int result = send_command(BT_HCI_OP_LE_READ_MAX_ADV_DATA_LEN, 0, NULL); + if (result == HCI_OK) { + struct bt_hci_rp_le_read_max_adv_data_len *response = + (struct bt_hci_rp_le_read_max_adv_data_len *) cmd_response_data; + if (response->status == BT_HCI_ERR_SUCCESS) { + *max_adv_data_len = response->max_adv_data_len; + } + } + + return result; +} + +hci_result_t hci_le_set_advertising_data(uint8_t len, uint8_t data[]) { + struct bt_hci_cp_le_set_adv_data params = { + // Zero out unused data bytes. + .data = { 0 }, + }; + + params.len = len; + memcpy(params.data, data, len); + + // All data bytes are sent even if some are unused. + return send_command(BT_HCI_OP_LE_SET_ADV_DATA, sizeof(params), ¶ms); +} + +hci_result_t hci_le_set_scan_response_data(uint8_t len, uint8_t data[]) { + struct bt_hci_cp_le_set_scan_rsp_data params = { + // Zero out unused data bytes. + .data = { 0 }, + }; + params.len = len; + memcpy(params.data, data, len); + + // All data bytes are sent even if some are unused. + return send_command(BT_HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(params), ¶ms); +} + +hci_result_t hci_le_set_advertise_enable(uint8_t enable) { + return send_command(BT_HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable); +} + +hci_result_t hci_le_set_scan_parameters(uint8_t scan_type, uint16_t interval, uint16_t window, uint8_t addr_type, uint8_t filter_policy) { + struct bt_hci_cp_le_set_scan_param params = { + .scan_type = scan_type, + .interval = interval, + .window = window, + .addr_type = addr_type, + .filter_policy = filter_policy, + }; + + return send_command(BT_HCI_OP_LE_SET_SCAN_PARAM, sizeof(params), ¶ms); +} + +hci_result_t hci_le_set_scan_enable(uint8_t enable, uint8_t filter_dup) { + struct bt_hci_cp_le_set_scan_enable params = { + .enable = enable, + .filter_dup = filter_dup, + }; + + return send_command(BT_HCI_OP_LE_SET_SCAN_ENABLE, sizeof(params), ¶ms); +} + +hci_result_t hci_le_create_conn(uint16_t scan_interval, uint16_t scan_window, uint8_t filter_policy, bt_addr_le_t *peer_addr, uint8_t own_addr_type, uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout, uint16_t min_ce_len, uint16_t max_ce_len) { + struct bt_hci_cp_le_create_conn params = { + .scan_interval = scan_interval, + .scan_window = scan_window, + .filter_policy = filter_policy, + // .peer_addr is set below + .own_addr_type = own_addr_type, + .conn_interval_min = conn_interval_min, + .conn_interval_max = conn_interval_max, + .conn_latency = conn_latency, + .supervision_timeout = supervision_timeout, + .min_ce_len = min_ce_len, + .max_ce_len = max_ce_len, + }; + params.peer_addr.type = peer_addr->type; + memcpy(params.peer_addr.a.val, peer_addr->a.val, sizeof(params.peer_addr.a.val)); + + return send_command(BT_HCI_OP_LE_CREATE_CONN, sizeof(params), ¶ms); +} + +hci_result_t hci_le_cancel_conn(void) { + return send_command(BT_HCI_OP_CONNECT_CANCEL, 0, NULL); +} + +hci_result_t hci_le_conn_update(uint16_t handle, uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout) { + struct hci_cp_le_conn_update params = { + .handle = handle, + .conn_interval_min = conn_interval_min, + .conn_interval_max = conn_interval_max, + .conn_latency = conn_latency, + .supervision_timeout = supervision_timeout, + .min_ce_len = 4, + .max_ce_len = 6, + }; + + return send_command(BT_HCI_OP_LE_CONN_UPDATE, sizeof(params), ¶ms); +} + +hci_result_t hci_disconnect(uint16_t handle) { + struct bt_hci_cp_disconnect params = { + .handle = handle, + .reason = BT_HCI_ERR_REMOTE_USER_TERM_CONN, + }; + + return send_command(BT_HCI_OP_DISCONNECT, sizeof(params), ¶ms); +} diff --git a/devices/ble_hci/common-hal/_bleio/hci_api.h b/devices/ble_hci/common-hal/_bleio/hci_api.h new file mode 100644 index 000000000..a2235ec8c --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/hci_api.h @@ -0,0 +1,69 @@ +/* + This file is part of the ArduinoBLE library. + Copyright (c) 2018 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef MICROPY_INCLUDED_DEVICES_BLE_HCI_COMMON_HAL_BLEIO_HCI_H +#define MICROPY_INCLUDED_DEVICES_BLE_HCI_COMMON_HAL_BLEIO_HCI_H + +#include + +#include "common-hal/_bleio/hci_include/hci.h" + +#include "common-hal/_bleio/Adapter.h" + +// An hci_result_t is one of the HCI_x values below, +// or is it > 0 and is an HCI command status value (see hci_include/hci_err.h) +typedef int hci_result_t; +#define HCI_OK (0) +#define HCI_NO_RESPONSE (-1) +#define HCI_ERR_RESPONSE (-2) +#define HCI_READ_TIMEOUT (-3) +#define HCI_WRITE_TIMEOUT (-4) +#define HCI_READ_ERROR (-5) +#define HCI_WRITE_ERROR (-6) + +void hci_init(bleio_adapter_obj_t *adapter_in); + +hci_result_t hci_disconnect(uint16_t handle); + +hci_result_t hci_le_cancel_conn(void); +hci_result_t hci_le_conn_update(uint16_t handle, uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout); +hci_result_t hci_le_create_conn(uint16_t scan_interval, uint16_t scan_window, uint8_t filter_policy, bt_addr_le_t *peer_addr, uint8_t own_addr_type, uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout, uint16_t min_ce_len, uint16_t max_ce_len); + +hci_result_t hci_le_read_maximum_advertising_data_length(int *max_adv_data_len); + +hci_result_t hci_le_set_advertise_enable(uint8_t enable); +hci_result_t hci_le_set_advertising_data(uint8_t length, uint8_t data[]); +hci_result_t hci_le_set_advertising_parameters(uint16_t min_interval, uint16_t max_interval, uint8_t type, uint8_t own_addr_type, bt_addr_le_t *direct_addr, uint8_t channel_map, uint8_t filter_policy); +hci_result_t hci_le_set_random_address(uint8_t addr[6]); +hci_result_t hci_le_set_scan_enable(uint8_t enable, uint8_t filter_dup); +hci_result_t hci_le_set_scan_parameters(uint8_t scan_type, uint16_t interval, uint16_t window, uint8_t addr_type, uint8_t filter_policy); +hci_result_t hci_le_set_scan_response_data(uint8_t length, uint8_t data[]); + +hci_result_t hci_poll_for_incoming_pkt(void); + +hci_result_t hci_read_bd_addr(bt_addr_t *addr); +hci_result_t hci_read_le_buffer_size(uint16_t *le_max_len, uint8_t *le_max_num); +hci_result_t hci_read_local_version(uint8_t *hci_version, uint16_t *hci_revision, uint8_t *lmp_version, uint16_t *manufacturer, uint16_t *lmp_subversion); +hci_result_t hci_read_rssi(uint16_t handle, int *rssi); + +hci_result_t hci_reset(void); + +hci_result_t hci_set_evt_mask(uint64_t event_mask); + +#endif // MICROPY_INCLUDED_DEVICES_BLE_HCI_COMMON_HAL_BLEIO_HCI_H diff --git a/devices/ble_hci/common-hal/_bleio/hci_include/#hci.h# b/devices/ble_hci/common-hal/_bleio/hci_include/#hci.h# new file mode 100644 index 000000000..942a82a3c --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/hci_include/#hci.h# @@ -0,0 +1,1775 @@ +/* hci.h - Bluetooth Host Control Interface definitions */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_HCI_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_HCI_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Special own address types for LL privacy (used in adv & scan parameters) */ +#define BT_HCI_OWN_ADDR_RPA_OR_PUBLIC 0x02 +#define BT_HCI_OWN_ADDR_RPA_OR_RANDOM 0x03 +#define BT_HCI_OWN_ADDR_RPA_MASK 0x02 + +#define BT_HCI_PEER_ADDR_RPA_UNRESOLVED 0xfe +#define BT_HCI_PEER_ADDR_ANONYMOUS 0xff + +#define BT_ENC_KEY_SIZE_MIN 0x07 +#define BT_ENC_KEY_SIZE_MAX 0x10 + +struct bt_hci_evt_hdr { + uint8_t evt; + uint8_t len; +} __packed; +#define BT_HCI_EVT_HDR_SIZE 2 + +#define BT_ACL_START_NO_FLUSH 0x00 +#define BT_ACL_CONT 0x01 +#define BT_ACL_START 0x02 +#define BT_ACL_COMPLETE 0x03 + +#define BT_ACL_POINT_TO_POINT 0x00 +#define BT_ACL_BROADCAST 0x01 + +#define bt_acl_handle(h) ((h) & BIT_MASK(12)) +#define bt_acl_flags(h) ((h) >> 12) +#define bt_acl_flags_pb(f) ((f) & BIT_MASK(2)) +#define bt_acl_flags_bc(f) ((f) >> 2) +#define bt_acl_handle_pack(h, f) ((h) | ((f) << 12)) + +struct bt_hci_acl_hdr { + uint16_t handle; + uint16_t len; +} __packed; +#define BT_HCI_ACL_HDR_SIZE 4 + +struct bt_hci_cmd_hdr { + uint16_t opcode; + uint8_t param_len; +} __packed; +#define BT_HCI_CMD_HDR_SIZE 3 + +/* Supported Commands */ +#define BT_CMD_TEST(cmd, octet, bit) (cmd[octet] & BIT(bit)) +#define BT_CMD_LE_STATES(cmd) BT_CMD_TEST(cmd, 28, 3) + +#define BT_FEAT_TEST(feat, page, octet, bit) (feat[page][octet] & BIT(bit)) + +#define BT_FEAT_BREDR(feat) !BT_FEAT_TEST(feat, 0, 4, 5) +#define BT_FEAT_LE(feat) BT_FEAT_TEST(feat, 0, 4, 6) +#define BT_FEAT_EXT_FEATURES(feat) BT_FEAT_TEST(feat, 0, 7, 7) +#define BT_FEAT_HOST_SSP(feat) BT_FEAT_TEST(feat, 1, 0, 0) +#define BT_FEAT_SC(feat) BT_FEAT_TEST(feat, 2, 1, 0) + +#define BT_FEAT_LMP_ESCO_CAPABLE(feat) BT_FEAT_TEST(feat, 0, 3, 7) +#define BT_FEAT_HV2_PKT(feat) BT_FEAT_TEST(feat, 0, 1, 4) +#define BT_FEAT_HV3_PKT(feat) BT_FEAT_TEST(feat, 0, 1, 5) +#define BT_FEAT_EV4_PKT(feat) BT_FEAT_TEST(feat, 0, 4, 0) +#define BT_FEAT_EV5_PKT(feat) BT_FEAT_TEST(feat, 0, 4, 1) +#define BT_FEAT_2EV3_PKT(feat) BT_FEAT_TEST(feat, 0, 5, 5) +#define BT_FEAT_3EV3_PKT(feat) BT_FEAT_TEST(feat, 0, 5, 6) +#define BT_FEAT_3SLOT_PKT(feat) BT_FEAT_TEST(feat, 0, 5, 7) + +/* LE features */ +#define BT_LE_FEAT_BIT_ENC 0 +#define BT_LE_FEAT_BIT_CONN_PARAM_REQ 1 +#define BT_LE_FEAT_BIT_EXT_REJ_IND 2 +#define BT_LE_FEAT_BIT_SLAVE_FEAT_REQ 3 +#define BT_LE_FEAT_BIT_PING 4 +#define BT_LE_FEAT_BIT_DLE 5 +#define BT_LE_FEAT_BIT_PRIVACY 6 +#define BT_LE_FEAT_BIT_EXT_SCAN 7 +#define BT_LE_FEAT_BIT_PHY_2M 8 +#define BT_LE_FEAT_BIT_SMI_TX 9 +#define BT_LE_FEAT_BIT_SMI_RX 10 +#define BT_LE_FEAT_BIT_PHY_CODED 11 +#define BT_LE_FEAT_BIT_EXT_ADV 12 +#define BT_LE_FEAT_BIT_PER_ADV 13 +#define BT_LE_FEAT_BIT_CHAN_SEL_ALGO_2 14 +#define BT_LE_FEAT_BIT_PWR_CLASS_1 15 +#define BT_LE_FEAT_BIT_MIN_USED_CHAN_PROC 16 +#define BT_LE_FEAT_BIT_CONN_CTE_REQ 17 +#define BT_LE_FEAT_BIT_CONN_CTE_RESP 18 +#define BT_LE_FEAT_BIT_CONNECTIONLESS_CTE_TX 19 +#define BT_LE_FEAT_BIT_CONNECTIONLESS_CTE_RX 20 +#define BT_LE_FEAT_BIT_ANT_SWITCH_TX_AOD 21 +#define BT_LE_FEAT_BIT_ANT_SWITCH_RX_AOA 22 +#define BT_LE_FEAT_BIT_RX_CTE 23 +#define BT_LE_FEAT_BIT_PERIODIC_SYNC_XFER_SEND 24 +#define BT_LE_FEAT_BIT_PERIODIC_SYNC_XFER_RECV 25 +#define BT_LE_FEAT_BIT_SCA_UPDATE 26 +#define BT_LE_FEAT_BIT_REMOTE_PUB_KEY_VALIDATE 27 +#define BT_LE_FEAT_BIT_CIS_MASTER 28 +#define BT_LE_FEAT_BIT_CIS_SLAVE 29 +#define BT_LE_FEAT_BIT_ISO_BROADCASTER 30 +#define BT_LE_FEAT_BIT_SYNC_RECEIVER 31 +#define BT_LE_FEAT_BIT_ISO_CHANNELS 32 +#define BT_LE_FEAT_BIT_PWR_CTRL_REQ 33 +#define BT_LE_FEAT_BIT_PWR_CHG_IND 34 +#define BT_LE_FEAT_BIT_PATH_LOSS_MONITOR 35 + +#define BT_LE_FEAT_TEST(feat, n) (feat[(n) >> 3] & \ + BIT((n) & 7)) + +#define BT_FEAT_LE_ENCR(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_ENC) +#define BT_FEAT_LE_CONN_PARAM_REQ_PROC(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CONN_PARAM_REQ) +#define BT_FEAT_LE_SLAVE_FEATURE_XCHG(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_SLAVE_FEAT_REQ) +#define BT_FEAT_LE_DLE(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_DLE) +#define BT_FEAT_LE_PHY_2M(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PHY_2M) +#define BT_FEAT_LE_PHY_CODED(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PHY_CODED) +#define BT_FEAT_LE_PRIVACY(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PRIVACY) +#define BT_FEAT_LE_EXT_ADV(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_EXT_ADV) + +/* LE States */ +#define BT_LE_STATES_SLAVE_CONN_ADV(states) (states & 0x0000004000000000) + +/* Bonding/authentication types */ +#define BT_HCI_NO_BONDING 0x00 +#define BT_HCI_NO_BONDING_MITM 0x01 +#define BT_HCI_DEDICATED_BONDING 0x02 +#define BT_HCI_DEDICATED_BONDING_MITM 0x03 +#define BT_HCI_GENERAL_BONDING 0x04 +#define BT_HCI_GENERAL_BONDING_MITM 0x05 + +/* + * MITM protection is enabled in SSP authentication requirements octet when + * LSB bit is set. + */ +#define BT_MITM 0x01 + +/* I/O capabilities */ +#define BT_IO_DISPLAY_ONLY 0x00 +#define BT_IO_DISPLAY_YESNO 0x01 +#define BT_IO_KEYBOARD_ONLY 0x02 +#define BT_IO_NO_INPUT_OUTPUT 0x03 + +/* SCO packet types */ +#define HCI_PKT_TYPE_HV1 0x0020 +#define HCI_PKT_TYPE_HV2 0x0040 +#define HCI_PKT_TYPE_HV3 0x0080 + +/* eSCO packet types */ +#define HCI_PKT_TYPE_ESCO_HV1 0x0001 +#define HCI_PKT_TYPE_ESCO_HV2 0x0002 +#define HCI_PKT_TYPE_ESCO_HV3 0x0004 +#define HCI_PKT_TYPE_ESCO_EV3 0x0008 +#define HCI_PKT_TYPE_ESCO_EV4 0x0010 +#define HCI_PKT_TYPE_ESCO_EV5 0x0020 +#define HCI_PKT_TYPE_ESCO_2EV3 0x0040 +#define HCI_PKT_TYPE_ESCO_3EV3 0x0080 +#define HCI_PKT_TYPE_ESCO_2EV5 0x0100 +#define HCI_PKT_TYPE_ESCO_3EV5 0x0200 + + +#define ESCO_PKT_MASK (HCI_PKT_TYPE_ESCO_HV1 | \ + HCI_PKT_TYPE_ESCO_HV2 | \ + HCI_PKT_TYPE_ESCO_HV3) +#define SCO_PKT_MASK (HCI_PKT_TYPE_HV1 | \ + HCI_PKT_TYPE_HV2 | \ + HCI_PKT_TYPE_HV3) +#define EDR_ESCO_PKT_MASK (HCI_PKT_TYPE_ESCO_2EV3 | \ + HCI_PKT_TYPE_ESCO_3EV3 | \ + HCI_PKT_TYPE_ESCO_2EV5 | \ + HCI_PKT_TYPE_ESCO_3EV5) + +/* HCI BR/EDR link types */ +#define BT_HCI_SCO 0x00 +#define BT_HCI_ACL 0x01 +#define BT_HCI_ESCO 0x02 + +/* OpCode Group Fields */ +#define BT_OGF_LINK_CTRL 0x01 +#define BT_OGF_BASEBAND 0x03 +#define BT_OGF_INFO 0x04 +#define BT_OGF_STATUS 0x05 +#define BT_OGF_LE 0x08 +#define BT_OGF_VS 0x3f + +/* Construct OpCode from OGF and OCF */ +#define BT_OP(ogf, ocf) ((ocf) | ((ogf) << 10)) + +/* Invalid opcode */ +#define BT_OP_NOP 0x0000 + +/* Obtain OGF from OpCode */ +#define BT_OGF(opcode) (((opcode) >> 10) & BIT_MASK(6)) +/* Obtain OCF from OpCode */ +#define BT_OCF(opcode) ((opcode) & BIT_MASK(10)) + +#define BT_HCI_OP_INQUIRY BT_OP(BT_OGF_LINK_CTRL, 0x0001) +struct bt_hci_op_inquiry { + uint8_t lap[3]; + uint8_t length; + uint8_t num_rsp; +} __packed; + +#define BT_HCI_OP_INQUIRY_CANCEL BT_OP(BT_OGF_LINK_CTRL, 0x0002) + +#define BT_HCI_OP_CONNECT BT_OP(BT_OGF_LINK_CTRL, 0x0005) +struct bt_hci_cp_connect { + bt_addr_t bdaddr; + uint16_t packet_type; + uint8_t pscan_rep_mode; + uint8_t reserved; + uint16_t clock_offset; + uint8_t allow_role_switch; +} __packed; + +#define BT_HCI_OP_DISCONNECT BT_OP(BT_OGF_LINK_CTRL, 0x0006) +struct bt_hci_cp_disconnect { + uint16_t handle; + uint8_t reason; +} __packed; + +#define BT_HCI_OP_CONNECT_CANCEL BT_OP(BT_OGF_LINK_CTRL, 0x0008) +struct bt_hci_cp_connect_cancel { + bt_addr_t bdaddr; +} __packed; +struct bt_hci_rp_connect_cancel { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_ACCEPT_CONN_REQ BT_OP(BT_OGF_LINK_CTRL, 0x0009) +struct bt_hci_cp_accept_conn_req { + bt_addr_t bdaddr; + uint8_t role; +} __packed; + +#define BT_HCI_OP_SETUP_SYNC_CONN BT_OP(BT_OGF_LINK_CTRL, 0x0028) +struct bt_hci_cp_setup_sync_conn { + uint16_t handle; + uint32_t tx_bandwidth; + uint32_t rx_bandwidth; + uint16_t max_latency; + uint16_t content_format; + uint8_t retrans_effort; + uint16_t pkt_type; +} __packed; + +#define BT_HCI_OP_ACCEPT_SYNC_CONN_REQ BT_OP(BT_OGF_LINK_CTRL, 0x0029) +struct bt_hci_cp_accept_sync_conn_req { + bt_addr_t bdaddr; + uint32_t tx_bandwidth; + uint32_t rx_bandwidth; + uint16_t max_latency; + uint16_t content_format; + uint8_t retrans_effort; + uint16_t pkt_type; +} __packed; + +#define BT_HCI_OP_REJECT_CONN_REQ BT_OP(BT_OGF_LINK_CTRL, 0x000a) +struct bt_hci_cp_reject_conn_req { + bt_addr_t bdaddr; + uint8_t reason; +} __packed; + +#define BT_HCI_OP_LINK_KEY_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x000b) +struct bt_hci_cp_link_key_reply { + bt_addr_t bdaddr; + uint8_t link_key[16]; +} __packed; + +#define BT_HCI_OP_LINK_KEY_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x000c) +struct bt_hci_cp_link_key_neg_reply { + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_PIN_CODE_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x000d) +struct bt_hci_cp_pin_code_reply { + bt_addr_t bdaddr; + uint8_t pin_len; + uint8_t pin_code[16]; +} __packed; +struct bt_hci_rp_pin_code_reply { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_PIN_CODE_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x000e) +struct bt_hci_cp_pin_code_neg_reply { + bt_addr_t bdaddr; +} __packed; +struct bt_hci_rp_pin_code_neg_reply { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_AUTH_REQUESTED BT_OP(BT_OGF_LINK_CTRL, 0x0011) +struct bt_hci_cp_auth_requested { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_SET_CONN_ENCRYPT BT_OP(BT_OGF_LINK_CTRL, 0x0013) +struct bt_hci_cp_set_conn_encrypt { + uint16_t handle; + uint8_t encrypt; +} __packed; + +#define BT_HCI_OP_REMOTE_NAME_REQUEST BT_OP(BT_OGF_LINK_CTRL, 0x0019) +struct bt_hci_cp_remote_name_request { + bt_addr_t bdaddr; + uint8_t pscan_rep_mode; + uint8_t reserved; + uint16_t clock_offset; +} __packed; + +#define BT_HCI_OP_REMOTE_NAME_CANCEL BT_OP(BT_OGF_LINK_CTRL, 0x001a) +struct bt_hci_cp_remote_name_cancel { + bt_addr_t bdaddr; +} __packed; +struct bt_hci_rp_remote_name_cancel { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_READ_REMOTE_FEATURES BT_OP(BT_OGF_LINK_CTRL, 0x001b) +struct bt_hci_cp_read_remote_features { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_READ_REMOTE_EXT_FEATURES BT_OP(BT_OGF_LINK_CTRL, 0x001c) +struct bt_hci_cp_read_remote_ext_features { + uint16_t handle; + uint8_t page; +} __packed; + +#define BT_HCI_OP_READ_REMOTE_VERSION_INFO BT_OP(BT_OGF_LINK_CTRL, 0x001d) +struct bt_hci_cp_read_remote_version_info { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_IO_CAPABILITY_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002b) +struct bt_hci_cp_io_capability_reply { + bt_addr_t bdaddr; + uint8_t capability; + uint8_t oob_data; + uint8_t authentication; +} __packed; + +#define BT_HCI_OP_USER_CONFIRM_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002c) +#define BT_HCI_OP_USER_CONFIRM_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002d) +struct bt_hci_cp_user_confirm_reply { + bt_addr_t bdaddr; +} __packed; +struct bt_hci_rp_user_confirm_reply { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_USER_PASSKEY_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002e) +struct bt_hci_cp_user_passkey_reply { + bt_addr_t bdaddr; + uint32_t passkey; +} __packed; + +#define BT_HCI_OP_USER_PASSKEY_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002f) +struct bt_hci_cp_user_passkey_neg_reply { + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_IO_CAPABILITY_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x0034) +struct bt_hci_cp_io_capability_neg_reply { + bt_addr_t bdaddr; + uint8_t reason; +} __packed; + +#define BT_HCI_OP_SET_EVENT_MASK BT_OP(BT_OGF_BASEBAND, 0x0001) +struct bt_hci_cp_set_event_mask { + uint8_t events[8]; +} __packed; + +#define BT_HCI_OP_RESET BT_OP(BT_OGF_BASEBAND, 0x0003) + +#define BT_HCI_OP_WRITE_LOCAL_NAME BT_OP(BT_OGF_BASEBAND, 0x0013) +struct bt_hci_write_local_name { + uint8_t local_name[248]; +} __packed; + +#define BT_HCI_OP_WRITE_PAGE_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x0018) + +#define BT_HCI_OP_WRITE_SCAN_ENABLE BT_OP(BT_OGF_BASEBAND, 0x001a) +#define BT_BREDR_SCAN_DISABLED 0x00 +#define BT_BREDR_SCAN_INQUIRY 0x01 +#define BT_BREDR_SCAN_PAGE 0x02 + +#define BT_TX_POWER_LEVEL_CURRENT 0x00 +#define BT_TX_POWER_LEVEL_MAX 0x01 +#define BT_HCI_OP_READ_TX_POWER_LEVEL BT_OP(BT_OGF_BASEBAND, 0x002d) +struct bt_hci_cp_read_tx_power_level { + uint16_t handle; + uint8_t type; +} __packed; + +struct bt_hci_rp_read_tx_power_level { + uint8_t status; + uint16_t handle; + int8_t tx_power_level; +} __packed; + +#define BT_HCI_CTL_TO_HOST_FLOW_DISABLE 0x00 +#define BT_HCI_CTL_TO_HOST_FLOW_ENABLE 0x01 +#define BT_HCI_OP_SET_CTL_TO_HOST_FLOW BT_OP(BT_OGF_BASEBAND, 0x0031) +struct bt_hci_cp_set_ctl_to_host_flow { + uint8_t flow_enable; +} __packed; + +#define BT_HCI_OP_HOST_BUFFER_SIZE BT_OP(BT_OGF_BASEBAND, 0x0033) +struct bt_hci_cp_host_buffer_size { + uint16_t acl_mtu; + uint8_t sco_mtu; + uint16_t acl_pkts; + uint16_t sco_pkts; +} __packed; + +struct bt_hci_handle_count { + uint16_t handle; + uint16_t count; +} __packed; + +#define BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS BT_OP(BT_OGF_BASEBAND, 0x0035) +struct bt_hci_cp_host_num_completed_packets { + uint8_t num_handles; + struct bt_hci_handle_count h[0]; +} __packed; + +#define BT_HCI_OP_WRITE_INQUIRY_MODE BT_OP(BT_OGF_BASEBAND, 0x0045) +struct bt_hci_cp_write_inquiry_mode { + uint8_t mode; +} __packed; + +#define BT_HCI_OP_WRITE_SSP_MODE BT_OP(BT_OGF_BASEBAND, 0x0056) +struct bt_hci_cp_write_ssp_mode { + uint8_t mode; +} __packed; + +#define BT_HCI_OP_SET_EVENT_MASK_PAGE_2 BT_OP(BT_OGF_BASEBAND, 0x0063) +struct bt_hci_cp_set_event_mask_page_2 { + uint8_t events_page_2[8]; +} __packed; + +#define BT_HCI_OP_LE_WRITE_LE_HOST_SUPP BT_OP(BT_OGF_BASEBAND, 0x006d) +struct bt_hci_cp_write_le_host_supp { + uint8_t le; + uint8_t simul; +} __packed; + +#define BT_HCI_OP_WRITE_SC_HOST_SUPP BT_OP(BT_OGF_BASEBAND, 0x007a) +struct bt_hci_cp_write_sc_host_supp { + uint8_t sc_support; +} __packed; + +#define BT_HCI_OP_READ_AUTH_PAYLOAD_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x007b) +struct bt_hci_cp_read_auth_payload_timeout { + uint16_t handle; +} __packed; + +struct bt_hci_rp_read_auth_payload_timeout { + uint8_t status; + uint16_t handle; + uint16_t auth_payload_timeout; +} __packed; + +#define BT_HCI_OP_WRITE_AUTH_PAYLOAD_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x007c) +struct bt_hci_cp_write_auth_payload_timeout { + uint16_t handle; + uint16_t auth_payload_timeout; +} __packed; + +struct bt_hci_rp_write_auth_payload_timeout { + uint8_t status; + uint16_t handle; +} __packed; + +/* HCI version from Assigned Numbers */ +#define BT_HCI_VERSION_1_0B 0 +#define BT_HCI_VERSION_1_1 1 +#define BT_HCI_VERSION_1_2 2 +#define BT_HCI_VERSION_2_0 3 +#define BT_HCI_VERSION_2_1 4 +#define BT_HCI_VERSION_3_0 5 +#define BT_HCI_VERSION_4_0 6 +#define BT_HCI_VERSION_4_1 7 +#define BT_HCI_VERSION_4_2 8 +#define BT_HCI_VERSION_5_0 9 +#define BT_HCI_VERSION_5_1 10 +#define BT_HCI_VERSION_5_2 11 + +#define BT_HCI_OP_READ_LOCAL_VERSION_INFO BT_OP(BT_OGF_INFO, 0x0001) +struct bt_hci_rp_read_local_version_info { + uint8_t status; + uint8_t hci_version; + uint16_t hci_revision; + uint8_t lmp_version; + uint16_t manufacturer; + uint16_t lmp_subversion; +} __packed; + +#define BT_HCI_OP_READ_SUPPORTED_COMMANDS BT_OP(BT_OGF_INFO, 0x0002) +struct bt_hci_rp_read_supported_commands { + uint8_t status; + uint8_t commands[64]; +} __packed; + +#define BT_HCI_OP_READ_LOCAL_EXT_FEATURES BT_OP(BT_OGF_INFO, 0x0004) +struct bt_hci_cp_read_local_ext_features { + uint8_t page; +}; +struct bt_hci_rp_read_local_ext_features { + uint8_t status; + uint8_t page; + uint8_t max_page; + uint8_t ext_features[8]; +} __packed; + +#define BT_HCI_OP_READ_LOCAL_FEATURES BT_OP(BT_OGF_INFO, 0x0003) +struct bt_hci_rp_read_local_features { + uint8_t status; + uint8_t features[8]; +} __packed; + +#define BT_HCI_OP_READ_BUFFER_SIZE BT_OP(BT_OGF_INFO, 0x0005) +struct bt_hci_rp_read_buffer_size { + uint8_t status; + uint16_t acl_max_len; + uint8_t sco_max_len; + uint16_t acl_max_num; + uint16_t sco_max_num; +} __packed; + +#define BT_HCI_OP_READ_BD_ADDR BT_OP(BT_OGF_INFO, 0x0009) +struct bt_hci_rp_read_bd_addr { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_READ_RSSI BT_OP(BT_OGF_STATUS, 0x0005) +struct bt_hci_cp_read_rssi { + uint16_t handle; +} __packed; +struct bt_hci_rp_read_rssi { + uint8_t status; + uint16_t handle; + int8_t rssi; +} __packed; + +#define BT_HCI_ENCRYPTION_KEY_SIZE_MIN 7 +#define BT_HCI_ENCRYPTION_KEY_SIZE_MAX 16 + +#define BT_HCI_OP_READ_ENCRYPTION_KEY_SIZE BT_OP(BT_OGF_STATUS, 0x0008) +struct bt_hci_cp_read_encryption_key_size { + uint16_t handle; +} __packed; +struct bt_hci_rp_read_encryption_key_size { + uint8_t status; + uint16_t handle; + uint8_t key_size; +} __packed; + +/* BLE */ + +#define BT_HCI_OP_LE_SET_EVENT_MASK BT_OP(BT_OGF_LE, 0x0001) +struct bt_hci_cp_le_set_event_mask { + uint8_t events[8]; +} __packed; + +#define BT_HCI_OP_LE_READ_BUFFER_SIZE BT_OP(BT_OGF_LE, 0x0002) +struct bt_hci_rp_le_read_buffer_size { + uint8_t status; + uint16_t le_max_len; + uint8_t le_max_num; +} __packed; + +#define BT_HCI_OP_LE_READ_LOCAL_FEATURES BT_OP(BT_OGF_LE, 0x0003) +struct bt_hci_rp_le_read_local_features { + uint8_t status; + uint8_t features[8]; +} __packed; + +#define BT_HCI_OP_LE_SET_RANDOM_ADDRESS BT_OP(BT_OGF_LE, 0x0005) +struct bt_hci_cp_le_set_random_address { + bt_addr_t bdaddr; +} __packed; + +/* LE Advertising Types (LE Advertising Parameters Set)*/ +#define BT_LE_ADV_IND (__DEPRECATED_MACRO 0x00) +#define BT_LE_ADV_DIRECT_IND (__DEPRECATED_MACRO 0x01) +#define BT_LE_ADV_SCAN_IND (__DEPRECATED_MACRO 0x02) +#define BT_LE_ADV_NONCONN_IND (__DEPRECATED_MACRO 0x03) +#define BT_LE_ADV_DIRECT_IND_LOW_DUTY (__DEPRECATED_MACRO 0x04) +/* LE Advertising PDU Types. */ +#define BT_LE_ADV_SCAN_RSP (__DEPRECATED_MACRO 0x04) + +#define BT_HCI_ADV_IND 0x00 +#define BT_HCI_ADV_DIRECT_IND 0x01 +#define BT_HCI_ADV_SCAN_IND 0x02 +#define BT_HCI_ADV_NONCONN_IND 0x03 +#define BT_HCI_ADV_DIRECT_IND_LOW_DUTY 0x04 +#define BT_HCI_ADV_SCAN_RSP 0x04 + +#define BT_LE_ADV_FP_NO_WHITELIST 0x00 +#define BT_LE_ADV_FP_WHITELIST_SCAN_REQ 0x01 +#define BT_LE_ADV_FP_WHITELIST_CONN_IND 0x02 +#define BT_LE_ADV_FP_WHITELIST_BOTH 0x03 + +#define BT_HCI_OP_LE_SET_ADV_PARAM BT_OP(BT_OGF_LE, 0x0006) +struct bt_hci_cp_le_set_adv_param { + uint16_t min_interval; + uint16_t max_interval; + uint8_t type; + uint8_t own_addr_type; + bt_addr_le_t direct_addr; + uint8_t channel_map; + uint8_t filter_policy; +} __packed; + +#define BT_HCI_OP_LE_READ_ADV_CHAN_TX_POWER BT_OP(BT_OGF_LE, 0x0007) +struct bt_hci_rp_le_read_chan_tx_power { + uint8_t status; + int8_t tx_power_level; +} __packed; + +#define BT_HCI_OP_LE_SET_ADV_DATA BT_OP(BT_OGF_LE, 0x0008) +struct bt_hci_cp_le_set_adv_data { + uint8_t len; + uint8_t data[31]; +} __packed; + +#define BT_HCI_OP_LE_SET_SCAN_RSP_DATA BT_OP(BT_OGF_LE, 0x0009) +struct bt_hci_cp_le_set_scan_rsp_data { + uint8_t len; + uint8_t data[31]; +} __packed; + +#define BT_HCI_LE_ADV_DISABLE 0x00 +#define BT_HCI_LE_ADV_ENABLE 0x01 + +#define BT_HCI_OP_LE_SET_ADV_ENABLE BT_OP(BT_OGF_LE, 0x000a) +struct bt_hci_cp_le_set_adv_enable { + uint8_t enable; +} __packed; + +/* Scan types */ +#define BT_HCI_OP_LE_SET_SCAN_PARAM BT_OP(BT_OGF_LE, 0x000b) +#define BT_HCI_LE_SCAN_PASSIVE 0x00 +#define BT_HCI_LE_SCAN_ACTIVE 0x01 + +#define BT_HCI_LE_SCAN_FP_NO_WHITELIST 0x00 +#define BT_HCI_LE_SCAN_FP_USE_WHITELIST 0x01 + +struct bt_hci_cp_le_set_scan_param { + uint8_t scan_type; + uint16_t interval; + uint16_t window; + uint8_t addr_type; + uint8_t filter_policy; +} __packed; + +#define BT_HCI_OP_LE_SET_SCAN_ENABLE BT_OP(BT_OGF_LE, 0x000c) + +#define BT_HCI_LE_SCAN_DISABLE 0x00 +#define BT_HCI_LE_SCAN_ENABLE 0x01 + +#define BT_HCI_LE_SCAN_FILTER_DUP_DISABLE 0x00 +#define BT_HCI_LE_SCAN_FILTER_DUP_ENABLE 0x01 + +struct bt_hci_cp_le_set_scan_enable { + uint8_t enable; + uint8_t filter_dup; +} __packed; + +#define BT_HCI_OP_LE_CREATE_CONN BT_OP(BT_OGF_LE, 0x000d) + +#define BT_HCI_LE_CREATE_CONN_FP_DIRECT 0x00 +#define BT_HCI_LE_CREATE_CONN_FP_WHITELIST 0x01 + +struct bt_hci_cp_le_create_conn { + uint16_t scan_interval; + uint16_t scan_window; + uint8_t filter_policy; + bt_addr_le_t peer_addr; + uint8_t own_addr_type; + uint16_t conn_interval_min; + uint16_t conn_interval_max; + uint16_t conn_latency; + uint16_t supervision_timeout; + uint16_t min_ce_len; + uint16_t max_ce_len; +} __packed; + +#define BT_HCI_OP_LE_CREATE_CONN_CANCEL BT_OP(BT_OGF_LE, 0x000e) + +#define BT_HCI_OP_LE_READ_WL_SIZE BT_OP(BT_OGF_LE, 0x000f) +struct bt_hci_rp_le_read_wl_size { + uint8_t status; + uint8_t wl_size; +} __packed; + +#define BT_HCI_OP_LE_CLEAR_WL BT_OP(BT_OGF_LE, 0x0010) + +#define BT_HCI_OP_LE_ADD_DEV_TO_WL BT_OP(BT_OGF_LE, 0x0011) +struct bt_hci_cp_le_add_dev_to_wl { + bt_addr_le_t addr; +} __packed; + +#define BT_HCI_OP_LE_REM_DEV_FROM_WL BT_OP(BT_OGF_LE, 0x0012) +struct bt_hci_cp_le_rem_dev_from_wl { + bt_addr_le_t addr; +} __packed; + +#define BT_HCI_OP_LE_CONN_UPDATE BT_OP(BT_OGF_LE, 0x0013) +struct hci_cp_le_conn_update { + uint16_t handle; + uint16_t conn_interval_min; + uint16_t conn_interval_max; + uint16_t conn_latency; + uint16_t supervision_timeout; + uint16_t min_ce_len; + uint16_t max_ce_len; +} __packed; + +#define BT_HCI_OP_LE_SET_HOST_CHAN_CLASSIF BT_OP(BT_OGF_LE, 0x0014) +struct bt_hci_cp_le_set_host_chan_classif { + uint8_t ch_map[5]; +} __packed; + +#define BT_HCI_OP_LE_READ_CHAN_MAP BT_OP(BT_OGF_LE, 0x0015) +struct bt_hci_cp_le_read_chan_map { + uint16_t handle; +} __packed; +struct bt_hci_rp_le_read_chan_map { + uint8_t status; + uint16_t handle; + uint8_t ch_map[5]; +} __packed; + +#define BT_HCI_OP_LE_READ_REMOTE_FEATURES BT_OP(BT_OGF_LE, 0x0016) +struct bt_hci_cp_le_read_remote_features { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_ENCRYPT BT_OP(BT_OGF_LE, 0x0017) +struct bt_hci_cp_le_encrypt { + uint8_t key[16]; + uint8_t plaintext[16]; +} __packed; +struct bt_hci_rp_le_encrypt { + uint8_t status; + uint8_t enc_data[16]; +} __packed; + +#define BT_HCI_OP_LE_RAND BT_OP(BT_OGF_LE, 0x0018) +struct bt_hci_rp_le_rand { + uint8_t status; + uint8_t rand[8]; +} __packed; + +#define BT_HCI_OP_LE_START_ENCRYPTION BT_OP(BT_OGF_LE, 0x0019) +struct bt_hci_cp_le_start_encryption { + uint16_t handle; + uint64_t rand; + uint16_t ediv; + uint8_t ltk[16]; +} __packed; + +#define BT_HCI_OP_LE_LTK_REQ_REPLY BT_OP(BT_OGF_LE, 0x001a) +struct bt_hci_cp_le_ltk_req_reply { + uint16_t handle; + uint8_t ltk[16]; +} __packed; +struct bt_hci_rp_le_ltk_req_reply { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_LTK_REQ_NEG_REPLY BT_OP(BT_OGF_LE, 0x001b) +struct bt_hci_cp_le_ltk_req_neg_reply { + uint16_t handle; +} __packed; +struct bt_hci_rp_le_ltk_req_neg_reply { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_READ_SUPP_STATES BT_OP(BT_OGF_LE, 0x001c) +struct bt_hci_rp_le_read_supp_states { + uint8_t status; + uint8_t le_states[8]; +} __packed; + +#define BT_HCI_OP_LE_RX_TEST BT_OP(BT_OGF_LE, 0x001d) +struct bt_hci_cp_le_rx_test { + uint8_t rx_ch; +} __packed; + +#define BT_HCI_OP_LE_TX_TEST BT_OP(BT_OGF_LE, 0x001e) +struct bt_hci_cp_le_tx_test { + uint8_t tx_ch; + uint8_t test_data_len; + uint8_t pkt_payload; +} __packed; + +#define BT_HCI_OP_LE_TEST_END BT_OP(BT_OGF_LE, 0x001f) +struct bt_hci_rp_le_test_end { + uint8_t status; + uint16_t rx_pkt_count; +} __packed; + +#define BT_HCI_OP_LE_CONN_PARAM_REQ_REPLY BT_OP(BT_OGF_LE, 0x0020) +struct bt_hci_cp_le_conn_param_req_reply { + uint16_t handle; + uint16_t interval_min; + uint16_t interval_max; + uint16_t latency; + uint16_t timeout; + uint16_t min_ce_len; + uint16_t max_ce_len; +} __packed; +struct bt_hci_rp_le_conn_param_req_reply { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_CONN_PARAM_REQ_NEG_REPLY BT_OP(BT_OGF_LE, 0x0021) +struct bt_hci_cp_le_conn_param_req_neg_reply { + uint16_t handle; + uint8_t reason; +} __packed; +struct bt_hci_rp_le_conn_param_req_neg_reply { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_SET_DATA_LEN BT_OP(BT_OGF_LE, 0x0022) +struct bt_hci_cp_le_set_data_len { + uint16_t handle; + uint16_t tx_octets; + uint16_t tx_time; +} __packed; +struct bt_hci_rp_le_set_data_len { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_READ_DEFAULT_DATA_LEN BT_OP(BT_OGF_LE, 0x0023) +struct bt_hci_rp_le_read_default_data_len { + uint8_t status; + uint16_t max_tx_octets; + uint16_t max_tx_time; +} __packed; + +#define BT_HCI_OP_LE_WRITE_DEFAULT_DATA_LEN BT_OP(BT_OGF_LE, 0x0024) +struct bt_hci_cp_le_write_default_data_len { + uint16_t max_tx_octets; + uint16_t max_tx_time; +} __packed; + +#define BT_HCI_OP_LE_P256_PUBLIC_KEY BT_OP(BT_OGF_LE, 0x0025) + +#define BT_HCI_OP_LE_GENERATE_DHKEY BT_OP(BT_OGF_LE, 0x0026) +struct bt_hci_cp_le_generate_dhkey { + uint8_t key[64]; +} __packed; + +#define BT_HCI_OP_LE_ADD_DEV_TO_RL BT_OP(BT_OGF_LE, 0x0027) +struct bt_hci_cp_le_add_dev_to_rl { + bt_addr_le_t peer_id_addr; + uint8_t peer_irk[16]; + uint8_t local_irk[16]; +} __packed; + +#define BT_HCI_OP_LE_REM_DEV_FROM_RL BT_OP(BT_OGF_LE, 0x0028) +struct bt_hci_cp_le_rem_dev_from_rl { + bt_addr_le_t peer_id_addr; +} __packed; + +#define BT_HCI_OP_LE_CLEAR_RL BT_OP(BT_OGF_LE, 0x0029) + +#define BT_HCI_OP_LE_READ_RL_SIZE BT_OP(BT_OGF_LE, 0x002a) +struct bt_hci_rp_le_read_rl_size { + uint8_t status; + uint8_t rl_size; +} __packed; + +#define BT_HCI_OP_LE_READ_PEER_RPA BT_OP(BT_OGF_LE, 0x002b) +struct bt_hci_cp_le_read_peer_rpa { + bt_addr_le_t peer_id_addr; +} __packed; +struct bt_hci_rp_le_read_peer_rpa { + uint8_t status; + bt_addr_t peer_rpa; +} __packed; + +#define BT_HCI_OP_LE_READ_LOCAL_RPA BT_OP(BT_OGF_LE, 0x002c) +struct bt_hci_cp_le_read_local_rpa { + bt_addr_le_t peer_id_addr; +} __packed; +struct bt_hci_rp_le_read_local_rpa { + uint8_t status; + bt_addr_t local_rpa; +} __packed; + +#define BT_HCI_ADDR_RES_DISABLE 0x00 +#define BT_HCI_ADDR_RES_ENABLE 0x01 + +#define BT_HCI_OP_LE_SET_ADDR_RES_ENABLE BT_OP(BT_OGF_LE, 0x002d) +struct bt_hci_cp_le_set_addr_res_enable { + uint8_t enable; +} __packed; + +#define BT_HCI_OP_LE_SET_RPA_TIMEOUT BT_OP(BT_OGF_LE, 0x002e) +struct bt_hci_cp_le_set_rpa_timeout { + uint16_t rpa_timeout; +} __packed; + +#define BT_HCI_OP_LE_READ_MAX_DATA_LEN BT_OP(BT_OGF_LE, 0x002f) +struct bt_hci_rp_le_read_max_data_len { + uint8_t status; + uint16_t max_tx_octets; + uint16_t max_tx_time; + uint16_t max_rx_octets; + uint16_t max_rx_time; +} __packed; + +#define BT_HCI_LE_PHY_1M 0x01 +#define BT_HCI_LE_PHY_2M 0x02 +#define BT_HCI_LE_PHY_CODED 0x03 + +#define BT_HCI_OP_LE_READ_PHY BT_OP(BT_OGF_LE, 0x0030) +struct bt_hci_cp_le_read_phy { + uint16_t handle; +} __packed; +struct bt_hci_rp_le_read_phy { + uint8_t status; + uint16_t handle; + uint8_t tx_phy; + uint8_t rx_phy; +} __packed; + +#define BT_HCI_LE_PHY_TX_ANY BIT(0) +#define BT_HCI_LE_PHY_RX_ANY BIT(1) + +#define BT_HCI_LE_PHY_PREFER_1M BIT(0) +#define BT_HCI_LE_PHY_PREFER_2M BIT(1) +#define BT_HCI_LE_PHY_PREFER_CODED BIT(2) + +#define BT_HCI_OP_LE_SET_DEFAULT_PHY BT_OP(BT_OGF_LE, 0x0031) +struct bt_hci_cp_le_set_default_phy { + uint8_t all_phys; + uint8_t tx_phys; + uint8_t rx_phys; +} __packed; + +#define BT_HCI_LE_PHY_CODED_ANY 0x00 +#define BT_HCI_LE_PHY_CODED_S2 0x01 +#define BT_HCI_LE_PHY_CODED_S8 0x02 + +#define BT_HCI_OP_LE_SET_PHY BT_OP(BT_OGF_LE, 0x0032) +struct bt_hci_cp_le_set_phy { + uint16_t handle; + uint8_t all_phys; + uint8_t tx_phys; + uint8_t rx_phys; + uint16_t phy_opts; +} __packed; + +#define BT_HCI_LE_MOD_INDEX_STANDARD 0x00 +#define BT_HCI_LE_MOD_INDEX_STABLE 0x01 + +#define BT_HCI_OP_LE_ENH_RX_TEST BT_OP(BT_OGF_LE, 0x0033) +struct bt_hci_cp_le_enh_rx_test { + uint8_t rx_ch; + uint8_t phy; + uint8_t mod_index; +} __packed; + +/* Extends BT_HCI_LE_PHY */ +#define BT_HCI_LE_TX_PHY_CODED_S8 0x03 +#define BT_HCI_LE_TX_PHY_CODED_S2 0x04 + +#define BT_HCI_OP_LE_ENH_TX_TEST BT_OP(BT_OGF_LE, 0x0034) +struct bt_hci_cp_le_enh_tx_test { + uint8_t tx_ch; + uint8_t test_data_len; + uint8_t pkt_payload; + uint8_t phy; +} __packed; + +#define BT_HCI_OP_LE_SET_ADV_SET_RANDOM_ADDR BT_OP(BT_OGF_LE, 0x0035) +struct bt_hci_cp_le_set_adv_set_random_addr { + uint8_t handle; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_LE_ADV_PROP_CONN BIT(0) +#define BT_HCI_LE_ADV_PROP_SCAN BIT(1) +#define BT_HCI_LE_ADV_PROP_DIRECT BIT(2) +#define BT_HCI_LE_ADV_PROP_HI_DC_CONN BIT(3) +#define BT_HCI_LE_ADV_PROP_LEGACY BIT(4) +#define BT_HCI_LE_ADV_PROP_ANON BIT(5) +#define BT_HCI_LE_ADV_PROP_TX_POWER BIT(6) + +#define BT_HCI_LE_ADV_SCAN_REQ_ENABLE 1 +#define BT_HCI_LE_ADV_SCAN_REQ_DISABLE 0 + +#define BT_HCI_LE_ADV_TX_POWER_NO_PREF 0x7F + +#define BT_HCI_OP_LE_SET_EXT_ADV_PARAM BT_OP(BT_OGF_LE, 0x0036) +struct bt_hci_cp_le_set_ext_adv_param { + uint8_t handle; + uint16_t props; + uint8_t prim_min_interval[3]; + uint8_t prim_max_interval[3]; + uint8_t prim_channel_map; + uint8_t own_addr_type; + bt_addr_le_t peer_addr; + uint8_t filter_policy; + int8_t tx_power; + uint8_t prim_adv_phy; + uint8_t sec_adv_max_skip; + uint8_t sec_adv_phy; + uint8_t sid; + uint8_t scan_req_notify_enable; +} __packed; +struct bt_hci_rp_le_set_ext_adv_param { + uint8_t status; + int8_t tx_power; +} __packed; + +#define BT_HCI_LE_EXT_ADV_OP_INTERM_FRAG 0x00 +#define BT_HCI_LE_EXT_ADV_OP_FIRST_FRAG 0x01 +#define BT_HCI_LE_EXT_ADV_OP_LAST_FRAG 0x02 +#define BT_HCI_LE_EXT_ADV_OP_COMPLETE_DATA 0x03 +#define BT_HCI_LE_EXT_ADV_OP_UNCHANGED_DATA 0x04 + +#define BT_HCI_LE_EXT_ADV_FRAG_ENABLED 0x00 +#define BT_HCI_LE_EXT_ADV_FRAG_DISABLED 0x01 + +#define BT_HCI_LE_EXT_ADV_FRAG_MAX_LEN 251 + +#define BT_HCI_OP_LE_SET_EXT_ADV_DATA BT_OP(BT_OGF_LE, 0x0037) +struct bt_hci_cp_le_set_ext_adv_data { + uint8_t handle; + uint8_t op; + uint8_t frag_pref; + uint8_t len; + uint8_t data[251]; +} __packed; + +#define BT_HCI_OP_LE_SET_EXT_SCAN_RSP_DATA BT_OP(BT_OGF_LE, 0x0038) +struct bt_hci_cp_le_set_ext_scan_rsp_data { + uint8_t handle; + uint8_t op; + uint8_t frag_pref; + uint8_t len; + uint8_t data[251]; +} __packed; + +#define BT_HCI_OP_LE_SET_EXT_ADV_ENABLE BT_OP(BT_OGF_LE, 0x0039) +struct bt_hci_ext_adv_set { + uint8_t handle; + uint16_t duration; + uint8_t max_ext_adv_evts; +} __packed; + +struct bt_hci_cp_le_set_ext_adv_enable { + uint8_t enable; + uint8_t set_num; + struct bt_hci_ext_adv_set s[0]; +} __packed; + +#define BT_HCI_OP_LE_READ_MAX_ADV_DATA_LEN BT_OP(BT_OGF_LE, 0x003a) +struct bt_hci_rp_le_read_max_adv_data_len { + uint8_t status; + uint16_t max_adv_data_len; +} __packed; + +#define BT_HCI_OP_LE_READ_NUM_ADV_SETS BT_OP(BT_OGF_LE, 0x003b) +struct bt_hci_rp_le_read_num_adv_sets { + uint8_t status; + uint8_t num_sets; +} __packed; + +#define BT_HCI_OP_LE_REMOVE_ADV_SET BT_OP(BT_OGF_LE, 0x003c) +struct bt_hci_cp_le_remove_adv_set { + uint8_t handle; +} __packed; + +#define BT_HCI_OP_CLEAR_ADV_SETS BT_OP(BT_OGF_LE, 0x003d) + +#define BT_HCI_OP_LE_SET_PER_ADV_PARAM BT_OP(BT_OGF_LE, 0x003e) +struct bt_hci_cp_le_set_per_adv_param { + uint8_t handle; + uint16_t min_interval; + uint16_t max_interval; + uint16_t props; +} __packed; + +#define BT_HCI_OP_LE_SET_PER_ADV_DATA BT_OP(BT_OGF_LE, 0x003f) +struct bt_hci_cp_le_set_per_adv_data { + uint8_t handle; + uint8_t op; + uint8_t len; + uint8_t data[251]; +} __packed; + +#define BT_HCI_OP_LE_SET_PER_ADV_ENABLE BT_OP(BT_OGF_LE, 0x0040) +struct bt_hci_cp_le_set_per_adv_enable { + uint8_t enable; + uint8_t handle; +} __packed; + +#define BT_HCI_OP_LE_SET_EXT_SCAN_PARAM BT_OP(BT_OGF_LE, 0x0041) +struct bt_hci_ext_scan_phy { + uint8_t type; + uint16_t interval; + uint16_t window; +} __packed; + +#define BT_HCI_LE_EXT_SCAN_PHY_1M BIT(0) +#define BT_HCI_LE_EXT_SCAN_PHY_2M BIT(1) +#define BT_HCI_LE_EXT_SCAN_PHY_CODED BIT(2) + +struct bt_hci_cp_le_set_ext_scan_param { + uint8_t own_addr_type; + uint8_t filter_policy; + uint8_t phys; + struct bt_hci_ext_scan_phy p[0]; +} __packed; + +/* Extends BT_HCI_LE_SCAN_FILTER_DUP */ +#define BT_HCI_LE_EXT_SCAN_FILTER_DUP_ENABLE_RESET 0x02 + +#define BT_HCI_OP_LE_SET_EXT_SCAN_ENABLE BT_OP(BT_OGF_LE, 0x0042) +struct bt_hci_cp_le_set_ext_scan_enable { + uint8_t enable; + uint8_t filter_dup; + uint16_t duration; + uint16_t period; +} __packed; + +#define BT_HCI_OP_LE_EXT_CREATE_CONN BT_OP(BT_OGF_LE, 0x0043) +struct bt_hci_ext_conn_phy { + uint16_t scan_interval; + uint16_t scan_window; + uint16_t conn_interval_min; + uint16_t conn_interval_max; + uint16_t conn_latency; + uint16_t supervision_timeout; + uint16_t min_ce_len; + uint16_t max_ce_len; +} __packed; + +struct bt_hci_cp_le_ext_create_conn { + uint8_t filter_policy; + uint8_t own_addr_type; + bt_addr_le_t peer_addr; + uint8_t phys; + struct bt_hci_ext_conn_phy p[0]; +} __packed; + +#define BT_HCI_OP_LE_PER_ADV_CREATE_SYNC BT_OP(BT_OGF_LE, 0x0044) +struct bt_hci_cp_le_per_adv_create_sync { + uint8_t filter_policy; + uint8_t sid; + bt_addr_le_t addr; + uint16_t skip; + uint16_t sync_timeout; + uint8_t unused; +} __packed; + +#define BT_HCI_OP_LE_PER_ADV_CREATE_SYNC_CANCEL BT_OP(BT_OGF_LE, 0x0045) + +#define BT_HCI_OP_LE_PER_ADV_TERMINATE_SYNC BT_OP(BT_OGF_LE, 0x0046) +struct bt_hci_cp_le_per_adv_terminate_sync { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_ADD_DEV_TO_PER_ADV_LIST BT_OP(BT_OGF_LE, 0x0047) +struct bt_hci_cp_le_add_dev_to_per_adv_list { + bt_addr_le_t addr; + uint8_t sid; +} __packed; + +#define BT_HCI_OP_LE_REM_DEV_FROM_PER_ADV_LIST BT_OP(BT_OGF_LE, 0x0048) +struct bt_hci_cp_le_rem_dev_from_per_adv_list { + bt_addr_le_t addr; + uint8_t sid; +} __packed; + +#define BT_HCI_OP_LE_CLEAR_PER_ADV_LIST BT_OP(BT_OGF_LE, 0x0049) + +#define BT_HCI_OP_LE_READ_PER_ADV_LIST_SIZE BT_OP(BT_OGF_LE, 0x004a) +struct bt_hci_rp_le_read_per_adv_list_size { + uint8_t status; + uint8_t list_size; +} __packed; + +#define BT_HCI_OP_LE_READ_TX_POWER BT_OP(BT_OGF_LE, 0x004b) +struct bt_hci_rp_le_read_tx_power { + uint8_t status; + int8_t min_tx_power; + int8_t max_tx_power; +} __packed; + +#define BT_HCI_OP_LE_READ_RF_PATH_COMP BT_OP(BT_OGF_LE, 0x004c) +struct bt_hci_rp_le_read_rf_path_comp { + uint8_t status; + int16_t tx_path_comp; + int16_t rx_path_comp; +} __packed; + +#define BT_HCI_OP_LE_WRITE_RF_PATH_COMP BT_OP(BT_OGF_LE, 0x004d) +struct bt_hci_cp_le_write_rf_path_comp { + int16_t tx_path_comp; + int16_t rx_path_comp; +} __packed; + +#define BT_HCI_LE_PRIVACY_MODE_NETWORK 0x00 +#define BT_HCI_LE_PRIVACY_MODE_DEVICE 0x01 + +#define BT_HCI_OP_LE_SET_PRIVACY_MODE BT_OP(BT_OGF_LE, 0x004e) +struct bt_hci_cp_le_set_privacy_mode { + bt_addr_le_t id_addr; + uint8_t mode; +} __packed; + +/* Event definitions */ + +#define BT_HCI_EVT_UNKNOWN 0x00 +#define BT_HCI_EVT_VENDOR 0xff + +#define BT_HCI_EVT_INQUIRY_COMPLETE 0x01 +struct bt_hci_evt_inquiry_complete { + uint8_t status; +} __packed; + +#define BT_HCI_EVT_CONN_COMPLETE 0x03 +struct bt_hci_evt_conn_complete { + uint8_t status; + uint16_t handle; + bt_addr_t bdaddr; + uint8_t link_type; + uint8_t encr_enabled; +} __packed; + +#define BT_HCI_EVT_CONN_REQUEST 0x04 +struct bt_hci_evt_conn_request { + bt_addr_t bdaddr; + uint8_t dev_class[3]; + uint8_t link_type; +} __packed; + +#define BT_HCI_EVT_DISCONN_COMPLETE 0x05 +struct bt_hci_evt_disconn_complete { + uint8_t status; + uint16_t handle; + uint8_t reason; +} __packed; + +#define BT_HCI_EVT_AUTH_COMPLETE 0x06 +struct bt_hci_evt_auth_complete { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_EVT_REMOTE_NAME_REQ_COMPLETE 0x07 +struct bt_hci_evt_remote_name_req_complete { + uint8_t status; + bt_addr_t bdaddr; + uint8_t name[248]; +} __packed; + +#define BT_HCI_EVT_ENCRYPT_CHANGE 0x08 +struct bt_hci_evt_encrypt_change { + uint8_t status; + uint16_t handle; + uint8_t encrypt; +} __packed; + +#define BT_HCI_EVT_REMOTE_FEATURES 0x0b +struct bt_hci_evt_remote_features { + uint8_t status; + uint16_t handle; + uint8_t features[8]; +} __packed; + +#define BT_HCI_EVT_REMOTE_VERSION_INFO 0x0c +struct bt_hci_evt_remote_version_info { + uint8_t status; + uint16_t handle; + uint8_t version; + uint16_t manufacturer; + uint16_t subversion; +} __packed; + +#define BT_HCI_EVT_CMD_COMPLETE 0x0e +struct bt_hci_evt_cmd_complete { + uint8_t ncmd; + uint16_t opcode; +} __packed; + +struct bt_hci_evt_cc_status { + uint8_t status; +} __packed; + +#define BT_HCI_EVT_CMD_STATUS 0x0f +struct bt_hci_evt_cmd_status { + uint8_t status; + uint8_t ncmd; + uint16_t opcode; +} __packed; + +#define BT_HCI_EVT_ROLE_CHANGE 0x12 +struct bt_hci_evt_role_change { + uint8_t status; + bt_addr_t bdaddr; + uint8_t role; +} __packed; + +#define BT_HCI_EVT_NUM_COMPLETED_PACKETS 0x13 +struct bt_hci_evt_num_completed_packets { + uint8_t num_handles; + struct bt_hci_handle_count h[0]; +} __packed; + +#define BT_HCI_EVT_PIN_CODE_REQ 0x16 +struct bt_hci_evt_pin_code_req { + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_EVT_LINK_KEY_REQ 0x17 +struct bt_hci_evt_link_key_req { + bt_addr_t bdaddr; +} __packed; + +/* Link Key types */ +#define BT_LK_COMBINATION 0x00 +#define BT_LK_LOCAL_UNIT 0x01 +#define BT_LK_REMOTE_UNIT 0x02 +#define BT_LK_DEBUG_COMBINATION 0x03 +#define BT_LK_UNAUTH_COMBINATION_P192 0x04 +#define BT_LK_AUTH_COMBINATION_P192 0x05 +#define BT_LK_CHANGED_COMBINATION 0x06 +#define BT_LK_UNAUTH_COMBINATION_P256 0x07 +#define BT_LK_AUTH_COMBINATION_P256 0x08 + +#define BT_HCI_EVT_LINK_KEY_NOTIFY 0x18 +struct bt_hci_evt_link_key_notify { + bt_addr_t bdaddr; + uint8_t link_key[16]; + uint8_t key_type; +} __packed; + +/* Overflow link types */ +#define BT_OVERFLOW_LINK_SYNCH 0x00 +#define BT_OVERFLOW_LINK_ACL 0x01 + +#define BT_HCI_EVT_DATA_BUF_OVERFLOW 0x1a +struct bt_hci_evt_data_buf_overflow { + uint8_t link_type; +} __packed; + +#define BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI 0x22 +struct bt_hci_evt_inquiry_result_with_rssi { + bt_addr_t addr; + uint8_t pscan_rep_mode; + uint8_t reserved; + uint8_t cod[3]; + uint16_t clock_offset; + int8_t rssi; +} __packed; + +#define BT_HCI_EVT_REMOTE_EXT_FEATURES 0x23 +struct bt_hci_evt_remote_ext_features { + uint8_t status; + uint16_t handle; + uint8_t page; + uint8_t max_page; + uint8_t features[8]; +} __packed; + +#define BT_HCI_EVT_SYNC_CONN_COMPLETE 0x2c +struct bt_hci_evt_sync_conn_complete { + uint8_t status; + uint16_t handle; + bt_addr_t bdaddr; + uint8_t link_type; + uint8_t tx_interval; + uint8_t retansmission_window; + uint16_t rx_pkt_length; + uint16_t tx_pkt_length; + uint8_t air_mode; +} __packed; + +#define BT_HCI_EVT_EXTENDED_INQUIRY_RESULT 0x2f +struct bt_hci_evt_extended_inquiry_result { + uint8_t num_reports; + bt_addr_t addr; + uint8_t pscan_rep_mode; + uint8_t reserved; + uint8_t cod[3]; + uint16_t clock_offset; + int8_t rssi; + uint8_t eir[240]; +} __packed; + +#define BT_HCI_EVT_ENCRYPT_KEY_REFRESH_COMPLETE 0x30 +struct bt_hci_evt_encrypt_key_refresh_complete { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_EVT_IO_CAPA_REQ 0x31 +struct bt_hci_evt_io_capa_req { + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_EVT_IO_CAPA_RESP 0x32 +struct bt_hci_evt_io_capa_resp { + bt_addr_t bdaddr; + uint8_t capability; + uint8_t oob_data; + uint8_t authentication; +} __packed; + +#define BT_HCI_EVT_USER_CONFIRM_REQ 0x33 +struct bt_hci_evt_user_confirm_req { + bt_addr_t bdaddr; + uint32_t passkey; +} __packed; + +#define BT_HCI_EVT_USER_PASSKEY_REQ 0x34 +struct bt_hci_evt_user_passkey_req { + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_EVT_SSP_COMPLETE 0x36 +struct bt_hci_evt_ssp_complete { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_EVT_USER_PASSKEY_NOTIFY 0x3b +struct bt_hci_evt_user_passkey_notify { + bt_addr_t bdaddr; + uint32_t passkey; +} __packed; + +#define BT_HCI_EVT_LE_META_EVENT 0x3e +struct bt_hci_evt_le_meta_event { + uint8_t subevent; +} __packed; + +#define BT_HCI_EVT_AUTH_PAYLOAD_TIMEOUT_EXP 0x57 +struct bt_hci_evt_auth_payload_timeout_exp { + uint16_t handle; +} __packed; + +#define BT_HCI_ROLE_MASTER 0x00 +#define BT_HCI_ROLE_SLAVE 0x01 + +#define BT_HCI_EVT_LE_CONN_COMPLETE 0x01 +struct bt_hci_evt_le_conn_complete { + uint8_t status; + uint16_t handle; + uint8_t role; + bt_addr_le_t peer_addr; + uint16_t interval; + uint16_t latency; + uint16_t supv_timeout; + uint8_t clock_accuracy; +} __packed; + +#define BT_HCI_EVT_LE_ADVERTISING_REPORT 0x02 +struct bt_hci_evt_le_advertising_info { + uint8_t evt_type; + bt_addr_le_t addr; + uint8_t length; + uint8_t data[0]; +} __packed; +struct bt_hci_evt_le_advertising_report { + uint8_t num_reports; + struct bt_hci_evt_le_advertising_info adv_info[0]; +} __packed; + +#define BT_HCI_EVT_LE_CONN_UPDATE_COMPLETE 0x03 +struct bt_hci_evt_le_conn_update_complete { + uint8_t status; + uint16_t handle; + uint16_t interval; + uint16_t latency; + uint16_t supv_timeout; +} __packed; + +#define BT_HCI_EV_LE_REMOTE_FEAT_COMPLETE 0x04 +struct bt_hci_evt_le_remote_feat_complete { + uint8_t status; + uint16_t handle; + uint8_t features[8]; +} __packed; + +#define BT_HCI_EVT_LE_LTK_REQUEST 0x05 +struct bt_hci_evt_le_ltk_request { + uint16_t handle; + uint64_t rand; + uint16_t ediv; +} __packed; + +#define BT_HCI_EVT_LE_CONN_PARAM_REQ 0x06 +struct bt_hci_evt_le_conn_param_req { + uint16_t handle; + uint16_t interval_min; + uint16_t interval_max; + uint16_t latency; + uint16_t timeout; +} __packed; + +#define BT_HCI_EVT_LE_DATA_LEN_CHANGE 0x07 +struct bt_hci_evt_le_data_len_change { + uint16_t handle; + uint16_t max_tx_octets; + uint16_t max_tx_time; + uint16_t max_rx_octets; + uint16_t max_rx_time; +} __packed; + +#define BT_HCI_EVT_LE_P256_PUBLIC_KEY_COMPLETE 0x08 +struct bt_hci_evt_le_p256_public_key_complete { + uint8_t status; + uint8_t key[64]; +} __packed; + +#define BT_HCI_EVT_LE_GENERATE_DHKEY_COMPLETE 0x09 +struct bt_hci_evt_le_generate_dhkey_complete { + uint8_t status; + uint8_t dhkey[32]; +} __packed; + +#define BT_HCI_EVT_LE_ENH_CONN_COMPLETE 0x0a +struct bt_hci_evt_le_enh_conn_complete { + uint8_t status; + uint16_t handle; + uint8_t role; + bt_addr_le_t peer_addr; + bt_addr_t local_rpa; + bt_addr_t peer_rpa; + uint16_t interval; + uint16_t latency; + uint16_t supv_timeout; + uint8_t clock_accuracy; +} __packed; + +#define BT_HCI_EVT_LE_DIRECT_ADV_REPORT 0x0b +struct bt_hci_evt_le_direct_adv_info { + uint8_t evt_type; + bt_addr_le_t addr; + bt_addr_le_t dir_addr; + int8_t rssi; +} __packed; +struct bt_hci_evt_le_direct_adv_report { + uint8_t num_reports; + struct bt_hci_evt_le_direct_adv_info direct_adv_info[0]; +} __packed; + +#define BT_HCI_EVT_LE_PHY_UPDATE_COMPLETE 0x0c +struct bt_hci_evt_le_phy_update_complete { + uint8_t status; + uint16_t handle; + uint8_t tx_phy; + uint8_t rx_phy; +} __packed; + +#define BT_HCI_EVT_LE_EXT_ADVERTISING_REPORT 0x0d + +#define BT_HCI_LE_ADV_EVT_TYPE_CONN BIT(0) +#define BT_HCI_LE_ADV_EVT_TYPE_SCAN BIT(1) +#define BT_HCI_LE_ADV_EVT_TYPE_DIRECT BIT(2) +#define BT_HCI_LE_ADV_EVT_TYPE_SCAN_RSP BIT(3) +#define BT_HCI_LE_ADV_EVT_TYPE_LEGACY BIT(4) + +#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS(ev_type) (((ev_type) >> 5) & 0x03) +#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_COMPLETE 0 +#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_PARTIAL 1 +#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_INCOMPLETE 2 + +struct bt_hci_evt_le_ext_advertising_info { + uint16_t evt_type; + bt_addr_le_t addr; + uint8_t prim_phy; + uint8_t sec_phy; + uint8_t sid; + int8_t tx_power; + int8_t rssi; + uint16_t interval; + bt_addr_le_t direct_addr; + uint8_t length; + uint8_t data[0]; +} __packed; +struct bt_hci_evt_le_ext_advertising_report { + uint8_t num_reports; + struct bt_hci_evt_le_ext_advertising_info adv_info[0]; +} __packed; + +#define BT_HCI_EVT_LE_PER_ADV_SYNC_ESTABLISHED 0x0e +struct bt_hci_evt_le_per_adv_sync_established { + uint8_t status; + uint16_t handle; + uint8_t sid; + bt_addr_le_t adv_addr; + uint8_t phy; + uint16_t interval; + uint8_t clock_accuracy; +} __packed; + +#define BT_HCI_EVT_LE_PER_ADVERTISING_REPORT 0x0f +struct bt_hci_evt_le_per_advertising_report { + uint16_t handle; + int8_t tx_power; + int8_t rssi; + uint8_t unused; + uint8_t data_status; + uint8_t length; + uint8_t data[0]; +} __packed; + +#define BT_HCI_EVT_LE_PER_ADV_SYNC_LOST 0x10 +struct bt_hci_evt_le_per_adv_sync_lost { + uint16_t handle; +} __packed; + +#define BT_HCI_EVT_LE_SCAN_TIMEOUT 0x11 + +#define BT_HCI_EVT_LE_ADV_SET_TERMINATED 0x12 +struct bt_hci_evt_le_adv_set_terminated { + uint8_t status; + uint8_t adv_handle; + uint16_t conn_handle; + uint8_t num_completed_ext_adv_evts; +} __packed; + +#define BT_HCI_EVT_LE_SCAN_REQ_RECEIVED 0x13 +struct bt_hci_evt_le_scan_req_received { + uint8_t handle; + bt_addr_le_t addr; +} __packed; + +#define BT_HCI_LE_CHAN_SEL_ALGO_1 0x00 +#define BT_HCI_LE_CHAN_SEL_ALGO_2 0x01 + +#define BT_HCI_EVT_LE_CHAN_SEL_ALGO 0x14 +struct bt_hci_evt_le_chan_sel_algo { + uint16_t handle; + uint8_t chan_sel_algo; +} __packed; + +/* Event mask bits */ + +#define BT_EVT_BIT(n) (1ULL << (n)) + +#define BT_EVT_MASK_INQUIRY_COMPLETE BT_EVT_BIT(0) +#define BT_EVT_MASK_CONN_COMPLETE BT_EVT_BIT(2) +#define BT_EVT_MASK_CONN_REQUEST BT_EVT_BIT(3) +#define BT_EVT_MASK_DISCONN_COMPLETE BT_EVT_BIT(4) +#define BT_EVT_MASK_AUTH_COMPLETE BT_EVT_BIT(5) +#define BT_EVT_MASK_REMOTE_NAME_REQ_COMPLETE BT_EVT_BIT(6) +#define BT_EVT_MASK_ENCRYPT_CHANGE BT_EVT_BIT(7) +#define BT_EVT_MASK_REMOTE_FEATURES BT_EVT_BIT(10) +#define BT_EVT_MASK_REMOTE_VERSION_INFO BT_EVT_BIT(11) +#define BT_EVT_MASK_HARDWARE_ERROR BT_EVT_BIT(15) +#define BT_EVT_MASK_ROLE_CHANGE BT_EVT_BIT(17) +#define BT_EVT_MASK_PIN_CODE_REQ BT_EVT_BIT(21) +#define BT_EVT_MASK_LINK_KEY_REQ BT_EVT_BIT(22) +#define BT_EVT_MASK_LINK_KEY_NOTIFY BT_EVT_BIT(23) +#define BT_EVT_MASK_DATA_BUFFER_OVERFLOW BT_EVT_BIT(25) +#define BT_EVT_MASK_INQUIRY_RESULT_WITH_RSSI BT_EVT_BIT(33) +#define BT_EVT_MASK_REMOTE_EXT_FEATURES BT_EVT_BIT(34) +#define BT_EVT_MASK_SYNC_CONN_COMPLETE BT_EVT_BIT(43) +#define BT_EVT_MASK_EXTENDED_INQUIRY_RESULT BT_EVT_BIT(46) +#define BT_EVT_MASK_ENCRYPT_KEY_REFRESH_COMPLETE BT_EVT_BIT(47) +#define BT_EVT_MASK_IO_CAPA_REQ BT_EVT_BIT(48) +#define BT_EVT_MASK_IO_CAPA_RESP BT_EVT_BIT(49) +#define BT_EVT_MASK_USER_CONFIRM_REQ BT_EVT_BIT(50) +#define BT_EVT_MASK_USER_PASSKEY_REQ BT_EVT_BIT(51) +#define BT_EVT_MASK_SSP_COMPLETE BT_EVT_BIT(53) +#define BT_EVT_MASK_USER_PASSKEY_NOTIFY BT_EVT_BIT(58) +#define BT_EVT_MASK_LE_META_EVENT BT_EVT_BIT(61) + +/* Page 2 */ +#define BT_EVT_MASK_PHY_LINK_COMPLETE BT_EVT_BIT(0) +#define BT_EVT_MASK_CH_SELECTED_COMPLETE BT_EVT_BIT(1) +#define BT_EVT_MASK_DISCONN_PHY_LINK_COMPLETE BT_EVT_BIT(2) +#define BT_EVT_MASK_PHY_LINK_LOSS_EARLY_WARN BT_EVT_BIT(3) +#define BT_EVT_MASK_PHY_LINK_RECOVERY BT_EVT_BIT(4) +#define BT_EVT_MASK_LOG_LINK_COMPLETE BT_EVT_BIT(5) +#define BT_EVT_MASK_DISCONN_LOG_LINK_COMPLETE BT_EVT_BIT(6) +#define BT_EVT_MASK_FLOW_SPEC_MODIFY_COMPLETE BT_EVT_BIT(7) +#define BT_EVT_MASK_NUM_COMPLETE_DATA_BLOCKS BT_EVT_BIT(8) +#define BT_EVT_MASK_AMP_START_TEST BT_EVT_BIT(9) +#define BT_EVT_MASK_AMP_TEST_END BT_EVT_BIT(10) +#define BT_EVT_MASK_AMP_RX_REPORT BT_EVT_BIT(11) +#define BT_EVT_MASK_AMP_SR_MODE_CHANGE_COMPLETE BT_EVT_BIT(12) +#define BT_EVT_MASK_AMP_STATUS_CHANGE BT_EVT_BIT(13) +#define BT_EVT_MASK_TRIGG_CLOCK_CAPTURE BT_EVT_BIT(14) +#define BT_EVT_MASK_SYNCH_TRAIN_COMPLETE BT_EVT_BIT(15) +#define BT_EVT_MASK_SYNCH_TRAIN_RX BT_EVT_BIT(16) +#define BT_EVT_MASK_CL_SLAVE_BC_RX BT_EVT_BIT(17) +#define BT_EVT_MASK_CL_SLAVE_BC_TIMEOUT BT_EVT_BIT(18) +#define BT_EVT_MASK_TRUNC_PAGE_COMPLETE BT_EVT_BIT(19) +#define BT_EVT_MASK_SLAVE_PAGE_RSP_TIMEOUT BT_EVT_BIT(20) +#define BT_EVT_MASK_CL_SLAVE_BC_CH_MAP_CHANGE BT_EVT_BIT(21) +#define BT_EVT_MASK_INQUIRY_RSP_NOT BT_EVT_BIT(22) +#define BT_EVT_MASK_AUTH_PAYLOAD_TIMEOUT_EXP BT_EVT_BIT(23) +#define BT_EVT_MASK_SAM_STATUS_CHANGE BT_EVT_BIT(24) + +#define BT_EVT_MASK_LE_CONN_COMPLETE BT_EVT_BIT(0) +#define BT_EVT_MASK_LE_ADVERTISING_REPORT BT_EVT_BIT(1) +#define BT_EVT_MASK_LE_CONN_UPDATE_COMPLETE BT_EVT_BIT(2) +#define BT_EVT_MASK_LE_REMOTE_FEAT_COMPLETE BT_EVT_BIT(3) +#define BT_EVT_MASK_LE_LTK_REQUEST BT_EVT_BIT(4) +#define BT_EVT_MASK_LE_CONN_PARAM_REQ BT_EVT_BIT(5) +#define BT_EVT_MASK_LE_DATA_LEN_CHANGE BT_EVT_BIT(6) +#define BT_EVT_MASK_LE_P256_PUBLIC_KEY_COMPLETE BT_EVT_BIT(7) +#define BT_EVT_MASK_LE_GENERATE_DHKEY_COMPLETE BT_EVT_BIT(8) +#define BT_EVT_MASK_LE_ENH_CONN_COMPLETE BT_EVT_BIT(9) +#define BT_EVT_MASK_LE_DIRECT_ADV_REPORT BT_EVT_BIT(10) +#define BT_EVT_MASK_LE_PHY_UPDATE_COMPLETE BT_EVT_BIT(11) +#define BT_EVT_MASK_LE_EXT_ADVERTISING_REPORT BT_EVT_BIT(12) +#define BT_EVT_MASK_LE_PER_ADV_SYNC_ESTABLISHED BT_EVT_BIT(13) +#define BT_EVT_MASK_LE_PER_ADVERTISING_REPORT BT_EVT_BIT(14) +#define BT_EVT_MASK_LE_PER_ADV_SYNC_LOST BT_EVT_BIT(15) +#define BT_EVT_MASK_LE_SCAN_TIMEOUT BT_EVT_BIT(16) +#define BT_EVT_MASK_LE_ADV_SET_TERMINATED BT_EVT_BIT(17) +#define BT_EVT_MASK_LE_SCAN_REQ_RECEIVED BT_EVT_BIT(18) +#define BT_EVT_MASK_LE_CHAN_SEL_ALGO BT_EVT_BIT(19) + + // +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_HCI_H_ */ diff --git a/devices/ble_hci/common-hal/_bleio/hci_include/README.md b/devices/ble_hci/common-hal/_bleio/hci_include/README.md new file mode 100644 index 000000000..4d2968c39 --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/hci_include/README.md @@ -0,0 +1,2 @@ +The HCI-related include files here are copied from the Zephyr project: +https://github.com/zephyrproject-rtos/zephyr/tree/master/include/bluetooth diff --git a/devices/ble_hci/common-hal/_bleio/hci_include/addr.h b/devices/ble_hci/common-hal/_bleio/hci_include/addr.h new file mode 100644 index 000000000..8f503b8a1 --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/hci_include/addr.h @@ -0,0 +1,100 @@ +// CircuitPython: Adapted from Zephyer include files. +/** @file + * @brief Bluetooth device address definitions and utilities. + */ + +/* + * Copyright (c) 2019 Nordic Semiconductor ASA + * Copyright 2020 Dan Halbert for Adafruit Industries + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_ADDR_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_ADDR_H_ + +#include + +/** + * @brief Bluetooth device address definitions and utilities. + * @defgroup bt_addr Device Address + * @ingroup bluetooth + * @{ + */ + +#define BT_ADDR_LE_PUBLIC 0x00 +#define BT_ADDR_LE_RANDOM 0x01 +#define BT_ADDR_LE_PUBLIC_ID 0x02 +#define BT_ADDR_LE_RANDOM_ID 0x03 + +/** Bluetooth Device Address */ +typedef struct { + uint8_t val[6]; +} bt_addr_t; + +/** Bluetooth LE Device Address */ +typedef struct { + uint8_t type; + bt_addr_t a; +} bt_addr_le_t; + +#define BT_ADDR_ANY ((bt_addr_t[]) { { { 0, 0, 0, 0, 0, 0 } } }) +#define BT_ADDR_NONE ((bt_addr_t[]) { { \ + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } } }) +#define BT_ADDR_LE_ANY ((bt_addr_le_t[]) { { 0, { { 0, 0, 0, 0, 0, 0 } } } }) +#define BT_ADDR_LE_NONE ((bt_addr_le_t[]) { { 0, \ + { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } } } }) + +static inline int bt_addr_cmp(const bt_addr_t *a, const bt_addr_t *b) +{ + return memcmp(a, b, sizeof(*a)); +} + +static inline int bt_addr_le_cmp(const bt_addr_le_t *a, const bt_addr_le_t *b) +{ + return memcmp(a, b, sizeof(*a)); +} + +static inline void bt_addr_copy(bt_addr_t *dst, const bt_addr_t *src) +{ + memcpy(dst, src, sizeof(*dst)); +} + +static inline void bt_addr_le_copy(bt_addr_le_t *dst, const bt_addr_le_t *src) +{ + memcpy(dst, src, sizeof(*dst)); +} + +#define BT_ADDR_IS_RPA(a) (((a)->val[5] & 0xc0) == 0x40) +#define BT_ADDR_IS_NRPA(a) (((a)->val[5] & 0xc0) == 0x00) +#define BT_ADDR_IS_STATIC(a) (((a)->val[5] & 0xc0) == 0xc0) + +#define BT_ADDR_SET_RPA(a) ((a)->val[5] = (((a)->val[5] & 0x3f) | 0x40)) +#define BT_ADDR_SET_NRPA(a) ((a)->val[5] &= 0x3f) +#define BT_ADDR_SET_STATIC(a) ((a)->val[5] |= 0xc0) + +int bt_addr_le_create_nrpa(bt_addr_le_t *addr); +int bt_addr_le_create_static(bt_addr_le_t *addr); + +static inline bool bt_addr_le_is_rpa(const bt_addr_le_t *addr) +{ + if (addr->type != BT_ADDR_LE_RANDOM) { + return false; + } + + return BT_ADDR_IS_RPA(&addr->a); +} + +static inline bool bt_addr_le_is_identity(const bt_addr_le_t *addr) +{ + if (addr->type == BT_ADDR_LE_PUBLIC) { + return true; + } + + return BT_ADDR_IS_STATIC(&addr->a); +} + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_ADDR_H_ */ diff --git a/devices/ble_hci/common-hal/_bleio/hci_include/hci.h b/devices/ble_hci/common-hal/_bleio/hci_include/hci.h new file mode 100644 index 000000000..dbe233fef --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/hci_include/hci.h @@ -0,0 +1,1764 @@ +// CircuitPython: Adapted from Zephyr include file. +/* hci.h - Bluetooth Host Control Interface definitions */ + +/* + * Copyright 2020 Dan Halbert for Adafruit Industries + * Copyright (c) 2015-2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_HCI_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_HCI_H_ + +#include +#include +#include "addr.h" + +/* Special own address types for LL privacy (used in adv & scan parameters) */ +#define BT_HCI_OWN_ADDR_RPA_OR_PUBLIC 0x02 +#define BT_HCI_OWN_ADDR_RPA_OR_RANDOM 0x03 +#define BT_HCI_OWN_ADDR_RPA_MASK 0x02 + +#define BT_HCI_PEER_ADDR_RPA_UNRESOLVED 0xfe +#define BT_HCI_PEER_ADDR_ANONYMOUS 0xff + +#define BT_ENC_KEY_SIZE_MIN 0x07 +#define BT_ENC_KEY_SIZE_MAX 0x10 + +struct bt_hci_evt_hdr { + uint8_t evt; + uint8_t len; +} __packed; +#define BT_HCI_EVT_HDR_SIZE 2 + +#define BT_ACL_START_NO_FLUSH 0x00 +#define BT_ACL_CONT 0x01 +#define BT_ACL_START 0x02 +#define BT_ACL_COMPLETE 0x03 + +#define BT_ACL_POINT_TO_POINT 0x00 +#define BT_ACL_BROADCAST 0x01 + +#define bt_acl_handle(h) ((h) & BIT_MASK(12)) +#define bt_acl_flags(h) ((h) >> 12) +#define bt_acl_flags_pb(f) ((f) & BIT_MASK(2)) +#define bt_acl_flags_bc(f) ((f) >> 2) +#define bt_acl_handle_pack(h, f) ((h) | ((f) << 12)) + +struct bt_hci_acl_hdr { + uint16_t handle; + uint16_t len; +} __packed; +#define BT_HCI_ACL_HDR_SIZE 4 + +struct bt_hci_cmd_hdr { + uint16_t opcode; + uint8_t param_len; +} __packed; +#define BT_HCI_CMD_HDR_SIZE 3 + +/* Supported Commands */ +#define BT_CMD_TEST(cmd, octet, bit) (cmd[octet] & BIT(bit)) +#define BT_CMD_LE_STATES(cmd) BT_CMD_TEST(cmd, 28, 3) + +#define BT_FEAT_TEST(feat, page, octet, bit) (feat[page][octet] & BIT(bit)) + +#define BT_FEAT_BREDR(feat) !BT_FEAT_TEST(feat, 0, 4, 5) +#define BT_FEAT_LE(feat) BT_FEAT_TEST(feat, 0, 4, 6) +#define BT_FEAT_EXT_FEATURES(feat) BT_FEAT_TEST(feat, 0, 7, 7) +#define BT_FEAT_HOST_SSP(feat) BT_FEAT_TEST(feat, 1, 0, 0) +#define BT_FEAT_SC(feat) BT_FEAT_TEST(feat, 2, 1, 0) + +#define BT_FEAT_LMP_ESCO_CAPABLE(feat) BT_FEAT_TEST(feat, 0, 3, 7) +#define BT_FEAT_HV2_PKT(feat) BT_FEAT_TEST(feat, 0, 1, 4) +#define BT_FEAT_HV3_PKT(feat) BT_FEAT_TEST(feat, 0, 1, 5) +#define BT_FEAT_EV4_PKT(feat) BT_FEAT_TEST(feat, 0, 4, 0) +#define BT_FEAT_EV5_PKT(feat) BT_FEAT_TEST(feat, 0, 4, 1) +#define BT_FEAT_2EV3_PKT(feat) BT_FEAT_TEST(feat, 0, 5, 5) +#define BT_FEAT_3EV3_PKT(feat) BT_FEAT_TEST(feat, 0, 5, 6) +#define BT_FEAT_3SLOT_PKT(feat) BT_FEAT_TEST(feat, 0, 5, 7) + +/* LE features */ +#define BT_LE_FEAT_BIT_ENC 0 +#define BT_LE_FEAT_BIT_CONN_PARAM_REQ 1 +#define BT_LE_FEAT_BIT_EXT_REJ_IND 2 +#define BT_LE_FEAT_BIT_SLAVE_FEAT_REQ 3 +#define BT_LE_FEAT_BIT_PING 4 +#define BT_LE_FEAT_BIT_DLE 5 +#define BT_LE_FEAT_BIT_PRIVACY 6 +#define BT_LE_FEAT_BIT_EXT_SCAN 7 +#define BT_LE_FEAT_BIT_PHY_2M 8 +#define BT_LE_FEAT_BIT_SMI_TX 9 +#define BT_LE_FEAT_BIT_SMI_RX 10 +#define BT_LE_FEAT_BIT_PHY_CODED 11 +#define BT_LE_FEAT_BIT_EXT_ADV 12 +#define BT_LE_FEAT_BIT_PER_ADV 13 +#define BT_LE_FEAT_BIT_CHAN_SEL_ALGO_2 14 +#define BT_LE_FEAT_BIT_PWR_CLASS_1 15 +#define BT_LE_FEAT_BIT_MIN_USED_CHAN_PROC 16 +#define BT_LE_FEAT_BIT_CONN_CTE_REQ 17 +#define BT_LE_FEAT_BIT_CONN_CTE_RESP 18 +#define BT_LE_FEAT_BIT_CONNECTIONLESS_CTE_TX 19 +#define BT_LE_FEAT_BIT_CONNECTIONLESS_CTE_RX 20 +#define BT_LE_FEAT_BIT_ANT_SWITCH_TX_AOD 21 +#define BT_LE_FEAT_BIT_ANT_SWITCH_RX_AOA 22 +#define BT_LE_FEAT_BIT_RX_CTE 23 +#define BT_LE_FEAT_BIT_PERIODIC_SYNC_XFER_SEND 24 +#define BT_LE_FEAT_BIT_PERIODIC_SYNC_XFER_RECV 25 +#define BT_LE_FEAT_BIT_SCA_UPDATE 26 +#define BT_LE_FEAT_BIT_REMOTE_PUB_KEY_VALIDATE 27 +#define BT_LE_FEAT_BIT_CIS_MASTER 28 +#define BT_LE_FEAT_BIT_CIS_SLAVE 29 +#define BT_LE_FEAT_BIT_ISO_BROADCASTER 30 +#define BT_LE_FEAT_BIT_SYNC_RECEIVER 31 +#define BT_LE_FEAT_BIT_ISO_CHANNELS 32 +#define BT_LE_FEAT_BIT_PWR_CTRL_REQ 33 +#define BT_LE_FEAT_BIT_PWR_CHG_IND 34 +#define BT_LE_FEAT_BIT_PATH_LOSS_MONITOR 35 + +#define BT_LE_FEAT_TEST(feat, n) (feat[(n) >> 3] & \ + BIT((n) & 7)) + +#define BT_FEAT_LE_ENCR(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_ENC) +#define BT_FEAT_LE_CONN_PARAM_REQ_PROC(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CONN_PARAM_REQ) +#define BT_FEAT_LE_SLAVE_FEATURE_XCHG(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_SLAVE_FEAT_REQ) +#define BT_FEAT_LE_DLE(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_DLE) +#define BT_FEAT_LE_PHY_2M(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PHY_2M) +#define BT_FEAT_LE_PHY_CODED(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PHY_CODED) +#define BT_FEAT_LE_PRIVACY(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PRIVACY) +#define BT_FEAT_LE_EXT_ADV(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_EXT_ADV) + +/* LE States */ +#define BT_LE_STATES_SLAVE_CONN_ADV(states) (states & 0x0000004000000000) + +/* Bonding/authentication types */ +#define BT_HCI_NO_BONDING 0x00 +#define BT_HCI_NO_BONDING_MITM 0x01 +#define BT_HCI_DEDICATED_BONDING 0x02 +#define BT_HCI_DEDICATED_BONDING_MITM 0x03 +#define BT_HCI_GENERAL_BONDING 0x04 +#define BT_HCI_GENERAL_BONDING_MITM 0x05 + +/* + * MITM protection is enabled in SSP authentication requirements octet when + * LSB bit is set. + */ +#define BT_MITM 0x01 + +/* I/O capabilities */ +#define BT_IO_DISPLAY_ONLY 0x00 +#define BT_IO_DISPLAY_YESNO 0x01 +#define BT_IO_KEYBOARD_ONLY 0x02 +#define BT_IO_NO_INPUT_OUTPUT 0x03 + +/* SCO packet types */ +#define HCI_PKT_TYPE_HV1 0x0020 +#define HCI_PKT_TYPE_HV2 0x0040 +#define HCI_PKT_TYPE_HV3 0x0080 + +/* eSCO packet types */ +#define HCI_PKT_TYPE_ESCO_HV1 0x0001 +#define HCI_PKT_TYPE_ESCO_HV2 0x0002 +#define HCI_PKT_TYPE_ESCO_HV3 0x0004 +#define HCI_PKT_TYPE_ESCO_EV3 0x0008 +#define HCI_PKT_TYPE_ESCO_EV4 0x0010 +#define HCI_PKT_TYPE_ESCO_EV5 0x0020 +#define HCI_PKT_TYPE_ESCO_2EV3 0x0040 +#define HCI_PKT_TYPE_ESCO_3EV3 0x0080 +#define HCI_PKT_TYPE_ESCO_2EV5 0x0100 +#define HCI_PKT_TYPE_ESCO_3EV5 0x0200 + + +#define ESCO_PKT_MASK (HCI_PKT_TYPE_ESCO_HV1 | \ + HCI_PKT_TYPE_ESCO_HV2 | \ + HCI_PKT_TYPE_ESCO_HV3) +#define SCO_PKT_MASK (HCI_PKT_TYPE_HV1 | \ + HCI_PKT_TYPE_HV2 | \ + HCI_PKT_TYPE_HV3) +#define EDR_ESCO_PKT_MASK (HCI_PKT_TYPE_ESCO_2EV3 | \ + HCI_PKT_TYPE_ESCO_3EV3 | \ + HCI_PKT_TYPE_ESCO_2EV5 | \ + HCI_PKT_TYPE_ESCO_3EV5) + +/* HCI BR/EDR link types */ +#define BT_HCI_SCO 0x00 +#define BT_HCI_ACL 0x01 +#define BT_HCI_ESCO 0x02 + +/* OpCode Group Fields */ +#define BT_OGF_LINK_CTRL 0x01 +#define BT_OGF_BASEBAND 0x03 +#define BT_OGF_INFO 0x04 +#define BT_OGF_STATUS 0x05 +#define BT_OGF_LE 0x08 +#define BT_OGF_VS 0x3f + +/* Construct OpCode from OGF and OCF */ +#define BT_OP(ogf, ocf) ((ocf) | ((ogf) << 10)) + +/* Invalid opcode */ +#define BT_OP_NOP 0x0000 + +/* Obtain OGF from OpCode */ +#define BT_OGF(opcode) (((opcode) >> 10) & BIT_MASK(6)) +/* Obtain OCF from OpCode */ +#define BT_OCF(opcode) ((opcode) & BIT_MASK(10)) + +#define BT_HCI_OP_INQUIRY BT_OP(BT_OGF_LINK_CTRL, 0x0001) +struct bt_hci_op_inquiry { + uint8_t lap[3]; + uint8_t length; + uint8_t num_rsp; +} __packed; + +#define BT_HCI_OP_INQUIRY_CANCEL BT_OP(BT_OGF_LINK_CTRL, 0x0002) + +#define BT_HCI_OP_CONNECT BT_OP(BT_OGF_LINK_CTRL, 0x0005) +struct bt_hci_cp_connect { + bt_addr_t bdaddr; + uint16_t packet_type; + uint8_t pscan_rep_mode; + uint8_t reserved; + uint16_t clock_offset; + uint8_t allow_role_switch; +} __packed; + +#define BT_HCI_OP_DISCONNECT BT_OP(BT_OGF_LINK_CTRL, 0x0006) +struct bt_hci_cp_disconnect { + uint16_t handle; + uint8_t reason; +} __packed; + +#define BT_HCI_OP_CONNECT_CANCEL BT_OP(BT_OGF_LINK_CTRL, 0x0008) +struct bt_hci_cp_connect_cancel { + bt_addr_t bdaddr; +} __packed; +struct bt_hci_rp_connect_cancel { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_ACCEPT_CONN_REQ BT_OP(BT_OGF_LINK_CTRL, 0x0009) +struct bt_hci_cp_accept_conn_req { + bt_addr_t bdaddr; + uint8_t role; +} __packed; + +#define BT_HCI_OP_SETUP_SYNC_CONN BT_OP(BT_OGF_LINK_CTRL, 0x0028) +struct bt_hci_cp_setup_sync_conn { + uint16_t handle; + uint32_t tx_bandwidth; + uint32_t rx_bandwidth; + uint16_t max_latency; + uint16_t content_format; + uint8_t retrans_effort; + uint16_t pkt_type; +} __packed; + +#define BT_HCI_OP_ACCEPT_SYNC_CONN_REQ BT_OP(BT_OGF_LINK_CTRL, 0x0029) +struct bt_hci_cp_accept_sync_conn_req { + bt_addr_t bdaddr; + uint32_t tx_bandwidth; + uint32_t rx_bandwidth; + uint16_t max_latency; + uint16_t content_format; + uint8_t retrans_effort; + uint16_t pkt_type; +} __packed; + +#define BT_HCI_OP_REJECT_CONN_REQ BT_OP(BT_OGF_LINK_CTRL, 0x000a) +struct bt_hci_cp_reject_conn_req { + bt_addr_t bdaddr; + uint8_t reason; +} __packed; + +#define BT_HCI_OP_LINK_KEY_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x000b) +struct bt_hci_cp_link_key_reply { + bt_addr_t bdaddr; + uint8_t link_key[16]; +} __packed; + +#define BT_HCI_OP_LINK_KEY_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x000c) +struct bt_hci_cp_link_key_neg_reply { + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_PIN_CODE_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x000d) +struct bt_hci_cp_pin_code_reply { + bt_addr_t bdaddr; + uint8_t pin_len; + uint8_t pin_code[16]; +} __packed; +struct bt_hci_rp_pin_code_reply { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_PIN_CODE_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x000e) +struct bt_hci_cp_pin_code_neg_reply { + bt_addr_t bdaddr; +} __packed; +struct bt_hci_rp_pin_code_neg_reply { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_AUTH_REQUESTED BT_OP(BT_OGF_LINK_CTRL, 0x0011) +struct bt_hci_cp_auth_requested { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_SET_CONN_ENCRYPT BT_OP(BT_OGF_LINK_CTRL, 0x0013) +struct bt_hci_cp_set_conn_encrypt { + uint16_t handle; + uint8_t encrypt; +} __packed; + +#define BT_HCI_OP_REMOTE_NAME_REQUEST BT_OP(BT_OGF_LINK_CTRL, 0x0019) +struct bt_hci_cp_remote_name_request { + bt_addr_t bdaddr; + uint8_t pscan_rep_mode; + uint8_t reserved; + uint16_t clock_offset; +} __packed; + +#define BT_HCI_OP_REMOTE_NAME_CANCEL BT_OP(BT_OGF_LINK_CTRL, 0x001a) +struct bt_hci_cp_remote_name_cancel { + bt_addr_t bdaddr; +} __packed; +struct bt_hci_rp_remote_name_cancel { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_READ_REMOTE_FEATURES BT_OP(BT_OGF_LINK_CTRL, 0x001b) +struct bt_hci_cp_read_remote_features { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_READ_REMOTE_EXT_FEATURES BT_OP(BT_OGF_LINK_CTRL, 0x001c) +struct bt_hci_cp_read_remote_ext_features { + uint16_t handle; + uint8_t page; +} __packed; + +#define BT_HCI_OP_READ_REMOTE_VERSION_INFO BT_OP(BT_OGF_LINK_CTRL, 0x001d) +struct bt_hci_cp_read_remote_version_info { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_IO_CAPABILITY_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002b) +struct bt_hci_cp_io_capability_reply { + bt_addr_t bdaddr; + uint8_t capability; + uint8_t oob_data; + uint8_t authentication; +} __packed; + +#define BT_HCI_OP_USER_CONFIRM_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002c) +#define BT_HCI_OP_USER_CONFIRM_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002d) +struct bt_hci_cp_user_confirm_reply { + bt_addr_t bdaddr; +} __packed; +struct bt_hci_rp_user_confirm_reply { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_USER_PASSKEY_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002e) +struct bt_hci_cp_user_passkey_reply { + bt_addr_t bdaddr; + uint32_t passkey; +} __packed; + +#define BT_HCI_OP_USER_PASSKEY_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002f) +struct bt_hci_cp_user_passkey_neg_reply { + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_IO_CAPABILITY_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x0034) +struct bt_hci_cp_io_capability_neg_reply { + bt_addr_t bdaddr; + uint8_t reason; +} __packed; + +#define BT_HCI_OP_SET_EVENT_MASK BT_OP(BT_OGF_BASEBAND, 0x0001) +struct bt_hci_cp_set_event_mask { + uint8_t events[8]; +} __packed; + +#define BT_HCI_OP_RESET BT_OP(BT_OGF_BASEBAND, 0x0003) + +#define BT_HCI_OP_WRITE_LOCAL_NAME BT_OP(BT_OGF_BASEBAND, 0x0013) +struct bt_hci_write_local_name { + uint8_t local_name[248]; +} __packed; + +#define BT_HCI_OP_WRITE_PAGE_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x0018) + +#define BT_HCI_OP_WRITE_SCAN_ENABLE BT_OP(BT_OGF_BASEBAND, 0x001a) +#define BT_BREDR_SCAN_DISABLED 0x00 +#define BT_BREDR_SCAN_INQUIRY 0x01 +#define BT_BREDR_SCAN_PAGE 0x02 + +#define BT_TX_POWER_LEVEL_CURRENT 0x00 +#define BT_TX_POWER_LEVEL_MAX 0x01 +#define BT_HCI_OP_READ_TX_POWER_LEVEL BT_OP(BT_OGF_BASEBAND, 0x002d) +struct bt_hci_cp_read_tx_power_level { + uint16_t handle; + uint8_t type; +} __packed; + +struct bt_hci_rp_read_tx_power_level { + uint8_t status; + uint16_t handle; + int8_t tx_power_level; +} __packed; + +#define BT_HCI_CTL_TO_HOST_FLOW_DISABLE 0x00 +#define BT_HCI_CTL_TO_HOST_FLOW_ENABLE 0x01 +#define BT_HCI_OP_SET_CTL_TO_HOST_FLOW BT_OP(BT_OGF_BASEBAND, 0x0031) +struct bt_hci_cp_set_ctl_to_host_flow { + uint8_t flow_enable; +} __packed; + +#define BT_HCI_OP_HOST_BUFFER_SIZE BT_OP(BT_OGF_BASEBAND, 0x0033) +struct bt_hci_cp_host_buffer_size { + uint16_t acl_mtu; + uint8_t sco_mtu; + uint16_t acl_pkts; + uint16_t sco_pkts; +} __packed; + +struct bt_hci_handle_count { + uint16_t handle; + uint16_t count; +} __packed; + +#define BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS BT_OP(BT_OGF_BASEBAND, 0x0035) +struct bt_hci_cp_host_num_completed_packets { + uint8_t num_handles; + struct bt_hci_handle_count h[0]; +} __packed; + +#define BT_HCI_OP_WRITE_INQUIRY_MODE BT_OP(BT_OGF_BASEBAND, 0x0045) +struct bt_hci_cp_write_inquiry_mode { + uint8_t mode; +} __packed; + +#define BT_HCI_OP_WRITE_SSP_MODE BT_OP(BT_OGF_BASEBAND, 0x0056) +struct bt_hci_cp_write_ssp_mode { + uint8_t mode; +} __packed; + +#define BT_HCI_OP_SET_EVENT_MASK_PAGE_2 BT_OP(BT_OGF_BASEBAND, 0x0063) +struct bt_hci_cp_set_event_mask_page_2 { + uint8_t events_page_2[8]; +} __packed; + +#define BT_HCI_OP_LE_WRITE_LE_HOST_SUPP BT_OP(BT_OGF_BASEBAND, 0x006d) +struct bt_hci_cp_write_le_host_supp { + uint8_t le; + uint8_t simul; +} __packed; + +#define BT_HCI_OP_WRITE_SC_HOST_SUPP BT_OP(BT_OGF_BASEBAND, 0x007a) +struct bt_hci_cp_write_sc_host_supp { + uint8_t sc_support; +} __packed; + +#define BT_HCI_OP_READ_AUTH_PAYLOAD_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x007b) +struct bt_hci_cp_read_auth_payload_timeout { + uint16_t handle; +} __packed; + +struct bt_hci_rp_read_auth_payload_timeout { + uint8_t status; + uint16_t handle; + uint16_t auth_payload_timeout; +} __packed; + +#define BT_HCI_OP_WRITE_AUTH_PAYLOAD_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x007c) +struct bt_hci_cp_write_auth_payload_timeout { + uint16_t handle; + uint16_t auth_payload_timeout; +} __packed; + +struct bt_hci_rp_write_auth_payload_timeout { + uint8_t status; + uint16_t handle; +} __packed; + +/* HCI version from Assigned Numbers */ +#define BT_HCI_VERSION_1_0B 0 +#define BT_HCI_VERSION_1_1 1 +#define BT_HCI_VERSION_1_2 2 +#define BT_HCI_VERSION_2_0 3 +#define BT_HCI_VERSION_2_1 4 +#define BT_HCI_VERSION_3_0 5 +#define BT_HCI_VERSION_4_0 6 +#define BT_HCI_VERSION_4_1 7 +#define BT_HCI_VERSION_4_2 8 +#define BT_HCI_VERSION_5_0 9 +#define BT_HCI_VERSION_5_1 10 +#define BT_HCI_VERSION_5_2 11 + +#define BT_HCI_OP_READ_LOCAL_VERSION_INFO BT_OP(BT_OGF_INFO, 0x0001) +struct bt_hci_rp_read_local_version_info { + uint8_t status; + uint8_t hci_version; + uint16_t hci_revision; + uint8_t lmp_version; + uint16_t manufacturer; + uint16_t lmp_subversion; +} __packed; + +#define BT_HCI_OP_READ_SUPPORTED_COMMANDS BT_OP(BT_OGF_INFO, 0x0002) +struct bt_hci_rp_read_supported_commands { + uint8_t status; + uint8_t commands[64]; +} __packed; + +#define BT_HCI_OP_READ_LOCAL_EXT_FEATURES BT_OP(BT_OGF_INFO, 0x0004) +struct bt_hci_cp_read_local_ext_features { + uint8_t page; +}; +struct bt_hci_rp_read_local_ext_features { + uint8_t status; + uint8_t page; + uint8_t max_page; + uint8_t ext_features[8]; +} __packed; + +#define BT_HCI_OP_READ_LOCAL_FEATURES BT_OP(BT_OGF_INFO, 0x0003) +struct bt_hci_rp_read_local_features { + uint8_t status; + uint8_t features[8]; +} __packed; + +#define BT_HCI_OP_READ_BUFFER_SIZE BT_OP(BT_OGF_INFO, 0x0005) +struct bt_hci_rp_read_buffer_size { + uint8_t status; + uint16_t acl_max_len; + uint8_t sco_max_len; + uint16_t acl_max_num; + uint16_t sco_max_num; +} __packed; + +#define BT_HCI_OP_READ_BD_ADDR BT_OP(BT_OGF_INFO, 0x0009) +struct bt_hci_rp_read_bd_addr { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_READ_RSSI BT_OP(BT_OGF_STATUS, 0x0005) +struct bt_hci_cp_read_rssi { + uint16_t handle; +} __packed; +struct bt_hci_rp_read_rssi { + uint8_t status; + uint16_t handle; + int8_t rssi; +} __packed; + +#define BT_HCI_ENCRYPTION_KEY_SIZE_MIN 7 +#define BT_HCI_ENCRYPTION_KEY_SIZE_MAX 16 + +#define BT_HCI_OP_READ_ENCRYPTION_KEY_SIZE BT_OP(BT_OGF_STATUS, 0x0008) +struct bt_hci_cp_read_encryption_key_size { + uint16_t handle; +} __packed; +struct bt_hci_rp_read_encryption_key_size { + uint8_t status; + uint16_t handle; + uint8_t key_size; +} __packed; + +/* BLE */ + +#define BT_HCI_OP_LE_SET_EVENT_MASK BT_OP(BT_OGF_LE, 0x0001) +struct bt_hci_cp_le_set_event_mask { + uint8_t events[8]; +} __packed; + +#define BT_HCI_OP_LE_READ_BUFFER_SIZE BT_OP(BT_OGF_LE, 0x0002) +struct bt_hci_rp_le_read_buffer_size { + uint8_t status; + uint16_t le_max_len; + uint8_t le_max_num; +} __packed; + +#define BT_HCI_OP_LE_READ_LOCAL_FEATURES BT_OP(BT_OGF_LE, 0x0003) +struct bt_hci_rp_le_read_local_features { + uint8_t status; + uint8_t features[8]; +} __packed; + +#define BT_HCI_OP_LE_SET_RANDOM_ADDRESS BT_OP(BT_OGF_LE, 0x0005) +struct bt_hci_cp_le_set_random_address { + bt_addr_t bdaddr; +} __packed; + +/* LE Advertising Types (LE Advertising Parameters Set)*/ +#define BT_LE_ADV_IND (__DEPRECATED_MACRO 0x00) +#define BT_LE_ADV_DIRECT_IND (__DEPRECATED_MACRO 0x01) +#define BT_LE_ADV_SCAN_IND (__DEPRECATED_MACRO 0x02) +#define BT_LE_ADV_NONCONN_IND (__DEPRECATED_MACRO 0x03) +#define BT_LE_ADV_DIRECT_IND_LOW_DUTY (__DEPRECATED_MACRO 0x04) +/* LE Advertising PDU Types. */ +#define BT_LE_ADV_SCAN_RSP (__DEPRECATED_MACRO 0x04) + +#define BT_HCI_ADV_IND 0x00 +#define BT_HCI_ADV_DIRECT_IND 0x01 +#define BT_HCI_ADV_SCAN_IND 0x02 +#define BT_HCI_ADV_NONCONN_IND 0x03 +#define BT_HCI_ADV_DIRECT_IND_LOW_DUTY 0x04 +#define BT_HCI_ADV_SCAN_RSP 0x04 + +#define BT_LE_ADV_FP_NO_WHITELIST 0x00 +#define BT_LE_ADV_FP_WHITELIST_SCAN_REQ 0x01 +#define BT_LE_ADV_FP_WHITELIST_CONN_IND 0x02 +#define BT_LE_ADV_FP_WHITELIST_BOTH 0x03 + +#define BT_HCI_OP_LE_SET_ADV_PARAM BT_OP(BT_OGF_LE, 0x0006) +struct bt_hci_cp_le_set_adv_param { + uint16_t min_interval; + uint16_t max_interval; + uint8_t type; + uint8_t own_addr_type; + bt_addr_le_t direct_addr; + uint8_t channel_map; + uint8_t filter_policy; +} __packed; + +#define BT_HCI_OP_LE_READ_ADV_CHAN_TX_POWER BT_OP(BT_OGF_LE, 0x0007) +struct bt_hci_rp_le_read_chan_tx_power { + uint8_t status; + int8_t tx_power_level; +} __packed; + +#define BT_HCI_OP_LE_SET_ADV_DATA BT_OP(BT_OGF_LE, 0x0008) +struct bt_hci_cp_le_set_adv_data { + uint8_t len; + uint8_t data[31]; +} __packed; + +#define BT_HCI_OP_LE_SET_SCAN_RSP_DATA BT_OP(BT_OGF_LE, 0x0009) +struct bt_hci_cp_le_set_scan_rsp_data { + uint8_t len; + uint8_t data[31]; +} __packed; + +#define BT_HCI_LE_ADV_DISABLE 0x00 +#define BT_HCI_LE_ADV_ENABLE 0x01 + +#define BT_HCI_OP_LE_SET_ADV_ENABLE BT_OP(BT_OGF_LE, 0x000a) +struct bt_hci_cp_le_set_adv_enable { + uint8_t enable; +} __packed; + +/* Scan types */ +#define BT_HCI_OP_LE_SET_SCAN_PARAM BT_OP(BT_OGF_LE, 0x000b) +#define BT_HCI_LE_SCAN_PASSIVE 0x00 +#define BT_HCI_LE_SCAN_ACTIVE 0x01 + +#define BT_HCI_LE_SCAN_FP_NO_WHITELIST 0x00 +#define BT_HCI_LE_SCAN_FP_USE_WHITELIST 0x01 + +struct bt_hci_cp_le_set_scan_param { + uint8_t scan_type; + uint16_t interval; + uint16_t window; + uint8_t addr_type; + uint8_t filter_policy; +} __packed; + +#define BT_HCI_OP_LE_SET_SCAN_ENABLE BT_OP(BT_OGF_LE, 0x000c) + +#define BT_HCI_LE_SCAN_DISABLE 0x00 +#define BT_HCI_LE_SCAN_ENABLE 0x01 + +#define BT_HCI_LE_SCAN_FILTER_DUP_DISABLE 0x00 +#define BT_HCI_LE_SCAN_FILTER_DUP_ENABLE 0x01 + +struct bt_hci_cp_le_set_scan_enable { + uint8_t enable; + uint8_t filter_dup; +} __packed; + +#define BT_HCI_OP_LE_CREATE_CONN BT_OP(BT_OGF_LE, 0x000d) + +#define BT_HCI_LE_CREATE_CONN_FP_DIRECT 0x00 +#define BT_HCI_LE_CREATE_CONN_FP_WHITELIST 0x01 + +struct bt_hci_cp_le_create_conn { + uint16_t scan_interval; + uint16_t scan_window; + uint8_t filter_policy; + bt_addr_le_t peer_addr; + uint8_t own_addr_type; + uint16_t conn_interval_min; + uint16_t conn_interval_max; + uint16_t conn_latency; + uint16_t supervision_timeout; + uint16_t min_ce_len; + uint16_t max_ce_len; +} __packed; + +#define BT_HCI_OP_LE_CREATE_CONN_CANCEL BT_OP(BT_OGF_LE, 0x000e) + +#define BT_HCI_OP_LE_READ_WL_SIZE BT_OP(BT_OGF_LE, 0x000f) +struct bt_hci_rp_le_read_wl_size { + uint8_t status; + uint8_t wl_size; +} __packed; + +#define BT_HCI_OP_LE_CLEAR_WL BT_OP(BT_OGF_LE, 0x0010) + +#define BT_HCI_OP_LE_ADD_DEV_TO_WL BT_OP(BT_OGF_LE, 0x0011) +struct bt_hci_cp_le_add_dev_to_wl { + bt_addr_le_t addr; +} __packed; + +#define BT_HCI_OP_LE_REM_DEV_FROM_WL BT_OP(BT_OGF_LE, 0x0012) +struct bt_hci_cp_le_rem_dev_from_wl { + bt_addr_le_t addr; +} __packed; + +#define BT_HCI_OP_LE_CONN_UPDATE BT_OP(BT_OGF_LE, 0x0013) +struct hci_cp_le_conn_update { + uint16_t handle; + uint16_t conn_interval_min; + uint16_t conn_interval_max; + uint16_t conn_latency; + uint16_t supervision_timeout; + uint16_t min_ce_len; + uint16_t max_ce_len; +} __packed; + +#define BT_HCI_OP_LE_SET_HOST_CHAN_CLASSIF BT_OP(BT_OGF_LE, 0x0014) +struct bt_hci_cp_le_set_host_chan_classif { + uint8_t ch_map[5]; +} __packed; + +#define BT_HCI_OP_LE_READ_CHAN_MAP BT_OP(BT_OGF_LE, 0x0015) +struct bt_hci_cp_le_read_chan_map { + uint16_t handle; +} __packed; +struct bt_hci_rp_le_read_chan_map { + uint8_t status; + uint16_t handle; + uint8_t ch_map[5]; +} __packed; + +#define BT_HCI_OP_LE_READ_REMOTE_FEATURES BT_OP(BT_OGF_LE, 0x0016) +struct bt_hci_cp_le_read_remote_features { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_ENCRYPT BT_OP(BT_OGF_LE, 0x0017) +struct bt_hci_cp_le_encrypt { + uint8_t key[16]; + uint8_t plaintext[16]; +} __packed; +struct bt_hci_rp_le_encrypt { + uint8_t status; + uint8_t enc_data[16]; +} __packed; + +#define BT_HCI_OP_LE_RAND BT_OP(BT_OGF_LE, 0x0018) +struct bt_hci_rp_le_rand { + uint8_t status; + uint8_t rand[8]; +} __packed; + +#define BT_HCI_OP_LE_START_ENCRYPTION BT_OP(BT_OGF_LE, 0x0019) +struct bt_hci_cp_le_start_encryption { + uint16_t handle; + uint64_t rand; + uint16_t ediv; + uint8_t ltk[16]; +} __packed; + +#define BT_HCI_OP_LE_LTK_REQ_REPLY BT_OP(BT_OGF_LE, 0x001a) +struct bt_hci_cp_le_ltk_req_reply { + uint16_t handle; + uint8_t ltk[16]; +} __packed; +struct bt_hci_rp_le_ltk_req_reply { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_LTK_REQ_NEG_REPLY BT_OP(BT_OGF_LE, 0x001b) +struct bt_hci_cp_le_ltk_req_neg_reply { + uint16_t handle; +} __packed; +struct bt_hci_rp_le_ltk_req_neg_reply { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_READ_SUPP_STATES BT_OP(BT_OGF_LE, 0x001c) +struct bt_hci_rp_le_read_supp_states { + uint8_t status; + uint8_t le_states[8]; +} __packed; + +#define BT_HCI_OP_LE_RX_TEST BT_OP(BT_OGF_LE, 0x001d) +struct bt_hci_cp_le_rx_test { + uint8_t rx_ch; +} __packed; + +#define BT_HCI_OP_LE_TX_TEST BT_OP(BT_OGF_LE, 0x001e) +struct bt_hci_cp_le_tx_test { + uint8_t tx_ch; + uint8_t test_data_len; + uint8_t pkt_payload; +} __packed; + +#define BT_HCI_OP_LE_TEST_END BT_OP(BT_OGF_LE, 0x001f) +struct bt_hci_rp_le_test_end { + uint8_t status; + uint16_t rx_pkt_count; +} __packed; + +#define BT_HCI_OP_LE_CONN_PARAM_REQ_REPLY BT_OP(BT_OGF_LE, 0x0020) +struct bt_hci_cp_le_conn_param_req_reply { + uint16_t handle; + uint16_t interval_min; + uint16_t interval_max; + uint16_t latency; + uint16_t timeout; + uint16_t min_ce_len; + uint16_t max_ce_len; +} __packed; +struct bt_hci_rp_le_conn_param_req_reply { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_CONN_PARAM_REQ_NEG_REPLY BT_OP(BT_OGF_LE, 0x0021) +struct bt_hci_cp_le_conn_param_req_neg_reply { + uint16_t handle; + uint8_t reason; +} __packed; +struct bt_hci_rp_le_conn_param_req_neg_reply { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_SET_DATA_LEN BT_OP(BT_OGF_LE, 0x0022) +struct bt_hci_cp_le_set_data_len { + uint16_t handle; + uint16_t tx_octets; + uint16_t tx_time; +} __packed; +struct bt_hci_rp_le_set_data_len { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_READ_DEFAULT_DATA_LEN BT_OP(BT_OGF_LE, 0x0023) +struct bt_hci_rp_le_read_default_data_len { + uint8_t status; + uint16_t max_tx_octets; + uint16_t max_tx_time; +} __packed; + +#define BT_HCI_OP_LE_WRITE_DEFAULT_DATA_LEN BT_OP(BT_OGF_LE, 0x0024) +struct bt_hci_cp_le_write_default_data_len { + uint16_t max_tx_octets; + uint16_t max_tx_time; +} __packed; + +#define BT_HCI_OP_LE_P256_PUBLIC_KEY BT_OP(BT_OGF_LE, 0x0025) + +#define BT_HCI_OP_LE_GENERATE_DHKEY BT_OP(BT_OGF_LE, 0x0026) +struct bt_hci_cp_le_generate_dhkey { + uint8_t key[64]; +} __packed; + +#define BT_HCI_OP_LE_ADD_DEV_TO_RL BT_OP(BT_OGF_LE, 0x0027) +struct bt_hci_cp_le_add_dev_to_rl { + bt_addr_le_t peer_id_addr; + uint8_t peer_irk[16]; + uint8_t local_irk[16]; +} __packed; + +#define BT_HCI_OP_LE_REM_DEV_FROM_RL BT_OP(BT_OGF_LE, 0x0028) +struct bt_hci_cp_le_rem_dev_from_rl { + bt_addr_le_t peer_id_addr; +} __packed; + +#define BT_HCI_OP_LE_CLEAR_RL BT_OP(BT_OGF_LE, 0x0029) + +#define BT_HCI_OP_LE_READ_RL_SIZE BT_OP(BT_OGF_LE, 0x002a) +struct bt_hci_rp_le_read_rl_size { + uint8_t status; + uint8_t rl_size; +} __packed; + +#define BT_HCI_OP_LE_READ_PEER_RPA BT_OP(BT_OGF_LE, 0x002b) +struct bt_hci_cp_le_read_peer_rpa { + bt_addr_le_t peer_id_addr; +} __packed; +struct bt_hci_rp_le_read_peer_rpa { + uint8_t status; + bt_addr_t peer_rpa; +} __packed; + +#define BT_HCI_OP_LE_READ_LOCAL_RPA BT_OP(BT_OGF_LE, 0x002c) +struct bt_hci_cp_le_read_local_rpa { + bt_addr_le_t peer_id_addr; +} __packed; +struct bt_hci_rp_le_read_local_rpa { + uint8_t status; + bt_addr_t local_rpa; +} __packed; + +#define BT_HCI_ADDR_RES_DISABLE 0x00 +#define BT_HCI_ADDR_RES_ENABLE 0x01 + +#define BT_HCI_OP_LE_SET_ADDR_RES_ENABLE BT_OP(BT_OGF_LE, 0x002d) +struct bt_hci_cp_le_set_addr_res_enable { + uint8_t enable; +} __packed; + +#define BT_HCI_OP_LE_SET_RPA_TIMEOUT BT_OP(BT_OGF_LE, 0x002e) +struct bt_hci_cp_le_set_rpa_timeout { + uint16_t rpa_timeout; +} __packed; + +#define BT_HCI_OP_LE_READ_MAX_DATA_LEN BT_OP(BT_OGF_LE, 0x002f) +struct bt_hci_rp_le_read_max_data_len { + uint8_t status; + uint16_t max_tx_octets; + uint16_t max_tx_time; + uint16_t max_rx_octets; + uint16_t max_rx_time; +} __packed; + +#define BT_HCI_LE_PHY_1M 0x01 +#define BT_HCI_LE_PHY_2M 0x02 +#define BT_HCI_LE_PHY_CODED 0x03 + +#define BT_HCI_OP_LE_READ_PHY BT_OP(BT_OGF_LE, 0x0030) +struct bt_hci_cp_le_read_phy { + uint16_t handle; +} __packed; +struct bt_hci_rp_le_read_phy { + uint8_t status; + uint16_t handle; + uint8_t tx_phy; + uint8_t rx_phy; +} __packed; + +#define BT_HCI_LE_PHY_TX_ANY BIT(0) +#define BT_HCI_LE_PHY_RX_ANY BIT(1) + +#define BT_HCI_LE_PHY_PREFER_1M BIT(0) +#define BT_HCI_LE_PHY_PREFER_2M BIT(1) +#define BT_HCI_LE_PHY_PREFER_CODED BIT(2) + +#define BT_HCI_OP_LE_SET_DEFAULT_PHY BT_OP(BT_OGF_LE, 0x0031) +struct bt_hci_cp_le_set_default_phy { + uint8_t all_phys; + uint8_t tx_phys; + uint8_t rx_phys; +} __packed; + +#define BT_HCI_LE_PHY_CODED_ANY 0x00 +#define BT_HCI_LE_PHY_CODED_S2 0x01 +#define BT_HCI_LE_PHY_CODED_S8 0x02 + +#define BT_HCI_OP_LE_SET_PHY BT_OP(BT_OGF_LE, 0x0032) +struct bt_hci_cp_le_set_phy { + uint16_t handle; + uint8_t all_phys; + uint8_t tx_phys; + uint8_t rx_phys; + uint16_t phy_opts; +} __packed; + +#define BT_HCI_LE_MOD_INDEX_STANDARD 0x00 +#define BT_HCI_LE_MOD_INDEX_STABLE 0x01 + +#define BT_HCI_OP_LE_ENH_RX_TEST BT_OP(BT_OGF_LE, 0x0033) +struct bt_hci_cp_le_enh_rx_test { + uint8_t rx_ch; + uint8_t phy; + uint8_t mod_index; +} __packed; + +/* Extends BT_HCI_LE_PHY */ +#define BT_HCI_LE_TX_PHY_CODED_S8 0x03 +#define BT_HCI_LE_TX_PHY_CODED_S2 0x04 + +#define BT_HCI_OP_LE_ENH_TX_TEST BT_OP(BT_OGF_LE, 0x0034) +struct bt_hci_cp_le_enh_tx_test { + uint8_t tx_ch; + uint8_t test_data_len; + uint8_t pkt_payload; + uint8_t phy; +} __packed; + +#define BT_HCI_OP_LE_SET_ADV_SET_RANDOM_ADDR BT_OP(BT_OGF_LE, 0x0035) +struct bt_hci_cp_le_set_adv_set_random_addr { + uint8_t handle; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_LE_ADV_PROP_CONN BIT(0) +#define BT_HCI_LE_ADV_PROP_SCAN BIT(1) +#define BT_HCI_LE_ADV_PROP_DIRECT BIT(2) +#define BT_HCI_LE_ADV_PROP_HI_DC_CONN BIT(3) +#define BT_HCI_LE_ADV_PROP_LEGACY BIT(4) +#define BT_HCI_LE_ADV_PROP_ANON BIT(5) +#define BT_HCI_LE_ADV_PROP_TX_POWER BIT(6) + +#define BT_HCI_LE_ADV_SCAN_REQ_ENABLE 1 +#define BT_HCI_LE_ADV_SCAN_REQ_DISABLE 0 + +#define BT_HCI_LE_ADV_TX_POWER_NO_PREF 0x7F + +#define BT_HCI_OP_LE_SET_EXT_ADV_PARAM BT_OP(BT_OGF_LE, 0x0036) +struct bt_hci_cp_le_set_ext_adv_param { + uint8_t handle; + uint16_t props; + uint8_t prim_min_interval[3]; + uint8_t prim_max_interval[3]; + uint8_t prim_channel_map; + uint8_t own_addr_type; + bt_addr_le_t peer_addr; + uint8_t filter_policy; + int8_t tx_power; + uint8_t prim_adv_phy; + uint8_t sec_adv_max_skip; + uint8_t sec_adv_phy; + uint8_t sid; + uint8_t scan_req_notify_enable; +} __packed; +struct bt_hci_rp_le_set_ext_adv_param { + uint8_t status; + int8_t tx_power; +} __packed; + +#define BT_HCI_LE_EXT_ADV_OP_INTERM_FRAG 0x00 +#define BT_HCI_LE_EXT_ADV_OP_FIRST_FRAG 0x01 +#define BT_HCI_LE_EXT_ADV_OP_LAST_FRAG 0x02 +#define BT_HCI_LE_EXT_ADV_OP_COMPLETE_DATA 0x03 +#define BT_HCI_LE_EXT_ADV_OP_UNCHANGED_DATA 0x04 + +#define BT_HCI_LE_EXT_ADV_FRAG_ENABLED 0x00 +#define BT_HCI_LE_EXT_ADV_FRAG_DISABLED 0x01 + +#define BT_HCI_LE_EXT_ADV_FRAG_MAX_LEN 251 + +#define BT_HCI_OP_LE_SET_EXT_ADV_DATA BT_OP(BT_OGF_LE, 0x0037) +struct bt_hci_cp_le_set_ext_adv_data { + uint8_t handle; + uint8_t op; + uint8_t frag_pref; + uint8_t len; + uint8_t data[251]; +} __packed; + +#define BT_HCI_OP_LE_SET_EXT_SCAN_RSP_DATA BT_OP(BT_OGF_LE, 0x0038) +struct bt_hci_cp_le_set_ext_scan_rsp_data { + uint8_t handle; + uint8_t op; + uint8_t frag_pref; + uint8_t len; + uint8_t data[251]; +} __packed; + +#define BT_HCI_OP_LE_SET_EXT_ADV_ENABLE BT_OP(BT_OGF_LE, 0x0039) +struct bt_hci_ext_adv_set { + uint8_t handle; + uint16_t duration; + uint8_t max_ext_adv_evts; +} __packed; + +struct bt_hci_cp_le_set_ext_adv_enable { + uint8_t enable; + uint8_t set_num; + struct bt_hci_ext_adv_set s[0]; +} __packed; + +#define BT_HCI_OP_LE_READ_MAX_ADV_DATA_LEN BT_OP(BT_OGF_LE, 0x003a) +struct bt_hci_rp_le_read_max_adv_data_len { + uint8_t status; + uint16_t max_adv_data_len; +} __packed; + +#define BT_HCI_OP_LE_READ_NUM_ADV_SETS BT_OP(BT_OGF_LE, 0x003b) +struct bt_hci_rp_le_read_num_adv_sets { + uint8_t status; + uint8_t num_sets; +} __packed; + +#define BT_HCI_OP_LE_REMOVE_ADV_SET BT_OP(BT_OGF_LE, 0x003c) +struct bt_hci_cp_le_remove_adv_set { + uint8_t handle; +} __packed; + +#define BT_HCI_OP_CLEAR_ADV_SETS BT_OP(BT_OGF_LE, 0x003d) + +#define BT_HCI_OP_LE_SET_PER_ADV_PARAM BT_OP(BT_OGF_LE, 0x003e) +struct bt_hci_cp_le_set_per_adv_param { + uint8_t handle; + uint16_t min_interval; + uint16_t max_interval; + uint16_t props; +} __packed; + +#define BT_HCI_OP_LE_SET_PER_ADV_DATA BT_OP(BT_OGF_LE, 0x003f) +struct bt_hci_cp_le_set_per_adv_data { + uint8_t handle; + uint8_t op; + uint8_t len; + uint8_t data[251]; +} __packed; + +#define BT_HCI_OP_LE_SET_PER_ADV_ENABLE BT_OP(BT_OGF_LE, 0x0040) +struct bt_hci_cp_le_set_per_adv_enable { + uint8_t enable; + uint8_t handle; +} __packed; + +#define BT_HCI_OP_LE_SET_EXT_SCAN_PARAM BT_OP(BT_OGF_LE, 0x0041) +struct bt_hci_ext_scan_phy { + uint8_t type; + uint16_t interval; + uint16_t window; +} __packed; + +#define BT_HCI_LE_EXT_SCAN_PHY_1M BIT(0) +#define BT_HCI_LE_EXT_SCAN_PHY_2M BIT(1) +#define BT_HCI_LE_EXT_SCAN_PHY_CODED BIT(2) + +struct bt_hci_cp_le_set_ext_scan_param { + uint8_t own_addr_type; + uint8_t filter_policy; + uint8_t phys; + struct bt_hci_ext_scan_phy p[0]; +} __packed; + +/* Extends BT_HCI_LE_SCAN_FILTER_DUP */ +#define BT_HCI_LE_EXT_SCAN_FILTER_DUP_ENABLE_RESET 0x02 + +#define BT_HCI_OP_LE_SET_EXT_SCAN_ENABLE BT_OP(BT_OGF_LE, 0x0042) +struct bt_hci_cp_le_set_ext_scan_enable { + uint8_t enable; + uint8_t filter_dup; + uint16_t duration; + uint16_t period; +} __packed; + +#define BT_HCI_OP_LE_EXT_CREATE_CONN BT_OP(BT_OGF_LE, 0x0043) +struct bt_hci_ext_conn_phy { + uint16_t scan_interval; + uint16_t scan_window; + uint16_t conn_interval_min; + uint16_t conn_interval_max; + uint16_t conn_latency; + uint16_t supervision_timeout; + uint16_t min_ce_len; + uint16_t max_ce_len; +} __packed; + +struct bt_hci_cp_le_ext_create_conn { + uint8_t filter_policy; + uint8_t own_addr_type; + bt_addr_le_t peer_addr; + uint8_t phys; + struct bt_hci_ext_conn_phy p[0]; +} __packed; + +#define BT_HCI_OP_LE_PER_ADV_CREATE_SYNC BT_OP(BT_OGF_LE, 0x0044) +struct bt_hci_cp_le_per_adv_create_sync { + uint8_t filter_policy; + uint8_t sid; + bt_addr_le_t addr; + uint16_t skip; + uint16_t sync_timeout; + uint8_t unused; +} __packed; + +#define BT_HCI_OP_LE_PER_ADV_CREATE_SYNC_CANCEL BT_OP(BT_OGF_LE, 0x0045) + +#define BT_HCI_OP_LE_PER_ADV_TERMINATE_SYNC BT_OP(BT_OGF_LE, 0x0046) +struct bt_hci_cp_le_per_adv_terminate_sync { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_ADD_DEV_TO_PER_ADV_LIST BT_OP(BT_OGF_LE, 0x0047) +struct bt_hci_cp_le_add_dev_to_per_adv_list { + bt_addr_le_t addr; + uint8_t sid; +} __packed; + +#define BT_HCI_OP_LE_REM_DEV_FROM_PER_ADV_LIST BT_OP(BT_OGF_LE, 0x0048) +struct bt_hci_cp_le_rem_dev_from_per_adv_list { + bt_addr_le_t addr; + uint8_t sid; +} __packed; + +#define BT_HCI_OP_LE_CLEAR_PER_ADV_LIST BT_OP(BT_OGF_LE, 0x0049) + +#define BT_HCI_OP_LE_READ_PER_ADV_LIST_SIZE BT_OP(BT_OGF_LE, 0x004a) +struct bt_hci_rp_le_read_per_adv_list_size { + uint8_t status; + uint8_t list_size; +} __packed; + +#define BT_HCI_OP_LE_READ_TX_POWER BT_OP(BT_OGF_LE, 0x004b) +struct bt_hci_rp_le_read_tx_power { + uint8_t status; + int8_t min_tx_power; + int8_t max_tx_power; +} __packed; + +#define BT_HCI_OP_LE_READ_RF_PATH_COMP BT_OP(BT_OGF_LE, 0x004c) +struct bt_hci_rp_le_read_rf_path_comp { + uint8_t status; + int16_t tx_path_comp; + int16_t rx_path_comp; +} __packed; + +#define BT_HCI_OP_LE_WRITE_RF_PATH_COMP BT_OP(BT_OGF_LE, 0x004d) +struct bt_hci_cp_le_write_rf_path_comp { + int16_t tx_path_comp; + int16_t rx_path_comp; +} __packed; + +#define BT_HCI_LE_PRIVACY_MODE_NETWORK 0x00 +#define BT_HCI_LE_PRIVACY_MODE_DEVICE 0x01 + +#define BT_HCI_OP_LE_SET_PRIVACY_MODE BT_OP(BT_OGF_LE, 0x004e) +struct bt_hci_cp_le_set_privacy_mode { + bt_addr_le_t id_addr; + uint8_t mode; +} __packed; + +/* Event definitions */ + +#define BT_HCI_EVT_UNKNOWN 0x00 +#define BT_HCI_EVT_VENDOR 0xff + +#define BT_HCI_EVT_INQUIRY_COMPLETE 0x01 +struct bt_hci_evt_inquiry_complete { + uint8_t status; +} __packed; + +#define BT_HCI_EVT_CONN_COMPLETE 0x03 +struct bt_hci_evt_conn_complete { + uint8_t status; + uint16_t handle; + bt_addr_t bdaddr; + uint8_t link_type; + uint8_t encr_enabled; +} __packed; + +#define BT_HCI_EVT_CONN_REQUEST 0x04 +struct bt_hci_evt_conn_request { + bt_addr_t bdaddr; + uint8_t dev_class[3]; + uint8_t link_type; +} __packed; + +#define BT_HCI_EVT_DISCONN_COMPLETE 0x05 +struct bt_hci_evt_disconn_complete { + uint8_t status; + uint16_t handle; + uint8_t reason; +} __packed; + +#define BT_HCI_EVT_AUTH_COMPLETE 0x06 +struct bt_hci_evt_auth_complete { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_EVT_REMOTE_NAME_REQ_COMPLETE 0x07 +struct bt_hci_evt_remote_name_req_complete { + uint8_t status; + bt_addr_t bdaddr; + uint8_t name[248]; +} __packed; + +#define BT_HCI_EVT_ENCRYPT_CHANGE 0x08 +struct bt_hci_evt_encrypt_change { + uint8_t status; + uint16_t handle; + uint8_t encrypt; +} __packed; + +#define BT_HCI_EVT_REMOTE_FEATURES 0x0b +struct bt_hci_evt_remote_features { + uint8_t status; + uint16_t handle; + uint8_t features[8]; +} __packed; + +#define BT_HCI_EVT_REMOTE_VERSION_INFO 0x0c +struct bt_hci_evt_remote_version_info { + uint8_t status; + uint16_t handle; + uint8_t version; + uint16_t manufacturer; + uint16_t subversion; +} __packed; + +#define BT_HCI_EVT_CMD_COMPLETE 0x0e +struct bt_hci_evt_cmd_complete { + uint8_t ncmd; + uint16_t opcode; +} __packed; + +struct bt_hci_evt_cc_status { + uint8_t status; +} __packed; + +#define BT_HCI_EVT_CMD_STATUS 0x0f +struct bt_hci_evt_cmd_status { + uint8_t status; + uint8_t ncmd; + uint16_t opcode; +} __packed; + +#define BT_HCI_EVT_ROLE_CHANGE 0x12 +struct bt_hci_evt_role_change { + uint8_t status; + bt_addr_t bdaddr; + uint8_t role; +} __packed; + +#define BT_HCI_EVT_NUM_COMPLETED_PACKETS 0x13 +struct bt_hci_evt_num_completed_packets { + uint8_t num_handles; + struct bt_hci_handle_count h[0]; +} __packed; + +#define BT_HCI_EVT_PIN_CODE_REQ 0x16 +struct bt_hci_evt_pin_code_req { + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_EVT_LINK_KEY_REQ 0x17 +struct bt_hci_evt_link_key_req { + bt_addr_t bdaddr; +} __packed; + +/* Link Key types */ +#define BT_LK_COMBINATION 0x00 +#define BT_LK_LOCAL_UNIT 0x01 +#define BT_LK_REMOTE_UNIT 0x02 +#define BT_LK_DEBUG_COMBINATION 0x03 +#define BT_LK_UNAUTH_COMBINATION_P192 0x04 +#define BT_LK_AUTH_COMBINATION_P192 0x05 +#define BT_LK_CHANGED_COMBINATION 0x06 +#define BT_LK_UNAUTH_COMBINATION_P256 0x07 +#define BT_LK_AUTH_COMBINATION_P256 0x08 + +#define BT_HCI_EVT_LINK_KEY_NOTIFY 0x18 +struct bt_hci_evt_link_key_notify { + bt_addr_t bdaddr; + uint8_t link_key[16]; + uint8_t key_type; +} __packed; + +/* Overflow link types */ +#define BT_OVERFLOW_LINK_SYNCH 0x00 +#define BT_OVERFLOW_LINK_ACL 0x01 + +#define BT_HCI_EVT_DATA_BUF_OVERFLOW 0x1a +struct bt_hci_evt_data_buf_overflow { + uint8_t link_type; +} __packed; + +#define BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI 0x22 +struct bt_hci_evt_inquiry_result_with_rssi { + bt_addr_t addr; + uint8_t pscan_rep_mode; + uint8_t reserved; + uint8_t cod[3]; + uint16_t clock_offset; + int8_t rssi; +} __packed; + +#define BT_HCI_EVT_REMOTE_EXT_FEATURES 0x23 +struct bt_hci_evt_remote_ext_features { + uint8_t status; + uint16_t handle; + uint8_t page; + uint8_t max_page; + uint8_t features[8]; +} __packed; + +#define BT_HCI_EVT_SYNC_CONN_COMPLETE 0x2c +struct bt_hci_evt_sync_conn_complete { + uint8_t status; + uint16_t handle; + bt_addr_t bdaddr; + uint8_t link_type; + uint8_t tx_interval; + uint8_t retansmission_window; + uint16_t rx_pkt_length; + uint16_t tx_pkt_length; + uint8_t air_mode; +} __packed; + +#define BT_HCI_EVT_EXTENDED_INQUIRY_RESULT 0x2f +struct bt_hci_evt_extended_inquiry_result { + uint8_t num_reports; + bt_addr_t addr; + uint8_t pscan_rep_mode; + uint8_t reserved; + uint8_t cod[3]; + uint16_t clock_offset; + int8_t rssi; + uint8_t eir[240]; +} __packed; + +#define BT_HCI_EVT_ENCRYPT_KEY_REFRESH_COMPLETE 0x30 +struct bt_hci_evt_encrypt_key_refresh_complete { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_EVT_IO_CAPA_REQ 0x31 +struct bt_hci_evt_io_capa_req { + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_EVT_IO_CAPA_RESP 0x32 +struct bt_hci_evt_io_capa_resp { + bt_addr_t bdaddr; + uint8_t capability; + uint8_t oob_data; + uint8_t authentication; +} __packed; + +#define BT_HCI_EVT_USER_CONFIRM_REQ 0x33 +struct bt_hci_evt_user_confirm_req { + bt_addr_t bdaddr; + uint32_t passkey; +} __packed; + +#define BT_HCI_EVT_USER_PASSKEY_REQ 0x34 +struct bt_hci_evt_user_passkey_req { + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_EVT_SSP_COMPLETE 0x36 +struct bt_hci_evt_ssp_complete { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_EVT_USER_PASSKEY_NOTIFY 0x3b +struct bt_hci_evt_user_passkey_notify { + bt_addr_t bdaddr; + uint32_t passkey; +} __packed; + +#define BT_HCI_EVT_LE_META_EVENT 0x3e +struct bt_hci_evt_le_meta_event { + uint8_t subevent; +} __packed; + +#define BT_HCI_EVT_AUTH_PAYLOAD_TIMEOUT_EXP 0x57 +struct bt_hci_evt_auth_payload_timeout_exp { + uint16_t handle; +} __packed; + +#define BT_HCI_ROLE_MASTER 0x00 +#define BT_HCI_ROLE_SLAVE 0x01 + +#define BT_HCI_EVT_LE_CONN_COMPLETE 0x01 +struct bt_hci_evt_le_conn_complete { + uint8_t status; + uint16_t handle; + uint8_t role; + bt_addr_le_t peer_addr; + uint16_t interval; + uint16_t latency; + uint16_t supv_timeout; + uint8_t clock_accuracy; +} __packed; + +#define BT_HCI_EVT_LE_ADVERTISING_REPORT 0x02 +struct bt_hci_evt_le_advertising_info { + uint8_t evt_type; + bt_addr_le_t addr; + uint8_t length; + uint8_t data[0]; +} __packed; +struct bt_hci_evt_le_advertising_report { + uint8_t num_reports; + struct bt_hci_evt_le_advertising_info adv_info[0]; +} __packed; + +#define BT_HCI_EVT_LE_CONN_UPDATE_COMPLETE 0x03 +struct bt_hci_evt_le_conn_update_complete { + uint8_t status; + uint16_t handle; + uint16_t interval; + uint16_t latency; + uint16_t supv_timeout; +} __packed; + +#define BT_HCI_EV_LE_REMOTE_FEAT_COMPLETE 0x04 +struct bt_hci_evt_le_remote_feat_complete { + uint8_t status; + uint16_t handle; + uint8_t features[8]; +} __packed; + +#define BT_HCI_EVT_LE_LTK_REQUEST 0x05 +struct bt_hci_evt_le_ltk_request { + uint16_t handle; + uint64_t rand; + uint16_t ediv; +} __packed; + +#define BT_HCI_EVT_LE_CONN_PARAM_REQ 0x06 +struct bt_hci_evt_le_conn_param_req { + uint16_t handle; + uint16_t interval_min; + uint16_t interval_max; + uint16_t latency; + uint16_t timeout; +} __packed; + +#define BT_HCI_EVT_LE_DATA_LEN_CHANGE 0x07 +struct bt_hci_evt_le_data_len_change { + uint16_t handle; + uint16_t max_tx_octets; + uint16_t max_tx_time; + uint16_t max_rx_octets; + uint16_t max_rx_time; +} __packed; + +#define BT_HCI_EVT_LE_P256_PUBLIC_KEY_COMPLETE 0x08 +struct bt_hci_evt_le_p256_public_key_complete { + uint8_t status; + uint8_t key[64]; +} __packed; + +#define BT_HCI_EVT_LE_GENERATE_DHKEY_COMPLETE 0x09 +struct bt_hci_evt_le_generate_dhkey_complete { + uint8_t status; + uint8_t dhkey[32]; +} __packed; + +#define BT_HCI_EVT_LE_ENH_CONN_COMPLETE 0x0a +struct bt_hci_evt_le_enh_conn_complete { + uint8_t status; + uint16_t handle; + uint8_t role; + bt_addr_le_t peer_addr; + bt_addr_t local_rpa; + bt_addr_t peer_rpa; + uint16_t interval; + uint16_t latency; + uint16_t supv_timeout; + uint8_t clock_accuracy; +} __packed; + +#define BT_HCI_EVT_LE_DIRECT_ADV_REPORT 0x0b +struct bt_hci_evt_le_direct_adv_info { + uint8_t evt_type; + bt_addr_le_t addr; + bt_addr_le_t dir_addr; + int8_t rssi; +} __packed; +struct bt_hci_evt_le_direct_adv_report { + uint8_t num_reports; + struct bt_hci_evt_le_direct_adv_info direct_adv_info[0]; +} __packed; + +#define BT_HCI_EVT_LE_PHY_UPDATE_COMPLETE 0x0c +struct bt_hci_evt_le_phy_update_complete { + uint8_t status; + uint16_t handle; + uint8_t tx_phy; + uint8_t rx_phy; +} __packed; + +#define BT_HCI_EVT_LE_EXT_ADVERTISING_REPORT 0x0d + +#define BT_HCI_LE_ADV_EVT_TYPE_CONN BIT(0) +#define BT_HCI_LE_ADV_EVT_TYPE_SCAN BIT(1) +#define BT_HCI_LE_ADV_EVT_TYPE_DIRECT BIT(2) +#define BT_HCI_LE_ADV_EVT_TYPE_SCAN_RSP BIT(3) +#define BT_HCI_LE_ADV_EVT_TYPE_LEGACY BIT(4) + +#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS(ev_type) (((ev_type) >> 5) & 0x03) +#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_COMPLETE 0 +#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_PARTIAL 1 +#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_INCOMPLETE 2 + +struct bt_hci_evt_le_ext_advertising_info { + uint16_t evt_type; + bt_addr_le_t addr; + uint8_t prim_phy; + uint8_t sec_phy; + uint8_t sid; + int8_t tx_power; + int8_t rssi; + uint16_t interval; + bt_addr_le_t direct_addr; + uint8_t length; + uint8_t data[0]; +} __packed; +struct bt_hci_evt_le_ext_advertising_report { + uint8_t num_reports; + struct bt_hci_evt_le_ext_advertising_info adv_info[0]; +} __packed; + +#define BT_HCI_EVT_LE_PER_ADV_SYNC_ESTABLISHED 0x0e +struct bt_hci_evt_le_per_adv_sync_established { + uint8_t status; + uint16_t handle; + uint8_t sid; + bt_addr_le_t adv_addr; + uint8_t phy; + uint16_t interval; + uint8_t clock_accuracy; +} __packed; + +#define BT_HCI_EVT_LE_PER_ADVERTISING_REPORT 0x0f +struct bt_hci_evt_le_per_advertising_report { + uint16_t handle; + int8_t tx_power; + int8_t rssi; + uint8_t unused; + uint8_t data_status; + uint8_t length; + uint8_t data[0]; +} __packed; + +#define BT_HCI_EVT_LE_PER_ADV_SYNC_LOST 0x10 +struct bt_hci_evt_le_per_adv_sync_lost { + uint16_t handle; +} __packed; + +#define BT_HCI_EVT_LE_SCAN_TIMEOUT 0x11 + +#define BT_HCI_EVT_LE_ADV_SET_TERMINATED 0x12 +struct bt_hci_evt_le_adv_set_terminated { + uint8_t status; + uint8_t adv_handle; + uint16_t conn_handle; + uint8_t num_completed_ext_adv_evts; +} __packed; + +#define BT_HCI_EVT_LE_SCAN_REQ_RECEIVED 0x13 +struct bt_hci_evt_le_scan_req_received { + uint8_t handle; + bt_addr_le_t addr; +} __packed; + +#define BT_HCI_LE_CHAN_SEL_ALGO_1 0x00 +#define BT_HCI_LE_CHAN_SEL_ALGO_2 0x01 + +#define BT_HCI_EVT_LE_CHAN_SEL_ALGO 0x14 +struct bt_hci_evt_le_chan_sel_algo { + uint16_t handle; + uint8_t chan_sel_algo; +} __packed; + +/* Event mask bits */ + +#define BT_EVT_BIT(n) (1ULL << (n)) + +#define BT_EVT_MASK_INQUIRY_COMPLETE BT_EVT_BIT(0) +#define BT_EVT_MASK_CONN_COMPLETE BT_EVT_BIT(2) +#define BT_EVT_MASK_CONN_REQUEST BT_EVT_BIT(3) +#define BT_EVT_MASK_DISCONN_COMPLETE BT_EVT_BIT(4) +#define BT_EVT_MASK_AUTH_COMPLETE BT_EVT_BIT(5) +#define BT_EVT_MASK_REMOTE_NAME_REQ_COMPLETE BT_EVT_BIT(6) +#define BT_EVT_MASK_ENCRYPT_CHANGE BT_EVT_BIT(7) +#define BT_EVT_MASK_REMOTE_FEATURES BT_EVT_BIT(10) +#define BT_EVT_MASK_REMOTE_VERSION_INFO BT_EVT_BIT(11) +#define BT_EVT_MASK_HARDWARE_ERROR BT_EVT_BIT(15) +#define BT_EVT_MASK_ROLE_CHANGE BT_EVT_BIT(17) +#define BT_EVT_MASK_PIN_CODE_REQ BT_EVT_BIT(21) +#define BT_EVT_MASK_LINK_KEY_REQ BT_EVT_BIT(22) +#define BT_EVT_MASK_LINK_KEY_NOTIFY BT_EVT_BIT(23) +#define BT_EVT_MASK_DATA_BUFFER_OVERFLOW BT_EVT_BIT(25) +#define BT_EVT_MASK_INQUIRY_RESULT_WITH_RSSI BT_EVT_BIT(33) +#define BT_EVT_MASK_REMOTE_EXT_FEATURES BT_EVT_BIT(34) +#define BT_EVT_MASK_SYNC_CONN_COMPLETE BT_EVT_BIT(43) +#define BT_EVT_MASK_EXTENDED_INQUIRY_RESULT BT_EVT_BIT(46) +#define BT_EVT_MASK_ENCRYPT_KEY_REFRESH_COMPLETE BT_EVT_BIT(47) +#define BT_EVT_MASK_IO_CAPA_REQ BT_EVT_BIT(48) +#define BT_EVT_MASK_IO_CAPA_RESP BT_EVT_BIT(49) +#define BT_EVT_MASK_USER_CONFIRM_REQ BT_EVT_BIT(50) +#define BT_EVT_MASK_USER_PASSKEY_REQ BT_EVT_BIT(51) +#define BT_EVT_MASK_SSP_COMPLETE BT_EVT_BIT(53) +#define BT_EVT_MASK_USER_PASSKEY_NOTIFY BT_EVT_BIT(58) +#define BT_EVT_MASK_LE_META_EVENT BT_EVT_BIT(61) + +/* Page 2 */ +#define BT_EVT_MASK_PHY_LINK_COMPLETE BT_EVT_BIT(0) +#define BT_EVT_MASK_CH_SELECTED_COMPLETE BT_EVT_BIT(1) +#define BT_EVT_MASK_DISCONN_PHY_LINK_COMPLETE BT_EVT_BIT(2) +#define BT_EVT_MASK_PHY_LINK_LOSS_EARLY_WARN BT_EVT_BIT(3) +#define BT_EVT_MASK_PHY_LINK_RECOVERY BT_EVT_BIT(4) +#define BT_EVT_MASK_LOG_LINK_COMPLETE BT_EVT_BIT(5) +#define BT_EVT_MASK_DISCONN_LOG_LINK_COMPLETE BT_EVT_BIT(6) +#define BT_EVT_MASK_FLOW_SPEC_MODIFY_COMPLETE BT_EVT_BIT(7) +#define BT_EVT_MASK_NUM_COMPLETE_DATA_BLOCKS BT_EVT_BIT(8) +#define BT_EVT_MASK_AMP_START_TEST BT_EVT_BIT(9) +#define BT_EVT_MASK_AMP_TEST_END BT_EVT_BIT(10) +#define BT_EVT_MASK_AMP_RX_REPORT BT_EVT_BIT(11) +#define BT_EVT_MASK_AMP_SR_MODE_CHANGE_COMPLETE BT_EVT_BIT(12) +#define BT_EVT_MASK_AMP_STATUS_CHANGE BT_EVT_BIT(13) +#define BT_EVT_MASK_TRIGG_CLOCK_CAPTURE BT_EVT_BIT(14) +#define BT_EVT_MASK_SYNCH_TRAIN_COMPLETE BT_EVT_BIT(15) +#define BT_EVT_MASK_SYNCH_TRAIN_RX BT_EVT_BIT(16) +#define BT_EVT_MASK_CL_SLAVE_BC_RX BT_EVT_BIT(17) +#define BT_EVT_MASK_CL_SLAVE_BC_TIMEOUT BT_EVT_BIT(18) +#define BT_EVT_MASK_TRUNC_PAGE_COMPLETE BT_EVT_BIT(19) +#define BT_EVT_MASK_SLAVE_PAGE_RSP_TIMEOUT BT_EVT_BIT(20) +#define BT_EVT_MASK_CL_SLAVE_BC_CH_MAP_CHANGE BT_EVT_BIT(21) +#define BT_EVT_MASK_INQUIRY_RSP_NOT BT_EVT_BIT(22) +#define BT_EVT_MASK_AUTH_PAYLOAD_TIMEOUT_EXP BT_EVT_BIT(23) +#define BT_EVT_MASK_SAM_STATUS_CHANGE BT_EVT_BIT(24) + +#define BT_EVT_MASK_LE_CONN_COMPLETE BT_EVT_BIT(0) +#define BT_EVT_MASK_LE_ADVERTISING_REPORT BT_EVT_BIT(1) +#define BT_EVT_MASK_LE_CONN_UPDATE_COMPLETE BT_EVT_BIT(2) +#define BT_EVT_MASK_LE_REMOTE_FEAT_COMPLETE BT_EVT_BIT(3) +#define BT_EVT_MASK_LE_LTK_REQUEST BT_EVT_BIT(4) +#define BT_EVT_MASK_LE_CONN_PARAM_REQ BT_EVT_BIT(5) +#define BT_EVT_MASK_LE_DATA_LEN_CHANGE BT_EVT_BIT(6) +#define BT_EVT_MASK_LE_P256_PUBLIC_KEY_COMPLETE BT_EVT_BIT(7) +#define BT_EVT_MASK_LE_GENERATE_DHKEY_COMPLETE BT_EVT_BIT(8) +#define BT_EVT_MASK_LE_ENH_CONN_COMPLETE BT_EVT_BIT(9) +#define BT_EVT_MASK_LE_DIRECT_ADV_REPORT BT_EVT_BIT(10) +#define BT_EVT_MASK_LE_PHY_UPDATE_COMPLETE BT_EVT_BIT(11) +#define BT_EVT_MASK_LE_EXT_ADVERTISING_REPORT BT_EVT_BIT(12) +#define BT_EVT_MASK_LE_PER_ADV_SYNC_ESTABLISHED BT_EVT_BIT(13) +#define BT_EVT_MASK_LE_PER_ADVERTISING_REPORT BT_EVT_BIT(14) +#define BT_EVT_MASK_LE_PER_ADV_SYNC_LOST BT_EVT_BIT(15) +#define BT_EVT_MASK_LE_SCAN_TIMEOUT BT_EVT_BIT(16) +#define BT_EVT_MASK_LE_ADV_SET_TERMINATED BT_EVT_BIT(17) +#define BT_EVT_MASK_LE_SCAN_REQ_RECEIVED BT_EVT_BIT(18) +#define BT_EVT_MASK_LE_CHAN_SEL_ALGO BT_EVT_BIT(19) + +// + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_HCI_H_ */ diff --git a/devices/ble_hci/common-hal/_bleio/hci_include/hci_err.h b/devices/ble_hci/common-hal/_bleio/hci_include/hci_err.h new file mode 100644 index 000000000..476d3f463 --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/hci_include/hci_err.h @@ -0,0 +1,92 @@ +/** @file + * @brief Bluetooth Host Control Interface status codes. + */ + +/* + * Copyright (c) 2019 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_HCI_STATUS_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_HCI_STATUS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** HCI Error Codes, BT Core Spec v5.2 [Vol 1, Part F]. */ +#define BT_HCI_ERR_SUCCESS 0x00 +#define BT_HCI_ERR_UNKNOWN_CMD 0x01 +#define BT_HCI_ERR_UNKNOWN_CONN_ID 0x02 +#define BT_HCI_ERR_HW_FAILURE 0x03 +#define BT_HCI_ERR_PAGE_TIMEOUT 0x04 +#define BT_HCI_ERR_AUTH_FAIL 0x05 +#define BT_HCI_ERR_PIN_OR_KEY_MISSING 0x06 +#define BT_HCI_ERR_MEM_CAPACITY_EXCEEDED 0x07 +#define BT_HCI_ERR_CONN_TIMEOUT 0x08 +#define BT_HCI_ERR_CONN_LIMIT_EXCEEDED 0x09 +#define BT_HCI_ERR_SYNC_CONN_LIMIT_EXCEEDED 0x0a +#define BT_HCI_ERR_CONN_ALREADY_EXISTS 0x0b +#define BT_HCI_ERR_CMD_DISALLOWED 0x0c +#define BT_HCI_ERR_INSUFFICIENT_RESOURCES 0x0d +#define BT_HCI_ERR_INSUFFICIENT_SECURITY 0x0e +#define BT_HCI_ERR_BD_ADDR_UNACCEPTABLE 0x0f +#define BT_HCI_ERR_CONN_ACCEPT_TIMEOUT 0x10 +#define BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL 0x11 +#define BT_HCI_ERR_INVALID_PARAM 0x12 +#define BT_HCI_ERR_REMOTE_USER_TERM_CONN 0x13 +#define BT_HCI_ERR_REMOTE_LOW_RESOURCES 0x14 +#define BT_HCI_ERR_REMOTE_POWER_OFF 0x15 +#define BT_HCI_ERR_LOCALHOST_TERM_CONN 0x16 +#define BT_HCI_ERR_REPEATED_ATTEMPTS 0x17 +#define BT_HCI_ERR_PAIRING_NOT_ALLOWED 0x18 +#define BT_HCI_ERR_UNKNOWN_LMP_PDU 0x19 +#define BT_HCI_ERR_UNSUPP_REMOTE_FEATURE 0x1a +#define BT_HCI_ERR_SCO_OFFSET_REJECTED 0x1b +#define BT_HCI_ERR_SCO_INTERVAL_REJECTED 0x1c +#define BT_HCI_ERR_SCO_AIR_MODE_REJECTED 0x1d +#define BT_HCI_ERR_INVALID_LL_PARAM 0x1e +#define BT_HCI_ERR_UNSPECIFIED 0x1f +#define BT_HCI_ERR_UNSUPP_LL_PARAM_VAL 0x20 +#define BT_HCI_ERR_ROLE_CHANGE_NOT_ALLOWED 0x21 +#define BT_HCI_ERR_LL_RESP_TIMEOUT 0x22 +#define BT_HCI_ERR_LL_PROC_COLLISION 0x23 +#define BT_HCI_ERR_LMP_PDU_NOT_ALLOWED 0x24 +#define BT_HCI_ERR_ENC_MODE_NOT_ACCEPTABLE 0x25 +#define BT_HCI_ERR_LINK_KEY_CANNOT_BE_CHANGED 0x26 +#define BT_HCI_ERR_REQUESTED_QOS_NOT_SUPPORTED 0x27 +#define BT_HCI_ERR_INSTANT_PASSED 0x28 +#define BT_HCI_ERR_PAIRING_NOT_SUPPORTED 0x29 +#define BT_HCI_ERR_DIFF_TRANS_COLLISION 0x2a +#define BT_HCI_ERR_QOS_UNACCEPTABLE_PARAM 0x2c +#define BT_HCI_ERR_QOS_REJECTED 0x2d +#define BT_HCI_ERR_CHAN_ASSESS_NOT_SUPPORTED 0x2e +#define BT_HCI_ERR_INSUFF_SECURITY 0x2f +#define BT_HCI_ERR_PARAM_OUT_OF_MANDATORY_RANGE 0x30 +#define BT_HCI_ERR_ROLE_SWITCH_PENDING 0x32 +#define BT_HCI_ERR_RESERVED_SLOT_VIOLATION 0x34 +#define BT_HCI_ERR_ROLE_SWITCH_FAILED 0x35 +#define BT_HCI_ERR_EXT_INQ_RESP_TOO_LARGE 0x36 +#define BT_HCI_ERR_SIMPLE_PAIR_NOT_SUPP_BY_HOST 0x37 +#define BT_HCI_ERR_HOST_BUSY_PAIRING 0x38 +#define BT_HCI_ERR_CONN_REJECTED_DUE_TO_NO_CHAN 0x39 +#define BT_HCI_ERR_CONTROLLER_BUSY 0x3a +#define BT_HCI_ERR_UNACCEPT_CONN_PARAM 0x3b +#define BT_HCI_ERR_ADV_TIMEOUT 0x3c +#define BT_HCI_ERR_TERM_DUE_TO_MIC_FAIL 0x3d +#define BT_HCI_ERR_CONN_FAIL_TO_ESTAB 0x3e +#define BT_HCI_ERR_MAC_CONN_FAILED 0x3f +#define BT_HCI_ERR_CLOCK_ADJUST_REJECTED 0x40 +#define BT_HCI_ERR_SUBMAP_NOT_DEFINED 0x41 +#define BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER 0x42 +#define BT_HCI_ERR_LIMIT_REACHED 0x43 +#define BT_HCI_ERR_OP_CANCELLED_BY_HOST 0x44 +#define BT_HCI_ERR_PACKET_TOO_LONG 0x45 + +#define BT_HCI_ERR_AUTHENTICATION_FAIL __DEPRECATED_MACRO BT_HCI_ERR_AUTH_FAIL + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_HCI_STATUS_H_ */ diff --git a/devices/ble_hci/common-hal/_bleio/hci_include/hci_raw.h b/devices/ble_hci/common-hal/_bleio/hci_include/hci_raw.h new file mode 100644 index 000000000..030fb0ca3 --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/hci_include/hci_raw.h @@ -0,0 +1,152 @@ +/** @file + * @brief Bluetooth HCI RAW channel handling + */ + +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_HCI_RAW_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_HCI_RAW_H_ + +/** + * @brief HCI RAW channel + * @defgroup hci_raw HCI RAW channel + * @ingroup bluetooth + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(CONFIG_BT_CTLR_TX_BUFFER_SIZE) +#define BT_L2CAP_MTU (CONFIG_BT_CTLR_TX_BUFFER_SIZE - BT_L2CAP_HDR_SIZE) +#else +#define BT_L2CAP_MTU 65 /* 64-byte public key + opcode */ +#endif /* CONFIG_BT_CTLR */ + +/** Data size needed for ACL buffers */ +#define BT_BUF_ACL_SIZE BT_L2CAP_BUF_SIZE(BT_L2CAP_MTU) + +#if defined(CONFIG_BT_CTLR_TX_BUFFERS) +#define BT_HCI_ACL_COUNT CONFIG_BT_CTLR_TX_BUFFERS +#else +#define BT_HCI_ACL_COUNT 6 +#endif + +#define BT_BUF_TX_SIZE MAX(BT_BUF_RX_SIZE, BT_BUF_ACL_SIZE) + +/** @brief Send packet to the Bluetooth controller + * + * Send packet to the Bluetooth controller. Caller needs to + * implement netbuf pool. + * + * @param buf netbuf packet to be send + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_send(struct net_buf *buf); + +enum { + /** Passthrough mode + * + * While in this mode the buffers are passed as is between the stack + * and the driver. + */ + BT_HCI_RAW_MODE_PASSTHROUGH = 0x00, + + /** H:4 mode + * + * While in this mode H:4 headers will added into the buffers + * according to the buffer type when coming from the stack and will be + * removed and used to set the buffer type. + */ + BT_HCI_RAW_MODE_H4 = 0x01, +}; + +/** @brief Set Bluetooth RAW channel mode + * + * Set access mode of Bluetooth RAW channel. + * + * @param mode Access mode. + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_hci_raw_set_mode(uint8_t mode); + +/** @brief Get Bluetooth RAW channel mode + * + * Get access mode of Bluetooth RAW channel. + * + * @return Access mode. + */ +uint8_t bt_hci_raw_get_mode(void); + +#define BT_HCI_ERR_EXT_HANDLED 0xff + +/** Helper macro to define a command extension + * + * @param _op Opcode of the command. + * @param _min_len Minimal length of the command. + * @param _func Handler function to be called. + */ +#define BT_HCI_RAW_CMD_EXT(_op, _min_len, _func) \ + { \ + .op = _op, \ + .min_len = _min_len, \ + .func = _func, \ + } + +struct bt_hci_raw_cmd_ext { + /** Opcode of the command */ + uint16_t op; + + /** Minimal length of the command */ + size_t min_len; + + /** Handler function. + * + * Handler function to be called when a command is intercepted. + * + * @param buf Buffer containing the command. + * + * @return HCI Status code or BT_HCI_ERR_EXT_HANDLED if command has + * been handled already and a response has been sent as oppose to + * BT_HCI_ERR_SUCCESS which just indicates that the command can be + * sent to the controller to be processed. + */ + uint8_t (*func)(struct net_buf *buf); +}; + +/** @brief Register Bluetooth RAW command extension table + * + * Register Bluetooth RAW channel command extension table, opcodes in this + * table are intercepted to sent to the handler function. + * + * @param cmds Pointer to the command extension table. + * @param size Size of the command extension table. + */ +void bt_hci_raw_cmd_ext_register(struct bt_hci_raw_cmd_ext *cmds, size_t size); + +/** @brief Enable Bluetooth RAW channel: + * + * Enable Bluetooth RAW HCI channel. + * + * @param rx_queue netbuf queue where HCI packets received from the Bluetooth + * controller are to be queued. The queue is defined in the caller while + * the available buffers pools are handled in the stack. + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_enable_raw(struct k_fifo *rx_queue); + +#ifdef __cplusplus +} +#endif +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_HCI_RAW_H_ */ diff --git a/devices/ble_hci/common-hal/_bleio/hci_include/hci_vs.h b/devices/ble_hci/common-hal/_bleio/hci_include/hci_vs.h new file mode 100644 index 000000000..e4f94b6a8 --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/hci_include/hci_vs.h @@ -0,0 +1,379 @@ +/* hci_vs.h - Bluetooth Host Control Interface Vendor Specific definitions */ + +/* + * Copyright (c) 2017-2018 Nordic Semiconductor ASA + * Copyright (c) 2015-2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_HCI_VS_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_HCI_VS_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define BT_VS_CMD_BIT_VERSION 0 +#define BT_VS_CMD_BIT_SUP_CMD 1 +#define BT_VS_CMD_BIT_SUP_FEAT 2 +#define BT_VS_CMD_BIT_SET_EVT_MASK 3 +#define BT_VS_CMD_BIT_RESET 4 +#define BT_VS_CMD_BIT_WRITE_BDADDR 5 +#define BT_VS_CMD_BIT_SET_TRACE_ENABLE 6 +#define BT_VS_CMD_BIT_READ_BUILD_INFO 7 +#define BT_VS_CMD_BIT_READ_STATIC_ADDRS 8 +#define BT_VS_CMD_BIT_READ_KEY_ROOTS 9 +#define BT_VS_CMD_BIT_READ_CHIP_TEMP 10 +#define BT_VS_CMD_BIT_READ_HOST_STACK_CMD 11 +#define BT_VS_CMD_BIT_SET_SCAN_REP_ENABLE 12 +#define BT_VS_CMD_BIT_WRITE_TX_POWER 13 +#define BT_VS_CMD_BIT_READ_TX_POWER 14 + +#define BT_VS_CMD_SUP_FEAT(cmd) BT_LE_FEAT_TEST(cmd, \ + BT_VS_CMD_BIT_SUP_FEAT) +#define BT_VS_CMD_READ_STATIC_ADDRS(cmd) BT_LE_FEAT_TEST(cmd, \ + BT_VS_CMD_BIT_READ_STATIC_ADDRS) +#define BT_VS_CMD_READ_KEY_ROOTS(cmd) BT_LE_FEAT_TEST(cmd, \ + BT_VS_CMD_BIT_READ_KEY_ROOTS) + +#define BT_HCI_VS_HW_PLAT_INTEL 0x0001 +#define BT_HCI_VS_HW_PLAT_NORDIC 0x0002 +#define BT_HCI_VS_HW_PLAT_NXP 0x0003 + +#define BT_HCI_VS_HW_VAR_NORDIC_NRF51X 0x0001 +#define BT_HCI_VS_HW_VAR_NORDIC_NRF52X 0x0002 +#define BT_HCI_VS_HW_VAR_NORDIC_NRF53X 0x0003 + +#define BT_HCI_VS_FW_VAR_STANDARD_CTLR 0x0001 +#define BT_HCI_VS_FW_VAR_VS_CTLR 0x0002 +#define BT_HCI_VS_FW_VAR_FW_LOADER 0x0003 +#define BT_HCI_VS_FW_VAR_RESCUE_IMG 0x0004 +#define BT_HCI_OP_VS_READ_VERSION_INFO BT_OP(BT_OGF_VS, 0x0001) +struct bt_hci_rp_vs_read_version_info { + uint8_t status; + uint16_t hw_platform; + uint16_t hw_variant; + uint8_t fw_variant; + uint8_t fw_version; + uint16_t fw_revision; + uint32_t fw_build; +} __packed; + +#define BT_HCI_OP_VS_READ_SUPPORTED_COMMANDS BT_OP(BT_OGF_VS, 0x0002) +struct bt_hci_rp_vs_read_supported_commands { + uint8_t status; + uint8_t commands[64]; +} __packed; + +#define BT_HCI_OP_VS_READ_SUPPORTED_FEATURES BT_OP(BT_OGF_VS, 0x0003) +struct bt_hci_rp_vs_read_supported_features { + uint8_t status; + uint8_t features[8]; +} __packed; + +#define BT_HCI_OP_VS_SET_EVENT_MASK BT_OP(BT_OGF_VS, 0x0004) +struct bt_hci_cp_vs_set_event_mask { + uint8_t event_mask[8]; +} __packed; + +#define BT_HCI_VS_RESET_SOFT 0x00 +#define BT_HCI_VS_RESET_HARD 0x01 +#define BT_HCI_OP_VS_RESET BT_OP(BT_OGF_VS, 0x0005) +struct bt_hci_cp_vs_reset { + uint8_t type; +} __packed; + +#define BT_HCI_OP_VS_WRITE_BD_ADDR BT_OP(BT_OGF_VS, 0x0006) +struct bt_hci_cp_vs_write_bd_addr { + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_VS_TRACE_DISABLED 0x00 +#define BT_HCI_VS_TRACE_ENABLED 0x01 + +#define BT_HCI_VS_TRACE_HCI_EVTS 0x00 +#define BT_HCI_VS_TRACE_VDC 0x01 +#define BT_HCI_OP_VS_SET_TRACE_ENABLE BT_OP(BT_OGF_VS, 0x0007) +struct bt_hci_cp_vs_set_trace_enable { + uint8_t enable; + uint8_t type; +} __packed; + +#define BT_HCI_OP_VS_READ_BUILD_INFO BT_OP(BT_OGF_VS, 0x0008) +struct bt_hci_rp_vs_read_build_info { + uint8_t status; + uint8_t info[0]; +} __packed; + +struct bt_hci_vs_static_addr { + bt_addr_t bdaddr; + uint8_t ir[16]; +} __packed; + +#define BT_HCI_OP_VS_READ_STATIC_ADDRS BT_OP(BT_OGF_VS, 0x0009) +struct bt_hci_rp_vs_read_static_addrs { + uint8_t status; + uint8_t num_addrs; + struct bt_hci_vs_static_addr a[0]; +} __packed; + +#define BT_HCI_OP_VS_READ_KEY_HIERARCHY_ROOTS BT_OP(BT_OGF_VS, 0x000a) +struct bt_hci_rp_vs_read_key_hierarchy_roots { + uint8_t status; + uint8_t ir[16]; + uint8_t er[16]; +} __packed; + +#define BT_HCI_OP_VS_READ_CHIP_TEMP BT_OP(BT_OGF_VS, 0x000b) +struct bt_hci_rp_vs_read_chip_temp { + uint8_t status; + int8_t temps; +} __packed; + +struct bt_hci_vs_cmd { + uint16_t vendor_id; + uint16_t opcode_base; +} __packed; + +#define BT_HCI_VS_VID_ANDROID 0x0001 +#define BT_HCI_VS_VID_MICROSOFT 0x0002 +#define BT_HCI_OP_VS_READ_HOST_STACK_CMDS BT_OP(BT_OGF_VS, 0x000c) +struct bt_hci_rp_vs_read_host_stack_cmds { + uint8_t status; + uint8_t num_cmds; + struct bt_hci_vs_cmd c[0]; +} __packed; + +#define BT_HCI_VS_SCAN_REQ_REPORTS_DISABLED 0x00 +#define BT_HCI_VS_SCAN_REQ_REPORTS_ENABLED 0x01 +#define BT_HCI_OP_VS_SET_SCAN_REQ_REPORTS BT_OP(BT_OGF_VS, 0x000d) +struct bt_hci_cp_vs_set_scan_req_reports { + uint8_t enable; +} __packed; + +#define BT_HCI_VS_LL_HANDLE_TYPE_ADV 0x00 +#define BT_HCI_VS_LL_HANDLE_TYPE_SCAN 0x01 +#define BT_HCI_VS_LL_HANDLE_TYPE_CONN 0x02 +#define BT_HCI_VS_LL_TX_POWER_LEVEL_NO_PREF 0x7F +#define BT_HCI_OP_VS_WRITE_TX_POWER_LEVEL BT_OP(BT_OGF_VS, 0x000e) +struct bt_hci_cp_vs_write_tx_power_level { + uint8_t handle_type; + uint16_t handle; + int8_t tx_power_level; +} __packed; + +struct bt_hci_rp_vs_write_tx_power_level { + uint8_t status; + uint8_t handle_type; + uint16_t handle; + int8_t selected_tx_power; +} __packed; + +#define BT_HCI_OP_VS_READ_TX_POWER_LEVEL BT_OP(BT_OGF_VS, 0x000f) +struct bt_hci_cp_vs_read_tx_power_level { + uint8_t handle_type; + uint16_t handle; +} __packed; + +struct bt_hci_rp_vs_read_tx_power_level { + uint8_t status; + uint8_t handle_type; + uint16_t handle; + int8_t tx_power_level; +} __packed; + +#define BT_HCI_OP_VS_READ_USB_TRANSPORT_MODE BT_OP(BT_OGF_VS, 0x0010) + +struct bt_hci_rp_vs_read_usb_transport_mode { + uint8_t status; + uint8_t num_supported_modes; + uint8_t supported_mode[0]; +} __packed; + +#define BT_HCI_VS_USB_H2_MODE 0x00 +#define BT_HCI_VS_USB_H4_MODE 0x01 + +#define BT_HCI_OP_VS_SET_USB_TRANSPORT_MODE BT_OP(BT_OGF_VS, 0x0011) + +struct bt_hci_cp_vs_set_usb_transport_mode { + uint8_t mode; +} __packed; + +/* Events */ + +struct bt_hci_evt_vs { + uint8_t subevent; +} __packed; + +#define BT_HCI_EVT_VS_FATAL_ERROR 0x02 +struct bt_hci_evt_vs_fatal_error { + uint64_t pc; + uint8_t err_info[0]; +} __packed; + +#define BT_HCI_VS_TRACE_LMP_TX 0x01 +#define BT_HCI_VS_TRACE_LMP_RX 0x02 +#define BT_HCI_VS_TRACE_LLCP_TX 0x03 +#define BT_HCI_VS_TRACE_LLCP_RX 0x04 +#define BT_HCI_VS_TRACE_LE_CONN_IND 0x05 +#define BT_HCI_EVT_VS_TRACE_INFO 0x03 +struct bt_hci_evt_vs_trace_info { + uint8_t type; + uint8_t data[0]; +} __packed; + +#define BT_HCI_EVT_VS_SCAN_REQ_RX 0x04 +struct bt_hci_evt_vs_scan_req_rx { + bt_addr_le_t addr; + int8_t rssi; +} __packed; + +/* Event mask bits */ + +#define BT_EVT_MASK_VS_FATAL_ERROR BT_EVT_BIT(1) +#define BT_EVT_MASK_VS_TRACE_INFO BT_EVT_BIT(2) +#define BT_EVT_MASK_VS_SCAN_REQ_RX BT_EVT_BIT(3) + +/* Mesh HCI commands */ +#define BT_HCI_MESH_REVISION 0x01 + +#define BT_HCI_OP_VS_MESH BT_OP(BT_OGF_VS, 0x0042) +#define BT_HCI_MESH_EVT_PREFIX 0xF0 + +struct bt_hci_cp_mesh { + uint8_t opcode; +} __packed; + +#define BT_HCI_OC_MESH_GET_OPTS 0x00 +struct bt_hci_rp_mesh_get_opts { + uint8_t status; + uint8_t opcode; + uint8_t revision; + uint8_t ch_map; + int8_t min_tx_power; + int8_t max_tx_power; + uint8_t max_scan_filter; + uint8_t max_filter_pattern; + uint8_t max_adv_slot; + uint8_t max_tx_window; + uint8_t evt_prefix_len; + uint8_t evt_prefix; +} __packed; + +#define BT_HCI_MESH_PATTERN_LEN_MAX 0x0f + +#define BT_HCI_OC_MESH_SET_SCAN_FILTER 0x01 +struct bt_hci_mesh_pattern { + uint8_t pattern_len; + uint8_t pattern[0]; +} __packed; + +struct bt_hci_cp_mesh_set_scan_filter { + uint8_t scan_filter; + uint8_t filter_dup; + uint8_t num_patterns; + struct bt_hci_mesh_pattern patterns[0]; +} __packed; +struct bt_hci_rp_mesh_set_scan_filter { + uint8_t status; + uint8_t opcode; + uint8_t scan_filter; +} __packed; + +#define BT_HCI_OC_MESH_ADVERTISE 0x02 +struct bt_hci_cp_mesh_advertise { + uint8_t adv_slot; + uint8_t own_addr_type; + bt_addr_t random_addr; + uint8_t ch_map; + int8_t tx_power; + uint8_t min_tx_delay; + uint8_t max_tx_delay; + uint8_t retx_count; + uint8_t retx_interval; + uint8_t scan_delay; + uint16_t scan_duration; + uint8_t scan_filter; + uint8_t data_len; + uint8_t data[31]; +} __packed; +struct bt_hci_rp_mesh_advertise { + uint8_t status; + uint8_t opcode; + uint8_t adv_slot; +} __packed; + +#define BT_HCI_OC_MESH_ADVERTISE_TIMED 0x03 +struct bt_hci_cp_mesh_advertise_timed { + uint8_t adv_slot; + uint8_t own_addr_type; + bt_addr_t random_addr; + uint8_t ch_map; + int8_t tx_power; + uint8_t retx_count; + uint8_t retx_interval; + uint32_t instant; + uint16_t tx_delay; + uint16_t tx_window; + uint8_t data_len; + uint8_t data[31]; +} __packed; +struct bt_hci_rp_mesh_advertise_timed { + uint8_t status; + uint8_t opcode; + uint8_t adv_slot; +} __packed; + +#define BT_HCI_OC_MESH_ADVERTISE_CANCEL 0x04 +struct bt_hci_cp_mesh_advertise_cancel { + uint8_t adv_slot; +} __packed; +struct bt_hci_rp_mesh_advertise_cancel { + uint8_t status; + uint8_t opcode; + uint8_t adv_slot; +} __packed; + +#define BT_HCI_OC_MESH_SET_SCANNING 0x05 +struct bt_hci_cp_mesh_set_scanning { + uint8_t enable; + uint8_t ch_map; + uint8_t scan_filter; +} __packed; +struct bt_hci_rp_mesh_set_scanning { + uint8_t status; + uint8_t opcode; +} __packed; + +/* Events */ +struct bt_hci_evt_mesh { + uint8_t prefix; + uint8_t subevent; +} __packed; + +#define BT_HCI_EVT_MESH_ADV_COMPLETE 0x00 +struct bt_hci_evt_mesh_adv_complete { + uint8_t adv_slot; +} __packed; + +#define BT_HCI_EVT_MESH_SCANNING_REPORT 0x01 +struct bt_hci_evt_mesh_scan_report { + bt_addr_le_t addr; + uint8_t chan; + int8_t rssi; + uint32_t instant; + uint8_t data_len; + uint8_t data[0]; +} __packed; +struct bt_hci_evt_mesh_scanning_report { + uint8_t num_reports; + struct bt_hci_evt_mesh_scan_report reports[0]; +} __packed; + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_HCI_VS_H_ */ diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index b30159c7c..0dd31904f 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -319,7 +319,7 @@ SRC_COMMON_HAL_ALL = \ ifeq ($(CIRCUITPY_BLEIO_HCI),1) SRC_C += \ - common-hal/_bleio/hci.c \ + common-hal/_bleio/hci_api.c \ endif diff --git a/shared-bindings/_bleio/Adapter.c b/shared-bindings/_bleio/Adapter.c index 1b991ac6d..6ad4b7545 100644 --- a/shared-bindings/_bleio/Adapter.c +++ b/shared-bindings/_bleio/Adapter.c @@ -68,52 +68,37 @@ //| Use `_bleio.adapter` to access the sole instance available.""" //| -//| def hci_init(self, *, tx: Pin, rx: Pin, rts: Pin, cts: Pin, baudrate: int = 115200, buffer_size: int = 256): +//| def hci_init(self, *, uart: busio.UART, cts: Pin, baudrate: int = 115200, buffer_size: int = 256): //| On boards that do not have native BLE, you can an use HCI co-processor. -//| Call `_bleio.adapter.hci_init()` passing it the pins used to communicate +//| Call `_bleio.adapter.hci_init()` passing it the uart and pins used to communicate //| with the co-processor, such as an Adafruit AirLift. //| The co-processor must have been reset and put into BLE mode beforehand //| by the appropriate pin manipulation. -//| The `tx`, `rx`, `rts`, and `cs` pins are used to communicate with the HCI co-processor in HCI mode. +//| The `uart` object, and `rts` and `cs` pins are used to +//| communicate with the HCI co-processor in HCI mode. //| mp_obj_t bleio_adapter_hci_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { #if CIRCUITPY_BLEIO_HCI bleio_adapter_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (self->enabled) { - mp_raise_ValueError(translate("HCI Adapter is already enabled")); - } - - enum { ARG_tx, ARG_rx, ARG_rts, ARG_cts, ARG_baudrate, ARG_buffer_size }; + enum { ARG_uart, ARG_rts, ARG_cts }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_tx, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_rx, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_uart, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_rts, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_cts, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 115200 } }, - { MP_QSTR_buffer_size, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 256 } }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - const mcu_pin_obj_t *tx = validate_obj_is_free_pin(args[ARG_tx].u_obj); - const mcu_pin_obj_t *rx = validate_obj_is_free_pin(args[ARG_rx].u_obj); + busio_uart_obj_t *uart = args[ARG_uart].u_obj; + if (!MP_OBJ_IS_TYPE(uart, &busio_uart_type)) { + mp_raise_ValueError(translate("Expected a UART")); + } const mcu_pin_obj_t *rts = validate_obj_is_free_pin(args[ARG_rts].u_obj); const mcu_pin_obj_t *cts = validate_obj_is_free_pin(args[ARG_cts].u_obj); - if (args[ARG_baudrate].u_int <= 0) { - mp_raise_ValueError(translate("baudrate must be > 0")); - } - const uint32_t baudrate = args[ARG_baudrate].u_int; - - if (args[ARG_buffer_size].u_int <= 1) { - mp_raise_ValueError(translate("buffer_size must be >= 1")); - } - const uint32_t buffer_size = args[ARG_buffer_size].u_int; - - common_hal_bleio_adapter_hci_init(&common_hal_bleio_adapter_obj, tx, rx, rts, cts, - baudrate, buffer_size); + common_hal_bleio_adapter_hci_init(self, uart, rts, cts); return mp_const_none; #else @@ -268,7 +253,7 @@ STATIC mp_obj_t bleio_adapter_stop_advertising(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_stop_advertising_obj, bleio_adapter_stop_advertising); -//| def start_scan(self, prefixes: sequence = b"", *, buffer_size: int = 512, extended: bool = False, timeout: float = None, interval: float = 0.1, window: float = 0.1, minimum_rssi: int = -80, active: bool = True) -> Any: +//| def start_scan(self, *, prefixes: sequence = b"", buffer_size: int = 512, extended: bool = False, timeout: float = None, interval: float = 0.1, window: float = 0.1, minimum_rssi: int = -80, active: bool = True) -> Any: //| """Starts a BLE scan and returns an iterator of results. Advertisements and scan responses are //| filtered and returned separately. //| diff --git a/shared-bindings/_bleio/Adapter.h b/shared-bindings/_bleio/Adapter.h index 8fdeb1354..9caca161f 100644 --- a/shared-bindings/_bleio/Adapter.h +++ b/shared-bindings/_bleio/Adapter.h @@ -38,7 +38,7 @@ const mp_obj_type_t bleio_adapter_type; #if CIRCUITPY_BLEIO_HCI -void common_hal_bleio_adapter_hci_init(bleio_adapter_obj_t *self, const mcu_pin_obj_t *tx, const mcu_pin_obj_t *rx, const mcu_pin_obj_t *rts, const mcu_pin_obj_t *cts, uint32_t baudrate, uint32_t buffer_size); +void common_hal_bleio_adapter_hci_init(bleio_adapter_obj_t *self, busio_uart_obj_t *uart, const mcu_pin_obj_t *rts, const mcu_pin_obj_t *cts); #endif // CIRCUITPY_BLEIO_HCI bool common_hal_bleio_adapter_get_advertising(bleio_adapter_obj_t *self); diff --git a/shared-bindings/time/__init__.c b/shared-bindings/time/__init__.c index 531980eff..60a67b216 100644 --- a/shared-bindings/time/__init__.c +++ b/shared-bindings/time/__init__.c @@ -43,8 +43,9 @@ //| way around.""" //| //| def monotonic() -> Any: -//| """Returns an always increasing value of time with an unknown reference -//| point. Only use it to compare against other values from `monotonic`. +//| """Returns an always increasing value of time, in fractional seconds, +//| with an unknown reference point. +//| Only use it to compare against other values from `monotonic`. //| //| :return: the current monotonic time //| :rtype: float""" -- cgit v1.2.3 From f6f45c82a118f59d5d155fbbbe091580ba0dcf31 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 23 Jul 2020 18:54:26 -0400 Subject: wip: ATT protocol --- devices/ble_hci/common-hal/_bleio/Adapter.c | 2 +- devices/ble_hci/common-hal/_bleio/Connection.h | 5 +- devices/ble_hci/common-hal/_bleio/__init__.h | 2 +- devices/ble_hci/common-hal/_bleio/att.c | 1621 ++++++++++++++++++++ devices/ble_hci/common-hal/_bleio/att.h | 57 + devices/ble_hci/common-hal/_bleio/hci.c | 826 ++++++++++ devices/ble_hci/common-hal/_bleio/hci.h | 79 + devices/ble_hci/common-hal/_bleio/hci_api.c | 808 ---------- devices/ble_hci/common-hal/_bleio/hci_api.h | 77 - .../ble_hci/common-hal/_bleio/hci_include/addr.h | 1 + .../ble_hci/common-hal/_bleio/hci_include/att.h | 41 + .../common-hal/_bleio/hci_include/att_internal.h | 266 ++++ .../ble_hci/common-hal/_bleio/hci_include/hci.h | 1 + .../common-hal/_bleio/hci_include/l2cap_internal.h | 230 +++ py/circuitpy_defns.mk | 4 +- py/misc.h | 2 + py/py.mk | 2 +- 17 files changed, 3134 insertions(+), 890 deletions(-) create mode 100644 devices/ble_hci/common-hal/_bleio/att.c create mode 100644 devices/ble_hci/common-hal/_bleio/att.h create mode 100644 devices/ble_hci/common-hal/_bleio/hci.c create mode 100644 devices/ble_hci/common-hal/_bleio/hci.h delete mode 100644 devices/ble_hci/common-hal/_bleio/hci_api.c delete mode 100644 devices/ble_hci/common-hal/_bleio/hci_api.h create mode 100644 devices/ble_hci/common-hal/_bleio/hci_include/att.h create mode 100644 devices/ble_hci/common-hal/_bleio/hci_include/att_internal.h create mode 100644 devices/ble_hci/common-hal/_bleio/hci_include/l2cap_internal.h (limited to 'py') diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index 17b66899a..55e0bde01 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.c +++ b/devices/ble_hci/common-hal/_bleio/Adapter.c @@ -31,7 +31,7 @@ #include #include -#include "hci_api.h" +#include "hci.h" #include "py/gc.h" #include "py/mphal.h" diff --git a/devices/ble_hci/common-hal/_bleio/Connection.h b/devices/ble_hci/common-hal/_bleio/Connection.h index bb0c140c5..8b9790d9e 100644 --- a/devices/ble_hci/common-hal/_bleio/Connection.h +++ b/devices/ble_hci/common-hal/_bleio/Connection.h @@ -64,13 +64,16 @@ typedef struct { //REMOVE ble_gap_conn_params_t conn_params; volatile bool conn_params_updating; uint16_t mtu; - // Request that CCCD values for this conenction be saved, using sys_attr values. + // Request that CCCD values for this connection be saved, using sys_attr values. volatile bool do_bond_cccds; // Request that security key info for this connection be saved. volatile bool do_bond_keys; // Time of setting do_bond_ccds: we delay a bit to consolidate multiple CCCD changes // into one write. Time is currently in ticks_ms. uint64_t do_bond_cccds_request_time; + //FIX from att.c + uint8_t role; + bt_addr_le_t addr; } bleio_connection_internal_t; typedef struct { diff --git a/devices/ble_hci/common-hal/_bleio/__init__.h b/devices/ble_hci/common-hal/_bleio/__init__.h index 0d1c2785f..18b4289e9 100644 --- a/devices/ble_hci/common-hal/_bleio/__init__.h +++ b/devices/ble_hci/common-hal/_bleio/__init__.h @@ -29,7 +29,7 @@ #include -#include "hci_api.h" +#include "hci.h" void bleio_background(void); void bleio_reset(void); diff --git a/devices/ble_hci/common-hal/_bleio/att.c b/devices/ble_hci/common-hal/_bleio/att.c new file mode 100644 index 000000000..d37012a0a --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/att.c @@ -0,0 +1,1621 @@ +// Derived from ArduinoBLE. +// Copyright 2020 Dan Halbert for Adafruit Industries + +/* + This file is part of the ArduinoBLE library. + Copyright (c) 2018 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "hci.h" +#include "att.h" + +// Zephyr include files to define HCI communication values and structs. +//#include "hci_include/hci.h" +//#include "hci_include/hci_err.h" +#include "hci_include/l2cap_internal.h" + +#include "py/obj.h" +#include "common-hal/_bleio/Adapter.h" +#include "supervisor/shared/tick.h" + +enum ble_attribute_type { + BLE_TYPE_UNKNOWN = 0x0000, + BLE_TYPE_PRIMARY_SERVICE = 0x2800, + BLE_TYPE_SECONDARY_SERVICE = 0x2801, + BLE_TYPE_CHARACTERISTIC = 0x2803, + BLE_TYPE_DESCRIPTOR = 0x2900 +}; + +STATIC uint16_t max_mtu = BT_ATT_DEFAULT_LE_MTU; // 23 +STATIC unsigned long timeout = 5000; + +STATIC volatile bool cnf; + +STATIC uint16_t long_write_handle = 0x0000; +STATIC uint8_t* long_write_value = NULL; +STATIC uint16_t long_write_value_length = 0; + +// When we send a request, fill this struct with info about the expected response. +// We check this against the actual received response. +STATIC struct { + uint16_t conn_handle; // Expected handle. + uint8_t opcode; // Expected RSP opcode. + uint8_t* buffer; // Pointer to response packet + uint8_t length; // Length of response packet. +} expected_rsp; + +//FIX BLEDeviceEventHandler event_handlers[2]; + + +STATIC void send_error(uint16_t conn_handle, uint8_t opcode, uint16_t handle, uint8_t code) { + struct __packed { + struct bt_att_hdr h; + struct bt_att_error_rsp r; + } rsp = { { + .code = BT_ATT_OP_ERROR_RSP, + }, { + .request = opcode, + } + }; + + hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, sizeof(rsp), (uint8_t *) &rsp); +} + +STATIC int send_req_wait_for_rsp(uint16_t conn_handle, int request_length, uint8_t* request_buffer, uint8_t response_buffer[]) { + // We expect a particular kind of response after this request. + expected_rsp.conn_handle = conn_handle; + // The response opcode is the request opcode + 1. + expected_rsp.opcode = request_buffer[0] + 1; + expected_rsp.buffer = response_buffer; + expected_rsp.length = 0; + + hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, request_length, request_buffer); + + if (response_buffer == NULL) { + // not expecting a response. + return 0; + } + + for (uint64_t start = supervisor_ticks_ms64(); supervisor_ticks_ms64() - start < timeout;) { + hci_poll_for_incoming_pkt(); + + if (!att_handle_is_connected(conn_handle)) { + break; + } + + if (expected_rsp.length != 0) { + expected_rsp.conn_handle = 0xffff; + return expected_rsp.length; + } + } + + expected_rsp.conn_handle = 0xffff; + return 0; +} + +// If a response matches what is in expected_rsp, copy the rest of it into the buffer. +STATIC void check_and_save_expected_rsp(uint16_t conn_handle, uint8_t opcode, uint8_t dlen, uint8_t data[]) { + if (conn_handle == expected_rsp.conn_handle && expected_rsp.opcode == opcode) { + expected_rsp.buffer[0] = opcode; + memcpy(&expected_rsp.buffer[1], data, dlen); + expected_rsp.length = dlen + 1; + } +} + +void att_init(void) { + max_mtu = BT_ATT_DEFAULT_LE_MTU; + timeout = 5000; + long_write_handle = 0x0000; + long_write_value = NULL; + long_write_value_length = 0; + + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + bleio_connections[i].conn_handle = BLE_CONN_HANDLE_INVALID; + bleio_connections[i].role = 0x00; + bleio_connections[i].addr.type = 0; + memset(bleio_connections[i].addr.a.val, 0, sizeof_field(bt_addr_t, val)); + bleio_connections[i].mtu = BT_ATT_DEFAULT_LE_MTU; + } + + //FIX memset(event_handlers, 0x00, sizeof(event_handlers)); +} + +bool att_connect_to_address(bt_addr_le_t *addr) { + //FIX + if (hci_le_create_conn(0x0060, 0x0030, 0x00, addr, 0x00, + 0x0006, 0x000c, 0x0000, 0x00c8, 0x0004, 0x0006) != 0) { + return false; + } + + bool is_connected = false; + + for (uint64_t start = supervisor_ticks_ms64(); supervisor_ticks_ms64() - start < timeout;) { + hci_poll_for_incoming_pkt(); + + is_connected = att_address_is_connected(addr); + + if (is_connected) { + break; + } + } + + if (!is_connected) { + hci_le_cancel_conn(); + } + + return is_connected; +} + +bool att_disconnect_from_address(bt_addr_le_t *addr) { + uint16_t conn_handle = att_conn_handle(addr); + if (conn_handle == 0xffff) { + return false; + } + + hci_disconnect(conn_handle); + + hci_poll_for_incoming_pkt_timeout(timeout); + + if (!att_handle_is_connected(conn_handle)) { + return true; + } + + return false; +} + +//FIX +// STATIC bool discover_services(uint16_t conn_handle, BLERemoteDevice* device, const char* serviceUuidFilter) { +// uint16_t reqStart_handle = 0x0001; +// uint16_t reqEnd_handle = 0xffff; + +// uint8_t response_buffer[max_mtu]; + +// BLEUuid serviceUuid(serviceUuidFilter); + +// while (reqEnd_handle == 0xffff) { +// int respLength = readByGroupReq(conn_handle, reqStart_handle, reqEnd_handle, BLE_TYPE_PRIMARY_SERVICE, response_buffer); + +// if (respLength == 0) { +// return false; +// } + +// if (response_buffer[0] == BT_ATT_OP_READ_BY_GROUP_RSP) { +// uint16_t lengthPerService = response_buffer[1]; +// uint8_t uuidLen = lengthPerService - 4; + +// for (size_t i = 2; i < respLength; i += lengthPerService) { +// struct __attribute__ ((packed)) RawService { +// uint16_t start_handle; +// uint16_t end_handle; +// uint8_t uuid[16]; +// } *rawService = (RawService*)&response_buffer[i]; + +// if (serviceUuidFilter == NULL || +// (uuidLen == serviceUuid.length() && memcmp(rawService->uuid, serviceUuid.data(), uuidLen) == 0)) { + +// BLERemoteService* service = new BLERemoteService(rawService->uuid, uuidLen, +// rawService->start_handle, +// rawService->end_handle); + +// if (service == NULL) { +// return false; +// } + +// device->addService(service); + +// } + +// reqStart_handle = rawService->end_handle + 1; + +// if (reqStart_handle == 0x0000) { +// reqEnd_handle = 0x0000; +// } +// } +// } else { +// reqEnd_handle = 0x0000; +// } +// } + +// return true; +// } + +// STATIC bool discover_characteristics(uint16_t conn_handle, BLERemoteDevice* device) { +// uint16_t reqStart_handle = 0x0001; +// uint16_t reqEnd_handle = 0xffff; + +// uint8_t response_buffer[max_mtu]; + +// int serviceCount = device->serviceCount(); + +// for (size_t i = 0; i < serviceCount; i++) { +// BLERemoteService* service = device->service(i); + +// reqStart_handle = service->start_handle(); +// reqEnd_handle = service->end_handle(); + +// while (1) { +// int respLength = readByTypeReq(conn_handle, reqStart_handle, reqEnd_handle, BLE_TYPE_CHARACTERISTIC, response_buffer); + +// if (respLength == 0) { +// return false; +// } + +// if (response_buffer[0] == BT_ATT_OP_READ_BY_TYPE_RSP) { +// uint16_t lengthPerCharacteristic = response_buffer[1]; +// uint8_t uuidLen = lengthPerCharacteristic - 5; + +// for (size_t i = 2; i < respLength; i += lengthPerCharacteristic) { +// struct __attribute__ ((packed)) RawCharacteristic { +// uint16_t start_handle; +// uint8_t properties; +// uint16_t value_handle; +// uint8_t uuid[16]; +// } *rawCharacteristic = (RawCharacteristic*)&response_buffer[i]; + +// BLERemoteCharacteristic* characteristic = new BLERemoteCharacteristic(rawCharacteristic->uuid, uuidLen, +// conn_handle, +// rawCharacteristic->start_handle, +// rawCharacteristic->properties, +// rawCharacteristic->value_handle); + +// if (characteristic == NULL) { +// return false; +// } + +// service->addCharacteristic(characteristic); + +// reqStart_handle = rawCharacteristic->value_handle + 1; +// } +// } else { +// break; +// } +// } +// } + +// return true; +// } + +// STATIC bool discover_descriptors(uint16_t conn_handle, BLERemoteDevice* device) { +// uint16_t reqStart_handle = 0x0001; +// uint16_t reqEnd_handle = 0xffff; + +// uint8_t response_buffer[max_mtu]; + +// int serviceCount = device->serviceCount(); + +// for (size_t i = 0; i < serviceCount; i++) { +// BLERemoteService* service = device->service(i); + +// uint16_t serviceEnd_handle = service->end_handle(); + +// int characteristicCount = service->characteristicCount(); + +// for (int j = 0; j < characteristicCount; j++) { +// BLERemoteCharacteristic* characteristic = service->characteristic(j); +// BLERemoteCharacteristic* nextCharacteristic = (j == (characteristicCount - 1)) ? NULL : service->characteristic(j); + +// reqStart_handle = characteristic->value_handle() + 1; +// reqEnd_handle = nextCharacteristic ? nextCharacteristic->value_handle() : serviceEnd_handle; + +// if (reqStart_handle > reqEnd_handle) { +// continue; +// } + +// while (1) { +// int respLength = findInfoReq(conn_handle, reqStart_handle, reqEnd_handle, response_buffer); + +// if (respLength == 0) { +// return false; +// } + +// if (response_buffer[0] == BT_ATT_OP_FIND_INFO_RSP) { +// uint16_t lengthPerDescriptor = response_buffer[1] * 4; +// uint8_t uuidLen = 2; + +// for (size_t i = 2; i < respLength; i += lengthPerDescriptor) { +// struct __attribute__ ((packed)) RawDescriptor { +// uint16_t handle; +// uint8_t uuid[16]; +// } *rawDescriptor = (RawDescriptor*)&response_buffer[i]; + +// BLERemoteDescriptor* descriptor = new BLERemoteDescriptor(rawDescriptor->uuid, uuidLen, +// conn_handle, +// rawDescriptor->handle); + +// if (descriptor == NULL) { +// return false; +// } + +// characteristic->addDescriptor(descriptor); + +// reqStart_handle = rawDescriptor->handle + 1; +// } +// } else { +// break; +// } +// } +// } +// } + +// return true; +// } + +bool att_discover_attributes(bt_addr_le_t *addr, const char* service_uuid_filter) { + uint16_t conn_handle = att_conn_handle(addr); + if (conn_handle == 0xffff) { + return false; + } + + // send MTU request + if (!att_exchange_mtu(conn_handle)) { + return false; + } + + // find the device entry for the peeer + //FIX BLERemoteDevice* device = NULL; + + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + // if (bleio_connections[i].conn_handle == conn_handle) { + // //FIX if (bleio_connections[i].device == NULL) { + // //FIX + // //bleio_connections[i].device = new BLERemoteDevice(); + // //} + + // //device = bleio_connections[i].device; + + // break; + // } + // } + + // //FIX if (device == NULL) { + // // return false; + // // } + + // if (service_uuid_filter == NULL) { + // // clear existing services + // //FIX device->clear_services(); + // } else { + // //FIX int service_count = device->service_count(); + + // for (size_t i = 0; i < service_count; i++) { + // //FIX BLERemoteService* service = device->service(i); + + // if (strcasecmp(service->uuid(), service_uuid_filter) == 0) { + // // found an existing service with same UUID + // return true; + // } + // } + } + + // discover services + //FIX + // if (!att_discover_services(conn_handle, device, service_uuid_filter)) { + // return false; + // } + + // // discover characteristics + // if (!discover_characteristics(conn_handle, device)) { + // return false; + // } + + // // discover descriptors396 + // if (!discover_descriptors(conn_handle, device)) { + // return false; + // } + + return true; +} + +void att_set_max_mtu(uint16_t max_mtu_in) { + max_mtu = max_mtu_in; +} + +void att_set_timeout(unsigned long timeout_in) { + timeout = timeout_in; +} + +void att_add_connection(uint16_t handle, uint8_t role, bt_addr_le_t *peer_addr, uint16_t interval, uint16_t latency, uint16_t supervision_timeout, uint8_t master_clock_accuracy) { + (void) interval; + (void) latency; + (void) supervision_timeout; + (void) master_clock_accuracy; + + int peer_index = -1; + + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + if (bleio_connections[i].conn_handle == 0xffff) { + peer_index = i; + break; + } + } + + if (peer_index == -1) { + // bail, no space + return; + } + + bleio_connections[peer_index].conn_handle = handle; + bleio_connections[peer_index].role = role; + bleio_connections[peer_index].mtu = 23; + memcpy(&bleio_connections[peer_index].addr, peer_addr, sizeof(bleio_connections[peer_index].addr)); + + //FIX if (event_handlers[BLEConnected]) { + // event_handlers[BLEConnected](BLEDevice(peer_bdaddr_type, peer_bdaddr)); + // } +} + + +void att_remove_connection(uint16_t handle, uint8_t reason) { + (void) reason; + int peer_index = -1; + int peer_count = 0; + + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + if (bleio_connections[i].conn_handle == handle) { + peer_index = i; + } + + if (bleio_connections[i].conn_handle != 0xffff) { + peer_count++; + } + } + + if (peer_index == -1) { + // bail not found + return; + } + + //FIX BLEDevice bleDevice(bleio_connections[peer_index].address_type, bleio_connections[peer_index].address); + + if (peer_count == 1) { + //FIX + // clear CCCD values on disconnect + // for (uint16_t i = 0; i < GATT.attributeCount(); i++) { + // BLELocalAttribute* attribute = GATT.attribute(i); + + // if (attribute->type() == BLE_TYPE_CHARACTERISTIC) { + // BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute; + + // characteristic->writeCccdValue(bleDevice, 0x0000); + // } + // } + + long_write_handle = 0x0000; + long_write_value_length = 0; + } + + //FIX + // if (event_handlers[BLEDisconnected]) { + // event_handlers[BLEDisconnected](bleDevice); + // } + + bleio_connections[peer_index].conn_handle = 0xffff; + bleio_connections[peer_index].role = 0x00; + memset(&bleio_connections[peer_index].addr, 0x00, sizeof(bleio_connections[peer_index].addr)); + bleio_connections[peer_index].mtu = 23; + + //FIX if (bleio_connections[peer_index].device) { + //FIX delete bleio_connections[peer_index].device; + // } + //FIX bleio_connections[peer_index].device = NULL; +} + +uint16_t att_conn_handle(bt_addr_le_t *addr) { + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + if (bleio_connections[i].addr.type == addr->type && + memcmp(&bleio_connections[i].addr.a.val, addr->a.val, sizeof(addr->a.val)) == 0) { + return bleio_connections[i].conn_handle; + } + } + + return 0xffff; +} + +//FIX +// BLERemoteDevice* att_device(uint8_t address_type, const uint8_t address[6]) { +// for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { +// if (bleio_connections[i].addr.type == addr->type && +// memcmp(&bleio_connections[i].addr.a.val, addr->a.val, sizeof(addr->a.val)) == 0) { +// } +// } + +// return NULL; +// } + +bool att_is_connected(void) { + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + if (bleio_connections[i].conn_handle != 0xffff) { + return true; + } + } + + return false; +} + +bool att_address_is_connected(bt_addr_le_t *addr) { + return (att_conn_handle(addr) != 0xffff); +} + +bool att_handle_is_connected(uint16_t handle) { + hci_poll_for_incoming_pkt(); + + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + if (bleio_connections[i].conn_handle == handle) { + return true; + } + } + + return false; +} + +uint16_t att_mtu(uint16_t handle) { + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + if (bleio_connections[i].conn_handle == handle) { + return bleio_connections[i].mtu; + } + } + + return 23; +} + +bool att_disconnect_all(void) { + int num_disconnects = 0; + + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + if (bleio_connections[i].conn_handle == 0xffff) { + continue; + } + + if (hci_disconnect(bleio_connections[i].conn_handle) != 0) { + continue; + } + + num_disconnects++; + + bleio_connections[i].conn_handle = 0xffff; + bleio_connections[i].role = 0x00; + bleio_connections[i].addr.type = 0; + memset(bleio_connections[i].addr.a.val, 0, sizeof(bleio_connections[i].addr.a.val)); + bleio_connections[i].mtu = 23; + + //FIX + // if (bleio_connections[i].device) { + // delete bleio_connections[i].device; + // } + // bleio_connections[i].device = NULL; + } + + return (num_disconnects > 0); +} + +// FIX +// BLEDevice att_central() { +// for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { +// if (bleio_connections[i].conn_handle == 0xffff || bleio_connections[i].role != 0x01) { +// continue; +// } + +// return BLEDevice(bleio_connections[i].address_type, bleio_connections[i].address); +// } + +// return BLEDevice(); +// } + +bool att_handle_notify(uint16_t handle, const uint8_t* value, int length) { + int num_notifications = 0; + + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + if (bleio_connections[i].conn_handle == 0xffff) { + continue; + } + + //FIX This seems fishy. Why just .mtu instead of .mtu + 1 for opcode + uint8_t notification[bleio_connections[i].mtu]; + uint16_t notification_length = 0; + + notification[0] = BT_ATT_OP_NOTIFY; + notification_length++; + + memcpy(¬ification[1], &handle, sizeof(handle)); + notification_length += sizeof(handle); + + length = MIN((uint16_t)(bleio_connections[i].mtu - notification_length), (uint16_t)length); + memcpy(¬ification[notification_length], value, length); + notification_length += length; + + hci_send_acl_pkt(bleio_connections[i].conn_handle, BT_L2CAP_CID_ATT, notification_length, notification); + + num_notifications++; + } + + return (num_notifications > 0); +} + +bool att_handle_ind(uint16_t handle, const uint8_t* value, int length) { + int num_indications = 0; + + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + if (bleio_connections[i].conn_handle == 0xffff) { + continue; + } + + uint8_t indication[bleio_connections[i].mtu]; + uint16_t indication_length = 0; + + indication[0] = BT_ATT_OP_INDICATE; + indication_length++; + + memcpy(&indication[1], &handle, sizeof(handle)); + indication_length += sizeof(handle); + + length = MIN((uint16_t)(bleio_connections[i].mtu - indication_length), (uint16_t)length); + memcpy(&indication[indication_length], value, length); + indication_length += length; + + cnf = false; + + hci_send_acl_pkt(bleio_connections[i].conn_handle, BT_L2CAP_CID_ATT, indication_length, indication); + + while (!cnf) { + hci_poll_for_incoming_pkt(); + + if (!att_address_is_connected(&bleio_connections[i].addr)) { + break; + } + } + + num_indications++; + } + + return (num_indications > 0); +} + +STATIC void process_error(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { + struct bt_att_error_rsp *rsp = (struct bt_att_error_rsp *) data; + if (dlen != sizeof(struct bt_att_error_rsp)) { + // Incorrect size; ignore. + return; + } + + // expected_rsp.opcode is an RSP opcode. Does it match the REQ opcode in this response? + if (expected_rsp.conn_handle == conn_handle && (expected_rsp.opcode - 1) == rsp->request) { + expected_rsp.buffer[0] = BT_ATT_OP_ERROR_RSP; + memcpy(&expected_rsp.buffer[1], data, dlen); + expected_rsp.length = dlen + 1; + } +} + +STATIC void process_mtu_req(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { + struct bt_att_exchange_mtu_req *req = (struct bt_att_exchange_mtu_req *) data; + if (dlen != sizeof(req)) { + send_error(conn_handle, BT_ATT_OP_MTU_REQ, 0x0000, BT_ATT_ERR_INVALID_PDU); + return; + } + + uint16_t mtu = req->mtu; + + if (mtu > max_mtu) { + mtu = max_mtu; + } + + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + if (bleio_connections[i].conn_handle == conn_handle) { + bleio_connections[i].mtu = mtu; + break; + } + } + + struct __packed { + struct bt_att_hdr h; + struct bt_att_exchange_mtu_req r; + } rsp = { { + .code = BT_ATT_OP_MTU_RSP, + }, { + .mtu = mtu, + } + }; + + hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, sizeof(rsp), (uint8_t *) &rsp); +} + +STATIC void process_mtu_rsp(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { + if (dlen != sizeof(struct bt_att_exchange_mtu_rsp)) { + return; + } + + struct bt_att_exchange_mtu_rsp *rsp = (struct bt_att_exchange_mtu_rsp *) data; + + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + if (bleio_connections[i].conn_handle == conn_handle) { + bleio_connections[i].mtu = rsp->mtu; + break; + } + } + + check_and_save_expected_rsp(conn_handle, BT_ATT_OP_MTU_RSP, dlen, data); +} + +STATIC void process_find_info_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, uint8_t data[]) { + struct bt_att_find_info_req *req = (struct bt_att_find_info_req *) data; + + if (dlen != sizeof(struct bt_att_find_info_req)) { + send_error(conn_handle, BT_ATT_OP_FIND_INFO_REQ, req->start_handle, BT_ATT_ERR_INVALID_PDU); + return; + } + + //FIX + // uint8_t response[mtu]; + // uint16_t response_length; + + // response[0] = BT_ATT_OP_FIND_INFO_RSP; + // response[1] = 0x00; + // response_length = 2; + + // for (uint16_t i = (req->start_handle - 1); i < GATT.attributeCount() && i <= (req->end_handle - 1); i++) { + // BLELocalAttribute* attribute = GATT.attribute(i); + // uint16_t handle = (i + 1); + // bool is_value_handle = (attribute->type() == BLE_TYPE_CHARACTERISTIC) && (((BLELocalCharacteristic*)attribute)->valueHandle() == handle); + // int uuid_len = is_value_handle ? 2 : attribute->uuid_length(); + // size_t info_type = (uuidLen == 2) ? 0x01 : 0x02; + + // if (response[1] == 0) { + // response[1] = info_type; + // } + + // if (response[1] != info_type) { + // // different type + // break; + // } + + // // add the handle + // memcpy(&response[response_length], &handle, sizeof(handle)); + // response_length += sizeof(handle); + + // if (is_value_handle || attribute->type() == BLE_TYPE_DESCRIPTOR) { + // // add the UUID + // memcpy(&response[response_length], attribute->uuid_data(), uuid_len); + // response_length += uuidLen; + // } else { + // // add the type + // uint16_t type = attribute->type(); + + // memcpy(&response[response_length], &type, sizeof(type)); + // response_length += sizeof(type); + // } + + // if ((response_length + (2 + uuidLen)) > mtu) { + // break; + // } + // } + + // if (response_length == 2) { + // send_error(conn_handle, BT_ATT_OP_FIND_INFO_REQ, findInfoReq->start_handle, BT_ATT_ERR_ATTR_NOT_FOUND); + // } else { + // hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, response_length, response); + // } +} + +int att_find_info_req(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, uint8_t response_buffer[]) { + struct __packed req { + struct bt_att_hdr h; + struct bt_att_find_info_req r; + } req = { { + .code = BT_ATT_OP_FIND_INFO_REQ, + }, { + .start_handle = start_handle, + .end_handle = end_handle, + } + }; + + return send_req_wait_for_rsp(conn_handle, sizeof(req), (uint8_t *) &req, response_buffer); +} + +STATIC void process_find_info_rsp(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { + if (dlen < 2) { + return; // invalid, drop + } + + check_and_save_expected_rsp(conn_handle, BT_ATT_OP_FIND_INFO_RSP, dlen, data); +} + +STATIC void process_find_by_type_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, uint8_t data[]) { + struct bt_att_find_type_req *req = (struct bt_att_find_type_req *) data; + + if (dlen < sizeof(struct bt_att_find_type_req)) { + send_error(conn_handle, BT_ATT_OP_FIND_TYPE_RSP, req->start_handle, BT_ATT_ERR_INVALID_PDU); + return; + } + + uint8_t response[mtu]; + uint16_t response_length; + + response[0] = BT_ATT_OP_FIND_TYPE_RSP; + response_length = 1; + + //FIX + // if (find_by_type_req->type == BLE_TYPE_PRIMARY_SERVICE) { + // for (uint16_t i = (find_by_type_req->start_handle - 1); i < GATT.attributeCount() && i <= (find_by_type_req->end_handle - 1); i++) { + // BLELocalAttribute* attribute = GATT.attribute(i); + + // if ((attribute->type() == find_by_type_req->type) && (attribute->uuidLength() == value_length) && memcmp(attribute->uuidData(), value, value_length) == 0) { + // BLELocalService* service = (BLELocalService*)attribute; + + // // add the start handle + // uint16_t start_handle = service->start_handle(); + // memcpy(&response[response_length], &start_handle, sizeof(start_handle)); + // response_length += sizeof(start_handle); + + // // add the end handle + // uint16_t end_handle = service->end_handle(); + // memcpy(&response[response_length], &end_handle, sizeof(end_handle)); + // response_length += sizeof(end_handle); + // } + + // if ((response_length + 4) > mtu) { + // break; + // } + // } + // } + + if (response_length == 1) { + send_error(conn_handle, BT_ATT_OP_FIND_TYPE_RSP, req->start_handle, BT_ATT_ERR_ATTRIBUTE_NOT_FOUND); + } else { + hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, response_length, response); + } +} + +void process_read_by_group_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, uint8_t data[]) { + struct bt_att_read_group_req *req = (struct bt_att_read_group_req *) data; + uint16_t uuid = req->uuid[0] | (req->uuid[1] << 8); + + if (dlen != sizeof(struct bt_att_find_type_req) || + (uuid != BLE_TYPE_PRIMARY_SERVICE && + uuid != BLE_TYPE_SECONDARY_SERVICE)) { + send_error(conn_handle, BT_ATT_OP_READ_GROUP_REQ, req->start_handle, BT_ATT_ERR_UNSUPPORTED_GROUP_TYPE); + return; + } + + uint8_t response[mtu]; + uint16_t response_length; + + response[0] = BT_ATT_OP_READ_GROUP_RSP; + response[1] = 0x00; + response_length = 2; + + // FIX + // for (uint16_t i = (readByGroupReq->start_handle - 1); i < GATT.attributeCount() && i <= (readByGroupReq->end_handle - 1); i++) { + //FIX + // BLELocalAttribute* attribute = GATT.attribute(i); + + // if (readByGroupReq->uuid != attribute->type()) { + // // not the type + // continue; + // } + + // int uuidLen = attribute->uuidLength(); + // size_t infoSize = (uuidLen == 2) ? 6 : 20; + + // if (response[1] == 0) { + // response[1] = infoSize; + // } + + // if (response[1] != infoSize) { + // // different size + // break; + // } + + // BLELocalService* service = (BLELocalService*)attribute; + + // // add the start handle + // uint16_t start_handle = service->start_handle(); + // memcpy(&response[response_length], &start_handle, sizeof(start_handle)); + // response_length += sizeof(start_handle); + + // // add the end handle + // uint16_t end_handle = service->end_handle(); + // memcpy(&response[response_length], &end_handle, sizeof(end_handle)); + // response_length += sizeof(end_handle); + + // // add the UUID + // memcpy(&response[response_length], service->uuidData(), uuidLen); + // response_length += uuidLen; + + // if ((response_length + infoSize) > mtu) { + // break; + // } + // } + + if (response_length == 2) { + send_error(conn_handle, BT_ATT_OP_READ_GROUP_REQ, req->start_handle, BT_ATT_ERR_ATTRIBUTE_NOT_FOUND); + } else { + hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, response_length, response); + } +} + +int att_read_by_group_req(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, uint16_t uuid, uint8_t response_buffer[]) { + struct __packed { + struct bt_att_hdr h; + struct bt_att_read_group_req r; + } req = { { + .code = BT_ATT_OP_ERROR_RSP, + }, { + .start_handle = start_handle, + .end_handle = end_handle, + } + }; + req.r.uuid[0] = uuid & 0xff; + req.r.uuid[1] = uuid >> 8; + + + return send_req_wait_for_rsp(conn_handle, sizeof(req), (uint8_t *) &req, response_buffer); +} + +STATIC void process_read_by_group_rsp(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { + if (dlen < 2) { + return; // invalid, drop + } + + check_and_save_expected_rsp(conn_handle, BT_ATT_OP_READ_GROUP_RSP, dlen, data); +} + +STATIC void process_read_or_read_blob_req(uint16_t conn_handle, uint16_t mtu, uint8_t opcode, uint8_t dlen, uint8_t data[]) { + uint16_t handle; + uint16_t offset = 0; + uint8_t response_opcode; + + if (opcode == BT_ATT_OP_READ_REQ) { + if (dlen != sizeof(struct bt_att_read_req)) { + send_error(conn_handle, BT_ATT_OP_READ_REQ, 0x0000, BT_ATT_ERR_INVALID_PDU); + return; + } + + struct bt_att_read_req *req = (struct bt_att_read_req *) data; + handle = req->handle; + response_opcode = BT_ATT_OP_READ_RSP; + + } else { + if (dlen != sizeof(struct bt_att_read_blob_req)) { + send_error(conn_handle, BT_ATT_OP_READ_BLOB_REQ, 0x0000, BT_ATT_ERR_INVALID_PDU); + return; + } + + struct bt_att_read_blob_req *req = (struct bt_att_read_blob_req *) data; + handle = req->handle; + offset = req->offset; + response_opcode = BT_ATT_OP_READ_BLOB_RSP; + } + + //FIX + (void) offset; + (void) handle; + //FIX if ((uint16_t)(handle - 1) > GATT.attributeCount()) { + // send_error(conn_handle, opcode, handle, BT_ATT_ERR_ATTR_NOT_FOUND); + // return; + // } + + uint8_t response[mtu]; + uint16_t response_length; + + response[0] = response_opcode; + response_length = 1; + + //FIX BLELocalAttribute* attribute = GATT.attribute(handle - 1); + // enum BLEAttributeType attributeType = attribute->type(); + + // if (attributeType == BLE_TYPE_PRIMARY_SERVICE) { + // if (offset) { + // send_error(conn_handle, BT_ATT_ERR_ATTR_NOT_LONG, handle, BT_ATT_ERR_INVALID_PDU); + // return; + // } + + // BLELocalService* service = (BLELocalService*)attribute; + + // // add the UUID + // uint8_t uuidLen = service->uuidLength(); + // memcpy(&response[response_length], service->uuidData(), uuidLen); + // response_length += uuidLen; + // } else if (attributeType == BLE_TYPE_CHARACTERISTIC) { + // BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute; + + // if (characteristic->handle() == handle) { + // if (offset) { + // send_error(conn_handle, opcode, handle, BT_ATT_ERR_ATTR_NOT_LONG); + // return; + // } + + // // add the properties + // response[response_length++] = characteristic->properties(); + + // // add the value handle + // uint16_t value_handle = characteristic->value_handle(); + // memcpy(&response[response_length], &value_handle, sizeof(value_handle)); + // response_length += sizeof(value_handle); + + // // add the UUID + // uint8_t uuidLen = characteristic->uuidLength(); + // memcpy(&response[response_length], characteristic->uuidData(), uuidLen); + // response_length += uuidLen; + // } else { + // if ((characteristic->properties() & BLERead) == 0) { + // send_error(conn_handle, opcode, handle, BT_ATT_ERR_READ_NOT_PERM); + // return; + // } + + // uint16_t value_length = characteristic->value_length(); + + // if (offset >= value_length) { + // send_error(conn_handle, opcode, handle, BT_ATT_ERR_INVALID_OFFSET); + // return; + // } + + // value_length = min(mtu - response_length, value_length - offset); + + // for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + // if (bleio_connections[i].conn_handle == conn_handle) { + // // FIX characteristic->readValue(BLEDevice(bleio_connections[i].address_type, bleio_connections[i].address), offset, &response[response_length], value_length); + // response_length += value_length; + // } + // } + // } + // } else if (attributeType == BLE_TYPE_DESCRIPTOR) { + // BLELocalDescriptor* descriptor = (BLELocalDescriptor*)attribute; + + // uint16_t value_length = descriptor->valueSize(); + + // if (offset >= value_length) { + // send_error(conn_handle, opcode, handle, BT_ATT_ERR_INVALID_OFFSET); + // return; + // } + + // value_length = min(mtu - response_length, value_length - offset); + + // memcpy(&response[response_length], descriptor->value() + offset, value_length); + // response_length += value_length; + // } + + hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, response_length, response); +} + +STATIC void process_read_rsp(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { + check_and_save_expected_rsp(conn_handle, BT_ATT_OP_READ_RSP, dlen, data); +} + +STATIC void process_read_by_type_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, uint8_t data[]) { + struct bt_att_read_type_req *req = (struct bt_att_read_type_req *) data; + + if (dlen != sizeof(struct bt_att_read_type_req)) { + send_error(conn_handle, BT_ATT_OP_READ_TYPE_REQ, req->start_handle, BT_ATT_ERR_INVALID_PDU); + return; + } + + // uint8_t response[mtu]; + // uint16_t response_length; + + // response[0] = BT_ATT_OP_READ_TYPE_RSP; + // response[1] = 0x00; + // response_length = 2; + + // for (uint16_t i = (req->start_handle - 1); i < GATT.attributeCount() && i <= (req->end_handle - 1); i++) { + // BLELocalAttribute* attribute = GATT.attribute(i); + // uint16_t handle = (i + 1); + + // if (attribute->type() == readByTypeReq->uuid) { + // if (attribute->type() == BLE_TYPE_CHARACTERISTIC) { + // BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute; + + // if (characteristic->value_handle() == handle) { + // // value handle, skip + // continue; + // } + + // int uuidLen = attribute->uuidLength(); + // int typeSize = (uuidLen == 2) ? 7 : 21; + + // if (response[1] == 0) { + // response[1] = typeSize; + // } + + // if (response[1] != typeSize) { + // // all done, wrong size + // break; + // } + + // // add the handle + // memcpy(&response[response_length], &handle, sizeof(handle)); + // response_length += sizeof(handle); + + // // add the properties + // response[response_length++] = characteristic->properties(); + + // // add the value handle + // uint16_t value_handle = (handle + 1); + // memcpy(&response[response_length], &value_handle, sizeof(value_handle)); + // response_length += sizeof(value_handle); + + // // add the UUID + // memcpy(&response[response_length], characteristic->uuidData(), uuidLen); + // response_length += uuidLen; + + // // skip the next handle, it's a value handle + // i++; + + // if ((response_length + typeSize) > mtu) { + // break; + // } + // } else if (attribute->type() == 0x2902) { + // BLELocalDescriptor* descriptor = (BLELocalDescriptor*)attribute; + + // // add the handle + // memcpy(&response[response_length], &handle, sizeof(handle)); + // response_length += sizeof(handle); + + // // add the value + // int valueSize = min((uint16_t)(mtu - response_length), (uint16_t)descriptor->valueSize()); + // memcpy(&response[response_length], descriptor->value(), valueSize); + // response_length += valueSize; + + // response[1] = 2 + valueSize; + + // break; // all done + // } + // } else if (attribute->type() == BLE_TYPE_CHARACTERISTIC && attribute->uuidLength() == 2 && memcmp(&readByTypeReq->uuid, attribute->uuidData(), 2) == 0) { + // BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute; + + // // add the handle + // memcpy(&response[response_length], &handle, sizeof(handle)); + // response_length += sizeof(handle); + + // // add the value + // int value_length = min((uint16_t)(mtu - response_length), (uint16_t)characteristic->value_length()); + // memcpy(&response[response_length], characteristic->value(), value_length); + // response_length += value_length; + + // response[1] = 2 + value_length; + + // break; // all done + // } + // } + + // if (response_length == 2) { + // send_error(conn_handle, BT_ATT_OP_READ_BY_TYPE_REQ, readByTypeReq->start_handle, BT_ATT_ERR_ATTR_NOT_FOUND); + // } else { + // hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, response_length, response); + // } +} + +int att_read_by_type_req(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, uint16_t type, uint8_t response_buffer[]) { + struct __packed { + struct bt_att_hdr h; + struct bt_att_read_type_req r; + } req = { { + .code = BT_ATT_OP_READ_TYPE_REQ, + }, { + .start_handle = start_handle, + .end_handle = end_handle, + } + }; + req.r.uuid[0] = type & 0xff; + req.r.uuid[1] = type >> 8; + + return send_req_wait_for_rsp(conn_handle, sizeof(req), (uint8_t *) &req, response_buffer); +} + +void att_read_by_type_rsp(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { + if (dlen < 1) { + return; // invalid, drop + } + + check_and_save_expected_rsp(conn_handle, BT_ATT_OP_READ_TYPE_RSP, dlen, data); +} + +// Handles BT_ATT_OP_WRITE_REQ or BT_ATT_OP_WRITE_ +STATIC void process_req_or_cmd(uint16_t conn_handle, uint16_t mtu, uint8_t op, uint8_t dlen, uint8_t data[]) { + boolean with_response = (op == BT_ATT_OP_WRITE_REQ); + + if (dlen < sizeof(struct bt_att_write_req)) { + if (with_response) { + send_error(conn_handle, BT_ATT_OP_WRITE_REQ, 0x0000, BT_ATT_ERR_INVALID_PDU); + } + return; + } + + uint16_t handle = *(uint16_t*)data; + + // if ((uint16_t)(handle - 1) > GATT.attributeCount()) { + // if (with_response) { + // send_error(conn_handle, BT_ATT_OP_WRITE_REQ, handle, BT_ATT_ERR_ATTR_NOT_FOUND); + // } + // return; + // } + + // uint8_t value_length = dlen - sizeof(handle); + // uint8_t* value = &data[sizeof(handle)]; + + // BLELocalAttribute* attribute = GATT.attribute(handle - 1); + + // if (attribute->type() == BLE_TYPE_CHARACTERISTIC) { + // BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute; + + // if (handle != characteristic->value_handle() || + // withResponse ? ((characteristic->properties() & BLEWrite) == 0) : + // ((characteristic->properties() & BLEWriteWithoutResponse) == 0)) { + // if (withResponse) { + // send_error(conn_handle, BT_ATT_OP_WRITE_REQ, handle, BT_ATT_ERR_WRITE_NOT_PERM); + // } + // return; + // } + + // for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + // if (bleio_connections[i].conn_handle == conn_handle) { + // // FIX characteristic->writeValue(BLEDevice(bleio_connections[i].address_type, bleio_connections[i].address), value, value_length); + // break; + // } + // } + // } else if (attribute->type() == BLE_TYPE_DESCRIPTOR) { + // BLELocalDescriptor* descriptor = (BLELocalDescriptor*)attribute; + + // // only CCCD's are writable + // if (descriptor->uuidLength() != 2 || *((uint16_t*)(descriptor->uuidData())) != 0x2902) { + // if (withResponse) { + // send_error(conn_handle, BT_ATT_OP_WRITE_REQ, handle, BT_ATT_ERR_WRITE_NOT_PERM); + // } + // return; + // } + + // // get the previous handle, should be the characteristic for the CCCD + // attribute = GATT.attribute(handle - 2); + + // if (attribute->type() != BLE_TYPE_CHARACTERISTIC) { + // if (withResponse) { + // send_error(conn_handle, BT_ATT_OP_WRITE_REQ, handle, BT_ATT_ERR_WRITE_NOT_PERM); + // } + // return; + // } + + // BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute; + + // for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + // if (bleio_connections[i].conn_handle == conn_handle) { + // //FIX characteristic->writeCccdValue(BLEDevice(bleio_connections[i].address_type, bleio_connections[i].address), *((uint16_t*)value)); + // break; + // } + // } + // } else { + // if (withResponse) { + // send_error(conn_handle, BT_ATT_OP_WRITE_REQ, handle, BT_ATT_ERR_WRITE_NOT_PERM); + // } + // return; + // } + + if (withResponse) { + uint8_t response[mtu]; + uint16_t response_length; + + response[0] = BT_ATT_OP_WRITE_RSP; + response_length = 1; + + hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, response_length, response); + } +} + +STATIC void process_write_rsp(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { + if (dlen != 0) { + return; // drop + } + + check_and_save_expected_rsp(conn_handle, BT_ATT_OP_WRITE_RSP, dlen, data); +} + +STATIC void process_prep_write_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, uint8_t data[]) { + struct __attribute__ ((packed)) PrepWriteReq { + uint16_t handle; + uint16_t offset; + } *prepWriteReq = (PrepWriteReq*)data; + + if (dlen < sizeof(PrepWriteReq)) { + send_error(conn_handle, BT_ATT_OP_PREP_WRITE_REQ, 0x0000, BT_ATT_ERR_INVALID_PDU); + return; + } + + uint16_t handle = prepWriteReq->handle; + uint16_t offset = prepWriteReq->offset; + + if ((uint16_t)(handle - 1) > GATT.attributeCount()) { + send_error(conn_handle, BT_ATT_OP_PREP_WRITE_REQ, handle, BT_ATT_ERR_ATTR_NOT_FOUND); + return; + } + + BLELocalAttribute* attribute = GATT.attribute(handle - 1); + + if (attribute->type() != BLE_TYPE_CHARACTERISTIC) { + send_error(conn_handle, BT_ATT_OP_PREP_WRITE_REQ, handle, BT_ATT_ERR_ATTR_NOT_LONG); + return; + } + + BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute; + + if (handle != characteristic->value_handle()) { + send_error(conn_handle, BT_ATT_OP_PREP_WRITE_REQ, handle, BT_ATT_ERR_ATTR_NOT_LONG); + return; + } + + if ((characteristic->properties() & BLEWrqite) == 0) { + send_error(conn_handle, BT_ATT_OP_PREP_WRITE_REQ, handle, BT_ATT_ERR_WRITE_NOT_PERM); + return; + } + + if (long_write_handle == 0) { + int valueSize = characteristic->valueSize(); + + long_write_value = (uint8_t*)realloc(long_write_value, valueSize); + long_write_value_length = 0; + long_write_handle = handle; + + memset(long_write_value, 0x00, valueSize); + } else if (long_write_handle != handle) { + send_error(conn_handle, BT_ATT_OP_PREP_WRITE_REQ, handle, BT_ATT_ERR_UNLIKELY); + return; + } + + uint8_t value_length = dlen - sizeof(PrepWriteReq); + uint8_t* value = &data[sizeof(PrepWriteReq)]; + + if ((offset != long_write_value_length) || ((offset + value_length) > (uint16_t)characteristic->valueSize())) { + send_error(conn_handle, BT_ATT_OP_PREP_WRITE_REQ, handle, BT_ATT_ERR_INVALID_OFFSET); + return; + } + + memcpy(long_write_value + offset, value, value_length); + long_write_value_length += value_length; + + uint8_t response[mtu]; + uint16_t response_length; + + response[0] = BT_ATT_OP_PREP_WRITE_RSP; + memcpy(&response[1], data, dlen); + response_length = dlen + 1; + + hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, response_length, response); +} + +STATIC void process_exec_write_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, uint8_t data[]) { + if (dlen != sizeof(uint8_t)) { + send_error(conn_handle, BT_ATT_OP_EXEC_WRITE_REQ, 0x0000, BT_ATT_ERR_INVALID_PDU); + return; + } + + uint8_t flag = data[0]; + + if (long_write_handle && (flag & 0x01)) { + BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)GATT.attribute(long_write_handle - 1); + + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + if (bleio_connections[i].conn_handle == conn_handle) { + //FIX characteristic->writeValue(BLEDevice(bleio_connections[i].address_type, bleio_connections[i].address), long_write_value, long_write_value_length); + break; + } + } + } + + long_write_handle = 0x0000; + long_write_value_length = 0; + + uint8_t response[mtu]; + uint16_t response_length; + + response[0] = BT_ATT_OP_EXEC_WRITE_RSP; + response_length = 1; + + hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, response_length, response); +} + +STATIC void process_handle_notify_or_ind(uint16_t conn_handle, uint8_t opcode, uint8_t dlen, uint8_t data[]) { + if (dlen < 2) { + return; // drop + } + + struct __attribute__ ((packed)) _handleNotifyOrInd { + uint16_t handle; + } *handleNotifyOrInd = (_handleNotifyOrInd*)data; + + uint8_t handle = handleNotifyOrInd->handle; + + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + if (bleio_connections[i].conn_handle != conn_handle) { + continue; + } + + BLERemoteDevice* device = bleio_connections[i].device; + + if (!device) { + break; + } + + int serviceCount = device->serviceCount(); + + for (size_t i = 0; i < serviceCount; i++) { + BLERemoteService* s = device->service(i); + + if (s->start_handle() < handle && s->end_handle() >= handle) { + int characteristicCount = s->characteristicCount(); + + for (int j = 0; j < characteristicCount; j++) { + BLERemoteCharacteristic* c = s->characteristic(j); + + if (c->value_handle() == handle) { + //FIX c->writeValue(BLEDevice(bleio_connections[i].address_type, bleio_connections[i].address), &data[2], dlen - 2); + } + } + + break; + } + } + } + + if (opcode == BT_ATT_OP_HANDLE_IND) { + // send CNF for IND + + uint8_t cnf = BT_ATT_OP_HANDLE_CNF; + + hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, sizeof(cnf), &cnf); + } +} + +STATIC void process_handle_cnf(uint16_t /*conn_handle*/, uint8_t /*dlen*/, uint8_t /*data*/[]) { + cnf = true; +} + +bool att_exchange_mtu(uint16_t conn_handle) { + uint8_t response_buffer[max_mtu]; + struct bt_att_exchange_mtu_req req; + req->mtu = max_mtu; + return send_req_wait_for_rsp(conn_handle, BT_ATT_OP_MTU_REQ, &req, sizeof(req), response_buffer); +} + + + +void att_set_event_handler(BLEDeviceEvent event, BLEDeviceEventHandler event_handler) { + if (event < (sizeof(event_handlers) / (sizeof(event_handlers[0])))) { + event_handlers[event] = event_handler; + } +} + +int att_read_req(uint16_t conn_handle, uint16_t handle, uint8_t response_buffer[]) { + struct __attribute__ ((packed)) { + uint8_t op; + uint16_t handle; + } read_req = { BT_ATT_OP_READ_REQ, handle }; + + return send_req_wait_for_rsp(conn_handle, &read_req, sizeof(read_req), response_buffer); +} + +int att_write_req(uint16_t conn_handle, uint16_t handle, const uint8_t* data, uint8_t data_len, uint8_t response_buffer[]) { + struct __attribute__ ((packed)) { + uint8_t op; + uint16_t handle; + uint8_t data[255]; + } write_req; + + write_req.opcode = BT_ATT_OP_WRITE_REQ; + write_req.handle = handle; + memcpy(write_req.data, data, data_len); + + return send_req_wait_for_rsp(conn_handle, &write_req, 3 + data_len, response_buffer); +} + +void att_write_cmd(uint16_t conn_handle, uint16_t handle, const uint8_t* data, uint8_t data_len) { + struct bt_att_write_cmd req = { + .handle = handle, + }; + memcpy(req.value, data, data_len); + + send_req_wait_for_rsp(conn_handle, &req, data_len + sizeof(req), NULL); +} + +void att_process_data(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { + // Opcode is a single byte at the front of the data. + uint8_t opcode = data[0]; + + // Skip over opcode. + dlen--; + data++; + + uint16_t mtu = this->mtu(conn_handle); + + switch (opcode) { + case BT_ATT_OP_ERROR_RSP: + process_error(conn_handle, dlen, data); + break; + + case BT_ATT_OP_MTU_REQ: + process_mtu_req(conn_handle, dlen, data); + break; + + case BT_ATT_OP_MTU_RSP: + process_mtu_rsp(conn_handle, dlen, data); + break; + + case BT_ATT_OP_FIND_INFO_REQ: + process_find_info_req(conn_handle, mtu, dlen, data); + break; + + case BT_ATT_OP_FIND_INFO_RSP: + process_find_info_rsp(conn_handle, dlen, data); + break; + + case BT_ATT_OP_FIND_BY_TYPE_REQ: + process_find_by_type_req(conn_handle, mtu, dlen, data); + break; + + case BT_ATT_OP_READ_BY_TYPE_REQ: + process_read_by_type_req(conn_handle, mtu, dlen, data); + break; + + case BT_ATT_OP_READ_BY_TYPE_RSP: + process_read_by_type_rsp(conn_handle, dlen, data); + break; + + case BT_ATT_OP_READ_BY_GROUP_REQ: + att_read_by_group_req(conn_handle, mtu, dlen, data); + break; + + case BT_ATT_OP_READ_BY_GROUP_RSP: + prcoess_read_by_group_rsp(conn_handle, dlen, data); + break; + + case BT_ATT_OP_READ_REQ: + case BT_ATT_OP_READ_BLOB_REQ: + process_read_or_read_blob_req(conn_handle, mtu, opcode, dlen, data); + break; + + case BT_ATT_OP_READ_RSP: + process_read_rsp(conn_handle, dlen, data); + break; + + case BT_ATT_OP_WRITE_REQ: + case BT_ATT_OP_WRITE_CMD: + process_write_req_or_cmd(conn_handle, mtu, opcode, dlen, data); + break; + + case BT_ATT_OP_WRITE_RSP: + process_write_rsp(conn_handle, dlen, data); + break; + + case BT_ATT_OP_PREP_WRITE_REQ: + process_prep_write_req(conn_handle, mtu, dlen, data); + break; + + case BT_ATT_OP_EXEC_WRITE_REQ: + process_exec_write_req(conn_handle, mtu, dlen, data); + break; + + case BT_ATT_OP_HANDLE_NOTIFY: + case BT_ATT_OP_HANDLE_IND: + process_handle_notify_or_ind(conn_handle, opcode, dlen, data); + break; + + case BT_ATT_OP_HANDLE_CNF: + process_handle_cnf(conn_handle, dlen, data); + break; + + case BT_ATT_OP_READ_MULTI_REQ: + case BT_ATT_OP_SIGNED_WRITE_CMD: + default: + send_error(conn_handle, opcode, 0x00, BT_ATT_ERR_REQ_NOT_SUPP); + break; + } +} diff --git a/devices/ble_hci/common-hal/_bleio/att.h b/devices/ble_hci/common-hal/_bleio/att.h new file mode 100644 index 000000000..108c44929 --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/att.h @@ -0,0 +1,57 @@ +// Derived from ArduinoBLE. +// Copyright 2020 Dan Halbert for Adafruit Industries + +/* + This file is part of the ArduinoBLE library. + Copyright (c) 2018 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef MICROPY_INCLUDED_DEVICES_BLE_HCI_COMMON_HAL_BLEIO_ATT_H +#define MICROPY_INCLUDED_DEVICES_BLE_HCI_COMMON_HAL_BLEIO_ATT_H + +#include +#include + +#include "hci_include/addr.h" +#include "hci_include/att.h" +#include "hci_include/att_internal.h" + +//FIX BLEDevice att_central(void); +//FIX BLERemoteDevice* att_device(uint8_t address_type, const uint8_t address[6]); +//FIX void att_set_event_handler(BLEDeviceEvent event, BLEDeviceEventHandler eventHandler); +bool att_address_is_connected(bt_addr_le_t *addr); +bool att_connect_to_address(bt_addr_le_t *addr); +bool att_disconnect_all(void); +bool att_disconnect_from_address(bt_addr_le_t *addr); +bool att_discover_attributes(bt_addr_le_t *addr, const char* service_uuid_filter); +bool att_exchange_mtu(uint16_t conn_handle); +bool att_handle_ind(uint16_t handle, const uint8_t* value, int length); +bool att_handle_is_connected(uint16_t handle); +bool att_handle_notify(uint16_t handle, const uint8_t* value, int length); +bool att_is_connected(void); +int att_read_req(uint16_t conn_handle, uint16_t handle, uint8_t response_buffer[]); +int att_write_req(uint16_t conn_handle, uint16_t handle, const uint8_t* data, uint8_t data_len, uint8_t response_buffer[]); +uint16_t att_conn_handle(bt_addr_le_t *addr); +uint16_t att_mtu(uint16_t handle); +void att_add_connection(uint16_t handle, uint8_t role, bt_addr_le_t *peer_addr, uint16_t interval, uint16_t latency, uint16_t supervision_timeout, uint8_t master_clock_accuracy); +void att_process_data(uint16_t conn_handle, uint8_t dlen, uint8_t data[]); +void att_remove_connection(uint16_t handle, uint8_t reason); +void att_set_max_mtu(uint16_t max_mtu); +void att_set_timeout(unsigned long timeout); +void att_write_cmd(uint16_t conn_handle, uint16_t handle, const uint8_t* data, uint8_t data_len); + +#endif // MICROPY_INCLUDED_DEVICES_BLE_HCI_COMMON_HAL_BLEIO_ATT_H diff --git a/devices/ble_hci/common-hal/_bleio/hci.c b/devices/ble_hci/common-hal/_bleio/hci.c new file mode 100644 index 000000000..83aba883a --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/hci.c @@ -0,0 +1,826 @@ +// This file is derived from the ArduinoBLE library. Its header is below. +/* + This file is part of the ArduinoBLE library. + Copyright (c) 2018 Arduino SA. All rights reserved. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "att.h" +#include "hci.h" + +#include "py/obj.h" + +// Zephyr include files to define HCI communication values and structs. +#include "hci_include/hci.h" +#include "hci_include/hci_err.h" +#include "hci_include/l2cap_internal.h" + +#include + +#include "supervisor/shared/tick.h" +#include "shared-bindings/_bleio/__init__.h" +#include "common-hal/_bleio/Adapter.h" +#include "shared-bindings/microcontroller/__init__.h" + + +// HCI H4 protocol packet types: first byte in the packet. +#define H4_CMD 0x01 +#define H4_ACL 0x02 +#define H4_SCO 0x03 +#define H4_EVT 0x04 + +#define CTS_TIMEOUT_MSECS (1000) +#define RESPONSE_TIMEOUT_MSECS (1000) + +#define adapter (&common_hal_bleio_adapter_obj) + +// These are the headers of the full packets that are sent over the serial interface. +// They all have a one-byte type-field at the front, one of the H4_xxx packet types. + +typedef struct __attribute__ ((packed)) { + uint8_t pkt_type; + uint16_t opcode; + uint8_t param_len; + uint8_t params[]; +} h4_hci_cmd_pkt_t; + +#define ACL_DATA_PB_FIRST_NON_FLUSH 0 +#define ACL_DATA_PB_MIDDLE 1 +#define ACL_DATA_PB_FIRST_FLUSH 2 +#define ACL_DATA_PB_FULL 3 + +typedef struct __attribute__ ((packed)) { + uint8_t pkt_type; + uint16_t handle : 12; + uint8_t pb: 2; // Packet boundary flag: ACL_DATA_PB values. + uint8_t bc: 2; // Broadcast flag: always 0b00 for BLE. + uint16_t data_len; // length of data[] in this packet. + uint8_t data[]; +} h4_hci_acl_pkt_t; + +// The ACL data in an h4_hci_acl_pkt_t may be fragmented across +// multiple ACL_DATA packets, and need to be recombined. This is the +// structure of the combined packet or the first fragment. +typedef struct __attribute__ ((packed)) { + uint16_t acl_data_len; // Length of acl_data. Does not include this header. + uint16_t cid; // Channel ID. + uint8_t acl_data[]; // Length is acl_data_len of full packet. +} acl_data_t; + +typedef struct __attribute__ ((packed)) { + uint8_t pkt_type; + uint8_t evt; + uint8_t param_len; + uint8_t params[]; +} h4_hci_evt_pkt_t; + + +////////////////////////////////////////////////////////////////////// +// Static storage: + +//FIX size +#define RX_BUFFER_SIZE (3 + 255) +#define ACL_DATA_BUFFER_SIZE (255) + +STATIC uint8_t rx_buffer[RX_BUFFER_SIZE]; +STATIC size_t rx_idx; + +STATIC uint8_t acl_data_buffer[ACL_DATA_BUFFER_SIZE]; +STATIC size_t acl_data_len; + +STATIC size_t num_command_packets_allowed; +STATIC size_t max_pkt; +STATIC size_t pending_pkt; + +// Results from parsing a command response packet. +STATIC bool cmd_response_received; +STATIC uint16_t cmd_response_opcode; +STATIC uint8_t cmd_response_status; +STATIC size_t cmd_response_len; +STATIC uint8_t* cmd_response_data; + +STATIC volatile bool hci_poll_in_progress = false; + +STATIC bool debug = true; + +////////////////////////////////////////////////////////////////////// + +STATIC void dump_cmd_pkt(bool tx, uint8_t pkt_len, uint8_t pkt_data[]) { + if (debug) { + h4_hci_cmd_pkt_t *pkt = (h4_hci_cmd_pkt_t *) pkt_data; + mp_printf(&mp_plat_print, + "%s HCI COMMAND (%x) opcode: %04x, len: %d, data: ", + tx ? "TX->" : "RX<-", + pkt->pkt_type, pkt->opcode, pkt->param_len); + for (size_t i = 0; i < pkt->param_len; i++) { + mp_printf(&mp_plat_print, "%02x ", pkt->params[i]); + } + if (pkt_len != sizeof(h4_hci_cmd_pkt_t) + pkt->param_len) { + mp_printf(&mp_plat_print, " LENGTH MISMATCH"); + } + mp_printf(&mp_plat_print, "\n"); + } +} + +STATIC void dump_acl_pkt(bool tx, uint8_t pkt_len, uint8_t pkt_data[]) { + if (debug) { + // mp_printf(&mp_plat_print, "\\ PKT_DATA: "); + // for (size_t i = 0; i < pkt_len; i++) { + // mp_printf(&mp_plat_print, "%02x ", pkt_data[i]); + // } + // mp_printf(&mp_plat_print, "\n"); + h4_hci_acl_pkt_t *pkt = (h4_hci_acl_pkt_t *) pkt_data; + mp_printf(&mp_plat_print, + "%s HCI ACLDATA (%x) handle: %04x, pb: %d, bc: %d, data_len: %d, ", + tx ? "TX->" : "RX<-", pkt->pkt_type, pkt->handle, pkt->pb, pkt->bc, pkt->data_len); + + if (pkt->pb != ACL_DATA_PB_MIDDLE) { + // This is the start of a fragmented acl_data packet or is a full packet. + acl_data_t *acl = (acl_data_t *) pkt->data; + mp_printf(&mp_plat_print, + "acl data_len: %d, cid: %04x, data: ", + acl->acl_data_len, acl->cid); + for (size_t i = 0; i < acl->acl_data_len; i++) { + mp_printf(&mp_plat_print, "%02x ", acl->acl_data[i]); + } + } else { + for (size_t i = 0; i < pkt->data_len; i++) { + mp_printf(&mp_plat_print, "more data: %02x ", pkt->data[i]); + } + } + + if (pkt_len != sizeof(h4_hci_acl_pkt_t) + pkt->data_len) { + mp_printf(&mp_plat_print, " LENGTH MISMATCH"); + } + mp_printf(&mp_plat_print, "\n"); + } +} + +STATIC void dump_evt_pkt(bool tx, uint8_t pkt_len, uint8_t pkt_data[]) { + if (debug) { + h4_hci_evt_pkt_t *pkt = (h4_hci_evt_pkt_t *) pkt_data; + mp_printf(&mp_plat_print, + "%s HCI EVENT (%x) evt: %02x, param_len: %d, data: ", + tx ? "TX->" : "RX<-", + pkt->pkt_type, pkt->evt, pkt->param_len); + for (size_t i = 0; i < pkt->param_len; i++) { + mp_printf(&mp_plat_print, "%02x ", pkt->params[i]); + } + if (pkt_len != sizeof(h4_hci_evt_pkt_t) + pkt->param_len) { + mp_printf(&mp_plat_print, " LENGTH MISMATCH"); + } + mp_printf(&mp_plat_print, "\n"); + } +} + +STATIC void process_acl_data_pkt(uint8_t pkt_len, uint8_t pkt_data[]) { + h4_hci_acl_pkt_t *pkt = (h4_hci_acl_pkt_t*) pkt_data; + + if (pkt->pb != ACL_DATA_PB_MIDDLE) { + // This is the start of a fragmented acl_data packet or is a full packet. + memcpy(acl_data_buffer, pkt->data, pkt->data_len); + acl_data_len = pkt->data_len; + } else { + // This is a middle or end fragment of acl data. + // Append to the accumulated data so far. + memcpy(&acl_data_buffer[acl_data_len], pkt->data, pkt->data_len); + acl_data_len += pkt->data_len; + } + + acl_data_t *acl = (acl_data_t *) &acl_data_buffer; + if (acl_data_len != acl->acl_data_len) { + // We don't have the full packet yet. + return; + } + + if (acl->cid == BT_L2CAP_CID_ATT) { + att_process_data(pkt->handle, acl->acl_data_len, acl->acl_data); + } + // } else if (aclHdr->cid == BT_L2CAP_CID_LE_SIG) { + // L2CAPSignaling.handleData(aclHdr->handle & 0x0fff, aclHdr->len, &rx_buffer[1 + sizeof(HCIACLHdr)]); + // } else { + // struct __attribute__ ((packed)) { + // uint8_t op; + // uint8_t id; + // uint16_t length; + // uint16_t reason; + // uint16_t localCid; + // uint16_t remoteCid; + // } l2capRejectCid= { 0x01, 0x00, 0x006, 0x0002, aclHdr->cid, 0x0000 }; + + // sendAclPkt(aclHdr->handle & 0x0fff, 0x0005, sizeof(l2capRejectCid), &l2capRejectCid); + // } +} + +// Process number of completed packets. Reduce number of pending packets by reported +// number of completed. +STATIC void process_num_comp_pkts(uint16_t handle, uint16_t num_pkts) { + if (num_pkts && pending_pkt > num_pkts) { + pending_pkt -= num_pkts; + } else { + pending_pkt = 0; + } +} + +STATIC void process_evt_pkt(size_t pkt_len, uint8_t pkt_data[]) +{ + h4_hci_evt_pkt_t *pkt = (h4_hci_evt_pkt_t*) pkt_data; + + switch (pkt->evt) { + case BT_HCI_EVT_DISCONN_COMPLETE: { + struct bt_hci_evt_disconn_complete *disconn_complete = + (struct bt_hci_evt_disconn_complete*) pkt->params; + (void) disconn_complete; + //FIX + // ATT.removeConnection(disconn_complete->handle, disconn_complete->reason); + // L2CAPSignaling.removeConnection(disconn_complete->handle, disconn_complete->reason); + hci_le_set_advertising_enable(0x01); + break; + } + + case BT_HCI_EVT_CMD_COMPLETE: { + + struct cmd_complete_with_status { + struct bt_hci_evt_cmd_complete cmd_complete; + struct bt_hci_evt_cc_status cc_status; + } __packed; + + struct cmd_complete_with_status *evt = (struct cmd_complete_with_status *) pkt->params; + + num_command_packets_allowed = evt->cmd_complete.ncmd; + + cmd_response_received = true; + cmd_response_opcode = evt->cmd_complete.opcode; + cmd_response_status = evt->cc_status.status; + // All the bytes following cmd_complete, -including- the status byte, which is + // included in all the _bt_hci_rp_* structs. + cmd_response_data = (uint8_t *) &evt->cc_status; + // Includes status byte. + cmd_response_len = pkt->param_len - sizeof_field(struct cmd_complete_with_status, cmd_complete); + + break; + } + + case BT_HCI_EVT_CMD_STATUS: { + struct bt_hci_evt_cmd_status *evt = (struct bt_hci_evt_cmd_status *) pkt->params; + + num_command_packets_allowed = evt->ncmd; + + cmd_response_received = true; + cmd_response_opcode = evt->opcode; + cmd_response_status = evt->status; + cmd_response_data = NULL; + cmd_response_len = 0; + + break; + } + + case BT_HCI_EVT_NUM_COMPLETED_PACKETS: { + struct bt_hci_evt_num_completed_packets *evt = + (struct bt_hci_evt_num_completed_packets *) pkt->params; + + // Start at zero-th pair: (conn handle, num completed packets). + struct bt_hci_handle_count *handle_and_count = &(evt->h[0]); + for (uint8_t i = 0; i < evt->num_handles; i++) { + process_num_comp_pkts(handle_and_count->handle, handle_and_count->count); + handle_and_count++; + } + break; + } + + case BT_HCI_EVT_LE_META_EVENT: { + struct bt_hci_evt_le_meta_event *meta_evt = (struct bt_hci_evt_le_meta_event *) pkt->params; + uint8_t *le_evt = pkt->params + sizeof (struct bt_hci_evt_le_meta_event); + + if (meta_evt->subevent == BT_HCI_EVT_LE_CONN_COMPLETE) { + struct bt_hci_evt_le_conn_complete *le_conn_complete = + (struct bt_hci_evt_le_conn_complete *) le_evt; + + if (le_conn_complete->status == BT_HCI_ERR_SUCCESS) { + // ATT.addConnection(le_conn_complete->handle, + // le_conn_complete->role, + // le_conn_complete->peer_addr //FIX struct + // le_conn_complete->interval, + // le_conn_complete->latency, + // le_conn_complete->supv_timeout + // le_conn_complete->clock_accuracy); + + } + } else if (meta_evt->subevent == BT_HCI_EVT_LE_ADVERTISING_REPORT) { + struct bt_hci_evt_le_advertising_info *le_advertising_info = + (struct bt_hci_evt_le_advertising_info *) le_evt; + if (le_advertising_info->evt_type == BT_HCI_ADV_DIRECT_IND) { //FIX handle kind of advertising + // last byte is RSSI + // GAP.handleLeAdvertisingReport(leAdvertisingReport->type, + // leAdvertisingReport->peerBdaddrType, + // leAdvertisingReport->peerBdaddr, + // leAdvertisingReport->eirLength, + // leAdvertisingReport->eirData, + // rssi); //FIX, don't separate + + } + } + break; + } + + default: + if (debug) { + mp_printf(&mp_plat_print, "process_evt_pkt: Unknown event: %02x\n"); + } + break; + } +} + +void hci_init(void) { + rx_idx = 0; + pending_pkt = 0; + hci_poll_in_progress = false; +} + +hci_result_t hci_poll_for_incoming_pkt_timeout(uint32_t timeout_msecs) { + uint64_t start = supervisor_ticks_ms64(); + + hci_result_t result; + + while (supervisor_ticks_ms64() -start < timeout_msecs) { + result = hci_poll_for_incoming_pkt(); + RUN_BACKGROUND_TASKS; + } + + return result; +} + + +hci_result_t hci_poll_for_incoming_pkt(void) { + if (hci_poll_in_progress) { + return HCI_OK; + } + common_hal_mcu_disable_interrupts(); + if (!hci_poll_in_progress) { + hci_poll_in_progress = true; + } + common_hal_mcu_enable_interrupts(); + + // Assert RTS low to say we're ready to read data. + common_hal_digitalio_digitalinout_set_value(adapter->rts_digitalinout, false); + + int errcode = 0; + bool packet_is_complete = false; + + // Read bytes until we run out, or accumulate a complete packet. + while (common_hal_busio_uart_rx_characters_available(adapter->hci_uart)) { + common_hal_busio_uart_read(adapter->hci_uart, rx_buffer + rx_idx, 1, &errcode); + if (errcode) { + hci_poll_in_progress = false; + return HCI_READ_ERROR; + } + rx_idx++; + + switch (rx_buffer[0]) { + case H4_ACL: + if (rx_idx > sizeof(h4_hci_acl_pkt_t) && + rx_idx >= sizeof(h4_hci_acl_pkt_t) + ((h4_hci_acl_pkt_t *) rx_buffer)->data_len) { + packet_is_complete = true; + } + break; + + case H4_EVT: + if (rx_idx > sizeof(h4_hci_evt_pkt_t) && + rx_idx >= sizeof(h4_hci_evt_pkt_t) + ((h4_hci_evt_pkt_t *) rx_buffer)->param_len) { + packet_is_complete = true; + } + break; + + default: + // Unknown or bad packet type. Start over. + rx_idx = 0; + break; + } + } + + if (!packet_is_complete) { + hci_poll_in_progress = false; + return HCI_OK; + } + + // Stop incoming data while processing packet. + common_hal_digitalio_digitalinout_set_value(adapter->rts_digitalinout, true); + size_t pkt_len = rx_idx; + // Reset for next packet. + rx_idx = 0; + + switch (rx_buffer[0]) { + case H4_ACL: + if (debug) { + dump_acl_pkt(false, pkt_len, rx_buffer); + } + + process_acl_data_pkt(pkt_len, rx_buffer); + break; + + case H4_EVT: + if (debug) { + dump_evt_pkt(false, pkt_len, rx_buffer); + } + + process_evt_pkt(pkt_len, rx_buffer); + break; + + default: + if (debug) { + mp_printf(&mp_plat_print, "Unknown HCI packet type: %d\n", rx_buffer[0]); + } + break; + } + + common_hal_digitalio_digitalinout_set_value(adapter->rts_digitalinout, true); + + hci_poll_in_progress = false; + return HCI_OK; +} + + +STATIC hci_result_t write_pkt(uint8_t *buffer, size_t len) { + // Wait for CTS to go low before writing to HCI adapter. + uint64_t start = supervisor_ticks_ms64(); + + while (common_hal_digitalio_digitalinout_get_value(adapter->cts_digitalinout)) { + RUN_BACKGROUND_TASKS; + if (supervisor_ticks_ms64() - start > CTS_TIMEOUT_MSECS) { + return HCI_WRITE_TIMEOUT; + } + } + + int errcode = 0; + common_hal_busio_uart_write(adapter->hci_uart, buffer, len, &errcode); + if (errcode) { + return HCI_WRITE_ERROR; + } + + return HCI_OK; +} + +STATIC hci_result_t send_command(uint16_t opcode, uint8_t params_len, void* params) { + uint8_t cmd_pkt_len = sizeof(h4_hci_cmd_pkt_t) + params_len; + uint8_t tx_buffer[cmd_pkt_len]; + + // cmd header is at the beginning of tx_buffer + h4_hci_cmd_pkt_t *cmd_pkt = (h4_hci_cmd_pkt_t *) tx_buffer; + cmd_pkt->pkt_type = H4_CMD; + cmd_pkt->opcode = opcode; + cmd_pkt->param_len = params_len; + + memcpy(cmd_pkt->params, params, params_len); + + if (debug) { + dump_cmd_pkt(true, sizeof(tx_buffer), tx_buffer); + } + + int result = write_pkt(tx_buffer, cmd_pkt_len); + if (result != HCI_OK) { + return result; + } + + cmd_response_received = false; + + // Wait for a response. Note that other packets may be received that are not + // command responses. + uint64_t start = supervisor_ticks_ms64(); + while (1) { + result = hci_poll_for_incoming_pkt(); + if (result != HCI_OK) { + // I/O error. + return result; + } + + if (cmd_response_received && cmd_response_opcode == opcode) { + // If this is definitely a response to the command that was sent, + // return the status value, which will will be + // BT_HCI_ERR_SUCCESS (0x00) if the command succeeded, + // or a BT_HCI_ERR_x value (> 0x00) if there ws a problem. + return cmd_response_status; + } + + if (supervisor_ticks_ms64() - start > RESPONSE_TIMEOUT_MSECS) { + return HCI_READ_TIMEOUT; + } + RUN_BACKGROUND_TASKS; + } + + // No I/O error, but no response sent back in time. + return HCI_NO_RESPONSE; +} + +hci_result_t hci_send_acl_pkt(uint16_t handle, uint8_t cid, uint8_t data_len, uint8_t *data) { + int result; + while (pending_pkt >= max_pkt) { + result = hci_poll_for_incoming_pkt(); + if (result != HCI_OK) { + return result; + } + } + + // data_len does not include cid + const size_t cid_len = sizeof_field(acl_data_t, cid); + // buf_len is size of entire packet including header. + const size_t buf_len = sizeof(h4_hci_acl_pkt_t) + cid_len + data_len; + uint8_t tx_buffer[buf_len]; + + h4_hci_acl_pkt_t *acl_pkt = (h4_hci_acl_pkt_t *) tx_buffer; + acl_data_t *acl_data = (acl_data_t *) acl_pkt->data; + acl_pkt->pkt_type = H4_ACL; + acl_pkt->handle = handle; + acl_pkt->data_len = (uint8_t)(cid_len + data_len); + acl_data->acl_data_len = (uint8_t) data_len; + acl_data->cid = cid; + + memcpy(&tx_buffer[sizeof(h4_hci_acl_pkt_t)], data, data_len); + + if (debug) { + dump_acl_pkt(true, buf_len, tx_buffer); + } + + pending_pkt++; + + int errcode = 0; + common_hal_busio_uart_write(adapter->hci_uart, tx_buffer, buf_len, &errcode); + if (errcode) { + return HCI_WRITE_ERROR; + } + + return HCI_OK; +} + +hci_result_t hci_reset(void) { + return send_command(BT_HCI_OP_RESET, 0, NULL); +} + +hci_result_t hci_read_local_version(uint8_t *hci_version, uint16_t *hci_revision, uint8_t *lmp_version, uint16_t *manufacturer, uint16_t *lmp_subversion) { + hci_result_t result = send_command(BT_HCI_OP_READ_LOCAL_VERSION_INFO, 0, NULL); + if (result == HCI_OK) { + struct bt_hci_rp_read_local_version_info *response = + (struct bt_hci_rp_read_local_version_info *) cmd_response_data; + *hci_version = response->hci_version; + *hci_revision = response->hci_revision; + *lmp_version = response->lmp_version; + *manufacturer = response->manufacturer; + *lmp_subversion = response->lmp_subversion; + } + + return result; +} + +hci_result_t hci_read_bd_addr(bt_addr_t *addr) { + int result = send_command(BT_HCI_OP_READ_BD_ADDR, 0, NULL); + if (result == HCI_OK) { + struct bt_hci_rp_read_bd_addr *response = (struct bt_hci_rp_read_bd_addr *) cmd_response_data; + memcpy(addr->val, response->bdaddr.val, sizeof_field(bt_addr_t, val)); + } + + return result; +} + +hci_result_t hci_read_rssi(uint16_t handle, int *rssi) { + int result = send_command(BT_HCI_OP_READ_RSSI, sizeof(handle), &handle); + if (result == HCI_OK) { + struct bt_hci_rp_read_rssi *response = (struct bt_hci_rp_read_rssi *) cmd_response_data; + if (response->handle != handle) { + // Handle doesn't match. + return HCI_NO_RESPONSE; + } + + *rssi = response->rssi; + } + + return result; +} + +hci_result_t hci_set_evt_mask(uint64_t event_mask) { + return send_command(BT_HCI_OP_SET_EVENT_MASK, sizeof(event_mask), &event_mask); +} + +hci_result_t hci_le_read_buffer_size(uint16_t *le_max_len, uint8_t *le_max_num) { + int result = send_command(BT_HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL); + if (result == HCI_OK) { + struct bt_hci_rp_le_read_buffer_size *response = + (struct bt_hci_rp_le_read_buffer_size *) cmd_response_data; + *le_max_len = response->le_max_len; + *le_max_num = response->le_max_num; + } + + return result; +} + +hci_result_t hci_read_buffer_size(uint16_t *acl_max_len, uint8_t *sco_max_len, uint16_t *acl_max_num, uint16_t *sco_max_num) { + int result = send_command(BT_HCI_OP_READ_BUFFER_SIZE, 0, NULL); + if (result == HCI_OK) { + struct bt_hci_rp_read_buffer_size *response = + (struct bt_hci_rp_read_buffer_size *) cmd_response_data; + *acl_max_len = response->acl_max_len; + *sco_max_len = response->sco_max_len; + *acl_max_num = response->acl_max_num; + *sco_max_num = response->sco_max_num; + } + + return result; +} + +hci_result_t hci_le_set_random_address(uint8_t addr[6]) { + return send_command(BT_HCI_OP_LE_SET_RANDOM_ADDRESS, 6, addr); +} + +hci_result_t hci_le_set_advertising_parameters(uint16_t min_interval, uint16_t max_interval, uint8_t type, uint8_t own_addr_type, bt_addr_le_t *direct_addr, uint8_t channel_map, uint8_t filter_policy) { + struct bt_hci_cp_le_set_adv_param params = { + .min_interval = min_interval, + .max_interval = max_interval, + .type = type, + .own_addr_type = own_addr_type, + // .direct_addr set below. + .channel_map = channel_map, + .filter_policy = filter_policy, + }; + params.direct_addr.type = direct_addr->type; + memcpy(params.direct_addr.a.val, direct_addr->a.val, sizeof(params.direct_addr.a.val)); + + return send_command(BT_HCI_OP_LE_SET_ADV_PARAM, sizeof(params), ¶ms); +} + +hci_result_t hci_le_set_extended_advertising_parameters(uint8_t handle, uint16_t props, uint32_t prim_min_interval, uint32_t prim_max_interval, uint8_t prim_channel_map, uint8_t own_addr_type, bt_addr_le_t *peer_addr, uint8_t filter_policy, int8_t tx_power, uint8_t prim_adv_phy, uint8_t sec_adv_max_skip, uint8_t sec_adv_phy, uint8_t sid, uint8_t scan_req_notify_enable) { + struct bt_hci_cp_le_set_ext_adv_param params = { + .handle = handle, + .props = props, + // .prim_min_interval and .prim_max_interval set below + .prim_channel_map = prim_channel_map, + .own_addr_type = own_addr_type, + // .peer_addr set below. + .tx_power = tx_power, + .sec_adv_max_skip = sec_adv_max_skip, + .sec_adv_phy = sec_adv_phy, + .sid = sid, + .scan_req_notify_enable = scan_req_notify_enable, + }; + // Assumes little-endian. + memcpy(params.prim_min_interval, (void *) &prim_min_interval, + sizeof_field(struct bt_hci_cp_le_set_ext_adv_param, prim_min_interval)); + memcpy(params.prim_max_interval, (void *) &prim_max_interval, + sizeof_field(struct bt_hci_cp_le_set_ext_adv_param, prim_max_interval)); + memcpy(params.peer_addr.a.val, peer_addr->a.val, sizeof_field(bt_addr_le_t, a.val)); + return send_command(BT_HCI_OP_LE_SET_EXT_ADV_PARAM, sizeof(params), ¶ms); +} + +hci_result_t hci_le_read_maximum_advertising_data_length(uint16_t *max_adv_data_len) { + int result = send_command(BT_HCI_OP_LE_READ_MAX_ADV_DATA_LEN, 0, NULL); + if (result == HCI_OK) { + struct bt_hci_rp_le_read_max_adv_data_len *response = + (struct bt_hci_rp_le_read_max_adv_data_len *) cmd_response_data; + *max_adv_data_len = response->max_adv_data_len; + } + + return result; +} + +hci_result_t hci_le_read_local_supported_features(uint8_t features[8]) { + int result = send_command(BT_HCI_OP_LE_READ_LOCAL_FEATURES, 0, NULL); + if (result == HCI_OK) { + struct bt_hci_rp_le_read_local_features *response = + (struct bt_hci_rp_le_read_local_features *) cmd_response_data; + memcpy(features, response->features, + sizeof_field(struct bt_hci_rp_le_read_local_features, features)); + } + + return result; +} + +hci_result_t hci_le_set_advertising_data(uint8_t len, uint8_t data[]) { + struct bt_hci_cp_le_set_adv_data params = { + // Zero out unused data bytes. + .data = { 0 }, + }; + + params.len = len; + memcpy(params.data, data, len); + + // All data bytes are sent even if some are unused. + return send_command(BT_HCI_OP_LE_SET_ADV_DATA, sizeof(params), ¶ms); +} + +hci_result_t hci_le_set_extended_advertising_data(uint8_t handle, uint8_t op, uint8_t frag_pref, uint8_t len, uint8_t data[]) { + const uint8_t max_len = sizeof_field(struct bt_hci_cp_le_set_ext_adv_data, data); + uint8_t valid_len = MIN(len, max_len); + struct bt_hci_cp_le_set_ext_adv_data params = { + .handle = handle, + .op = op, + .frag_pref = frag_pref, + .len = valid_len, + }; + memcpy(params.data, data, valid_len); + return send_command(BT_HCI_OP_LE_SET_EXT_ADV_DATA, sizeof(params) - (max_len - valid_len), ¶ms); +} + + +hci_result_t hci_le_set_scan_response_data(uint8_t len, uint8_t data[]) { + struct bt_hci_cp_le_set_scan_rsp_data params = { + // Zero out unused data bytes. + .data = { 0 }, + }; + params.len = len; + memcpy(params.data, data, len); + + // All data bytes are sent even if some are unused. + return send_command(BT_HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(params), ¶ms); +} + +hci_result_t hci_le_set_advertising_enable(uint8_t enable) { + return send_command(BT_HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable); +} + +hci_result_t hci_le_set_extended_advertising_enable(uint8_t enable, uint8_t set_num, uint8_t handle[], uint16_t duration[], uint8_t max_ext_adv_evts[]) { + uint8_t params[sizeof(struct bt_hci_cp_le_set_ext_adv_enable) + + set_num * (sizeof(struct bt_hci_ext_adv_set))]; + struct bt_hci_cp_le_set_ext_adv_enable *params_p = (struct bt_hci_cp_le_set_ext_adv_enable *) ¶ms; + params_p->enable = enable; + params_p->set_num = set_num; + for (size_t i = 0; i < set_num; i++) { + params_p->s[i].handle = handle[i]; + params_p->s[i].duration = duration[i]; + params_p->s[i].max_ext_adv_evts = max_ext_adv_evts[i]; + } + + return send_command(BT_HCI_OP_LE_SET_EXT_ADV_ENABLE, sizeof(params), ¶ms); +} + +hci_result_t hci_le_set_scan_parameters(uint8_t scan_type, uint16_t interval, uint16_t window, uint8_t addr_type, uint8_t filter_policy) { + struct bt_hci_cp_le_set_scan_param params = { + .scan_type = scan_type, + .interval = interval, + .window = window, + .addr_type = addr_type, + .filter_policy = filter_policy, + }; + + return send_command(BT_HCI_OP_LE_SET_SCAN_PARAM, sizeof(params), ¶ms); +} + +hci_result_t hci_le_set_scan_enable(uint8_t enable, uint8_t filter_dup) { + struct bt_hci_cp_le_set_scan_enable params = { + .enable = enable, + .filter_dup = filter_dup, + }; + + return send_command(BT_HCI_OP_LE_SET_SCAN_ENABLE, sizeof(params), ¶ms); +} + +hci_result_t hci_le_create_conn(uint16_t scan_interval, uint16_t scan_window, uint8_t filter_policy, bt_addr_le_t *peer_addr, uint8_t own_addr_type, uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout, uint16_t min_ce_len, uint16_t max_ce_len) { + struct bt_hci_cp_le_create_conn params = { + .scan_interval = scan_interval, + .scan_window = scan_window, + .filter_policy = filter_policy, + // .peer_addr is set below + .own_addr_type = own_addr_type, + .conn_interval_min = conn_interval_min, + .conn_interval_max = conn_interval_max, + .conn_latency = conn_latency, + .supervision_timeout = supervision_timeout, + .min_ce_len = min_ce_len, + .max_ce_len = max_ce_len, + }; + params.peer_addr.type = peer_addr->type; + memcpy(params.peer_addr.a.val, peer_addr->a.val, sizeof(params.peer_addr.a.val)); + + return send_command(BT_HCI_OP_LE_CREATE_CONN, sizeof(params), ¶ms); +} + +hci_result_t hci_le_cancel_conn(void) { + return send_command(BT_HCI_OP_CONNECT_CANCEL, 0, NULL); +} + +hci_result_t hci_le_conn_update(uint16_t handle, uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout) { + struct hci_cp_le_conn_update params = { + .handle = handle, + .conn_interval_min = conn_interval_min, + .conn_interval_max = conn_interval_max, + .conn_latency = conn_latency, + .supervision_timeout = supervision_timeout, + .min_ce_len = 4, + .max_ce_len = 6, + }; + + return send_command(BT_HCI_OP_LE_CONN_UPDATE, sizeof(params), ¶ms); +} + +hci_result_t hci_disconnect(uint16_t handle) { + struct bt_hci_cp_disconnect params = { + .handle = handle, + .reason = BT_HCI_ERR_REMOTE_USER_TERM_CONN, + }; + + return send_command(BT_HCI_OP_DISCONNECT, sizeof(params), ¶ms); +} diff --git a/devices/ble_hci/common-hal/_bleio/hci.h b/devices/ble_hci/common-hal/_bleio/hci.h new file mode 100644 index 000000000..736877ddc --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/hci.h @@ -0,0 +1,79 @@ +/* + This file is part of the ArduinoBLE library. + Copyright (c) 2018 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef MICROPY_INCLUDED_DEVICES_BLE_HCI_COMMON_HAL_BLEIO_HCI_H +#define MICROPY_INCLUDED_DEVICES_BLE_HCI_COMMON_HAL_BLEIO_HCI_H + +#include + +#include "common-hal/_bleio/hci_include/hci.h" +#include "common-hal/_bleio/hci_include/hci_err.h" + +// Incomplete forward declaration to get around mutually-dependent include files. +typedef struct _bleio_adapter_obj_t bleio_adapter_obj_t; + +// An hci_result_t is one of the HCI_x values below, +// or is it > 0 and is an HCI command status value (see hci_include/hci_err.h) +typedef int hci_result_t; +#define HCI_OK (0) +#define HCI_NO_RESPONSE (-1) +#define HCI_READ_TIMEOUT (-2) +#define HCI_WRITE_TIMEOUT (-3) +#define HCI_READ_ERROR (-4) +#define HCI_WRITE_ERROR (-5) + +void hci_init(void); + +hci_result_t hci_disconnect(uint16_t handle); + +hci_result_t hci_le_cancel_conn(void); +hci_result_t hci_le_conn_update(uint16_t handle, uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout); +hci_result_t hci_le_create_conn(uint16_t scan_interval, uint16_t scan_window, uint8_t filter_policy, bt_addr_le_t *peer_addr, uint8_t own_addr_type, uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout, uint16_t min_ce_len, uint16_t max_ce_len); + +hci_result_t hci_le_read_buffer_size(uint16_t *le_max_len, uint8_t *le_max_num); +hci_result_t hci_le_read_maximum_advertising_data_length(uint16_t *max_adv_data_len); +hci_result_t hci_le_read_local_supported_features(uint8_t features[8]); + +hci_result_t hci_le_set_advertising_data(uint8_t length, uint8_t data[]); +hci_result_t hci_le_set_advertising_enable(uint8_t enable); +hci_result_t hci_le_set_advertising_parameters(uint16_t min_interval, uint16_t max_interval, uint8_t type, uint8_t own_addr_type, bt_addr_le_t *direct_addr, uint8_t channel_map, uint8_t filter_policy); + +hci_result_t hci_le_set_extended_advertising_data(uint8_t handle, uint8_t op, uint8_t frag_pref, uint8_t len, uint8_t data[]); +hci_result_t hci_le_set_extended_advertising_enable(uint8_t enable, uint8_t set_num, uint8_t handle[], uint16_t duration[], uint8_t max_ext_adv_evts[]); +hci_result_t hci_le_set_extended_advertising_parameters(uint8_t handle, uint16_t props, uint32_t prim_min_interval, uint32_t prim_max_interval, uint8_t prim_channel_map, uint8_t own_addr_type, bt_addr_le_t *peer_addr, uint8_t filter_policy, int8_t tx_power, uint8_t prim_adv_phy, uint8_t sec_adv_max_skip, uint8_t sec_adv_phy, uint8_t sid, uint8_t scan_req_notify_enable); + +hci_result_t hci_le_set_random_address(uint8_t addr[6]); +hci_result_t hci_le_set_scan_enable(uint8_t enable, uint8_t filter_dup); +hci_result_t hci_le_set_scan_parameters(uint8_t scan_type, uint16_t interval, uint16_t window, uint8_t addr_type, uint8_t filter_policy); +hci_result_t hci_le_set_scan_response_data(uint8_t length, uint8_t data[]); + +hci_result_t hci_poll_for_incoming_pkt(void); +hci_result_t hci_poll_for_incoming_pkt_timeout(uint32_t timeout_msecs); + +hci_result_t hci_read_bd_addr(bt_addr_t *addr); +hci_result_t hci_read_buffer_size(uint16_t *acl_max_len, uint8_t *sco_max_len, uint16_t *acl_max_num, uint16_t *sco_max_num); +hci_result_t hci_read_local_version(uint8_t *hci_version, uint16_t *hci_revision, uint8_t *lmp_version, uint16_t *manufacturer, uint16_t *lmp_subversion); +hci_result_t hci_read_rssi(uint16_t handle, int *rssi); + +hci_result_t hci_reset(void); + +hci_result_t hci_send_acl_pkt(uint16_t handle, uint8_t cid, uint8_t data_len, uint8_t *data); +hci_result_t hci_set_evt_mask(uint64_t event_mask); + +#endif // MICROPY_INCLUDED_DEVICES_BLE_HCI_COMMON_HAL_BLEIO_HCI_H diff --git a/devices/ble_hci/common-hal/_bleio/hci_api.c b/devices/ble_hci/common-hal/_bleio/hci_api.c deleted file mode 100644 index 854f7c0a0..000000000 --- a/devices/ble_hci/common-hal/_bleio/hci_api.c +++ /dev/null @@ -1,808 +0,0 @@ -// This file is derived from the ArduinoBLE library. Its header is below. -/* - This file is part of the ArduinoBLE library. - Copyright (c) 2018 Arduino SA. All rights reserved. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include "hci_api.h" - -#include "py/obj.h" - -// Zephyr include files to define HCI communication values and structs. -#include "hci_include/hci.h" -#include "hci_include/hci_err.h" - -#include - -#include "supervisor/shared/tick.h" -#include "shared-bindings/_bleio/__init__.h" -#include "common-hal/_bleio/Adapter.h" -#include "shared-bindings/microcontroller/__init__.h" - -// HCI H4 protocol packet types: first byte in the packet. -#define H4_CMD 0x01 -#define H4_ACL 0x02 -#define H4_SCO 0x03 -#define H4_EVT 0x04 - -//FIX replace -#define ATT_CID 0x0004 - -#define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER)) - -#define RX_BUFFER_SIZE (3 + 255) -#define ACL_DATA_BUFFER_SIZE (255 + 1) - -#define CTS_TIMEOUT_MSECS (1000) -#define RESPONSE_TIMEOUT_MSECS (1000) - -#define adapter (&common_hal_bleio_adapter_obj) - -STATIC uint8_t rx_buffer[RX_BUFFER_SIZE]; -STATIC size_t rx_idx; - -STATIC size_t num_command_packets_allowed; -STATIC size_t max_pkt; -STATIC size_t pending_pkt; - -// Results from parsing a command response packet. -STATIC bool cmd_response_received; -STATIC uint16_t cmd_response_opcode; -STATIC uint8_t cmd_response_status; -STATIC size_t cmd_response_len; -STATIC uint8_t* cmd_response_data; - -STATIC uint8_t acl_data_buffer[ACL_DATA_BUFFER_SIZE]; -STATIC size_t acl_data_len; - -STATIC volatile bool hci_poll_in_progress = false; - -STATIC bool debug = true; - -// These are the headers of the full packets that are sent over the serial interface. -// They all have a one-byte type-field at the front, one of the H4_xxx packet types. - -typedef struct __attribute__ ((packed)) { - uint8_t pkt_type; - uint16_t opcode; - uint8_t param_len; - uint8_t params[]; -} h4_hci_cmd_pkt_t; - -#define ACL_DATA_PB_FIRST_NON_FLUSH 0 -#define ACL_DATA_PB_MIDDLE 1 -#define ACL_DATA_PB_FIRST_FLUSH 2 -#define ACL_DATA_PB_FULL 3 - -typedef struct __attribute__ ((packed)) { - uint8_t pkt_type; - uint16_t handle : 12; - uint8_t pb: 2; // Packet boundary flag: ACL_DATA_PB values. - uint8_t bc: 2; // Broadcast flag: always 0b00 for BLE. - uint16_t data_len; // length of data[] in this packet. - uint8_t data[]; -} h4_hci_acl_pkt_t; - -// The ACL data in an h4_hci_acl_pkt_t may be fragmented across -// multiple ACL_DATA packets, and need to be recombined. This is the -// structure of the combined packet or the first fragment. -typedef struct __attribute__ ((packed)) { - uint16_t acl_data_len; // Length of acl_data. Does not include this header. - uint16_t cid; // Channel ID. - uint8_t acl_data[]; // Length is acl_data_len of full packet. -} acl_data_t; - -typedef struct __attribute__ ((packed)) { - uint8_t pkt_type; - uint8_t evt; - uint8_t param_len; - uint8_t params[]; -} h4_hci_evt_pkt_t; - - -STATIC void dump_cmd_pkt(bool tx, uint8_t pkt_len, uint8_t pkt_data[]) { - if (debug) { - h4_hci_cmd_pkt_t *pkt = (h4_hci_cmd_pkt_t *) pkt_data; - mp_printf(&mp_plat_print, - "%s HCI COMMAND (%x) opcode: %04x, len: %d, data: ", - tx ? "TX->" : "RX<-", - pkt->pkt_type, pkt->opcode, pkt->param_len); - for (size_t i = 0; i < pkt->param_len; i++) { - mp_printf(&mp_plat_print, "%02x ", pkt->params[i]); - } - if (pkt_len != sizeof(h4_hci_cmd_pkt_t) + pkt->param_len) { - mp_printf(&mp_plat_print, " LENGTH MISMATCH"); - } - mp_printf(&mp_plat_print, "\n"); - } -} - -STATIC void dump_acl_pkt(bool tx, uint8_t pkt_len, uint8_t pkt_data[]) { - if (debug) { - // mp_printf(&mp_plat_print, "\\ PKT_DATA: "); - // for (size_t i = 0; i < pkt_len; i++) { - // mp_printf(&mp_plat_print, "%02x ", pkt_data[i]); - // } - // mp_printf(&mp_plat_print, "\n"); - h4_hci_acl_pkt_t *pkt = (h4_hci_acl_pkt_t *) pkt_data; - mp_printf(&mp_plat_print, - "%s HCI ACLDATA (%x) handle: %04x, pb: %d, bc: %d, data_len: %d, ", - tx ? "TX->" : "RX<-", pkt->pkt_type, pkt->handle, pkt->pb, pkt->bc, pkt->data_len); - - if (pkt->pb != ACL_DATA_PB_MIDDLE) { - // This is the start of a fragmented acl_data packet or is a full packet. - acl_data_t *acl = (acl_data_t *) pkt->data; - mp_printf(&mp_plat_print, - "acl data_len: %d, cid: %04x, data: ", - acl->acl_data_len, acl->cid); - for (size_t i = 0; i < acl->acl_data_len; i++) { - mp_printf(&mp_plat_print, "%02x ", acl->acl_data[i]); - } - } else { - for (size_t i = 0; i < pkt->data_len; i++) { - mp_printf(&mp_plat_print, "more data: %02x ", pkt->data[i]); - } - } - - if (pkt_len != sizeof(h4_hci_acl_pkt_t) + pkt->data_len) { - mp_printf(&mp_plat_print, " LENGTH MISMATCH"); - } - mp_printf(&mp_plat_print, "\n"); - } -} - -STATIC void dump_evt_pkt(bool tx, uint8_t pkt_len, uint8_t pkt_data[]) { - if (debug) { - h4_hci_evt_pkt_t *pkt = (h4_hci_evt_pkt_t *) pkt_data; - mp_printf(&mp_plat_print, - "%s HCI EVENT (%x) evt: %02x, param_len: %d, data: ", - tx ? "TX->" : "RX<-", - pkt->pkt_type, pkt->evt, pkt->param_len); - for (size_t i = 0; i < pkt->param_len; i++) { - mp_printf(&mp_plat_print, "%02x ", pkt->params[i]); - } - if (pkt_len != sizeof(h4_hci_evt_pkt_t) + pkt->param_len) { - mp_printf(&mp_plat_print, " LENGTH MISMATCH"); - } - mp_printf(&mp_plat_print, "\n"); - } -} - -STATIC void process_acl_data_pkt(uint8_t pkt_len, uint8_t pkt_data[]) { - h4_hci_acl_pkt_t *pkt = (h4_hci_acl_pkt_t*) pkt_data; - - if (pkt->pb != ACL_DATA_PB_MIDDLE) { - // This is the start of a fragmented acl_data packet or is a full packet. - memcpy(acl_data_buffer, pkt->data, pkt->data_len); - acl_data_len = pkt->data_len; - } else { - // This is a middle or end fragment of acl data. - // Append to the accumulated data so far. - memcpy(&acl_data_buffer[acl_data_len], pkt->data, pkt->data_len); - acl_data_len += pkt->data_len; - } - - acl_data_t *acl_so_far = (acl_data_t *) acl_data_buffer; - if (acl_data_len != acl_so_far->acl_data_len) { - // We don't have the full packet yet. - return; - } - - // if (aclHdr->cid == ATT_CID) { - // ATT.handleData(aclHdr->handle & 0x0fff, aclHdr->len, &rx_buffer[1 + sizeof(HCIACLHdr)]); - // } else if (aclHdr->cid == SIGNALING_CID) { - // L2CAPSignaling.handleData(aclHdr->handle & 0x0fff, aclHdr->len, &rx_buffer[1 + sizeof(HCIACLHdr)]); - // } else { - // struct __attribute__ ((packed)) { - // uint8_t op; - // uint8_t id; - // uint16_t length; - // uint16_t reason; - // uint16_t localCid; - // uint16_t remoteCid; - // } l2capRejectCid= { 0x01, 0x00, 0x006, 0x0002, aclHdr->cid, 0x0000 }; - - // sendAclPkt(aclHdr->handle & 0x0fff, 0x0005, sizeof(l2capRejectCid), &l2capRejectCid); - // } -} - -// Process number of completed packets. Reduce number of pending packets by reported -// number of completed. -STATIC void process_num_comp_pkts(uint16_t handle, uint16_t num_pkts) { - if (num_pkts && pending_pkt > num_pkts) { - pending_pkt -= num_pkts; - } else { - pending_pkt = 0; - } -} - -STATIC void process_evt_pkt(size_t pkt_len, uint8_t pkt_data[]) -{ - h4_hci_evt_pkt_t *pkt = (h4_hci_evt_pkt_t*) pkt_data; - - switch (pkt->evt) { - case BT_HCI_EVT_DISCONN_COMPLETE: { - struct bt_hci_evt_disconn_complete *disconn_complete = - (struct bt_hci_evt_disconn_complete*) pkt->params; - (void) disconn_complete; - //FIX - // ATT.removeConnection(disconn_complete->handle, disconn_complete->reason); - // L2CAPSignaling.removeConnection(disconn_complete->handle, disconn_complete->reason); - hci_le_set_advertising_enable(0x01); - break; - } - - case BT_HCI_EVT_CMD_COMPLETE: { - - struct cmd_complete_with_status { - struct bt_hci_evt_cmd_complete cmd_complete; - struct bt_hci_evt_cc_status cc_status; - } __packed; - - struct cmd_complete_with_status *evt = (struct cmd_complete_with_status *) pkt->params; - - num_command_packets_allowed = evt->cmd_complete.ncmd; - - cmd_response_received = true; - cmd_response_opcode = evt->cmd_complete.opcode; - cmd_response_status = evt->cc_status.status; - // All the bytes following cmd_complete, -including- the status byte, which is - // included in all the _bt_hci_rp_* structs. - cmd_response_data = (uint8_t *) &evt->cc_status; - // Includes status byte. - cmd_response_len = pkt->param_len - sizeof_field(struct cmd_complete_with_status, cmd_complete); - - break; - } - - case BT_HCI_EVT_CMD_STATUS: { - struct bt_hci_evt_cmd_status *evt = (struct bt_hci_evt_cmd_status *) pkt->params; - - num_command_packets_allowed = evt->ncmd; - - cmd_response_received = true; - cmd_response_opcode = evt->opcode; - cmd_response_status = evt->status; - cmd_response_data = NULL; - cmd_response_len = 0; - - break; - } - - case BT_HCI_EVT_NUM_COMPLETED_PACKETS: { - struct bt_hci_evt_num_completed_packets *evt = - (struct bt_hci_evt_num_completed_packets *) pkt->params; - - // Start at zero-th pair: (conn handle, num completed packets). - struct bt_hci_handle_count *handle_and_count = &(evt->h[0]); - for (uint8_t i = 0; i < evt->num_handles; i++) { - process_num_comp_pkts(handle_and_count->handle, handle_and_count->count); - handle_and_count++; - } - break; - } - - case BT_HCI_EVT_LE_META_EVENT: { - struct bt_hci_evt_le_meta_event *meta_evt = (struct bt_hci_evt_le_meta_event *) pkt->params; - uint8_t *le_evt = pkt->params + sizeof (struct bt_hci_evt_le_meta_event); - - if (meta_evt->subevent == BT_HCI_EVT_LE_CONN_COMPLETE) { - struct bt_hci_evt_le_conn_complete *le_conn_complete = - (struct bt_hci_evt_le_conn_complete *) le_evt; - - if (le_conn_complete->status == BT_HCI_ERR_SUCCESS) { - // ATT.addConnection(le_conn_complete->handle, - // le_conn_complete->role, - // le_conn_complete->peer_addr //FIX struct - // le_conn_complete->interval, - // le_conn_complete->latency, - // le_conn_complete->supv_timeout - // le_conn_complete->clock_accuracy); - - } - } else if (meta_evt->subevent == BT_HCI_EVT_LE_ADVERTISING_REPORT) { - struct bt_hci_evt_le_advertising_info *le_advertising_info = - (struct bt_hci_evt_le_advertising_info *) le_evt; - if (le_advertising_info->evt_type == BT_HCI_ADV_DIRECT_IND) { //FIX handle kind of advertising - // last byte is RSSI - // GAP.handleLeAdvertisingReport(leAdvertisingReport->type, - // leAdvertisingReport->peerBdaddrType, - // leAdvertisingReport->peerBdaddr, - // leAdvertisingReport->eirLength, - // leAdvertisingReport->eirData, - // rssi); //FIX, don't separate - - } - } - break; - } - - default: - if (debug) { - mp_printf(&mp_plat_print, "process_evt_pkt: Unknown event: %02x\n"); - } - break; - } -} - -void hci_init(void) { - rx_idx = 0; - pending_pkt = 0; - hci_poll_in_progress = false; -} - -hci_result_t hci_poll_for_incoming_pkt(void) { - if (hci_poll_in_progress) { - return HCI_OK; - } - common_hal_mcu_disable_interrupts(); - if (!hci_poll_in_progress) { - hci_poll_in_progress = true; - } - common_hal_mcu_enable_interrupts(); - - // Assert RTS low to say we're ready to read data. - common_hal_digitalio_digitalinout_set_value(adapter->rts_digitalinout, false); - - int errcode = 0; - bool packet_is_complete = false; - - // Read bytes until we run out, or accumulate a complete packet. - while (common_hal_busio_uart_rx_characters_available(adapter->hci_uart)) { - common_hal_busio_uart_read(adapter->hci_uart, rx_buffer + rx_idx, 1, &errcode); - if (errcode) { - hci_poll_in_progress = false; - return HCI_READ_ERROR; - } - rx_idx++; - - switch (rx_buffer[0]) { - case H4_ACL: - if (rx_idx > sizeof(h4_hci_acl_pkt_t) && - rx_idx >= sizeof(h4_hci_acl_pkt_t) + ((h4_hci_acl_pkt_t *) rx_buffer)->data_len) { - packet_is_complete = true; - } - break; - - case H4_EVT: - if (rx_idx > sizeof(h4_hci_evt_pkt_t) && - rx_idx >= sizeof(h4_hci_evt_pkt_t) + ((h4_hci_evt_pkt_t *) rx_buffer)->param_len) { - packet_is_complete = true; - } - break; - - default: - // Unknown or bad packet type. Start over. - rx_idx = 0; - break; - } - } - - if (!packet_is_complete) { - hci_poll_in_progress = false; - return HCI_OK; - } - - // Stop incoming data while processing packet. - common_hal_digitalio_digitalinout_set_value(adapter->rts_digitalinout, true); - size_t pkt_len = rx_idx; - // Reset for next packet. - rx_idx = 0; - - switch (rx_buffer[0]) { - case H4_ACL: - if (debug) { - dump_acl_pkt(false, pkt_len, rx_buffer); - } - - process_acl_data_pkt(pkt_len, rx_buffer); - break; - - case H4_EVT: - if (debug) { - dump_evt_pkt(false, pkt_len, rx_buffer); - } - - process_evt_pkt(pkt_len, rx_buffer); - break; - - default: - if (debug) { - mp_printf(&mp_plat_print, "Unknown HCI packet type: %d\n", rx_buffer[0]); - } - break; - } - - common_hal_digitalio_digitalinout_set_value(adapter->rts_digitalinout, true); - - hci_poll_in_progress = false; - return HCI_OK; -} - - -STATIC hci_result_t write_pkt(uint8_t *buffer, size_t len) { - // Wait for CTS to go low before writing to HCI adapter. - uint64_t start = supervisor_ticks_ms64(); - - while (common_hal_digitalio_digitalinout_get_value(adapter->cts_digitalinout)) { - RUN_BACKGROUND_TASKS; - if (supervisor_ticks_ms64() - start > CTS_TIMEOUT_MSECS) { - return HCI_WRITE_TIMEOUT; - } - } - - int errcode = 0; - common_hal_busio_uart_write(adapter->hci_uart, buffer, len, &errcode); - if (errcode) { - return HCI_WRITE_ERROR; - } - - return HCI_OK; -} - -STATIC hci_result_t send_command(uint16_t opcode, uint8_t params_len, void* params) { - uint8_t cmd_pkt_len = sizeof(h4_hci_cmd_pkt_t) + params_len; - uint8_t tx_buffer[cmd_pkt_len]; - - // cmd header is at the beginning of tx_buffer - h4_hci_cmd_pkt_t *cmd_pkt = (h4_hci_cmd_pkt_t *) tx_buffer; - cmd_pkt->pkt_type = H4_CMD; - cmd_pkt->opcode = opcode; - cmd_pkt->param_len = params_len; - - memcpy(cmd_pkt->params, params, params_len); - - if (debug) { - dump_cmd_pkt(true, sizeof(tx_buffer), tx_buffer); - } - - int result = write_pkt(tx_buffer, cmd_pkt_len); - if (result != HCI_OK) { - return result; - } - - cmd_response_received = false; - - // Wait for a response. Note that other packets may be received that are not - // command responses. - uint64_t start = supervisor_ticks_ms64(); - while (1) { - result = hci_poll_for_incoming_pkt(); - if (result != HCI_OK) { - // I/O error. - return result; - } - - if (cmd_response_received && cmd_response_opcode == opcode) { - // If this is definitely a response to the command that was sent, - // return the status value, which will will be - // BT_HCI_ERR_SUCCESS (0x00) if the command succeeded, - // or a BT_HCI_ERR_x value (> 0x00) if there ws a problem. - return cmd_response_status; - } - - if (supervisor_ticks_ms64() - start > RESPONSE_TIMEOUT_MSECS) { - return HCI_READ_TIMEOUT; - } - RUN_BACKGROUND_TASKS; - } - - // No I/O error, but no response sent back in time. - return HCI_NO_RESPONSE; -} - -//FIX remove unused -STATIC int __attribute__((unused)) send_acl_pkt(uint16_t handle, uint8_t cid, void* data, uint8_t data_len) { - int result; - while (pending_pkt >= max_pkt) { - result = hci_poll_for_incoming_pkt(); - if (result != HCI_OK) { - return result; - } - } - - // data_len does not include cid. - const size_t cid_len = sizeof_field(acl_data_t, cid); - // buf_len is size of entire packet including header. - const size_t buf_len = sizeof(h4_hci_acl_pkt_t) + cid_len + data_len; - uint8_t tx_buffer[buf_len]; - - h4_hci_acl_pkt_t *acl_pkt = (h4_hci_acl_pkt_t *) tx_buffer; - acl_data_t *acl_data = (acl_data_t *) acl_pkt->data; - acl_pkt->pkt_type = H4_ACL; - acl_pkt->handle = handle; - acl_pkt->data_len = (uint8_t)(cid_len + data_len); - acl_data->acl_data_len = (uint8_t) data_len; - acl_data->cid = cid; - - memcpy(&tx_buffer[sizeof(h4_hci_acl_pkt_t)], data, data_len); - - if (debug) { - dump_acl_pkt(true, buf_len, tx_buffer); - } - - pending_pkt++; - - int errcode = 0; - common_hal_busio_uart_write(adapter->hci_uart, tx_buffer, buf_len, &errcode); - if (errcode) { - return HCI_WRITE_ERROR; - } - - return HCI_OK; -} - -hci_result_t hci_reset(void) { - return send_command(BT_HCI_OP_RESET, 0, NULL); -} - -hci_result_t hci_read_local_version(uint8_t *hci_version, uint16_t *hci_revision, uint8_t *lmp_version, uint16_t *manufacturer, uint16_t *lmp_subversion) { - hci_result_t result = send_command(BT_HCI_OP_READ_LOCAL_VERSION_INFO, 0, NULL); - if (result == HCI_OK) { - struct bt_hci_rp_read_local_version_info *response = - (struct bt_hci_rp_read_local_version_info *) cmd_response_data; - *hci_version = response->hci_version; - *hci_revision = response->hci_revision; - *lmp_version = response->lmp_version; - *manufacturer = response->manufacturer; - *lmp_subversion = response->lmp_subversion; - } - - return result; -} - -hci_result_t hci_read_bd_addr(bt_addr_t *addr) { - int result = send_command(BT_HCI_OP_READ_BD_ADDR, 0, NULL); - if (result == HCI_OK) { - struct bt_hci_rp_read_bd_addr *response = (struct bt_hci_rp_read_bd_addr *) cmd_response_data; - memcpy(addr->val, response->bdaddr.val, sizeof_field(bt_addr_t, val)); - } - - return result; -} - -hci_result_t hci_read_rssi(uint16_t handle, int *rssi) { - int result = send_command(BT_HCI_OP_READ_RSSI, sizeof(handle), &handle); - if (result == HCI_OK) { - struct bt_hci_rp_read_rssi *response = (struct bt_hci_rp_read_rssi *) cmd_response_data; - if (response->handle != handle) { - // Handle doesn't match. - return HCI_NO_RESPONSE; - } - - *rssi = response->rssi; - } - - return result; -} - -hci_result_t hci_set_evt_mask(uint64_t event_mask) { - return send_command(BT_HCI_OP_SET_EVENT_MASK, sizeof(event_mask), &event_mask); -} - -hci_result_t hci_le_read_buffer_size(uint16_t *le_max_len, uint8_t *le_max_num) { - int result = send_command(BT_HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL); - if (result == HCI_OK) { - struct bt_hci_rp_le_read_buffer_size *response = - (struct bt_hci_rp_le_read_buffer_size *) cmd_response_data; - *le_max_len = response->le_max_len; - *le_max_num = response->le_max_num; - } - - return result; -} - -hci_result_t hci_read_buffer_size(uint16_t *acl_max_len, uint8_t *sco_max_len, uint16_t *acl_max_num, uint16_t *sco_max_num) { - int result = send_command(BT_HCI_OP_READ_BUFFER_SIZE, 0, NULL); - if (result == HCI_OK) { - struct bt_hci_rp_read_buffer_size *response = - (struct bt_hci_rp_read_buffer_size *) cmd_response_data; - *acl_max_len = response->acl_max_len; - *sco_max_len = response->sco_max_len; - *acl_max_num = response->acl_max_num; - *sco_max_num = response->sco_max_num; - } - - return result; -} - -hci_result_t hci_le_set_random_address(uint8_t addr[6]) { - return send_command(BT_HCI_OP_LE_SET_RANDOM_ADDRESS, 6, addr); -} - -hci_result_t hci_le_set_advertising_parameters(uint16_t min_interval, uint16_t max_interval, uint8_t type, uint8_t own_addr_type, bt_addr_le_t *direct_addr, uint8_t channel_map, uint8_t filter_policy) { - struct bt_hci_cp_le_set_adv_param params = { - .min_interval = min_interval, - .max_interval = max_interval, - .type = type, - .own_addr_type = own_addr_type, - // .direct_addr set below. - .channel_map = channel_map, - .filter_policy = filter_policy, - }; - params.direct_addr.type = direct_addr->type; - memcpy(params.direct_addr.a.val, direct_addr->a.val, sizeof(params.direct_addr.a.val)); - - return send_command(BT_HCI_OP_LE_SET_ADV_PARAM, sizeof(params), ¶ms); -} - -hci_result_t hci_le_set_extended_advertising_parameters(uint8_t handle, uint16_t props, uint32_t prim_min_interval, uint32_t prim_max_interval, uint8_t prim_channel_map, uint8_t own_addr_type, bt_addr_le_t *peer_addr, uint8_t filter_policy, int8_t tx_power, uint8_t prim_adv_phy, uint8_t sec_adv_max_skip, uint8_t sec_adv_phy, uint8_t sid, uint8_t scan_req_notify_enable) { - struct bt_hci_cp_le_set_ext_adv_param params = { - .handle = handle, - .props = props, - // .prim_min_interval and .prim_max_interval set below - .prim_channel_map = prim_channel_map, - .own_addr_type = own_addr_type, - // .peer_addr set below. - .tx_power = tx_power, - .sec_adv_max_skip = sec_adv_max_skip, - .sec_adv_phy = sec_adv_phy, - .sid = sid, - .scan_req_notify_enable = scan_req_notify_enable, - }; - // Assumes little-endian. - memcpy(params.prim_min_interval, (void *) &prim_min_interval, - sizeof_field(struct bt_hci_cp_le_set_ext_adv_param, prim_min_interval)); - memcpy(params.prim_max_interval, (void *) &prim_max_interval, - sizeof_field(struct bt_hci_cp_le_set_ext_adv_param, prim_max_interval)); - memcpy(params.peer_addr.a.val, peer_addr->a.val, sizeof_field(bt_addr_le_t, a.val)); - return send_command(BT_HCI_OP_LE_SET_EXT_ADV_PARAM, sizeof(params), ¶ms); -} - -hci_result_t hci_le_read_maximum_advertising_data_length(uint16_t *max_adv_data_len) { - int result = send_command(BT_HCI_OP_LE_READ_MAX_ADV_DATA_LEN, 0, NULL); - if (result == HCI_OK) { - struct bt_hci_rp_le_read_max_adv_data_len *response = - (struct bt_hci_rp_le_read_max_adv_data_len *) cmd_response_data; - *max_adv_data_len = response->max_adv_data_len; - } - - return result; -} - -hci_result_t hci_le_read_local_supported_features(uint8_t features[8]) { - int result = send_command(BT_HCI_OP_LE_READ_LOCAL_FEATURES, 0, NULL); - if (result == HCI_OK) { - struct bt_hci_rp_le_read_local_features *response = - (struct bt_hci_rp_le_read_local_features *) cmd_response_data; - memcpy(features, response->features, - sizeof_field(struct bt_hci_rp_le_read_local_features, features)); - } - - return result; -} - -hci_result_t hci_le_set_advertising_data(uint8_t len, uint8_t data[]) { - struct bt_hci_cp_le_set_adv_data params = { - // Zero out unused data bytes. - .data = { 0 }, - }; - - params.len = len; - memcpy(params.data, data, len); - - // All data bytes are sent even if some are unused. - return send_command(BT_HCI_OP_LE_SET_ADV_DATA, sizeof(params), ¶ms); -} - -hci_result_t hci_le_set_extended_advertising_data(uint8_t handle, uint8_t op, uint8_t frag_pref, uint8_t len, uint8_t data[]) { - const uint8_t max_len = sizeof_field(struct bt_hci_cp_le_set_ext_adv_data, data); - uint8_t valid_len = MIN(len, max_len); - struct bt_hci_cp_le_set_ext_adv_data params = { - .handle = handle, - .op = op, - .frag_pref = frag_pref, - .len = valid_len, - }; - memcpy(params.data, data, valid_len); - return send_command(BT_HCI_OP_LE_SET_EXT_ADV_DATA, sizeof(params) - (max_len - valid_len), ¶ms); -} - - -hci_result_t hci_le_set_scan_response_data(uint8_t len, uint8_t data[]) { - struct bt_hci_cp_le_set_scan_rsp_data params = { - // Zero out unused data bytes. - .data = { 0 }, - }; - params.len = len; - memcpy(params.data, data, len); - - // All data bytes are sent even if some are unused. - return send_command(BT_HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(params), ¶ms); -} - -hci_result_t hci_le_set_advertising_enable(uint8_t enable) { - return send_command(BT_HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable); -} - -hci_result_t hci_le_set_extended_advertising_enable(uint8_t enable, uint8_t set_num, uint8_t handle[], uint16_t duration[], uint8_t max_ext_adv_evts[]) { - uint8_t params[sizeof(struct bt_hci_cp_le_set_ext_adv_enable) + - set_num * (sizeof(struct bt_hci_ext_adv_set))]; - struct bt_hci_cp_le_set_ext_adv_enable *params_p = (struct bt_hci_cp_le_set_ext_adv_enable *) ¶ms; - params_p->enable = enable; - params_p->set_num = set_num; - for (size_t i = 0; i < set_num; i++) { - params_p->s[i].handle = handle[i]; - params_p->s[i].duration = duration[i]; - params_p->s[i].max_ext_adv_evts = max_ext_adv_evts[i]; - } - - return send_command(BT_HCI_OP_LE_SET_EXT_ADV_ENABLE, sizeof(params), ¶ms); -} - -hci_result_t hci_le_set_scan_parameters(uint8_t scan_type, uint16_t interval, uint16_t window, uint8_t addr_type, uint8_t filter_policy) { - struct bt_hci_cp_le_set_scan_param params = { - .scan_type = scan_type, - .interval = interval, - .window = window, - .addr_type = addr_type, - .filter_policy = filter_policy, - }; - - return send_command(BT_HCI_OP_LE_SET_SCAN_PARAM, sizeof(params), ¶ms); -} - -hci_result_t hci_le_set_scan_enable(uint8_t enable, uint8_t filter_dup) { - struct bt_hci_cp_le_set_scan_enable params = { - .enable = enable, - .filter_dup = filter_dup, - }; - - return send_command(BT_HCI_OP_LE_SET_SCAN_ENABLE, sizeof(params), ¶ms); -} - -hci_result_t hci_le_create_conn(uint16_t scan_interval, uint16_t scan_window, uint8_t filter_policy, bt_addr_le_t *peer_addr, uint8_t own_addr_type, uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout, uint16_t min_ce_len, uint16_t max_ce_len) { - struct bt_hci_cp_le_create_conn params = { - .scan_interval = scan_interval, - .scan_window = scan_window, - .filter_policy = filter_policy, - // .peer_addr is set below - .own_addr_type = own_addr_type, - .conn_interval_min = conn_interval_min, - .conn_interval_max = conn_interval_max, - .conn_latency = conn_latency, - .supervision_timeout = supervision_timeout, - .min_ce_len = min_ce_len, - .max_ce_len = max_ce_len, - }; - params.peer_addr.type = peer_addr->type; - memcpy(params.peer_addr.a.val, peer_addr->a.val, sizeof(params.peer_addr.a.val)); - - return send_command(BT_HCI_OP_LE_CREATE_CONN, sizeof(params), ¶ms); -} - -hci_result_t hci_le_cancel_conn(void) { - return send_command(BT_HCI_OP_CONNECT_CANCEL, 0, NULL); -} - -hci_result_t hci_le_conn_update(uint16_t handle, uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout) { - struct hci_cp_le_conn_update params = { - .handle = handle, - .conn_interval_min = conn_interval_min, - .conn_interval_max = conn_interval_max, - .conn_latency = conn_latency, - .supervision_timeout = supervision_timeout, - .min_ce_len = 4, - .max_ce_len = 6, - }; - - return send_command(BT_HCI_OP_LE_CONN_UPDATE, sizeof(params), ¶ms); -} - -hci_result_t hci_disconnect(uint16_t handle) { - struct bt_hci_cp_disconnect params = { - .handle = handle, - .reason = BT_HCI_ERR_REMOTE_USER_TERM_CONN, - }; - - return send_command(BT_HCI_OP_DISCONNECT, sizeof(params), ¶ms); -} diff --git a/devices/ble_hci/common-hal/_bleio/hci_api.h b/devices/ble_hci/common-hal/_bleio/hci_api.h deleted file mode 100644 index f6d96d48f..000000000 --- a/devices/ble_hci/common-hal/_bleio/hci_api.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - This file is part of the ArduinoBLE library. - Copyright (c) 2018 Arduino SA. All rights reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef MICROPY_INCLUDED_DEVICES_BLE_HCI_COMMON_HAL_BLEIO_HCI_API_H -#define MICROPY_INCLUDED_DEVICES_BLE_HCI_COMMON_HAL_BLEIO_HCI_API_H - -#include - -#include "common-hal/_bleio/hci_include/hci.h" -#include "common-hal/_bleio/hci_include/hci_err.h" - -// Incomplete forward declaration to get around mutually-dependent include files. -typedef struct _bleio_adapter_obj_t bleio_adapter_obj_t; - -// An hci_result_t is one of the HCI_x values below, -// or is it > 0 and is an HCI command status value (see hci_include/hci_err.h) -typedef int hci_result_t; -#define HCI_OK (0) -#define HCI_NO_RESPONSE (-1) -#define HCI_READ_TIMEOUT (-2) -#define HCI_WRITE_TIMEOUT (-3) -#define HCI_READ_ERROR (-4) -#define HCI_WRITE_ERROR (-5) - -void hci_init(void); - -hci_result_t hci_disconnect(uint16_t handle); - -hci_result_t hci_le_cancel_conn(void); -hci_result_t hci_le_conn_update(uint16_t handle, uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout); -hci_result_t hci_le_create_conn(uint16_t scan_interval, uint16_t scan_window, uint8_t filter_policy, bt_addr_le_t *peer_addr, uint8_t own_addr_type, uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout, uint16_t min_ce_len, uint16_t max_ce_len); - -hci_result_t hci_le_read_buffer_size(uint16_t *le_max_len, uint8_t *le_max_num); -hci_result_t hci_le_read_maximum_advertising_data_length(uint16_t *max_adv_data_len); -hci_result_t hci_le_read_local_supported_features(uint8_t features[8]); - -hci_result_t hci_le_set_advertising_data(uint8_t length, uint8_t data[]); -hci_result_t hci_le_set_advertising_enable(uint8_t enable); -hci_result_t hci_le_set_advertising_parameters(uint16_t min_interval, uint16_t max_interval, uint8_t type, uint8_t own_addr_type, bt_addr_le_t *direct_addr, uint8_t channel_map, uint8_t filter_policy); - -hci_result_t hci_le_set_extended_advertising_data(uint8_t handle, uint8_t op, uint8_t frag_pref, uint8_t len, uint8_t data[]); -hci_result_t hci_le_set_extended_advertising_enable(uint8_t enable, uint8_t set_num, uint8_t handle[], uint16_t duration[], uint8_t max_ext_adv_evts[]); -hci_result_t hci_le_set_extended_advertising_parameters(uint8_t handle, uint16_t props, uint32_t prim_min_interval, uint32_t prim_max_interval, uint8_t prim_channel_map, uint8_t own_addr_type, bt_addr_le_t *peer_addr, uint8_t filter_policy, int8_t tx_power, uint8_t prim_adv_phy, uint8_t sec_adv_max_skip, uint8_t sec_adv_phy, uint8_t sid, uint8_t scan_req_notify_enable); - -hci_result_t hci_le_set_random_address(uint8_t addr[6]); -hci_result_t hci_le_set_scan_enable(uint8_t enable, uint8_t filter_dup); -hci_result_t hci_le_set_scan_parameters(uint8_t scan_type, uint16_t interval, uint16_t window, uint8_t addr_type, uint8_t filter_policy); -hci_result_t hci_le_set_scan_response_data(uint8_t length, uint8_t data[]); - -hci_result_t hci_poll_for_incoming_pkt(void); - -hci_result_t hci_read_bd_addr(bt_addr_t *addr); -hci_result_t hci_read_buffer_size(uint16_t *acl_max_len, uint8_t *sco_max_len, uint16_t *acl_max_num, uint16_t *sco_max_num); -hci_result_t hci_read_local_version(uint8_t *hci_version, uint16_t *hci_revision, uint8_t *lmp_version, uint16_t *manufacturer, uint16_t *lmp_subversion); -hci_result_t hci_read_rssi(uint16_t handle, int *rssi); - -hci_result_t hci_reset(void); - -hci_result_t hci_set_evt_mask(uint64_t event_mask); - -#endif // MICROPY_INCLUDED_DEVICES_BLE_HCI_COMMON_HAL_BLEIO_HCI_API_H diff --git a/devices/ble_hci/common-hal/_bleio/hci_include/addr.h b/devices/ble_hci/common-hal/_bleio/hci_include/addr.h index 8f503b8a1..fd74a95e8 100644 --- a/devices/ble_hci/common-hal/_bleio/hci_include/addr.h +++ b/devices/ble_hci/common-hal/_bleio/hci_include/addr.h @@ -12,6 +12,7 @@ #ifndef ZEPHYR_INCLUDE_BLUETOOTH_ADDR_H_ #define ZEPHYR_INCLUDE_BLUETOOTH_ADDR_H_ +#include #include /** diff --git a/devices/ble_hci/common-hal/_bleio/hci_include/att.h b/devices/ble_hci/common-hal/_bleio/hci_include/att.h new file mode 100644 index 000000000..8117a48f4 --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/hci_include/att.h @@ -0,0 +1,41 @@ +// CircuitPython: Adapted from Zephyr include file. +/** @file + * @brief Attribute Protocol handling. + */ + +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_ATT_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_ATT_H_ + +/* Error codes for Error response PDU */ +#define BT_ATT_ERR_INVALID_HANDLE 0x01 +#define BT_ATT_ERR_READ_NOT_PERMITTED 0x02 +#define BT_ATT_ERR_WRITE_NOT_PERMITTED 0x03 +#define BT_ATT_ERR_INVALID_PDU 0x04 +#define BT_ATT_ERR_AUTHENTICATION 0x05 +#define BT_ATT_ERR_NOT_SUPPORTED 0x06 +#define BT_ATT_ERR_INVALID_OFFSET 0x07 +#define BT_ATT_ERR_AUTHORIZATION 0x08 +#define BT_ATT_ERR_PREPARE_QUEUE_FULL 0x09 +#define BT_ATT_ERR_ATTRIBUTE_NOT_FOUND 0x0a +#define BT_ATT_ERR_ATTRIBUTE_NOT_LONG 0x0b +#define BT_ATT_ERR_ENCRYPTION_KEY_SIZE 0x0c +#define BT_ATT_ERR_INVALID_ATTRIBUTE_LEN 0x0d +#define BT_ATT_ERR_UNLIKELY 0x0e +#define BT_ATT_ERR_INSUFFICIENT_ENCRYPTION 0x0f +#define BT_ATT_ERR_UNSUPPORTED_GROUP_TYPE 0x10 +#define BT_ATT_ERR_INSUFFICIENT_RESOURCES 0x11 +#define BT_ATT_ERR_DB_OUT_OF_SYNC 0x12 +#define BT_ATT_ERR_VALUE_NOT_ALLOWED 0x13 + +/* Common Profile Error Codes (from CSS) */ +#define BT_ATT_ERR_WRITE_REQ_REJECTED 0xfc +#define BT_ATT_ERR_CCC_IMPROPER_CONF 0xfd +#define BT_ATT_ERR_PROCEDURE_IN_PROGRESS 0xfe +#define BT_ATT_ERR_OUT_OF_RANGE 0xff + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_ATT_H_ */ diff --git a/devices/ble_hci/common-hal/_bleio/hci_include/att_internal.h b/devices/ble_hci/common-hal/_bleio/hci_include/att_internal.h new file mode 100644 index 000000000..1c75275da --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/hci_include/att_internal.h @@ -0,0 +1,266 @@ +// CircuitPython: Adapted from Zephyr include file. + +/* att_internal.h - Attribute protocol handling */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +#include +// for __packed +#include + +#define BT_EATT_PSM 0x27 +#define BT_ATT_DEFAULT_LE_MTU 23 +#define BT_ATT_TIMEOUT K_SECONDS(30) + +//FIX #if BT_L2CAP_RX_MTU < CONFIG_BT_L2CAP_TX_MTU +// #define BT_ATT_MTU BT_L2CAP_RX_MTU +// #else +// #define BT_ATT_MTU CONFIG_BT_L2CAP_TX_MTU +// #endif + +struct bt_att_hdr { + uint8_t code; +} __packed; + +#define BT_ATT_OP_ERROR_RSP 0x01 +struct bt_att_error_rsp { + uint8_t request; + uint16_t handle; + uint8_t error; +} __packed; + +#define BT_ATT_OP_MTU_REQ 0x02 +struct bt_att_exchange_mtu_req { + uint16_t mtu; +} __packed; + +#define BT_ATT_OP_MTU_RSP 0x03 +struct bt_att_exchange_mtu_rsp { + uint16_t mtu; +} __packed; + +/* Find Information Request */ +#define BT_ATT_OP_FIND_INFO_REQ 0x04 +struct bt_att_find_info_req { + uint16_t start_handle; + uint16_t end_handle; +} __packed; + +/* Format field values for BT_ATT_OP_FIND_INFO_RSP */ +#define BT_ATT_INFO_16 0x01 +#define BT_ATT_INFO_128 0x02 + +struct bt_att_info_16 { + uint16_t handle; + uint16_t uuid; +} __packed; + +struct bt_att_info_128 { + uint16_t handle; + uint8_t uuid[16]; +} __packed; + +/* Find Information Response */ +#define BT_ATT_OP_FIND_INFO_RSP 0x05 +struct bt_att_find_info_rsp { + uint8_t format; + uint8_t info[0]; +} __packed; + +/* Find By Type Value Request */ +#define BT_ATT_OP_FIND_TYPE_REQ 0x06 +struct bt_att_find_type_req { + uint16_t start_handle; + uint16_t end_handle; + uint16_t type; + uint8_t value[0]; +} __packed; + +struct bt_att_handle_group { + uint16_t start_handle; + uint16_t end_handle; +} __packed; + +/* Find By Type Value Response */ +#define BT_ATT_OP_FIND_TYPE_RSP 0x07 +struct bt_att_find_type_rsp { + struct bt_att_handle_group list[0]; +} __packed; + +/* Read By Type Request */ +#define BT_ATT_OP_READ_TYPE_REQ 0x08 +struct bt_att_read_type_req { + uint16_t start_handle; + uint16_t end_handle; + uint8_t uuid[0]; +} __packed; + +struct bt_att_data { + uint16_t handle; + uint8_t value[0]; +} __packed; + +/* Read By Type Response */ +#define BT_ATT_OP_READ_TYPE_RSP 0x09 +struct bt_att_read_type_rsp { + uint8_t len; + struct bt_att_data data[0]; +} __packed; + +/* Read Request */ +#define BT_ATT_OP_READ_REQ 0x0a +struct bt_att_read_req { + uint16_t handle; +} __packed; + +/* Read Response */ +#define BT_ATT_OP_READ_RSP 0x0b +struct bt_att_read_rsp { + uint8_t value[0]; +} __packed; + +/* Read Blob Request */ +#define BT_ATT_OP_READ_BLOB_REQ 0x0c +struct bt_att_read_blob_req { + uint16_t handle; + uint16_t offset; +} __packed; + +/* Read Blob Response */ +#define BT_ATT_OP_READ_BLOB_RSP 0x0d +struct bt_att_read_blob_rsp { + uint8_t value[0]; +} __packed; + +/* Read Multiple Request */ +#define BT_ATT_READ_MULT_MIN_LEN_REQ 0x04 + +#define BT_ATT_OP_READ_MULT_REQ 0x0e +struct bt_att_read_mult_req { + uint16_t handles[0]; +} __packed; + +/* Read Multiple Respose */ +#define BT_ATT_OP_READ_MULT_RSP 0x0f +struct bt_att_read_mult_rsp { + uint8_t value[0]; +} __packed; + +/* Read by Group Type Request */ +#define BT_ATT_OP_READ_GROUP_REQ 0x10 +struct bt_att_read_group_req { + uint16_t start_handle; + uint16_t end_handle; + uint8_t uuid[0]; +} __packed; + +struct bt_att_group_data { + uint16_t start_handle; + uint16_t end_handle; + uint8_t value[0]; +} __packed; + +/* Read by Group Type Response */ +#define BT_ATT_OP_READ_GROUP_RSP 0x11 +struct bt_att_read_group_rsp { + uint8_t len; + struct bt_att_group_data data[0]; +} __packed; + +/* Write Request */ +#define BT_ATT_OP_WRITE_REQ 0x12 +struct bt_att_write_req { + uint16_t handle; + uint8_t value[0]; +} __packed; + +/* Write Response */ +#define BT_ATT_OP_WRITE_RSP 0x13 + +/* Prepare Write Request */ +#define BT_ATT_OP_PREPARE_WRITE_REQ 0x16 +struct bt_att_prepare_write_req { + uint16_t handle; + uint16_t offset; + uint8_t value[0]; +} __packed; + +/* Prepare Write Respond */ +#define BT_ATT_OP_PREPARE_WRITE_RSP 0x17 +struct bt_att_prepare_write_rsp { + uint16_t handle; + uint16_t offset; + uint8_t value[0]; +} __packed; + +/* Execute Write Request */ +#define BT_ATT_FLAG_CANCEL 0x00 +#define BT_ATT_FLAG_EXEC 0x01 + +#define BT_ATT_OP_EXEC_WRITE_REQ 0x18 +struct bt_att_exec_write_req { + uint8_t flags; +} __packed; + +/* Execute Write Response */ +#define BT_ATT_OP_EXEC_WRITE_RSP 0x19 + +/* Handle Value Notification */ +#define BT_ATT_OP_NOTIFY 0x1b +struct bt_att_notify { + uint16_t handle; + uint8_t value[0]; +} __packed; + +/* Handle Value Indication */ +#define BT_ATT_OP_INDICATE 0x1d +struct bt_att_indicate { + uint16_t handle; + uint8_t value[0]; +} __packed; + +/* Handle Value Confirm */ +#define BT_ATT_OP_CONFIRM 0x1e + +struct bt_att_signature { + uint8_t value[12]; +} __packed; + +#define BT_ATT_OP_READ_MULT_VL_REQ 0x20 +struct bt_att_read_mult_vl_req { + uint16_t handles[0]; +} __packed; + +/* Read Multiple Respose */ +#define BT_ATT_OP_READ_MULT_VL_RSP 0x21 +struct bt_att_read_mult_vl_rsp { + uint16_t len; + uint8_t value[0]; +} __packed; + +/* Handle Multiple Value Notification */ +#define BT_ATT_OP_NOTIFY_MULT 0x23 +struct bt_att_notify_mult { + uint16_t handle; + uint16_t len; + uint8_t value[0]; +} __packed; + +/* Write Command */ +#define BT_ATT_OP_WRITE_CMD 0x52 +struct bt_att_write_cmd { + uint16_t handle; + uint8_t value[0]; +} __packed; + +/* Signed Write Command */ +#define BT_ATT_OP_SIGNED_WRITE_CMD 0xd2 +struct bt_att_signed_write_cmd { + uint16_t handle; + uint8_t value[0]; +} __packed; diff --git a/devices/ble_hci/common-hal/_bleio/hci_include/hci.h b/devices/ble_hci/common-hal/_bleio/hci_include/hci.h index 2de58b3d8..6c3a2b5bd 100644 --- a/devices/ble_hci/common-hal/_bleio/hci_include/hci.h +++ b/devices/ble_hci/common-hal/_bleio/hci_include/hci.h @@ -1,4 +1,5 @@ // CircuitPython: Adapted from Zephyr include file. + /* hci.h - Bluetooth Host Control Interface definitions */ /* diff --git a/devices/ble_hci/common-hal/_bleio/hci_include/l2cap_internal.h b/devices/ble_hci/common-hal/_bleio/hci_include/l2cap_internal.h new file mode 100644 index 000000000..bed311cf3 --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/hci_include/l2cap_internal.h @@ -0,0 +1,230 @@ +// CircuitPython: Adapted from Zephyr include file. + +/** @file + * @brief Internal APIs for Bluetooth L2CAP handling. + */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +// for __packed +#include + +enum l2cap_conn_list_action { + BT_L2CAP_CHAN_LOOKUP, + BT_L2CAP_CHAN_DETACH, +}; + +#define BT_L2CAP_CID_BR_SIG 0x0001 +#define BT_L2CAP_CID_ATT 0x0004 +#define BT_L2CAP_CID_LE_SIG 0x0005 +#define BT_L2CAP_CID_SMP 0x0006 +#define BT_L2CAP_CID_BR_SMP 0x0007 + +#define BT_L2CAP_PSM_RFCOMM 0x0003 + +struct bt_l2cap_hdr { + uint16_t len; + uint16_t cid; +} __packed; + +struct bt_l2cap_sig_hdr { + uint8_t code; + uint8_t ident; + uint16_t len; +} __packed; + +#define BT_L2CAP_REJ_NOT_UNDERSTOOD 0x0000 +#define BT_L2CAP_REJ_MTU_EXCEEDED 0x0001 +#define BT_L2CAP_REJ_INVALID_CID 0x0002 + +#define BT_L2CAP_CMD_REJECT 0x01 +struct bt_l2cap_cmd_reject { + uint16_t reason; + uint8_t data[0]; +} __packed; + +struct bt_l2cap_cmd_reject_cid_data { + uint16_t scid; + uint16_t dcid; +} __packed; + +#define BT_L2CAP_CONN_REQ 0x02 +struct bt_l2cap_conn_req { + uint16_t psm; + uint16_t scid; +} __packed; + +/* command statuses in reposnse */ +#define BT_L2CAP_CS_NO_INFO 0x0000 +#define BT_L2CAP_CS_AUTHEN_PEND 0x0001 + +/* valid results in conn response on BR/EDR */ +#define BT_L2CAP_BR_SUCCESS 0x0000 +#define BT_L2CAP_BR_PENDING 0x0001 +#define BT_L2CAP_BR_ERR_PSM_NOT_SUPP 0x0002 +#define BT_L2CAP_BR_ERR_SEC_BLOCK 0x0003 +#define BT_L2CAP_BR_ERR_NO_RESOURCES 0x0004 +#define BT_L2CAP_BR_ERR_INVALID_SCID 0x0006 +#define BT_L2CAP_BR_ERR_SCID_IN_USE 0x0007 + +#define BT_L2CAP_CONN_RSP 0x03 +struct bt_l2cap_conn_rsp { + uint16_t dcid; + uint16_t scid; + uint16_t result; + uint16_t status; +} __packed; + +#define BT_L2CAP_CONF_SUCCESS 0x0000 +#define BT_L2CAP_CONF_UNACCEPT 0x0001 +#define BT_L2CAP_CONF_REJECT 0x0002 + +#define BT_L2CAP_CONF_REQ 0x04 +struct bt_l2cap_conf_req { + uint16_t dcid; + uint16_t flags; + uint8_t data[0]; +} __packed; + +#define BT_L2CAP_CONF_RSP 0x05 +struct bt_l2cap_conf_rsp { + uint16_t scid; + uint16_t flags; + uint16_t result; + uint8_t data[0]; +} __packed; + +/* Option type used by MTU config request data */ +#define BT_L2CAP_CONF_OPT_MTU 0x01 +/* Options bits selecting most significant bit (hint) in type field */ +#define BT_L2CAP_CONF_HINT 0x80 +#define BT_L2CAP_CONF_MASK 0x7f + +struct bt_l2cap_conf_opt { + uint8_t type; + uint8_t len; + uint8_t data[0]; +} __packed; + +#define BT_L2CAP_DISCONN_REQ 0x06 +struct bt_l2cap_disconn_req { + uint16_t dcid; + uint16_t scid; +} __packed; + +#define BT_L2CAP_DISCONN_RSP 0x07 +struct bt_l2cap_disconn_rsp { + uint16_t dcid; + uint16_t scid; +} __packed; + +#define BT_L2CAP_INFO_FEAT_MASK 0x0002 +#define BT_L2CAP_INFO_FIXED_CHAN 0x0003 + +#define BT_L2CAP_INFO_REQ 0x0a +struct bt_l2cap_info_req { + uint16_t type; +} __packed; + +/* info result */ +#define BT_L2CAP_INFO_SUCCESS 0x0000 +#define BT_L2CAP_INFO_NOTSUPP 0x0001 + +#define BT_L2CAP_INFO_RSP 0x0b +struct bt_l2cap_info_rsp { + uint16_t type; + uint16_t result; + uint8_t data[0]; +} __packed; + +#define BT_L2CAP_CONN_PARAM_REQ 0x12 +struct bt_l2cap_conn_param_req { + uint16_t min_interval; + uint16_t max_interval; + uint16_t latency; + uint16_t timeout; +} __packed; + +#define BT_L2CAP_CONN_PARAM_ACCEPTED 0x0000 +#define BT_L2CAP_CONN_PARAM_REJECTED 0x0001 + +#define BT_L2CAP_CONN_PARAM_RSP 0x13 +struct bt_l2cap_conn_param_rsp { + uint16_t result; +} __packed; + +#define BT_L2CAP_LE_CONN_REQ 0x14 +struct bt_l2cap_le_conn_req { + uint16_t psm; + uint16_t scid; + uint16_t mtu; + uint16_t mps; + uint16_t credits; +} __packed; + +/* valid results in conn response on LE */ +#define BT_L2CAP_LE_SUCCESS 0x0000 +#define BT_L2CAP_LE_ERR_PSM_NOT_SUPP 0x0002 +#define BT_L2CAP_LE_ERR_NO_RESOURCES 0x0004 +#define BT_L2CAP_LE_ERR_AUTHENTICATION 0x0005 +#define BT_L2CAP_LE_ERR_AUTHORIZATION 0x0006 +#define BT_L2CAP_LE_ERR_KEY_SIZE 0x0007 +#define BT_L2CAP_LE_ERR_ENCRYPTION 0x0008 +#define BT_L2CAP_LE_ERR_INVALID_SCID 0x0009 +#define BT_L2CAP_LE_ERR_SCID_IN_USE 0x000A +#define BT_L2CAP_LE_ERR_UNACCEPT_PARAMS 0x000B +#define BT_L2CAP_LE_ERR_INVALID_PARAMS 0x000C + +#define BT_L2CAP_LE_CONN_RSP 0x15 +struct bt_l2cap_le_conn_rsp { + uint16_t dcid; + uint16_t mtu; + uint16_t mps; + uint16_t credits; + uint16_t result; +} __packed; + +#define BT_L2CAP_LE_CREDITS 0x16 +struct bt_l2cap_le_credits { + uint16_t cid; + uint16_t credits; +} __packed; + +#define BT_L2CAP_ECRED_CONN_REQ 0x17 +struct bt_l2cap_ecred_conn_req { + uint16_t psm; + uint16_t mtu; + uint16_t mps; + uint16_t credits; + uint16_t scid[0]; +} __packed; + +#define BT_L2CAP_ECRED_CONN_RSP 0x18 +struct bt_l2cap_ecred_conn_rsp { + uint16_t mtu; + uint16_t mps; + uint16_t credits; + uint16_t result; + uint16_t dcid[0]; +} __packed; + +#define BT_L2CAP_ECRED_RECONF_REQ 0x19 +struct bt_l2cap_ecred_reconf_req { + uint16_t mtu; + uint16_t mps; + uint16_t scid[0]; +} __packed; + +#define BT_L2CAP_RECONF_SUCCESS 0x0000 +#define BT_L2CAP_RECONF_INVALID_MTU 0x0001 +#define BT_L2CAP_RECONF_INVALID_MPS 0x0002 + +#define BT_L2CAP_ECRED_RECONF_RSP 0x1a +struct bt_l2cap_ecred_reconf_rsp { + uint16_t result; +} __packed; diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 0dd31904f..e2850e63f 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -318,8 +318,10 @@ SRC_COMMON_HAL_ALL = \ watchdog/__init__.c \ ifeq ($(CIRCUITPY_BLEIO_HCI),1) +# Helper code for _bleio HCI. SRC_C += \ - common-hal/_bleio/hci_api.c \ + common-hal/_bleio/att.c \ + common-hal/_bleio/hci.c \ endif diff --git a/py/misc.h b/py/misc.h index 673568f22..abcc7edf7 100644 --- a/py/misc.h +++ b/py/misc.h @@ -120,6 +120,8 @@ size_t m_get_peak_bytes_allocated(void); // align ptr to the nearest multiple of "alignment" #define MP_ALIGN(ptr, alignment) (void*)(((uintptr_t)(ptr) + ((alignment) - 1)) & ~((alignment) - 1)) +#define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER)) + /** unichar / UTF-8 *********************************************/ #if MICROPY_PY_BUILTINS_STR_UNICODE diff --git a/py/py.mk b/py/py.mk index 3cb505920..62050519b 100644 --- a/py/py.mk +++ b/py/py.mk @@ -19,7 +19,7 @@ endif QSTR_GLOBAL_DEPENDENCIES += $(PY_SRC)/mpconfig.h mpconfigport.h # some code is performance bottleneck and compiled with other optimization options -CSUPEROPT = -O3 +_CSUPEROPT = -O3 # this sets the config file for FatFs CFLAGS_MOD += -DFFCONF_H=\"lib/oofatfs/ffconf.h\" -- cgit v1.2.3 From 455226ffded69538f5f453b566b499361b201ffb Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sun, 30 Aug 2020 11:09:49 -0500 Subject: builtinimport: Fix a crash with 'import ulab.linalg' on unix port only A crash like the following occurs in the unix port: ``` Program received signal SIGSEGV, Segmentation fault. 0x00005555555a2d7a in mp_obj_module_set_globals (self_in=0x55555562c860 , globals=0x55555562c840 ) at ../../py/objmodule.c:145 145 self->globals = globals; (gdb) up #1 0x00005555555b2781 in mp_builtin___import__ (n_args=5, args=0x7fffffffdbb0) at ../../py/builtinimport.c:496 496 mp_obj_module_set_globals(outer_module_obj, (gdb) #2 0x00005555555940c9 in mp_import_name (name=824, fromlist=0x555555621f10 , level=0x1) at ../../py/runtime.c:1392 1392 return mp_builtin___import__(5, args); ``` I don't understand how it doesn't happen on the embedded ports, because the module object should reside in ROM and the assignment of self->globals should trigger a Hard Fault. By checking VERIFY_PTR, we know that the pointed-to data is on the heap so we can do things like mutate it. --- py/builtinimport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'py') diff --git a/py/builtinimport.c b/py/builtinimport.c index 597819f55..47ffab519 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -488,7 +488,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { // afterwards. gc_collect(); } - if (outer_module_obj != MP_OBJ_NULL) { + if (outer_module_obj != MP_OBJ_NULL && VERIFY_PTR(outer_module_obj) ) { qstr s = qstr_from_strn(mod_str + last, i - last); mp_store_attr(outer_module_obj, s, module_obj); // The above store can cause a dictionary rehash and new allocation. So, -- cgit v1.2.3 From b27d51125134b4317b429eb7b015c9f94f22adb0 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 30 Aug 2020 14:06:48 -0400 Subject: address review; use constructor for HCI Adapter --- devices/ble_hci/common-hal/_bleio/Adapter.c | 3 +- devices/ble_hci/common-hal/_bleio/Adapter.h | 1 + devices/ble_hci/common-hal/_bleio/__init__.c | 10 +++ .../ble_hci/common-hal/_bleio/hci_include/NOTE.txt | 4 +- py/obj.h | 25 +++++++- shared-bindings/_bleio/Adapter.c | 43 ++++++------- shared-bindings/_bleio/Adapter.h | 2 +- shared-bindings/_bleio/__init__.c | 72 +++++++++++++++++++++- shared-bindings/_bleio/__init__.h | 3 + shared-bindings/usb_midi/__init__.c | 12 +--- 10 files changed, 133 insertions(+), 42 deletions(-) (limited to 'py') diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index 27a251281..559b586de 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.c +++ b/devices/ble_hci/common-hal/_bleio/Adapter.c @@ -341,7 +341,8 @@ STATIC void bleio_adapter_hci_init(bleio_adapter_obj_t *self) { } } -void common_hal_bleio_adapter_hci_uart_init(bleio_adapter_obj_t *self, busio_uart_obj_t *uart, digitalio_digitalinout_obj_t *rts, digitalio_digitalinout_obj_t *cts) { +void common_hal_bleio_adapter_construct_hci_uart(bleio_adapter_obj_t *self, busio_uart_obj_t *uart, digitalio_digitalinout_obj_t *rts, digitalio_digitalinout_obj_t *cts) { + self->allocated = true; self->hci_uart = uart; self->rts_digitalinout = rts; self->cts_digitalinout = cts; diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.h b/devices/ble_hci/common-hal/_bleio/Adapter.h index dbccfbfb1..bec1329f2 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.h +++ b/devices/ble_hci/common-hal/_bleio/Adapter.h @@ -52,6 +52,7 @@ typedef struct _bleio_adapter_obj_t { busio_uart_obj_t* hci_uart; digitalio_digitalinout_obj_t *rts_digitalinout; digitalio_digitalinout_obj_t *cts_digitalinout; + bool allocated; // True when in use. bool now_advertising; bool extended_advertising; bool circuitpython_advertising; diff --git a/devices/ble_hci/common-hal/_bleio/__init__.c b/devices/ble_hci/common-hal/_bleio/__init__.c index 25aca39b5..9fc4b480d 100644 --- a/devices/ble_hci/common-hal/_bleio/__init__.c +++ b/devices/ble_hci/common-hal/_bleio/__init__.c @@ -74,6 +74,9 @@ void bleio_reset() { return; } common_hal_bleio_adapter_set_enabled(&common_hal_bleio_adapter_obj, false); + common_hal_bleio_adapter_obj.allocated = false; + + bleio_set_adapter(mp_const_none); //FIX bonding_reset(); supervisor_start_bluetooth(); @@ -86,6 +89,13 @@ bleio_adapter_obj_t common_hal_bleio_adapter_obj = { }, }; +bleio_adapter_obj_t *common_hal_bleio_allocate_adapter_or_raise(void) { + if (common_hal_bleio_adapter_obj.allocated) { + mp_raise_RuntimeError(translate("Too many Adapters")); + } + return &common_hal_bleio_adapter_obj; +} + void common_hal_bleio_check_connected(uint16_t conn_handle) { if (conn_handle == BLE_CONN_HANDLE_INVALID) { mp_raise_bleio_ConnectionError(translate("Not connected")); diff --git a/devices/ble_hci/common-hal/_bleio/hci_include/NOTE.txt b/devices/ble_hci/common-hal/_bleio/hci_include/NOTE.txt index 4d2968c39..ac34c815c 100644 --- a/devices/ble_hci/common-hal/_bleio/hci_include/NOTE.txt +++ b/devices/ble_hci/common-hal/_bleio/hci_include/NOTE.txt @@ -1,2 +1,2 @@ -The HCI-related include files here are copied from the Zephyr project: -https://github.com/zephyrproject-rtos/zephyr/tree/master/include/bluetooth +The HCI-related include files here were copied from the Zephyr project, from this commit: +https://github.com/zephyrproject-rtos/zephyr/tree/0a87f9359edf1ec1c169626df3e19c2b4a4e9646/include/bluetooth diff --git a/py/obj.h b/py/obj.h index e9d867f77..943e1a389 100644 --- a/py/obj.h +++ b/py/obj.h @@ -303,7 +303,7 @@ typedef struct _mp_rom_obj_t { mp_const_obj_t o; } mp_rom_obj_t; (mp_obj_t)&mp_const_none_obj, \ (mp_obj_t)&mp_const_none_obj}, } -// These macros are used to define constant map/dict objects +// These macros are used to define constant or mutable map/dict objects // You can put "static" in front of the definition to make it local #define MP_DEFINE_CONST_MAP(map_name, table_name) \ @@ -329,6 +329,29 @@ typedef struct _mp_rom_obj_t { mp_const_obj_t o; } mp_rom_obj_t; }, \ } +#define MP_DEFINE_MUTABLE_MAP(map_name, table_name) \ + mp_map_t map_name = { \ + .all_keys_are_qstrs = 1, \ + .is_fixed = 1, \ + .is_ordered = 1, \ + .used = MP_ARRAY_SIZE(table_name), \ + .alloc = MP_ARRAY_SIZE(table_name), \ + .table = table_name, \ + } + +#define MP_DEFINE_MUTABLE_DICT(dict_name, table_name) \ + mp_obj_dict_t dict_name = { \ + .base = {&mp_type_dict}, \ + .map = { \ + .all_keys_are_qstrs = 1, \ + .is_fixed = 1, \ + .is_ordered = 1, \ + .used = MP_ARRAY_SIZE(table_name), \ + .alloc = MP_ARRAY_SIZE(table_name), \ + .table = table_name, \ + }, \ + } + // These macros are used to declare and define constant staticmethond and classmethod objects // You can put "static" in front of the definitions to make them local diff --git a/shared-bindings/_bleio/Adapter.c b/shared-bindings/_bleio/Adapter.c index 5b67a9ae9..b70fd17f8 100644 --- a/shared-bindings/_bleio/Adapter.c +++ b/shared-bindings/_bleio/Adapter.c @@ -48,46 +48,42 @@ #define WINDOW_DEFAULT (0.1f) //| class Adapter: -//| """BLE adapter -//| -//| The Adapter manages the discovery and connection to other nearby Bluetooth Low Energy devices. +//| """ +//| The BLE Adapter object manages the discovery and connection to other nearby Bluetooth Low Energy devices. //| This part of the Bluetooth Low Energy Specification is known as Generic Access Profile (GAP). //| //| Discovery of other devices happens during a scanning process that listens for small packets of //| information, known as advertisements, that are broadcast unencrypted. The advertising packets //| have two different uses. The first is to broadcast a small piece of data to anyone who cares and -//| and nothing more. These are known as Beacons. The second class of advertisement is to promote +//| and nothing more. These are known as beacons. The second class of advertisement is to promote //| additional functionality available after the devices establish a connection. For example, a -//| BLE keyboard may advertise that it can provide key information, but not what the key info is. +//| BLE heart rate monitor would advertise that it provides the standard BLE Heart Rate Service. //| -//| The built-in BLE adapter can do both parts of this process: it can scan for other device +//| The Adapter can do both parts of this process: it can scan for other device //| advertisements and it can advertise its own data. Furthermore, Adapters can accept incoming //| connections and also initiate connections.""" //| -//| def __init__(self) -> None: -//| """You cannot create an instance of `_bleio.Adapter`. -//| Use `_bleio.adapter` to access the sole instance available.""" -//| ... -//| - -//| def hci_uart_init(self, *, uart: busio.UART, rts: digitalio.DigitalInOut, cts: digitalio.DigitalInOut, baudrate: int = 115200, buffer_size: int = 256) -> None: -//| """On boards that do not have native BLE, you can an use HCI co-processor. +//| def __init__(self, *, uart: busio.UART, rts: digitalio.DigitalInOut, cts: digitalio.DigitalInOut) -> None: +//| """On boards that do not have native BLE, you can use an HCI co-processor. //| Pass the uart and pins used to communicate with the co-processor, such as an Adafruit AirLift. //| The co-processor must have been reset and put into BLE mode beforehand //| by the appropriate pin manipulation. //| The ``uart``, ``rts``, and ``cts`` objects are used to //| communicate with the HCI co-processor in HCI mode. +//| The `Adapter` object is enabled during this call. //| -//| The `_bleio.adapter` object is enabled during this call. +//| After instantiating the Adapter, assign it to _bleio.adapter //| -//| Raises `RuntimeError` on boards with native BLE. +//| On boards with native BLE, you cannot create an instance of `_bleio.Adapter`; +//| this constructor will raise `NotImplementedError`. +//| Use `_bleio.adapter` to access the sole instance already available.""" //| """ //| ... //| -STATIC mp_obj_t bleio_adapter_hci_uart_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +STATIC mp_obj_t bleio_adapter_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { #if CIRCUITPY_BLEIO_HCI - bleio_adapter_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + bleio_adapter_obj_t *self = common_hal_bleio_allocate_adapter_or_raise(); enum { ARG_uart, ARG_rts, ARG_cts }; static const mp_arg_t allowed_args[] = { @@ -97,7 +93,7 @@ STATIC mp_obj_t bleio_adapter_hci_uart_init(mp_uint_t n_args, const mp_obj_t *po }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); busio_uart_obj_t *uart = args[ARG_uart].u_obj; if (!MP_OBJ_IS_TYPE(uart, &busio_uart_type)) { @@ -112,15 +108,14 @@ STATIC mp_obj_t bleio_adapter_hci_uart_init(mp_uint_t n_args, const mp_obj_t *po } // Will enable the adapter. - common_hal_bleio_adapter_hci_uart_init(self, uart, rts, cts); + common_hal_bleio_adapter_construct_hci_uart(self, uart, rts, cts); - return mp_const_none; + return MP_OBJ_FROM_PTR(self); #else - mp_raise_RuntimeError(translate("hci_uart_init not available")); + mp_raise_NotImplementedError(translate("Cannot create a new Adapter; use _bleio.adapter;")); return mp_const_none; #endif // CIRCUITPY_BLEIO_HCI } -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_adapter_hci_uart_init_obj, 1, bleio_adapter_hci_uart_init); //| //| enabled: bool @@ -454,7 +449,6 @@ STATIC mp_obj_t bleio_adapter_erase_bonding(mp_obj_t self_in) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_erase_bonding_obj, bleio_adapter_erase_bonding); STATIC const mp_rom_map_elem_t bleio_adapter_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_hci_uart_init), MP_ROM_PTR(&bleio_adapter_hci_uart_init_obj) }, { MP_ROM_QSTR(MP_QSTR_enabled), MP_ROM_PTR(&bleio_adapter_enabled_obj) }, { MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&bleio_adapter_address_obj) }, { MP_ROM_QSTR(MP_QSTR_name), MP_ROM_PTR(&bleio_adapter_name_obj) }, @@ -479,5 +473,6 @@ STATIC MP_DEFINE_CONST_DICT(bleio_adapter_locals_dict, bleio_adapter_locals_dict const mp_obj_type_t bleio_adapter_type = { .base = { &mp_type_type }, .name = MP_QSTR_Adapter, + .make_new = bleio_adapter_make_new, .locals_dict = (mp_obj_t)&bleio_adapter_locals_dict, }; diff --git a/shared-bindings/_bleio/Adapter.h b/shared-bindings/_bleio/Adapter.h index 62a1d1c76..36e9db761 100644 --- a/shared-bindings/_bleio/Adapter.h +++ b/shared-bindings/_bleio/Adapter.h @@ -38,7 +38,7 @@ const mp_obj_type_t bleio_adapter_type; #if CIRCUITPY_BLEIO_HCI -void common_hal_bleio_adapter_hci_uart_init(bleio_adapter_obj_t *self, busio_uart_obj_t *uart, digitalio_digitalinout_obj_t *rts, digitalio_digitalinout_obj_t *cts); +void common_hal_bleio_adapter_construct_hci_uart(bleio_adapter_obj_t *self, busio_uart_obj_t *uart, digitalio_digitalinout_obj_t *rts, digitalio_digitalinout_obj_t *cts); #endif // CIRCUITPY_BLEIO_HCI extern bool common_hal_bleio_adapter_get_advertising(bleio_adapter_obj_t *self); diff --git a/shared-bindings/_bleio/__init__.c b/shared-bindings/_bleio/__init__.c index f3fdc517e..dece5820f 100644 --- a/shared-bindings/_bleio/__init__.c +++ b/shared-bindings/_bleio/__init__.c @@ -108,8 +108,8 @@ NORETURN void mp_raise_bleio_SecurityError(const compressed_string_t* fmt, ...) // Called when _bleio is imported. STATIC mp_obj_t bleio___init__(void) { +// HCI cannot be enabled on import, because we need to setup the HCI adapter first. #if !CIRCUITPY_BLEIO_HCI - // HCI cannot be enabled on import, because we need to setup the HCI adapter first. common_hal_bleio_adapter_set_enabled(&common_hal_bleio_adapter_obj, true); #endif return mp_const_none; @@ -117,6 +117,74 @@ STATIC mp_obj_t bleio___init__(void) { STATIC MP_DEFINE_CONST_FUN_OBJ_0(bleio___init___obj, bleio___init__); +// Need a forward reference due to mutual references. +#if CIRCUITPY_BLEIO_HCI +STATIC mp_obj_dict_t bleio_module_globals; +#endif + +//| def set_adapter(adapter: Optional[_bleio.Adapter]) -> None: +//| """Set the adapter to use for BLE. Not settable when the adapter is a singleton.""" +//| ... +//| +mp_obj_t bleio_set_adapter(mp_obj_t adapter_obj) { +#if CIRCUITPY_BLEIO_HCI + if (adapter_obj != mp_const_none && !MP_OBJ_IS_TYPE(adapter_obj, &bleio_adapter_type)) { + mp_raise_TypeError_varg(translate("Expected a %q"), bleio_adapter_type.name); + } + + // Equivalent of: + // bleio.adapter = adapter_obj + mp_map_elem_t *elem = mp_map_lookup(&bleio_module_globals.map, MP_ROM_QSTR(MP_QSTR_adapter), MP_MAP_LOOKUP); + if (elem) { + elem->value = adapter_obj; + } +#else + mp_raise_NotImplementedError(translate("Not settable")); +#endif + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(bleio_set_adapter_obj, bleio_set_adapter); + +#if CIRCUITPY_BLEIO_HCI +// Make the module dictionary be in RAM, so that _bleio.adapter can be set. + +STATIC mp_map_elem_t bleio_module_globals_table[] = { + // Name must be the first entry so that the exception printing below is correct. + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__bleio) }, + { MP_ROM_QSTR(MP_QSTR_Adapter), MP_OBJ_FROM_PTR(&bleio_adapter_type) }, + { MP_ROM_QSTR(MP_QSTR_Address), MP_OBJ_FROM_PTR(&bleio_address_type) }, + { MP_ROM_QSTR(MP_QSTR_Attribute), MP_OBJ_FROM_PTR(&bleio_attribute_type) }, + { MP_ROM_QSTR(MP_QSTR_Connection), MP_OBJ_FROM_PTR(&bleio_connection_type) }, + { MP_ROM_QSTR(MP_QSTR_Characteristic), MP_OBJ_FROM_PTR(&bleio_characteristic_type) }, + { MP_ROM_QSTR(MP_QSTR_CharacteristicBuffer), MP_OBJ_FROM_PTR(&bleio_characteristic_buffer_type) }, + { MP_ROM_QSTR(MP_QSTR_Descriptor), MP_OBJ_FROM_PTR(&bleio_descriptor_type) }, + { MP_ROM_QSTR(MP_QSTR_PacketBuffer), MP_OBJ_FROM_PTR(&bleio_packet_buffer_type) }, + { MP_ROM_QSTR(MP_QSTR_ScanEntry), MP_OBJ_FROM_PTR(&bleio_scanentry_type) }, + { MP_ROM_QSTR(MP_QSTR_ScanResults), MP_OBJ_FROM_PTR(&bleio_scanresults_type) }, + { MP_ROM_QSTR(MP_QSTR_Service), MP_OBJ_FROM_PTR(&bleio_service_type) }, + { MP_ROM_QSTR(MP_QSTR_UUID), MP_OBJ_FROM_PTR(&bleio_uuid_type) }, + + // Attributes + { MP_ROM_QSTR(MP_QSTR_adapter), mp_const_none }, + + // Functions + { MP_ROM_QSTR(MP_QSTR_set_adapter), (mp_obj_t) &bleio_set_adapter_obj }, + + // Errors + { MP_ROM_QSTR(MP_QSTR_BluetoothError), MP_OBJ_FROM_PTR(&mp_type_bleio_BluetoothError) }, + { MP_ROM_QSTR(MP_QSTR_ConnectionError), MP_OBJ_FROM_PTR(&mp_type_bleio_ConnectionError) }, + { MP_ROM_QSTR(MP_QSTR_RoleError), MP_OBJ_FROM_PTR(&mp_type_bleio_RoleError) }, + { MP_ROM_QSTR(MP_QSTR_SecurityError), MP_OBJ_FROM_PTR(&mp_type_bleio_SecurityError) }, + + // Initialization + { MP_ROM_QSTR(MP_QSTR___init__), MP_OBJ_FROM_PTR(&bleio___init___obj) }, +}; + +STATIC MP_DEFINE_MUTABLE_DICT(bleio_module_globals, bleio_module_globals_table); + +#else +// When _bleio.adapter is a singleton, and can't be set. + STATIC const mp_rom_map_elem_t bleio_module_globals_table[] = { // Name must be the first entry so that the exception printing below is correct. { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__bleio) }, @@ -144,10 +212,10 @@ STATIC const mp_rom_map_elem_t bleio_module_globals_table[] = { // Initialization { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&bleio___init___obj) }, - }; STATIC MP_DEFINE_CONST_DICT(bleio_module_globals, bleio_module_globals_table); +#endif void bleio_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { mp_print_kind_t k = kind & ~PRINT_EXC_SUBCLASS; diff --git a/shared-bindings/_bleio/__init__.h b/shared-bindings/_bleio/__init__.h index 969d2efb1..588b1f197 100644 --- a/shared-bindings/_bleio/__init__.h +++ b/shared-bindings/_bleio/__init__.h @@ -55,11 +55,14 @@ extern const mp_obj_type_t mp_type_bleio_ConnectionError; extern const mp_obj_type_t mp_type_bleio_RoleError; extern const mp_obj_type_t mp_type_bleio_SecurityError; +extern mp_obj_t bleio_set_adapter(mp_obj_t adapter_obj); + NORETURN void mp_raise_bleio_BluetoothError(const compressed_string_t* msg, ...); NORETURN void mp_raise_bleio_ConnectionError(const compressed_string_t* msg, ...); NORETURN void mp_raise_bleio_RoleError(const compressed_string_t* msg); NORETURN void mp_raise_bleio_SecurityError(const compressed_string_t* msg, ...); +bleio_adapter_obj_t *common_hal_bleio_allocate_adapter_or_raise(void); void common_hal_bleio_check_connected(uint16_t conn_handle); uint16_t common_hal_bleio_device_get_conn_handle(mp_obj_t device); diff --git a/shared-bindings/usb_midi/__init__.c b/shared-bindings/usb_midi/__init__.c index e61086f84..d88a0db48 100644 --- a/shared-bindings/usb_midi/__init__.c +++ b/shared-bindings/usb_midi/__init__.c @@ -51,17 +51,7 @@ mp_map_elem_t usb_midi_module_globals_table[] = { }; // This isn't const so we can set ports dynamically. -mp_obj_dict_t usb_midi_module_globals = { - .base = {&mp_type_dict}, - .map = { - .all_keys_are_qstrs = 1, - .is_fixed = 1, - .is_ordered = 1, - .used = MP_ARRAY_SIZE(usb_midi_module_globals_table), - .alloc = MP_ARRAY_SIZE(usb_midi_module_globals_table), - .table = usb_midi_module_globals_table, - }, -}; +MP_DEFINE_MUTABLE_DICT(usb_midi_module_globals, usb_midi_module_globals_table); const mp_obj_module_t usb_midi_module = { .base = { &mp_type_module }, -- cgit v1.2.3