start timer on handle value indication, assert only on indication is active, notify client about handle value indication completion, extend ble_peripheral

This commit is contained in:
matthias.ringwald@gmail.com 2014-01-12 21:24:25 +00:00
parent 9e4b002b3d
commit 8a3fac4ff5
5 changed files with 89 additions and 13 deletions

View File

@ -73,8 +73,8 @@ extern "C" {
#define ATT_EXECUTE_WRITE_RESPONSE 0x19
#define ATT_HANDLE_VALUE_NOTIFICATION 0x1b
#define ATT_HANDLE_VALUE_CONFIRMATION 0x1c
#define ATT_HANDLE_VALUE_INDICATION 0x1d
#define ATT_HANDLE_VALUE_CONFIRMATION 0x1e
#define ATT_WRITE_COMMAND 0x52
@ -120,6 +120,14 @@ extern "C" {
#define ATT_PROPERTY_AUTHORIZATION_REQUIRED 0x800
// Encryption key size stored in upper 4 bits, 0 == no encryption, encryption key size - 1 otherwise
// ATT Transaxtion Timeout of 30 seconds for Command/Response or Incidationc/Confirmation
#define ATT_TRANSACTION_TIMEOUT_MS 30000
#define ATT_TRANSACTION_MODE_NONE 0x0
#define ATT_TRANSACTION_MODE_ACTIVE 0x1
#define ATT_TRANSACTION_MODE_EXECUTE 0x2
#define ATT_TRANSACTION_MODE_CANCEL 0x3
// MARK: GATT UUIDs
#define GATT_PRIMARY_SERVICE_UUID 0x2800
#define GATT_SECONDARY_SERVICE_UUID 0x2801
@ -129,10 +137,6 @@ extern "C" {
#define GAP_SERVICE_UUID 0x1800
#define GAP_DEVICE_NAME_UUID 0x2a00
#define ATT_TRANSACTION_MODE_NONE 0x0
#define ATT_TRANSACTION_MODE_ACTIVE 0x1
#define ATT_TRANSACTION_MODE_EXECUTE 0x2
#define ATT_TRANSACTION_MODE_CANCEL 0x3
typedef struct att_connection {
uint16_t mtu;

View File

@ -81,8 +81,31 @@ static uint8_t att_request_buffer[28];
static int att_ir_central_device_db_index = -1;
static int att_ir_lookup_active = 0;
static int att_handle_value_indication_handle = 0;
static timer_source_t att_handle_value_indication_timer;
static btstack_packet_handler_t att_client_packet_handler = NULL;
static int att_handle_value_indication_notify_client(uint8_t status, uint16_t client_handle, uint16_t attribute_handle){
uint8_t event[7];
int pos = 0;
event[pos++] = ATT_HANDLE_VALUE_INDICATION_COMPLETE;
event[pos++] = sizeof(event) - 2;
event[pos++] = status;
bt_store_16(event, pos, client_handle);
pos += 2;
bt_store_16(event, pos, attribute_handle);
pos += 2;
(*att_client_packet_handler)(HCI_EVENT_PACKET, 0, &event[0], sizeof(event));
}
static void att_handle_value_indication_timeout(timer_source_t *ts){
uint16_t att_handle = att_handle_value_indication_handle;
att_handle_value_indication_handle = 0;
att_handle_value_indication_notify_client(ATT_HANDLE_VALUE_INDICATION_TIMEOUT, att_request_handle, att_handle);
}
static void att_event_packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
switch (packet_type) {
@ -255,6 +278,15 @@ static void att_run(void){
static void att_packet_handler(uint8_t packet_type, uint16_t handle, uint8_t *packet, uint16_t size){
if (packet_type != ATT_DATA_PACKET) return;
// handle value indication confirms
if (packet[0] == ATT_HANDLE_VALUE_CONFIRMATION && att_handle_value_indication_handle){
run_loop_remove_timer(&att_handle_value_indication_timer);
uint16_t att_handle = att_handle_value_indication_handle;
att_handle_value_indication_handle = 0;
att_handle_value_indication_notify_client(0, att_request_handle, att_handle);
return;
}
// check size
if (size > sizeof(att_request_buffer)) return;
@ -292,14 +324,24 @@ int att_server_can_send(){
return hci_can_send_packet_now(HCI_ACL_DATA_PACKET);
}
void att_server_notify(uint16_t handle, uint8_t *value, uint16_t value_len){
int att_server_notify(uint16_t handle, uint8_t *value, uint16_t value_len){
uint8_t packet_buffer[att_connection.mtu];
uint16_t size = att_prepare_handle_value_notification(&att_connection, handle, value, value_len, packet_buffer);
l2cap_send_connectionless(att_request_handle, L2CAP_CID_ATTRIBUTE_PROTOCOL, packet_buffer, size);
return l2cap_send_connectionless(att_request_handle, L2CAP_CID_ATTRIBUTE_PROTOCOL, packet_buffer, size);
}
void att_server_indicate(uint16_t handle, uint8_t *value, uint16_t value_len){
int att_server_indicate(uint16_t handle, uint8_t *value, uint16_t value_len){
if (att_handle_value_indication_handle) return ATT_HANDLE_VALUE_INDICATION_IN_PORGRESS;
if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)) return BTSTACK_ACL_BUFFERS_FULL;
// track indication
att_handle_value_indication_handle = handle;
run_loop_set_timer_handler(&att_handle_value_indication_timer, att_handle_value_indication_timeout);
run_loop_set_timer(&att_handle_value_indication_timer, ATT_TRANSACTION_TIMEOUT_MS);
run_loop_add_timer(&att_handle_value_indication_timer);
uint8_t packet_buffer[att_connection.mtu];
uint16_t size = att_prepare_handle_value_indication(&att_connection, handle, value, value_len, packet_buffer);
l2cap_send_connectionless(att_request_handle, L2CAP_CID_ATTRIBUTE_PROTOCOL, packet_buffer, size);
return 0;
}

View File

@ -65,13 +65,15 @@ int att_server_can_send();
/*
* @brief notify client about attribute value change
* @ereturns 0 if ok, error otherwise
*/
void att_server_notify(uint16_t handle, uint8_t *value, uint16_t value_len);
int att_server_notify(uint16_t handle, uint8_t *value, uint16_t value_len);
/*
* @brief indicate value change to client. client is supposed to reply with an indication_response
* @ereturns 0 if ok, error otherwise
*/
void att_server_indicate(uint16_t handle, uint8_t *value, uint16_t value_len);
int att_server_indicate(uint16_t handle, uint8_t *value, uint16_t value_len);
#if defined __cplusplus
}

View File

@ -83,11 +83,27 @@ static void heartbeat_handler(struct timer *ts){
}
static void app_run(){
if (!client_configuration || !update_client) return;
if (!update_client) return;
if (!att_server_can_send()) return;
printf("Notify value %u\n", counter);
int result = -1;
switch (client_configuration){
case 0x01:
printf("Notify value %u\n", counter);
result = att_server_notify(0x0f, &counter, 1);
break;
case 0x02:
printf("Indicate value %u\n", counter);
result = att_server_indicate(0x0f, &counter, 1);
break;
default:
return;
}
if (result){
printf("Error 0x%02x\n", result);
return;
}
update_client = 0;
att_server_notify(0x0f, &counter, 1);
}
// write requests
@ -177,6 +193,10 @@ static void app_packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *
sm_authorization_grant(event->addr_type, event->address);
break;
}
case ATT_HANDLE_VALUE_INDICATION_COMPLETE:
printf("ATT_HANDLE_VALUE_INDICATION_COMPLETE status %u\n", packet[2]);
break;
default:
break;
}

View File

@ -228,6 +228,9 @@ extern "C" {
#define GATT_CHARACTERISTIC_QUERY_RESULT 0xA4
#define GATT_CHARACTERISTIC_QUERY_COMPLETE 0xA5
// data: event(8), len(8), status (8), hci_handle (16), attribute_handle (16)
#define ATT_HANDLE_VALUE_INDICATION_COMPLETE 0xAF
// data: event(8), address_type(8), address (48), [number(32)]
#define SM_JUST_WORKS_REQUEST 0xb0
#define SM_JUST_WORKS_CANCEL 0xb1
@ -241,6 +244,8 @@ extern "C" {
#define SM_AUTHORIZATION_REQUEST 0xb9
#define SM_AUTHORIZATION_RESULT 0xba
// ATT
// last error code in 2.1 is 0x38 - we start with 0x50 for BTstack errors
#define BTSTACK_CONNECTION_TO_BTDAEMON_FAILED 0x50
@ -278,6 +283,9 @@ extern "C" {
#define SDP_HANDLE_ALREADY_REGISTERED 0x80
#define SDP_QUERY_INCOMPLETE 0x81
#define ATT_HANDLE_VALUE_INDICATION_IN_PORGRESS 0x90
#define ATT_HANDLE_VALUE_INDICATION_TIMEOUT 0x91
/**
* Default INQ Mode
*/