Skip to content
Snippets Groups Projects
Commit 68a8906a authored by schneider's avatar schneider
Browse files

Merge branch 'schneider/mp-ble-gattc' into 'master'

feat(mp-ble): add support for ATT client operation

See merge request !451
parents ffead262 51043956
No related branches found
No related tags found
1 merge request!451feat(mp-ble): add support for ATT client operation
Pipeline #5142 passed
...@@ -25,15 +25,29 @@ static int next_handle = ATTS_DYN_START_HANDLE; ...@@ -25,15 +25,29 @@ static int next_handle = ATTS_DYN_START_HANDLE;
void ble_epic_att_api_event(attEvt_t *att_event) void ble_epic_att_api_event(attEvt_t *att_event)
{ {
if (att_event->handle >= ATTS_DYN_START_HANDLE && if (att_event->hdr.event != ATTS_HANDLE_VALUE_CNF ||
att_event->handle < next_handle) { (att_event->handle >= ATTS_DYN_START_HANDLE &&
attEvt_t *e = WsfBufAlloc(sizeof(*e)); att_event->handle < next_handle)) {
size_t value_len = 0;
if (att_event->hdr.event == ATTC_READ_BY_GROUP_TYPE_RSP ||
att_event->hdr.event == ATTC_READ_BY_TYPE_RSP ||
att_event->hdr.event == ATTC_FIND_INFO_RSP ||
att_event->hdr.event == ATTC_HANDLE_VALUE_NTF ||
att_event->hdr.event == ATTC_HANDLE_VALUE_IND) {
value_len = att_event->valueLen;
}
attEvt_t *e = WsfBufAlloc(sizeof(*e) + value_len);
if (e) { if (e) {
memcpy(e, att_event, sizeof(*e)); memcpy(e, att_event, sizeof(*e));
memcpy(e + 1, att_event->pValue, value_len);
ble_epic_ble_api_trigger_event(BLE_EVENT_ATT_EVENT, e); ble_epic_ble_api_trigger_event(BLE_EVENT_ATT_EVENT, e);
} else { } else {
LOG_WARN("ble", "could not allocate att event"); LOG_WARN(
"ble",
"could not allocate att event of size %d",
sizeof(*e) + att_event->valueLen
);
} }
} }
} }
...@@ -278,3 +292,70 @@ int epic_ble_atts_set_attr( ...@@ -278,3 +292,70 @@ int epic_ble_atts_set_attr(
uint8_t ret = AttsSetAttr(handle, value_len, (uint8_t *)value); uint8_t ret = AttsSetAttr(handle, value_len, (uint8_t *)value);
return ret; return ret;
} }
int epic_ble_attc_discover_primary_services(
uint8_t connId, const uint8_t *uuid, uint8_t uuid_len
) {
if (uuid_len == 0 || uuid == NULL) {
AttcReadByGroupTypeReq(
connId, 1, 0xFFFF, 2, (uint8_t *)attPrimSvcUuid, TRUE
);
} else {
AttcFindByTypeValueReq(
connId,
ATT_HANDLE_START,
ATT_HANDLE_MAX,
ATT_UUID_PRIMARY_SERVICE,
uuid_len,
(uint8_t *)uuid,
FALSE
);
}
return 0;
}
int epic_ble_attc_discover_characteristics(
uint8_t connId, uint16_t start_handle, uint16_t end_handle
) {
AttcReadByTypeReq(
connId,
start_handle,
end_handle,
ATT_16_UUID_LEN,
(uint8_t *)attChUuid,
TRUE
);
return 0;
}
int epic_ble_attc_discover_descriptors(
uint8_t connId, uint16_t start_handle, uint16_t end_handle
) {
AttcFindInfoReq(connId, start_handle, end_handle, TRUE);
return 0;
}
int epic_ble_attc_read(uint8_t connId, uint16_t value_handle)
{
AttcReadReq(connId, value_handle);
return 0;
}
int epic_ble_attc_write_no_rsp(
uint8_t connId,
uint16_t value_handle,
const uint8_t *value,
uint16_t value_len
) {
AttcWriteCmd(connId, value_handle, value_len, (uint8_t *)value);
return 0;
}
int epic_ble_attc_write(
uint8_t connId,
uint16_t value_handle,
const uint8_t *value,
uint16_t value_len
) {
AttcWriteReq(connId, value_handle, value_len, (uint8_t *)value);
return 0;
}
...@@ -182,6 +182,12 @@ typedef _Bool bool; ...@@ -182,6 +182,12 @@ typedef _Bool bool;
#define API_BLE_GET_ADDRESS 0x184 #define API_BLE_GET_ADDRESS 0x184
#define API_BLE_ADVERTISE 0x185 #define API_BLE_ADVERTISE 0x185
#define API_BLE_ADVERTISE_STOP 0x186 #define API_BLE_ADVERTISE_STOP 0x186
#define API_BLE_DISCOVER_PRIMARY_SERVICES 0x187
#define API_BLE_DISCOVER_CHARACTERISTICS 0x188
#define API_BLE_DISCOVER_DESCRIPTORS 0x189
#define API_BLE_ATTC_READ 0x18A
#define API_BLE_ATTC_WRITE_NO_RSP 0x18B
#define API_BLE_ATTC_WRITE 0x18C
/* clang-format on */ /* clang-format on */
...@@ -2666,5 +2672,11 @@ API(API_BLE_GET_ADDRESS, void epic_ble_get_address(uint8_t *addr)); ...@@ -2666,5 +2672,11 @@ API(API_BLE_GET_ADDRESS, void epic_ble_get_address(uint8_t *addr));
API(API_BLE_ADVERTISE, int epic_ble_advertise(int interval_us, const uint8_t *adv_data, size_t adv_data_len, const uint8_t *sr_data, size_t sr_data_len, bool connectable)); API(API_BLE_ADVERTISE, int epic_ble_advertise(int interval_us, const uint8_t *adv_data, size_t adv_data_len, const uint8_t *sr_data, size_t sr_data_len, bool connectable));
API(API_BLE_ADVERTISE_STOP, int epic_ble_advertise_stop(void)); API(API_BLE_ADVERTISE_STOP, int epic_ble_advertise_stop(void));
API(API_BLE_DISCOVER_PRIMARY_SERVICES, int epic_ble_attc_discover_primary_services(uint8_t connId, const uint8_t *uuid, uint8_t uuid_len));
API(API_BLE_DISCOVER_CHARACTERISTICS, int epic_ble_attc_discover_characteristics(uint8_t connId, uint16_t start_handle, uint16_t end_handle));
API(API_BLE_DISCOVER_DESCRIPTORS, int epic_ble_attc_discover_descriptors(uint8_t connId, uint16_t start_handle, uint16_t end_handle));
API(API_BLE_ATTC_READ, int epic_ble_attc_read(uint8_t connId, uint16_t value_handle));
API(API_BLE_ATTC_WRITE_NO_RSP, int epic_ble_attc_write_no_rsp(uint8_t connId, uint16_t value_handle, const uint8_t *value, uint16_t value_len));
API(API_BLE_ATTC_WRITE, int epic_ble_attc_write(uint8_t connId, uint16_t value_handle, const uint8_t *value, uint16_t value_len));
#endif /* _EPICARDIUM_H */ #endif /* _EPICARDIUM_H */
#include "modbluetooth_card10.h" #include "modbluetooth_card10.h"
#include "extmod/modbluetooth.h" #include "extmod/modbluetooth.h"
#include "py/runtime.h" #include "py/runtime.h"
#include "py/mperrno.h"
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
...@@ -27,6 +28,7 @@ typedef struct { ...@@ -27,6 +28,7 @@ typedef struct {
} gatts_status_entry_t; } gatts_status_entry_t;
static bool active = false; static bool active = false;
static mp_obj_bluetooth_uuid_t uuid_filter;
static void gatts_status_create_entry(mp_gatts_db_t db, uint16_t handle) static void gatts_status_create_entry(mp_gatts_db_t db, uint16_t handle)
{ {
...@@ -75,12 +77,195 @@ static void handle_att_event(struct epic_att_event *att_event) ...@@ -75,12 +77,195 @@ static void handle_att_event(struct epic_att_event *att_event)
e->notification_status = NOTIFICATION_STATUS_OVERFLOW; e->notification_status = NOTIFICATION_STATUS_OVERFLOW;
} }
} }
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
if (att_event->hdr.event == ATTC_READ_BY_GROUP_TYPE_RSP) {
// TODO: can we get the connection id from the event?
uint8_t *v = att_event->pValue;
uint8_t entry_size = v[0];
if (att_event->hdr.status == ATT_SUCCESS) {
for (size_t i = 1; i < att_event->valueLen;
i += entry_size) {
uint16_t start_handle = (v[i + 1] << 8) | v[i];
uint16_t end_handle =
(v[i + 3] << 8) | v[i + 2];
mp_obj_bluetooth_uuid_t service_uuid;
if (entry_size == 6) {
memcpy(service_uuid.data, v + i + 4, 2);
service_uuid.type =
MP_BLUETOOTH_UUID_TYPE_16;
} else if (entry_size == 20) {
memcpy(service_uuid.data,
v + i + 4,
16);
service_uuid.type =
MP_BLUETOOTH_UUID_TYPE_128;
}
mp_bluetooth_gattc_on_primary_service_result(
1,
start_handle,
end_handle,
&service_uuid
);
}
}
if (att_event->hdr.status != ATT_SUCCESS ||
att_event->continuing == 0) {
uint16_t status = 0;
mp_bluetooth_gattc_on_discover_complete(
MP_BLUETOOTH_IRQ_GATTC_SERVICE_DONE, 1, status
);
}
}
if (att_event->hdr.event == ATTC_READ_BY_TYPE_RSP) {
/* if read by type successful */
if (att_event->hdr.status == ATT_SUCCESS) {
// TODO: can we get the connection id from the event?
uint8_t *v = att_event->pValue;
uint8_t entry_size = v[0];
for (size_t i = 1; i < att_event->valueLen;
i += entry_size) {
uint16_t def_handle = (v[i + 1] << 8) | v[i];
uint8_t properties = v[i + 2];
uint16_t value_handle =
(v[i + 4] << 8) | v[i + 3];
mp_obj_bluetooth_uuid_t characteristic_uuid;
if (entry_size == 2 + 1 + 2 + 2) {
memcpy(characteristic_uuid.data,
v + i + 5,
2);
characteristic_uuid.type =
MP_BLUETOOTH_UUID_TYPE_16;
} else if (entry_size == 2 + 1 + 2 + 16) {
memcpy(characteristic_uuid.data,
v + i + 5,
16);
characteristic_uuid.type =
MP_BLUETOOTH_UUID_TYPE_128;
}
// TODO: uuid_filter is set: compare against uuid
mp_bluetooth_gattc_on_characteristic_result(
1,
def_handle,
value_handle,
properties,
&characteristic_uuid
);
}
}
if (att_event->hdr.status != ATT_SUCCESS ||
att_event->continuing == 0) {
uint16_t status = 0;
mp_bluetooth_gattc_on_discover_complete(
MP_BLUETOOTH_IRQ_GATTC_CHARACTERISTIC_DONE,
1,
status
);
}
}
if (att_event->hdr.event == ATTC_FIND_INFO_RSP) {
if (att_event->hdr.status == ATT_SUCCESS) {
// TODO: can we get the connection id from the event?
uint8_t *v = att_event->pValue;
uint8_t entry_size = v[0] == 1 ? 4 : 18;
for (size_t i = 1; i < att_event->valueLen;
i += entry_size) {
uint16_t descriptor_handle =
(v[i + 1] << 8) | v[i];
mp_obj_bluetooth_uuid_t descriptor_uuid;
if (entry_size == 2 + 2) {
memcpy(descriptor_uuid.data,
v + i + 2,
2);
descriptor_uuid.type =
MP_BLUETOOTH_UUID_TYPE_16;
} else if (entry_size == 2 + 16) {
memcpy(descriptor_uuid.data,
v + i + 2,
16);
descriptor_uuid.type =
MP_BLUETOOTH_UUID_TYPE_128;
}
mp_bluetooth_gattc_on_descriptor_result(
1, descriptor_handle, &descriptor_uuid
);
}
}
if (att_event->hdr.status != ATT_SUCCESS ||
att_event->continuing == 0) {
uint16_t status = 0;
mp_bluetooth_gattc_on_discover_complete(
MP_BLUETOOTH_IRQ_GATTC_DESCRIPTOR_DONE,
1,
status
);
}
}
if (att_event->hdr.event == ATTC_READ_RSP) {
mp_uint_t atomic_state;
size_t len = mp_bluetooth_gattc_on_data_available_start(
MP_BLUETOOTH_IRQ_GATTC_READ_RESULT,
1,
att_event->handle,
att_event->valueLen,
&atomic_state
);
mp_bluetooth_gattc_on_data_available_chunk(
att_event->pValue, len
);
mp_bluetooth_gattc_on_data_available_end(atomic_state);
mp_bluetooth_gattc_on_read_write_status(
MP_BLUETOOTH_IRQ_GATTC_READ_DONE,
1,
att_event->handle,
att_event->hdr.status
);
}
if (att_event->hdr.event == ATTC_HANDLE_VALUE_NTF ||
att_event->hdr.event == ATTC_HANDLE_VALUE_IND) {
uint16_t ev = att_event->hdr.event == ATTC_HANDLE_VALUE_NTF ?
MP_BLUETOOTH_IRQ_GATTC_NOTIFY :
MP_BLUETOOTH_IRQ_GATTC_INDICATE;
mp_uint_t atomic_state;
size_t len = mp_bluetooth_gattc_on_data_available_start(
ev,
1,
att_event->handle,
att_event->valueLen,
&atomic_state
);
mp_bluetooth_gattc_on_data_available_chunk(
att_event->pValue, len
);
mp_bluetooth_gattc_on_data_available_end(atomic_state);
}
if (att_event->hdr.event == ATTC_WRITE_RSP) {
mp_bluetooth_gattc_on_read_write_status(
MP_BLUETOOTH_IRQ_GATTC_WRITE_DONE,
1,
att_event->handle,
att_event->hdr.status
);
}
#endif
} }
static void handle_dm_event(struct epic_dm_event *dm_event) static void handle_dm_event(struct epic_dm_event *dm_event)
{ {
struct epic_wsf_header *hdr = (struct epic_wsf_header *)dm_event; struct epic_wsf_header *hdr = (struct epic_wsf_header *)dm_event;
if (hdr->event == DM_CONN_OPEN_IND) { if (hdr->event == DM_CONN_OPEN_IND) {
struct epic_hciLeConnCmpl_event *e = struct epic_hciLeConnCmpl_event *e =
(struct epic_hciLeConnCmpl_event *)dm_event; (struct epic_hciLeConnCmpl_event *)dm_event;
...@@ -508,7 +693,10 @@ static void raise(void) ...@@ -508,7 +693,10 @@ static void raise(void)
// Start a discovery (scan). Set duration to zero to run continuously. // Start a discovery (scan). Set duration to zero to run continuously.
int mp_bluetooth_gap_scan_start( int mp_bluetooth_gap_scan_start(
int32_t duration_ms, int32_t interval_us, int32_t window_us int32_t duration_ms,
int32_t interval_us,
int32_t window_us,
bool active_scan
) { ) {
raise(); raise();
return 0; return 0;
...@@ -530,33 +718,52 @@ int mp_bluetooth_gap_peripheral_connect( ...@@ -530,33 +718,52 @@ int mp_bluetooth_gap_peripheral_connect(
} }
// Find all primary services on the connected peripheral. // Find all primary services on the connected peripheral.
int mp_bluetooth_gattc_discover_primary_services(uint16_t conn_handle) int mp_bluetooth_gattc_discover_primary_services(
{ uint16_t conn_handle, const mp_obj_bluetooth_uuid_t *uuid
raise(); ) {
return 0; if (uuid) {
uint8_t uuid_len =
uuid->type == MP_BLUETOOTH_UUID_TYPE_16 ? 2 : 16;
return epic_ble_attc_discover_primary_services(
conn_handle, uuid->data, uuid_len
);
} else {
return epic_ble_attc_discover_primary_services(
conn_handle, NULL, 0
);
}
} }
// Find all characteristics on the specified service on a connected peripheral. // Find all characteristics on the specified service on a connected peripheral.
int mp_bluetooth_gattc_discover_characteristics( int mp_bluetooth_gattc_discover_characteristics(
uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle uint16_t conn_handle,
uint16_t start_handle,
uint16_t end_handle,
const mp_obj_bluetooth_uuid_t *uuid
) { ) {
raise(); if (uuid) {
return 0; uuid_filter = *uuid;
} else {
uuid_filter.type = 0;
}
return epic_ble_attc_discover_characteristics(
conn_handle, start_handle, end_handle
);
} }
// Find all descriptors on the specified characteristic on a connected peripheral. // Find all descriptors on the specified characteristic on a connected peripheral.
int mp_bluetooth_gattc_discover_descriptors( int mp_bluetooth_gattc_discover_descriptors(
uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle
) { ) {
raise(); return epic_ble_attc_discover_descriptors(
return 0; conn_handle, start_handle, end_handle
);
} }
// Initiate read of a value from the remote peripheral. // Initiate read of a value from the remote peripheral.
int mp_bluetooth_gattc_read(uint16_t conn_handle, uint16_t value_handle) int mp_bluetooth_gattc_read(uint16_t conn_handle, uint16_t value_handle)
{ {
raise(); return epic_ble_attc_read(conn_handle, value_handle);
return 0;
} }
// Write the value to the remote peripheral. // Write the value to the remote peripheral.
...@@ -567,7 +774,18 @@ int mp_bluetooth_gattc_write( ...@@ -567,7 +774,18 @@ int mp_bluetooth_gattc_write(
size_t *value_len, size_t *value_len,
unsigned int mode unsigned int mode
) { ) {
raise(); int err;
return 0; if (mode == MP_BLUETOOTH_WRITE_MODE_NO_RESPONSE) {
err = epic_ble_attc_write_no_rsp(
conn_handle, value_handle, value, *value_len
);
} else if (mode == MP_BLUETOOTH_WRITE_MODE_WITH_RESPONSE) {
err = epic_ble_attc_write(
conn_handle, value_handle, value, *value_len
);
} else {
err = MP_EINVAL;
}
return err;
} }
#endif #endif
...@@ -126,6 +126,39 @@ enum { DM_RESET_CMPL_IND = DM_CBACK_START, /*!< \brief Reset complete */ ...@@ -126,6 +126,39 @@ enum { DM_RESET_CMPL_IND = DM_CBACK_START, /*!< \brief Reset complete */
DM_VENDOR_SPEC_IND /*!< \brief Vendor specific event */ DM_VENDOR_SPEC_IND /*!< \brief Vendor specific event */
}; };
#define ATTS_HANDLE_VALUE_CNF 15 /** \name ATT Callback Events
* Events related to ATT transactions.
*/
/**@{*/
#define ATT_CBACK_START 0x02 /*!< \brief ATT callback event starting value */
/*! \brief ATT client callback events */
enum /*!< \brief Internal note: event values match method values */
{
ATTC_FIND_INFO_RSP = ATT_CBACK_START, /*!< \brief Find information response */
ATTC_FIND_BY_TYPE_VALUE_RSP, /*!< \brief Find by type value response */
ATTC_READ_BY_TYPE_RSP, /*!< \brief Read by type value response */
ATTC_READ_RSP, /*!< \brief Read response */
ATTC_READ_LONG_RSP, /*!< \brief Read long response */
ATTC_READ_MULTIPLE_RSP, /*!< \brief Read multiple response */
ATTC_READ_BY_GROUP_TYPE_RSP, /*!< \brief Read group type response */
ATTC_WRITE_RSP, /*!< \brief Write response */
ATTC_WRITE_CMD_RSP, /*!< \brief Write command response */
ATTC_PREPARE_WRITE_RSP, /*!< \brief Prepare write response */
ATTC_EXECUTE_WRITE_RSP, /*!< \brief Execute write response */
ATTC_HANDLE_VALUE_NTF, /*!< \brief Handle value notification */
ATTC_HANDLE_VALUE_IND, /*!< \brief Handle value indication */
/* ATT server callback events */
ATTS_HANDLE_VALUE_CNF, /*!< \brief Handle value confirmation */
ATTS_CCC_STATE_IND, /*!< \brief Client chracteristic configuration state change */
ATTS_DB_HASH_CALC_CMPL_IND, /*!< \brief Database hash calculation complete */
/* ATT common callback events */
ATT_MTU_UPDATE_IND /*!< \brief Negotiated MTU value */
};
/*! \brief ATT callback events */
#define ATT_CBACK_END ATT_MTU_UPDATE_IND /*!< \brief ATT callback event ending value */
/**@}*/
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
#define MICROPY_ENABLE_SCHEDULER (1) #define MICROPY_ENABLE_SCHEDULER (1)
#define MICROPY_SCHEDULER_DEPTH (8)
#define MICROPY_ENABLE_SOURCE_LINE (1) #define MICROPY_ENABLE_SOURCE_LINE (1)
...@@ -54,6 +55,7 @@ int mp_hal_csprng_read_int(void); ...@@ -54,6 +55,7 @@ int mp_hal_csprng_read_int(void);
#define MICROPY_PY_FRAMEBUF (1) #define MICROPY_PY_FRAMEBUF (1)
#define MICROPY_PY_BLUETOOTH (1) #define MICROPY_PY_BLUETOOTH (1)
#define MICROPY_PY_BUILTINS_MEMORYVIEW (1) #define MICROPY_PY_BUILTINS_MEMORYVIEW (1)
#define MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE (1)
/* Modules */ /* Modules */
#define MODULE_BHI160_ENABLED (1) #define MODULE_BHI160_ENABLED (1)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment