From 2bd0c9beb6400a6ef4e86c678175345d28d4be10 Mon Sep 17 00:00:00 2001 From: Milanka Ringwald Date: Wed, 12 Aug 2015 15:53:55 +0200 Subject: [PATCH] hfp: fix indicators parsing, add test for set ag status update enable --- include/btstack/hci_cmds.h | 2 +- src/hfp.c | 55 +++++++++++++++++++++++--------------- src/hfp.h | 3 ++- src/hfp_ag.c | 4 +-- src/hfp_hf.c | 4 +++ test/pts/hfp_hf_test.c | 55 +++++++++++++++++++++++--------------- 6 files changed, 77 insertions(+), 46 deletions(-) diff --git a/include/btstack/hci_cmds.h b/include/btstack/hci_cmds.h index 5bbdcd9fd..61891fee7 100644 --- a/include/btstack/hci_cmds.h +++ b/include/btstack/hci_cmds.h @@ -615,7 +615,7 @@ extern "C" { #define HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED 0x01 #define HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED 0x02 - +#define HFP_SUBEVENT_OK 0x03 // ANCS Client #define ANCS_CLIENT_CONNECTED 0xF0 diff --git a/src/hfp.c b/src/hfp.c index 4fe0f6d65..efd2a69a7 100644 --- a/src/hfp.c +++ b/src/hfp.c @@ -484,11 +484,10 @@ uint32_t fromBinary(char *s) { void hfp_parse(hfp_connection_t * context, uint8_t byte){ int i; int value; - + context->line_buffer[context->line_size] = 0; + if (byte == ' ') return; - if (context->line_size == 0 && (byte == '\n' || byte == '\r')) return; - if ((byte == '\n' || byte == '\r') && (context->parser_state > HFP_PARSER_CMD_SEQUENCE && context->parser_state != HFP_PARSER_CMD_INITITAL_STATE_GENERIC_STATUS_INDICATORS) )return; - + switch (context->parser_state){ case HFP_PARSER_CMD_HEADER: // header if (byte == ':' || byte == '='){ @@ -501,6 +500,7 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){ if (byte == '\n' || byte == '\r'){ context->line_buffer[context->line_size] = 0; if (context->line_size == 2){ + printf("Parsed OK\n"); update_command(context); } context->line_size = 0; @@ -519,11 +519,19 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){ if (byte == '(' ){ // tuple separated mit comma break; } - + if (byte == ',' || byte == '\n' || byte == '\r' || byte == ')'){ context->line_buffer[context->line_size] = 0; switch (context->command){ + case HFP_CMD_INDICATOR: + if (byte == ')'){ + context->parser_state = HFP_PARSER_CMD_SEQUENCE; + context->parser_item_index = 0; + context->line_size = 0; + break; + } + break; case HFP_CMD_SUPPORTED_FEATURES: context->remote_supported_features = 0; for (i=0; i<16; i++){ @@ -531,24 +539,23 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){ context->remote_supported_features = store_bit(context->remote_supported_features,15-i,1); } } - printf("Received supported feature %d\n", context->remote_supported_features); + printf("Parsed supported feature %d\n", context->remote_supported_features); context->parser_state = HFP_PARSER_CMD_HEADER; break; case HFP_CMD_AVAILABLE_CODECS: - // printf("Received codec %s\n", context->line_buffer); - // context->remote_codecs[context->remote_codecs_nr] = (uint16_t)atoi((char*)context->line_buffer); + printf("Parsed codec %s\n", context->line_buffer); context->remote_codecs[context->parser_item_index] = (uint16_t)atoi((char*)context->line_buffer); context->parser_item_index++; context->remote_codecs_nr = context->parser_item_index; break; case HFP_CMD_INDICATOR_STATUS: - // printf("Indicator %d with status: %s\n", context->parser_item_index+1, context->line_buffer); + printf("Parsed Indicator %d with status: %s\n", context->parser_item_index+1, context->line_buffer); context->ag_indicators[context->parser_item_index].status = atoi((char *) context->line_buffer); context->parser_item_index++; break; case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE: if (context->parser_item_index == 3){ - printf("Enable indicators: %s\n", context->line_buffer); + printf("Parsed Enable indicators: %s\n", context->line_buffer); value = atoi((char *)&context->line_buffer[0]); context->enable_status_update_for_ag_indicators = (uint8_t) value; } else { @@ -556,24 +563,31 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){ } break; case HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES: - // printf("Support call hold: %s\n", context->line_buffer); + printf("Parsed Support call hold: %s\n", context->line_buffer); if (context->line_size > 2 ) break; strcpy((char *)context->remote_call_services[context->remote_call_services_nr].name, (char *)context->line_buffer); context->remote_call_services_nr++; + + if (byte == ')'){ + context->parser_state = HFP_PARSER_CMD_HEADER; + context->parser_item_index = 0; + } break; case HFP_CMD_GENERIC_STATUS_INDICATOR: + printf("Parsed Generic status indicator: %s\n", context->line_buffer); context->generic_status_indicators[context->parser_item_index].uuid = (uint16_t)atoi((char*)context->line_buffer); context->parser_item_index++; context->generic_status_indicators_nr = context->parser_item_index; break; case HFP_CMD_GENERIC_STATUS_INDICATOR_STATE: // HF parses inital AG gen. ind. state - printf("HFP_CMD_GENERIC_STATUS_INDICATOR_STATE %s, %d\n", context->line_buffer, context->command); + printf("Parsed List generic status indicator %s state: ", context->line_buffer); context->parser_state = HFP_PARSER_CMD_INITITAL_STATE_GENERIC_STATUS_INDICATORS; context->generic_status_indicator_state_index = (uint8_t)atoi((char*)context->line_buffer); break; case HFP_CMD_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE: // AG parses new gen. ind. state + printf("Parsed Enable generic status indicator state: %s\n", context->line_buffer); value = atoi((char *)&context->line_buffer[0]); context->generic_status_indicators[context->parser_item_index].state = value; context->parser_item_index++; @@ -584,11 +598,7 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){ context->line_size = 0; if (byte == '\n' || byte == '\r'){ - context->parser_state = HFP_PARSER_CMD_HEADER; - context->parser_item_index = 0; - break; - } - if (byte == ')' && context->command == HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES){ // tuple separated mit comma + printf("parse done 1, state %d\n", context->parser_state); context->parser_state = HFP_PARSER_CMD_HEADER; context->parser_item_index = 0; break; @@ -604,7 +614,7 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){ context->line_buffer[context->line_size] = 0; context->line_size = 0; context->parser_state = HFP_PARSER_CMD_HEADER; - printf("to %s [0-dissabled, 1-enabled]\n", context->line_buffer); + printf("%s [0-dissabled, 1-enabled]\n", context->line_buffer); // HF stores inital AG gen. ind. state context->generic_status_indicators[context->generic_status_indicator_state_index].state = (uint8_t)atoi((char*)context->line_buffer); break; @@ -613,10 +623,11 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){ break; case HFP_PARSER_CMD_INDICATOR_NAME: // parse indicator name + //if (byte == '\n' || byte == '\r') return; if (byte == '"'){ context->line_buffer[context->line_size] = 0; context->line_size = 0; - //printf("Indicator %d: %s (", context->ag_indicators_nr+1, context->line_buffer); + printf("Indicator %d: %s (", context->ag_indicators_nr+1, context->line_buffer); strcpy((char *)context->ag_indicators[context->parser_item_index].name, (char *)context->line_buffer); context->ag_indicators[context->parser_item_index].index = context->parser_item_index+1; break; @@ -628,10 +639,11 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){ context->line_buffer[context->line_size++] = byte; break; case HFP_PARSER_CMD_INDICATOR_MIN_RANGE: + //if (byte == '\n' || byte == '\r') return; if (byte == ',' || byte == '-'){ // end min_range context->parser_state = HFP_PARSER_CMD_INDICATOR_MAX_RANGE; context->line_buffer[context->line_size] = 0; - //printf("%d, ", atoi((char *)&context->line_buffer[0])); + printf("%d, ", atoi((char *)&context->line_buffer[0])); context->ag_indicators[context->parser_item_index].min_range = atoi((char *)context->line_buffer); context->line_size = 0; break; @@ -640,10 +652,11 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){ context->line_buffer[context->line_size++] = byte; break; case HFP_PARSER_CMD_INDICATOR_MAX_RANGE: + //if (byte == '\n' || byte == '\r') return; if (byte == ')'){ // end max_range context->parser_state = HFP_PARSER_CMD_SEQUENCE; context->line_buffer[context->line_size] = 0; - //printf("%d)\n", atoi((char *)&context->line_buffer[0])); + printf("%d)\n", atoi((char *)&context->line_buffer[0])); context->ag_indicators[context->parser_item_index].max_range = atoi((char *)context->line_buffer); context->line_size = 0; context->parser_item_index++; diff --git a/src/hfp.h b/src/hfp.h index 0a899ca75..0cd8e9043 100644 --- a/src/hfp.h +++ b/src/hfp.h @@ -105,7 +105,7 @@ extern "C" { #define HFP_AVAILABLE_CODECS "+BAC" #define HFP_INDICATOR "+CIND" #define HFP_ENABLE_STATUS_UPDATE_FOR_AG_INDICATORS "+CMER" -#define HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS "+BIA" +#define HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS "+BIA" // list of [0,1] for every AG indicator #define HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES "+CHLD" #define HFP_GENERIC_STATUS_INDICATOR "+BIND" @@ -225,6 +225,7 @@ typedef struct hfp_connection { int remote_call_services_nr; hfp_call_service_t remote_call_services[HFP_MAX_INDICATOR_DESC_SIZE]; + // TODO: use bitmap. int generic_status_indicators_nr; hfp_generic_status_indicators_t generic_status_indicators[HFP_MAX_INDICATOR_DESC_SIZE]; uint8_t generic_status_indicator_state_index; diff --git a/src/hfp_ag.c b/src/hfp_ag.c index a37012bdb..cd3f44fe4 100644 --- a/src/hfp_ag.c +++ b/src/hfp_ag.c @@ -157,10 +157,10 @@ int hfp_ag_indicators_join(char * buffer, int buffer_size){ int i; int offset = 0; for (i = 0; i < hfp_ag_indicators_nr-1; i++) { - offset += snprintf(buffer+offset, buffer_size-offset, "\"%s\",(%d,%d),", hfp_ag_indicators[i].name, hfp_ag_indicators[i].min_range, hfp_ag_indicators[i].max_range);; + offset += snprintf(buffer+offset, buffer_size-offset, "(\"%s\",(%d,%d)),", hfp_ag_indicators[i].name, hfp_ag_indicators[i].min_range, hfp_ag_indicators[i].max_range);; } if (istate){ case HFP_W4_EXCHANGE_SUPPORTED_FEATURES: if (has_codec_negotiation_feature(context)){ @@ -376,6 +377,8 @@ void handle_switch_on_ok(hfp_connection_t *context){ case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED: context->wait_ok = 0; + hfp_emit_event(hfp_callback, HFP_SUBEVENT_OK, 0); + break; default: break; @@ -391,6 +394,7 @@ static void hfp_handle_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8 packet[size] = 0; int pos; + // printf("parse command: %s, state: %d\n", packet, context->parser_state); for (pos = 0; pos < size ; pos++){ hfp_parse(context, packet[pos]); diff --git a/test/pts/hfp_hf_test.c b/test/pts/hfp_hf_test.c index d50c267cf..bd7b2d0c3 100644 --- a/test/pts/hfp_hf_test.c +++ b/test/pts/hfp_hf_test.c @@ -74,10 +74,14 @@ const char hfp_hf_service_name[] = "BTstack HFP HF Test"; static bd_addr_t pts_addr = {0x00,0x1b,0xDC,0x07,0x32,0xEF}; static bd_addr_t local_mac = {0x04, 0x0C, 0xCE, 0xE4, 0x85, 0xD3}; -static bd_addr_t phone = {0xD8,0xBb,0x2C,0xDf,0xF1,0x08}; +static bd_addr_t phone_addr = {0xD8,0xBb,0x2C,0xDf,0xF1,0x08}; + +static bd_addr_t device_addr; static uint8_t codecs[1] = {HFP_CODEC_CVSD}; static uint16_t indicators[1] = {0x01}; +char cmd; + // prototypes static void show_usage(); @@ -88,6 +92,7 @@ static void show_usage(void){ printf("---\n"); printf("p - establish HFP connection to PTS module\n"); printf("e - establish HFP connection to local mac\n"); + printf("r - enable registration status update\n"); printf("d - release HFP connection\n"); printf("---\n"); printf("Ctrl-c - exit\n"); @@ -95,21 +100,25 @@ static void show_usage(void){ } static int stdin_process(struct data_source *ds){ - char buffer; - read(ds->fd, &buffer, 1); - switch (buffer){ + read(ds->fd, &cmd, 1); + switch (cmd){ case 'p': - printf("Establishing HFP service level connection to PTS module %s...\n", bd_addr_to_str(pts_addr)); - hfp_hf_establish_service_level_connection(pts_addr); + memcpy(device_addr, pts_addr, 6); + printf("Establishing HFP service level connection to PTS module %s...\n", bd_addr_to_str(device_addr)); + hfp_hf_establish_service_level_connection(device_addr); break; case 'e': - printf("Establishing HFP service level connection to %s...\n", bd_addr_to_str(phone)); - hfp_hf_establish_service_level_connection(phone); + memcpy(device_addr, phone_addr, 6); + printf("Establishing HFP service level connection to %s...\n", bd_addr_to_str(device_addr)); + hfp_hf_establish_service_level_connection(device_addr); break; case 'd': printf("Releasing HFP service level connection.\n"); - hfp_hf_release_service_level_connection(phone); + hfp_hf_release_service_level_connection(device_addr); break; + case 'r': + printf("Enabling HFP AG registration status update.\n"); + hfp_hf_enable_status_update_for_all_ag_indicators(device_addr, 1); default: show_usage(); break; @@ -121,20 +130,24 @@ static int stdin_process(struct data_source *ds){ void packet_handler(uint8_t * event, uint16_t event_size){ if (event[0] != HCI_EVENT_HFP_META) return; - + if (event[3]){ + printf("Command \'%c\' failed with status %u\n", cmd, event[3]); + return; + } switch (event[2]) { case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED: - if (event[3] == 0){ - printf("Service level connection established.\n\n"); - } else { - printf("Service level connection establishment failed with status %u\n", event[3]); - } + printf("Service level connection established.\n\n"); break; case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED: - if (event[3] == 0){ - printf("Service level connection released.\n\n"); - } else { - printf("Service level connection releasing failed with status %u\n", event[3]); + printf("Service level connection released.\n\n"); + break; + case HFP_SUBEVENT_OK: + switch (cmd){ + case 'r': + printf("HFP AG registration status update enabled.\n"); + break; + default: + break; } break; default: @@ -164,7 +177,7 @@ int btstack_main(int argc, const char * argv[]){ hci_power_control(HCI_POWER_ON); btstack_stdin_setup(stdin_process); - // printf("Establishing HFP connection to %s...\n", bd_addr_to_str(phone)); - // hfp_hf_connect(phone); + // printf("Establishing HFP connection to %s...\n", bd_addr_to_str(phone_addr)); + // hfp_hf_connect(phone_addr); return 0; }