ble client: connect functionality moved to hci

This commit is contained in:
mila@ringwald.ch 2014-05-02 21:53:08 +00:00
parent 755c826fc1
commit 4f3229d8d2
4 changed files with 110 additions and 298 deletions

View File

@ -80,7 +80,7 @@ static void ble_packet_handler(void * connection, uint8_t packet_type, uint16_t
void (*le_central_callback)(le_event_t * event);
static void le_packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
// static void le_packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
static void le_central_run();
@ -131,234 +131,9 @@ void le_central_register_packet_handler(void (*handler)(uint8_t packet_type, uin
static inline void send_le_central_connection_complete_event(le_central_t * peripheral, uint8_t type, uint8_t status){
le_central_connection_complete_event_t event;
event.type = type;
event.device = peripheral;
event.status = status;
(*le_central_callback)((le_event_t*)&event);
}
static le_central_t * get_le_central_context_for_handle(uint16_t handle){
linked_item_t *it;
for (it = (linked_item_t *) le_central_connections; it ; it = it->next){
le_central_t * peripheral = (le_central_t *) it;
if (peripheral->handle == handle){
return peripheral;
}
}
return NULL;
}
static le_central_t * get_le_central_context_with_address(uint8_t addr_type, bd_addr_t addr){
linked_item_t *it;
for (it = (linked_item_t *) le_central_connections; it ; it = it->next){
le_central_t * peripheral = (le_central_t *) it;
if (BD_ADDR_CMP(addr, peripheral->address) == 0 && peripheral->address_type == addr_type){
return peripheral;
}
}
return 0;
}
static le_central_t * get_le_central_context_with_state(le_central_state_t p_state){
linked_item_t *it;
for (it = (linked_item_t *) le_central_connections; it ; it = it->next){
le_central_t * peripheral = (le_central_t *) it;
if (peripheral->le_central_state == p_state){
return peripheral;
}
}
return NULL;
}
static inline le_central_t * get_le_central_w4_connect_cancelled(){
return get_le_central_context_with_state(P_W4_CONNECT_CANCELLED);
}
static inline le_central_t * get_le_central_w4_connected(){
return get_le_central_context_with_state(P_W4_CONNECTED);
}
static void le_central_handle_context_list(){
// only one connect is allowed, wait for result
if (get_le_central_w4_connected()) return;
// only one cancel connect is allowed, wait for result
if (get_le_central_w4_connect_cancelled()) return;
if (!hci_can_send_packet_now_using_packet_buffer(HCI_COMMAND_DATA_PACKET)) return;
if (!l2cap_can_send_connectionless_packet_now()) return;
// printf("handle_peripheral_list empty %u\n", linked_list_empty(&le_connections));
linked_item_t *it;
for (it = (linked_item_t *) le_central_connections; it ; it = it->next){
le_central_t * peripheral = (le_central_t *) it;
// printf("handle_peripheral_list, status %u\n", peripheral->state);
switch (peripheral->le_central_state){
case P_W2_CONNECT:
peripheral->le_central_state = P_W4_CONNECTED;
hci_send_cmd(&hci_le_create_connection,
1000, // scan interval: 625 ms
1000, // scan interval: 625 ms
0, // don't use whitelist
peripheral->address_type, // peer address type
peripheral->address, // peer bd addr
0, // our addr type: public
80, // conn interval min
80, // conn interval max (3200 * 0.625)
0, // conn latency
2000, // supervision timeout
0, // min ce length
1000 // max ce length
);
return;
case P_W2_CANCEL_CONNECT:
peripheral->le_central_state = P_W4_CONNECT_CANCELLED;
hci_send_cmd(&hci_le_create_connection_cancel);
return;
case P_W2_DISCONNECT:
peripheral->le_central_state = P_W4_DISCONNECTED;
hci_send_cmd(&hci_disconnect, peripheral->handle,0x13);
return;
default:
break;
}
}
}
static void le_central_context_init(le_central_t *context, uint8_t addr_type, bd_addr_t addr){
memset(context, 0, sizeof(le_central_t));
context->address_type = addr_type;
memcpy (context->address, addr, 6);
}
le_command_status_t le_central_connect(le_central_t *context, uint8_t addr_type, bd_addr_t addr){
//TODO: align with hci connection list capacity
le_central_t * peripheral = get_le_central_context_with_address(addr_type, addr);
if (!peripheral) {
le_central_context_init(context, addr_type, addr);
context->le_central_state = P_W2_CONNECT;
linked_list_add(&le_central_connections, (linked_item_t *) context);
} else if (peripheral == context) {
if (context->le_central_state != P_W2_CONNECT) return BLE_PERIPHERAL_IN_WRONG_STATE;
} else {
return BLE_PERIPHERAL_DIFFERENT_CONTEXT_FOR_ADDRESS_ALREADY_EXISTS;
}
le_central_run();
return BLE_PERIPHERAL_OK;
}
le_command_status_t le_central_disconnect(le_central_t *context){
le_central_t * peripheral = get_le_central_context_with_address(context->address_type, context->address);
if (!peripheral || (peripheral && peripheral != context)){
return BLE_PERIPHERAL_DIFFERENT_CONTEXT_FOR_ADDRESS_ALREADY_EXISTS;
}
switch(context->le_central_state){
case P_W2_CONNECT:
linked_list_remove(&le_central_connections, (linked_item_t *) context);
send_le_central_connection_complete_event(peripheral, GATT_CONNECTION_COMPLETE, 0);
break;
case P_W4_CONNECTED:
case P_W2_CANCEL_CONNECT:
// trigger cancel connect
context->le_central_state = P_W2_CANCEL_CONNECT;
break;
case P_W4_DISCONNECTED:
case P_W4_CONNECT_CANCELLED:
return BLE_PERIPHERAL_IN_WRONG_STATE;
default:
context->le_central_state = P_W2_DISCONNECT;
break;
}
le_central_run();
return BLE_PERIPHERAL_OK;
}
static void le_central_run(){
// check if command is send
le_central_handle_context_list();
}
static void le_packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
switch (packet[0]) {
case HCI_EVENT_COMMAND_COMPLETE:
if (COMMAND_COMPLETE_EVENT(packet, hci_le_create_connection_cancel)){
// printf("packet_handler:: hci_le_create_connection_cancel: cancel connect\n");
if (packet[3] != 0x0B) break;
// cancel connection failed, as connection already established
le_central_t * peripheral = get_le_central_w4_connect_cancelled();
peripheral->le_central_state = P_W2_DISCONNECT;
break;
}
break;
case HCI_EVENT_DISCONNECTION_COMPLETE:
{
uint16_t handle = READ_BT_16(packet,3);
le_central_t * peripheral = get_le_central_context_for_handle(handle);
if (!peripheral) break;
peripheral->le_central_state = P_IDLE;
linked_list_remove(&le_central_connections, (linked_item_t *) peripheral);
// TODO shouldn't we send some kind of disconnect complete?
send_le_central_connection_complete_event(peripheral, GATT_CONNECTION_COMPLETE, packet[5]);
// printf("Peripheral disconnected, and removed from list\n");
break;
}
case HCI_EVENT_LE_META:
switch (packet[2]) {
case HCI_SUBEVENT_LE_CONNECTION_COMPLETE: {
le_central_t * peripheral = get_le_central_w4_connected();
if (peripheral){
if (packet[3]){
peripheral->le_central_state = P_IDLE;
linked_list_remove(&le_central_connections, (linked_item_t *) peripheral);
} else {
peripheral->le_central_state = P_CONNECTED;
peripheral->handle = READ_BT_16(packet, 4);
}
send_le_central_connection_complete_event(peripheral, GATT_CONNECTION_COMPLETE, packet[3]);
break;
}
// cancel success?
peripheral = get_le_central_w4_connect_cancelled();
if (!peripheral) break;
linked_list_remove(&le_central_connections, (linked_item_t *) peripheral);
send_le_central_connection_complete_event(peripheral, GATT_CONNECTION_COMPLETE, packet[3]);
break;
}
default:
break;
}
break;
default:
break;
}
le_central_run();
}
static void ble_packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
if (packet_type != HCI_EVENT_PACKET) return;
le_packet_handler(connection, packet_type, channel, packet, size);
gatt_packet_handler(connection, packet_type, channel, packet, size);
// hexdump2(packet, size);
@ -421,7 +196,7 @@ static void dump_descriptor(le_characteristic_descriptor_t * descriptor){
//}
le_central_t test_device;
gatt_client_t test_gatt_client_context;
le_service_t services[40];
@ -967,21 +742,21 @@ static void handle_ble_client_event(le_event_t * event){
handle_disconnect(event);
switch(tc_state){
case TC_W4_CONNECT: {
if (event->type != GATT_CONNECTION_COMPLETE) break;
tc_state = TC_W4_SERVICE_RESULT;
printf("\n test client - CONNECTED, query ACC service\n");
// create gatt client context for this
le_central_connection_complete_event_t * peripheral_event = (le_central_connection_complete_event_t *) event;
uint16_t handle = peripheral_event->device->handle;
gatt_client_start(&test_gatt_client_context, handle);
// let's start
gatt_client_discover_primary_services_by_uuid128(&test_gatt_client_context, acc_service_uuid);
break;
}
// case TC_W4_CONNECT: {
// if (event->type != GATT_CONNECTION_COMPLETE) break;
//
// tc_state = TC_W4_SERVICE_RESULT;
// printf("\n test client - CONNECTED, query ACC service\n");
//
// // create gatt client context for this
// le_central_connection_complete_event_t * peripheral_event = (le_central_connection_complete_event_t *) event;
// uint16_t handle = peripheral_event->device->handle;
// gatt_client_start(&test_gatt_client_context, handle);
//
// // let's start
// gatt_client_discover_primary_services_by_uuid128(&test_gatt_client_context, acc_service_uuid);
// break;
// }
case TC_W4_SERVICE_RESULT:
switch(event->type){
@ -1034,7 +809,7 @@ static void handle_ble_client_event(le_event_t * event){
printf("DONE");
tc_state = TC_W4_DISCONNECT;
printf("\n\n test client - DISCONNECT ");
le_central_disconnect(&test_device);
// le_central_disconnect(&test_device);
break;
default:
@ -1082,7 +857,7 @@ static void handle_hci_event(uint8_t packet_type, uint8_t *packet, uint16_t size
tc_state = TC_W4_CONNECT;
le_central_stop_scan();
le_central_connect(&test_device, test_device_addr_type, test_device_addr);
le_central_connect(&test_device_addr, test_device_addr_type);
break;
case BTSTACK_EVENT_STATE:
@ -1093,6 +868,23 @@ static void handle_hci_event(uint8_t packet_type, uint8_t *packet, uint16_t size
le_central_start_scan();
}
break;
case HCI_EVENT_LE_META:
switch (packet[2]) {
case HCI_SUBEVENT_LE_CONNECTION_COMPLETE: {
if (tc_state != TC_W4_CONNECT) return;
tc_state = TC_W4_SERVICE_RESULT;
printf("\n test client - CONNECTED, query ACC service\n");
gatt_client_start(&test_gatt_client_context, READ_BT_16(packet, 4));
// let's start
gatt_client_discover_primary_services_by_uuid128(&test_gatt_client_context, acc_service_uuid);
break;
}
default:
break;
}
break;
case DAEMON_EVENT_HCI_PACKET_SENT:
switch(tc_state){
case TC_W2_WRITE_WITHOUT_RESPONSE:
@ -1109,6 +901,7 @@ static void handle_hci_event(uint8_t packet_type, uint8_t *packet, uint16_t size
}
}
#ifndef UNIT_TEST
static hci_uart_config_t config;

View File

@ -55,48 +55,10 @@ extern "C" {
#define LE_CENTRAL_MAX_INCLUDE_DEPTH 3
//*************** le central client
typedef enum{
P_IDLE,
P_W2_CONNECT,
P_W4_CONNECTED,
P_CONNECTED,
P_W2_CANCEL_CONNECT,
P_W4_CONNECT_CANCELLED,
P_W2_DISCONNECT,
P_W4_DISCONNECTED
} le_central_state_t;
typedef struct le_central{
linked_item_t item;
le_central_state_t le_central_state;
uint8_t address_type;
bd_addr_t address;
uint16_t handle;
} le_central_t;
typedef struct le_central_connection_complete_event{
uint8_t type;
le_central_t * device;
uint8_t status;
} le_central_connection_complete_event_t;
//*************** gatt client
void ble_client_init();
void le_central_init();
void le_central_register_connection_handler(void (*le_callback)(le_event_t * event));
//void ble_client_register_packet_handler(void (*le_callback)(le_event_t * event));
le_command_status_t le_central_connect(le_central_t *context, uint8_t addr_type, bd_addr_t addr);
le_command_status_t le_central_disconnect(le_central_t *context);
#if defined __cplusplus
}

View File

@ -80,16 +80,6 @@ static hci_stack_t hci_stack_static;
#endif
static hci_stack_t * hci_stack = NULL;
// static void (*le_central_callback)(le_event_t * event);
//static void dummy_notify(le_event_t* event){}
//void le_central_register_handler(void (*le_callback)(le_event_t* event)){
// if (le_callback == NULL){
// le_callback = dummy_notify;
// }
// le_central_callback = le_callback;
//}
// test helper
static uint8_t disable_l2cap_timeouts = 0;
@ -1394,7 +1384,29 @@ void hci_run(){
if (connection->state == SEND_CREATE_CONNECTION){
log_info("sending hci_create_connection\n");
hci_send_cmd(&hci_create_connection, connection->address, hci_usable_acl_packet_types(), 0, 0, 0, 1);
switch(connection->address_type){
case BD_ADDR_TYPE_CLASSIC:
hci_send_cmd(&hci_create_connection, connection->address, hci_usable_acl_packet_types(), 0, 0, 0, 1);
break;
default:
hci_send_cmd(&hci_le_create_connection,
1000, // scan interval: 625 ms
1000, // scan interval: 625 ms
0, // don't use whitelist
connection->address_type, // peer address type
connection->address, // peer bd addr
0, // our addr type: public
80, // conn interval min
80, // conn interval max (3200 * 0.625)
0, // conn latency
2000, // supervision timeout
0, // min ce length
1000 // max ce length
);
connection->state = SENT_CREATE_CONNECTION;
break;
}
return;
}
@ -1863,7 +1875,25 @@ void hci_emit_connection_complete(hci_connection_t *conn, uint8_t status){
bt_flip_addr(&event[5], conn->address);
event[11] = 1; // ACL connection
event[12] = 0; // encryption disabled
hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
hci_stack->packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
}
void hci_emit_le_connection_complete(hci_connection_t *conn, uint8_t status){
uint8_t event[21];
event[0] = HCI_EVENT_LE_META;
event[1] = sizeof(event) - 2;
event[2] = HCI_SUBEVENT_LE_CONNECTION_COMPLETE;
event[3] = status;
bt_store_16(event, 4, conn->con_handle);
event[6] = 0; // TODO: role
event[7] = conn->address_type;
bt_flip_addr(&event[8], conn->address);
bt_store_16(event, 14, 0); // interval
bt_store_16(event, 16, 0); // latency
bt_store_16(event, 18, 0); // supervision timeout
event[20] = 0; // master clock accuracy
hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
hci_stack->packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
}
@ -1874,7 +1904,7 @@ void hci_emit_disconnection_complete(uint16_t handle, uint8_t reason){
event[2] = 0; // status = OK
bt_store_16(event, 3, handle);
event[5] = reason;
hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
hci_stack->packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
}
@ -1885,7 +1915,7 @@ void hci_emit_l2cap_check_timeout(hci_connection_t *conn){
event[0] = L2CAP_EVENT_TIMEOUT_CHECK;
event[1] = sizeof(event) - 2;
bt_store_16(event, 2, conn->con_handle);
hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
hci_stack->packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
}
@ -2126,3 +2156,27 @@ le_command_status_t le_central_stop_scan(){
hci_run();
return BLE_PERIPHERAL_OK;
}
le_command_status_t le_central_connect(bd_addr_t * addr, bd_addr_type_t addr_type){
hci_connection_t * conn = hci_connection_for_bd_addr_and_type(addr, addr_type);
if (!conn){
conn = create_connection_for_bd_addr_and_type(*addr, addr_type);
if (!conn){
// notify client that alloc failed
hci_emit_le_connection_complete(conn, BTSTACK_MEMORY_ALLOC_FAILED);
return BLE_PERIPHERAL_NOT_CONNECTED; // don't sent packet to controller
}
conn->state = SEND_CREATE_CONNECTION;
return BLE_PERIPHERAL_OK;
}
conn->state = OPEN;
hci_emit_le_connection_complete(conn, 0);
hci_run();
return BLE_PERIPHERAL_OK;
}
le_command_status_t le_central_disconnect(uint16_t * handle){
return BLE_PERIPHERAL_OK;
}

View File

@ -262,6 +262,7 @@ typedef enum {
LE_STOP_SCAN,
} le_scanning_state_t;
typedef struct {
// linked list - assert: first field
linked_item_t item;
@ -307,9 +308,9 @@ typedef struct {
// number ACL packets sent to controller
uint8_t num_acl_packets_sent;
} hci_connection_t;
/**
* main data structure
*/
@ -399,7 +400,9 @@ typedef enum {
// void le_central_register_handler(void (*le_callback)(le_event_t* event));
le_command_status_t le_central_start_scan();
le_command_status_t le_central_stop_scan();
le_command_status_t le_central_connect(bd_addr_t * addr, bd_addr_type_t addr_type);
le_command_status_t le_central_disconnect(uint16_t * handle);
//*************** le client end
// create and send hci command packets based on a template and a list of parameters