From 759929c24a9966b64075bedfb365f3dfc66ad681 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 25 Jun 2020 20:57:17 -0400 Subject: [PATCH 01/84] hci early wip; refactor supervisor bluetooth.c for nrf: tested --- devices/ble_hci/common-hal/_bleio/Adapter.c | 717 ++++++++++++++++ devices/ble_hci/common-hal/_bleio/Adapter.h | 71 ++ devices/ble_hci/common-hal/_bleio/Attribute.c | 60 ++ devices/ble_hci/common-hal/_bleio/Attribute.h | 34 + .../common-hal/_bleio/Characteristic.c | 266 ++++++ .../common-hal/_bleio/Characteristic.h | 55 ++ .../common-hal/_bleio/CharacteristicBuffer.c | 151 ++++ .../common-hal/_bleio/CharacteristicBuffer.h | 41 + .../ble_hci/common-hal/_bleio/Connection.c | 768 ++++++++++++++++++ .../ble_hci/common-hal/_bleio/Connection.h | 90 ++ .../ble_hci/common-hal/_bleio/Descriptor.c | 97 +++ .../ble_hci/common-hal/_bleio/Descriptor.h | 53 ++ .../ble_hci/common-hal/_bleio/PacketBuffer.c | 402 +++++++++ .../ble_hci/common-hal/_bleio/PacketBuffer.h | 51 ++ devices/ble_hci/common-hal/_bleio/Service.c | 147 ++++ devices/ble_hci/common-hal/_bleio/Service.h | 54 ++ devices/ble_hci/common-hal/_bleio/UUID.c | 88 ++ devices/ble_hci/common-hal/_bleio/UUID.h | 47 ++ devices/ble_hci/common-hal/_bleio/__init__.c | 246 ++++++ devices/ble_hci/common-hal/_bleio/__init__.h | 50 ++ devices/ble_hci/common-hal/_bleio/bonding.c | 306 +++++++ devices/ble_hci/common-hal/_bleio/bonding.h | 83 ++ devices/ble_hci/common-hal/_bleio/hci.c | 675 +++++++++++++++ devices/ble_hci/supervisor/bluetooth.c | 48 ++ devices/ble_hci/supervisor/bluetooth.h | 34 + ports/atmel-samd/asf4 | 2 +- .../metro_m4_airlift_lite/mpconfigboard.mk | 4 + ports/atmel-samd/peripherals | 2 +- ports/nrf/bluetooth/ble_drv.c | 1 + ports/nrf/supervisor/bluetooth.c | 81 ++ ports/nrf/supervisor/bluetooth.h | 36 + py/circuitpy_defns.mk | 10 +- py/circuitpy_mpconfig.mk | 4 + py/mkrules.mk | 5 +- shared-bindings/_bleio/Adapter.c | 56 +- shared-bindings/_bleio/Connection.c | 1 - supervisor/shared/bluetooth.c | 82 +- supervisor/shared/bluetooth.h | 3 +- supervisor/supervisor.mk | 2 +- 39 files changed, 4845 insertions(+), 78 deletions(-) create mode 100644 devices/ble_hci/common-hal/_bleio/Adapter.c create mode 100644 devices/ble_hci/common-hal/_bleio/Adapter.h create mode 100644 devices/ble_hci/common-hal/_bleio/Attribute.c create mode 100644 devices/ble_hci/common-hal/_bleio/Attribute.h create mode 100644 devices/ble_hci/common-hal/_bleio/Characteristic.c create mode 100644 devices/ble_hci/common-hal/_bleio/Characteristic.h create mode 100644 devices/ble_hci/common-hal/_bleio/CharacteristicBuffer.c create mode 100644 devices/ble_hci/common-hal/_bleio/CharacteristicBuffer.h create mode 100644 devices/ble_hci/common-hal/_bleio/Connection.c create mode 100644 devices/ble_hci/common-hal/_bleio/Connection.h create mode 100644 devices/ble_hci/common-hal/_bleio/Descriptor.c create mode 100644 devices/ble_hci/common-hal/_bleio/Descriptor.h create mode 100644 devices/ble_hci/common-hal/_bleio/PacketBuffer.c create mode 100644 devices/ble_hci/common-hal/_bleio/PacketBuffer.h create mode 100644 devices/ble_hci/common-hal/_bleio/Service.c create mode 100644 devices/ble_hci/common-hal/_bleio/Service.h create mode 100644 devices/ble_hci/common-hal/_bleio/UUID.c create mode 100644 devices/ble_hci/common-hal/_bleio/UUID.h create mode 100644 devices/ble_hci/common-hal/_bleio/__init__.c create mode 100644 devices/ble_hci/common-hal/_bleio/__init__.h create mode 100644 devices/ble_hci/common-hal/_bleio/bonding.c create mode 100644 devices/ble_hci/common-hal/_bleio/bonding.h create mode 100644 devices/ble_hci/common-hal/_bleio/hci.c create mode 100644 devices/ble_hci/supervisor/bluetooth.c create mode 100644 devices/ble_hci/supervisor/bluetooth.h create mode 100644 ports/nrf/supervisor/bluetooth.c create mode 100644 ports/nrf/supervisor/bluetooth.h diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c new file mode 100644 index 0000000000..7e1bfe9920 --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/Adapter.c @@ -0,0 +1,717 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Dan Halbert for Adafruit Industries + * Copyright (c) 2016 Glenn Ruben Bakke + * Copyright (c) 2018 Artur Pacholec + * + * 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 + +#include "bonding.h" + +#include "py/gc.h" +#include "py/objstr.h" +#include "py/runtime.h" +#include "supervisor/shared/safe_mode.h" +#include "supervisor/shared/tick.h" +#include "supervisor/usb.h" +#include "shared-bindings/_bleio/__init__.h" +#include "shared-bindings/_bleio/Adapter.h" +#include "shared-bindings/_bleio/Address.h" +#include "shared-bindings/nvm/ByteArray.h" +#include "shared-bindings/_bleio/Connection.h" +#include "shared-bindings/_bleio/ScanEntry.h" +#include "shared-bindings/time/__init__.h" + +#define BLE_MIN_CONN_INTERVAL MSEC_TO_UNITS(15, UNIT_0_625_MS) +#define BLE_MAX_CONN_INTERVAL MSEC_TO_UNITS(15, UNIT_0_625_MS) +#define BLE_SLAVE_LATENCY 0 +#define BLE_CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS) + +#ifndef BLEIO_VS_UUID_COUNT +#define BLEIO_VS_UUID_COUNT 75 +#endif + +#ifndef BLEIO_HVN_TX_QUEUE_SIZE +#define BLEIO_HVN_TX_QUEUE_SIZE 9 +#endif + +#ifndef BLEIO_CENTRAL_ROLE_COUNT +#define BLEIO_CENTRAL_ROLE_COUNT 4 +#endif + +#ifndef BLEIO_PERIPH_ROLE_COUNT +#define BLEIO_PERIPH_ROLE_COUNT 4 +#endif + +#ifndef BLEIO_ATTR_TAB_SIZE +#define BLEIO_ATTR_TAB_SIZE (BLE_GATTS_ATTR_TAB_SIZE_DEFAULT * 5) +#endif + +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; + // } + + // 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) { +// 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; + + 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 + + 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) { + self->tx = tx; + self->rx = rx; + self->rts = rts; + self->cts = cts; + self->baudrate = baudrate; + self->buffer_size = buffer_size; + self->spi_cs = spi_cs; + self->gpio0 = gpio0; + self->reset = reset; + self->reset_high = reset_high; + self->enabled = false; +} + +void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enabled) { + const bool is_enabled = common_hal_bleio_adapter_get_enabled(self); + + // Don't enable or disable twice + if (is_enabled == enabled) { + return; + } + + if (enabled) { + // Enable adapter. + + // 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); + + // RTS is output, active high + common_hal_digitalio_digitalinout_construct(&self->rts_digitalio, self->rts); + common_hal_digitalio_digitalinout_switch_to_output(&self->rts_digitalio, false, DRIVE_MODE_PUSH_PULL); + + // CTS is input. + common_hal_digitalio_digitalinout_construct(&self->cts_digitalio, self->cts); + + // 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_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); + + // RESET is output, start in non-reset state. + common_hal_digitalio_digitalinout_construct(&self->reset_digitalio, self->reset); + common_hal_digitalio_digitalinout_switch_to_output(&self->reset_digitalio, + !self->reset_high, DRIVE_MODE_PUSH_PULL); + + // Adapter will enter BLE mode on reset, based on SPI_CS and GPIO0 settings. + // Reset HCI processor. Assert reset for 100ms, then wait 750ms for reset to complete. + common_hal_digitalio_digitalinout_set_value(&self->reset_digitalio, self->reset_high); + mp_hal_delay_ms(100); + common_hal_digitalio_digitalinout_set_value(&self->reset_digitalio, !self->reset_high); + mp_hal_delay_ms(750); + + // After reset, set SPI_CS high. + common_hal_digitalio_digitalinout_set_value(&self->spi_cs_digitalio, true); + + return; + } + + // Disable. + common_hal_digitalio_digitalinout_set_value(&self->reset_digitalio, self->reset_high); + mp_hal_delay_ms(100); + common_hal_digitalio_digitalinout_set_value(&self->reset_digitalio, !self->reset_high); + + // Free all pins. + common_hal_busio_uart_deinit(&self->hci_uart); + 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->reset_digitalio); +} + +bool common_hal_bleio_adapter_get_enabled(bleio_adapter_obj_t *self) { + return self->enabled; +} + +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); + + 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); + 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); +} + +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)); +} + +// STATIC bool scan_on_ble_evt(ble_evt_t *ble_evt, void *scan_results_in) { +// bleio_scanresults_obj_t *scan_results = (bleio_scanresults_obj_t*)scan_results_in; + +// if (ble_evt->header.evt_id == BLE_GAP_EVT_TIMEOUT && +// ble_evt->evt.gap_evt.params.timeout.src == BLE_GAP_TIMEOUT_SRC_SCAN) { +// shared_module_bleio_scanresults_set_done(scan_results, true); +// ble_drv_remove_event_handler(scan_on_ble_evt, scan_results); +// return true; +// } + +// if (ble_evt->header.evt_id != BLE_GAP_EVT_ADV_REPORT) { +// return false; +// } +// ble_gap_evt_adv_report_t *report = &ble_evt->evt.gap_evt.params.adv_report; + +// shared_module_bleio_scanresults_append(scan_results, +// supervisor_ticks_ms64(), +// report->type.connectable, +// report->type.scan_response, +// report->rssi, +// report->peer_addr.addr, +// report->peer_addr.addr_type, +// report->data.p_data, +// report->data.len); + +// const uint32_t err_code = sd_ble_gap_scan_start(NULL, scan_results->common_hal_data); +// if (err_code != NRF_SUCCESS) { +// // TODO: Pass the error into the scan results so it can throw an exception. +// scan_results->done = true; +// } +// return true; +// } + +mp_obj_t common_hal_bleio_adapter_start_scan(bleio_adapter_obj_t *self, uint8_t* prefixes, size_t prefix_length, bool extended, mp_int_t buffer_size, mp_float_t timeout, mp_float_t interval, mp_float_t window, mp_int_t minimum_rssi, bool active) { + if (self->scan_results != NULL) { + if (!shared_module_bleio_scanresults_get_done(self->scan_results)) { + mp_raise_bleio_BluetoothError(translate("Scan already in progess. Stop with stop_scan.")); + } + self->scan_results = NULL; + } + self->scan_results = shared_module_bleio_new_scanresults(buffer_size, prefixes, prefix_length, minimum_rssi); + // size_t max_packet_size = extended ? BLE_GAP_SCAN_BUFFER_EXTENDED_MAX_SUPPORTED : BLE_GAP_SCAN_BUFFER_MAX; + // uint8_t *raw_data = m_malloc(sizeof(ble_data_t) + max_packet_size, false); + // ble_data_t * sd_data = (ble_data_t *) raw_data; + // self->scan_results->common_hal_data = sd_data; + // sd_data->len = max_packet_size; + // sd_data->p_data = raw_data + sizeof(ble_data_t); + + // ble_drv_add_event_handler(scan_on_ble_evt, self->scan_results); + + // uint32_t nrf_timeout = SEC_TO_UNITS(timeout, UNIT_10_MS); + // if (timeout <= 0.0001) { + // nrf_timeout = BLE_GAP_SCAN_TIMEOUT_UNLIMITED; + // } + + // ble_gap_scan_params_t scan_params = { + // .extended = extended, + // .interval = SEC_TO_UNITS(interval, UNIT_0_625_MS), + // .timeout = nrf_timeout, + // .window = SEC_TO_UNITS(window, UNIT_0_625_MS), + // .scan_phys = BLE_GAP_PHY_1MBPS, + // .active = active + // }; + // uint32_t err_code; + // vm_used_ble = true; + // err_code = sd_ble_gap_scan_start(&scan_params, sd_data); + + // if (err_code != NRF_SUCCESS) { + // self->scan_results = NULL; + // ble_drv_remove_event_handler(scan_on_ble_evt, self->scan_results); + // check_nrf_error(err_code); + // } + + return MP_OBJ_FROM_PTR(self->scan_results); +} + +void common_hal_bleio_adapter_stop_scan(bleio_adapter_obj_t *self) { + // sd_ble_gap_scan_stop(); + shared_module_bleio_scanresults_set_done(self->scan_results, true); + // ble_drv_remove_event_handler(scan_on_ble_evt, self->scan_results); + self->scan_results = NULL; +} + +// typedef struct { +// uint16_t conn_handle; +// volatile bool done; +// } connect_info_t; + +// STATIC bool connect_on_ble_evt(ble_evt_t *ble_evt, void *info_in) { +// connect_info_t *info = (connect_info_t*)info_in; + +// switch (ble_evt->header.evt_id) { +// case BLE_GAP_EVT_CONNECTED: +// info->conn_handle = ble_evt->evt.gap_evt.conn_handle; +// info->done = true; + +// break; + +// case BLE_GAP_EVT_TIMEOUT: +// // Handle will be invalid. +// info->done = true; +// break; +// default: +// // For debugging. +// // mp_printf(&mp_plat_print, "Unhandled central event: 0x%04x\n", ble_evt->header.evt_id); +// return false; +// break; +// } +// return true; +// } + +mp_obj_t common_hal_bleio_adapter_connect(bleio_adapter_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout) { + + // ble_gap_addr_t addr; + + // addr.addr_type = address->type; + // mp_buffer_info_t address_buf_info; + // mp_get_buffer_raise(address->bytes, &address_buf_info, MP_BUFFER_READ); + // memcpy(addr.addr, (uint8_t *) address_buf_info.buf, NUM_BLEIO_ADDRESS_BYTES); + + // ble_gap_scan_params_t scan_params = { + // .interval = MSEC_TO_UNITS(100, UNIT_0_625_MS), + // .window = MSEC_TO_UNITS(100, UNIT_0_625_MS), + // .scan_phys = BLE_GAP_PHY_1MBPS, + // // timeout of 0 means no timeout + // .timeout = SEC_TO_UNITS(timeout, UNIT_10_MS), + // }; + + // ble_gap_conn_params_t conn_params = { + // .conn_sup_timeout = MSEC_TO_UNITS(4000, UNIT_10_MS), + // .min_conn_interval = MSEC_TO_UNITS(15, UNIT_1_25_MS), + // .max_conn_interval = MSEC_TO_UNITS(300, UNIT_1_25_MS), + // .slave_latency = 0, // number of conn events + // }; + + // connect_info_t event_info; + // ble_drv_add_event_handler(connect_on_ble_evt, &event_info); + // event_info.done = false; + + vm_used_ble = true; + // uint32_t err_code = sd_ble_gap_connect(&addr, &scan_params, &conn_params, BLE_CONN_CFG_TAG_CUSTOM); + + // if (err_code != NRF_SUCCESS) { + // ble_drv_remove_event_handler(connect_on_ble_evt, &event_info); + // check_nrf_error(err_code); + // } + + // while (!event_info.done) { + // RUN_BACKGROUND_TASKS; + // } + + // ble_drv_remove_event_handler(connect_on_ble_evt, &event_info); + + // uint16_t conn_handle = event_info.conn_handle; + // if (conn_handle == BLE_CONN_HANDLE_INVALID) { + // mp_raise_bleio_BluetoothError(translate("Failed to connect: timeout")); + // } + + // // Negotiate for better PHY, larger MTU and data lengths since we are the central. These are + // // nice-to-haves so ignore any errors. + // ble_gap_phys_t const phys = { + // .rx_phys = BLE_GAP_PHY_AUTO, + // .tx_phys = BLE_GAP_PHY_AUTO, + // }; + // sd_ble_gap_phy_update(conn_handle, &phys); + // sd_ble_gattc_exchange_mtu_request(conn_handle, BLE_GATTS_VAR_ATTR_LEN_MAX); + // 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); + } + } + + mp_raise_bleio_BluetoothError(translate("Failed to connect: internal error")); + + return mp_const_none; +} + +// 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; + +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")); + } +} + +// STATIC bool advertising_on_ble_evt(ble_evt_t *ble_evt, void *self_in) { +// bleio_adapter_obj_t *self = (bleio_adapter_obj_t*)self_in; + +// switch (ble_evt->header.evt_id) { +// case BLE_GAP_EVT_ADV_SET_TERMINATED: +// common_hal_bleio_adapter_stop_advertising(self); +// ble_drv_remove_event_handler(advertising_on_ble_evt, self_in); +// break; + +// default: +// // For debugging. +// // mp_printf(&mp_plat_print, "Unhandled advertising event: 0x%04x\n", ble_evt->header.evt_id); +// return false; +// break; +// } +// return true; +// } + +uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, bool connectable, bool anonymous, uint32_t timeout, float interval, uint8_t *advertising_data, uint16_t advertising_data_len, uint8_t *scan_response_data, uint16_t scan_response_data_len) { + // if (self->current_advertising_data != NULL && self->current_advertising_data == self->advertising_data) { + // return NRF_ERROR_BUSY; + // } + + // // If the current advertising data isn't owned by the adapter then it must be an internal + // // advertisement that we should stop. + // if (self->current_advertising_data != NULL) { + // common_hal_bleio_adapter_stop_advertising(self); + // } + + // uint32_t err_code; + // bool extended = advertising_data_len > BLE_GAP_ADV_SET_DATA_SIZE_MAX || + // scan_response_data_len > BLE_GAP_ADV_SET_DATA_SIZE_MAX; + + // uint8_t adv_type; + // if (extended) { + // if (connectable) { + // adv_type = BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_UNDIRECTED; + // } else if (scan_response_data_len > 0) { + // adv_type = BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_UNDIRECTED; + // } else { + // adv_type = BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED; + // } + // } else if (connectable) { + // adv_type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED; + // } else if (scan_response_data_len > 0) { + // adv_type = BLE_GAP_ADV_TYPE_NONCONNECTABLE_SCANNABLE_UNDIRECTED; + // } else { + // adv_type = BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED; + // } + + // if (anonymous) { + // ble_gap_privacy_params_t privacy = { + // .privacy_mode = BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY, + // .private_addr_type = BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE, + // // Rotate the keys one second after we're scheduled to stop + // // advertising. This prevents a potential race condition where we + // // fire off a beacon with the same advertising data but a new MAC + // // address just as we tear down the connection. + // .private_addr_cycle_s = timeout + 1, + // .p_device_irk = NULL, + // }; + // err_code = sd_ble_gap_privacy_set(&privacy); + // } else { + // ble_gap_privacy_params_t privacy = { + // .privacy_mode = BLE_GAP_PRIVACY_MODE_OFF, + // .private_addr_type = BLE_GAP_ADDR_TYPE_PUBLIC, + // .private_addr_cycle_s = 0, + // .p_device_irk = NULL, + // }; + // err_code = sd_ble_gap_privacy_set(&privacy); + // } + // if (err_code != NRF_SUCCESS) { + // return err_code; + // } + + // ble_gap_adv_params_t adv_params = { + // .interval = SEC_TO_UNITS(interval, UNIT_0_625_MS), + // .properties.type = adv_type, + // .duration = SEC_TO_UNITS(timeout, UNIT_10_MS), + // .filter_policy = BLE_GAP_ADV_FP_ANY, + // .primary_phy = BLE_GAP_PHY_1MBPS, + // }; + + // const ble_gap_adv_data_t ble_gap_adv_data = { + // .adv_data.p_data = advertising_data, + // .adv_data.len = advertising_data_len, + // .scan_rsp_data.p_data = scan_response_data_len > 0 ? scan_response_data : NULL, + // .scan_rsp_data.len = scan_response_data_len, + // }; + + // err_code = sd_ble_gap_adv_set_configure(&adv_handle, &ble_gap_adv_data, &adv_params); + // if (err_code != NRF_SUCCESS) { + // return err_code; + // } + + // ble_drv_add_event_handler(advertising_on_ble_evt, self); + + // vm_used_ble = true; + // err_code = sd_ble_gap_adv_start(adv_handle, BLE_CONN_CFG_TAG_CUSTOM); + // if (err_code != NRF_SUCCESS) { + // return err_code; + // } + // self->current_advertising_data = advertising_data; + // return NRF_SUCCESS; + return 0; +} + + +void common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, bool connectable, bool anonymous, uint32_t timeout, mp_float_t interval, mp_buffer_info_t *advertising_data_bufinfo, mp_buffer_info_t *scan_response_data_bufinfo) { + if (self->current_advertising_data != NULL && self->current_advertising_data == self->advertising_data) { + mp_raise_bleio_BluetoothError(translate("Already advertising.")); + } + // interval value has already been validated. + + check_data_fit(advertising_data_bufinfo->len, connectable); + check_data_fit(scan_response_data_bufinfo->len, connectable); + + if (advertising_data_bufinfo->len > 31 && scan_response_data_bufinfo->len > 0) { + mp_raise_bleio_BluetoothError(translate("Extended advertisements with scan response not supported.")); + } + + // Anonymous mode requires a timeout so that we don't continue to broadcast + // 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; + } + } 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)); + } + } + + // 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); + } + + 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); + + // check_nrf_error(_common_hal_bleio_adapter_start_advertising(self, connectable, anonymous, timeout, interval, + // self->advertising_data, + // advertising_data_bufinfo->len, + // self->scan_response_data, + // scan_response_data_bufinfo->len)); +} + +void common_hal_bleio_adapter_stop_advertising(bleio_adapter_obj_t *self) { + // if (adv_handle == BLE_GAP_ADV_SET_HANDLE_NOT_SET) + // return; + + // // TODO: Don't actually stop. Switch to advertising CircuitPython if we don't already have a connection. + // const uint32_t err_code = sd_ble_gap_adv_stop(adv_handle); + // self->current_advertising_data = NULL; + + // if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_INVALID_STATE)) { + // check_nrf_error(err_code); + // } +} + +bool common_hal_bleio_adapter_get_advertising(bleio_adapter_obj_t *self) { + return self->current_advertising_data != NULL; +} + +bool common_hal_bleio_adapter_get_connected(bleio_adapter_obj_t *self) { + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + bleio_connection_internal_t *connection = &bleio_connections[i]; + if (connection->conn_handle != BLE_CONN_HANDLE_INVALID) { + return true; + } + } + return false; +} + +mp_obj_t common_hal_bleio_adapter_get_connections(bleio_adapter_obj_t *self) { + if (self->connection_objs != NULL) { + return self->connection_objs; + } + size_t total_connected = 0; + mp_obj_t items[BLEIO_TOTAL_CONNECTION_COUNT]; + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + bleio_connection_internal_t *connection = &bleio_connections[i]; + if (connection->conn_handle != BLE_CONN_HANDLE_INVALID) { + if (connection->connection_obj == mp_const_none) { + connection->connection_obj = bleio_connection_new_from_internal(connection); + } + items[total_connected] = connection->connection_obj; + total_connected++; + } + } + self->connection_objs = mp_obj_new_tuple(total_connected, items); + return self->connection_objs; +} + +void common_hal_bleio_adapter_erase_bonding(bleio_adapter_obj_t *self) { + bonding_erase_storage(); +} + +void bleio_adapter_gc_collect(bleio_adapter_obj_t* adapter) { + gc_collect_root((void**)adapter, sizeof(bleio_adapter_obj_t) / sizeof(size_t)); + gc_collect_root((void**)bleio_connections, sizeof(bleio_connections) / sizeof(size_t)); +} + +void bleio_adapter_reset(bleio_adapter_obj_t* adapter) { + common_hal_bleio_adapter_stop_scan(adapter); + if (adapter->current_advertising_data != NULL) { + common_hal_bleio_adapter_stop_advertising(adapter); + } + + adapter->connection_objs = NULL; + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + bleio_connection_internal_t *connection = &bleio_connections[i]; + // Disconnect all connections with Python state cleanly. Keep any supervisor-only connections. + if (connection->connection_obj != mp_const_none && + connection->conn_handle != BLE_CONN_HANDLE_INVALID) { + common_hal_bleio_connection_disconnect(connection); + } + connection->connection_obj = mp_const_none; + } +} diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.h b/devices/ble_hci/common-hal/_bleio/Adapter.h new file mode 100644 index 0000000000..c12e9105c4 --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/Adapter.h @@ -0,0 +1,71 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2016 Glenn Ruben Bakke + * + * 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_ADAPTER_H +#define MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_ADAPTER_H + +#include "py/obj.h" +#include "py/objtuple.h" + +#include "shared-bindings/_bleio/Connection.h" +#include "shared-bindings/_bleio/ScanResults.h" +#include "shared-bindings/microcontroller/Pin.h" + +extern bleio_connection_internal_t bleio_connections[BLEIO_TOTAL_CONNECTION_COUNT]; + +typedef struct { + mp_obj_base_t base; + uint8_t* advertising_data; + uint8_t* scan_response_data; + uint8_t* current_advertising_data; + 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; + uint32_t baudrate; + uint16_t buffer_size; + mcu_pin_obj_t* spi_cs; + mcu_pin_obj_t* gpio0; + mcu_pin_obj_t* reset; + bool reset_high; + busio_uart_obj_t hci_uart; + digitalio_digitalinout_obj_t rts_digitalio; + digitalio_digitalinout_obj_t cts_digitalio; + digitalio_digitalinout_obj_t spi_cs_digitalio; + digitalio_digitalinout_obj_t gpio0_digitalio; + digitalio_digitalinout_obj_t reset_digitalio; + bool enabled; +} bleio_adapter_obj_t; + +void bleio_adapter_gc_collect(bleio_adapter_obj_t* adapter); +void bleio_adapter_reset(bleio_adapter_obj_t* adapter); + +#endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_ADAPTER_H diff --git a/devices/ble_hci/common-hal/_bleio/Attribute.c b/devices/ble_hci/common-hal/_bleio/Attribute.c new file mode 100644 index 0000000000..c55914b10d --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/Attribute.c @@ -0,0 +1,60 @@ +/* + * 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 "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; + } +} diff --git a/devices/ble_hci/common-hal/_bleio/Attribute.h b/devices/ble_hci/common-hal/_bleio/Attribute.h new file mode 100644 index 0000000000..cd9c86ca39 --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/Attribute.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 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_ATTRIBUTE_H +#define MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_ATTRIBUTE_H + +#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); + +#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 new file mode 100644 index 0000000000..d507cecca4 --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/Characteristic.c @@ -0,0 +1,266 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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 "py/runtime.h" + +#include "shared-bindings/_bleio/__init__.h" +#include "shared-bindings/_bleio/Characteristic.h" +#include "shared-bindings/_bleio/Descriptor.h" +#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); + } +} + +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; + 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"); + } + self->max_length = max_length; + self->fixed_length = fixed_length; + + if (service->is_remote) { + self->handle = handle; + } else { + common_hal_bleio_service_add_characteristic(self->service, self, initial_value_bufinfo); + } + + if (initial_value_bufinfo != NULL) { + common_hal_bleio_characteristic_set_value(self, initial_value_bufinfo); + } +} + +bleio_descriptor_obj_t *common_hal_bleio_characteristic_get_descriptor_list(bleio_characteristic_obj_t *self) { + return self->descriptor_list; +} + +bleio_service_obj_t *common_hal_bleio_characteristic_get_service(bleio_characteristic_obj_t *self) { + return self->service; +} + +size_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *self, uint8_t* buf, size_t len) { + // Do GATT operations only if this characteristic has been added to a registered service. + if (self->handle != BLE_GATT_HANDLE_INVALID) { + uint16_t conn_handle = bleio_connection_get_conn_handle(self->service->connection); + if (common_hal_bleio_service_get_is_remote(self->service)) { + // self->value is set by evt handler. + return common_hal_bleio_gattc_read(self->handle, conn_handle, buf, len); + } else { + // conn_handle is ignored for non-system attributes. + return common_hal_bleio_gatts_read(self->handle, conn_handle, buf, len); + } + } + + return 0; +} + +void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo) { + if (self->fixed_length && bufinfo->len != self->max_length) { + mp_raise_ValueError(translate("Value length != required fixed length")); + } + if (bufinfo->len > self->max_length) { + mp_raise_ValueError(translate("Value length > max_length")); + } + + // Do GATT operations only if this characteristic has been added to a registered service. + if (self->handle != BLE_GATT_HANDLE_INVALID) { + + if (common_hal_bleio_service_get_is_remote(self->service)) { + uint16_t conn_handle = bleio_connection_get_conn_handle(self->service->connection); + // Last argument is true if write-no-reponse desired. + common_hal_bleio_gattc_write(self->handle, conn_handle, bufinfo, + (self->props & CHAR_PROP_WRITE_NO_RESPONSE)); + } else { + // Always write the value locally even if no connections are active. + // conn_handle is ignored for non-system attributes, so we use BLE_CONN_HANDLE_INVALID. + common_hal_bleio_gatts_write(self->handle, BLE_CONN_HANDLE_INVALID, bufinfo); + // Check to see if we need to notify or indicate any active connections. + 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) { + 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); + } + } + } + } +} + +bleio_uuid_obj_t *common_hal_bleio_characteristic_get_uuid(bleio_characteristic_obj_t *self) { + return self->uuid; +} + +bleio_characteristic_properties_t common_hal_bleio_characteristic_get_properties(bleio_characteristic_obj_t *self) { + return self->props; +} + +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; +} + +void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, bool notify, bool indicate) { + if (self->cccd_handle == BLE_GATT_HANDLE_INVALID) { + mp_raise_bleio_BluetoothError(translate("No CCCD for this Characteristic")); + } + + if (!common_hal_bleio_service_get_is_remote(self->service)) { + mp_raise_bleio_RoleError(translate("Can't set CCCD on local Characteristic")); + } + + 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); + } + +} diff --git a/devices/ble_hci/common-hal/_bleio/Characteristic.h b/devices/ble_hci/common-hal/_bleio/Characteristic.h new file mode 100644 index 0000000000..4d5fa02f05 --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/Characteristic.h @@ -0,0 +1,55 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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_CHARACTERISTIC_H +#define MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_CHARACTERISTIC_H + +#include "shared-bindings/_bleio/Attribute.h" +#include "common-hal/_bleio/Descriptor.h" +#include "shared-module/_bleio/Characteristic.h" +#include "common-hal/_bleio/Service.h" +#include "common-hal/_bleio/UUID.h" + +typedef struct _bleio_characteristic_obj { + mp_obj_base_t base; + // Will be MP_OBJ_NULL before being assigned to a Service. + bleio_service_obj_t *service; + bleio_uuid_obj_t *uuid; + mp_obj_t value; + uint16_t max_length; + bool fixed_length; + uint16_t handle; + bleio_characteristic_properties_t props; + bleio_attribute_security_mode_t read_perm; + bleio_attribute_security_mode_t write_perm; + bleio_descriptor_obj_t *descriptor_list; + uint16_t user_desc_handle; + uint16_t cccd_handle; + uint16_t sccd_handle; +} bleio_characteristic_obj_t; + +#endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_CHARACTERISTIC_H diff --git a/devices/ble_hci/common-hal/_bleio/CharacteristicBuffer.c b/devices/ble_hci/common-hal/_bleio/CharacteristicBuffer.c new file mode 100644 index 0000000000..6f848f8583 --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/CharacteristicBuffer.c @@ -0,0 +1,151 @@ +/* + * 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 "lib/utils/interrupt_char.h" +#include "py/runtime.h" +#include "py/stream.h" + +#include "shared-bindings/_bleio/__init__.h" +#include "shared-bindings/_bleio/Connection.h" +#include "supervisor/shared/tick.h" +#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; +} + +// Assumes that timeout and buffer_size have been validated before call. +void common_hal_bleio_characteristic_buffer_construct(bleio_characteristic_buffer_obj_t *self, + bleio_characteristic_obj_t *characteristic, + mp_float_t timeout, + size_t buffer_size) { + + self->characteristic = characteristic; + self->timeout_ms = timeout * 1000; + // This is a macro. + // 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); + +} + +uint32_t common_hal_bleio_characteristic_buffer_read(bleio_characteristic_buffer_obj_t *self, uint8_t *data, size_t len, int *errcode) { + uint64_t start_ticks = supervisor_ticks_ms64(); + + // Wait for all bytes received or timeout + while ( (ringbuf_num_filled(&self->ringbuf) < len) && (supervisor_ticks_ms64() - start_ticks < self->timeout_ms) ) { + RUN_BACKGROUND_TASKS; + // Allow user to break out of a timeout with a KeyboardInterrupt. + if ( mp_hal_is_interrupted() ) { + return 0; + } + } + + // 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); + + uint32_t num_bytes_read = ringbuf_get_n(&self->ringbuf, data, len); + + // Writes now OK. + 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); + uint16_t count = ringbuf_num_filled(&self->ringbuf); + 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); + ringbuf_clear(&self->ringbuf); + sd_nvic_critical_region_exit(is_nested_critical_region); +} + +bool common_hal_bleio_characteristic_buffer_deinited(bleio_characteristic_buffer_obj_t *self) { + return self->characteristic == NULL; +} + +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); + } +} + +bool common_hal_bleio_characteristic_buffer_connected(bleio_characteristic_buffer_obj_t *self) { + return self->characteristic != NULL && + self->characteristic->service != NULL && + (!self->characteristic->service->is_remote || + (self->characteristic->service->connection != MP_OBJ_NULL && + common_hal_bleio_connection_get_connected(self->characteristic->service->connection))); +} diff --git a/devices/ble_hci/common-hal/_bleio/CharacteristicBuffer.h b/devices/ble_hci/common-hal/_bleio/CharacteristicBuffer.h new file mode 100644 index 0000000000..8738d2c59c --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/CharacteristicBuffer.h @@ -0,0 +1,41 @@ +/* + * 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_CHARACTERISTICBUFFER_H +#define MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_CHARACTERISTICBUFFER_H + +#include "py/ringbuf.h" +#include "shared-bindings/_bleio/Characteristic.h" + +typedef struct { + mp_obj_base_t base; + bleio_characteristic_obj_t *characteristic; + uint32_t timeout_ms; + // Ring buffer storing consecutive incoming values. + ringbuf_t ringbuf; +} bleio_characteristic_buffer_obj_t; + +#endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_CHARACTERISTICBUFFER_H diff --git a/devices/ble_hci/common-hal/_bleio/Connection.c b/devices/ble_hci/common-hal/_bleio/Connection.c new file mode 100644 index 0000000000..6c63f4261f --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/Connection.c @@ -0,0 +1,768 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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 "shared-bindings/_bleio/Connection.h" + +#include +#include + +#include "lib/utils/interrupt_char.h" +#include "py/gc.h" +#include "py/objlist.h" +#include "py/objstr.h" +#include "py/qstr.h" +#include "py/runtime.h" +#include "shared-bindings/_bleio/__init__.h" +#include "shared-bindings/_bleio/Adapter.h" +#include "shared-bindings/_bleio/Attribute.h" +#include "shared-bindings/_bleio/Characteristic.h" +#include "shared-bindings/_bleio/Service.h" +#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}, +}; + +#define CONNECTION_DEBUG (1) +#if CONNECTION_DEBUG + #define CONNECTION_DEBUG_PRINTF(...) printf(__VA_ARGS__) +#else + #define CONNECTION_DEBUG_PRINTF(...) +#endif + +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; +} + +void bleio_connection_clear(bleio_connection_internal_t *self) { + self->remote_service_list = NULL; + + self->conn_handle = BLE_CONN_HANDLE_INVALID; + self->pair_status = PAIR_NOT_PAIRED; + bonding_clear_keys(&self->bonding_keys); +} + +bool common_hal_bleio_connection_get_paired(bleio_connection_obj_t *self) { + if (self->connection == NULL) { + return false; + } + return self->connection->pair_status == PAIR_PAIRED; +} + +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; +} + +void common_hal_bleio_connection_disconnect(bleio_connection_internal_t *self) { + 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)); + + while (self->pair_status == PAIR_WAITING && !mp_hal_is_interrupted()) { + RUN_BACKGROUND_TASKS; + } + if (mp_hal_is_interrupted()) { + return; + } + check_sec_status(self->sec_status); +} + +mp_float_t common_hal_bleio_connection_get_connection_interval(bleio_connection_internal_t *self) { + while (self->conn_params_updating && !mp_hal_is_interrupted()) { + RUN_BACKGROUND_TASKS; + } + return 1.25f * self->conn_params.min_conn_interval; +} + +// 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; +} + +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); +} + +// 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); + +} + +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); + 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); + self->connection->remote_service_list = NULL; + + return services_tuple; +} + +uint16_t bleio_connection_get_conn_handle(bleio_connection_obj_t *self) { + if (self == NULL || self->connection == NULL) { + return BLE_CONN_HANDLE_INVALID; + } + return self->connection->conn_handle; +} + +mp_obj_t bleio_connection_new_from_internal(bleio_connection_internal_t* internal) { + if (internal->connection_obj != mp_const_none) { + return internal->connection_obj; + } + bleio_connection_obj_t *connection = m_new_obj(bleio_connection_obj_t); + connection->base.type = &bleio_connection_type; + connection->connection = internal; + internal->connection_obj = connection; + + return MP_OBJ_FROM_PTR(connection); +} + +// 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; + } + } + + return NULL; +} diff --git a/devices/ble_hci/common-hal/_bleio/Connection.h b/devices/ble_hci/common-hal/_bleio/Connection.h new file mode 100644 index 0000000000..1b6616ab10 --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/Connection.h @@ -0,0 +1,90 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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_CONNECTION_H +#define MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_CONNECTION_H + +#include + +#include "py/obj.h" +#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" + +typedef enum { + PAIR_NOT_PAIRED, + PAIR_WAITING, + PAIR_PAIRED, +} pair_status_t; + +// We split the Connection object into two so that the internal mechanics can live outside of the +// VM. If it were one object, then we'd risk user code seeing a connection object of theirs be +// reused. +typedef struct { + uint16_t conn_handle; + bool is_central; + // Remote services discovered when this peripheral is acting as a client. + bleio_service_obj_t *remote_service_list; + // The advertising data and scan response buffers are held by us, not by the SD, so we must + // maintain them and not change it. If we need to change the contents during advertising, + // there are tricks to get the SD to notice (see DevZone - TBS). + bonding_keys_t bonding_keys; + // EDIV: Encrypted Diversifier: Identifies LTK during legacy pairing. + uint16_t ediv; + volatile pair_status_t pair_status; + uint8_t sec_status; // Internal security status. + mp_obj_t connection_obj; + ble_drv_evt_handler_entry_t handler_entry; + 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. + 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; +} bleio_connection_internal_t; + +typedef struct { + mp_obj_base_t base; + bleio_connection_internal_t* connection; + // The HCI disconnect reason. + uint8_t disconnect_reason; +} bleio_connection_obj_t; + +bool connection_on_ble_evt(ble_evt_t *ble_evt, void *self_in); + +uint16_t bleio_connection_get_conn_handle(bleio_connection_obj_t *self); +mp_obj_t bleio_connection_new_from_internal(bleio_connection_internal_t* connection); +bleio_connection_internal_t *bleio_conn_handle_to_connection(uint16_t conn_handle); + +#endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_CONNECTION_H diff --git a/devices/ble_hci/common-hal/_bleio/Descriptor.c b/devices/ble_hci/common-hal/_bleio/Descriptor.c new file mode 100644 index 0000000000..faf50c658c --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/Descriptor.c @@ -0,0 +1,97 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2016 Glenn Ruben Bakke + * + * 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 "py/runtime.h" + +#include "shared-bindings/_bleio/__init__.h" +#include "shared-bindings/_bleio/Descriptor.h" +#include "shared-bindings/_bleio/Service.h" +#include "shared-bindings/_bleio/UUID.h" + +void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, bleio_characteristic_obj_t *characteristic, bleio_uuid_obj_t *uuid, 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->characteristic = characteristic; + self->uuid = uuid; + self->handle = BLE_GATT_HANDLE_INVALID; + self->read_perm = read_perm; + self->write_perm = write_perm; + + 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; + + common_hal_bleio_descriptor_set_value(self, initial_value_bufinfo); +} + +bleio_uuid_obj_t *common_hal_bleio_descriptor_get_uuid(bleio_descriptor_obj_t *self) { + return self->uuid; +} + +bleio_characteristic_obj_t *common_hal_bleio_descriptor_get_characteristic(bleio_descriptor_obj_t *self) { + return self->characteristic; +} + +size_t common_hal_bleio_descriptor_get_value(bleio_descriptor_obj_t *self, uint8_t* buf, size_t len) { + // Do GATT operations only if this descriptor has been registered + if (self->handle != BLE_GATT_HANDLE_INVALID) { + uint16_t conn_handle = bleio_connection_get_conn_handle(self->characteristic->service->connection); + if (common_hal_bleio_service_get_is_remote(self->characteristic->service)) { + return common_hal_bleio_gattc_read(self->handle, conn_handle, buf, len); + } else { + return common_hal_bleio_gatts_read(self->handle, conn_handle, buf, len); + } + } + + return 0; +} + +void common_hal_bleio_descriptor_set_value(bleio_descriptor_obj_t *self, mp_buffer_info_t *bufinfo) { + if (self->fixed_length && bufinfo->len != self->max_length) { + mp_raise_ValueError(translate("Value length != required fixed length")); + } + if (bufinfo->len > self->max_length) { + mp_raise_ValueError(translate("Value length > max_length")); + } + + self->value = mp_obj_new_bytes(bufinfo->buf, bufinfo->len); + + // Do GATT operations only if this descriptor has been registered. + if (self->handle != BLE_GATT_HANDLE_INVALID) { + uint16_t conn_handle = bleio_connection_get_conn_handle(self->characteristic->service->connection); + if (common_hal_bleio_service_get_is_remote(self->characteristic->service)) { + // false means WRITE_REQ, not write-no-response + common_hal_bleio_gattc_write(self->handle, conn_handle, bufinfo, false); + } else { + common_hal_bleio_gatts_write(self->handle, conn_handle, bufinfo); + } + } + +} diff --git a/devices/ble_hci/common-hal/_bleio/Descriptor.h b/devices/ble_hci/common-hal/_bleio/Descriptor.h new file mode 100644 index 0000000000..097a49f8ec --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/Descriptor.h @@ -0,0 +1,53 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2016 Glenn Ruben Bakke + * + * 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_DESCRIPTOR_H +#define MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_DESCRIPTOR_H + +#include "py/obj.h" + +#include "common-hal/_bleio/UUID.h" + +// Forward declare characteristic because it includes a Descriptor. +struct _bleio_characteristic_obj; + +typedef struct _bleio_descriptor_obj { + mp_obj_base_t base; + // Will be MP_OBJ_NULL before being assigned to a Characteristic. + struct _bleio_characteristic_obj *characteristic; + bleio_uuid_obj_t *uuid; + mp_obj_t value; + uint16_t max_length; + bool fixed_length; + uint16_t handle; + bleio_attribute_security_mode_t read_perm; + bleio_attribute_security_mode_t write_perm; + struct _bleio_descriptor_obj* next; +} bleio_descriptor_obj_t; + +#endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_DESCRIPTOR_H diff --git a/devices/ble_hci/common-hal/_bleio/PacketBuffer.c b/devices/ble_hci/common-hal/_bleio/PacketBuffer.c new file mode 100644 index 0000000000..c3f41bc9d4 --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/PacketBuffer.c @@ -0,0 +1,402 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019-2020 Scott Shawcroft 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 "lib/utils/interrupt_char.h" +#include "py/runtime.h" +#include "py/stream.h" + +#include "shared-bindings/_bleio/__init__.h" +#include "shared-bindings/_bleio/Connection.h" +#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; +} + +void common_hal_bleio_packet_buffer_construct( + bleio_packet_buffer_obj_t *self, bleio_characteristic_obj_t *characteristic, + size_t buffer_size) { + + self->characteristic = characteristic; + self->client = self->characteristic->service->is_remote; + bleio_characteristic_properties_t incoming = self->characteristic->props & (CHAR_PROP_WRITE_NO_RESPONSE | CHAR_PROP_WRITE); + bleio_characteristic_properties_t outgoing = self->characteristic->props & (CHAR_PROP_NOTIFY | CHAR_PROP_INDICATE); + + if (self->client) { + // Swap if we're the client. + bleio_characteristic_properties_t temp = incoming; + incoming = outgoing; + outgoing = temp; + self->conn_handle = bleio_connection_get_conn_handle(MP_OBJ_TO_PTR(self->characteristic->service->connection)); + } else { + self->conn_handle = BLE_CONN_HANDLE_INVALID; + } + + if (incoming) { + if (!ringbuf_alloc(&self->ringbuf, buffer_size * (sizeof(uint16_t) + characteristic->max_length), false)) { + mp_raise_ValueError(translate("Buffer too large and unable to allocate")); + } + } + + if (outgoing) { + self->packet_queued = false; + self->pending_index = 0; + self->pending_size = 0; + self->outgoing[0] = m_malloc(characteristic->max_length, false); + self->outgoing[1] = m_malloc(characteristic->max_length, false); + } else { + self->outgoing[0] = NULL; + 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; + } + } + } +} + +mp_int_t common_hal_bleio_packet_buffer_readinto(bleio_packet_buffer_obj_t *self, uint8_t *data, size_t len) { + if (ringbuf_num_filled(&self->ringbuf) < 2) { + return 0; + } + + // 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); + + // Get packet length, which is in first two bytes of packet. + uint16_t packet_length; + ringbuf_get_n(&self->ringbuf, (uint8_t*) &packet_length, sizeof(uint16_t)); + + mp_int_t ret; + if (packet_length > len) { + // Packet is longer than requested. Return negative of overrun value. + ret = len - packet_length; + // Discard the packet if it's too large. Don't fill data. + while (packet_length--) { + (void) ringbuf_get(&self->ringbuf); + } + } else { + // Read as much as possible, but might be shorter than len. + ringbuf_get_n(&self->ringbuf, data, packet_length); + ret = packet_length; + } + + // Writes now OK. + sd_nvic_critical_region_exit(is_nested_critical_region); + + return ret; +} + +mp_int_t common_hal_bleio_packet_buffer_write(bleio_packet_buffer_obj_t *self, uint8_t *data, size_t len, uint8_t* header, size_t header_len) { + if (self->outgoing[0] == NULL) { + mp_raise_bleio_BluetoothError(translate("Writes not supported on Characteristic")); + } + if (self->conn_handle == BLE_CONN_HANDLE_INVALID) { + return -1; + } + uint16_t outgoing_packet_length = common_hal_bleio_packet_buffer_get_outgoing_packet_length(self); + + if (len + header_len > outgoing_packet_length) { + // Supplied data will not fit in a single BLE packet. + mp_raise_ValueError(translate("Total data to write is larger than outgoing_packet_length")); + } + + if (len + self->pending_size > outgoing_packet_length) { + // No room to append len bytes to packet. Wait until we get a free buffer, + // and keep checking that we haven't been disconnected. + while (self->pending_size != 0 && self->conn_handle != BLE_CONN_HANDLE_INVALID) { + RUN_BACKGROUND_TASKS; + } + } + if (self->conn_handle == BLE_CONN_HANDLE_INVALID) { + return -1; + } + + size_t num_bytes_written = 0; + + uint8_t is_nested_critical_region; + sd_nvic_critical_region_enter(&is_nested_critical_region); + + uint8_t* pending = self->outgoing[self->pending_index]; + + if (self->pending_size == 0) { + memcpy(pending, header, header_len); + self->pending_size += header_len; + num_bytes_written += header_len; + } + memcpy(pending + self->pending_size, data, len); + self->pending_size += len; + num_bytes_written += len; + + 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); + } + return num_bytes_written; +} + +mp_int_t common_hal_bleio_packet_buffer_get_incoming_packet_length(bleio_packet_buffer_obj_t *self) { + // If this PacketBuffer is coming from a remote service via NOTIFY or INDICATE + // the maximum size is what can be sent in one + // BLE packet. But we must be connected to know that value. + // + // Otherwise it can be as long as the characteristic + // will permit, whether or not we're connected. + + if (self->characteristic == NULL) { + return -1; + } + + if (self->characteristic->service != NULL && + self->characteristic->service->is_remote && + (common_hal_bleio_characteristic_get_properties(self->characteristic) & + (CHAR_PROP_INDICATE | CHAR_PROP_NOTIFY))) { + // We are talking to a remote service, and data is arriving via NOTIFY or INDICATE. + if (self->conn_handle != BLE_CONN_HANDLE_INVALID) { + bleio_connection_internal_t *connection = bleio_conn_handle_to_connection(self->conn_handle); + if (connection) { + return MIN(common_hal_bleio_connection_get_max_packet_length(connection), + self->characteristic->max_length); + } + } + // There's no current connection, so we don't know the MTU, and + // we can't tell what the largest incoming packet length would be. + return -1; + } + return self->characteristic->max_length; +} + +mp_int_t common_hal_bleio_packet_buffer_get_outgoing_packet_length(bleio_packet_buffer_obj_t *self) { + // If we are sending data via NOTIFY or INDICATE, the maximum size + // is what can be sent in one BLE packet. But we must be connected + // to know that value. + // + // Otherwise it can be as long as the characteristic + // will permit, whether or not we're connected. + + if (self->characteristic == NULL) { + return -1; + } + + if (self->characteristic->service != NULL && + !self->characteristic->service->is_remote && + (common_hal_bleio_characteristic_get_properties(self->characteristic) & + (CHAR_PROP_INDICATE | CHAR_PROP_NOTIFY))) { + // We are sending to a client, via NOTIFY or INDICATE. + if (self->conn_handle != BLE_CONN_HANDLE_INVALID) { + bleio_connection_internal_t *connection = bleio_conn_handle_to_connection(self->conn_handle); + if (connection) { + return MIN(common_hal_bleio_connection_get_max_packet_length(connection), + self->characteristic->max_length); + } + } + // There's no current connection, so we don't know the MTU, and + // we can't tell what the largest outgoing packet length would be. + return -1; + } + return self->characteristic->max_length; +} + +bool common_hal_bleio_packet_buffer_deinited(bleio_packet_buffer_obj_t *self) { + return self->characteristic == NULL; +} + +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); + } +} diff --git a/devices/ble_hci/common-hal/_bleio/PacketBuffer.h b/devices/ble_hci/common-hal/_bleio/PacketBuffer.h new file mode 100644 index 0000000000..e1577a9957 --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/PacketBuffer.h @@ -0,0 +1,51 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019-2020 Scott Shawcroft 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_PACKETBUFFER_H +#define MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_PACKETBUFFER_H + +#include "py/ringbuf.h" +#include "shared-bindings/_bleio/Characteristic.h" + +typedef struct { + mp_obj_base_t base; + bleio_characteristic_obj_t *characteristic; + // Ring buffer storing consecutive incoming values. + ringbuf_t ringbuf; + // Two outgoing buffers to alternate between. One will be queued for transmission by the SD and + // the other is waiting to be queued and can be extended. + uint8_t* outgoing[2]; + volatile uint16_t pending_size; + // We remember the conn_handle so we can do a NOTIFY/INDICATE to a client. + // We can find out the conn_handle on a Characteristic write or a CCCD write (but not a read). + volatile uint16_t conn_handle; + uint8_t pending_index; + uint8_t write_type; + bool client; + bool packet_queued; +} bleio_packet_buffer_obj_t; + +#endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_PACKETBUFFER_H diff --git a/devices/ble_hci/common-hal/_bleio/Service.c b/devices/ble_hci/common-hal/_bleio/Service.c new file mode 100644 index 0000000000..f194a95dd7 --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/Service.c @@ -0,0 +1,147 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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 "py/runtime.h" +#include "common-hal/_bleio/__init__.h" +#include "shared-bindings/_bleio/Characteristic.h" +#include "shared-bindings/_bleio/Descriptor.h" +#include "shared-bindings/_bleio/Service.h" +#include "shared-bindings/_bleio/Adapter.h" + +uint32_t _common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uuid_obj_t *uuid, bool is_secondary, mp_obj_list_t * characteristic_list) { + self->handle = 0xFFFF; + self->uuid = uuid; + self->characteristic_list = characteristic_list; + self->is_remote = false; + self->connection = NULL; + self->is_secondary = is_secondary; + + 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; + } + + vm_used_ble = true; + + return sd_ble_gatts_service_add(service_type, &nordic_uuid, &self->handle); +} + +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))); +} + +void bleio_service_from_connection(bleio_service_obj_t *self, mp_obj_t connection) { + self->handle = 0xFFFF; + self->uuid = NULL; + self->characteristic_list = mp_obj_new_list(0, NULL); + self->is_remote = true; + self->is_secondary = false; + self->connection = connection; +} + +bleio_uuid_obj_t *common_hal_bleio_service_get_uuid(bleio_service_obj_t *self) { + return self->uuid; +} + +mp_obj_list_t *common_hal_bleio_service_get_characteristic_list(bleio_service_obj_t *self) { + return self->characteristic_list; +} + +bool common_hal_bleio_service_get_is_remote(bleio_service_obj_t *self) { + return self->is_remote; +} + +bool common_hal_bleio_service_get_is_secondary(bleio_service_obj_t *self) { + return self->is_secondary; +} + +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)); +} diff --git a/devices/ble_hci/common-hal/_bleio/Service.h b/devices/ble_hci/common-hal/_bleio/Service.h new file mode 100644 index 0000000000..bb8bc61edc --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/Service.h @@ -0,0 +1,54 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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_SERVICE_H +#define MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_SERVICE_H + +#include "py/objlist.h" +#include "common-hal/_bleio/UUID.h" + +typedef struct bleio_service_obj { + mp_obj_base_t base; + // Handle for the local service. + uint16_t handle; + // True if created during discovery. + bool is_remote; + bool is_secondary; + bleio_uuid_obj_t *uuid; + // The connection object is set only when this is a remote service. + // A local service doesn't know the connection. + mp_obj_t connection; + mp_obj_list_t *characteristic_list; + // Range of attribute handles of this remote service. + uint16_t start_handle; + uint16_t end_handle; + struct bleio_service_obj* next; +} bleio_service_obj_t; + +void bleio_service_from_connection(bleio_service_obj_t *self, mp_obj_t connection); + +#endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_SERVICE_H diff --git a/devices/ble_hci/common-hal/_bleio/UUID.c b/devices/ble_hci/common-hal/_bleio/UUID.c new file mode 100644 index 0000000000..1c6c35e477 --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/UUID.c @@ -0,0 +1,88 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2016 Glenn Ruben Bakke + * + * 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 "py/runtime.h" +#include "common-hal/_bleio/UUID.h" +#include "shared-bindings/_bleio/__init__.h" +#include "shared-bindings/_bleio/Adapter.h" + +// If uuid128 is NULL, this is a Bluetooth SIG 16-bit UUID. +// 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)); + + // 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; +} + +uint32_t common_hal_bleio_uuid_get_uuid16(bleio_uuid_obj_t *self) { + // 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)); +} + +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) { + // buf[0] = self->nrf_ble_uuid.uuid & 0xff; + // buf[1] = self->nrf_ble_uuid.uuid >> 8; + // } else { + // common_hal_bleio_uuid_get_uuid128(self, buf); + // } +} + +// 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")); +// } +// self->nrf_ble_uuid.uuid = nrf_ble_uuid->uuid; +// self->nrf_ble_uuid.type = nrf_ble_uuid->type; +// } + +// // Fill in a ble_uuid_t from my values. +// void bleio_uuid_convert_to_nrf_ble_uuid(bleio_uuid_obj_t *self, ble_uuid_t *nrf_ble_uuid) { +// nrf_ble_uuid->uuid = self->nrf_ble_uuid.uuid; +// nrf_ble_uuid->type = self->nrf_ble_uuid.type; +// } diff --git a/devices/ble_hci/common-hal/_bleio/UUID.h b/devices/ble_hci/common-hal/_bleio/UUID.h new file mode 100644 index 0000000000..584a28960b --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/UUID.h @@ -0,0 +1,47 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2016 Glenn Ruben Bakke + * + * 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_UUID_H +#define MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_UUID_H + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + // 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 + // 128-bit UUIDs. + // ble_uuid_t nrf_ble_uuid; +} bleio_uuid_obj_t; + +// void bleio_uuid_construct_from_nrf_ble_uuid(bleio_uuid_obj_t *self, ble_uuid_t *nrf_uuid); +// void bleio_uuid_convert_to_nrf_ble_uuid(bleio_uuid_obj_t *self, ble_uuid_t *nrf_uuid); + +#endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_UUID_H diff --git a/devices/ble_hci/common-hal/_bleio/__init__.c b/devices/ble_hci/common-hal/_bleio/__init__.c new file mode 100644 index 0000000000..e84bba6626 --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/__init__.c @@ -0,0 +1,246 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2016 Glenn Ruben Bakke + * + * 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 "py/runtime.h" +#include "shared-bindings/_bleio/__init__.h" +#include "shared-bindings/_bleio/Adapter.h" +#include "shared-bindings/_bleio/Characteristic.h" +#include "shared-bindings/_bleio/Connection.h" +#include "shared-bindings/_bleio/Descriptor.h" +#include "shared-bindings/_bleio/Service.h" +#include "shared-bindings/_bleio/UUID.h" +#include "supervisor/shared/bluetooth.h" + +#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); + } +} + +// Turn off BLE on a reset or reload. +void bleio_reset() { + if (!common_hal_bleio_adapter_get_enabled(&common_hal_bleio_adapter_obj)) { + return; + } + bleio_adapter_reset(&common_hal_bleio_adapter_obj); + if (!vm_used_ble) { + // No user-code BLE operations were done, so we can maintain the supervisor state. + return; + } + common_hal_bleio_adapter_set_enabled(&common_hal_bleio_adapter_obj, false); + bonding_reset(); + supervisor_start_bluetooth(); +} + +// The singleton _bleio.Adapter object, bound to _bleio.adapter +// It currently only has properties and no state +bleio_adapter_obj_t common_hal_bleio_adapter_obj = { + .base = { + .type = &bleio_adapter_type, + }, +}; + +void common_hal_bleio_check_connected(uint16_t conn_handle) { + if (conn_handle == BLE_CONN_HANDLE_INVALID) { + mp_raise_bleio_ConnectionError(translate("Not connected")); + } +} + +// GATTS read of a Characteristic or Descriptor. +size_t common_hal_bleio_gatts_read(uint16_t handle, uint16_t conn_handle, uint8_t* buf, size_t len) { + // 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, + }; + + check_nrf_error(sd_ble_gatts_value_get(conn_handle, handle, &gatts_value)); + + return gatts_value.len; +} + +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, + }; + + 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; +} + +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; +} + +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); + } + +} + +void common_hal_bleio_gc_collect(void) { + bleio_adapter_gc_collect(&common_hal_bleio_adapter_obj); +} diff --git a/devices/ble_hci/common-hal/_bleio/__init__.h b/devices/ble_hci/common-hal/_bleio/__init__.h new file mode 100644 index 0000000000..77548dac15 --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/__init__.h @@ -0,0 +1,50 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 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_INIT_H +#define MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_INIT_H + +void bleio_reset(void); + +typedef struct { + // ble_gap_enc_key_t own_enc; + // ble_gap_enc_key_t peer_enc; + // ble_gap_id_key_t peer_id; +} bonding_keys_t; + +// We assume variable length data. +// 20 bytes max (23 - 3). +#define GATT_MAX_DATA_LENGTH (BLE_GATT_ATT_MTU_DEFAULT - 3) + +// 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); +void check_sec_status(uint8_t sec_status); + +// Track if the user code modified the BLE state to know if we need to undo it on reload. +bool vm_used_ble; + +#endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_INIT_H diff --git a/devices/ble_hci/common-hal/_bleio/bonding.c b/devices/ble_hci/common-hal/_bleio/bonding.c new file mode 100644 index 0000000000..d03e418f7f --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/bonding.c @@ -0,0 +1,306 @@ +/* + * 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 new file mode 100644 index 0000000000..7fa66972de --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/bonding.h @@ -0,0 +1,83 @@ +/* + * 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/devices/ble_hci/common-hal/_bleio/hci.c b/devices/ble_hci/common-hal/_bleio/hci.c new file mode 100644 index 0000000000..8ff69f2027 --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/hci.c @@ -0,0 +1,675 @@ + + 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" + +#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 + +HCIClass::HCIClass() : + _debug(NULL), + _recvIndex(0), + _pendingPkt(0) +{ +} + +HCIClass::~HCIClass() +{ +} + +int HCIClass::begin() +{ + _recvIndex = 0; + + return HCITransport.begin(); +} + +void HCIClass::end() +{ + HCITransport.end(); +} + +void HCIClass::poll() +{ + poll(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 + + if (timeout) { + HCITransport.wait(timeout); + } + + while (HCITransport.available()) { + byte b = HCITransport.read(); + + _recvBuffer[_recvIndex++] = b; + + 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; + + handleAclDataPkt(pktLen, &_recvBuffer[1]); + +#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; + + handleEventPkt(pktLen, &_recvBuffer[1]); + +#if defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_METRO_M4_AIRLIFT_LITE) + digitalWrite(NINA_RTS, LOW); +#endif + } + } else { + _recvIndex = 0; + + if (_debug) { + _debug->println(b, HEX); + } + } + } + +#if defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_METRO_M4_AIRLIFT_LITE) + digitalWrite(NINA_RTS, HIGH); +#endif +} + +int HCIClass::reset() +{ + return sendCommand(OGF_HOST_CTL << 10 | OCF_RESET); +} + +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 HCIClass::readBdAddr(uint8_t addr[6]) +{ + int result = sendCommand(OGF_INFO_PARAM << 10 | OCF_READ_BD_ADDR); + + if (result == 0) { + memcpy(addr, _cmdResponse, 6); + } + + return result; +} + +int HCIClass::readRssi(uint16_t handle) +{ + int result = sendCommand(OGF_STATUS_PARAM << 10 | 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 (readRssi->handle == handle) { + rssi = readRssi->rssi; + } + } + + return rssi; +} + +int HCIClass::setEventMask(uint64_t eventMask) +{ + return sendCommand(OGF_HOST_CTL << 10 | OCF_SET_EVENT_MASK, sizeof(eventMask), &eventMask); +} + +int HCIClass::readLeBufferSize(uint16_t& pktLen, uint8_t& maxPkt) +{ + int result = sendCommand(OGF_LE_CTL << 10 | OCF_LE_READ_BUFFER_SIZE); + + if (result == 0) { + struct __attribute__ ((packed)) HCILeBufferSize { + uint16_t pktLen; + uint8_t maxPkt; + } *leBufferSize = (HCILeBufferSize*)_cmdResponse; + + pktLen = leBufferSize->pktLen; + _maxPkt = maxPkt = leBufferSize->maxPkt; + +#ifndef __AVR__ + ATT.setMaxMtu(pktLen - 9); // max pkt len - ACL header size +#endif + } + + return result; +} + +int HCIClass::leSetRandomAddress(uint8_t addr[6]) +{ + return sendCommand(OGF_LE_CTL << 10 | OCF_LE_SET_RANDOM_ADDRESS, 6, addr); +} + +int HCIClass::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); +} + +int HCIClass::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 sendCommand(OGF_LE_CTL << 10 | OCF_LE_SET_ADVERTISING_DATA, sizeof(leAdvertisingData), &leAdvertisingData); +} + +int HCIClass::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); +} + +int HCIClass::leSetAdvertiseEnable(uint8_t enable) +{ + return sendCommand(OGF_LE_CTL << 10 | OCF_LE_SET_ADVERTISE_ENABLE, sizeof(enable), &enable); +} + +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); +} + +int HCIClass::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 sendCommand(OGF_LE_CTL << 10 | OCF_LE_SET_SCAN_ENABLE, sizeof(leScanEnableData), &leScanEnableData); +} + +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) +{ + 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); +} + +int HCIClass::leCancelConn() +{ + return sendCommand(OGF_LE_CTL << 10 | OCF_LE_CANCEL_CONN, 0, NULL); +} + +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); +} + +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; +} + +int HCIClass::disconnect(uint16_t handle) +{ + 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); +} + +void HCIClass::debug(Stream& stream) +{ + _debug = &stream; +} + +void HCIClass::noDebug() +{ + _debug = NULL; +} + +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(); + } + + return _cmdCompleteStatus; +} + +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; + + memcpy(&_aclPktBuffer[sizeof(HCIACLHdr) + aclBufferHeader->dlen - 4], &_recvBuffer[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, &_aclPktBuffer[sizeof(HCIACLHdr)]); + } else { + // use the recv buffer + ATT.handleData(aclHdr->handle & 0x0fff, aclHdr->len, &_recvBuffer[1 + sizeof(HCIACLHdr)]); + } + } 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; + } +} + +void HCIClass::handleEventPkt(uint8_t /*plen*/, uint8_t pdata[]) +{ + 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; + 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); + } + + _debug->println(); + _debug->flush(); + } +} +` diff --git a/devices/ble_hci/supervisor/bluetooth.c b/devices/ble_hci/supervisor/bluetooth.c new file mode 100644 index 0000000000..7a0b775643 --- /dev/null +++ b/devices/ble_hci/supervisor/bluetooth.c @@ -0,0 +1,48 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Scott Shawcroft 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. + */ + +#if CIRCUITPY_BLE_FILE_SERVICE +#error CIRCUITPY_BLE_FILE_SERVICE not implemented for CIRCUITPY_BLEIO_HCI +#endif + +void supervisor_bluetooth_start_advertising(void) { +} + +void supervisor_start_bluetooth(void) { +} + +FIL active_file; +volatile bool new_filename; +volatile bool run_ble_background; +bool was_connected; + +void supervisor_bluetooth_background(void) { +} + +// This happens in an interrupt so we need to be quick. +bool supervisor_bluetooth_hook(ble_evt_t *ble_evt) { + return false; +} diff --git a/devices/ble_hci/supervisor/bluetooth.h b/devices/ble_hci/supervisor/bluetooth.h new file mode 100644 index 0000000000..03645829b1 --- /dev/null +++ b/devices/ble_hci/supervisor/bluetooth.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Scott Shawcroft 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_DEVICE_BLE_HCI_SUPERVISOR_BLUETOOTH_H +#define MICROPY_INCLUDED_DEVICE_BLE_HCI_SUPERVISOR_BLUETOOTH_H + +void supervisor_start_bluetooth(void); +bool supervisor_bluetooth_hook(ble_evt_t *ble_evt); +void supervisor_bluetooth_background(void); + +#endif // MICROPY_INCLUDED_DEVICE_BLE_HCI_SUPERVISOR_BLUETOOTH_H diff --git a/ports/atmel-samd/asf4 b/ports/atmel-samd/asf4 index c0eef7b751..039b5f3bbc 160000 --- a/ports/atmel-samd/asf4 +++ b/ports/atmel-samd/asf4 @@ -1 +1 @@ -Subproject commit c0eef7b75124fc946af5f75e12d82d6d01315ab1 +Subproject commit 039b5f3bbc3f4ba4421e581db290560d59fef625 diff --git a/ports/atmel-samd/boards/metro_m4_airlift_lite/mpconfigboard.mk b/ports/atmel-samd/boards/metro_m4_airlift_lite/mpconfigboard.mk index 4895cda77b..e999629c32 100644 --- a/ports/atmel-samd/boards/metro_m4_airlift_lite/mpconfigboard.mk +++ b/ports/atmel-samd/boards/metro_m4_airlift_lite/mpconfigboard.mk @@ -6,6 +6,10 @@ USB_MANUFACTURER = "Adafruit Industries LLC" CHIP_VARIANT = SAMD51J19A CHIP_FAMILY = samd51 +# Support _bleio via the on-board ESP32 module. +CIRCUITPY_BLEIO = 1 +CIRCUITPY_BLEIO_HCI = 1 + QSPI_FLASH_FILESYSTEM = 1 EXTERNAL_FLASH_DEVICE_COUNT = 3 EXTERNAL_FLASH_DEVICES = "S25FL116K, S25FL216K, GD25Q16C" diff --git a/ports/atmel-samd/peripherals b/ports/atmel-samd/peripherals index e4161d7d6d..6b531fc923 160000 --- a/ports/atmel-samd/peripherals +++ b/ports/atmel-samd/peripherals @@ -1 +1 @@ -Subproject commit e4161d7d6d98d78eddcccb82128856af4baf7e50 +Subproject commit 6b531fc923d9f02b14bd731a5f584ddf716e8773 diff --git a/ports/nrf/bluetooth/ble_drv.c b/ports/nrf/bluetooth/ble_drv.c index e410ac3b42..67c6f34687 100644 --- a/ports/nrf/bluetooth/ble_drv.c +++ b/ports/nrf/bluetooth/ble_drv.c @@ -39,6 +39,7 @@ #include "py/mpstate.h" #include "supervisor/shared/bluetooth.h" +#include "supervisor/bluetooth.h" nrf_nvic_state_t nrf_nvic_state = { 0 }; diff --git a/ports/nrf/supervisor/bluetooth.c b/ports/nrf/supervisor/bluetooth.c new file mode 100644 index 0000000000..8d89d62723 --- /dev/null +++ b/ports/nrf/supervisor/bluetooth.c @@ -0,0 +1,81 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Scott Shawcroft 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 "supervisor/shared/bluetooth.h" +#include "supervisor/bluetooth.h" + +// This happens in an interrupt so we need to be quick. +bool supervisor_bluetooth_hook(ble_evt_t *ble_evt) { +#if CIRCUITPY_BLE_FILE_SERVICE + // Catch writes to filename or contents. Length is read-only. + + bool done = false; + switch (ble_evt->header.evt_id) { + case BLE_GAP_EVT_CONNECTED: + // We run our background task even if it wasn't us connected to because we may want to + // advertise if the user code stopped advertising. + run_ble_background = true; + break; + case BLE_GAP_EVT_DISCONNECTED: + run_ble_background = true; + break; + case BLE_GATTS_EVT_WRITE: { + // A client wrote to a 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 == supervisor_ble_contents_characteristic.handle) { + // Handle events + //write_to_ringbuf(self, evt_write->data, evt_write->len); + // First packet includes a uint16_t le for length at the start. + uint16_t current_length = ((uint16_t*) current_command)[0]; + memcpy(((uint8_t*) current_command) + current_offset, evt_write->data, evt_write->len); + current_offset += evt_write->len; + current_length = ((uint16_t*) current_command)[0]; + if (current_offset == current_length) { + run_ble_background = true; + done = true; + } + } else if (evt_write->handle == supervisor_ble_filename_characteristic.handle) { + new_filename = true; + run_ble_background = true; + done = true; + } else { + return done; + } + break; + } + + default: + // For debugging. + // mp_printf(&mp_plat_print, "Unhandled peripheral event: 0x%04x\n", ble_evt->header.evt_id); + break; + } + return done; +#else + return false; +#endif +} diff --git a/ports/nrf/supervisor/bluetooth.h b/ports/nrf/supervisor/bluetooth.h new file mode 100644 index 0000000000..425de07e4d --- /dev/null +++ b/ports/nrf/supervisor/bluetooth.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Scott Shawcroft 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_NRF_SUPERVISOR_BLUETOOTH_H +#define MICROPY_INCLUDED_NRF_SUPERVISOR_BLUETOOTH_H + +#include + +#include "ble.h" + +bool supervisor_bluetooth_hook(ble_evt_t *ble_evt); + +#endif // MICROPY_INCLUDED_NRF_SUPERVISOR_BLUETOOTH_H diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 74d8f548dd..811de78664 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 3459bff6d7..239bb665e4 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 13a73b90e6..0b3ecc0e17 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 $@ $< diff --git a/shared-bindings/_bleio/Adapter.c b/shared-bindings/_bleio/Adapter.c index 13acb9d3cf..0780e0a327 100644 --- a/shared-bindings/_bleio/Adapter.c +++ b/shared-bindings/_bleio/Adapter.c @@ -65,12 +65,59 @@ //| connections and also initiate connections.""" //| -//| def __init__(self, ): -//| """You cannot create an instance of `_bleio.Adapter`. +//| def __init__(self, *, tx: Pin, rx: Pin, rts: Pin, cts: Pin, baudrate: int = 115200, buffer_size: int = 256, spi_cs: Pin, gpio0: Pin, reset: Pin, reset_high: bool): +//| """On boards with native BLE, such as the nRf52840, +//| 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, +//| call `_bleio.Adapter()` once, passing it the pins used to communicate +//| with an HCI co-processor, such as an Adafruit AirLift, on or off the board. +//| The `Adapter` object will be initialized, enabled, and will be available as `_bleio.adapter`. +//| The `tx`, `rx`, `rts`, and `cs` pins are used to communicate with the HCI co-processor in HCI mode. +//| The `spi_cs` and `gpio0` pins are used to enable BLE mode +//| (usually `spi_cs` is low and `gpio0` is high to enter BLE mode). +//| The `reset` pin is used to reset the co-processor. +//| `reset_high` describes whether the reset pin is active high or active low. +//| +#if CIRCUITPY_BLEIO_HCI +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) { + enum { ARG_tx, ARG_rx, ARG_rts, ARG_cts, ARG_baudrate, ARG_buffer_size, ARG_spi_cs, ARG_gpio0, ARG_reset, ARG_reset_high }; + 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_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_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)]; + mp_arg_parse_all(n_args, pos_args, 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); + 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); + const mcu_pin_obj_t *spi_cs = validate_obj_is_free_pin(args[ARG_spi_cs].u_obj); + const mcu_pin_obj_t *gpio0 = validate_obj_is_free_pin(args[ARG_gpio0].u_obj); + 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; + + common_hal_bleio_adapter_construct(&common_hal_bleio_adapter_obj, tx, rx, rts, cts, + args[ARG_baudrate], arg[ARG_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); +} +#endif +//| //| enabled: Any = ... //| """State of the BLE adapter.""" //| @@ -418,5 +465,8 @@ 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, +#if CIRCUITPY_BLEIO_HCI + .make_new = bleio_adapter_make_new, + #endif .locals_dict = (mp_obj_t)&bleio_adapter_locals_dict, }; diff --git a/shared-bindings/_bleio/Connection.c b/shared-bindings/_bleio/Connection.c index 0a96d8a111..69fc45a777 100644 --- a/shared-bindings/_bleio/Connection.c +++ b/shared-bindings/_bleio/Connection.c @@ -31,7 +31,6 @@ #include #include -#include "ble_drv.h" #include "py/objarray.h" #include "py/objproperty.h" #include "py/objstr.h" diff --git a/supervisor/shared/bluetooth.c b/supervisor/shared/bluetooth.c index 98d0fab38e..d2ff55377a 100644 --- a/supervisor/shared/bluetooth.c +++ b/supervisor/shared/bluetooth.c @@ -24,6 +24,15 @@ * THE SOFTWARE. */ +#if !CIRCUITPY_BLE_FILE_SERVICE +void supervisor_start_bluetooth(void) { +} + +void supervisor_bluetooth_background(void) { +} + +#else + #include #include "extmod/vfs.h" @@ -41,6 +50,8 @@ #include "py/mpstate.h" + + bleio_service_obj_t supervisor_ble_service; bleio_uuid_obj_t supervisor_ble_service_uuid; bleio_characteristic_obj_t supervisor_ble_version_characteristic; @@ -63,10 +74,7 @@ mp_obj_t service_list_items[1]; mp_obj_list_t characteristic_list; mp_obj_t characteristic_list_items[4]; -void supervisor_bluetooth_start_advertising(void) { - #if !CIRCUITPY_BLE_FILE_SERVICE - return; - #endif +STATIC void supervisor_bluetooth_start_advertising(void) { bool is_connected = common_hal_bleio_adapter_get_connected(&common_hal_bleio_adapter_obj); if (is_connected) { return; @@ -83,10 +91,6 @@ void supervisor_bluetooth_start_advertising(void) { } void supervisor_start_bluetooth(void) { - #if !CIRCUITPY_BLE_FILE_SERVICE - return; - #endif - common_hal_bleio_adapter_set_enabled(&common_hal_bleio_adapter_obj, true); supervisor_ble_service_uuid.base.type = &bleio_uuid_type; @@ -177,7 +181,7 @@ volatile bool new_filename; volatile bool run_ble_background; bool was_connected; -void update_file_length(void) { +STATIC void update_file_length(void) { int32_t file_length = -1; mp_buffer_info_t bufinfo; bufinfo.buf = &file_length; @@ -188,7 +192,7 @@ void update_file_length(void) { common_hal_bleio_characteristic_set_value(&supervisor_ble_length_characteristic, &bufinfo); } -void open_current_file(void) { +STATIC void open_current_file(void) { if (active_file.obj.fs != 0) { return; } @@ -203,17 +207,15 @@ void open_current_file(void) { update_file_length(); } -void close_current_file(void) { +STATIC void close_current_file(void) { f_close(&active_file); } uint32_t current_command[1024 / sizeof(uint32_t)]; volatile size_t current_offset; + void supervisor_bluetooth_background(void) { - #if !CIRCUITPY_BLE_FILE_SERVICE - return; - #endif if (!run_ble_background) { return; } @@ -305,54 +307,4 @@ void supervisor_bluetooth_background(void) { } } -// This happens in an interrupt so we need to be quick. -bool supervisor_bluetooth_hook(ble_evt_t *ble_evt) { - #if !CIRCUITPY_BLE_FILE_SERVICE - return false; - #endif - // Catch writes to filename or contents. Length is read-only. - - bool done = false; - switch (ble_evt->header.evt_id) { - case BLE_GAP_EVT_CONNECTED: - // We run our background task even if it wasn't us connected to because we may want to - // advertise if the user code stopped advertising. - run_ble_background = true; - break; - case BLE_GAP_EVT_DISCONNECTED: - run_ble_background = true; - break; - case BLE_GATTS_EVT_WRITE: { - // A client wrote to a 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 == supervisor_ble_contents_characteristic.handle) { - // Handle events - //write_to_ringbuf(self, evt_write->data, evt_write->len); - // First packet includes a uint16_t le for length at the start. - uint16_t current_length = ((uint16_t*) current_command)[0]; - memcpy(((uint8_t*) current_command) + current_offset, evt_write->data, evt_write->len); - current_offset += evt_write->len; - current_length = ((uint16_t*) current_command)[0]; - if (current_offset == current_length) { - run_ble_background = true; - done = true; - } - } else if (evt_write->handle == supervisor_ble_filename_characteristic.handle) { - new_filename = true; - run_ble_background = true; - done = true; - } else { - return done; - } - break; - } - - default: - // For debugging. - // mp_printf(&mp_plat_print, "Unhandled peripheral event: 0x%04x\n", ble_evt->header.evt_id); - break; - } - return done; -} +#endif // #else diff --git a/supervisor/shared/bluetooth.h b/supervisor/shared/bluetooth.h index 1fb6a879a8..aa5ae60bf7 100644 --- a/supervisor/shared/bluetooth.h +++ b/supervisor/shared/bluetooth.h @@ -28,7 +28,6 @@ #define MICROPY_INCLUDED_SUPERVISOR_SHARED_BLUETOOTH_H void supervisor_start_bluetooth(void); -bool supervisor_bluetooth_hook(ble_evt_t *ble_evt); void supervisor_bluetooth_background(void); -#endif +#endif // MICROPY_INCLUDED_SUPERVISOR_SHARED_BLUETOOTH_H diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk index 21803ae0a3..51a8f68255 100644 --- a/supervisor/supervisor.mk +++ b/supervisor/supervisor.mk @@ -33,7 +33,7 @@ endif CFLAGS += -DSPI_FLASH_FILESYSTEM=$(SPI_FLASH_FILESYSTEM) ifeq ($(CIRCUITPY_BLEIO),1) - SRC_SUPERVISOR += supervisor/shared/bluetooth.c + SRC_SUPERVISOR += supervisor/shared/bluetooth.c supervisor/bluetooth.c endif # Choose which flash filesystem impl to use. From 3e616ccead60030a04e237d28cd1034527818509 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 26 Jun 2020 12:21:57 -0400 Subject: [PATCH 02/84] update submodules --- ports/atmel-samd/asf4 | 2 +- ports/atmel-samd/peripherals | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/atmel-samd/asf4 b/ports/atmel-samd/asf4 index 039b5f3bbc..c0eef7b751 160000 --- a/ports/atmel-samd/asf4 +++ b/ports/atmel-samd/asf4 @@ -1 +1 @@ -Subproject commit 039b5f3bbc3f4ba4421e581db290560d59fef625 +Subproject commit c0eef7b75124fc946af5f75e12d82d6d01315ab1 diff --git a/ports/atmel-samd/peripherals b/ports/atmel-samd/peripherals index 6b531fc923..e4161d7d6d 160000 --- a/ports/atmel-samd/peripherals +++ b/ports/atmel-samd/peripherals @@ -1 +1 @@ -Subproject commit 6b531fc923d9f02b14bd731a5f584ddf716e8773 +Subproject commit e4161d7d6d98d78eddcccb82128856af4baf7e50 From 57bac9a1fce15135ba35cdc8e3ca8c63eb2be7c3 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 26 Jun 2020 12:42:54 -0400 Subject: [PATCH 03/84] update submodules --- devices/ble_hci/common-hal/_bleio/Adapter.h | 6 ++++++ .../ble_hci/common-hal/_bleio/Connection.h | 6 ++---- devices/ble_hci/supervisor/bluetooth.c | 19 ------------------- 3 files changed, 8 insertions(+), 23 deletions(-) diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.h b/devices/ble_hci/common-hal/_bleio/Adapter.h index c12e9105c4..9d4d5abf86 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.h +++ b/devices/ble_hci/common-hal/_bleio/Adapter.h @@ -34,8 +34,14 @@ #include "shared-bindings/_bleio/Connection.h" #include "shared-bindings/_bleio/ScanResults.h" +#include "shared-bindings/busio/UART.h" +#include "shared-bindings/digitalio/DigitalInOut.h" #include "shared-bindings/microcontroller/Pin.h" +#ifndef BLEIO_TOTAL_CONNECTION_COUNT +#define BLEIO_TOTAL_CONNECTION_COUNT 5 +#endif + extern bleio_connection_internal_t bleio_connections[BLEIO_TOTAL_CONNECTION_COUNT]; typedef struct { diff --git a/devices/ble_hci/common-hal/_bleio/Connection.h b/devices/ble_hci/common-hal/_bleio/Connection.h index 1b6616ab10..7ad91aa5c5 100644 --- a/devices/ble_hci/common-hal/_bleio/Connection.h +++ b/devices/ble_hci/common-hal/_bleio/Connection.h @@ -61,8 +61,8 @@ typedef struct { volatile pair_status_t pair_status; uint8_t sec_status; // Internal security status. mp_obj_t connection_obj; - ble_drv_evt_handler_entry_t handler_entry; - ble_gap_conn_params_t conn_params; + //REMOVE ble_drv_evt_handler_entry_t handler_entry; + //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. @@ -81,8 +81,6 @@ typedef struct { uint8_t disconnect_reason; } bleio_connection_obj_t; -bool connection_on_ble_evt(ble_evt_t *ble_evt, void *self_in); - uint16_t bleio_connection_get_conn_handle(bleio_connection_obj_t *self); mp_obj_t bleio_connection_new_from_internal(bleio_connection_internal_t* connection); bleio_connection_internal_t *bleio_conn_handle_to_connection(uint16_t conn_handle); diff --git a/devices/ble_hci/supervisor/bluetooth.c b/devices/ble_hci/supervisor/bluetooth.c index 7a0b775643..83a46728e5 100644 --- a/devices/ble_hci/supervisor/bluetooth.c +++ b/devices/ble_hci/supervisor/bluetooth.c @@ -27,22 +27,3 @@ #if CIRCUITPY_BLE_FILE_SERVICE #error CIRCUITPY_BLE_FILE_SERVICE not implemented for CIRCUITPY_BLEIO_HCI #endif - -void supervisor_bluetooth_start_advertising(void) { -} - -void supervisor_start_bluetooth(void) { -} - -FIL active_file; -volatile bool new_filename; -volatile bool run_ble_background; -bool was_connected; - -void supervisor_bluetooth_background(void) { -} - -// This happens in an interrupt so we need to be quick. -bool supervisor_bluetooth_hook(ble_evt_t *ble_evt) { - return false; -} From 1bc2e979eb9ca2f3cb0eed396cc35406eceea27a Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 26 Jun 2020 17:23:20 -0400 Subject: [PATCH 04/84] wip; compiles; much commented out --- devices/ble_hci/common-hal/_bleio/Adapter.c | 254 ++-- devices/ble_hci/common-hal/_bleio/Adapter.h | 14 +- devices/ble_hci/common-hal/_bleio/Attribute.c | 50 +- devices/ble_hci/common-hal/_bleio/Attribute.h | 9 +- .../common-hal/_bleio/Characteristic.c | 215 +-- .../common-hal/_bleio/CharacteristicBuffer.c | 90 +- .../ble_hci/common-hal/_bleio/Connection.c | 1187 +++++++++-------- .../ble_hci/common-hal/_bleio/Connection.h | 1 - .../ble_hci/common-hal/_bleio/PacketBuffer.c | 343 ++--- devices/ble_hci/common-hal/_bleio/Service.c | 114 +- 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 | 268 ++-- 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, 1340 insertions(+), 1675 deletions(-) delete mode 100644 devices/ble_hci/common-hal/_bleio/bonding.c delete mode 100644 devices/ble_hci/common-hal/_bleio/bonding.h diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index 7e1bfe9920..adfd12845e 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; +// 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); +// // 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; - // } - // } +// 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; +// // 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; +// 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; +// 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)); +// // 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 +// #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; +// // 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; - // } +// break; +// } - // case BLE_GAP_EVT_ADV_SET_TERMINATED: - // self->current_advertising_data = 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; -} +// 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 9d4d5abf86..f045f920f4 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 c55914b10d..30a0ebcf05 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; +// 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_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_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_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_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_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; - } -} +// 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 cd9c86ca39..f527bcf740 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 d507cecca4..ff08bf15c4 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, - }; +// 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); +// // 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); - } +// // 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; -} +// 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; +// 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, - }; +// 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; - } +// 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); - } -} +// // 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; + //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); - } + // 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); - } + // // 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); + //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, - }; + // 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); + // 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); + // 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, - }; + // 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)); + // check_nrf_error(sd_ble_gatts_descriptor_add(self->handle, &desc_attr, &descriptor->handle)); - descriptor->next = self->descriptor_list; - self->descriptor_list = descriptor; + // 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); + //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, - }; + // 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; - } + // 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; - } + // // 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); - } + // // 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 6f848f8583..c4eb6a19fe 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 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. +// 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; - } +// 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. +// 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; -} +// 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 6c63f4261f..913f120feb 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; +//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; +// 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; - } +// 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; +// 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_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_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_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_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; +// 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; - } +// 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; - } +// 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; +// 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; - } +// 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_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; +// 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: { +// #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; +// 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; +// 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 +// 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; +// 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 +// #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 +// 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 - }, +// 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 - } - }; +// .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; - } +// 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_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_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_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; - } +// 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; -} +// 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 7ad91aa5c5..bb0c140c55 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 c3f41bc9d4..65d4139605 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 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); +// } -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, - }; +//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; +// 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; -} +// 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; - } +// 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; -} +// 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. +// 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; +// 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; -} +// // 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 f194a95dd7..1f9649b6c3 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_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_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_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, - }; + // 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); + // 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; - } + // 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 + // 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_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; + // ble_gatts_char_handles_t char_handles; - check_nrf_error(sd_ble_gatts_characteristic_add(self->handle, &char_md, &char_attr, &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 + // 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)); + // 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 1c6c35e477..3f5fbe4fe4 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 584a28960b..4a72d38acd 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 e84bba6626..a09c3a05c5 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; - } -} +//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_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; - } +// 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); - } -} +// 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; +//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) { +// 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. +// // 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; - } +// 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; -} +// 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); + //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); - } + // 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; - } + // 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; + // 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, - }; + //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; - } + // 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); - } + // // 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 77548dac15..784dcefdcb 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 d03e418f7f..0000000000 --- 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 7fa66972de..0000000000 --- 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 811de78664..38ef373126 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 0780e0a327..cf3b62ff18 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 39147b6ebc..3f7cd54304 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); From f879114c43297e6cb94f697a6009904d7e260131 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 26 Jun 2020 19:27:05 -0400 Subject: [PATCH 05/84] do HCI pin init in Python, not here --- devices/ble_hci/common-hal/_bleio/Adapter.c | 62 +--------------- devices/ble_hci/common-hal/_bleio/Adapter.h | 7 -- shared-bindings/_bleio/Adapter.c | 82 ++++++++++----------- shared-bindings/_bleio/Adapter.h | 36 ++++----- 4 files changed, 58 insertions(+), 129 deletions(-) diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index adfd12845e..c25bec5b82 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.c +++ b/devices/ble_hci/common-hal/_bleio/Adapter.c @@ -177,17 +177,13 @@ 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_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) { +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->baudrate = baudrate; self->buffer_size = buffer_size; - self->spi_cs = spi_cs; - self->gpio0 = gpio0; - self->reset = reset; - self->reset_high = reset_high; self->enabled = false; } @@ -199,60 +195,8 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable return; } - if (enabled) { - // Enable adapter. - - // 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, 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); - common_hal_digitalio_digitalinout_switch_to_output(&self->rts_digitalio, false, DRIVE_MODE_PUSH_PULL); - - // CTS is input. - common_hal_digitalio_digitalinout_construct(&self->cts_digitalio, self->cts); - - // 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->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); - - // RESET is output, start in non-reset state. - common_hal_digitalio_digitalinout_construct(&self->reset_digitalio, self->reset); - common_hal_digitalio_digitalinout_switch_to_output(&self->reset_digitalio, - !self->reset_high, DRIVE_MODE_PUSH_PULL); - - // Adapter will enter BLE mode on reset, based on SPI_CS and GPIO0 settings. - // Reset HCI processor. Assert reset for 100ms, then wait 750ms for reset to complete. - common_hal_digitalio_digitalinout_set_value(&self->reset_digitalio, self->reset_high); - mp_hal_delay_ms(100); - common_hal_digitalio_digitalinout_set_value(&self->reset_digitalio, !self->reset_high); - mp_hal_delay_ms(750); - - // After reset, set SPI_CS high. - common_hal_digitalio_digitalinout_set_value(&self->spi_cs_digitalio, true); - - return; - } - - // Disable. - common_hal_digitalio_digitalinout_set_value(&self->reset_digitalio, self->reset_high); - mp_hal_delay_ms(100); - common_hal_digitalio_digitalinout_set_value(&self->reset_digitalio, !self->reset_high); - - // Free all pins. - common_hal_busio_uart_deinit(&self->hci_uart); - 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->gpio0_digitalio); - common_hal_digitalio_digitalinout_deinit(&self->reset_digitalio); + //FIX enable/disable HCI adapter, but don't reset it, since we don't know how. + self->enabled = enabled; } bool common_hal_bleio_adapter_get_enabled(bleio_adapter_obj_t *self) { diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.h b/devices/ble_hci/common-hal/_bleio/Adapter.h index f045f920f4..38303062aa 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.h +++ b/devices/ble_hci/common-hal/_bleio/Adapter.h @@ -58,16 +58,9 @@ typedef struct { const mcu_pin_obj_t* cts; uint32_t baudrate; uint16_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; busio_uart_obj_t hci_uart; digitalio_digitalinout_obj_t rts_digitalio; digitalio_digitalinout_obj_t cts_digitalio; - digitalio_digitalinout_obj_t spi_cs_digitalio; - digitalio_digitalinout_obj_t gpio0_digitalio; - digitalio_digitalinout_obj_t reset_digitalio; bool enabled; } bleio_adapter_obj_t; diff --git a/shared-bindings/_bleio/Adapter.c b/shared-bindings/_bleio/Adapter.c index cf3b62ff18..911fa6d35a 100644 --- a/shared-bindings/_bleio/Adapter.c +++ b/shared-bindings/_bleio/Adapter.c @@ -65,24 +65,26 @@ //| connections and also initiate connections.""" //| -//| def __init__(self, *, tx: Pin, rx: Pin, rts: Pin, cts: Pin, baudrate: int = 115200, buffer_size: int = 256, spi_cs: Pin, gpio0: Pin, reset: Pin, reset_high: bool): -//| """On boards with native BLE, such as the nRf52840, -//| you cannot create an instance of `_bleio.Adapter`. +//| 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, -//| call `_bleio.Adapter()` once, passing it the pins used to communicate -//| with an HCI co-processor, such as an Adafruit AirLift, on or off the board. -//| The `Adapter` object will be initialized, enabled, and will be available as `_bleio.adapter`. +//| On boards that do not have native BLE. You can 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. -//| The `spi_cs` and `gpio0` pins are used to enable BLE mode -//| (usually `spi_cs` is low and `gpio0` is high to enter BLE mode). -//| The `reset` pin is used to reset the co-processor. -//| `reset_high` describes whether the reset pin is active high or active low. //| #if CIRCUITPY_BLEIO_HCI -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) { - enum { ARG_tx, ARG_rx, ARG_rts, ARG_cts, ARG_baudrate, ARG_buffer_size, ARG_spi_cs, ARG_gpio0, ARG_reset, ARG_reset_high }; +mp_obj_t bleio_adapter_hci_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + 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 }; 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 }, @@ -90,43 +92,33 @@ 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_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, 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); - 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); - const mcu_pin_obj_t *spi_cs = validate_obj_is_free_pin(args[ARG_spi_cs].u_obj); - const mcu_pin_obj_t *gpio0 = validate_obj_is_free_pin(args[ARG_gpio0].u_obj); - 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; + 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); + 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_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; + 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, - 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(&common_hal_bleio_adapter_obj); + common_hal_bleio_adapter_hci_init(&common_hal_bleio_adapter_obj, tx, rx, rts, cts, + baudrate, buffer_size); + return mp_const_none; } -#endif +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_adapter_hci_init_obj, 1, bleio_adapter_hci_init); +#endif // CIRCUITPY_BLEIO_HCI + //| //| enabled: Any = ... //| """State of the BLE adapter.""" @@ -451,6 +443,9 @@ 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[] = { +#if CIRCUITPY_BLEIO_HCI + { MP_ROM_QSTR(MP_QSTR_hci_init), MP_ROM_PTR(&bleio_adapter_hci_init_obj) }, +#endif { 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) }, @@ -475,8 +470,5 @@ 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, -#if CIRCUITPY_BLEIO_HCI - .make_new = bleio_adapter_make_new, - #endif .locals_dict = (mp_obj_t)&bleio_adapter_locals_dict, }; diff --git a/shared-bindings/_bleio/Adapter.h b/shared-bindings/_bleio/Adapter.h index 3f7cd54304..8fdeb1354c 100644 --- a/shared-bindings/_bleio/Adapter.h +++ b/shared-bindings/_bleio/Adapter.h @@ -38,30 +38,30 @@ 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 +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); +#endif // CIRCUITPY_BLEIO_HCI -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); -extern bool common_hal_bleio_adapter_get_connected(bleio_adapter_obj_t *self); -extern bleio_address_obj_t *common_hal_bleio_adapter_get_address(bleio_adapter_obj_t *self); +bool common_hal_bleio_adapter_get_advertising(bleio_adapter_obj_t *self); +bool common_hal_bleio_adapter_get_enabled(bleio_adapter_obj_t *self); +void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enabled); +bool common_hal_bleio_adapter_get_connected(bleio_adapter_obj_t *self); +bleio_address_obj_t *common_hal_bleio_adapter_get_address(bleio_adapter_obj_t *self); -extern mp_obj_str_t* common_hal_bleio_adapter_get_name(bleio_adapter_obj_t *self); -extern void common_hal_bleio_adapter_set_name(bleio_adapter_obj_t *self, const char* name); +mp_obj_str_t* common_hal_bleio_adapter_get_name(bleio_adapter_obj_t *self); +void common_hal_bleio_adapter_set_name(bleio_adapter_obj_t *self, const char* name); -extern uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, bool connectable, bool anonymous, uint32_t timeout, float interval, uint8_t *advertising_data, uint16_t advertising_data_len, uint8_t *scan_response_data, uint16_t scan_response_data_len); +uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, bool connectable, bool anonymous, uint32_t timeout, float interval, uint8_t *advertising_data, uint16_t advertising_data_len, uint8_t *scan_response_data, uint16_t scan_response_data_len); -extern void common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, bool connectable, bool anonymous, uint32_t timeout, mp_float_t interval, mp_buffer_info_t *advertising_data_bufinfo, mp_buffer_info_t *scan_response_data_bufinfo); -extern void common_hal_bleio_adapter_stop_advertising(bleio_adapter_obj_t *self); +void common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, bool connectable, bool anonymous, uint32_t timeout, mp_float_t interval, mp_buffer_info_t *advertising_data_bufinfo, mp_buffer_info_t *scan_response_data_bufinfo); +void common_hal_bleio_adapter_stop_advertising(bleio_adapter_obj_t *self); -extern mp_obj_t common_hal_bleio_adapter_start_scan(bleio_adapter_obj_t *self, uint8_t* prefixes, size_t prefix_length, bool extended, mp_int_t buffer_size, mp_float_t timeout, mp_float_t interval, mp_float_t window, mp_int_t minimum_rssi, bool active); -extern void common_hal_bleio_adapter_stop_scan(bleio_adapter_obj_t *self); +mp_obj_t common_hal_bleio_adapter_start_scan(bleio_adapter_obj_t *self, uint8_t* prefixes, size_t prefix_length, bool extended, mp_int_t buffer_size, mp_float_t timeout, mp_float_t interval, mp_float_t window, mp_int_t minimum_rssi, bool active); +void common_hal_bleio_adapter_stop_scan(bleio_adapter_obj_t *self); -extern bool common_hal_bleio_adapter_get_connected(bleio_adapter_obj_t *self); -extern mp_obj_t common_hal_bleio_adapter_get_connections(bleio_adapter_obj_t *self); -extern mp_obj_t common_hal_bleio_adapter_connect(bleio_adapter_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout); +bool common_hal_bleio_adapter_get_connected(bleio_adapter_obj_t *self); +mp_obj_t common_hal_bleio_adapter_get_connections(bleio_adapter_obj_t *self); +mp_obj_t common_hal_bleio_adapter_connect(bleio_adapter_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout); -extern void common_hal_bleio_adapter_erase_bonding(bleio_adapter_obj_t *self); +void common_hal_bleio_adapter_erase_bonding(bleio_adapter_obj_t *self); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADAPTER_H From 11cb3e3b4b18a12b56f926f342c65c0f7db93896 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 30 Jun 2020 23:19:40 -0400 Subject: [PATCH 06/84] 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 | 1055 +++++++++---------- 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, 587 insertions(+), 549 deletions(-) diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index c25bec5b82..5f5259f7ef 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 38303062aa..565963dc0d 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 8ff69f2027..7d4add9afd 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); -HCIClass::~HCIClass() -{ -} - -int HCIClass::begin() -{ - _recvIndex = 0; - - return HCITransport.begin(); -} - -void HCIClass::end() -{ - HCITransport.end(); -} - -void HCIClass::poll() -{ - poll(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 - - if (timeout) { - HCITransport.wait(timeout); - } - - while (HCITransport.available()) { - byte b = HCITransport.read(); - - _recvBuffer[_recvIndex++] = b; - - if (_recvBuffer[0] == HCI_ACLDATA_PKT) { - if (_recvIndex > 5 && _recvIndex >= (5 + (_recvBuffer[3] + (_recvBuffer[4] << 8)))) { - if (_debug) { - dumpPkt("HCI ACLDATA RX <- ", _recvIndex, _recvBuffer); + for (uint8_t i = 0; i < plen; i++) { + mp_printf(&mp_plat_print, "%02x", pdata[i]); } -#if defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_METRO_M4_AIRLIFT_LITE) - digitalWrite(NINA_RTS, HIGH); -#endif - int pktLen = _recvIndex - 1; - _recvIndex = 0; + mp_printf(&mp_plat_print, "\n"); + } +} - handleAclDataPkt(pktLen, &_recvBuffer[1]); -#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; +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; - handleEventPkt(pktLen, &_recvBuffer[1]); + // HCIACLHdr *aclHdr = (HCIACLHdr*)pdata; -#if defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_METRO_M4_AIRLIFT_LITE) - digitalWrite(NINA_RTS, LOW); -#endif - } + // 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 { - _recvIndex = 0; - - if (_debug) { - _debug->println(b, HEX); - } + pending_pkt = 0; } - } - -#if defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_METRO_M4_AIRLIFT_LITE) - digitalWrite(NINA_RTS, HIGH); -#endif } -int HCIClass::reset() +STATIC void handleEventPkt(uint8_t plen, uint8_t pdata[]) { - return sendCommand(OGF_HOST_CTL << 10 | OCF_RESET); -} + HCIEventHdr *eventHdr = (HCIEventHdr*)pdata; -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 (eventHdr->evt == EVT_DISCONN_COMPLETE) { + typedef struct __attribute__ ((packed)) { + uint8_t status; + uint16_t handle; + uint8_t reason; + } DisconnComplete; - 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; + DisconnComplete *disconnComplete = (DisconnComplete*)&pdata[sizeof(HCIEventHdr)]; + (void) disconnComplete; + //FIX + // ATT.removeConnection(disconnComplete->handle, disconnComplete->reason); + // L2CAPSignaling.removeConnection(disconnComplete->handle, disconnComplete->reason); - hciVer = localVersion->hciVer; - hciRev = localVersion->hciRev; - lmpVer = localVersion->lmpVer; - manufacturer = localVersion->manufacturer; - lmpSubVer = localVersion->lmpSubVer; - } + hci_leSetAdvertiseEnable(0x01); + } else if (eventHdr->evt == EVT_CMD_COMPLETE) { + typedef struct __attribute__ ((packed)) { + uint8_t ncmd; + uint16_t opcode; + uint8_t status; + } CmdComplete; - return result; -} + 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)]; -int HCIClass::readBdAddr(uint8_t addr[6]) -{ - int result = sendCommand(OGF_INFO_PARAM << 10 | OCF_READ_BD_ADDR); + } else if (eventHdr->evt == EVT_CMD_STATUS) { + typedef struct __attribute__ ((packed)) { + uint8_t status; + uint8_t ncmd; + uint16_t opcode; + } CmdStatus; - if (result == 0) { - memcpy(addr, _cmdResponse, 6); - } + 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)]; - return result; -} + for (uint8_t i = 0; i < numHandles; i++) { + handleNumCompPkts(data[0], data[1]); -int HCIClass::readRssi(uint16_t handle) -{ - int result = sendCommand(OGF_STATUS_PARAM << 10 | OCF_READ_RSSI, sizeof(handle), &handle); - int rssi = 127; + data += 2; + } + } else if (eventHdr->evt == EVT_LE_META_EVENT) { + typedef struct __attribute__ ((packed)) { + uint8_t subevent; + } LeMetaEventHeader; - if (result == 0) { - struct __attribute__ ((packed)) HCIReadRssi { - uint16_t handle; - int8_t rssi; - } *readRssi = (HCIReadRssi*)_cmdResponse; + 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; - if (readRssi->handle == handle) { - rssi = readRssi->rssi; + 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); + + } + } } - } - - return rssi; } -int HCIClass::setEventMask(uint64_t eventMask) -{ - return sendCommand(OGF_HOST_CTL << 10 | OCF_SET_EVENT_MASK, sizeof(eventMask), &eventMask); +void hci_init(bleio_adapter_obj_t *adapter_in) { + adapter = adapter_in; + recv_idx = 0; + pending_pkt = 0; } -int HCIClass::readLeBufferSize(uint16_t& pktLen, uint8_t& maxPkt) +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) { - int result = sendCommand(OGF_LE_CTL << 10 | OCF_LE_READ_BUFFER_SIZE); + uint16_t opcode = ogf << 10 | ocf; - if (result == 0) { - struct __attribute__ ((packed)) HCILeBufferSize { - uint16_t pktLen; - uint8_t maxPkt; - } *leBufferSize = (HCILeBufferSize*)_cmdResponse; + struct __attribute__ ((packed)) { + uint8_t pktType; + uint16_t opcode; + uint8_t plen; + } pktHdr = {HCI_COMMAND_PKT, opcode, plen}; - pktLen = leBufferSize->pktLen; - _maxPkt = maxPkt = leBufferSize->maxPkt; + 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__ - 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; + 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; + 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); + 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; + 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); + 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); + return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_SCAN_RESPONSE_DATA, sizeof(leScanResponseData), &leScanResponseData); } -int HCIClass::leSetAdvertiseEnable(uint8_t enable) +int hci_leSetAdvertiseEnable(uint8_t enable) { - return sendCommand(OGF_LE_CTL << 10 | OCF_LE_SET_ADVERTISE_ENABLE, sizeof(enable), &enable); + return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_ADVERTISE_ENABLE, sizeof(enable), &enable); } -int HCIClass::leSetScanParameters(uint8_t type, uint16_t interval, uint16_t window, - uint8_t ownBdaddrType, uint8_t filter) +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; + 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; + 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_PARAMETERS, sizeof(leScanParameters), &leScanParameters); } -int HCIClass::leSetScanEnable(uint8_t enabled, uint8_t duplicates) +int hci_leSetScanEnable(uint8_t enabled, uint8_t duplicates) { - struct __attribute__ ((packed)) HCILeSetScanEnableData { - uint8_t enabled; - uint8_t duplicates; - } leScanEnableData; + struct __attribute__ ((packed)) HCILeSetScanEnableData { + uint8_t enabled; + uint8_t duplicates; + } leScanEnableData; - leScanEnableData.enabled = enabled; - leScanEnableData.duplicates = duplicates; + 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_SCAN_ENABLE, sizeof(leScanEnableData), &leScanEnableData); } -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_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 sendCommand(OGF_LE_CTL << 10 | OCF_LE_CREATE_CONN, sizeof(leCreateConnData), &leCreateConnData); -} - -int HCIClass::leCancelConn() -{ - return sendCommand(OGF_LE_CTL << 10 | OCF_LE_CANCEL_CONN, 0, NULL); -} - -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); -} - -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; -} - -int HCIClass::disconnect(uint16_t handle) -{ - 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); -} - -void HCIClass::debug(Stream& stream) -{ - _debug = &stream; -} - -void HCIClass::noDebug() -{ - _debug = NULL; -} - -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(); - } - - return _cmdCompleteStatus; -} - -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; - - memcpy(&_aclPktBuffer[sizeof(HCIACLHdr) + aclBufferHeader->dlen - 4], &_recvBuffer[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, &_aclPktBuffer[sizeof(HCIACLHdr)]); - } else { - // use the recv buffer - ATT.handleData(aclHdr->handle & 0x0fff, aclHdr->len, &_recvBuffer[1 + sizeof(HCIACLHdr)]); - } - } 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; - } -} - -void HCIClass::handleEventPkt(uint8_t /*plen*/, uint8_t pdata[]) -{ - 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; - uint16_t handle; - uint8_t role; + struct __attribute__ ((packed)) HCILeCreateConnData { + uint16_t interval; + uint16_t window; + uint8_t initiatorFilter; uint8_t peerBdaddrType; uint8_t peerBdaddr[6]; - uint16_t interval; + uint8_t ownBdaddrType; + uint16_t minInterval; + uint16_t maxInterval; uint16_t latency; uint16_t supervisionTimeout; - uint8_t masterClockAccuracy; - } *leConnectionComplete = (EvtLeConnectionComplete*)&pdata[sizeof(HCIEventHdr) + sizeof(LeMetaEventHeader)]; + uint16_t minCeLength; + uint16_t maxCeLength; + } leCreateConnData; - if (leConnectionComplete->status == 0x00) { - ATT.addConnection(leConnectionComplete->handle, - leConnectionComplete->role, - leConnectionComplete->peerBdaddrType, - leConnectionComplete->peerBdaddr, - leConnectionComplete->interval, - leConnectionComplete->latency, - leConnectionComplete->supervisionTimeout, - leConnectionComplete->masterClockAccuracy); + 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; - 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); - - } - } - } + return hci_sendCommand(OGF_LE_CTL, OCF_LE_CREATE_CONN, sizeof(leCreateConnData), &leCreateConnData); } -void HCIClass::dumpPkt(const char* prefix, uint8_t plen, uint8_t pdata[]) +int hci_leCancelConn() { - if (_debug) { - _debug->print(prefix); + return hci_sendCommand(OGF_LE_CTL, OCF_LE_CANCEL_CONN, 0, NULL); +} - for (uint8_t i = 0; i < plen; i++) { - byte b = pdata[i]; +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; - if (b < 16) { - _debug->print("0"); - } + leConnUpdateData.handle = handle; + leConnUpdateData.minInterval = minInterval; + leConnUpdateData.maxInterval = maxInterval; + leConnUpdateData.latency = latency; + leConnUpdateData.supervisionTimeout = supervisionTimeout; + leConnUpdateData.minCeLength = 0x0004; + leConnUpdateData.maxCeLength = 0x0006; - _debug->print(b, HEX); + 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(); } - _debug->println(); - _debug->flush(); - } + 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/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile index 5f901a1991..cce89a7acb 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 38ef373126..b30159c7c1 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 911fa6d35a..1b991ac6d4 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 90b185f79a..29405ecadd 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__); From a5ab2829eb90f15d0b78678cd2f2aadd18160fed Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 8 Jul 2020 09:33:41 -0400 Subject: [PATCH 07/84] 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 + .../common-hal/_bleio/hci_include/#hci.h# | 1775 +++++++++++++++++ .../common-hal/_bleio/hci_include/README.md | 2 + .../common-hal/_bleio/hci_include/addr.h | 100 + .../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 ++ .../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 diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index 5f5259f7ef..9dbeca68f5 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 565963dc0d..73b9fed0b0 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 7d4add9afd..0000000000 --- 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 0000000000..180ab6f5ec --- /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 0000000000..a2235ec8c1 --- /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 0000000000..942a82a3c6 --- /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 0000000000..4d2968c39c --- /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 0000000000..8f503b8a17 --- /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 0000000000..dbe233fef0 --- /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 0000000000..476d3f4638 --- /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 0000000000..030fb0ca3c --- /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 0000000000..e4f94b6a83 --- /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 b30159c7c1..0dd31904f2 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 1b991ac6d4..6ad4b75456 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 8fdeb1354c..9caca161f2 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 531980effc..60a67b2161 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""" From f03045b97e7fa9c1b65f5d457036aec1f451f3da Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 8 Jul 2020 23:15:48 -0400 Subject: [PATCH 08/84] address working; improved pkt dump --- devices/ble_hci/common-hal/_bleio/Adapter.c | 22 +- devices/ble_hci/common-hal/_bleio/Adapter.h | 11 +- .../ble_hci/common-hal/_bleio/Connection.c | 2 +- devices/ble_hci/common-hal/_bleio/__init__.c | 53 +- devices/ble_hci/common-hal/_bleio/__init__.h | 4 +- devices/ble_hci/common-hal/_bleio/hci_api.c | 96 +- devices/ble_hci/common-hal/_bleio/hci_api.h | 20 +- .../common-hal/_bleio/hci_include/#hci.h# | 1775 ----------------- shared-bindings/_bleio/Adapter.c | 25 +- shared-bindings/_bleio/Adapter.h | 2 +- 10 files changed, 148 insertions(+), 1862 deletions(-) delete mode 100644 devices/ble_hci/common-hal/_bleio/hci_include/#hci.h# diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index 9dbeca68f5..c08eb2db40 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.c +++ b/devices/ble_hci/common-hal/_bleio/Adapter.c @@ -179,10 +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, busio_uart_obj_t *uart, const mcu_pin_obj_t *rts, const mcu_pin_obj_t *cts) { +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) { self->hci_uart = uart; - self->rts_pin = rts; - self->cts_pin = cts; + self->rts_digitalinout = rts; + self->cts_digitalinout = cts; self->enabled = false; } @@ -194,16 +194,6 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable return; } - if (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_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; } @@ -213,13 +203,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) { - bt_addr_le_t addr; - hci_read_bd_addr(&addr.a); + bt_addr_t addr; + check_hci_error(hci_read_bd_addr(&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, addr.a.val, addr.type); + common_hal_bleio_address_construct(address, addr.val, BT_ADDR_LE_PUBLIC); return address; } diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.h b/devices/ble_hci/common-hal/_bleio/Adapter.h index 73b9fed0b0..dbec03bd84 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.h +++ b/devices/ble_hci/common-hal/_bleio/Adapter.h @@ -36,7 +36,6 @@ #include "shared-bindings/_bleio/ScanResults.h" #include "shared-bindings/busio/UART.h" #include "shared-bindings/digitalio/DigitalInOut.h" -#include "shared-bindings/microcontroller/Pin.h" #ifndef BLEIO_TOTAL_CONNECTION_COUNT #define BLEIO_TOTAL_CONNECTION_COUNT 5 @@ -44,19 +43,17 @@ extern bleio_connection_internal_t bleio_connections[BLEIO_TOTAL_CONNECTION_COUNT]; -typedef struct { +typedef struct _bleio_adapter_obj_t { mp_obj_base_t base; uint8_t* advertising_data; uint8_t* scan_response_data; uint8_t* current_advertising_data; - bleio_scanresults_obj_t* scan_results; + bleio_scanresults_obj_t *scan_results; mp_obj_t name; mp_obj_tuple_t *connection_objs; busio_uart_obj_t* hci_uart; - const mcu_pin_obj_t* rts_pin; - const mcu_pin_obj_t* cts_pin; - digitalio_digitalinout_obj_t rts_digitalinout; - digitalio_digitalinout_obj_t cts_digitalinout; + 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/Connection.c b/devices/ble_hci/common-hal/_bleio/Connection.c index 913f120feb..6b528552ae 100644 --- a/devices/ble_hci/common-hal/_bleio/Connection.c +++ b/devices/ble_hci/common-hal/_bleio/Connection.c @@ -356,7 +356,7 @@ void common_hal_bleio_connection_pair(bleio_connection_internal_t *self, bool bo if (mp_hal_is_interrupted()) { return; } - check_sec_status(self->sec_status); + //FIX check_sec_status(self->sec_status); } mp_float_t common_hal_bleio_connection_get_connection_interval(bleio_connection_internal_t *self) { diff --git a/devices/ble_hci/common-hal/_bleio/__init__.c b/devices/ble_hci/common-hal/_bleio/__init__.c index a09c3a05c5..e32ca55ec8 100644 --- a/devices/ble_hci/common-hal/_bleio/__init__.c +++ b/devices/ble_hci/common-hal/_bleio/__init__.c @@ -38,25 +38,41 @@ #include "shared-bindings/_bleio/UUID.h" #include "supervisor/shared/bluetooth.h" -#include "common-hal/_bleio/__init__.h" +void check_hci_error(hci_result_t result) { + switch (result) { + case HCI_OK: + return; -//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; -// } -// } + case HCI_NO_RESPONSE: + mp_raise_bleio_BluetoothError(translate("No HCI command response received")); + return; + + case HCI_READ_TIMEOUT: + mp_raise_bleio_BluetoothError(translate("Timeout waiting for HCI response")); + return; + + case HCI_WRITE_TIMEOUT: + mp_raise_bleio_BluetoothError(translate("Timeout waiting to write HCI request")); + return; + + case HCI_READ_ERROR: + mp_raise_bleio_BluetoothError(translate("Error reading from HCI adapter")); + return; + + case HCI_WRITE_ERROR: + mp_raise_bleio_BluetoothError(translate("Error writing to HCI adapter")); + return; + + default: + // Should be an HCI status error, > 0. + if (result > 0) { + mp_raise_bleio_BluetoothError(translate("HCI status error: %02x"), result); + } else { + mp_raise_bleio_BluetoothError(translate("Unknown hci_result_t: %d"), result); + } + return; + } +} // void check_gatt_status(uint16_t gatt_status) { // if (gatt_status == BLE_GATT_STATUS_SUCCESS) { @@ -104,7 +120,6 @@ void bleio_reset() { } // The singleton _bleio.Adapter object, bound to _bleio.adapter -// It currently only has properties and no state bleio_adapter_obj_t common_hal_bleio_adapter_obj = { .base = { .type = &bleio_adapter_type, diff --git a/devices/ble_hci/common-hal/_bleio/__init__.h b/devices/ble_hci/common-hal/_bleio/__init__.h index 784dcefdcb..00f5e0c68c 100644 --- a/devices/ble_hci/common-hal/_bleio/__init__.h +++ b/devices/ble_hci/common-hal/_bleio/__init__.h @@ -29,6 +29,8 @@ #include +#include "hci_api.h" + void bleio_reset(void); typedef struct { @@ -49,7 +51,7 @@ typedef struct { // These helpers raise the appropriate exceptions if the code doesn't equal success. -void check_nrf_error(uint32_t err_code); +void check_hci_error(hci_result_t result); void check_gatt_status(uint16_t gatt_status); void check_sec_status(uint8_t sec_status); diff --git a/devices/ble_hci/common-hal/_bleio/hci_api.c b/devices/ble_hci/common-hal/_bleio/hci_api.c index 180ab6f5ec..a82c0c93ca 100644 --- a/devices/ble_hci/common-hal/_bleio/hci_api.c +++ b/devices/ble_hci/common-hal/_bleio/hci_api.c @@ -14,6 +14,8 @@ #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" @@ -21,6 +23,8 @@ #include #include "supervisor/shared/tick.h" +#include "shared-bindings/_bleio/__init__.h" +#include "common-hal/_bleio/Adapter.h" // HCI H4 protocol packet types: first byte in the packet. #define H4_CMD 0x01 @@ -31,13 +35,15 @@ //FIX replace #define ATT_CID 0x0004 +#define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER)) + #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; +#define adapter (&common_hal_bleio_adapter_obj) STATIC uint8_t rx_buffer[RX_BUFFER_SIZE]; STATIC size_t rx_idx; @@ -81,12 +87,55 @@ typedef struct __attribute__ ((packed)) { } h4_hci_evt_hdr_t; - -STATIC void dump_pkt(const char* prefix, uint8_t pkt_len, uint8_t pkt_data[]) { +STATIC void dump_cmd_pkt(bool tx, 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]); + h4_hci_cmd_hdr_t *pkt = (h4_hci_cmd_hdr_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); + uint8_t i; + for (i = sizeof(h4_hci_cmd_hdr_t); i < pkt_len; i++) { + mp_printf(&mp_plat_print, "%02x ", pkt_data[i]); + } + if (i != pkt->param_len + sizeof(h4_hci_cmd_hdr_t)) { + 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) { + h4_hci_acl_hdr_t *pkt = (h4_hci_acl_hdr_t *) pkt_data; + mp_printf(&mp_plat_print, + "%s HCI ACLDATA (%x) handle: %04x, total_data_len: %d, acl_data_len: %d, cid: %04x, data: ", + tx ? "TX->" : "RX<-", + pkt->pkt_type, pkt->handle, pkt->total_data_len, pkt->acl_data_len, pkt->cid); + uint8_t i; + for (i = sizeof(h4_hci_acl_hdr_t); i < pkt_len; i++) { + mp_printf(&mp_plat_print, "%02x ", pkt_data[i]); + } + if (i != pkt->acl_data_len + sizeof(h4_hci_acl_hdr_t)) { + 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_hdr_t *pkt = (h4_hci_evt_hdr_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); + uint8_t i; + for (i = sizeof(h4_hci_evt_hdr_t); i < pkt_len; i++) { + mp_printf(&mp_plat_print, "%02x ", pkt_data[i]); + } + if (i != pkt->param_len + sizeof(h4_hci_evt_hdr_t)) { + mp_printf(&mp_plat_print, " LENGTH MISMATCH"); } mp_printf(&mp_plat_print, "\n"); } @@ -184,9 +233,11 @@ STATIC void process_evt_pkt(size_t pkt_len, uint8_t pkt[]) 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); + // All the bytes following cmd_complete, -including- the status byte, which is + // included in all the _bt_hci_rp_* structs. + cmd_response_data = &evt_data[sizeof_field(struct cmd_complete_with_status, cmd_complete)]; + // Includes status byte. + cmd_response_len = evt_hdr->param_len - sizeof_field(struct cmd_complete_with_status, cmd_complete); break; } @@ -265,15 +316,14 @@ STATIC void process_evt_pkt(size_t pkt_len, uint8_t pkt[]) } } -void hci_init(bleio_adapter_obj_t *adapter_in) { - adapter = adapter_in; +void hci_init(void) { 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); + common_hal_digitalio_digitalinout_set_value(adapter->rts_digitalinout, false); int errcode = 0; bool packet_is_complete = false; @@ -281,7 +331,7 @@ hci_result_t hci_poll_for_incoming_pkt(void) { // 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) { + if (errcode) { return HCI_READ_ERROR; } rx_idx++; @@ -313,14 +363,15 @@ hci_result_t hci_poll_for_incoming_pkt(void) { } // Stop incoming data while processing packet. - common_hal_digitalio_digitalinout_set_value(&adapter->rts_digitalinout, true); + common_hal_digitalio_digitalinout_set_value(adapter->rts_digitalinout, true); size_t pkt_len = rx_idx; + // Reset for next pack rx_idx = 0; switch (rx_buffer[0]) { case H4_ACL: if (debug) { - dump_pkt("HCI EVENT RX <- ", rx_idx, rx_buffer); + dump_acl_pkt(false, pkt_len, rx_buffer); } process_acl_data_pkt(pkt_len, rx_buffer); @@ -328,7 +379,7 @@ hci_result_t hci_poll_for_incoming_pkt(void) { case H4_EVT: if (debug) { - dump_pkt("HCI ACLDATA RX <- ", rx_idx, rx_buffer); + dump_evt_pkt(false, pkt_len, rx_buffer); } process_evt_pkt(pkt_len, rx_buffer); @@ -338,7 +389,7 @@ hci_result_t hci_poll_for_incoming_pkt(void) { break; } - common_hal_digitalio_digitalinout_set_value(&adapter->rts_digitalinout, true); + common_hal_digitalio_digitalinout_set_value(adapter->rts_digitalinout, true); return HCI_OK; } @@ -348,7 +399,8 @@ hci_result_t hci_poll_for_incoming_pkt(void) { 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)) { + + 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; @@ -377,7 +429,7 @@ STATIC hci_result_t send_command(uint16_t opcode, uint8_t params_len, void* para memcpy(&tx_buffer[sizeof(h4_hci_cmd_hdr_t)], params, params_len); if (debug) { - dump_pkt("HCI COMMAND TX -> ", sizeof(tx_buffer), tx_buffer); + dump_cmd_pkt(true, sizeof(tx_buffer), tx_buffer); } int result = write_pkt(tx_buffer, sizeof(h4_hci_cmd_hdr_t) + params_len); @@ -426,7 +478,7 @@ STATIC int __attribute__((unused)) send_acl_pkt(uint16_t handle, uint8_t cid, vo } // data_len does not include cid. - const size_t cid_len = sizeof(((h4_hci_acl_hdr_t *)0)->cid); + const size_t cid_len = sizeof_field(h4_hci_acl_hdr_t, 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]; @@ -441,7 +493,7 @@ STATIC int __attribute__((unused)) send_acl_pkt(uint16_t handle, uint8_t cid, vo memcpy(&tx_buffer[sizeof(h4_hci_acl_hdr_t)], data, data_len); if (debug) { - dump_pkt("HCI ACLDATA TX -> ", buf_len, tx_buffer); + dump_acl_pkt(true, buf_len, tx_buffer); } pending_pkt++; @@ -478,7 +530,7 @@ 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)); + memcpy(addr->val, response->bdaddr.val, sizeof_field(bt_addr_t, val)); } return result; diff --git a/devices/ble_hci/common-hal/_bleio/hci_api.h b/devices/ble_hci/common-hal/_bleio/hci_api.h index a2235ec8c1..303f26ba5e 100644 --- a/devices/ble_hci/common-hal/_bleio/hci_api.h +++ b/devices/ble_hci/common-hal/_bleio/hci_api.h @@ -17,27 +17,27 @@ 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 +#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/Adapter.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_ERR_RESPONSE (-2) -#define HCI_READ_TIMEOUT (-3) -#define HCI_WRITE_TIMEOUT (-4) -#define HCI_READ_ERROR (-5) -#define HCI_WRITE_ERROR (-6) +#define HCI_READ_TIMEOUT (-2) +#define HCI_WRITE_TIMEOUT (-3) +#define HCI_READ_ERROR (-4) +#define HCI_WRITE_ERROR (-5) -void hci_init(bleio_adapter_obj_t *adapter_in); +void hci_init(void); hci_result_t hci_disconnect(uint16_t handle); @@ -66,4 +66,4 @@ 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 +#endif // MICROPY_INCLUDED_DEVICES_BLE_HCI_COMMON_HAL_BLEIO_HCI_API_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# deleted file mode 100644 index 942a82a3c6..0000000000 --- a/devices/ble_hci/common-hal/_bleio/hci_include/#hci.h# +++ /dev/null @@ -1,1775 +0,0 @@ -/* 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/shared-bindings/_bleio/Adapter.c b/shared-bindings/_bleio/Adapter.c index 6ad4b75456..13b84bbac7 100644 --- a/shared-bindings/_bleio/Adapter.c +++ b/shared-bindings/_bleio/Adapter.c @@ -68,16 +68,16 @@ //| Use `_bleio.adapter` to access the sole instance available.""" //| -//| def hci_init(self, *, uart: busio.UART, cts: Pin, baudrate: int = 115200, buffer_size: int = 256): +//| def hci_uart_init(self, *, uart: busio.UART, rts: digitalio.DigitalInOut, cts: digitalio.DigitalInOut, 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 uart and pins used to communicate +//| Call `_bleio.adapter.hci_uart_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 `uart` object, and `rts` and `cs` pins are used to +//| The `uart`, `rts`, and `cts` objects 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) { +mp_obj_t bleio_adapter_hci_uart_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]); @@ -95,18 +95,23 @@ mp_obj_t bleio_adapter_hci_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_m 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); - common_hal_bleio_adapter_hci_init(self, uart, rts, cts); + digitalio_digitalinout_obj_t *rts = args[ARG_rts].u_obj; + digitalio_digitalinout_obj_t *cts = args[ARG_cts].u_obj; + if (!MP_OBJ_IS_TYPE(rts, &digitalio_digitalinout_type) || + !MP_OBJ_IS_TYPE(cts, &digitalio_digitalinout_type)) { + mp_raise_ValueError(translate("Expected a DigitalInOut")); + } + common_hal_bleio_adapter_hci_uart_init(self, uart, rts, cts); + common_hal_bleio_adapter_set_enabled(self, true); return mp_const_none; #else - mp_raise_RuntimeError(translate("hci_init not available")); + mp_raise_RuntimeError(translate("hci_uart_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); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_adapter_hci_uart_init_obj, 1, bleio_adapter_hci_uart_init); //| //| enabled: Any = ... @@ -433,7 +438,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_erase_bonding_obj, bleio_adapter_ STATIC const mp_rom_map_elem_t bleio_adapter_locals_dict_table[] = { #if CIRCUITPY_BLEIO_HCI - { MP_ROM_QSTR(MP_QSTR_hci_init), MP_ROM_PTR(&bleio_adapter_hci_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_hci_uart_init), MP_ROM_PTR(&bleio_adapter_hci_uart_init_obj) }, #endif { 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) }, diff --git a/shared-bindings/_bleio/Adapter.h b/shared-bindings/_bleio/Adapter.h index 9caca161f2..0cce55ca80 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, busio_uart_obj_t *uart, const mcu_pin_obj_t *rts, const mcu_pin_obj_t *cts); +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); #endif // CIRCUITPY_BLEIO_HCI bool common_hal_bleio_adapter_get_advertising(bleio_adapter_obj_t *self); From f6869c69c5fda701b57fbfca0eaf1aa03a2d164b Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 12 Jul 2020 19:45:23 -0400 Subject: [PATCH 09/84] wip: advertising; not tested --- devices/ble_hci/common-hal/_bleio/Adapter.c | 349 +++++++++++------- devices/ble_hci/common-hal/_bleio/Adapter.h | 18 +- devices/ble_hci/common-hal/_bleio/__init__.c | 7 + devices/ble_hci/common-hal/_bleio/__init__.h | 1 + devices/ble_hci/common-hal/_bleio/hci_api.c | 63 +++- devices/ble_hci/common-hal/_bleio/hci_api.h | 11 +- .../common-hal/_bleio/hci_include/hci.h | 2 + ports/atmel-samd/background.c | 26 +- ports/cxd56/background.c | 4 + ports/esp32s2/background.c | 4 + ports/litex/background.c | 13 +- ports/mimxrt10xx/background.c | 20 +- ports/nrf/background.c | 3 +- ports/nrf/common-hal/_bleio/__init__.c | 5 + ports/nrf/common-hal/_bleio/__init__.h | 1 + ports/stm/background.c | 13 +- shared-bindings/_bleio/Adapter.c | 14 + supervisor/shared/bluetooth.c | 1 - supervisor/shared/bluetooth.h | 3 +- 19 files changed, 379 insertions(+), 179 deletions(-) diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index c08eb2db40..7817ea4707 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.c +++ b/devices/ble_hci/common-hal/_bleio/Adapter.c @@ -48,6 +48,21 @@ #include "shared-bindings/_bleio/ScanEntry.h" #include "shared-bindings/time/__init__.h" +#define MSEC_TO_UNITS(TIME, RESOLUTION) (((TIME) * 1000) / (RESOLUTION)) +#define SEC_TO_UNITS(TIME, RESOLUTION) (((TIME) * 1000000) / (RESOLUTION)) +#define UNITS_TO_SEC(TIME, RESOLUTION) (((TIME) * (RESOLUTION)) / 1000000) +// 0.625 msecs (625 usecs) +#define ADV_INTERVAL_UNIT_FLOAT_SECS (0.000625) +// Microseconds is the base unit. The macros above know that. +#define UNIT_0_625_MS (625) +#define UNIT_1_25_MS (1250) +#define UNIT_10_MS (10000) + +// TODO make this settable from Python. +#define DEFAULT_TX_POWER 0 // 0 dBm +#define MAX_ANONYMOUS_ADV_TIMEOUT_SECS (60*15) +#define MAX_LIMITED_DISCOVERABLE_ADV_TIMEOUT_SECS (180) + #define BLE_MIN_CONN_INTERVAL MSEC_TO_UNITS(15, UNIT_0_625_MS) #define BLE_MAX_CONN_INTERVAL MSEC_TO_UNITS(15, UNIT_0_625_MS) #define BLE_SLAVE_LATENCY 0 @@ -158,32 +173,66 @@ bleio_connection_internal_t bleio_connections[BLEIO_TOTAL_CONNECTION_COUNT]; // return true; // } -// 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); + bt_addr_t addr; + check_hci_error(hci_read_bd_addr(&addr)); -// // 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[addr.val[1] >> 4 & 0xf]; + default_ble_name[len - 3] = nibble_to_hex_lower[addr.val[1] & 0xf]; + default_ble_name[len - 2] = nibble_to_hex_lower[addr.val[0] >> 4 & 0xf]; + default_ble_name[len - 1] = nibble_to_hex_lower[addr.val[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); +} + +// Get various values and limits set by the adapter. +STATIC void bleio_adapter_get_info(bleio_adapter_obj_t *self) { + + // Get ACL buffer info. + uint16_t le_max_len; + uint8_t le_max_num; + if (hci_le_read_buffer_size(&le_max_len, &le_max_num) == HCI_OK) { + self->max_acl_buffer_len = le_max_len; + self->max_acl_num_buffers = le_max_num; + } else { + // LE Read Buffer Size not available; use the general Read Buffer Size. + uint16_t acl_max_len; + uint8_t sco_max_len; + uint16_t acl_max_num; + uint16_t sco_max_num; + if (hci_read_buffer_size(&acl_max_len, &sco_max_len, &acl_max_num, &sco_max_num) != HCI_OK) { + mp_raise_bleio_BluetoothError(translate("Could not read BLE buffer info")); + } + self->max_acl_buffer_len = acl_max_len; + self->max_acl_num_buffers = acl_max_num; + } + + // Get max advertising length. + uint16_t max_adv_data_len; + if (hci_le_read_maximum_advertising_data_length(&max_adv_data_len) != HCI_OK) { + mp_raise_bleio_BluetoothError(translate("Could not get max advertising length")); + } + self->max_adv_data_len = max_adv_data_len; +} 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) { self->hci_uart = uart; self->rts_digitalinout = rts; self->cts_digitalinout = cts; self->enabled = false; + self->now_advertising = false; + self->circuitpython_advertising = false; + self->extended_advertising = false; + self->advertising_timeout_msecs = 0; + + bleio_adapter_get_info(self); + + bleio_adapter_reset_name(self); } void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enabled) { @@ -196,6 +245,13 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable //FIX enable/disable HCI adapter, but don't reset it, since we don't know how. self->enabled = enabled; + if (!enabled) { + // Stop any current activity. + check_hci_error(hci_reset()); + self->now_advertising = false; + self->extended_advertising = false; + self->circuitpython_advertising = false; + } } bool common_hal_bleio_adapter_get_enabled(bleio_adapter_obj_t *self) { @@ -221,6 +277,7 @@ void common_hal_bleio_adapter_set_name(bleio_adapter_obj_t *self, const char* na self->name = mp_obj_new_str(name, strlen(name)); } + // STATIC bool scan_on_ble_evt(ble_evt_t *ble_evt, void *scan_results_in) { // bleio_scanresults_obj_t *scan_results = (bleio_scanresults_obj_t*)scan_results_in; @@ -262,6 +319,7 @@ mp_obj_t common_hal_bleio_adapter_start_scan(bleio_adapter_obj_t *self, uint8_t* self->scan_results = NULL; } self->scan_results = shared_module_bleio_new_scanresults(buffer_size, prefixes, prefix_length, minimum_rssi); + // size_t max_packet_size = extended ? BLE_GAP_SCAN_BUFFER_EXTENDED_MAX_SUPPORTED : BLE_GAP_SCAN_BUFFER_MAX; // uint8_t *raw_data = m_malloc(sizeof(ble_data_t) + max_packet_size, false); // ble_data_t * sd_data = (ble_data_t *) raw_data; @@ -298,9 +356,8 @@ mp_obj_t common_hal_bleio_adapter_start_scan(bleio_adapter_obj_t *self, uint8_t* } void common_hal_bleio_adapter_stop_scan(bleio_adapter_obj_t *self) { - // sd_ble_gap_scan_stop(); + check_hci_error(hci_le_set_scan_enable(BT_HCI_LE_SCAN_DISABLE, BT_HCI_LE_SCAN_FILTER_DUP_DISABLE)); shared_module_bleio_scanresults_set_done(self->scan_results, true); - // ble_drv_remove_event_handler(scan_on_ble_evt, self->scan_results); self->scan_results = NULL; } @@ -431,99 +488,123 @@ STATIC void check_data_fit(size_t data_len, bool connectable) { // } uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, bool connectable, bool anonymous, uint32_t timeout, float interval, uint8_t *advertising_data, uint16_t advertising_data_len, uint8_t *scan_response_data, uint16_t scan_response_data_len) { - // if (self->current_advertising_data != NULL && self->current_advertising_data == self->advertising_data) { - // return NRF_ERROR_BUSY; - // } + if (self->now_advertising) { + if (self->circuitpython_advertising) { + common_hal_bleio_adapter_stop_advertising(self); + } else { + // User-requested advertising. + // TODO allow multiple advertisements. + // Already advertising. Can't advertise twice. + return 1; + } + } - // // If the current advertising data isn't owned by the adapter then it must be an internal - // // advertisement that we should stop. - // if (self->current_advertising_data != NULL) { - // common_hal_bleio_adapter_stop_advertising(self); - // } + // Peer address, which we don't use (no directed advertising). + bt_addr_le_t empty_addr = { 0 }; - // uint32_t err_code; - // bool extended = advertising_data_len > BLE_GAP_ADV_SET_DATA_SIZE_MAX || - // scan_response_data_len > BLE_GAP_ADV_SET_DATA_SIZE_MAX; + bool extended = + advertising_data_len > self->max_adv_data_len || scan_response_data_len > self->max_adv_data_len; - // uint8_t adv_type; - // if (extended) { - // if (connectable) { - // adv_type = BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_UNDIRECTED; - // } else if (scan_response_data_len > 0) { - // adv_type = BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_UNDIRECTED; - // } else { - // adv_type = BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED; - // } - // } else if (connectable) { - // adv_type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED; - // } else if (scan_response_data_len > 0) { - // adv_type = BLE_GAP_ADV_TYPE_NONCONNECTABLE_SCANNABLE_UNDIRECTED; - // } else { - // adv_type = BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED; - // } + if (extended) { + uint16_t props = 0; + if (connectable) { + props |= BT_HCI_LE_ADV_PROP_CONN; + } + if (scan_response_data_len > 0) { + props |= BT_HCI_LE_ADV_PROP_SCAN; + } - // if (anonymous) { - // ble_gap_privacy_params_t privacy = { - // .privacy_mode = BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY, - // .private_addr_type = BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE, - // // Rotate the keys one second after we're scheduled to stop - // // advertising. This prevents a potential race condition where we - // // fire off a beacon with the same advertising data but a new MAC - // // address just as we tear down the connection. - // .private_addr_cycle_s = timeout + 1, - // .p_device_irk = NULL, - // }; - // err_code = sd_ble_gap_privacy_set(&privacy); - // } else { - // ble_gap_privacy_params_t privacy = { - // .privacy_mode = BLE_GAP_PRIVACY_MODE_OFF, - // .private_addr_type = BLE_GAP_ADDR_TYPE_PUBLIC, - // .private_addr_cycle_s = 0, - // .p_device_irk = NULL, - // }; - // err_code = sd_ble_gap_privacy_set(&privacy); - // } - // if (err_code != NRF_SUCCESS) { - // return err_code; - // } + // Advertising interval. + uint32_t interval_units = SEC_TO_UNITS(interval, UNIT_0_625_MS); - // ble_gap_adv_params_t adv_params = { - // .interval = SEC_TO_UNITS(interval, UNIT_0_625_MS), - // .properties.type = adv_type, - // .duration = SEC_TO_UNITS(timeout, UNIT_10_MS), - // .filter_policy = BLE_GAP_ADV_FP_ANY, - // .primary_phy = BLE_GAP_PHY_1MBPS, - // }; + check_hci_error( + hci_le_set_extended_advertising_parameters( + 0, // handle + props, // adv properties + interval_units, // min interval + interval_units, // max interval + 0b111, // channel map: channels 37, 38, 39 + anonymous ? BT_ADDR_LE_RANDOM : BT_ADDR_LE_PUBLIC, + &empty_addr, // peer_addr, + 0x00, // filter policy: no filter + DEFAULT_TX_POWER, + BT_HCI_LE_EXT_SCAN_PHY_1M, // Secondary PHY to use + 0x00, // AUX_ADV_IND shall be sent prior to next adv event + BT_HCI_LE_EXT_SCAN_PHY_1M, // Secondary PHY to use + 0x00, // Advertising SID + 0x00 // Scan req notify disable + )); - // const ble_gap_adv_data_t ble_gap_adv_data = { - // .adv_data.p_data = advertising_data, - // .adv_data.len = advertising_data_len, - // .scan_rsp_data.p_data = scan_response_data_len > 0 ? scan_response_data : NULL, - // .scan_rsp_data.len = scan_response_data_len, - // }; + // We can use the duration mechanism provided, instead of our own. + self->advertising_timeout_msecs = 0; - // err_code = sd_ble_gap_adv_set_configure(&adv_handle, &ble_gap_adv_data, &adv_params); - // if (err_code != NRF_SUCCESS) { - // return err_code; - // } + uint8_t handle[1] = { 0 }; + uint16_t duration_10msec[1] = { timeout * 100 }; + uint8_t max_ext_adv_evts[1] = { 0 }; + check_hci_error( + hci_le_set_extended_advertising_enable( + BT_HCI_LE_ADV_ENABLE, + 1, // one advertising set. + handle, + duration_10msec, + max_ext_adv_evts + )); - // ble_drv_add_event_handler(advertising_on_ble_evt, self); + self->extended_advertising = true; + } else { + // Legacy advertising (not extended). - // vm_used_ble = true; - // err_code = sd_ble_gap_adv_start(adv_handle, BLE_CONN_CFG_TAG_CUSTOM); - // if (err_code != NRF_SUCCESS) { - // return err_code; - // } - // self->current_advertising_data = advertising_data; - // return NRF_SUCCESS; + uint8_t adv_type; + if (connectable) { + // Connectable, scannable, undirected. + adv_type = BT_HCI_ADV_IND; + } else if (scan_response_data_len > 0) { + // Unconnectable, scannable, undirected. + adv_type = BT_HCI_ADV_SCAN_IND; + } else { + // Unconnectable, unscannable, undirected. + adv_type = BT_HCI_ADV_NONCONN_IND; + } + + // Advertising interval. + uint16_t interval_units = SEC_TO_UNITS(interval, UNIT_0_625_MS); + + check_hci_error( + hci_le_set_advertising_parameters( + interval_units, // min interval + interval_units, // max interval + adv_type, + anonymous ? BT_ADDR_LE_RANDOM : BT_ADDR_LE_PUBLIC, + &empty_addr, + 0b111, // channel map: channels 37, 38, 39 + 0x00 // filter policy: no filter + )); + + // The HCI commands expect 31 octets, even though the actual data length may be shorter. + uint8_t full_data[31] = { 0 }; + memcpy(full_data, advertising_data, MIN(sizeof(full_data), advertising_data_len)); + check_hci_error(hci_le_set_advertising_data(advertising_data_len, full_data)); + memset(full_data, 0, sizeof(full_data)); + if (scan_response_data_len > 0) { + memcpy(full_data, advertising_data, MIN(sizeof(full_data), scan_response_data_len)); + check_hci_error(hci_le_set_scan_response_data(scan_response_data_len, full_data)); + } + + // No duration mechanism is provided for legacy advertising, so we need to do our own. + self->advertising_timeout_msecs = timeout * 1000; + self->advertising_start_ticks = supervisor_ticks_ms64(); + + // Start advertising. + check_hci_error(hci_le_set_advertising_enable(BT_HCI_LE_ADV_ENABLE)); + self->extended_advertising = false; + } // end legacy advertising setup + + vm_used_ble = true; + self->now_advertising = true; return 0; } - void common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, bool connectable, bool anonymous, uint32_t timeout, mp_float_t interval, mp_buffer_info_t *advertising_data_bufinfo, mp_buffer_info_t *scan_response_data_bufinfo) { - if (self->current_advertising_data != NULL && self->current_advertising_data == self->advertising_data) { - mp_raise_bleio_BluetoothError(translate("Already advertising.")); - } // interval value has already been validated. check_data_fit(advertising_data_bufinfo->len, connectable); @@ -536,58 +617,38 @@ void common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, bool // Anonymous mode requires a timeout so that we don't continue to broadcast // the same data while cycling the MAC address -- otherwise, what's the // point of randomizing the MAC address? - if (!timeout) { - //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; - // } + if (timeout == 0 && anonymous) { + timeout = MAX_ANONYMOUS_ADV_TIMEOUT_SECS; } else { - //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)); - // } + if (timeout > MAX_LIMITED_DISCOVERABLE_ADV_TIMEOUT_SECS) { + mp_raise_bleio_BluetoothError(translate("Timeout is too long: Maximum timeout length is %d seconds"), + MAX_LIMITED_DISCOVERABLE_ADV_TIMEOUT_SECS); + } } - // The advertising data buffers must not move, because the SoftDevice depends on them. - // So make them long-lived and reuse them onwards. - //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); - // } + const uint32_t result =_common_hal_bleio_adapter_start_advertising( + self, connectable, anonymous, timeout, interval, + advertising_data_bufinfo->buf, + advertising_data_bufinfo->len, + scan_response_data_bufinfo->buf, + scan_response_data_bufinfo->len); - 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); - - // check_nrf_error(_common_hal_bleio_adapter_start_advertising(self, connectable, anonymous, timeout, interval, - // self->advertising_data, - // advertising_data_bufinfo->len, - // self->scan_response_data, - // scan_response_data_bufinfo->len)); + if (result) { + mp_raise_bleio_BluetoothError(translate("Already advertising")); + } + self->circuitpython_advertising = false; } void common_hal_bleio_adapter_stop_advertising(bleio_adapter_obj_t *self) { - // if (adv_handle == BLE_GAP_ADV_SET_HANDLE_NOT_SET) - // return; - - // // TODO: Don't actually stop. Switch to advertising CircuitPython if we don't already have a connection. - // const uint32_t err_code = sd_ble_gap_adv_stop(adv_handle); - // self->current_advertising_data = NULL; - - // if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_INVALID_STATE)) { - // check_nrf_error(err_code); - // } + self->now_advertising = false; + self->extended_advertising = false; + self->circuitpython_advertising = false; + check_hci_error(hci_le_set_advertising_enable(BT_HCI_LE_ADV_DISABLE)); + //TODO startup CircuitPython advertising again. } bool common_hal_bleio_adapter_get_advertising(bleio_adapter_obj_t *self) { - return self->current_advertising_data != NULL; + return self->now_advertising; } bool common_hal_bleio_adapter_get_connected(bleio_adapter_obj_t *self) { @@ -631,7 +692,7 @@ void bleio_adapter_gc_collect(bleio_adapter_obj_t* adapter) { void bleio_adapter_reset(bleio_adapter_obj_t* adapter) { common_hal_bleio_adapter_stop_scan(adapter); - if (adapter->current_advertising_data != NULL) { + if (adapter->now_advertising) { common_hal_bleio_adapter_stop_advertising(adapter); } @@ -646,3 +707,11 @@ void bleio_adapter_reset(bleio_adapter_obj_t* adapter) { connection->connection_obj = mp_const_none; } } + +void bleio_adapter_background(bleio_adapter_obj_t* adapter) { + if (adapter->advertising_timeout_msecs > 0 && + supervisor_ticks_ms64() - adapter->advertising_start_ticks > adapter->advertising_timeout_msecs) { + adapter->advertising_timeout_msecs = 0; + common_hal_bleio_adapter_stop_advertising(adapter); + } +} diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.h b/devices/ble_hci/common-hal/_bleio/Adapter.h index dbec03bd84..8e34f86631 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.h +++ b/devices/ble_hci/common-hal/_bleio/Adapter.h @@ -43,20 +43,32 @@ extern bleio_connection_internal_t bleio_connections[BLEIO_TOTAL_CONNECTION_COUNT]; + + typedef struct _bleio_adapter_obj_t { mp_obj_base_t base; - uint8_t* advertising_data; - uint8_t* scan_response_data; - uint8_t* current_advertising_data; bleio_scanresults_obj_t *scan_results; mp_obj_t name; mp_obj_tuple_t *connection_objs; busio_uart_obj_t* hci_uart; digitalio_digitalinout_obj_t *rts_digitalinout; digitalio_digitalinout_obj_t *cts_digitalinout; + bool now_advertising; + bool extended_advertising; + bool circuitpython_advertising; bool enabled; + + // Used to monitor advertising timeout for legacy avertising. + uint64_t advertising_start_ticks; + uint64_t advertising_timeout_msecs; // If zero, do not check. + + uint16_t max_acl_buffer_len; + uint16_t max_acl_num_buffers; + uint16_t max_adv_data_len; + } bleio_adapter_obj_t; +void bleio_adapter_background(bleio_adapter_obj_t* adapter); void bleio_adapter_gc_collect(bleio_adapter_obj_t* adapter); void bleio_adapter_reset(bleio_adapter_obj_t* adapter); diff --git a/devices/ble_hci/common-hal/_bleio/__init__.c b/devices/ble_hci/common-hal/_bleio/__init__.c index e32ca55ec8..07aaee747e 100644 --- a/devices/ble_hci/common-hal/_bleio/__init__.c +++ b/devices/ble_hci/common-hal/_bleio/__init__.c @@ -263,3 +263,10 @@ void common_hal_bleio_gattc_write(uint16_t handle, uint16_t conn_handle, mp_buff void common_hal_bleio_gc_collect(void) { bleio_adapter_gc_collect(&common_hal_bleio_adapter_obj); } + + +void bleio_background(void) { + supervisor_bluetooth_background(); + bleio_adapter_background(&common_hal_bleio_adapter_obj); + //FIX bonding_background(); +} diff --git a/devices/ble_hci/common-hal/_bleio/__init__.h b/devices/ble_hci/common-hal/_bleio/__init__.h index 00f5e0c68c..0d1c2785f7 100644 --- a/devices/ble_hci/common-hal/_bleio/__init__.h +++ b/devices/ble_hci/common-hal/_bleio/__init__.h @@ -31,6 +31,7 @@ #include "hci_api.h" +void bleio_background(void); void bleio_reset(void); typedef struct { diff --git a/devices/ble_hci/common-hal/_bleio/hci_api.c b/devices/ble_hci/common-hal/_bleio/hci_api.c index a82c0c93ca..4901ffeedb 100644 --- a/devices/ble_hci/common-hal/_bleio/hci_api.c +++ b/devices/ble_hci/common-hal/_bleio/hci_api.c @@ -215,7 +215,7 @@ STATIC void process_evt_pkt(size_t pkt_len, uint8_t pkt[]) //FIX // ATT.removeConnection(disconn_complete->handle, disconn_complete->reason); // L2CAPSignaling.removeConnection(disconn_complete->handle, disconn_complete->reason); - hci_le_set_advertise_enable(0x01); + hci_le_set_advertising_enable(0x01); break; } @@ -365,7 +365,7 @@ hci_result_t hci_poll_for_incoming_pkt(void) { // 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 pack + // Reset for next packet. rx_idx = 0; switch (rx_buffer[0]) { @@ -395,7 +395,6 @@ hci_result_t hci_poll_for_incoming_pkt(void) { } -// 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(); @@ -555,7 +554,7 @@ 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) { +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 = @@ -567,6 +566,20 @@ hci_result_t hci_read_le_buffer_size(uint16_t *le_max_len, uint8_t *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); } @@ -587,7 +600,30 @@ hci_result_t hci_le_set_advertising_parameters(uint16_t min_interval, uint16_t m 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) { +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 = @@ -625,10 +661,25 @@ hci_result_t hci_le_set_scan_response_data(uint8_t len, uint8_t data[]) { 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) { +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, diff --git a/devices/ble_hci/common-hal/_bleio/hci_api.h b/devices/ble_hci/common-hal/_bleio/hci_api.h index 303f26ba5e..23e45375cc 100644 --- a/devices/ble_hci/common-hal/_bleio/hci_api.h +++ b/devices/ble_hci/common-hal/_bleio/hci_api.h @@ -45,11 +45,16 @@ 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_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_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_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_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); @@ -58,7 +63,7 @@ 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_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); 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 dbe233fef0..2de58b3d89 100644 --- a/devices/ble_hci/common-hal/_bleio/hci_include/hci.h +++ b/devices/ble_hci/common-hal/_bleio/hci_include/hci.h @@ -14,6 +14,8 @@ #include #include "addr.h" +#define BIT(n) (1UL << (n)) + /* 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 diff --git a/ports/atmel-samd/background.c b/ports/atmel-samd/background.c index 767c7f3b6b..0608cb9bd1 100644 --- a/ports/atmel-samd/background.c +++ b/ports/atmel-samd/background.c @@ -35,7 +35,11 @@ #include "supervisor/shared/stack.h" #include "supervisor/port.h" -#ifdef CIRCUITPY_DISPLAYIO +#if CIRCUITPY_BLEIO +#include "common-hal/_bleio/__init__.h" +#endif + +#if CIRCUITPY_DISPLAYIO #include "shared-module/displayio/__init__.h" #endif @@ -77,16 +81,22 @@ void run_background_tasks(void) { assert_heap_ok(); running_background_tasks = true; - #if CIRCUITPY_AUDIOIO || CIRCUITPY_AUDIOBUSIO +#if CIRCUITPY_AUDIOIO || CIRCUITPY_AUDIOBUSIO audio_dma_background(); - #endif - #if CIRCUITPY_DISPLAYIO - displayio_background(); - #endif +#endif - #if CIRCUITPY_NETWORK +#if CIRCUITPY_BLEIO + bleio_background(); +#endif + +#if CIRCUITPY_DISPLAYIO + displayio_background(); +#endif + +#if CIRCUITPY_NETWORK network_module_background(); - #endif +#endif + filesystem_background(); usb_background(); running_background_tasks = false; diff --git a/ports/cxd56/background.c b/ports/cxd56/background.c index ade257dd24..af0957bd07 100644 --- a/ports/cxd56/background.c +++ b/ports/cxd56/background.c @@ -45,6 +45,10 @@ void run_background_tasks(void) { assert_heap_ok(); running_background_tasks = true; +#if CIRCUITPY_BLEIO + bleio_background(); +#endif + usb_background(); filesystem_background(); diff --git a/ports/esp32s2/background.c b/ports/esp32s2/background.c index e22cf4aacc..81ebf960ff 100644 --- a/ports/esp32s2/background.c +++ b/ports/esp32s2/background.c @@ -54,6 +54,10 @@ void run_background_tasks(void) { running_background_tasks = true; filesystem_background(); +#if CIRCUITPY_BLEIO + bleio_background(); +#endif + // #if CIRCUITPY_DISPLAYIO // displayio_background(); // #endif diff --git a/ports/litex/background.c b/ports/litex/background.c index 8c18970434..b1b765536d 100644 --- a/ports/litex/background.c +++ b/ports/litex/background.c @@ -47,13 +47,18 @@ void run_background_tasks(void) { running_background_tasks = true; filesystem_background(); - #if USB_AVAILABLE +#if USB_AVAILABLE usb_background(); - #endif +#endif - #if CIRCUITPY_DISPLAYIO +#if CIRCUITPY_BLEIO + bleio_background(); +#endif + +#if CIRCUITPY_DISPLAYIO displayio_background(); - #endif +#endif + running_background_tasks = false; assert_heap_ok(); diff --git a/ports/mimxrt10xx/background.c b/ports/mimxrt10xx/background.c index ff53ea44f4..550009473e 100644 --- a/ports/mimxrt10xx/background.c +++ b/ports/mimxrt10xx/background.c @@ -58,16 +58,22 @@ void PLACE_IN_ITCM(run_background_tasks)(void) { assert_heap_ok(); running_background_tasks = true; - #if CIRCUITPY_AUDIOIO || CIRCUITPY_AUDIOBUSIO +#if CIRCUITPY_AUDIOIO || CIRCUITPY_AUDIOBUSIO audio_dma_background(); - #endif - #if CIRCUITPY_DISPLAYIO - displayio_background(); - #endif +#endif - #if CIRCUITPY_NETWORK +#if CIRCUITPY_BLEIO + bleio_background(); +#endif + +#if CIRCUITPY_DISPLAYIO + displayio_background(); +#endif + +#if CIRCUITPY_NETWORK network_module_background(); - #endif +#endif + filesystem_background(); usb_background(); running_background_tasks = false; diff --git a/ports/nrf/background.c b/ports/nrf/background.c index 966c56e0b7..faaf80b6c3 100644 --- a/ports/nrf/background.c +++ b/ports/nrf/background.c @@ -68,8 +68,7 @@ void run_background_tasks(void) { #endif #if CIRCUITPY_BLEIO - supervisor_bluetooth_background(); - bonding_background(); + bleio_background(); #endif #if CIRCUITPY_DISPLAYIO diff --git a/ports/nrf/common-hal/_bleio/__init__.c b/ports/nrf/common-hal/_bleio/__init__.c index e84bba6626..9ac26aee3c 100644 --- a/ports/nrf/common-hal/_bleio/__init__.c +++ b/ports/nrf/common-hal/_bleio/__init__.c @@ -244,3 +244,8 @@ void common_hal_bleio_gattc_write(uint16_t handle, uint16_t conn_handle, mp_buff void common_hal_bleio_gc_collect(void) { bleio_adapter_gc_collect(&common_hal_bleio_adapter_obj); } + +void bleio_background(void) { + supervisor_bluetooth_background(); + bonding_background(); +} diff --git a/ports/nrf/common-hal/_bleio/__init__.h b/ports/nrf/common-hal/_bleio/__init__.h index e216795fcd..0b2c5334bb 100644 --- a/ports/nrf/common-hal/_bleio/__init__.h +++ b/ports/nrf/common-hal/_bleio/__init__.h @@ -27,6 +27,7 @@ #ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_INIT_H #define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_INIT_H +void bleio_background(void); void bleio_reset(void); typedef struct { diff --git a/ports/stm/background.c b/ports/stm/background.c index 8c18970434..b1b765536d 100644 --- a/ports/stm/background.c +++ b/ports/stm/background.c @@ -47,13 +47,18 @@ void run_background_tasks(void) { running_background_tasks = true; filesystem_background(); - #if USB_AVAILABLE +#if USB_AVAILABLE usb_background(); - #endif +#endif - #if CIRCUITPY_DISPLAYIO +#if CIRCUITPY_BLEIO + bleio_background(); +#endif + +#if CIRCUITPY_DISPLAYIO displayio_background(); - #endif +#endif + running_background_tasks = false; assert_heap_ok(); diff --git a/shared-bindings/_bleio/Adapter.c b/shared-bindings/_bleio/Adapter.c index 13b84bbac7..8673044165 100644 --- a/shared-bindings/_bleio/Adapter.c +++ b/shared-bindings/_bleio/Adapter.c @@ -47,6 +47,12 @@ #define INTERVAL_MAX_STRING "40.959375" #define WINDOW_DEFAULT (0.1f) +STATIC void check_enabled(bleio_adapter_obj_t *self) { + if (!common_hal_bleio_adapter_get_enabled(self)) { + mp_raise_bleio_BluetoothError(translate("Adapter not enabled")); + } +} + //| class Adapter: //| """BLE adapter //| @@ -102,6 +108,7 @@ mp_obj_t bleio_adapter_hci_uart_init(mp_uint_t n_args, const mp_obj_t *pos_args, !MP_OBJ_IS_TYPE(cts, &digitalio_digitalinout_type)) { mp_raise_ValueError(translate("Expected a DigitalInOut")); } + check_enabled(self); common_hal_bleio_adapter_hci_uart_init(self, uart, rts, cts); common_hal_bleio_adapter_set_enabled(self, true); @@ -238,6 +245,7 @@ STATIC mp_obj_t bleio_adapter_start_advertising(mp_uint_t n_args, const mp_obj_t mp_raise_bleio_BluetoothError(translate("Cannot have scan responses for extended, connectable advertisements.")); } + check_enabled(self); common_hal_bleio_adapter_start_advertising(self, connectable, anonymous, timeout, interval, &data_bufinfo, &scan_response_bufinfo); @@ -252,6 +260,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_adapter_start_advertising_obj, 2, bleio_ STATIC mp_obj_t bleio_adapter_stop_advertising(mp_obj_t self_in) { bleio_adapter_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_enabled(self); common_hal_bleio_adapter_stop_advertising(self); return mp_const_none; @@ -327,6 +336,7 @@ STATIC mp_obj_t bleio_adapter_start_scan(size_t n_args, const mp_obj_t *pos_args } } + check_enabled(self); return common_hal_bleio_adapter_start_scan(self, prefix_bufinfo.buf, prefix_bufinfo.len, args[ARG_extended].u_bool, args[ARG_buffer_size].u_int, timeout, interval, window, args[ARG_minimum_rssi].u_int, args[ARG_active].u_bool); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_adapter_start_scan_obj, 1, bleio_adapter_start_scan); @@ -338,6 +348,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_adapter_start_scan_obj, 1, bleio_adapter STATIC mp_obj_t bleio_adapter_stop_scan(mp_obj_t self_in) { bleio_adapter_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_enabled(self); common_hal_bleio_adapter_stop_scan(self); return mp_const_none; @@ -365,6 +376,7 @@ const mp_obj_property_t bleio_adapter_advertising_obj = { //| connection. (read-only)""" //| STATIC mp_obj_t bleio_adapter_get_connected(mp_obj_t self) { + check_enabled(self); return mp_obj_new_bool(common_hal_bleio_adapter_get_connected(self)); } @@ -382,6 +394,7 @@ const mp_obj_property_t bleio_adapter_connected_obj = { //| :py:meth:`_bleio.Adapter.connect`. (read-only)""" //| STATIC mp_obj_t bleio_adapter_get_connections(mp_obj_t self) { + check_enabled(self); return common_hal_bleio_adapter_get_connections(self); } MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_get_connections_obj, bleio_adapter_get_connections); @@ -419,6 +432,7 @@ STATIC mp_obj_t bleio_adapter_connect(mp_uint_t n_args, const mp_obj_t *pos_args bleio_address_obj_t *address = MP_OBJ_TO_PTR(args[ARG_address].u_obj); mp_float_t timeout = mp_obj_get_float(args[ARG_timeout].u_obj); + check_enabled(self); return common_hal_bleio_adapter_connect(self, address, timeout); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_adapter_connect_obj, 2, bleio_adapter_connect); diff --git a/supervisor/shared/bluetooth.c b/supervisor/shared/bluetooth.c index d2ff55377a..56bf321173 100644 --- a/supervisor/shared/bluetooth.c +++ b/supervisor/shared/bluetooth.c @@ -214,7 +214,6 @@ STATIC void close_current_file(void) { uint32_t current_command[1024 / sizeof(uint32_t)]; volatile size_t current_offset; - void supervisor_bluetooth_background(void) { if (!run_ble_background) { return; diff --git a/supervisor/shared/bluetooth.h b/supervisor/shared/bluetooth.h index aa5ae60bf7..4c40c65d2d 100644 --- a/supervisor/shared/bluetooth.h +++ b/supervisor/shared/bluetooth.h @@ -27,7 +27,8 @@ #ifndef MICROPY_INCLUDED_SUPERVISOR_SHARED_BLUETOOTH_H #define MICROPY_INCLUDED_SUPERVISOR_SHARED_BLUETOOTH_H -void supervisor_start_bluetooth(void); +void bleio_background(void); void supervisor_bluetooth_background(void); +void supervisor_start_bluetooth(void); #endif // MICROPY_INCLUDED_SUPERVISOR_SHARED_BLUETOOTH_H From b08b0264cce3fae379035da4d53b8e96174405aa Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 15 Jul 2020 09:46:13 -0400 Subject: [PATCH 10/84] back to working; check for extended advertising support --- devices/ble_hci/common-hal/_bleio/Adapter.c | 66 +++++++++------------ devices/ble_hci/common-hal/_bleio/Adapter.h | 1 + devices/ble_hci/common-hal/_bleio/hci_api.c | 30 +++++++++- devices/ble_hci/common-hal/_bleio/hci_api.h | 2 + shared-bindings/_bleio/Adapter.c | 6 +- 5 files changed, 62 insertions(+), 43 deletions(-) diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index 7817ea4707..92eb42ee0f 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.c +++ b/devices/ble_hci/common-hal/_bleio/Adapter.c @@ -68,26 +68,6 @@ #define BLE_SLAVE_LATENCY 0 #define BLE_CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS) -#ifndef BLEIO_VS_UUID_COUNT -#define BLEIO_VS_UUID_COUNT 75 -#endif - -#ifndef BLEIO_HVN_TX_QUEUE_SIZE -#define BLEIO_HVN_TX_QUEUE_SIZE 9 -#endif - -#ifndef BLEIO_CENTRAL_ROLE_COUNT -#define BLEIO_CENTRAL_ROLE_COUNT 4 -#endif - -#ifndef BLEIO_PERIPH_ROLE_COUNT -#define BLEIO_PERIPH_ROLE_COUNT 4 -#endif - -#ifndef BLEIO_ATTR_TAB_SIZE -#define BLEIO_ATTR_TAB_SIZE (BLE_GATTS_ATTR_TAB_SIZE_DEFAULT * 5) -#endif - bleio_connection_internal_t bleio_connections[BLEIO_TOTAL_CONNECTION_COUNT]; // STATIC bool adapter_on_ble_evt(ble_evt_t *ble_evt, void *self_in) { @@ -193,6 +173,11 @@ STATIC void bleio_adapter_reset_name(bleio_adapter_obj_t *self) { // Get various values and limits set by the adapter. STATIC void bleio_adapter_get_info(bleio_adapter_obj_t *self) { + // Get supported features. + if (hci_le_read_local_supported_features(self->features) != HCI_OK) { + mp_raise_bleio_BluetoothError(translate("Could not read BLE features")); + } + // Get ACL buffer info. uint16_t le_max_len; uint8_t le_max_num; @@ -212,26 +197,28 @@ STATIC void bleio_adapter_get_info(bleio_adapter_obj_t *self) { self->max_acl_num_buffers = acl_max_num; } - // Get max advertising length. - uint16_t max_adv_data_len; - if (hci_le_read_maximum_advertising_data_length(&max_adv_data_len) != HCI_OK) { - mp_raise_bleio_BluetoothError(translate("Could not get max advertising length")); + // Get max advertising length if extended advertising is supported. + if (BT_FEAT_LE_EXT_ADV(self->features)) { + uint16_t max_adv_data_len; + if (hci_le_read_maximum_advertising_data_length(&max_adv_data_len) != HCI_OK) { + mp_raise_bleio_BluetoothError(translate("Could not get max advertising length")); + } + self->max_adv_data_len = max_adv_data_len; + } else { + self->max_adv_data_len = 31; } - self->max_adv_data_len = max_adv_data_len; } 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) { self->hci_uart = uart; self->rts_digitalinout = rts; self->cts_digitalinout = cts; + + // Advertising-related fields are initialized by common_hal_bleio_adapter_set_enabled(). self->enabled = false; - self->now_advertising = false; - self->circuitpython_advertising = false; - self->extended_advertising = false; - self->advertising_timeout_msecs = 0; + common_hal_bleio_adapter_set_enabled(self, true); bleio_adapter_get_info(self); - bleio_adapter_reset_name(self); } @@ -243,15 +230,14 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable return; } - //FIX enable/disable HCI adapter, but don't reset it, since we don't know how. self->enabled = enabled; - if (!enabled) { - // Stop any current activity. - check_hci_error(hci_reset()); - self->now_advertising = false; - self->extended_advertising = false; - self->circuitpython_advertising = false; - } + + // Stop any current activity; reset to known state. + check_hci_error(hci_reset()); + self->now_advertising = false; + self->extended_advertising = false; + self->circuitpython_advertising = false; + self->advertising_timeout_msecs = 0; } bool common_hal_bleio_adapter_get_enabled(bleio_adapter_obj_t *self) { @@ -506,6 +492,10 @@ uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, advertising_data_len > self->max_adv_data_len || scan_response_data_len > self->max_adv_data_len; if (extended) { + if (!BT_FEAT_LE_EXT_ADV(self->features)) { + mp_raise_bleio_BluetoothError(translate("Data length needs extended advertising, but this adapter does not support it")); + } + uint16_t props = 0; if (connectable) { props |= BT_HCI_LE_ADV_PROP_CONN; diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.h b/devices/ble_hci/common-hal/_bleio/Adapter.h index 8e34f86631..10a398b24f 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.h +++ b/devices/ble_hci/common-hal/_bleio/Adapter.h @@ -65,6 +65,7 @@ typedef struct _bleio_adapter_obj_t { uint16_t max_acl_buffer_len; uint16_t max_acl_num_buffers; uint16_t max_adv_data_len; + uint8_t features[8]; // Supported BLE features. } bleio_adapter_obj_t; diff --git a/devices/ble_hci/common-hal/_bleio/hci_api.c b/devices/ble_hci/common-hal/_bleio/hci_api.c index 4901ffeedb..ece06f169f 100644 --- a/devices/ble_hci/common-hal/_bleio/hci_api.c +++ b/devices/ble_hci/common-hal/_bleio/hci_api.c @@ -628,9 +628,19 @@ hci_result_t hci_le_read_maximum_advertising_data_length(uint16_t *max_adv_data_ 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; - } + *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; @@ -649,6 +659,20 @@ hci_result_t hci_le_set_advertising_data(uint8_t len, uint8_t data[]) { 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. diff --git a/devices/ble_hci/common-hal/_bleio/hci_api.h b/devices/ble_hci/common-hal/_bleio/hci_api.h index 23e45375cc..3e53a37752 100644 --- a/devices/ble_hci/common-hal/_bleio/hci_api.h +++ b/devices/ble_hci/common-hal/_bleio/hci_api.h @@ -47,11 +47,13 @@ hci_result_t hci_le_create_conn(uint16_t scan_interval, uint16_t scan_window, ui 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); diff --git a/shared-bindings/_bleio/Adapter.c b/shared-bindings/_bleio/Adapter.c index 8673044165..61999282c8 100644 --- a/shared-bindings/_bleio/Adapter.c +++ b/shared-bindings/_bleio/Adapter.c @@ -83,6 +83,8 @@ STATIC void check_enabled(bleio_adapter_obj_t *self) { //| The `uart`, `rts`, and `cts` objects are used to //| communicate with the HCI co-processor in HCI mode. //| +//| The `_bleio.adapter` object is enabled during this call. +//| mp_obj_t bleio_adapter_hci_uart_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]); @@ -108,9 +110,9 @@ mp_obj_t bleio_adapter_hci_uart_init(mp_uint_t n_args, const mp_obj_t *pos_args, !MP_OBJ_IS_TYPE(cts, &digitalio_digitalinout_type)) { mp_raise_ValueError(translate("Expected a DigitalInOut")); } - check_enabled(self); + + // Will enable the adapter. common_hal_bleio_adapter_hci_uart_init(self, uart, rts, cts); - common_hal_bleio_adapter_set_enabled(self, true); return mp_const_none; #else From 6494bbdc64f1633b5935c8b314139c19945328ba Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 16 Jul 2020 23:14:49 -0400 Subject: [PATCH 11/84] snapshot --- devices/ble_hci/common-hal/_bleio/Adapter.c | 9 +- .../common-hal/_bleio/Characteristic.c | 10 +- devices/ble_hci/common-hal/_bleio/UUID.c | 58 ++---- devices/ble_hci/common-hal/_bleio/UUID.h | 12 +- devices/ble_hci/common-hal/_bleio/hci_api.c | 165 ++++++++++-------- devices/ble_hci/common-hal/_bleio/hci_api.h | 1 + ports/nrf/common-hal/_bleio/UUID.c | 2 +- shared-bindings/_bleio/UUID.h | 2 +- 8 files changed, 131 insertions(+), 128 deletions(-) diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index 92eb42ee0f..17b66899a5 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.c +++ b/devices/ble_hci/common-hal/_bleio/Adapter.c @@ -633,7 +633,12 @@ void common_hal_bleio_adapter_stop_advertising(bleio_adapter_obj_t *self) { self->now_advertising = false; self->extended_advertising = false; self->circuitpython_advertising = false; - check_hci_error(hci_le_set_advertising_enable(BT_HCI_LE_ADV_DISABLE)); + int result = hci_le_set_advertising_enable(BT_HCI_LE_ADV_DISABLE); + // OK if we're already stopped. + if (result != BT_HCI_ERR_CMD_DISALLOWED) { + check_hci_error(result); + } + //TODO startup CircuitPython advertising again. } @@ -704,4 +709,6 @@ void bleio_adapter_background(bleio_adapter_obj_t* adapter) { adapter->advertising_timeout_msecs = 0; common_hal_bleio_adapter_stop_advertising(adapter); } + + hci_poll_for_incoming_pkt(); } diff --git a/devices/ble_hci/common-hal/_bleio/Characteristic.c b/devices/ble_hci/common-hal/_bleio/Characteristic.c index ff08bf15c4..74cbede0eb 100644 --- a/devices/ble_hci/common-hal/_bleio/Characteristic.c +++ b/devices/ble_hci/common-hal/_bleio/Characteristic.c @@ -91,12 +91,10 @@ void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, self->write_perm = write_perm; self->descriptor_list = NULL; - //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"); - // } + const mp_int_t max_length_max = 512; + if (max_length < 0 || max_length > max_length_max) { + mp_raise_ValueError(translate("max_length must be <= 512")); + } self->max_length = max_length; self->fixed_length = fixed_length; diff --git a/devices/ble_hci/common-hal/_bleio/UUID.c b/devices/ble_hci/common-hal/_bleio/UUID.c index 3f5fbe4fe4..d86878e472 100644 --- a/devices/ble_hci/common-hal/_bleio/UUID.c +++ b/devices/ble_hci/common-hal/_bleio/UUID.c @@ -36,55 +36,35 @@ // If uuid128 is NULL, this is a Bluetooth SIG 16-bit UUID. // 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[]) { - //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; - // } +void common_hal_bleio_uuid_construct(bleio_uuid_obj_t *self, uint32_t uuid16, const uint8_t uuid128[16]) { + self->size = uuid128 == NULL ? 16 : 128; + self->uuid16 = uuid16; + if (uuid128) { + memcpy(self->uuid128, uuid128, 16); + self->uuid128[12] = uuid16 & 0xff; + self->uuid128[13] = uuid16 >> 8; + } else { + memset(self->uuid128, 0, 16); + } } uint32_t common_hal_bleio_uuid_get_size(bleio_uuid_obj_t *self) { - //FIX return self->nrf_ble_uuid.type == BLE_UUID_TYPE_BLE ? 16 : 128; - return 0; + return self->size; } uint32_t common_hal_bleio_uuid_get_uuid16(bleio_uuid_obj_t *self) { - //FIX return self->nrf_ble_uuid.uuid; - return 0; + return self->uuid16; } void common_hal_bleio_uuid_get_uuid128(bleio_uuid_obj_t *self, uint8_t uuid128[16]) { - //FIX uint8_t length; - //FIX check_nrf_error(sd_ble_uuid_encode(&self->nrf_ble_uuid, &length, uuid128)); + memcpy(uuid128, self->uuid128, 16); } void common_hal_bleio_uuid_pack_into(bleio_uuid_obj_t *self, uint8_t* buf) { - //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 { - // common_hal_bleio_uuid_get_uuid128(self, buf); - // } + if (self->size == 16) { + buf[0] = self->uuid16 & 0xff; + buf[1] = self->uuid16 >> 8; + } else { + common_hal_bleio_uuid_get_uuid128(self, 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")); -// } -// self->nrf_ble_uuid.uuid = nrf_ble_uuid->uuid; -// self->nrf_ble_uuid.type = nrf_ble_uuid->type; -// } - -// // Fill in a ble_uuid_t from my values. -// void bleio_uuid_convert_to_nrf_ble_uuid(bleio_uuid_obj_t *self, ble_uuid_t *nrf_ble_uuid) { -// nrf_ble_uuid->uuid = self->nrf_ble_uuid.uuid; -// nrf_ble_uuid->type = self->nrf_ble_uuid.type; -// } diff --git a/devices/ble_hci/common-hal/_bleio/UUID.h b/devices/ble_hci/common-hal/_bleio/UUID.h index 4a72d38acd..deaf76d5c6 100644 --- a/devices/ble_hci/common-hal/_bleio/UUID.h +++ b/devices/ble_hci/common-hal/_bleio/UUID.h @@ -33,15 +33,9 @@ typedef struct { mp_obj_base_t base; - //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 - // 128-bit UUIDs. - // ble_uuid_t nrf_ble_uuid; + uint8_t size; + uint16_t uuid16; + uint8_t uuid128[16]; } bleio_uuid_obj_t; -// void bleio_uuid_construct_from_nrf_ble_uuid(bleio_uuid_obj_t *self, ble_uuid_t *nrf_uuid); -// void bleio_uuid_convert_to_nrf_ble_uuid(bleio_uuid_obj_t *self, ble_uuid_t *nrf_uuid); - #endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_UUID_H diff --git a/devices/ble_hci/common-hal/_bleio/hci_api.c b/devices/ble_hci/common-hal/_bleio/hci_api.c index ece06f169f..8155bca56e 100644 --- a/devices/ble_hci/common-hal/_bleio/hci_api.c +++ b/devices/ble_hci/common-hal/_bleio/hci_api.c @@ -25,6 +25,7 @@ #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 @@ -61,44 +62,61 @@ STATIC uint8_t* cmd_response_data; //FIX STATIC uint8_t acl_pkt_buffer[ACL_PKT_BUFFER_SIZE]; +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; -} h4_hci_cmd_hdr_t; + uint8_t pkt_type; + uint16_t opcode; + uint8_t param_len; + uint8_t params[]; +} h4_hci_cmd_pkt_t; + +#define ACLDATA_PB_FIRST_NON_FLUSH 0 +#define ACLDATA_HCI_PB_MIDDLE 1 +#define ACLDATA_PB_FIRST_FLUSH 2 +#define ACLDATA_PB_FULL 3 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; + uint16_t handle : 12; + uint8_t pb: 2; // Packet boundary flag: ACLDATA_PB values. + uint8_t bc: 2; // Broadcast flag: always 0b00 for BLE. + uint16_t data_len; // Total data length, including acl_data header. + uint8_t data[]; // Data following the header +} h4_hci_acl_pkt_t; + +// L2CAP data, which is in h4_hci_acl_pkt_t.data +typedef struct __attribute__ ((packed)) { + uint16_t l2cap_data_len; // Length of acl_data. Does not include this header. + uint16_t cid; // Channel ID. + uint8_t l2cap_data[]; +} l2cap_data_t; + typedef struct __attribute__ ((packed)) { uint8_t pkt_type; uint8_t evt; uint8_t param_len; -} h4_hci_evt_hdr_t; + 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_hdr_t *pkt = (h4_hci_cmd_hdr_t *) pkt_data; + 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); - uint8_t i; - for (i = sizeof(h4_hci_cmd_hdr_t); i < pkt_len; i++) { - mp_printf(&mp_plat_print, "%02x ", pkt_data[i]); + for (size_t i = 0; i < pkt->param_len; i++) { + mp_printf(&mp_plat_print, "%02x ", pkt->params[i]); } - if (i != pkt->param_len + sizeof(h4_hci_cmd_hdr_t)) { + 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"); @@ -107,16 +125,16 @@ STATIC void dump_cmd_pkt(bool tx, uint8_t pkt_len, uint8_t pkt_data[]) { STATIC void dump_acl_pkt(bool tx, uint8_t pkt_len, uint8_t pkt_data[]) { if (debug) { - h4_hci_acl_hdr_t *pkt = (h4_hci_acl_hdr_t *) pkt_data; + h4_hci_acl_pkt_t *pkt = (h4_hci_acl_pkt_t *) pkt_data; + l2cap_data_t *l2cap = (l2cap_data_t *) pkt->data; mp_printf(&mp_plat_print, - "%s HCI ACLDATA (%x) handle: %04x, total_data_len: %d, acl_data_len: %d, cid: %04x, data: ", + "%s HCI ACLDATA (%x) handle: %04x, pb: %d, bc: %d, data_len: %d, l2cap_data_len: %d, cid: %04x, l2cap_data: ", tx ? "TX->" : "RX<-", - pkt->pkt_type, pkt->handle, pkt->total_data_len, pkt->acl_data_len, pkt->cid); - uint8_t i; - for (i = sizeof(h4_hci_acl_hdr_t); i < pkt_len; i++) { - mp_printf(&mp_plat_print, "%02x ", pkt_data[i]); + pkt->pkt_type, pkt->handle, pkt->data_len, l2cap->l2cap_data_len, l2cap->cid); + for (size_t i = 0; i < l2cap->l2cap_data_len; i++) { + mp_printf(&mp_plat_print, "%02x ", l2cap->l2cap_data[i]); } - if (i != pkt->acl_data_len + sizeof(h4_hci_acl_hdr_t)) { + 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"); @@ -125,16 +143,15 @@ STATIC void dump_acl_pkt(bool tx, uint8_t pkt_len, uint8_t pkt_data[]) { STATIC void dump_evt_pkt(bool tx, uint8_t pkt_len, uint8_t pkt_data[]) { if (debug) { - h4_hci_evt_hdr_t *pkt = (h4_hci_evt_hdr_t *) pkt_data; + 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); - uint8_t i; - for (i = sizeof(h4_hci_evt_hdr_t); i < pkt_len; i++) { - mp_printf(&mp_plat_print, "%02x ", pkt_data[i]); + for (size_t i = 0; i < pkt->param_len; i++) { + mp_printf(&mp_plat_print, "%02x ", pkt->params[i]); } - if (i != pkt->param_len + sizeof(h4_hci_evt_hdr_t)) { + 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"); @@ -143,7 +160,7 @@ STATIC void dump_evt_pkt(bool tx, uint8_t pkt_len, uint8_t pkt_data[]) { 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; + // h4_hci_acl_pkt_t *aclHdr = (h4_hci_acl_pkt_t*)pkt_data; // uint16_t aclFlags = (aclHdr->handle & 0xf000) >> 12; @@ -202,15 +219,14 @@ STATIC void process_num_comp_pkts(uint16_t handle, uint16_t num_pkts) { } } -STATIC void process_evt_pkt(size_t pkt_len, uint8_t pkt[]) +STATIC void process_evt_pkt(size_t pkt_len, uint8_t pkt_data[]) { - 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); + h4_hci_evt_pkt_t *pkt = (h4_hci_evt_pkt_t*) pkt_data; - switch (evt_hdr->evt) { + switch (pkt->evt) { case BT_HCI_EVT_DISCONN_COMPLETE: { - struct bt_hci_evt_disconn_complete *disconn_complete = (struct bt_hci_evt_disconn_complete*) evt_data; + 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); @@ -226,7 +242,7 @@ STATIC void process_evt_pkt(size_t pkt_len, uint8_t pkt[]) struct bt_hci_evt_cc_status cc_status; } __packed; - struct cmd_complete_with_status *evt = (struct cmd_complete_with_status *) evt_data; + struct cmd_complete_with_status *evt = (struct cmd_complete_with_status *) pkt->params; num_command_packets_allowed = evt->cmd_complete.ncmd; @@ -235,15 +251,15 @@ STATIC void process_evt_pkt(size_t pkt_len, uint8_t pkt[]) 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 = &evt_data[sizeof_field(struct cmd_complete_with_status, cmd_complete)]; + cmd_response_data = (uint8_t *) &evt->cc_status; // Includes status byte. - cmd_response_len = evt_hdr->param_len - sizeof_field(struct cmd_complete_with_status, cmd_complete); + 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 *) evt_data; + struct bt_hci_evt_cmd_status *evt = (struct bt_hci_evt_cmd_status *) pkt->params; num_command_packets_allowed = evt->ncmd; @@ -257,7 +273,8 @@ STATIC void process_evt_pkt(size_t pkt_len, uint8_t pkt[]) } case BT_HCI_EVT_NUM_COMPLETED_PACKETS: { - struct bt_hci_evt_num_completed_packets *evt = (struct bt_hci_evt_num_completed_packets *) evt_data; + 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]); @@ -269,15 +286,14 @@ STATIC void process_evt_pkt(size_t pkt_len, uint8_t pkt[]) } 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); + 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 == 0x00) { + 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 @@ -286,13 +302,6 @@ STATIC void process_evt_pkt(size_t pkt_len, uint8_t pkt[]) // 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 = @@ -319,9 +328,19 @@ STATIC void process_evt_pkt(size_t pkt_len, uint8_t pkt[]) 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); @@ -332,21 +351,22 @@ hci_result_t hci_poll_for_incoming_pkt(void) { 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_hdr_t) && - rx_idx >= sizeof(h4_hci_acl_hdr_t) + ((h4_hci_acl_hdr_t *) rx_buffer)->total_data_len) { + 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_hdr_t) && - rx_idx >= sizeof(h4_hci_evt_hdr_t) + ((h4_hci_evt_hdr_t *) rx_buffer)->param_len) { + 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; @@ -359,6 +379,7 @@ hci_result_t hci_poll_for_incoming_pkt(void) { } if (!packet_is_complete) { + hci_poll_in_progress = false; return HCI_OK; } @@ -391,6 +412,7 @@ hci_result_t hci_poll_for_incoming_pkt(void) { common_hal_digitalio_digitalinout_set_value(adapter->rts_digitalinout, true); + hci_poll_in_progress = false; return HCI_OK; } @@ -416,22 +438,22 @@ STATIC hci_result_t write_pkt(uint8_t *buffer, size_t len) { } 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]; + 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_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; + 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; - // Copy the params data into the space after the header. - memcpy(&tx_buffer[sizeof(h4_hci_cmd_hdr_t)], params, 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, sizeof(h4_hci_cmd_hdr_t) + params_len); + int result = write_pkt(tx_buffer, cmd_pkt_len); if (result != HCI_OK) { return result; } @@ -477,19 +499,20 @@ STATIC int __attribute__((unused)) send_acl_pkt(uint16_t handle, uint8_t cid, vo } // data_len does not include cid. - const size_t cid_len = sizeof_field(h4_hci_acl_hdr_t, cid); + const size_t cid_len = sizeof_field(l2cap_data_t, 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; + const size_t buf_len = sizeof(h4_hci_acl_pkt_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; + h4_hci_acl_pkt_t *acl_pkt = (h4_hci_acl_pkt_t *) tx_buffer; + l2cap_data_t *l2cap = (l2cap_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); + l2cap->l2cap_data_len = (uint8_t) data_len; + l2cap->cid = cid; - memcpy(&tx_buffer[sizeof(h4_hci_acl_hdr_t)], data, data_len); + memcpy(&tx_buffer[sizeof(h4_hci_acl_pkt_t)], data, data_len); if (debug) { dump_acl_pkt(true, buf_len, tx_buffer); diff --git a/devices/ble_hci/common-hal/_bleio/hci_api.h b/devices/ble_hci/common-hal/_bleio/hci_api.h index 3e53a37752..f6d96d48fe 100644 --- a/devices/ble_hci/common-hal/_bleio/hci_api.h +++ b/devices/ble_hci/common-hal/_bleio/hci_api.h @@ -23,6 +23,7 @@ #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; diff --git a/ports/nrf/common-hal/_bleio/UUID.c b/ports/nrf/common-hal/_bleio/UUID.c index 6a3d643050..f80352ccb6 100644 --- a/ports/nrf/common-hal/_bleio/UUID.c +++ b/ports/nrf/common-hal/_bleio/UUID.c @@ -40,7 +40,7 @@ // If uuid128 is NULL, this is a Bluetooth SIG 16-bit UUID. // 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[]) { +void common_hal_bleio_uuid_construct(bleio_uuid_obj_t *self, uint32_t uuid16, const uint8_t uuid128[16]) { self->nrf_ble_uuid.uuid = uuid16; if (uuid128 == NULL) { self->nrf_ble_uuid.type = BLE_UUID_TYPE_BLE; diff --git a/shared-bindings/_bleio/UUID.h b/shared-bindings/_bleio/UUID.h index 1490737a71..178b0ca965 100644 --- a/shared-bindings/_bleio/UUID.h +++ b/shared-bindings/_bleio/UUID.h @@ -34,7 +34,7 @@ void bleio_uuid_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t extern const mp_obj_type_t bleio_uuid_type; -extern void common_hal_bleio_uuid_construct(bleio_uuid_obj_t *self, mp_int_t uuid16, const uint8_t uuid128[]); +extern void common_hal_bleio_uuid_construct(bleio_uuid_obj_t *self, mp_int_t uuid16, const uint8_t uuid128[16]); extern uint32_t common_hal_bleio_uuid_get_uuid16(bleio_uuid_obj_t *self); extern bool common_hal_bleio_uuid_get_uuid128(bleio_uuid_obj_t *self, uint8_t uuid128[16]); extern uint32_t common_hal_bleio_uuid_get_size(bleio_uuid_obj_t *self); From 90ae1efa001a590a758e125726e67023b69e2779 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 17 Jul 2020 21:28:24 -0400 Subject: [PATCH 12/84] revamp ACLDATA reassembly --- devices/ble_hci/common-hal/_bleio/hci_api.c | 124 +++++++++++--------- 1 file changed, 68 insertions(+), 56 deletions(-) diff --git a/devices/ble_hci/common-hal/_bleio/hci_api.c b/devices/ble_hci/common-hal/_bleio/hci_api.c index 8155bca56e..854f7c0a00 100644 --- a/devices/ble_hci/common-hal/_bleio/hci_api.c +++ b/devices/ble_hci/common-hal/_bleio/hci_api.c @@ -1,3 +1,4 @@ +// 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. @@ -39,7 +40,7 @@ #define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER)) #define RX_BUFFER_SIZE (3 + 255) -#define ACL_PKT_BUFFER_SIZE (255) +#define ACL_DATA_BUFFER_SIZE (255 + 1) #define CTS_TIMEOUT_MSECS (1000) #define RESPONSE_TIMEOUT_MSECS (1000) @@ -60,7 +61,8 @@ 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 uint8_t acl_data_buffer[ACL_DATA_BUFFER_SIZE]; +STATIC size_t acl_data_len; STATIC volatile bool hci_poll_in_progress = false; @@ -76,27 +78,28 @@ typedef struct __attribute__ ((packed)) { uint8_t params[]; } h4_hci_cmd_pkt_t; -#define ACLDATA_PB_FIRST_NON_FLUSH 0 -#define ACLDATA_HCI_PB_MIDDLE 1 -#define ACLDATA_PB_FIRST_FLUSH 2 -#define ACLDATA_PB_FULL 3 +#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: ACLDATA_PB values. - uint8_t bc: 2; // Broadcast flag: always 0b00 for BLE. - uint16_t data_len; // Total data length, including acl_data header. - uint8_t data[]; // Data following the header + 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; -// L2CAP data, which is in h4_hci_acl_pkt_t.data +// 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 l2cap_data_len; // Length of acl_data. Does not include this header. - uint16_t cid; // Channel ID. - uint8_t l2cap_data[]; -} l2cap_data_t; - + 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; @@ -125,15 +128,31 @@ STATIC void dump_cmd_pkt(bool tx, uint8_t pkt_len, uint8_t pkt_data[]) { 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; - l2cap_data_t *l2cap = (l2cap_data_t *) pkt->data; mp_printf(&mp_plat_print, - "%s HCI ACLDATA (%x) handle: %04x, pb: %d, bc: %d, data_len: %d, l2cap_data_len: %d, cid: %04x, l2cap_data: ", - tx ? "TX->" : "RX<-", - pkt->pkt_type, pkt->handle, pkt->data_len, l2cap->l2cap_data_len, l2cap->cid); - for (size_t i = 0; i < l2cap->l2cap_data_len; i++) { - mp_printf(&mp_plat_print, "%02x ", l2cap->l2cap_data[i]); + "%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"); } @@ -159,40 +178,27 @@ STATIC void dump_evt_pkt(bool tx, uint8_t pkt_len, uint8_t pkt_data[]) { } 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_pkt_t *aclHdr = (h4_hci_acl_pkt_t*)pkt_data; + h4_hci_acl_pkt_t *pkt = (h4_hci_acl_pkt_t*) pkt_data; - // uint16_t aclFlags = (aclHdr->handle & 0xf000) >> 12; + 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; + } - // 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; - // } + 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) { - // 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)]); - // } + // 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 { @@ -321,6 +327,9 @@ STATIC void process_evt_pkt(size_t pkt_len, uint8_t pkt_data[]) } default: + if (debug) { + mp_printf(&mp_plat_print, "process_evt_pkt: Unknown event: %02x\n"); + } break; } } @@ -407,6 +416,9 @@ hci_result_t hci_poll_for_incoming_pkt(void) { break; default: + if (debug) { + mp_printf(&mp_plat_print, "Unknown HCI packet type: %d\n", rx_buffer[0]); + } break; } @@ -499,18 +511,18 @@ STATIC int __attribute__((unused)) send_acl_pkt(uint16_t handle, uint8_t cid, vo } // data_len does not include cid. - const size_t cid_len = sizeof_field(l2cap_data_t, 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; - l2cap_data_t *l2cap = (l2cap_data_t *) acl_pkt->data; + 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); - l2cap->l2cap_data_len = (uint8_t) data_len; - l2cap->cid = cid; + 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); From f6f45c82a118f59d5d155fbbbe091580ba0dcf31 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 23 Jul 2020 18:54:26 -0400 Subject: [PATCH 13/84] wip: ATT protocol --- devices/ble_hci/common-hal/_bleio/Adapter.c | 2 +- .../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 + .../common-hal/_bleio/{hci_api.c => hci.c} | 94 +- .../common-hal/_bleio/{hci_api.h => hci.h} | 8 +- .../common-hal/_bleio/hci_include/addr.h | 1 + .../common-hal/_bleio/hci_include/att.h | 41 + .../_bleio/hci_include/att_internal.h | 266 +++ .../common-hal/_bleio/hci_include/hci.h | 1 + .../_bleio/hci_include/l2cap_internal.h | 230 +++ py/circuitpy_defns.mk | 4 +- py/misc.h | 2 + py/py.mk | 2 +- 15 files changed, 2290 insertions(+), 46 deletions(-) create mode 100644 devices/ble_hci/common-hal/_bleio/att.c create mode 100644 devices/ble_hci/common-hal/_bleio/att.h rename devices/ble_hci/common-hal/_bleio/{hci_api.c => hci.c} (96%) rename devices/ble_hci/common-hal/_bleio/{hci_api.h => hci.h} (93%) 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 diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index 17b66899a5..55e0bde017 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 bb0c140c55..8b9790d9ed 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 0d1c2785f7..18b4289e9a 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 0000000000..d37012a0ad --- /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 0000000000..108c44929f --- /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_api.c b/devices/ble_hci/common-hal/_bleio/hci.c similarity index 96% rename from devices/ble_hci/common-hal/_bleio/hci_api.c rename to devices/ble_hci/common-hal/_bleio/hci.c index 854f7c0a00..83aba883ad 100644 --- a/devices/ble_hci/common-hal/_bleio/hci_api.c +++ b/devices/ble_hci/common-hal/_bleio/hci.c @@ -13,13 +13,15 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "hci_api.h" +#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 @@ -28,46 +30,18 @@ #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. @@ -109,6 +83,36 @@ typedef struct __attribute__ ((packed)) { } 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; @@ -191,15 +195,16 @@ STATIC void process_acl_data_pkt(uint8_t pkt_len, uint8_t pkt_data[]) { 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) { + 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 (aclHdr->cid == ATT_CID) { - // ATT.handleData(aclHdr->handle & 0x0fff, aclHdr->len, &rx_buffer[1 + sizeof(HCIACLHdr)]); - // } else if (aclHdr->cid == SIGNALING_CID) { + 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)) { @@ -340,6 +345,20 @@ void hci_init(void) { 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; @@ -500,8 +519,7 @@ STATIC hci_result_t send_command(uint16_t opcode, uint8_t params_len, void* para 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) { +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(); @@ -510,7 +528,7 @@ STATIC int __attribute__((unused)) send_acl_pkt(uint16_t handle, uint8_t cid, vo } } - // data_len does not include cid. + // 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; diff --git a/devices/ble_hci/common-hal/_bleio/hci_api.h b/devices/ble_hci/common-hal/_bleio/hci.h similarity index 93% rename from devices/ble_hci/common-hal/_bleio/hci_api.h rename to devices/ble_hci/common-hal/_bleio/hci.h index f6d96d48fe..736877ddc6 100644 --- a/devices/ble_hci/common-hal/_bleio/hci_api.h +++ b/devices/ble_hci/common-hal/_bleio/hci.h @@ -17,8 +17,8 @@ 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 +#ifndef MICROPY_INCLUDED_DEVICES_BLE_HCI_COMMON_HAL_BLEIO_HCI_H +#define MICROPY_INCLUDED_DEVICES_BLE_HCI_COMMON_HAL_BLEIO_HCI_H #include @@ -64,6 +64,7 @@ hci_result_t hci_le_set_scan_parameters(uint8_t scan_type, uint16_t interval, ui 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); @@ -72,6 +73,7 @@ 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_API_H +#endif // MICROPY_INCLUDED_DEVICES_BLE_HCI_COMMON_HAL_BLEIO_HCI_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 8f503b8a17..fd74a95e8d 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 0000000000..8117a48f45 --- /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 0000000000..1c75275daa --- /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 2de58b3d89..6c3a2b5bd0 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 0000000000..bed311cf3c --- /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 0dd31904f2..e2850e63fc 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 673568f226..abcc7edf74 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 3cb505920c..62050519b3 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\" From d37326326dba329392964d283eb13507643bfbec Mon Sep 17 00:00:00 2001 From: sabas1080 Date: Tue, 28 Jul 2020 00:56:37 -0500 Subject: [PATCH 14/84] init bastwifi --- .../boards/electroniccats_bastwifi/board.c | 47 +++++++++++++++++++ .../electroniccats_bastwifi/mpconfigboard.h | 32 +++++++++++++ .../electroniccats_bastwifi/mpconfigboard.mk | 19 ++++++++ .../boards/electroniccats_bastwifi/pins.c | 46 ++++++++++++++++++ .../boards/electroniccats_bastwifi/sdkconfig | 0 5 files changed, 144 insertions(+) create mode 100644 ports/esp32s2/boards/electroniccats_bastwifi/board.c create mode 100644 ports/esp32s2/boards/electroniccats_bastwifi/mpconfigboard.h create mode 100644 ports/esp32s2/boards/electroniccats_bastwifi/mpconfigboard.mk create mode 100644 ports/esp32s2/boards/electroniccats_bastwifi/pins.c create mode 100644 ports/esp32s2/boards/electroniccats_bastwifi/sdkconfig diff --git a/ports/esp32s2/boards/electroniccats_bastwifi/board.c b/ports/esp32s2/boards/electroniccats_bastwifi/board.c new file mode 100644 index 0000000000..9f708874bf --- /dev/null +++ b/ports/esp32s2/boards/electroniccats_bastwifi/board.c @@ -0,0 +1,47 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft 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 "boards/board.h" +#include "mpconfigboard.h" +#include "shared-bindings/microcontroller/Pin.h" + +void board_init(void) { + // USB + common_hal_never_reset_pin(&pin_GPIO19); + common_hal_never_reset_pin(&pin_GPIO20); + + // Debug UART + common_hal_never_reset_pin(&pin_GPIO43); + common_hal_never_reset_pin(&pin_GPIO44); +} + +bool board_requests_safe_mode(void) { + return false; +} + +void reset_board(void) { + +} diff --git a/ports/esp32s2/boards/electroniccats_bastwifi/mpconfigboard.h b/ports/esp32s2/boards/electroniccats_bastwifi/mpconfigboard.h new file mode 100644 index 0000000000..ed3f23a3c4 --- /dev/null +++ b/ports/esp32s2/boards/electroniccats_bastwifi/mpconfigboard.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Scott Shawcroft 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. + */ + +//Micropython setup + +#define MICROPY_HW_BOARD_NAME "BastWiFi" +#define MICROPY_HW_MCU_NAME "ESP32S2" + +#define AUTORESET_DELAY_MS 500 diff --git a/ports/esp32s2/boards/electroniccats_bastwifi/mpconfigboard.mk b/ports/esp32s2/boards/electroniccats_bastwifi/mpconfigboard.mk new file mode 100644 index 0000000000..4a2e8ecd8a --- /dev/null +++ b/ports/esp32s2/boards/electroniccats_bastwifi/mpconfigboard.mk @@ -0,0 +1,19 @@ +USB_VID = 0x239A +USB_PID = 0x80A6 +USB_PRODUCT = "Bast WiFi" +USB_MANUFACTURER = "ElectronicCats" + +INTERNAL_FLASH_FILESYSTEM = 1 +LONGINT_IMPL = MPZ + +# The default queue depth of 16 overflows on release builds, +# so increase it to 32. +CFLAGS += -DCFG_TUD_TASK_QUEUE_SZ=32 + +CIRCUITPY_NEOPIXEL_WRITE = 0 + +CIRCUITPY_ESP_FLASH_MODE=dio +CIRCUITPY_ESP_FLASH_FREQ=40m +CIRCUITPY_ESP_FLASH_SIZE=4MB + +CIRCUITPY_MODULE=wrover diff --git a/ports/esp32s2/boards/electroniccats_bastwifi/pins.c b/ports/esp32s2/boards/electroniccats_bastwifi/pins.c new file mode 100644 index 0000000000..1d4e2c4eba --- /dev/null +++ b/ports/esp32s2/boards/electroniccats_bastwifi/pins.c @@ -0,0 +1,46 @@ +#include "shared-bindings/board/__init__.h" + +STATIC const mp_rom_map_elem_t board_global_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_IO10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_IO11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_IO12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_IO13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_IO14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_IO15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_IO16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_IO17), MP_ROM_PTR(&pin_GPIO17) }, + + + { MP_ROM_QSTR(MP_QSTR_IO18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_IO19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_IO20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_IO26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_IO33), MP_ROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_IO34), MP_ROM_PTR(&pin_GPIO34) }, + { MP_ROM_QSTR(MP_QSTR_IO35), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_IO36), MP_ROM_PTR(&pin_GPIO36) }, + { MP_ROM_QSTR(MP_QSTR_IO37), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_IO38), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_IO39), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_IO40), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_IO41), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_IO42), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_IO43), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_IO44), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_IO45), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_IO46), MP_ROM_PTR(&pin_GPIO46) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table); diff --git a/ports/esp32s2/boards/electroniccats_bastwifi/sdkconfig b/ports/esp32s2/boards/electroniccats_bastwifi/sdkconfig new file mode 100644 index 0000000000..e69de29bb2 From 9572f306d3a4cbbbb662961890147b7793e740a9 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 28 Jul 2020 11:56:00 -0400 Subject: [PATCH 15/84] ATT WIP --- devices/ble_hci/common-hal/_bleio/Adapter.c | 3 + devices/ble_hci/common-hal/_bleio/Adapter.h | 3 + devices/ble_hci/common-hal/_bleio/Service.c | 47 ++- devices/ble_hci/common-hal/_bleio/att.c | 318 +++++++++++--------- devices/ble_hci/common-hal/_bleio/att.h | 2 +- 5 files changed, 206 insertions(+), 167 deletions(-) diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index 55e0bde017..6c94bb1a92 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.c +++ b/devices/ble_hci/common-hal/_bleio/Adapter.c @@ -238,6 +238,9 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable self->extended_advertising = false; self->circuitpython_advertising = false; self->advertising_timeout_msecs = 0; + + // Reset list of known attributes. + self->attributes = mp_obj_new_list(0, NULL); } bool common_hal_bleio_adapter_get_enabled(bleio_adapter_obj_t *self) { diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.h b/devices/ble_hci/common-hal/_bleio/Adapter.h index 10a398b24f..d2f38b757c 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.h +++ b/devices/ble_hci/common-hal/_bleio/Adapter.h @@ -67,6 +67,9 @@ typedef struct _bleio_adapter_obj_t { uint16_t max_adv_data_len; uint8_t features[8]; // Supported BLE features. + // All the local attributes for this device. The index into the list + // corresponds to the handle. + mp_obj_list_t *attributes; } bleio_adapter_obj_t; void bleio_adapter_background(bleio_adapter_obj_t* adapter); diff --git a/devices/ble_hci/common-hal/_bleio/Service.c b/devices/ble_hci/common-hal/_bleio/Service.c index 1f9649b6c3..07a9b4de25 100644 --- a/devices/ble_hci/common-hal/_bleio/Service.c +++ b/devices/ble_hci/common-hal/_bleio/Service.c @@ -40,24 +40,18 @@ uint32_t _common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uu self->connection = NULL; self->is_secondary = is_secondary; - //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; - // } - vm_used_ble = true; - //FIX return sd_ble_gatts_service_add(service_type, &nordic_uuid, &self->handle); - return 0; + uint32_t status; + self->handle = bleio_adapter_add_attribute( + is_secondary ? BLE_TYPE_SECONDARY_SERVICE : BLE_TYPE_PRIMARY_SERVICE, + uuid, &status); + return status; } void common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uuid_obj_t *uuid, bool is_secondary) { - //FIX check_nrf_error(_common_hal_bleio_service_construct(self, uuid, is_secondary, - // mp_obj_new_list(0, NULL))); + check_hci_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) { @@ -88,6 +82,30 @@ 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) { + common_hal_bleio_adapter_obj + //FIX how it's done by ArduinoBLE when a service is added. + // uint16_t startHandle = attributeCount(); + + // for (unsigned int i = 0; i < service->characteristicCount(); i++) { + // BLELocalCharacteristic* characteristic = service->characteristic(i); + + // characteristic->retain(); + // _attributes.add(characteristic); + // characteristic->setHandle(attributeCount()); + + // // add the characteristic again to make space of the characteristic value handle + // _attributes.add(characteristic); + + // for (unsigned int j = 0; j < characteristic->descriptorCount(); j++) { + // BLELocalDescriptor* descriptor = characteristic->descriptor(j); + + // descriptor->retain(); + // _attributes.add(descriptor); + // descriptor->setHandle(attributeCount()); + // } + // } + + service->setHandles(startHandle, attributeCount()); // 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, @@ -101,9 +119,6 @@ void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, // .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, diff --git a/devices/ble_hci/common-hal/_bleio/att.c b/devices/ble_hci/common-hal/_bleio/att.c index d37012a0ad..ad1dddca22 100644 --- a/devices/ble_hci/common-hal/_bleio/att.c +++ b/devices/ble_hci/common-hal/_bleio/att.c @@ -43,7 +43,7 @@ enum ble_attribute_type { STATIC uint16_t max_mtu = BT_ATT_DEFAULT_LE_MTU; // 23 STATIC unsigned long timeout = 5000; -STATIC volatile bool cnf; +STATIC volatile bool confirm; STATIC uint16_t long_write_handle = 0x0000; STATIC uint8_t* long_write_value = NULL; @@ -75,7 +75,11 @@ STATIC void send_error(uint16_t conn_handle, uint8_t opcode, uint16_t handle, ui 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[]) { +STATIC void send_req(uint16_t conn_handle, size_t request_length, uint8_t* request_buffer) { + hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, request_length, request_buffer); +} + +STATIC int send_req_wait_for_rsp(uint16_t conn_handle, size_t 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. @@ -83,7 +87,7 @@ STATIC int send_req_wait_for_rsp(uint16_t conn_handle, int request_length, uint expected_rsp.buffer = response_buffer; expected_rsp.length = 0; - hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, request_length, request_buffer); + send_req(conn_handle, request_length, request_buffer); if (response_buffer == NULL) { // not expecting a response. @@ -450,7 +454,7 @@ void att_add_connection(uint16_t handle, uint8_t role, bt_addr_le_t *peer_addr, bleio_connections[peer_index].conn_handle = handle; bleio_connections[peer_index].role = role; - bleio_connections[peer_index].mtu = 23; + bleio_connections[peer_index].mtu = BT_ATT_DEFAULT_LE_MTU; memcpy(&bleio_connections[peer_index].addr, peer_addr, sizeof(bleio_connections[peer_index].addr)); //FIX if (event_handlers[BLEConnected]) { @@ -506,7 +510,7 @@ void att_remove_connection(uint16_t handle, uint8_t reason) { 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; + bleio_connections[peer_index].mtu = BT_ATT_DEFAULT_LE_MTU; //FIX if (bleio_connections[peer_index].device) { //FIX delete bleio_connections[peer_index].device; @@ -569,7 +573,7 @@ uint16_t att_mtu(uint16_t handle) { } } - return 23; + return BT_ATT_DEFAULT_LE_MTU; } bool att_disconnect_all(void) { @@ -590,7 +594,7 @@ bool att_disconnect_all(void) { 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; + bleio_connections[i].mtu = BT_ATT_DEFAULT_LE_MTU; //FIX // if (bleio_connections[i].device) { @@ -645,7 +649,7 @@ bool att_handle_notify(uint16_t handle, const uint8_t* value, int length) { return (num_notifications > 0); } -bool att_handle_ind(uint16_t handle, const uint8_t* value, int length) { +bool att_handle_indicate(uint16_t handle, const uint8_t* value, int length) { int num_indications = 0; for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { @@ -666,11 +670,11 @@ bool att_handle_ind(uint16_t handle, const uint8_t* value, int length) { memcpy(&indication[indication_length], value, length); indication_length += length; - cnf = false; + confirm = false; hci_send_acl_pkt(bleio_connections[i].conn_handle, BT_L2CAP_CID_ATT, indication_length, indication); - while (!cnf) { + while (!confirm) { hci_poll_for_incoming_pkt(); if (!att_address_is_connected(&bleio_connections[i].addr)) { @@ -1214,7 +1218,7 @@ int att_read_by_type_req(uint16_t conn_handle, uint16_t start_handle, uint16_t e 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[]) { +STATIC void process_read_by_type_rsp(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { if (dlen < 1) { return; // invalid, drop } @@ -1223,8 +1227,10 @@ void att_read_by_type_rsp(uint16_t conn_handle, uint8_t dlen, uint8_t 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); +STATIC void process_write_req_or_cmd(uint16_t conn_handle, uint16_t mtu, uint8_t op, uint8_t dlen, uint8_t data[]) { + // struct bt_att_write_cmd is identical, so don't bother to split code paths based on opcode. + //FIX REMOVE this later struct bt_att_write_req *req = (struct bt_att_write_req *) data; + bool with_response = (op == BT_ATT_OP_WRITE_REQ); if (dlen < sizeof(struct bt_att_write_req)) { if (with_response) { @@ -1233,24 +1239,23 @@ STATIC void process_req_or_cmd(uint16_t conn_handle, uint16_t mtu, uint8_t op, u return; } - uint16_t handle = *(uint16_t*)data; - - // if ((uint16_t)(handle - 1) > GATT.attributeCount()) { + //FIX why cast? + // if ((uint16_t)(req->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)]; + // uint8_t value_length = dlen - sizeof(req->handle); + // uint8_t* value = &data[sizeof(req->handle)]; - // BLELocalAttribute* attribute = GATT.attribute(handle - 1); + // BLELocalAttribute* attribute = GATT.attribute(req->handle - 1); // if (attribute->type() == BLE_TYPE_CHARACTERISTIC) { // BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute; - // if (handle != characteristic->value_handle() || + // if (req->handle != characteristic->value_handle() || // withResponse ? ((characteristic->properties() & BLEWrite) == 0) : // ((characteristic->properties() & BLEWriteWithoutResponse) == 0)) { // if (withResponse) { @@ -1301,7 +1306,7 @@ STATIC void process_req_or_cmd(uint16_t conn_handle, uint16_t mtu, uint8_t op, u // return; // } - if (withResponse) { + if (with_response) { uint8_t response[mtu]; uint16_t response_length; @@ -1320,88 +1325,85 @@ STATIC void process_write_rsp(uint16_t conn_handle, uint8_t dlen, uint8_t data[] 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; +STATIC void process_prepare_write_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, uint8_t data[]) { + //FIX struct bt_att_prepare_write_req *req = (struct bt_att_prepare_write_req *) data; - if (dlen < sizeof(PrepWriteReq)) { - send_error(conn_handle, BT_ATT_OP_PREP_WRITE_REQ, 0x0000, BT_ATT_ERR_INVALID_PDU); + if (dlen < sizeof(struct bt_att_prepare_write_req)) { + send_error(conn_handle, BT_ATT_OP_PREPARE_WRITE_REQ, 0x0000, BT_ATT_ERR_INVALID_PDU); return; } - uint16_t handle = prepWriteReq->handle; - uint16_t offset = prepWriteReq->offset; + // uint16_t handle = req->handle; + // uint16_t offset = req->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; - } + // if ((uint16_t)(handle - 1) > GATT.attributeCount()) { + // send_error(conn_handle, BT_ATT_OP_PREPARE_WRITE_REQ, handle, BT_ATT_ERR_ATTR_NOT_FOUND); + // return; + // } - BLELocalAttribute* attribute = GATT.attribute(handle - 1); + // 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; - } + // if (attribute->type() != BLE_TYPE_CHARACTERISTIC) { + // send_error(conn_handle, BT_ATT_OP_PREPARE_WRITE_REQ, handle, BT_ATT_ERR_ATTR_NOT_LONG); + // return; + // } - BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute; + // 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 (handle != characteristic->value_handle()) { + // send_error(conn_handle, BT_ATT_OP_PREPARE_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 ((characteristic->properties() & BLEWrqite) == 0) { + // send_error(conn_handle, BT_ATT_OP_PREPARE_WRITE_REQ, handle, BT_ATT_ERR_WRITE_NOT_PERM); + // return; + // } - if (long_write_handle == 0) { - int valueSize = characteristic->valueSize(); + // 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; + // 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; - } + // memset(long_write_value, 0x00, valueSize); + // } else if (long_write_handle != handle) { + // send_error(conn_handle, BT_ATT_OP_PREPARE_WRITE_REQ, handle, BT_ATT_ERR_UNLIKELY); + // return; + // } - uint8_t value_length = dlen - sizeof(PrepWriteReq); - uint8_t* value = &data[sizeof(PrepWriteReq)]; + // uint8_t value_length = dlen - sizeof(struct bt_att_prepare_write_req); + // uint8_t* value = &data[sizeof(struct bt_att_prepare_write_req)]; - 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; - } + // if ((offset != long_write_value_length) || ((offset + value_length) > (uint16_t)characteristic->valueSize())) { + // send_error(conn_handle, BT_ATT_OP_PREPARE_WRITE_REQ, handle, BT_ATT_ERR_INVALID_OFFSET); + // return; + // } - memcpy(long_write_value + offset, value, value_length); - long_write_value_length += value_length; + // memcpy(long_write_value + offset, value, value_length); + // long_write_value_length += value_length; - uint8_t response[mtu]; - uint16_t response_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; + // 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); + // 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)) { + struct bt_att_exec_write_req *req = (struct bt_att_exec_write_req *) data; + + if (dlen != sizeof(struct bt_att_exec_write_req)) { 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); + if (long_write_handle && (req->flags & 0x01)) { + //FIX 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) { @@ -1423,107 +1425,123 @@ STATIC void process_exec_write_req(uint16_t conn_handle, uint16_t mtu, uint8_t d 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[]) { +STATIC void process_handle_notify_or_indicate(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; + // struct bt_att_notify and bt_att_indicate are identical. + //FIXunused struct bt_att_notify *req = (struct bt_att_notify *) data; - uint8_t handle = handleNotifyOrInd->handle; + //FIXunused uint8_t handle = req->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; + //FIX BLERemoteDevice* device = bleio_connections[i].device; - if (!device) { - break; - } + // if (!device) { + // break; + // } - int serviceCount = device->serviceCount(); + // int serviceCount = device->serviceCount(); - for (size_t i = 0; i < serviceCount; i++) { - BLERemoteService* s = device->service(i); + // 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(); + // 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); + // 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); - } - } + // if (c->value_handle() == handle) { + // //FIX c->writeValue(BLEDevice(bleio_connections[i].address_type, bleio_connections[i].address), &data[2], dlen - 2); + // } + // } - break; - } - } + // break; + // } + // } } - if (opcode == BT_ATT_OP_HANDLE_IND) { - // send CNF for IND + if (opcode == BT_ATT_OP_INDICATE) { + // send CONFIRM for INDICATE - uint8_t cnf = BT_ATT_OP_HANDLE_CNF; + uint8_t op_confirm = BT_ATT_OP_CONFIRM; - hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, sizeof(cnf), &cnf); + hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, sizeof(op_confirm), &op_confirm); } } -STATIC void process_handle_cnf(uint16_t /*conn_handle*/, uint8_t /*dlen*/, uint8_t /*data*/[]) { - cnf = true; +STATIC void process_handle_confirm(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { + (void) conn_handle; + (void) dlen; + (void) data; + + confirm = 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); + struct bt_att_exchange_mtu_req req = { + .mtu = max_mtu, + }; + return send_req_wait_for_rsp(conn_handle, sizeof(req), (uint8_t *) &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; - } -} +//FIX 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 }; + struct __packed { + struct bt_att_hdr h; + struct bt_att_read_req r; + } req = { { + .code = BT_ATT_OP_READ_REQ, + }, { + .handle = handle, + } + }; - return send_req_wait_for_rsp(conn_handle, &read_req, sizeof(read_req), response_buffer); + return send_req_wait_for_rsp(conn_handle, sizeof(req), (uint8_t *) &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; + struct __packed { + struct bt_att_hdr h; + struct bt_att_write_req r; + } req = { { + .code = BT_ATT_OP_WRITE_REQ, + }, { + .handle = handle, + } + }; + memcpy(req.r.value, data, data_len); - 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); + return send_req_wait_for_rsp(conn_handle, sizeof(req) + data_len, (uint8_t *) &req, 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, + struct __packed { + struct bt_att_hdr h; + struct bt_att_write_cmd r; + } req = { { + .code = BT_ATT_OP_WRITE_CMD, + }, { + .handle = handle, + } }; - memcpy(req.value, data, data_len); + memcpy(req.r.value, data, data_len); - send_req_wait_for_rsp(conn_handle, &req, data_len + sizeof(req), NULL); + return send_req(conn_handle, sizeof(req) + data_len, (uint8_t *) &req); } void att_process_data(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { @@ -1534,7 +1552,7 @@ void att_process_data(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { dlen--; data++; - uint16_t mtu = this->mtu(conn_handle); + uint16_t mtu = att_mtu(conn_handle); switch (opcode) { case BT_ATT_OP_ERROR_RSP: @@ -1557,24 +1575,24 @@ void att_process_data(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { process_find_info_rsp(conn_handle, dlen, data); break; - case BT_ATT_OP_FIND_BY_TYPE_REQ: + case BT_ATT_OP_FIND_TYPE_REQ: process_find_by_type_req(conn_handle, mtu, dlen, data); break; - case BT_ATT_OP_READ_BY_TYPE_REQ: + case BT_ATT_OP_READ_TYPE_REQ: process_read_by_type_req(conn_handle, mtu, dlen, data); break; - case BT_ATT_OP_READ_BY_TYPE_RSP: + case BT_ATT_OP_READ_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); + case BT_ATT_OP_READ_GROUP_REQ: + process_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); + case BT_ATT_OP_READ_GROUP_RSP: + process_read_by_group_rsp(conn_handle, dlen, data); break; case BT_ATT_OP_READ_REQ: @@ -1595,27 +1613,27 @@ void att_process_data(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { process_write_rsp(conn_handle, dlen, data); break; - case BT_ATT_OP_PREP_WRITE_REQ: - process_prep_write_req(conn_handle, mtu, dlen, data); + case BT_ATT_OP_PREPARE_WRITE_REQ: + process_prepare_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); + case BT_ATT_OP_NOTIFY: + case BT_ATT_OP_INDICATE: + process_handle_notify_or_indicate(conn_handle, opcode, dlen, data); break; - case BT_ATT_OP_HANDLE_CNF: - process_handle_cnf(conn_handle, dlen, data); + case BT_ATT_OP_CONFIRM: + process_handle_confirm(conn_handle, dlen, data); break; - case BT_ATT_OP_READ_MULTI_REQ: + case BT_ATT_OP_READ_MULT_REQ: case BT_ATT_OP_SIGNED_WRITE_CMD: default: - send_error(conn_handle, opcode, 0x00, BT_ATT_ERR_REQ_NOT_SUPP); + send_error(conn_handle, opcode, 0x00, BT_ATT_ERR_NOT_SUPPORTED); break; } } diff --git a/devices/ble_hci/common-hal/_bleio/att.h b/devices/ble_hci/common-hal/_bleio/att.h index 108c44929f..ee01e33f60 100644 --- a/devices/ble_hci/common-hal/_bleio/att.h +++ b/devices/ble_hci/common-hal/_bleio/att.h @@ -39,7 +39,7 @@ 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_indicate(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); From 0619966c19bb9aeba7ec4fc19562878ca77e15ab Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 28 Jul 2020 14:28:09 -0400 Subject: [PATCH 16/84] wip --- devices/ble_hci/common-hal/_bleio/Service.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/devices/ble_hci/common-hal/_bleio/Service.c b/devices/ble_hci/common-hal/_bleio/Service.c index 07a9b4de25..938f687119 100644 --- a/devices/ble_hci/common-hal/_bleio/Service.c +++ b/devices/ble_hci/common-hal/_bleio/Service.c @@ -44,6 +44,7 @@ uint32_t _common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uu uint32_t status; self->handle = bleio_adapter_add_attribute( + common_hal_bleio_adapter_obj, is_secondary ? BLE_TYPE_SECONDARY_SERVICE : BLE_TYPE_PRIMARY_SERVICE, uuid, &status); return status; @@ -82,9 +83,10 @@ 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) { - common_hal_bleio_adapter_obj + //FIX how it's done by ArduinoBLE when a service is added. - // uint16_t startHandle = attributeCount(); + // uint16_t startHandle = attributeCount(); + uint16_t start_handle bleio_adapter_num_attributes(common_hal_bleio_adapter_obj); // for (unsigned int i = 0; i < service->characteristicCount(); i++) { // BLELocalCharacteristic* characteristic = service->characteristic(i); From e6bd99a5ee1e2ada3ad99e1de429c13e1b9d47cf Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 28 Jul 2020 18:18:41 -0400 Subject: [PATCH 17/84] wip --- devices/ble_hci/common-hal/_bleio/Adapter.h | 2 -- devices/ble_hci/common-hal/_bleio/Attribute.c | 4 ++++ devices/ble_hci/common-hal/_bleio/Service.c | 1 - 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.h b/devices/ble_hci/common-hal/_bleio/Adapter.h index d2f38b757c..9ff122d26a 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.h +++ b/devices/ble_hci/common-hal/_bleio/Adapter.h @@ -43,8 +43,6 @@ extern bleio_connection_internal_t bleio_connections[BLEIO_TOTAL_CONNECTION_COUNT]; - - typedef struct _bleio_adapter_obj_t { mp_obj_base_t base; bleio_scanresults_obj_t *scan_results; diff --git a/devices/ble_hci/common-hal/_bleio/Attribute.c b/devices/ble_hci/common-hal/_bleio/Attribute.c index 30a0ebcf05..d9041da717 100644 --- a/devices/ble_hci/common-hal/_bleio/Attribute.c +++ b/devices/ble_hci/common-hal/_bleio/Attribute.c @@ -26,6 +26,10 @@ #include "shared-bindings/_bleio/Attribute.h" +// Return the type of the attribute +bleio_attribute_type_uuid(mp_obj_t *attribute) { + if mp_is_o + // 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) { diff --git a/devices/ble_hci/common-hal/_bleio/Service.c b/devices/ble_hci/common-hal/_bleio/Service.c index 938f687119..ef2de6ee7d 100644 --- a/devices/ble_hci/common-hal/_bleio/Service.c +++ b/devices/ble_hci/common-hal/_bleio/Service.c @@ -42,7 +42,6 @@ uint32_t _common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uu vm_used_ble = true; - uint32_t status; self->handle = bleio_adapter_add_attribute( common_hal_bleio_adapter_obj, is_secondary ? BLE_TYPE_SECONDARY_SERVICE : BLE_TYPE_PRIMARY_SERVICE, From a76ad3415c6aeae7bb9c915f20220d32001e8094 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 30 Jul 2020 22:07:55 -0400 Subject: [PATCH 18/84] wip: implementing functionality --- devices/ble_hci/common-hal/_bleio/Adapter.c | 24 +++ devices/ble_hci/common-hal/_bleio/Adapter.h | 7 + devices/ble_hci/common-hal/_bleio/Attribute.c | 20 ++- devices/ble_hci/common-hal/_bleio/Attribute.h | 11 +- .../common-hal/_bleio/Characteristic.c | 129 +++---------- .../common-hal/_bleio/Characteristic.h | 1 + devices/ble_hci/common-hal/_bleio/Service.c | 106 ++++------- devices/ble_hci/common-hal/_bleio/__init__.c | 4 + devices/ble_hci/common-hal/_bleio/att.c | 169 +++++++++--------- devices/ble_hci/common-hal/_bleio/att.h | 4 +- devices/ble_hci/common-hal/_bleio/hci.h | 1 + 11 files changed, 206 insertions(+), 270 deletions(-) diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index 6c94bb1a92..2e1baea041 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.c +++ b/devices/ble_hci/common-hal/_bleio/Adapter.c @@ -240,7 +240,12 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable self->advertising_timeout_msecs = 0; // Reset list of known attributes. + // Indices into the list are handles. Handle 0x0000 designates an invalid handle, + // so store None there to skip it. self->attributes = mp_obj_new_list(0, NULL); + bleio_adapter_add_attribute(mp_const_none); + self->last_added_service_handle = BLE_GATT_HANDLE_INVALID; + self->last_added_characteristic_handle = BLE_GATT_HANDLE_INVALID; } bool common_hal_bleio_adapter_get_enabled(bleio_adapter_obj_t *self) { @@ -683,6 +688,25 @@ void common_hal_bleio_adapter_erase_bonding(bleio_adapter_obj_t *self) { //FIX bonding_erase_storage(); } +uint16_t bleio_adapter_add_attribute(bleio_adapter_obj_t *adapter, mp_obj_t *attribute) { + // The handle is the index of this attribute in the attributes list. + uint16_t handle = (uint16_t) adapter->attributes->len; + mp_obj_list_append(adapter->attributes, attribute); + return handle; +} + +mp_obj_t* bleio_adapter_get_attribute(bleio_adapter_obj_t *adapter, uint16_t handle) { + if (handle == 0 || handle >= adapter->attributes->len) { + return mp_const_none; + } + return adapter->attributes->items[handle]; +} + +uint16_t bleio_adapter_max_attribute_handle(bleio_adapter_obj_t *adapter) { + return adapter->attributes->len - 1; +} + + void bleio_adapter_gc_collect(bleio_adapter_obj_t* adapter) { gc_collect_root((void**)adapter, sizeof(bleio_adapter_obj_t) / sizeof(size_t)); gc_collect_root((void**)bleio_connections, sizeof(bleio_connections) / sizeof(size_t)); diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.h b/devices/ble_hci/common-hal/_bleio/Adapter.h index 9ff122d26a..1fae5f6829 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.h +++ b/devices/ble_hci/common-hal/_bleio/Adapter.h @@ -68,8 +68,15 @@ typedef struct _bleio_adapter_obj_t { // All the local attributes for this device. The index into the list // corresponds to the handle. mp_obj_list_t *attributes; + // Handle for last added service. Characteristics can only be added immediately after + // the service they belong to. This vets that. + uint16_t last_added_service_handle; + uint16_t last_added_characteristic_handle; } bleio_adapter_obj_t; +uint16_t bleio_adapter_add_attribute(bleio_adapter_obj_t *adapter, mp_obj_t *attribute); +mp_obj_t* bleio_adapter_get_attribute(bleio_adapter_obj_t *adapter, uint16_t handle); +uint16_t bleio_adapter_max_attribute_handle(bleio_adapter_obj_t *adapter); void bleio_adapter_background(bleio_adapter_obj_t* adapter); void bleio_adapter_gc_collect(bleio_adapter_obj_t* adapter); void bleio_adapter_reset(bleio_adapter_obj_t* adapter); diff --git a/devices/ble_hci/common-hal/_bleio/Attribute.c b/devices/ble_hci/common-hal/_bleio/Attribute.c index d9041da717..0c56c08a88 100644 --- a/devices/ble_hci/common-hal/_bleio/Attribute.c +++ b/devices/ble_hci/common-hal/_bleio/Attribute.c @@ -25,10 +25,24 @@ */ #include "shared-bindings/_bleio/Attribute.h" +#include "shared-bindings/_bleio/Characteristic.h" +#include "shared-bindings/_bleio/Descriptor.h" +#include "shared-bindings/_bleio/Service.h" -// Return the type of the attribute -bleio_attribute_type_uuid(mp_obj_t *attribute) { - if mp_is_o +// Return the type of the attribute. +ble_attribute_type bleio_attribute_type_uuid(mp_obj_t *attribute) { + if (MP_OBJ_IS_TYPE(attribute, &bleio_characteristic_type)) { + return BLE_TYPE_CHARACTERISTIC; + } + if (MP_OBJ_IS_TYPE(attribute, &bleio_descriptor_type)) { + return BLE_TYPE_DESCRIPTOR; + } + if (MP_OBJ_IS_TYPE(attribute, &bleio_service_type)) { + bleio_service_obj_t *service = MP_OBJ_TO_PTR(attribute); + return service->is_secondary ? BLE_TYPE_SECONDARY_SERVICE : BLE_TYPE_PRIMARY_SERVICE; + } + return BLE_TYPE_UNKNOWN; +} // 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) { diff --git a/devices/ble_hci/common-hal/_bleio/Attribute.h b/devices/ble_hci/common-hal/_bleio/Attribute.h index f527bcf740..5ad2142d3e 100644 --- a/devices/ble_hci/common-hal/_bleio/Attribute.h +++ b/devices/ble_hci/common-hal/_bleio/Attribute.h @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * Copyright (c) 2020 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 @@ -29,6 +29,15 @@ #include "shared-module/_bleio/Attribute.h" +// Types returned by attribute table lookups. These are UUIDs. +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 +}; + // typedef struct // { // uint8_t sm : 4; /**< Security Mode (1 or 2), 0 for no permissions at all. */ diff --git a/devices/ble_hci/common-hal/_bleio/Characteristic.c b/devices/ble_hci/common-hal/_bleio/Characteristic.c index 74cbede0eb..1c678b7617 100644 --- a/devices/ble_hci/common-hal/_bleio/Characteristic.c +++ b/devices/ble_hci/common-hal/_bleio/Characteristic.c @@ -34,58 +34,10 @@ #include "common-hal/_bleio/Adapter.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); -// } -// } - 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; - //FIX self->handle = BLE_GATT_HANDLE_INVALID; + self->handle = BLE_GATT_HANDLE_INVALID; self->props = props; self->read_perm = read_perm; self->write_perm = write_perm; @@ -153,30 +105,23 @@ void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, // Always write the value locally even if no connections are active. // conn_handle is ignored for non-system attributes, so we use BLE_CONN_HANDLE_INVALID. common_hal_bleio_gatts_write(self->handle, BLE_CONN_HANDLE_INVALID, bufinfo); - // Check to see if we need to notify or indicate any active connections. - 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 (conn_handle == BLE_CONN_HANDLE_INVALID) { - continue; - } + // Notify or indicate all active connections. + uint16_t cccd = 0; - //FIX - // uint16_t cccd = 0; + const bool notify = self->props & CHAR_PROP_NOTIFY; + const bool indicate = self->props & CHAR_PROP_INDICATE; + // Read the CCCD value, if there is one. + if ((notify | indicate) && self->cccd_handle != BLE_GATT_HANDLE_INVALID) { + common_hal_bleio_gatts_read(self->cccd_handle, conn_handle, &cccd, sizeof(cccd)); + } - // 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)) { + att_notify(self->handle, bufinfo->buf, MIN(bufinfo->len, self->max_length)); + } + if (indicate && (cccd & BLE_GATT_HVX_INDICATION)) { + att_indicate(self->handle, bufinfo->buf, MIN(bufinfo->len, self->max_length)); - // // 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); - // } } } } @@ -191,35 +136,16 @@ 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) { - //FIX - // ble_uuid_t desc_uuid; - // bleio_uuid_convert_to_nrf_ble_uuid(descriptor->uuid, &desc_uuid); + if (self->handle != common_hal_bleio_adapter_obj->last_added_characteristic_handle) { + mp_raise_bleio_BluetoothError( + translate("Descriptor can only be added to most recently added characteristic")); + } - // 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, - // }; + descriptor->handle = bleio_adapter_add_attribute(common_hal_bleio_adapter_obj, descriptor); - // 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; + // Link together all the descriptors for this characteristic. + 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,11 +160,12 @@ 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); - //FIX - // uint16_t cccd_value = - // (notify ? BLE_GATT_HVX_NOTIFICATION : 0) | - // (indicate ? BLE_GATT_HVX_INDICATION : 0); + uint16_t cccd_value = + (notify ? BLE_GATT_HVX_NOTIFICATION : 0) | + (indicate ? BLE_GATT_HVX_INDICATION : 0); + (void) cccd_value; + //FIX call att_something to set remote CCCD // ble_gattc_write_params_t write_params = { // .write_op = BLE_GATT_OP_WRITE_REQ, // .handle = self->cccd_handle, diff --git a/devices/ble_hci/common-hal/_bleio/Characteristic.h b/devices/ble_hci/common-hal/_bleio/Characteristic.h index 4d5fa02f05..7887afdfba 100644 --- a/devices/ble_hci/common-hal/_bleio/Characteristic.h +++ b/devices/ble_hci/common-hal/_bleio/Characteristic.h @@ -43,6 +43,7 @@ typedef struct _bleio_characteristic_obj { uint16_t max_length; bool fixed_length; uint16_t handle; + uint16_t value_handle; // Should be handle+1. bleio_characteristic_properties_t props; bleio_attribute_security_mode_t read_perm; bleio_attribute_security_mode_t write_perm; diff --git a/devices/ble_hci/common-hal/_bleio/Service.c b/devices/ble_hci/common-hal/_bleio/Service.c index ef2de6ee7d..696b8b943e 100644 --- a/devices/ble_hci/common-hal/_bleio/Service.c +++ b/devices/ble_hci/common-hal/_bleio/Service.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2020 Dan Halbert for Adafruit Industries * Copyright (c) 2018 Artur Pacholec * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -33,7 +33,6 @@ #include "shared-bindings/_bleio/Adapter.h" uint32_t _common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uuid_obj_t *uuid, bool is_secondary, mp_obj_list_t * characteristic_list) { - self->handle = 0xFFFF; self->uuid = uuid; self->characteristic_list = characteristic_list; self->is_remote = false; @@ -42,16 +41,18 @@ uint32_t _common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uu vm_used_ble = true; - self->handle = bleio_adapter_add_attribute( - common_hal_bleio_adapter_obj, - is_secondary ? BLE_TYPE_SECONDARY_SERVICE : BLE_TYPE_PRIMARY_SERVICE, - uuid, &status); - return status; + self->handle = bleio_adapter_add_attribute(common_hal_bleio_adapter_obj, self); + if (self->handle = BLE_GATT_HANDLE_INVALID) { + return 1; + } + return 0; } void common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uuid_obj_t *uuid, bool is_secondary) { - check_hci_error(_common_hal_bleio_service_construct(self, uuid, is_secondary, - mp_obj_new_list(0, NULL))); + if (_common_hal_bleio_service_construct(self, uuid, is_secondary, + mp_obj_new_list(0, NULL)) != 0) { + mp_raise_RuntimeError(translate("Failed to add service")); + } } void bleio_service_from_connection(bleio_service_obj_t *self, mp_obj_t connection) { @@ -83,83 +84,36 @@ void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *initial_value_bufinfo) { - //FIX how it's done by ArduinoBLE when a service is added. - // uint16_t startHandle = attributeCount(); - uint16_t start_handle bleio_adapter_num_attributes(common_hal_bleio_adapter_obj); + if (self->handle != common_hal_bleio_adapter_obj->last_added_service_handle) { + mp_raise_bleio_BluetoothError( + translate("Characteristic can only be added to most recently added service")); + } + characteristic->decl_handle = bleio_adapter_add_attribute(common_hal_bleio_adapter_obj, characteristic); + // This is the value handle + characteristic->value_handle = bleio_adapter_add_attribute(common_hal_bleio_adapter_obj, characteristic); - // for (unsigned int i = 0; i < service->characteristicCount(); i++) { - // BLELocalCharacteristic* characteristic = service->characteristic(i); + if (characteristic->props & (CHAR_PROP_NOTIFY | CHAR_PROP_INDICATE)) { + // We need a CCCD. + bleio_descriptor_obj_t *cccd = m_new_obj(bleio_descriptor_obj_t); + cccd->base.type = &bleio_descriptor_type; + cccd->read_perm = SECURITY_MODE_OPEN; + // Make CCCD write permission match characteristic read permission. + cccd->write_perm = characteristic->read_perm; + characteristic->cccd_handle = common_hal_bleio_characteristic_add_descriptor(characteristic, cccd); + } - // characteristic->retain(); - // _attributes.add(characteristic); - // characteristic->setHandle(attributeCount()); - - // // add the characteristic again to make space of the characteristic value handle - // _attributes.add(characteristic); - - // for (unsigned int j = 0; j < characteristic->descriptorCount(); j++) { - // BLELocalDescriptor* descriptor = characteristic->descriptor(j); - - // descriptor->retain(); - // _attributes.add(descriptor); - // descriptor->setHandle(attributeCount()); - // } - // } - - service->setHandles(startHandle, attributeCount()); - // 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_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, - // }; + // These are not supplied or available. + characteristic->user_desc_handle = BLE_GATT_HANDLE_INVALID; + characteristic->sccd_handle = BLE_GATT_HANDLE_INVALID; - // 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)); + mp_obj_list_append(self->characteristic_list, MP_OBJ_FROM_PTR(characteristic)); } diff --git a/devices/ble_hci/common-hal/_bleio/__init__.c b/devices/ble_hci/common-hal/_bleio/__init__.c index 07aaee747e..c647190994 100644 --- a/devices/ble_hci/common-hal/_bleio/__init__.c +++ b/devices/ble_hci/common-hal/_bleio/__init__.c @@ -63,6 +63,10 @@ void check_hci_error(hci_result_t result) { mp_raise_bleio_BluetoothError(translate("Error writing to HCI adapter")); return; + case HCI_ATT_ERROR: + mp_raise_RuntimeError(translate("Error in ATT protocol code")); + return; + default: // Should be an HCI status error, > 0. if (result > 0) { diff --git a/devices/ble_hci/common-hal/_bleio/att.c b/devices/ble_hci/common-hal/_bleio/att.c index ad1dddca22..013a517378 100644 --- a/devices/ble_hci/common-hal/_bleio/att.c +++ b/devices/ble_hci/common-hal/_bleio/att.c @@ -30,22 +30,15 @@ #include "py/obj.h" #include "common-hal/_bleio/Adapter.h" +#include "common-hal/_bleio/Attribute.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 confirm; -STATIC uint16_t long_write_handle = 0x0000; +STATIC uint16_t long_write_handle = BLE_GATT_HANDLE_INVALID; STATIC uint8_t* long_write_value = NULL; STATIC uint16_t long_write_value_length = 0; @@ -123,7 +116,7 @@ STATIC void check_and_save_expected_rsp(uint16_t conn_handle, uint8_t opcode, ui void att_init(void) { max_mtu = BT_ATT_DEFAULT_LE_MTU; timeout = 5000; - long_write_handle = 0x0000; + long_write_handle = BLE_GATT_HANDLE_INVALID; long_write_value = NULL; long_write_value_length = 0; @@ -225,12 +218,12 @@ bool att_disconnect_from_address(bt_addr_le_t *addr) { // reqStart_handle = rawService->end_handle + 1; -// if (reqStart_handle == 0x0000) { -// reqEnd_handle = 0x0000; +// if (reqStart_handle == BLE_GATT_HANDLE_INVALID) { +// reqEnd_handle = BLE_GATT_HANDLE_INVALID; // } // } // } else { -// reqEnd_handle = 0x0000; +// reqEnd_handle = BLE_GATT_HANDLE_INVALID; // } // } @@ -498,7 +491,7 @@ void att_remove_connection(uint16_t handle, uint8_t reason) { // } // } - long_write_handle = 0x0000; + long_write_handle = BLE_GATT_HANDLE_INVALID; long_write_value_length = 0; } @@ -619,7 +612,7 @@ bool att_disconnect_all(void) { // return BLEDevice(); // } -bool att_handle_notify(uint16_t handle, const uint8_t* value, int length) { +bool att_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++) { @@ -627,21 +620,20 @@ bool att_handle_notify(uint16_t handle, const uint8_t* value, int length) { 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; + typedef struct notify_t __packed { + struct bt_att_hdr hdr; + struct bt_att_notify ntf; + }; - notification[0] = BT_ATT_OP_NOTIFY; - notification_length++; + size_t allowed_length = MIN((uint16_t)(bleio_connections[i].mtu - sizeof(notify_t)), (uint16_t)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); + uint8_t notify_bytes[sizeof(cmd_s) + allowed_length]; + notify_t *notify_p = (notify_t *) notify_bytes; + notify_p->hdr.code = BT_ATT_OP_NOTIFY;; + notify_p->ntf.handle = handle; + memcpy(notify_p->ntf.value, data, allowed_length); + hci_send_acl_pkt(bleio_connections[i].conn_handle, BT_L2CAP_CID_ATT, + size_of(notify_bytes), notify_bytes); num_notifications++; } @@ -649,7 +641,7 @@ bool att_handle_notify(uint16_t handle, const uint8_t* value, int length) { return (num_notifications > 0); } -bool att_handle_indicate(uint16_t handle, const uint8_t* value, int length) { +bool att_indicate(conn_handle, uint16_t handle, const uint8_t* value, int length) { int num_indications = 0; for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { @@ -657,22 +649,23 @@ bool att_handle_indicate(uint16_t handle, const uint8_t* value, int length) { continue; } - uint8_t indication[bleio_connections[i].mtu]; - uint16_t indication_length = 0; + typedef struct indicate_t __packed { + struct bt_att_hdr hdr; + struct bt_att_indicate ind; + }; - indication[0] = BT_ATT_OP_INDICATE; - indication_length++; + size_t allowed_length = MIN((uint16_t)(bleio_connections[i].mtu - sizeof(indicate_t)), (uint16_t)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; + uint8_t indicate_bytes[sizeof(cmd_s) + allowed_length]; + struct indicate_s *indicate_p = (indicate_s *) indicate_bytes; + indicate_p->hdr.code = BT_ATT_OP_INDICATE;; + indicate_p->ind.handle = handle; + memcpy(indicate->ind.value, data, allowed_length); confirm = false; - hci_send_acl_pkt(bleio_connections[i].conn_handle, BT_L2CAP_CID_ATT, indication_length, indication); + hci_send_acl_pkt(bleio_connections[i].conn_handle, BT_L2CAP_CID_ATT, + sizeof(indicate_bytes), indicate_bytes); while (!confirm) { hci_poll_for_incoming_pkt(); @@ -706,7 +699,7 @@ STATIC void process_error(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { 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); + send_error(conn_handle, BT_ATT_OP_MTU_REQ, BLE_GATT_HANDLE_INVALID, BT_ATT_ERR_INVALID_PDU); return; } @@ -983,7 +976,7 @@ STATIC void process_read_or_read_blob_req(uint16_t conn_handle, uint16_t mtu, ui 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); + send_error(conn_handle, BT_ATT_OP_READ_REQ, BLE_GATT_HANDLE_INVALID, BT_ATT_ERR_INVALID_PDU); return; } @@ -993,7 +986,7 @@ STATIC void process_read_or_read_blob_req(uint16_t conn_handle, uint16_t mtu, ui } 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); + send_error(conn_handle, BT_ATT_OP_READ_BLOB_REQ, BLE_GATT_HANDLE_INVALID, BT_ATT_ERR_INVALID_PDU); return; } @@ -1234,7 +1227,7 @@ STATIC void process_write_req_or_cmd(uint16_t conn_handle, uint16_t mtu, uint8_t 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); + send_error(conn_handle, BT_ATT_OP_WRITE_REQ, BLE_GATT_HANDLE_INVALID, BT_ATT_ERR_INVALID_PDU); } return; } @@ -1326,41 +1319,41 @@ STATIC void process_write_rsp(uint16_t conn_handle, uint8_t dlen, uint8_t data[] } STATIC void process_prepare_write_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, uint8_t data[]) { - //FIX struct bt_att_prepare_write_req *req = (struct bt_att_prepare_write_req *) data; + FIX struct bt_att_prepare_write_req *req = (struct bt_att_prepare_write_req *) data; if (dlen < sizeof(struct bt_att_prepare_write_req)) { - send_error(conn_handle, BT_ATT_OP_PREPARE_WRITE_REQ, 0x0000, BT_ATT_ERR_INVALID_PDU); + send_error(conn_handle, BT_ATT_OP_PREPARE_WRITE_REQ, BLE_GATT_HANDLE_INVALID, BT_ATT_ERR_INVALID_PDU); return; } - // uint16_t handle = req->handle; - // uint16_t offset = req->offset; + uint16_t handle = req->handle; + uint16_t offset = req->offset; - // if ((uint16_t)(handle - 1) > GATT.attributeCount()) { - // send_error(conn_handle, BT_ATT_OP_PREPARE_WRITE_REQ, handle, BT_ATT_ERR_ATTR_NOT_FOUND); - // return; - // } + if (handle > bleio_adapter_max_attribute_handle(common_hal_bleio_adapter_obj)) { + send_error(conn_handle, BT_ATT_OP_PREPARE_WRITE_REQ, handle, BT_ATT_ERR_ATTR_NOT_FOUND); + return; + } - // BLELocalAttribute* attribute = GATT.attribute(handle - 1); + mp_obj_t *attribute = bleio_adapter_get_attribute(common_hal_bleio_adapter_obj, handle); - // if (attribute->type() != BLE_TYPE_CHARACTERISTIC) { - // send_error(conn_handle, BT_ATT_OP_PREPARE_WRITE_REQ, handle, BT_ATT_ERR_ATTR_NOT_LONG); - // return; - // } + if (!MP_OBJ_IS_TYPE(attribute, &bleio_characteristic_type)) { + send_error(conn_handle, BT_ATT_OP_PREPARE_WRITE_REQ, handle, BT_ATT_ERR_ATTR_NOT_LONG); + return; + } - // BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute; + bleio_characteristic_obj_t* characteristic = MP_OBJ_TO_PTR(attribute); - // if (handle != characteristic->value_handle()) { - // send_error(conn_handle, BT_ATT_OP_PREPARE_WRITE_REQ, handle, BT_ATT_ERR_ATTR_NOT_LONG); - // return; - // } + if (handle != characteristic->value_handle) { + send_error(conn_handle, BT_ATT_OP_PREPARE_WRITE_REQ, handle, BT_ATT_ERR_ATTR_NOT_LONG); + return; + } - // if ((characteristic->properties() & BLEWrqite) == 0) { - // send_error(conn_handle, BT_ATT_OP_PREPARE_WRITE_REQ, handle, BT_ATT_ERR_WRITE_NOT_PERM); - // return; - // } + if (characteristic->props & CHAR_PROP_WRITE) { + send_error(conn_handle, BT_ATT_OP_PREPARE_WRITE_REQ, handle, BT_ATT_ERR_WRITE_NOT_PERM); + return; + } - // if (long_write_handle == 0) { + if (long_write_handle == BLE_GATT_HANDLE_INVALID) // int valueSize = characteristic->valueSize(); // long_write_value = (uint8_t*)realloc(long_write_value, valueSize); @@ -1398,7 +1391,7 @@ STATIC void process_exec_write_req(uint16_t conn_handle, uint16_t mtu, uint8_t d struct bt_att_exec_write_req *req = (struct bt_att_exec_write_req *) data; if (dlen != sizeof(struct bt_att_exec_write_req)) { - send_error(conn_handle, BT_ATT_OP_EXEC_WRITE_REQ, 0x0000, BT_ATT_ERR_INVALID_PDU); + send_error(conn_handle, BT_ATT_OP_EXEC_WRITE_REQ, BLE_GATT_HANDLE_INVALID, BT_ATT_ERR_INVALID_PDU); return; } @@ -1413,7 +1406,7 @@ STATIC void process_exec_write_req(uint16_t conn_handle, uint16_t mtu, uint8_t d } } - long_write_handle = 0x0000; + long_write_handle = BLE_GATT_HANDLE_INVALID; long_write_value_length = 0; uint8_t response[mtu]; @@ -1515,33 +1508,35 @@ 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[]) { - struct __packed { - struct bt_att_hdr h; - struct bt_att_write_req r; - } req = { { - .code = BT_ATT_OP_WRITE_REQ, - }, { - .handle = handle, - } + typedef struct write_req_t __packed { + struct bt_att_hdr hdr; + struct bt_att_write_req req; }; - memcpy(req.r.value, data, data_len); - return send_req_wait_for_rsp(conn_handle, sizeof(req) + data_len, (uint8_t *) &req, response_buffer); + uint8_t req_bytes[sizeof(write_req_t) + data_len]; + struct write_req_t *write_req_P = (write_req_t *) req_bytes; + req_p->hdr.code = BT_ATT_OP_WRITE_REQ; + req_p->req.handle = handle; + memcpy(req_p->req.value, data, data_len); + + memcpy(req.req.value, data, data_len); + + return send_req_wait_for_rsp(conn_handle, sizeof(req_bytes), req, response_buffer); } void att_write_cmd(uint16_t conn_handle, uint16_t handle, const uint8_t* data, uint8_t data_len) { - struct __packed { + struct cmd_s __packed { struct bt_att_hdr h; struct bt_att_write_cmd r; - } req = { { - .code = BT_ATT_OP_WRITE_CMD, - }, { - .handle = handle, - } }; - memcpy(req.r.value, data, data_len); - return send_req(conn_handle, sizeof(req) + data_len, (uint8_t *) &req); + uint8_t cmd_bytes[sizeof(cmd_s) + data_len]; + struct cmd_s *cmd_p = (cmd_s *) cmd_bytes; + cmd_p->h.code = BT_ATT_OP_WRITE_CMD; + cmd_p->r.handle = handle; + memcpy(cmd_p->r.value, data, data_len); + + return send_cmd(conn_handle, sizeof(cmd_bytes), cmd_bytes); } void att_process_data(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { diff --git a/devices/ble_hci/common-hal/_bleio/att.h b/devices/ble_hci/common-hal/_bleio/att.h index ee01e33f60..6cf9b305b2 100644 --- a/devices/ble_hci/common-hal/_bleio/att.h +++ b/devices/ble_hci/common-hal/_bleio/att.h @@ -39,10 +39,10 @@ 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_indicate(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_indicate(uint16_t handle, const uint8_t* value, int length); bool att_is_connected(void); +bool att_notify(uint16_t handle, const uint8_t* value, int length); 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); diff --git a/devices/ble_hci/common-hal/_bleio/hci.h b/devices/ble_hci/common-hal/_bleio/hci.h index 736877ddc6..89a2b3304a 100644 --- a/devices/ble_hci/common-hal/_bleio/hci.h +++ b/devices/ble_hci/common-hal/_bleio/hci.h @@ -37,6 +37,7 @@ typedef int hci_result_t; #define HCI_WRITE_TIMEOUT (-3) #define HCI_READ_ERROR (-4) #define HCI_WRITE_ERROR (-5) +#define HCI_ATT_ERROR (-6) void hci_init(void); From fea1cad02cba369f3b9c0da8da5829a5066fc318 Mon Sep 17 00:00:00 2001 From: sabas1080 Date: Sat, 1 Aug 2020 17:51:45 -0500 Subject: [PATCH 19/84] add support for Bast Wifi Electronic Cats --- .github/workflows/build.yml | 1 + .../boards/electroniccats_bastwifi/pins.c | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 406f6c43ba..aa743f87b6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -384,6 +384,7 @@ jobs: - "espressif_saola_1_wroom" - "espressif_saola_1_wrover" - "unexpectedmaker_feathers2" + - "electroniccats_bastwifi" steps: - name: Set up Python 3.8 diff --git a/ports/esp32s2/boards/electroniccats_bastwifi/pins.c b/ports/esp32s2/boards/electroniccats_bastwifi/pins.c index 1d4e2c4eba..0b19346455 100644 --- a/ports/esp32s2/boards/electroniccats_bastwifi/pins.c +++ b/ports/esp32s2/boards/electroniccats_bastwifi/pins.c @@ -2,12 +2,19 @@ STATIC const mp_rom_map_elem_t board_global_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO0) }, { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO1) }, { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO2) }, { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO3) }, { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_GPIO4) }, { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO5) }, { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_A6), MP_ROM_PTR(&pin_GPIO6) }, { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) }, { MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) }, @@ -18,6 +25,8 @@ STATIC const mp_rom_map_elem_t board_global_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_IO14), MP_ROM_PTR(&pin_GPIO14) }, { MP_ROM_QSTR(MP_QSTR_IO15), MP_ROM_PTR(&pin_GPIO15) }, { MP_ROM_QSTR(MP_QSTR_IO16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO16) }, { MP_ROM_QSTR(MP_QSTR_IO17), MP_ROM_PTR(&pin_GPIO17) }, @@ -31,6 +40,14 @@ STATIC const mp_rom_map_elem_t board_global_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_IO35), MP_ROM_PTR(&pin_GPIO35) }, { MP_ROM_QSTR(MP_QSTR_IO36), MP_ROM_PTR(&pin_GPIO36) }, { MP_ROM_QSTR(MP_QSTR_IO37), MP_ROM_PTR(&pin_GPIO37) }, + + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO36) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_CS), MP_ROM_PTR(&pin_GPIO11) }, + + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_IO38), MP_ROM_PTR(&pin_GPIO38) }, { MP_ROM_QSTR(MP_QSTR_IO39), MP_ROM_PTR(&pin_GPIO39) }, { MP_ROM_QSTR(MP_QSTR_IO40), MP_ROM_PTR(&pin_GPIO40) }, @@ -42,5 +59,9 @@ STATIC const mp_rom_map_elem_t board_global_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_IO44), MP_ROM_PTR(&pin_GPIO44) }, { MP_ROM_QSTR(MP_QSTR_IO45), MP_ROM_PTR(&pin_GPIO45) }, { MP_ROM_QSTR(MP_QSTR_IO46), MP_ROM_PTR(&pin_GPIO46) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, }; MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table); From b074f8a1618e765307f01ac99bd7a37f0663cf68 Mon Sep 17 00:00:00 2001 From: sabas1080 Date: Sun, 2 Aug 2020 00:42:36 -0500 Subject: [PATCH 20/84] update for build test --- .github/workflows/build.yml | 2 +- ports/esp32s2/boards/electroniccats_bastwifi/pins.c | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index aa743f87b6..435dae2bb2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -381,10 +381,10 @@ jobs: fail-fast: false matrix: board: + - "electroniccats_bastwifi" - "espressif_saola_1_wroom" - "espressif_saola_1_wrover" - "unexpectedmaker_feathers2" - - "electroniccats_bastwifi" steps: - name: Set up Python 3.8 diff --git a/ports/esp32s2/boards/electroniccats_bastwifi/pins.c b/ports/esp32s2/boards/electroniccats_bastwifi/pins.c index 0b19346455..2f9987b0ed 100644 --- a/ports/esp32s2/boards/electroniccats_bastwifi/pins.c +++ b/ports/esp32s2/boards/electroniccats_bastwifi/pins.c @@ -40,14 +40,11 @@ STATIC const mp_rom_map_elem_t board_global_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_IO35), MP_ROM_PTR(&pin_GPIO35) }, { MP_ROM_QSTR(MP_QSTR_IO36), MP_ROM_PTR(&pin_GPIO36) }, { MP_ROM_QSTR(MP_QSTR_IO37), MP_ROM_PTR(&pin_GPIO37) }, - { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO37) }, { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO36) }, { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO35) }, { MP_ROM_QSTR(MP_QSTR_CS), MP_ROM_PTR(&pin_GPIO11) }, - { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO14) }, - { MP_ROM_QSTR(MP_QSTR_IO38), MP_ROM_PTR(&pin_GPIO38) }, { MP_ROM_QSTR(MP_QSTR_IO39), MP_ROM_PTR(&pin_GPIO39) }, { MP_ROM_QSTR(MP_QSTR_IO40), MP_ROM_PTR(&pin_GPIO40) }, From 0e30fe1cc56ae48b1e1ea4b4ef07ffdfdf928fc4 Mon Sep 17 00:00:00 2001 From: sabas1080 Date: Sun, 2 Aug 2020 19:54:11 -0500 Subject: [PATCH 21/84] Update VID & PID codes --- ports/esp32s2/boards/electroniccats_bastwifi/mpconfigboard.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/esp32s2/boards/electroniccats_bastwifi/mpconfigboard.mk b/ports/esp32s2/boards/electroniccats_bastwifi/mpconfigboard.mk index 4a2e8ecd8a..6a6ae7937e 100644 --- a/ports/esp32s2/boards/electroniccats_bastwifi/mpconfigboard.mk +++ b/ports/esp32s2/boards/electroniccats_bastwifi/mpconfigboard.mk @@ -1,5 +1,5 @@ -USB_VID = 0x239A -USB_PID = 0x80A6 +USB_VID = 0x1209 +USB_PID = 0xBAB0 USB_PRODUCT = "Bast WiFi" USB_MANUFACTURER = "ElectronicCats" From a995a5c58fa4c231fcfb8c5e0eb6a3847faabbcc Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 3 Aug 2020 21:02:57 -0400 Subject: [PATCH 22/84] wip: partial discovery responses; compiles; not tested --- devices/ble_hci/common-hal/_bleio/Adapter.c | 60 ++++ devices/ble_hci/common-hal/_bleio/Attribute.c | 2 +- devices/ble_hci/common-hal/_bleio/Attribute.h | 4 +- devices/ble_hci/common-hal/_bleio/att.c | 117 +++--- devices/ble_hci/common-hal/_bleio/hci.c | 123 ++----- devices/ble_hci/common-hal/_bleio/hci_debug.c | 335 ++++++++++++++++++ ports/atmel-samd/Makefile | 2 +- 7 files changed, 496 insertions(+), 147 deletions(-) create mode 100644 devices/ble_hci/common-hal/_bleio/hci_debug.c diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index 3acae9bebb..c8147fbc1b 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.c +++ b/devices/ble_hci/common-hal/_bleio/Adapter.c @@ -43,6 +43,8 @@ #include "shared-bindings/_bleio/__init__.h" #include "shared-bindings/_bleio/Adapter.h" #include "shared-bindings/_bleio/Address.h" +#include "shared-bindings/_bleio/Characteristic.h" +#include "shared-bindings/_bleio/Service.h" #include "shared-bindings/nvm/ByteArray.h" #include "shared-bindings/_bleio/Connection.h" #include "shared-bindings/_bleio/ScanEntry.h" @@ -70,6 +72,12 @@ bleio_connection_internal_t bleio_connections[BLEIO_TOTAL_CONNECTION_COUNT]; +STATIC void check_enabled(bleio_adapter_obj_t *adapter) { + if (!common_hal_bleio_adapter_get_enabled(adapter)) { + mp_raise_bleio_BluetoothError(translate("Adapter not enabled")); + } +} + // 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; @@ -232,6 +240,14 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable self->enabled = enabled; + // We must poll for input from the HCI adapter. + // TODO Can we instead trigger an interrupt on UART input traffic? + if (enabled) { + supervisor_enable_tick(); + } else { + supervisor_disable_tick(); + } + // Stop any current activity; reset to known state. check_hci_error(hci_reset()); self->now_advertising = false; @@ -253,6 +269,8 @@ 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) { + check_enabled(self); + bt_addr_t addr; check_hci_error(hci_read_bd_addr(&addr)); @@ -306,6 +324,8 @@ void common_hal_bleio_adapter_set_name(bleio_adapter_obj_t *self, const char* na // } mp_obj_t common_hal_bleio_adapter_start_scan(bleio_adapter_obj_t *self, uint8_t* prefixes, size_t prefix_length, bool extended, mp_int_t buffer_size, mp_float_t timeout, mp_float_t interval, mp_float_t window, mp_int_t minimum_rssi, bool active) { + check_enabled(self); + if (self->scan_results != NULL) { if (!shared_module_bleio_scanresults_get_done(self->scan_results)) { mp_raise_bleio_BluetoothError(translate("Scan already in progess. Stop with stop_scan.")); @@ -350,6 +370,8 @@ mp_obj_t common_hal_bleio_adapter_start_scan(bleio_adapter_obj_t *self, uint8_t* } void common_hal_bleio_adapter_stop_scan(bleio_adapter_obj_t *self) { + check_enabled(self); + check_hci_error(hci_le_set_scan_enable(BT_HCI_LE_SCAN_DISABLE, BT_HCI_LE_SCAN_FILTER_DUP_DISABLE)); shared_module_bleio_scanresults_set_done(self->scan_results, true); self->scan_results = NULL; @@ -385,6 +407,8 @@ void common_hal_bleio_adapter_stop_scan(bleio_adapter_obj_t *self) { mp_obj_t common_hal_bleio_adapter_connect(bleio_adapter_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout) { + check_enabled(self); + // ble_gap_addr_t addr; // addr.addr_type = address->type; @@ -482,6 +506,8 @@ STATIC void check_data_fit(size_t data_len, bool connectable) { // } uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, bool connectable, bool anonymous, uint32_t timeout, float interval, uint8_t *advertising_data, uint16_t advertising_data_len, uint8_t *scan_response_data, uint16_t scan_response_data_len) { + check_enabled(self); + if (self->now_advertising) { if (self->circuitpython_advertising) { common_hal_bleio_adapter_stop_advertising(self); @@ -603,6 +629,8 @@ uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, } void common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, bool connectable, bool anonymous, uint32_t timeout, mp_float_t interval, mp_buffer_info_t *advertising_data_bufinfo, mp_buffer_info_t *scan_response_data_bufinfo) { + check_enabled(self); + // interval value has already been validated. check_data_fit(advertising_data_bufinfo->len, connectable); @@ -638,6 +666,8 @@ void common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, bool } void common_hal_bleio_adapter_stop_advertising(bleio_adapter_obj_t *self) { + check_enabled(self); + self->now_advertising = false; self->extended_advertising = false; self->circuitpython_advertising = false; @@ -651,10 +681,14 @@ void common_hal_bleio_adapter_stop_advertising(bleio_adapter_obj_t *self) { } bool common_hal_bleio_adapter_get_advertising(bleio_adapter_obj_t *self) { + check_enabled(self); + return self->now_advertising; } bool common_hal_bleio_adapter_get_connected(bleio_adapter_obj_t *self) { + check_enabled(self); + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { bleio_connection_internal_t *connection = &bleio_connections[i]; if (connection->conn_handle != BLE_CONN_HANDLE_INVALID) { @@ -665,6 +699,8 @@ bool common_hal_bleio_adapter_get_connected(bleio_adapter_obj_t *self) { } mp_obj_t common_hal_bleio_adapter_get_connections(bleio_adapter_obj_t *self) { + check_enabled(self); + if (self->connection_objs != NULL) { return self->connection_objs; } @@ -685,17 +721,31 @@ 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) { + check_enabled(self); + //FIX bonding_erase_storage(); } uint16_t bleio_adapter_add_attribute(bleio_adapter_obj_t *adapter, mp_obj_t *attribute) { + check_enabled(adapter); + // The handle is the index of this attribute in the attributes list. uint16_t handle = (uint16_t) adapter->attributes->len; mp_obj_list_append(adapter->attributes, attribute); + + if (MP_OBJ_IS_TYPE(attribute, &bleio_service_type)) { + adapter->last_added_service_handle = handle; + } + if (MP_OBJ_IS_TYPE(attribute, &bleio_characteristic_type)) { + adapter->last_added_characteristic_handle = handle; + } + return handle; } mp_obj_t* bleio_adapter_get_attribute(bleio_adapter_obj_t *adapter, uint16_t handle) { + check_enabled(adapter); + if (handle == 0 || handle >= adapter->attributes->len) { return mp_const_none; } @@ -703,6 +753,8 @@ mp_obj_t* bleio_adapter_get_attribute(bleio_adapter_obj_t *adapter, uint16_t han } uint16_t bleio_adapter_max_attribute_handle(bleio_adapter_obj_t *adapter) { + check_enabled(adapter); + return adapter->attributes->len - 1; } @@ -713,6 +765,10 @@ void bleio_adapter_gc_collect(bleio_adapter_obj_t* adapter) { } void bleio_adapter_reset(bleio_adapter_obj_t* adapter) { + if (!common_hal_bleio_adapter_get_enabled(adapter)) { + return; + } + common_hal_bleio_adapter_stop_scan(adapter); if (adapter->now_advertising) { common_hal_bleio_adapter_stop_advertising(adapter); @@ -731,6 +787,10 @@ void bleio_adapter_reset(bleio_adapter_obj_t* adapter) { } void bleio_adapter_background(bleio_adapter_obj_t* adapter) { + if (!common_hal_bleio_adapter_get_enabled(adapter)) { + return; + } + if (adapter->advertising_timeout_msecs > 0 && supervisor_ticks_ms64() - adapter->advertising_start_ticks > adapter->advertising_timeout_msecs) { adapter->advertising_timeout_msecs = 0; diff --git a/devices/ble_hci/common-hal/_bleio/Attribute.c b/devices/ble_hci/common-hal/_bleio/Attribute.c index 0c56c08a88..d32ed11679 100644 --- a/devices/ble_hci/common-hal/_bleio/Attribute.c +++ b/devices/ble_hci/common-hal/_bleio/Attribute.c @@ -30,7 +30,7 @@ #include "shared-bindings/_bleio/Service.h" // Return the type of the attribute. -ble_attribute_type bleio_attribute_type_uuid(mp_obj_t *attribute) { +ble_attribute_type_uuid bleio_attribute_type_uuid(mp_obj_t *attribute) { if (MP_OBJ_IS_TYPE(attribute, &bleio_characteristic_type)) { return BLE_TYPE_CHARACTERISTIC; } diff --git a/devices/ble_hci/common-hal/_bleio/Attribute.h b/devices/ble_hci/common-hal/_bleio/Attribute.h index 4301614fca..47327437bc 100644 --- a/devices/ble_hci/common-hal/_bleio/Attribute.h +++ b/devices/ble_hci/common-hal/_bleio/Attribute.h @@ -36,7 +36,7 @@ typedef enum { BLE_TYPE_SECONDARY_SERVICE = 0x2801, BLE_TYPE_CHARACTERISTIC = 0x2803, BLE_TYPE_DESCRIPTOR = 0x2900 -} ble_attribute_type; +} ble_attribute_type_uuid; // typedef struct // { @@ -45,6 +45,6 @@ typedef enum { // } 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); +ble_attribute_type_uuid bleio_attribute_type_uuid(mp_obj_t *attribute); #endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_ATTRIBUTE_H diff --git a/devices/ble_hci/common-hal/_bleio/att.c b/devices/ble_hci/common-hal/_bleio/att.c index 2982861f76..08324c37ed 100644 --- a/devices/ble_hci/common-hal/_bleio/att.c +++ b/devices/ble_hci/common-hal/_bleio/att.c @@ -33,6 +33,7 @@ #include "common-hal/_bleio/Attribute.h" #include "shared-bindings/_bleio/__init__.h" #include "shared-bindings/_bleio/Characteristic.h" +#include "shared-bindings/_bleio/UUID.h" #include "supervisor/shared/tick.h" STATIC uint16_t max_mtu = BT_ATT_DEFAULT_LE_MTU; // 23 @@ -685,6 +686,7 @@ bool att_indicate(uint16_t handle, const uint8_t* value, int length) { 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; @@ -700,7 +702,8 @@ STATIC void process_error(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { 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)) { + + if (dlen != sizeof(struct bt_att_exchange_mtu_req)) { send_error(conn_handle, BT_ATT_OP_MTU_REQ, BLE_GATT_HANDLE_INVALID, BT_ATT_ERR_INVALID_PDU); return; } @@ -720,7 +723,7 @@ STATIC void process_mtu_req(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) struct __packed { struct bt_att_hdr h; - struct bt_att_exchange_mtu_req r; + struct bt_att_exchange_mtu_rsp r; } rsp = { { .code = BT_ATT_OP_MTU_RSP, }, { @@ -732,12 +735,12 @@ STATIC void process_mtu_req(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) } STATIC void process_mtu_rsp(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { + struct bt_att_exchange_mtu_rsp *rsp = (struct bt_att_exchange_mtu_rsp *) 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; @@ -879,69 +882,82 @@ STATIC void process_find_by_type_req(uint16_t conn_handle, uint16_t mtu, uint8_t 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); + uint16_t type_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)) { + if (dlen != sizeof(struct bt_att_read_group_req) + sizeof(type_uuid) || + (type_uuid != BLE_TYPE_PRIMARY_SERVICE && + type_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; + typedef struct __packed { + struct bt_att_hdr h; + struct bt_att_read_group_rsp r; + } rsp_t; - response[0] = BT_ATT_OP_READ_GROUP_RSP; - response[1] = 0x00; - response_length = 2; + uint8_t rsp_bytes[mtu]; + rsp_t *rsp = (rsp_t *) &rsp_bytes; + rsp->h.code = BT_ATT_OP_READ_GROUP_RSP; + rsp->r.len = 0; - // FIX - // for (uint16_t i = (readByGroupReq->start_handle - 1); i < GATT.attributeCount() && i <= (readByGroupReq->end_handle - 1); i++) { - //FIX - // BLELocalAttribute* attribute = GATT.attribute(i); + // Keeps track of total length of the response. + size_t rsp_length = sizeof(rsp_t); - // if (readByGroupReq->uuid != attribute->type()) { - // // not the type - // continue; - // } + bool no_data = true; - // int uuidLen = attribute->uuidLength(); - // size_t infoSize = (uuidLen == 2) ? 6 : 20; + // All the data chunks must have uuid's that are the same size. + // Keep track fo the first one to make sure. + size_t sizeof_first_service_uuid = 0; + const uint16_t max_attribute_handle = bleio_adapter_max_attribute_handle(&common_hal_bleio_adapter_obj); + for (uint16_t handle = req->start_handle; + handle <= max_attribute_handle && handle <= req->end_handle; + handle++) { + no_data = false; - // if (response[1] == 0) { - // response[1] = infoSize; - // } + mp_obj_t *attribute_obj = bleio_adapter_get_attribute(&common_hal_bleio_adapter_obj, handle); + if (type_uuid != bleio_attribute_type_uuid(attribute_obj)) { + // Not a primary or secondary service. + continue; + } + // Now we know it's a service. + bleio_service_obj_t *service = MP_OBJ_TO_PTR(attribute_obj); - // if (response[1] != infoSize) { - // // different size - // break; - // } + // Is this a 16-bit or a 128-bit uuid? It must match in size with any previous attribute + // in this transmission. + const uint8_t sizeof_service_uuid = common_hal_bleio_uuid_get_size(service->uuid) / 8; + if (sizeof_first_service_uuid == 0) { + sizeof_first_service_uuid = sizeof_service_uuid; + } else if (sizeof_first_service_uuid != sizeof_service_uuid) { + // Mismatched sizes. Transmit just what we have so far in this batch. + break; + } - // BLELocalService* service = (BLELocalService*)attribute; + // Size of bt_att_group_data chunk with uuid. + const uint16_t data_length = sizeof(struct bt_att_group_data) + sizeof_service_uuid; - // // 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); + if (rsp_length + data_length > mtu) { + // No room for another bt_att_group_data chunk. + break; + } - // // 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); + // Pass the length of ONE bt_att_group_data chunk. There may be multiple ones in this transmission. + rsp->r.len = data_length; - // // add the UUID - // memcpy(&response[response_length], service->uuidData(), uuidLen); - // response_length += uuidLen; + uint8_t group_data_bytes[data_length]; + struct bt_att_group_data *group_data = (struct bt_att_group_data *) group_data_bytes; - // if ((response_length + infoSize) > mtu) { - // break; - // } - // } + group_data->start_handle = service->start_handle; + group_data->end_handle = service->end_handle; + common_hal_bleio_uuid_pack_into(service->uuid, group_data->value); - if (response_length == 2) { + rsp_length += data_length; + } + + if (no_data) { 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); + hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, rsp_length, rsp_bytes); } } @@ -986,7 +1002,7 @@ STATIC void process_read_or_read_blob_req(uint16_t conn_handle, uint16_t mtu, ui handle = req->handle; response_opcode = BT_ATT_OP_READ_RSP; - } else { + } else if (opcode == BT_ATT_OP_READ_BLOB_REQ) { if (dlen != sizeof(struct bt_att_read_blob_req)) { send_error(conn_handle, BT_ATT_OP_READ_BLOB_REQ, BLE_GATT_HANDLE_INVALID, BT_ATT_ERR_INVALID_PDU); return; @@ -996,8 +1012,11 @@ STATIC void process_read_or_read_blob_req(uint16_t conn_handle, uint16_t mtu, ui handle = req->handle; offset = req->offset; response_opcode = BT_ATT_OP_READ_BLOB_RSP; + } else { + return; } + //FIX (void) offset; (void) handle; diff --git a/devices/ble_hci/common-hal/_bleio/hci.c b/devices/ble_hci/common-hal/_bleio/hci.c index 9c8d7f692a..7b4adaa79a 100644 --- a/devices/ble_hci/common-hal/_bleio/hci.c +++ b/devices/ble_hci/common-hal/_bleio/hci.c @@ -95,7 +95,6 @@ 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. @@ -107,77 +106,13 @@ STATIC uint8_t* cmd_response_data; STATIC volatile bool hci_poll_in_progress = false; -STATIC bool debug = true; +#define DEBUG_HCI 1 ////////////////////////////////////////////////////////////////////// -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"); - } -} +#if DEBUG_HCI +#include "hci_debug.c" +#endif // DEBUG_HCI 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; @@ -194,7 +129,7 @@ STATIC void process_acl_data_pkt(uint8_t pkt_len, uint8_t pkt_data[]) { } acl_data_t *acl = (acl_data_t *) &acl_data_buffer; - if (acl_data_len != acl->acl_data_len) { + if (acl_data_len != sizeof(acl) + acl->acl_data_len) { // We don't have the full packet yet. return; } @@ -330,9 +265,9 @@ STATIC void process_evt_pkt(size_t pkt_len, uint8_t pkt_data[]) } default: - if (debug) { - mp_printf(&mp_plat_print, "process_evt_pkt: Unknown event: %02x\n"); - } +#if DEBUG_HCI + mp_printf(&mp_plat_print, "process_evt_pkt: Unknown event: %02x\n"); +#endif break; } } @@ -374,7 +309,8 @@ hci_result_t hci_poll_for_incoming_pkt(void) { bool packet_is_complete = false; // Read bytes until we run out, or accumulate a complete packet. - while (common_hal_busio_uart_rx_characters_available(common_hal_bleio_adapter_obj.hci_uart)) { + while (!packet_is_complete && + common_hal_busio_uart_rx_characters_available(common_hal_bleio_adapter_obj.hci_uart)) { common_hal_busio_uart_read(common_hal_bleio_adapter_obj.hci_uart, rx_buffer + rx_idx, 1, &errcode); if (errcode) { hci_poll_in_progress = false; @@ -417,25 +353,25 @@ hci_result_t hci_poll_for_incoming_pkt(void) { switch (rx_buffer[0]) { case H4_ACL: - if (debug) { - dump_acl_pkt(false, pkt_len, rx_buffer); - } +#if DEBUG_HCI + dump_acl_pkt(false, pkt_len, rx_buffer); +#endif process_acl_data_pkt(pkt_len, rx_buffer); break; case H4_EVT: - if (debug) { - dump_evt_pkt(false, pkt_len, rx_buffer); - } +#if DEBUG_HCI + dump_evt_pkt(false, pkt_len, rx_buffer); +#endif 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]); - } +#if DEBUG_HCI + mp_printf(&mp_plat_print, "Unknown HCI packet type: %d\n", rx_buffer[0]); +#endif break; } @@ -478,9 +414,9 @@ STATIC hci_result_t send_command(uint16_t opcode, uint8_t params_len, void* para memcpy(cmd_pkt->params, params, params_len); - if (debug) { +#if DEBUG_HCI dump_cmd_pkt(true, sizeof(tx_buffer), tx_buffer); - } +#endif int result = write_pkt(tx_buffer, cmd_pkt_len); if (result != HCI_OK) { @@ -519,32 +455,31 @@ STATIC hci_result_t send_command(uint16_t opcode, uint8_t params_len, void* para 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) { + while (pending_pkt >= common_hal_bleio_adapter_obj.max_acl_num_buffers) { 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; + const size_t buf_len = sizeof(h4_hci_acl_pkt_t) + sizeof(acl_data_t) + 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_pkt->pb = ACL_DATA_PB_FIRST_FLUSH; + acl_pkt->data_len = (uint8_t)(sizeof(acl_data_t) + data_len); + acl_data->acl_data_len = data_len; acl_data->cid = cid; - memcpy(&tx_buffer[sizeof(h4_hci_acl_pkt_t)], data, data_len); + memcpy(&acl_data->acl_data, data, data_len); - if (debug) { +#if DEBUG_HCI dump_acl_pkt(true, buf_len, tx_buffer); - } +#endif pending_pkt++; diff --git a/devices/ble_hci/common-hal/_bleio/hci_debug.c b/devices/ble_hci/common-hal/_bleio/hci_debug.c new file mode 100644 index 0000000000..8231bc5cc1 --- /dev/null +++ b/devices/ble_hci/common-hal/_bleio/hci_debug.c @@ -0,0 +1,335 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 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. + */ + +// This file is #include'd in hci.c when HCI_DEBUG is non-zero. + +STATIC const char* att_opcode_name(uint16_t opcode) { + switch (opcode) { + case BT_ATT_OP_ERROR_RSP: return "ERROR_RSP"; + case BT_ATT_OP_MTU_REQ: return "MTU_REQ"; + case BT_ATT_OP_MTU_RSP: return "MTU_RSP"; + case BT_ATT_OP_FIND_INFO_REQ: return "FIND_INFO_REQ"; + case BT_ATT_OP_FIND_INFO_RSP: return "FIND_INFO_RSP"; + case BT_ATT_OP_FIND_TYPE_REQ: return "FIND_TYPE_REQ"; + case BT_ATT_OP_FIND_TYPE_RSP: return "FIND_TYPE_RSP"; + case BT_ATT_OP_READ_TYPE_REQ: return "READ_TYPE_REQ"; + case BT_ATT_OP_READ_TYPE_RSP: return "READ_TYPE_RSP"; + case BT_ATT_OP_READ_REQ: return "READ_REQ"; + case BT_ATT_OP_READ_RSP: return "READ_RSP"; + case BT_ATT_OP_READ_BLOB_REQ: return "READ_BLOB_REQ"; + case BT_ATT_OP_READ_BLOB_RSP: return "READ_BLOB_RSP"; + case BT_ATT_OP_READ_MULT_REQ: return "READ_MULT_REQ"; + case BT_ATT_OP_READ_MULT_RSP: return "READ_MULT_RSP"; + case BT_ATT_OP_READ_GROUP_REQ: return "READ_GROUP_REQ"; + case BT_ATT_OP_READ_GROUP_RSP: return "READ_GROUP_RSP"; + case BT_ATT_OP_WRITE_REQ: return "WRITE_REQ"; + case BT_ATT_OP_WRITE_RSP: return "WRITE_RSP"; + case BT_ATT_OP_PREPARE_WRITE_REQ: return "PREPARE_WRITE_REQ"; + case BT_ATT_OP_PREPARE_WRITE_RSP: return "PREPARE_WRITE_RSP"; + case BT_ATT_OP_EXEC_WRITE_REQ: return "EXEC_WRITE_REQ"; + case BT_ATT_OP_EXEC_WRITE_RSP: return "EXEC_WRITE_RSP"; + case BT_ATT_OP_NOTIFY: return "NOTIFY"; + case BT_ATT_OP_INDICATE: return "INDICATE"; + case BT_ATT_OP_CONFIRM: return "CONFIRM"; + case BT_ATT_OP_READ_MULT_VL_REQ: return "READ_MULT_VL_REQ"; + case BT_ATT_OP_READ_MULT_VL_RSP: return "READ_MULT_VL_RSP"; + case BT_ATT_OP_NOTIFY_MULT: return "NOTIFY_MULT"; + case BT_ATT_OP_WRITE_CMD: return "WRITE_CMD"; + case BT_ATT_OP_SIGNED_WRITE_CMD: return "SIGNED_WRITE_CMD"; + default: return ""; + } +} + +STATIC const char* hci_evt_name(uint8_t evt) { + switch (evt) { + case BT_HCI_EVT_UNKNOWN: return "UNKNOWN"; + case BT_HCI_EVT_VENDOR: return "VENDOR"; + case BT_HCI_EVT_INQUIRY_COMPLETE: return "INQUIRY_COMPLETE"; + case BT_HCI_EVT_CONN_COMPLETE: return "CONN_COMPLETE"; + case BT_HCI_EVT_CONN_REQUEST: return "CONN_REQUEST"; + case BT_HCI_EVT_DISCONN_COMPLETE: return "DISCONN_COMPLETE"; + case BT_HCI_EVT_AUTH_COMPLETE: return "AUTH_COMPLETE"; + case BT_HCI_EVT_REMOTE_NAME_REQ_COMPLETE: return "REMOTE_NAME_REQ_COMPLETE"; + case BT_HCI_EVT_ENCRYPT_CHANGE: return "ENCRYPT_CHANGE"; + case BT_HCI_EVT_REMOTE_FEATURES: return "REMOTE_FEATURES"; + case BT_HCI_EVT_REMOTE_VERSION_INFO: return "REMOTE_VERSION_INFO"; + case BT_HCI_EVT_CMD_COMPLETE: return "CMD_COMPLETE"; + case BT_HCI_EVT_CMD_STATUS: return "CMD_STATUS"; + case BT_HCI_EVT_ROLE_CHANGE: return "ROLE_CHANGE"; + case BT_HCI_EVT_NUM_COMPLETED_PACKETS: return "NUM_COMPLETED_PACKETS"; + case BT_HCI_EVT_PIN_CODE_REQ: return "PIN_CODE_REQ"; + case BT_HCI_EVT_LINK_KEY_REQ: return "LINK_KEY_REQ"; + case BT_HCI_EVT_LINK_KEY_NOTIFY: return "LINK_KEY_NOTIFY"; + case BT_HCI_EVT_DATA_BUF_OVERFLOW: return "DATA_BUF_OVERFLOW"; + case BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI: return "INQUIRY_RESULT_WITH_RSSI"; + case BT_HCI_EVT_REMOTE_EXT_FEATURES: return "REMOTE_EXT_FEATURES"; + case BT_HCI_EVT_SYNC_CONN_COMPLETE: return "SYNC_CONN_COMPLETE"; + case BT_HCI_EVT_EXTENDED_INQUIRY_RESULT: return "EXTENDED_INQUIRY_RESULT"; + case BT_HCI_EVT_ENCRYPT_KEY_REFRESH_COMPLETE: return "ENCRYPT_KEY_REFRESH_COMPLETE"; + case BT_HCI_EVT_IO_CAPA_REQ: return "IO_CAPA_REQ"; + case BT_HCI_EVT_IO_CAPA_RESP: return "IO_CAPA_RESP"; + case BT_HCI_EVT_USER_CONFIRM_REQ: return "USER_CONFIRM_REQ"; + case BT_HCI_EVT_USER_PASSKEY_REQ: return "USER_PASSKEY_REQ"; + case BT_HCI_EVT_SSP_COMPLETE: return "SSP_COMPLETE"; + case BT_HCI_EVT_USER_PASSKEY_NOTIFY: return "USER_PASSKEY_NOTIFY"; + case BT_HCI_EVT_LE_META_EVENT: return "LE_META_EVENT"; + case BT_HCI_EVT_AUTH_PAYLOAD_TIMEOUT_EXP: return "AUTH_PAYLOAD_TIMEOUT_EXP"; + default: return ""; + } +} + +STATIC const char* hci_evt_le_name(uint8_t evt_le) { + switch (evt_le) { + case BT_HCI_EVT_LE_CONN_COMPLETE: return "LE_CONN_COMPLETE"; + case BT_HCI_EVT_LE_ADVERTISING_REPORT: return "LE_ADVERTISING_REPORT"; + case BT_HCI_EVT_LE_CONN_UPDATE_COMPLETE: return "LE_CONN_UPDATE_COMPLETE"; + case BT_HCI_EVT_LE_LTK_REQUEST: return "LE_LTK_REQUEST"; + case BT_HCI_EVT_LE_CONN_PARAM_REQ: return "LE_CONN_PARAM_REQ"; + case BT_HCI_EVT_LE_DATA_LEN_CHANGE: return "LE_DATA_LEN_CHANGE"; + case BT_HCI_EVT_LE_P256_PUBLIC_KEY_COMPLETE: return "LE_P256_PUBLIC_KEY_COMPLETE"; + case BT_HCI_EVT_LE_GENERATE_DHKEY_COMPLETE: return "LE_GENERATE_DHKEY_COMPLETE"; + case BT_HCI_EVT_LE_ENH_CONN_COMPLETE: return "LE_ENH_CONN_COMPLETE"; + case BT_HCI_EVT_LE_DIRECT_ADV_REPORT: return "LE_DIRECT_ADV_REPORT"; + case BT_HCI_EVT_LE_PHY_UPDATE_COMPLETE: return "LE_PHY_UPDATE_COMPLETE"; + case BT_HCI_EVT_LE_EXT_ADVERTISING_REPORT: return "LE_EXT_ADVERTISING_REPORT"; + case BT_HCI_EVT_LE_PER_ADV_SYNC_ESTABLISHED: return "LE_PER_ADV_SYNC_ESTABLISHED"; + case BT_HCI_EVT_LE_PER_ADVERTISING_REPORT: return "LE_PER_ADVERTISING_REPORT"; + case BT_HCI_EVT_LE_PER_ADV_SYNC_LOST: return "LE_PER_ADV_SYNC_LOST"; + case BT_HCI_EVT_LE_SCAN_TIMEOUT: return "LE_SCAN_TIMEOUT"; + case BT_HCI_EVT_LE_ADV_SET_TERMINATED: return "LE_ADV_SET_TERMINATED"; + case BT_HCI_EVT_LE_SCAN_REQ_RECEIVED: return "LE_SCAN_REQ_RECEIVED"; + case BT_HCI_EVT_LE_CHAN_SEL_ALGO: return "LE_CHAN_SEL_ALGO"; + default: return ""; + } +} + +STATIC const char* hci_opcode_name(uint16_t opcode) { + switch (opcode) { + case BT_OP_NOP: return "NOP"; + case BT_HCI_OP_INQUIRY: return "INQUIRY"; + case BT_HCI_OP_INQUIRY_CANCEL: return "INQUIRY_CANCEL"; + case BT_HCI_OP_CONNECT: return "CONNECT"; + case BT_HCI_OP_DISCONNECT: return "DISCONNECT"; + case BT_HCI_OP_CONNECT_CANCEL: return "CONNECT_CANCEL"; + case BT_HCI_OP_ACCEPT_CONN_REQ: return "ACCEPT_CONN_REQ"; + case BT_HCI_OP_SETUP_SYNC_CONN: return "SETUP_SYNC_CONN"; + case BT_HCI_OP_ACCEPT_SYNC_CONN_REQ: return "ACCEPT_SYNC_CONN_REQ"; + case BT_HCI_OP_REJECT_CONN_REQ: return "REJECT_CONN_REQ"; + case BT_HCI_OP_LINK_KEY_REPLY: return "LINK_KEY_REPLY"; + case BT_HCI_OP_LINK_KEY_NEG_REPLY: return "LINK_KEY_NEG_REPLY"; + case BT_HCI_OP_PIN_CODE_REPLY: return "PIN_CODE_REPLY"; + case BT_HCI_OP_PIN_CODE_NEG_REPLY: return "PIN_CODE_NEG_REPLY"; + case BT_HCI_OP_AUTH_REQUESTED: return "AUTH_REQUESTED"; + case BT_HCI_OP_SET_CONN_ENCRYPT: return "SET_CONN_ENCRYPT"; + case BT_HCI_OP_REMOTE_NAME_REQUEST: return "REMOTE_NAME_REQUEST"; + case BT_HCI_OP_REMOTE_NAME_CANCEL: return "REMOTE_NAME_CANCEL"; + case BT_HCI_OP_READ_REMOTE_FEATURES: return "READ_REMOTE_FEATURES"; + case BT_HCI_OP_READ_REMOTE_EXT_FEATURES: return "READ_REMOTE_EXT_FEATURES"; + case BT_HCI_OP_READ_REMOTE_VERSION_INFO: return "READ_REMOTE_VERSION_INFO"; + case BT_HCI_OP_IO_CAPABILITY_REPLY: return "IO_CAPABILITY_REPLY"; + case BT_HCI_OP_USER_CONFIRM_REPLY: return "USER_CONFIRM_REPLY"; + case BT_HCI_OP_USER_CONFIRM_NEG_REPLY: return "USER_CONFIRM_NEG_REPLY"; + case BT_HCI_OP_USER_PASSKEY_REPLY: return "USER_PASSKEY_REPLY"; + case BT_HCI_OP_USER_PASSKEY_NEG_REPLY: return "USER_PASSKEY_NEG_REPLY"; + case BT_HCI_OP_IO_CAPABILITY_NEG_REPLY: return "IO_CAPABILITY_NEG_REPLY"; + case BT_HCI_OP_SET_EVENT_MASK: return "SET_EVENT_MASK"; + case BT_HCI_OP_RESET: return "RESET"; + case BT_HCI_OP_WRITE_LOCAL_NAME: return "WRITE_LOCAL_NAME"; + case BT_HCI_OP_WRITE_PAGE_TIMEOUT: return "WRITE_PAGE_TIMEOUT"; + case BT_HCI_OP_WRITE_SCAN_ENABLE: return "WRITE_SCAN_ENABLE"; + case BT_HCI_OP_READ_TX_POWER_LEVEL: return "READ_TX_POWER_LEVEL"; + case BT_HCI_OP_SET_CTL_TO_HOST_FLOW: return "SET_CTL_TO_HOST_FLOW"; + case BT_HCI_OP_HOST_BUFFER_SIZE: return "HOST_BUFFER_SIZE"; + case BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS: return "HOST_NUM_COMPLETED_PACKETS"; + case BT_HCI_OP_WRITE_INQUIRY_MODE: return "WRITE_INQUIRY_MODE"; + case BT_HCI_OP_WRITE_SSP_MODE: return "WRITE_SSP_MODE"; + case BT_HCI_OP_SET_EVENT_MASK_PAGE_2: return "SET_EVENT_MASK_PAGE_2"; + case BT_HCI_OP_LE_WRITE_LE_HOST_SUPP: return "LE_WRITE_LE_HOST_SUPP"; + case BT_HCI_OP_WRITE_SC_HOST_SUPP: return "WRITE_SC_HOST_SUPP"; + case BT_HCI_OP_READ_AUTH_PAYLOAD_TIMEOUT: return "READ_AUTH_PAYLOAD_TIMEOUT"; + case BT_HCI_OP_WRITE_AUTH_PAYLOAD_TIMEOUT: return "WRITE_AUTH_PAYLOAD_TIMEOUT"; + case BT_HCI_OP_READ_LOCAL_VERSION_INFO: return "READ_LOCAL_VERSION_INFO"; + case BT_HCI_OP_READ_SUPPORTED_COMMANDS: return "READ_SUPPORTED_COMMANDS"; + case BT_HCI_OP_READ_LOCAL_EXT_FEATURES: return "READ_LOCAL_EXT_FEATURES"; + case BT_HCI_OP_READ_LOCAL_FEATURES: return "READ_LOCAL_FEATURES"; + case BT_HCI_OP_READ_BUFFER_SIZE: return "READ_BUFFER_SIZE"; + case BT_HCI_OP_READ_BD_ADDR: return "READ_BD_ADDR"; + case BT_HCI_OP_READ_RSSI: return "READ_RSSI"; + case BT_HCI_OP_READ_ENCRYPTION_KEY_SIZE: return "READ_ENCRYPTION_KEY_SIZE"; + case BT_HCI_OP_LE_SET_EVENT_MASK: return "LE_SET_EVENT_MASK"; + case BT_HCI_OP_LE_READ_BUFFER_SIZE: return "LE_READ_BUFFER_SIZE"; + case BT_HCI_OP_LE_READ_LOCAL_FEATURES: return "LE_READ_LOCAL_FEATURES"; + case BT_HCI_OP_LE_SET_RANDOM_ADDRESS: return "LE_SET_RANDOM_ADDRESS"; + case BT_HCI_OP_LE_SET_ADV_PARAM: return "LE_SET_ADV_PARAM"; + case BT_HCI_OP_LE_READ_ADV_CHAN_TX_POWER: return "LE_READ_ADV_CHAN_TX_POWER"; + case BT_HCI_OP_LE_SET_ADV_DATA: return "LE_SET_ADV_DATA"; + case BT_HCI_OP_LE_SET_SCAN_RSP_DATA: return "LE_SET_SCAN_RSP_DATA"; + case BT_HCI_OP_LE_SET_ADV_ENABLE: return "LE_SET_ADV_ENABLE"; + case BT_HCI_OP_LE_SET_SCAN_PARAM: return "LE_SET_SCAN_PARAM"; + case BT_HCI_OP_LE_SET_SCAN_ENABLE: return "LE_SET_SCAN_ENABLE"; + case BT_HCI_OP_LE_CREATE_CONN: return "LE_CREATE_CONN"; + case BT_HCI_OP_LE_CREATE_CONN_CANCEL: return "LE_CREATE_CONN_CANCEL"; + case BT_HCI_OP_LE_READ_WL_SIZE: return "LE_READ_WL_SIZE"; + case BT_HCI_OP_LE_CLEAR_WL: return "LE_CLEAR_WL"; + case BT_HCI_OP_LE_ADD_DEV_TO_WL: return "LE_ADD_DEV_TO_WL"; + case BT_HCI_OP_LE_REM_DEV_FROM_WL: return "LE_REM_DEV_FROM_WL"; + case BT_HCI_OP_LE_CONN_UPDATE: return "LE_CONN_UPDATE"; + case BT_HCI_OP_LE_SET_HOST_CHAN_CLASSIF: return "LE_SET_HOST_CHAN_CLASSIF"; + case BT_HCI_OP_LE_READ_CHAN_MAP: return "LE_READ_CHAN_MAP"; + case BT_HCI_OP_LE_READ_REMOTE_FEATURES: return "LE_READ_REMOTE_FEATURES"; + case BT_HCI_OP_LE_ENCRYPT: return "LE_ENCRYPT"; + case BT_HCI_OP_LE_RAND: return "LE_RAND"; + case BT_HCI_OP_LE_START_ENCRYPTION: return "LE_START_ENCRYPTION"; + case BT_HCI_OP_LE_LTK_REQ_REPLY: return "LE_LTK_REQ_REPLY"; + case BT_HCI_OP_LE_LTK_REQ_NEG_REPLY: return "LE_LTK_REQ_NEG_REPLY"; + case BT_HCI_OP_LE_READ_SUPP_STATES: return "LE_READ_SUPP_STATES"; + case BT_HCI_OP_LE_RX_TEST: return "LE_RX_TEST"; + case BT_HCI_OP_LE_TX_TEST: return "LE_TX_TEST"; + case BT_HCI_OP_LE_TEST_END: return "LE_TEST_END"; + case BT_HCI_OP_LE_CONN_PARAM_REQ_REPLY: return "LE_CONN_PARAM_REQ_REPLY"; + case BT_HCI_OP_LE_CONN_PARAM_REQ_NEG_REPLY: return "LE_CONN_PARAM_REQ_NEG_REPLY"; + case BT_HCI_OP_LE_SET_DATA_LEN: return "LE_SET_DATA_LEN"; + case BT_HCI_OP_LE_READ_DEFAULT_DATA_LEN: return "LE_READ_DEFAULT_DATA_LEN"; + case BT_HCI_OP_LE_WRITE_DEFAULT_DATA_LEN: return "LE_WRITE_DEFAULT_DATA_LEN"; + case BT_HCI_OP_LE_P256_PUBLIC_KEY: return "LE_P256_PUBLIC_KEY"; + case BT_HCI_OP_LE_GENERATE_DHKEY: return "LE_GENERATE_DHKEY"; + case BT_HCI_OP_LE_ADD_DEV_TO_RL: return "LE_ADD_DEV_TO_RL"; + case BT_HCI_OP_LE_REM_DEV_FROM_RL: return "LE_REM_DEV_FROM_RL"; + case BT_HCI_OP_LE_CLEAR_RL: return "LE_CLEAR_RL"; + case BT_HCI_OP_LE_READ_RL_SIZE: return "LE_READ_RL_SIZE"; + case BT_HCI_OP_LE_READ_PEER_RPA: return "LE_READ_PEER_RPA"; + case BT_HCI_OP_LE_READ_LOCAL_RPA: return "LE_READ_LOCAL_RPA"; + case BT_HCI_OP_LE_SET_ADDR_RES_ENABLE: return "LE_SET_ADDR_RES_ENABLE"; + case BT_HCI_OP_LE_SET_RPA_TIMEOUT: return "LE_SET_RPA_TIMEOUT"; + case BT_HCI_OP_LE_READ_MAX_DATA_LEN: return "LE_READ_MAX_DATA_LEN"; + case BT_HCI_OP_LE_READ_PHY: return "LE_READ_PHY"; + case BT_HCI_OP_LE_SET_DEFAULT_PHY: return "LE_SET_DEFAULT_PHY"; + case BT_HCI_OP_LE_SET_PHY: return "LE_SET_PHY"; + case BT_HCI_OP_LE_ENH_RX_TEST: return "LE_ENH_RX_TEST"; + case BT_HCI_OP_LE_ENH_TX_TEST: return "LE_ENH_TX_TEST"; + case BT_HCI_OP_LE_SET_ADV_SET_RANDOM_ADDR: return "LE_SET_ADV_SET_RANDOM_ADDR"; + case BT_HCI_OP_LE_SET_EXT_ADV_PARAM: return "LE_SET_EXT_ADV_PARAM"; + case BT_HCI_OP_LE_SET_EXT_ADV_DATA: return "LE_SET_EXT_ADV_DATA"; + case BT_HCI_OP_LE_SET_EXT_SCAN_RSP_DATA: return "LE_SET_EXT_SCAN_RSP_DATA"; + case BT_HCI_OP_LE_SET_EXT_ADV_ENABLE: return "LE_SET_EXT_ADV_ENABLE"; + case BT_HCI_OP_LE_READ_MAX_ADV_DATA_LEN: return "LE_READ_MAX_ADV_DATA_LEN"; + case BT_HCI_OP_LE_READ_NUM_ADV_SETS: return "LE_READ_NUM_ADV_SETS"; + case BT_HCI_OP_LE_REMOVE_ADV_SET: return "LE_REMOVE_ADV_SET"; + case BT_HCI_OP_CLEAR_ADV_SETS: return "CLEAR_ADV_SETS"; + case BT_HCI_OP_LE_SET_PER_ADV_PARAM: return "LE_SET_PER_ADV_PARAM"; + case BT_HCI_OP_LE_SET_PER_ADV_DATA: return "LE_SET_PER_ADV_DATA"; + case BT_HCI_OP_LE_SET_PER_ADV_ENABLE: return "LE_SET_PER_ADV_ENABLE"; + case BT_HCI_OP_LE_SET_EXT_SCAN_PARAM: return "LE_SET_EXT_SCAN_PARAM"; + case BT_HCI_OP_LE_SET_EXT_SCAN_ENABLE: return "LE_SET_EXT_SCAN_ENABLE"; + case BT_HCI_OP_LE_EXT_CREATE_CONN: return "LE_EXT_CREATE_CONN"; + case BT_HCI_OP_LE_PER_ADV_CREATE_SYNC: return "LE_PER_ADV_CREATE_SYNC"; + case BT_HCI_OP_LE_PER_ADV_CREATE_SYNC_CANCEL: return "LE_PER_ADV_CREATE_SYNC_CANCEL"; + case BT_HCI_OP_LE_PER_ADV_TERMINATE_SYNC: return "LE_PER_ADV_TERMINATE_SYNC"; + case BT_HCI_OP_LE_ADD_DEV_TO_PER_ADV_LIST: return "LE_ADD_DEV_TO_PER_ADV_LIST"; + case BT_HCI_OP_LE_REM_DEV_FROM_PER_ADV_LIST: return "LE_REM_DEV_FROM_PER_ADV_LIST"; + case BT_HCI_OP_LE_CLEAR_PER_ADV_LIST: return "LE_CLEAR_PER_ADV_LIST"; + case BT_HCI_OP_LE_READ_PER_ADV_LIST_SIZE: return "LE_READ_PER_ADV_LIST_SIZE"; + case BT_HCI_OP_LE_READ_TX_POWER: return "LE_READ_TX_POWER"; + case BT_HCI_OP_LE_READ_RF_PATH_COMP: return "LE_READ_RF_PATH_COMP"; + case BT_HCI_OP_LE_WRITE_RF_PATH_COMP: return "LE_WRITE_RF_PATH_COMP"; + case BT_HCI_OP_LE_SET_PRIVACY_MODE: return "LE_SET_PRIVACY_MODE"; + default: return ""; + } +} + + +STATIC void dump_cmd_pkt(bool tx, uint8_t pkt_len, uint8_t pkt_data[]) { + h4_hci_cmd_pkt_t *pkt = (h4_hci_cmd_pkt_t *) pkt_data; + mp_printf(&mp_plat_print, + "%s HCI COMMAND (%x) op: %s (%04x), len: %d, data: ", + tx ? "TX->" : "RX<-", + pkt->pkt_type, + hci_opcode_name(pkt->opcode), 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, pkt_len: %d", pkt_len); + } + mp_printf(&mp_plat_print, "\n"); +} + +STATIC void dump_acl_pkt(bool tx, uint8_t pkt_len, uint8_t pkt_data[]) { + h4_hci_acl_pkt_t *pkt = (h4_hci_acl_pkt_t *) pkt_data; + acl_data_t *acl = (acl_data_t *) pkt->data; + + mp_printf(&mp_plat_print, + "%s HCI ACLDATA (%x) ", + tx ? "TX->" : "RX<-", pkt->pkt_type); + + if (pkt->pb != ACL_DATA_PB_MIDDLE && acl->cid == BT_L2CAP_CID_ATT) { + // This is the start of a fragmented acl_data packet or is a full packet, + // and is an ATT protocol packet. + mp_printf(&mp_plat_print, "att: %s, ", att_opcode_name(acl->acl_data[0])); + } + + mp_printf(&mp_plat_print, + "handle: %04x, pb: %d, bc: %d, data_len: %d, ", + 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. + 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, pkt_len: %d", pkt_len); + } + mp_printf(&mp_plat_print, "\n"); +} + +STATIC void dump_evt_pkt(bool tx, uint8_t pkt_len, uint8_t pkt_data[]) { + h4_hci_evt_pkt_t *pkt = (h4_hci_evt_pkt_t *) pkt_data; + mp_printf(&mp_plat_print, + "%s HCI EVENT (%x) evt: %s (%02x), param_len: %d, data: ", + tx ? "TX->" : "RX<-", + pkt->pkt_type, + pkt->evt == BT_HCI_EVT_LE_META_EVENT + ? hci_evt_le_name(pkt->params[0]) + : hci_evt_name(pkt->evt), + 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, pkt_len: %d", pkt_len); + } + mp_printf(&mp_plat_print, "\n"); +} diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile index f63698eba5..db26df570b 100644 --- a/ports/atmel-samd/Makefile +++ b/ports/atmel-samd/Makefile @@ -112,7 +112,7 @@ CFLAGS += $(OPTIMIZATION_FLAGS) -DNDEBUG $(echo PERIPHERALS_CHIP_FAMILY=$(PERIPHERALS_CHIP_FAMILY)) #Debugging/Optimization ifeq ($(DEBUG), 1) - CFLAGS += -ggdb + CFLAGS += -ggdb -Og # You may want to disable -flto if it interferes with debugging. CFLAGS += -flto -flto-partition=none # You may want to enable these flags to make setting breakpoints easier. From ac95106b8867072cb40043a1a4298aa0317f101c Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 4 Aug 2020 18:24:37 -0400 Subject: [PATCH 23/84] service discovery works; need to work on char and descriptor discovery --- .../common-hal/_bleio/Characteristic.c | 2 ++ devices/ble_hci/common-hal/_bleio/Service.c | 8 ++++- devices/ble_hci/common-hal/_bleio/Service.h | 2 +- devices/ble_hci/common-hal/_bleio/__init__.c | 4 +++ devices/ble_hci/common-hal/_bleio/__init__.h | 2 +- devices/ble_hci/common-hal/_bleio/att.c | 36 +++++++++++-------- devices/ble_hci/common-hal/_bleio/att.h | 2 ++ devices/ble_hci/common-hal/_bleio/hci.c | 8 +++-- devices/ble_hci/common-hal/_bleio/hci.h | 2 +- main.c | 8 +++++ ports/atmel-samd/Makefile | 2 +- 11 files changed, 53 insertions(+), 23 deletions(-) diff --git a/devices/ble_hci/common-hal/_bleio/Characteristic.c b/devices/ble_hci/common-hal/_bleio/Characteristic.c index e2cdac08cc..2f4a81f9a2 100644 --- a/devices/ble_hci/common-hal/_bleio/Characteristic.c +++ b/devices/ble_hci/common-hal/_bleio/Characteristic.c @@ -149,6 +149,8 @@ void common_hal_bleio_characteristic_add_descriptor(bleio_characteristic_obj_t * } descriptor->handle = bleio_adapter_add_attribute(&common_hal_bleio_adapter_obj, MP_OBJ_TO_PTR(descriptor)); + // Include this desriptor in the service handles range. + self->service->end_handle = descriptor->handle; // Link together all the descriptors for this characteristic. descriptor->next = self->descriptor_list; diff --git a/devices/ble_hci/common-hal/_bleio/Service.c b/devices/ble_hci/common-hal/_bleio/Service.c index c683557912..abccfd5c4e 100644 --- a/devices/ble_hci/common-hal/_bleio/Service.c +++ b/devices/ble_hci/common-hal/_bleio/Service.c @@ -42,6 +42,8 @@ uint32_t _common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uu vm_used_ble = true; self->handle = bleio_adapter_add_attribute(&common_hal_bleio_adapter_obj, MP_OBJ_TO_PTR(self)); + self->start_handle = self->handle; + self->end_handle = self->handle; if (self->handle == BLE_GATT_HANDLE_INVALID) { return 1; } @@ -90,10 +92,12 @@ void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, } characteristic->decl_handle = bleio_adapter_add_attribute( &common_hal_bleio_adapter_obj, MP_OBJ_TO_PTR(characteristic)); - // This is the value handle + // This is the value handle. characteristic->handle = bleio_adapter_add_attribute( &common_hal_bleio_adapter_obj, MP_OBJ_TO_PTR(characteristic)); + self->end_handle = characteristic->handle; + if (characteristic->props & (CHAR_PROP_NOTIFY | CHAR_PROP_INDICATE)) { // We need a CCCD. bleio_descriptor_obj_t *cccd = m_new_obj(bleio_descriptor_obj_t); @@ -107,6 +111,8 @@ void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, cccd->handle = cccd_handle; characteristic->cccd_handle = cccd_handle; common_hal_bleio_characteristic_add_descriptor(characteristic, cccd); + + self->end_handle = cccd_handle; } // #if CIRCUITPY_VERBOSE_BLE diff --git a/devices/ble_hci/common-hal/_bleio/Service.h b/devices/ble_hci/common-hal/_bleio/Service.h index bb8bc61edc..11e7d1c960 100644 --- a/devices/ble_hci/common-hal/_bleio/Service.h +++ b/devices/ble_hci/common-hal/_bleio/Service.h @@ -43,7 +43,7 @@ typedef struct bleio_service_obj { // A local service doesn't know the connection. mp_obj_t connection; mp_obj_list_t *characteristic_list; - // Range of attribute handles of this remote service. + // Range of attribute handles of this service. uint16_t start_handle; uint16_t end_handle; struct bleio_service_obj* next; diff --git a/devices/ble_hci/common-hal/_bleio/__init__.c b/devices/ble_hci/common-hal/_bleio/__init__.c index 7139e61932..ee953cfeb9 100644 --- a/devices/ble_hci/common-hal/_bleio/__init__.c +++ b/devices/ble_hci/common-hal/_bleio/__init__.c @@ -38,6 +38,8 @@ #include "shared-bindings/_bleio/UUID.h" #include "supervisor/shared/bluetooth.h" +bool vm_used_ble; + void check_hci_error(hci_result_t result) { switch (result) { case HCI_OK: @@ -110,6 +112,8 @@ void check_hci_error(hci_result_t result) { // Turn off BLE on a reset or reload. void bleio_reset() { + bleio_hci_reset(); + if (!common_hal_bleio_adapter_get_enabled(&common_hal_bleio_adapter_obj)) { return; } diff --git a/devices/ble_hci/common-hal/_bleio/__init__.h b/devices/ble_hci/common-hal/_bleio/__init__.h index 18b4289e9a..5873675af8 100644 --- a/devices/ble_hci/common-hal/_bleio/__init__.h +++ b/devices/ble_hci/common-hal/_bleio/__init__.h @@ -57,6 +57,6 @@ void check_gatt_status(uint16_t gatt_status); void check_sec_status(uint8_t sec_status); // Track if the user code modified the BLE state to know if we need to undo it on reload. -bool vm_used_ble; +extern bool vm_used_ble; #endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_INIT_H diff --git a/devices/ble_hci/common-hal/_bleio/att.c b/devices/ble_hci/common-hal/_bleio/att.c index 08324c37ed..ba6c7c3d06 100644 --- a/devices/ble_hci/common-hal/_bleio/att.c +++ b/devices/ble_hci/common-hal/_bleio/att.c @@ -116,7 +116,7 @@ STATIC void check_and_save_expected_rsp(uint16_t conn_handle, uint8_t opcode, ui } } -void att_init(void) { +void bleio_att_reset(void) { max_mtu = BT_ATT_DEFAULT_LE_MTU; timeout = 5000; long_write_handle = BLE_GATT_HANDLE_INVALID; @@ -884,6 +884,8 @@ void process_read_by_group_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, struct bt_att_read_group_req *req = (struct bt_att_read_group_req *) data; uint16_t type_uuid = req->uuid[0] | (req->uuid[1] << 8); + // We only support returning services for BT_ATT_OP_READ_GROUP_REQ, which is typically used + // for service discovery. if (dlen != sizeof(struct bt_att_read_group_req) + sizeof(type_uuid) || (type_uuid != BLE_TYPE_PRIMARY_SERVICE && type_uuid != BLE_TYPE_SECONDARY_SERVICE)) { @@ -897,7 +899,7 @@ void process_read_by_group_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, } rsp_t; uint8_t rsp_bytes[mtu]; - rsp_t *rsp = (rsp_t *) &rsp_bytes; + rsp_t *rsp = (rsp_t *) rsp_bytes; rsp->h.code = BT_ATT_OP_READ_GROUP_RSP; rsp->r.len = 0; @@ -907,13 +909,22 @@ void process_read_by_group_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, bool no_data = true; // All the data chunks must have uuid's that are the same size. - // Keep track fo the first one to make sure. + // Keep track of the first one to make sure. size_t sizeof_first_service_uuid = 0; + + // Size of a single bt_att_group_data chunk. Start with the intial size, and + // add the uuid size in the loop below. + size_t data_length = sizeof(struct bt_att_group_data); + const uint16_t max_attribute_handle = bleio_adapter_max_attribute_handle(&common_hal_bleio_adapter_obj); for (uint16_t handle = req->start_handle; handle <= max_attribute_handle && handle <= req->end_handle; handle++) { - no_data = false; + + if (rsp_length + data_length > mtu) { + // The next possible bt_att_group_data chunk won't fit. The response is full. + break; + } mp_obj_t *attribute_obj = bleio_adapter_get_attribute(&common_hal_bleio_adapter_obj, handle); if (type_uuid != bleio_attribute_type_uuid(attribute_obj)) { @@ -925,33 +936,28 @@ void process_read_by_group_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, // Is this a 16-bit or a 128-bit uuid? It must match in size with any previous attribute // in this transmission. - const uint8_t sizeof_service_uuid = common_hal_bleio_uuid_get_size(service->uuid) / 8; + const uint32_t sizeof_service_uuid = common_hal_bleio_uuid_get_size(service->uuid) / 8; if (sizeof_first_service_uuid == 0) { sizeof_first_service_uuid = sizeof_service_uuid; + data_length += sizeof_service_uuid; } else if (sizeof_first_service_uuid != sizeof_service_uuid) { - // Mismatched sizes. Transmit just what we have so far in this batch. + // Mismatched sizes, which can't be in the same batch. + // Transmit just what we have so far in this batch. break; } - // Size of bt_att_group_data chunk with uuid. - const uint16_t data_length = sizeof(struct bt_att_group_data) + sizeof_service_uuid; - - if (rsp_length + data_length > mtu) { - // No room for another bt_att_group_data chunk. - break; - } // Pass the length of ONE bt_att_group_data chunk. There may be multiple ones in this transmission. rsp->r.len = data_length; - uint8_t group_data_bytes[data_length]; - struct bt_att_group_data *group_data = (struct bt_att_group_data *) group_data_bytes; + struct bt_att_group_data *group_data = (struct bt_att_group_data *) &rsp_bytes[rsp_length]; group_data->start_handle = service->start_handle; group_data->end_handle = service->end_handle; common_hal_bleio_uuid_pack_into(service->uuid, group_data->value); rsp_length += data_length; + no_data = false; } if (no_data) { diff --git a/devices/ble_hci/common-hal/_bleio/att.h b/devices/ble_hci/common-hal/_bleio/att.h index 6cf9b305b2..48f7836e0e 100644 --- a/devices/ble_hci/common-hal/_bleio/att.h +++ b/devices/ble_hci/common-hal/_bleio/att.h @@ -30,6 +30,8 @@ #include "hci_include/att.h" #include "hci_include/att_internal.h" +void bleio_att_reset(void); + //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); diff --git a/devices/ble_hci/common-hal/_bleio/hci.c b/devices/ble_hci/common-hal/_bleio/hci.c index 7b4adaa79a..52452a26d1 100644 --- a/devices/ble_hci/common-hal/_bleio/hci.c +++ b/devices/ble_hci/common-hal/_bleio/hci.c @@ -272,18 +272,20 @@ STATIC void process_evt_pkt(size_t pkt_len, uint8_t pkt_data[]) } } -void hci_init(void) { +void bleio_hci_reset(void) { rx_idx = 0; pending_pkt = 0; hci_poll_in_progress = false; + + bleio_att_reset(); } hci_result_t hci_poll_for_incoming_pkt_timeout(uint32_t timeout_msecs) { uint64_t start = supervisor_ticks_ms64(); - hci_result_t result; + hci_result_t result = HCI_OK; - while (supervisor_ticks_ms64() -start < timeout_msecs) { + while (supervisor_ticks_ms64() - start < timeout_msecs) { result = hci_poll_for_incoming_pkt(); RUN_BACKGROUND_TASKS; } diff --git a/devices/ble_hci/common-hal/_bleio/hci.h b/devices/ble_hci/common-hal/_bleio/hci.h index 89a2b3304a..d907a84b7d 100644 --- a/devices/ble_hci/common-hal/_bleio/hci.h +++ b/devices/ble_hci/common-hal/_bleio/hci.h @@ -39,7 +39,7 @@ typedef int hci_result_t; #define HCI_WRITE_ERROR (-5) #define HCI_ATT_ERROR (-6) -void hci_init(void); +void bleio_hci_reset(void); hci_result_t hci_disconnect(uint16_t handle); diff --git a/main.c b/main.c index 8c5c9ac37d..4dd93374e3 100755 --- a/main.c +++ b/main.c @@ -105,6 +105,12 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) { static size_t PLACE_IN_DTCM_BSS(_pystack[CIRCUITPY_PYSTACK_SIZE / sizeof(size_t)]); #endif +static void reset_devices(void) { +#if CIRCUITPY_BLEIO_HCI + bleio_reset(); +#endif +} + void start_mp(supervisor_allocation* heap) { reset_status_led(); autoreload_stop(); @@ -459,6 +465,8 @@ int __attribute__((used)) main(void) { // Reset everything and prep MicroPython to run boot.py. reset_port(); + // Port-independent devices, like CIRCUITPY_BLEIO_HCI. + reset_devices(); reset_board(); // Turn on autoreload by default but before boot.py in case it wants to change it. diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile index db26df570b..038585fc3a 100644 --- a/ports/atmel-samd/Makefile +++ b/ports/atmel-samd/Makefile @@ -112,7 +112,7 @@ CFLAGS += $(OPTIMIZATION_FLAGS) -DNDEBUG $(echo PERIPHERALS_CHIP_FAMILY=$(PERIPHERALS_CHIP_FAMILY)) #Debugging/Optimization ifeq ($(DEBUG), 1) - CFLAGS += -ggdb -Og + CFLAGS += -ggdb3 -Og # You may want to disable -flto if it interferes with debugging. CFLAGS += -flto -flto-partition=none # You may want to enable these flags to make setting breakpoints easier. From 0f4b969d62b5eb933a674a23a338d9d420cf61b4 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sat, 8 Aug 2020 00:29:37 -0400 Subject: [PATCH 24/84] discovery of Nordic UART service working --- devices/ble_hci/common-hal/_bleio/Attribute.c | 49 +- devices/ble_hci/common-hal/_bleio/Attribute.h | 26 +- .../common-hal/_bleio/Characteristic.c | 2 +- devices/ble_hci/common-hal/_bleio/Service.c | 30 +- devices/ble_hci/common-hal/_bleio/UUID.c | 2 +- devices/ble_hci/common-hal/_bleio/__init__.c | 8 + devices/ble_hci/common-hal/_bleio/__init__.h | 5 + devices/ble_hci/common-hal/_bleio/att.c | 460 +++++++++++------- ports/nrf/common-hal/_bleio/UUID.c | 2 +- shared-bindings/_bleio/UUID.c | 2 +- shared-bindings/_bleio/UUID.h | 2 +- shared-module/_bleio/Characteristic.h | 13 + 12 files changed, 370 insertions(+), 231 deletions(-) diff --git a/devices/ble_hci/common-hal/_bleio/Attribute.c b/devices/ble_hci/common-hal/_bleio/Attribute.c index d32ed11679..26fabed098 100644 --- a/devices/ble_hci/common-hal/_bleio/Attribute.c +++ b/devices/ble_hci/common-hal/_bleio/Attribute.c @@ -24,55 +24,26 @@ * THE SOFTWARE. */ +#include "py/runtime.h" + #include "shared-bindings/_bleio/Attribute.h" #include "shared-bindings/_bleio/Characteristic.h" #include "shared-bindings/_bleio/Descriptor.h" #include "shared-bindings/_bleio/Service.h" -// Return the type of the attribute. -ble_attribute_type_uuid bleio_attribute_type_uuid(mp_obj_t *attribute) { + +bleio_uuid_obj_t *bleio_attribute_get_uuid(mp_obj_t *attribute) { if (MP_OBJ_IS_TYPE(attribute, &bleio_characteristic_type)) { - return BLE_TYPE_CHARACTERISTIC; + bleio_characteristic_obj_t *characteristic = MP_OBJ_TO_PTR(attribute); + return characteristic->uuid; } if (MP_OBJ_IS_TYPE(attribute, &bleio_descriptor_type)) { - return BLE_TYPE_DESCRIPTOR; + bleio_descriptor_obj_t *descriptor = MP_OBJ_TO_PTR(attribute); + return descriptor->uuid; } if (MP_OBJ_IS_TYPE(attribute, &bleio_service_type)) { bleio_service_obj_t *service = MP_OBJ_TO_PTR(attribute); - return service->is_secondary ? BLE_TYPE_SECONDARY_SERVICE : BLE_TYPE_PRIMARY_SERVICE; + return service->uuid; } - return BLE_TYPE_UNKNOWN; + mp_raise_RuntimeError(translate("Invalid BLE attribute")); } - -// 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; -// } -// } diff --git a/devices/ble_hci/common-hal/_bleio/Attribute.h b/devices/ble_hci/common-hal/_bleio/Attribute.h index 47327437bc..f4b0b7dbba 100644 --- a/devices/ble_hci/common-hal/_bleio/Attribute.h +++ b/devices/ble_hci/common-hal/_bleio/Attribute.h @@ -28,23 +28,23 @@ #define MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_ATTRIBUTE_H #include "shared-module/_bleio/Attribute.h" +#include "shared-bindings/_bleio/UUID.h" // Types returned by attribute table lookups. These are UUIDs. typedef enum { - BLE_TYPE_UNKNOWN = 0x0000, - BLE_TYPE_PRIMARY_SERVICE = 0x2800, - BLE_TYPE_SECONDARY_SERVICE = 0x2801, - BLE_TYPE_CHARACTERISTIC = 0x2803, - BLE_TYPE_DESCRIPTOR = 0x2900 + BLE_TYPE_UNKNOWN = 0x0000, + BLE_TYPE_SERVICE_PRIMARY = 0x2800, + BLE_TYPE_SERVICE_SECONDARY = 0x2801, + BLE_TYPE_SERVICE_INCLUDE = 0x2802, // not yet implemented by us + BLE_TYPE_CHARACTERISTIC = 0x2803, + BLE_TYPE_CHAR_EXTENDED_PROPS = 0x2900, // not yet implemented by us + BLE_TYPE_CHAR_USER_DESC = 0x2901, // not yet implemented by us + BLE_TYPE_CCCD = 0x2902, + BLE_TYPE_SCCD = 0x2903, // not yet implemented by us + BLE_TYPE_CHAR_PRESENTATION_FMT = 0x2904, // not yet implemented by us + BLE_TYPE_CHAR_AGGREGATE_FMT = 0x2905, // not yet implemented by us } ble_attribute_type_uuid; -// 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; - -ble_attribute_type_uuid bleio_attribute_type_uuid(mp_obj_t *attribute); +bleio_uuid_obj_t *bleio_attribute_get_uuid(mp_obj_t *attribute); #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 2f4a81f9a2..b62957ea6a 100644 --- a/devices/ble_hci/common-hal/_bleio/Characteristic.c +++ b/devices/ble_hci/common-hal/_bleio/Characteristic.c @@ -149,7 +149,7 @@ void common_hal_bleio_characteristic_add_descriptor(bleio_characteristic_obj_t * } descriptor->handle = bleio_adapter_add_attribute(&common_hal_bleio_adapter_obj, MP_OBJ_TO_PTR(descriptor)); - // Include this desriptor in the service handles range. + // Include this descriptor in the service handle's range. self->service->end_handle = descriptor->handle; // Link together all the descriptors for this characteristic. diff --git a/devices/ble_hci/common-hal/_bleio/Service.c b/devices/ble_hci/common-hal/_bleio/Service.c index abccfd5c4e..b6963b7a4a 100644 --- a/devices/ble_hci/common-hal/_bleio/Service.c +++ b/devices/ble_hci/common-hal/_bleio/Service.c @@ -99,20 +99,30 @@ void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, self->end_handle = characteristic->handle; if (characteristic->props & (CHAR_PROP_NOTIFY | CHAR_PROP_INDICATE)) { - // We need a CCCD. + // We need a CCCD if this characteristic is doing notify or indicate. bleio_descriptor_obj_t *cccd = m_new_obj(bleio_descriptor_obj_t); cccd->base.type = &bleio_descriptor_type; - cccd->read_perm = SECURITY_MODE_OPEN; - // Make CCCD write permission match characteristic read permission. - cccd->write_perm = characteristic->read_perm; - const uint16_t cccd_handle = bleio_adapter_add_attribute( - &common_hal_bleio_adapter_obj, MP_OBJ_TO_PTR(cccd)); - cccd->handle = cccd_handle; - characteristic->cccd_handle = cccd_handle; + uint16_t zero = 0; + mp_buffer_info_t zero_cccd = { + .buf = &zero, + .len = sizeof(zero), + }; + + common_hal_bleio_descriptor_construct( + cccd, + characteristic, + &cccd_uuid, // 0x2902 + SECURITY_MODE_OPEN, // CCCD read perm + characteristic->read_perm, // Make CCCD write perm match characteristic read perm. + 2, // 2 bytes + true, // fixed length + &zero_cccd // Initial value is 0. + ); + + // Adds CCCD to attribute table, and also extends self->end_handle to include the CCCD. common_hal_bleio_characteristic_add_descriptor(characteristic, cccd); - - self->end_handle = cccd_handle; + characteristic->cccd_handle = cccd->handle; } // #if CIRCUITPY_VERBOSE_BLE diff --git a/devices/ble_hci/common-hal/_bleio/UUID.c b/devices/ble_hci/common-hal/_bleio/UUID.c index d86878e472..fd8d8bfe9e 100644 --- a/devices/ble_hci/common-hal/_bleio/UUID.c +++ b/devices/ble_hci/common-hal/_bleio/UUID.c @@ -36,7 +36,7 @@ // If uuid128 is NULL, this is a Bluetooth SIG 16-bit UUID. // 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[16]) { +void common_hal_bleio_uuid_construct(bleio_uuid_obj_t *self, mp_int_t uuid16, const uint8_t uuid128[16]) { self->size = uuid128 == NULL ? 16 : 128; self->uuid16 = uuid16; if (uuid128) { diff --git a/devices/ble_hci/common-hal/_bleio/__init__.c b/devices/ble_hci/common-hal/_bleio/__init__.c index ee953cfeb9..16b4a26e29 100644 --- a/devices/ble_hci/common-hal/_bleio/__init__.c +++ b/devices/ble_hci/common-hal/_bleio/__init__.c @@ -38,6 +38,9 @@ #include "shared-bindings/_bleio/UUID.h" #include "supervisor/shared/bluetooth.h" +// UUID shared by all cccd's. +bleio_uuid_obj_t cccd_uuid; + bool vm_used_ble; void check_hci_error(hci_result_t result) { @@ -112,6 +115,10 @@ void check_hci_error(hci_result_t result) { // Turn off BLE on a reset or reload. void bleio_reset() { + // Create a UUID object for all CCCD's. + cccd_uuid.base.type = &bleio_uuid_type; + common_hal_bleio_uuid_construct(&cccd_uuid, BLE_TYPE_CCCD, NULL); + bleio_hci_reset(); if (!common_hal_bleio_adapter_get_enabled(&common_hal_bleio_adapter_obj)) { @@ -123,6 +130,7 @@ void bleio_reset() { return; } common_hal_bleio_adapter_set_enabled(&common_hal_bleio_adapter_obj, false); + //FIX bonding_reset(); supervisor_start_bluetooth(); } diff --git a/devices/ble_hci/common-hal/_bleio/__init__.h b/devices/ble_hci/common-hal/_bleio/__init__.h index 5873675af8..e84320e30c 100644 --- a/devices/ble_hci/common-hal/_bleio/__init__.h +++ b/devices/ble_hci/common-hal/_bleio/__init__.h @@ -29,6 +29,8 @@ #include +#include "shared-bindings/_bleio/UUID.h" + #include "hci.h" void bleio_background(void); @@ -59,4 +61,7 @@ void check_sec_status(uint8_t sec_status); // Track if the user code modified the BLE state to know if we need to undo it on reload. extern bool vm_used_ble; +// UUID shared by all CCCD's. +extern bleio_uuid_obj_t cccd_uuid; + #endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_INIT_H diff --git a/devices/ble_hci/common-hal/_bleio/att.c b/devices/ble_hci/common-hal/_bleio/att.c index ba6c7c3d06..8daddd3a96 100644 --- a/devices/ble_hci/common-hal/_bleio/att.c +++ b/devices/ble_hci/common-hal/_bleio/att.c @@ -33,6 +33,8 @@ #include "common-hal/_bleio/Attribute.h" #include "shared-bindings/_bleio/__init__.h" #include "shared-bindings/_bleio/Characteristic.h" +#include "shared-bindings/_bleio/Descriptor.h" +#include "shared-bindings/_bleio/Service.h" #include "shared-bindings/_bleio/UUID.h" #include "supervisor/shared/tick.h" @@ -54,8 +56,63 @@ STATIC struct { uint8_t length; // Length of response packet. } expected_rsp; +// A characteristic declaration has this data, in this order: +// See Bluetooth v5.1 spec, section 3.3.1 Characteristic declaration. +typedef struct __packed { + uint8_t properties; + uint16_t value_handle; + uint8_t uuid[0]; // 2 or 16 bytes +} characteristic_declaration_t; + //FIX BLEDeviceEventHandler event_handlers[2]; +STATIC uint8_t bleio_properties_to_ble_spec_properties(uint8_t bleio_properties) { + uint8_t ble_spec_properties = 0; + if (bleio_properties & CHAR_PROP_BROADCAST) { + ble_spec_properties |= BT_GATT_CHRC_BROADCAST; + } + if (bleio_properties & CHAR_PROP_INDICATE) { + ble_spec_properties |= BT_GATT_CHRC_INDICATE; + } + if (bleio_properties & CHAR_PROP_NOTIFY) { + ble_spec_properties |= BT_GATT_CHRC_NOTIFY; + } + if (bleio_properties & CHAR_PROP_READ) { + ble_spec_properties |= BT_GATT_CHRC_READ; + } + if (bleio_properties & CHAR_PROP_WRITE) { + ble_spec_properties |= BT_GATT_CHRC_WRITE; + } + if (bleio_properties & CHAR_PROP_WRITE_NO_RESPONSE) { + ble_spec_properties |= BT_GATT_CHRC_WRITE_WITHOUT_RESP; + } + + return ble_spec_properties; +} + +// STATIC uint8_t ble_spec_properties_to_bleio_properties(uint8_t ble_spec_properties) { +// uint8_t bleio_properties = 0; +// if (ble_spec_properties & BT_GATT_CHRC_BROADCAST) { +// bleio_properties |= CHAR_PROP_BROADCAST; +// } +// if (ble_spec_properties & BT_GATT_CHRC_INDICATE) { +// bleio_properties |= CHAR_PROP_INDICATE; +// } +// if (ble_spec_properties & BT_GATT_CHRC_NOTIFY) { +// bleio_properties |= CHAR_PROP_NOTIFY; +// } +// if (ble_spec_properties & BT_GATT_CHRC_READ) { +// bleio_properties |= CHAR_PROP_READ; +// } +// if (ble_spec_properties & BT_GATT_CHRC_WRITE) { +// bleio_properties |= CHAR_PROP_WRITE; +// } +// if (ble_spec_properties & BT_GATT_CHRC_WRITE_WITHOUT_RESP) { +// bleio_properties |= CHAR_PROP_WRITE_NO_RESPONSE; +// } + +// return bleio_properties; +// } STATIC void send_error(uint16_t conn_handle, uint8_t opcode, uint16_t handle, uint8_t code) { struct __packed { @@ -187,13 +244,13 @@ bool att_disconnect_from_address(bt_addr_le_t *addr) { // BLEUuid serviceUuid(serviceUuidFilter); // while (reqEnd_handle == 0xffff) { -// int respLength = readByGroupReq(conn_handle, reqStart_handle, reqEnd_handle, BLE_TYPE_PRIMARY_SERVICE, response_buffer); +// int respLength = readByGroupReq(conn_handle, reqStart_handle, reqEnd_handle, BLE_TYPE_SERVICE_PRIMARY, response_buffer); // if (respLength == 0) { // return false; // } -// if (response_buffer[0] == BT_ATT_OP_READ_BY_GROUP_RSP) { +// if (response_buffer[0] == BT_ATT_OP_READ_GROUP_RSP) { // uint16_t lengthPerService = response_buffer[1]; // uint8_t uuidLen = lengthPerService - 4; @@ -254,7 +311,7 @@ bool att_disconnect_from_address(bt_addr_le_t *addr) { // return false; // } -// if (response_buffer[0] == BT_ATT_OP_READ_BY_TYPE_RSP) { +// if (response_buffer[0] == BT_ATT_OP_READ_TYPE_RSP) { // uint16_t lengthPerCharacteristic = response_buffer[1]; // uint8_t uuidLen = lengthPerCharacteristic - 5; @@ -759,56 +816,88 @@ STATIC void process_find_info_req(uint16_t conn_handle, uint16_t mtu, uint8_t dl return; } - //FIX - // uint8_t response[mtu]; - // uint16_t response_length; + typedef struct __packed { + struct bt_att_hdr h; + struct bt_att_find_info_rsp r; + } rsp_t; - // response[0] = BT_ATT_OP_FIND_INFO_RSP; - // response[1] = 0x00; - // response_length = 2; + uint8_t rsp_bytes[mtu]; + rsp_t *rsp = (rsp_t *) rsp_bytes; + rsp->h.code = BT_ATT_OP_FIND_INFO_RSP; - // 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; + // Keeps track of total length of the response. + size_t rsp_length = sizeof(rsp_t); - // if (response[1] == 0) { - // response[1] = info_type; - // } + bool no_data = true; - // if (response[1] != info_type) { - // // different type - // break; - // } + // All the data chunks must have uuid's that are the same size. + // Keep track of the first one to make sure. + size_t sizeof_first_uuid = 0; - // // add the handle - // memcpy(&response[response_length], &handle, sizeof(handle)); - // response_length += sizeof(handle); + const uint16_t max_attribute_handle = bleio_adapter_max_attribute_handle(&common_hal_bleio_adapter_obj); + for (uint16_t handle = req->start_handle; + handle <= max_attribute_handle && handle <= req->end_handle; + 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(); + mp_obj_t *attribute_obj = bleio_adapter_get_attribute(&common_hal_bleio_adapter_obj, handle); - // memcpy(&response[response_length], &type, sizeof(type)); - // response_length += sizeof(type); - // } + // Fetch the uuid for the given attribute, which might be a characteristic or a descriptor. + bleio_uuid_obj_t *uuid; - // if ((response_length + (2 + uuidLen)) > mtu) { - // break; - // } - // } + if (MP_OBJ_IS_TYPE(attribute_obj, &bleio_characteristic_type)) { + bleio_characteristic_obj_t *characteristic = MP_OBJ_TO_PTR(attribute_obj); + if (characteristic->handle != handle) { + // If the handles don't match, this is the characteristic definition attribute. + // Skip it. We want the characteristic value attribute. + continue; + } + uuid = characteristic->uuid; - // 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); - // } + } else { + uuid = bleio_attribute_get_uuid(attribute_obj); + } + + const uint32_t sizeof_uuid = common_hal_bleio_uuid_get_size(uuid) / 8; + if (sizeof_first_uuid == 0) { + sizeof_first_uuid = sizeof_uuid; + // All the uuids in the response will be the same size. + rsp->r.format = sizeof_uuid == 2 ? BT_ATT_INFO_16 : BT_ATT_INFO_128; + } + + if (sizeof_uuid != sizeof_first_uuid) { + // Previous UUID was a different size. We can't mix sizes. + // Stop and send what we have so far. + break; + } + + if (rsp_length + sizeof_uuid > mtu) { + // No remaining room in response for this uuid. + break; + } + + if (sizeof_uuid == 2) { + struct bt_att_info_16 *info_16 = (struct bt_att_info_16 *) &rsp_bytes[rsp_length]; + info_16->handle = handle; + info_16->uuid = common_hal_bleio_uuid_get_uuid16(uuid); + + rsp_length += sizeof(struct bt_att_info_16); + } else { + struct bt_att_info_128 *info_128 = (struct bt_att_info_128 *) &rsp_bytes[rsp_length]; + info_128->handle = handle; + common_hal_bleio_uuid_get_uuid128(uuid, info_128->uuid); + + rsp_length += sizeof(struct bt_att_info_128); + } + + no_data =false; + } // end for + + + if (no_data) { + send_error(conn_handle, BT_ATT_OP_FIND_INFO_REQ, req->start_handle, BT_ATT_ERR_ATTRIBUTE_NOT_FOUND); + } else { + hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, rsp_length, rsp_bytes); + } } int att_find_info_req(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, uint8_t response_buffer[]) { @@ -834,7 +923,7 @@ STATIC void process_find_info_rsp(uint16_t conn_handle, uint8_t dlen, uint8_t da 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[]) { +STATIC void process_find_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)) { @@ -849,11 +938,11 @@ STATIC void process_find_by_type_req(uint16_t conn_handle, uint16_t mtu, uint8_t 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++) { + // if (find_type_req->type == BLE_TYPE_SERVICE_PRIMARY) { + // for (uint16_t i = (find_type_req->start_handle - 1); i < GATT.attributeCount() && i <= (find_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) { + // if ((attribute->type() == find_type_req->type) && (attribute->uuidLength() == value_length) && memcmp(attribute->uuidData(), value, value_length) == 0) { // BLELocalService* service = (BLELocalService*)attribute; // // add the start handle @@ -880,15 +969,15 @@ STATIC void process_find_by_type_req(uint16_t conn_handle, uint16_t mtu, uint8_t } } -void process_read_by_group_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, uint8_t data[]) { +void process_read_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 type_uuid = req->uuid[0] | (req->uuid[1] << 8); // We only support returning services for BT_ATT_OP_READ_GROUP_REQ, which is typically used // for service discovery. if (dlen != sizeof(struct bt_att_read_group_req) + sizeof(type_uuid) || - (type_uuid != BLE_TYPE_PRIMARY_SERVICE && - type_uuid != BLE_TYPE_SECONDARY_SERVICE)) { + (type_uuid != BLE_TYPE_SERVICE_PRIMARY && + type_uuid != BLE_TYPE_SERVICE_SECONDARY)) { send_error(conn_handle, BT_ATT_OP_READ_GROUP_REQ, req->start_handle, BT_ATT_ERR_UNSUPPORTED_GROUP_TYPE); return; } @@ -927,37 +1016,34 @@ void process_read_by_group_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, } mp_obj_t *attribute_obj = bleio_adapter_get_attribute(&common_hal_bleio_adapter_obj, handle); - if (type_uuid != bleio_attribute_type_uuid(attribute_obj)) { - // Not a primary or secondary service. - continue; + if (MP_OBJ_IS_TYPE(attribute_obj, &bleio_service_type)) { + bleio_service_obj_t *service = MP_OBJ_TO_PTR(attribute_obj); + + // Is this a 16-bit or a 128-bit uuid? It must match in size with any previous attribute + // in this transmission. + const uint32_t sizeof_service_uuid = common_hal_bleio_uuid_get_size(service->uuid) / 8; + if (sizeof_first_service_uuid == 0) { + sizeof_first_service_uuid = sizeof_service_uuid; + data_length += sizeof_service_uuid; + } else if (sizeof_first_service_uuid != sizeof_service_uuid) { + // Mismatched sizes, which can't be in the same batch. + // Transmit just what we have so far in this batch. + break; + } + + // Pass the length of ONE bt_att_group_data chunk. + // There may be multiple chunks in this transmission. + rsp->r.len = data_length; + + struct bt_att_group_data *group_data = (struct bt_att_group_data *) &rsp_bytes[rsp_length]; + + group_data->start_handle = service->start_handle; + group_data->end_handle = service->end_handle; + common_hal_bleio_uuid_pack_into(service->uuid, group_data->value); + + rsp_length += data_length; + no_data = false; } - // Now we know it's a service. - bleio_service_obj_t *service = MP_OBJ_TO_PTR(attribute_obj); - - // Is this a 16-bit or a 128-bit uuid? It must match in size with any previous attribute - // in this transmission. - const uint32_t sizeof_service_uuid = common_hal_bleio_uuid_get_size(service->uuid) / 8; - if (sizeof_first_service_uuid == 0) { - sizeof_first_service_uuid = sizeof_service_uuid; - data_length += sizeof_service_uuid; - } else if (sizeof_first_service_uuid != sizeof_service_uuid) { - // Mismatched sizes, which can't be in the same batch. - // Transmit just what we have so far in this batch. - break; - } - - - // Pass the length of ONE bt_att_group_data chunk. There may be multiple ones in this transmission. - rsp->r.len = data_length; - - struct bt_att_group_data *group_data = (struct bt_att_group_data *) &rsp_bytes[rsp_length]; - - group_data->start_handle = service->start_handle; - group_data->end_handle = service->end_handle; - common_hal_bleio_uuid_pack_into(service->uuid, group_data->value); - - rsp_length += data_length; - no_data = false; } if (no_data) { @@ -967,7 +1053,7 @@ void process_read_by_group_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, } } -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[]) { +int att_read_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; @@ -985,7 +1071,7 @@ int att_read_by_group_req(uint16_t conn_handle, uint16_t start_handle, uint16_t 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[]) { +STATIC void process_read_group_rsp(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { if (dlen < 2) { return; // invalid, drop } @@ -1040,7 +1126,7 @@ STATIC void process_read_or_read_blob_req(uint16_t conn_handle, uint16_t mtu, ui //FIX BLELocalAttribute* attribute = GATT.attribute(handle - 1); // enum BLEAttributeType attributeType = attribute->type(); - // if (attributeType == BLE_TYPE_PRIMARY_SERVICE) { + // if (attributeType == BLE_TYPE_SERVICE_PRIMARY) { // if (offset) { // send_error(conn_handle, BT_ATT_ERR_ATTR_NOT_LONG, handle, BT_ATT_ERR_INVALID_PDU); // return; @@ -1118,110 +1204,156 @@ 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[]) { +STATIC void process_read_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; + uint16_t type_uuid = req->uuid[0] | (req->uuid[1] << 8); - if (dlen != sizeof(struct bt_att_read_type_req)) { + if (dlen != sizeof(struct bt_att_read_type_req) + sizeof(type_uuid)) { 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; + typedef struct __packed { + struct bt_att_hdr h; + struct bt_att_read_type_rsp r; + } rsp_t; - // response[0] = BT_ATT_OP_READ_TYPE_RSP; - // response[1] = 0x00; - // response_length = 2; + uint8_t rsp_bytes[mtu]; + rsp_t *rsp = (rsp_t *) rsp_bytes; + rsp->h.code = BT_ATT_OP_READ_TYPE_RSP; + rsp->r.len = 0; - // 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); + // Keeps track of total length of the response. + size_t rsp_length = sizeof(rsp_t); - // if (attribute->type() == readByTypeReq->uuid) { - // if (attribute->type() == BLE_TYPE_CHARACTERISTIC) { - // BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute; + bool no_data = true; - // if (characteristic->value_handle() == handle) { - // // value handle, skip - // continue; - // } + // All the data chunks must have uuid's that are the same size. + // Keep track of the first one to make sure. + size_t sizeof_first_uuid = 0; - // int uuidLen = attribute->uuidLength(); - // int typeSize = (uuidLen == 2) ? 7 : 21; + // Size of a single bt_att_data chunk. Start with the initial size, and + // add the uuid size and other data sizes in the loop below. + size_t data_length = sizeof(struct bt_att_data); - // if (response[1] == 0) { - // response[1] = typeSize; - // } + const uint16_t max_attribute_handle = bleio_adapter_max_attribute_handle(&common_hal_bleio_adapter_obj); + for (uint16_t handle = req->start_handle; + handle <= max_attribute_handle && handle <= req->end_handle; + handle++) { - // if (response[1] != typeSize) { - // // all done, wrong size - // break; - // } + if (rsp_length + data_length > mtu) { + // The next possible bt_att_data chunk won't fit. The response is full. + break; + } - // // add the handle - // memcpy(&response[response_length], &handle, sizeof(handle)); - // response_length += sizeof(handle); + mp_obj_t *attribute_obj = bleio_adapter_get_attribute(&common_hal_bleio_adapter_obj, handle); - // // add the properties - // response[response_length++] = characteristic->properties(); + if (type_uuid == BLE_TYPE_CHARACTERISTIC && + MP_OBJ_IS_TYPE(attribute_obj, &bleio_characteristic_type)) { + // Request is for characteristic declarations. + bleio_characteristic_obj_t *characteristic = MP_OBJ_TO_PTR(attribute_obj); - // // add the value handle - // uint16_t value_handle = (handle + 1); - // memcpy(&response[response_length], &value_handle, sizeof(value_handle)); - // response_length += sizeof(value_handle); + if (characteristic->handle == handle) { + // If the characteristic's handle is this attribute's handle, skip it: + // it's the attribute for characteristic value. We want to return the declaration + // handle attribute instead. (It will probably get skipped below, by the + // handle++). + continue; + } - // // add the UUID - // memcpy(&response[response_length], characteristic->uuidData(), uuidLen); - // response_length += uuidLen; + // Is this a 16-bit or a 128-bit uuid? It must match in size with any previous attribute + // in this transmission. + const uint32_t sizeof_uuid = common_hal_bleio_uuid_get_size(characteristic->uuid) / 8; + if (sizeof_first_uuid == 0) { + sizeof_first_uuid = sizeof_uuid; + data_length += sizeof_uuid; + data_length += sizeof(characteristic_declaration_t); + } else if (sizeof_first_uuid != sizeof_uuid) { + // Mismatched sizes, which can't be in the same batch. + // Transmit just what we have so far in this batch. + break; + } - // // skip the next handle, it's a value handle - // i++; + // Pass the length of ONE bt_att_data chunk. + // There may be multiple chunks in this transmission. + rsp->r.len = data_length; - // if ((response_length + typeSize) > mtu) { - // break; - // } - // } else if (attribute->type() == 0x2902) { - // BLELocalDescriptor* descriptor = (BLELocalDescriptor*)attribute; + struct bt_att_data *att_data = (struct bt_att_data *) &rsp_bytes[rsp_length]; - // // add the handle - // memcpy(&response[response_length], &handle, sizeof(handle)); - // response_length += sizeof(handle); + att_data->handle = characteristic->decl_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; + characteristic_declaration_t *char_decl = (characteristic_declaration_t *) att_data->value; - // response[1] = 2 + valueSize; + // Convert from the bleio properties bit values to the BLE spec properties bit values. + // They are not the same :(. + char_decl->properties = bleio_properties_to_ble_spec_properties(characteristic->props); + char_decl->value_handle = characteristic->handle; + common_hal_bleio_uuid_pack_into(characteristic->uuid, char_decl->uuid); - // break; // all done - // } - // } else if (attribute->type() == BLE_TYPE_CHARACTERISTIC && attribute->uuidLength() == 2 && memcmp(&readByTypeReq->uuid, attribute->uuidData(), 2) == 0) { - // BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute; + // We know the next handle will be the characteristic value handle, so skip it. + handle++; - // // add the handle - // memcpy(&response[response_length], &handle, sizeof(handle)); - // response_length += sizeof(handle); + rsp_length += data_length; + no_data = false; - // // 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; + } else if (MP_OBJ_IS_TYPE(attribute_obj, &bleio_descriptor_type)) { + // See if request is for a descriptor value with a 16-bit UUID, such as the CCCD. + bleio_descriptor_obj_t *descriptor = MP_OBJ_TO_PTR(attribute_obj); + if (common_hal_bleio_uuid_get_size(descriptor->uuid) == 16 && + common_hal_bleio_uuid_get_uuid16(descriptor->uuid) == type_uuid) { - // response[1] = 2 + value_length; + struct bt_att_data *att_data = (struct bt_att_data *) &rsp_bytes[rsp_length]; - // break; // all done - // } - // } + att_data->handle = handle; - // 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); - // } + mp_buffer_info_t bufinfo; + if (!mp_get_buffer(descriptor->value, &bufinfo, MP_BUFFER_READ)) { + break; + } + uint16_t value_size = MIN(mtu - rsp_length, bufinfo.len); + memcpy(att_data->value, bufinfo.buf, value_size); + rsp_length += value_size; + + // Only return one descriptor value. + no_data = false; + break; + } + + } else if (MP_OBJ_IS_TYPE(attribute_obj, &bleio_characteristic_type)) { + // See if request is for a characteristic value with a 16-bit UUID. + bleio_characteristic_obj_t *characteristic = MP_OBJ_TO_PTR(attribute_obj); + if (common_hal_bleio_uuid_get_size(characteristic->uuid) == 16 && + common_hal_bleio_uuid_get_uuid16(characteristic->uuid) == type_uuid) { + + struct bt_att_data *att_data = (struct bt_att_data *) &rsp_bytes[rsp_length]; + + att_data->handle = handle; + + mp_buffer_info_t bufinfo; + if (!mp_get_buffer(characteristic->value, &bufinfo, MP_BUFFER_READ)) { + // This shouldn't happen. There should be a buf in characteristic->value. + break; + } + uint16_t value_size = MIN(mtu - rsp_length, bufinfo.len); + memcpy(att_data->value, bufinfo.buf, value_size); + rsp_length += value_size; + + // Only return one characteristic value. + no_data = false; + break; + } + } + } // end for loop + + if (no_data) { + send_error(conn_handle, BT_ATT_OP_READ_TYPE_REQ, + req->start_handle, BT_ATT_ERR_ATTRIBUTE_NOT_FOUND); + } else { + hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, rsp_length, rsp_bytes); + } } -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[]) { +int att_read_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; @@ -1238,7 +1370,7 @@ int att_read_by_type_req(uint16_t conn_handle, uint16_t start_handle, uint16_t e return send_req_wait_for_rsp(conn_handle, sizeof(req), (uint8_t *) &req, response_buffer); } -STATIC void process_read_by_type_rsp(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { +STATIC void process_read_type_rsp(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { if (dlen < 1) { return; // invalid, drop } @@ -1597,23 +1729,23 @@ void att_process_data(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { break; case BT_ATT_OP_FIND_TYPE_REQ: - process_find_by_type_req(conn_handle, mtu, dlen, data); + process_find_type_req(conn_handle, mtu, dlen, data); break; case BT_ATT_OP_READ_TYPE_REQ: - process_read_by_type_req(conn_handle, mtu, dlen, data); + process_read_type_req(conn_handle, mtu, dlen, data); break; case BT_ATT_OP_READ_TYPE_RSP: - process_read_by_type_rsp(conn_handle, dlen, data); + process_read_type_rsp(conn_handle, dlen, data); break; case BT_ATT_OP_READ_GROUP_REQ: - process_read_by_group_req(conn_handle, mtu, dlen, data); + process_read_group_req(conn_handle, mtu, dlen, data); break; case BT_ATT_OP_READ_GROUP_RSP: - process_read_by_group_rsp(conn_handle, dlen, data); + process_read_group_rsp(conn_handle, dlen, data); break; case BT_ATT_OP_READ_REQ: diff --git a/ports/nrf/common-hal/_bleio/UUID.c b/ports/nrf/common-hal/_bleio/UUID.c index f80352ccb6..0c79e980ee 100644 --- a/ports/nrf/common-hal/_bleio/UUID.c +++ b/ports/nrf/common-hal/_bleio/UUID.c @@ -40,7 +40,7 @@ // If uuid128 is NULL, this is a Bluetooth SIG 16-bit UUID. // 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[16]) { +void common_hal_bleio_uuid_construct(bleio_uuid_obj_t *self, mp_int_t uuid16, const uint8_t uuid128[16]) { self->nrf_ble_uuid.uuid = uuid16; if (uuid128 == NULL) { self->nrf_ble_uuid.type = BLE_UUID_TYPE_BLE; diff --git a/shared-bindings/_bleio/UUID.c b/shared-bindings/_bleio/UUID.c index 6d92cf7931..93f89403b1 100644 --- a/shared-bindings/_bleio/UUID.c +++ b/shared-bindings/_bleio/UUID.c @@ -283,7 +283,7 @@ void bleio_uuid_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t mp_printf(print, "UUID(0x%04x)", common_hal_bleio_uuid_get_uuid16(self)); } else { uint8_t uuid128[16]; - (void) common_hal_bleio_uuid_get_uuid128(self, uuid128); + common_hal_bleio_uuid_get_uuid128(self, uuid128); mp_printf(print, "UUID('" "%02x%02x%02x%02x-" "%02x%02x-" diff --git a/shared-bindings/_bleio/UUID.h b/shared-bindings/_bleio/UUID.h index 178b0ca965..b10cce67f3 100644 --- a/shared-bindings/_bleio/UUID.h +++ b/shared-bindings/_bleio/UUID.h @@ -36,7 +36,7 @@ extern const mp_obj_type_t bleio_uuid_type; extern void common_hal_bleio_uuid_construct(bleio_uuid_obj_t *self, mp_int_t uuid16, const uint8_t uuid128[16]); extern uint32_t common_hal_bleio_uuid_get_uuid16(bleio_uuid_obj_t *self); -extern bool common_hal_bleio_uuid_get_uuid128(bleio_uuid_obj_t *self, uint8_t uuid128[16]); +extern void common_hal_bleio_uuid_get_uuid128(bleio_uuid_obj_t *self, uint8_t uuid128[16]); extern uint32_t common_hal_bleio_uuid_get_size(bleio_uuid_obj_t *self); void common_hal_bleio_uuid_pack_into(bleio_uuid_obj_t *self, uint8_t* buf); diff --git a/shared-module/_bleio/Characteristic.h b/shared-module/_bleio/Characteristic.h index 409a57c76e..7776b1fa57 100644 --- a/shared-module/_bleio/Characteristic.h +++ b/shared-module/_bleio/Characteristic.h @@ -27,6 +27,9 @@ #ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CHARACTERISTIC_H #define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CHARACTERISTIC_H +// These are not the Bluetooth spec values. They are what is used by the Nordic SoftDevice. +// The bit values are in different positions. + typedef enum { CHAR_PROP_NONE = 0, CHAR_PROP_BROADCAST = 1u << 0, @@ -40,4 +43,14 @@ typedef enum { } bleio_characteristic_properties_enum_t; typedef uint8_t bleio_characteristic_properties_t; +// Bluetooth spec property values +#define BT_GATT_CHRC_BROADCAST 0x01 +#define BT_GATT_CHRC_READ 0x02 +#define BT_GATT_CHRC_WRITE_WITHOUT_RESP 0x04 +#define BT_GATT_CHRC_WRITE 0x08 +#define BT_GATT_CHRC_NOTIFY 0x10 +#define BT_GATT_CHRC_INDICATE 0x20 +#define BT_GATT_CHRC_AUTH 0x40 +#define BT_GATT_CHRC_EXT_PROP 0x80 + #endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CHARACTERISTIC_H From 74034d6b9d14bf70a5a65e3f001998f6716c7d46 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 10 Aug 2020 19:46:18 -0400 Subject: [PATCH 25/84] characteristic/cccd r/w; not tested --- devices/ble_hci/common-hal/_bleio/Attribute.h | 15 - devices/ble_hci/common-hal/_bleio/Service.c | 4 +- devices/ble_hci/common-hal/_bleio/UUID.c | 5 + devices/ble_hci/common-hal/_bleio/UUID.h | 17 + devices/ble_hci/common-hal/_bleio/__init__.c | 2 +- devices/ble_hci/common-hal/_bleio/att.c | 388 ++++++++---------- devices/ble_hci/common-hal/_bleio/att.h | 2 - 7 files changed, 193 insertions(+), 240 deletions(-) diff --git a/devices/ble_hci/common-hal/_bleio/Attribute.h b/devices/ble_hci/common-hal/_bleio/Attribute.h index f4b0b7dbba..b8702cae45 100644 --- a/devices/ble_hci/common-hal/_bleio/Attribute.h +++ b/devices/ble_hci/common-hal/_bleio/Attribute.h @@ -30,21 +30,6 @@ #include "shared-module/_bleio/Attribute.h" #include "shared-bindings/_bleio/UUID.h" -// Types returned by attribute table lookups. These are UUIDs. -typedef enum { - BLE_TYPE_UNKNOWN = 0x0000, - BLE_TYPE_SERVICE_PRIMARY = 0x2800, - BLE_TYPE_SERVICE_SECONDARY = 0x2801, - BLE_TYPE_SERVICE_INCLUDE = 0x2802, // not yet implemented by us - BLE_TYPE_CHARACTERISTIC = 0x2803, - BLE_TYPE_CHAR_EXTENDED_PROPS = 0x2900, // not yet implemented by us - BLE_TYPE_CHAR_USER_DESC = 0x2901, // not yet implemented by us - BLE_TYPE_CCCD = 0x2902, - BLE_TYPE_SCCD = 0x2903, // not yet implemented by us - BLE_TYPE_CHAR_PRESENTATION_FMT = 0x2904, // not yet implemented by us - BLE_TYPE_CHAR_AGGREGATE_FMT = 0x2905, // not yet implemented by us -} ble_attribute_type_uuid; - bleio_uuid_obj_t *bleio_attribute_get_uuid(mp_obj_t *attribute); #endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_ATTRIBUTE_H diff --git a/devices/ble_hci/common-hal/_bleio/Service.c b/devices/ble_hci/common-hal/_bleio/Service.c index b6963b7a4a..0b6c830022 100644 --- a/devices/ble_hci/common-hal/_bleio/Service.c +++ b/devices/ble_hci/common-hal/_bleio/Service.c @@ -104,7 +104,7 @@ void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, cccd->base.type = &bleio_descriptor_type; uint16_t zero = 0; - mp_buffer_info_t zero_cccd = { + mp_buffer_info_t zero_cccd_value = { .buf = &zero, .len = sizeof(zero), }; @@ -117,7 +117,7 @@ void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, characteristic->read_perm, // Make CCCD write perm match characteristic read perm. 2, // 2 bytes true, // fixed length - &zero_cccd // Initial value is 0. + &zero_cccd_value // Initial value is 0. ); // Adds CCCD to attribute table, and also extends self->end_handle to include the CCCD. diff --git a/devices/ble_hci/common-hal/_bleio/UUID.c b/devices/ble_hci/common-hal/_bleio/UUID.c index fd8d8bfe9e..a50efc3b1e 100644 --- a/devices/ble_hci/common-hal/_bleio/UUID.c +++ b/devices/ble_hci/common-hal/_bleio/UUID.c @@ -68,3 +68,8 @@ void common_hal_bleio_uuid_pack_into(bleio_uuid_obj_t *self, uint8_t* buf) { common_hal_bleio_uuid_get_uuid128(self, buf); } } + +// Return a uui16 only if this is a standard uuid. Otherwise return BLE_UUID_UNKNOWN. +uint16_t bleio_uuid_get_uuid16_or_unknown(bleio_uuid_obj_t *uuid) { + return uuid->size == 16 ? uuid->uuid16 : BLE_UUID_UNKNOWN; +} diff --git a/devices/ble_hci/common-hal/_bleio/UUID.h b/devices/ble_hci/common-hal/_bleio/UUID.h index deaf76d5c6..1a0ab91c44 100644 --- a/devices/ble_hci/common-hal/_bleio/UUID.h +++ b/devices/ble_hci/common-hal/_bleio/UUID.h @@ -31,6 +31,21 @@ #include "py/obj.h" +// Types returned by attribute table lookups. These are UUIDs. +typedef enum { + BLE_UUID_UNKNOWN = 0x0000, + BLE_UUID_SERVICE_PRIMARY = 0x2800, + BLE_UUID_SERVICE_SECONDARY = 0x2801, + BLE_UUID_SERVICE_INCLUDE = 0x2802, // not yet implemented by us + BLE_UUID_CHARACTERISTIC = 0x2803, + BLE_UUID_CHAR_EXTENDED_PROPS = 0x2900, // not yet implemented by us + BLE_UUID_CHAR_USER_DESC = 0x2901, // not yet implemented by us + BLE_UUID_CCCD = 0x2902, + BLE_UUID_SCCD = 0x2903, // not yet implemented by us + BLE_UUID_CHAR_PRESENTATION_FMT = 0x2904, // not yet implemented by us + BLE_UUID_CHAR_AGGREGATE_FMT = 0x2905, // not yet implemented by us +} ble_standard_uuid; + typedef struct { mp_obj_base_t base; uint8_t size; @@ -38,4 +53,6 @@ typedef struct { uint8_t uuid128[16]; } bleio_uuid_obj_t; +uint16_t bleio_uuid_get_uuid16_or_unknown(bleio_uuid_obj_t *uuid); + #endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_UUID_H diff --git a/devices/ble_hci/common-hal/_bleio/__init__.c b/devices/ble_hci/common-hal/_bleio/__init__.c index 16b4a26e29..e2b463af8a 100644 --- a/devices/ble_hci/common-hal/_bleio/__init__.c +++ b/devices/ble_hci/common-hal/_bleio/__init__.c @@ -117,7 +117,7 @@ void check_hci_error(hci_result_t result) { void bleio_reset() { // Create a UUID object for all CCCD's. cccd_uuid.base.type = &bleio_uuid_type; - common_hal_bleio_uuid_construct(&cccd_uuid, BLE_TYPE_CCCD, NULL); + common_hal_bleio_uuid_construct(&cccd_uuid, BLE_UUID_CCCD, NULL); bleio_hci_reset(); diff --git a/devices/ble_hci/common-hal/_bleio/att.c b/devices/ble_hci/common-hal/_bleio/att.c index 8daddd3a96..e19a73558e 100644 --- a/devices/ble_hci/common-hal/_bleio/att.c +++ b/devices/ble_hci/common-hal/_bleio/att.c @@ -90,29 +90,32 @@ STATIC uint8_t bleio_properties_to_ble_spec_properties(uint8_t bleio_properties) return ble_spec_properties; } -// STATIC uint8_t ble_spec_properties_to_bleio_properties(uint8_t ble_spec_properties) { -// uint8_t bleio_properties = 0; -// if (ble_spec_properties & BT_GATT_CHRC_BROADCAST) { -// bleio_properties |= CHAR_PROP_BROADCAST; -// } -// if (ble_spec_properties & BT_GATT_CHRC_INDICATE) { -// bleio_properties |= CHAR_PROP_INDICATE; -// } -// if (ble_spec_properties & BT_GATT_CHRC_NOTIFY) { -// bleio_properties |= CHAR_PROP_NOTIFY; -// } -// if (ble_spec_properties & BT_GATT_CHRC_READ) { -// bleio_properties |= CHAR_PROP_READ; -// } -// if (ble_spec_properties & BT_GATT_CHRC_WRITE) { -// bleio_properties |= CHAR_PROP_WRITE; -// } -// if (ble_spec_properties & BT_GATT_CHRC_WRITE_WITHOUT_RESP) { -// bleio_properties |= CHAR_PROP_WRITE_NO_RESPONSE; -// } +//FIX not currently used; reenable when used. +#if 0 +STATIC uint8_t ble_spec_properties_to_bleio_properties(uint8_t ble_spec_properties) { + uint8_t bleio_properties = 0; + if (ble_spec_properties & BT_GATT_CHRC_BROADCAST) { + bleio_properties |= CHAR_PROP_BROADCAST; + } + if (ble_spec_properties & BT_GATT_CHRC_INDICATE) { + bleio_properties |= CHAR_PROP_INDICATE; + } + if (ble_spec_properties & BT_GATT_CHRC_NOTIFY) { + bleio_properties |= CHAR_PROP_NOTIFY; + } + if (ble_spec_properties & BT_GATT_CHRC_READ) { + bleio_properties |= CHAR_PROP_READ; + } + if (ble_spec_properties & BT_GATT_CHRC_WRITE) { + bleio_properties |= CHAR_PROP_WRITE; + } + if (ble_spec_properties & BT_GATT_CHRC_WRITE_WITHOUT_RESP) { + bleio_properties |= CHAR_PROP_WRITE_NO_RESPONSE; + } -// return bleio_properties; -// } + return bleio_properties; +} +#endif // #if 0 STATIC void send_error(uint16_t conn_handle, uint8_t opcode, uint16_t handle, uint8_t code) { struct __packed { @@ -244,7 +247,7 @@ bool att_disconnect_from_address(bt_addr_le_t *addr) { // BLEUuid serviceUuid(serviceUuidFilter); // while (reqEnd_handle == 0xffff) { -// int respLength = readByGroupReq(conn_handle, reqStart_handle, reqEnd_handle, BLE_TYPE_SERVICE_PRIMARY, response_buffer); +// int respLength = readByGroupReq(conn_handle, reqStart_handle, reqEnd_handle, BLE_UUID_SERVICE_PRIMARY, response_buffer); // if (respLength == 0) { // return false; @@ -305,7 +308,7 @@ bool att_disconnect_from_address(bt_addr_le_t *addr) { // reqEnd_handle = service->end_handle(); // while (1) { -// int respLength = readByTypeReq(conn_handle, reqStart_handle, reqEnd_handle, BLE_TYPE_CHARACTERISTIC, response_buffer); +// int respLength = readByTypeReq(conn_handle, reqStart_handle, reqEnd_handle, BLE_UUID_CHARACTERISTIC, response_buffer); // if (respLength == 0) { // return false; @@ -532,24 +535,30 @@ void att_remove_connection(uint16_t handle, uint8_t reason) { } if (peer_index == -1) { - // bail not found + // Peer 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; + // Clear CCCD values on disconnect. + size_t max_attribute_handle = bleio_adapter_max_attribute_handle(&common_hal_bleio_adapter_obj); + for (size_t i = 1; handle <= max_attribute_handle; i++) { + mp_obj_t attribute_obj = bleio_adapter_get_attribute(&common_hal_bleio_adapter_obj, handle); - // characteristic->writeCccdValue(bleDevice, 0x0000); - // } - // } + uint16_t zero = 0; + mp_buffer_info_t zero_cccd_value = { + .buf = &zero, + .len = sizeof(zero), + }; + + if (MP_OBJ_IS_TYPE(attribute_obj, &bleio_descriptor_type)) { + bleio_descriptor_obj_t *descriptor = MP_OBJ_TO_PTR(attribute_obj); + if (bleio_uuid_get_uuid16_or_unknown(descriptor->uuid) == BLE_UUID_CCCD) { + common_hal_bleio_descriptor_set_value(descriptor, &zero_cccd_value); + } + } + } long_write_handle = BLE_GATT_HANDLE_INVALID; long_write_value_length = 0; @@ -564,11 +573,6 @@ void att_remove_connection(uint16_t handle, uint8_t reason) { bleio_connections[peer_index].role = 0x00; memset(&bleio_connections[peer_index].addr, 0x00, sizeof(bleio_connections[peer_index].addr)); bleio_connections[peer_index].mtu = BT_ATT_DEFAULT_LE_MTU; - - //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) { @@ -582,17 +586,6 @@ uint16_t att_conn_handle(bt_addr_le_t *addr) { 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) { @@ -648,30 +641,11 @@ bool att_disconnect_all(void) { 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 = BT_ATT_DEFAULT_LE_MTU; - - //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_notify(uint16_t handle, const uint8_t* value, int length) { int num_notifications = 0; @@ -938,7 +912,7 @@ STATIC void process_find_type_req(uint16_t conn_handle, uint16_t mtu, uint8_t dl response_length = 1; //FIX - // if (find_type_req->type == BLE_TYPE_SERVICE_PRIMARY) { + // if (find_type_req->type == BLE_UUID_SERVICE_PRIMARY) { // for (uint16_t i = (find_type_req->start_handle - 1); i < GATT.attributeCount() && i <= (find_type_req->end_handle - 1); i++) { // BLELocalAttribute* attribute = GATT.attribute(i); @@ -976,8 +950,8 @@ void process_read_group_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, ui // We only support returning services for BT_ATT_OP_READ_GROUP_REQ, which is typically used // for service discovery. if (dlen != sizeof(struct bt_att_read_group_req) + sizeof(type_uuid) || - (type_uuid != BLE_TYPE_SERVICE_PRIMARY && - type_uuid != BLE_TYPE_SERVICE_SECONDARY)) { + (type_uuid != BLE_UUID_SERVICE_PRIMARY && + type_uuid != BLE_UUID_SERVICE_SECONDARY)) { send_error(conn_handle, BT_ATT_OP_READ_GROUP_REQ, req->start_handle, BT_ATT_ERR_UNSUPPORTED_GROUP_TYPE); return; } @@ -1109,95 +1083,93 @@ STATIC void process_read_or_read_blob_req(uint16_t conn_handle, uint16_t mtu, ui } - //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; - // } + if (handle > bleio_adapter_max_attribute_handle(&common_hal_bleio_adapter_obj)) { + send_error(conn_handle, opcode, handle, BT_ATT_ERR_ATTRIBUTE_NOT_FOUND); + return; + } - uint8_t response[mtu]; - uint16_t response_length; + typedef struct __packed { + struct bt_att_hdr h; + struct bt_att_read_rsp r; // Same as bt_att_read_blob_rsp. + } rsp_t; - response[0] = response_opcode; - response_length = 1; + uint8_t rsp_bytes[mtu]; + rsp_t *rsp = (rsp_t *) rsp_bytes; + rsp->h.code = response_opcode; - //FIX BLELocalAttribute* attribute = GATT.attribute(handle - 1); - // enum BLEAttributeType attributeType = attribute->type(); + // Keeps track of total length of the response. + size_t rsp_length = sizeof(rsp_t); - // if (attributeType == BLE_TYPE_SERVICE_PRIMARY) { - // if (offset) { - // send_error(conn_handle, BT_ATT_ERR_ATTR_NOT_LONG, handle, BT_ATT_ERR_INVALID_PDU); - // return; - // } + mp_obj_t *attribute_obj = bleio_adapter_get_attribute(&common_hal_bleio_adapter_obj, handle); + if (MP_OBJ_IS_TYPE(attribute_obj, &bleio_service_type)) { + if (offset) { + send_error(conn_handle, BT_ATT_ERR_ATTRIBUTE_NOT_LONG, handle, BT_ATT_ERR_INVALID_PDU); + return; + } - // BLELocalService* service = (BLELocalService*)attribute; + bleio_service_obj_t *service = MP_OBJ_TO_PTR(attribute_obj); + const uint32_t sizeof_service_uuid = common_hal_bleio_uuid_get_size(service->uuid) / 8; - // // 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; + common_hal_bleio_uuid_pack_into(service->uuid, rsp->r.value); + rsp_length += sizeof_service_uuid; - // if (characteristic->handle() == handle) { - // if (offset) { - // send_error(conn_handle, opcode, handle, BT_ATT_ERR_ATTR_NOT_LONG); - // return; - // } + } else if (MP_OBJ_IS_TYPE(attribute_obj, &bleio_characteristic_type)) { + bleio_characteristic_obj_t *characteristic = MP_OBJ_TO_PTR(attribute_obj); + if (characteristic->decl_handle == handle) { + // Read characteristic declaration. Return properties, value handle, and uuid. + if (offset) { + send_error(conn_handle, opcode, handle, BT_ATT_ERR_ATTRIBUTE_NOT_LONG); + return; + } - // // add the properties - // response[response_length++] = characteristic->properties(); + characteristic_declaration_t *char_decl = (characteristic_declaration_t *) rsp->r.value; - // // 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); + // Convert from the bleio properties bit values to the BLE spec properties bit values. + // They are not the same :(. + char_decl->properties = bleio_properties_to_ble_spec_properties(characteristic->props); + char_decl->value_handle = characteristic->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; - // } + const uint32_t sizeof_char_uuid = common_hal_bleio_uuid_get_size(characteristic->uuid) / 8; + common_hal_bleio_uuid_pack_into(characteristic->uuid, char_decl->uuid); + rsp_length += sizeof_char_uuid; - // uint16_t value_length = characteristic->value_length(); + } else { + // Read characteristic value. - // if (offset >= value_length) { - // send_error(conn_handle, opcode, handle, BT_ATT_ERR_INVALID_OFFSET); - // return; - // } + if ((characteristic->props & CHAR_PROP_READ) == 0) { + send_error(conn_handle, opcode, handle, BT_ATT_ERR_READ_NOT_PERMITTED); + return; + } - // value_length = min(mtu - response_length, value_length - offset); + mp_buffer_info_t bufinfo; + mp_get_buffer(characteristic->value, &bufinfo, MP_BUFFER_READ); - // 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; + if (offset >= bufinfo.len) { + send_error(conn_handle, opcode, handle, BT_ATT_ERR_INVALID_OFFSET); + return; + } - // uint16_t value_length = descriptor->valueSize(); + size_t value_length = MIN(mtu - rsp_length, bufinfo.len - offset); + memcpy(rsp->r.value, bufinfo.buf + offset, value_length); + rsp_length += value_length; + } + } else if (MP_OBJ_IS_TYPE(attribute_obj, &bleio_descriptor_type)) { + bleio_descriptor_obj_t *descriptor = MP_OBJ_TO_PTR(attribute_obj); - // if (offset >= value_length) { - // send_error(conn_handle, opcode, handle, BT_ATT_ERR_INVALID_OFFSET); - // return; - // } + mp_buffer_info_t bufinfo; + mp_get_buffer(descriptor->value, &bufinfo, MP_BUFFER_READ); - // value_length = min(mtu - response_length, value_length - offset); + if (offset >= bufinfo.len) { + send_error(conn_handle, opcode, handle, BT_ATT_ERR_INVALID_OFFSET); + return; + } - // memcpy(&response[response_length], descriptor->value() + offset, value_length); - // response_length += value_length; - // } + size_t value_length = MIN(mtu - rsp_length, bufinfo.len - offset); + memcpy(rsp->r.value, bufinfo.buf + offset, value_length); + rsp_length += value_length; + } - hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, response_length, response); + hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, rsp_length, rsp_bytes); } STATIC void process_read_rsp(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { @@ -1248,7 +1220,7 @@ STATIC void process_read_type_req(uint16_t conn_handle, uint16_t mtu, uint8_t dl mp_obj_t *attribute_obj = bleio_adapter_get_attribute(&common_hal_bleio_adapter_obj, handle); - if (type_uuid == BLE_TYPE_CHARACTERISTIC && + if (type_uuid == BLE_UUID_CHARACTERISTIC && MP_OBJ_IS_TYPE(attribute_obj, &bleio_characteristic_type)) { // Request is for characteristic declarations. bleio_characteristic_obj_t *characteristic = MP_OBJ_TO_PTR(attribute_obj); @@ -1299,9 +1271,7 @@ STATIC void process_read_type_req(uint16_t conn_handle, uint16_t mtu, uint8_t dl } else if (MP_OBJ_IS_TYPE(attribute_obj, &bleio_descriptor_type)) { // See if request is for a descriptor value with a 16-bit UUID, such as the CCCD. bleio_descriptor_obj_t *descriptor = MP_OBJ_TO_PTR(attribute_obj); - if (common_hal_bleio_uuid_get_size(descriptor->uuid) == 16 && - common_hal_bleio_uuid_get_uuid16(descriptor->uuid) == type_uuid) { - + if (bleio_uuid_get_uuid16_or_unknown(descriptor->uuid) == type_uuid) { struct bt_att_data *att_data = (struct bt_att_data *) &rsp_bytes[rsp_length]; att_data->handle = handle; @@ -1322,8 +1292,7 @@ STATIC void process_read_type_req(uint16_t conn_handle, uint16_t mtu, uint8_t dl } else if (MP_OBJ_IS_TYPE(attribute_obj, &bleio_characteristic_type)) { // See if request is for a characteristic value with a 16-bit UUID. bleio_characteristic_obj_t *characteristic = MP_OBJ_TO_PTR(attribute_obj); - if (common_hal_bleio_uuid_get_size(characteristic->uuid) == 16 && - common_hal_bleio_uuid_get_uuid16(characteristic->uuid) == type_uuid) { + if (bleio_uuid_get_uuid16_or_unknown(characteristic->uuid) == type_uuid) { struct bt_att_data *att_data = (struct bt_att_data *) &rsp_bytes[rsp_length]; @@ -1381,7 +1350,8 @@ STATIC void process_read_type_rsp(uint16_t conn_handle, uint8_t dlen, uint8_t da // Handles BT_ATT_OP_WRITE_REQ or BT_ATT_OP_WRITE_ STATIC void process_write_req_or_cmd(uint16_t conn_handle, uint16_t mtu, uint8_t op, uint8_t dlen, uint8_t data[]) { // struct bt_att_write_cmd is identical, so don't bother to split code paths based on opcode. - //FIX REMOVE this later struct bt_att_write_req *req = (struct bt_att_write_req *) data; + struct bt_att_write_req *req = (struct bt_att_write_req *) data; + bool with_response = (op == BT_ATT_OP_WRITE_REQ); if (dlen < sizeof(struct bt_att_write_req)) { @@ -1391,81 +1361,59 @@ STATIC void process_write_req_or_cmd(uint16_t conn_handle, uint16_t mtu, uint8_t return; } - //FIX why cast? - // if ((uint16_t)(req->handle - 1) > GATT.attributeCount()) { - // if (with_response) { - // send_error(conn_handle, BT_ATT_OP_WRITE_REQ, handle, BT_ATT_ERR_ATTR_NOT_FOUND); - // } - // return; - // } + if (req->handle > bleio_adapter_max_attribute_handle(&common_hal_bleio_adapter_obj)) { + if (with_response) { + send_error(conn_handle, BT_ATT_OP_WRITE_REQ, req->handle, BT_ATT_ERR_ATTRIBUTE_NOT_FOUND); + } + return; + } - // uint8_t value_length = dlen - sizeof(req->handle); - // uint8_t* value = &data[sizeof(req->handle)]; + size_t value_length = dlen - sizeof(struct bt_att_write_req); - // BLELocalAttribute* attribute = GATT.attribute(req->handle - 1); + mp_buffer_info_t bufinfo; + bufinfo.buf = req->value; + bufinfo.len = value_length; - // if (attribute->type() == BLE_TYPE_CHARACTERISTIC) { - // BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute; + mp_obj_t attribute_obj = bleio_adapter_get_attribute(&common_hal_bleio_adapter_obj, req->handle); - // if (req->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; - // } + if (MP_OBJ_IS_TYPE(attribute_obj, &bleio_characteristic_type)) { + bleio_characteristic_obj_t *characteristic = MP_OBJ_TO_PTR(attribute_obj); - // 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; + // Don't write the characteristic declaration. + // Also, this must be a writable characteristic. + if (req->handle != characteristic->handle || + (with_response + ? (characteristic->props & CHAR_PROP_WRITE) == 0 + : (characteristic->props & CHAR_PROP_WRITE_NO_RESPONSE) == 0)) { + if (with_response) { + send_error(conn_handle, BT_ATT_OP_WRITE_REQ, req->handle, BT_ATT_ERR_WRITE_NOT_PERMITTED); + } + return; + } - // // 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; - // } + common_hal_bleio_characteristic_set_value(characteristic, &bufinfo); - // // get the previous handle, should be the characteristic for the CCCD - // attribute = GATT.attribute(handle - 2); + } else if (MP_OBJ_IS_TYPE(attribute_obj, &bleio_descriptor_type)) { + bleio_descriptor_obj_t *descriptor = MP_OBJ_TO_PTR(attribute_obj); + // Only CCCD's are writable. + if (bleio_uuid_get_uuid16_or_unknown(descriptor->uuid) != BLE_UUID_CCCD) { + if (with_response) { + send_error(conn_handle, BT_ATT_OP_WRITE_REQ, req->handle, BT_ATT_ERR_WRITE_NOT_PERMITTED); + } + return; + } - // 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; - // } + //FIX need to set up event handlers, etc.? + common_hal_bleio_descriptor_set_value(descriptor, &bufinfo); + } if (with_response) { - uint8_t response[mtu]; - uint16_t response_length; + // There's no data in the response. We just indicate the write happened. + struct bt_att_hdr rsp = { + .code = BT_ATT_OP_READ_REQ, + }; - response[0] = BT_ATT_OP_WRITE_RSP; - response_length = 1; - - hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, response_length, response); + hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, sizeof(rsp), (uint8_t *) &rsp); } } @@ -1508,7 +1456,7 @@ STATIC void process_prepare_write_req(uint16_t conn_handle, uint16_t mtu, uint8_ return; } - if (characteristic->props & CHAR_PROP_WRITE) { + if ((characteristic->props & CHAR_PROP_WRITE) == 0) { send_error(conn_handle, BT_ATT_OP_PREPARE_WRITE_REQ, handle, BT_ATT_ERR_WRITE_NOT_PERMITTED); return; } @@ -1578,7 +1526,7 @@ STATIC void process_exec_write_req(uint16_t conn_handle, uint16_t mtu, uint8_t d hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, response_length, response); } -STATIC void process_handle_notify_or_indicate(uint16_t conn_handle, uint8_t opcode, uint8_t dlen, uint8_t data[]) { +STATIC void process_notify_or_indicate(uint16_t conn_handle, uint8_t opcode, uint8_t dlen, uint8_t data[]) { if (dlen < 2) { return; // drop } @@ -1629,7 +1577,7 @@ STATIC void process_handle_notify_or_indicate(uint16_t conn_handle, uint8_t opco } } -STATIC void process_handle_confirm(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { +STATIC void process_confirm(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { (void) conn_handle; (void) dlen; (void) data; @@ -1776,11 +1724,11 @@ void att_process_data(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { case BT_ATT_OP_NOTIFY: case BT_ATT_OP_INDICATE: - process_handle_notify_or_indicate(conn_handle, opcode, dlen, data); + process_notify_or_indicate(conn_handle, opcode, dlen, data); break; case BT_ATT_OP_CONFIRM: - process_handle_confirm(conn_handle, dlen, data); + process_confirm(conn_handle, dlen, data); break; case BT_ATT_OP_READ_MULT_REQ: diff --git a/devices/ble_hci/common-hal/_bleio/att.h b/devices/ble_hci/common-hal/_bleio/att.h index 48f7836e0e..820e86bfb6 100644 --- a/devices/ble_hci/common-hal/_bleio/att.h +++ b/devices/ble_hci/common-hal/_bleio/att.h @@ -32,8 +32,6 @@ void bleio_att_reset(void); -//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); From 92cf56004fedb412cde1ac5159ef23df7398fa20 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 10 Aug 2020 22:33:20 -0400 Subject: [PATCH 26/84] blue_uart_echo_test from Bluefruit app is working --- devices/ble_hci/common-hal/_bleio/att.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/devices/ble_hci/common-hal/_bleio/att.c b/devices/ble_hci/common-hal/_bleio/att.c index e19a73558e..603f1dde34 100644 --- a/devices/ble_hci/common-hal/_bleio/att.c +++ b/devices/ble_hci/common-hal/_bleio/att.c @@ -1032,7 +1032,7 @@ int att_read_group_req(uint16_t conn_handle, uint16_t start_handle, uint16_t end struct bt_att_hdr h; struct bt_att_read_group_req r; } req = { { - .code = BT_ATT_OP_ERROR_RSP, + .code = BT_ATT_OP_READ_GROUP_REQ, }, { .start_handle = start_handle, .end_handle = end_handle, @@ -1410,7 +1410,7 @@ STATIC void process_write_req_or_cmd(uint16_t conn_handle, uint16_t mtu, uint8_t if (with_response) { // There's no data in the response. We just indicate the write happened. struct bt_att_hdr rsp = { - .code = BT_ATT_OP_READ_REQ, + .code = BT_ATT_OP_WRITE_RSP, }; hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, sizeof(rsp), (uint8_t *) &rsp); From 06f3b4048a4ec18d9e46444972d12dc677745793 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 11 Aug 2020 16:21:16 -0400 Subject: [PATCH 27/84] fix #3228 for nrf; still needs to be fixed for HCI; tested --- .../common-hal/_bleio/Characteristic.c | 28 ++++++++++--- .../common-hal/_bleio/Characteristic.h | 4 +- .../ble_hci/common-hal/_bleio/Connection.c | 22 +++++----- .../ble_hci/common-hal/_bleio/Connection.h | 2 +- ports/nrf/common-hal/_bleio/Adapter.c | 3 ++ ports/nrf/common-hal/_bleio/Characteristic.c | 10 ++--- ports/nrf/common-hal/_bleio/Characteristic.h | 2 +- ports/nrf/common-hal/_bleio/Connection.c | 42 ++++++++++--------- ports/nrf/common-hal/_bleio/Connection.h | 5 ++- ports/nrf/common-hal/_bleio/Descriptor.h | 1 - ports/nrf/common-hal/_bleio/Service.c | 4 +- ports/nrf/common-hal/_bleio/Service.h | 1 - shared-bindings/_bleio/Characteristic.c | 18 ++------ shared-bindings/_bleio/Characteristic.h | 10 ++--- shared-bindings/_bleio/Service.c | 24 +---------- shared-bindings/_bleio/Service.h | 4 +- shared-bindings/_bleio/__init__.h | 1 - 17 files changed, 85 insertions(+), 96 deletions(-) diff --git a/devices/ble_hci/common-hal/_bleio/Characteristic.c b/devices/ble_hci/common-hal/_bleio/Characteristic.c index b62957ea6a..4e69c3522c 100644 --- a/devices/ble_hci/common-hal/_bleio/Characteristic.c +++ b/devices/ble_hci/common-hal/_bleio/Characteristic.c @@ -47,7 +47,8 @@ void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, self->props = props; self->read_perm = read_perm; self->write_perm = write_perm; - self->descriptor_list = NULL; + self->descriptor_linked_list = mp_obj_new_list(0, NULL); + self->watchers_list = mp_obj_new_list(0, NULL); const mp_int_t max_length_max = 512; if (max_length < 0 || max_length > max_length_max) { @@ -67,8 +68,8 @@ void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, } } -bleio_descriptor_obj_t *common_hal_bleio_characteristic_get_descriptor_list(bleio_characteristic_obj_t *self) { - return self->descriptor_list; +bleio_descriptor_obj_t *common_hal_bleio_characteristic_get_descriptor_linked_list(bleio_characteristic_obj_t *self) { + return self->descriptor_linked_list; } bleio_service_obj_t *common_hal_bleio_characteristic_get_service(bleio_characteristic_obj_t *self) { @@ -153,8 +154,8 @@ void common_hal_bleio_characteristic_add_descriptor(bleio_characteristic_obj_t * self->service->end_handle = descriptor->handle; // Link together all the descriptors for this characteristic. - descriptor->next = self->descriptor_list; - self->descriptor_list = descriptor; + descriptor->next = self->descriptor_linked_list; + self->descriptor_linked_list = descriptor; } void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, bool notify, bool indicate) { @@ -201,3 +202,20 @@ void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, // } } + +bool bleio_characteristic_set_local_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo) { + if (self->fixed_length && bufinfo->len != self->max_length) { + return false; + } + if (bufinfo->len > self->max_length) { + bool + } + + mp_buffer_info_t char_bufinfo; + if (!mp_get_buffer(characteristic->value, &bufinfo, MP_BUFFER_WRITE)) { + return false; + } + memcpy(&char_bufinfo->buf, bufinfo->buf, bufinfo->len); + + for (size_t i; i < characteristic->set_callbacks. +} diff --git a/devices/ble_hci/common-hal/_bleio/Characteristic.h b/devices/ble_hci/common-hal/_bleio/Characteristic.h index ce8302fcf8..cc5ba4108b 100644 --- a/devices/ble_hci/common-hal/_bleio/Characteristic.h +++ b/devices/ble_hci/common-hal/_bleio/Characteristic.h @@ -40,6 +40,8 @@ typedef struct _bleio_characteristic_obj { bleio_service_obj_t *service; bleio_uuid_obj_t *uuid; mp_obj_t value; + mp_obj_list_t watcher_list; + mp_obj_list_t descriptor_linked_list; uint16_t max_length; bool fixed_length; uint16_t decl_handle; @@ -47,7 +49,7 @@ typedef struct _bleio_characteristic_obj { bleio_characteristic_properties_t props; bleio_attribute_security_mode_t read_perm; bleio_attribute_security_mode_t write_perm; - bleio_descriptor_obj_t *descriptor_list; + bleio_descriptor_obj_t *descriptor_linked_list; uint16_t user_desc_handle; uint16_t cccd_handle; uint16_t sccd_handle; diff --git a/devices/ble_hci/common-hal/_bleio/Connection.c b/devices/ble_hci/common-hal/_bleio/Connection.c index 6b528552ae..98fa4d1f72 100644 --- a/devices/ble_hci/common-hal/_bleio/Connection.c +++ b/devices/ble_hci/common-hal/_bleio/Connection.c @@ -319,7 +319,7 @@ static volatile bool m_discovery_successful; // } void bleio_connection_clear(bleio_connection_internal_t *self) { - self->remote_service_list = NULL; + self->remote_service_linked_list = NULL; //FIX self->conn_handle = BLE_CONN_HANDLE_INVALID; self->pair_status = PAIR_NOT_PAIRED; @@ -449,7 +449,7 @@ void common_hal_bleio_connection_set_connection_interval(bleio_connection_intern // } // 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; +// bleio_service_obj_t* tail = connection->remote_service_linked_list; // for (size_t i = 0; i < response->count; ++i) { // ble_gattc_service_t *gattc_service = &response->services[i]; @@ -482,7 +482,7 @@ void common_hal_bleio_connection_set_connection_interval(bleio_connection_intern // tail = service; // } -// connection->remote_service_list = tail; +// connection->remote_service_linked_list = tail; // if (response->count > 0) { // m_discovery_successful = true; @@ -581,7 +581,7 @@ void common_hal_bleio_connection_set_connection_interval(bleio_connection_intern // 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)); +// mp_obj_list_append(m_desc_discovery_characteristic->descriptor_linked_list, MP_OBJ_FROM_PTR(descriptor)); // } // if (response->count > 0) { @@ -622,7 +622,7 @@ void common_hal_bleio_connection_set_connection_interval(bleio_connection_intern // ble_drv_add_event_handler(discovery_on_ble_evt, self); // // Start over with an empty list. -// self->remote_service_list = NULL; +// self->remote_service_linked_list = NULL; // if (service_uuids_whitelist == mp_const_none) { // // List of service UUID's not given, so discover all available services. @@ -634,7 +634,7 @@ void common_hal_bleio_connection_set_connection_interval(bleio_connection_intern // // 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; +// const bleio_service_obj_t *service = self->remote_service_linked_list; // next_service_start_handle = service->end_handle + 1; // } // } else { @@ -658,7 +658,7 @@ void common_hal_bleio_connection_set_connection_interval(bleio_connection_intern // } -// bleio_service_obj_t *service = self->remote_service_list; +// bleio_service_obj_t *service = self->remote_service_linked_list; // while (service != NULL) { // // Skip the service if it had an unknown (unregistered) UUID. // if (service->uuid == NULL) { @@ -707,14 +707,14 @@ void common_hal_bleio_connection_set_connection_interval(bleio_connection_intern // // 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. +// // discover_next_descriptors() appends to the descriptor_linked_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; +// const bleio_descriptor_obj_t *descriptor = characteristic->descriptor_linked_list; // next_desc_start_handle = descriptor->handle + 1; // } // } @@ -730,8 +730,8 @@ mp_obj_tuple_t *common_hal_bleio_connection_discover_remote_services(bleio_conne //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); - self->connection->remote_service_list = NULL; + mp_obj_tuple_t *services_tuple = service_linked_list_to_tuple(self->connection->remote_service_linked_list); + self->connection->remote_service_linked_list = NULL; return services_tuple; } diff --git a/devices/ble_hci/common-hal/_bleio/Connection.h b/devices/ble_hci/common-hal/_bleio/Connection.h index 8b9790d9ed..efd496ecc5 100644 --- a/devices/ble_hci/common-hal/_bleio/Connection.h +++ b/devices/ble_hci/common-hal/_bleio/Connection.h @@ -50,7 +50,7 @@ typedef struct { uint16_t conn_handle; bool is_central; // Remote services discovered when this peripheral is acting as a client. - bleio_service_obj_t *remote_service_list; + bleio_service_obj_t *remote_service_linked_list; // The advertising data and scan response buffers are held by us, not by the SD, so we must // maintain them and not change it. If we need to change the contents during advertising, // there are tricks to get the SD to notice (see DevZone - TBS). diff --git a/ports/nrf/common-hal/_bleio/Adapter.c b/ports/nrf/common-hal/_bleio/Adapter.c index 0b23bb7bfa..dffaaf8b85 100644 --- a/ports/nrf/common-hal/_bleio/Adapter.c +++ b/ports/nrf/common-hal/_bleio/Adapter.c @@ -352,6 +352,8 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable if (enabled) { for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { bleio_connection_internal_t *connection = &bleio_connections[i]; + // Reset connection. + bleio_connection_clear(connection); connection->conn_handle = BLE_CONN_HANDLE_INVALID; } bleio_adapter_reset_name(self); @@ -576,6 +578,7 @@ mp_obj_t common_hal_bleio_adapter_connect(bleio_adapter_obj_t *self, bleio_addre 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) { + connection->is_central = true; return bleio_connection_new_from_internal(connection); } } diff --git a/ports/nrf/common-hal/_bleio/Characteristic.c b/ports/nrf/common-hal/_bleio/Characteristic.c index d507cecca4..cacd53417a 100644 --- a/ports/nrf/common-hal/_bleio/Characteristic.c +++ b/ports/nrf/common-hal/_bleio/Characteristic.c @@ -90,7 +90,7 @@ void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, self->props = props; self->read_perm = read_perm; self->write_perm = write_perm; - self->descriptor_list = NULL; + self->descriptor_list = mp_obj_new_list(0, 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) { @@ -111,8 +111,8 @@ void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, } } -bleio_descriptor_obj_t *common_hal_bleio_characteristic_get_descriptor_list(bleio_characteristic_obj_t *self) { - return self->descriptor_list; +mp_obj_tuple_t *common_hal_bleio_characteristic_get_descriptors(bleio_characteristic_obj_t *self) { + return mp_obj_new_tuple(self->descriptor_list->len, self->descriptor_list->items); } bleio_service_obj_t *common_hal_bleio_characteristic_get_service(bleio_characteristic_obj_t *self) { @@ -218,8 +218,8 @@ void common_hal_bleio_characteristic_add_descriptor(bleio_characteristic_obj_t * check_nrf_error(sd_ble_gatts_descriptor_add(self->handle, &desc_attr, &descriptor->handle)); - descriptor->next = self->descriptor_list; - self->descriptor_list = descriptor; + mp_obj_list_append(MP_OBJ_FROM_PTR(self->descriptor_list), + MP_OBJ_FROM_PTR(descriptor)); } void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, bool notify, bool indicate) { diff --git a/ports/nrf/common-hal/_bleio/Characteristic.h b/ports/nrf/common-hal/_bleio/Characteristic.h index bb8f28495e..19970ef820 100644 --- a/ports/nrf/common-hal/_bleio/Characteristic.h +++ b/ports/nrf/common-hal/_bleio/Characteristic.h @@ -46,7 +46,7 @@ typedef struct _bleio_characteristic_obj { bleio_characteristic_properties_t props; bleio_attribute_security_mode_t read_perm; bleio_attribute_security_mode_t write_perm; - bleio_descriptor_obj_t *descriptor_list; + mp_obj_list_t *descriptor_list; uint16_t user_desc_handle; uint16_t cccd_handle; uint16_t sccd_handle; diff --git a/ports/nrf/common-hal/_bleio/Connection.c b/ports/nrf/common-hal/_bleio/Connection.c index 00c1acd4d4..fccb5a22a7 100644 --- a/ports/nrf/common-hal/_bleio/Connection.c +++ b/ports/nrf/common-hal/_bleio/Connection.c @@ -325,10 +325,11 @@ bool connection_on_ble_evt(ble_evt_t *ble_evt, void *self_in) { } void bleio_connection_clear(bleio_connection_internal_t *self) { - self->remote_service_list = NULL; + mp_obj_list_clear(MP_OBJ_FROM_PTR(self->remote_service_list)); self->conn_handle = BLE_CONN_HANDLE_INVALID; self->pair_status = PAIR_NOT_PAIRED; + self->is_central = false; bonding_clear_keys(&self->bonding_keys); } @@ -452,8 +453,6 @@ STATIC bool discover_next_descriptors(bleio_connection_internal_t* connection, b } 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]; @@ -481,12 +480,10 @@ STATIC void on_primary_srv_discovery_rsp(ble_gattc_evt_prim_srvc_disc_rsp_t *res service->uuid = NULL; } - service->next = tail; - tail = service; + mp_obj_list_append(MP_OBJ_FROM_PTR(connection->remote_service_list), + MP_OBJ_FROM_PTR(service)); } - connection->remote_service_list = tail; - if (response->count > 0) { m_discovery_successful = true; } @@ -528,7 +525,8 @@ STATIC void on_char_discovery_rsp(ble_gattc_evt_char_disc_rsp_t *response, bleio 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)); + mp_obj_list_append(MP_OBJ_FROM_PTR(m_char_discovery_service->characteristic_list), + MP_OBJ_FROM_PTR(characteristic)); } if (response->count > 0) { @@ -584,7 +582,8 @@ STATIC void on_desc_discovery_rsp(ble_gattc_evt_desc_disc_rsp_t *response, bleio 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)); + mp_obj_list_append(MP_OBJ_FROM_PTR(m_desc_discovery_characteristic->descriptor_list), + MP_OBJ_FROM_PTR(descriptor)); } if (response->count > 0) { @@ -625,7 +624,7 @@ STATIC void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t ble_drv_add_event_handler(discovery_on_ble_evt, self); // Start over with an empty list. - self->remote_service_list = NULL; + self->remote_service_list = mp_obj_new_list(0, NULL); if (service_uuids_whitelist == mp_const_none) { // List of service UUID's not given, so discover all available services. @@ -637,7 +636,9 @@ STATIC void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t // 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; + // There must be at least one if discover_next_services() returned true. + const bleio_service_obj_t *service = + self->remote_service_list->items[self->remote_service_list->len - 1]; next_service_start_handle = service->end_handle + 1; } } else { @@ -661,11 +662,10 @@ STATIC void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t } - bleio_service_obj_t *service = self->remote_service_list; - while (service != NULL) { + for (size_t i = 0; i < self->remote_service_list->len; i++) { + bleio_service_obj_t *service = MP_OBJ_TO_PTR(self->remote_service_list->items[i]); // Skip the service if it had an unknown (unregistered) UUID. if (service->uuid == NULL) { - service = service->next; continue; } @@ -677,9 +677,9 @@ STATIC void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t 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. + // There must be at least one if discover_next_characteristics() returned true. const bleio_characteristic_obj_t *characteristic = MP_OBJ_TO_PTR(service->characteristic_list->items[service->characteristic_list->len - 1]); @@ -717,24 +717,26 @@ STATIC void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t 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; + // There must be at least one if discover_next_descriptors() returned true. + const bleio_descriptor_obj_t *descriptor = + characteristic->descriptor_list->items[characteristic->descriptor_list->len - 1]; 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); 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); - self->connection->remote_service_list = NULL; + mp_obj_tuple_t *services_tuple = + mp_obj_new_tuple(self->connection->remote_service_list->len, + self->connection->remote_service_list->items); + mp_obj_list_clear(MP_OBJ_FROM_PTR(self->connection->remote_service_list)); return services_tuple; } diff --git a/ports/nrf/common-hal/_bleio/Connection.h b/ports/nrf/common-hal/_bleio/Connection.h index b051e5c511..180b2727ca 100644 --- a/ports/nrf/common-hal/_bleio/Connection.h +++ b/ports/nrf/common-hal/_bleio/Connection.h @@ -53,7 +53,7 @@ typedef struct { uint16_t conn_handle; bool is_central; // Remote services discovered when this peripheral is acting as a client. - bleio_service_obj_t *remote_service_list; + mp_obj_list_t *remote_service_list; // The advertising data and scan response buffers are held by us, not by the SD, so we must // maintain them and not change it. If we need to change the contents during advertising, // there are tricks to get the SD to notice (see DevZone - TBS). @@ -67,7 +67,7 @@ typedef struct { 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; @@ -83,6 +83,7 @@ typedef struct { uint8_t disconnect_reason; } bleio_connection_obj_t; +void bleio_connection_clear(bleio_connection_internal_t *self); bool connection_on_ble_evt(ble_evt_t *ble_evt, void *self_in); uint16_t bleio_connection_get_conn_handle(bleio_connection_obj_t *self); diff --git a/ports/nrf/common-hal/_bleio/Descriptor.h b/ports/nrf/common-hal/_bleio/Descriptor.h index c70547c08e..f76510d128 100644 --- a/ports/nrf/common-hal/_bleio/Descriptor.h +++ b/ports/nrf/common-hal/_bleio/Descriptor.h @@ -47,7 +47,6 @@ typedef struct _bleio_descriptor_obj { uint16_t handle; bleio_attribute_security_mode_t read_perm; bleio_attribute_security_mode_t write_perm; - struct _bleio_descriptor_obj* next; } bleio_descriptor_obj_t; #endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_DESCRIPTOR_H diff --git a/ports/nrf/common-hal/_bleio/Service.c b/ports/nrf/common-hal/_bleio/Service.c index 19288f7479..8c57442f29 100644 --- a/ports/nrf/common-hal/_bleio/Service.c +++ b/ports/nrf/common-hal/_bleio/Service.c @@ -73,8 +73,8 @@ bleio_uuid_obj_t *common_hal_bleio_service_get_uuid(bleio_service_obj_t *self) { return self->uuid; } -mp_obj_list_t *common_hal_bleio_service_get_characteristic_list(bleio_service_obj_t *self) { - return self->characteristic_list; +mp_obj_tuple_t *common_hal_bleio_service_get_characteristics(bleio_service_obj_t *self) { + return mp_obj_new_tuple(self->characteristic_list->len, self->characteristic_list->items); } bool common_hal_bleio_service_get_is_remote(bleio_service_obj_t *self) { diff --git a/ports/nrf/common-hal/_bleio/Service.h b/ports/nrf/common-hal/_bleio/Service.h index 6ee9fe63de..00f611dd9d 100644 --- a/ports/nrf/common-hal/_bleio/Service.h +++ b/ports/nrf/common-hal/_bleio/Service.h @@ -46,7 +46,6 @@ typedef struct bleio_service_obj { // Range of attribute handles of this remote service. uint16_t start_handle; uint16_t end_handle; - struct bleio_service_obj* next; } bleio_service_obj_t; void bleio_service_from_connection(bleio_service_obj_t *self, mp_obj_t connection); diff --git a/shared-bindings/_bleio/Characteristic.c b/shared-bindings/_bleio/Characteristic.c index 557a356b69..24b127e4a3 100644 --- a/shared-bindings/_bleio/Characteristic.c +++ b/shared-bindings/_bleio/Characteristic.c @@ -212,26 +212,14 @@ const mp_obj_property_t bleio_characteristic_value_obj = { }; //| descriptors: Descriptor -//| """A tuple of :py:class:`Descriptor` that describe this characteristic. (read-only)""" +//| """A tuple of :py:class:`Descriptor` objects related to this characteristic. (read-only)""" //| STATIC mp_obj_t bleio_characteristic_get_descriptors(mp_obj_t self_in) { bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); // Return list as a tuple so user won't be able to change it. - bleio_descriptor_obj_t *descriptors = common_hal_bleio_characteristic_get_descriptor_list(self); - bleio_descriptor_obj_t *head = descriptors; - size_t len = 0; - while (head != NULL) { - len++; - head = head->next; - } - mp_obj_tuple_t * t = MP_OBJ_TO_PTR(mp_obj_new_tuple(len, NULL)); - head = descriptors; - for (size_t i = len - 1; i >= 0; i--) { - t->items[i] = MP_OBJ_FROM_PTR(head); - head = head->next; - } - return MP_OBJ_FROM_PTR(t); + return MP_OBJ_FROM_PTR(common_hal_bleio_characteristic_get_descriptors(self)); } + STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_descriptors_obj, bleio_characteristic_get_descriptors); const mp_obj_property_t bleio_characteristic_descriptors_obj = { diff --git a/shared-bindings/_bleio/Characteristic.h b/shared-bindings/_bleio/Characteristic.h index c4356fd4b9..e28d61e1f0 100644 --- a/shared-bindings/_bleio/Characteristic.h +++ b/shared-bindings/_bleio/Characteristic.h @@ -36,14 +36,14 @@ extern const mp_obj_type_t bleio_characteristic_type; -extern 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); -extern size_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *self, uint8_t* buf, size_t len); -extern void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo); extern bleio_characteristic_properties_t common_hal_bleio_characteristic_get_properties(bleio_characteristic_obj_t *self); -extern bleio_uuid_obj_t *common_hal_bleio_characteristic_get_uuid(bleio_characteristic_obj_t *self); -extern bleio_descriptor_obj_t *common_hal_bleio_characteristic_get_descriptor_list(bleio_characteristic_obj_t *self); +extern mp_obj_tuple_t *common_hal_bleio_characteristic_get_descriptors(bleio_characteristic_obj_t *self); extern bleio_service_obj_t *common_hal_bleio_characteristic_get_service(bleio_characteristic_obj_t *self); +extern bleio_uuid_obj_t *common_hal_bleio_characteristic_get_uuid(bleio_characteristic_obj_t *self); +extern size_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *self, uint8_t* buf, size_t len); extern void common_hal_bleio_characteristic_add_descriptor(bleio_characteristic_obj_t *self, bleio_descriptor_obj_t *descriptor); +extern 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); extern void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, bool notify, bool indicate); +extern void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTIC_H diff --git a/shared-bindings/_bleio/Service.c b/shared-bindings/_bleio/Service.c index f410b1798e..2ddf1a7126 100644 --- a/shared-bindings/_bleio/Service.c +++ b/shared-bindings/_bleio/Service.c @@ -79,9 +79,7 @@ STATIC mp_obj_t bleio_service_make_new(const mp_obj_type_t *type, size_t n_args, //| STATIC mp_obj_t bleio_service_get_characteristics(mp_obj_t self_in) { bleio_service_obj_t *self = MP_OBJ_TO_PTR(self_in); - // Return list as a tuple so user won't be able to change it. - mp_obj_list_t *char_list = common_hal_bleio_service_get_characteristic_list(self); - return mp_obj_new_tuple(char_list->len, char_list->items); + return MP_OBJ_FROM_PTR(common_hal_bleio_service_get_characteristics(self)); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_service_get_characteristics_obj, bleio_service_get_characteristics); @@ -151,7 +149,7 @@ STATIC const mp_rom_map_elem_t bleio_service_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_characteristics), MP_ROM_PTR(&bleio_service_characteristics_obj) }, { MP_ROM_QSTR(MP_QSTR_secondary), MP_ROM_PTR(&bleio_service_secondary_obj) }, { MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&bleio_service_uuid_obj) }, - { MP_ROM_QSTR(MP_QSTR_remote), MP_ROM_PTR(&bleio_service_remote_obj) }, + { MP_ROM_QSTR(MP_QSTR_remote), MP_ROM_PTR(&bleio_service_remote_obj) }, }; STATIC MP_DEFINE_CONST_DICT(bleio_service_locals_dict, bleio_service_locals_dict_table); @@ -173,21 +171,3 @@ const mp_obj_type_t bleio_service_type = { .print = bleio_service_print, .locals_dict = (mp_obj_dict_t*)&bleio_service_locals_dict }; - -// Helper for classes that store lists of services. -mp_obj_tuple_t* service_linked_list_to_tuple(bleio_service_obj_t * services) { - // Return list as a tuple so user won't be able to change it. - bleio_service_obj_t *head = services; - size_t len = 0; - while (head != NULL) { - len++; - head = head->next; - } - mp_obj_tuple_t * t = MP_OBJ_TO_PTR(mp_obj_new_tuple(len, NULL)); - head = services; - for (int32_t i = len - 1; i >= 0; i--) { - t->items[i] = MP_OBJ_FROM_PTR(head); - head = head->next; - } - return t; -} diff --git a/shared-bindings/_bleio/Service.h b/shared-bindings/_bleio/Service.h index 273c6bd989..8b8a6ce773 100644 --- a/shared-bindings/_bleio/Service.h +++ b/shared-bindings/_bleio/Service.h @@ -41,11 +41,9 @@ extern uint32_t _common_hal_bleio_service_construct(bleio_service_obj_t *self, b extern void common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uuid_obj_t *uuid, bool is_secondary); extern void common_hal_bleio_service_from_remote_service(bleio_service_obj_t *self, bleio_connection_obj_t* connection, bleio_uuid_obj_t *uuid, bool is_secondary); extern bleio_uuid_obj_t *common_hal_bleio_service_get_uuid(bleio_service_obj_t *self); -extern mp_obj_list_t *common_hal_bleio_service_get_characteristic_list(bleio_service_obj_t *self); +extern mp_obj_tuple_t *common_hal_bleio_service_get_characteristics(bleio_service_obj_t *self); extern bool common_hal_bleio_service_get_is_remote(bleio_service_obj_t *self); extern bool common_hal_bleio_service_get_is_secondary(bleio_service_obj_t *self); extern void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *initial_value_bufinfo); -mp_obj_tuple_t* service_linked_list_to_tuple(bleio_service_obj_t * services); - #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SERVICE_H diff --git a/shared-bindings/_bleio/__init__.h b/shared-bindings/_bleio/__init__.h index 5256bdaa0e..969d2efb1c 100644 --- a/shared-bindings/_bleio/__init__.h +++ b/shared-bindings/_bleio/__init__.h @@ -63,7 +63,6 @@ NORETURN void mp_raise_bleio_SecurityError(const compressed_string_t* msg, ...); void common_hal_bleio_check_connected(uint16_t conn_handle); uint16_t common_hal_bleio_device_get_conn_handle(mp_obj_t device); -mp_obj_list_t *common_hal_bleio_device_get_remote_service_list(mp_obj_t device); void common_hal_bleio_device_discover_remote_services(mp_obj_t device, mp_obj_t service_uuids_whitelist); size_t common_hal_bleio_gatts_read(uint16_t handle, uint16_t conn_handle, uint8_t* buf, size_t len); From 44c9c43cd15ea7be3192313b1a1bb204743492a1 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 13 Aug 2020 00:03:39 -0400 Subject: [PATCH 28/84] ble_uart_echo_test works --- devices/ble_hci/common-hal/_bleio/Adapter.c | 43 +++- devices/ble_hci/common-hal/_bleio/Adapter.h | 7 + .../common-hal/_bleio/Characteristic.c | 129 +++++----- .../common-hal/_bleio/Characteristic.h | 15 +- .../common-hal/_bleio/CharacteristicBuffer.c | 63 +---- .../common-hal/_bleio/CharacteristicBuffer.h | 2 + .../ble_hci/common-hal/_bleio/Connection.c | 73 +++--- .../ble_hci/common-hal/_bleio/Connection.h | 3 +- .../ble_hci/common-hal/_bleio/Descriptor.c | 33 ++- .../ble_hci/common-hal/_bleio/PacketBuffer.c | 232 ++++-------------- .../ble_hci/common-hal/_bleio/PacketBuffer.h | 2 + devices/ble_hci/common-hal/_bleio/Service.c | 19 +- devices/ble_hci/common-hal/_bleio/__init__.c | 143 ----------- devices/ble_hci/common-hal/_bleio/__init__.h | 3 +- devices/ble_hci/common-hal/_bleio/att.c | 113 ++++++--- devices/ble_hci/common-hal/_bleio/att.h | 2 +- devices/ble_hci/common-hal/_bleio/hci.c | 27 +- devices/ble_hci/common-hal/_bleio/hci.h | 2 +- ports/nrf/common-hal/_bleio/Characteristic.c | 8 +- ports/nrf/common-hal/_bleio/Characteristic.h | 2 +- ports/nrf/common-hal/_bleio/Connection.c | 2 +- ports/nrf/common-hal/_bleio/Descriptor.c | 5 +- ports/nrf/common-hal/_bleio/Descriptor.h | 2 +- ports/nrf/common-hal/_bleio/Service.c | 7 +- 24 files changed, 350 insertions(+), 587 deletions(-) diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index c8147fbc1b..4ed85f7540 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.c +++ b/devices/ble_hci/common-hal/_bleio/Adapter.c @@ -60,6 +60,8 @@ #define UNIT_1_25_MS (1250) #define UNIT_10_MS (10000) +#define MAX_ADVERTISEMENT_SIZE (31) + // TODO make this settable from Python. #define DEFAULT_TX_POWER 0 // 0 dBm #define MAX_ANONYMOUS_ADV_TIMEOUT_SECS (60*15) @@ -179,13 +181,31 @@ STATIC void bleio_adapter_reset_name(bleio_adapter_obj_t *self) { } // Get various values and limits set by the adapter. -STATIC void bleio_adapter_get_info(bleio_adapter_obj_t *self) { +// Set event mask. +STATIC void bleio_adapter_setup(bleio_adapter_obj_t *self) { + // Get version information. + if (hci_read_local_version(&self->hci_version, &self->hci_revision, &self->lmp_version, + &self->manufacturer, &self->lmp_subversion) != HCI_OK) { + mp_raise_bleio_BluetoothError(translate("Could not read HCI version")); + } // Get supported features. if (hci_le_read_local_supported_features(self->features) != HCI_OK) { mp_raise_bleio_BluetoothError(translate("Could not read BLE features")); } + // Enabled desired events. + // Most importantly, includes: + // BT_EVT_MASK_LE_META_EVENT BT_EVT_BIT(61) + if (hci_set_event_mask(0x3FFFFFFFFFFFFFFF) != HCI_OK) { + mp_raise_bleio_BluetoothError(translate("Could not set event mask")); + } + // The default events for LE are: + // BT_EVT_MASK_LE_CONN_COMPLETE, BT_EVT_MASK_LE_ADVERTISING_REPORT, + // BT_EVT_MASK_LE_CONN_UPDATE_COMPLETE, BT_EVT_MASK_LE_REMOTE_FEAT_COMPLETE + // BT_EVT_MASK_LE_LTK_REQUEST. + // That's all we need right now, so we don't bother to set the LE event mask. + // Get ACL buffer info. uint16_t le_max_len; uint8_t le_max_num; @@ -213,7 +233,7 @@ STATIC void bleio_adapter_get_info(bleio_adapter_obj_t *self) { } self->max_adv_data_len = max_adv_data_len; } else { - self->max_adv_data_len = 31; + self->max_adv_data_len = MAX_ADVERTISEMENT_SIZE; } } @@ -226,7 +246,7 @@ void common_hal_bleio_adapter_hci_uart_init(bleio_adapter_obj_t *self, busio_uar self->enabled = false; common_hal_bleio_adapter_set_enabled(self, true); - bleio_adapter_get_info(self); + bleio_adapter_setup(self); bleio_adapter_reset_name(self); } @@ -477,14 +497,10 @@ mp_obj_t common_hal_bleio_adapter_connect(bleio_adapter_obj_t *self, bleio_addre return mp_const_none; } -// The nRF SD 6.1.0 can only do one concurrent advertisement so share the advertising handle. -//FIX uint8_t adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET; - STATIC void check_data_fit(size_t data_len, bool connectable) { - //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")); - // } + if (data_len > MAX_ADVERTISEMENT_SIZE) { + mp_raise_ValueError(translate("Data too large for advertisement packet")); + } } // STATIC bool advertising_on_ble_evt(ble_evt_t *ble_evt, void *self_in) { @@ -604,8 +620,9 @@ uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, 0x00 // filter policy: no filter )); - // The HCI commands expect 31 octets, even though the actual data length may be shorter. - uint8_t full_data[31] = { 0 }; + // The HCI commands expect MAX_ADVERTISEMENT_SIZE (31)octets, + // even though the actual data length may be shorter. + uint8_t full_data[MAX_ADVERTISEMENT_SIZE] = { 0 }; memcpy(full_data, advertising_data, MIN(sizeof(full_data), advertising_data_len)); check_hci_error(hci_le_set_advertising_data(advertising_data_len, full_data)); memset(full_data, 0, sizeof(full_data)); @@ -636,7 +653,7 @@ void common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, bool check_data_fit(advertising_data_bufinfo->len, connectable); check_data_fit(scan_response_data_bufinfo->len, connectable); - if (advertising_data_bufinfo->len > 31 && scan_response_data_bufinfo->len > 0) { + if (advertising_data_bufinfo->len > MAX_ADVERTISEMENT_SIZE && scan_response_data_bufinfo->len > 0) { mp_raise_bleio_BluetoothError(translate("Extended advertisements with scan response not supported.")); } diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.h b/devices/ble_hci/common-hal/_bleio/Adapter.h index 1fae5f6829..a6a78f67e7 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.h +++ b/devices/ble_hci/common-hal/_bleio/Adapter.h @@ -56,6 +56,13 @@ typedef struct _bleio_adapter_obj_t { bool circuitpython_advertising; bool enabled; + // HCI adapter version info. + uint8_t hci_version; + uint8_t lmp_version; + uint16_t hci_revision; + uint16_t manufacturer; + uint16_t lmp_subversion; + // Used to monitor advertising timeout for legacy avertising. uint64_t advertising_start_ticks; uint64_t advertising_timeout_msecs; // If zero, do not check. diff --git a/devices/ble_hci/common-hal/_bleio/Characteristic.c b/devices/ble_hci/common-hal/_bleio/Characteristic.c index 4e69c3522c..5f9b96b354 100644 --- a/devices/ble_hci/common-hal/_bleio/Characteristic.c +++ b/devices/ble_hci/common-hal/_bleio/Characteristic.c @@ -29,7 +29,9 @@ #include "shared-bindings/_bleio/__init__.h" #include "shared-bindings/_bleio/Characteristic.h" +#include "shared-bindings/_bleio/CharacteristicBuffer.h" #include "shared-bindings/_bleio/Descriptor.h" +#include "shared-bindings/_bleio/PacketBuffer.h" #include "shared-bindings/_bleio/Service.h" #include "common-hal/_bleio/Adapter.h" @@ -47,8 +49,12 @@ void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, self->props = props; self->read_perm = read_perm; self->write_perm = write_perm; - self->descriptor_linked_list = mp_obj_new_list(0, NULL); - self->watchers_list = mp_obj_new_list(0, NULL); + self->descriptor_list = mp_obj_new_list(0, NULL); + self->observer = mp_const_none; + self->user_desc = NULL; + self->cccd = NULL; + self->sccd = NULL; + self->value = mp_obj_new_bytes(initial_value_bufinfo->buf, initial_value_bufinfo->len); const mp_int_t max_length_max = 512; if (max_length < 0 || max_length > max_length_max) { @@ -62,14 +68,10 @@ void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, } else { common_hal_bleio_service_add_characteristic(self->service, self, initial_value_bufinfo); } - - if (initial_value_bufinfo != NULL) { - common_hal_bleio_characteristic_set_value(self, initial_value_bufinfo); - } } -bleio_descriptor_obj_t *common_hal_bleio_characteristic_get_descriptor_linked_list(bleio_characteristic_obj_t *self) { - return self->descriptor_linked_list; +mp_obj_tuple_t *common_hal_bleio_characteristic_get_descriptors(bleio_characteristic_obj_t *self) { + return mp_obj_new_tuple(self->descriptor_list->len, self->descriptor_list->items); } bleio_service_obj_t *common_hal_bleio_characteristic_get_service(bleio_characteristic_obj_t *self) { @@ -79,13 +81,19 @@ bleio_service_obj_t *common_hal_bleio_characteristic_get_service(bleio_character size_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *self, uint8_t* buf, size_t len) { // Do GATT operations only if this characteristic has been added to a registered service. if (self->handle != BLE_GATT_HANDLE_INVALID) { - uint16_t conn_handle = bleio_connection_get_conn_handle(self->service->connection); + //FIX uint16_t conn_handle = bleio_connection_get_conn_handle(self->service->connection); if (common_hal_bleio_service_get_is_remote(self->service)) { - // self->value is set by evt handler. - return common_hal_bleio_gattc_read(self->handle, conn_handle, buf, len); + //FIX read remote chars + //uint8_t rsp[MAX(len, 512)]; + //FIX improve att_read_req to write into our requested buffer. + // return att_read_req(conn_handle, self->handle, rsp); + return 0; //FIX } else { - // conn_handle is ignored for non-system attributes. - return common_hal_bleio_gatts_read(self->handle, conn_handle, buf, len); + mp_buffer_info_t bufinfo; + if (!mp_get_buffer(self->value, &bufinfo, MP_BUFFER_READ)) { + return 0; + } + memcpy(buf, bufinfo.buf, MIN(len, bufinfo.len)); } } @@ -102,32 +110,40 @@ void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, // Do GATT operations only if this characteristic has been added to a registered service. if (self->handle != BLE_GATT_HANDLE_INVALID) { - if (common_hal_bleio_service_get_is_remote(self->service)) { - uint16_t conn_handle = bleio_connection_get_conn_handle(self->service->connection); - // Last argument is true if write-no-reponse desired. - common_hal_bleio_gattc_write(self->handle, conn_handle, bufinfo, - (self->props & CHAR_PROP_WRITE_NO_RESPONSE)); + //FIX uint16_t conn_handle = bleio_connection_get_conn_handle(self->service->connection); + if (self->props & CHAR_PROP_WRITE) { + //FIX writing remote chars + //uint8_t rsp[sizeof(bt_att_error_rsp)]; + //att_write_req(conn_handle, self->handle, bufinfo->buf, bufinfo->len, rsp); + } else if (self->props & CHAR_PROP_WRITE_NO_RESPONSE) { + //att_write_cmd(conn_handle, self->handle, bufinfo->buff, bufinfo->len); + } else { + mp_raise_bleio_BluetoothError(translate("Characteristic not writable")); + } } else { // Always write the value locally even if no connections are active. - // conn_handle is ignored for non-system attributes, so we use BLE_CONN_HANDLE_INVALID. - common_hal_bleio_gatts_write(self->handle, BLE_CONN_HANDLE_INVALID, bufinfo); + bleio_characteristic_set_local_value(self, bufinfo); // Notify or indicate all active connections. - uint16_t cccd = 0; + + uint16_t cccd_value = 0; + mp_buffer_info_t cccd_bufinfo = { + .buf = &cccd_value, + .len = sizeof(cccd_value), + }; const bool notify = self->props & CHAR_PROP_NOTIFY; const bool indicate = self->props & CHAR_PROP_INDICATE; // Read the CCCD value, if there is one. - if ((notify | indicate) && self->cccd_handle != BLE_GATT_HANDLE_INVALID) { - common_hal_bleio_gatts_read(self->cccd_handle, BLE_CONN_HANDLE_INVALID, - (uint8_t *) &cccd, sizeof(cccd)); + if ((notify | indicate) && self->cccd != NULL) { + common_hal_bleio_descriptor_get_value(self->cccd, cccd_bufinfo.buf, cccd_bufinfo.len); } // It's possible that both notify and indicate are set. - if (notify && (cccd & CCCD_NOTIFY)) { + if (notify && (cccd_value & CCCD_NOTIFY)) { att_notify(self->handle, bufinfo->buf, MIN(bufinfo->len, self->max_length)); } - if (indicate && (cccd & CCCD_INDICATE)) { + if (indicate && (cccd_value & CCCD_INDICATE)) { att_indicate(self->handle, bufinfo->buf, MIN(bufinfo->len, self->max_length)); } @@ -153,13 +169,12 @@ void common_hal_bleio_characteristic_add_descriptor(bleio_characteristic_obj_t * // Include this descriptor in the service handle's range. self->service->end_handle = descriptor->handle; - // Link together all the descriptors for this characteristic. - descriptor->next = self->descriptor_linked_list; - self->descriptor_linked_list = descriptor; + mp_obj_list_append(MP_OBJ_FROM_PTR(self->descriptor_list), + MP_OBJ_FROM_PTR(descriptor)); } void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, bool notify, bool indicate) { - if (self->cccd_handle == BLE_GATT_HANDLE_INVALID) { + if (self->cccd == NULL) { mp_raise_bleio_BluetoothError(translate("No CCCD for this Characteristic")); } @@ -174,33 +189,12 @@ void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, (notify ? CCCD_NOTIFY : 0) | (indicate ? CCCD_INDICATE : 0); + //FIX do remote (void) cccd_value; - //FIX call att_something to set remote CCCD - // 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); + // uint8_t rsp[sizeof(bt_att_error_rsp)]; + // if (att_write_req(conn_handle, self->cccd->handle, &cccd_value, sizeof(cccd_value)) == 0) { + // mp_raise_bleio_BluetoothError(translate("Could not write CCCD")); // } - } bool bleio_characteristic_set_local_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo) { @@ -208,14 +202,25 @@ bool bleio_characteristic_set_local_value(bleio_characteristic_obj_t *self, mp_b return false; } if (bufinfo->len > self->max_length) { - bool - } - - mp_buffer_info_t char_bufinfo; - if (!mp_get_buffer(characteristic->value, &bufinfo, MP_BUFFER_WRITE)) { return false; } - memcpy(&char_bufinfo->buf, bufinfo->buf, bufinfo->len); - for (size_t i; i < characteristic->set_callbacks. + self->value = mp_obj_new_bytes(bufinfo->buf, bufinfo->len); + + if (MP_OBJ_IS_TYPE(self->observer, &bleio_characteristic_buffer_type)) { + bleio_characteristic_buffer_update(MP_OBJ_FROM_PTR(self->observer), bufinfo); + } else if (MP_OBJ_IS_TYPE(self->observer, &bleio_packet_buffer_type)) { + bleio_packet_buffer_update(MP_OBJ_FROM_PTR(self->observer), bufinfo); + } else { + return false; + } + return true; +} + +void bleio_characteristic_set_observer(bleio_characteristic_obj_t *self, mp_obj_t observer) { + self->observer = observer; +} + +void bleio_characteristic_clear_observer(bleio_characteristic_obj_t *self) { + self->observer = mp_const_none; } diff --git a/devices/ble_hci/common-hal/_bleio/Characteristic.h b/devices/ble_hci/common-hal/_bleio/Characteristic.h index cc5ba4108b..6d5a12509c 100644 --- a/devices/ble_hci/common-hal/_bleio/Characteristic.h +++ b/devices/ble_hci/common-hal/_bleio/Characteristic.h @@ -40,8 +40,8 @@ typedef struct _bleio_characteristic_obj { bleio_service_obj_t *service; bleio_uuid_obj_t *uuid; mp_obj_t value; - mp_obj_list_t watcher_list; - mp_obj_list_t descriptor_linked_list; + mp_obj_t observer; + mp_obj_list_t *descriptor_list; uint16_t max_length; bool fixed_length; uint16_t decl_handle; @@ -50,9 +50,14 @@ typedef struct _bleio_characteristic_obj { bleio_attribute_security_mode_t read_perm; bleio_attribute_security_mode_t write_perm; bleio_descriptor_obj_t *descriptor_linked_list; - uint16_t user_desc_handle; - uint16_t cccd_handle; - uint16_t sccd_handle; + bleio_descriptor_obj_t *user_desc; + bleio_descriptor_obj_t *cccd; + bleio_descriptor_obj_t *sccd; } bleio_characteristic_obj_t; +bool bleio_characteristic_set_local_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo); + +void bleio_characteristic_set_observer(bleio_characteristic_obj_t *self, mp_obj_t observer); +void bleio_characteristic_clear_observer(bleio_characteristic_obj_t *self); + #endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_CHARACTERISTIC_H diff --git a/devices/ble_hci/common-hal/_bleio/CharacteristicBuffer.c b/devices/ble_hci/common-hal/_bleio/CharacteristicBuffer.c index c4eb6a19fe..e8cd518808 100644 --- a/devices/ble_hci/common-hal/_bleio/CharacteristicBuffer.c +++ b/devices/ble_hci/common-hal/_bleio/CharacteristicBuffer.c @@ -37,44 +37,13 @@ #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 void write_to_ringbuf(bleio_characteristic_buffer_obj_t *self, uint8_t *data, uint16_t len) { + ringbuf_put_n(&self->ringbuf, data, len); +} -// 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; -// } +void bleio_characteristic_buffer_update(bleio_characteristic_buffer_obj_t *self, mp_buffer_info_t *bufinfo) { + write_to_ringbuf(self, bufinfo->buf, bufinfo->len); +} // 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,8 +57,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); - // FIX ble_drv_add_event_handler(characteristic_buffer_on_ble_evt, self); - + bleio_characteristic_set_observer(characteristic, self); } uint32_t common_hal_bleio_characteristic_buffer_read(bleio_characteristic_buffer_obj_t *self, uint8_t *data, size_t len, int *errcode) { @@ -104,32 +72,17 @@ uint32_t common_hal_bleio_characteristic_buffer_read(bleio_characteristic_buffer } } - // Copy received data. Lock out write interrupt handler while copying. - // 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. - // 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) { - //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); - //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 - //FIX uint8_t is_nested_critical_region; - //FIX sd_nvic_critical_region_enter(&is_nested_critical_region); ringbuf_clear(&self->ringbuf); - //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 +91,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)) { - //FIX ble_drv_remove_event_handler(characteristic_buffer_on_ble_evt, self); + bleio_characteristic_clear_observer(self->characteristic); } } diff --git a/devices/ble_hci/common-hal/_bleio/CharacteristicBuffer.h b/devices/ble_hci/common-hal/_bleio/CharacteristicBuffer.h index 8738d2c59c..107e5801f8 100644 --- a/devices/ble_hci/common-hal/_bleio/CharacteristicBuffer.h +++ b/devices/ble_hci/common-hal/_bleio/CharacteristicBuffer.h @@ -38,4 +38,6 @@ typedef struct { ringbuf_t ringbuf; } bleio_characteristic_buffer_obj_t; +void bleio_characteristic_buffer_update(bleio_characteristic_buffer_obj_t *self, mp_buffer_info_t *bufinfo); + #endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_CHARACTERISTICBUFFER_H diff --git a/devices/ble_hci/common-hal/_bleio/Connection.c b/devices/ble_hci/common-hal/_bleio/Connection.c index 98fa4d1f72..ba4eb477d9 100644 --- a/devices/ble_hci/common-hal/_bleio/Connection.c +++ b/devices/ble_hci/common-hal/_bleio/Connection.c @@ -27,6 +27,8 @@ #include "shared-bindings/_bleio/Connection.h" +#include "att.h" + #include #include @@ -319,10 +321,11 @@ static volatile bool m_discovery_successful; // } void bleio_connection_clear(bleio_connection_internal_t *self) { - self->remote_service_linked_list = NULL; + mp_obj_list_clear(MP_OBJ_FROM_PTR(self->remote_service_list)); - //FIX self->conn_handle = BLE_CONN_HANDLE_INVALID; + self->conn_handle = BLE_CONN_HANDLE_INVALID; self->pair_status = PAIR_NOT_PAIRED; + self->is_central = false; //FIX bonding_clear_keys(&self->bonding_keys); } @@ -337,12 +340,11 @@ bool common_hal_bleio_connection_get_connected(bleio_connection_obj_t *self) { if (self->connection == NULL) { return false; } - return false; - //FIX return self->connection->conn_handle != BLE_CONN_HANDLE_INVALID; + return self->connection->conn_handle != BLE_CONN_HANDLE_INVALID; } void common_hal_bleio_connection_disconnect(bleio_connection_internal_t *self) { - //FIX sd_ble_gap_disconnect(self->conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); + hci_disconnect(self->conn_handle); } void common_hal_bleio_connection_pair(bleio_connection_internal_t *self, bool bond) { @@ -369,8 +371,7 @@ mp_float_t common_hal_bleio_connection_get_connection_interval(bleio_connection_ // Return the current negotiated MTU length, minus overhead. mp_int_t common_hal_bleio_connection_get_max_packet_length(bleio_connection_internal_t *self) { - /// FIX return (self->mtu == 0 ? BLE_GATT_ATT_MTU_DEFAULT : self->mtu) - 3; - return 0; + return (self->mtu == 0 ? BT_ATT_DEFAULT_LE_MTU : self->mtu) - 3; } void common_hal_bleio_connection_set_connection_interval(bleio_connection_internal_t *self, mp_float_t new_interval) { @@ -449,8 +450,6 @@ void common_hal_bleio_connection_set_connection_interval(bleio_connection_intern // } // 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_linked_list; - // for (size_t i = 0; i < response->count; ++i) { // ble_gattc_service_t *gattc_service = &response->services[i]; @@ -477,13 +476,11 @@ void common_hal_bleio_connection_set_connection_interval(bleio_connection_intern // // For now, just set the UUID to NULL. // service->uuid = NULL; // } - -// service->next = tail; -// tail = service; +// +// mp_obj_list_append(MP_OBJ_FROM_PTR(connection->remote_service_list), +// MP_OBJ_FROM_PTR(service)); // } - -// connection->remote_service_linked_list = tail; - +// // if (response->count > 0) { // m_discovery_successful = true; // } @@ -525,7 +522,8 @@ void common_hal_bleio_connection_set_connection_interval(bleio_connection_intern // 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)); +// mp_obj_list_append(MP_OBJ_FROM_PTR(m_char_discovery_service->characteristic_list), +// MP_OBJ_FROM_PTR(characteristic)); // } // if (response->count > 0) { @@ -581,7 +579,8 @@ void common_hal_bleio_connection_set_connection_interval(bleio_connection_intern // GATT_MAX_DATA_LENGTH, false, mp_const_empty_bytes); // descriptor->handle = gattc_desc->handle; -// mp_obj_list_append(m_desc_discovery_characteristic->descriptor_linked_list, MP_OBJ_FROM_PTR(descriptor)); +// mp_obj_list_append(MP_OBJ_FROM_PTR(m_desc_discovery_characteristic->descriptor_list), +// MP_OBJ_FROM_PTR(descriptor)); // } // if (response->count > 0) { @@ -622,7 +621,8 @@ void common_hal_bleio_connection_set_connection_interval(bleio_connection_intern // ble_drv_add_event_handler(discovery_on_ble_evt, self); // // Start over with an empty list. -// self->remote_service_linked_list = NULL; +// self->remote_service_list = mp_obj_new_list(0, NULL); + // if (service_uuids_whitelist == mp_const_none) { // // List of service UUID's not given, so discover all available services. @@ -634,7 +634,9 @@ void common_hal_bleio_connection_set_connection_interval(bleio_connection_intern // // 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_linked_list; +// // There must be at least one if discover_next_services() returned true. +// const bleio_service_obj_t *service = +// self->remote_service_list->items[self->remote_service_list->len - 1]; // next_service_start_handle = service->end_handle + 1; // } // } else { @@ -658,11 +660,10 @@ void common_hal_bleio_connection_set_connection_interval(bleio_connection_intern // } -// bleio_service_obj_t *service = self->remote_service_linked_list; -// while (service != NULL) { +// for (size_t i = 0; i < self->remote_service_list->len; i++) { +// bleio_service_obj_t *service = MP_OBJ_TO_PTR(self->remote_service_list->items[i]); // // Skip the service if it had an unknown (unregistered) UUID. // if (service->uuid == NULL) { -// service = service->next; // continue; // } @@ -714,11 +715,12 @@ void common_hal_bleio_connection_set_connection_interval(bleio_connection_intern // 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_linked_list; +// // There must be at least one if discover_next_descriptors() returned true. +// const bleio_descriptor_obj_t *descriptor = +// characteristic->descriptor_list->items[characteristic->descriptor_list->len - 1]; // next_desc_start_handle = descriptor->handle + 1; // } // } -// service = service->next; // } // // This event handler is no longer needed. @@ -730,10 +732,11 @@ mp_obj_tuple_t *common_hal_bleio_connection_discover_remote_services(bleio_conne //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_linked_list); - self->connection->remote_service_linked_list = NULL; - - return services_tuple; + mp_obj_tuple_t *services_tuple = + mp_obj_new_tuple(self->connection->remote_service_list->len, + self->connection->remote_service_list->items); + mp_obj_list_clear(MP_OBJ_FROM_PTR(self->connection->remote_service_list)); + return services_tuple; } uint16_t bleio_connection_get_conn_handle(bleio_connection_obj_t *self) { @@ -757,13 +760,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) { - //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; - // } - // } + 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 efd496ecc5..0b1f26a213 100644 --- a/devices/ble_hci/common-hal/_bleio/Connection.h +++ b/devices/ble_hci/common-hal/_bleio/Connection.h @@ -50,7 +50,7 @@ typedef struct { uint16_t conn_handle; bool is_central; // Remote services discovered when this peripheral is acting as a client. - bleio_service_obj_t *remote_service_linked_list; + mp_obj_list_t *remote_service_list; // The advertising data and scan response buffers are held by us, not by the SD, so we must // maintain them and not change it. If we need to change the contents during advertising, // there are tricks to get the SD to notice (see DevZone - TBS). @@ -60,7 +60,6 @@ typedef struct { volatile pair_status_t pair_status; uint8_t sec_status; // Internal security status. mp_obj_t connection_obj; - //REMOVE ble_drv_evt_handler_entry_t handler_entry; //REMOVE ble_gap_conn_params_t conn_params; volatile bool conn_params_updating; uint16_t mtu; diff --git a/devices/ble_hci/common-hal/_bleio/Descriptor.c b/devices/ble_hci/common-hal/_bleio/Descriptor.c index faf50c658c..cc45a89857 100644 --- a/devices/ble_hci/common-hal/_bleio/Descriptor.c +++ b/devices/ble_hci/common-hal/_bleio/Descriptor.c @@ -39,6 +39,7 @@ void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, bleio_c self->handle = BLE_GATT_HANDLE_INVALID; self->read_perm = read_perm; self->write_perm = write_perm; + self->value = mp_obj_new_bytes(initial_value_bufinfo->buf, initial_value_bufinfo->len); 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) { @@ -62,11 +63,20 @@ bleio_characteristic_obj_t *common_hal_bleio_descriptor_get_characteristic(bleio size_t common_hal_bleio_descriptor_get_value(bleio_descriptor_obj_t *self, uint8_t* buf, size_t len) { // Do GATT operations only if this descriptor has been registered if (self->handle != BLE_GATT_HANDLE_INVALID) { - uint16_t conn_handle = bleio_connection_get_conn_handle(self->characteristic->service->connection); if (common_hal_bleio_service_get_is_remote(self->characteristic->service)) { - return common_hal_bleio_gattc_read(self->handle, conn_handle, buf, len); + //uint16_t conn_handle = bleio_connection_get_conn_handle(self->characteristic->service->connection); + //FIX have att_read_req fill in a buffer + //uint8_t rsp[MAX(len, 512)]; + //return att_read_req(conn_handle, self->handle, rsp, len); + return 0; } else { - return common_hal_bleio_gatts_read(self->handle, conn_handle, buf, len); + mp_buffer_info_t bufinfo; + if (!mp_get_buffer(self->value, &bufinfo, MP_BUFFER_READ)) { + return 0; + } + size_t actual_length = MIN(len, bufinfo.len); + memcpy(buf, bufinfo.buf, actual_length); + return actual_length; } } @@ -85,13 +95,20 @@ void common_hal_bleio_descriptor_set_value(bleio_descriptor_obj_t *self, mp_buff // Do GATT operations only if this descriptor has been registered. if (self->handle != BLE_GATT_HANDLE_INVALID) { - uint16_t conn_handle = bleio_connection_get_conn_handle(self->characteristic->service->connection); if (common_hal_bleio_service_get_is_remote(self->characteristic->service)) { - // false means WRITE_REQ, not write-no-response - common_hal_bleio_gattc_write(self->handle, conn_handle, bufinfo, false); + //FIX + // uint16_t conn_handle = bleio_connection_get_conn_handle(self->service->connection); + // att_write_req(conn_handle, self->handle, bufinfo->buf, bufinfo->len, rsp); } else { - common_hal_bleio_gatts_write(self->handle, conn_handle, bufinfo); + // Always write the value locally even if no connections are active. + if (self->fixed_length && bufinfo->len != self->max_length) { + return; + } + if (bufinfo->len > self->max_length) { + return; + } + + self->value = mp_obj_new_bytes(bufinfo->buf, bufinfo->len); } } - } diff --git a/devices/ble_hci/common-hal/_bleio/PacketBuffer.c b/devices/ble_hci/common-hal/_bleio/PacketBuffer.c index 65d4139605..98912ba902 100644 --- a/devices/ble_hci/common-hal/_bleio/PacketBuffer.c +++ b/devices/ble_hci/common-hal/_bleio/PacketBuffer.c @@ -36,152 +36,48 @@ #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. -// //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); -// } +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. + // 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 -// 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, -// }; +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) { + mp_buffer_info_t bufinfo = { + .buf = self->outgoing[self->pending_index], + .len = self->pending_size, + }; + common_hal_bleio_characteristic_set_value(self->characteristic, &bufinfo); -// err_code = sd_ble_gattc_write(conn_handle, &write_params); -// } else { -// uint16_t hvx_len = self->pending_size; + self->pending_size = 0; + self->pending_index = (self->pending_index + 1) % 2; + self->packet_queued = true; + } + return 0; +} -// 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 bleio_packet_buffer_update(bleio_packet_buffer_obj_t *self, mp_buffer_info_t *bufinfo) { + write_to_ringbuf(self, bufinfo->buf, bufinfo->len); +} void common_hal_bleio_packet_buffer_construct( bleio_packet_buffer_obj_t *self, bleio_characteristic_obj_t *characteristic, @@ -189,8 +85,10 @@ void common_hal_bleio_packet_buffer_construct( self->characteristic = characteristic; self->client = self->characteristic->service->is_remote; - bleio_characteristic_properties_t incoming = self->characteristic->props & (CHAR_PROP_WRITE_NO_RESPONSE | CHAR_PROP_WRITE); - bleio_characteristic_properties_t outgoing = self->characteristic->props & (CHAR_PROP_NOTIFY | CHAR_PROP_INDICATE); + bleio_characteristic_properties_t incoming = + self->characteristic->props & (CHAR_PROP_WRITE_NO_RESPONSE | CHAR_PROP_WRITE); + bleio_characteristic_properties_t outgoing = + self->characteristic->props & (CHAR_PROP_NOTIFY | CHAR_PROP_INDICATE); if (self->client) { // Swap if we're the client. @@ -219,32 +117,7 @@ void common_hal_bleio_packet_buffer_construct( self->outgoing[1] = NULL; } - //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; - // } - // } - // } + bleio_characteristic_set_observer(self->characteristic, self); } mp_int_t common_hal_bleio_packet_buffer_readinto(bleio_packet_buffer_obj_t *self, uint8_t *data, size_t len) { @@ -252,10 +125,7 @@ mp_int_t common_hal_bleio_packet_buffer_readinto(bleio_packet_buffer_obj_t *self return 0; } - // Copy received data. Lock out write interrupt handler while copying. - //FIX uint8_t is_nested_critical_region; - //FIX sd_nvic_critical_region_enter(&is_nested_critical_region); - + // Copy received data. // Get packet length, which is in first two bytes of packet. uint16_t packet_length; ringbuf_get_n(&self->ringbuf, (uint8_t*) &packet_length, sizeof(uint16_t)); @@ -274,9 +144,6 @@ mp_int_t common_hal_bleio_packet_buffer_readinto(bleio_packet_buffer_obj_t *self ret = packet_length; } - // Writes now OK. - //FIX sd_nvic_critical_region_exit(is_nested_critical_region); - return ret; } @@ -307,9 +174,6 @@ mp_int_t common_hal_bleio_packet_buffer_write(bleio_packet_buffer_obj_t *self, u size_t num_bytes_written = 0; - //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]; if (self->pending_size == 0) { @@ -321,11 +185,9 @@ mp_int_t common_hal_bleio_packet_buffer_write(bleio_packet_buffer_obj_t *self, u self->pending_size += len; num_bytes_written += len; - //FIX sd_nvic_critical_region_exit(is_nested_critical_region); - // If no writes are queued then sneak in this data. if (!self->packet_queued) { - //FIX queue_next_write(self); + queue_next_write(self); } return num_bytes_written; } @@ -398,6 +260,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)) { - //FIX ble_drv_remove_event_handler(packet_buffer_on_ble_client_evt, self); + bleio_characteristic_clear_observer(self->characteristic); } } diff --git a/devices/ble_hci/common-hal/_bleio/PacketBuffer.h b/devices/ble_hci/common-hal/_bleio/PacketBuffer.h index e1577a9957..074c03dc69 100644 --- a/devices/ble_hci/common-hal/_bleio/PacketBuffer.h +++ b/devices/ble_hci/common-hal/_bleio/PacketBuffer.h @@ -48,4 +48,6 @@ typedef struct { bool packet_queued; } bleio_packet_buffer_obj_t; +void bleio_packet_buffer_update(bleio_packet_buffer_obj_t *self, mp_buffer_info_t *bufinfo); + #endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_PACKETBUFFER_H diff --git a/devices/ble_hci/common-hal/_bleio/Service.c b/devices/ble_hci/common-hal/_bleio/Service.c index 0b6c830022..5803f5309d 100644 --- a/devices/ble_hci/common-hal/_bleio/Service.c +++ b/devices/ble_hci/common-hal/_bleio/Service.c @@ -70,8 +70,8 @@ bleio_uuid_obj_t *common_hal_bleio_service_get_uuid(bleio_service_obj_t *self) { return self->uuid; } -mp_obj_list_t *common_hal_bleio_service_get_characteristic_list(bleio_service_obj_t *self) { - return self->characteristic_list; +mp_obj_tuple_t *common_hal_bleio_service_get_characteristics(bleio_service_obj_t *self) { + return mp_obj_new_tuple(self->characteristic_list->len, self->characteristic_list->items); } bool common_hal_bleio_service_get_is_remote(bleio_service_obj_t *self) { @@ -122,21 +122,8 @@ void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, // Adds CCCD to attribute table, and also extends self->end_handle to include the CCCD. common_hal_bleio_characteristic_add_descriptor(characteristic, cccd); - characteristic->cccd_handle = cccd->handle; + characteristic->cccd = cccd; } - // #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 - - // These are not supplied or available. - characteristic->user_desc_handle = BLE_GATT_HANDLE_INVALID; - characteristic->sccd_handle = BLE_GATT_HANDLE_INVALID; - - // #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/__init__.c b/devices/ble_hci/common-hal/_bleio/__init__.c index e2b463af8a..3c23c160ea 100644 --- a/devices/ble_hci/common-hal/_bleio/__init__.c +++ b/devices/ble_hci/common-hal/_bleio/__init__.c @@ -83,21 +83,6 @@ void check_hci_error(hci_result_t result) { } } -// 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) { @@ -148,134 +133,6 @@ void common_hal_bleio_check_connected(uint16_t conn_handle) { } } -// GATTS read of a Characteristic or Descriptor. -size_t common_hal_bleio_gatts_read(uint16_t handle, uint16_t conn_handle, uint8_t* buf, size_t len) { - // 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. - - //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)); - - // 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. - - //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)); -} - -//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); - - //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); - - //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) { bleio_adapter_gc_collect(&common_hal_bleio_adapter_obj); } diff --git a/devices/ble_hci/common-hal/_bleio/__init__.h b/devices/ble_hci/common-hal/_bleio/__init__.h index e84320e30c..086d56a4b0 100644 --- a/devices/ble_hci/common-hal/_bleio/__init__.h +++ b/devices/ble_hci/common-hal/_bleio/__init__.h @@ -31,6 +31,7 @@ #include "shared-bindings/_bleio/UUID.h" +#include "att.h" #include "hci.h" void bleio_background(void); @@ -44,7 +45,7 @@ typedef struct { // We assume variable length data. // 20 bytes max (23 - 3). -#define GATT_MAX_DATA_LENGTH (BLE_GATT_ATT_MTU_DEFAULT - 3) +#define GATT_MAX_DATA_LENGTH (BT_ATT_DEFAULT_LE_MTU - 3) //FIX #define BLE_GATT_HANDLE_INVALID 0x0000 diff --git a/devices/ble_hci/common-hal/_bleio/att.c b/devices/ble_hci/common-hal/_bleio/att.c index 603f1dde34..aa436faa58 100644 --- a/devices/ble_hci/common-hal/_bleio/att.c +++ b/devices/ble_hci/common-hal/_bleio/att.c @@ -64,8 +64,6 @@ typedef struct __packed { uint8_t uuid[0]; // 2 or 16 bytes } characteristic_declaration_t; -//FIX BLEDeviceEventHandler event_handlers[2]; - STATIC uint8_t bleio_properties_to_ble_spec_properties(uint8_t bleio_properties) { uint8_t ble_spec_properties = 0; if (bleio_properties & CHAR_PROP_BROADCAST) { @@ -220,21 +218,16 @@ bool att_connect_to_address(bt_addr_le_t *addr) { 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) { +bool att_disconnect(uint16_t conn_handle) { + if (conn_handle == BLE_CONN_HANDLE_INVALID) { return false; } hci_disconnect(conn_handle); - hci_poll_for_incoming_pkt_timeout(timeout); - if (!att_handle_is_connected(conn_handle)) { - return true; - } - - return false; + // Confirm we're now disconnected. + return !att_handle_is_connected(conn_handle); } //FIX @@ -512,10 +505,6 @@ void att_add_connection(uint16_t handle, uint8_t role, bt_addr_le_t *peer_addr, bleio_connections[peer_index].role = role; bleio_connections[peer_index].mtu = BT_ATT_DEFAULT_LE_MTU; 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)); - // } } @@ -564,11 +553,6 @@ void att_remove_connection(uint16_t handle, uint8_t reason) { 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)); @@ -630,7 +614,7 @@ bool att_disconnect_all(void) { continue; } - if (hci_disconnect(bleio_connections[i].conn_handle) != 0) { + if (att_disconnect(bleio_connections[i].conn_handle) != 0) { continue; } @@ -1391,7 +1375,8 @@ STATIC void process_write_req_or_cmd(uint16_t conn_handle, uint16_t mtu, uint8_t return; } - common_hal_bleio_characteristic_set_value(characteristic, &bufinfo); + // Just change the local value. Don't fire off notifications, etc. + bleio_characteristic_set_local_value(characteristic, &bufinfo); } else if (MP_OBJ_IS_TYPE(attribute_obj, &bleio_descriptor_type)) { bleio_descriptor_obj_t *descriptor = MP_OBJ_TO_PTR(attribute_obj); @@ -1403,7 +1388,6 @@ STATIC void process_write_req_or_cmd(uint16_t conn_handle, uint16_t mtu, uint8_t return; } - //FIX need to set up event handlers, etc.? common_hal_bleio_descriptor_set_value(descriptor, &bufinfo); } @@ -1593,14 +1577,6 @@ bool att_exchange_mtu(uint16_t conn_handle) { return send_req_wait_for_rsp(conn_handle, sizeof(req), (uint8_t *) &req, response_buffer); } - - -//FIX 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 __packed { struct bt_att_hdr h; @@ -1642,7 +1618,7 @@ void att_write_cmd(uint16_t conn_handle, uint16_t handle, const uint8_t* data, u cmd->r.handle = handle; memcpy(cmd->r.value, data, data_len); - return send_req(conn_handle, sizeof(cmd_bytes), cmd_bytes); + send_req(conn_handle, sizeof(cmd_bytes), cmd_bytes); } void att_process_data(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { @@ -1738,3 +1714,76 @@ void att_process_data(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { break; } } + +//FIX Do we need all of these? +void check_att_err(uint8_t err) { + const compressed_string_t *msg = NULL; + switch (err) { + case 0: + return; + case BT_ATT_ERR_INVALID_HANDLE: + msg = translate("Invalid handle"); + break; + case BT_ATT_ERR_READ_NOT_PERMITTED: + msg = translate("Read not permitted"); + break; + case BT_ATT_ERR_WRITE_NOT_PERMITTED: + msg = translate("Write not permitted"); + break; + case BT_ATT_ERR_INVALID_PDU: + msg = translate("Invalid PDU"); + break; + case BT_ATT_ERR_NOT_SUPPORTED: + msg = translate("Not supported"); + break; + case BT_ATT_ERR_INVALID_OFFSET: + msg = translate("Invalid offset"); + break; + case BT_ATT_ERR_PREPARE_QUEUE_FULL: + msg = translate("Prepare queue full"); + break; + case BT_ATT_ERR_ATTRIBUTE_NOT_FOUND: + msg = translate("Attribute not found"); + break; + case BT_ATT_ERR_ATTRIBUTE_NOT_LONG: + msg = translate("Attribute not long"); + break; + case BT_ATT_ERR_ENCRYPTION_KEY_SIZE: + msg = translate("Encryption key size"); + case BT_ATT_ERR_INVALID_ATTRIBUTE_LEN: + msg = translate("Invalid attribute length"); + break; + case BT_ATT_ERR_UNLIKELY: + msg = translate("Unlikely"); + break; + case BT_ATT_ERR_UNSUPPORTED_GROUP_TYPE: + msg = translate("Unsupported group type"); + break; + case BT_ATT_ERR_INSUFFICIENT_RESOURCES: + msg = translate("Insufficient resources"); + break; + case BT_ATT_ERR_DB_OUT_OF_SYNC: + msg = translate("DB out of sync"); + break; + case BT_ATT_ERR_VALUE_NOT_ALLOWED: + msg = translate("Value not allowed"); + break; + } + if (msg) { + mp_raise_bleio_BluetoothError(msg); + } + + switch (err) { + case BT_ATT_ERR_AUTHENTICATION: + msg = translate("Insufficient authentication"); + break; + case BT_ATT_ERR_INSUFFICIENT_ENCRYPTION: + msg = translate("Insufficient encryption"); + break; + } + if (msg) { + mp_raise_bleio_SecurityError(msg); + } + + mp_raise_bleio_BluetoothError(translate("Unknown ATT error: 0x%02x"), err); +} diff --git a/devices/ble_hci/common-hal/_bleio/att.h b/devices/ble_hci/common-hal/_bleio/att.h index 820e86bfb6..2b1723440f 100644 --- a/devices/ble_hci/common-hal/_bleio/att.h +++ b/devices/ble_hci/common-hal/_bleio/att.h @@ -35,8 +35,8 @@ void bleio_att_reset(void); //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(uint16_t conn_handle); 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_is_connected(uint16_t handle); diff --git a/devices/ble_hci/common-hal/_bleio/hci.c b/devices/ble_hci/common-hal/_bleio/hci.c index 52452a26d1..f29121aaa2 100644 --- a/devices/ble_hci/common-hal/_bleio/hci.c +++ b/devices/ble_hci/common-hal/_bleio/hci.c @@ -172,15 +172,14 @@ STATIC void process_evt_pkt(size_t pkt_len, uint8_t pkt_data[]) 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); + + att_remove_connection(disconn_complete->handle, disconn_complete->reason); + //FIX 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; @@ -238,19 +237,21 @@ STATIC void process_evt_pkt(size_t pkt_len, uint8_t pkt_data[]) (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); + att_add_connection( + le_conn_complete->handle, + le_conn_complete->role, + &le_conn_complete->peer_addr, + 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 + if (le_advertising_info->evt_type == BT_HCI_ADV_DIRECT_IND) { + //FIX // last byte is RSSI // GAP.handleLeAdvertisingReport(leAdvertisingReport->type, // leAdvertisingReport->peerBdaddrType, @@ -538,7 +539,7 @@ hci_result_t hci_read_rssi(uint16_t handle, int *rssi) { return result; } -hci_result_t hci_set_evt_mask(uint64_t event_mask) { +hci_result_t hci_set_event_mask(uint64_t event_mask) { return send_command(BT_HCI_OP_SET_EVENT_MASK, sizeof(event_mask), &event_mask); } diff --git a/devices/ble_hci/common-hal/_bleio/hci.h b/devices/ble_hci/common-hal/_bleio/hci.h index d907a84b7d..5dc831eb48 100644 --- a/devices/ble_hci/common-hal/_bleio/hci.h +++ b/devices/ble_hci/common-hal/_bleio/hci.h @@ -75,6 +75,6 @@ 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); +hci_result_t hci_set_event_mask(uint64_t event_mask); #endif // MICROPY_INCLUDED_DEVICES_BLE_HCI_COMMON_HAL_BLEIO_HCI_H diff --git a/ports/nrf/common-hal/_bleio/Characteristic.c b/ports/nrf/common-hal/_bleio/Characteristic.c index cacd53417a..57c4814489 100644 --- a/ports/nrf/common-hal/_bleio/Characteristic.c +++ b/ports/nrf/common-hal/_bleio/Characteristic.c @@ -90,6 +90,7 @@ void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, self->props = props; self->read_perm = read_perm; self->write_perm = write_perm; + self->initial_value = mp_obj_new_bytes(initial_value_bufinfo->buf, initial_value_bufinfo->len); self->descriptor_list = mp_obj_new_list(0, NULL); const mp_int_t max_length_max = fixed_length ? BLE_GATTS_FIX_ATTR_LEN_MAX : BLE_GATTS_VAR_ATTR_LEN_MAX; @@ -105,10 +106,6 @@ void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, } else { common_hal_bleio_service_add_characteristic(self->service, self, initial_value_bufinfo); } - - if (initial_value_bufinfo != NULL) { - common_hal_bleio_characteristic_set_value(self, initial_value_bufinfo); - } } mp_obj_tuple_t *common_hal_bleio_characteristic_get_descriptors(bleio_characteristic_obj_t *self) { @@ -124,7 +121,6 @@ size_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *sel if (self->handle != BLE_GATT_HANDLE_INVALID) { uint16_t conn_handle = bleio_connection_get_conn_handle(self->service->connection); if (common_hal_bleio_service_get_is_remote(self->service)) { - // self->value is set by evt handler. return common_hal_bleio_gattc_read(self->handle, conn_handle, buf, len); } else { // conn_handle is ignored for non-system attributes. @@ -205,7 +201,7 @@ void common_hal_bleio_characteristic_add_descriptor(bleio_characteristic_obj_t * 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); + mp_get_buffer_raise(descriptor->initial_value, &desc_value_bufinfo, MP_BUFFER_READ); ble_gatts_attr_t desc_attr = { .p_uuid = &desc_uuid, diff --git a/ports/nrf/common-hal/_bleio/Characteristic.h b/ports/nrf/common-hal/_bleio/Characteristic.h index 19970ef820..382fd4a81e 100644 --- a/ports/nrf/common-hal/_bleio/Characteristic.h +++ b/ports/nrf/common-hal/_bleio/Characteristic.h @@ -39,7 +39,7 @@ typedef struct _bleio_characteristic_obj { // Will be MP_OBJ_NULL before being assigned to a Service. bleio_service_obj_t *service; bleio_uuid_obj_t *uuid; - mp_obj_t value; + mp_obj_t initial_value; uint16_t max_length; bool fixed_length; uint16_t handle; diff --git a/ports/nrf/common-hal/_bleio/Connection.c b/ports/nrf/common-hal/_bleio/Connection.c index fccb5a22a7..4f747bf976 100644 --- a/ports/nrf/common-hal/_bleio/Connection.c +++ b/ports/nrf/common-hal/_bleio/Connection.c @@ -523,7 +523,7 @@ STATIC void on_char_discovery_rsp(ble_gattc_evt_char_disc_rsp_t *response, bleio 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_const_empty_bytes); mp_obj_list_append(MP_OBJ_FROM_PTR(m_char_discovery_service->characteristic_list), MP_OBJ_FROM_PTR(characteristic)); diff --git a/ports/nrf/common-hal/_bleio/Descriptor.c b/ports/nrf/common-hal/_bleio/Descriptor.c index faf50c658c..9e91107231 100644 --- a/ports/nrf/common-hal/_bleio/Descriptor.c +++ b/ports/nrf/common-hal/_bleio/Descriptor.c @@ -39,6 +39,7 @@ void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, bleio_c self->handle = BLE_GATT_HANDLE_INVALID; self->read_perm = read_perm; self->write_perm = write_perm; + self->initial_value = mp_obj_new_bytes(initial_value_bufinfo->buf, initial_value_bufinfo->len); 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) { @@ -47,8 +48,6 @@ void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, bleio_c } self->max_length = max_length; self->fixed_length = fixed_length; - - common_hal_bleio_descriptor_set_value(self, initial_value_bufinfo); } bleio_uuid_obj_t *common_hal_bleio_descriptor_get_uuid(bleio_descriptor_obj_t *self) { @@ -81,8 +80,6 @@ void common_hal_bleio_descriptor_set_value(bleio_descriptor_obj_t *self, mp_buff mp_raise_ValueError(translate("Value length > max_length")); } - self->value = mp_obj_new_bytes(bufinfo->buf, bufinfo->len); - // Do GATT operations only if this descriptor has been registered. if (self->handle != BLE_GATT_HANDLE_INVALID) { uint16_t conn_handle = bleio_connection_get_conn_handle(self->characteristic->service->connection); diff --git a/ports/nrf/common-hal/_bleio/Descriptor.h b/ports/nrf/common-hal/_bleio/Descriptor.h index f76510d128..4d6ac2543f 100644 --- a/ports/nrf/common-hal/_bleio/Descriptor.h +++ b/ports/nrf/common-hal/_bleio/Descriptor.h @@ -41,7 +41,7 @@ typedef struct _bleio_descriptor_obj { // Will be MP_OBJ_NULL before being assigned to a Characteristic. struct _bleio_characteristic_obj *characteristic; bleio_uuid_obj_t *uuid; - mp_obj_t value; + mp_obj_t initial_value; uint16_t max_length; bool fixed_length; uint16_t handle; diff --git a/ports/nrf/common-hal/_bleio/Service.c b/ports/nrf/common-hal/_bleio/Service.c index 8c57442f29..3159d3392f 100644 --- a/ports/nrf/common-hal/_bleio/Service.c +++ b/ports/nrf/common-hal/_bleio/Service.c @@ -124,11 +124,14 @@ void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, char_attr_md.rd_auth = true; #endif + mp_buffer_info_t char_value_bufinfo; + mp_get_buffer_raise(characteristic->initial_value, &char_value_bufinfo, MP_BUFFER_READ); + ble_gatts_attr_t char_attr = { .p_uuid = &char_uuid, .p_attr_md = &char_attr_md, - .init_len = 0, - .p_value = NULL, + .init_len = char_value_bufinfo.len, + .p_value = char_value_bufinfo.buf, .init_offs = 0, .max_len = characteristic->max_length, }; From d0ffdda5bb8f81fcf5002e2a75b4fef5b652fd7a Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 13 Aug 2020 17:47:35 -0400 Subject: [PATCH 29/84] fix reset logic to not do pin ops or heap ops at bad times --- devices/ble_hci/common-hal/_bleio/Adapter.c | 34 ++++++++++++--------- main.c | 2 ++ 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index 4ed85f7540..fe32241d17 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.c +++ b/devices/ble_hci/common-hal/_bleio/Adapter.c @@ -268,20 +268,22 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable supervisor_disable_tick(); } - // Stop any current activity; reset to known state. + // Enabling or disabling: stop any current activity; reset to known state. check_hci_error(hci_reset()); self->now_advertising = false; self->extended_advertising = false; self->circuitpython_advertising = false; self->advertising_timeout_msecs = 0; - // Reset list of known attributes. - // Indices into the list are handles. Handle 0x0000 designates an invalid handle, - // so store None there to skip it. - self->attributes = mp_obj_new_list(0, NULL); - bleio_adapter_add_attribute(self, mp_const_none); - self->last_added_service_handle = BLE_GATT_HANDLE_INVALID; - self->last_added_characteristic_handle = BLE_GATT_HANDLE_INVALID; + if (enabled) { + // Reset list of known attributes. + // Indices into the list are handles. Handle 0x0000 designates an invalid handle, + // so store None there to skip it. + self->attributes = mp_obj_new_list(0, NULL); + bleio_adapter_add_attribute(self, mp_const_none); + self->last_added_service_handle = BLE_GATT_HANDLE_INVALID; + self->last_added_characteristic_handle = BLE_GATT_HANDLE_INVALID; + } } bool common_hal_bleio_adapter_get_enabled(bleio_adapter_obj_t *self) { @@ -392,9 +394,11 @@ mp_obj_t common_hal_bleio_adapter_start_scan(bleio_adapter_obj_t *self, uint8_t* void common_hal_bleio_adapter_stop_scan(bleio_adapter_obj_t *self) { check_enabled(self); - check_hci_error(hci_le_set_scan_enable(BT_HCI_LE_SCAN_DISABLE, BT_HCI_LE_SCAN_FILTER_DUP_DISABLE)); - shared_module_bleio_scanresults_set_done(self->scan_results, true); - self->scan_results = NULL; + // If not already scanning, no problem. + if (hci_le_set_scan_enable(BT_HCI_LE_SCAN_DISABLE, BT_HCI_LE_SCAN_FILTER_DUP_DISABLE) == HCI_OK) { + shared_module_bleio_scanresults_set_done(self->scan_results, true); + self->scan_results = NULL; + } } // typedef struct { @@ -782,14 +786,13 @@ void bleio_adapter_gc_collect(bleio_adapter_obj_t* adapter) { } void bleio_adapter_reset(bleio_adapter_obj_t* adapter) { + if (!common_hal_bleio_adapter_get_enabled(adapter)) { return; } - common_hal_bleio_adapter_stop_scan(adapter); - if (adapter->now_advertising) { - common_hal_bleio_adapter_stop_advertising(adapter); - } + // Adapter will be reset. + common_hal_bleio_adapter_set_enabled(adapter, false); adapter->connection_objs = NULL; for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { @@ -801,6 +804,7 @@ void bleio_adapter_reset(bleio_adapter_obj_t* adapter) { } connection->connection_obj = mp_const_none; } + } void bleio_adapter_background(bleio_adapter_obj_t* adapter) { diff --git a/main.c b/main.c index 4dd93374e3..e1078edc14 100755 --- a/main.c +++ b/main.c @@ -212,6 +212,8 @@ bool maybe_run_list(const char ** filenames, pyexec_result_t* exec_result) { } void cleanup_after_vm(supervisor_allocation* heap) { + // Reset port-independent devices, like CIRCUITPY_BLEIO_HCI. + reset_devices(); // Turn off the display and flush the fileystem before the heap disappears. #if CIRCUITPY_DISPLAYIO reset_displays(); From 1c8e11b2cb74656d0dcde1ba5bec8fabb8b0461b Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 14 Aug 2020 23:38:58 -0400 Subject: [PATCH 30/84] bug in char get_value; raise NotImpl; better arg validation --- devices/ble_hci/common-hal/_bleio/Adapter.c | 8 ++++++++ devices/ble_hci/common-hal/_bleio/Characteristic.c | 4 +++- devices/ble_hci/common-hal/_bleio/Descriptor.c | 2 +- shared-bindings/_bleio/Characteristic.c | 12 ++++++++++-- shared-bindings/_bleio/Descriptor.c | 11 +++++++++-- 5 files changed, 31 insertions(+), 6 deletions(-) diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index fe32241d17..b197659ac2 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.c +++ b/devices/ble_hci/common-hal/_bleio/Adapter.c @@ -346,6 +346,8 @@ void common_hal_bleio_adapter_set_name(bleio_adapter_obj_t *self, const char* na // } mp_obj_t common_hal_bleio_adapter_start_scan(bleio_adapter_obj_t *self, uint8_t* prefixes, size_t prefix_length, bool extended, mp_int_t buffer_size, mp_float_t timeout, mp_float_t interval, mp_float_t window, mp_int_t minimum_rssi, bool active) { + // TODO + mp_raise_NotImplementedError(NULL); check_enabled(self); if (self->scan_results != NULL) { @@ -392,6 +394,8 @@ mp_obj_t common_hal_bleio_adapter_start_scan(bleio_adapter_obj_t *self, uint8_t* } void common_hal_bleio_adapter_stop_scan(bleio_adapter_obj_t *self) { + // TODO + mp_raise_NotImplementedError(NULL); check_enabled(self); // If not already scanning, no problem. @@ -430,6 +434,8 @@ void common_hal_bleio_adapter_stop_scan(bleio_adapter_obj_t *self) { // } mp_obj_t common_hal_bleio_adapter_connect(bleio_adapter_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout) { + // TODO + mp_raise_NotImplementedError(NULL); check_enabled(self); @@ -742,6 +748,8 @@ 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) { + // TODO + mp_raise_NotImplementedError(NULL); check_enabled(self); //FIX bonding_erase_storage(); diff --git a/devices/ble_hci/common-hal/_bleio/Characteristic.c b/devices/ble_hci/common-hal/_bleio/Characteristic.c index 5f9b96b354..393b80459a 100644 --- a/devices/ble_hci/common-hal/_bleio/Characteristic.c +++ b/devices/ble_hci/common-hal/_bleio/Characteristic.c @@ -93,7 +93,9 @@ size_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *sel if (!mp_get_buffer(self->value, &bufinfo, MP_BUFFER_READ)) { return 0; } - memcpy(buf, bufinfo.buf, MIN(len, bufinfo.len)); + const size_t actual_length = MIN(len, bufinfo.len); + memcpy(buf, bufinfo.buf, actual_length); + return actual_length; } } diff --git a/devices/ble_hci/common-hal/_bleio/Descriptor.c b/devices/ble_hci/common-hal/_bleio/Descriptor.c index cc45a89857..645273e285 100644 --- a/devices/ble_hci/common-hal/_bleio/Descriptor.c +++ b/devices/ble_hci/common-hal/_bleio/Descriptor.c @@ -74,7 +74,7 @@ size_t common_hal_bleio_descriptor_get_value(bleio_descriptor_obj_t *self, uint8 if (!mp_get_buffer(self->value, &bufinfo, MP_BUFFER_READ)) { return 0; } - size_t actual_length = MIN(len, bufinfo.len); + const size_t actual_length = MIN(len, bufinfo.len); memcpy(buf, bufinfo.buf, actual_length); return actual_length; } diff --git a/shared-bindings/_bleio/Characteristic.c b/shared-bindings/_bleio/Characteristic.c index 24b127e4a3..8372321fbf 100644 --- a/shared-bindings/_bleio/Characteristic.c +++ b/shared-bindings/_bleio/Characteristic.c @@ -109,11 +109,14 @@ STATIC mp_obj_t bleio_characteristic_add_to_service(size_t n_args, const mp_obj_ const bleio_attribute_security_mode_t write_perm = args[ARG_write_perm].u_int; common_hal_bleio_attribute_security_mode_check_valid(write_perm); - const mp_int_t max_length = args[ARG_max_length].u_int; + const mp_int_t max_length_int = args[ARG_max_length].u_int; + if (max_length_int <= 0) { + mp_raise_ValueError(translate("max_length must be > 0")); + } + const size_t max_length = (size_t) max_length_int; const bool fixed_length = args[ARG_fixed_length].u_bool; mp_obj_t initial_value = args[ARG_initial_value].u_obj; - // Length will be validated in common_hal. mp_buffer_info_t initial_value_bufinfo; if (initial_value == mp_const_none) { if (fixed_length && max_length > 0) { @@ -122,7 +125,12 @@ STATIC mp_obj_t bleio_characteristic_add_to_service(size_t n_args, const mp_obj_ initial_value = mp_const_empty_bytes; } } + mp_get_buffer_raise(initial_value, &initial_value_bufinfo, MP_BUFFER_READ); + if (initial_value_bufinfo.len > max_length || + (fixed_length && initial_value_bufinfo.len != max_length)) { + mp_raise_ValueError(translate("initial_value length is wrong")); + } bleio_characteristic_obj_t *characteristic = m_new_obj(bleio_characteristic_obj_t); characteristic->base.type = &bleio_characteristic_type; diff --git a/shared-bindings/_bleio/Descriptor.c b/shared-bindings/_bleio/Descriptor.c index e24751f759..dce618ecec 100644 --- a/shared-bindings/_bleio/Descriptor.c +++ b/shared-bindings/_bleio/Descriptor.c @@ -100,11 +100,14 @@ STATIC mp_obj_t bleio_descriptor_add_to_characteristic(size_t n_args, const mp_o const bleio_attribute_security_mode_t write_perm = args[ARG_write_perm].u_int; common_hal_bleio_attribute_security_mode_check_valid(write_perm); - const mp_int_t max_length = args[ARG_max_length].u_int; + const mp_int_t max_length_int = args[ARG_max_length].u_int; + if (max_length_int <= 0) { + mp_raise_ValueError(translate("max_length must be > 0")); + } + const size_t max_length = (size_t) max_length_int; const bool fixed_length = args[ARG_fixed_length].u_bool; mp_obj_t initial_value = args[ARG_initial_value].u_obj; - // Length will be validated in common_hal. mp_buffer_info_t initial_value_bufinfo; if (initial_value == mp_const_none) { if (fixed_length && max_length > 0) { @@ -114,6 +117,10 @@ STATIC mp_obj_t bleio_descriptor_add_to_characteristic(size_t n_args, const mp_o } } mp_get_buffer_raise(initial_value, &initial_value_bufinfo, MP_BUFFER_READ); + if (initial_value_bufinfo.len > max_length || + (fixed_length && initial_value_bufinfo.len != max_length)) { + mp_raise_ValueError(translate("initial_value length is wrong")); + } bleio_descriptor_obj_t *descriptor = m_new_obj(bleio_descriptor_obj_t); descriptor->base.type = &bleio_descriptor_type; From da48ab0568cc5c42996761fd2a09c5ac804b895c Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 16 Aug 2020 23:17:08 -0400 Subject: [PATCH 31/84] add generic services --- devices/ble_hci/common-hal/_bleio/Adapter.c | 138 +++++++++++++++++--- devices/ble_hci/common-hal/_bleio/Adapter.h | 6 + 2 files changed, 128 insertions(+), 16 deletions(-) diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index b197659ac2..e2296bb2aa 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.c +++ b/devices/ble_hci/common-hal/_bleio/Adapter.c @@ -74,6 +74,114 @@ bleio_connection_internal_t bleio_connections[BLEIO_TOTAL_CONNECTION_COUNT]; +STATIC void add_generic_services(bleio_adapter_obj_t *adapter) { + // Create Generic Access UUID, Service, and Characteristics. + + // Generic Access Service setup. + + bleio_uuid_obj_t *generic_access_service_uuid = m_new_obj(bleio_uuid_obj_t); + generic_access_service_uuid->base.type = &bleio_uuid_type; + common_hal_bleio_uuid_construct(generic_access_service_uuid, 0x1800, NULL); + + bleio_uuid_obj_t *device_name_characteristic_uuid = m_new_obj(bleio_uuid_obj_t); + device_name_characteristic_uuid->base.type = &bleio_uuid_type; + common_hal_bleio_uuid_construct(device_name_characteristic_uuid, 0x2A00, NULL); + + bleio_uuid_obj_t *appearance_characteristic_uuid = m_new_obj(bleio_uuid_obj_t); + appearance_characteristic_uuid->base.type = &bleio_uuid_type; + common_hal_bleio_uuid_construct(appearance_characteristic_uuid, 0x2A01, NULL); + + // Not implemented: + // Peripheral Preferred Connection Parameters + // Central Address Resolution + + bleio_service_obj_t *generic_access_service = m_new_obj(bleio_service_obj_t); + generic_access_service->base.type = &bleio_service_type; + common_hal_bleio_service_construct(generic_access_service, generic_access_service_uuid, false); + + adapter->device_name_characteristic = m_new_obj(bleio_characteristic_obj_t); + adapter->device_name_characteristic->base.type = &bleio_characteristic_type; + + char generic_name[] = { 'C', 'I', 'R', 'C', 'U', 'I', 'T', 'P', 'Y', 'n', 'n', 'n', 'n' }; + mp_buffer_info_t generic_name_bufinfo = { + .buf = generic_name, + .len = sizeof(generic_name), + }; + + // Will be added to service by constructor. + common_hal_bleio_characteristic_construct( + adapter->device_name_characteristic, + generic_access_service, + BLE_GATT_HANDLE_INVALID, + device_name_characteristic_uuid, + CHAR_PROP_READ, + SECURITY_MODE_OPEN, + SECURITY_MODE_NO_ACCESS, + 248, // max length, from Bluetooth spec + false, // not fixed length + &generic_name_bufinfo + ); + + uint16_t zero_16 = 0; + mp_buffer_info_t zero_16_value = { + .buf = &zero_16, + .len = sizeof(zero_16), + }; + + adapter->appearance_characteristic = m_new_obj(bleio_characteristic_obj_t); + adapter->appearance_characteristic->base.type = &bleio_characteristic_type; + + common_hal_bleio_characteristic_construct( + adapter->appearance_characteristic, + generic_access_service, + BLE_GATT_HANDLE_INVALID, + appearance_characteristic_uuid, + CHAR_PROP_READ, + SECURITY_MODE_OPEN, + SECURITY_MODE_NO_ACCESS, + 2, // max length, from Bluetooth spec + true, // fixed length + &zero_16_value + ); + + // Generic Attribute Service setup. + + bleio_uuid_obj_t *generic_attribute_service_uuid = m_new_obj(bleio_uuid_obj_t); + generic_attribute_service_uuid->base.type = &bleio_uuid_type; + common_hal_bleio_uuid_construct(generic_attribute_service_uuid, 0x1801, NULL); + + bleio_uuid_obj_t *service_changed_characteristic_uuid = m_new_obj(bleio_uuid_obj_t); + service_changed_characteristic_uuid->base.type = &bleio_uuid_type; + common_hal_bleio_uuid_construct(service_changed_characteristic_uuid, 0x2A05, NULL); + + bleio_service_obj_t *generic_attribute_service = m_new_obj(bleio_service_obj_t); + generic_attribute_service->base.type = &bleio_service_type; + common_hal_bleio_service_construct(generic_attribute_service, generic_attribute_service_uuid, false); + + adapter->service_changed_characteristic = m_new_obj(bleio_characteristic_obj_t); + adapter->service_changed_characteristic->base.type = &bleio_characteristic_type; + + uint32_t zero_32 = 0; + mp_buffer_info_t zero_32_value = { + .buf = &zero_32, + .len = sizeof(zero_32), + }; + + common_hal_bleio_characteristic_construct( + adapter->service_changed_characteristic, + generic_attribute_service, + BLE_GATT_HANDLE_INVALID, + service_changed_characteristic_uuid, + CHAR_PROP_INDICATE, + SECURITY_MODE_OPEN, + SECURITY_MODE_NO_ACCESS, + 4, // max length, from Bluetooth spec + true, // fixed length + &zero_32_value + ); +} + + STATIC void check_enabled(bleio_adapter_obj_t *adapter) { if (!common_hal_bleio_adapter_get_enabled(adapter)) { mp_raise_bleio_BluetoothError(translate("Adapter not enabled")); @@ -163,10 +271,13 @@ STATIC void check_enabled(bleio_adapter_obj_t *adapter) { // return true; // } -char default_ble_name[] = { 'C', 'I', 'R', 'C', 'U', 'I', 'T', 'P', 'Y', 0, 0, 0, 0 , 0}; +char default_ble_name[] = { 'C', 'I', 'R', 'C', 'U', 'I', 'T', 'P', 'Y', 0, 0, 0, 0}; -STATIC void bleio_adapter_reset_name(bleio_adapter_obj_t *self) { - uint8_t len = sizeof(default_ble_name) - 1; +// Get various values and limits set by the adapter. +// Set event mask. +STATIC void bleio_adapter_hci_init(bleio_adapter_obj_t *self) { + + const size_t len = sizeof(default_ble_name); bt_addr_t addr; check_hci_error(hci_read_bd_addr(&addr)); @@ -175,14 +286,7 @@ STATIC void bleio_adapter_reset_name(bleio_adapter_obj_t *self) { default_ble_name[len - 3] = nibble_to_hex_lower[addr.val[1] & 0xf]; default_ble_name[len - 2] = nibble_to_hex_lower[addr.val[0] >> 4 & 0xf]; default_ble_name[len - 1] = nibble_to_hex_lower[addr.val[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); -} - -// Get various values and limits set by the adapter. -// Set event mask. -STATIC void bleio_adapter_setup(bleio_adapter_obj_t *self) { + self->name = mp_obj_new_str(default_ble_name, len); // Get version information. if (hci_read_local_version(&self->hci_version, &self->hci_revision, &self->lmp_version, @@ -246,8 +350,8 @@ void common_hal_bleio_adapter_hci_uart_init(bleio_adapter_obj_t *self, busio_uar self->enabled = false; common_hal_bleio_adapter_set_enabled(self, true); - bleio_adapter_setup(self); - bleio_adapter_reset_name(self); + bleio_adapter_hci_init(self); + common_hal_bleio_adapter_set_name(self, default_ble_name); } void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enabled) { @@ -281,8 +385,7 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable // so store None there to skip it. self->attributes = mp_obj_new_list(0, NULL); bleio_adapter_add_attribute(self, mp_const_none); - self->last_added_service_handle = BLE_GATT_HANDLE_INVALID; - self->last_added_characteristic_handle = BLE_GATT_HANDLE_INVALID; + add_generic_services(self); } } @@ -309,6 +412,9 @@ mp_obj_str_t* common_hal_bleio_adapter_get_name(bleio_adapter_obj_t *self) { void common_hal_bleio_adapter_set_name(bleio_adapter_obj_t *self, const char* name) { self->name = mp_obj_new_str(name, strlen(name)); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(self->name, &bufinfo, MP_BUFFER_READ); + bleio_characteristic_set_local_value(self->device_name_characteristic, &bufinfo); } @@ -637,7 +743,7 @@ uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, check_hci_error(hci_le_set_advertising_data(advertising_data_len, full_data)); memset(full_data, 0, sizeof(full_data)); if (scan_response_data_len > 0) { - memcpy(full_data, advertising_data, MIN(sizeof(full_data), scan_response_data_len)); + memcpy(full_data, scan_response_data, MIN(sizeof(full_data), scan_response_data_len)); check_hci_error(hci_le_set_scan_response_data(scan_response_data_len, full_data)); } diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.h b/devices/ble_hci/common-hal/_bleio/Adapter.h index a6a78f67e7..f8748e5be1 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.h +++ b/devices/ble_hci/common-hal/_bleio/Adapter.h @@ -32,6 +32,7 @@ #include "py/obj.h" #include "py/objtuple.h" +#include "shared-bindings/_bleio/Characteristic.h" #include "shared-bindings/_bleio/Connection.h" #include "shared-bindings/_bleio/ScanResults.h" #include "shared-bindings/busio/UART.h" @@ -67,6 +68,11 @@ typedef struct _bleio_adapter_obj_t { uint64_t advertising_start_ticks; uint64_t advertising_timeout_msecs; // If zero, do not check. + // Generic services characteristics. + bleio_characteristic_obj_t *device_name_characteristic; + bleio_characteristic_obj_t *appearance_characteristic; + bleio_characteristic_obj_t * service_changed_characteristic; + uint16_t max_acl_buffer_len; uint16_t max_acl_num_buffers; uint16_t max_adv_data_len; From dfe50d08d573f2bf49a77e22de1843eb8db4b855 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 18 Aug 2020 16:10:09 -0400 Subject: [PATCH 32/84] Fix a few bugs --- devices/ble_hci/common-hal/_bleio/Adapter.c | 14 ++++++- devices/ble_hci/common-hal/_bleio/Adapter.h | 1 + devices/ble_hci/common-hal/_bleio/__init__.c | 6 +-- devices/ble_hci/common-hal/_bleio/att.c | 7 ++-- devices/ble_hci/common-hal/_bleio/att.h | 2 +- devices/ble_hci/common-hal/_bleio/hci.c | 42 +++++--------------- devices/ble_hci/common-hal/_bleio/hci.h | 12 +++--- 7 files changed, 33 insertions(+), 51 deletions(-) diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index e2296bb2aa..a86893dcde 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.c +++ b/devices/ble_hci/common-hal/_bleio/Adapter.c @@ -804,15 +804,25 @@ void common_hal_bleio_adapter_stop_advertising(bleio_adapter_obj_t *self) { self->now_advertising = false; self->extended_advertising = false; self->circuitpython_advertising = false; + int result = hci_le_set_advertising_enable(BT_HCI_LE_ADV_DISABLE); - // OK if we're already stopped. - if (result != BT_HCI_ERR_CMD_DISALLOWED) { + // OK if we're already stopped. There seems to be an ESP32 HCI bug: + // If advertising is already off, then LE_SET_ADV_ENABLE does not return a response. + if (result != HCI_RESPONSE_TIMEOUT) { check_hci_error(result); } //TODO startup CircuitPython advertising again. } +// Note that something stopped advertising, such as a connection happening. +//Don't ask the adapter to stop. +void bleio_adapter_advertising_was_stopped(bleio_adapter_obj_t *self) { + self->now_advertising = false; + self->extended_advertising = false; + self->circuitpython_advertising = false; +} + bool common_hal_bleio_adapter_get_advertising(bleio_adapter_obj_t *self) { check_enabled(self); diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.h b/devices/ble_hci/common-hal/_bleio/Adapter.h index f8748e5be1..dbccfbfb1a 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.h +++ b/devices/ble_hci/common-hal/_bleio/Adapter.h @@ -88,6 +88,7 @@ typedef struct _bleio_adapter_obj_t { } bleio_adapter_obj_t; uint16_t bleio_adapter_add_attribute(bleio_adapter_obj_t *adapter, mp_obj_t *attribute); +void bleio_adapter_advertising_was_stopped(bleio_adapter_obj_t *self); mp_obj_t* bleio_adapter_get_attribute(bleio_adapter_obj_t *adapter, uint16_t handle); uint16_t bleio_adapter_max_attribute_handle(bleio_adapter_obj_t *adapter); void bleio_adapter_background(bleio_adapter_obj_t* adapter); diff --git a/devices/ble_hci/common-hal/_bleio/__init__.c b/devices/ble_hci/common-hal/_bleio/__init__.c index 3c23c160ea..9dd531e25d 100644 --- a/devices/ble_hci/common-hal/_bleio/__init__.c +++ b/devices/ble_hci/common-hal/_bleio/__init__.c @@ -48,11 +48,7 @@ void check_hci_error(hci_result_t result) { case HCI_OK: return; - case HCI_NO_RESPONSE: - mp_raise_bleio_BluetoothError(translate("No HCI command response received")); - return; - - case HCI_READ_TIMEOUT: + case HCI_RESPONSE_TIMEOUT: mp_raise_bleio_BluetoothError(translate("Timeout waiting for HCI response")); return; diff --git a/devices/ble_hci/common-hal/_bleio/att.c b/devices/ble_hci/common-hal/_bleio/att.c index aa436faa58..aa25680124 100644 --- a/devices/ble_hci/common-hal/_bleio/att.c +++ b/devices/ble_hci/common-hal/_bleio/att.c @@ -224,7 +224,6 @@ bool att_disconnect(uint16_t conn_handle) { } hci_disconnect(conn_handle); - hci_poll_for_incoming_pkt_timeout(timeout); // Confirm we're now disconnected. return !att_handle_is_connected(conn_handle); @@ -508,13 +507,13 @@ void att_add_connection(uint16_t handle, uint8_t role, bt_addr_le_t *peer_addr, } -void att_remove_connection(uint16_t handle, uint8_t reason) { +void att_remove_connection(uint16_t conn_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) { + if (bleio_connections[i].conn_handle == conn_handle) { peer_index = i; } @@ -532,7 +531,7 @@ void att_remove_connection(uint16_t handle, uint8_t reason) { // Clear CCCD values on disconnect. size_t max_attribute_handle = bleio_adapter_max_attribute_handle(&common_hal_bleio_adapter_obj); - for (size_t i = 1; handle <= max_attribute_handle; i++) { + for (size_t handle = 1; handle <= max_attribute_handle; handle++) { mp_obj_t attribute_obj = bleio_adapter_get_attribute(&common_hal_bleio_adapter_obj, handle); uint16_t zero = 0; diff --git a/devices/ble_hci/common-hal/_bleio/att.h b/devices/ble_hci/common-hal/_bleio/att.h index 2b1723440f..b34b74dc37 100644 --- a/devices/ble_hci/common-hal/_bleio/att.h +++ b/devices/ble_hci/common-hal/_bleio/att.h @@ -49,7 +49,7 @@ 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_remove_connection(uint16_t conn_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); diff --git a/devices/ble_hci/common-hal/_bleio/hci.c b/devices/ble_hci/common-hal/_bleio/hci.c index f29121aaa2..e8fc324e1f 100644 --- a/devices/ble_hci/common-hal/_bleio/hci.c +++ b/devices/ble_hci/common-hal/_bleio/hci.c @@ -175,7 +175,6 @@ STATIC void process_evt_pkt(size_t pkt_len, uint8_t pkt_data[]) att_remove_connection(disconn_complete->handle, disconn_complete->reason); //FIX L2CAPSignaling.removeConnection(disconn_complete->handle, disconn_complete->reason); - hci_le_set_advertising_enable(0x01); break; } @@ -233,6 +232,12 @@ STATIC void process_evt_pkt(size_t pkt_len, uint8_t pkt_data[]) uint8_t *le_evt = pkt->params + sizeof (struct bt_hci_evt_le_meta_event); if (meta_evt->subevent == BT_HCI_EVT_LE_CONN_COMPLETE) { + // Advertising stops when connection occurs. + // We don't tell the adapter to stop, because stopping advertising + // when it's already stopped seems to exercise a bug in the ESP32 HCI code: + // It doesn't return a response. + bleio_adapter_advertising_was_stopped(&common_hal_bleio_adapter_obj); + struct bt_hci_evt_le_conn_complete *le_conn_complete = (struct bt_hci_evt_le_conn_complete *) le_evt; @@ -281,29 +286,11 @@ void bleio_hci_reset(void) { bleio_att_reset(); } -hci_result_t hci_poll_for_incoming_pkt_timeout(uint32_t timeout_msecs) { - uint64_t start = supervisor_ticks_ms64(); - - hci_result_t result = HCI_OK; - - 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(); + hci_poll_in_progress = true; // Assert RTS low to say we're ready to read data. common_hal_digitalio_digitalinout_set_value(common_hal_bleio_adapter_obj.rts_digitalinout, false); @@ -431,7 +418,7 @@ STATIC hci_result_t send_command(uint16_t opcode, uint8_t params_len, void* para // Wait for a response. Note that other packets may be received that are not // command responses. uint64_t start = supervisor_ticks_ms64(); - while (1) { + while (supervisor_ticks_ms64() - start < RESPONSE_TIMEOUT_MSECS) { result = hci_poll_for_incoming_pkt(); if (result != HCI_OK) { // I/O error. @@ -442,18 +429,14 @@ STATIC hci_result_t send_command(uint16_t opcode, uint8_t params_len, void* para // 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. + // or a BT_HCI_ERR_x value (> 0x00) if there was 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; + return HCI_RESPONSE_TIMEOUT; } hci_result_t hci_send_acl_pkt(uint16_t handle, uint8_t cid, uint8_t data_len, uint8_t *data) { @@ -528,11 +511,6 @@ 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; } diff --git a/devices/ble_hci/common-hal/_bleio/hci.h b/devices/ble_hci/common-hal/_bleio/hci.h index 5dc831eb48..58aa71d3b3 100644 --- a/devices/ble_hci/common-hal/_bleio/hci.h +++ b/devices/ble_hci/common-hal/_bleio/hci.h @@ -32,12 +32,11 @@ typedef struct _bleio_adapter_obj_t bleio_adapter_obj_t; // 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) -#define HCI_ATT_ERROR (-6) +#define HCI_RESPONSE_TIMEOUT (-1) +#define HCI_WRITE_TIMEOUT (-2) +#define HCI_READ_ERROR (-3) +#define HCI_WRITE_ERROR (-4) +#define HCI_ATT_ERROR (-5) void bleio_hci_reset(void); @@ -65,7 +64,6 @@ hci_result_t hci_le_set_scan_parameters(uint8_t scan_type, uint16_t interval, ui 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); From 490380a504b539adbb9e2b9902c404733ff0a03f Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 20 Aug 2020 20:41:05 -0400 Subject: [PATCH 33/84] remove debugging uart code --- devices/ble_hci/common-hal/_bleio/hci.c | 35 ------------------------- 1 file changed, 35 deletions(-) diff --git a/devices/ble_hci/common-hal/_bleio/hci.c b/devices/ble_hci/common-hal/_bleio/hci.c index b366aa4ac9..ed9320330e 100644 --- a/devices/ble_hci/common-hal/_bleio/hci.c +++ b/devices/ble_hci/common-hal/_bleio/hci.c @@ -36,11 +36,6 @@ // Set to 1 for extensive HCI packet logging. #define HCI_DEBUG 0 -//FIX **********8 -busio_uart_obj_t debug_out; -bool debug_out_in_use; - - // HCI H4 protocol packet types: first byte in the packet. #define H4_CMD 0x01 #define H4_ACL 0x02 @@ -165,11 +160,6 @@ STATIC void process_acl_data_pkt(uint8_t pkt_len, uint8_t pkt_data[]) { // 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) { - const uint8_t ff = 0xff; - int err; - common_hal_busio_uart_write(&debug_out, (uint8_t *) &pending_pkt, 1, &err); - common_hal_busio_uart_write(&debug_out, (uint8_t *) &ff, 1, &err); - common_hal_busio_uart_write(&debug_out, (uint8_t *) &ff, 1, &err); if (num_pkts && pending_pkt > num_pkts) { pending_pkt -= num_pkts; } else { @@ -292,30 +282,14 @@ STATIC void process_evt_pkt(size_t pkt_len, uint8_t pkt_data[]) } } -//FIX -busio_uart_obj_t debug_out; -bool debug_out_in_use; - void bleio_hci_reset(void) { rx_idx = 0; pending_pkt = 0; hci_poll_in_progress = false; - debug_out_in_use = false; bleio_att_reset(); } hci_result_t hci_poll_for_incoming_pkt(void) { - if (!debug_out_in_use) { - debug_out.base.type = &busio_uart_type; - common_hal_busio_uart_construct(&debug_out, - &pin_PB12 /*D7*/, NULL, // no RX - NULL, NULL, - NULL, false, - 115200, 8, BUSIO_UART_PARITY_NONE, 1, 0, - 512, NULL, false); - debug_out_in_use = true; - } - common_hal_mcu_disable_interrupts(); if (hci_poll_in_progress) { common_hal_mcu_enable_interrupts(); @@ -394,15 +368,6 @@ hci_result_t hci_poll_for_incoming_pkt(void) { common_hal_digitalio_digitalinout_set_value(common_hal_bleio_adapter_obj.rts_digitalinout, true); size_t pkt_len = rx_idx; - //FIX output packet for debugging - int err; - common_hal_busio_uart_write(&debug_out, (uint8_t *) &rx_idx, 1, &err); - common_hal_busio_uart_write(&debug_out, (uint8_t *) &rx_idx, 1, &err); - common_hal_busio_uart_write(&debug_out, (uint8_t *) &rx_idx, 1, &err); - - common_hal_busio_uart_write(&debug_out, rx_buffer, rx_idx, &err); - - // Reset for next packet. rx_idx = 0; packet_is_complete = false; From 097f93a630199ae81732981ce3778632e7744f6c Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 21 Aug 2020 10:17:59 -0400 Subject: [PATCH 34/84] improve HCI packet error handling --- devices/ble_hci/common-hal/_bleio/hci.c | 12 ++++++++---- devices/ble_hci/common-hal/_bleio/hci.h | 15 ++++++++------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/devices/ble_hci/common-hal/_bleio/hci.c b/devices/ble_hci/common-hal/_bleio/hci.c index ed9320330e..e261a98475 100644 --- a/devices/ble_hci/common-hal/_bleio/hci.c +++ b/devices/ble_hci/common-hal/_bleio/hci.c @@ -331,27 +331,27 @@ hci_result_t hci_poll_for_incoming_pkt(void) { switch (rx_buffer[0]) { case H4_ACL: - if (rx_idx > sizeof(h4_hci_acl_pkt_t)) { + if (rx_idx >= sizeof(h4_hci_acl_pkt_t)) { const size_t total_len = sizeof(h4_hci_acl_pkt_t) + ((h4_hci_acl_pkt_t *) rx_buffer)->data_len; if (rx_idx == total_len) { packet_is_complete = true; } if (rx_idx > total_len) { - mp_printf(&mp_plat_print, "acl: rx_idx > total_len\n"); + return HCI_PACKET_SIZE_ERROR; } } break; case H4_EVT: - if (rx_idx > sizeof(h4_hci_evt_pkt_t)) { + if (rx_idx >= sizeof(h4_hci_evt_pkt_t)) { const size_t total_len = sizeof(h4_hci_evt_pkt_t) + ((h4_hci_evt_pkt_t *) rx_buffer)->param_len; if (rx_idx == total_len) { packet_is_complete = true; } if (rx_idx > total_len) { - mp_printf(&mp_plat_print, "evt: rx_idx > total_len\n"); + return HCI_PACKET_SIZE_ERROR; } } break; @@ -786,6 +786,10 @@ void hci_check_error(hci_result_t result) { mp_raise_bleio_BluetoothError(translate("Error writing to HCI adapter")); return; + case HCI_PACKET_SIZE_ERROR: + mp_raise_RuntimeError(translate("HCI packet size mismatch")); + return; + case HCI_ATT_ERROR: mp_raise_RuntimeError(translate("Error in ATT protocol code")); return; diff --git a/devices/ble_hci/common-hal/_bleio/hci.h b/devices/ble_hci/common-hal/_bleio/hci.h index 3d082c49cb..c9fd2393af 100644 --- a/devices/ble_hci/common-hal/_bleio/hci.h +++ b/devices/ble_hci/common-hal/_bleio/hci.h @@ -29,14 +29,15 @@ 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) +// or it is > 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_RESPONSE_TIMEOUT (-1) -#define HCI_WRITE_TIMEOUT (-2) -#define HCI_READ_ERROR (-3) -#define HCI_WRITE_ERROR (-4) -#define HCI_ATT_ERROR (-5) +#define HCI_OK (0) +#define HCI_RESPONSE_TIMEOUT (-1) +#define HCI_WRITE_TIMEOUT (-2) +#define HCI_READ_ERROR (-3) +#define HCI_WRITE_ERROR (-4) +#define HCI_ATT_ERROR (-5) +#define HCI_PACKET_SIZE_ERROR (-6) extern void bleio_hci_reset(void); From c21c39be5a3cdf9cc4688250bc39518c90424a89 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 21 Aug 2020 10:48:41 -0400 Subject: [PATCH 35/84] merge from upstream; update ulab --- extmod/ulab | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extmod/ulab b/extmod/ulab index 0394801933..11a7ecff6d 160000 --- a/extmod/ulab +++ b/extmod/ulab @@ -1 +1 @@ -Subproject commit 0394801933f6e68a5bc7cdb0da76c7884e8cf70a +Subproject commit 11a7ecff6d76a02644ff23a734b792afaa615e44 From 58573a70e19d69efd78f75a4780b55dced0e3cda Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 21 Aug 2020 11:02:24 -0400 Subject: [PATCH 36/84] bring submodules up to date --- frozen/circuitpython-stage | 2 +- lib/mp3 | 2 +- lib/protomatter | 2 +- lib/tinyusb | 2 +- ports/atmel-samd/asf4 | 2 +- ports/atmel-samd/peripherals | 2 +- ports/cxd56/spresense-exported-sdk | 2 +- ports/esp32s2/esp-idf | 2 +- ports/stm/st_driver | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/frozen/circuitpython-stage b/frozen/circuitpython-stage index 0d2c083a2f..9596a5904e 160000 --- a/frozen/circuitpython-stage +++ b/frozen/circuitpython-stage @@ -1 +1 @@ -Subproject commit 0d2c083a2fb57a1562d4806775f45273abbfbfae +Subproject commit 9596a5904ed757e6fbffcf03e7aa77ae9ecf5223 diff --git a/lib/mp3 b/lib/mp3 index c3c664bf4d..bc58a65496 160000 --- a/lib/mp3 +++ b/lib/mp3 @@ -1 +1 @@ -Subproject commit c3c664bf4db6a36d11808dfcbb5dbf7cff1715b8 +Subproject commit bc58a654964c799e972719a63ff12694998f3549 diff --git a/lib/protomatter b/lib/protomatter index 9f71088d2c..761d6437e8 160000 --- a/lib/protomatter +++ b/lib/protomatter @@ -1 +1 @@ -Subproject commit 9f71088d2c32206c6f0495704ae0c040426d5764 +Subproject commit 761d6437e8cd6a131d51de96974337121a9c7164 diff --git a/lib/tinyusb b/lib/tinyusb index dc5445e2f4..22100b252f 160000 --- a/lib/tinyusb +++ b/lib/tinyusb @@ -1 +1 @@ -Subproject commit dc5445e2f45cb348a44fe24fc1be4bc8b5ba5bab +Subproject commit 22100b252fc2eb8f51ed407949645653c4880fd9 diff --git a/ports/atmel-samd/asf4 b/ports/atmel-samd/asf4 index c0eef7b751..35a1525796 160000 --- a/ports/atmel-samd/asf4 +++ b/ports/atmel-samd/asf4 @@ -1 +1 @@ -Subproject commit c0eef7b75124fc946af5f75e12d82d6d01315ab1 +Subproject commit 35a1525796c7ef8a3893d90befdad2f267fca20e diff --git a/ports/atmel-samd/peripherals b/ports/atmel-samd/peripherals index e4161d7d6d..0f5f1522d0 160000 --- a/ports/atmel-samd/peripherals +++ b/ports/atmel-samd/peripherals @@ -1 +1 @@ -Subproject commit e4161d7d6d98d78eddcccb82128856af4baf7e50 +Subproject commit 0f5f1522d09c8fa7d858edec484a994c21c59668 diff --git a/ports/cxd56/spresense-exported-sdk b/ports/cxd56/spresense-exported-sdk index 7f6568c7f4..c991d439fa 160000 --- a/ports/cxd56/spresense-exported-sdk +++ b/ports/cxd56/spresense-exported-sdk @@ -1 +1 @@ -Subproject commit 7f6568c7f4898cdb24a2f06040784a836050686e +Subproject commit c991d439fac9c23cfcac0da16fe8055f818d40a4 diff --git a/ports/esp32s2/esp-idf b/ports/esp32s2/esp-idf index 7aae7f034b..160ba4924d 160000 --- a/ports/esp32s2/esp-idf +++ b/ports/esp32s2/esp-idf @@ -1 +1 @@ -Subproject commit 7aae7f034bab68d2dd6aaa763924c91eb697d87e +Subproject commit 160ba4924d8b588e718f76e3a0d0e92c11052fa3 diff --git a/ports/stm/st_driver b/ports/stm/st_driver index 3fc2e0f3db..1900834751 160000 --- a/ports/stm/st_driver +++ b/ports/stm/st_driver @@ -1 +1 @@ -Subproject commit 3fc2e0f3db155b33177bb0705e0dd65cadb58412 +Subproject commit 1900834751fd6754457874b8c971690bab33e0a7 From 8d785cbbe577a0ee6592aa263cae45e817f3e9ee Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 21 Aug 2020 11:37:15 -0400 Subject: [PATCH 37/84] fix stubs; make translate --- locale/circuitpython.pot | 26 +++++++++++++++++++++----- shared-bindings/_bleio/Adapter.c | 6 ++++-- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 1e227dcbc0..f53c9c51f8 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-18 11:19-0400\n" +"POT-Creation-Date: 2020-08-21 11:37-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -754,10 +754,18 @@ msgstr "" msgid "Expected a Characteristic" msgstr "" +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a DigitalInOut" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c msgid "Expected a Service" msgstr "" +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a UART" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c #: shared-bindings/_bleio/Service.c msgid "Expected a UUID" @@ -1349,10 +1357,6 @@ msgstr "" msgid "Pull not used when direction is output." msgstr "" -#: ports/stm/ref/pulseout-pre-timeralloc.c -msgid "PulseOut not supported on this chip" -msgstr "" - #: ports/stm/common-hal/os/__init__.c msgid "RNG DeInit Error" msgstr "" @@ -2409,6 +2413,10 @@ msgstr "" msgid "graphic must be 2048 bytes long" msgstr "" +#: shared-bindings/_bleio/Adapter.c +msgid "hci_uart_init not available" +msgstr "" + #: extmod/moduheapq.c msgid "heap must be a list" msgstr "" @@ -2453,6 +2461,10 @@ msgstr "" msgid "initial values must be iterable" msgstr "" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "initial_value length is wrong" +msgstr "" + #: py/compile.c msgid "inline assembler must be a function" msgstr "" @@ -2645,6 +2657,10 @@ msgstr "" msgid "max_length must be 0-%d when fixed_length is %s" msgstr "" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "max_length must be > 0" +msgstr "" + #: py/runtime.c msgid "maximum recursion depth exceeded" msgstr "" diff --git a/shared-bindings/_bleio/Adapter.c b/shared-bindings/_bleio/Adapter.c index 6942f37098..8f96d13ea1 100644 --- a/shared-bindings/_bleio/Adapter.c +++ b/shared-bindings/_bleio/Adapter.c @@ -71,8 +71,8 @@ //| ... //| -//| def hci_uart_init(self, *, uart: busio.UART, rts: digitalio.DigitalInOut, cts: digitalio.DigitalInOut, baudrate: int = 115200, buffer_size: int = 256): -//| On boards that do not have native BLE, you can an use HCI co-processor. +//| 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. //| Call `_bleio.adapter.hci_uart_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 @@ -83,6 +83,8 @@ //| The `_bleio.adapter` object is enabled during this call. //| //| Raises `RuntimeError` on boards with native BLE. +//| """ +//| ... //| 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) { #if CIRCUITPY_BLEIO_HCI From 6553628fcb66134d43edf1ce8b02f0e010bf57ea Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 21 Aug 2020 11:51:17 -0400 Subject: [PATCH 38/84] rename hci_include/README.dm to avoid triggering sphinx warning --- .../ble_hci/common-hal/_bleio/hci_include/{README.md => NOTE.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename devices/ble_hci/common-hal/_bleio/hci_include/{README.md => NOTE.txt} (100%) diff --git a/devices/ble_hci/common-hal/_bleio/hci_include/README.md b/devices/ble_hci/common-hal/_bleio/hci_include/NOTE.txt similarity index 100% rename from devices/ble_hci/common-hal/_bleio/hci_include/README.md rename to devices/ble_hci/common-hal/_bleio/hci_include/NOTE.txt From 770c204d5a283add29e03e421490e1d5b9663f3c Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 21 Aug 2020 17:03:45 -0400 Subject: [PATCH 39/84] sphinx fixes --- shared-bindings/_bleio/Adapter.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/shared-bindings/_bleio/Adapter.c b/shared-bindings/_bleio/Adapter.c index 8f96d13ea1..5b67a9ae95 100644 --- a/shared-bindings/_bleio/Adapter.c +++ b/shared-bindings/_bleio/Adapter.c @@ -73,11 +73,10 @@ //| 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. -//| Call `_bleio.adapter.hci_uart_init()` passing it the uart and pins used to communicate -//| with the co-processor, such as an Adafruit AirLift. +//| 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 +//| The ``uart``, ``rts``, and ``cts`` objects are used to //| communicate with the HCI co-processor in HCI mode. //| //| The `_bleio.adapter` object is enabled during this call. From c137a1612133e06d2b7bec06b325695c9a60c4b9 Mon Sep 17 00:00:00 2001 From: Lucian Copeland Date: Mon, 24 Aug 2020 14:49:06 -0400 Subject: [PATCH 40/84] Remove Meowbit LSE flag, harsher failure for LSE issues --- ports/stm/boards/meowbit_v121/mpconfigboard.h | 3 +-- ports/stm/peripherals/stm32f4/clocks.c | 17 +++-------------- ports/stm/peripherals/stm32f7/clocks.c | 17 +++-------------- ports/stm/peripherals/stm32h7/clocks.c | 17 +++-------------- 4 files changed, 10 insertions(+), 44 deletions(-) diff --git a/ports/stm/boards/meowbit_v121/mpconfigboard.h b/ports/stm/boards/meowbit_v121/mpconfigboard.h index 106f25b15c..be9f2a75fb 100644 --- a/ports/stm/boards/meowbit_v121/mpconfigboard.h +++ b/ports/stm/boards/meowbit_v121/mpconfigboard.h @@ -36,8 +36,7 @@ #define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000) #define HSE_VALUE ((uint32_t)12000000U) -#define LSE_VALUE ((uint32_t)32000U) -#define BOARD_HAS_LOW_SPEED_CRYSTAL (1) +#define BOARD_HAS_LOW_SPEED_CRYSTAL (0) #define BOARD_NO_VBUS_SENSE (1) #define BOARD_VTOR_DEFER (1) //Leave VTOR relocation to bootloader diff --git a/ports/stm/peripherals/stm32f4/clocks.c b/ports/stm/peripherals/stm32f4/clocks.c index 7a16812b36..c2d0a452a0 100644 --- a/ports/stm/peripherals/stm32f4/clocks.c +++ b/ports/stm/peripherals/stm32f4/clocks.c @@ -49,7 +49,6 @@ void stm32_peripherals_clocks_init(void) { RCC_ClkInitTypeDef RCC_ClkInitStruct; RCC_OscInitTypeDef RCC_OscInitStruct; RCC_PeriphCLKInitTypeDef PeriphClkInitStruct; - bool lse_failure = false; // Set voltage scaling in accordance with system clock speed __HAL_RCC_PWR_CLK_ENABLE(); @@ -76,15 +75,9 @@ void stm32_peripherals_clocks_init(void) { #endif if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { - // Failure likely means a LSE issue - attempt to swap to LSI, and set to crash - RCC_OscInitStruct.LSEState = RCC_LSE_OFF; - RCC_OscInitStruct.OscillatorType |= RCC_OSCILLATORTYPE_LSI; - RCC_OscInitStruct.LSIState = RCC_LSI_ON; - if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { - // No HSE means no USB, so just fail forever - while(1); - } - lse_failure = true; + // Clock issues are too problematic to even attempt recovery. + // If you end up here, check whether your LSE settings match your board. + while(1); } // Configure bus clock sources and divisors @@ -113,8 +106,4 @@ void stm32_peripherals_clocks_init(void) { #endif HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct); - - if (lse_failure) { - reset_into_safe_mode(HARD_CRASH); //TODO: make safe mode category CLOCK_FAULT? - } } diff --git a/ports/stm/peripherals/stm32f7/clocks.c b/ports/stm/peripherals/stm32f7/clocks.c index 93016f6828..f130887822 100644 --- a/ports/stm/peripherals/stm32f7/clocks.c +++ b/ports/stm/peripherals/stm32f7/clocks.c @@ -40,7 +40,6 @@ void stm32_peripherals_clocks_init(void) { RCC_ClkInitTypeDef RCC_ClkInitStruct; RCC_OscInitTypeDef RCC_OscInitStruct; RCC_PeriphCLKInitTypeDef PeriphClkInitStruct; - bool lse_failure = false; // Configure LSE Drive HAL_PWR_EnableBkUpAccess(); @@ -68,15 +67,9 @@ void stm32_peripherals_clocks_init(void) { RCC_OscInitStruct.PLL.PLLQ = CPY_CLK_PLLQ; if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { - // Failure likely means a LSE issue - attempt to swap to LSI, and set to crash - RCC_OscInitStruct.LSEState = RCC_LSE_OFF; - RCC_OscInitStruct.OscillatorType |= RCC_OSCILLATORTYPE_LSI; - RCC_OscInitStruct.LSIState = RCC_LSI_ON; - if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { - // No HSE means no USB, so just fail forever - while(1); - } - lse_failure = true; + // Clock issues are too problematic to even attempt recovery. + // If you end up here, check whether your LSE settings match your board. + while(1); } /* Activate the OverDrive to reach the 216 MHz Frequency */ @@ -111,8 +104,4 @@ void stm32_peripherals_clocks_init(void) { #endif HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct); - - if (lse_failure) { - reset_into_safe_mode(HARD_CRASH); //TODO: make safe mode category CLOCK_FAULT? - } } diff --git a/ports/stm/peripherals/stm32h7/clocks.c b/ports/stm/peripherals/stm32h7/clocks.c index 0e4e79f9f7..a088f78bf2 100644 --- a/ports/stm/peripherals/stm32h7/clocks.c +++ b/ports/stm/peripherals/stm32h7/clocks.c @@ -37,7 +37,6 @@ void stm32_peripherals_clocks_init(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; - bool lse_failure = false; // Set voltage scaling in accordance with system clock speed HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY); @@ -73,15 +72,9 @@ void stm32_peripherals_clocks_init(void) { RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE; RCC_OscInitStruct.PLL.PLLFRACN = 0; if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { - // Failure likely means a LSE issue - attempt to swap to LSI, and set to crash - RCC_OscInitStruct.LSEState = RCC_LSE_OFF; - RCC_OscInitStruct.OscillatorType |= RCC_OSCILLATORTYPE_LSI; - RCC_OscInitStruct.LSIState = RCC_LSI_ON; - if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { - // No HSE means no USB, so just fail forever - while(1); - } - lse_failure = true; + // Clock issues are too problematic to even attempt recovery. + // If you end up here, check whether your LSE settings match your board. + while(1); } // Configure bus clock sources and divisors @@ -116,8 +109,4 @@ void stm32_peripherals_clocks_init(void) { // Enable USB Voltage detector HAL_PWREx_EnableUSBVoltageDetector(); - - if (lse_failure) { - reset_into_safe_mode(HARD_CRASH); //TODO: make safe mode category CLOCK_FAULT? - } } From de9fd4a0fb26c1a62b97d6175c75568b68e50abd Mon Sep 17 00:00:00 2001 From: Lucian Copeland Date: Mon, 24 Aug 2020 17:59:13 -0400 Subject: [PATCH 41/84] Fix null dereference, invert auto_brightness to reenable screen --- ports/stm/boards/meowbit_v121/board.c | 2 +- ports/stm/boards/meowbit_v121/mpconfigboard.mk | 4 +++- ports/stm/common-hal/pulseio/PWMOut.c | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ports/stm/boards/meowbit_v121/board.c b/ports/stm/boards/meowbit_v121/board.c index 812a8c208c..b74f135165 100644 --- a/ports/stm/boards/meowbit_v121/board.c +++ b/ports/stm/boards/meowbit_v121/board.c @@ -106,7 +106,7 @@ void board_init(void) { &pin_PB03, NO_BRIGHTNESS_COMMAND, 1.0f, // brightness (ignored) - true, // auto_brightness + false, // auto_brightness false, // single_byte_bounds false, // data_as_commands true, // auto_refresh diff --git a/ports/stm/boards/meowbit_v121/mpconfigboard.mk b/ports/stm/boards/meowbit_v121/mpconfigboard.mk index 852836ef8f..9eaa1bd8fb 100644 --- a/ports/stm/boards/meowbit_v121/mpconfigboard.mk +++ b/ports/stm/boards/meowbit_v121/mpconfigboard.mk @@ -18,4 +18,6 @@ OPTIMIZATION_FLAGS = -Os LD_COMMON = boards/common_default.ld LD_FILE = boards/STM32F401xe_boot.ld -# LD_FILE = boards/STM32F401xe_fs.ld # use for internal flash + +# For debugging - also comment BOOTLOADER_OFFSET and BOARD_VTOR_DEFER +# LD_FILE = boards/STM32F401xe_fs.ld diff --git a/ports/stm/common-hal/pulseio/PWMOut.c b/ports/stm/common-hal/pulseio/PWMOut.c index ddbadaf4ce..4bcb072122 100644 --- a/ports/stm/common-hal/pulseio/PWMOut.c +++ b/ports/stm/common-hal/pulseio/PWMOut.c @@ -239,13 +239,14 @@ void common_hal_pulseio_pwmout_deinit(pulseio_pwmout_obj_t* self) { HAL_TIM_PWM_Stop(&self->handle, self->channel); } reset_pin_number(self->tim->pin->port,self->tim->pin->number); - self->tim = NULL; //if reserved timer has no active channels, we can disable it if (!reserved_tim[self->tim->tim_index - 1]) { tim_frequencies[self->tim->tim_index - 1] = 0x00; stm_peripherals_timer_free(self->handle.Instance); } + + self->tim = NULL; } void common_hal_pulseio_pwmout_set_duty_cycle(pulseio_pwmout_obj_t* self, uint16_t duty) { From a03b6a99e60c8c428d95bc78b1ee6948607f69c6 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 27 Aug 2020 15:10:52 -0500 Subject: [PATCH 42/84] gen_usb_descriptor: Fix off-by-1 error in endpoint counting --- tools/gen_usb_descriptor.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/gen_usb_descriptor.py b/tools/gen_usb_descriptor.py index baee8cad7b..adf0d8270d 100644 --- a/tools/gen_usb_descriptor.py +++ b/tools/gen_usb_descriptor.py @@ -382,8 +382,9 @@ if args.max_ep != 0: for interface in interfaces: for subdescriptor in interface.subdescriptors: endpoint_address = getattr(subdescriptor, 'bEndpointAddress', 0) & 0x7f - if endpoint_address > args.max_ep: - raise ValueError("Endpoint address %d of %s may not exceed %d" % (endpoint_address & 0x7f, interface.description, args.max_ep)) + print("Endpoint %d - vs max_ep %d" % (endpoint_address, args.max_ep)) + if endpoint_address >= args.max_ep: + raise ValueError("Endpoint address %d of %s must be less than %d" % (endpoint_address & 0x7f, interface.description, args.max_ep)) else: print("Unable to check whether maximum number of endpoints is respected", file=sys.stderr) From 563e038c0d210dd0d17f6dc65f2c9eb5bbff1892 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 27 Aug 2020 15:11:17 -0500 Subject: [PATCH 43/84] stm: Specify max endpoints for stm32f405xx .. which is why we can't have HID or MIDI on the stm32f405 feather --- ports/stm/mpconfigport.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/stm/mpconfigport.mk b/ports/stm/mpconfigport.mk index 19f9ffa44c..b827aa48b9 100644 --- a/ports/stm/mpconfigport.mk +++ b/ports/stm/mpconfigport.mk @@ -7,6 +7,7 @@ ifeq ($(MCU_VARIANT),STM32F405xx) CIRCUITPY_FRAMEBUFFERIO ?= 1 CIRCUITPY_RGBMATRIX ?= 1 CIRCUITPY_SDIOIO ?= 1 + USB_NUM_EP = 4 endif ifeq ($(MCU_SERIES),F4) From a09243472cf4e57d9c157ecd4c55416a42fb7081 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 28 Aug 2020 16:08:24 -0700 Subject: [PATCH 44/84] Add Kaluga board definition --- .github/workflows/build.yml | 1 + .../esp32s2/boards/espressif_kaluga_1/board.c | 47 +++++++++++++ .../boards/espressif_kaluga_1/mpconfigboard.h | 34 ++++++++++ .../espressif_kaluga_1/mpconfigboard.mk | 17 +++++ .../esp32s2/boards/espressif_kaluga_1/pins.c | 66 +++++++++++++++++++ .../boards/espressif_kaluga_1/sdkconfig | 33 ++++++++++ 6 files changed, 198 insertions(+) create mode 100644 ports/esp32s2/boards/espressif_kaluga_1/board.c create mode 100644 ports/esp32s2/boards/espressif_kaluga_1/mpconfigboard.h create mode 100644 ports/esp32s2/boards/espressif_kaluga_1/mpconfigboard.mk create mode 100644 ports/esp32s2/boards/espressif_kaluga_1/pins.c create mode 100644 ports/esp32s2/boards/espressif_kaluga_1/sdkconfig diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a8528168ac..e780f652ab 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -409,6 +409,7 @@ jobs: matrix: board: - "electroniccats_bastwifi" + - "espressif_kaluga_1" - "espressif_saola_1_wroom" - "espressif_saola_1_wrover" - "microdev_micro_s2" diff --git a/ports/esp32s2/boards/espressif_kaluga_1/board.c b/ports/esp32s2/boards/espressif_kaluga_1/board.c new file mode 100644 index 0000000000..9f708874bf --- /dev/null +++ b/ports/esp32s2/boards/espressif_kaluga_1/board.c @@ -0,0 +1,47 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft 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 "boards/board.h" +#include "mpconfigboard.h" +#include "shared-bindings/microcontroller/Pin.h" + +void board_init(void) { + // USB + common_hal_never_reset_pin(&pin_GPIO19); + common_hal_never_reset_pin(&pin_GPIO20); + + // Debug UART + common_hal_never_reset_pin(&pin_GPIO43); + common_hal_never_reset_pin(&pin_GPIO44); +} + +bool board_requests_safe_mode(void) { + return false; +} + +void reset_board(void) { + +} diff --git a/ports/esp32s2/boards/espressif_kaluga_1/mpconfigboard.h b/ports/esp32s2/boards/espressif_kaluga_1/mpconfigboard.h new file mode 100644 index 0000000000..84d15ffc2b --- /dev/null +++ b/ports/esp32s2/boards/espressif_kaluga_1/mpconfigboard.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Scott Shawcroft 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. + */ + +//Micropython setup + +#define MICROPY_HW_BOARD_NAME "Kaluga 1" +#define MICROPY_HW_MCU_NAME "ESP32S2" + +#define MICROPY_HW_NEOPIXEL (&pin_GPIO45) + +#define AUTORESET_DELAY_MS 500 diff --git a/ports/esp32s2/boards/espressif_kaluga_1/mpconfigboard.mk b/ports/esp32s2/boards/espressif_kaluga_1/mpconfigboard.mk new file mode 100644 index 0000000000..43b1a9a688 --- /dev/null +++ b/ports/esp32s2/boards/espressif_kaluga_1/mpconfigboard.mk @@ -0,0 +1,17 @@ +USB_VID = 0x239A +USB_PID = 0x80A6 +USB_PRODUCT = "Kaluga 1" +USB_MANUFACTURER = "Espressif" + +INTERNAL_FLASH_FILESYSTEM = 1 +LONGINT_IMPL = MPZ + +# The default queue depth of 16 overflows on release builds, +# so increase it to 32. +CFLAGS += -DCFG_TUD_TASK_QUEUE_SZ=32 + +CIRCUITPY_ESP_FLASH_MODE=dio +CIRCUITPY_ESP_FLASH_FREQ=40m +CIRCUITPY_ESP_FLASH_SIZE=4MB + +CIRCUITPY_MODULE=wrover diff --git a/ports/esp32s2/boards/espressif_kaluga_1/pins.c b/ports/esp32s2/boards/espressif_kaluga_1/pins.c new file mode 100644 index 0000000000..b0e9957a1d --- /dev/null +++ b/ports/esp32s2/boards/espressif_kaluga_1/pins.c @@ -0,0 +1,66 @@ +#include "shared-bindings/board/__init__.h" + +STATIC const mp_rom_map_elem_t board_global_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_IO10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_IO11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_IO12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_IO13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_IO14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_IO15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_IO16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_IO17), MP_ROM_PTR(&pin_GPIO17) }, + + + { MP_ROM_QSTR(MP_QSTR_IO18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_IO19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_IO20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_IO26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_IO33), MP_ROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_IO34), MP_ROM_PTR(&pin_GPIO34) }, + { MP_ROM_QSTR(MP_QSTR_IO35), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_IO36), MP_ROM_PTR(&pin_GPIO36) }, + { MP_ROM_QSTR(MP_QSTR_IO37), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_IO38), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_IO39), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_IO40), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_IO41), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_IO42), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_IO43), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_IO44), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_IO45), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_IO46), MP_ROM_PTR(&pin_GPIO46) }, + + + { MP_ROM_QSTR(MP_QSTR_CAMERA_XCLK), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_PCLK), MP_ROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_HREF), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_VSYNC), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_SIOD), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_SIOC), MP_ROM_PTR(&pin_GPIO7) }, + + + { MP_ROM_QSTR(MP_QSTR_CAMERA_D2), MP_ROM_PTR(&pin_GPIO46) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_D3), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_D4), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_D5), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_D6), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_D7), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_D8), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_D9), MP_ROM_PTR(&pin_GPIO38) }, + + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO45) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table); diff --git a/ports/esp32s2/boards/espressif_kaluga_1/sdkconfig b/ports/esp32s2/boards/espressif_kaluga_1/sdkconfig new file mode 100644 index 0000000000..9d8bbde967 --- /dev/null +++ b/ports/esp32s2/boards/espressif_kaluga_1/sdkconfig @@ -0,0 +1,33 @@ +CONFIG_ESP32S2_SPIRAM_SUPPORT=y + +# +# SPI RAM config +# +# CONFIG_SPIRAM_TYPE_AUTO is not set +CONFIG_SPIRAM_TYPE_ESPPSRAM16=y +# CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set +# CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not set +CONFIG_SPIRAM_SIZE=2097152 + +# +# PSRAM clock and cs IO for ESP32S2 +# +CONFIG_DEFAULT_PSRAM_CLK_IO=30 +CONFIG_DEFAULT_PSRAM_CS_IO=26 +# end of PSRAM clock and cs IO for ESP32S2 + +# CONFIG_SPIRAM_FETCH_INSTRUCTIONS is not set +# CONFIG_SPIRAM_RODATA is not set +# CONFIG_SPIRAM_SPEED_80M is not set +CONFIG_SPIRAM_SPEED_40M=y +# CONFIG_SPIRAM_SPEED_26M is not set +# CONFIG_SPIRAM_SPEED_20M is not set +CONFIG_SPIRAM=y +CONFIG_SPIRAM_BOOT_INIT=y +# CONFIG_SPIRAM_IGNORE_NOTFOUND is not set +CONFIG_SPIRAM_USE_MEMMAP=y +# CONFIG_SPIRAM_USE_CAPS_ALLOC is not set +# CONFIG_SPIRAM_USE_MALLOC is not set +CONFIG_SPIRAM_MEMTEST=y +# CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY is not set +# end of SPI RAM config From 81870413af5efc35beb31449a099fb69ba05e15c Mon Sep 17 00:00:00 2001 From: lady ada Date: Fri, 28 Aug 2020 19:08:36 -0400 Subject: [PATCH 45/84] add default I2C --- ports/atmel-samd/boards/blm_badge/pins.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/atmel-samd/boards/blm_badge/pins.c b/ports/atmel-samd/boards/blm_badge/pins.c index af1b693584..6e7d8da754 100644 --- a/ports/atmel-samd/boards/blm_badge/pins.c +++ b/ports/atmel-samd/boards/blm_badge/pins.c @@ -39,5 +39,7 @@ STATIC const mp_rom_map_elem_t board_global_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_L), MP_ROM_PTR(&pin_PA03) }, { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PA03) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, }; MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table); From 0bb5c6c07fdb0ce4100cd4b8a9465ad9f4d090ff Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 28 Aug 2020 16:37:25 -0700 Subject: [PATCH 46/84] Add unique USB PID --- ports/esp32s2/boards/espressif_kaluga_1/mpconfigboard.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/esp32s2/boards/espressif_kaluga_1/mpconfigboard.mk b/ports/esp32s2/boards/espressif_kaluga_1/mpconfigboard.mk index 43b1a9a688..ba85e46efc 100644 --- a/ports/esp32s2/boards/espressif_kaluga_1/mpconfigboard.mk +++ b/ports/esp32s2/boards/espressif_kaluga_1/mpconfigboard.mk @@ -1,5 +1,5 @@ USB_VID = 0x239A -USB_PID = 0x80A6 +USB_PID = 0x80C8 USB_PRODUCT = "Kaluga 1" USB_MANUFACTURER = "Espressif" From 7b59ede25e4bba09e2b104c2404399bbf0af7fb6 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 28 Aug 2020 18:22:22 -0700 Subject: [PATCH 47/84] Add remaining pins --- .../esp32s2/boards/espressif_kaluga_1/pins.c | 61 ++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/ports/esp32s2/boards/espressif_kaluga_1/pins.c b/ports/esp32s2/boards/espressif_kaluga_1/pins.c index b0e9957a1d..c1657d6c0e 100644 --- a/ports/esp32s2/boards/espressif_kaluga_1/pins.c +++ b/ports/esp32s2/boards/espressif_kaluga_1/pins.c @@ -44,6 +44,8 @@ STATIC const mp_rom_map_elem_t board_global_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_IO46), MP_ROM_PTR(&pin_GPIO46) }, + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_XCLK), MP_ROM_PTR(&pin_GPIO1) }, { MP_ROM_QSTR(MP_QSTR_CAMERA_PCLK), MP_ROM_PTR(&pin_GPIO33) }, { MP_ROM_QSTR(MP_QSTR_CAMERA_HREF), MP_ROM_PTR(&pin_GPIO3) }, @@ -61,6 +63,63 @@ STATIC const mp_rom_map_elem_t board_global_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_CAMERA_D8), MP_ROM_PTR(&pin_GPIO21) }, { MP_ROM_QSTR(MP_QSTR_CAMERA_D9), MP_ROM_PTR(&pin_GPIO38) }, - { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO45) }, + + { MP_ROM_QSTR(MP_QSTR_TOUCH1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH14), MP_ROM_PTR(&pin_GPIO14) }, + + // LED FPC + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_BT_ARRAY_ADC), MP_ROM_PTR(&pin_GPIO6) }, + + // 3.2 inch LCD FPC + { MP_ROM_QSTR(MP_QSTR_LCD_TP_MISO), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_LCD_TP_MOSI), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_LCD_TP_SCK), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_LCD_TP_CS), MP_ROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_LCD_TP_IRQ), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_LCD_TP_BUSY), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_LCD_BL_CTR), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_LCD_MISO), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_LCD_MOSI), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_LCD_CS), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_LCD_D_C), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_LCD_CLK), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_LCD_RST), MP_ROM_PTR(&pin_GPIO16) }, + + // Audio + { MP_ROM_QSTR(MP_QSTR_AUDIO_SPI_MISO), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_AUDIO_SPI_MOSI), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_AUDIO_SPI_SCK), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_AUDIO_SPI_CS), MP_ROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_AUDIO_BT_ADC), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_AUDIO_SCL), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_AUDIO_SDA), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_AUDIO_I2S0_MCLK), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_AUDIO_I2S0_BCLK), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_AUDIO_I2S0_LRCK), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_AUDIO_I2S0_SDI), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_AUDIO_I2S0_SDO), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_AUDIO_RST), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_AUDIO_WAKE_INT), MP_ROM_PTR(&pin_GPIO34) }, + { MP_ROM_QSTR(MP_QSTR_AUDIO_I2S1_MCLK), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_AUDIO_PA_CTRL), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_AUDIO_I2S1_SDI), MP_ROM_PTR(&pin_GPIO46) }, + { MP_ROM_QSTR(MP_QSTR_AUDIO_I2S1_SDO), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_AUDIO_I2S1_LRCK_DAC1), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_AUDIO_I2S1_BCLK_DAC2), MP_ROM_PTR(&pin_GPIO18) }, + }; MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table); From 455226ffded69538f5f453b566b499361b201ffb Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sun, 30 Aug 2020 11:09:49 -0500 Subject: [PATCH 48/84] 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(-) diff --git a/py/builtinimport.c b/py/builtinimport.c index 597819f55c..47ffab5196 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, From b27d51125134b4317b429eb7b015c9f94f22adb0 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 30 Aug 2020 14:06:48 -0400 Subject: [PATCH 49/84] 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 +++ .../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(-) diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index 27a2512815..559b586de3 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 dbccfbfb1a..bec1329f28 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 25aca39b51..9fc4b480d9 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 4d2968c39c..ac34c815ce 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 e9d867f77b..943e1a389b 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 5b67a9ae95..b70fd17f8f 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 62a1d1c767..36e9db7610 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 f3fdc517e4..dece5820fb 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 969d2efb1c..588b1f1973 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 e61086f84f..d88a0db48d 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 }, From aeeec581780bf1d7486b51b3b6f2de396941f73f Mon Sep 17 00:00:00 2001 From: Jonny Bergdahl Date: Wed, 26 Aug 2020 23:31:33 +0000 Subject: [PATCH 50/84] Translated using Weblate (Swedish) Currently translated at 99.8% (776 of 777 strings) Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/sv/ --- locale/sv.po | 70 ++++++++++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/locale/sv.po b/locale/sv.po index df205b1095..a72f8b4fbc 100644 --- a/locale/sv.po +++ b/locale/sv.po @@ -6,7 +6,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-08-18 11:19-0400\n" -"PO-Revision-Date: 2020-07-25 20:58+0000\n" +"PO-Revision-Date: 2020-08-30 18:28+0000\n" "Last-Translator: Jonny Bergdahl \n" "Language-Team: LANGUAGE \n" "Language: sv\n" @@ -14,7 +14,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.2-dev\n" +"X-Generator: Weblate 4.2.1-dev\n" #: main.c msgid "" @@ -82,7 +82,7 @@ msgstr "Index %q ligger utanför intervallet" #: py/obj.c msgid "%q indices must be integers, not %q" -msgstr "" +msgstr "%q index måste vara heltal, inte %q" #: shared-bindings/vectorio/Polygon.c msgid "%q list must be a list" @@ -122,39 +122,39 @@ msgstr "'%q' argument krävs" #: py/runtime.c msgid "'%q' object cannot assign attribute '%q'" -msgstr "" +msgstr "Objektet '%q' kan inte tilldela attributet '%q'" #: py/proto.c msgid "'%q' object does not support '%q'" -msgstr "" +msgstr "Objektet '%q' stöder inte '%q'" #: py/obj.c msgid "'%q' object does not support item assignment" -msgstr "" +msgstr "Objektet '%q' stöder inte tilldelning" #: py/obj.c msgid "'%q' object does not support item deletion" -msgstr "" +msgstr "Objektet '%q' stöder inte borttagning av objekt" #: py/runtime.c msgid "'%q' object has no attribute '%q'" -msgstr "" +msgstr "Objektet '%q' har inget attribut '%q'" #: py/runtime.c msgid "'%q' object is not an iterator" -msgstr "" +msgstr "Objektet '%q' är inte en iterator" #: py/objtype.c py/runtime.c msgid "'%q' object is not callable" -msgstr "" +msgstr "Objektet '%q' kan inte anropas" #: py/runtime.c msgid "'%q' object is not iterable" -msgstr "" +msgstr "Objektet '%q' är inte itererbart" #: py/obj.c msgid "'%q' object is not subscriptable" -msgstr "" +msgstr "Objektet '%q' är inte indexbar" #: py/emitinlinethumb.c py/emitinlinextensa.c #, c-format @@ -224,7 +224,7 @@ msgstr "'await' utanför funktion" #: py/compile.c msgid "'await', 'async for' or 'async with' outside async function" -msgstr "" +msgstr "'await', 'async for' eller 'async with' utanför asynk-funktion" #: py/compile.c msgid "'break' outside loop" @@ -457,7 +457,7 @@ msgstr "Buffertlängd måste vara en multipel av 512" #: ports/stm/common-hal/sdioio/SDCard.c msgid "Buffer must be a multiple of 512 bytes" -msgstr "" +msgstr "Bufferten måste vara en multipel av 512 byte" #: shared-bindings/bitbangio/I2C.c shared-bindings/busio/I2C.c msgid "Buffer must be at least length 1" @@ -657,7 +657,7 @@ msgstr "Det gick inte att starta om PWM" #: shared-bindings/_bleio/Adapter.c msgid "Could not set address" -msgstr "" +msgstr "Kan inte ange adress" #: ports/stm/common-hal/pulseio/PWMOut.c msgid "Could not start PWM" @@ -844,7 +844,7 @@ msgstr "Filen finns redan" #: shared-module/framebufferio/FramebufferDisplay.c #, c-format msgid "Framebuffer requires %d bytes" -msgstr "" +msgstr "Framebuffer kräver %d byte" #: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c msgid "Frequency captured is above capability. Capture Paused." @@ -888,7 +888,7 @@ msgstr "I2C init-fel" #: shared-bindings/audiobusio/I2SOut.c msgid "I2SOut not available" -msgstr "" +msgstr "I2SOut är inte tillgängligt" #: shared-bindings/aesio/aes.c #, c-format @@ -940,7 +940,7 @@ msgstr "Ogiltig %q-pinne" #: ports/stm/common-hal/busio/I2C.c ports/stm/common-hal/busio/SPI.c #: ports/stm/common-hal/busio/UART.c ports/stm/common-hal/sdioio/SDCard.c msgid "Invalid %q pin selection" -msgstr "" +msgstr "Ogiltigt val av % q pinne" #: ports/stm/common-hal/analogio/AnalogIn.c msgid "Invalid ADC Unit value" @@ -1258,7 +1258,7 @@ msgstr "Ingen uppspelning" #: main.c msgid "Not running saved code.\n" -msgstr "" +msgstr "Kör inte sparad kod.\n" #: shared-bindings/util.c msgid "" @@ -1442,7 +1442,7 @@ msgstr "Radvärdet måste vara digitalio.DigitalInOut" #: main.c msgid "Running in safe mode! " -msgstr "" +msgstr "Kör i säkert läge! " #: shared-module/sdcardio/SDCard.c msgid "SD card CSD format not supported" @@ -1456,12 +1456,12 @@ msgstr "SDA eller SCL behöver en pullup" #: ports/stm/common-hal/sdioio/SDCard.c #, c-format msgid "SDIO GetCardInfo Error %d" -msgstr "" +msgstr "SDIO GetCardInfo-fel %d" #: ports/stm/common-hal/sdioio/SDCard.c #, c-format msgid "SDIO Init Error %d" -msgstr "" +msgstr "SDIO Init-fel %d" #: ports/stm/common-hal/busio/SPI.c msgid "SPI Init Error" @@ -1831,7 +1831,7 @@ msgstr "__init __ () ska returnera None" #: py/objtype.c msgid "__init__() should return None, not '%q'" -msgstr "" +msgstr "__init__() ska returnera None, inte '%q'" #: py/objobject.c msgid "__new__ arg must be a user-type" @@ -1876,7 +1876,7 @@ msgstr "argumentet har fel typ" #: extmod/ulab/code/linalg/linalg.c msgid "argument must be ndarray" -msgstr "" +msgstr "argument måste vara ndarray" #: py/argcheck.c shared-bindings/_stage/__init__.c #: shared-bindings/digitalio/DigitalInOut.c shared-bindings/gamepad/GamePad.c @@ -2019,7 +2019,7 @@ msgstr "kan inte tilldela uttryck" #: py/obj.c py/objint.c shared-bindings/i2cperipheral/I2CPeripheral.c #: shared-module/_pixelbuf/PixelBuf.c msgid "can't convert %q to %q" -msgstr "" +msgstr "kan inte konvertera %q till %q" #: py/objstr.c msgid "can't convert '%q' object to %q implicitly" @@ -2027,7 +2027,7 @@ msgstr "kan inte konvertera '%q' objekt implicit till %q" #: py/obj.c msgid "can't convert to %q" -msgstr "" +msgstr "kan inte konvertera till %q" #: py/objstr.c msgid "can't convert to str implicitly" @@ -2848,7 +2848,7 @@ msgstr "antal punkter måste vara minst 2" #: py/obj.c msgid "object '%q' is not a tuple or list" -msgstr "" +msgstr "objektet '%q' är inte en tuple eller list" #: py/obj.c msgid "object does not support item assignment" @@ -2884,7 +2884,7 @@ msgstr "objektet är inte iterable" #: py/obj.c msgid "object of type '%q' has no len()" -msgstr "" +msgstr "objekt av typen '%q' har inte len()" #: py/obj.c msgid "object with buffer protocol required" @@ -2980,7 +2980,7 @@ msgstr "polygon kan endast registreras i en förälder" #: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c #: shared-bindings/ps2io/Ps2.c msgid "pop from empty %q" -msgstr "" +msgstr "pop från tom %q" #: py/objint_mpz.c msgid "pow() 3rd argument cannot be 0" @@ -3139,7 +3139,7 @@ msgstr "stream-åtgärd stöds inte" #: py/objstrunicode.c msgid "string indices must be integers, not %q" -msgstr "" +msgstr "strängindex måste vara heltal, inte %q" #: py/stream.c msgid "string not supported; use bytes or bytearray" @@ -3216,7 +3216,7 @@ msgstr "för många värden att packa upp (förväntat %d)" #: extmod/ulab/code/approx/approx.c msgid "trapz is defined for 1D arrays of equal length" -msgstr "" +msgstr "trapz är definierad för 1D-matriser med samma längd" #: extmod/ulab/code/linalg/linalg.c msgid "tuple index out of range" @@ -3282,7 +3282,7 @@ msgstr "okänd konverteringsspecificerare %c" #: py/objstr.c msgid "unknown format code '%c' for object of type '%q'" -msgstr "" +msgstr "okänd formatkod '%c' för objekt av typ '%q'" #: py/compile.c msgid "unknown type" @@ -3322,7 +3322,7 @@ msgstr "Formattecknet '%c' (0x%x) stöds inte vid index %d" #: py/runtime.c msgid "unsupported type for %q: '%q'" -msgstr "" +msgstr "typen %q stöder inte '%q'" #: py/runtime.c msgid "unsupported type for operator" @@ -3330,7 +3330,7 @@ msgstr "typ stöds inte för operatören" #: py/runtime.c msgid "unsupported types for %q: '%q', '%q'" -msgstr "" +msgstr "typen %q stöder inte '%q', '%q'" #: py/objint.c #, c-format @@ -3343,7 +3343,7 @@ msgstr "value_count måste vara > 0" #: extmod/ulab/code/linalg/linalg.c msgid "vectors must have same lengths" -msgstr "" +msgstr "vektorer måste ha samma längd" #: shared-bindings/watchdog/WatchDogTimer.c msgid "watchdog timeout must be greater than 0" From 6b506ab0adefb0a71b0a343df2cbf309c53ecb31 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Sun, 30 Aug 2020 20:28:56 +0200 Subject: [PATCH 51/84] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/ID.po | 60 +++++++++++++++++++-------------- locale/cs.po | 60 +++++++++++++++++++-------------- locale/de_DE.po | 60 +++++++++++++++++++-------------- locale/es.po | 60 +++++++++++++++++++-------------- locale/fil.po | 60 +++++++++++++++++++-------------- locale/fr.po | 60 +++++++++++++++++++-------------- locale/hi.po | 60 +++++++++++++++++++-------------- locale/it_IT.po | 60 +++++++++++++++++++-------------- locale/ja.po | 60 +++++++++++++++++++-------------- locale/ko.po | 60 +++++++++++++++++++-------------- locale/nl.po | 60 +++++++++++++++++++-------------- locale/pl.po | 60 +++++++++++++++++++-------------- locale/pt_BR.po | 71 +++++++++++++++++++++++++--------------- locale/sv.po | 60 +++++++++++++++++++-------------- locale/zh_Latn_pinyin.po | 60 +++++++++++++++++++-------------- 15 files changed, 549 insertions(+), 362 deletions(-) diff --git a/locale/ID.po b/locale/ID.po index ec5b6f6e86..6b2ef5f266 100644 --- a/locale/ID.po +++ b/locale/ID.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-18 11:19-0400\n" +"POT-Creation-Date: 2020-08-27 11:21-0400\n" "PO-Revision-Date: 2020-07-06 18:10+0000\n" "Last-Translator: oon arfiandwi \n" "Language-Team: LANGUAGE \n" @@ -308,7 +308,7 @@ msgstr "Semua channel event sedang digunakan" msgid "All sync event channels in use" msgstr "Semua channel event yang disinkronisasi sedang digunakan" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "All timers for this pin are in use" msgstr "Semua timer untuk pin ini sedang digunakan" @@ -320,7 +320,7 @@ msgstr "Semua timer untuk pin ini sedang digunakan" #: ports/cxd56/common-hal/pulseio/PulseOut.c #: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #: ports/nrf/common-hal/pulseio/PulseIn.c ports/nrf/peripherals/nrf/timers.c -#: ports/stm/peripherals/timers.c shared-bindings/pulseio/PWMOut.c +#: ports/stm/peripherals/timers.c shared-bindings/pwmio/PWMOut.c msgid "All timers in use" msgstr "Semua timer sedang digunakan" @@ -566,7 +566,7 @@ msgstr "Tidak dapat transfer tanpa pin MOSI dan MISO." msgid "Cannot unambiguously get sizeof scalar" msgstr "tidak dapat mendapatkan ukuran scalar secara tidak ambigu" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Cannot vary frequency on a timer that is already in use" msgstr "" "Tidak dapat membuat variasi frekuensi pada penghitung waktu yang sudah " @@ -640,23 +640,23 @@ msgstr "" msgid "Could not initialize UART" msgstr "Tidak dapat menginisialisasi UART" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize channel" msgstr "Tidak dapat menginisialisasi kanal" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize timer" msgstr "Tidak dapat menginisialisasi timer" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init channel" msgstr "Tidak dapat menginisialisasi ulang kanal" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init timer" msgstr "Tidak dapat menginisialisasi ulang timer" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not restart PWM" msgstr "Tidak dapat memulai ulang PWM" @@ -664,7 +664,7 @@ msgstr "Tidak dapat memulai ulang PWM" msgid "Could not set address" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not start PWM" msgstr "Tidak dapat memulai PWM" @@ -857,7 +857,7 @@ msgid "Frequency captured is above capability. Capture Paused." msgstr "" "Frekuensi yang ditangkap berada di atas kemampuan. Penangkapan Ditunda." -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Frequency must match existing PWMOut using this timer" msgstr "Frekuensi harus cocok dengan PWMOut yang ada menggunakan timer ini" @@ -961,9 +961,9 @@ msgstr "File BMP tidak valid" msgid "Invalid DAC pin supplied" msgstr "Pin DAC yang diberikan tidak valid" -#: ports/atmel-samd/common-hal/pulseio/PWMOut.c -#: ports/cxd56/common-hal/pulseio/PWMOut.c -#: ports/nrf/common-hal/pulseio/PWMOut.c shared-bindings/pulseio/PWMOut.c +#: ports/atmel-samd/common-hal/pwmio/PWMOut.c +#: ports/cxd56/common-hal/pwmio/PWMOut.c ports/nrf/common-hal/pwmio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "Invalid PWM frequency" msgstr "Frekuensi PWM tidak valid" @@ -1003,7 +1003,7 @@ msgstr "File tidak valid" msgid "Invalid format chunk size" msgstr "Ukuran potongan format tidak valid" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid frequency supplied" msgstr "Frekuensi yang diberikan tidak valid" @@ -1021,8 +1021,8 @@ msgid "Invalid phase" msgstr "Fase tidak valid" #: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -#: shared-bindings/pulseio/PWMOut.c shared-module/rgbmatrix/RGBMatrix.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c shared-bindings/pwmio/PWMOut.c +#: shared-module/rgbmatrix/RGBMatrix.c msgid "Invalid pin" msgstr "Pin tidak valid" @@ -1046,7 +1046,7 @@ msgstr "Pin untuk channel kanan tidak valid" msgid "Invalid pins" msgstr "Pin-pin tidak valid" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid pins for PWMOut" msgstr "Pin untuk PWMOut tidak valid" @@ -1228,7 +1228,7 @@ msgstr "" msgid "No long integer support" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "No more timers available on this pin." msgstr "" @@ -1297,12 +1297,12 @@ msgstr "" msgid "Oversample must be multiple of 8." msgstr "" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "" "PWM duty_cycle must be between 0 and 65535 inclusive (16 bit resolution)" msgstr "" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "" "PWM frequency not writable when variable_frequency is False on construction." msgstr "" @@ -1357,8 +1357,8 @@ msgstr "" #: ports/nrf/common-hal/pulseio/PulseOut.c #: ports/stm/common-hal/pulseio/PulseOut.c msgid "" -"Port does not accept pins or frequency. " -"Construct and pass a PWMOut Carrier instead" +"Port does not accept pins or frequency. Construct and pass a PWMOut Carrier " +"instead" msgstr "" #: shared-bindings/_bleio/Adapter.c @@ -1591,7 +1591,7 @@ msgstr "" msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "" "Timer was reserved for internal use - declare PWM pins earlier in the program" msgstr "" @@ -2915,6 +2915,14 @@ msgstr "" msgid "ord() expected a character, but string of length %d found" msgstr "" +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of source" +msgstr "" + +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of target" +msgstr "" + #: py/objint_mpz.c msgid "overflow converting long int to machine word" msgstr "" @@ -3092,6 +3100,10 @@ msgstr "" msgid "sosfilt requires iterable arguments" msgstr "" +#: shared-bindings/displayio/Bitmap.c +msgid "source palette too large" +msgstr "" + #: py/objstr.c msgid "start/end indices" msgstr "" diff --git a/locale/cs.po b/locale/cs.po index b353f46306..4d13478eb1 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-18 11:19-0400\n" +"POT-Creation-Date: 2020-08-27 11:21-0400\n" "PO-Revision-Date: 2020-05-24 03:22+0000\n" "Last-Translator: dronecz \n" "Language-Team: LANGUAGE \n" @@ -308,7 +308,7 @@ msgstr "" msgid "All sync event channels in use" msgstr "" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "All timers for this pin are in use" msgstr "" @@ -320,7 +320,7 @@ msgstr "" #: ports/cxd56/common-hal/pulseio/PulseOut.c #: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #: ports/nrf/common-hal/pulseio/PulseIn.c ports/nrf/peripherals/nrf/timers.c -#: ports/stm/peripherals/timers.c shared-bindings/pulseio/PWMOut.c +#: ports/stm/peripherals/timers.c shared-bindings/pwmio/PWMOut.c msgid "All timers in use" msgstr "" @@ -558,7 +558,7 @@ msgstr "" msgid "Cannot unambiguously get sizeof scalar" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Cannot vary frequency on a timer that is already in use" msgstr "" @@ -627,23 +627,23 @@ msgstr "" msgid "Could not initialize UART" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize channel" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize timer" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init channel" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init timer" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not restart PWM" msgstr "" @@ -651,7 +651,7 @@ msgstr "" msgid "Could not set address" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not start PWM" msgstr "" @@ -842,7 +842,7 @@ msgstr "" msgid "Frequency captured is above capability. Capture Paused." msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Frequency must match existing PWMOut using this timer" msgstr "" @@ -944,9 +944,9 @@ msgstr "" msgid "Invalid DAC pin supplied" msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PWMOut.c -#: ports/cxd56/common-hal/pulseio/PWMOut.c -#: ports/nrf/common-hal/pulseio/PWMOut.c shared-bindings/pulseio/PWMOut.c +#: ports/atmel-samd/common-hal/pwmio/PWMOut.c +#: ports/cxd56/common-hal/pwmio/PWMOut.c ports/nrf/common-hal/pwmio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "Invalid PWM frequency" msgstr "" @@ -986,7 +986,7 @@ msgstr "" msgid "Invalid format chunk size" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid frequency supplied" msgstr "" @@ -1004,8 +1004,8 @@ msgid "Invalid phase" msgstr "" #: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -#: shared-bindings/pulseio/PWMOut.c shared-module/rgbmatrix/RGBMatrix.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c shared-bindings/pwmio/PWMOut.c +#: shared-module/rgbmatrix/RGBMatrix.c msgid "Invalid pin" msgstr "" @@ -1029,7 +1029,7 @@ msgstr "" msgid "Invalid pins" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid pins for PWMOut" msgstr "" @@ -1211,7 +1211,7 @@ msgstr "" msgid "No long integer support" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "No more timers available on this pin." msgstr "" @@ -1279,12 +1279,12 @@ msgstr "" msgid "Oversample must be multiple of 8." msgstr "" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "" "PWM duty_cycle must be between 0 and 65535 inclusive (16 bit resolution)" msgstr "" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "" "PWM frequency not writable when variable_frequency is False on construction." msgstr "" @@ -1339,8 +1339,8 @@ msgstr "" #: ports/nrf/common-hal/pulseio/PulseOut.c #: ports/stm/common-hal/pulseio/PulseOut.c msgid "" -"Port does not accept pins or frequency. " -"Construct and pass a PWMOut Carrier instead" +"Port does not accept pins or frequency. Construct and pass a PWMOut Carrier " +"instead" msgstr "" #: shared-bindings/_bleio/Adapter.c @@ -1570,7 +1570,7 @@ msgstr "" msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "" "Timer was reserved for internal use - declare PWM pins earlier in the program" msgstr "" @@ -2885,6 +2885,14 @@ msgstr "" msgid "ord() expected a character, but string of length %d found" msgstr "" +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of source" +msgstr "" + +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of target" +msgstr "" + #: py/objint_mpz.c msgid "overflow converting long int to machine word" msgstr "" @@ -3062,6 +3070,10 @@ msgstr "" msgid "sosfilt requires iterable arguments" msgstr "" +#: shared-bindings/displayio/Bitmap.c +msgid "source palette too large" +msgstr "" + #: py/objstr.c msgid "start/end indices" msgstr "" diff --git a/locale/de_DE.po b/locale/de_DE.po index 87cca4a77f..6be135ebdf 100644 --- a/locale/de_DE.po +++ b/locale/de_DE.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-18 11:19-0400\n" +"POT-Creation-Date: 2020-08-27 11:21-0400\n" "PO-Revision-Date: 2020-06-16 18:24+0000\n" "Last-Translator: Andreas Buchen \n" "Language: de_DE\n" @@ -307,7 +307,7 @@ msgstr "Alle event Kanäle werden benutzt" msgid "All sync event channels in use" msgstr "Alle sync event Kanäle werden benutzt" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "All timers for this pin are in use" msgstr "Alle timer für diesen Pin werden bereits benutzt" @@ -319,7 +319,7 @@ msgstr "Alle timer für diesen Pin werden bereits benutzt" #: ports/cxd56/common-hal/pulseio/PulseOut.c #: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #: ports/nrf/common-hal/pulseio/PulseIn.c ports/nrf/peripherals/nrf/timers.c -#: ports/stm/peripherals/timers.c shared-bindings/pulseio/PWMOut.c +#: ports/stm/peripherals/timers.c shared-bindings/pwmio/PWMOut.c msgid "All timers in use" msgstr "Alle timer werden benutzt" @@ -562,7 +562,7 @@ msgstr "Übertragung ohne MOSI- und MISO-Pins nicht möglich." msgid "Cannot unambiguously get sizeof scalar" msgstr "sizeof scalar kann nicht eindeutig bestimmt werden" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Cannot vary frequency on a timer that is already in use" msgstr "" "Die Frequenz eines bereits verwendeten Timers kann nicht variiert werden" @@ -637,23 +637,23 @@ msgstr "" msgid "Could not initialize UART" msgstr "Konnte UART nicht initialisieren" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize channel" msgstr "Kanal konnte nicht initialisiert werden" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize timer" msgstr "Timer konnte nicht initialisiert werden" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init channel" msgstr "Kanal konnte nicht neu initiiert werden" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init timer" msgstr "Timer konnte nicht neu gestartet werden" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not restart PWM" msgstr "PWM konnte nicht neu gestartet werden" @@ -661,7 +661,7 @@ msgstr "PWM konnte nicht neu gestartet werden" msgid "Could not set address" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not start PWM" msgstr "PWM konnte nicht gestartet werden" @@ -855,7 +855,7 @@ msgstr "" "Die aufgezeichnete Frequenz liegt über der Leistungsgrenze. Aufnahme " "angehalten." -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Frequency must match existing PWMOut using this timer" msgstr "" "Die Frequenz muss mit dem vorhandenen PWMOut unter Verwendung dieses Timers " @@ -961,9 +961,9 @@ msgstr "Ungültige BMP-Datei" msgid "Invalid DAC pin supplied" msgstr "Ungültiger DAC-Pin angegeben" -#: ports/atmel-samd/common-hal/pulseio/PWMOut.c -#: ports/cxd56/common-hal/pulseio/PWMOut.c -#: ports/nrf/common-hal/pulseio/PWMOut.c shared-bindings/pulseio/PWMOut.c +#: ports/atmel-samd/common-hal/pwmio/PWMOut.c +#: ports/cxd56/common-hal/pwmio/PWMOut.c ports/nrf/common-hal/pwmio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "Invalid PWM frequency" msgstr "Ungültige PWM Frequenz" @@ -1003,7 +1003,7 @@ msgstr "Ungültige Datei" msgid "Invalid format chunk size" msgstr "Ungültige format chunk size" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid frequency supplied" msgstr "Ungültige Frequenz geliefert" @@ -1021,8 +1021,8 @@ msgid "Invalid phase" msgstr "Ungültige Phase" #: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -#: shared-bindings/pulseio/PWMOut.c shared-module/rgbmatrix/RGBMatrix.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c shared-bindings/pwmio/PWMOut.c +#: shared-module/rgbmatrix/RGBMatrix.c msgid "Invalid pin" msgstr "Ungültiger Pin" @@ -1046,7 +1046,7 @@ msgstr "Ungültiger Pin für rechten Kanal" msgid "Invalid pins" msgstr "Ungültige Pins" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid pins for PWMOut" msgstr "Ungültige Pins für PWMOut" @@ -1230,7 +1230,7 @@ msgstr "Es wurde kein Schlüssel angegeben" msgid "No long integer support" msgstr "Keine langen Integer (long) unterstützt" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "No more timers available on this pin." msgstr "An diesem Pin sind keine Timer mehr verfügbar." @@ -1304,12 +1304,12 @@ msgstr "" msgid "Oversample must be multiple of 8." msgstr "Oversample muss ein Vielfaches von 8 sein." -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "" "PWM duty_cycle must be between 0 and 65535 inclusive (16 bit resolution)" msgstr "PWM duty_cycle muss zwischen 0 und 65535 (16 Bit Auflösung) liegen" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "" "PWM frequency not writable when variable_frequency is False on construction." msgstr "Die PWM-Frequenz ist nicht schreibbar wenn variable_Frequenz = False." @@ -1367,8 +1367,8 @@ msgstr "Polygone brauchen mindestens 3 Punkte" #: ports/nrf/common-hal/pulseio/PulseOut.c #: ports/stm/common-hal/pulseio/PulseOut.c msgid "" -"Port does not accept pins or frequency. " -"Construct and pass a PWMOut Carrier instead" +"Port does not accept pins or frequency. Construct and pass a PWMOut Carrier " +"instead" msgstr "" #: shared-bindings/_bleio/Adapter.c @@ -1612,7 +1612,7 @@ msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "" "Zeitbeschränkung ist zu groß: Maximale Zeitbeschränkung ist %d Sekunden" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "" "Timer was reserved for internal use - declare PWM pins earlier in the program" msgstr "" @@ -2966,6 +2966,14 @@ msgstr "" "ord() erwartet einen Buchstaben(char) aber es wurde ein String mit Länge %d " "gefunden" +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of source" +msgstr "" + +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of target" +msgstr "" + #: py/objint_mpz.c msgid "overflow converting long int to machine word" msgstr "Überlauf beim konvertieren von long int zu machine word" @@ -3145,6 +3153,10 @@ msgstr "" msgid "sosfilt requires iterable arguments" msgstr "" +#: shared-bindings/displayio/Bitmap.c +msgid "source palette too large" +msgstr "" + #: py/objstr.c msgid "start/end indices" msgstr "start/end Indizes" diff --git a/locale/es.po b/locale/es.po index 882904f640..2820d01a82 100644 --- a/locale/es.po +++ b/locale/es.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-18 11:19-0400\n" +"POT-Creation-Date: 2020-08-27 11:21-0400\n" "PO-Revision-Date: 2020-08-17 21:11+0000\n" "Last-Translator: Alvaro Figueroa \n" "Language-Team: \n" @@ -313,7 +313,7 @@ msgstr "" "Todos los canales de eventos de sincronización (sync event channels) están " "siendo utilizados" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "All timers for this pin are in use" msgstr "Todos los timers para este pin están siendo utilizados" @@ -325,7 +325,7 @@ msgstr "Todos los timers para este pin están siendo utilizados" #: ports/cxd56/common-hal/pulseio/PulseOut.c #: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #: ports/nrf/common-hal/pulseio/PulseIn.c ports/nrf/peripherals/nrf/timers.c -#: ports/stm/peripherals/timers.c shared-bindings/pulseio/PWMOut.c +#: ports/stm/peripherals/timers.c shared-bindings/pwmio/PWMOut.c msgid "All timers in use" msgstr "Todos los timers en uso" @@ -569,7 +569,7 @@ msgstr "No se puede transmitir sin pines MOSI y MISO." msgid "Cannot unambiguously get sizeof scalar" msgstr "No se puede obtener inequívocamente sizeof escalar" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Cannot vary frequency on a timer that is already in use" msgstr "No puede variar la frecuencia en un temporizador que ya está en uso" @@ -642,23 +642,23 @@ msgstr "No se pudo inicializar SDCard" msgid "Could not initialize UART" msgstr "No se puede inicializar la UART" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize channel" msgstr "No se pudo inicializar el canal" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize timer" msgstr "No se pudo inicializar el temporizador" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init channel" msgstr "No se pudo reiniciar el canal" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init timer" msgstr "No se pudo reiniciar el temporizador" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not restart PWM" msgstr "No se pudo reiniciar el PWM" @@ -666,7 +666,7 @@ msgstr "No se pudo reiniciar el PWM" msgid "Could not set address" msgstr "No se puede definir la dirección" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not start PWM" msgstr "No se pudo iniciar el PWM" @@ -857,7 +857,7 @@ msgstr "Framebuffer requiere %d bytes" msgid "Frequency captured is above capability. Capture Paused." msgstr "Frecuencia capturada por encima de la capacidad. Captura en pausa." -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Frequency must match existing PWMOut using this timer" msgstr "" "La frecuencia debe coincidir con PWMOut existente usando este temporizador" @@ -962,9 +962,9 @@ msgstr "Archivo BMP inválido" msgid "Invalid DAC pin supplied" msgstr "Pin suministrado inválido para DAC" -#: ports/atmel-samd/common-hal/pulseio/PWMOut.c -#: ports/cxd56/common-hal/pulseio/PWMOut.c -#: ports/nrf/common-hal/pulseio/PWMOut.c shared-bindings/pulseio/PWMOut.c +#: ports/atmel-samd/common-hal/pwmio/PWMOut.c +#: ports/cxd56/common-hal/pwmio/PWMOut.c ports/nrf/common-hal/pwmio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "Invalid PWM frequency" msgstr "Frecuencia PWM inválida" @@ -1004,7 +1004,7 @@ msgstr "Archivo inválido" msgid "Invalid format chunk size" msgstr "Formato de fragmento de formato no válido" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid frequency supplied" msgstr "Frecuencia suministrada no válida" @@ -1022,8 +1022,8 @@ msgid "Invalid phase" msgstr "Fase inválida" #: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -#: shared-bindings/pulseio/PWMOut.c shared-module/rgbmatrix/RGBMatrix.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c shared-bindings/pwmio/PWMOut.c +#: shared-module/rgbmatrix/RGBMatrix.c msgid "Invalid pin" msgstr "Pin inválido" @@ -1047,7 +1047,7 @@ msgstr "Pin inválido para canal derecho" msgid "Invalid pins" msgstr "pines inválidos" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid pins for PWMOut" msgstr "Pines inválidos para PWMOut" @@ -1229,7 +1229,7 @@ msgstr "No se especificó ninguna llave" msgid "No long integer support" msgstr "No hay soporte de entero largo" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "No more timers available on this pin." msgstr "No hay más temporizadores disponibles en este pin." @@ -1303,12 +1303,12 @@ msgstr "" msgid "Oversample must be multiple of 8." msgstr "El sobremuestreo debe ser un múltiplo de 8." -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "" "PWM duty_cycle must be between 0 and 65535 inclusive (16 bit resolution)" msgstr "PWM duty_cycle debe ser entre 0 y 65535 inclusivo (16 bit resolution)" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "" "PWM frequency not writable when variable_frequency is False on construction." msgstr "" @@ -1367,8 +1367,8 @@ msgstr "El polígono necesita al menos 3 puntos" #: ports/nrf/common-hal/pulseio/PulseOut.c #: ports/stm/common-hal/pulseio/PulseOut.c msgid "" -"Port does not accept pins or frequency. " -"Construct and pass a PWMOut Carrier instead" +"Port does not accept pins or frequency. Construct and pass a PWMOut Carrier " +"instead" msgstr "" #: shared-bindings/_bleio/Adapter.c @@ -1610,7 +1610,7 @@ msgstr "" "Tiempo de espera demasiado largo: El tiempo máximo de espera es de %d " "segundos" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "" "Timer was reserved for internal use - declare PWM pins earlier in the program" msgstr "" @@ -2952,6 +2952,14 @@ msgstr "ord espera un carácter" msgid "ord() expected a character, but string of length %d found" msgstr "ord() espera un carácter, pero encontró un string de longitud %d" +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of source" +msgstr "" + +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of target" +msgstr "" + #: py/objint_mpz.c msgid "overflow converting long int to machine word" msgstr "desbordamiento convirtiendo long int a palabra de máquina" @@ -3131,6 +3139,10 @@ msgstr "sos[:, 3] deberían ser todos unos" msgid "sosfilt requires iterable arguments" msgstr "sosfilt requiere argumentos iterables" +#: shared-bindings/displayio/Bitmap.c +msgid "source palette too large" +msgstr "" + #: py/objstr.c msgid "start/end indices" msgstr "índices inicio/final" diff --git a/locale/fil.po b/locale/fil.po index ec4f9f6856..60be99da76 100644 --- a/locale/fil.po +++ b/locale/fil.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-18 11:19-0400\n" +"POT-Creation-Date: 2020-08-27 11:21-0400\n" "PO-Revision-Date: 2018-12-20 22:15-0800\n" "Last-Translator: Timothy \n" "Language-Team: fil\n" @@ -304,7 +304,7 @@ msgstr "Lahat ng event channels ginagamit" msgid "All sync event channels in use" msgstr "Lahat ng sync event channels ay ginagamit" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "All timers for this pin are in use" msgstr "Lahat ng timers para sa pin na ito ay ginagamit" @@ -316,7 +316,7 @@ msgstr "Lahat ng timers para sa pin na ito ay ginagamit" #: ports/cxd56/common-hal/pulseio/PulseOut.c #: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #: ports/nrf/common-hal/pulseio/PulseIn.c ports/nrf/peripherals/nrf/timers.c -#: ports/stm/peripherals/timers.c shared-bindings/pulseio/PWMOut.c +#: ports/stm/peripherals/timers.c shared-bindings/pwmio/PWMOut.c msgid "All timers in use" msgstr "Lahat ng timer ginagamit" @@ -558,7 +558,7 @@ msgstr "Hindi maaaring ilipat kapag walang MOSI at MISO pin." msgid "Cannot unambiguously get sizeof scalar" msgstr "Hindi puedeng hindi sigurado ang get sizeof scalar" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Cannot vary frequency on a timer that is already in use" msgstr "" @@ -628,23 +628,23 @@ msgstr "" msgid "Could not initialize UART" msgstr "Hindi ma-initialize ang UART" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize channel" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize timer" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init channel" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init timer" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not restart PWM" msgstr "" @@ -652,7 +652,7 @@ msgstr "" msgid "Could not set address" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not start PWM" msgstr "" @@ -848,7 +848,7 @@ msgstr "" msgid "Frequency captured is above capability. Capture Paused." msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Frequency must match existing PWMOut using this timer" msgstr "" @@ -952,9 +952,9 @@ msgstr "Mali ang BMP file" msgid "Invalid DAC pin supplied" msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PWMOut.c -#: ports/cxd56/common-hal/pulseio/PWMOut.c -#: ports/nrf/common-hal/pulseio/PWMOut.c shared-bindings/pulseio/PWMOut.c +#: ports/atmel-samd/common-hal/pwmio/PWMOut.c +#: ports/cxd56/common-hal/pwmio/PWMOut.c ports/nrf/common-hal/pwmio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "Invalid PWM frequency" msgstr "Mali ang PWM frequency" @@ -994,7 +994,7 @@ msgstr "Mali ang file" msgid "Invalid format chunk size" msgstr "Mali ang format ng chunk size" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid frequency supplied" msgstr "" @@ -1012,8 +1012,8 @@ msgid "Invalid phase" msgstr "Mali ang phase" #: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -#: shared-bindings/pulseio/PWMOut.c shared-module/rgbmatrix/RGBMatrix.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c shared-bindings/pwmio/PWMOut.c +#: shared-module/rgbmatrix/RGBMatrix.c msgid "Invalid pin" msgstr "Mali ang pin" @@ -1037,7 +1037,7 @@ msgstr "Mali ang pin para sa kanang channel" msgid "Invalid pins" msgstr "Mali ang pins" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid pins for PWMOut" msgstr "" @@ -1219,7 +1219,7 @@ msgstr "" msgid "No long integer support" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "No more timers available on this pin." msgstr "" @@ -1290,12 +1290,12 @@ msgstr "" msgid "Oversample must be multiple of 8." msgstr "Oversample ay dapat multiple ng 8." -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "" "PWM duty_cycle must be between 0 and 65535 inclusive (16 bit resolution)" msgstr "PWM duty_cycle ay dapat sa loob ng 0 at 65535 (16 bit resolution)" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "" "PWM frequency not writable when variable_frequency is False on construction." msgstr "" @@ -1351,8 +1351,8 @@ msgstr "" #: ports/nrf/common-hal/pulseio/PulseOut.c #: ports/stm/common-hal/pulseio/PulseOut.c msgid "" -"Port does not accept pins or frequency. " -"Construct and pass a PWMOut Carrier instead" +"Port does not accept pins or frequency. Construct and pass a PWMOut Carrier " +"instead" msgstr "" #: shared-bindings/_bleio/Adapter.c @@ -1585,7 +1585,7 @@ msgstr "" msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "" "Timer was reserved for internal use - declare PWM pins earlier in the program" msgstr "" @@ -2928,6 +2928,14 @@ msgstr "ord umaasa ng character" msgid "ord() expected a character, but string of length %d found" msgstr "ord() umaasa ng character pero string ng %d haba ang nakita" +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of source" +msgstr "" + +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of target" +msgstr "" + #: py/objint_mpz.c msgid "overflow converting long int to machine word" msgstr "overflow nagcoconvert ng long int sa machine word" @@ -3108,6 +3116,10 @@ msgstr "" msgid "sosfilt requires iterable arguments" msgstr "" +#: shared-bindings/displayio/Bitmap.c +msgid "source palette too large" +msgstr "" + #: py/objstr.c msgid "start/end indices" msgstr "start/end indeks" diff --git a/locale/fr.po b/locale/fr.po index 0562053f15..043fe6cf23 100644 --- a/locale/fr.po +++ b/locale/fr.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-18 11:19-0400\n" +"POT-Creation-Date: 2020-08-27 11:21-0400\n" "PO-Revision-Date: 2020-07-27 21:27+0000\n" "Last-Translator: Nathan \n" "Language: fr\n" @@ -312,7 +312,7 @@ msgstr "Tous les canaux d'événements sont utilisés" msgid "All sync event channels in use" msgstr "Tous les canaux d'événements de synchro sont utilisés" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "All timers for this pin are in use" msgstr "Tous les timers pour cette broche sont utilisés" @@ -324,7 +324,7 @@ msgstr "Tous les timers pour cette broche sont utilisés" #: ports/cxd56/common-hal/pulseio/PulseOut.c #: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #: ports/nrf/common-hal/pulseio/PulseIn.c ports/nrf/peripherals/nrf/timers.c -#: ports/stm/peripherals/timers.c shared-bindings/pulseio/PWMOut.c +#: ports/stm/peripherals/timers.c shared-bindings/pwmio/PWMOut.c msgid "All timers in use" msgstr "Tous les timers sont utilisés" @@ -570,7 +570,7 @@ msgstr "Pas de transfert sans broches MOSI et MISO." msgid "Cannot unambiguously get sizeof scalar" msgstr "Impossible d'obtenir la taille du scalaire sans ambigüité" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Cannot vary frequency on a timer that is already in use" msgstr "" "Impossible de faire varier la fréquence sur une minuterie déjà utilisée" @@ -645,23 +645,23 @@ msgstr "Impossible d'initialiser la carte SD" msgid "Could not initialize UART" msgstr "L'UART n'a pu être initialisé" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize channel" msgstr "Impossible d'initialiser la chaîne" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize timer" msgstr "Impossible d'initialiser la minuterie" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init channel" msgstr "Impossible de réinitialiser la chaîne" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init timer" msgstr "Impossible de réinitialiser le minuteur" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not restart PWM" msgstr "Impossible de redémarrer PWM" @@ -669,7 +669,7 @@ msgstr "Impossible de redémarrer PWM" msgid "Could not set address" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not start PWM" msgstr "Impossible de démarrer PWM" @@ -861,7 +861,7 @@ msgstr "" msgid "Frequency captured is above capability. Capture Paused." msgstr "La fréquence capturée est au delà des capacités. Capture en pause." -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Frequency must match existing PWMOut using this timer" msgstr "" "La fréquence doit correspondre à PWMOut existant à l'aide de cette minuterie" @@ -966,9 +966,9 @@ msgstr "Fichier BMP invalide" msgid "Invalid DAC pin supplied" msgstr "Broche DAC non valide fournie" -#: ports/atmel-samd/common-hal/pulseio/PWMOut.c -#: ports/cxd56/common-hal/pulseio/PWMOut.c -#: ports/nrf/common-hal/pulseio/PWMOut.c shared-bindings/pulseio/PWMOut.c +#: ports/atmel-samd/common-hal/pwmio/PWMOut.c +#: ports/cxd56/common-hal/pwmio/PWMOut.c ports/nrf/common-hal/pwmio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "Invalid PWM frequency" msgstr "Fréquence de PWM invalide" @@ -1008,7 +1008,7 @@ msgstr "Fichier invalide" msgid "Invalid format chunk size" msgstr "Taille de bloc de formatage invalide" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid frequency supplied" msgstr "Fréquence invalide fournie" @@ -1026,8 +1026,8 @@ msgid "Invalid phase" msgstr "Phase invalide" #: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -#: shared-bindings/pulseio/PWMOut.c shared-module/rgbmatrix/RGBMatrix.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c shared-bindings/pwmio/PWMOut.c +#: shared-module/rgbmatrix/RGBMatrix.c msgid "Invalid pin" msgstr "Broche invalide" @@ -1051,7 +1051,7 @@ msgstr "Broche invalide pour le canal droit" msgid "Invalid pins" msgstr "Broches invalides" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid pins for PWMOut" msgstr "Broches non valides pour PWMOut" @@ -1233,7 +1233,7 @@ msgstr "Aucune clé n'a été spécifiée" msgid "No long integer support" msgstr "Pas de support entier long" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "No more timers available on this pin." msgstr "Plus de minuteurs disponibles sur cette broche." @@ -1307,14 +1307,14 @@ msgstr "" msgid "Oversample must be multiple of 8." msgstr "Le sur-échantillonage doit être un multiple de 8." -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "" "PWM duty_cycle must be between 0 and 65535 inclusive (16 bit resolution)" msgstr "" "La valeur de cycle PWM doit être entre 0 et 65535 inclus (résolution de 16 " "bits)" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "" "PWM frequency not writable when variable_frequency is False on construction." msgstr "" @@ -1374,8 +1374,8 @@ msgstr "Polygone a besoin d’au moins 3 points" #: ports/nrf/common-hal/pulseio/PulseOut.c #: ports/stm/common-hal/pulseio/PulseOut.c msgid "" -"Port does not accept pins or frequency. " -"Construct and pass a PWMOut Carrier instead" +"Port does not accept pins or frequency. Construct and pass a PWMOut Carrier " +"instead" msgstr "" #: shared-bindings/_bleio/Adapter.c @@ -1614,7 +1614,7 @@ msgstr "La largeur de la tuile doit diviser exactement la largeur de l'image" msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "Le délai est trop long : le délai maximal est de %d secondes" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "" "Timer was reserved for internal use - declare PWM pins earlier in the program" msgstr "" @@ -2972,6 +2972,14 @@ msgstr "" "ord() attend un caractère mais une chaîne de caractère de longueur %d a été " "trouvée" +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of source" +msgstr "" + +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of target" +msgstr "" + #: py/objint_mpz.c msgid "overflow converting long int to machine word" msgstr "dépassement de capacité en convertissant un entier long en mot machine" @@ -3152,6 +3160,10 @@ msgstr "" msgid "sosfilt requires iterable arguments" msgstr "" +#: shared-bindings/displayio/Bitmap.c +msgid "source palette too large" +msgstr "" + #: py/objstr.c msgid "start/end indices" msgstr "indices de début/fin" diff --git a/locale/hi.po b/locale/hi.po index 50a1887f67..717d21a275 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-18 11:19-0400\n" +"POT-Creation-Date: 2020-08-27 11:21-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" @@ -301,7 +301,7 @@ msgstr "" msgid "All sync event channels in use" msgstr "" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "All timers for this pin are in use" msgstr "" @@ -313,7 +313,7 @@ msgstr "" #: ports/cxd56/common-hal/pulseio/PulseOut.c #: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #: ports/nrf/common-hal/pulseio/PulseIn.c ports/nrf/peripherals/nrf/timers.c -#: ports/stm/peripherals/timers.c shared-bindings/pulseio/PWMOut.c +#: ports/stm/peripherals/timers.c shared-bindings/pwmio/PWMOut.c msgid "All timers in use" msgstr "" @@ -551,7 +551,7 @@ msgstr "" msgid "Cannot unambiguously get sizeof scalar" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Cannot vary frequency on a timer that is already in use" msgstr "" @@ -620,23 +620,23 @@ msgstr "" msgid "Could not initialize UART" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize channel" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize timer" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init channel" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init timer" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not restart PWM" msgstr "" @@ -644,7 +644,7 @@ msgstr "" msgid "Could not set address" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not start PWM" msgstr "" @@ -835,7 +835,7 @@ msgstr "" msgid "Frequency captured is above capability. Capture Paused." msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Frequency must match existing PWMOut using this timer" msgstr "" @@ -937,9 +937,9 @@ msgstr "" msgid "Invalid DAC pin supplied" msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PWMOut.c -#: ports/cxd56/common-hal/pulseio/PWMOut.c -#: ports/nrf/common-hal/pulseio/PWMOut.c shared-bindings/pulseio/PWMOut.c +#: ports/atmel-samd/common-hal/pwmio/PWMOut.c +#: ports/cxd56/common-hal/pwmio/PWMOut.c ports/nrf/common-hal/pwmio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "Invalid PWM frequency" msgstr "" @@ -979,7 +979,7 @@ msgstr "" msgid "Invalid format chunk size" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid frequency supplied" msgstr "" @@ -997,8 +997,8 @@ msgid "Invalid phase" msgstr "" #: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -#: shared-bindings/pulseio/PWMOut.c shared-module/rgbmatrix/RGBMatrix.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c shared-bindings/pwmio/PWMOut.c +#: shared-module/rgbmatrix/RGBMatrix.c msgid "Invalid pin" msgstr "" @@ -1022,7 +1022,7 @@ msgstr "" msgid "Invalid pins" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid pins for PWMOut" msgstr "" @@ -1204,7 +1204,7 @@ msgstr "" msgid "No long integer support" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "No more timers available on this pin." msgstr "" @@ -1272,12 +1272,12 @@ msgstr "" msgid "Oversample must be multiple of 8." msgstr "" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "" "PWM duty_cycle must be between 0 and 65535 inclusive (16 bit resolution)" msgstr "" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "" "PWM frequency not writable when variable_frequency is False on construction." msgstr "" @@ -1332,8 +1332,8 @@ msgstr "" #: ports/nrf/common-hal/pulseio/PulseOut.c #: ports/stm/common-hal/pulseio/PulseOut.c msgid "" -"Port does not accept pins or frequency. " -"Construct and pass a PWMOut Carrier instead" +"Port does not accept pins or frequency. Construct and pass a PWMOut Carrier " +"instead" msgstr "" #: shared-bindings/_bleio/Adapter.c @@ -1563,7 +1563,7 @@ msgstr "" msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "" "Timer was reserved for internal use - declare PWM pins earlier in the program" msgstr "" @@ -2878,6 +2878,14 @@ msgstr "" msgid "ord() expected a character, but string of length %d found" msgstr "" +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of source" +msgstr "" + +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of target" +msgstr "" + #: py/objint_mpz.c msgid "overflow converting long int to machine word" msgstr "" @@ -3055,6 +3063,10 @@ msgstr "" msgid "sosfilt requires iterable arguments" msgstr "" +#: shared-bindings/displayio/Bitmap.c +msgid "source palette too large" +msgstr "" + #: py/objstr.c msgid "start/end indices" msgstr "" diff --git a/locale/it_IT.po b/locale/it_IT.po index 9635220af3..c4214a1500 100644 --- a/locale/it_IT.po +++ b/locale/it_IT.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-18 11:19-0400\n" +"POT-Creation-Date: 2020-08-27 11:21-0400\n" "PO-Revision-Date: 2018-10-02 16:27+0200\n" "Last-Translator: Enrico Paganin \n" "Language-Team: \n" @@ -303,7 +303,7 @@ msgstr "Tutti i canali eventi utilizati" msgid "All sync event channels in use" msgstr "Tutti i canali di eventi sincronizzati in uso" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "All timers for this pin are in use" msgstr "Tutti i timer per questo pin sono in uso" @@ -315,7 +315,7 @@ msgstr "Tutti i timer per questo pin sono in uso" #: ports/cxd56/common-hal/pulseio/PulseOut.c #: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #: ports/nrf/common-hal/pulseio/PulseIn.c ports/nrf/peripherals/nrf/timers.c -#: ports/stm/peripherals/timers.c shared-bindings/pulseio/PWMOut.c +#: ports/stm/peripherals/timers.c shared-bindings/pwmio/PWMOut.c msgid "All timers in use" msgstr "Tutti i timer utilizzati" @@ -559,7 +559,7 @@ msgstr "Impossibile trasferire senza i pin MOSI e MISO." msgid "Cannot unambiguously get sizeof scalar" msgstr "Impossibile ricavare la grandezza scalare di sizeof inequivocabilmente" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Cannot vary frequency on a timer that is already in use" msgstr "" @@ -629,23 +629,23 @@ msgstr "" msgid "Could not initialize UART" msgstr "Impossibile inizializzare l'UART" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize channel" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize timer" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init channel" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init timer" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not restart PWM" msgstr "" @@ -653,7 +653,7 @@ msgstr "" msgid "Could not set address" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not start PWM" msgstr "" @@ -848,7 +848,7 @@ msgstr "" msgid "Frequency captured is above capability. Capture Paused." msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Frequency must match existing PWMOut using this timer" msgstr "" @@ -952,9 +952,9 @@ msgstr "File BMP non valido" msgid "Invalid DAC pin supplied" msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PWMOut.c -#: ports/cxd56/common-hal/pulseio/PWMOut.c -#: ports/nrf/common-hal/pulseio/PWMOut.c shared-bindings/pulseio/PWMOut.c +#: ports/atmel-samd/common-hal/pwmio/PWMOut.c +#: ports/cxd56/common-hal/pwmio/PWMOut.c ports/nrf/common-hal/pwmio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "Invalid PWM frequency" msgstr "Frequenza PWM non valida" @@ -996,7 +996,7 @@ msgstr "File non valido" msgid "Invalid format chunk size" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid frequency supplied" msgstr "" @@ -1014,8 +1014,8 @@ msgid "Invalid phase" msgstr "Fase non valida" #: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -#: shared-bindings/pulseio/PWMOut.c shared-module/rgbmatrix/RGBMatrix.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c shared-bindings/pwmio/PWMOut.c +#: shared-module/rgbmatrix/RGBMatrix.c msgid "Invalid pin" msgstr "Pin non valido" @@ -1039,7 +1039,7 @@ msgstr "Pin non valido per il canale destro" msgid "Invalid pins" msgstr "Pin non validi" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid pins for PWMOut" msgstr "" @@ -1223,7 +1223,7 @@ msgstr "" msgid "No long integer support" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "No more timers available on this pin." msgstr "" @@ -1295,14 +1295,14 @@ msgstr "" msgid "Oversample must be multiple of 8." msgstr "L'oversampling deve essere multiplo di 8." -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "" "PWM duty_cycle must be between 0 and 65535 inclusive (16 bit resolution)" msgstr "" "duty_cycle del PWM deve essere compresa tra 0 e 65535 inclusiva (risoluzione " "a 16 bit)" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c #, fuzzy msgid "" "PWM frequency not writable when variable_frequency is False on construction." @@ -1361,8 +1361,8 @@ msgstr "" #: ports/nrf/common-hal/pulseio/PulseOut.c #: ports/stm/common-hal/pulseio/PulseOut.c msgid "" -"Port does not accept pins or frequency. " -"Construct and pass a PWMOut Carrier instead" +"Port does not accept pins or frequency. Construct and pass a PWMOut Carrier " +"instead" msgstr "" #: shared-bindings/_bleio/Adapter.c @@ -1596,7 +1596,7 @@ msgstr "" msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "" "Timer was reserved for internal use - declare PWM pins earlier in the program" msgstr "" @@ -2934,6 +2934,14 @@ msgid "ord() expected a character, but string of length %d found" msgstr "" "ord() aspettava un carattere, ma ha ricevuto una stringa di lunghezza %d" +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of source" +msgstr "" + +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of target" +msgstr "" + #: py/objint_mpz.c msgid "overflow converting long int to machine word" msgstr "overflow convertendo long int in parola" @@ -3115,6 +3123,10 @@ msgstr "" msgid "sosfilt requires iterable arguments" msgstr "" +#: shared-bindings/displayio/Bitmap.c +msgid "source palette too large" +msgstr "" + #: py/objstr.c msgid "start/end indices" msgstr "" diff --git a/locale/ja.po b/locale/ja.po index 7c3b42580a..10e1d09a06 100644 --- a/locale/ja.po +++ b/locale/ja.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-18 11:19-0400\n" +"POT-Creation-Date: 2020-08-27 11:21-0400\n" "PO-Revision-Date: 2020-08-16 13:25+0000\n" "Last-Translator: Taku Fukada \n" "Language-Team: none\n" @@ -311,7 +311,7 @@ msgstr "全てのイベントチャネルが使用中" msgid "All sync event channels in use" msgstr "全ての同期イベントチャネルが使用中" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "All timers for this pin are in use" msgstr "このピン用の全てのタイマが使用中" @@ -323,7 +323,7 @@ msgstr "このピン用の全てのタイマが使用中" #: ports/cxd56/common-hal/pulseio/PulseOut.c #: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #: ports/nrf/common-hal/pulseio/PulseIn.c ports/nrf/peripherals/nrf/timers.c -#: ports/stm/peripherals/timers.c shared-bindings/pulseio/PWMOut.c +#: ports/stm/peripherals/timers.c shared-bindings/pwmio/PWMOut.c msgid "All timers in use" msgstr "全てのタイマーが使用中" @@ -565,7 +565,7 @@ msgstr "MOSIピンとMISOピンなしに転送できません" msgid "Cannot unambiguously get sizeof scalar" msgstr "スカラのサイズを曖昧さなしに取得できません" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Cannot vary frequency on a timer that is already in use" msgstr "使用中のタイマー上で周波数を変えられません" @@ -636,23 +636,23 @@ msgstr "SDカードを初期化できません" msgid "Could not initialize UART" msgstr "UARTを初期化できません" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize channel" msgstr "チャネルを初期化できません" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize timer" msgstr "タイマーを初期化できません" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init channel" msgstr "チャネルを再初期化できません" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init timer" msgstr "タイマーを再初期化できません" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not restart PWM" msgstr "PWMを再スタートできません" @@ -660,7 +660,7 @@ msgstr "PWMを再スタートできません" msgid "Could not set address" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not start PWM" msgstr "PWMをスタートできません" @@ -851,7 +851,7 @@ msgstr "" msgid "Frequency captured is above capability. Capture Paused." msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Frequency must match existing PWMOut using this timer" msgstr "このタイマーを使う既存のPWMOutと周波数を一致させてください" @@ -955,9 +955,9 @@ msgstr "不正なBMPファイル" msgid "Invalid DAC pin supplied" msgstr "無効なDACピンが与えられました" -#: ports/atmel-samd/common-hal/pulseio/PWMOut.c -#: ports/cxd56/common-hal/pulseio/PWMOut.c -#: ports/nrf/common-hal/pulseio/PWMOut.c shared-bindings/pulseio/PWMOut.c +#: ports/atmel-samd/common-hal/pwmio/PWMOut.c +#: ports/cxd56/common-hal/pwmio/PWMOut.c ports/nrf/common-hal/pwmio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "Invalid PWM frequency" msgstr "無効なPWM周波数" @@ -997,7 +997,7 @@ msgstr "不正なファイル" msgid "Invalid format chunk size" msgstr "フォーマットチャンクのサイズが不正" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid frequency supplied" msgstr "不正な周波数が与えられました" @@ -1015,8 +1015,8 @@ msgid "Invalid phase" msgstr "" #: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -#: shared-bindings/pulseio/PWMOut.c shared-module/rgbmatrix/RGBMatrix.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c shared-bindings/pwmio/PWMOut.c +#: shared-module/rgbmatrix/RGBMatrix.c msgid "Invalid pin" msgstr "不正なピン" @@ -1040,7 +1040,7 @@ msgstr "右チャネルのピンが不正" msgid "Invalid pins" msgstr "ピンが不正" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid pins for PWMOut" msgstr "PWMOutのピンが不正" @@ -1222,7 +1222,7 @@ msgstr "キーが指定されていません" msgid "No long integer support" msgstr "long integerサポートがありません" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "No more timers available on this pin." msgstr "このピンに利用可能なタイマーがもうありません" @@ -1292,13 +1292,13 @@ msgstr "" msgid "Oversample must be multiple of 8." msgstr "オーバーサンプルは8の倍数でなければなりません" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "" "PWM duty_cycle must be between 0 and 65535 inclusive (16 bit resolution)" msgstr "" "PWMの duty_cycle 値は 0 から 65535 の間でなければなりません(16ビット解像度)" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "" "PWM frequency not writable when variable_frequency is False on construction." msgstr "PWM周波数は、生成時のvariable_frequencyがFalseのとき書き換え不可" @@ -1353,8 +1353,8 @@ msgstr "ポリゴンには少なくとも3つの点が必要" #: ports/nrf/common-hal/pulseio/PulseOut.c #: ports/stm/common-hal/pulseio/PulseOut.c msgid "" -"Port does not accept pins or frequency. " -"Construct and pass a PWMOut Carrier instead" +"Port does not accept pins or frequency. Construct and pass a PWMOut Carrier " +"instead" msgstr "" #: shared-bindings/_bleio/Adapter.c @@ -1593,7 +1593,7 @@ msgstr "タイルの幅はビットマップの幅を割り切れる値でなけ msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "タイムアウトが長すぎ。最大のタイムアウト長は%d秒" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "" "Timer was reserved for internal use - declare PWM pins earlier in the program" msgstr "" @@ -2912,6 +2912,14 @@ msgstr "ord()は1文字を受け取ります" msgid "ord() expected a character, but string of length %d found" msgstr "ord()は1文字を要求しますが、長さ %d の文字列が与えられました" +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of source" +msgstr "" + +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of target" +msgstr "" + #: py/objint_mpz.c msgid "overflow converting long int to machine word" msgstr "long int をマシンの word に変換する際にオーバーフローしました" @@ -3091,6 +3099,10 @@ msgstr "" msgid "sosfilt requires iterable arguments" msgstr "" +#: shared-bindings/displayio/Bitmap.c +msgid "source palette too large" +msgstr "" + #: py/objstr.c msgid "start/end indices" msgstr "" diff --git a/locale/ko.po b/locale/ko.po index ecf539946f..2404c561d0 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-18 11:19-0400\n" +"POT-Creation-Date: 2020-08-27 11:21-0400\n" "PO-Revision-Date: 2019-05-06 14:22-0700\n" "Last-Translator: \n" "Language-Team: LANGUAGE \n" @@ -302,7 +302,7 @@ msgstr "" msgid "All sync event channels in use" msgstr "" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "All timers for this pin are in use" msgstr "핀의 모든 타이머가 사용 중입니다" @@ -314,7 +314,7 @@ msgstr "핀의 모든 타이머가 사용 중입니다" #: ports/cxd56/common-hal/pulseio/PulseOut.c #: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #: ports/nrf/common-hal/pulseio/PulseIn.c ports/nrf/peripherals/nrf/timers.c -#: ports/stm/peripherals/timers.c shared-bindings/pulseio/PWMOut.c +#: ports/stm/peripherals/timers.c shared-bindings/pwmio/PWMOut.c msgid "All timers in use" msgstr "모든 타이머가 사용 중입니다" @@ -554,7 +554,7 @@ msgstr "" msgid "Cannot unambiguously get sizeof scalar" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Cannot vary frequency on a timer that is already in use" msgstr "" @@ -623,23 +623,23 @@ msgstr "" msgid "Could not initialize UART" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize channel" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize timer" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init channel" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init timer" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not restart PWM" msgstr "" @@ -647,7 +647,7 @@ msgstr "" msgid "Could not set address" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not start PWM" msgstr "" @@ -838,7 +838,7 @@ msgstr "" msgid "Frequency captured is above capability. Capture Paused." msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Frequency must match existing PWMOut using this timer" msgstr "" @@ -940,9 +940,9 @@ msgstr "" msgid "Invalid DAC pin supplied" msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PWMOut.c -#: ports/cxd56/common-hal/pulseio/PWMOut.c -#: ports/nrf/common-hal/pulseio/PWMOut.c shared-bindings/pulseio/PWMOut.c +#: ports/atmel-samd/common-hal/pwmio/PWMOut.c +#: ports/cxd56/common-hal/pwmio/PWMOut.c ports/nrf/common-hal/pwmio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "Invalid PWM frequency" msgstr "" @@ -982,7 +982,7 @@ msgstr "파일이 유효하지 않습니다" msgid "Invalid format chunk size" msgstr "형식 청크 크기가 잘못되었습니다" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid frequency supplied" msgstr "" @@ -1000,8 +1000,8 @@ msgid "Invalid phase" msgstr "단계가 잘못되었습니다" #: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -#: shared-bindings/pulseio/PWMOut.c shared-module/rgbmatrix/RGBMatrix.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c shared-bindings/pwmio/PWMOut.c +#: shared-module/rgbmatrix/RGBMatrix.c msgid "Invalid pin" msgstr "핀이 잘못되었습니다" @@ -1025,7 +1025,7 @@ msgstr "오른쪽 채널 핀이 잘못되었습니다" msgid "Invalid pins" msgstr "핀이 유효하지 않습니다" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid pins for PWMOut" msgstr "" @@ -1207,7 +1207,7 @@ msgstr "" msgid "No long integer support" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "No more timers available on this pin." msgstr "" @@ -1275,12 +1275,12 @@ msgstr "" msgid "Oversample must be multiple of 8." msgstr "" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "" "PWM duty_cycle must be between 0 and 65535 inclusive (16 bit resolution)" msgstr "" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "" "PWM frequency not writable when variable_frequency is False on construction." msgstr "" @@ -1335,8 +1335,8 @@ msgstr "" #: ports/nrf/common-hal/pulseio/PulseOut.c #: ports/stm/common-hal/pulseio/PulseOut.c msgid "" -"Port does not accept pins or frequency. " -"Construct and pass a PWMOut Carrier instead" +"Port does not accept pins or frequency. Construct and pass a PWMOut Carrier " +"instead" msgstr "" #: shared-bindings/_bleio/Adapter.c @@ -1566,7 +1566,7 @@ msgstr "" msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "" "Timer was reserved for internal use - declare PWM pins earlier in the program" msgstr "" @@ -2882,6 +2882,14 @@ msgstr "" msgid "ord() expected a character, but string of length %d found" msgstr "" +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of source" +msgstr "" + +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of target" +msgstr "" + #: py/objint_mpz.c msgid "overflow converting long int to machine word" msgstr "" @@ -3059,6 +3067,10 @@ msgstr "" msgid "sosfilt requires iterable arguments" msgstr "" +#: shared-bindings/displayio/Bitmap.c +msgid "source palette too large" +msgstr "" + #: py/objstr.c msgid "start/end indices" msgstr "" diff --git a/locale/nl.po b/locale/nl.po index 3133596686..87133a4606 100644 --- a/locale/nl.po +++ b/locale/nl.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-18 11:19-0400\n" +"POT-Creation-Date: 2020-08-27 11:21-0400\n" "PO-Revision-Date: 2020-08-10 19:59+0000\n" "Last-Translator: _fonzlate \n" "Language-Team: none\n" @@ -308,7 +308,7 @@ msgstr "Alle event kanalen zijn in gebruik" msgid "All sync event channels in use" msgstr "Alle sync event kanalen zijn in gebruik" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "All timers for this pin are in use" msgstr "Alle timers voor deze pin zijn in gebruik" @@ -320,7 +320,7 @@ msgstr "Alle timers voor deze pin zijn in gebruik" #: ports/cxd56/common-hal/pulseio/PulseOut.c #: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #: ports/nrf/common-hal/pulseio/PulseIn.c ports/nrf/peripherals/nrf/timers.c -#: ports/stm/peripherals/timers.c shared-bindings/pulseio/PWMOut.c +#: ports/stm/peripherals/timers.c shared-bindings/pwmio/PWMOut.c msgid "All timers in use" msgstr "Alle timers zijn in gebruik" @@ -564,7 +564,7 @@ msgstr "Kan niet overdragen zonder MOSI en MISO pinnen." msgid "Cannot unambiguously get sizeof scalar" msgstr "Kan niet ondubbelzinning sizeof scalar verkrijgen" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Cannot vary frequency on a timer that is already in use" msgstr "Kan de frequentie van een timer die al in gebruik is niet variëren" @@ -637,23 +637,23 @@ msgstr "Kan SDCard niet initialiseren" msgid "Could not initialize UART" msgstr "Kan UART niet initialiseren" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize channel" msgstr "Kan kanaal niet initialiseren" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize timer" msgstr "Kan timer niet initialiseren" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init channel" msgstr "Kan kanaal niet her-initialiseren" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init timer" msgstr "Kan timer niet her-initialiseren" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not restart PWM" msgstr "Kan PWM niet herstarten" @@ -663,7 +663,7 @@ msgstr "Kan PWM niet herstarten" msgid "Could not set address" msgstr "Kan PWM niet starten" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not start PWM" msgstr "Kan PWM niet starten" @@ -855,7 +855,7 @@ msgid "Frequency captured is above capability. Capture Paused." msgstr "" "De vastgelegde frequentie is boven de capaciteit. Vastleggen gepauzeerd." -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Frequency must match existing PWMOut using this timer" msgstr "" "Frequentie moet overeenkomen met bestaande PWMOut bij gebruik van deze timer" @@ -962,9 +962,9 @@ msgstr "Ongeldig BMP bestand" msgid "Invalid DAC pin supplied" msgstr "Ongeldige DAC pin opgegeven" -#: ports/atmel-samd/common-hal/pulseio/PWMOut.c -#: ports/cxd56/common-hal/pulseio/PWMOut.c -#: ports/nrf/common-hal/pulseio/PWMOut.c shared-bindings/pulseio/PWMOut.c +#: ports/atmel-samd/common-hal/pwmio/PWMOut.c +#: ports/cxd56/common-hal/pwmio/PWMOut.c ports/nrf/common-hal/pwmio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "Invalid PWM frequency" msgstr "Ongeldige PWM frequentie" @@ -1004,7 +1004,7 @@ msgstr "Ongeldig bestand" msgid "Invalid format chunk size" msgstr "Ongeldig formaat stuk grootte" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid frequency supplied" msgstr "Ongeldige frequentie opgegeven" @@ -1022,8 +1022,8 @@ msgid "Invalid phase" msgstr "Ongeldige fase" #: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -#: shared-bindings/pulseio/PWMOut.c shared-module/rgbmatrix/RGBMatrix.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c shared-bindings/pwmio/PWMOut.c +#: shared-module/rgbmatrix/RGBMatrix.c msgid "Invalid pin" msgstr "Ongeldige pin" @@ -1047,7 +1047,7 @@ msgstr "Ongeldige pin voor rechter kanaal" msgid "Invalid pins" msgstr "Ongeldige pinnen" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid pins for PWMOut" msgstr "Ongeldige pinnen voor PWMOut" @@ -1229,7 +1229,7 @@ msgstr "Een sleutel was niet gespecificeerd" msgid "No long integer support" msgstr "Geen lange integer ondersteuning" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "No more timers available on this pin." msgstr "Geen timers meer beschikbaar op deze pin." @@ -1303,13 +1303,13 @@ msgstr "" msgid "Oversample must be multiple of 8." msgstr "Oversample moet een meervoud van 8 zijn." -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "" "PWM duty_cycle must be between 0 and 65535 inclusive (16 bit resolution)" msgstr "" "PWM duty_cycle moet tussen 0 en 65535 inclusief zijn (16 bit resolutie)" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "" "PWM frequency not writable when variable_frequency is False on construction." msgstr "" @@ -1369,8 +1369,8 @@ msgstr "Polygon heeft op zijn minst 3 punten nodig" #: ports/nrf/common-hal/pulseio/PulseOut.c #: ports/stm/common-hal/pulseio/PulseOut.c msgid "" -"Port does not accept pins or frequency. " -"Construct and pass a PWMOut Carrier instead" +"Port does not accept pins or frequency. Construct and pass a PWMOut Carrier " +"instead" msgstr "" #: shared-bindings/_bleio/Adapter.c @@ -1611,7 +1611,7 @@ msgstr "Tile breedte moet exact de bitmap breedte verdelen" msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "Time-out is te lang. Maximale time-out lengte is %d seconden" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "" "Timer was reserved for internal use - declare PWM pins earlier in the program" msgstr "" @@ -2947,6 +2947,14 @@ msgstr "ord verwacht een teken (char)" msgid "ord() expected a character, but string of length %d found" msgstr "ord() verwacht een teken (char) maar vond een string van lengte %d" +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of source" +msgstr "" + +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of target" +msgstr "" + #: py/objint_mpz.c msgid "overflow converting long int to machine word" msgstr "overloop bij converteren van long int naar machine word" @@ -3127,6 +3135,10 @@ msgstr "sos[:, 3] moeten allemaal 1 zijn" msgid "sosfilt requires iterable arguments" msgstr "sosfilt vereist itereerbare argumenten" +#: shared-bindings/displayio/Bitmap.c +msgid "source palette too large" +msgstr "" + #: py/objstr.c msgid "start/end indices" msgstr "start/stop indices" diff --git a/locale/pl.po b/locale/pl.po index 6c52062d9a..610da7bfc0 100644 --- a/locale/pl.po +++ b/locale/pl.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-18 11:19-0400\n" +"POT-Creation-Date: 2020-08-27 11:21-0400\n" "PO-Revision-Date: 2019-03-19 18:37-0700\n" "Last-Translator: Radomir Dopieralski \n" "Language-Team: pl\n" @@ -302,7 +302,7 @@ msgstr "Wszystkie kanały zdarzeń w użyciu" msgid "All sync event channels in use" msgstr "Wszystkie kanały zdarzeń synchronizacji w użyciu" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "All timers for this pin are in use" msgstr "Wszystkie timery tej nóżki w użyciu" @@ -314,7 +314,7 @@ msgstr "Wszystkie timery tej nóżki w użyciu" #: ports/cxd56/common-hal/pulseio/PulseOut.c #: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #: ports/nrf/common-hal/pulseio/PulseIn.c ports/nrf/peripherals/nrf/timers.c -#: ports/stm/peripherals/timers.c shared-bindings/pulseio/PWMOut.c +#: ports/stm/peripherals/timers.c shared-bindings/pwmio/PWMOut.c msgid "All timers in use" msgstr "Wszystkie timery w użyciu" @@ -554,7 +554,7 @@ msgstr "Nie można przesyłać bez nóżek MOSI i MISO." msgid "Cannot unambiguously get sizeof scalar" msgstr "Wielkość skalara jest niejednoznaczna" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Cannot vary frequency on a timer that is already in use" msgstr "" @@ -623,23 +623,23 @@ msgstr "" msgid "Could not initialize UART" msgstr "Ustawienie UART nie powiodło się" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize channel" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize timer" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init channel" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init timer" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not restart PWM" msgstr "" @@ -647,7 +647,7 @@ msgstr "" msgid "Could not set address" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not start PWM" msgstr "" @@ -838,7 +838,7 @@ msgstr "" msgid "Frequency captured is above capability. Capture Paused." msgstr "Uzyskana częstotliwość jest niemożliwa. Spauzowano." -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Frequency must match existing PWMOut using this timer" msgstr "" @@ -942,9 +942,9 @@ msgstr "Zły BMP" msgid "Invalid DAC pin supplied" msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PWMOut.c -#: ports/cxd56/common-hal/pulseio/PWMOut.c -#: ports/nrf/common-hal/pulseio/PWMOut.c shared-bindings/pulseio/PWMOut.c +#: ports/atmel-samd/common-hal/pwmio/PWMOut.c +#: ports/cxd56/common-hal/pwmio/PWMOut.c ports/nrf/common-hal/pwmio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "Invalid PWM frequency" msgstr "Zła częstotliwość PWM" @@ -984,7 +984,7 @@ msgstr "Zły plik" msgid "Invalid format chunk size" msgstr "Zła wielkość fragmentu formatu" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid frequency supplied" msgstr "" @@ -1002,8 +1002,8 @@ msgid "Invalid phase" msgstr "Zła faza" #: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -#: shared-bindings/pulseio/PWMOut.c shared-module/rgbmatrix/RGBMatrix.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c shared-bindings/pwmio/PWMOut.c +#: shared-module/rgbmatrix/RGBMatrix.c msgid "Invalid pin" msgstr "Zła nóżka" @@ -1027,7 +1027,7 @@ msgstr "Zła nóżka dla prawego kanału" msgid "Invalid pins" msgstr "Złe nóżki" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid pins for PWMOut" msgstr "" @@ -1209,7 +1209,7 @@ msgstr "" msgid "No long integer support" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "No more timers available on this pin." msgstr "" @@ -1277,12 +1277,12 @@ msgstr "" msgid "Oversample must be multiple of 8." msgstr "Nadpróbkowanie musi być wielokrotnością 8." -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "" "PWM duty_cycle must be between 0 and 65535 inclusive (16 bit resolution)" msgstr "duty_cycle musi być pomiędzy 0 a 65535 włącznie (rozdzielczość 16 bit)" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "" "PWM frequency not writable when variable_frequency is False on construction." msgstr "Nie można zmienić częstotliwości PWM gdy variable_frequency=False." @@ -1337,8 +1337,8 @@ msgstr "" #: ports/nrf/common-hal/pulseio/PulseOut.c #: ports/stm/common-hal/pulseio/PulseOut.c msgid "" -"Port does not accept pins or frequency. " -"Construct and pass a PWMOut Carrier instead" +"Port does not accept pins or frequency. Construct and pass a PWMOut Carrier " +"instead" msgstr "" #: shared-bindings/_bleio/Adapter.c @@ -1568,7 +1568,7 @@ msgstr "Szerokość bitmapy musi być wielokrotnością szerokości kafelka" msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "" "Timer was reserved for internal use - declare PWM pins earlier in the program" msgstr "" @@ -2887,6 +2887,14 @@ msgstr "ord oczekuje znaku" msgid "ord() expected a character, but string of length %d found" msgstr "ord() oczekuje znaku, a jest łańcuch od długości %d" +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of source" +msgstr "" + +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of target" +msgstr "" + #: py/objint_mpz.c msgid "overflow converting long int to machine word" msgstr "przepełnienie przy konwersji long in to słowa maszynowego" @@ -3066,6 +3074,10 @@ msgstr "" msgid "sosfilt requires iterable arguments" msgstr "" +#: shared-bindings/displayio/Bitmap.c +msgid "source palette too large" +msgstr "" + #: py/objstr.c msgid "start/end indices" msgstr "początkowe/końcowe indeksy" diff --git a/locale/pt_BR.po b/locale/pt_BR.po index 9fb4142c47..65fe17cde8 100644 --- a/locale/pt_BR.po +++ b/locale/pt_BR.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-18 11:19-0400\n" +"POT-Creation-Date: 2020-08-27 11:21-0400\n" "PO-Revision-Date: 2020-08-21 18:19+0000\n" "Last-Translator: Wellington Terumi Uemura \n" "Language-Team: \n" @@ -312,7 +312,7 @@ msgstr "Todos os canais de eventos em uso" msgid "All sync event channels in use" msgstr "Todos os canais dos eventos de sincronização em uso" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "All timers for this pin are in use" msgstr "Todos os temporizadores para este pino estão em uso" @@ -324,7 +324,7 @@ msgstr "Todos os temporizadores para este pino estão em uso" #: ports/cxd56/common-hal/pulseio/PulseOut.c #: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #: ports/nrf/common-hal/pulseio/PulseIn.c ports/nrf/peripherals/nrf/timers.c -#: ports/stm/peripherals/timers.c shared-bindings/pulseio/PWMOut.c +#: ports/stm/peripherals/timers.c shared-bindings/pwmio/PWMOut.c msgid "All timers in use" msgstr "Todos os temporizadores em uso" @@ -571,7 +571,7 @@ msgstr "Não é possível transferir sem os pinos MOSI e MISO." msgid "Cannot unambiguously get sizeof scalar" msgstr "Não é possível obter inequivocamente o tamanho do escalar" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Cannot vary frequency on a timer that is already in use" msgstr "Não é possível variar a frequência em um timer que já esteja em uso" @@ -644,23 +644,23 @@ msgstr "Não foi possível inicializar o SDCard" msgid "Could not initialize UART" msgstr "Não foi possível inicializar o UART" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize channel" msgstr "Não foi possível inicializar o canal" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize timer" msgstr "Não foi possível inicializar o temporizador" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init channel" msgstr "Não foi possível reiniciar o canal" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init timer" msgstr "Não foi possível reiniciar o temporizador" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not restart PWM" msgstr "Não foi possível reiniciar o PWM" @@ -668,7 +668,7 @@ msgstr "Não foi possível reiniciar o PWM" msgid "Could not set address" msgstr "Não foi possível definir o endereço" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not start PWM" msgstr "Não foi possível iniciar o PWM" @@ -860,7 +860,7 @@ msgid "Frequency captured is above capability. Capture Paused." msgstr "" "A frequência capturada está acima da capacidade. A captura está em pausa." -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Frequency must match existing PWMOut using this timer" msgstr "" "A frequência deve coincidir com o PWMOut existente usando este temporizador" @@ -965,9 +965,9 @@ msgstr "Arquivo BMP inválido" msgid "Invalid DAC pin supplied" msgstr "O pino DAC informado é inválido" -#: ports/atmel-samd/common-hal/pulseio/PWMOut.c -#: ports/cxd56/common-hal/pulseio/PWMOut.c -#: ports/nrf/common-hal/pulseio/PWMOut.c shared-bindings/pulseio/PWMOut.c +#: ports/atmel-samd/common-hal/pwmio/PWMOut.c +#: ports/cxd56/common-hal/pwmio/PWMOut.c ports/nrf/common-hal/pwmio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "Invalid PWM frequency" msgstr "Frequência PWM inválida" @@ -1007,7 +1007,7 @@ msgstr "Arquivo inválido" msgid "Invalid format chunk size" msgstr "Tamanho do pedaço de formato inválido" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid frequency supplied" msgstr "A frequência informada é inválida" @@ -1025,8 +1025,8 @@ msgid "Invalid phase" msgstr "Fase Inválida" #: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -#: shared-bindings/pulseio/PWMOut.c shared-module/rgbmatrix/RGBMatrix.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c shared-bindings/pwmio/PWMOut.c +#: shared-module/rgbmatrix/RGBMatrix.c msgid "Invalid pin" msgstr "Pino inválido" @@ -1050,7 +1050,7 @@ msgstr "Pino inválido para canal direito" msgid "Invalid pins" msgstr "Pinos inválidos" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid pins for PWMOut" msgstr "Os pinos para o PWMOut são inválidos" @@ -1232,7 +1232,7 @@ msgstr "Nenhuma chave foi definida" msgid "No long integer support" msgstr "Não há compatibilidade com inteiro longo" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "No more timers available on this pin." msgstr "Não há mais temporizadores disponíveis neste pino." @@ -1305,14 +1305,14 @@ msgstr "" msgid "Oversample must be multiple of 8." msgstr "A superamostragem deve ser um múltiplo de 8." -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "" "PWM duty_cycle must be between 0 and 65535 inclusive (16 bit resolution)" msgstr "" "O duty_cycle do PWM deve estar entre 0 e inclusive 65535 (com resolução de " "16 bits)" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "" "PWM frequency not writable when variable_frequency is False on construction." msgstr "" @@ -1372,11 +1372,9 @@ msgstr "O Polígono precisa de pelo menos 3 pontos" #: ports/nrf/common-hal/pulseio/PulseOut.c #: ports/stm/common-hal/pulseio/PulseOut.c msgid "" -"Port does not accept pins or frequency. " -"Construct and pass a PWMOut Carrier instead" +"Port does not accept pins or frequency. Construct and pass a PWMOut Carrier " +"instead" msgstr "" -"A porta não aceita pinos ou frequência. " -"Em vez disso, Construa e encaminhe um PWMOut Carrier" #: shared-bindings/_bleio/Adapter.c msgid "Prefix buffer must be on the heap" @@ -1619,7 +1617,7 @@ msgstr "" "O tempo limite é long demais: O comprimento máximo do tempo limite é de %d " "segundos" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "" "Timer was reserved for internal use - declare PWM pins earlier in the program" msgstr "" @@ -2967,6 +2965,14 @@ msgstr "" "o ord() esperava um caractere, porém a sequência do comprimento %d foi " "encontrada" +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of source" +msgstr "" + +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of target" +msgstr "" + #: py/objint_mpz.c msgid "overflow converting long int to machine word" msgstr "" @@ -3148,6 +3154,10 @@ msgstr "sos[:, 3] deve ser um em todos" msgid "sosfilt requires iterable arguments" msgstr "o sosfilt requer que os argumentos sejam iteráveis" +#: shared-bindings/displayio/Bitmap.c +msgid "source palette too large" +msgstr "" + #: py/objstr.c msgid "start/end indices" msgstr "os índices de início/fim" @@ -3444,6 +3454,15 @@ msgstr "zi deve ser de um tipo float" msgid "zi must be of shape (n_section, 2)" msgstr "zi deve estar na forma (n_section, 2)" +#~ msgid "" +#~ "Port does not accept pins or " +#~ "frequency. Construct and pass a " +#~ "PWMOut Carrier instead" +#~ msgstr "" +#~ "A porta não aceita pinos ou " +#~ "frequência. Em vez disso, Construa e " +#~ "encaminhe um PWMOut Carrier" + #~ msgid "tuple/list required on RHS" #~ msgstr "a tupla/lista necessária no RHS" diff --git a/locale/sv.po b/locale/sv.po index a72f8b4fbc..3f8be415f8 100644 --- a/locale/sv.po +++ b/locale/sv.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-18 11:19-0400\n" +"POT-Creation-Date: 2020-08-27 11:21-0400\n" "PO-Revision-Date: 2020-08-30 18:28+0000\n" "Last-Translator: Jonny Bergdahl \n" "Language-Team: LANGUAGE \n" @@ -308,7 +308,7 @@ msgstr "Alla händelsekanaler används" msgid "All sync event channels in use" msgstr "Alla händelsekanaler används" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "All timers for this pin are in use" msgstr "Alla timers för denna pinne är i bruk" @@ -320,7 +320,7 @@ msgstr "Alla timers för denna pinne är i bruk" #: ports/cxd56/common-hal/pulseio/PulseOut.c #: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #: ports/nrf/common-hal/pulseio/PulseIn.c ports/nrf/peripherals/nrf/timers.c -#: ports/stm/peripherals/timers.c shared-bindings/pulseio/PWMOut.c +#: ports/stm/peripherals/timers.c shared-bindings/pwmio/PWMOut.c msgid "All timers in use" msgstr "Alla timers används" @@ -562,7 +562,7 @@ msgstr "Kan inte överföra utan MOSI- och MISO-pinnar." msgid "Cannot unambiguously get sizeof scalar" msgstr "Kan inte entydigt få sizeof scalar" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Cannot vary frequency on a timer that is already in use" msgstr "Det går inte att ändra frekvensen på en timer som redan används" @@ -635,23 +635,23 @@ msgstr "Kan inte initiera SD-kort" msgid "Could not initialize UART" msgstr "Det gick inte att initiera UART" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize channel" msgstr "Det gick inte att initiera kanalen" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize timer" msgstr "Det gick inte att initialisera timern" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init channel" msgstr "Det gick inte att återinitiera kanalen" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init timer" msgstr "Det gick inte att återinitiera timern" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not restart PWM" msgstr "Det gick inte att starta om PWM" @@ -659,7 +659,7 @@ msgstr "Det gick inte att starta om PWM" msgid "Could not set address" msgstr "Kan inte ange adress" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not start PWM" msgstr "Det gick inte att starta PWM" @@ -850,7 +850,7 @@ msgstr "Framebuffer kräver %d byte" msgid "Frequency captured is above capability. Capture Paused." msgstr "Infångningsfrekvens är för hög. Infångning pausad." -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Frequency must match existing PWMOut using this timer" msgstr "Frekvensen måste matcha befintlig PWMOut med denna timer" @@ -954,9 +954,9 @@ msgstr "Ogiltig BMP-fil" msgid "Invalid DAC pin supplied" msgstr "Ogiltig DAC-pinne angiven" -#: ports/atmel-samd/common-hal/pulseio/PWMOut.c -#: ports/cxd56/common-hal/pulseio/PWMOut.c -#: ports/nrf/common-hal/pulseio/PWMOut.c shared-bindings/pulseio/PWMOut.c +#: ports/atmel-samd/common-hal/pwmio/PWMOut.c +#: ports/cxd56/common-hal/pwmio/PWMOut.c ports/nrf/common-hal/pwmio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "Invalid PWM frequency" msgstr "Ogiltig PWM-frekvens" @@ -996,7 +996,7 @@ msgstr "Felaktig fil" msgid "Invalid format chunk size" msgstr "Ogiltig formatsegmentstorlek" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid frequency supplied" msgstr "Ogiltig frekvens angiven" @@ -1014,8 +1014,8 @@ msgid "Invalid phase" msgstr "Ogiltig fas" #: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -#: shared-bindings/pulseio/PWMOut.c shared-module/rgbmatrix/RGBMatrix.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c shared-bindings/pwmio/PWMOut.c +#: shared-module/rgbmatrix/RGBMatrix.c msgid "Invalid pin" msgstr "Ogiltig pinne" @@ -1039,7 +1039,7 @@ msgstr "Ogiltig pinne för höger kanal" msgid "Invalid pins" msgstr "Ogiltiga pinnar" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid pins for PWMOut" msgstr "Ogiltiga pinnar för PWMOut" @@ -1222,7 +1222,7 @@ msgstr "Ingen nyckel angavs" msgid "No long integer support" msgstr "Inget stöd för långt heltal" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "No more timers available on this pin." msgstr "Inga fler timers tillgängliga på denna pinne." @@ -1295,12 +1295,12 @@ msgstr "" msgid "Oversample must be multiple of 8." msgstr "Översampling måste vara multipel av 8." -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "" "PWM duty_cycle must be between 0 and 65535 inclusive (16 bit resolution)" msgstr "PWM duty_cykel måste vara mellan 0 och 65535 (16 bitars upplösning)" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "" "PWM frequency not writable when variable_frequency is False on construction." msgstr "" @@ -1360,8 +1360,8 @@ msgstr "Polygonen behöver minst 3 punkter" #: ports/nrf/common-hal/pulseio/PulseOut.c #: ports/stm/common-hal/pulseio/PulseOut.c msgid "" -"Port does not accept pins or frequency. " -"Construct and pass a PWMOut Carrier instead" +"Port does not accept pins or frequency. Construct and pass a PWMOut Carrier " +"instead" msgstr "" #: shared-bindings/_bleio/Adapter.c @@ -1600,7 +1600,7 @@ msgstr "Tile-bredd måste vara jämnt delbar med bredd på bitmap" msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "Åtgärden tog för lång tid: Max väntetid är %d sekunder" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "" "Timer was reserved for internal use - declare PWM pins earlier in the program" msgstr "" @@ -2933,6 +2933,14 @@ msgstr "ord förväntar sig ett tecken" msgid "ord() expected a character, but string of length %d found" msgstr "ord() förväntade sig ett tecken, men en sträng med längden %d hittades" +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of source" +msgstr "" + +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of target" +msgstr "" + #: py/objint_mpz.c msgid "overflow converting long int to machine word" msgstr "Konvertering av long int till machine word överskred maxvärde" @@ -3113,6 +3121,10 @@ msgstr "sos[:, 3] måste vara ettor" msgid "sosfilt requires iterable arguments" msgstr "sosfilt kräver iterable argument" +#: shared-bindings/displayio/Bitmap.c +msgid "source palette too large" +msgstr "" + #: py/objstr.c msgid "start/end indices" msgstr "start-/slutindex" diff --git a/locale/zh_Latn_pinyin.po b/locale/zh_Latn_pinyin.po index 725491f5b2..290d4749ef 100644 --- a/locale/zh_Latn_pinyin.po +++ b/locale/zh_Latn_pinyin.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: circuitpython-cn\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-18 11:19-0400\n" +"POT-Creation-Date: 2020-08-27 11:21-0400\n" "PO-Revision-Date: 2019-04-13 10:10-0700\n" "Last-Translator: hexthat\n" "Language-Team: Chinese Hanyu Pinyin\n" @@ -309,7 +309,7 @@ msgstr "Suǒyǒu shǐyòng de shìjiàn píndào" msgid "All sync event channels in use" msgstr "Suǒyǒu tóngbù shìjiàn píndào shǐyòng" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "All timers for this pin are in use" msgstr "Cǐ yǐn jiǎo de suǒyǒu jìshí qì zhèngzài shǐyòng" @@ -321,7 +321,7 @@ msgstr "Cǐ yǐn jiǎo de suǒyǒu jìshí qì zhèngzài shǐyòng" #: ports/cxd56/common-hal/pulseio/PulseOut.c #: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #: ports/nrf/common-hal/pulseio/PulseIn.c ports/nrf/peripherals/nrf/timers.c -#: ports/stm/peripherals/timers.c shared-bindings/pulseio/PWMOut.c +#: ports/stm/peripherals/timers.c shared-bindings/pwmio/PWMOut.c msgid "All timers in use" msgstr "Suǒyǒu jìshí qì shǐyòng" @@ -561,7 +561,7 @@ msgstr "Méiyǒu MOSI/MISO jiù wúfǎ zhuǎnyí." msgid "Cannot unambiguously get sizeof scalar" msgstr "Wúfǎ míngquè de huòdé biāoliàng de dàxiǎo" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Cannot vary frequency on a timer that is already in use" msgstr "Wúfǎ gēnggǎi yǐ zài shǐyòng de jìshí qì shàng de pínlǜ" @@ -632,23 +632,23 @@ msgstr "wú fǎ chū shǐ huà SDCard" msgid "Could not initialize UART" msgstr "Wúfǎ chūshǐhuà UART" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize channel" msgstr "Wúfǎ chūshǐhuà píndào" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not initialize timer" msgstr "Wúfǎ chūshǐhuà jìshí qì" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init channel" msgstr "Wúfǎ chóngxīn chūshǐhuà píndào" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not re-init timer" msgstr "Wúfǎ chóngxīn qǐdòng jìshí qì" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not restart PWM" msgstr "Wúfǎ chóngqǐ PWM" @@ -656,7 +656,7 @@ msgstr "Wúfǎ chóngqǐ PWM" msgid "Could not set address" msgstr "wú fǎ shè zhì dì zhǐ" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not start PWM" msgstr "Wúfǎ qǐdòng PWM" @@ -847,7 +847,7 @@ msgstr "zhēn huǎn chōng qū xū yào %d zì jié" msgid "Frequency captured is above capability. Capture Paused." msgstr "Pínlǜ bǔhuò gāo yú nénglì. Bǔhuò zàntíng." -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Frequency must match existing PWMOut using this timer" msgstr "Pínlǜ bìxū yǔ shǐyòng cǐ jìshí qì de xiàn yǒu PWMOut xiāng pǐpèi" @@ -951,9 +951,9 @@ msgstr "Wúxiào de BMP wénjiàn" msgid "Invalid DAC pin supplied" msgstr "Tí gōng liǎo wúxiào de DAC yǐn jiǎo" -#: ports/atmel-samd/common-hal/pulseio/PWMOut.c -#: ports/cxd56/common-hal/pulseio/PWMOut.c -#: ports/nrf/common-hal/pulseio/PWMOut.c shared-bindings/pulseio/PWMOut.c +#: ports/atmel-samd/common-hal/pwmio/PWMOut.c +#: ports/cxd56/common-hal/pwmio/PWMOut.c ports/nrf/common-hal/pwmio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "Invalid PWM frequency" msgstr "Wúxiào de PWM pínlǜ" @@ -993,7 +993,7 @@ msgstr "Wúxiào de wénjiàn" msgid "Invalid format chunk size" msgstr "Géshì kuài dàxiǎo wúxiào" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid frequency supplied" msgstr "Tígōng de pínlǜ wúxiào" @@ -1011,8 +1011,8 @@ msgid "Invalid phase" msgstr "Jiēduàn wúxiào" #: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -#: shared-bindings/pulseio/PWMOut.c shared-module/rgbmatrix/RGBMatrix.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c shared-bindings/pwmio/PWMOut.c +#: shared-module/rgbmatrix/RGBMatrix.c msgid "Invalid pin" msgstr "Wúxiào de yǐn jiǎo" @@ -1036,7 +1036,7 @@ msgstr "Yòuxián tōngdào yǐn jiǎo wúxiào" msgid "Invalid pins" msgstr "Wúxiào de yǐn jiǎo" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "Invalid pins for PWMOut" msgstr "PWMOut de yǐn jiǎo wú xiào" @@ -1218,7 +1218,7 @@ msgstr "Wèi zhǐdìng mì yào" msgid "No long integer support" msgstr "Méiyǒu zhǎng zhěngshù zhīchí" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "No more timers available on this pin." msgstr "Gāi yǐn jiǎo shàng méiyǒu kěyòng de dìngshí qì." @@ -1291,13 +1291,13 @@ msgstr "" msgid "Oversample must be multiple of 8." msgstr "Guò cǎiyàng bìxū shì 8 de bèishù." -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "" "PWM duty_cycle must be between 0 and 65535 inclusive (16 bit resolution)" msgstr "" "PWM yìwù zhōuqí bìxū jiè yú 0 zhì 65535 de bāoróng xìng (16 wèi fēnbiàn lǜ)" -#: shared-bindings/pulseio/PWMOut.c +#: shared-bindings/pwmio/PWMOut.c msgid "" "PWM frequency not writable when variable_frequency is False on construction." msgstr "Dāng biànliàng_pínlǜ shì False zài jiànzhú shí PWM pínlǜ bùkě xiě." @@ -1355,8 +1355,8 @@ msgstr "Duōbiānxíng zhìshǎo xūyào 3 diǎn" #: ports/nrf/common-hal/pulseio/PulseOut.c #: ports/stm/common-hal/pulseio/PulseOut.c msgid "" -"Port does not accept pins or frequency. " -"Construct and pass a PWMOut Carrier instead" +"Port does not accept pins or frequency. Construct and pass a PWMOut Carrier " +"instead" msgstr "" #: shared-bindings/_bleio/Adapter.c @@ -1593,7 +1593,7 @@ msgstr "Píng pū kuāndù bìxū huàfēn wèi tú kuāndù" msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "Chāoshí shíjiān tài zhǎng: Zuìdà chāoshí shíjiān wèi%d miǎo" -#: ports/stm/common-hal/pulseio/PWMOut.c +#: ports/stm/common-hal/pwmio/PWMOut.c msgid "" "Timer was reserved for internal use - declare PWM pins earlier in the program" msgstr "" @@ -2924,6 +2924,14 @@ msgstr "ord yùqí zìfú" msgid "ord() expected a character, but string of length %d found" msgstr "ord() yùqí zìfú, dàn chángdù zìfú chuàn %d" +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of source" +msgstr "" + +#: shared-bindings/displayio/Bitmap.c +msgid "out of range of target" +msgstr "" + #: py/objint_mpz.c msgid "overflow converting long int to machine word" msgstr "chāo gāo zhuǎnhuàn zhǎng zhěng shùzì shí" @@ -3103,6 +3111,10 @@ msgstr "sos [:, 3] yīnggāi quán shì" msgid "sosfilt requires iterable arguments" msgstr "sosfilt xūyào diédài cānshù" +#: shared-bindings/displayio/Bitmap.c +msgid "source palette too large" +msgstr "" + #: py/objstr.c msgid "start/end indices" msgstr "kāishǐ/jiéshù zhǐshù" From 767f3d0feb1e145efc2def5048e91d910bbe2f9a Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 30 Aug 2020 14:35:02 -0400 Subject: [PATCH 52/84] make translate --- locale/circuitpython.pot | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index f53c9c51f8..92e9b6d241 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-21 11:37-0400\n" +"POT-Creation-Date: 2020-08-30 14:34-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -490,6 +490,10 @@ msgstr "" msgid "Can't set CCCD on local Characteristic" msgstr "" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot create a new Adapter; use _bleio.adapter;" +msgstr "" + #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c @@ -742,8 +746,8 @@ msgstr "" msgid "Error in regex" msgstr "" -#: shared-bindings/aesio/aes.c shared-bindings/busio/SPI.c -#: shared-bindings/microcontroller/Pin.c +#: shared-bindings/_bleio/__init__.c shared-bindings/aesio/aes.c +#: shared-bindings/busio/SPI.c shared-bindings/microcontroller/Pin.c #: shared-bindings/neopixel_write/__init__.c #: shared-bindings/terminalio/Terminal.c msgid "Expected a %q" @@ -1251,6 +1255,10 @@ msgstr "" msgid "Not running saved code.\n" msgstr "" +#: shared-bindings/_bleio/__init__.c +msgid "Not settable" +msgstr "" + #: shared-bindings/util.c msgid "" "Object has been deinitialized and can no longer be used. Create a new object." @@ -2413,10 +2421,6 @@ msgstr "" msgid "graphic must be 2048 bytes long" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "hci_uart_init not available" -msgstr "" - #: extmod/moduheapq.c msgid "heap must be a list" msgstr "" From f5a5fc4c8494cd80f0e113c7cd4de975925b9bac Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 30 Aug 2020 14:59:03 -0400 Subject: [PATCH 53/84] Fix stub; mismatched triple quotes --- shared-bindings/_bleio/Adapter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-bindings/_bleio/Adapter.c b/shared-bindings/_bleio/Adapter.c index b70fd17f8f..4facd818a3 100644 --- a/shared-bindings/_bleio/Adapter.c +++ b/shared-bindings/_bleio/Adapter.c @@ -77,7 +77,7 @@ //| //| 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.""" +//| Use `_bleio.adapter` to access the sole instance already available. //| """ //| ... //| From aba27c12e506fe44674e11fd1db5a25abc004f6b Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sun, 30 Aug 2020 20:02:24 +0000 Subject: [PATCH 54/84] Translated using Weblate (Swedish) Currently translated at 99.4% (776 of 780 strings) Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/sv/ --- locale/sv.po | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/locale/sv.po b/locale/sv.po index 3f8be415f8..9946917445 100644 --- a/locale/sv.po +++ b/locale/sv.po @@ -6,8 +6,8 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-08-27 11:21-0400\n" -"PO-Revision-Date: 2020-08-30 18:28+0000\n" -"Last-Translator: Jonny Bergdahl \n" +"PO-Revision-Date: 2020-08-30 20:02+0000\n" +"Last-Translator: Jeff Epler \n" "Language-Team: LANGUAGE \n" "Language: sv\n" "MIME-Version: 1.0\n" @@ -940,7 +940,7 @@ msgstr "Ogiltig %q-pinne" #: ports/stm/common-hal/busio/I2C.c ports/stm/common-hal/busio/SPI.c #: ports/stm/common-hal/busio/UART.c ports/stm/common-hal/sdioio/SDCard.c msgid "Invalid %q pin selection" -msgstr "Ogiltigt val av % q pinne" +msgstr "Ogiltigt val av %q pinne" #: ports/stm/common-hal/analogio/AnalogIn.c msgid "Invalid ADC Unit value" From ef8cde94a47a140c21175cbe7fc877535b9ed0ea Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sun, 30 Aug 2020 20:51:04 -0500 Subject: [PATCH 55/84] actions: Clone the esp-idf submodules ourselves Builds of the esp32s2 targets frequently fail: ``` -- Found Git: /usr/bin/git (found version "2.28.0") -- Initialising new submodule components/asio/asio... warning: could not look up configuration 'remote.origin.url'. Assuming this repository is its own authoritative upstream. Submodule 'components/asio/asio' (/home/runner/work/circuitpython/circuitpython/ports/espressif/asio.git) registered for path 'components/asio/asio' fatal: repository '/home/runner/work/circuitpython/circuitpython/ports/espressif/asio.git' does not exist fatal: clone of '/home/runner/work/circuitpython/circuitpython/ports/espressif/asio.git' into submodule path '/home/runner/work/circuitpython/circuitpython/ports/esp32s2/esp-idf/components/asio/asio' failed Failed to clone 'components/asio/asio'. Retry scheduled fatal: repository '/home/runner/work/circuitpython/circuitpython/ports/espressif/asio.git' does not exist fatal: clone of '/home/runner/work/circuitpython/circuitpython/ports/espressif/asio.git' into submodule path '/home/runner/work/circuitpython/circuitpython/ports/esp32s2/esp-idf/components/asio/asio' failed Failed to clone 'components/asio/asio' a second time, aborting CMake Error at esp-idf/tools/cmake/git_submodules.cmake:48 (message): Git submodule init failed for components/asio/asio Call Stack (most recent call first): esp-idf/tools/cmake/build.cmake:78 (git_submodule_check) esp-idf/tools/cmake/build.cmake:160 (__build_get_idf_git_revision) esp-idf/tools/cmake/idf.cmake:49 (__build_init) esp-idf/tools/cmake/project.cmake:7 (include) CMakeLists.txt:8 (include) ``` It's not clear how/why this happens--is it something to do with our multithreaded build?. Attempt to clear it up by manually checking out these submodules ourselves. --- .github/workflows/build.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e780f652ab..3c7cc781bf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -433,6 +433,11 @@ jobs: with: path: ${{ github.workspace }}/.idf_tools key: ${{ runner.os }}-idf-tools-${{ hashFiles('.git/modules/ports/esp32s2/esp-idf/HEAD') }}-20200801 + - name: Clone IDF submodules + run: | + (cd $IDF_PATH && git submodule update --init) + env: + IDF_PATH: ${{ github.workspace }}/ports/esp32s2/esp-idf - name: Install IDF tools run: | $IDF_PATH/tools/idf_tools.py --non-interactive install required From 07e2fc721a9903a2f5340fe9763c8b2f17310521 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 30 Aug 2020 23:14:50 -0400 Subject: [PATCH 56/84] Remove debugging print-out for endpoint checking. --- tools/gen_usb_descriptor.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/gen_usb_descriptor.py b/tools/gen_usb_descriptor.py index adf0d8270d..15bf2daa00 100644 --- a/tools/gen_usb_descriptor.py +++ b/tools/gen_usb_descriptor.py @@ -382,7 +382,6 @@ if args.max_ep != 0: for interface in interfaces: for subdescriptor in interface.subdescriptors: endpoint_address = getattr(subdescriptor, 'bEndpointAddress', 0) & 0x7f - print("Endpoint %d - vs max_ep %d" % (endpoint_address, args.max_ep)) if endpoint_address >= args.max_ep: raise ValueError("Endpoint address %d of %s must be less than %d" % (endpoint_address & 0x7f, interface.description, args.max_ep)) else: From 4ac7650f22c049d9059e6173e55cf44c43b1b5ac Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 31 Aug 2020 23:56:38 -0400 Subject: [PATCH 57/84] matrix portal board --- .github/workflows/build.yml | 1 + .../atmel-samd/boards/matrixportal_m4/board.c | 39 ++++++++++++ .../boards/matrixportal_m4/mpconfigboard.h | 30 +++++++++ .../boards/matrixportal_m4/mpconfigboard.mk | 12 ++++ .../atmel-samd/boards/matrixportal_m4/pins.c | 61 +++++++++++++++++++ 5 files changed, 143 insertions(+) create mode 100644 ports/atmel-samd/boards/matrixportal_m4/board.c create mode 100644 ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.h create mode 100644 ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.mk create mode 100644 ports/atmel-samd/boards/matrixportal_m4/pins.c diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e780f652ab..ec57f889f7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -234,6 +234,7 @@ jobs: - "makerdiary_nrf52840_m2_devkit" - "makerdiary_nrf52840_mdk" - "makerdiary_nrf52840_mdk_usb_dongle" + - "matrixportal_m4" - "meowbit_v121" - "meowmeow" - "metro_m0_express" diff --git a/ports/atmel-samd/boards/matrixportal_m4/board.c b/ports/atmel-samd/boards/matrixportal_m4/board.c new file mode 100644 index 0000000000..2d4f302391 --- /dev/null +++ b/ports/atmel-samd/boards/matrixportal_m4/board.c @@ -0,0 +1,39 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 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 "boards/board.h" +#include "mpconfigboard.h" +#include "hal/include/hal_gpio.h" + +void board_init(void) { +} + +bool board_requests_safe_mode(void) { + return false; +} + +void reset_board(void) { +} diff --git a/ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.h b/ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.h new file mode 100644 index 0000000000..0368d577bf --- /dev/null +++ b/ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.h @@ -0,0 +1,30 @@ +#define MICROPY_HW_BOARD_NAME "Adafruit Matrix Portal M4" +#define MICROPY_HW_MCU_NAME "samd51j19" + +#define CIRCUITPY_MCU_FAMILY samd51 + +#define MICROPY_HW_LED_STATUS (&pin_PA14) + +#define MICROPY_HW_NEOPIXEL (&pin_PA23) + +// These are pins not to reset. +// QSPI Data pins, PA23 is NeoPixel +#define MICROPY_PORT_A (PORT_PA08 | PORT_PA09 | PORT_PA10 | PORT_PA11 | PA23) +// QSPI CS, QSPI SCK +#define MICROPY_PORT_B (PORT_PB10 | PORT_PB11) +#define MICROPY_PORT_C (0) +#define MICROPY_PORT_D (0) + +#define DEFAULT_I2C_BUS_SCL (&pin_PB03) +#define DEFAULT_I2C_BUS_SDA (&pin_PB02) + +#define DEFAULT_SPI_BUS_SCK (&pin_PA16) +#define DEFAULT_SPI_BUS_MOSI (&pin_PA19) +#define DEFAULT_SPI_BUS_MISO (&pin_PA17) + +#define DEFAULT_UART_BUS_RX (&pin_PA01) +#define DEFAULT_UART_BUS_TX (&pin_PA00) + +// USB is always used internally so skip the pin objects for it. +#define IGNORE_PIN_PA24 1 +#define IGNORE_PIN_PA25 1 diff --git a/ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.mk b/ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.mk new file mode 100644 index 0000000000..44b28acbcb --- /dev/null +++ b/ports/atmel-samd/boards/matrixportal_m4/mpconfigboard.mk @@ -0,0 +1,12 @@ +USB_VID = 0x239A +USB_PID = 0x80CA +USB_PRODUCT = "Matrix Portal M4" +USB_MANUFACTURER = "Adafruit Industries LLC" + +CHIP_VARIANT = SAMD51J19A +CHIP_FAMILY = samd51 + +QSPI_FLASH_FILESYSTEM = 1 +EXTERNAL_FLASH_DEVICE_COUNT = 3 +EXTERNAL_FLASH_DEVICES = "S25FL116K, S25FL216K, GD25Q16C" +LONGINT_IMPL = MPZ diff --git a/ports/atmel-samd/boards/matrixportal_m4/pins.c b/ports/atmel-samd/boards/matrixportal_m4/pins.c new file mode 100644 index 0000000000..34865597b6 --- /dev/null +++ b/ports/atmel-samd/boards/matrixportal_m4/pins.c @@ -0,0 +1,61 @@ +#include "shared-bindings/board/__init__.h" + +STATIC const mp_rom_map_elem_t board_global_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_PA02) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_PA05) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_PA04) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_PA06) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_PA07) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_TX),MP_ROM_PTR(&pin_PA00) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_RX),MP_ROM_PTR(&pin_PA01) }, + + // ESP control + { MP_OBJ_NEW_QSTR(MP_QSTR_ESP_CS), MP_ROM_PTR(&pin_PB17) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ESP_GPIO0), MP_ROM_PTR(&pin_PA20) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ESP_BUSY), MP_ROM_PTR(&pin_PA22) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ESP_RESET), MP_ROM_PTR(&pin_PA21) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ESP_RTS), MP_ROM_PTR(&pin_PA18) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ESP_TX), MP_ROM_PTR(&pin_PA12) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ESP_RX), MP_ROM_PTR(&pin_PA13) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_SCL),MP_ROM_PTR(&pin_PB30) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SDA),MP_ROM_PTR(&pin_PB31) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_NEOPIXEL),MP_ROM_PTR(&pin_PA23) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_SCK),MP_ROM_PTR(&pin_PA16) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_MOSI),MP_ROM_PTR(&pin_PA19) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_MISO),MP_ROM_PTR(&pin_PA17) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_MTX_R1),MP_ROM_PTR(&pin_PB00) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_MTX_G1),MP_ROM_PTR(&pin_PB01) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_MTX_B1),MP_ROM_PTR(&pin_PB02) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_MTX_R2),MP_ROM_PTR(&pin_PB03) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_MTX_G2),MP_ROM_PTR(&pin_PB04) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_MTX_B2),MP_ROM_PTR(&pin_PB05) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_MTX_ADDRA),MP_ROM_PTR(&pin_PB07) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_MTX_ADDRB),MP_ROM_PTR(&pin_PB08) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_MTX_ADDRC),MP_ROM_PTR(&pin_PB09) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_MTX_ADDRD),MP_ROM_PTR(&pin_PB15) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_MTX_ADDRE),MP_ROM_PTR(&pin_PB13) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_MTX_CLK),MP_ROM_PTR(&pin_PB06) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_MTX_LAT),MP_ROM_PTR(&pin_PB14) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_MTX_OE),MP_ROM_PTR(&pin_PB12) }, + + { MP_ROM_QSTR(MP_QSTR_ACCELEROMETER_INTERRUPT), MP_ROM_PTR(&pin_PA27) }, + + // Grounded when closed. + { MP_OBJ_NEW_QSTR(MP_QSTR_BUTTON_UP),MP_ROM_PTR(&pin_PB22) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_BUTTON_DOWN),MP_ROM_PTR(&pin_PB23) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_L),MP_ROM_PTR(&pin_PA14) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table); From fc513956be8cb0389d450308f6363c6b742af072 Mon Sep 17 00:00:00 2001 From: Kevin Matocha Date: Tue, 1 Sep 2020 09:36:29 -0500 Subject: [PATCH 58/84] Update refresh to force immediate redraw with display.refresh() or display.refresh(target_frames_per_second=None), even with auto_refresh=False --- shared-bindings/displayio/Display.c | 19 +++++++++++++++++-- shared-module/displayio/Display.c | 2 +- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index c4fbdab2e4..ff003ab4bf 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -227,6 +227,9 @@ MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show //| When auto refresh is on, updates the display immediately. (The display will also update //| without calls to this.) //| +//| When auto refresh is off, refresh() or refresh(target_frames_per_second=None) will update +//| the display immediately. +//| //| :param int target_frames_per_second: How many times a second `refresh` should be called and the screen updated. //| :param int minimum_frames_per_second: The minimum number of times the screen should be updated per second.""" //| ... @@ -234,9 +237,11 @@ MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show STATIC mp_obj_t displayio_display_obj_refresh(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_target_frames_per_second, ARG_minimum_frames_per_second }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_target_frames_per_second, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 60} }, + //{ MP_QSTR_target_frames_per_second, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 60} }, + { MP_QSTR_target_frames_per_second, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(60)} }, { MP_QSTR_minimum_frames_per_second, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, }; + 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); @@ -246,8 +251,18 @@ STATIC mp_obj_t displayio_display_obj_refresh(size_t n_args, const mp_obj_t *pos if (minimum_frames_per_second > 0) { maximum_ms_per_real_frame = 1000 / minimum_frames_per_second; } - return mp_obj_new_bool(common_hal_displayio_display_refresh(self, 1000 / args[ARG_target_frames_per_second].u_int, maximum_ms_per_real_frame)); + + uint32_t target_ms_per_frame; + if ( (args[ARG_target_frames_per_second].u_obj == mp_const_none) || (n_args == 1) ) { // if None or no arguments + target_ms_per_frame = 0xffffffff; + } + else { + target_ms_per_frame = 1000 / mp_obj_get_int(args[ARG_target_frames_per_second].u_obj); + } + + return mp_obj_new_bool(common_hal_displayio_display_refresh(self, target_ms_per_frame, maximum_ms_per_real_frame)); } + MP_DEFINE_CONST_FUN_OBJ_KW(displayio_display_refresh_obj, 1, displayio_display_obj_refresh); //| auto_refresh: bool diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index 4f92f249fd..021159c0d9 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -352,7 +352,7 @@ uint16_t common_hal_displayio_display_get_rotation(displayio_display_obj_t* self bool common_hal_displayio_display_refresh(displayio_display_obj_t* self, uint32_t target_ms_per_frame, uint32_t maximum_ms_per_real_frame) { - if (!self->auto_refresh && !self->first_manual_refresh) { + if (!self->auto_refresh && !self->first_manual_refresh && (target_ms_per_frame != 0xffffffff) ) { uint64_t current_time = supervisor_ticks_ms64(); uint32_t current_ms_since_real_refresh = current_time - self->core.last_refresh; // Test to see if the real frame time is below our minimum. From c4b1db006f3f091f67076226e26c3f53c9e76f8b Mon Sep 17 00:00:00 2001 From: Kevin Matocha Date: Tue, 1 Sep 2020 09:38:57 -0500 Subject: [PATCH 59/84] delete unnecessary comment --- shared-bindings/displayio/Display.c | 1 - 1 file changed, 1 deletion(-) diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index ff003ab4bf..cf1b840dc9 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -237,7 +237,6 @@ MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show STATIC mp_obj_t displayio_display_obj_refresh(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_target_frames_per_second, ARG_minimum_frames_per_second }; static const mp_arg_t allowed_args[] = { - //{ MP_QSTR_target_frames_per_second, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 60} }, { MP_QSTR_target_frames_per_second, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(60)} }, { MP_QSTR_minimum_frames_per_second, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, }; From 8be862e644dad22641f5a4f9c1520f91df08d7a5 Mon Sep 17 00:00:00 2001 From: Kevin Matocha Date: Tue, 1 Sep 2020 10:26:48 -0500 Subject: [PATCH 60/84] Remove trailing whitespace --- shared-bindings/displayio/Display.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index cf1b840dc9..9f3148dc76 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -227,7 +227,7 @@ MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show //| When auto refresh is on, updates the display immediately. (The display will also update //| without calls to this.) //| -//| When auto refresh is off, refresh() or refresh(target_frames_per_second=None) will update +//| When auto refresh is off, refresh() or refresh(target_frames_per_second=None) will update //| the display immediately. //| //| :param int target_frames_per_second: How many times a second `refresh` should be called and the screen updated. @@ -252,8 +252,9 @@ STATIC mp_obj_t displayio_display_obj_refresh(size_t n_args, const mp_obj_t *pos } uint32_t target_ms_per_frame; - if ( (args[ARG_target_frames_per_second].u_obj == mp_const_none) || (n_args == 1) ) { // if None or no arguments - target_ms_per_frame = 0xffffffff; + if ( (args[ARG_target_frames_per_second].u_obj == mp_const_none) || (n_args == 1) ) { + // if None or no arguments + target_ms_per_frame = 0xffffffff; } else { target_ms_per_frame = 1000 / mp_obj_get_int(args[ARG_target_frames_per_second].u_obj); From ad4bf75367b1b1992d653428593c0f66f5b5e7ff Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 1 Sep 2020 10:05:13 -0500 Subject: [PATCH 61/84] samd: only set NDEBUG for non-debug builds --- ports/atmel-samd/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile index 30487ae3ef..25dc0cf15e 100644 --- a/ports/atmel-samd/Makefile +++ b/ports/atmel-samd/Makefile @@ -107,7 +107,7 @@ CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_SAME5X -DCFG_TUD_MIDI_RX_BUFSIZE=128 -DCFG_TUD_ endif # option to override default optimization level, set in boards/$(BOARD)/mpconfigboard.mk -CFLAGS += $(OPTIMIZATION_FLAGS) -DNDEBUG +CFLAGS += $(OPTIMIZATION_FLAGS) $(echo PERIPHERALS_CHIP_FAMILY=$(PERIPHERALS_CHIP_FAMILY)) #Debugging/Optimization @@ -121,6 +121,7 @@ ifeq ($(DEBUG), 1) CFLAGS += -DENABLE_MICRO_TRACE_BUFFER endif else + CFLAGS += -DNDEBUG # -finline-limit can shrink the image size. # -finline-limit=80 or so is similar to not having it on. # There is no simple default value, though. From 952d9bbb4a99cc598b56e170cdc05d94087d0d6d Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 28 Aug 2020 11:24:36 -0500 Subject: [PATCH 62/84] samd: Ignore a maybe-uninitialized diagnostic in asf4 I encountered this when changing optimization flags for debugging purposes. The diagnostic appears spurious and unrelated to what I'm debugging. --- ports/atmel-samd/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile index 25dc0cf15e..3b7ab75bb0 100644 --- a/ports/atmel-samd/Makefile +++ b/ports/atmel-samd/Makefile @@ -258,6 +258,8 @@ SRC_ASF += \ $(BUILD)/asf4/$(CHIP_FAMILY)/hpl/sdhc/hpl_sdhc.o: CFLAGS += -Wno-cast-align endif +$(BUILD)/asf4/$(CHIP_FAMILY)/hpl/sercom/hpl_sercom.o: CFLAGS += -Wno-maybe-uninitialized + SRC_ASF := $(addprefix asf4/$(CHIP_FAMILY)/, $(SRC_ASF)) SRC_C = \ From 9bd2a61d8b2ba56cef241f3b93aed50e718998b5 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 1 Sep 2020 10:29:10 -0500 Subject: [PATCH 63/84] supervisor: Always allocate at least a 1x1 terminal Otherwise, out of range writes would occur in tilegrid_set_tile, causing a safe mode reset. ``` Hardware watchpoint 6: -location *stack_alloc->ptr Old value = 24652061 New value = 24641565 0x000444f2 in common_hal_displayio_tilegrid_set_tile (self=0x200002c8 , x=1, y=1, tile_index=0 '\000') at ../../shared-module/displayio/TileGrid.c:236 236 if (!self->partial_change) { (gdb) ``` --- supervisor/shared/display.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/supervisor/shared/display.c b/supervisor/shared/display.c index 634720d0ab..afb3f3a9a6 100644 --- a/supervisor/shared/display.c +++ b/supervisor/shared/display.c @@ -65,10 +65,14 @@ void supervisor_start_terminal(uint16_t width_px, uint16_t height_px) { if (width_in_tiles < 80) { scale = 1; } + width_in_tiles = (width_px - blinka_bitmap.width * scale) / (grid->tile_width * scale); + if (width_in_tiles < 1) { + width_in_tiles = 1; + } uint16_t height_in_tiles = height_px / (grid->tile_height * scale); uint16_t remaining_pixels = height_px % (grid->tile_height * scale); - if (remaining_pixels > 0) { + if (height_in_tiles < 1 || remaining_pixels > 0) { height_in_tiles += 1; } @@ -94,6 +98,8 @@ void supervisor_start_terminal(uint16_t width_px, uint16_t height_px) { } grid->width_in_tiles = width_in_tiles; grid->height_in_tiles = height_in_tiles; + assert(width_in_tiles > 0); + assert(height_in_tiles > 0); grid->pixel_width = width_in_tiles * grid->tile_width; grid->pixel_height = height_in_tiles * grid->tile_height; grid->tiles = tiles; From 2f120c70eee692b8e036f8f0778af2b723e1f0e7 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 28 Aug 2020 11:17:07 -0500 Subject: [PATCH 64/84] rgbmatrix: recover gracefully from allocation errors e.g., allocating a 192x32x6bpp matrix would be enough to trigger this reliably on a Metro M4 Express using the "memory hogging" layout. Allocating 64x32x6bpp could trigger it, but somewhat unreliably. There are several things going on here: * we make the failing call with interrupts off * we were throwing an exception with interrupts off * protomatter failed badly in _PM_free when it was partially-initialized Incorporate the fix from protomatter, switch to a non-throwing malloc variant, and ensure that interrupts get turned back on. This decreases the quality of the MemoryError (it cannot report the size of the failed allocation) but allows CircuitPython to survive, rather than faulting. --- lib/protomatter | 2 +- shared-module/rgbmatrix/RGBMatrix.c | 17 +++++++++++------ shared-module/rgbmatrix/allocator.h | 2 +- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/lib/protomatter b/lib/protomatter index 761d6437e8..2a1ba8fa47 160000 --- a/lib/protomatter +++ b/lib/protomatter @@ -1 +1 @@ -Subproject commit 761d6437e8cd6a131d51de96974337121a9c7164 +Subproject commit 2a1ba8fa4753b2bcb158c9b17351cf18eade0d2b diff --git a/shared-module/rgbmatrix/RGBMatrix.c b/shared-module/rgbmatrix/RGBMatrix.c index 6dad91679f..a020ef0896 100644 --- a/shared-module/rgbmatrix/RGBMatrix.c +++ b/shared-module/rgbmatrix/RGBMatrix.c @@ -89,6 +89,7 @@ void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t* self, self->bufinfo.typecode = 'H' | MP_OBJ_ARRAY_TYPECODE_FLAG_RW; } + memset(&self->core, 0, sizeof(self->core)); ProtomatterStatus stat = _PM_init(&self->core, self->width, self->bit_depth, self->rgb_count/6, self->rgb_pins, @@ -101,14 +102,17 @@ void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t* self, common_hal_mcu_disable_interrupts(); common_hal_rgbmatrix_timer_enable(self->timer); stat = _PM_begin(&self->core); - _PM_convert_565(&self->core, self->bufinfo.buf, self->width); + + if (stat == PROTOMATTER_OK) { + _PM_convert_565(&self->core, self->bufinfo.buf, self->width); + } common_hal_mcu_enable_interrupts(); - _PM_swapbuffer_maybe(&self->core); + if (stat == PROTOMATTER_OK) { + _PM_swapbuffer_maybe(&self->core); + } } if (stat != PROTOMATTER_OK) { - // XXX this deinit() actually makes crashy-crashy - // can trigger it by sending inappropriate pins common_hal_rgbmatrix_rgbmatrix_deinit(self); switch (stat) { case PROTOMATTER_ERR_PINS: @@ -117,7 +121,9 @@ void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t* self, case PROTOMATTER_ERR_ARG: mp_raise_ValueError(translate("Invalid argument")); break; - case PROTOMATTER_ERR_MALLOC: /// should have already been signaled as NLR + case PROTOMATTER_ERR_MALLOC: + mp_raise_msg(&mp_type_MemoryError, NULL); + break; default: mp_raise_msg_varg(&mp_type_RuntimeError, translate("Internal error #%d"), (int)stat); @@ -126,7 +132,6 @@ void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t* self, } self->paused = 0; - } STATIC void free_pin(uint8_t *pin) { diff --git a/shared-module/rgbmatrix/allocator.h b/shared-module/rgbmatrix/allocator.h index 5e6f0b41d2..172d82684b 100644 --- a/shared-module/rgbmatrix/allocator.h +++ b/shared-module/rgbmatrix/allocator.h @@ -11,7 +11,7 @@ static inline void *_PM_allocator_impl(size_t sz) { if (gc_alloc_possible()) { - return m_malloc(sz + sizeof(void*), true); + return m_malloc_maybe(sz + sizeof(void*), true); } else { supervisor_allocation *allocation = allocate_memory(align32_size(sz), false); return allocation ? allocation->ptr : NULL; From e01ade3848cf828620ea25ada2b2b829dbe180f3 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 28 Aug 2020 11:24:59 -0500 Subject: [PATCH 65/84] rgbmatrix: Don't inline the allocator functions --- shared-module/rgbmatrix/RGBMatrix.c | 19 ++++++++++++++++++- shared-module/rgbmatrix/allocator.h | 28 +++++----------------------- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/shared-module/rgbmatrix/RGBMatrix.c b/shared-module/rgbmatrix/RGBMatrix.c index a020ef0896..6fb36f6e3a 100644 --- a/shared-module/rgbmatrix/RGBMatrix.c +++ b/shared-module/rgbmatrix/RGBMatrix.c @@ -84,7 +84,7 @@ void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t* self, _PM_FREE(self->core.screenData); self->framebuffer = NULL; - self->bufinfo.buf = _PM_allocator_impl(self->bufsize); + self->bufinfo.buf = common_hal_rgbmatrix_allocator_impl(self->bufsize); self->bufinfo.len = self->bufsize; self->bufinfo.typecode = 'H' | MP_OBJ_ARRAY_TYPECODE_FLAG_RW; } @@ -211,3 +211,20 @@ int common_hal_rgbmatrix_rgbmatrix_get_height(rgbmatrix_rgbmatrix_obj_t* self) { int computed_height = (self->rgb_count / 3) << (self->addr_count); return computed_height; } + +void *common_hal_rgbmatrix_allocator_impl(size_t sz) { + if (gc_alloc_possible()) { + return m_malloc_maybe(sz + sizeof(void*), true); + } else { + supervisor_allocation *allocation = allocate_memory(align32_size(sz), false); + return allocation ? allocation->ptr : NULL; + } +} + +void common_hal_rgbmatrix_free_impl(void *ptr_in) { + supervisor_allocation *allocation = allocation_from_ptr(ptr_in); + + if (allocation) { + free_memory(allocation); + } +} diff --git a/shared-module/rgbmatrix/allocator.h b/shared-module/rgbmatrix/allocator.h index 172d82684b..3191565a36 100644 --- a/shared-module/rgbmatrix/allocator.h +++ b/shared-module/rgbmatrix/allocator.h @@ -1,29 +1,11 @@ -#ifndef MICROPY_INCLUDED_SHARED_MODULE_RGBMATRIX_ALLOCATOR_H -#define MICROPY_INCLUDED_SHARED_MODULE_RGBMATRIX_ALLOCATOR_H +#pragma once #include #include "py/gc.h" #include "py/misc.h" #include "supervisor/memory.h" -#define _PM_ALLOCATOR _PM_allocator_impl -#define _PM_FREE(x) (_PM_free_impl((x)), (x)=NULL, (void)0) - -static inline void *_PM_allocator_impl(size_t sz) { - if (gc_alloc_possible()) { - return m_malloc_maybe(sz + sizeof(void*), true); - } else { - supervisor_allocation *allocation = allocate_memory(align32_size(sz), false); - return allocation ? allocation->ptr : NULL; - } -} - -static inline void _PM_free_impl(void *ptr_in) { - supervisor_allocation *allocation = allocation_from_ptr(ptr_in); - - if (allocation) { - free_memory(allocation); - } -} - -#endif +#define _PM_ALLOCATOR common_hal_rgbmatrix_allocator_impl +#define _PM_FREE(x) (common_hal_rgbmatrix_free_impl((x)), (x)=NULL, (void)0) +extern void *common_hal_rgbmatrix_allocator_impl(size_t sz); +extern void common_hal_rgbmatrix_free_impl(void *); From dfa90cc11ddf7cd719c448ae9c516bf2b117aa3a Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 1 Sep 2020 11:00:19 -0500 Subject: [PATCH 66/84] allocator.h: add a missing license notice --- shared-module/rgbmatrix/allocator.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/shared-module/rgbmatrix/allocator.h b/shared-module/rgbmatrix/allocator.h index 3191565a36..323fa5ec06 100644 --- a/shared-module/rgbmatrix/allocator.h +++ b/shared-module/rgbmatrix/allocator.h @@ -1,3 +1,29 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler 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. + */ + #pragma once #include From ce603dfebfa9a6ef057110c14c5d5b819eb93069 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 31 Aug 2020 16:00:41 -0500 Subject: [PATCH 67/84] rgbmatrix: Disable timer while reconstructing the display --- shared-module/rgbmatrix/RGBMatrix.c | 1 + 1 file changed, 1 insertion(+) diff --git a/shared-module/rgbmatrix/RGBMatrix.c b/shared-module/rgbmatrix/RGBMatrix.c index 6fb36f6e3a..edeef7c1fc 100644 --- a/shared-module/rgbmatrix/RGBMatrix.c +++ b/shared-module/rgbmatrix/RGBMatrix.c @@ -66,6 +66,7 @@ void common_hal_rgbmatrix_rgbmatrix_construct(rgbmatrix_rgbmatrix_obj_t *self, i } void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t* self, mp_obj_t framebuffer) { + common_hal_rgbmatrix_timer_disable(self->timer); if (framebuffer) { self->framebuffer = framebuffer; framebuffer = mp_obj_new_bytearray_of_zeros(self->bufsize); From 71c63c2812ce63ceabdc74aac1b2dda5eb1ca338 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 1 Sep 2020 10:30:14 -0500 Subject: [PATCH 68/84] FramebufferDisplay: Don't set rotation via core_construct The expectations of displayio.Display and frambufferio.FramebufferDisplay are different when it comes to rotation. In displayio.Display, if you call core_construct with a WxH = 64x32 and rotation=90, you get something that is 32 pixels wide and 64 pixels tall in the LCD's coordinate system. This is fine, as the existing definitions were written to work like this. With framebuffer displays, however, the underlying framebuffer (such as RGBMatrix) says "I am WxH pixels wide in my coordinate system" and the constructor is given a rotation; when the rotation indicates a transpose that means "exchange rows and columns, so that to the Groups displayed on it, there is an effectively HxW pixel region for use". Happily, we already have a set_rotation method. Thus (modulo the time spent debugging things anyway:) the fix is simple: Always request no rotation from core_construct, then immediately fix up the rotation to match what was requested. Testing performed: 32x16 RGBMatrix on Metro M4 Express (but using the Airlift firmware, as this is the configuration the error was reported on): * initially construct display at 0, 90, 180, 270 degrees * later change angle to 0, 90, 180, 270 degrees * no garbled display * no safe mode crashes --- shared-module/framebufferio/FramebufferDisplay.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index 6b5346877c..5163c3a7bc 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -66,7 +66,7 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu ram_height, 0, 0, - rotation, + 0, // rotation depth, fb_getter_default(get_grayscale, (depth < 8)), fb_getter_default(get_pixels_in_byte_share_row, false), @@ -92,6 +92,10 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu self->native_frames_per_second = fb_getter_default(get_native_frames_per_second, 60); self->native_ms_per_frame = 1000 / self->native_frames_per_second; + if (rotation != 0) { + common_hal_framebufferio_framebufferdisplay_set_rotation(self, rotation); + } + supervisor_start_terminal(self->core.width, self->core.height); // Set the group after initialization otherwise we may send pixels while we delay in From 3c083330f8a201d74b120c1f9f83baef8124fae5 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 1 Sep 2020 10:58:54 -0500 Subject: [PATCH 69/84] RGBMatrix: Remove unused, dead allocation @tannewt noticed this in a pull request review. The allocated memory was never used, but the GC would have collected it eventually. --- shared-module/rgbmatrix/RGBMatrix.c | 1 - 1 file changed, 1 deletion(-) diff --git a/shared-module/rgbmatrix/RGBMatrix.c b/shared-module/rgbmatrix/RGBMatrix.c index edeef7c1fc..c39ec99a27 100644 --- a/shared-module/rgbmatrix/RGBMatrix.c +++ b/shared-module/rgbmatrix/RGBMatrix.c @@ -69,7 +69,6 @@ void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t* self, common_hal_rgbmatrix_timer_disable(self->timer); if (framebuffer) { self->framebuffer = framebuffer; - framebuffer = mp_obj_new_bytearray_of_zeros(self->bufsize); mp_get_buffer_raise(self->framebuffer, &self->bufinfo, MP_BUFFER_READ); if (mp_get_buffer(self->framebuffer, &self->bufinfo, MP_BUFFER_RW)) { self->bufinfo.typecode = 'H' | MP_OBJ_ARRAY_TYPECODE_FLAG_RW; From 4e3cb55ce705878a811cad2c68317391c7b5497d Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 1 Sep 2020 12:41:58 -0400 Subject: [PATCH 70/84] share more of _bleio dict; fix one doc error --- shared-bindings/_bleio/Adapter.c | 2 +- shared-bindings/_bleio/__init__.c | 91 ++++++++++++------------------- 2 files changed, 37 insertions(+), 56 deletions(-) diff --git a/shared-bindings/_bleio/Adapter.c b/shared-bindings/_bleio/Adapter.c index 4facd818a3..682177093d 100644 --- a/shared-bindings/_bleio/Adapter.c +++ b/shared-bindings/_bleio/Adapter.c @@ -73,7 +73,7 @@ //| communicate with the HCI co-processor in HCI mode. //| The `Adapter` object is enabled during this call. //| -//| After instantiating the Adapter, assign it to _bleio.adapter +//| After instantiating an Adapter, call `_bleio.set_adapter()` to set `_bleio.adapter` //| //| On boards with native BLE, you cannot create an instance of `_bleio.Adapter`; //| this constructor will raise `NotImplementedError`. diff --git a/shared-bindings/_bleio/__init__.c b/shared-bindings/_bleio/__init__.c index dece5820fb..3d9084dd53 100644 --- a/shared-bindings/_bleio/__init__.c +++ b/shared-bindings/_bleio/__init__.c @@ -123,7 +123,8 @@ 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.""" +//| """Set the adapter to use for BLE, such as when using an HCI adapter. +//| Raises `NotImplementedError` when the adapter is a singleton and cannot be set.""" //| ... //| mp_obj_t bleio_set_adapter(mp_obj_t adapter_obj) { @@ -147,73 +148,53 @@ 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. - +// Use a local macro to define how table entries should be converted. +#define OBJ_FROM_PTR MP_OBJ_FROM_PTR 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. - +#define OBJ_FROM_PTR MP_ROM_PTR STATIC const mp_rom_map_elem_t bleio_module_globals_table[] = { +#endif // 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_ROM_PTR(&bleio_adapter_type) }, - { MP_ROM_QSTR(MP_QSTR_Address), MP_ROM_PTR(&bleio_address_type) }, - { MP_ROM_QSTR(MP_QSTR_Attribute), MP_ROM_PTR(&bleio_attribute_type) }, - { MP_ROM_QSTR(MP_QSTR_Connection), MP_ROM_PTR(&bleio_connection_type) }, - { MP_ROM_QSTR(MP_QSTR_Characteristic), MP_ROM_PTR(&bleio_characteristic_type) }, - { MP_ROM_QSTR(MP_QSTR_CharacteristicBuffer), MP_ROM_PTR(&bleio_characteristic_buffer_type) }, - { MP_ROM_QSTR(MP_QSTR_Descriptor), MP_ROM_PTR(&bleio_descriptor_type) }, - { MP_ROM_QSTR(MP_QSTR_PacketBuffer), MP_ROM_PTR(&bleio_packet_buffer_type) }, - { MP_ROM_QSTR(MP_QSTR_ScanEntry), MP_ROM_PTR(&bleio_scanentry_type) }, - { MP_ROM_QSTR(MP_QSTR_ScanResults), MP_ROM_PTR(&bleio_scanresults_type) }, - { MP_ROM_QSTR(MP_QSTR_Service), MP_ROM_PTR(&bleio_service_type) }, - { MP_ROM_QSTR(MP_QSTR_UUID), MP_ROM_PTR(&bleio_uuid_type) }, + { MP_ROM_QSTR(MP_QSTR_Adapter), OBJ_FROM_PTR(&bleio_adapter_type) }, + { MP_ROM_QSTR(MP_QSTR_Address), OBJ_FROM_PTR(&bleio_address_type) }, + { MP_ROM_QSTR(MP_QSTR_Attribute), OBJ_FROM_PTR(&bleio_attribute_type) }, + { MP_ROM_QSTR(MP_QSTR_Connection), OBJ_FROM_PTR(&bleio_connection_type) }, + { MP_ROM_QSTR(MP_QSTR_Characteristic), OBJ_FROM_PTR(&bleio_characteristic_type) }, + { MP_ROM_QSTR(MP_QSTR_CharacteristicBuffer), OBJ_FROM_PTR(&bleio_characteristic_buffer_type) }, + { MP_ROM_QSTR(MP_QSTR_Descriptor), OBJ_FROM_PTR(&bleio_descriptor_type) }, + { MP_ROM_QSTR(MP_QSTR_PacketBuffer), OBJ_FROM_PTR(&bleio_packet_buffer_type) }, + { MP_ROM_QSTR(MP_QSTR_ScanEntry), OBJ_FROM_PTR(&bleio_scanentry_type) }, + { MP_ROM_QSTR(MP_QSTR_ScanResults), OBJ_FROM_PTR(&bleio_scanresults_type) }, + { MP_ROM_QSTR(MP_QSTR_Service), OBJ_FROM_PTR(&bleio_service_type) }, + { MP_ROM_QSTR(MP_QSTR_UUID), OBJ_FROM_PTR(&bleio_uuid_type) }, - // Properties +#if CIRCUITPY_BLEIO_HCI + // For HCI, _bleio.adapter is settable, and starts as None. + { MP_ROM_QSTR(MP_QSTR_adapter), mp_const_none }, + { MP_ROM_QSTR(MP_QSTR_set_adapter), (mp_obj_t) &bleio_set_adapter_obj }, +#else + // For non-HCI _bleio.adapter is a fixed singleton, and is not settable. + // _bleio.set_adapter will raise NotImplementedError. { MP_ROM_QSTR(MP_QSTR_adapter), MP_ROM_PTR(&common_hal_bleio_adapter_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_adapter), MP_ROM_PTR(&bleio_set_adapter_obj) }, +#endif // Errors - { MP_ROM_QSTR(MP_QSTR_BluetoothError), MP_ROM_PTR(&mp_type_bleio_BluetoothError) }, - { MP_ROM_QSTR(MP_QSTR_ConnectionError), MP_ROM_PTR(&mp_type_bleio_ConnectionError) }, - { MP_ROM_QSTR(MP_QSTR_RoleError), MP_ROM_PTR(&mp_type_bleio_RoleError) }, - { MP_ROM_QSTR(MP_QSTR_SecurityError), MP_ROM_PTR(&mp_type_bleio_SecurityError) }, + { MP_ROM_QSTR(MP_QSTR_BluetoothError), OBJ_FROM_PTR(&mp_type_bleio_BluetoothError) }, + { MP_ROM_QSTR(MP_QSTR_ConnectionError), OBJ_FROM_PTR(&mp_type_bleio_ConnectionError) }, + { MP_ROM_QSTR(MP_QSTR_RoleError), OBJ_FROM_PTR(&mp_type_bleio_RoleError) }, + { MP_ROM_QSTR(MP_QSTR_SecurityError), OBJ_FROM_PTR(&mp_type_bleio_SecurityError) }, // Initialization - { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&bleio___init___obj) }, + { MP_ROM_QSTR(MP_QSTR___init__), OBJ_FROM_PTR(&bleio___init___obj) }, }; +#if CIRCUITPY_BLEIO_HCI +// Module dict is mutable to allow setting _bleio.adapter. +STATIC MP_DEFINE_MUTABLE_DICT(bleio_module_globals, bleio_module_globals_table); +#else STATIC MP_DEFINE_CONST_DICT(bleio_module_globals, bleio_module_globals_table); #endif From 51acfbbb01978e0b4a31013d9b25d28f2d7265f3 Mon Sep 17 00:00:00 2001 From: Wellington Terumi Uemura Date: Sun, 30 Aug 2020 22:05:24 +0000 Subject: [PATCH 71/84] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (780 of 780 strings) Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/pt_BR/ --- locale/pt_BR.po | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/locale/pt_BR.po b/locale/pt_BR.po index 65fe17cde8..b0233b5dbc 100644 --- a/locale/pt_BR.po +++ b/locale/pt_BR.po @@ -6,7 +6,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-08-27 11:21-0400\n" -"PO-Revision-Date: 2020-08-21 18:19+0000\n" +"PO-Revision-Date: 2020-08-31 00:37+0000\n" "Last-Translator: Wellington Terumi Uemura \n" "Language-Team: \n" "Language: pt_BR\n" @@ -1375,6 +1375,8 @@ msgid "" "Port does not accept pins or frequency. Construct and pass a PWMOut Carrier " "instead" msgstr "" +"A porta não aceita pinos ou frequência. Em vez disso, construa e passe um " +"PWMOut Carrier" #: shared-bindings/_bleio/Adapter.c msgid "Prefix buffer must be on the heap" @@ -2967,11 +2969,11 @@ msgstr "" #: shared-bindings/displayio/Bitmap.c msgid "out of range of source" -msgstr "" +msgstr "fora do alcance da fonte" #: shared-bindings/displayio/Bitmap.c msgid "out of range of target" -msgstr "" +msgstr "fora do alcance do alvo" #: py/objint_mpz.c msgid "overflow converting long int to machine word" @@ -3156,7 +3158,7 @@ msgstr "o sosfilt requer que os argumentos sejam iteráveis" #: shared-bindings/displayio/Bitmap.c msgid "source palette too large" -msgstr "" +msgstr "a paleta de origem é muito grande" #: py/objstr.c msgid "start/end indices" From 23fc7a573ee0a53a49004690d39efcf71698b977 Mon Sep 17 00:00:00 2001 From: Taku Fukada Date: Tue, 1 Sep 2020 05:56:43 +0000 Subject: [PATCH 72/84] Translated using Weblate (Japanese) Currently translated at 68.7% (536 of 780 strings) Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ja/ --- locale/ja.po | 345 +++++++++++++++++++++++++-------------------------- 1 file changed, 170 insertions(+), 175 deletions(-) diff --git a/locale/ja.po b/locale/ja.po index 10e1d09a06..789930cd00 100644 --- a/locale/ja.po +++ b/locale/ja.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-08-27 11:21-0400\n" -"PO-Revision-Date: 2020-08-16 13:25+0000\n" +"PO-Revision-Date: 2020-09-01 12:07+0000\n" "Last-Translator: Taku Fukada \n" "Language-Team: none\n" "Language: ja\n" @@ -16,7 +16,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 4.2-dev\n" +"X-Generator: Weblate 4.2.1-dev\n" #: main.c msgid "" @@ -42,7 +42,7 @@ msgid "" "To exit, please reset the board without " msgstr "" "\n" -"終了するには、次の操作なしにリセットしてください: " +"終了するには、次の操作をせずにリセットしてください: " #: py/obj.c msgid " File \"%q\"" @@ -84,7 +84,7 @@ msgstr "%q インデックスは範囲外" #: py/obj.c msgid "%q indices must be integers, not %q" -msgstr "%qインデクスは、%qでなく整数が必要です" +msgstr "%qインデクスは、%qでなく整数が必要" #: shared-bindings/vectorio/Polygon.c msgid "%q list must be a list" @@ -121,7 +121,7 @@ msgstr "%q()は%d個の位置引数を受け取りますが、%d個しか与え #: py/argcheck.c msgid "'%q' argument required" -msgstr "引数'%q'が必要" +msgstr "引数 '%q' が必要" #: py/runtime.c msgid "'%q' object cannot assign attribute '%q'" @@ -177,7 +177,7 @@ msgstr "" #: py/emitinlinethumb.c #, c-format msgid "'%s' expects an FPU register" -msgstr "" +msgstr "'%s'にはFPUレジスタが必要" #: py/emitinlinethumb.c #, c-format @@ -227,15 +227,15 @@ msgstr "関数外でのawait" #: py/compile.c msgid "'await', 'async for' or 'async with' outside async function" -msgstr "async関数外でのawait, async for, async with" +msgstr "async関数外での await, async for, async with" #: py/compile.c msgid "'break' outside loop" -msgstr "ループ外での 'break'" +msgstr "ループ外でのbreak" #: py/compile.c msgid "'continue' outside loop" -msgstr "ループ外での 'continue'" +msgstr "ループ外でのcontinue" #: py/objgenerator.c msgid "'coroutine' object is not an iterator" @@ -243,11 +243,11 @@ msgstr "'coroutine' オブジェクトはイテレータではありません" #: py/compile.c msgid "'data' requires at least 2 arguments" -msgstr "" +msgstr "'data'には少なくとも2つの引数が必要" #: py/compile.c msgid "'data' requires integer arguments" -msgstr "" +msgstr "'data'には整数の引数が必要" #: py/compile.c msgid "'label' requires 1 argument" @@ -255,11 +255,11 @@ msgstr "" #: py/compile.c msgid "'return' outside function" -msgstr "関数外での 'return'" +msgstr "関数外でのreturn" #: py/compile.c msgid "'yield' outside function" -msgstr "関数外での 'yield'" +msgstr "関数外でのyield" #: py/compile.c msgid "*x must be assignment target" @@ -285,7 +285,7 @@ msgstr "ハードウェア割り込みチャネルは使用中" #: shared-bindings/_bleio/Address.c #, c-format msgid "Address must be %d bytes long" -msgstr "アドレスの長さは %d バイトでなければなりません" +msgstr "アドレスは、%dバイト長でなければなりません" #: shared-bindings/_bleio/Address.c msgid "Address type out of range" @@ -369,16 +369,16 @@ msgstr "Arrayの各値は1バイトでなければなりません" #: shared-bindings/microcontroller/Pin.c msgid "At most %d %q may be specified (not %d)" -msgstr "最大で %d 個の %q が指定できます(%d個でなく)" +msgstr "最大で %d個の %q が指定できます(%d個でなく)" #: shared-module/memorymonitor/AllocationAlarm.c #, c-format msgid "Attempt to allocate %d blocks" -msgstr "%d 個のブロックの確保を試みました" +msgstr "%d個のブロックの確保を試みました" #: supervisor/shared/safe_mode.c msgid "Attempted heap allocation when MicroPython VM not running." -msgstr "MicroPython VMの非実行時にヒープの確保を試みました" +msgstr "MicroPython VM 非実行時にヒープの確保を試みました" #: main.c msgid "Auto-reload is off.\n" @@ -407,7 +407,7 @@ msgstr "ビット深度は8の倍数でなければなりません" #: ports/mimxrt10xx/common-hal/busio/UART.c msgid "Both RX and TX required for flow control" -msgstr "フロー制御のためにRXとTXの両方が必要" +msgstr "フロー制御のためRXとTXの両方が必要" #: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c msgid "Both pins must support hardware interrupts" @@ -417,7 +417,7 @@ msgstr "両方のピンにハードウェア割り込み対応が必要" #: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-bindings/rgbmatrix/RGBMatrix.c msgid "Brightness must be 0-1.0" -msgstr "Brightnessは0から1.0まででなければなりません" +msgstr "brightnessは0から1.0まででなければなりません" #: shared-bindings/supervisor/__init__.c msgid "Brightness must be between 0 and 255" @@ -529,7 +529,7 @@ msgstr "同じピン上の両チャネルに出力できません" #: shared-module/bitbangio/SPI.c msgid "Cannot read without MISO pin." -msgstr "MISOピンなしで読み込みはできません" +msgstr "MISOピンなしで読み込めません" #: shared-bindings/audiobusio/PDMIn.c msgid "Cannot record to a file" @@ -537,13 +537,13 @@ msgstr "ファイルへ記録できません" #: shared-module/storage/__init__.c msgid "Cannot remount '/' when USB is active." -msgstr "USBがアクティブな時に '/' を再マウントできません" +msgstr "USBがアクティブの時に'/'を再マウントできません" #: ports/atmel-samd/common-hal/microcontroller/__init__.c #: ports/cxd56/common-hal/microcontroller/__init__.c #: ports/mimxrt10xx/common-hal/microcontroller/__init__.c msgid "Cannot reset into bootloader because no bootloader is present." -msgstr "ブートローダが存在しないためブートローダへとリセットできません" +msgstr "ブートローダが存在しないため、ブートローダへとリセットできません" #: shared-bindings/digitalio/DigitalInOut.c msgid "Cannot set value when direction is input." @@ -567,11 +567,11 @@ msgstr "スカラのサイズを曖昧さなしに取得できません" #: ports/stm/common-hal/pwmio/PWMOut.c msgid "Cannot vary frequency on a timer that is already in use" -msgstr "使用中のタイマー上で周波数を変えられません" +msgstr "使用中のタイマー上では周波数を変えられません" #: shared-module/bitbangio/SPI.c msgid "Cannot write without MOSI pin." -msgstr "MOSIピンなしに書き込みできません" +msgstr "MOSIピンなしで書き込みできません" #: shared-bindings/_bleio/CharacteristicBuffer.c msgid "CharacteristicBuffer writing not provided" @@ -622,7 +622,7 @@ msgstr "破損した .mpy ファイル" #: py/emitglue.c msgid "Corrupt raw code" -msgstr "破損した raw code" +msgstr "破損したraw code" #: ports/cxd56/common-hal/gnss/GNSS.c msgid "Could not initialize GNSS" @@ -658,7 +658,7 @@ msgstr "PWMを再スタートできません" #: shared-bindings/_bleio/Adapter.c msgid "Could not set address" -msgstr "" +msgstr "アドレスをセットできません" #: ports/stm/common-hal/pwmio/PWMOut.c msgid "Could not start PWM" @@ -762,7 +762,7 @@ msgstr "正規表現にエラーがあります" #: shared-bindings/neopixel_write/__init__.c #: shared-bindings/terminalio/Terminal.c msgid "Expected a %q" -msgstr "" +msgstr "%qが必要" #: shared-bindings/_bleio/CharacteristicBuffer.c #: shared-bindings/_bleio/Descriptor.c shared-bindings/_bleio/PacketBuffer.c @@ -776,7 +776,7 @@ msgstr "" #: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c #: shared-bindings/_bleio/Service.c msgid "Expected a UUID" -msgstr "" +msgstr "UUIDが必要" #: shared-bindings/_bleio/Adapter.c msgid "Expected an Address" @@ -793,7 +793,7 @@ msgstr "" #: extmod/ulab/code/fft/fft.c msgid "FFT is defined for ndarrays only" -msgstr "FFTは ndarray に対してのみ定義されています" +msgstr "FFTはndarrayでのみ使えます" #: shared-bindings/ps2io/Ps2.c msgid "Failed sending command." @@ -815,7 +815,7 @@ msgstr "RXバッファの確保に失敗" #: ports/stm/common-hal/pulseio/PulseIn.c #, c-format msgid "Failed to allocate RX buffer of %d bytes" -msgstr "%d バイトのRXバッファの確保に失敗" +msgstr "%dバイトのRXバッファの確保に失敗" #: ports/nrf/common-hal/_bleio/Adapter.c msgid "Failed to connect: internal error" @@ -849,11 +849,11 @@ msgstr "" #: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c msgid "Frequency captured is above capability. Capture Paused." -msgstr "" +msgstr "キャプチャした周波数は能力を超えています。キャプチャ停止" #: ports/stm/common-hal/pwmio/PWMOut.c msgid "Frequency must match existing PWMOut using this timer" -msgstr "このタイマーを使う既存のPWMOutと周波数を一致させてください" +msgstr "このタイマーを使う既存のPWMOutと周波数を一致させる必要があります" #: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c #: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c @@ -877,11 +877,11 @@ msgstr "ハードウェアビジー。代替のピンを試してください" #: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "Hardware in use, try alternative pins" -msgstr "ハードウェア使用中。代替のピンを試してください" +msgstr "ハードウェア使用中。代わりのピンを試してください" #: extmod/vfs_posix_file.c py/objstringio.c msgid "I/O operation on closed file" -msgstr "閉じられたファイルに対するI/O操作" +msgstr "閉じられたファイルへのI/O操作" #: ports/stm/common-hal/busio/I2C.c msgid "I2C Init Error" @@ -894,15 +894,13 @@ msgstr "I2SOutが利用できません" #: shared-bindings/aesio/aes.c #, c-format msgid "IV must be %d bytes long" -msgstr "IV の長さは %d バイトでなければなりません" +msgstr "IVは%dバイト長でなければなりません" #: py/persistentcode.c msgid "" "Incompatible .mpy file. Please update all .mpy files. See http://adafru.it/" "mpy-update for more info." -msgstr "" -"非互換の.mpyファイルです。全ての.mpyファイルをアップデートしてください。詳細" -"は http://adafru.it/mpy-update を参照" +msgstr "非互換の.mpyファイルです。全ての.mpyファイルを更新してください。詳細は http://adafru.it/mpy-update を参照" #: shared-bindings/_pew/PewPew.c msgid "Incorrect buffer size" @@ -941,7 +939,7 @@ msgstr "不正な%qピン" #: ports/stm/common-hal/busio/I2C.c ports/stm/common-hal/busio/SPI.c #: ports/stm/common-hal/busio/UART.c ports/stm/common-hal/sdioio/SDCard.c msgid "Invalid %q pin selection" -msgstr "" +msgstr "不正な%qピン選択" #: ports/stm/common-hal/analogio/AnalogIn.c msgid "Invalid ADC Unit value" @@ -953,7 +951,7 @@ msgstr "不正なBMPファイル" #: ports/stm/common-hal/analogio/AnalogOut.c msgid "Invalid DAC pin supplied" -msgstr "無効なDACピンが与えられました" +msgstr "不正なDACピンが与えられました" #: ports/atmel-samd/common-hal/pwmio/PWMOut.c #: ports/cxd56/common-hal/pwmio/PWMOut.c ports/nrf/common-hal/pwmio/PWMOut.c @@ -967,7 +965,7 @@ msgstr "不正な引数" #: shared-module/displayio/Bitmap.c msgid "Invalid bits per value" -msgstr "値ごとのビット数が不正" +msgstr "不正なbits per value" #: ports/nrf/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "Invalid buffer size" @@ -979,7 +977,7 @@ msgstr "不正なバイトオーダー文字列" #: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c msgid "Invalid capture period. Valid range: 1 - 500" -msgstr "不正なキャプチャ周期。有効な周期は1 - 500" +msgstr "不正なキャプチャ周期。有効な周期は1-500" #: shared-bindings/audiomixer/Mixer.c msgid "Invalid channel count" @@ -987,7 +985,7 @@ msgstr "不正なチャンネル数" #: shared-bindings/digitalio/DigitalInOut.c msgid "Invalid direction." -msgstr "不正な方向" +msgstr "不正な入出力方向" #: shared-module/audiocore/WaveFile.c msgid "Invalid file" @@ -1012,7 +1010,7 @@ msgstr "不正なビット数" #: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c #: shared-bindings/displayio/FourWire.c msgid "Invalid phase" -msgstr "" +msgstr "不正なphase" #: ports/atmel-samd/common-hal/audioio/AudioOut.c #: ports/atmel-samd/common-hal/touchio/TouchIn.c shared-bindings/pwmio/PWMOut.c @@ -1055,11 +1053,11 @@ msgstr "不正なプロパティ" #: shared-bindings/microcontroller/__init__.c msgid "Invalid run mode." -msgstr "不正な Run Mode" +msgstr "不正なRun Mode" #: shared-module/_bleio/Attribute.c msgid "Invalid security_mode" -msgstr "不正な security_mode" +msgstr "不正なsecurity_mode" #: shared-bindings/audiomixer/Mixer.c msgid "Invalid voice" @@ -1071,7 +1069,7 @@ msgstr "不正なボイス数" #: shared-module/audiocore/WaveFile.c msgid "Invalid wave file" -msgstr "不正なWaveファイル" +msgstr "不正なwaveファイル" #: ports/stm/common-hal/busio/UART.c msgid "Invalid word/bit length" @@ -1167,7 +1165,7 @@ msgstr "DMAチャネルが見つかりません" #: ports/mimxrt10xx/common-hal/busio/SPI.c ports/stm/common-hal/busio/SPI.c msgid "No MISO Pin" -msgstr "MISOピンがありません" +msgstr "MISOピンなし" #: ports/mimxrt10xx/common-hal/busio/SPI.c ports/stm/common-hal/busio/SPI.c msgid "No MOSI Pin" @@ -1203,7 +1201,7 @@ msgstr "使われていないGCLKがありません" #: shared-bindings/os/__init__.c msgid "No hardware random available" -msgstr "ハードウェア乱数が利用できません" +msgstr "利用可能なハードウェア乱数なし" #: ports/atmel-samd/common-hal/ps2io/Ps2.c msgid "No hardware support on clk pin" @@ -1254,7 +1252,7 @@ msgstr "接続されていません" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c #: shared-bindings/audiopwmio/PWMAudioOut.c msgid "Not playing" -msgstr "再生中していません" +msgstr "再生していません" #: main.c msgid "Not running saved code.\n" @@ -1290,13 +1288,12 @@ msgstr "" #: shared-bindings/audiobusio/PDMIn.c msgid "Oversample must be multiple of 8." -msgstr "オーバーサンプルは8の倍数でなければなりません" +msgstr "オーバーサンプルは8の倍数が必要" #: shared-bindings/pwmio/PWMOut.c msgid "" "PWM duty_cycle must be between 0 and 65535 inclusive (16 bit resolution)" -msgstr "" -"PWMの duty_cycle 値は 0 から 65535 の間でなければなりません(16ビット解像度)" +msgstr "PWMのduty_cycle値は0から65535の間でなければなりません(16ビット解像度)" #: shared-bindings/pwmio/PWMOut.c msgid "" @@ -1364,7 +1361,7 @@ msgstr "Prefixバッファはヒープ上になければなりません" #: main.c #, fuzzy msgid "Press any key to enter the REPL. Use CTRL-D to reload." -msgstr "何らかのキーを押すとREPLに入ります。CTRL-Dでリロードします" +msgstr "いずれかのキーを押すとREPLに入ります。リロードはCTRL-D" #: shared-bindings/digitalio/DigitalInOut.c msgid "Pull not used when direction is output." @@ -1372,11 +1369,11 @@ msgstr "方向がoutputのときpullは使われません" #: ports/stm/ref/pulseout-pre-timeralloc.c msgid "PulseOut not supported on this chip" -msgstr "" +msgstr "PulseOutはこのチップでサポートされていません" #: ports/stm/common-hal/os/__init__.c msgid "RNG DeInit Error" -msgstr "乱数生成器の解体エラー" +msgstr "RNG解体エラー" #: ports/stm/common-hal/os/__init__.c msgid "RNG Init Error" @@ -1427,7 +1424,7 @@ msgstr "要求のAESモードは非サポート" #: ports/atmel-samd/common-hal/audioio/AudioOut.c msgid "Right channel unsupported" -msgstr "右チャネルは非サポート" +msgstr "右チャネルはサポートされていません" #: shared-bindings/_pew/PewPew.c msgid "Row entry must be digitalio.DigitalInOut" @@ -1454,7 +1451,7 @@ msgstr "" #: ports/stm/common-hal/sdioio/SDCard.c #, c-format msgid "SDIO Init Error %d" -msgstr "" +msgstr "SDIO初期化エラー %d" #: ports/stm/common-hal/busio/SPI.c msgid "SPI Init Error" @@ -1466,7 +1463,7 @@ msgstr "SPI再初期化エラー" #: shared-bindings/audiomixer/Mixer.c msgid "Sample rate must be positive" -msgstr "サンプルレートは正数でなければなりません" +msgstr "サンプルレートには正の数が必要" #: ports/atmel-samd/common-hal/audioio/AudioOut.c #, c-format @@ -1479,7 +1476,7 @@ msgstr "スキャンはすでに進行中。stop_scanで停止してください #: ports/mimxrt10xx/common-hal/busio/UART.c msgid "Selected CTS pin not valid" -msgstr "選択されたCTSピンが不正です" +msgstr "選択されたCTSピンが不正" #: ports/mimxrt10xx/common-hal/busio/UART.c msgid "Selected RTS pin not valid" @@ -1515,7 +1512,7 @@ msgstr "スタックサイズは少なくとも256以上が必要" #: shared-bindings/multiterminal/__init__.c msgid "Stream missing readinto() or write() method." -msgstr "" +msgstr "streamにreadinto()またはwrite()メソッドがありません" #: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "Supply at least one UART pin" @@ -1534,8 +1531,8 @@ msgid "" "The CircuitPython heap was corrupted because the stack was too small.\n" "Please increase the stack size if you know how, or if not:" msgstr "" -"スタックが小さすぎたことによりCircuitPythonのヒープが破損しました。\n" -"スタックサイズを上げるか、その方法が分からなければ:" +"スタックが小さすぎたためCircuitPythonのヒープが壊れました。\n" +"スタックサイズを上げるか、その方法が分からなければ:" #: supervisor/shared/safe_mode.c msgid "" @@ -1566,11 +1563,11 @@ msgstr "" #: shared-module/audiomixer/MixerVoice.c msgid "The sample's sample rate does not match the mixer's" -msgstr "" +msgstr "サンプルレートがサンプルとミキサーで一致しません" #: shared-module/audiomixer/MixerVoice.c msgid "The sample's signedness does not match the mixer's" -msgstr "サンプルの符号有無がミキサーと一致しません" +msgstr "符号の有無がサンプルとミキサーで一致しません" #: shared-bindings/displayio/TileGrid.c msgid "Tile height must exactly divide bitmap height" @@ -1582,7 +1579,7 @@ msgstr "タイルのインデクスが範囲外" #: shared-bindings/displayio/TileGrid.c msgid "Tile value out of bounds" -msgstr "タイルの値が範囲外" +msgstr "タイル値が範囲外" #: shared-bindings/displayio/TileGrid.c msgid "Tile width must exactly divide bitmap width" @@ -1591,7 +1588,7 @@ msgstr "タイルの幅はビットマップの幅を割り切れる値でなけ #: ports/nrf/common-hal/_bleio/Adapter.c #, c-format msgid "Timeout is too long: Maximum timeout length is %d seconds" -msgstr "タイムアウトが長すぎ。最大のタイムアウト長は%d秒" +msgstr "タイムアウトが長すぎです。最大のタイムアウト長は%d秒" #: ports/stm/common-hal/pwmio/PWMOut.c msgid "" @@ -1616,7 +1613,7 @@ msgstr "" #: py/obj.c msgid "Traceback (most recent call last):\n" -msgstr "" +msgstr "トレースバック(最新の呼び出しが末尾):\n" #: shared-bindings/time/__init__.c msgid "Tuple or struct_time argument required" @@ -1672,7 +1669,7 @@ msgstr "" #: shared-module/displayio/I2CDisplay.c #, c-format msgid "Unable to find I2C Display at %x" -msgstr "" +msgstr "I2Cディスプレイを %x に見つけられません" #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c #: ports/atmel-samd/common-hal/audiobusio/PDMIn.c @@ -1685,7 +1682,7 @@ msgstr "パーザを初期化できません" #: shared-module/displayio/OnDiskBitmap.c msgid "Unable to read color palette data" -msgstr "カラーパレットのデータを読み込めません" +msgstr "カラーパレットデータを読み込めません" #: shared-bindings/nvm/ByteArray.c msgid "Unable to write to nvm." @@ -1728,7 +1725,7 @@ msgstr "" #: ports/atmel-samd/common-hal/busio/I2C.c ports/cxd56/common-hal/busio/I2C.c #: ports/stm/common-hal/busio/I2C.c msgid "Unsupported baudrate" -msgstr "" +msgstr "非サポートのbaudrate" #: shared-module/displayio/display_core.c msgid "Unsupported display bus type" @@ -1736,11 +1733,11 @@ msgstr "" #: shared-module/audiocore/WaveFile.c msgid "Unsupported format" -msgstr "" +msgstr "サポートされていないフォーマット" #: py/moduerrno.c msgid "Unsupported operation" -msgstr "" +msgstr "サポートされていない操作" #: shared-bindings/digitalio/DigitalInOut.c msgid "Unsupported pull value." @@ -1762,7 +1759,7 @@ msgstr "" #: ports/stm/common-hal/microcontroller/Processor.c msgid "Voltage read timed out" -msgstr "" +msgstr "電圧読み取りがタイムアウト" #: main.c msgid "WARNING: Your code filename has two extensions\n" @@ -1824,11 +1821,11 @@ msgstr "" #: extmod/modubinascii.c extmod/moduhashlib.c py/objarray.c msgid "a bytes-like object is required" -msgstr "" +msgstr "bytes-likeオブジェクトが必要" #: lib/embed/abort_.c msgid "abort() called" -msgstr "" +msgstr "abort()が呼ばれました" #: extmod/machine_mem.c #, c-format @@ -1837,7 +1834,7 @@ msgstr "" #: shared-bindings/i2cperipheral/I2CPeripheral.c msgid "address out of bounds" -msgstr "" +msgstr "アドレスが範囲外" #: shared-bindings/i2cperipheral/I2CPeripheral.c msgid "addresses is empty" @@ -1870,7 +1867,7 @@ msgstr "" #: py/runtime.c msgid "argument should be a '%q' not a '%q'" -msgstr "" +msgstr "引数には '%q' が必要('%q' ではなく)" #: extmod/ulab/code/linalg/linalg.c msgid "arguments must be ndarrays" @@ -1878,7 +1875,7 @@ msgstr "" #: py/objarray.c shared-bindings/nvm/ByteArray.c msgid "array/bytes required on right side" -msgstr "" +msgstr "右辺にはarray/bytesが必要" #: extmod/ulab/code/numerical/numerical.c msgid "attempt to get argmin/argmax of an empty sequence" @@ -1886,7 +1883,7 @@ msgstr "" #: py/objstr.c msgid "attributes not supported yet" -msgstr "" +msgstr "属性はまだサポートされていません" #: extmod/ulab/code/numerical/numerical.c msgid "axis must be -1, 0, None, or 1" @@ -1898,7 +1895,7 @@ msgstr "axisは -1, 0, 1 のいずれかでなければなりません" #: extmod/ulab/code/numerical/numerical.c msgid "axis must be None, 0, or 1" -msgstr "axisは None, 0, 1 のいずれかが必要です" +msgstr "axisは None, 0, 1 のいずれか" #: py/builtinevex.c msgid "bad compile mode" @@ -1910,11 +1907,11 @@ msgstr "" #: py/objstr.c msgid "bad format string" -msgstr "" +msgstr "不正な書式化文字列" #: py/binary.c msgid "bad typecode" -msgstr "typecodeが不正" +msgstr "不正なtypecode" #: py/emitnative.c msgid "binary op %q not implemented" @@ -1922,7 +1919,7 @@ msgstr "" #: shared-bindings/busio/UART.c msgid "bits must be 7, 8 or 9" -msgstr "" +msgstr "bitsは7, 8, 9のいずれかが必要" #: shared-bindings/audiomixer/Mixer.c msgid "bits_per_sample must be 8 or 16" @@ -1959,7 +1956,7 @@ msgstr "" #: shared-bindings/_pixelbuf/PixelBuf.c msgid "byteorder is not a string" -msgstr "" +msgstr "byteorderが文字列ではありません" #: ports/atmel-samd/common-hal/busio/UART.c msgid "bytes > 8 bits not supported" @@ -1967,15 +1964,15 @@ msgstr "" #: py/objstr.c msgid "bytes value out of range" -msgstr "" +msgstr "範囲外のバイト値" #: ports/atmel-samd/bindings/samd/Clock.c ports/atmel-samd/common-hal/rtc/RTC.c msgid "calibration is out of range" -msgstr "" +msgstr "キャリブレーションが範囲外" #: ports/atmel-samd/bindings/samd/Clock.c msgid "calibration is read only" -msgstr "" +msgstr "calibrationは読み込み専用" #: ports/atmel-samd/common-hal/rtc/RTC.c msgid "calibration value out of range +/-127" @@ -1995,24 +1992,24 @@ msgstr "" #: py/objtype.c msgid "can't add special method to already-subclassed class" -msgstr "" +msgstr "サブクラス化済みのクラスに特殊メソッドを追加できません" #: py/compile.c msgid "can't assign to expression" -msgstr "" +msgstr "式には代入できません" #: py/obj.c py/objint.c shared-bindings/i2cperipheral/I2CPeripheral.c #: shared-module/_pixelbuf/PixelBuf.c msgid "can't convert %q to %q" -msgstr "" +msgstr "%qを%qに変換できません" #: py/objstr.c msgid "can't convert '%q' object to %q implicitly" -msgstr "" +msgstr "オブジェクト '%q' を %q に暗黙に変換できません" #: py/obj.c msgid "can't convert to %q" -msgstr "" +msgstr "%q に変換できません" #: py/objstr.c msgid "can't convert to str implicitly" @@ -2020,7 +2017,7 @@ msgstr "" #: py/compile.c msgid "can't declare nonlocal in outer code" -msgstr "" +msgstr "外側のコードでnonlocalは使えません" #: py/compile.c msgid "can't delete expression" @@ -2032,15 +2029,15 @@ msgstr "" #: py/objcomplex.c msgid "can't do truncated division of a complex number" -msgstr "" +msgstr "複素数の切り捨て除算はできません" #: py/compile.c msgid "can't have multiple **x" -msgstr "" +msgstr "複数の **x は持てません" #: py/compile.c msgid "can't have multiple *x" -msgstr "" +msgstr "複数の *x は持てません" #: py/emitnative.c msgid "can't implicitly convert '%q' to 'bool'" @@ -2090,7 +2087,7 @@ msgstr "" #: py/objstr.c msgid "" "can't switch from manual field specification to automatic field numbering" -msgstr "" +msgstr "手動と自動のフィールド指定は混在できません" #: py/objtype.c msgid "cannot create '%q' instances" @@ -2106,11 +2103,11 @@ msgstr "" #: py/builtinimport.c msgid "cannot perform relative import" -msgstr "" +msgstr "相対インポートはできません" #: extmod/ulab/code/ndarray.c msgid "cannot reshape array (incompatible input/output shape)" -msgstr "" +msgstr "入力/出力シェイプが互換でなくreshapeできません" #: py/emitnative.c msgid "casting" @@ -2138,7 +2135,7 @@ msgstr "" #: shared-bindings/displayio/Palette.c msgid "color buffer must be a buffer, tuple, list, or int" -msgstr "" +msgstr "カラーバッファはbuffer, tuple, list, int のいずれかです" #: shared-bindings/displayio/Palette.c msgid "color buffer must be a bytearray or array of type 'b' or 'B'" @@ -2146,7 +2143,7 @@ msgstr "" #: shared-bindings/displayio/Palette.c msgid "color must be between 0x000000 and 0xffffff" -msgstr "" +msgstr "色は0x000000から0xffffffでなければなりません" #: shared-bindings/displayio/ColorConverter.c msgid "color should be an int" @@ -2154,7 +2151,7 @@ msgstr "" #: py/objcomplex.c msgid "complex division by zero" -msgstr "" +msgstr "複素数ゼロ除算" #: py/objfloat.c py/parsenum.c msgid "complex values not supported" @@ -2162,7 +2159,7 @@ msgstr "" #: extmod/moduzlib.c msgid "compression header" -msgstr "" +msgstr "圧縮ヘッダー" #: py/parse.c msgid "constant must be an integer" @@ -2174,11 +2171,11 @@ msgstr "" #: extmod/ulab/code/filter/filter.c msgid "convolve arguments must be linear arrays" -msgstr "" +msgstr "convolve引数には1次元arrayが必要" #: extmod/ulab/code/filter/filter.c msgid "convolve arguments must be ndarrays" -msgstr "" +msgstr "convolve引数にはndarrayが必要" #: extmod/ulab/code/filter/filter.c msgid "convolve arguments must not be empty" @@ -2190,7 +2187,7 @@ msgstr "" #: extmod/ulab/code/poly/poly.c msgid "could not invert Vandermonde matrix" -msgstr "" +msgstr "ヴァンデルモンド行列の逆行列を求められません" #: shared-module/sdcardio/SDCard.c msgid "couldn't determine SD card version" @@ -2214,7 +2211,7 @@ msgstr "" #: py/compile.c msgid "default 'except' must be last" -msgstr "" +msgstr "デフォルトのexceptは最後に置く必要があります" #: shared-bindings/audiobusio/PDMIn.c msgid "" @@ -2223,11 +2220,11 @@ msgstr "" #: shared-bindings/audiobusio/PDMIn.c msgid "destination buffer must be an array of type 'H' for bit_depth = 16" -msgstr "" +msgstr "bit_depath = 16 用のバッファにはタイプ'H'のarrayが必要" #: shared-bindings/audiobusio/PDMIn.c msgid "destination_length must be an int >= 0" -msgstr "" +msgstr "desitination_lengthには正の整数が必要" #: py/objdict.c msgid "dict update sequence has wrong length" @@ -2235,7 +2232,7 @@ msgstr "" #: extmod/ulab/code/numerical/numerical.c msgid "diff argument must be an ndarray" -msgstr "" +msgstr "引数にはndarrayが必要" #: py/modmath.c py/objfloat.c py/objint_longlong.c py/objint_mpz.c py/runtime.c #: shared-bindings/math/__init__.c @@ -2325,7 +2322,7 @@ msgstr "f-string: '}'が必要" #: py/parse.c msgid "f-string: single '}' is not allowed" -msgstr "f-string: 1つだけの '}' は許されません" +msgstr "f-string: 1つだけの'}'は許されません" #: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c #: shared-bindings/displayio/OnDiskBitmap.c @@ -2334,7 +2331,7 @@ msgstr "fileにはバイトモードで開かれたファイルが必要" #: shared-bindings/storage/__init__.c msgid "filesystem must provide mount method" -msgstr "" +msgstr "filesystemにはmountメソッドが必要" #: extmod/ulab/code/vector/vectorise.c msgid "first argument must be a callable" @@ -2374,7 +2371,7 @@ msgstr "" #: py/objstr.c msgid "format requires a dict" -msgstr "" +msgstr "formatにはdictが必要" #: py/objdeque.c msgid "full" @@ -2399,7 +2396,7 @@ msgstr "" #: extmod/ulab/code/compare/compare.c msgid "function is implemented for scalars and ndarrays only" -msgstr "" +msgstr "スカラ値およびndarrayのみを受け取ります" #: py/argcheck.c #, c-format @@ -2427,7 +2424,7 @@ msgstr "" #: shared-bindings/time/__init__.c msgid "function takes exactly 9 arguments" -msgstr "この関数はちょうど9個の引数をとります" +msgstr "関数はちょうど9個の引数をとります" #: py/objgenerator.c msgid "generator already executing" @@ -2443,7 +2440,7 @@ msgstr "" #: extmod/moduheapq.c msgid "heap must be a list" -msgstr "" +msgstr "heapにはリストが必要" #: py/compile.c msgid "identifier redefined as global" @@ -2488,7 +2485,7 @@ msgstr "" #: py/compile.c msgid "inline assembler must be a function" -msgstr "" +msgstr "インラインアセンブラは関数でなければなりません" #: extmod/ulab/code/ulab_create.c msgid "input argument must be an integer or a 2-tuple" @@ -2496,7 +2493,7 @@ msgstr "" #: extmod/ulab/code/fft/fft.c msgid "input array length must be power of 2" -msgstr "入力 array の長さは2の累乗でなければなりません" +msgstr "入力array長は2の累乗でなければなりません" #: extmod/ulab/code/poly/poly.c msgid "input data must be an iterable" @@ -2508,7 +2505,7 @@ msgstr "入力行列が非対称" #: extmod/ulab/code/linalg/linalg.c msgid "input matrix is singular" -msgstr "" +msgstr "入力が非正則行列" #: extmod/ulab/code/linalg/linalg.c msgid "input must be square matrix" @@ -2516,7 +2513,7 @@ msgstr "" #: extmod/ulab/code/numerical/numerical.c msgid "input must be tuple, list, range, or ndarray" -msgstr "" +msgstr "入力はtuple, list, range, ndarrayでなければなりません" #: extmod/ulab/code/poly/poly.c msgid "input vectors must be of equal length" @@ -2524,7 +2521,7 @@ msgstr "" #: py/parsenum.c msgid "int() arg 2 must be >= 2 and <= 36" -msgstr "int() の2番目の引数は 2 以上 36 以下でなければなりません" +msgstr "int()の第2引数は2以上36以下でなければなりません" #: py/objstr.c msgid "integer required" @@ -2537,7 +2534,7 @@ msgstr "" #: shared-bindings/_bleio/Adapter.c #, c-format msgid "interval must be in range %s-%s" -msgstr "" +msgstr "intervalは%s-%sの範囲でなければなりません" #: lib/netutils/netutils.c msgid "invalid arguments" @@ -2565,7 +2562,7 @@ msgstr "不正な鍵" #: py/compile.c msgid "invalid micropython decorator" -msgstr "" +msgstr "不正なmicropythonデコレータ" #: shared-bindings/random/__init__.c msgid "invalid step" @@ -2590,7 +2587,7 @@ msgstr "数字として不正な構文" #: py/objtype.c msgid "issubclass() arg 1 must be a class" -msgstr "issubclass()の1つ目の引数はクラスです" +msgstr "issubclass()の第1引数はクラスが必要" #: py/objtype.c msgid "issubclass() arg 2 must be a class or a tuple of classes" @@ -2598,19 +2595,19 @@ msgstr "" #: extmod/ulab/code/ndarray.c msgid "iterables are not of the same length" -msgstr "イテレート可能なオブジェクトが同じ長さではありません" +msgstr "iterableが同じ長さではありません" #: extmod/ulab/code/linalg/linalg.c msgid "iterations did not converge" -msgstr "" +msgstr "収束しません" #: py/objstr.c msgid "join expects a list of str/bytes objects consistent with self object" -msgstr "" +msgstr "joinには、str/bytes(のうち自身と一致した型の)リストが必要" #: py/argcheck.c msgid "keyword argument(s) not yet implemented - use normal args instead" -msgstr "" +msgstr "キーワード引数はまだ実装されていません。通常の引数を使ってください。" #: py/bc.c msgid "keywords must be strings" @@ -2618,7 +2615,7 @@ msgstr "キーワードは文字列でなければなりません" #: py/emitinlinethumb.c py/emitinlinextensa.c msgid "label '%q' not defined" -msgstr "" +msgstr "ラベル'%q'は定義されていません" #: py/compile.c msgid "label redefined" @@ -2721,11 +2718,11 @@ msgstr "" #: extmod/ulab/code/numerical/numerical.c msgid "n must be between 0, and 9" -msgstr "nは0から9までです" +msgstr "nは0から9まで" #: py/runtime.c msgid "name '%q' is not defined" -msgstr "名前'%q'は定義されていません" +msgstr "名前 '%q' は定義されていません" #: py/runtime.c msgid "name not defined" @@ -2733,7 +2730,7 @@ msgstr "名前が定義されていません" #: py/compile.c msgid "name reused for argument" -msgstr "名前が引数で再利用されています" +msgstr "引数で名前が再利用されています" #: py/emitnative.c msgid "native yield" @@ -2742,7 +2739,7 @@ msgstr "" #: py/runtime.c #, c-format msgid "need more than %d values to unpack" -msgstr "" +msgstr "アンパックする値は%d個では足りません" #: py/objint_longlong.c py/objint_mpz.c py/runtime.c msgid "negative power with no float support" @@ -2766,7 +2763,7 @@ msgstr "利用可能なNICがありません" #: py/compile.c msgid "no binding for nonlocal found" -msgstr "" +msgstr "nonlocalの対象が見つかりません" #: py/builtinimport.c msgid "no module named '%q'" @@ -2783,7 +2780,7 @@ msgstr "SDカードからの応答がありません" #: py/runtime.c msgid "no such attribute" -msgstr "そのような属性はありません" +msgstr "指定の属性はありません" #: ports/nrf/common-hal/_bleio/Connection.c msgid "non-UUID found in service_uuids_whitelist" @@ -2791,7 +2788,7 @@ msgstr "" #: py/compile.c msgid "non-default argument follows default argument" -msgstr "" +msgstr "デフォルト引数の後に通常の引数は置けません" #: extmod/modubinascii.c msgid "non-hex digit found" @@ -2815,11 +2812,11 @@ msgstr "" #: py/objstr.c msgid "not enough arguments for format string" -msgstr "" +msgstr "書式化文字列への引数が足りません" #: extmod/ulab/code/poly/poly.c msgid "number of arguments must be 2, or 3" -msgstr "引数の数は2個または3個でなければなりません" +msgstr "引数は2個または3個でなければなりません" #: extmod/ulab/code/ulab_create.c msgid "number of points must be at least 2" @@ -2847,7 +2844,7 @@ msgstr "オブジェクトは要素の取得をサポートしていません" #: py/runtime.c msgid "object not an iterator" -msgstr "オブジェクトはイテレータではありません" +msgstr "オブジェクトがイテレータではありません" #: py/objtype.c py/runtime.c msgid "object not callable" @@ -2863,7 +2860,7 @@ msgstr "オブジェクトはイテレートできません" #: py/obj.c msgid "object of type '%q' has no len()" -msgstr "" +msgstr "オブジェクト(型 '%q')はlen()を持ちません" #: py/obj.c msgid "object with buffer protocol required" @@ -2879,7 +2876,7 @@ msgstr "" #: ports/nrf/common-hal/audiobusio/PDMIn.c msgid "only bit_depth=16 is supported" -msgstr "" +msgstr "bit_depth=16のみサポートしています" #: ports/nrf/common-hal/audiobusio/PDMIn.c msgid "only sample_rate=16000 is supported" @@ -2914,7 +2911,7 @@ msgstr "ord()は1文字を要求しますが、長さ %d の文字列が与え #: shared-bindings/displayio/Bitmap.c msgid "out of range of source" -msgstr "" +msgstr "ソースが範囲外" #: shared-bindings/displayio/Bitmap.c msgid "out of range of target" @@ -2922,7 +2919,7 @@ msgstr "" #: py/objint_mpz.c msgid "overflow converting long int to machine word" -msgstr "long int をマシンの word に変換する際にオーバーフローしました" +msgstr "long intをマシンのwordに変換する際にオーバーフローしました" #: shared-bindings/_stage/Layer.c shared-bindings/_stage/Text.c msgid "palette must be 32 bytes long" @@ -2930,7 +2927,7 @@ msgstr "パレットの長さは32バイトでなければなりません" #: shared-bindings/displayio/Palette.c msgid "palette_index should be an int" -msgstr "palette_indexは整数です" +msgstr "palette_indexには整数が必要" #: py/compile.c msgid "parameter annotation must be an identifier" @@ -2974,7 +2971,7 @@ msgstr "pow()の3つ目の引数は0にできません" #: py/objint_mpz.c msgid "pow() with 3 arguments requires integers" -msgstr "pow()の3番目の引数には整数が必要" +msgstr "pow()の第3引数には整数が必要" #: extmod/modutimeq.c msgid "queue overflow" @@ -2982,7 +2979,7 @@ msgstr "キューがオーバーフローしました" #: py/parse.c msgid "raw f-strings are not implemented" -msgstr "" +msgstr "raw f-文字列は実装されていません" #: extmod/ulab/code/fft/fft.c msgid "real and imaginary parts must be of equal length" @@ -2995,7 +2992,7 @@ msgstr "相対インポート" #: py/obj.c #, c-format msgid "requested length %d but object has length %d" -msgstr "長さ%dが必要。オブジェクトの長さは%d" +msgstr "必要な長さは%dですがオブジェクトの長さは%d" #: py/compile.c msgid "return annotation must be an identifier" @@ -3027,9 +3024,7 @@ msgstr "rsplit(None,n)" msgid "" "sample_source buffer must be a bytearray or array of type 'h', 'H', 'b' or " "'B'" -msgstr "" -"sample_source バッファは、bytearray または 'h', 'H', 'b', 'B'型のarrayでなけ" -"ればなりません" +msgstr "sample_source バッファには bytearray または 'h','H','b','B'型のarrayが必要" #: ports/atmel-samd/common-hal/audiobusio/PDMIn.c msgid "sampling rate out of range" @@ -3045,7 +3040,7 @@ msgstr "スクリプトのコンパイルは非サポート" #: extmod/ulab/code/ndarray.c msgid "shape must be a 2-tuple" -msgstr "shapeは 2値のタプルでなければなりません" +msgstr "shapeは2値のタプルでなければなりません" #: py/objstr.c msgid "sign not allowed in string format specifier" @@ -3113,11 +3108,11 @@ msgstr "" #: shared-bindings/random/__init__.c msgid "step must be non-zero" -msgstr "" +msgstr "stepは非ゼロ値が必要" #: shared-bindings/busio/UART.c msgid "stop must be 1 or 2" -msgstr "stopは1または2でなければなりません" +msgstr "stopは1または2のいずれか" #: shared-bindings/random/__init__.c msgid "stop not reachable from start" @@ -3129,11 +3124,11 @@ msgstr "ストリーム操作はサポートされていません" #: py/objstrunicode.c msgid "string indices must be integers, not %q" -msgstr "" +msgstr "文字列のインデクスには整数が必要(%qでなく)" #: py/stream.c msgid "string not supported; use bytes or bytearray" -msgstr "" +msgstr "文字列ではなくbytesまたはbytesarrayが必要" #: extmod/moductypes.c msgid "struct: cannot index" @@ -3149,7 +3144,7 @@ msgstr "部分文字列が見つかりません" #: py/compile.c msgid "super() can't find self" -msgstr "" +msgstr "super()がselfを見つけられません" #: extmod/modujson.c msgid "syntax error in JSON" @@ -3161,7 +3156,7 @@ msgstr "uctypedディスクリプタの構文エラー" #: shared-bindings/touchio/TouchIn.c msgid "threshold must be in the range 0-65536" -msgstr "threshouldは0から65536までです" +msgstr "threshouldは0から65536まで" #: shared-bindings/time/__init__.c msgid "time.struct_time() takes a 9-sequence" @@ -3169,7 +3164,7 @@ msgstr "time.struct_time()は9要素のシーケンスを受け取ります" #: ports/nrf/common-hal/watchdog/WatchDogTimer.c msgid "timeout duration exceeded the maximum supported value" -msgstr "" +msgstr "タイムアウト長がサポートされる最大値を超えています" #: shared-bindings/busio/UART.c msgid "timeout must be 0.0-100.0 seconds" @@ -3189,11 +3184,11 @@ msgstr "v2カードの待機がタイムアウトしました" #: shared-bindings/time/__init__.c msgid "timestamp out of range for platform time_t" -msgstr "" +msgstr "timestampがプラットフォームのtime_tの範囲外" #: shared-module/struct/__init__.c msgid "too many arguments provided with the given format" -msgstr "" +msgstr "指定された書式に対して引数が多すぎます" #: extmod/ulab/code/ndarray.c msgid "too many indices" @@ -3202,11 +3197,11 @@ msgstr "インデクスが多すぎます" #: py/runtime.c #, c-format msgid "too many values to unpack (expected %d)" -msgstr "" +msgstr "アンパックする値が多すぎます (%d個を期待)" #: extmod/ulab/code/approx/approx.c msgid "trapz is defined for 1D arrays of equal length" -msgstr "" +msgstr "trapzは同じ長さの1次元arrayに対して定義されています" #: extmod/ulab/code/linalg/linalg.c msgid "tuple index out of range" @@ -3219,7 +3214,7 @@ msgstr "タプル/リストの長さが正しくありません" #: ports/atmel-samd/common-hal/busio/UART.c ports/nrf/common-hal/busio/UART.c #: shared-bindings/busio/UART.c msgid "tx and rx cannot both be None" -msgstr "txとrxの両方をNoneにすることはできません" +msgstr "txとrxを両方ともNoneにできません" #: py/objtype.c msgid "type '%q' is not an acceptable base type" @@ -3235,7 +3230,7 @@ msgstr "" #: py/objtype.c msgid "type takes 1 or 3 arguments" -msgstr "typeは1つまたは3つの引数をとります" +msgstr "typeは1つか3つの引数をとります" #: py/objint_longlong.c msgid "ulonglong too large" @@ -3272,7 +3267,7 @@ msgstr "" #: py/objstr.c msgid "unknown format code '%c' for object of type '%q'" -msgstr "" +msgstr "型'%q'のオブジェクトに対する不明な書式コード'%c'" #: py/compile.c msgid "unknown type" @@ -3320,12 +3315,12 @@ msgstr "演算子がサポートしていない型" #: py/runtime.c msgid "unsupported types for %q: '%q', '%q'" -msgstr "" +msgstr "%qでサポートされない型: '%q', '%q'" #: py/objint.c #, c-format msgid "value must fit in %d byte(s)" -msgstr "値は %d バイトに収まらなければなりません" +msgstr "値は%dバイトに収まらなければなりません" #: shared-bindings/displayio/Bitmap.c msgid "value_count must be > 0" @@ -3345,11 +3340,11 @@ msgstr "" #: extmod/ulab/code/linalg/linalg.c msgid "wrong argument type" -msgstr "引数の型が正しくありません" +msgstr "引数の型が不正" #: extmod/ulab/code/ndarray.c msgid "wrong index type" -msgstr "インデクスの型が不正です" +msgstr "インデクスの型が不正" #: extmod/ulab/code/vector/vectorise.c msgid "wrong input type" @@ -3361,7 +3356,7 @@ msgstr "" #: py/runtime.c msgid "wrong number of values to unpack" -msgstr "" +msgstr "アンパックする値の個数が不正です" #: extmod/ulab/code/ndarray.c msgid "wrong operand type" @@ -3377,15 +3372,15 @@ msgstr "" #: shared-bindings/displayio/Shape.c msgid "y should be an int" -msgstr "yは整数でなければなりません" +msgstr "yは整数が必要" #: shared-module/displayio/Shape.c msgid "y value out of bounds" -msgstr "" +msgstr "yが範囲外" #: py/objrange.c msgid "zero step" -msgstr "" +msgstr "ステップが0" #: extmod/ulab/code/filter/filter.c msgid "zi must be an ndarray" @@ -3393,7 +3388,7 @@ msgstr "ziはndarrayでなければなりません" #: extmod/ulab/code/filter/filter.c msgid "zi must be of float type" -msgstr "ziはfloat値が必要です" +msgstr "ziはfloat値が必要" #: extmod/ulab/code/filter/filter.c msgid "zi must be of shape (n_section, 2)" From 00eb0b5a1a98517bb4cd602c745815e67ac782d7 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Tue, 1 Sep 2020 20:28:15 +0200 Subject: [PATCH 73/84] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/ID.po | 34 +++++++++++++++++++++++++++------- locale/cs.po | 34 +++++++++++++++++++++++++++------- locale/de_DE.po | 37 ++++++++++++++++++++++++++++++------- locale/es.po | 37 ++++++++++++++++++++++++++++++------- locale/fil.po | 34 +++++++++++++++++++++++++++------- locale/fr.po | 37 ++++++++++++++++++++++++++++++------- locale/hi.po | 34 +++++++++++++++++++++++++++------- locale/it_IT.po | 34 +++++++++++++++++++++++++++------- locale/ko.po | 34 +++++++++++++++++++++++++++------- locale/nl.po | 37 ++++++++++++++++++++++++++++++------- locale/pl.po | 34 +++++++++++++++++++++++++++------- locale/pt_BR.po | 37 ++++++++++++++++++++++++++++++------- locale/sv.po | 37 ++++++++++++++++++++++++++++++------- locale/zh_Latn_pinyin.po | 34 +++++++++++++++++++++++++++------- 14 files changed, 396 insertions(+), 98 deletions(-) diff --git a/locale/ID.po b/locale/ID.po index 6b2ef5f266..dd41b740f1 100644 --- a/locale/ID.po +++ b/locale/ID.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-27 11:21-0400\n" +"POT-Creation-Date: 2020-08-30 14:38-0400\n" "PO-Revision-Date: 2020-07-06 18:10+0000\n" "Last-Translator: oon arfiandwi \n" "Language-Team: LANGUAGE \n" @@ -498,6 +498,10 @@ msgstr "Panggil super().__init__() sebelum mengakses objek asli." msgid "Can't set CCCD on local Characteristic" msgstr "Tidak dapat mengatur CCCD pada Karakteristik lokal" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot create a new Adapter; use _bleio.adapter;" +msgstr "" + #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c @@ -762,8 +766,8 @@ msgstr "Channel EXTINT sedang digunakan" msgid "Error in regex" msgstr "Error pada regex" -#: shared-bindings/aesio/aes.c shared-bindings/busio/SPI.c -#: shared-bindings/microcontroller/Pin.c +#: shared-bindings/_bleio/__init__.c shared-bindings/aesio/aes.c +#: shared-bindings/busio/SPI.c shared-bindings/microcontroller/Pin.c #: shared-bindings/neopixel_write/__init__.c #: shared-bindings/terminalio/Terminal.c msgid "Expected a %q" @@ -774,10 +778,18 @@ msgstr "Diharapkan %q" msgid "Expected a Characteristic" msgstr "Diharapkan sebuah Karakteristik" +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a DigitalInOut" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c msgid "Expected a Service" msgstr "Diharapkan sebuah Layanan" +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a UART" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c #: shared-bindings/_bleio/Service.c msgid "Expected a UUID" @@ -1267,6 +1279,10 @@ msgstr "" msgid "Not running saved code.\n" msgstr "" +#: shared-bindings/_bleio/__init__.c +msgid "Not settable" +msgstr "" + #: shared-bindings/util.c msgid "" "Object has been deinitialized and can no longer be used. Create a new object." @@ -1375,10 +1391,6 @@ msgstr "" msgid "Pull not used when direction is output." msgstr "" -#: ports/stm/ref/pulseout-pre-timeralloc.c -msgid "PulseOut not supported on this chip" -msgstr "" - #: ports/stm/common-hal/os/__init__.c msgid "RNG DeInit Error" msgstr "" @@ -2488,6 +2500,10 @@ msgstr "" msgid "initial values must be iterable" msgstr "" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "initial_value length is wrong" +msgstr "" + #: py/compile.c msgid "inline assembler must be a function" msgstr "inline assembler harus sebuah fungsi" @@ -2680,6 +2696,10 @@ msgstr "" msgid "max_length must be 0-%d when fixed_length is %s" msgstr "" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "max_length must be > 0" +msgstr "" + #: py/runtime.c msgid "maximum recursion depth exceeded" msgstr "" diff --git a/locale/cs.po b/locale/cs.po index 4d13478eb1..cd81c258fe 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-27 11:21-0400\n" +"POT-Creation-Date: 2020-08-30 14:38-0400\n" "PO-Revision-Date: 2020-05-24 03:22+0000\n" "Last-Translator: dronecz \n" "Language-Team: LANGUAGE \n" @@ -496,6 +496,10 @@ msgstr "" msgid "Can't set CCCD on local Characteristic" msgstr "" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot create a new Adapter; use _bleio.adapter;" +msgstr "" + #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c @@ -748,8 +752,8 @@ msgstr "" msgid "Error in regex" msgstr "" -#: shared-bindings/aesio/aes.c shared-bindings/busio/SPI.c -#: shared-bindings/microcontroller/Pin.c +#: shared-bindings/_bleio/__init__.c shared-bindings/aesio/aes.c +#: shared-bindings/busio/SPI.c shared-bindings/microcontroller/Pin.c #: shared-bindings/neopixel_write/__init__.c #: shared-bindings/terminalio/Terminal.c msgid "Expected a %q" @@ -760,10 +764,18 @@ msgstr "" msgid "Expected a Characteristic" msgstr "" +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a DigitalInOut" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c msgid "Expected a Service" msgstr "" +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a UART" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c #: shared-bindings/_bleio/Service.c msgid "Expected a UUID" @@ -1249,6 +1261,10 @@ msgstr "" msgid "Not running saved code.\n" msgstr "" +#: shared-bindings/_bleio/__init__.c +msgid "Not settable" +msgstr "" + #: shared-bindings/util.c msgid "" "Object has been deinitialized and can no longer be used. Create a new object." @@ -1355,10 +1371,6 @@ msgstr "" msgid "Pull not used when direction is output." msgstr "" -#: ports/stm/ref/pulseout-pre-timeralloc.c -msgid "PulseOut not supported on this chip" -msgstr "" - #: ports/stm/common-hal/os/__init__.c msgid "RNG DeInit Error" msgstr "" @@ -2459,6 +2471,10 @@ msgstr "" msgid "initial values must be iterable" msgstr "" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "initial_value length is wrong" +msgstr "" + #: py/compile.c msgid "inline assembler must be a function" msgstr "" @@ -2651,6 +2667,10 @@ msgstr "" msgid "max_length must be 0-%d when fixed_length is %s" msgstr "" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "max_length must be > 0" +msgstr "" + #: py/runtime.c msgid "maximum recursion depth exceeded" msgstr "" diff --git a/locale/de_DE.po b/locale/de_DE.po index 6be135ebdf..3debbcb621 100644 --- a/locale/de_DE.po +++ b/locale/de_DE.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-27 11:21-0400\n" +"POT-Creation-Date: 2020-08-30 14:38-0400\n" "PO-Revision-Date: 2020-06-16 18:24+0000\n" "Last-Translator: Andreas Buchen \n" "Language: de_DE\n" @@ -499,6 +499,10 @@ msgstr "Rufe super().__init__() vor dem Zugriff auf ein natives Objekt auf." msgid "Can't set CCCD on local Characteristic" msgstr "CCCD kann nicht auf lokales Merkmal eingestellt werden" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot create a new Adapter; use _bleio.adapter;" +msgstr "" + #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c @@ -758,8 +762,8 @@ msgstr "EXTINT Kanal ist schon in Benutzung" msgid "Error in regex" msgstr "Fehler in regex" -#: shared-bindings/aesio/aes.c shared-bindings/busio/SPI.c -#: shared-bindings/microcontroller/Pin.c +#: shared-bindings/_bleio/__init__.c shared-bindings/aesio/aes.c +#: shared-bindings/busio/SPI.c shared-bindings/microcontroller/Pin.c #: shared-bindings/neopixel_write/__init__.c #: shared-bindings/terminalio/Terminal.c msgid "Expected a %q" @@ -770,10 +774,18 @@ msgstr "Erwartet ein(e) %q" msgid "Expected a Characteristic" msgstr "Characteristic wird erwartet" +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a DigitalInOut" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c msgid "Expected a Service" msgstr "Ein Service wird erwartet" +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a UART" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c #: shared-bindings/_bleio/Service.c msgid "Expected a UUID" @@ -1268,6 +1280,10 @@ msgstr "Spielt nicht ab" msgid "Not running saved code.\n" msgstr "" +#: shared-bindings/_bleio/__init__.c +msgid "Not settable" +msgstr "" + #: shared-bindings/util.c msgid "" "Object has been deinitialized and can no longer be used. Create a new object." @@ -1385,10 +1401,6 @@ msgstr "" msgid "Pull not used when direction is output." msgstr "Pull wird nicht verwendet, wenn die Richtung output ist." -#: ports/stm/ref/pulseout-pre-timeralloc.c -msgid "PulseOut not supported on this chip" -msgstr "PulseOut wird auf diesem Chip nicht unterstützt" - #: ports/stm/common-hal/os/__init__.c msgid "RNG DeInit Error" msgstr "RNG DeInit-Fehler" @@ -2530,6 +2542,10 @@ msgstr "Indizes müssen Integer, Slices oder Boolesche Listen sein" msgid "initial values must be iterable" msgstr "" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "initial_value length is wrong" +msgstr "" + #: py/compile.c msgid "inline assembler must be a function" msgstr "inline assembler muss eine function sein" @@ -2728,6 +2744,10 @@ msgstr "Matrix ist nicht positiv definitiv" msgid "max_length must be 0-%d when fixed_length is %s" msgstr "max_length muss 0-%d sein, wenn fixed_length %s ist" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "max_length must be > 0" +msgstr "" + #: py/runtime.c msgid "maximum recursion depth exceeded" msgstr "maximale Rekursionstiefe überschritten" @@ -3458,6 +3478,9 @@ msgstr "" msgid "zi must be of shape (n_section, 2)" msgstr "" +#~ msgid "PulseOut not supported on this chip" +#~ msgstr "PulseOut wird auf diesem Chip nicht unterstützt" + #~ msgid "tuple/list required on RHS" #~ msgstr "Tupel / Liste auf RHS erforderlich" diff --git a/locale/es.po b/locale/es.po index 2820d01a82..15b4fe7806 100644 --- a/locale/es.po +++ b/locale/es.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-27 11:21-0400\n" +"POT-Creation-Date: 2020-08-30 14:38-0400\n" "PO-Revision-Date: 2020-08-17 21:11+0000\n" "Last-Translator: Alvaro Figueroa \n" "Language-Team: \n" @@ -505,6 +505,10 @@ msgstr "Llame a super().__ init __() antes de acceder al objeto nativo." msgid "Can't set CCCD on local Characteristic" msgstr "No se puede configurar CCCD en la característica local" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot create a new Adapter; use _bleio.adapter;" +msgstr "" + #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c @@ -763,8 +767,8 @@ msgstr "El canal EXTINT ya está siendo utilizado" msgid "Error in regex" msgstr "Error en regex" -#: shared-bindings/aesio/aes.c shared-bindings/busio/SPI.c -#: shared-bindings/microcontroller/Pin.c +#: shared-bindings/_bleio/__init__.c shared-bindings/aesio/aes.c +#: shared-bindings/busio/SPI.c shared-bindings/microcontroller/Pin.c #: shared-bindings/neopixel_write/__init__.c #: shared-bindings/terminalio/Terminal.c msgid "Expected a %q" @@ -775,10 +779,18 @@ msgstr "Se espera un %q" msgid "Expected a Characteristic" msgstr "Se esperaba una Característica" +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a DigitalInOut" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c msgid "Expected a Service" msgstr "Se esperaba un servicio" +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a UART" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c #: shared-bindings/_bleio/Service.c msgid "Expected a UUID" @@ -1267,6 +1279,10 @@ msgstr "No reproduciendo" msgid "Not running saved code.\n" msgstr "No ejecutando el código almacenado.\n" +#: shared-bindings/_bleio/__init__.c +msgid "Not settable" +msgstr "" + #: shared-bindings/util.c msgid "" "Object has been deinitialized and can no longer be used. Create a new object." @@ -1384,10 +1400,6 @@ msgstr "" msgid "Pull not used when direction is output." msgstr "Pull no se usa cuando la dirección es output." -#: ports/stm/ref/pulseout-pre-timeralloc.c -msgid "PulseOut not supported on this chip" -msgstr "PulseOut no es compatible con este chip" - #: ports/stm/common-hal/os/__init__.c msgid "RNG DeInit Error" msgstr "Error de desinicializado del RNG" @@ -2520,6 +2532,10 @@ msgstr "los índices deben ser enteros, particiones o listas de booleanos" msgid "initial values must be iterable" msgstr "los valores iniciales deben permitir iteración" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "initial_value length is wrong" +msgstr "" + #: py/compile.c msgid "inline assembler must be a function" msgstr "ensamblador en línea debe ser una función" @@ -2715,6 +2731,10 @@ msgstr "matrix no es definida positiva" msgid "max_length must be 0-%d when fixed_length is %s" msgstr "max_length debe ser 0-%d cuando fixed_length es %s" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "max_length must be > 0" +msgstr "" + #: py/runtime.c msgid "maximum recursion depth exceeded" msgstr "profundidad máxima de recursión excedida" @@ -3440,6 +3460,9 @@ msgstr "zi debe ser de tipo flotante" msgid "zi must be of shape (n_section, 2)" msgstr "zi debe ser una forma (n_section,2)" +#~ msgid "PulseOut not supported on this chip" +#~ msgstr "PulseOut no es compatible con este chip" + #~ msgid "tuple/list required on RHS" #~ msgstr "tuple/lista se require en RHS" diff --git a/locale/fil.po b/locale/fil.po index 60be99da76..5bb696c83b 100644 --- a/locale/fil.po +++ b/locale/fil.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-27 11:21-0400\n" +"POT-Creation-Date: 2020-08-30 14:38-0400\n" "PO-Revision-Date: 2018-12-20 22:15-0800\n" "Last-Translator: Timothy \n" "Language-Team: fil\n" @@ -495,6 +495,10 @@ msgstr "" msgid "Can't set CCCD on local Characteristic" msgstr "" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot create a new Adapter; use _bleio.adapter;" +msgstr "" + #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c @@ -752,8 +756,8 @@ msgstr "Ginagamit na ang EXTINT channel" msgid "Error in regex" msgstr "May pagkakamali sa REGEX" -#: shared-bindings/aesio/aes.c shared-bindings/busio/SPI.c -#: shared-bindings/microcontroller/Pin.c +#: shared-bindings/_bleio/__init__.c shared-bindings/aesio/aes.c +#: shared-bindings/busio/SPI.c shared-bindings/microcontroller/Pin.c #: shared-bindings/neopixel_write/__init__.c #: shared-bindings/terminalio/Terminal.c msgid "Expected a %q" @@ -765,10 +769,18 @@ msgstr "Umasa ng %q" msgid "Expected a Characteristic" msgstr "Hindi mabasa and Characteristic." +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a DigitalInOut" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c msgid "Expected a Service" msgstr "" +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a UART" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c #: shared-bindings/_bleio/Service.c #, fuzzy @@ -1258,6 +1270,10 @@ msgstr "Hindi playing" msgid "Not running saved code.\n" msgstr "" +#: shared-bindings/_bleio/__init__.c +msgid "Not settable" +msgstr "" + #: shared-bindings/util.c msgid "" "Object has been deinitialized and can no longer be used. Create a new object." @@ -1369,10 +1385,6 @@ msgstr "" msgid "Pull not used when direction is output." msgstr "Pull hindi ginagamit kapag ang direksyon ay output." -#: ports/stm/ref/pulseout-pre-timeralloc.c -msgid "PulseOut not supported on this chip" -msgstr "" - #: ports/stm/common-hal/os/__init__.c msgid "RNG DeInit Error" msgstr "" @@ -2497,6 +2509,10 @@ msgstr "" msgid "initial values must be iterable" msgstr "" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "initial_value length is wrong" +msgstr "" + #: py/compile.c msgid "inline assembler must be a function" msgstr "inline assembler ay dapat na function" @@ -2693,6 +2709,10 @@ msgstr "" msgid "max_length must be 0-%d when fixed_length is %s" msgstr "" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "max_length must be > 0" +msgstr "" + #: py/runtime.c msgid "maximum recursion depth exceeded" msgstr "lumagpas ang maximum recursion depth" diff --git a/locale/fr.po b/locale/fr.po index 043fe6cf23..3ab4858020 100644 --- a/locale/fr.po +++ b/locale/fr.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-27 11:21-0400\n" +"POT-Creation-Date: 2020-08-30 14:38-0400\n" "PO-Revision-Date: 2020-07-27 21:27+0000\n" "Last-Translator: Nathan \n" "Language: fr\n" @@ -505,6 +505,10 @@ msgstr "Appelez super () .__ init __ () avant d'accéder à l'objet natif." msgid "Can't set CCCD on local Characteristic" msgstr "Impossible de définir CCCD sur une caractéristique locale" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot create a new Adapter; use _bleio.adapter;" +msgstr "" + #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c @@ -766,8 +770,8 @@ msgstr "Canal EXTINT déjà utilisé" msgid "Error in regex" msgstr "Erreur dans l'expression régulière" -#: shared-bindings/aesio/aes.c shared-bindings/busio/SPI.c -#: shared-bindings/microcontroller/Pin.c +#: shared-bindings/_bleio/__init__.c shared-bindings/aesio/aes.c +#: shared-bindings/busio/SPI.c shared-bindings/microcontroller/Pin.c #: shared-bindings/neopixel_write/__init__.c #: shared-bindings/terminalio/Terminal.c msgid "Expected a %q" @@ -778,10 +782,18 @@ msgstr "Attendu un %q" msgid "Expected a Characteristic" msgstr "Une 'Characteristic' est attendue" +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a DigitalInOut" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c msgid "Expected a Service" msgstr "Attendu un service" +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a UART" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c #: shared-bindings/_bleio/Service.c msgid "Expected a UUID" @@ -1271,6 +1283,10 @@ msgstr "Ne joue pas" msgid "Not running saved code.\n" msgstr "" +#: shared-bindings/_bleio/__init__.c +msgid "Not settable" +msgstr "" + #: shared-bindings/util.c msgid "" "Object has been deinitialized and can no longer be used. Create a new object." @@ -1390,10 +1406,6 @@ msgstr "Appuyez sur une touche pour entrer sur REPL ou CTRL-D pour recharger." msgid "Pull not used when direction is output." msgstr "Le tirage 'pull' n'est pas utilisé quand la direction est 'output'." -#: ports/stm/ref/pulseout-pre-timeralloc.c -msgid "PulseOut not supported on this chip" -msgstr "PulseOut non pris en charge sur cette puce" - #: ports/stm/common-hal/os/__init__.c msgid "RNG DeInit Error" msgstr "Erreur RNG DeInit" @@ -2538,6 +2550,10 @@ msgstr "" msgid "initial values must be iterable" msgstr "les valeurs initiales doivent être itérables" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "initial_value length is wrong" +msgstr "" + #: py/compile.c msgid "inline assembler must be a function" msgstr "l'assembleur doit être une fonction" @@ -2734,6 +2750,10 @@ msgstr "la matrice n'est pas définie positive" msgid "max_length must be 0-%d when fixed_length is %s" msgstr "max_length doit être 0-%d lorsque fixed_length est %s" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "max_length must be > 0" +msgstr "" + #: py/runtime.c msgid "maximum recursion depth exceeded" msgstr "profondeur maximale de récursivité dépassée" @@ -3461,6 +3481,9 @@ msgstr "" msgid "zi must be of shape (n_section, 2)" msgstr "" +#~ msgid "PulseOut not supported on this chip" +#~ msgstr "PulseOut non pris en charge sur cette puce" + #~ msgid "tuple/list required on RHS" #~ msgstr "tuple ou liste requis en partie droite" diff --git a/locale/hi.po b/locale/hi.po index 717d21a275..3803348aa4 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-27 11:21-0400\n" +"POT-Creation-Date: 2020-08-30 14:38-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" @@ -489,6 +489,10 @@ msgstr "" msgid "Can't set CCCD on local Characteristic" msgstr "" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot create a new Adapter; use _bleio.adapter;" +msgstr "" + #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c @@ -741,8 +745,8 @@ msgstr "" msgid "Error in regex" msgstr "" -#: shared-bindings/aesio/aes.c shared-bindings/busio/SPI.c -#: shared-bindings/microcontroller/Pin.c +#: shared-bindings/_bleio/__init__.c shared-bindings/aesio/aes.c +#: shared-bindings/busio/SPI.c shared-bindings/microcontroller/Pin.c #: shared-bindings/neopixel_write/__init__.c #: shared-bindings/terminalio/Terminal.c msgid "Expected a %q" @@ -753,10 +757,18 @@ msgstr "" msgid "Expected a Characteristic" msgstr "" +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a DigitalInOut" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c msgid "Expected a Service" msgstr "" +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a UART" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c #: shared-bindings/_bleio/Service.c msgid "Expected a UUID" @@ -1242,6 +1254,10 @@ msgstr "" msgid "Not running saved code.\n" msgstr "" +#: shared-bindings/_bleio/__init__.c +msgid "Not settable" +msgstr "" + #: shared-bindings/util.c msgid "" "Object has been deinitialized and can no longer be used. Create a new object." @@ -1348,10 +1364,6 @@ msgstr "" msgid "Pull not used when direction is output." msgstr "" -#: ports/stm/ref/pulseout-pre-timeralloc.c -msgid "PulseOut not supported on this chip" -msgstr "" - #: ports/stm/common-hal/os/__init__.c msgid "RNG DeInit Error" msgstr "" @@ -2452,6 +2464,10 @@ msgstr "" msgid "initial values must be iterable" msgstr "" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "initial_value length is wrong" +msgstr "" + #: py/compile.c msgid "inline assembler must be a function" msgstr "" @@ -2644,6 +2660,10 @@ msgstr "" msgid "max_length must be 0-%d when fixed_length is %s" msgstr "" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "max_length must be > 0" +msgstr "" + #: py/runtime.c msgid "maximum recursion depth exceeded" msgstr "" diff --git a/locale/it_IT.po b/locale/it_IT.po index c4214a1500..e9dfc0474d 100644 --- a/locale/it_IT.po +++ b/locale/it_IT.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-27 11:21-0400\n" +"POT-Creation-Date: 2020-08-30 14:38-0400\n" "PO-Revision-Date: 2018-10-02 16:27+0200\n" "Last-Translator: Enrico Paganin \n" "Language-Team: \n" @@ -495,6 +495,10 @@ msgstr "" msgid "Can't set CCCD on local Characteristic" msgstr "" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot create a new Adapter; use _bleio.adapter;" +msgstr "" + #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c @@ -752,8 +756,8 @@ msgstr "Canale EXTINT già in uso" msgid "Error in regex" msgstr "Errore nella regex" -#: shared-bindings/aesio/aes.c shared-bindings/busio/SPI.c -#: shared-bindings/microcontroller/Pin.c +#: shared-bindings/_bleio/__init__.c shared-bindings/aesio/aes.c +#: shared-bindings/busio/SPI.c shared-bindings/microcontroller/Pin.c #: shared-bindings/neopixel_write/__init__.c #: shared-bindings/terminalio/Terminal.c msgid "Expected a %q" @@ -765,10 +769,18 @@ msgstr "Atteso un %q" msgid "Expected a Characteristic" msgstr "Non è possibile aggiungere Characteristic." +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a DigitalInOut" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c msgid "Expected a Service" msgstr "" +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a UART" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c #: shared-bindings/_bleio/Service.c #, fuzzy @@ -1262,6 +1274,10 @@ msgstr "In pausa" msgid "Not running saved code.\n" msgstr "" +#: shared-bindings/_bleio/__init__.c +msgid "Not settable" +msgstr "" + #: shared-bindings/util.c msgid "" "Object has been deinitialized and can no longer be used. Create a new object." @@ -1378,10 +1394,6 @@ msgstr "" msgid "Pull not used when direction is output." msgstr "" -#: ports/stm/ref/pulseout-pre-timeralloc.c -msgid "PulseOut not supported on this chip" -msgstr "" - #: ports/stm/common-hal/os/__init__.c msgid "RNG DeInit Error" msgstr "" @@ -2498,6 +2510,10 @@ msgstr "" msgid "initial values must be iterable" msgstr "" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "initial_value length is wrong" +msgstr "" + #: py/compile.c msgid "inline assembler must be a function" msgstr "inline assembler deve essere una funzione" @@ -2695,6 +2711,10 @@ msgstr "" msgid "max_length must be 0-%d when fixed_length is %s" msgstr "" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "max_length must be > 0" +msgstr "" + #: py/runtime.c msgid "maximum recursion depth exceeded" msgstr "profondità massima di ricorsione superata" diff --git a/locale/ko.po b/locale/ko.po index 2404c561d0..a4e088bc40 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-27 11:21-0400\n" +"POT-Creation-Date: 2020-08-30 14:38-0400\n" "PO-Revision-Date: 2019-05-06 14:22-0700\n" "Last-Translator: \n" "Language-Team: LANGUAGE \n" @@ -492,6 +492,10 @@ msgstr "" msgid "Can't set CCCD on local Characteristic" msgstr "" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot create a new Adapter; use _bleio.adapter;" +msgstr "" + #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c @@ -744,8 +748,8 @@ msgstr "" msgid "Error in regex" msgstr "Regex에 오류가 있습니다." -#: shared-bindings/aesio/aes.c shared-bindings/busio/SPI.c -#: shared-bindings/microcontroller/Pin.c +#: shared-bindings/_bleio/__init__.c shared-bindings/aesio/aes.c +#: shared-bindings/busio/SPI.c shared-bindings/microcontroller/Pin.c #: shared-bindings/neopixel_write/__init__.c #: shared-bindings/terminalio/Terminal.c msgid "Expected a %q" @@ -756,10 +760,18 @@ msgstr "%q 이 예상되었습니다." msgid "Expected a Characteristic" msgstr "특성(Characteristic)이 예상되었습니다." +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a DigitalInOut" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c msgid "Expected a Service" msgstr "" +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a UART" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c #: shared-bindings/_bleio/Service.c msgid "Expected a UUID" @@ -1245,6 +1257,10 @@ msgstr "" msgid "Not running saved code.\n" msgstr "" +#: shared-bindings/_bleio/__init__.c +msgid "Not settable" +msgstr "" + #: shared-bindings/util.c msgid "" "Object has been deinitialized and can no longer be used. Create a new object." @@ -1351,10 +1367,6 @@ msgstr "" msgid "Pull not used when direction is output." msgstr "" -#: ports/stm/ref/pulseout-pre-timeralloc.c -msgid "PulseOut not supported on this chip" -msgstr "" - #: ports/stm/common-hal/os/__init__.c msgid "RNG DeInit Error" msgstr "" @@ -2456,6 +2468,10 @@ msgstr "" msgid "initial values must be iterable" msgstr "" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "initial_value length is wrong" +msgstr "" + #: py/compile.c msgid "inline assembler must be a function" msgstr "" @@ -2648,6 +2664,10 @@ msgstr "" msgid "max_length must be 0-%d when fixed_length is %s" msgstr "" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "max_length must be > 0" +msgstr "" + #: py/runtime.c msgid "maximum recursion depth exceeded" msgstr "" diff --git a/locale/nl.po b/locale/nl.po index 87133a4606..9cce2523ed 100644 --- a/locale/nl.po +++ b/locale/nl.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-27 11:21-0400\n" +"POT-Creation-Date: 2020-08-30 14:38-0400\n" "PO-Revision-Date: 2020-08-10 19:59+0000\n" "Last-Translator: _fonzlate \n" "Language-Team: none\n" @@ -500,6 +500,10 @@ msgstr "Roep super().__init__() aan voor toegang native object." msgid "Can't set CCCD on local Characteristic" msgstr "Kan CCCD niet toewijzen aan lokaal Characteristic" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot create a new Adapter; use _bleio.adapter;" +msgstr "" + #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c @@ -760,8 +764,8 @@ msgstr "EXTINT kanaal al in gebruik" msgid "Error in regex" msgstr "Fout in regex" -#: shared-bindings/aesio/aes.c shared-bindings/busio/SPI.c -#: shared-bindings/microcontroller/Pin.c +#: shared-bindings/_bleio/__init__.c shared-bindings/aesio/aes.c +#: shared-bindings/busio/SPI.c shared-bindings/microcontroller/Pin.c #: shared-bindings/neopixel_write/__init__.c #: shared-bindings/terminalio/Terminal.c msgid "Expected a %q" @@ -772,10 +776,18 @@ msgstr "Verwacht een %q" msgid "Expected a Characteristic" msgstr "Verwachtte een Characteristic" +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a DigitalInOut" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c msgid "Expected a Service" msgstr "Verwachtte een Service" +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a UART" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c #: shared-bindings/_bleio/Service.c msgid "Expected a UUID" @@ -1267,6 +1279,10 @@ msgstr "Wordt niet afgespeeld" msgid "Not running saved code.\n" msgstr "Opgeslagen code wordt niet uitgevoerd.\n" +#: shared-bindings/_bleio/__init__.c +msgid "Not settable" +msgstr "" + #: shared-bindings/util.c msgid "" "Object has been deinitialized and can no longer be used. Create a new object." @@ -1387,10 +1403,6 @@ msgstr "" msgid "Pull not used when direction is output." msgstr "Pull niet gebruikt wanneer de richting output is." -#: ports/stm/ref/pulseout-pre-timeralloc.c -msgid "PulseOut not supported on this chip" -msgstr "PulseOut niet ondersteund door deze chip" - #: ports/stm/common-hal/os/__init__.c msgid "RNG DeInit Error" msgstr "RNG DeInit Fout" @@ -2518,6 +2530,10 @@ msgstr "indices moeten integers, segmenten (slices) of Boolean lijsten zijn" msgid "initial values must be iterable" msgstr "oorspronkelijke waarden moeten itereerbaar zijn" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "initial_value length is wrong" +msgstr "" + #: py/compile.c msgid "inline assembler must be a function" msgstr "inline assembler moet een functie zijn" @@ -2713,6 +2729,10 @@ msgstr "matrix is niet positief-definiet" msgid "max_length must be 0-%d when fixed_length is %s" msgstr "max_length moet 0-%d zijn als fixed_length %s is" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "max_length must be > 0" +msgstr "" + #: py/runtime.c msgid "maximum recursion depth exceeded" msgstr "maximale recursiediepte overschreden" @@ -3435,6 +3455,9 @@ msgstr "zi moet van type float zijn" msgid "zi must be of shape (n_section, 2)" msgstr "zi moet vorm (n_section, 2) hebben" +#~ msgid "PulseOut not supported on this chip" +#~ msgstr "PulseOut niet ondersteund door deze chip" + #~ msgid "tuple/list required on RHS" #~ msgstr "tuple of lijst vereist op RHS" diff --git a/locale/pl.po b/locale/pl.po index 610da7bfc0..b072629cd1 100644 --- a/locale/pl.po +++ b/locale/pl.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-27 11:21-0400\n" +"POT-Creation-Date: 2020-08-30 14:38-0400\n" "PO-Revision-Date: 2019-03-19 18:37-0700\n" "Last-Translator: Radomir Dopieralski \n" "Language-Team: pl\n" @@ -492,6 +492,10 @@ msgstr "" msgid "Can't set CCCD on local Characteristic" msgstr "" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot create a new Adapter; use _bleio.adapter;" +msgstr "" + #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c @@ -744,8 +748,8 @@ msgstr "Kanał EXTINT w użyciu" msgid "Error in regex" msgstr "Błąd w regex" -#: shared-bindings/aesio/aes.c shared-bindings/busio/SPI.c -#: shared-bindings/microcontroller/Pin.c +#: shared-bindings/_bleio/__init__.c shared-bindings/aesio/aes.c +#: shared-bindings/busio/SPI.c shared-bindings/microcontroller/Pin.c #: shared-bindings/neopixel_write/__init__.c #: shared-bindings/terminalio/Terminal.c msgid "Expected a %q" @@ -756,10 +760,18 @@ msgstr "Oczekiwano %q" msgid "Expected a Characteristic" msgstr "Oczekiwano charakterystyki" +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a DigitalInOut" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c msgid "Expected a Service" msgstr "" +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a UART" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c #: shared-bindings/_bleio/Service.c msgid "Expected a UUID" @@ -1247,6 +1259,10 @@ msgstr "Nic nie jest odtwarzane" msgid "Not running saved code.\n" msgstr "" +#: shared-bindings/_bleio/__init__.c +msgid "Not settable" +msgstr "" + #: shared-bindings/util.c msgid "" "Object has been deinitialized and can no longer be used. Create a new object." @@ -1353,10 +1369,6 @@ msgstr "Dowolny klawisz aby uruchomić konsolę. CTRL-D aby przeładować." msgid "Pull not used when direction is output." msgstr "Podciągnięcie nieużywane w trybie wyjścia." -#: ports/stm/ref/pulseout-pre-timeralloc.c -msgid "PulseOut not supported on this chip" -msgstr "" - #: ports/stm/common-hal/os/__init__.c msgid "RNG DeInit Error" msgstr "" @@ -2461,6 +2473,10 @@ msgstr "" msgid "initial values must be iterable" msgstr "" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "initial_value length is wrong" +msgstr "" + #: py/compile.c msgid "inline assembler must be a function" msgstr "wtrącony asembler musi być funkcją" @@ -2653,6 +2669,10 @@ msgstr "" msgid "max_length must be 0-%d when fixed_length is %s" msgstr "" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "max_length must be > 0" +msgstr "" + #: py/runtime.c msgid "maximum recursion depth exceeded" msgstr "przekroczono dozwoloną głębokość rekurencji" diff --git a/locale/pt_BR.po b/locale/pt_BR.po index b0233b5dbc..e407756d07 100644 --- a/locale/pt_BR.po +++ b/locale/pt_BR.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-27 11:21-0400\n" +"POT-Creation-Date: 2020-08-30 14:38-0400\n" "PO-Revision-Date: 2020-08-31 00:37+0000\n" "Last-Translator: Wellington Terumi Uemura \n" "Language-Team: \n" @@ -506,6 +506,10 @@ msgstr "Chame super().__init__() antes de acessar o objeto nativo." msgid "Can't set CCCD on local Characteristic" msgstr "Não é possível definir o CCCD com a característica local" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot create a new Adapter; use _bleio.adapter;" +msgstr "" + #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c @@ -765,8 +769,8 @@ msgstr "Canal EXTINT em uso" msgid "Error in regex" msgstr "Erro no regex" -#: shared-bindings/aesio/aes.c shared-bindings/busio/SPI.c -#: shared-bindings/microcontroller/Pin.c +#: shared-bindings/_bleio/__init__.c shared-bindings/aesio/aes.c +#: shared-bindings/busio/SPI.c shared-bindings/microcontroller/Pin.c #: shared-bindings/neopixel_write/__init__.c #: shared-bindings/terminalio/Terminal.c msgid "Expected a %q" @@ -777,10 +781,18 @@ msgstr "Esperado um" msgid "Expected a Characteristic" msgstr "Uma característica é necessária" +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a DigitalInOut" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c msgid "Expected a Service" msgstr "Esperava um Serviço" +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a UART" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c #: shared-bindings/_bleio/Service.c msgid "Expected a UUID" @@ -1270,6 +1282,10 @@ msgstr "Não está jogando" msgid "Not running saved code.\n" msgstr "O código salvo não está em execução.\n" +#: shared-bindings/_bleio/__init__.c +msgid "Not settable" +msgstr "" + #: shared-bindings/util.c msgid "" "Object has been deinitialized and can no longer be used. Create a new object." @@ -1393,10 +1409,6 @@ msgstr "" msgid "Pull not used when direction is output." msgstr "O Pull não foi usado quando a direção for gerada." -#: ports/stm/ref/pulseout-pre-timeralloc.c -msgid "PulseOut not supported on this chip" -msgstr "O PulseOut não é compatível neste CI" - #: ports/stm/common-hal/os/__init__.c msgid "RNG DeInit Error" msgstr "Erro DeInit RNG" @@ -2533,6 +2545,10 @@ msgstr "os índices devem ser números inteiros, fatias ou listas booleanas" msgid "initial values must be iterable" msgstr "os valores iniciais devem ser iteráveis" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "initial_value length is wrong" +msgstr "" + #: py/compile.c msgid "inline assembler must be a function" msgstr "o assembler em linha deve ser uma função" @@ -2728,6 +2744,10 @@ msgstr "a matriz não é definitiva positiva" msgid "max_length must be 0-%d when fixed_length is %s" msgstr "o max_length deve ser 0-%d quando Fixed_length for %s" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "max_length must be > 0" +msgstr "" + #: py/runtime.c msgid "maximum recursion depth exceeded" msgstr "a recursão máxima da profundidade foi excedida" @@ -3456,6 +3476,9 @@ msgstr "zi deve ser de um tipo float" msgid "zi must be of shape (n_section, 2)" msgstr "zi deve estar na forma (n_section, 2)" +#~ msgid "PulseOut not supported on this chip" +#~ msgstr "O PulseOut não é compatível neste CI" + #~ msgid "" #~ "Port does not accept pins or " #~ "frequency. Construct and pass a " diff --git a/locale/sv.po b/locale/sv.po index 9946917445..9b9a52dacf 100644 --- a/locale/sv.po +++ b/locale/sv.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-27 11:21-0400\n" +"POT-Creation-Date: 2020-08-30 14:38-0400\n" "PO-Revision-Date: 2020-08-30 20:02+0000\n" "Last-Translator: Jeff Epler \n" "Language-Team: LANGUAGE \n" @@ -498,6 +498,10 @@ msgstr "Anropa super().__init__() innan du använder det ursprungliga objektet." msgid "Can't set CCCD on local Characteristic" msgstr "Kan inte ställa in CCCD på lokal karaktäristik" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot create a new Adapter; use _bleio.adapter;" +msgstr "" + #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c @@ -756,8 +760,8 @@ msgstr "EXTINT-kanalen används redan" msgid "Error in regex" msgstr "Fel i regex" -#: shared-bindings/aesio/aes.c shared-bindings/busio/SPI.c -#: shared-bindings/microcontroller/Pin.c +#: shared-bindings/_bleio/__init__.c shared-bindings/aesio/aes.c +#: shared-bindings/busio/SPI.c shared-bindings/microcontroller/Pin.c #: shared-bindings/neopixel_write/__init__.c #: shared-bindings/terminalio/Terminal.c msgid "Expected a %q" @@ -768,10 +772,18 @@ msgstr "Förväntade %q" msgid "Expected a Characteristic" msgstr "Förväntade en karaktäristik" +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a DigitalInOut" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c msgid "Expected a Service" msgstr "Förväntade en tjänst" +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a UART" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c #: shared-bindings/_bleio/Service.c msgid "Expected a UUID" @@ -1260,6 +1272,10 @@ msgstr "Ingen uppspelning" msgid "Not running saved code.\n" msgstr "Kör inte sparad kod.\n" +#: shared-bindings/_bleio/__init__.c +msgid "Not settable" +msgstr "" + #: shared-bindings/util.c msgid "" "Object has been deinitialized and can no longer be used. Create a new object." @@ -1377,10 +1393,6 @@ msgstr "" msgid "Pull not used when direction is output." msgstr "Pull används inte när riktningen är output." -#: ports/stm/ref/pulseout-pre-timeralloc.c -msgid "PulseOut not supported on this chip" -msgstr "PulseIn stöds inte av detta chip" - #: ports/stm/common-hal/os/__init__.c msgid "RNG DeInit Error" msgstr "RNG DeInit-fel" @@ -2504,6 +2516,10 @@ msgstr "index måste vara heltal, slices, eller Boolean-listor" msgid "initial values must be iterable" msgstr "initialvärden måste vara iterable" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "initial_value length is wrong" +msgstr "" + #: py/compile.c msgid "inline assembler must be a function" msgstr "inline assembler måste vara en funktion" @@ -2699,6 +2715,10 @@ msgstr "matrisen är inte positiv bestämd" msgid "max_length must be 0-%d when fixed_length is %s" msgstr "max_length måste vara 0-%d när fixed_length är %s" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "max_length must be > 0" +msgstr "" + #: py/runtime.c msgid "maximum recursion depth exceeded" msgstr "maximal rekursionsdjup överskriden" @@ -3421,6 +3441,9 @@ msgstr "zi måste vara av typ float" msgid "zi must be of shape (n_section, 2)" msgstr "zi måste vara i formen (n_section, 2)" +#~ msgid "PulseOut not supported on this chip" +#~ msgstr "PulseIn stöds inte av detta chip" + #~ msgid "tuple/list required on RHS" #~ msgstr "tupel/lista krävs för RHS" diff --git a/locale/zh_Latn_pinyin.po b/locale/zh_Latn_pinyin.po index 290d4749ef..56f9bae8c1 100644 --- a/locale/zh_Latn_pinyin.po +++ b/locale/zh_Latn_pinyin.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: circuitpython-cn\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-27 11:21-0400\n" +"POT-Creation-Date: 2020-08-30 14:38-0400\n" "PO-Revision-Date: 2019-04-13 10:10-0700\n" "Last-Translator: hexthat\n" "Language-Team: Chinese Hanyu Pinyin\n" @@ -499,6 +499,10 @@ msgstr "Zài fǎngwèn běn jī wùjiàn zhīqián diàoyòng super().__init__() msgid "Can't set CCCD on local Characteristic" msgstr "Wúfǎ jiāng CCCD shèzhì wéi běndì tèzhēng" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot create a new Adapter; use _bleio.adapter;" +msgstr "" + #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c @@ -753,8 +757,8 @@ msgstr "EXTINT píndào yǐjīng shǐyòng" msgid "Error in regex" msgstr "Zhèngzé biǎodá shì cuòwù" -#: shared-bindings/aesio/aes.c shared-bindings/busio/SPI.c -#: shared-bindings/microcontroller/Pin.c +#: shared-bindings/_bleio/__init__.c shared-bindings/aesio/aes.c +#: shared-bindings/busio/SPI.c shared-bindings/microcontroller/Pin.c #: shared-bindings/neopixel_write/__init__.c #: shared-bindings/terminalio/Terminal.c msgid "Expected a %q" @@ -765,10 +769,18 @@ msgstr "Yùqí %q" msgid "Expected a Characteristic" msgstr "Yùqí de tèdiǎn" +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a DigitalInOut" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c msgid "Expected a Service" msgstr "Yùqí fúwù" +#: shared-bindings/_bleio/Adapter.c +msgid "Expected a UART" +msgstr "" + #: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c #: shared-bindings/_bleio/Service.c msgid "Expected a UUID" @@ -1256,6 +1268,10 @@ msgstr "Wèi bòfàng" msgid "Not running saved code.\n" msgstr "Méiyǒu yùnxíng yǐ bǎocún de dàimǎ.\n" +#: shared-bindings/_bleio/__init__.c +msgid "Not settable" +msgstr "" + #: shared-bindings/util.c msgid "" "Object has been deinitialized and can no longer be used. Create a new object." @@ -1371,10 +1387,6 @@ msgstr "Àn xià rènhé jiàn jìnrù REPL. Shǐyòng CTRL-D chóngxīn jiāzà msgid "Pull not used when direction is output." msgstr "Fāngxiàng shūchū shí Pull méiyǒu shǐyòng." -#: ports/stm/ref/pulseout-pre-timeralloc.c -msgid "PulseOut not supported on this chip" -msgstr "" - #: ports/stm/common-hal/os/__init__.c msgid "RNG DeInit Error" msgstr "RNG qǔxiāo chūshǐhuà cuòwù" @@ -2496,6 +2508,10 @@ msgstr "suǒyǐn bìxū shì zhěngshù, qiēpiàn huò bù'ěr zhí lièbiǎo" msgid "initial values must be iterable" msgstr "chūshǐ zhí bìxū shì kě diédài de" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "initial_value length is wrong" +msgstr "" + #: py/compile.c msgid "inline assembler must be a function" msgstr "nèi lián jíhé bìxū shì yīgè hánshù" @@ -2689,6 +2705,10 @@ msgstr "jǔzhèn bùshì zhèngdìng de" msgid "max_length must be 0-%d when fixed_length is %s" msgstr "Dāng gùdìng chángdù wèi %s shí, zuìdà chángdù bìxū wèi 0-%d" +#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c +msgid "max_length must be > 0" +msgstr "" + #: py/runtime.c msgid "maximum recursion depth exceeded" msgstr "chāochū zuìdà dìguī shēndù" From bb17882065034053444ff9cebe637c12285e5b95 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 1 Sep 2020 18:43:45 +0000 Subject: [PATCH 74/84] Translated using Weblate (Japanese) Currently translated at 68.7% (536 of 780 strings) Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ja/ --- locale/ja.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/locale/ja.po b/locale/ja.po index 789930cd00..b9fb7ce7a5 100644 --- a/locale/ja.po +++ b/locale/ja.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-08-27 11:21-0400\n" -"PO-Revision-Date: 2020-09-01 12:07+0000\n" -"Last-Translator: Taku Fukada \n" +"PO-Revision-Date: 2020-09-01 18:44+0000\n" +"Last-Translator: Jeff Epler \n" "Language-Team: none\n" "Language: ja\n" "MIME-Version: 1.0\n" @@ -2143,7 +2143,7 @@ msgstr "" #: shared-bindings/displayio/Palette.c msgid "color must be between 0x000000 and 0xffffff" -msgstr "色は0x000000から0xffffffでなければなりません" +msgstr "色は0x000000から0xffffffでなければなりません" #: shared-bindings/displayio/ColorConverter.c msgid "color should be an int" @@ -2739,7 +2739,7 @@ msgstr "" #: py/runtime.c #, c-format msgid "need more than %d values to unpack" -msgstr "アンパックする値は%d個では足りません" +msgstr "アンパックする値は%d個では足りません" #: py/objint_longlong.c py/objint_mpz.c py/runtime.c msgid "negative power with no float support" From e14de385283ad01b17e5abf51c5830db59a1a0f2 Mon Sep 17 00:00:00 2001 From: Kevin Matocha Date: Tue, 1 Sep 2020 13:57:19 -0500 Subject: [PATCH 75/84] Revise .refresh input default value for target_frames_per_second to None --- shared-bindings/displayio/Display.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index 9f3148dc76..b9e8d02b4b 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -215,7 +215,7 @@ STATIC mp_obj_t displayio_display_obj_show(mp_obj_t self_in, mp_obj_t group_in) } MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show); -//| def refresh(self, *, target_frames_per_second: int = 60, minimum_frames_per_second: int = 1) -> bool: +//| def refresh(self, *, target_frames_per_second: int = None, minimum_frames_per_second: int = 1) -> bool: //| """When auto refresh is off, waits for the target frame rate and then refreshes the display, //| returning True. If the call has taken too long since the last refresh call for the given //| target frame rate, then the refresh returns False immediately without updating the screen to @@ -231,13 +231,14 @@ MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show //| the display immediately. //| //| :param int target_frames_per_second: How many times a second `refresh` should be called and the screen updated. +//| Set to None for immediate refresh. //| :param int minimum_frames_per_second: The minimum number of times the screen should be updated per second.""" //| ... //| STATIC mp_obj_t displayio_display_obj_refresh(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_target_frames_per_second, ARG_minimum_frames_per_second }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_target_frames_per_second, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(60)} }, + { MP_QSTR_target_frames_per_second, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, { MP_QSTR_minimum_frames_per_second, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, }; @@ -252,8 +253,7 @@ STATIC mp_obj_t displayio_display_obj_refresh(size_t n_args, const mp_obj_t *pos } uint32_t target_ms_per_frame; - if ( (args[ARG_target_frames_per_second].u_obj == mp_const_none) || (n_args == 1) ) { - // if None or no arguments + if (args[ARG_target_frames_per_second].u_obj == mp_const_none) { target_ms_per_frame = 0xffffffff; } else { From f5015e4485e8885d1af2507f61229a09faa332f3 Mon Sep 17 00:00:00 2001 From: Kevin Matocha Date: Tue, 1 Sep 2020 14:36:43 -0500 Subject: [PATCH 76/84] Add hanging tab to doc --- shared-bindings/displayio/Display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index b9e8d02b4b..a11a17c558 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -231,7 +231,7 @@ MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show //| the display immediately. //| //| :param int target_frames_per_second: How many times a second `refresh` should be called and the screen updated. -//| Set to None for immediate refresh. +//| Set to None for immediate refresh. //| :param int minimum_frames_per_second: The minimum number of times the screen should be updated per second.""" //| ... //| From c6529daac576aa3492abef2073b7e597c3ffee5d Mon Sep 17 00:00:00 2001 From: Kevin Matocha Date: Tue, 1 Sep 2020 14:44:32 -0500 Subject: [PATCH 77/84] Added some backticks to clarify the docs --- shared-bindings/displayio/Display.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index a11a17c558..3df36d1bd3 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -227,11 +227,11 @@ MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show //| When auto refresh is on, updates the display immediately. (The display will also update //| without calls to this.) //| -//| When auto refresh is off, refresh() or refresh(target_frames_per_second=None) will update +//| When auto refresh is off, `refresh()` or `refresh(target_frames_per_second=None)` will update //| the display immediately. //| //| :param int target_frames_per_second: How many times a second `refresh` should be called and the screen updated. -//| Set to None for immediate refresh. +//| Set to `None` for immediate refresh. //| :param int minimum_frames_per_second: The minimum number of times the screen should be updated per second.""" //| ... //| From 649a955a74ec8206dfb53511e7a2e6a679968648 Mon Sep 17 00:00:00 2001 From: Kevin Matocha Date: Tue, 1 Sep 2020 15:02:37 -0500 Subject: [PATCH 78/84] Modified docs to try to pass sphinx build --- shared-bindings/displayio/Display.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index 3df36d1bd3..9b63e4fec7 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -230,8 +230,7 @@ MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show //| When auto refresh is off, `refresh()` or `refresh(target_frames_per_second=None)` will update //| the display immediately. //| -//| :param int target_frames_per_second: How many times a second `refresh` should be called and the screen updated. -//| Set to `None` for immediate refresh. +//| :param int target_frames_per_second: How many times a second `refresh` should be called and the screen updated. Set to `None` for immediate refresh. //| :param int minimum_frames_per_second: The minimum number of times the screen should be updated per second.""" //| ... //| From 7b6d805580a3da679bd14807c7646c5a8c830ef6 Mon Sep 17 00:00:00 2001 From: Kevin Matocha Date: Tue, 1 Sep 2020 15:40:55 -0500 Subject: [PATCH 79/84] Add Optional[int] to docs string --- shared-bindings/displayio/Display.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index 9b63e4fec7..4d94fa1e0d 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -215,7 +215,7 @@ STATIC mp_obj_t displayio_display_obj_show(mp_obj_t self_in, mp_obj_t group_in) } MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show); -//| def refresh(self, *, target_frames_per_second: int = None, minimum_frames_per_second: int = 1) -> bool: +//| def refresh(self, *, target_frames_per_second: Optional[int] = None, minimum_frames_per_second: int = 1) -> bool: //| """When auto refresh is off, waits for the target frame rate and then refreshes the display, //| returning True. If the call has taken too long since the last refresh call for the given //| target frame rate, then the refresh returns False immediately without updating the screen to @@ -230,7 +230,8 @@ MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show //| When auto refresh is off, `refresh()` or `refresh(target_frames_per_second=None)` will update //| the display immediately. //| -//| :param int target_frames_per_second: How many times a second `refresh` should be called and the screen updated. Set to `None` for immediate refresh. +//| :param int target_frames_per_second: How many times a second `refresh` should be called +//| and the screen updated. Set to `None` for immediate refresh. //| :param int minimum_frames_per_second: The minimum number of times the screen should be updated per second.""" //| ... //| From 554cc356dbdce74101e86090d71ea2955908f78a Mon Sep 17 00:00:00 2001 From: Kevin Matocha Date: Tue, 1 Sep 2020 15:43:18 -0500 Subject: [PATCH 80/84] Delete trailing whitespace --- shared-bindings/displayio/Display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index 4d94fa1e0d..5d9569f4c1 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -230,7 +230,7 @@ MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show //| When auto refresh is off, `refresh()` or `refresh(target_frames_per_second=None)` will update //| the display immediately. //| -//| :param int target_frames_per_second: How many times a second `refresh` should be called +//| :param int target_frames_per_second: How many times a second `refresh` should be called //| and the screen updated. Set to `None` for immediate refresh. //| :param int minimum_frames_per_second: The minimum number of times the screen should be updated per second.""" //| ... From 4b9306aa7cc87a5c0eed52db36cbccd5d00152b6 Mon Sep 17 00:00:00 2001 From: Kevin Matocha Date: Tue, 1 Sep 2020 18:10:40 -0500 Subject: [PATCH 81/84] Cleanup for sphinx --- shared-bindings/displayio/Display.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index 5d9569f4c1..72b0eef279 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -227,11 +227,11 @@ MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show //| When auto refresh is on, updates the display immediately. (The display will also update //| without calls to this.) //| -//| When auto refresh is off, `refresh()` or `refresh(target_frames_per_second=None)` will update +//| When auto refresh is off, refresh() or refresh(target_frames_per_second=None) will update //| the display immediately. //| -//| :param int target_frames_per_second: How many times a second `refresh` should be called -//| and the screen updated. Set to `None` for immediate refresh. +//| :param int target_frames_per_second: How many times a second `refresh` should be called and the screen updated. +//| Set to None for immediate refresh. //| :param int minimum_frames_per_second: The minimum number of times the screen should be updated per second.""" //| ... //| From 8256bf7ea68d714f16503c97329632b7c0ca477d Mon Sep 17 00:00:00 2001 From: Kevin Matocha Date: Wed, 2 Sep 2020 11:20:30 -0500 Subject: [PATCH 82/84] Add backticks to function references in docs --- shared-bindings/displayio/Display.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index 72b0eef279..fa180fe38e 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -222,16 +222,16 @@ MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show //| hopefully help getting caught up. //| //| If the time since the last successful refresh is below the minimum frame rate, then an -//| exception will be raised. Set minimum_frames_per_second to 0 to disable. +//| exception will be raised. Set ``minimum_frames_per_second`` to 0 to disable. +//| +//| When auto refresh is off, ``display.refresh()`` or ``display.refresh(target_frames_per_second=None)`` +//| will update the display immediately. //| //| When auto refresh is on, updates the display immediately. (The display will also update //| without calls to this.) //| -//| When auto refresh is off, refresh() or refresh(target_frames_per_second=None) will update -//| the display immediately. -//| //| :param int target_frames_per_second: How many times a second `refresh` should be called and the screen updated. -//| Set to None for immediate refresh. +//| Set to `None` for immediate refresh. //| :param int minimum_frames_per_second: The minimum number of times the screen should be updated per second.""" //| ... //| From d224183a7e10ed2b10c92f9cc2f8a14412b1ed0a Mon Sep 17 00:00:00 2001 From: Kevin Matocha Date: Wed, 2 Sep 2020 11:26:37 -0500 Subject: [PATCH 83/84] Delete trailing whitespace --- shared-bindings/displayio/Display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index fa180fe38e..f36aeed18c 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -224,7 +224,7 @@ MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show //| If the time since the last successful refresh is below the minimum frame rate, then an //| exception will be raised. Set ``minimum_frames_per_second`` to 0 to disable. //| -//| When auto refresh is off, ``display.refresh()`` or ``display.refresh(target_frames_per_second=None)`` +//| When auto refresh is off, ``display.refresh()`` or ``display.refresh(target_frames_per_second=None)`` //| will update the display immediately. //| //| When auto refresh is on, updates the display immediately. (The display will also update From 17a5a85528525352ec1821127fafec2acb239196 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 2 Sep 2020 13:34:16 -0500 Subject: [PATCH 84/84] rgbmatrix: Move struct definition to shared-module, rename 'core' member --- shared-bindings/rgbmatrix/RGBMatrix.c | 2 +- shared-bindings/rgbmatrix/RGBMatrix.h | 21 +----------- shared-module/rgbmatrix/RGBMatrix.c | 40 +++++++++++------------ shared-module/rgbmatrix/RGBMatrix.h | 47 +++++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 41 deletions(-) diff --git a/shared-bindings/rgbmatrix/RGBMatrix.c b/shared-bindings/rgbmatrix/RGBMatrix.c index 9cfc0d4095..e4683af920 100644 --- a/shared-bindings/rgbmatrix/RGBMatrix.c +++ b/shared-bindings/rgbmatrix/RGBMatrix.c @@ -252,7 +252,7 @@ STATIC mp_obj_t rgbmatrix_rgbmatrix_deinit(mp_obj_t self_in) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(rgbmatrix_rgbmatrix_deinit_obj, rgbmatrix_rgbmatrix_deinit); static void check_for_deinit(rgbmatrix_rgbmatrix_obj_t *self) { - if (!self->core.rgbPins) { + if (!self->protomatter.rgbPins) { raise_deinited_error(); } } diff --git a/shared-bindings/rgbmatrix/RGBMatrix.h b/shared-bindings/rgbmatrix/RGBMatrix.h index 027f817bb6..1dc5a406ca 100644 --- a/shared-bindings/rgbmatrix/RGBMatrix.h +++ b/shared-bindings/rgbmatrix/RGBMatrix.h @@ -24,29 +24,12 @@ * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_RGBMATRIX_RGBMATRIX_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_RGBMATRIX_RGBMATRIX_H +#pragma once #include "shared-module/rgbmatrix/RGBMatrix.h" #include "lib/protomatter/core.h" extern const mp_obj_type_t rgbmatrix_RGBMatrix_type; -typedef struct { - mp_obj_base_t base; - mp_obj_t framebuffer; - mp_buffer_info_t bufinfo; - Protomatter_core core; - void *timer; - uint16_t bufsize, width; - uint8_t rgb_pins[30]; - uint8_t addr_pins[10]; - uint8_t clock_pin, latch_pin, oe_pin; - uint8_t rgb_count, addr_count; - uint8_t bit_depth; - bool core_is_initialized; - bool paused; - bool doublebuffer; -} rgbmatrix_rgbmatrix_obj_t; void common_hal_rgbmatrix_rgbmatrix_construct(rgbmatrix_rgbmatrix_obj_t* self, int width, int bit_depth, uint8_t rgb_count, uint8_t* rgb_pins, uint8_t addr_count, uint8_t* addr_pins, uint8_t clock_pin, uint8_t latch_pin, uint8_t oe_pin, bool doublebuffer, mp_obj_t framebuffer, void* timer); void common_hal_rgbmatrix_rgbmatrix_deinit(rgbmatrix_rgbmatrix_obj_t*); @@ -57,5 +40,3 @@ bool common_hal_rgbmatrix_rgbmatrix_get_paused(rgbmatrix_rgbmatrix_obj_t* self); void common_hal_rgbmatrix_rgbmatrix_refresh(rgbmatrix_rgbmatrix_obj_t* self); int common_hal_rgbmatrix_rgbmatrix_get_width(rgbmatrix_rgbmatrix_obj_t* self); int common_hal_rgbmatrix_rgbmatrix_get_height(rgbmatrix_rgbmatrix_obj_t* self); - -#endif diff --git a/shared-module/rgbmatrix/RGBMatrix.c b/shared-module/rgbmatrix/RGBMatrix.c index c39ec99a27..3007ca4db5 100644 --- a/shared-module/rgbmatrix/RGBMatrix.c +++ b/shared-module/rgbmatrix/RGBMatrix.c @@ -79,9 +79,9 @@ void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t* self, mp_get_index(mp_obj_get_type(self->framebuffer), self->bufinfo.len, MP_OBJ_NEW_SMALL_INT(self->bufsize-1), false); } else { _PM_FREE(self->bufinfo.buf); - _PM_FREE(self->core.rgbPins); - _PM_FREE(self->core.addr); - _PM_FREE(self->core.screenData); + _PM_FREE(self->protomatter.rgbPins); + _PM_FREE(self->protomatter.addr); + _PM_FREE(self->protomatter.screenData); self->framebuffer = NULL; self->bufinfo.buf = common_hal_rgbmatrix_allocator_impl(self->bufsize); @@ -89,8 +89,8 @@ void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t* self, self->bufinfo.typecode = 'H' | MP_OBJ_ARRAY_TYPECODE_FLAG_RW; } - memset(&self->core, 0, sizeof(self->core)); - ProtomatterStatus stat = _PM_init(&self->core, + memset(&self->protomatter, 0, sizeof(self->protomatter)); + ProtomatterStatus stat = _PM_init(&self->protomatter, self->width, self->bit_depth, self->rgb_count/6, self->rgb_pins, self->addr_count, self->addr_pins, @@ -98,17 +98,17 @@ void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t* self, self->doublebuffer, self->timer); if (stat == PROTOMATTER_OK) { - _PM_protoPtr = &self->core; + _PM_protoPtr = &self->protomatter; common_hal_mcu_disable_interrupts(); common_hal_rgbmatrix_timer_enable(self->timer); - stat = _PM_begin(&self->core); + stat = _PM_begin(&self->protomatter); if (stat == PROTOMATTER_OK) { - _PM_convert_565(&self->core, self->bufinfo.buf, self->width); + _PM_convert_565(&self->protomatter, self->bufinfo.buf, self->width); } common_hal_mcu_enable_interrupts(); if (stat == PROTOMATTER_OK) { - _PM_swapbuffer_maybe(&self->core); + _PM_swapbuffer_maybe(&self->protomatter); } } @@ -153,7 +153,7 @@ void common_hal_rgbmatrix_rgbmatrix_deinit(rgbmatrix_rgbmatrix_obj_t* self) { self->timer = 0; } - if (_PM_protoPtr == &self->core) { + if (_PM_protoPtr == &self->protomatter) { _PM_protoPtr = NULL; } @@ -163,10 +163,10 @@ void common_hal_rgbmatrix_rgbmatrix_deinit(rgbmatrix_rgbmatrix_obj_t* self) { free_pin(&self->latch_pin); free_pin(&self->oe_pin); - if (self->core.rgbPins) { - _PM_free(&self->core); + if (self->protomatter.rgbPins) { + _PM_free(&self->protomatter); } - memset(&self->core, 0, sizeof(self->core)); + memset(&self->protomatter, 0, sizeof(self->protomatter)); // If it was supervisor-allocated, it is supervisor-freed and the pointer // is zeroed, otherwise the pointer is just zeroed @@ -180,16 +180,16 @@ void common_hal_rgbmatrix_rgbmatrix_deinit(rgbmatrix_rgbmatrix_obj_t* self) { void rgbmatrix_rgbmatrix_collect_ptrs(rgbmatrix_rgbmatrix_obj_t* self) { gc_collect_ptr(self->framebuffer); - gc_collect_ptr(self->core.rgbPins); - gc_collect_ptr(self->core.addr); - gc_collect_ptr(self->core.screenData); + gc_collect_ptr(self->protomatter.rgbPins); + gc_collect_ptr(self->protomatter.addr); + gc_collect_ptr(self->protomatter.screenData); } void common_hal_rgbmatrix_rgbmatrix_set_paused(rgbmatrix_rgbmatrix_obj_t* self, bool paused) { if (paused && !self->paused) { - _PM_stop(&self->core); + _PM_stop(&self->protomatter); } else if (!paused && self->paused) { - _PM_resume(&self->core); + _PM_resume(&self->protomatter); } self->paused = paused; } @@ -199,8 +199,8 @@ bool common_hal_rgbmatrix_rgbmatrix_get_paused(rgbmatrix_rgbmatrix_obj_t* self) } void common_hal_rgbmatrix_rgbmatrix_refresh(rgbmatrix_rgbmatrix_obj_t* self) { - _PM_convert_565(&self->core, self->bufinfo.buf, self->width); - _PM_swapbuffer_maybe(&self->core); + _PM_convert_565(&self->protomatter, self->bufinfo.buf, self->width); + _PM_swapbuffer_maybe(&self->protomatter); } int common_hal_rgbmatrix_rgbmatrix_get_width(rgbmatrix_rgbmatrix_obj_t* self) { diff --git a/shared-module/rgbmatrix/RGBMatrix.h b/shared-module/rgbmatrix/RGBMatrix.h index e69de29bb2..19d7d5f2e7 100644 --- a/shared-module/rgbmatrix/RGBMatrix.h +++ b/shared-module/rgbmatrix/RGBMatrix.h @@ -0,0 +1,47 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler 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. + */ + +#pragma once + +#include "lib/protomatter/core.h" + +extern const mp_obj_type_t rgbmatrix_RGBMatrix_type; +typedef struct { + mp_obj_base_t base; + mp_obj_t framebuffer; + mp_buffer_info_t bufinfo; + Protomatter_core protomatter; + void *timer; + uint16_t bufsize, width; + uint8_t rgb_pins[30]; + uint8_t addr_pins[10]; + uint8_t clock_pin, latch_pin, oe_pin; + uint8_t rgb_count, addr_count; + uint8_t bit_depth; + bool core_is_initialized; + bool paused; + bool doublebuffer; +} rgbmatrix_rgbmatrix_obj_t;