ble_uart_echo_test works

This commit is contained in:
Dan Halbert 2020-08-13 00:03:39 -04:00
parent 06f3b4048a
commit 44c9c43cd1
24 changed files with 350 additions and 587 deletions

View File

@ -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."));
}

View File

@ -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.

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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

View File

@ -27,6 +27,8 @@
#include "shared-bindings/_bleio/Connection.h"
#include "att.h"
#include <string.h>
#include <stdio.h>
@ -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;
}

View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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));
}

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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

View File

@ -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,

View File

@ -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;

View File

@ -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));

View File

@ -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);

View File

@ -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;

View File

@ -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,
};