diff --git a/include/btstack/hci_cmds.h b/include/btstack/hci_cmds.h index 8c4a2c4d4..4b90910e9 100644 --- a/include/btstack/hci_cmds.h +++ b/include/btstack/hci_cmds.h @@ -622,7 +622,8 @@ extern "C" { #define HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED 0x01 #define HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED 0x02 - +#define HFP_SUBEVENT_COMPLETE 0x03 +#define HFP_SUBEVENT_AG_INDICATOR_STATUS_CHANGED 0x04 // ANCS Client #define ANCS_CLIENT_CONNECTED 0xF0 diff --git a/src/hfp.c b/src/hfp.c index 4fe0f6d65..16f3243c7 100644 --- a/src/hfp.c +++ b/src/hfp.c @@ -94,22 +94,22 @@ static const char * hfp_ag_features[] = { }; static int hfp_generic_status_indicators_nr = 0; -static hfp_generic_status_indicators_t hfp_generic_status_indicators[HFP_MAX_NUM_HF_INDICATORS]; +static hfp_generic_status_indicator_t hfp_generic_status_indicators[HFP_MAX_NUM_HF_INDICATORS]; static linked_list_t hfp_connections = NULL; -hfp_generic_status_indicators_t * get_hfp_generic_status_indicators(){ - return (hfp_generic_status_indicators_t *) &hfp_generic_status_indicators; +hfp_generic_status_indicator_t * get_hfp_generic_status_indicators(){ + return (hfp_generic_status_indicator_t *) &hfp_generic_status_indicators; } int get_hfp_generic_status_indicators_nr(){ return hfp_generic_status_indicators_nr; } -void set_hfp_generic_status_indicators(hfp_generic_status_indicators_t * indicators, int indicator_nr){ +void set_hfp_generic_status_indicators(hfp_generic_status_indicator_t * indicators, int indicator_nr){ if (indicator_nr > HFP_MAX_NUM_HF_INDICATORS) return; hfp_generic_status_indicators_nr = indicator_nr; - memcpy(hfp_generic_status_indicators, indicators, indicator_nr * sizeof(hfp_generic_status_indicators_t)); + memcpy(hfp_generic_status_indicators, indicators, indicator_nr * sizeof(hfp_generic_status_indicator_t)); } const char * hfp_hf_feature(int index){ @@ -177,11 +177,13 @@ int join(char * buffer, int buffer_size, uint8_t * values, int values_nr){ int join_bitmap(char * buffer, int buffer_size, uint32_t values, int values_nr){ if (buffer_size < values_nr * 3) return 0; + int i; int offset = 0; for (i = 0; i < values_nr-1; i++) { offset += snprintf(buffer+offset, buffer_size-offset, "%d,", get_bit(values,i)); // puts string into buffer } + if (inegotiated_codec = HFP_CODEC_CVSD; context->enable_status_update_for_ag_indicators = 0xFF; - context->change_enable_status_update_for_individual_ag_indicators = 0xFF; context->generic_status_indicators_nr = hfp_generic_status_indicators_nr; - memcpy(context->generic_status_indicators, hfp_generic_status_indicators, hfp_generic_status_indicators_nr * sizeof(hfp_generic_status_indicators_t)); + memcpy(context->generic_status_indicators, hfp_generic_status_indicators, hfp_generic_status_indicators_nr * sizeof(hfp_generic_status_indicator_t)); linked_list_add(&hfp_connections, (linked_item_t*)context); return context; @@ -458,6 +459,12 @@ void hfp_handle_hci_event(hfp_callback_t callback, uint8_t packet_type, uint8_t rfcomm_cid = READ_BT_16(packet,2); context = get_hfp_connection_context_for_rfcomm_cid(rfcomm_cid); if (!context) break; + if (context->state == HFP_W4_RFCOMM_DISCONNECTED_AND_RESTART){ + context->state = HFP_IDLE; + hfp_establish_service_level_connection(context->remote_addr, context->service_uuid); + break; + } + remove_hfp_connection_context(context); hfp_emit_event(callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED, 0); break; @@ -466,6 +473,11 @@ void hfp_handle_hci_event(hfp_callback_t callback, uint8_t packet_type, uint8_t handle = READ_BT_16(packet,3); context = get_hfp_connection_context_for_handle(handle); if (!context) break; + if (context->state == HFP_W4_RFCOMM_DISCONNECTED_AND_RESTART){ + context->state = HFP_IDLE; + hfp_establish_service_level_connection(context->remote_addr, context->service_uuid); + break; + } hfp_emit_event(callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED, packet[2]); remove_hfp_connection_context(context); break; @@ -484,11 +496,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 +512,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,7 +531,7 @@ 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; @@ -531,24 +543,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,39 +567,50 @@ 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); - context->parser_state = HFP_PARSER_CMD_INITITAL_STATE_GENERIC_STATUS_INDICATORS; - context->generic_status_indicator_state_index = (uint8_t)atoi((char*)context->line_buffer); + printf("Parsed List generic status indicator %s state: ", context->line_buffer); + context->parser_state = HFP_PARSER_CMD_INDICATOR_STATUS; + context->parser_item_index = (uint8_t)atoi((char*)context->line_buffer); break; - case HFP_CMD_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE: + case HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE: // AG parses new gen. ind. state + printf("Parsed Enable ag indicator state: %s\n", context->line_buffer); value = atoi((char *)&context->line_buffer[0]); - context->generic_status_indicators[context->parser_item_index].state = value; + if (!context->ag_indicators[context->parser_item_index].mandatory){ + context->ag_indicators[context->parser_item_index].enabled = value; + } context->parser_item_index++; break; + case HFP_CMD_TRANSFER_AG_INDICATOR_STATUS: + printf("Parsed AG indicator status: %s\n", context->line_buffer); + // indicators are indexed starting with 1 + context->parser_item_index = atoi((char *)&context->line_buffer[0]) - 1; + context->parser_state = HFP_PARSER_CMD_INDICATOR_STATUS; + break; default: break; } 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; @@ -597,26 +619,37 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){ } context->line_buffer[context->line_size++] = byte; break; - case HFP_PARSER_CMD_INITITAL_STATE_GENERIC_STATUS_INDICATORS: + case HFP_PARSER_CMD_INDICATOR_STATUS: context->line_buffer[context->line_size] = 0; if (byte == ',') break; if (byte == '\n' || byte == '\r'){ 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\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); + switch (context->command){ + case HFP_CMD_GENERIC_STATUS_INDICATOR_STATE: + context->generic_status_indicators[context->parser_item_index].state = (uint8_t)atoi((char*)context->line_buffer); + break; + case HFP_CMD_TRANSFER_AG_INDICATOR_STATUS: + context->ag_indicators[context->parser_item_index].status = (uint8_t)atoi((char*)context->line_buffer); + context->ag_indicators[context->parser_item_index].status_changed = 1; + break; + default: + break; + } break; } context->line_buffer[context->line_size++] = 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 +661,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,14 +674,16 @@ 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++; context->ag_indicators_nr = context->parser_item_index; + printf("parser ag nr %d \n", context->ag_indicators_nr); break; } @@ -670,13 +706,23 @@ void hfp_establish_service_level_connection(bd_addr_t bd_addr, uint16_t service_ log_error("hfp_establish_service_level_connection for addr %s failed", bd_addr_to_str(bd_addr)); return; } - if (context->state != HFP_IDLE) return; - - memcpy(context->remote_addr, bd_addr, 6); - context->state = HFP_W4_SDP_QUERY_COMPLETE; - - connection_doing_sdp_query = context; - sdp_query_rfcomm_channel_and_name_for_uuid(context->remote_addr, service_uuid); + switch (context->state){ + case HFP_W2_DISCONNECT_RFCOMM: + context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; + return; + case HFP_W4_RFCOMM_DISCONNECTED: + context->state = HFP_W4_RFCOMM_DISCONNECTED_AND_RESTART; + return; + case HFP_IDLE: + memcpy(context->remote_addr, bd_addr, 6); + context->state = HFP_W4_SDP_QUERY_COMPLETE; + connection_doing_sdp_query = context; + context->service_uuid = service_uuid; + sdp_query_rfcomm_channel_and_name_for_uuid(context->remote_addr, service_uuid); + break; + default: + break; + } } void hfp_release_service_level_connection(hfp_connection_t * context){ diff --git a/src/hfp.h b/src/hfp.h index 0a899ca75..e4c5e79a6 100644 --- a/src/hfp.h +++ b/src/hfp.h @@ -105,11 +105,13 @@ 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" // +BIA:,,,,, #define HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES "+CHLD" #define HFP_GENERIC_STATUS_INDICATOR "+BIND" +#define HFP_TRANSFER_AG_INDICATOR_STATUS "+CIEV" // +CIEV: , #define HFP_OK "OK" +#define HFP_ERROR "ERROR" // Codecs #define HFP_CODEC_CVSD 0x01 @@ -117,17 +119,19 @@ extern "C" { typedef enum { HFP_CMD_NONE = 0, + HFP_CMD_ERROR, HFP_CMD_OK, HFP_CMD_SUPPORTED_FEATURES, HFP_CMD_AVAILABLE_CODECS, HFP_CMD_INDICATOR, HFP_CMD_INDICATOR_STATUS, // 5 HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE, - HFP_CMD_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE, + HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE, HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES, HFP_CMD_LIST_GENERIC_STATUS_INDICATOR, HFP_CMD_GENERIC_STATUS_INDICATOR, // 10 - HFP_CMD_GENERIC_STATUS_INDICATOR_STATE + HFP_CMD_GENERIC_STATUS_INDICATOR_STATE, + HFP_CMD_TRANSFER_AG_INDICATOR_STATUS } hfp_command_t; typedef enum { @@ -136,7 +140,7 @@ typedef enum { HFP_PARSER_CMD_INDICATOR_NAME, HFP_PARSER_CMD_INDICATOR_MIN_RANGE, HFP_PARSER_CMD_INDICATOR_MAX_RANGE, - HFP_PARSER_CMD_INITITAL_STATE_GENERIC_STATUS_INDICATORS + HFP_PARSER_CMD_INDICATOR_STATUS } hfp_parser_state_t; @@ -177,6 +181,7 @@ typedef enum { HFP_W2_DISCONNECT_RFCOMM, HFP_W4_RFCOMM_DISCONNECTED, + HFP_W4_RFCOMM_DISCONNECTED_AND_RESTART, HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN } hfp_state_t; @@ -185,7 +190,7 @@ typedef void (*hfp_callback_t)(uint8_t * event, uint16_t event_size); typedef struct{ uint16_t uuid; uint8_t state; // enabled -} hfp_generic_status_indicators_t; +} hfp_generic_status_indicator_t; typedef struct{ uint8_t index; @@ -193,7 +198,9 @@ typedef struct{ uint8_t min_range; uint8_t max_range; uint8_t status; + uint8_t mandatory; uint8_t enabled; + uint8_t status_changed; } hfp_ag_indicator_t; typedef struct{ @@ -209,7 +216,9 @@ typedef struct hfp_connection { uint16_t rfcomm_cid; hfp_state_t state; - + // needed for reestablishing connection + uint16_t service_uuid; + // used during service level connection establishment hfp_command_t command; hfp_parser_state_t parser_state; @@ -225,8 +234,9 @@ 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]; + hfp_generic_status_indicator_t generic_status_indicators[HFP_MAX_INDICATOR_DESC_SIZE]; uint8_t generic_status_indicator_state_index; uint8_t enable_status_update_for_ag_indicators; @@ -234,7 +244,7 @@ typedef struct hfp_connection { // 0 = deactivate, 1 = activate, 0xff = do nothing uint8_t wait_ok; hfp_command_t sent_command; - uint8_t change_enable_status_update_for_individual_ag_indicators; + uint8_t change_status_update_for_individual_ag_indicators; uint32_t ag_indicators_status_update_bitmap; diff --git a/src/hfp_ag.c b/src/hfp_ag.c index a37012bdb..eeda3cb3a 100644 --- a/src/hfp_ag.c +++ b/src/hfp_ag.c @@ -75,20 +75,18 @@ static hfp_callback_t hfp_callback; static void packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); -hfp_generic_status_indicators_t * get_hfp_generic_status_indicators(); +hfp_generic_status_indicator_t * get_hfp_generic_status_indicators(); int get_hfp_generic_status_indicators_nr(); -void set_hfp_generic_status_indicators(hfp_generic_status_indicators_t * indicators, int indicator_nr); +void set_hfp_generic_status_indicators(hfp_generic_status_indicator_t * indicators, int indicator_nr); -static void set_ag_indicators(hfp_ag_indicator_t * indicators, int indicator_nr){ - int i; - if (indicator_nr > HFP_MAX_NUM_AG_INDICATORS) return; - for (i = 0; icommand = HFP_CMD_NONE; @@ -310,7 +314,7 @@ void update_command(hfp_connection_t * context){ } if (strncmp((char *)context->line_buffer+2, HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS, strlen(HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS)) == 0){ - context->command = HFP_CMD_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE; + context->command = HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE; return; } } @@ -320,6 +324,21 @@ void hfp_run_for_context(hfp_connection_t *context){ if (!context) return; if (!rfcomm_can_send_packet_now(context->rfcomm_cid)) return; + if (context->state == HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED){ + if (context->enable_status_update_for_ag_indicators == 1){ + int i; + for (i = 0; i < context->ag_indicators_nr; i++){ + if (context->ag_indicators[i].enabled == 0) continue; + if (context->ag_indicators[i].status_changed == 0) continue; + + hfp_ag_transfer_ag_indicators_status_cmd(context->rfcomm_cid, context->ag_indicators[i]); + context->ag_indicators[i].status_changed = 0; + return; + } + } + return; + } + switch(context->command){ case HFP_CMD_SUPPORTED_FEATURES: switch(context->state){ @@ -422,10 +441,7 @@ void hfp_run_for_context(hfp_connection_t *context){ break; } break; - case HFP_CMD_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE: - - break; - + case HFP_CMD_NONE: switch(context->state){ case HFP_W2_DISCONNECT_RFCOMM: @@ -489,7 +505,7 @@ static void packet_handler(void * connection, uint8_t packet_type, uint16_t chan void hfp_ag_init(uint16_t rfcomm_channel_nr, uint32_t supported_features, uint8_t * codecs, int codecs_nr, hfp_ag_indicator_t * ag_indicators, int ag_indicators_nr, - hfp_generic_status_indicators_t * hf_indicators, int hf_indicators_nr, + hfp_generic_status_indicator_t * hf_indicators, int hf_indicators_nr, char *call_hold_services[], int call_hold_services_nr){ if (codecs_nr > HFP_MAX_NUM_CODECS){ log_error("hfp_init: codecs_nr (%d) > HFP_MAX_NUM_CODECS (%d)", codecs_nr, HFP_MAX_NUM_CODECS); diff --git a/src/hfp_ag.h b/src/hfp_ag.h index ef625884b..7eedfd3ba 100644 --- a/src/hfp_ag.h +++ b/src/hfp_ag.h @@ -67,7 +67,7 @@ void hfp_ag_create_sdp_record(uint8_t * service, int rfcomm_channel_nr, const ch void hfp_ag_init(uint16_t rfcomm_channel_nr, uint32_t supported_features, uint8_t * codecs, int codecs_nr, hfp_ag_indicator_t * ag_indicators, int ag_indicators_nr, - hfp_generic_status_indicators_t * hf_indicators, int hf_indicators_nr, + hfp_generic_status_indicator_t * hf_indicators, int hf_indicators_nr, char *call_hold_services[], int call_hold_services_nr); /** diff --git a/src/hfp_hf.c b/src/hfp_hf.c index 061d20f43..adcec937f 100644 --- a/src/hfp_hf.c +++ b/src/hfp_hf.c @@ -149,8 +149,8 @@ int hfp_hs_activate_status_update_for_all_ag_indicators_cmd(uint16_t cid, uint8_ return send_str_over_rfcomm(cid, buffer); } -int hfp_hs_activate_status_update_for_ag_indicator_cmd(uint16_t cid, uint32_t indicators_status, int indicators_nr, uint8_t activate){ - char buffer[20]; +int hfp_hs_activate_status_update_for_ag_indicator_cmd(uint16_t cid, uint32_t indicators_status, int indicators_nr){ + char buffer[50]; int offset = snprintf(buffer, sizeof(buffer), "AT%s=", HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS); offset += join_bitmap(buffer+offset, sizeof(buffer)-offset, indicators_status, indicators_nr); offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n"); @@ -188,6 +188,17 @@ int hfp_hs_list_initital_supported_generic_status_indicators_cmd(uint16_t cid){ return send_str_over_rfcomm(cid, buffer); } +static void hfp_emit_ag_indicator_event(hfp_callback_t callback, hfp_ag_indicator_t indicator){ + if (!callback) return; + uint8_t event[5]; + event[0] = HCI_EVENT_HFP_META; + event[1] = sizeof(event) - 2; + event[2] = HFP_SUBEVENT_AG_INDICATOR_STATUS_CHANGED; + event[3] = indicator.index; + event[4] = indicator.status; + (*callback)(event, sizeof(event)); +} + static void hfp_run_for_context(hfp_connection_t * context){ if (!context) return; // printf("hfp send cmd: context %p, RFCOMM cid %u \n", context, context->rfcomm_cid ); @@ -239,23 +250,32 @@ static void hfp_run_for_context(hfp_connection_t * context){ context->state = HFP_W4_RFCOMM_DISCONNECTED; rfcomm_disconnect_internal(context->rfcomm_cid); break; - case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED: + case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED:{ if (context->wait_ok == 1) return; if (context->enable_status_update_for_ag_indicators != 0xFF){ hfp_hs_activate_status_update_for_all_ag_indicators_cmd(context->rfcomm_cid, context->enable_status_update_for_ag_indicators); context->wait_ok = 1; + context->enable_status_update_for_ag_indicators = 0xFF; break; }; - if (context->change_enable_status_update_for_individual_ag_indicators != 0xFF){ + if (context->change_status_update_for_individual_ag_indicators == 1){ hfp_hs_activate_status_update_for_ag_indicator_cmd(context->rfcomm_cid, context->ag_indicators_status_update_bitmap, - context->ag_indicators_nr, - context->change_enable_status_update_for_individual_ag_indicators); + context->ag_indicators_nr); context->wait_ok = 1; + context->change_status_update_for_individual_ag_indicators = 0; break; } + + int i; + for (i = 0; i < context->ag_indicators_nr; i++){ + if (context->ag_indicators[i].status_changed == 1) { + hfp_emit_ag_indicator_event(hfp_callback, context->ag_indicators[i]); + } + } break; + } default: break; } @@ -263,6 +283,11 @@ static void hfp_run_for_context(hfp_connection_t * context){ void update_command(hfp_connection_t * context){ context->command = HFP_CMD_NONE; + if (strncmp((char *)context->line_buffer, HFP_ERROR, strlen(HFP_ERROR)) == 0){ + context->command = HFP_CMD_ERROR; + printf("Received ERROR\n"); + } + if (strncmp((char *)context->line_buffer, HFP_OK, strlen(HFP_OK)) == 0){ context->command = HFP_CMD_OK; printf("Received OK\n"); @@ -307,9 +332,9 @@ void update_command(hfp_connection_t * context){ return; } - if (strncmp((char *)context->line_buffer, HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS, strlen(HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS)) == 0){ - printf("Received +BIA\n"); - context->command = HFP_CMD_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE; + if (strncmp((char *)context->line_buffer, HFP_TRANSFER_AG_INDICATOR_STATUS, strlen(HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS)) == 0){ + printf("Received +CIEV\n"); + context->command = HFP_CMD_TRANSFER_AG_INDICATOR_STATUS; return; } @@ -317,6 +342,7 @@ void update_command(hfp_connection_t * context){ void handle_switch_on_ok(hfp_connection_t *context){ + // printf("switch on ok\n"); switch (context->state){ case HFP_W4_EXCHANGE_SUPPORTED_FEATURES: if (has_codec_negotiation_feature(context)){ @@ -376,6 +402,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_COMPLETE, 0); + break; default: break; @@ -391,10 +419,20 @@ 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]); // trigger next action after CMD received + if (context->command == HFP_CMD_ERROR){ + if (context->state == HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED){ + context->wait_ok = 0; + // TODO: reset state? repeat commands? restore bitmaps? get ERROR codes. + hfp_emit_event(hfp_callback, HFP_SUBEVENT_COMPLETE, 1); + } else { + + } + } if (context->command != HFP_CMD_OK) continue; handle_switch_on_ok(context); } @@ -456,6 +494,7 @@ void hfp_hf_release_service_level_connection(bd_addr_t bd_addr){ } void hfp_hf_enable_status_update_for_all_ag_indicators(bd_addr_t bd_addr, uint8_t enable){ + hfp_hf_establish_service_level_connection(bd_addr); hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); if (!connection){ log_error("HFP HF: connection doesn't exist."); @@ -465,13 +504,15 @@ void hfp_hf_enable_status_update_for_all_ag_indicators(bd_addr_t bd_addr, uint8_ hfp_run_for_context(connection); } -void hfp_hf_enable_status_update_for_ag_indicator(bd_addr_t bd_addr, uint32_t indicators_status_bitmap, uint8_t enable){ +// TODO: returned ERROR - wrong format +void hfp_hf_enable_status_update_for_individual_ag_indicators(bd_addr_t bd_addr, uint32_t indicators_status_bitmap){ + hfp_hf_establish_service_level_connection(bd_addr); hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); if (!connection){ log_error("HFP HF: connection doesn't exist."); return; } - connection->change_enable_status_update_for_individual_ag_indicators = 1; + connection->change_status_update_for_individual_ag_indicators = 1; connection->ag_indicators_status_update_bitmap = indicators_status_bitmap; hfp_run_for_context(connection); } diff --git a/src/hfp_hf.h b/src/hfp_hf.h index 10c1dc039..071194b7b 100644 --- a/src/hfp_hf.h +++ b/src/hfp_hf.h @@ -98,7 +98,7 @@ void hfp_hf_enable_status_update_for_all_ag_indicators(bd_addr_t bd_addr, uint8_ /** * @brief Deactivate/reactivate status update for the individual indicators in the AG using bitmap. */ -void hfp_hf_enable_status_update_for_ag_indicator(bd_addr_t bd_addr, uint32_t indicators_status_bitmap, uint8_t enable); +void hfp_hf_enable_status_update_for_individual_ag_indicators(bd_addr_t bd_addr, uint32_t indicators_status_bitmap); /** diff --git a/test/hfp/hfp_ag_parser_test.c b/test/hfp/hfp_ag_parser_test.c index 93f9c91c1..afcb39877 100644 --- a/test/hfp/hfp_ag_parser_test.c +++ b/test/hfp/hfp_ag_parser_test.c @@ -47,17 +47,33 @@ #include "hfp.h" void hfp_parse(hfp_connection_t * context, uint8_t byte); -hfp_generic_status_indicators_t * get_hfp_generic_status_indicators(); -void set_hfp_generic_status_indicators(hfp_generic_status_indicators_t * indicators, int indicator_nr); +hfp_generic_status_indicator_t * get_hfp_generic_status_indicators(); +void set_hfp_generic_status_indicators(hfp_generic_status_indicator_t * indicators, int indicator_nr); +hfp_ag_indicator_t * get_hfp_ag_indicators(); +int get_hfp_ag_indicators_nr(); +void set_hfp_ag_indicators(hfp_ag_indicator_t * indicators, int indicator_nr); static int hf_indicators_nr = 3; -static hfp_generic_status_indicators_t hf_indicators[] = { +static hfp_generic_status_indicator_t hf_indicators[] = { {1, 1}, {2, 1}, {3, 1} }; +static int hfp_ag_indicators_nr = 7; +static hfp_ag_indicator_t hfp_ag_indicators[] = { + // index, name, min range, max range, status, mandatory, enabled, status changed + {1, "service", 0, 1, 1, 0, 0, 0}, + {2, "call", 0, 1, 0, 1, 1, 0}, + {3, "callsetup", 0, 3, 0, 1, 1, 0}, + {4, "battchg", 0, 5, 3, 0, 0, 0}, + {5, "signal", 0, 5, 5, 0, 0, 0}, + {6, "roam", 0, 1, 0, 0, 0, 0}, + {7, "callheld", 0, 2, 0, 1, 1, 0} +}; + + static hfp_connection_t context; TEST_GROUP(HFPParser){ @@ -123,29 +139,46 @@ TEST(HFPParser, HFP_AG_ENABLE_INDICATOR_STATUS_UPDATE){ TEST(HFPParser, HFP_AG_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE){ - set_hfp_generic_status_indicators((hfp_generic_status_indicators_t *)&hf_indicators, hf_indicators_nr); - context.generic_status_indicators_nr = hf_indicators_nr; - memcpy(context.generic_status_indicators, hf_indicators, hf_indicators_nr * sizeof(hfp_generic_status_indicators_t)); + set_hfp_ag_indicators((hfp_ag_indicator_t *)&hfp_ag_indicators, hfp_ag_indicators_nr); + context.ag_indicators_nr = hfp_ag_indicators_nr; + memcpy(context.ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t)); - for (pos = 0; pos < hf_indicators_nr; pos++){ - CHECK_EQUAL(get_hfp_generic_status_indicators()[pos].uuid, hf_indicators[pos].uuid); - CHECK_EQUAL(get_hfp_generic_status_indicators()[pos].state, hf_indicators[pos].state); - CHECK_EQUAL(context.generic_status_indicators[pos].uuid, hf_indicators[pos].uuid); - CHECK_EQUAL(context.generic_status_indicators[pos].state, hf_indicators[pos].state); + for (pos = 0; pos < hfp_ag_indicators_nr; pos++){ + CHECK_EQUAL(get_hfp_ag_indicators()[pos].index, hfp_ag_indicators[pos].index); + CHECK_EQUAL(get_hfp_ag_indicators()[pos].enabled, hfp_ag_indicators[pos].enabled); + CHECK_EQUAL(context.ag_indicators[pos].index, hfp_ag_indicators[pos].index); + CHECK_EQUAL(context.ag_indicators[pos].enabled, hfp_ag_indicators[pos].enabled); } - sprintf(packet, "\r\nAT%s=0,0,0\r\n", + sprintf(packet, "\r\nAT%s=0,0,0,0,0,0,0\r\n", HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS); for (pos = 0; pos < strlen(packet); pos++){ hfp_parse(&context, packet[pos]); } - CHECK_EQUAL(HFP_CMD_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE, context.command); + CHECK_EQUAL(HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE, context.command); - for (pos = 0; pos < hf_indicators_nr; pos++){ - CHECK_EQUAL(get_hfp_generic_status_indicators()[pos].state, 1); - CHECK_EQUAL(context.generic_status_indicators[pos].state, 0); + for (pos = 0; pos < hfp_ag_indicators_nr; pos++){ + if (get_hfp_ag_indicators()[pos].mandatory){ + CHECK_EQUAL(get_hfp_ag_indicators()[pos].enabled, 1); + CHECK_EQUAL(context.ag_indicators[pos].enabled, 1); + } else { + CHECK_EQUAL(get_hfp_ag_indicators()[pos].enabled, 0); + CHECK_EQUAL(context.ag_indicators[pos].enabled, 0); + } } + // sprintf(packet, "\r\nAT%s=1,,,1,1,1,\r\n", + // HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS); + // for (pos = 0; pos < strlen(packet); pos++){ + // hfp_parse(&context, packet[pos]); + // } + + // CHECK_EQUAL(HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE, context.command); + + // for (pos = 0; pos < hfp_ag_indicators_nr; pos++){ + // CHECK_EQUAL(get_hfp_ag_indicators()[pos].enabled, 1); + // CHECK_EQUAL(context.ag_indicators[pos].enabled, 1); + // } } int main (int argc, const char * argv[]){ diff --git a/test/hfp/hfp_hf_parser_test.c b/test/hfp/hfp_hf_parser_test.c index e42691b3c..c6e19cc0a 100644 --- a/test/hfp/hfp_hf_parser_test.c +++ b/test/hfp/hfp_hf_parser_test.c @@ -49,15 +49,16 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte); static hfp_connection_t context; -static int ag_indicators_nr = 7; -static hfp_ag_indicator_t ag_indicators[] = { - {1, "service", 0, 1, 1}, - {2, "call", 0, 1, 0}, - {3, "callsetup", 0, 3, 0}, - {4, "battchg", 0, 5, 3}, - {5, "signal", 0, 5, 5}, - {6, "roam", 0, 1, 0}, - {7, "callheld", 0, 2, 0}, +static int hfp_ag_indicators_nr = 7; +static hfp_ag_indicator_t hfp_ag_indicators[] = { + // index, name, min range, max range, status, mandatory, enabled, status changed + {1, "service", 0, 1, 1, 0, 0, 0}, + {2, "call", 0, 1, 0, 1, 1, 0}, + {3, "callsetup", 0, 3, 0, 1, 1, 0}, + {4, "battchg", 0, 5, 3, 0, 0, 0}, + {5, "signal", 0, 5, 5, 0, 0, 0}, + {6, "roam", 0, 1, 0, 0, 0, 0}, + {7, "callheld", 0, 2, 0, 1, 1, 0} }; TEST_GROUP(HFPParser){ @@ -95,10 +96,10 @@ TEST(HFPParser, HFP_HF_SUPPORTED_FEATURES){ TEST(HFPParser, HFP_HF_INDICATORS){ offset = 0; offset += snprintf(packet, sizeof(packet), "%s:", HFP_INDICATOR); - for (pos = 0; pos < ag_indicators_nr - 1; pos++){ - offset += snprintf(packet+offset, sizeof(packet)-offset, "\"%s\", (%d, %d),", ag_indicators[pos].name, ag_indicators[pos].min_range, ag_indicators[pos].max_range); + for (pos = 0; pos < hfp_ag_indicators_nr - 1; pos++){ + offset += snprintf(packet+offset, sizeof(packet)-offset, "\"%s\", (%d, %d),", hfp_ag_indicators[pos].name, hfp_ag_indicators[pos].min_range, hfp_ag_indicators[pos].max_range); } - offset += snprintf(packet+offset, sizeof(packet)-offset, "\"%s\", (%d, %d)\r\n", ag_indicators[pos].name, ag_indicators[pos].min_range, ag_indicators[pos].max_range); + offset += snprintf(packet+offset, sizeof(packet)-offset, "\"%s\", (%d, %d)\r\n", hfp_ag_indicators[pos].name, hfp_ag_indicators[pos].min_range, hfp_ag_indicators[pos].max_range); context.sent_command = HFP_CMD_INDICATOR; @@ -106,12 +107,12 @@ TEST(HFPParser, HFP_HF_INDICATORS){ hfp_parse(&context, packet[pos]); } CHECK_EQUAL(HFP_CMD_INDICATOR, context.command); - CHECK_EQUAL(ag_indicators_nr, context.ag_indicators_nr); - for (pos = 0; pos < ag_indicators_nr; pos++){ - CHECK_EQUAL(ag_indicators[pos].index, context.ag_indicators[pos].index); - CHECK_EQUAL(0, strcmp(ag_indicators[pos].name, context.ag_indicators[pos].name)); - CHECK_EQUAL(ag_indicators[pos].min_range, context.ag_indicators[pos].min_range); - CHECK_EQUAL(ag_indicators[pos].max_range, context.ag_indicators[pos].max_range); + CHECK_EQUAL(hfp_ag_indicators_nr, context.ag_indicators_nr); + for (pos = 0; pos < hfp_ag_indicators_nr; pos++){ + CHECK_EQUAL(hfp_ag_indicators[pos].index, context.ag_indicators[pos].index); + CHECK_EQUAL(0, strcmp(hfp_ag_indicators[pos].name, context.ag_indicators[pos].name)); + CHECK_EQUAL(hfp_ag_indicators[pos].min_range, context.ag_indicators[pos].min_range); + CHECK_EQUAL(hfp_ag_indicators[pos].max_range, context.ag_indicators[pos].max_range); } } @@ -119,10 +120,10 @@ TEST(HFPParser, HFP_HF_INDICATOR_STATUS){ // send status offset = 0; offset += snprintf(packet, sizeof(packet), "%s:", HFP_INDICATOR); - for (pos = 0; pos < ag_indicators_nr - 1; pos++){ - offset += snprintf(packet+offset, sizeof(packet)-offset, "%d,", ag_indicators[pos].status); + for (pos = 0; pos < hfp_ag_indicators_nr - 1; pos++){ + offset += snprintf(packet+offset, sizeof(packet)-offset, "%d,", hfp_ag_indicators[pos].status); } - offset += snprintf(packet+offset, sizeof(packet)-offset, "%d\r\n", ag_indicators[pos].status); + offset += snprintf(packet+offset, sizeof(packet)-offset, "%d\r\n", hfp_ag_indicators[pos].status); context.sent_command = HFP_CMD_INDICATOR_STATUS; @@ -131,8 +132,8 @@ TEST(HFPParser, HFP_HF_INDICATOR_STATUS){ } CHECK_EQUAL(HFP_CMD_INDICATOR_STATUS, context.command); - for (pos = 0; pos < ag_indicators_nr; pos++){ - CHECK_EQUAL(ag_indicators[pos].status, context.ag_indicators[pos].status); + for (pos = 0; pos < hfp_ag_indicators_nr; pos++){ + CHECK_EQUAL(hfp_ag_indicators[pos].status, context.ag_indicators[pos].status); } } @@ -179,6 +180,22 @@ TEST(HFPParser, HFP_HF_GENERIC_STATUS_INDICATOR_STATE){ CHECK_EQUAL(1, context.generic_status_indicators[0].state); } +TEST(HFPParser, HFP_HF_AG_INDICATOR_STATUS_UPDATE){ + context.ag_indicators_nr = hfp_ag_indicators_nr; + memcpy(context.ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t)); + + uint8_t index = 4; + uint8_t status = 5; + + sprintf(packet, "\r\n%s=%d,%d\r\n", HFP_TRANSFER_AG_INDICATOR_STATUS, index, status); + for (pos = 0; pos < strlen(packet); pos++){ + hfp_parse(&context, packet[pos]); + } + + CHECK_EQUAL(HFP_CMD_TRANSFER_AG_INDICATOR_STATUS, context.command); + CHECK_EQUAL(context.ag_indicators[index - 1].status, status); +} + int main (int argc, const char * argv[]){ return CommandLineTestRunner::RunAllTests(argc, argv); } diff --git a/test/pts/hfp_ag_test.c b/test/pts/hfp_ag_test.c index 703018ee0..d1139d47d 100644 --- a/test/pts/hfp_ag_test.c +++ b/test/pts/hfp_ag_test.c @@ -78,20 +78,21 @@ static uint8_t codecs[1] = {HFP_CODEC_CVSD}; static int ag_indicators_nr = 7; static hfp_ag_indicator_t ag_indicators[] = { - {1, "service", 0, 1, 1}, - {2, "call", 0, 1, 0}, - {3, "callsetup", 0, 3, 0}, - {4, "battchg", 0, 5, 3}, - {5, "signal", 0, 5, 5}, - {6, "roam", 0, 1, 0}, - {7, "callheld", 0, 2, 0}, + // index, name, min range, max range, status, mandatory, enabled, status changed + {1, "service", 0, 1, 1, 0, 0, 0}, + {2, "call", 0, 1, 0, 1, 1, 0}, + {3, "callsetup", 0, 3, 0, 1, 1, 0}, + {4, "battchg", 0, 5, 3, 0, 0, 0}, + {5, "signal", 0, 5, 5, 0, 0, 0}, + {6, "roam", 0, 1, 0, 0, 0, 0}, + {7, "callheld", 0, 2, 0, 1, 1, 0} }; static int call_hold_services_nr = 5; static char* call_hold_services[] = {"1", "1x", "2", "2x", "3"}; static int hf_indicators_nr = 2; -static hfp_generic_status_indicators_t hf_indicators[] = { +static hfp_generic_status_indicator_t hf_indicators[] = { {1, 1}, {2, 1}, }; diff --git a/test/pts/hfp_hf_test.c b/test/pts/hfp_hf_test.c index d50c267cf..9318ae6cc 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,20 +100,29 @@ 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); + break; + case 'i': + printf("Enabling HFP AG registration status update for individual indicators.\n"); + hfp_hf_enable_status_update_for_individual_ag_indicators(device_addr, 63); break; default: show_usage(); @@ -121,22 +135,29 @@ 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_COMPLETE: + switch (cmd){ + case 'r': + printf("HFP AG registration status update enabled.\n"); + break; + default: + break; } break; + case HFP_SUBEVENT_AG_INDICATOR_STATUS_CHANGED: + printf("AG_INDICATOR_STATUS_CHANGED, AG indicator index: %d, status %d\n", event[3], event[4]); + break; default: printf("event not handled %u\n", event[2]); break; @@ -164,7 +185,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; }