From 4f3229d8d21e4e71318d76f1812d13d938923ceb Mon Sep 17 00:00:00 2001 From: "mila@ringwald.ch" Date: Fri, 2 May 2014 21:53:08 +0000 Subject: [PATCH] ble client: connect functionality moved to hci --- example/libusb/ble_client.c | 281 +++++------------------------------- example/libusb/ble_client.h | 38 ----- src/hci.c | 82 +++++++++-- src/hci.h | 7 +- 4 files changed, 110 insertions(+), 298 deletions(-) diff --git a/example/libusb/ble_client.c b/example/libusb/ble_client.c index adf7c6629..4b16d29cd 100644 --- a/example/libusb/ble_client.c +++ b/example/libusb/ble_client.c @@ -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; diff --git a/example/libusb/ble_client.h b/example/libusb/ble_client.h index ddbc844c2..0eb56ed40 100644 --- a/example/libusb/ble_client.h +++ b/example/libusb/ble_client.h @@ -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 } diff --git a/src/hci.c b/src/hci.c index 7101150f6..1c2642d3c 100644 --- a/src/hci.c +++ b/src/hci.c @@ -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; +} diff --git a/src/hci.h b/src/hci.h index 086bd1b21..f235bc729 100644 --- a/src/hci.h +++ b/src/hci.h @@ -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