diff --git a/ble/att.h b/ble/att.h index 5a788ff38..1f99d51e1 100644 --- a/ble/att.h +++ b/ble/att.h @@ -104,7 +104,8 @@ extern "C" { #define ATT_ERROR_INSUFFICIENT_ENCRYPTION 0x0f #define ATT_ERROR_UNSUPPORTED_GROUP_TYPE 0x10 #define ATT_ERROR_INSUFFICIENT_RESOURCES 0x11 -#define ATT_ERROR_TIMEOUT 0x12 +// custom BTstack ATT error coders +#define ATT_ERROR_TIMEOUT 0x7F // custom BTstack error codes @@ -143,7 +144,12 @@ extern "C" { #define GATT_SECONDARY_SERVICE_UUID 0x2801 #define GATT_INCLUDE_SERVICE_UUID 0x2802 #define GATT_CHARACTERISTICS_UUID 0x2803 +#define GATT_CHARACTERISTIC_EXTENDED_PROPERTIES 0x2900 +#define GATT_CHARACTERISTIC_USER_DESCRIPTION 0x2901 #define GATT_CLIENT_CHARACTERISTICS_CONFIGURATION 0x2902 +#define GATT_SERVER_CHARACTERISTICS_CONFIGURATION 0x2903 +#define GATT_CHARACTERISTIC_PRESENTATION_FORMAT 0x2904 +#define GATT_CHARACTERISTIC_AGGREGATE_FORMAT 0x2905 #define GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NONE 0 #define GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION 1 diff --git a/ble/att_server.c b/ble/att_server.c index 59a7a3974..d3cd8728c 100644 --- a/ble/att_server.c +++ b/ble/att_server.c @@ -267,7 +267,7 @@ static void att_run(void){ // signature is { sequence counter, secure hash } sm_key_t csrk; - le_device_db_csrk_get(att_ir_le_device_db_index, csrk); + le_device_db_remote_csrk_get(att_ir_le_device_db_index, csrk); att_server_state = ATT_SERVER_W4_SIGNED_WRITE_VALIDATION; log_info("Orig Signature: "); hexdump( &att_request_buffer[att_request_size-8], 8); diff --git a/ble/gatt_client.c b/ble/gatt_client.c index 7a1cac8dc..898c5d55a 100644 --- a/ble/gatt_client.c +++ b/ble/gatt_client.c @@ -62,6 +62,7 @@ static linked_list_t gatt_client_connections = NULL; static linked_list_t gatt_subclients = NULL; static uint16_t gatt_client_id = 0; +static uint8_t pts_suppress_mtu_exchange; static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle, uint8_t *packet, uint16_t size); static void gatt_client_report_error_if_pending(gatt_client_t *peripheral, uint8_t error_code); @@ -128,6 +129,7 @@ void gatt_client_unregister_packet_handler(uint16_t gatt_client_id){ void gatt_client_init(void){ gatt_client_connections = NULL; + pts_suppress_mtu_exchange = 0; att_dispatch_register_client(gatt_client_att_packet_handler); } @@ -184,11 +186,17 @@ static gatt_client_t * provide_context_for_conn_handle(uint16_t con_handle){ context = btstack_memory_gatt_client_get(); if (!context) return NULL; // init state + memset(context, 0, sizeof(gatt_client_t)); context->handle = con_handle; context->mtu = ATT_DEFAULT_MTU; context->mtu_state = SEND_MTU_EXCHANGE; context->gatt_client_state = P_READY; linked_list_add(&gatt_client_connections, (linked_item_t*)context); + + // skip mtu exchange for testing sm with pts + if (pts_suppress_mtu_exchange){ + context->mtu_state = MTU_EXCHANGED; + } return context; } @@ -489,6 +497,15 @@ static void emit_event(uint16_t gatt_client_id, le_event_t* event){ (*gatt_client_callback)(event); } +static void emit_event_to_all_subclients(le_event_t * event){ + linked_list_iterator_t it; + linked_list_iterator_init(&it, &gatt_subclients); + while (linked_list_iterator_has_next(&it)){ + gatt_subclient_t * subclient = (gatt_subclient_t*) linked_list_iterator_next(&it); + (*subclient->callback)(event); + } +} + static void emit_gatt_complete_event(gatt_client_t * peripheral, uint8_t status){ gatt_complete_event_t event; event.type = GATT_QUERY_COMPLETE; @@ -604,14 +621,18 @@ static void report_gatt_included_service(gatt_client_t * peripheral, uint8_t *uu emit_event(peripheral->subclient_id, (le_event_t*)&event); } +static void setup_characteristic_value_event(le_characteristic_value_event_t * event, uint16_t handle, uint16_t value_handle, uint8_t * value, uint16_t length, uint16_t offset, uint8_t event_type){ + event->type = event_type; + event->handle = handle; + event->value_handle = value_handle; + event->value_offset = offset; + event->blob_length = length; + event->blob = value; +} + static void send_characteristic_value_event(gatt_client_t * peripheral, uint16_t value_handle, uint8_t * value, uint16_t length, uint16_t offset, uint8_t event_type){ le_characteristic_value_event_t event; - event.type = event_type; - event.handle = peripheral->handle; - event.value_handle = value_handle; - event.value_offset = offset; - event.blob_length = length; - event.blob = value; + setup_characteristic_value_event(&event, peripheral->handle, value_handle, value, length, offset, event_type); emit_event(peripheral->subclient_id, (le_event_t*)&event); } @@ -619,12 +640,16 @@ static void report_gatt_long_characteristic_value_blob(gatt_client_t * periphera send_characteristic_value_event(peripheral, peripheral->attribute_handle, value, blob_length, value_offset, GATT_LONG_CHARACTERISTIC_VALUE_QUERY_RESULT); } -static void report_gatt_notification(gatt_client_t * peripheral, uint16_t handle, uint8_t * value, int length){ - send_characteristic_value_event(peripheral, handle, value, length, 0, GATT_NOTIFICATION); +static void report_gatt_notification(uint16_t con_handle, uint16_t value_handle, uint8_t * value, int length){ + le_characteristic_value_event_t event; + setup_characteristic_value_event(&event, con_handle, value_handle, value, length, 0, GATT_NOTIFICATION); + emit_event_to_all_subclients((le_event_t*)&event); } -static void report_gatt_indication(gatt_client_t * peripheral, uint16_t handle, uint8_t * value, int length){ - send_characteristic_value_event(peripheral, handle, value, length, 0, GATT_INDICATION); +static void report_gatt_indication(uint16_t con_handle, uint16_t value_handle, uint8_t * value, int length){ + le_characteristic_value_event_t event; + setup_characteristic_value_event(&event, con_handle, value_handle, value, length, 0, GATT_INDICATION); + emit_event_to_all_subclients((le_event_t*)&event); } static void report_gatt_characteristic_value(gatt_client_t * peripheral, uint16_t handle, uint8_t * value, int length){ @@ -672,17 +697,20 @@ static void report_gatt_all_characteristic_descriptors(gatt_client_t * periphera } -static void trigger_next_query(gatt_client_t * peripheral, uint16_t last_result_handle, gatt_client_state_t next_query_state){ - if (last_result_handle < peripheral->end_group_handle){ - peripheral->start_group_handle = last_result_handle + 1; - peripheral->gatt_client_state = next_query_state; - return; - } - // DONE - gatt_client_handle_transaction_complete(peripheral); - emit_gatt_complete_event(peripheral, 0); +static int is_query_done(gatt_client_t * peripheral, uint16_t last_result_handle){ + return last_result_handle >= peripheral->end_group_handle; } +static void trigger_next_query(gatt_client_t * peripheral, uint16_t last_result_handle, gatt_client_state_t next_query_state){ + if (is_query_done(peripheral, last_result_handle)){ + gatt_client_handle_transaction_complete(peripheral); + emit_gatt_complete_event(peripheral, 0); + return; + } + // next + peripheral->start_group_handle = last_result_handle + 1; + peripheral->gatt_client_state = next_query_state; +} static inline void trigger_next_included_service_query(gatt_client_t * peripheral, uint16_t last_result_handle){ trigger_next_query(peripheral, last_result_handle, P_W2_SEND_INCLUDED_SERVICE_QUERY); @@ -697,6 +725,10 @@ static inline void trigger_next_service_by_uuid_query(gatt_client_t * peripheral } static inline void trigger_next_characteristic_query(gatt_client_t * peripheral, uint16_t last_result_handle){ + if (is_query_done(peripheral, last_result_handle)){ + // report last characteristic + characteristic_end_found(peripheral, peripheral->end_group_handle); + } trigger_next_query(peripheral, last_result_handle, P_W2_SEND_ALL_CHARACTERISTICS_OF_SERVICE_QUERY); } @@ -905,7 +937,7 @@ static void gatt_client_run(void){ case P_W4_CMAC_READY: if (sm_cmac_ready()){ sm_key_t csrk; - le_device_db_csrk_get(peripheral->le_device_index, csrk); + le_device_db_local_csrk_get(peripheral->le_device_index, csrk); uint32_t sign_counter = le_device_db_local_counter_get(peripheral->le_device_index); peripheral->gatt_client_state = P_W4_CMAC_RESULT; sm_cmac_start(csrk, ATT_SIGNED_WRITE_COMMAND, peripheral->attribute_handle, peripheral->attribute_length, peripheral->attribute_value, sign_counter, att_signed_write_handle_cmac_result); @@ -932,15 +964,6 @@ static void gatt_client_run(void){ } -static void emit_event_to_all_subclients(le_event_t * event){ - linked_list_iterator_t it; - linked_list_iterator_init(&it, &gatt_subclients); - while (linked_list_iterator_has_next(&it)){ - gatt_subclient_t * subclient = (gatt_subclient_t*) linked_list_iterator_next(&it); - (*subclient->callback)(event); - } -} - static void gatt_client_report_error_if_pending(gatt_client_t *peripheral, uint8_t error_code) { if (is_ready(peripheral)) return; gatt_client_handle_transaction_complete(peripheral); @@ -981,8 +1004,21 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle, } if (packet_type != ATT_DATA_PACKET) return; - - gatt_client_t * peripheral = get_gatt_client_context_for_handle(handle); + + // special cases: notifications don't need a context while indications motivate creating one + gatt_client_t * peripheral; + switch (packet[0]){ + case ATT_HANDLE_VALUE_NOTIFICATION: + report_gatt_notification(handle, READ_BT_16(packet,1), &packet[3], size-3); + return; + case ATT_HANDLE_VALUE_INDICATION: + peripheral = provide_context_for_conn_handle(handle); + break; + default: + peripheral = get_gatt_client_context_for_handle(handle); + break; + } + if (!peripheral) return; switch (packet[0]){ @@ -1006,12 +1042,8 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle, break; } break; - case ATT_HANDLE_VALUE_NOTIFICATION: - report_gatt_notification(peripheral, READ_BT_16(packet,1), &packet[3], size-3); - break; - case ATT_HANDLE_VALUE_INDICATION: - report_gatt_indication(peripheral, READ_BT_16(packet,1), &packet[3], size-3); + report_gatt_indication(handle, READ_BT_16(packet,1), &packet[3], size-3); peripheral->send_confirmation = 1; break; @@ -1020,12 +1052,12 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle, case P_W4_ALL_CHARACTERISTICS_OF_SERVICE_QUERY_RESULT: report_gatt_characteristics(peripheral, packet, size); trigger_next_characteristic_query(peripheral, get_last_result_handle_from_characteristics_list(packet, size)); - // GATT_QUERY_COMPLETE is emitted by trigger_next_xxx when done + // GATT_QUERY_COMPLETE is emitted by trigger_next_xxx when done, or by ATT_ERROR break; case P_W4_CHARACTERISTIC_WITH_UUID_QUERY_RESULT: report_gatt_characteristics(peripheral, packet, size); trigger_next_characteristic_query(peripheral, get_last_result_handle_from_characteristics_list(packet, size)); - // GATT_QUERY_COMPLETE is emitted by trigger_next_xxx when done + // GATT_QUERY_COMPLETE is emitted by trigger_next_xxx when done, or by ATT_ERROR break; case P_W4_INCLUDED_SERVICE_QUERY_RESULT: { @@ -1724,4 +1756,7 @@ le_command_status_t gatt_client_write_long_characteristic_descriptor(uint16_t ga return gatt_client_write_long_characteristic_descriptor_using_descriptor_handle(gatt_client_id, con_handle, descriptor->handle, length, value); } +void gatt_client_pts_suppress_mtu_exchange(void){ + pts_suppress_mtu_exchange = 1; +} diff --git a/ble/gatt_client.h b/ble/gatt_client.h index 0bc985e5a..ccdf0a786 100644 --- a/ble/gatt_client.h +++ b/ble/gatt_client.h @@ -379,6 +379,9 @@ le_command_status_t gatt_client_write_long_characteristic_descriptor_using_descr le_command_status_t gatt_client_write_client_characteristic_configuration(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_t * characteristic, uint16_t configuration); /* API_END */ +// only used for testing +void gatt_client_pts_suppress_mtu_exchange(); + #if defined __cplusplus } #endif diff --git a/ble/le_device_db.h b/ble/le_device_db.h index ce82e7e42..cf1c4e351 100644 --- a/ble/le_device_db.h +++ b/ble/le_device_db.h @@ -115,18 +115,32 @@ void le_device_db_encryption_set(int index, uint16_t ediv, uint8_t rand[8], sm_k void le_device_db_encryption_get(int index, uint16_t * ediv, uint8_t rand[8], sm_key_t ltk, int * key_size, int * authenticated, int * authorized); /** - * @brief set signing key for this device + * @brief set local signing key for this device * @param index * @param signing key as input */ -void le_device_db_csrk_set(int index, sm_key_t csrk); +void le_device_db_local_csrk_set(int index, sm_key_t csrk); /** - * @brief get signing key for this device + * @brief get local signing key for this device * @param index * @param signing key as output */ -void le_device_db_csrk_get(int index, sm_key_t csrk); +void le_device_db_local_csrk_get(int index, sm_key_t csrk); + +/** + * @brief set remote signing key for this device + * @param index + * @param signing key as input + */ +void le_device_db_remote_csrk_set(int index, sm_key_t csrk); + +/** + * @brief get remote signing key for this device + * @param index + * @param signing key as output + */ +void le_device_db_remote_csrk_get(int index, sm_key_t csrk); /** * @brief query last used/seen signing counter diff --git a/ble/le_device_db_dummy.c b/ble/le_device_db_dummy.c index 345513a9e..c2eaf1680 100644 --- a/ble/le_device_db_dummy.c +++ b/ble/le_device_db_dummy.c @@ -57,7 +57,15 @@ void le_device_db_encryption_get(int index, uint16_t * ediv, uint8_t rand[8], sm void le_device_db_info(int index, int * addr_type, bd_addr_t addr, sm_key_t csrk){} // get signature key -void le_device_db_csrk_get(int index, sm_key_t csrk){} +void le_device_db_remote_csrk_get(int index, sm_key_t csrk){} + +void le_device_db_remote_csrk_set(int index, sm_key_t csrk){} + +// get signature key +void le_device_db_local_csrk_get(int index, sm_key_t csrk){} + +void le_device_db_local_csrk_set(int index, sm_key_t csrk){} + // query last used/seen signing counter uint32_t le_device_db_remote_counter_get(int index){ diff --git a/ble/le_device_db_memory.c b/ble/le_device_db_memory.c index a57cdfcb5..81a5fb939 100644 --- a/ble/le_device_db_memory.c +++ b/ble/le_device_db_memory.c @@ -59,10 +59,11 @@ typedef struct le_device_memory_db { uint8_t authorized; // Signed Writes by remote - sm_key_t csrk; + sm_key_t remote_csrk; uint32_t remote_counter; - // Signed Writes to remote (local CSRK is fixed) + // Signed Writes by us + sm_key_t local_csrk; uint32_t local_counter; } le_device_memory_db_t; @@ -150,12 +151,20 @@ void le_device_db_encryption_get(int index, uint16_t * ediv, uint8_t rand[8], sm } // get signature key -void le_device_db_csrk_get(int index, sm_key_t csrk){ - if (csrk) memcpy(csrk, le_devices[index].csrk, 16); +void le_device_db_remote_csrk_get(int index, sm_key_t csrk){ + if (csrk) memcpy(csrk, le_devices[index].remote_csrk, 16); } -void le_device_db_csrk_set(int index, sm_key_t csrk){ - if (csrk) memcpy(le_devices[index].csrk, csrk, 16); +void le_device_db_remote_csrk_set(int index, sm_key_t csrk){ + if (csrk) memcpy(le_devices[index].remote_csrk, csrk, 16); +} + +void le_device_db_local_csrk_get(int index, sm_key_t csrk){ + if (csrk) memcpy(csrk, le_devices[index].local_csrk, 16); +} + +void le_device_db_local_csrk_set(int index, sm_key_t csrk){ + if (csrk) memcpy(le_devices[index].local_csrk, csrk, 16); } // query last used/seen signing counter @@ -185,6 +194,7 @@ void le_device_db_dump(void){ if (le_devices[i].addr_type == INVALID_ENTRY_ADDR_TYPE) continue; log_info("%u: %u %s", i, le_devices[i].addr_type, bd_addr_to_str(le_devices[i].addr)); log_key("irk", le_devices[i].irk); - log_key("csrk", le_devices[i].csrk); + log_key("local csrk", le_devices[i].local_csrk); + log_key("remote csrk", le_devices[i].remote_csrk); } } diff --git a/ble/sm.c b/ble/sm.c index b6c89e9f2..f91ee303f 100644 --- a/ble/sm.c +++ b/ble/sm.c @@ -117,6 +117,8 @@ typedef enum { // GLOBAL DATA // +static uint8_t test_use_fixed_local_csrk; + // configuration static uint8_t sm_accepted_stk_generation_methods; static uint8_t sm_max_encryption_key_size; @@ -1013,7 +1015,7 @@ static void sm_key_distribution_handle_all_received(sm_connection_t * sm_conn){ // store CSRK if (setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION){ log_info("sm: store remote CSRK"); - le_device_db_csrk_set(le_db_index, setup->sm_peer_csrk); + le_device_db_remote_csrk_set(le_db_index, setup->sm_peer_csrk); le_device_db_remote_counter_set(le_db_index, 0); } @@ -1505,16 +1507,15 @@ static void sm_run(void){ if (setup->sm_key_distribution_send_set & SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION){ setup->sm_key_distribution_send_set &= ~SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION; + // hack to reproduce test runs + if (test_use_fixed_local_csrk){ + memset(setup->sm_local_csrk, 0xcc, 16); + } + uint8_t buffer[17]; buffer[0] = SM_CODE_SIGNING_INFORMATION; - // optimization: use CSRK of Peripheral if received, to avoid storing two CSRKs in our DB - if (setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION){ - log_info("sm: mirror CSRK"); - memcpy(setup->sm_local_csrk, setup->sm_peer_csrk, 16); - } else { - log_info("sm: store local CSRK"); - le_device_db_csrk_set(connection->sm_le_db_index, setup->sm_local_csrk); - } + log_info("sm: store local CSRK"); + le_device_db_local_csrk_set(connection->sm_le_db_index, setup->sm_local_csrk); swap128(setup->sm_local_csrk, &buffer[1]); l2cap_send_connectionless(connection->sm_handle, L2CAP_CID_SECURITY_MANAGER_PROTOCOL, (uint8_t*) buffer, sizeof(buffer)); sm_timeout_reset(connection); @@ -2286,6 +2287,10 @@ void sm_test_set_irk(sm_key_t irk){ sm_persistent_irk_ready = 1; } +void sm_test_use_fixed_local_csrk(void){ + test_use_fixed_local_csrk = 1; +} + void sm_init(void){ // set some (BTstack default) ER and IR int i; @@ -2317,6 +2322,8 @@ void sm_init(void){ sm_active_connection = 0; + test_use_fixed_local_csrk = 0; + // attach to lower layers l2cap_register_fixed_channel(sm_packet_handler, L2CAP_CID_SECURITY_MANAGER_PROTOCOL); } diff --git a/ble/sm.h b/ble/sm.h index 0e45c2fd5..b603be8ed 100644 --- a/ble/sm.h +++ b/ble/sm.h @@ -279,6 +279,9 @@ int sm_address_resolution_lookup(uint8_t addr_type, bd_addr_t addr); int sm_le_device_index(uint16_t handle ); /* API_END */ +// testing only +void sm_test_use_fixed_local_csrk(void); + #if defined __cplusplus } #endif diff --git a/platforms/posix-h4/.gitignore b/platforms/posix-h4/.gitignore new file mode 100644 index 000000000..506c45d91 --- /dev/null +++ b/platforms/posix-h4/.gitignore @@ -0,0 +1,27 @@ +ancs_client +ancs_client.h +ble_central_test +ble_peripheral +ble_peripheral_sm_minimal +bnep_test +classic_test +gap_dedicated_bonding +gap_inquiry +gap_inquiry_and_bond +gatt_battery_query +gatt_browser +hsp_ag_test +hsp_hs_test +l2cap_test +profile.h +sdp_bnep_query +sdp_general_query +sdp_rfcomm_query +spp_and_le_counter +spp_and_le_counter.h +spp_counter +spp_streamer +led_counter +le_counter.h +ble_peripheral_test +le_counter diff --git a/platforms/posix-h4/Makefile b/platforms/posix-h4/Makefile new file mode 100644 index 000000000..3fb1d1789 --- /dev/null +++ b/platforms/posix-h4/Makefile @@ -0,0 +1,27 @@ +# Makefile for libusb based examples +BTSTACK_ROOT = ../.. +POSIX_ROOT= ${BTSTACK_ROOT}/platforms/posix + +CORE += main.c stdin_support.c + +COMMON += hci_transport_h4.c run_loop_posix.c remote_device_db_fs.c + +include ${BTSTACK_ROOT}/example/embedded/Makefile.inc + +# CC = gcc-fsf-4.9 +CFLAGS += -g -Wall +# CFLAGS += -Werror + +VPATH += ${BTSTACK_ROOT}/platforms/posix/src + +ifeq ($(OS),Windows_NT) +LDFLAGS += -lws2_32 +endif + +# Command Line examples require porting to win32, so only build on other unix-ish hosts +ifneq ($(OS),Windows_NT) +EXAMPLES += ${EXAMPLES_CLI} +CFLAGS += -I${POSIX_ROOT}/src +endif + +all: ${BTSTACK_ROOT}/include/btstack/version.h ${EXAMPLES} diff --git a/platforms/posix-h4/btstack-config.h b/platforms/posix-h4/btstack-config.h new file mode 100644 index 000000000..0448f2826 --- /dev/null +++ b/platforms/posix-h4/btstack-config.h @@ -0,0 +1,24 @@ +// config.h created by configure for BTstack Tue Jun 4 23:10:20 CEST 2013 + +#ifndef __BTSTACK_CONFIG +#define __BTSTACK_CONFIG + +#define HAVE_TRANSPORT_USB +#define HAVE_BLE +#define USE_POSIX_RUN_LOOP +#define HAVE_SDP +#define HAVE_RFCOMM +#define REMOTE_DEVICE_DB remote_device_db_iphone +#define HAVE_SO_NOSIGPIPE +#define HAVE_TIME +#define HAVE_MALLOC +#define HAVE_BZERO +#define SDP_DES_DUMP +#define ENABLE_LOG_INFO +#define ENABLE_LOG_ERROR +#define HCI_INCOMING_PRE_BUFFER_SIZE 14 // sizeof benep heade, avoid memcpy +#define HCI_ACL_PAYLOAD_SIZE (1691 + 4) +#define HAVE_HCI_DUMP +#define SDP_DES_DUMP + +#endif diff --git a/platforms/posix-h4/main.c b/platforms/posix-h4/main.c new file mode 100644 index 000000000..6eb1da79b --- /dev/null +++ b/platforms/posix-h4/main.c @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2014 BlueKitchen GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * 4. Any redistribution, use, or modification is done solely for + * personal benefit and not for any commercial purpose or for + * monetary gain. + * + * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS + * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Please inquire about commercial licensing options at + * contact@bluekitchen-gmbh.com + * + */ + +// ***************************************************************************** +// +// minimal setup for HCI code +// +// ***************************************************************************** + +#include +#include +#include +#include +#include + +#include "btstack-config.h" + +#include + +#include "debug.h" +#include "btstack_memory.h" +#include "hci.h" +#include "hci_dump.h" +#include "stdin_support.h" + +int btstack_main(int argc, const char * argv[]); + +static hci_uart_config_t hci_uart_config_generic = { + NULL, + 115200, +}; + +static void sigint_handler(int param){ + +#ifndef _WIN32 + // reset anyway + btstack_stdin_reset(); +#endif + + log_info(" <= SIGINT received, shutting down..\n"); + hci_power_control(HCI_POWER_OFF); + hci_close(); + log_info("Good bye, see you.\n"); + exit(0); +} + +static int led_state = 0; +void hal_led_toggle(void){ + led_state = 1 - led_state; + printf("LED State %u\n", led_state); +} + +int main(int argc, const char * argv[]){ + + /// GET STARTED with BTstack /// + btstack_memory_init(); + run_loop_init(RUN_LOOP_POSIX); + + // use logger: format HCI_DUMP_PACKETLOGGER, HCI_DUMP_BLUEZ or HCI_DUMP_STDOUT + hci_dump_open("/tmp/hci_dump.pklg", HCI_DUMP_PACKETLOGGER); + + // pick serial port + hci_uart_config_generic.device_name = "/dev/tty.usbmodem1413"; + + // init HCI + hci_transport_t * transport = hci_transport_h4_instance(); + remote_device_db_t * remote_db = (remote_device_db_t *) &remote_device_db_fs; + + hci_init(transport, (void*) &hci_uart_config_generic, NULL, remote_db); + + // handle CTRL-c + signal(SIGINT, sigint_handler); + + // setup app + btstack_main(argc, argv); + + // go + run_loop_execute(); + + return 0; +} diff --git a/src/hci.c b/src/hci.c index 32e4be948..bb6edff7e 100644 --- a/src/hci.c +++ b/src/hci.c @@ -85,6 +85,7 @@ static void hci_connection_timestamp(hci_connection_t *connection); static int hci_power_control_on(void); static void hci_power_control_off(void); static void hci_state_reset(void); +static void hci_remove_from_whitelist(bd_addr_type_t address_type, bd_addr_t address); // the STACK is here #ifndef HAVE_MALLOC @@ -1573,27 +1574,35 @@ static void event_handler(uint8_t *packet, int size){ addr_type = (bd_addr_type_t)packet[7]; log_info("LE Connection_complete (status=%u) type %u, %s", packet[3], addr_type, bd_addr_to_str(addr)); conn = hci_connection_for_bd_addr_and_type(addr, addr_type); - // handle error first + // if auto-connect, remove from whitelist in both roles + if (hci_stack->le_connecting_state == LE_CONNECTING_WHITELIST){ + hci_remove_from_whitelist(addr_type, addr); + } + // handle error: error is reported only to the initiator -> outgoing connection if (packet[3]){ + // outgoing connection establishment is done + hci_stack->le_connecting_state = LE_CONNECTING_IDLE; + // remove entry if (conn){ - // outgoing connection failed, remove entry linked_list_remove(&hci_stack->connections, (linked_item_t *) conn); btstack_memory_hci_connection_free( conn ); } - // if authentication error, also delete link key - if (packet[3] == 0x05) { - hci_drop_link_key_for_bd_addr(addr); - } break; } - if (!conn){ - // advertisemts are stopped on incoming connection + // on success, both hosts receive connection complete event + if (packet[6] == 0){ + // if we're master, it was an outgoing connection and we're done with it + hci_stack->le_connecting_state = LE_CONNECTING_IDLE; + } else { + // if we're slave, it was an incoming connection, advertisements have stopped hci_stack->le_advertisements_active = 0; - // LE connections are auto-accepted, so just create a connection if there isn't one already + } + // LE connections are auto-accepted, so just create a connection if there isn't one already + if (!conn){ conn = create_connection_for_bd_addr_and_type(addr, addr_type); } + // no memory, sorry. if (!conn){ - // no memory break; } @@ -2204,9 +2213,12 @@ void hci_run(void){ } if (entry->state & LE_WHITELIST_REMOVE_FROM_CONTROLLER){ + bd_addr_t address; + bd_addr_type_t address_type = entry->address_type; + memcpy(address, entry->address, 6); linked_list_remove(&hci_stack->le_whitelist, (linked_item_t *) entry); btstack_memory_whitelist_entry_free(entry); - hci_send_cmd(&hci_le_remove_device_from_white_list, entry->address_type, entry->address); + hci_send_cmd(&hci_le_remove_device_from_white_list, address_type, address); return; } } @@ -3125,7 +3137,7 @@ void gap_advertisements_set_data(uint8_t advertising_data_length, uint8_t * adve hci_stack->le_advertisements_data = advertising_data; hci_stack->le_advertisements_todo |= LE_ADVERTISEMENT_TASKS_SET_DATA; // disable advertisements before setting data - if (hci_stack->le_advertisements_enabled){ + if (hci_stack->le_advertisements_active){ hci_stack->le_advertisements_todo |= LE_ADVERTISEMENT_TASKS_DISABLE | LE_ADVERTISEMENT_TASKS_ENABLE; } hci_run(); @@ -3159,7 +3171,7 @@ void gap_advertisements_set_data(uint8_t advertising_data_length, uint8_t * adve hci_stack->le_advertisements_todo |= LE_ADVERTISEMENT_TASKS_SET_PARAMS; // disable advertisements before changing params - if (hci_stack->le_advertisements_enabled){ + if (hci_stack->le_advertisements_active){ hci_stack->le_advertisements_todo |= LE_ADVERTISEMENT_TASKS_DISABLE | LE_ADVERTISEMENT_TASKS_ENABLE; } hci_run(); @@ -3214,13 +3226,7 @@ int gap_auto_connection_start(bd_addr_type_t address_type, bd_addr_t address){ return 0; } -/** - * @brief Auto Connection Establishment - Stop Connecting to device - * @param address_typ - * @param address - * @returns 0 if ok - */ -int gap_auto_connection_stop(bd_addr_type_t address_type, bd_addr_t address){ +static void hci_remove_from_whitelist(bd_addr_type_t address_type, bd_addr_t address){ linked_list_iterator_t it; linked_list_iterator_init(&it, &hci_stack->le_whitelist); while (linked_list_iterator_has_next(&it)){ @@ -3236,6 +3242,16 @@ int gap_auto_connection_stop(bd_addr_type_t address_type, bd_addr_t address){ linked_list_iterator_remove(&it); btstack_memory_whitelist_entry_free(entry); } +} + +/** + * @brief Auto Connection Establishment - Stop Connecting to device + * @param address_typ + * @param address + * @returns 0 if ok + */ +int gap_auto_connection_stop(bd_addr_type_t address_type, bd_addr_t address){ + hci_remove_from_whitelist(address_type, address); hci_run(); return 0; } diff --git a/test/Makefile b/test/Makefile index cbeaab0fc..7c64dfdf5 100644 --- a/test/Makefile +++ b/test/Makefile @@ -12,24 +12,23 @@ SUBDIRS = \ sdp_client \ security_manager \ -# security_manager \ - -EXCLUDED = ios - subdirs: echo Building all tests + @set -e; \ for dir in $(SUBDIRS); do \ $(MAKE) -C $$dir; \ done clean: echo Clean all test + @set -e; \ for dir in $(SUBDIRS); do \ $(MAKE) -C $$dir clean; \ done test: echo Run all test + @set -e; \ for dir in $(SUBDIRS); do \ $(MAKE) -C $$dir test; \ done diff --git a/test/att_db/Makefile b/test/att_db/Makefile index b3516652f..9f9606953 100644 --- a/test/att_db/Makefile +++ b/test/att_db/Makefile @@ -13,6 +13,7 @@ VPATH += ${BTSTACK_ROOT}/platforms/posix/src COMMON = \ utils.c \ + hci_dump.c \ att_db_util.c \ COMMON_OBJ = $(COMMON:.c=.o) diff --git a/test/des_iterator/Makefile b/test/des_iterator/Makefile index a2899f21a..8459b2f70 100644 --- a/test/des_iterator/Makefile +++ b/test/des_iterator/Makefile @@ -13,6 +13,7 @@ VPATH += ${BTSTACK_ROOT}/platforms/posix/src COMMON = \ sdp_util.c \ + hci_dump.c \ utils.c COMMON_OBJ = $(COMMON:.c=.o) diff --git a/test/gatt_client/expected_results.h b/test/gatt_client/expected_results.h index 4539fd499..170a87543 100644 --- a/test/gatt_client/expected_results.h +++ b/test/gatt_client/expected_results.h @@ -32,7 +32,7 @@ const uint8_t included_services_uuid128_handles[][2] = { uint8_t characteristic_handles[][2]= { {0x26, 0x2a}, {0x2b, 0x2f}, {0x30, 0x32}, {0x33, 0x35}, {0x36, 0x38}, {0x39, 0x3b}, {0x3c, 0x3e}, {0x3f, 0x41}, {0x42, 0x44}, {0x45, 0x47}, - {0x48, 0x49}, {0x4a, 0x4f}, {0x50, 0x51}, {0x52, 0x53} + {0x48, 0x49}, {0x4a, 0x4f}, {0x50, 0x51}, {0x52, 0x53}, {0x54, 0x55} }; uint8_t characteristic_uuids[][16] = { @@ -49,7 +49,8 @@ uint8_t characteristic_uuids[][16] = { {0x00, 0x00, 0xf1, 0x0a, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}, {0x00, 0x00, 0xf1, 0x0b, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}, {0x00, 0x00, 0xf1, 0x0d, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}, - {0x00, 0x00, 0xf1, 0x0c, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb} + {0x00, 0x00, 0xf1, 0x0c, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}, + {0x00, 0x00, 0xf1, 0x0e, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}, }; uint8_t indication[] = {GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION, 0x00}; diff --git a/test/gatt_client/gatt_client_test.c b/test/gatt_client/gatt_client_test.c index 547c44b9c..b369731dc 100644 --- a/test/gatt_client/gatt_client_test.c +++ b/test/gatt_client/gatt_client_test.c @@ -128,7 +128,7 @@ static void verify_included_services_uuid128(void){ } static void verify_charasteristics(void){ - CHECK_EQUAL(14, result_index); + CHECK_EQUAL(15, result_index); for (int i=0; i= 0xe0) return att_error_common_error; if (code >= 0xa0) return att_error_reserved; if (code >= 0x80) return att_error_application; + if (code == 0x7f) return att_error_timeout; if (code >= 0x12) return att_error_reserved; return att_errors[code]; } @@ -391,6 +422,7 @@ void use_public_pts_address(void){ void handle_gatt_client_event(le_event_t * event){ le_characteristic_value_event_t * value; + le_characteristic_event_t * characteristic_event; uint8_t address_type; bd_addr_t flipped_address; le_service_t * service; @@ -416,25 +448,41 @@ void handle_gatt_client_event(le_event_t * event){ printf(", start group handle 0x%04x, end group handle 0x%04x\n", service->start_group_handle, service->end_group_handle); break; case GATT_CHARACTERISTIC_QUERY_RESULT: + characteristic_event = ((le_characteristic_event_t *) event); switch (central_state) { case CENTRAL_W4_NAME_QUERY_COMPLETE: - gap_name_characteristic = ((le_characteristic_event_t *) event)->characteristic; + gap_name_characteristic = characteristic_event->characteristic; printf("GAP Name Characteristic found, value handle: 0x04%x\n", gap_name_characteristic.value_handle); break; case CENTRAL_W4_RECONNECTION_ADDRESS_QUERY_COMPLETE: - gap_reconnection_address_characteristic = ((le_characteristic_event_t *) event)->characteristic; + gap_reconnection_address_characteristic = characteristic_event->characteristic; printf("GAP Reconnection Address Characteristic found, value handle: 0x04%x\n", gap_reconnection_address_characteristic.value_handle); break; case CENTRAL_W4_PERIPHERAL_PRIVACY_FLAG_QUERY_COMPLETE: - gap_peripheral_privacy_flag_characteristic = ((le_characteristic_event_t *) event)->characteristic; + gap_peripheral_privacy_flag_characteristic = characteristic_event->characteristic; printf("GAP Peripheral Privacy Flag Characteristic found, value handle: 0x04%x\n", gap_peripheral_privacy_flag_characteristic.value_handle); break; case CENTRAL_W4_SIGNED_WRITE_QUERY_COMPLETE: - signed_write_characteristic = ((le_characteristic_event_t *) event)->characteristic; + signed_write_characteristic = characteristic_event->characteristic; printf("Characteristic for Signed Write found, value handle: 0x%04x\n", signed_write_characteristic.value_handle); break; case CENTRAL_W4_CHARACTERISTICS: - printf("Characteristic found with handle 0x%04x\n", (((le_characteristic_event_t *) event)->characteristic).value_handle); + printf("Characteristic found with handle 0x%04x, uuid ", (characteristic_event->characteristic).value_handle); + if ((characteristic_event->characteristic).uuid16){ + printf("%04x\n", (characteristic_event->characteristic).uuid16); + } else { + printf_hexdump((characteristic_event->characteristic).uuid128, 16); + } + break; + case CENTRAL_GPA_W4_RESPONSE2: + switch (ui_uuid16){ + case GATT_CHARACTERISTIC_PRESENTATION_FORMAT: + case GATT_CHARACTERISTIC_AGGREGATE_FORMAT: + ui_attribute_handle = characteristic_event->characteristic.value_handle; + break; + default: + break; + } break; default: break; @@ -453,7 +501,80 @@ void handle_gatt_client_event(le_event_t * event){ printf("Value: "); printf_hexdump(value->blob, value->blob_length); break; - default: + case CENTRAL_GPA_W4_RESPONSE: + switch (ui_uuid16){ + case GATT_PRIMARY_SERVICE_UUID: + printf ("Attribute handle 0x%04x, primary service 0x%04x\n", value->value_handle, READ_BT_16(value->blob,0)); + break; + case GATT_SECONDARY_SERVICE_UUID: + printf ("Attribute handle 0x%04x, secondary service 0x%04x\n", value->value_handle, READ_BT_16(value->blob,0)); + break; + case GATT_INCLUDE_SERVICE_UUID: + printf ("Attribute handle 0x%04x, included service attribute handle 0x%04x, end group handle 0x%04x, uuid %04x\n", + value->value_handle, READ_BT_16(value->blob,0), READ_BT_16(value->blob,2), READ_BT_16(value->blob,4)); + break; + case GATT_CHARACTERISTICS_UUID: + printf ("Attribute handle 0x%04x, properties 0x%02x, value handle 0x%04x, uuid ", + value->value_handle, value->blob[0], READ_BT_16(value->blob,1)); + if (value->blob_length < 19){ + printf("%04x\n", READ_BT_16(value->blob, 3)); + } else { + printUUID128(&value->blob[3]); + printf("\n"); + } + break; + case GATT_CHARACTERISTIC_EXTENDED_PROPERTIES: + printf ("Attribute handle 0x%04x, gatt characteristic properties 0x%04x\n", value->value_handle, READ_BT_16(value->blob,0)); + break; + case GATT_CHARACTERISTIC_USER_DESCRIPTION: + // go the value, but PTS 6.3 requires another request + printf("Read by type request received, store attribute handle for read request\n"); + ui_attribute_handle = value->value_handle; + break; + case GATT_CLIENT_CHARACTERISTICS_CONFIGURATION: + printf ("Attribute handle 0x%04x, gatt client characteristic configuration 0x%04x\n", value->value_handle, READ_BT_16(value->blob,0)); + break; + case GATT_CHARACTERISTIC_AGGREGATE_FORMAT: + ui_handles_count = value->blob_length >> 1; + printf ("Attribute handle 0x%04x, gatt characteristic aggregate format. Handles: ", value->value_handle); + for (ui_handles_index = 0; ui_handles_index < ui_handles_count ; ui_handles_index++){ + ui_handles[ui_handles_index] = READ_BT_16(value->blob, (ui_handles_index << 1)); + printf("0x%04x, ", ui_handles[ui_handles_index]); + } + printf("\n"); + ui_handles_index = 0; + ui_aggregate_handle = value->value_handle; + break; + case GATT_CHARACTERISTIC_PRESENTATION_FORMAT: + printf("Presentation format: "); + printf_hexdump(value->blob, value->blob_length); + memcpy(ui_presentation_format, value->blob, 7); + break; + default: + printf("Value: "); + printf_hexdump(value->blob, value->blob_length); + break; + } + break; + case CENTRAL_GPA_W4_RESPONSE3: + switch (ui_uuid16){ + case GATT_CHARACTERISTIC_PRESENTATION_FORMAT: + printf("Value: "); + printf_hexdump(value->blob, value->blob_length); + printf("Format 0x%02x, Exponent 0x%02x, Unit 0x%04x\n", + ui_presentation_format[0], ui_presentation_format[1], READ_BT_16(ui_presentation_format, 2)); + break; + case GATT_CHARACTERISTIC_AGGREGATE_FORMAT: + printf("Aggregated value: "); + printf_hexdump(value->blob, value->blob_length); + memcpy(ui_value_data, value->blob, value->blob_length); + ui_value_pos = 0; + central_state = CENTRAL_GPA_W4_RESPONSE4; + default: + break; + } + break; + default: break; } break; @@ -465,8 +586,32 @@ void handle_gatt_client_event(le_event_t * event){ break; case GATT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT: characteristic_descriptor_event = (le_characteristic_descriptor_event_t *) event; - printf("Value: "); - printf_hexdump(characteristic_descriptor_event->value, characteristic_descriptor_event->value_length); + switch (central_state){ + case CENTRAL_GPA_W4_RESPONSE2: + switch (ui_uuid16){ + case GATT_CHARACTERISTIC_USER_DESCRIPTION: + characteristic_descriptor_event->value[characteristic_descriptor_event->value_length] = 0; + printf ("Attribute handle 0x%04x, characteristic user descriptor: %s\n", + characteristic_descriptor_event->handle, characteristic_descriptor_event->value); + break; + default: + break; + } + break; + case CENTRAL_GPA_W4_RESPONSE4: + // only characteristic aggregate format + printf("Value: "); + printf_hexdump(&ui_value_data[ui_value_pos], gpa_format_type_len[characteristic_descriptor_event->value[0]]); + ui_value_pos += gpa_format_type_len[characteristic_descriptor_event->value[0]]; + printf("Format 0x%02x, Exponent 0x%02x, Unit 0x%04x\n", + characteristic_descriptor_event->value[0], characteristic_descriptor_event->value[1], + READ_BT_16(characteristic_descriptor_event->value, 2)); + break; + default: + printf("Value: "); + printf_hexdump(characteristic_descriptor_event->value, characteristic_descriptor_event->value_length); + break; + } break; case GATT_LONG_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT: characteristic_descriptor_event = (le_characteristic_descriptor_event_t *) event; @@ -523,11 +668,70 @@ void handle_gatt_client_event(le_event_t * event){ printf("Primary Service Discovery complete\n"); central_state = CENTRAL_IDLE; break; + case CENTRAL_GPA_W4_RESPONSE: + switch (ui_uuid16){ + case GATT_CHARACTERISTIC_USER_DESCRIPTION: + central_state = CENTRAL_GPA_W4_RESPONSE2; + printf("Sending Read Characteristic Descriptor at 0x%04x\n", ui_attribute_handle); + gatt_client_read_characteristic_descriptor_using_descriptor_handle(gc_id, handle, ui_attribute_handle); + break; + case GATT_CHARACTERISTIC_PRESENTATION_FORMAT: + case GATT_CHARACTERISTIC_AGGREGATE_FORMAT: + { + printf("Searching Characteristic Declaration\n"); + central_state = CENTRAL_GPA_W4_RESPONSE2; + le_service_t service; + service.start_group_handle = ui_start_handle; + service.end_group_handle = ui_end_handle; + gatt_client_discover_characteristics_for_service(gc_id, handle, &service); + break; + } + break; + default: + break; + } + break; + case CENTRAL_GPA_W4_RESPONSE2: + switch(ui_uuid16){ + case GATT_CHARACTERISTIC_PRESENTATION_FORMAT: + case GATT_CHARACTERISTIC_AGGREGATE_FORMAT: + printf("Reading characteristic value at 0x%04x\n", ui_attribute_handle); + central_state = CENTRAL_GPA_W4_RESPONSE3; + gatt_client_read_value_of_characteristic_using_value_handle(gc_id, handle, ui_attribute_handle); + break; + default: + break; + } + break; + case CENTRAL_GPA_W4_RESPONSE4: + // so far, only GATT_CHARACTERISTIC_AGGREGATE_FORMAT + if (ui_handles_index < ui_handles_count) { + printf("Reading Characteristic Presentation Format at 0x%04x\n", ui_handles[ui_handles_index]); + gatt_client_read_characteristic_descriptor_using_descriptor_handle(gc_id, handle, ui_handles[ui_handles_index]); + ui_handles_index++; + break; + } + if (ui_handles_index == ui_handles_count ) { + // PTS rqequires to read the characteristic aggregate descriptor again (no idea why) + gatt_client_read_value_of_characteristic_using_value_handle(gc_id, handle, ui_aggregate_handle); + ui_handles_index++; + } + break; default: central_state = CENTRAL_IDLE; break; } break; + case GATT_NOTIFICATION: + value = (le_characteristic_value_event_t *) event; + printf("Notification handle 0x%04x, value: ", value->value_handle); + printf_hexdump(value->blob, value->blob_length); + break; + case GATT_INDICATION: + value = (le_characteristic_value_event_t *) event; + printf("Indication handle 0x%04x, value: ", value->value_handle); + printf_hexdump(value->blob, value->blob_length); + break; default: break; } @@ -537,81 +741,143 @@ uint16_t value_handle = 1; uint16_t attribute_size = 1; int scanning_active = 0; +int num_rows = 0; +int num_lines = 0; +const char * rows[100]; +const char * lines[100]; +const char * empty_string = ""; +const int width = 70; + +void reset_screen(void){ + // free memory + int i = 0; + for (i=0;i '9') { - printf("stdinprocess: invalid input 0x%02x\n", buffer); return 0; } printf("%c", buffer); @@ -688,6 +955,15 @@ static int ui_process_digits_for_passkey(char buffer){ } static int ui_process_uint16_request(char buffer){ + if (buffer == 0x7f || buffer == 0x08) { + if (ui_uint16_pos){ + printf("\b \b"); + fflush(stdout); + ui_uint16 >>= 4; + ui_uint16_pos--; + } + return 0; + } if (buffer == '\n' || buffer == '\r'){ ui_uint16_request = 0; printf("\n"); @@ -696,6 +972,20 @@ static int ui_process_uint16_request(char buffer){ printf("Discover Primary Services with UUID16 %04x\n", ui_uint16); gatt_client_discover_primary_services_by_uuid16(gc_id, handle, ui_uint16); return 0; + case CENTRAL_ENTER_START_HANDLE_4_DISCOVER_CHARACTERISTICS: + ui_attribute_handle = ui_uint16; + ui_request_uint16("Please enter end handle: "); + central_state = CENTRAL_ENTER_END_HANDLE_4_DISCOVER_CHARACTERISTICS; + return 0; + case CENTRAL_ENTER_END_HANDLE_4_DISCOVER_CHARACTERISTICS: { + printf("Discover Characteristics from 0x%04x to 0x%04x\n", ui_attribute_handle, ui_uint16); + central_state = CENTRAL_W4_CHARACTERISTICS; + le_service_t service; + service.start_group_handle = ui_attribute_handle; + service.end_group_handle = ui_uint16; + gatt_client_discover_characteristics_for_service(gc_id, handle, &service); + return 0; + } case CENTRAL_W4_CHARACTERISTICS: printf("Discover Characteristics with UUID16 %04x\n", ui_uint16); gatt_client_discover_characteristics_for_handle_range_by_uuid16(gc_id, handle, 0x0001, 0xffff, ui_uint16); @@ -737,16 +1027,16 @@ static int ui_process_uint16_request(char buffer){ return 0; case CENTRAL_W4_READ_MULTIPLE_CHARACTERISTIC_VALUES: if (ui_uint16){ - ui_handles[ui_num_handles++] = ui_uint16; + ui_handles[ui_handles_count++] = ui_uint16; ui_request_uint16("Please enter handle: "); } else { int i; printf("Read multiple values, handles: "); - for (i=0;i> 1] |= hex; + ui_uuid128[ui_uuid128_pos >> 1] = (ui_uuid128[ui_uuid128_pos >> 1] & 0xf0) | hex; } else { ui_uuid128[ui_uuid128_pos >> 1] = hex << 4; } @@ -823,19 +1157,11 @@ static int ui_process_uuid128_request(char buffer){ return 0; } } - switch(ui_uuid128_pos){ - case 8: - case 12: - case 16: - case 20: - printf("-"); - fflush(stdout); - break; - default: - break; + if (uuid128_pos_starts_with_dash(ui_uuid128_pos)){ + printf("-"); + fflush(stdout); } return 0; - } static void ui_announce_write(const char * method){ @@ -845,6 +1171,17 @@ static void ui_announce_write(const char * method){ } static int ui_process_data_request(char buffer){ + if (buffer == 0x7f || buffer == 0x08) { + if (ui_value_pos){ + if ((ui_value_pos & 1) == 0){ + printf("\b"); + } + printf("\b \b"); + fflush(stdout); + ui_value_pos--; + } + return 0; + } if (buffer == '\n' || buffer == '\r'){ ui_value_request = 0; printf("\n"); @@ -884,20 +1221,20 @@ static int ui_process_data_request(char buffer){ } int hex = hexForChar(buffer); if (hex < 0){ - printf("stdinprocess: invalid input 0x%02x\n", buffer); return 0; } printf("%c", buffer); - fflush(stdout); if (ui_value_pos & 1){ - ui_value_data[ui_value_pos >> 1] |= hex; + ui_value_data[ui_value_pos >> 1] = (ui_value_data[ui_value_pos >> 1] & 0xf0) | hex; + printf(" "); } else { ui_value_data[ui_value_pos >> 1] = hex << 4; } ui_value_pos++; + fflush(stdout); return 0; } @@ -1041,7 +1378,7 @@ static void ui_process_command(char buffer){ break; case 'W': // fetch csrk - le_device_db_csrk_get(le_device_db_index, signing_csrk); + le_device_db_local_csrk_get(le_device_db_index, signing_csrk); // calc signature sm_cmac_start(signing_csrk, ATT_SIGNED_WRITE_COMMAND, pts_signed_write_characteristic_handle, sizeof(signed_write_value), signed_write_value, 0, att_signed_write_handle_cmac_result); break; @@ -1094,6 +1431,10 @@ static void ui_process_command(char buffer){ gatt_client_discover_characteristics_for_service(gc_id, handle, &service); break; } + case 'h': + central_state = CENTRAL_ENTER_START_HANDLE_4_DISCOVER_CHARACTERISTICS; + ui_request_uint16("Please enter start_handle: "); + break; case 'i': { central_state = CENTRAL_W4_CHARACTERISTICS; @@ -1129,7 +1470,7 @@ static void ui_process_command(char buffer){ break; case 'N': ui_request_uint16("Read Multiple Characteristic Values - enter 0 to complete list.\nPlease enter handle: "); - ui_num_handles = 0; + ui_handles_count = 0; central_state = CENTRAL_W4_READ_MULTIPLE_CHARACTERISTIC_VALUES; break; case 'O': @@ -1160,6 +1501,10 @@ static void ui_process_command(char buffer){ central_state = CENTRAL_W4_SIGNED_WRITE; ui_request_uint16("Please enter handle: "); break; + case 'T': + central_state = CENTRAL_GPA_ENTER_START_HANDLE; + ui_request_uint16("Please enter start handle: "); + break; default: show_usage(); break; @@ -1237,6 +1582,9 @@ int btstack_main(int argc, const char * argv[]){ printf("BTstack LE Peripheral starting up...\n"); + memset(rows, 0, sizeof(char *) * 100); + memset(lines, 0, sizeof(char *) * 100); + strcpy(gap_device_name, "BTstack"); // set up l2cap_le @@ -1252,6 +1600,7 @@ int btstack_main(int argc, const char * argv[]){ sm_set_encryption_key_size_range(sm_min_key_size, 16); sm_test_set_irk(test_irk); + sm_test_use_fixed_local_csrk(); // setup GATT Client gatt_client_init(); diff --git a/test/remote_device_db/Makefile b/test/remote_device_db/Makefile index 5e7f30eeb..7391132da 100644 --- a/test/remote_device_db/Makefile +++ b/test/remote_device_db/Makefile @@ -14,6 +14,7 @@ VPATH += ${BTSTACK_ROOT}/platforms/posix/src FS = \ utils.c \ + hci_dump.c \ remote_device_db_fs.c @@ -21,6 +22,7 @@ MEMORY = \ utils.c \ memory_pool.c \ btstack_memory.c \ + hci_dump.c \ remote_device_db_memory.c \ linked_list.c diff --git a/test/sdp_client/Makefile b/test/sdp_client/Makefile index c65f5db72..9f388931c 100644 --- a/test/sdp_client/Makefile +++ b/test/sdp_client/Makefile @@ -16,6 +16,7 @@ VPATH += ${BTSTACK_ROOT}/platforms/posix/src COMMON = \ sdp_util.c \ sdp_parser.c \ + hci_dump.c \ utils.c \ COMMON_OBJ = $(COMMON:.c=.o)