summaryrefslogtreecommitdiff
path: root/devices
diff options
context:
space:
mode:
Diffstat (limited to 'devices')
-rw-r--r--devices/ble_hci/common-hal/_bleio/Adapter.c2
-rw-r--r--devices/ble_hci/common-hal/_bleio/Connection.h5
-rw-r--r--devices/ble_hci/common-hal/_bleio/__init__.h2
-rw-r--r--devices/ble_hci/common-hal/_bleio/att.c1621
-rw-r--r--devices/ble_hci/common-hal/_bleio/att.h57
-rw-r--r--devices/ble_hci/common-hal/_bleio/hci.c (renamed from devices/ble_hci/common-hal/_bleio/hci_api.c)94
-rw-r--r--devices/ble_hci/common-hal/_bleio/hci.h (renamed from devices/ble_hci/common-hal/_bleio/hci_api.h)8
-rw-r--r--devices/ble_hci/common-hal/_bleio/hci_include/addr.h1
-rw-r--r--devices/ble_hci/common-hal/_bleio/hci_include/att.h41
-rw-r--r--devices/ble_hci/common-hal/_bleio/hci_include/att_internal.h266
-rw-r--r--devices/ble_hci/common-hal/_bleio/hci_include/hci.h1
-rw-r--r--devices/ble_hci/common-hal/_bleio/hci_include/l2cap_internal.h230
12 files changed, 2284 insertions, 44 deletions
diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c
index 17b66899a..55e0bde01 100644
--- a/devices/ble_hci/common-hal/_bleio/Adapter.c
+++ b/devices/ble_hci/common-hal/_bleio/Adapter.c
@@ -31,7 +31,7 @@
#include <stdio.h>
#include <string.h>
-#include "hci_api.h"
+#include "hci.h"
#include "py/gc.h"
#include "py/mphal.h"
diff --git a/devices/ble_hci/common-hal/_bleio/Connection.h b/devices/ble_hci/common-hal/_bleio/Connection.h
index bb0c140c5..8b9790d9e 100644
--- a/devices/ble_hci/common-hal/_bleio/Connection.h
+++ b/devices/ble_hci/common-hal/_bleio/Connection.h
@@ -64,13 +64,16 @@ typedef struct {
//REMOVE ble_gap_conn_params_t conn_params;
volatile bool conn_params_updating;
uint16_t mtu;
- // Request that CCCD values for this conenction be saved, using sys_attr values.
+ // Request that CCCD values for this connection be saved, using sys_attr values.
volatile bool do_bond_cccds;
// Request that security key info for this connection be saved.
volatile bool do_bond_keys;
// Time of setting do_bond_ccds: we delay a bit to consolidate multiple CCCD changes
// into one write. Time is currently in ticks_ms.
uint64_t do_bond_cccds_request_time;
+ //FIX from att.c
+ uint8_t role;
+ bt_addr_le_t addr;
} bleio_connection_internal_t;
typedef struct {
diff --git a/devices/ble_hci/common-hal/_bleio/__init__.h b/devices/ble_hci/common-hal/_bleio/__init__.h
index 0d1c2785f..18b4289e9 100644
--- a/devices/ble_hci/common-hal/_bleio/__init__.h
+++ b/devices/ble_hci/common-hal/_bleio/__init__.h
@@ -29,7 +29,7 @@
#include <stdbool.h>
-#include "hci_api.h"
+#include "hci.h"
void bleio_background(void);
void bleio_reset(void);
diff --git a/devices/ble_hci/common-hal/_bleio/att.c b/devices/ble_hci/common-hal/_bleio/att.c
new file mode 100644
index 000000000..d37012a0a
--- /dev/null
+++ b/devices/ble_hci/common-hal/_bleio/att.c
@@ -0,0 +1,1621 @@
+// Derived from ArduinoBLE.
+// Copyright 2020 Dan Halbert for Adafruit Industries
+
+/*
+ This file is part of the ArduinoBLE library.
+ Copyright (c) 2018 Arduino SA. All rights reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "hci.h"
+#include "att.h"
+
+// Zephyr include files to define HCI communication values and structs.
+//#include "hci_include/hci.h"
+//#include "hci_include/hci_err.h"
+#include "hci_include/l2cap_internal.h"
+
+#include "py/obj.h"
+#include "common-hal/_bleio/Adapter.h"
+#include "supervisor/shared/tick.h"
+
+enum ble_attribute_type {
+ BLE_TYPE_UNKNOWN = 0x0000,
+ BLE_TYPE_PRIMARY_SERVICE = 0x2800,
+ BLE_TYPE_SECONDARY_SERVICE = 0x2801,
+ BLE_TYPE_CHARACTERISTIC = 0x2803,
+ BLE_TYPE_DESCRIPTOR = 0x2900
+};
+
+STATIC uint16_t max_mtu = BT_ATT_DEFAULT_LE_MTU; // 23
+STATIC unsigned long timeout = 5000;
+
+STATIC volatile bool cnf;
+
+STATIC uint16_t long_write_handle = 0x0000;
+STATIC uint8_t* long_write_value = NULL;
+STATIC uint16_t long_write_value_length = 0;
+
+// When we send a request, fill this struct with info about the expected response.
+// We check this against the actual received response.
+STATIC struct {
+ uint16_t conn_handle; // Expected handle.
+ uint8_t opcode; // Expected RSP opcode.
+ uint8_t* buffer; // Pointer to response packet
+ uint8_t length; // Length of response packet.
+} expected_rsp;
+
+//FIX BLEDeviceEventHandler event_handlers[2];
+
+
+STATIC void send_error(uint16_t conn_handle, uint8_t opcode, uint16_t handle, uint8_t code) {
+ struct __packed {
+ struct bt_att_hdr h;
+ struct bt_att_error_rsp r;
+ } rsp = { {
+ .code = BT_ATT_OP_ERROR_RSP,
+ }, {
+ .request = opcode,
+ }
+ };
+
+ hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, sizeof(rsp), (uint8_t *) &rsp);
+}
+
+STATIC int send_req_wait_for_rsp(uint16_t conn_handle, int request_length, uint8_t* request_buffer, uint8_t response_buffer[]) {
+ // We expect a particular kind of response after this request.
+ expected_rsp.conn_handle = conn_handle;
+ // The response opcode is the request opcode + 1.
+ expected_rsp.opcode = request_buffer[0] + 1;
+ expected_rsp.buffer = response_buffer;
+ expected_rsp.length = 0;
+
+ hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, request_length, request_buffer);
+
+ if (response_buffer == NULL) {
+ // not expecting a response.
+ return 0;
+ }
+
+ for (uint64_t start = supervisor_ticks_ms64(); supervisor_ticks_ms64() - start < timeout;) {
+ hci_poll_for_incoming_pkt();
+
+ if (!att_handle_is_connected(conn_handle)) {
+ break;
+ }
+
+ if (expected_rsp.length != 0) {
+ expected_rsp.conn_handle = 0xffff;
+ return expected_rsp.length;
+ }
+ }
+
+ expected_rsp.conn_handle = 0xffff;
+ return 0;
+}
+
+// If a response matches what is in expected_rsp, copy the rest of it into the buffer.
+STATIC void check_and_save_expected_rsp(uint16_t conn_handle, uint8_t opcode, uint8_t dlen, uint8_t data[]) {
+ if (conn_handle == expected_rsp.conn_handle && expected_rsp.opcode == opcode) {
+ expected_rsp.buffer[0] = opcode;
+ memcpy(&expected_rsp.buffer[1], data, dlen);
+ expected_rsp.length = dlen + 1;
+ }
+}
+
+void att_init(void) {
+ max_mtu = BT_ATT_DEFAULT_LE_MTU;
+ timeout = 5000;
+ long_write_handle = 0x0000;
+ long_write_value = NULL;
+ long_write_value_length = 0;
+
+ for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
+ bleio_connections[i].conn_handle = BLE_CONN_HANDLE_INVALID;
+ bleio_connections[i].role = 0x00;
+ bleio_connections[i].addr.type = 0;
+ memset(bleio_connections[i].addr.a.val, 0, sizeof_field(bt_addr_t, val));
+ bleio_connections[i].mtu = BT_ATT_DEFAULT_LE_MTU;
+ }
+
+ //FIX memset(event_handlers, 0x00, sizeof(event_handlers));
+}
+
+bool att_connect_to_address(bt_addr_le_t *addr) {
+ //FIX
+ if (hci_le_create_conn(0x0060, 0x0030, 0x00, addr, 0x00,
+ 0x0006, 0x000c, 0x0000, 0x00c8, 0x0004, 0x0006) != 0) {
+ return false;
+ }
+
+ bool is_connected = false;
+
+ for (uint64_t start = supervisor_ticks_ms64(); supervisor_ticks_ms64() - start < timeout;) {
+ hci_poll_for_incoming_pkt();
+
+ is_connected = att_address_is_connected(addr);
+
+ if (is_connected) {
+ break;
+ }
+ }
+
+ if (!is_connected) {
+ hci_le_cancel_conn();
+ }
+
+ return is_connected;
+}
+
+bool att_disconnect_from_address(bt_addr_le_t *addr) {
+ uint16_t conn_handle = att_conn_handle(addr);
+ if (conn_handle == 0xffff) {
+ return false;
+ }
+
+ hci_disconnect(conn_handle);
+
+ hci_poll_for_incoming_pkt_timeout(timeout);
+
+ if (!att_handle_is_connected(conn_handle)) {
+ return true;
+ }
+
+ return false;
+}
+
+//FIX
+// STATIC bool discover_services(uint16_t conn_handle, BLERemoteDevice* device, const char* serviceUuidFilter) {
+// uint16_t reqStart_handle = 0x0001;
+// uint16_t reqEnd_handle = 0xffff;
+
+// uint8_t response_buffer[max_mtu];
+
+// BLEUuid serviceUuid(serviceUuidFilter);
+
+// while (reqEnd_handle == 0xffff) {
+// int respLength = readByGroupReq(conn_handle, reqStart_handle, reqEnd_handle, BLE_TYPE_PRIMARY_SERVICE, response_buffer);
+
+// if (respLength == 0) {
+// return false;
+// }
+
+// if (response_buffer[0] == BT_ATT_OP_READ_BY_GROUP_RSP) {
+// uint16_t lengthPerService = response_buffer[1];
+// uint8_t uuidLen = lengthPerService - 4;
+
+// for (size_t i = 2; i < respLength; i += lengthPerService) {
+// struct __attribute__ ((packed)) RawService {
+// uint16_t start_handle;
+// uint16_t end_handle;
+// uint8_t uuid[16];
+// } *rawService = (RawService*)&response_buffer[i];
+
+// if (serviceUuidFilter == NULL ||
+// (uuidLen == serviceUuid.length() && memcmp(rawService->uuid, serviceUuid.data(), uuidLen) == 0)) {
+
+// BLERemoteService* service = new BLERemoteService(rawService->uuid, uuidLen,
+// rawService->start_handle,
+// rawService->end_handle);
+
+// if (service == NULL) {
+// return false;
+// }
+
+// device->addService(service);
+
+// }
+
+// reqStart_handle = rawService->end_handle + 1;
+
+// if (reqStart_handle == 0x0000) {
+// reqEnd_handle = 0x0000;
+// }
+// }
+// } else {
+// reqEnd_handle = 0x0000;
+// }
+// }
+
+// return true;
+// }
+
+// STATIC bool discover_characteristics(uint16_t conn_handle, BLERemoteDevice* device) {
+// uint16_t reqStart_handle = 0x0001;
+// uint16_t reqEnd_handle = 0xffff;
+
+// uint8_t response_buffer[max_mtu];
+
+// int serviceCount = device->serviceCount();
+
+// for (size_t i = 0; i < serviceCount; i++) {
+// BLERemoteService* service = device->service(i);
+
+// reqStart_handle = service->start_handle();
+// reqEnd_handle = service->end_handle();
+
+// while (1) {
+// int respLength = readByTypeReq(conn_handle, reqStart_handle, reqEnd_handle, BLE_TYPE_CHARACTERISTIC, response_buffer);
+
+// if (respLength == 0) {
+// return false;
+// }
+
+// if (response_buffer[0] == BT_ATT_OP_READ_BY_TYPE_RSP) {
+// uint16_t lengthPerCharacteristic = response_buffer[1];
+// uint8_t uuidLen = lengthPerCharacteristic - 5;
+
+// for (size_t i = 2; i < respLength; i += lengthPerCharacteristic) {
+// struct __attribute__ ((packed)) RawCharacteristic {
+// uint16_t start_handle;
+// uint8_t properties;
+// uint16_t value_handle;
+// uint8_t uuid[16];
+// } *rawCharacteristic = (RawCharacteristic*)&response_buffer[i];
+
+// BLERemoteCharacteristic* characteristic = new BLERemoteCharacteristic(rawCharacteristic->uuid, uuidLen,
+// conn_handle,
+// rawCharacteristic->start_handle,
+// rawCharacteristic->properties,
+// rawCharacteristic->value_handle);
+
+// if (characteristic == NULL) {
+// return false;
+// }
+
+// service->addCharacteristic(characteristic);
+
+// reqStart_handle = rawCharacteristic->value_handle + 1;
+// }
+// } else {
+// break;
+// }
+// }
+// }
+
+// return true;
+// }
+
+// STATIC bool discover_descriptors(uint16_t conn_handle, BLERemoteDevice* device) {
+// uint16_t reqStart_handle = 0x0001;
+// uint16_t reqEnd_handle = 0xffff;
+
+// uint8_t response_buffer[max_mtu];
+
+// int serviceCount = device->serviceCount();
+
+// for (size_t i = 0; i < serviceCount; i++) {
+// BLERemoteService* service = device->service(i);
+
+// uint16_t serviceEnd_handle = service->end_handle();
+
+// int characteristicCount = service->characteristicCount();
+
+// for (int j = 0; j < characteristicCount; j++) {
+// BLERemoteCharacteristic* characteristic = service->characteristic(j);
+// BLERemoteCharacteristic* nextCharacteristic = (j == (characteristicCount - 1)) ? NULL : service->characteristic(j);
+
+// reqStart_handle = characteristic->value_handle() + 1;
+// reqEnd_handle = nextCharacteristic ? nextCharacteristic->value_handle() : serviceEnd_handle;
+
+// if (reqStart_handle > reqEnd_handle) {
+// continue;
+// }
+
+// while (1) {
+// int respLength = findInfoReq(conn_handle, reqStart_handle, reqEnd_handle, response_buffer);
+
+// if (respLength == 0) {
+// return false;
+// }
+
+// if (response_buffer[0] == BT_ATT_OP_FIND_INFO_RSP) {
+// uint16_t lengthPerDescriptor = response_buffer[1] * 4;
+// uint8_t uuidLen = 2;
+
+// for (size_t i = 2; i < respLength; i += lengthPerDescriptor) {
+// struct __attribute__ ((packed)) RawDescriptor {
+// uint16_t handle;
+// uint8_t uuid[16];
+// } *rawDescriptor = (RawDescriptor*)&response_buffer[i];
+
+// BLERemoteDescriptor* descriptor = new BLERemoteDescriptor(rawDescriptor->uuid, uuidLen,
+// conn_handle,
+// rawDescriptor->handle);
+
+// if (descriptor == NULL) {
+// return false;
+// }
+
+// characteristic->addDescriptor(descriptor);
+
+// reqStart_handle = rawDescriptor->handle + 1;
+// }
+// } else {
+// break;
+// }
+// }
+// }
+// }
+
+// return true;
+// }
+
+bool att_discover_attributes(bt_addr_le_t *addr, const char* service_uuid_filter) {
+ uint16_t conn_handle = att_conn_handle(addr);
+ if (conn_handle == 0xffff) {
+ return false;
+ }
+
+ // send MTU request
+ if (!att_exchange_mtu(conn_handle)) {
+ return false;
+ }
+
+ // find the device entry for the peeer
+ //FIX BLERemoteDevice* device = NULL;
+
+ for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
+ // if (bleio_connections[i].conn_handle == conn_handle) {
+ // //FIX if (bleio_connections[i].device == NULL) {
+ // //FIX
+ // //bleio_connections[i].device = new BLERemoteDevice();
+ // //}
+
+ // //device = bleio_connections[i].device;
+
+ // break;
+ // }
+ // }
+
+ // //FIX if (device == NULL) {
+ // // return false;
+ // // }
+
+ // if (service_uuid_filter == NULL) {
+ // // clear existing services
+ // //FIX device->clear_services();
+ // } else {
+ // //FIX int service_count = device->service_count();
+
+ // for (size_t i = 0; i < service_count; i++) {
+ // //FIX BLERemoteService* service = device->service(i);
+
+ // if (strcasecmp(service->uuid(), service_uuid_filter) == 0) {
+ // // found an existing service with same UUID
+ // return true;
+ // }
+ // }
+ }
+
+ // discover services
+ //FIX
+ // if (!att_discover_services(conn_handle, device, service_uuid_filter)) {
+ // return false;
+ // }
+
+ // // discover characteristics
+ // if (!discover_characteristics(conn_handle, device)) {
+ // return false;
+ // }
+
+ // // discover descriptors396
+ // if (!discover_descriptors(conn_handle, device)) {
+ // return false;
+ // }
+
+ return true;
+}
+
+void att_set_max_mtu(uint16_t max_mtu_in) {
+ max_mtu = max_mtu_in;
+}
+
+void att_set_timeout(unsigned long timeout_in) {
+ timeout = timeout_in;
+}
+
+void att_add_connection(uint16_t handle, uint8_t role, bt_addr_le_t *peer_addr, uint16_t interval, uint16_t latency, uint16_t supervision_timeout, uint8_t master_clock_accuracy) {
+ (void) interval;
+ (void) latency;
+ (void) supervision_timeout;
+ (void) master_clock_accuracy;
+
+ int peer_index = -1;
+
+ for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
+ if (bleio_connections[i].conn_handle == 0xffff) {
+ peer_index = i;
+ break;
+ }
+ }
+
+ if (peer_index == -1) {
+ // bail, no space
+ return;
+ }
+
+ bleio_connections[peer_index].conn_handle = handle;
+ bleio_connections[peer_index].role = role;
+ bleio_connections[peer_index].mtu = 23;
+ memcpy(&bleio_connections[peer_index].addr, peer_addr, sizeof(bleio_connections[peer_index].addr));
+
+ //FIX if (event_handlers[BLEConnected]) {
+ // event_handlers[BLEConnected](BLEDevice(peer_bdaddr_type, peer_bdaddr));
+ // }
+}
+
+
+void att_remove_connection(uint16_t handle, uint8_t reason) {
+ (void) reason;
+ int peer_index = -1;
+ int peer_count = 0;
+
+ for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
+ if (bleio_connections[i].conn_handle == handle) {
+ peer_index = i;
+ }
+
+ if (bleio_connections[i].conn_handle != 0xffff) {
+ peer_count++;
+ }
+ }
+
+ if (peer_index == -1) {
+ // bail not found
+ return;
+ }
+
+ //FIX BLEDevice bleDevice(bleio_connections[peer_index].address_type, bleio_connections[peer_index].address);
+
+ if (peer_count == 1) {
+ //FIX
+ // clear CCCD values on disconnect
+ // for (uint16_t i = 0; i < GATT.attributeCount(); i++) {
+ // BLELocalAttribute* attribute = GATT.attribute(i);
+
+ // if (attribute->type() == BLE_TYPE_CHARACTERISTIC) {
+ // BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute;
+
+ // characteristic->writeCccdValue(bleDevice, 0x0000);
+ // }
+ // }
+
+ long_write_handle = 0x0000;
+ long_write_value_length = 0;
+ }
+
+ //FIX
+ // if (event_handlers[BLEDisconnected]) {
+ // event_handlers[BLEDisconnected](bleDevice);
+ // }
+
+ bleio_connections[peer_index].conn_handle = 0xffff;
+ bleio_connections[peer_index].role = 0x00;
+ memset(&bleio_connections[peer_index].addr, 0x00, sizeof(bleio_connections[peer_index].addr));
+ bleio_connections[peer_index].mtu = 23;
+
+ //FIX if (bleio_connections[peer_index].device) {
+ //FIX delete bleio_connections[peer_index].device;
+ // }
+ //FIX bleio_connections[peer_index].device = NULL;
+}
+
+uint16_t att_conn_handle(bt_addr_le_t *addr) {
+ for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
+ if (bleio_connections[i].addr.type == addr->type &&
+ memcmp(&bleio_connections[i].addr.a.val, addr->a.val, sizeof(addr->a.val)) == 0) {
+ return bleio_connections[i].conn_handle;
+ }
+ }
+
+ return 0xffff;
+}
+
+//FIX
+// BLERemoteDevice* att_device(uint8_t address_type, const uint8_t address[6]) {
+// for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
+// if (bleio_connections[i].addr.type == addr->type &&
+// memcmp(&bleio_connections[i].addr.a.val, addr->a.val, sizeof(addr->a.val)) == 0) {
+// }
+// }
+
+// return NULL;
+// }
+
+bool att_is_connected(void) {
+ for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
+ if (bleio_connections[i].conn_handle != 0xffff) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool att_address_is_connected(bt_addr_le_t *addr) {
+ return (att_conn_handle(addr) != 0xffff);
+}
+
+bool att_handle_is_connected(uint16_t handle) {
+ hci_poll_for_incoming_pkt();
+
+ for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
+ if (bleio_connections[i].conn_handle == handle) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+uint16_t att_mtu(uint16_t handle) {
+ for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
+ if (bleio_connections[i].conn_handle == handle) {
+ return bleio_connections[i].mtu;
+ }
+ }
+
+ return 23;
+}
+
+bool att_disconnect_all(void) {
+ int num_disconnects = 0;
+
+ for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
+ if (bleio_connections[i].conn_handle == 0xffff) {
+ continue;
+ }
+
+ if (hci_disconnect(bleio_connections[i].conn_handle) != 0) {
+ continue;
+ }
+
+ num_disconnects++;
+
+ bleio_connections[i].conn_handle = 0xffff;
+ bleio_connections[i].role = 0x00;
+ bleio_connections[i].addr.type = 0;
+ memset(bleio_connections[i].addr.a.val, 0, sizeof(bleio_connections[i].addr.a.val));
+ bleio_connections[i].mtu = 23;
+
+ //FIX
+ // if (bleio_connections[i].device) {
+ // delete bleio_connections[i].device;
+ // }
+ // bleio_connections[i].device = NULL;
+ }
+
+ return (num_disconnects > 0);
+}
+
+// FIX
+// BLEDevice att_central() {
+// for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
+// if (bleio_connections[i].conn_handle == 0xffff || bleio_connections[i].role != 0x01) {
+// continue;
+// }
+
+// return BLEDevice(bleio_connections[i].address_type, bleio_connections[i].address);
+// }
+
+// return BLEDevice();
+// }
+
+bool att_handle_notify(uint16_t handle, const uint8_t* value, int length) {
+ int num_notifications = 0;
+
+ for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
+ if (bleio_connections[i].conn_handle == 0xffff) {
+ continue;
+ }
+
+ //FIX This seems fishy. Why just .mtu instead of .mtu + 1 for opcode
+ uint8_t notification[bleio_connections[i].mtu];
+ uint16_t notification_length = 0;
+
+ notification[0] = BT_ATT_OP_NOTIFY;
+ notification_length++;
+
+ memcpy(&notification[1], &handle, sizeof(handle));
+ notification_length += sizeof(handle);
+
+ length = MIN((uint16_t)(bleio_connections[i].mtu - notification_length), (uint16_t)length);
+ memcpy(&notification[notification_length], value, length);
+ notification_length += length;
+
+ hci_send_acl_pkt(bleio_connections[i].conn_handle, BT_L2CAP_CID_ATT, notification_length, notification);
+
+ num_notifications++;
+ }
+
+ return (num_notifications > 0);
+}
+
+bool att_handle_ind(uint16_t handle, const uint8_t* value, int length) {
+ int num_indications = 0;
+
+ for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
+ if (bleio_connections[i].conn_handle == 0xffff) {
+ continue;
+ }
+
+ uint8_t indication[bleio_connections[i].mtu];
+ uint16_t indication_length = 0;
+
+ indication[0] = BT_ATT_OP_INDICATE;
+ indication_length++;
+
+ memcpy(&indication[1], &handle, sizeof(handle));
+ indication_length += sizeof(handle);
+
+ length = MIN((uint16_t)(bleio_connections[i].mtu - indication_length), (uint16_t)length);
+ memcpy(&indication[indication_length], value, length);
+ indication_length += length;
+
+ cnf = false;
+
+ hci_send_acl_pkt(bleio_connections[i].conn_handle, BT_L2CAP_CID_ATT, indication_length, indication);
+
+ while (!cnf) {
+ hci_poll_for_incoming_pkt();
+
+ if (!att_address_is_connected(&bleio_connections[i].addr)) {
+ break;
+ }
+ }
+
+ num_indications++;
+ }
+
+ return (num_indications > 0);
+}
+
+STATIC void process_error(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) {
+ struct bt_att_error_rsp *rsp = (struct bt_att_error_rsp *) data;
+ if (dlen != sizeof(struct bt_att_error_rsp)) {
+ // Incorrect size; ignore.
+ return;
+ }
+
+ // expected_rsp.opcode is an RSP opcode. Does it match the REQ opcode in this response?
+ if (expected_rsp.conn_handle == conn_handle && (expected_rsp.opcode - 1) == rsp->request) {
+ expected_rsp.buffer[0] = BT_ATT_OP_ERROR_RSP;
+ memcpy(&expected_rsp.buffer[1], data, dlen);
+ expected_rsp.length = dlen + 1;
+ }
+}
+
+STATIC void process_mtu_req(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) {
+ struct bt_att_exchange_mtu_req *req = (struct bt_att_exchange_mtu_req *) data;
+ if (dlen != sizeof(req)) {
+ send_error(conn_handle, BT_ATT_OP_MTU_REQ, 0x0000, BT_ATT_ERR_INVALID_PDU);
+ return;
+ }
+
+ uint16_t mtu = req->mtu;
+
+ if (mtu > max_mtu) {
+ mtu = max_mtu;
+ }
+
+ for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
+ if (bleio_connections[i].conn_handle == conn_handle) {
+ bleio_connections[i].mtu = mtu;
+ break;
+ }
+ }
+
+ struct __packed {
+ struct bt_att_hdr h;
+ struct bt_att_exchange_mtu_req r;
+ } rsp = { {
+ .code = BT_ATT_OP_MTU_RSP,
+ }, {
+ .mtu = mtu,
+ }
+ };
+
+ hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, sizeof(rsp), (uint8_t *) &rsp);
+}
+
+STATIC void process_mtu_rsp(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) {
+ if (dlen != sizeof(struct bt_att_exchange_mtu_rsp)) {
+ return;
+ }
+
+ struct bt_att_exchange_mtu_rsp *rsp = (struct bt_att_exchange_mtu_rsp *) data;
+
+ for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
+ if (bleio_connections[i].conn_handle == conn_handle) {
+ bleio_connections[i].mtu = rsp->mtu;
+ break;
+ }
+ }
+
+ check_and_save_expected_rsp(conn_handle, BT_ATT_OP_MTU_RSP, dlen, data);
+}
+
+STATIC void process_find_info_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, uint8_t data[]) {
+ struct bt_att_find_info_req *req = (struct bt_att_find_info_req *) data;
+
+ if (dlen != sizeof(struct bt_att_find_info_req)) {
+ send_error(conn_handle, BT_ATT_OP_FIND_INFO_REQ, req->start_handle, BT_ATT_ERR_INVALID_PDU);
+ return;
+ }
+
+ //FIX
+ // uint8_t response[mtu];
+ // uint16_t response_length;
+
+ // response[0] = BT_ATT_OP_FIND_INFO_RSP;
+ // response[1] = 0x00;
+ // response_length = 2;
+
+ // for (uint16_t i = (req->start_handle - 1); i < GATT.attributeCount() && i <= (req->end_handle - 1); i++) {
+ // BLELocalAttribute* attribute = GATT.attribute(i);
+ // uint16_t handle = (i + 1);
+ // bool is_value_handle = (attribute->type() == BLE_TYPE_CHARACTERISTIC) && (((BLELocalCharacteristic*)attribute)->valueHandle() == handle);
+ // int uuid_len = is_value_handle ? 2 : attribute->uuid_length();
+ // size_t info_type = (uuidLen == 2) ? 0x01 : 0x02;
+
+ // if (response[1] == 0) {
+ // response[1] = info_type;
+ // }
+
+ // if (response[1] != info_type) {
+ // // different type
+ // break;
+ // }
+
+ // // add the handle
+ // memcpy(&response[response_length], &handle, sizeof(handle));
+ // response_length += sizeof(handle);
+
+ // if (is_value_handle || attribute->type() == BLE_TYPE_DESCRIPTOR) {
+ // // add the UUID
+ // memcpy(&response[response_length], attribute->uuid_data(), uuid_len);
+ // response_length += uuidLen;
+ // } else {
+ // // add the type
+ // uint16_t type = attribute->type();
+
+ // memcpy(&response[response_length], &type, sizeof(type));
+ // response_length += sizeof(type);
+ // }
+
+ // if ((response_length + (2 + uuidLen)) > mtu) {
+ // break;
+ // }
+ // }
+
+ // if (response_length == 2) {
+ // send_error(conn_handle, BT_ATT_OP_FIND_INFO_REQ, findInfoReq->start_handle, BT_ATT_ERR_ATTR_NOT_FOUND);
+ // } else {
+ // hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, response_length, response);
+ // }
+}
+
+int att_find_info_req(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, uint8_t response_buffer[]) {
+ struct __packed req {
+ struct bt_att_hdr h;
+ struct bt_att_find_info_req r;
+ } req = { {
+ .code = BT_ATT_OP_FIND_INFO_REQ,
+ }, {
+ .start_handle = start_handle,
+ .end_handle = end_handle,
+ }
+ };
+
+ return send_req_wait_for_rsp(conn_handle, sizeof(req), (uint8_t *) &req, response_buffer);
+}
+
+STATIC void process_find_info_rsp(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) {
+ if (dlen < 2) {
+ return; // invalid, drop
+ }
+
+ check_and_save_expected_rsp(conn_handle, BT_ATT_OP_FIND_INFO_RSP, dlen, data);
+}
+
+STATIC void process_find_by_type_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, uint8_t data[]) {
+ struct bt_att_find_type_req *req = (struct bt_att_find_type_req *) data;
+
+ if (dlen < sizeof(struct bt_att_find_type_req)) {
+ send_error(conn_handle, BT_ATT_OP_FIND_TYPE_RSP, req->start_handle, BT_ATT_ERR_INVALID_PDU);
+ return;
+ }
+
+ uint8_t response[mtu];
+ uint16_t response_length;
+
+ response[0] = BT_ATT_OP_FIND_TYPE_RSP;
+ response_length = 1;
+
+ //FIX
+ // if (find_by_type_req->type == BLE_TYPE_PRIMARY_SERVICE) {
+ // for (uint16_t i = (find_by_type_req->start_handle - 1); i < GATT.attributeCount() && i <= (find_by_type_req->end_handle - 1); i++) {
+ // BLELocalAttribute* attribute = GATT.attribute(i);
+
+ // if ((attribute->type() == find_by_type_req->type) && (attribute->uuidLength() == value_length) && memcmp(attribute->uuidData(), value, value_length) == 0) {
+ // BLELocalService* service = (BLELocalService*)attribute;
+
+ // // add the start handle
+ // uint16_t start_handle = service->start_handle();
+ // memcpy(&response[response_length], &start_handle, sizeof(start_handle));
+ // response_length += sizeof(start_handle);
+
+ // // add the end handle
+ // uint16_t end_handle = service->end_handle();
+ // memcpy(&response[response_length], &end_handle, sizeof(end_handle));
+ // response_length += sizeof(end_handle);
+ // }
+
+ // if ((response_length + 4) > mtu) {
+ // break;
+ // }
+ // }
+ // }
+
+ if (response_length == 1) {
+ send_error(conn_handle, BT_ATT_OP_FIND_TYPE_RSP, req->start_handle, BT_ATT_ERR_ATTRIBUTE_NOT_FOUND);
+ } else {
+ hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, response_length, response);
+ }
+}
+
+void process_read_by_group_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, uint8_t data[]) {
+ struct bt_att_read_group_req *req = (struct bt_att_read_group_req *) data;
+ uint16_t uuid = req->uuid[0] | (req->uuid[1] << 8);
+
+ if (dlen != sizeof(struct bt_att_find_type_req) ||
+ (uuid != BLE_TYPE_PRIMARY_SERVICE &&
+ uuid != BLE_TYPE_SECONDARY_SERVICE)) {
+ send_error(conn_handle, BT_ATT_OP_READ_GROUP_REQ, req->start_handle, BT_ATT_ERR_UNSUPPORTED_GROUP_TYPE);
+ return;
+ }
+
+ uint8_t response[mtu];
+ uint16_t response_length;
+
+ response[0] = BT_ATT_OP_READ_GROUP_RSP;
+ response[1] = 0x00;
+ response_length = 2;
+
+ // FIX
+ // for (uint16_t i = (readByGroupReq->start_handle - 1); i < GATT.attributeCount() && i <= (readByGroupReq->end_handle - 1); i++) {
+ //FIX
+ // BLELocalAttribute* attribute = GATT.attribute(i);
+
+ // if (readByGroupReq->uuid != attribute->type()) {
+ // // not the type
+ // continue;
+ // }
+
+ // int uuidLen = attribute->uuidLength();
+ // size_t infoSize = (uuidLen == 2) ? 6 : 20;
+
+ // if (response[1] == 0) {
+ // response[1] = infoSize;
+ // }
+
+ // if (response[1] != infoSize) {
+ // // different size
+ // break;
+ // }
+
+ // BLELocalService* service = (BLELocalService*)attribute;
+
+ // // add the start handle
+ // uint16_t start_handle = service->start_handle();
+ // memcpy(&response[response_length], &start_handle, sizeof(start_handle));
+ // response_length += sizeof(start_handle);
+
+ // // add the end handle
+ // uint16_t end_handle = service->end_handle();
+ // memcpy(&response[response_length], &end_handle, sizeof(end_handle));
+ // response_length += sizeof(end_handle);
+
+ // // add the UUID
+ // memcpy(&response[response_length], service->uuidData(), uuidLen);
+ // response_length += uuidLen;
+
+ // if ((response_length + infoSize) > mtu) {
+ // break;
+ // }
+ // }
+
+ if (response_length == 2) {
+ send_error(conn_handle, BT_ATT_OP_READ_GROUP_REQ, req->start_handle, BT_ATT_ERR_ATTRIBUTE_NOT_FOUND);
+ } else {
+ hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, response_length, response);
+ }
+}
+
+int att_read_by_group_req(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, uint16_t uuid, uint8_t response_buffer[]) {
+ struct __packed {
+ struct bt_att_hdr h;
+ struct bt_att_read_group_req r;
+ } req = { {
+ .code = BT_ATT_OP_ERROR_RSP,
+ }, {
+ .start_handle = start_handle,
+ .end_handle = end_handle,
+ }
+ };
+ req.r.uuid[0] = uuid & 0xff;
+ req.r.uuid[1] = uuid >> 8;
+
+
+ return send_req_wait_for_rsp(conn_handle, sizeof(req), (uint8_t *) &req, response_buffer);
+}
+
+STATIC void process_read_by_group_rsp(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) {
+ if (dlen < 2) {
+ return; // invalid, drop
+ }
+
+ check_and_save_expected_rsp(conn_handle, BT_ATT_OP_READ_GROUP_RSP, dlen, data);
+}
+
+STATIC void process_read_or_read_blob_req(uint16_t conn_handle, uint16_t mtu, uint8_t opcode, uint8_t dlen, uint8_t data[]) {
+ uint16_t handle;
+ uint16_t offset = 0;
+ uint8_t response_opcode;
+
+ if (opcode == BT_ATT_OP_READ_REQ) {
+ if (dlen != sizeof(struct bt_att_read_req)) {
+ send_error(conn_handle, BT_ATT_OP_READ_REQ, 0x0000, BT_ATT_ERR_INVALID_PDU);
+ return;
+ }
+
+ struct bt_att_read_req *req = (struct bt_att_read_req *) data;
+ handle = req->handle;
+ response_opcode = BT_ATT_OP_READ_RSP;
+
+ } else {
+ if (dlen != sizeof(struct bt_att_read_blob_req)) {
+ send_error(conn_handle, BT_ATT_OP_READ_BLOB_REQ, 0x0000, BT_ATT_ERR_INVALID_PDU);
+ return;
+ }
+
+ struct bt_att_read_blob_req *req = (struct bt_att_read_blob_req *) data;
+ handle = req->handle;
+ offset = req->offset;
+ response_opcode = BT_ATT_OP_READ_BLOB_RSP;
+ }
+
+ //FIX
+ (void) offset;
+ (void) handle;
+ //FIX if ((uint16_t)(handle - 1) > GATT.attributeCount()) {
+ // send_error(conn_handle, opcode, handle, BT_ATT_ERR_ATTR_NOT_FOUND);
+ // return;
+ // }
+
+ uint8_t response[mtu];
+ uint16_t response_length;
+
+ response[0] = response_opcode;
+ response_length = 1;
+
+ //FIX BLELocalAttribute* attribute = GATT.attribute(handle - 1);
+ // enum BLEAttributeType attributeType = attribute->type();
+
+ // if (attributeType == BLE_TYPE_PRIMARY_SERVICE) {
+ // if (offset) {
+ // send_error(conn_handle, BT_ATT_ERR_ATTR_NOT_LONG, handle, BT_ATT_ERR_INVALID_PDU);
+ // return;
+ // }
+
+ // BLELocalService* service = (BLELocalService*)attribute;
+
+ // // add the UUID
+ // uint8_t uuidLen = service->uuidLength();
+ // memcpy(&response[response_length], service->uuidData(), uuidLen);
+ // response_length += uuidLen;
+ // } else if (attributeType == BLE_TYPE_CHARACTERISTIC) {
+ // BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute;
+
+ // if (characteristic->handle() == handle) {
+ // if (offset) {
+ // send_error(conn_handle, opcode, handle, BT_ATT_ERR_ATTR_NOT_LONG);
+ // return;
+ // }
+
+ // // add the properties
+ // response[response_length++] = characteristic->properties();
+
+ // // add the value handle
+ // uint16_t value_handle = characteristic->value_handle();
+ // memcpy(&response[response_length], &value_handle, sizeof(value_handle));
+ // response_length += sizeof(value_handle);
+
+ // // add the UUID
+ // uint8_t uuidLen = characteristic->uuidLength();
+ // memcpy(&response[response_length], characteristic->uuidData(), uuidLen);
+ // response_length += uuidLen;
+ // } else {
+ // if ((characteristic->properties() & BLERead) == 0) {
+ // send_error(conn_handle, opcode, handle, BT_ATT_ERR_READ_NOT_PERM);
+ // return;
+ // }
+
+ // uint16_t value_length = characteristic->value_length();
+
+ // if (offset >= value_length) {
+ // send_error(conn_handle, opcode, handle, BT_ATT_ERR_INVALID_OFFSET);
+ // return;
+ // }
+
+ // value_length = min(mtu - response_length, value_length - offset);
+
+ // for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
+ // if (bleio_connections[i].conn_handle == conn_handle) {
+ // // FIX characteristic->readValue(BLEDevice(bleio_connections[i].address_type, bleio_connections[i].address), offset, &response[response_length], value_length);
+ // response_length += value_length;
+ // }
+ // }
+ // }
+ // } else if (attributeType == BLE_TYPE_DESCRIPTOR) {
+ // BLELocalDescriptor* descriptor = (BLELocalDescriptor*)attribute;
+
+ // uint16_t value_length = descriptor->valueSize();
+
+ // if (offset >= value_length) {
+ // send_error(conn_handle, opcode, handle, BT_ATT_ERR_INVALID_OFFSET);
+ // return;
+ // }
+
+ // value_length = min(mtu - response_length, value_length - offset);
+
+ // memcpy(&response[response_length], descriptor->value() + offset, value_length);
+ // response_length += value_length;
+ // }
+
+ hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, response_length, response);
+}
+
+STATIC void process_read_rsp(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) {
+ check_and_save_expected_rsp(conn_handle, BT_ATT_OP_READ_RSP, dlen, data);
+}
+
+STATIC void process_read_by_type_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, uint8_t data[]) {
+ struct bt_att_read_type_req *req = (struct bt_att_read_type_req *) data;
+
+ if (dlen != sizeof(struct bt_att_read_type_req)) {
+ send_error(conn_handle, BT_ATT_OP_READ_TYPE_REQ, req->start_handle, BT_ATT_ERR_INVALID_PDU);
+ return;
+ }
+
+ // uint8_t response[mtu];
+ // uint16_t response_length;
+
+ // response[0] = BT_ATT_OP_READ_TYPE_RSP;
+ // response[1] = 0x00;
+ // response_length = 2;
+
+ // for (uint16_t i = (req->start_handle - 1); i < GATT.attributeCount() && i <= (req->end_handle - 1); i++) {
+ // BLELocalAttribute* attribute = GATT.attribute(i);
+ // uint16_t handle = (i + 1);
+
+ // if (attribute->type() == readByTypeReq->uuid) {
+ // if (attribute->type() == BLE_TYPE_CHARACTERISTIC) {
+ // BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute;
+
+ // if (characteristic->value_handle() == handle) {
+ // // value handle, skip
+ // continue;
+ // }
+
+ // int uuidLen = attribute->uuidLength();
+ // int typeSize = (uuidLen == 2) ? 7 : 21;
+
+ // if (response[1] == 0) {
+ // response[1] = typeSize;
+ // }
+
+ // if (response[1] != typeSize) {
+ // // all done, wrong size
+ // break;
+ // }
+
+ // // add the handle
+ // memcpy(&response[response_length], &handle, sizeof(handle));
+ // response_length += sizeof(handle);
+
+ // // add the properties
+ // response[response_length++] = characteristic->properties();
+
+ // // add the value handle
+ // uint16_t value_handle = (handle + 1);
+ // memcpy(&response[response_length], &value_handle, sizeof(value_handle));
+ // response_length += sizeof(value_handle);
+
+ // // add the UUID
+ // memcpy(&response[response_length], characteristic->uuidData(), uuidLen);
+ // response_length += uuidLen;
+
+ // // skip the next handle, it's a value handle
+ // i++;
+
+ // if ((response_length + typeSize) > mtu) {
+ // break;
+ // }
+ // } else if (attribute->type() == 0x2902) {
+ // BLELocalDescriptor* descriptor = (BLELocalDescriptor*)attribute;
+
+ // // add the handle
+ // memcpy(&response[response_length], &handle, sizeof(handle));
+ // response_length += sizeof(handle);
+
+ // // add the value
+ // int valueSize = min((uint16_t)(mtu - response_length), (uint16_t)descriptor->valueSize());
+ // memcpy(&response[response_length], descriptor->value(), valueSize);
+ // response_length += valueSize;
+
+ // response[1] = 2 + valueSize;
+
+ // break; // all done
+ // }
+ // } else if (attribute->type() == BLE_TYPE_CHARACTERISTIC && attribute->uuidLength() == 2 && memcmp(&readByTypeReq->uuid, attribute->uuidData(), 2) == 0) {
+ // BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute;
+
+ // // add the handle
+ // memcpy(&response[response_length], &handle, sizeof(handle));
+ // response_length += sizeof(handle);
+
+ // // add the value
+ // int value_length = min((uint16_t)(mtu - response_length), (uint16_t)characteristic->value_length());
+ // memcpy(&response[response_length], characteristic->value(), value_length);
+ // response_length += value_length;
+
+ // response[1] = 2 + value_length;
+
+ // break; // all done
+ // }
+ // }
+
+ // if (response_length == 2) {
+ // send_error(conn_handle, BT_ATT_OP_READ_BY_TYPE_REQ, readByTypeReq->start_handle, BT_ATT_ERR_ATTR_NOT_FOUND);
+ // } else {
+ // hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, response_length, response);
+ // }
+}
+
+int att_read_by_type_req(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, uint16_t type, uint8_t response_buffer[]) {
+ struct __packed {
+ struct bt_att_hdr h;
+ struct bt_att_read_type_req r;
+ } req = { {
+ .code = BT_ATT_OP_READ_TYPE_REQ,
+ }, {
+ .start_handle = start_handle,
+ .end_handle = end_handle,
+ }
+ };
+ req.r.uuid[0] = type & 0xff;
+ req.r.uuid[1] = type >> 8;
+
+ return send_req_wait_for_rsp(conn_handle, sizeof(req), (uint8_t *) &req, response_buffer);
+}
+
+void att_read_by_type_rsp(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) {
+ if (dlen < 1) {
+ return; // invalid, drop
+ }
+
+ check_and_save_expected_rsp(conn_handle, BT_ATT_OP_READ_TYPE_RSP, dlen, data);
+}
+
+// Handles BT_ATT_OP_WRITE_REQ or BT_ATT_OP_WRITE_
+STATIC void process_req_or_cmd(uint16_t conn_handle, uint16_t mtu, uint8_t op, uint8_t dlen, uint8_t data[]) {
+ boolean with_response = (op == BT_ATT_OP_WRITE_REQ);
+
+ if (dlen < sizeof(struct bt_att_write_req)) {
+ if (with_response) {
+ send_error(conn_handle, BT_ATT_OP_WRITE_REQ, 0x0000, BT_ATT_ERR_INVALID_PDU);
+ }
+ return;
+ }
+
+ uint16_t handle = *(uint16_t*)data;
+
+ // if ((uint16_t)(handle - 1) > GATT.attributeCount()) {
+ // if (with_response) {
+ // send_error(conn_handle, BT_ATT_OP_WRITE_REQ, handle, BT_ATT_ERR_ATTR_NOT_FOUND);
+ // }
+ // return;
+ // }
+
+ // uint8_t value_length = dlen - sizeof(handle);
+ // uint8_t* value = &data[sizeof(handle)];
+
+ // BLELocalAttribute* attribute = GATT.attribute(handle - 1);
+
+ // if (attribute->type() == BLE_TYPE_CHARACTERISTIC) {
+ // BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute;
+
+ // if (handle != characteristic->value_handle() ||
+ // withResponse ? ((characteristic->properties() & BLEWrite) == 0) :
+ // ((characteristic->properties() & BLEWriteWithoutResponse) == 0)) {
+ // if (withResponse) {
+ // send_error(conn_handle, BT_ATT_OP_WRITE_REQ, handle, BT_ATT_ERR_WRITE_NOT_PERM);
+ // }
+ // return;
+ // }
+
+ // for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
+ // if (bleio_connections[i].conn_handle == conn_handle) {
+ // // FIX characteristic->writeValue(BLEDevice(bleio_connections[i].address_type, bleio_connections[i].address), value, value_length);
+ // break;
+ // }
+ // }
+ // } else if (attribute->type() == BLE_TYPE_DESCRIPTOR) {
+ // BLELocalDescriptor* descriptor = (BLELocalDescriptor*)attribute;
+
+ // // only CCCD's are writable
+ // if (descriptor->uuidLength() != 2 || *((uint16_t*)(descriptor->uuidData())) != 0x2902) {
+ // if (withResponse) {
+ // send_error(conn_handle, BT_ATT_OP_WRITE_REQ, handle, BT_ATT_ERR_WRITE_NOT_PERM);
+ // }
+ // return;
+ // }
+
+ // // get the previous handle, should be the characteristic for the CCCD
+ // attribute = GATT.attribute(handle - 2);
+
+ // if (attribute->type() != BLE_TYPE_CHARACTERISTIC) {
+ // if (withResponse) {
+ // send_error(conn_handle, BT_ATT_OP_WRITE_REQ, handle, BT_ATT_ERR_WRITE_NOT_PERM);
+ // }
+ // return;
+ // }
+
+ // BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute;
+
+ // for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
+ // if (bleio_connections[i].conn_handle == conn_handle) {
+ // //FIX characteristic->writeCccdValue(BLEDevice(bleio_connections[i].address_type, bleio_connections[i].address), *((uint16_t*)value));
+ // break;
+ // }
+ // }
+ // } else {
+ // if (withResponse) {
+ // send_error(conn_handle, BT_ATT_OP_WRITE_REQ, handle, BT_ATT_ERR_WRITE_NOT_PERM);
+ // }
+ // return;
+ // }
+
+ if (withResponse) {
+ uint8_t response[mtu];
+ uint16_t response_length;
+
+ response[0] = BT_ATT_OP_WRITE_RSP;
+ response_length = 1;
+
+ hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, response_length, response);
+ }
+}
+
+STATIC void process_write_rsp(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) {
+ if (dlen != 0) {
+ return; // drop
+ }
+
+ check_and_save_expected_rsp(conn_handle, BT_ATT_OP_WRITE_RSP, dlen, data);
+}
+
+STATIC void process_prep_write_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, uint8_t data[]) {
+ struct __attribute__ ((packed)) PrepWriteReq {
+ uint16_t handle;
+ uint16_t offset;
+ } *prepWriteReq = (PrepWriteReq*)data;
+
+ if (dlen < sizeof(PrepWriteReq)) {
+ send_error(conn_handle, BT_ATT_OP_PREP_WRITE_REQ, 0x0000, BT_ATT_ERR_INVALID_PDU);
+ return;
+ }
+
+ uint16_t handle = prepWriteReq->handle;
+ uint16_t offset = prepWriteReq->offset;
+
+ if ((uint16_t)(handle - 1) > GATT.attributeCount()) {
+ send_error(conn_handle, BT_ATT_OP_PREP_WRITE_REQ, handle, BT_ATT_ERR_ATTR_NOT_FOUND);
+ return;
+ }
+
+ BLELocalAttribute* attribute = GATT.attribute(handle - 1);
+
+ if (attribute->type() != BLE_TYPE_CHARACTERISTIC) {
+ send_error(conn_handle, BT_ATT_OP_PREP_WRITE_REQ, handle, BT_ATT_ERR_ATTR_NOT_LONG);
+ return;
+ }
+
+ BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute;
+
+ if (handle != characteristic->value_handle()) {
+ send_error(conn_handle, BT_ATT_OP_PREP_WRITE_REQ, handle, BT_ATT_ERR_ATTR_NOT_LONG);
+ return;
+ }
+
+ if ((characteristic->properties() & BLEWrqite) == 0) {
+ send_error(conn_handle, BT_ATT_OP_PREP_WRITE_REQ, handle, BT_ATT_ERR_WRITE_NOT_PERM);
+ return;
+ }
+
+ if (long_write_handle == 0) {
+ int valueSize = characteristic->valueSize();
+
+ long_write_value = (uint8_t*)realloc(long_write_value, valueSize);
+ long_write_value_length = 0;
+ long_write_handle = handle;
+
+ memset(long_write_value, 0x00, valueSize);
+ } else if (long_write_handle != handle) {
+ send_error(conn_handle, BT_ATT_OP_PREP_WRITE_REQ, handle, BT_ATT_ERR_UNLIKELY);
+ return;
+ }
+
+ uint8_t value_length = dlen - sizeof(PrepWriteReq);
+ uint8_t* value = &data[sizeof(PrepWriteReq)];
+
+ if ((offset != long_write_value_length) || ((offset + value_length) > (uint16_t)characteristic->valueSize())) {
+ send_error(conn_handle, BT_ATT_OP_PREP_WRITE_REQ, handle, BT_ATT_ERR_INVALID_OFFSET);
+ return;
+ }
+
+ memcpy(long_write_value + offset, value, value_length);
+ long_write_value_length += value_length;
+
+ uint8_t response[mtu];
+ uint16_t response_length;
+
+ response[0] = BT_ATT_OP_PREP_WRITE_RSP;
+ memcpy(&response[1], data, dlen);
+ response_length = dlen + 1;
+
+ hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, response_length, response);
+}
+
+STATIC void process_exec_write_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, uint8_t data[]) {
+ if (dlen != sizeof(uint8_t)) {
+ send_error(conn_handle, BT_ATT_OP_EXEC_WRITE_REQ, 0x0000, BT_ATT_ERR_INVALID_PDU);
+ return;
+ }
+
+ uint8_t flag = data[0];
+
+ if (long_write_handle && (flag & 0x01)) {
+ BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)GATT.attribute(long_write_handle - 1);
+
+ for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
+ if (bleio_connections[i].conn_handle == conn_handle) {
+ //FIX characteristic->writeValue(BLEDevice(bleio_connections[i].address_type, bleio_connections[i].address), long_write_value, long_write_value_length);
+ break;
+ }
+ }
+ }
+
+ long_write_handle = 0x0000;
+ long_write_value_length = 0;
+
+ uint8_t response[mtu];
+ uint16_t response_length;
+
+ response[0] = BT_ATT_OP_EXEC_WRITE_RSP;
+ response_length = 1;
+
+ hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, response_length, response);
+}
+
+STATIC void process_handle_notify_or_ind(uint16_t conn_handle, uint8_t opcode, uint8_t dlen, uint8_t data[]) {
+ if (dlen < 2) {
+ return; // drop
+ }
+
+ struct __attribute__ ((packed)) _handleNotifyOrInd {
+ uint16_t handle;
+ } *handleNotifyOrInd = (_handleNotifyOrInd*)data;
+
+ uint8_t handle = handleNotifyOrInd->handle;
+
+ for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
+ if (bleio_connections[i].conn_handle != conn_handle) {
+ continue;
+ }
+
+ BLERemoteDevice* device = bleio_connections[i].device;
+
+ if (!device) {
+ break;
+ }
+
+ int serviceCount = device->serviceCount();
+
+ for (size_t i = 0; i < serviceCount; i++) {
+ BLERemoteService* s = device->service(i);
+
+ if (s->start_handle() < handle && s->end_handle() >= handle) {
+ int characteristicCount = s->characteristicCount();
+
+ for (int j = 0; j < characteristicCount; j++) {
+ BLERemoteCharacteristic* c = s->characteristic(j);
+
+ if (c->value_handle() == handle) {
+ //FIX c->writeValue(BLEDevice(bleio_connections[i].address_type, bleio_connections[i].address), &data[2], dlen - 2);
+ }
+ }
+
+ break;
+ }
+ }
+ }
+
+ if (opcode == BT_ATT_OP_HANDLE_IND) {
+ // send CNF for IND
+
+ uint8_t cnf = BT_ATT_OP_HANDLE_CNF;
+
+ hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, sizeof(cnf), &cnf);
+ }
+}
+
+STATIC void process_handle_cnf(uint16_t /*conn_handle*/, uint8_t /*dlen*/, uint8_t /*data*/[]) {
+ cnf = true;
+}
+
+bool att_exchange_mtu(uint16_t conn_handle) {
+ uint8_t response_buffer[max_mtu];
+ struct bt_att_exchange_mtu_req req;
+ req->mtu = max_mtu;
+ return send_req_wait_for_rsp(conn_handle, BT_ATT_OP_MTU_REQ, &req, sizeof(req), response_buffer);
+}
+
+
+
+void att_set_event_handler(BLEDeviceEvent event, BLEDeviceEventHandler event_handler) {
+ if (event < (sizeof(event_handlers) / (sizeof(event_handlers[0])))) {
+ event_handlers[event] = event_handler;
+ }
+}
+
+int att_read_req(uint16_t conn_handle, uint16_t handle, uint8_t response_buffer[]) {
+ struct __attribute__ ((packed)) {
+ uint8_t op;
+ uint16_t handle;
+ } read_req = { BT_ATT_OP_READ_REQ, handle };
+
+ return send_req_wait_for_rsp(conn_handle, &read_req, sizeof(read_req), response_buffer);
+}
+
+int att_write_req(uint16_t conn_handle, uint16_t handle, const uint8_t* data, uint8_t data_len, uint8_t response_buffer[]) {
+ struct __attribute__ ((packed)) {
+ uint8_t op;
+ uint16_t handle;
+ uint8_t data[255];
+ } write_req;
+
+ write_req.opcode = BT_ATT_OP_WRITE_REQ;
+ write_req.handle = handle;
+ memcpy(write_req.data, data, data_len);
+
+ return send_req_wait_for_rsp(conn_handle, &write_req, 3 + data_len, response_buffer);
+}
+
+void att_write_cmd(uint16_t conn_handle, uint16_t handle, const uint8_t* data, uint8_t data_len) {
+ struct bt_att_write_cmd req = {
+ .handle = handle,
+ };
+ memcpy(req.value, data, data_len);
+
+ send_req_wait_for_rsp(conn_handle, &req, data_len + sizeof(req), NULL);
+}
+
+void att_process_data(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) {
+ // Opcode is a single byte at the front of the data.
+ uint8_t opcode = data[0];
+
+ // Skip over opcode.
+ dlen--;
+ data++;
+
+ uint16_t mtu = this->mtu(conn_handle);
+
+ switch (opcode) {
+ case BT_ATT_OP_ERROR_RSP:
+ process_error(conn_handle, dlen, data);
+ break;
+
+ case BT_ATT_OP_MTU_REQ:
+ process_mtu_req(conn_handle, dlen, data);
+ break;
+
+ case BT_ATT_OP_MTU_RSP:
+ process_mtu_rsp(conn_handle, dlen, data);
+ break;
+
+ case BT_ATT_OP_FIND_INFO_REQ:
+ process_find_info_req(conn_handle, mtu, dlen, data);
+ break;
+
+ case BT_ATT_OP_FIND_INFO_RSP:
+ process_find_info_rsp(conn_handle, dlen, data);
+ break;
+
+ case BT_ATT_OP_FIND_BY_TYPE_REQ:
+ process_find_by_type_req(conn_handle, mtu, dlen, data);
+ break;
+
+ case BT_ATT_OP_READ_BY_TYPE_REQ:
+ process_read_by_type_req(conn_handle, mtu, dlen, data);
+ break;
+
+ case BT_ATT_OP_READ_BY_TYPE_RSP:
+ process_read_by_type_rsp(conn_handle, dlen, data);
+ break;
+
+ case BT_ATT_OP_READ_BY_GROUP_REQ:
+ att_read_by_group_req(conn_handle, mtu, dlen, data);
+ break;
+
+ case BT_ATT_OP_READ_BY_GROUP_RSP:
+ prcoess_read_by_group_rsp(conn_handle, dlen, data);
+ break;
+
+ case BT_ATT_OP_READ_REQ:
+ case BT_ATT_OP_READ_BLOB_REQ:
+ process_read_or_read_blob_req(conn_handle, mtu, opcode, dlen, data);
+ break;
+
+ case BT_ATT_OP_READ_RSP:
+ process_read_rsp(conn_handle, dlen, data);
+ break;
+
+ case BT_ATT_OP_WRITE_REQ:
+ case BT_ATT_OP_WRITE_CMD:
+ process_write_req_or_cmd(conn_handle, mtu, opcode, dlen, data);
+ break;
+
+ case BT_ATT_OP_WRITE_RSP:
+ process_write_rsp(conn_handle, dlen, data);
+ break;
+
+ case BT_ATT_OP_PREP_WRITE_REQ:
+ process_prep_write_req(conn_handle, mtu, dlen, data);
+ break;
+
+ case BT_ATT_OP_EXEC_WRITE_REQ:
+ process_exec_write_req(conn_handle, mtu, dlen, data);
+ break;
+
+ case BT_ATT_OP_HANDLE_NOTIFY:
+ case BT_ATT_OP_HANDLE_IND:
+ process_handle_notify_or_ind(conn_handle, opcode, dlen, data);
+ break;
+
+ case BT_ATT_OP_HANDLE_CNF:
+ process_handle_cnf(conn_handle, dlen, data);
+ break;
+
+ case BT_ATT_OP_READ_MULTI_REQ:
+ case BT_ATT_OP_SIGNED_WRITE_CMD:
+ default:
+ send_error(conn_handle, opcode, 0x00, BT_ATT_ERR_REQ_NOT_SUPP);
+ break;
+ }
+}
diff --git a/devices/ble_hci/common-hal/_bleio/att.h b/devices/ble_hci/common-hal/_bleio/att.h
new file mode 100644
index 000000000..108c44929
--- /dev/null
+++ b/devices/ble_hci/common-hal/_bleio/att.h
@@ -0,0 +1,57 @@
+// Derived from ArduinoBLE.
+// Copyright 2020 Dan Halbert for Adafruit Industries
+
+/*
+ This file is part of the ArduinoBLE library.
+ Copyright (c) 2018 Arduino SA. All rights reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef MICROPY_INCLUDED_DEVICES_BLE_HCI_COMMON_HAL_BLEIO_ATT_H
+#define MICROPY_INCLUDED_DEVICES_BLE_HCI_COMMON_HAL_BLEIO_ATT_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#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
index 854f7c0a0..83aba883a 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 <string.h>
@@ -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
index f6d96d48f..736877ddc 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 <stdint.h>
@@ -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 8f503b8a1..fd74a95e8 100644
--- a/devices/ble_hci/common-hal/_bleio/hci_include/addr.h
+++ b/devices/ble_hci/common-hal/_bleio/hci_include/addr.h
@@ -12,6 +12,7 @@
#ifndef ZEPHYR_INCLUDE_BLUETOOTH_ADDR_H_
#define ZEPHYR_INCLUDE_BLUETOOTH_ADDR_H_
+#include <stdbool.h>
#include <string.h>
/**
diff --git a/devices/ble_hci/common-hal/_bleio/hci_include/att.h b/devices/ble_hci/common-hal/_bleio/hci_include/att.h
new file mode 100644
index 000000000..8117a48f4
--- /dev/null
+++ b/devices/ble_hci/common-hal/_bleio/hci_include/att.h
@@ -0,0 +1,41 @@
+// CircuitPython: Adapted from Zephyr include file.
+/** @file
+ * @brief Attribute Protocol handling.
+ */
+
+/*
+ * Copyright (c) 2016 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef ZEPHYR_INCLUDE_BLUETOOTH_ATT_H_
+#define ZEPHYR_INCLUDE_BLUETOOTH_ATT_H_
+
+/* Error codes for Error response PDU */
+#define BT_ATT_ERR_INVALID_HANDLE 0x01
+#define BT_ATT_ERR_READ_NOT_PERMITTED 0x02
+#define BT_ATT_ERR_WRITE_NOT_PERMITTED 0x03
+#define BT_ATT_ERR_INVALID_PDU 0x04
+#define BT_ATT_ERR_AUTHENTICATION 0x05
+#define BT_ATT_ERR_NOT_SUPPORTED 0x06
+#define BT_ATT_ERR_INVALID_OFFSET 0x07
+#define BT_ATT_ERR_AUTHORIZATION 0x08
+#define BT_ATT_ERR_PREPARE_QUEUE_FULL 0x09
+#define BT_ATT_ERR_ATTRIBUTE_NOT_FOUND 0x0a
+#define BT_ATT_ERR_ATTRIBUTE_NOT_LONG 0x0b
+#define BT_ATT_ERR_ENCRYPTION_KEY_SIZE 0x0c
+#define BT_ATT_ERR_INVALID_ATTRIBUTE_LEN 0x0d
+#define BT_ATT_ERR_UNLIKELY 0x0e
+#define BT_ATT_ERR_INSUFFICIENT_ENCRYPTION 0x0f
+#define BT_ATT_ERR_UNSUPPORTED_GROUP_TYPE 0x10
+#define BT_ATT_ERR_INSUFFICIENT_RESOURCES 0x11
+#define BT_ATT_ERR_DB_OUT_OF_SYNC 0x12
+#define BT_ATT_ERR_VALUE_NOT_ALLOWED 0x13
+
+/* Common Profile Error Codes (from CSS) */
+#define BT_ATT_ERR_WRITE_REQ_REJECTED 0xfc
+#define BT_ATT_ERR_CCC_IMPROPER_CONF 0xfd
+#define BT_ATT_ERR_PROCEDURE_IN_PROGRESS 0xfe
+#define BT_ATT_ERR_OUT_OF_RANGE 0xff
+
+#endif /* ZEPHYR_INCLUDE_BLUETOOTH_ATT_H_ */
diff --git a/devices/ble_hci/common-hal/_bleio/hci_include/att_internal.h b/devices/ble_hci/common-hal/_bleio/hci_include/att_internal.h
new file mode 100644
index 000000000..1c75275da
--- /dev/null
+++ b/devices/ble_hci/common-hal/_bleio/hci_include/att_internal.h
@@ -0,0 +1,266 @@
+// CircuitPython: Adapted from Zephyr include file.
+
+/* att_internal.h - Attribute protocol handling */
+
+/*
+ * Copyright (c) 2015-2016 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+
+#include <stdbool.h>
+// for __packed
+#include <string.h>
+
+#define BT_EATT_PSM 0x27
+#define BT_ATT_DEFAULT_LE_MTU 23
+#define BT_ATT_TIMEOUT K_SECONDS(30)
+
+//FIX #if BT_L2CAP_RX_MTU < CONFIG_BT_L2CAP_TX_MTU
+// #define BT_ATT_MTU BT_L2CAP_RX_MTU
+// #else
+// #define BT_ATT_MTU CONFIG_BT_L2CAP_TX_MTU
+// #endif
+
+struct bt_att_hdr {
+ uint8_t code;
+} __packed;
+
+#define BT_ATT_OP_ERROR_RSP 0x01
+struct bt_att_error_rsp {
+ uint8_t request;
+ uint16_t handle;
+ uint8_t error;
+} __packed;
+
+#define BT_ATT_OP_MTU_REQ 0x02
+struct bt_att_exchange_mtu_req {
+ uint16_t mtu;
+} __packed;
+
+#define BT_ATT_OP_MTU_RSP 0x03
+struct bt_att_exchange_mtu_rsp {
+ uint16_t mtu;
+} __packed;
+
+/* Find Information Request */
+#define BT_ATT_OP_FIND_INFO_REQ 0x04
+struct bt_att_find_info_req {
+ uint16_t start_handle;
+ uint16_t end_handle;
+} __packed;
+
+/* Format field values for BT_ATT_OP_FIND_INFO_RSP */
+#define BT_ATT_INFO_16 0x01
+#define BT_ATT_INFO_128 0x02
+
+struct bt_att_info_16 {
+ uint16_t handle;
+ uint16_t uuid;
+} __packed;
+
+struct bt_att_info_128 {
+ uint16_t handle;
+ uint8_t uuid[16];
+} __packed;
+
+/* Find Information Response */
+#define BT_ATT_OP_FIND_INFO_RSP 0x05
+struct bt_att_find_info_rsp {
+ uint8_t format;
+ uint8_t info[0];
+} __packed;
+
+/* Find By Type Value Request */
+#define BT_ATT_OP_FIND_TYPE_REQ 0x06
+struct bt_att_find_type_req {
+ uint16_t start_handle;
+ uint16_t end_handle;
+ uint16_t type;
+ uint8_t value[0];
+} __packed;
+
+struct bt_att_handle_group {
+ uint16_t start_handle;
+ uint16_t end_handle;
+} __packed;
+
+/* Find By Type Value Response */
+#define BT_ATT_OP_FIND_TYPE_RSP 0x07
+struct bt_att_find_type_rsp {
+ struct bt_att_handle_group list[0];
+} __packed;
+
+/* Read By Type Request */
+#define BT_ATT_OP_READ_TYPE_REQ 0x08
+struct bt_att_read_type_req {
+ uint16_t start_handle;
+ uint16_t end_handle;
+ uint8_t uuid[0];
+} __packed;
+
+struct bt_att_data {
+ uint16_t handle;
+ uint8_t value[0];
+} __packed;
+
+/* Read By Type Response */
+#define BT_ATT_OP_READ_TYPE_RSP 0x09
+struct bt_att_read_type_rsp {
+ uint8_t len;
+ struct bt_att_data data[0];
+} __packed;
+
+/* Read Request */
+#define BT_ATT_OP_READ_REQ 0x0a
+struct bt_att_read_req {
+ uint16_t handle;
+} __packed;
+
+/* Read Response */
+#define BT_ATT_OP_READ_RSP 0x0b
+struct bt_att_read_rsp {
+ uint8_t value[0];
+} __packed;
+
+/* Read Blob Request */
+#define BT_ATT_OP_READ_BLOB_REQ 0x0c
+struct bt_att_read_blob_req {
+ uint16_t handle;
+ uint16_t offset;
+} __packed;
+
+/* Read Blob Response */
+#define BT_ATT_OP_READ_BLOB_RSP 0x0d
+struct bt_att_read_blob_rsp {
+ uint8_t value[0];
+} __packed;
+
+/* Read Multiple Request */
+#define BT_ATT_READ_MULT_MIN_LEN_REQ 0x04
+
+#define BT_ATT_OP_READ_MULT_REQ 0x0e
+struct bt_att_read_mult_req {
+ uint16_t handles[0];
+} __packed;
+
+/* Read Multiple Respose */
+#define BT_ATT_OP_READ_MULT_RSP 0x0f
+struct bt_att_read_mult_rsp {
+ uint8_t value[0];
+} __packed;
+
+/* Read by Group Type Request */
+#define BT_ATT_OP_READ_GROUP_REQ 0x10
+struct bt_att_read_group_req {
+ uint16_t start_handle;
+ uint16_t end_handle;
+ uint8_t uuid[0];
+} __packed;
+
+struct bt_att_group_data {
+ uint16_t start_handle;
+ uint16_t end_handle;
+ uint8_t value[0];
+} __packed;
+
+/* Read by Group Type Response */
+#define BT_ATT_OP_READ_GROUP_RSP 0x11
+struct bt_att_read_group_rsp {
+ uint8_t len;
+ struct bt_att_group_data data[0];
+} __packed;
+
+/* Write Request */
+#define BT_ATT_OP_WRITE_REQ 0x12
+struct bt_att_write_req {
+ uint16_t handle;
+ uint8_t value[0];
+} __packed;
+
+/* Write Response */
+#define BT_ATT_OP_WRITE_RSP 0x13
+
+/* Prepare Write Request */
+#define BT_ATT_OP_PREPARE_WRITE_REQ 0x16
+struct bt_att_prepare_write_req {
+ uint16_t handle;
+ uint16_t offset;
+ uint8_t value[0];
+} __packed;
+
+/* Prepare Write Respond */
+#define BT_ATT_OP_PREPARE_WRITE_RSP 0x17
+struct bt_att_prepare_write_rsp {
+ uint16_t handle;
+ uint16_t offset;
+ uint8_t value[0];
+} __packed;
+
+/* Execute Write Request */
+#define BT_ATT_FLAG_CANCEL 0x00
+#define BT_ATT_FLAG_EXEC 0x01
+
+#define BT_ATT_OP_EXEC_WRITE_REQ 0x18
+struct bt_att_exec_write_req {
+ uint8_t flags;
+} __packed;
+
+/* Execute Write Response */
+#define BT_ATT_OP_EXEC_WRITE_RSP 0x19
+
+/* Handle Value Notification */
+#define BT_ATT_OP_NOTIFY 0x1b
+struct bt_att_notify {
+ uint16_t handle;
+ uint8_t value[0];
+} __packed;
+
+/* Handle Value Indication */
+#define BT_ATT_OP_INDICATE 0x1d
+struct bt_att_indicate {
+ uint16_t handle;
+ uint8_t value[0];
+} __packed;
+
+/* Handle Value Confirm */
+#define BT_ATT_OP_CONFIRM 0x1e
+
+struct bt_att_signature {
+ uint8_t value[12];
+} __packed;
+
+#define BT_ATT_OP_READ_MULT_VL_REQ 0x20
+struct bt_att_read_mult_vl_req {
+ uint16_t handles[0];
+} __packed;
+
+/* Read Multiple Respose */
+#define BT_ATT_OP_READ_MULT_VL_RSP 0x21
+struct bt_att_read_mult_vl_rsp {
+ uint16_t len;
+ uint8_t value[0];
+} __packed;
+
+/* Handle Multiple Value Notification */
+#define BT_ATT_OP_NOTIFY_MULT 0x23
+struct bt_att_notify_mult {
+ uint16_t handle;
+ uint16_t len;
+ uint8_t value[0];
+} __packed;
+
+/* Write Command */
+#define BT_ATT_OP_WRITE_CMD 0x52
+struct bt_att_write_cmd {
+ uint16_t handle;
+ uint8_t value[0];
+} __packed;
+
+/* Signed Write Command */
+#define BT_ATT_OP_SIGNED_WRITE_CMD 0xd2
+struct bt_att_signed_write_cmd {
+ uint16_t handle;
+ uint8_t value[0];
+} __packed;
diff --git a/devices/ble_hci/common-hal/_bleio/hci_include/hci.h b/devices/ble_hci/common-hal/_bleio/hci_include/hci.h
index 2de58b3d8..6c3a2b5bd 100644
--- a/devices/ble_hci/common-hal/_bleio/hci_include/hci.h
+++ b/devices/ble_hci/common-hal/_bleio/hci_include/hci.h
@@ -1,4 +1,5 @@
// CircuitPython: Adapted from Zephyr include file.
+
/* hci.h - Bluetooth Host Control Interface definitions */
/*
diff --git a/devices/ble_hci/common-hal/_bleio/hci_include/l2cap_internal.h b/devices/ble_hci/common-hal/_bleio/hci_include/l2cap_internal.h
new file mode 100644
index 000000000..bed311cf3
--- /dev/null
+++ b/devices/ble_hci/common-hal/_bleio/hci_include/l2cap_internal.h
@@ -0,0 +1,230 @@
+// CircuitPython: Adapted from Zephyr include file.
+
+/** @file
+ * @brief Internal APIs for Bluetooth L2CAP handling.
+ */
+
+/*
+ * Copyright (c) 2015-2016 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <stdbool.h>
+// for __packed
+#include <string.h>
+
+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;