att: moved service handling from att_db into att_server, att_register_service_handler -> att_server_register_service_handler

This commit is contained in:
Matthias Ringwald 2017-10-17 16:54:51 +02:00
parent 304b2f4d7e
commit 3d71c7a4e0
7 changed files with 120 additions and 99 deletions

View File

@ -71,8 +71,6 @@ 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
@ -156,30 +154,6 @@ 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;
@ -192,9 +166,7 @@ uint16_t att_uuid_for_handle(uint16_t attribute_handle){
static void att_update_value_len(att_iterator_t *it, hci_con_handle_t con_handle){
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);
it->value_len = (*att_read_callback)(con_handle, it->handle, 0, NULL, 0);
return;
}
@ -203,9 +175,7 @@ static int att_copy_value(att_iterator_t *it, uint16_t offset, uint8_t * buffer,
// DYNAMIC
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);
return (*att_read_callback)(con_handle, it->handle, offset, buffer, buffer_size);
}
// STATIC
@ -906,8 +876,7 @@ 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);
}
att_write_callback_t callback = att_write_callback_for_handle(handle);
if (!callback) {
if (!att_write_callback) {
return setup_error_write_not_permitted(response_buffer, request_type, handle);
}
if ((it.flags & ATT_PROPERTY_WRITE) == 0) {
@ -921,7 +890,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 = (*callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_NONE, 0, request_buffer + 3, request_len - 3);
error_code = (*att_write_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);
}
@ -940,8 +909,7 @@ 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);
att_write_callback_t callback = att_write_callback_for_handle(handle);
if (!callback) {
if (!att_write_callback) {
return setup_error_write_not_permitted(response_buffer, request_type, handle);
}
att_iterator_t it;
@ -961,7 +929,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 = (*callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_ACTIVE, offset, request_buffer + 5, request_len - 5);
error_code = (*att_write_callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_ACTIVE, offset, request_buffer + 5, request_len - 5);
switch (error_code){
case 0:
break;
@ -980,38 +948,11 @@ 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);
}
// returns first reported error or 0
static uint8_t att_validate_prepared_write(att_connection_t * att_connection){
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;
uint8_t error_code = (*handler->write_callback)(att_connection->con_handle, 0, ATT_TRANSACTION_MODE_VALIDATE, 0, NULL, 0);
if (error_code) return error_code;
}
if (!att_write_callback) return 0;
return (*att_write_callback)(att_connection->con_handle, 0, ATT_TRANSACTION_MODE_VALIDATE, 0, NULL, 0);
}
/*
* @brief transcation queue of prepared writes, e.g., after disconnect
*/
void att_clear_transaction_queue(att_connection_t * att_connection){
att_notify_write_callbacks(att_connection, ATT_TRANSACTION_MODE_CANCEL);
(*att_write_callback)(att_connection->con_handle, 0, ATT_TRANSACTION_MODE_CANCEL, 0, NULL, 0);
}
// MARK: ATT_EXECUTE_WRITE_REQUEST 0x18
@ -1026,7 +967,7 @@ static uint16_t handle_execute_write_request(att_connection_t * att_connection,
if (request_buffer[1]) {
// validate queued write
if (att_prepare_write_error_code == 0){
att_prepare_write_error_code = att_validate_prepared_write(att_connection);
att_prepare_write_error_code = (*att_write_callback)(att_connection->con_handle, 0, ATT_TRANSACTION_MODE_VALIDATE, 0, NULL, 0);
}
// deliver queued errors
if (att_prepare_write_error_code){
@ -1036,7 +977,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_notify_write_callbacks(att_connection, ATT_TRANSACTION_MODE_EXECUTE);
att_write_callback(att_connection->con_handle, 0, ATT_TRANSACTION_MODE_EXECUTE, 0, NULL, 0);
} else {
att_clear_transaction_queue(att_connection);
}
@ -1054,8 +995,7 @@ static void handle_write_command(att_connection_t * att_connection, uint8_t * re
UNUSED(response_buffer_size);
uint16_t handle = little_endian_read_16(request_buffer, 1);
att_write_callback_t callback = att_write_callback_for_handle(handle);
if (!callback) return;
if (!att_write_callback) return;
att_iterator_t it;
int ok = att_find_handle(&it, handle);
@ -1063,7 +1003,7 @@ static void handle_write_command(att_connection_t * att_connection, uint8_t * re
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;
(*callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_NONE, 0, request_buffer + 3, request_len - 3);
(*att_write_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
@ -1160,19 +1100,6 @@ uint16_t att_handle_request(att_connection_t * att_connection,
return response_len;
}
/**
* @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);
}
// returns 1 if service found. only primary service.
int gatt_server_get_get_handle_range_for_service_with_uuid16(uint16_t uuid16, uint16_t * start_handle, uint16_t * end_handle){
uint16_t in_group = 0;

View File

@ -170,13 +170,6 @@ uint16_t att_prepare_handle_value_indication(att_connection_t * att_connection,
*/
void att_clear_transaction_queue(att_connection_t * att_connection);
/**
* @brief register read/write callbacks for specific handle range
* @param att_service_handler_t
*/
void att_register_service_handler(att_service_handler_t * handler);
// att_read_callback helpers for a various data types
/*

View File

@ -72,8 +72,12 @@ static btstack_packet_callback_registration_t hci_event_callback_registration;
static btstack_packet_callback_registration_t sm_event_callback_registration;
static btstack_packet_handler_t att_client_packet_handler = NULL;
static btstack_linked_list_t can_send_now_clients;
static btstack_linked_list_t service_handlers;
static uint8_t att_client_waiting_for_can_send;
static att_read_callback_t att_server_client_read_callback;
static att_write_callback_t att_server_client_write_callback;
static att_server_t * att_server_for_handle(hci_con_handle_t con_handle){
hci_connection_t * hci_connection = hci_connection_for_handle(con_handle);
if (!hci_connection) return NULL;
@ -456,8 +460,99 @@ static void att_packet_handler(uint8_t packet_type, uint16_t handle, uint8_t *pa
}
}
// gatt service management
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_server_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_server_client_read_callback;
}
static att_write_callback_t att_server_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_server_client_write_callback;
}
static void att_notify_write_callbacks(hci_con_handle_t con_handle, uint16_t transaction_mode){
// notify all callbacks
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)(con_handle, 0, transaction_mode, 0, NULL, 0);
}
if (!att_server_client_write_callback) return;
(*att_server_client_write_callback)(con_handle, 0, transaction_mode, 0, NULL, 0);
}
// returns first reported error or 0
static uint8_t att_validate_prepared_write(hci_con_handle_t con_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->write_callback) continue;
uint8_t error_code = (*handler->write_callback)(con_handle, 0, ATT_TRANSACTION_MODE_VALIDATE, 0, NULL, 0);
if (error_code) return error_code;
}
if (!att_server_client_write_callback) return 0;
return (*att_server_client_write_callback)(con_handle, 0, ATT_TRANSACTION_MODE_VALIDATE, 0, NULL, 0);
}
static uint16_t att_server_read_callback(hci_con_handle_t con_handle, uint16_t attribute_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){
att_read_callback_t callback = att_server_read_callback_for_handle(attribute_handle);
return (*callback)(con_handle, attribute_handle, offset, buffer, buffer_size);
}
static int att_server_write_callback(hci_con_handle_t con_handle, uint16_t attribute_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size){
switch (transaction_mode){
case ATT_TRANSACTION_MODE_VALIDATE:
return att_validate_prepared_write(con_handle);
case ATT_TRANSACTION_MODE_EXECUTE:
case ATT_TRANSACTION_MODE_CANCEL:
att_notify_write_callbacks(con_handle, transaction_mode);
return 0;
default:
break;
}
att_write_callback_t callback = att_server_write_callback_for_handle(attribute_handle);
// TODO: check if write for ccc, if yes store in tlv
return (*callback)(con_handle, attribute_handle, transaction_mode, offset, buffer, buffer_size);
}
/**
* @brief register read/write callbacks for specific handle range
* @param att_service_handler_t
*/
void att_server_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("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);
}
void att_server_init(uint8_t const * db, att_read_callback_t read_callback, att_write_callback_t write_callback){
// store callbacks
att_server_client_read_callback = read_callback;
att_server_client_write_callback = write_callback;
// register for HCI Events
hci_event_callback_registration.callback = &att_event_packet_handler;
hci_add_event_handler(&hci_event_callback_registration);
@ -470,8 +565,8 @@ void att_server_init(uint8_t const * db, att_read_callback_t read_callback, att_
att_dispatch_register_server(att_packet_handler);
att_set_db(db);
att_set_read_callback(read_callback);
att_set_write_callback(write_callback);
att_set_read_callback(att_server_read_callback);
att_set_write_callback(att_server_write_callback);
}

View File

@ -63,6 +63,12 @@ void att_server_init(uint8_t const * db, att_read_callback_t read_callback, att_
*/
void att_server_register_packet_handler(btstack_packet_handler_t handler);
/**
* @brief register read/write callbacks for specific handle range
* @param att_service_handler_t
*/
void att_server_register_service_handler(att_service_handler_t * handler);
/*
* @brief tests if a notification or indication can be send right now
* @param con_handle

View File

@ -112,12 +112,12 @@ void battery_service_server_init(uint8_t value){
battery_value_handle_value = gatt_server_get_value_handle_for_characteristic_with_uuid16(start_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_LEVEL);
battery_value_handle_client_configuration = gatt_server_get_client_configuration_handle_for_characteristic_with_uuid16(start_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_LEVEL);
// register service with ATT DB
// register service with ATT Server
battery_service.start_handle = start_handle;
battery_service.end_handle = end_handle;
battery_service.read_callback = &battery_service_read_callback;
battery_service.write_callback = &battery_service_write_callback;
att_register_service_handler(&battery_service);
att_server_register_service_handler(&battery_service);
}
void battery_service_server_set_battery_value(uint8_t value){

View File

@ -129,12 +129,12 @@ void device_information_service_server_init(void){
device_information_fields[i].value_handle = gatt_server_get_value_handle_for_characteristic_with_uuid16(start_handle, end_handle, device_information_characteristic_uuids[i]);
}
// register service with ATT DB
// register service with ATT Server
device_information_service.start_handle = start_handle;
device_information_service.end_handle = end_handle;
device_information_service.read_callback = &device_information_service_read_callback;
device_information_service.write_callback = NULL;
att_register_service_handler(&device_information_service);
att_server_register_service_handler(&device_information_service);
}
/**

View File

@ -196,12 +196,12 @@ void hids_device_init(uint8_t country_code, const uint8_t * descriptor, uint16_t
hid_report_input_value_handle = gatt_server_get_value_handle_for_characteristic_with_uuid16(start_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_REPORT);
hid_report_input_client_configuration_handle = gatt_server_get_client_configuration_handle_for_characteristic_with_uuid16(start_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_REPORT);
// register service with ATT DB
// register service with ATT Server
hid_service.start_handle = start_handle;
hid_service.end_handle = end_handle;
hid_service.read_callback = &att_read_callback;
hid_service.write_callback = &att_write_callback;
att_register_service_handler(&hid_service);
att_server_register_service_handler(&hid_service);
}
/**