mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-21 04:21:03 +00:00
att_server: allow to register handler for handle range - needed for modular service implmeentation
This commit is contained in:
parent
60b51a4c4e
commit
8ac574d6fa
128
src/ble/att_db.c
128
src/ble/att_db.c
@ -39,9 +39,9 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bluetooth.h"
|
||||
#include "ble/att_db.h"
|
||||
#include "ble/core.h"
|
||||
#include "bluetooth.h"
|
||||
#include "btstack_debug.h"
|
||||
#include "btstack_util.h"
|
||||
|
||||
@ -69,6 +69,8 @@ static att_write_callback_t att_write_callback = NULL;
|
||||
static uint8_t att_prepare_write_error_code = 0;
|
||||
static uint16_t att_prepare_write_error_handle = 0x0000;
|
||||
|
||||
static btstack_linked_list_t service_handlers;
|
||||
|
||||
// new java-style iterator
|
||||
typedef struct att_iterator {
|
||||
// private
|
||||
@ -152,6 +154,30 @@ static int att_find_handle(att_iterator_t *it, uint16_t handle){
|
||||
return 0;
|
||||
}
|
||||
|
||||
static att_service_handler_t * att_service_handler_for_handle(uint16_t handle){
|
||||
btstack_linked_list_iterator_t it;
|
||||
btstack_linked_list_iterator_init(&it, &service_handlers);
|
||||
while (btstack_linked_list_iterator_has_next(&it)){
|
||||
att_service_handler_t * handler = (att_service_handler_t*) btstack_linked_list_iterator_next(&it);
|
||||
if (handler->start_handle > handle) continue;
|
||||
if (handler->end_handle < handle) continue;
|
||||
return handler;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static att_read_callback_t att_read_callback_for_handle(uint16_t handle){
|
||||
att_service_handler_t * handler = att_service_handler_for_handle(handle);
|
||||
if (handler) return handler->read_callback;
|
||||
return att_read_callback;
|
||||
}
|
||||
|
||||
static att_write_callback_t att_write_callback_for_handle(uint16_t handle){
|
||||
att_service_handler_t * handler = att_service_handler_for_handle(handle);
|
||||
if (handler) return handler->write_callback;
|
||||
return att_write_callback;
|
||||
}
|
||||
|
||||
// experimental client API
|
||||
uint16_t att_uuid_for_handle(uint16_t attribute_handle){
|
||||
att_iterator_t it;
|
||||
@ -163,8 +189,10 @@ uint16_t att_uuid_for_handle(uint16_t attribute_handle){
|
||||
// end of client API
|
||||
|
||||
static void att_update_value_len(att_iterator_t *it, hci_con_handle_t con_handle){
|
||||
if ((it->flags & ATT_PROPERTY_DYNAMIC) == 0 || !att_read_callback) return;
|
||||
it->value_len = (*att_read_callback)(con_handle, it->handle, 0, NULL, 0);
|
||||
if ((it->flags & ATT_PROPERTY_DYNAMIC) == 0) return;
|
||||
att_read_callback_t callback = att_read_callback_for_handle(it->handle);
|
||||
if (!callback) return;
|
||||
it->value_len = (*callback)(con_handle, it->handle, 0, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -172,8 +200,10 @@ static void att_update_value_len(att_iterator_t *it, hci_con_handle_t con_handle
|
||||
static int att_copy_value(att_iterator_t *it, uint16_t offset, uint8_t * buffer, uint16_t buffer_size, hci_con_handle_t con_handle){
|
||||
|
||||
// DYNAMIC
|
||||
if ((it->flags & ATT_PROPERTY_DYNAMIC) && att_read_callback) {
|
||||
return (*att_read_callback)(con_handle, it->handle, offset, buffer, buffer_size);
|
||||
if (it->flags & ATT_PROPERTY_DYNAMIC){
|
||||
att_read_callback_t callback = att_read_callback_for_handle(it->handle);
|
||||
if (!callback) return 0;
|
||||
return (*callback)(con_handle, it->handle, offset, buffer, buffer_size);
|
||||
}
|
||||
|
||||
// STATIC
|
||||
@ -854,7 +884,8 @@ static uint16_t handle_write_request(att_connection_t * att_connection, uint8_t
|
||||
if (!ok) {
|
||||
return setup_error_invalid_handle(response_buffer, request_type, handle);
|
||||
}
|
||||
if (!att_write_callback) {
|
||||
att_write_callback_t callback = att_write_callback_for_handle(handle);
|
||||
if (!callback) {
|
||||
return setup_error_write_not_permitted(response_buffer, request_type, handle);
|
||||
}
|
||||
if ((it.flags & ATT_PROPERTY_WRITE) == 0) {
|
||||
@ -868,7 +899,7 @@ static uint16_t handle_write_request(att_connection_t * att_connection, uint8_t
|
||||
if (error_code) {
|
||||
return setup_error(response_buffer, request_type, handle, error_code);
|
||||
}
|
||||
error_code = (*att_write_callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_NONE, 0, request_buffer + 3, request_len - 3);
|
||||
error_code = (*callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_NONE, 0, request_buffer + 3, request_len - 3);
|
||||
if (error_code) {
|
||||
return setup_error(response_buffer, request_type, handle, error_code);
|
||||
}
|
||||
@ -885,7 +916,8 @@ static uint16_t handle_prepare_write_request(att_connection_t * att_connection,
|
||||
|
||||
uint16_t handle = little_endian_read_16(request_buffer, 1);
|
||||
uint16_t offset = little_endian_read_16(request_buffer, 3);
|
||||
if (!att_write_callback) {
|
||||
att_write_callback_t callback = att_write_callback_for_handle(handle);
|
||||
if (!callback) {
|
||||
return setup_error_write_not_permitted(response_buffer, request_type, handle);
|
||||
}
|
||||
att_iterator_t it;
|
||||
@ -905,7 +937,7 @@ static uint16_t handle_prepare_write_request(att_connection_t * att_connection,
|
||||
return setup_error(response_buffer, request_type, handle, error_code);
|
||||
}
|
||||
|
||||
error_code = (*att_write_callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_ACTIVE, offset, request_buffer + 5, request_len - 5);
|
||||
error_code = (*callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_ACTIVE, offset, request_buffer + 5, request_len - 5);
|
||||
switch (error_code){
|
||||
case 0:
|
||||
break;
|
||||
@ -924,12 +956,24 @@ static uint16_t handle_prepare_write_request(att_connection_t * att_connection,
|
||||
return request_len;
|
||||
}
|
||||
|
||||
static void att_notify_write_callbacks(att_connection_t * att_connection, uint16_t transaction_mode){
|
||||
// notify all
|
||||
btstack_linked_list_iterator_t it;
|
||||
btstack_linked_list_iterator_init(&it, &service_handlers);
|
||||
while (btstack_linked_list_iterator_has_next(&it)){
|
||||
att_service_handler_t * handler = (att_service_handler_t*) btstack_linked_list_iterator_next(&it);
|
||||
if (!handler->write_callback) continue;
|
||||
(*handler->write_callback)(att_connection->con_handle, 0, transaction_mode, 0, NULL, 0);
|
||||
}
|
||||
if (!att_write_callback) return;
|
||||
(*att_write_callback)(att_connection->con_handle, 0, transaction_mode, 0, NULL, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief transcation queue of prepared writes, e.g., after disconnect
|
||||
*/
|
||||
void att_clear_transaction_queue(att_connection_t * att_connection){
|
||||
if (!att_write_callback) return;
|
||||
(*att_write_callback)(att_connection->con_handle, 0, ATT_TRANSACTION_MODE_CANCEL, 0, NULL, 0);
|
||||
att_notify_write_callbacks(att_connection, ATT_TRANSACTION_MODE_CANCEL);
|
||||
}
|
||||
|
||||
// MARK: ATT_EXECUTE_WRITE_REQUEST 0x18
|
||||
@ -938,10 +982,6 @@ static uint16_t handle_execute_write_request(att_connection_t * att_connection,
|
||||
uint8_t * response_buffer, uint16_t response_buffer_size){
|
||||
|
||||
uint8_t request_type = ATT_EXECUTE_WRITE_REQUEST;
|
||||
|
||||
if (!att_write_callback) {
|
||||
return setup_error_write_not_permitted(response_buffer, request_type, 0);
|
||||
}
|
||||
if (request_buffer[1]) {
|
||||
// deliver queued errors
|
||||
if (att_prepare_write_error_code){
|
||||
@ -951,7 +991,7 @@ static uint16_t handle_execute_write_request(att_connection_t * att_connection,
|
||||
att_prepare_write_reset();
|
||||
return setup_error(response_buffer, request_type, handle, error_code);
|
||||
}
|
||||
(*att_write_callback)(att_connection->con_handle, 0, ATT_TRANSACTION_MODE_EXECUTE, 0, NULL, 0);
|
||||
att_notify_write_callbacks(att_connection, ATT_TRANSACTION_MODE_EXECUTE);
|
||||
} else {
|
||||
att_clear_transaction_queue(att_connection);
|
||||
}
|
||||
@ -965,15 +1005,17 @@ static uint16_t handle_execute_write_request(att_connection_t * att_connection,
|
||||
static void handle_write_command(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len,
|
||||
uint8_t * response_buffer, uint16_t response_buffer_size){
|
||||
|
||||
if (!att_write_callback) return;
|
||||
uint16_t handle = little_endian_read_16(request_buffer, 1);
|
||||
att_write_callback_t callback = att_write_callback_for_handle(handle);
|
||||
if (!callback) return;
|
||||
|
||||
att_iterator_t it;
|
||||
int ok = att_find_handle(&it, handle);
|
||||
if (!ok) return;
|
||||
if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) return;
|
||||
if ((it.flags & ATT_PROPERTY_WRITE_WITHOUT_RESPONSE) == 0) return;
|
||||
if (att_validate_security(att_connection, &it)) return;
|
||||
(*att_write_callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_NONE, 0, request_buffer + 3, request_len - 3);
|
||||
(*callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_NONE, 0, request_buffer + 3, request_len - 3);
|
||||
}
|
||||
|
||||
// MARK: helper for ATT_HANDLE_VALUE_NOTIFICATION and ATT_HANDLE_VALUE_INDICATION
|
||||
@ -1068,42 +1110,16 @@ uint16_t att_handle_request(att_connection_t * att_connection,
|
||||
return response_len;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
// test profile
|
||||
#include "profile.h"
|
||||
|
||||
int main(void){
|
||||
int acl_buffer_size;
|
||||
uint8_t acl_buffer[27];
|
||||
att_set_db(profile_data);
|
||||
att_dump_attributes();
|
||||
|
||||
uint8_t uuid_1[] = { 0x00, 0x18};
|
||||
acl_buffer_size = handle_find_by_type_value_request2(acl_buffer, 19, 0, 0xffff, 0x2800, 2, (uint8_t *) &uuid_1);
|
||||
log_info_hexdump(acl_buffer, acl_buffer_size);
|
||||
|
||||
uint8_t uuid_3[] = { 0x00, 0x2a};
|
||||
acl_buffer_size = handle_read_by_type_request2(acl_buffer, 19, 0, 0xffff, 2, (uint8_t *) &uuid_3);
|
||||
log_info_hexdump(acl_buffer, acl_buffer_size);
|
||||
|
||||
acl_buffer_size = handle_find_by_type_value_request2(acl_buffer, 19, 0, 0xffff, 0x2800, 2, (uint8_t *) &uuid_1);
|
||||
log_info_hexdump(acl_buffer, acl_buffer_size);
|
||||
|
||||
uint8_t uuid_4[] = { 0x00, 0x28};
|
||||
acl_buffer_size = handle_read_by_group_type_request2(acl_buffer, 20, 0, 0xffff, 2, (uint8_t *) &uuid_4);
|
||||
log_info_hexdump(acl_buffer, acl_buffer_size);
|
||||
|
||||
acl_buffer_size = handle_find_information_request2(acl_buffer, 20, 0, 0xffff);
|
||||
log_info_hexdump(acl_buffer, acl_buffer_size);
|
||||
acl_buffer_size = handle_find_information_request2(acl_buffer, 20, 3, 0xffff);
|
||||
log_info_hexdump(acl_buffer, acl_buffer_size);
|
||||
acl_buffer_size = handle_find_information_request2(acl_buffer, 20, 5, 0xffff);
|
||||
log_info_hexdump(acl_buffer, acl_buffer_size);
|
||||
|
||||
acl_buffer_size = handle_read_request2(acl_buffer, 19, 0x0003);
|
||||
log_info_hexdump(acl_buffer, acl_buffer_size);
|
||||
|
||||
return 0;
|
||||
/**
|
||||
* @brief register read/write callbacks for specific handle range
|
||||
* @param att_service_handler_t
|
||||
*/
|
||||
void att_register_service_handler(att_service_handler_t * handler){
|
||||
if (att_service_handler_for_handle(handler->start_handle) ||
|
||||
att_service_handler_for_handle(handler->end_handle)){
|
||||
log_error("att_register_service_handler: handler for range 0x%04x-0x%04x already registered", handler->start_handle, handler->end_handle);
|
||||
return;
|
||||
}
|
||||
btstack_linked_list_add(&service_handlers, (btstack_linked_item_t*) handler);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -41,7 +41,8 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include "bluetooth.h"
|
||||
|
||||
#include "btstack_linked_list.h"
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -49,7 +50,7 @@ extern "C" {
|
||||
// custom BTstack error codes
|
||||
#define ATT_ERROR_HCI_DISCONNECT_RECEIVED 0x1f
|
||||
|
||||
// custom BTstack ATT error coders
|
||||
// custom BTstack ATT error codes
|
||||
#define ATT_ERROR_DATA_MISMATCH 0x7e
|
||||
#define ATT_ERROR_TIMEOUT 0x7F
|
||||
|
||||
@ -83,6 +84,16 @@ typedef uint16_t (*att_read_callback_t)(hci_con_handle_t con_handle, uint16_t at
|
||||
// @returns 0 if write was ok, ATT_ERROR_PREPARE_QUEUE_FULL if no space in queue, ATT_ERROR_INVALID_OFFSET if offset is larger than max buffer
|
||||
typedef int (*att_write_callback_t)(hci_con_handle_t con_handle, uint16_t attribute_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size);
|
||||
|
||||
|
||||
// Read & Write Callbacks for handle range
|
||||
typedef struct att_service_handler {
|
||||
btstack_linked_item_t * item;
|
||||
uint16_t start_handle;
|
||||
uint16_t end_handle;
|
||||
att_read_callback_t read_callback;
|
||||
att_write_callback_t write_callback;
|
||||
} att_service_handler_t;
|
||||
|
||||
// MARK: ATT Operations
|
||||
|
||||
/*
|
||||
@ -152,7 +163,14 @@ uint16_t att_prepare_handle_value_indication(att_connection_t * att_connection,
|
||||
*/
|
||||
void att_clear_transaction_queue(att_connection_t * att_connection);
|
||||
|
||||
// experimental client API
|
||||
/**
|
||||
* @brief register read/write callbacks for specific handle range
|
||||
* @param att_service_handler_t
|
||||
*/
|
||||
void att_register_service_handler(att_service_handler_t * handler);
|
||||
|
||||
|
||||
// experimental client API
|
||||
uint16_t att_uuid_for_handle(uint16_t attribute_handle);
|
||||
|
||||
#if defined __cplusplus
|
||||
|
Loading…
x
Reference in New Issue
Block a user