From 5b69ff6c7f867d1786a2f1a568e8e58d5acdbc20 Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Fri, 18 Dec 2015 14:37:08 +0100 Subject: [PATCH 1/5] hfp: mock support prepared packets --- test/hfp/mock.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/test/hfp/mock.c b/test/hfp/mock.c index a0e6942ec..feef456a1 100644 --- a/test/hfp/mock.c +++ b/test/hfp/mock.c @@ -67,6 +67,8 @@ static uint16_t rfcomm_payload_len = 0; static uint8_t outgoing_rfcomm_payload[200]; static uint16_t outgoing_rfcomm_payload_len = 0; +static uint8_t rfcomm_reserved_buffer[1000]; + void * active_connection; hfp_connection_t * hfp_context; @@ -110,7 +112,8 @@ char * get_next_hfp_command(int start_command_offset, int end_command_offset){ return NULL; } -static void print_without_newlines(uint8_t *data, uint16_t len){ +void print_without_newlines(uint8_t *data, uint16_t len); +void print_without_newlines(uint8_t *data, uint16_t len){ int found_newline = 0; int found_item = 0; @@ -132,7 +135,6 @@ extern "C" void l2cap_init(void){} extern "C" void l2cap_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)){ } - int rfcomm_send_internal(uint16_t rfcomm_cid, uint8_t *data, uint16_t len){ int start_command_offset = 2; int end_command_offset = 2; @@ -156,6 +158,21 @@ int rfcomm_send_internal(uint16_t rfcomm_cid, uint8_t *data, uint16_t len){ return 0; } +int rfcomm_reserve_packet_buffer(void){ + return 1; +}; +void rfcomm_release_packet_buffer(void){}; +uint8_t * rfcomm_get_outgoing_buffer(void) { + return rfcomm_reserved_buffer; +} +uint16_t rfcomm_get_max_frame_size(uint16_t rfcomm_cid){ + return sizeof(rfcomm_reserved_buffer); +} +int rfcomm_send_prepared(uint16_t rfcomm_cid, uint16_t len){ + printf("--- rfcomm_send_prepared with len %u ---\n", len); + return rfcomm_send_internal(rfcomm_cid, rfcomm_reserved_buffer, len); +} + static void hci_event_sco_complete(){ uint8_t event[19]; uint8_t pos = 0; From fbe69a2b49c9c961553fbc8b6b9c1aa46f678821 Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Fri, 18 Dec 2015 15:11:08 +0100 Subject: [PATCH 2/5] hfp: use generator to split ag indicators list into multiple segements --- src/hfp.c | 1 + src/hfp.h | 1 + src/hfp_ag.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 118 insertions(+), 4 deletions(-) diff --git a/src/hfp.c b/src/hfp.c index 93a4b9043..be970483e 100644 --- a/src/hfp.c +++ b/src/hfp.c @@ -993,6 +993,7 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte, int isHandsFree){ context->command = HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS; break; case HFP_W4_RETRIEVE_INDICATORS: + context->send_ag_indicators_segment = 0; context->command = HFP_CMD_RETRIEVE_AG_INDICATORS; break; default: diff --git a/src/hfp.h b/src/hfp.h index d0142a579..b933b8156 100644 --- a/src/hfp.h +++ b/src/hfp.h @@ -540,6 +540,7 @@ typedef struct hfp_connection { uint8_t send_phone_number_for_voice_tag; uint8_t send_ag_status_indicators; + uint8_t send_ag_indicators_segment; uint8_t send_response_and_hold_status; // 0 - don't send. BRTH:0 == 1, .. // AG only diff --git a/src/hfp_ag.c b/src/hfp_ag.c index 567140088..296316fed 100644 --- a/src/hfp_ag.c +++ b/src/hfp_ag.c @@ -256,6 +256,84 @@ static int hfp_ag_report_extended_audio_gateway_error(uint16_t cid, uint8_t erro return send_str_over_rfcomm(cid, buffer); } +// fast & small implementation for fixed int size +static int string_len_for_uint32(uint32_t i){ + if (i < 10) return 1; + if (i < 100) return 2; + if (i < 1000) return 3; + if (i < 10000) return 4; + if (i < 10000) return 5; + if (i < 1000000) return 6; + if (i < 10000000) return 7; + if (i < 100000000) return 8; + if (i < 1000000000) return 9; + return 10; +} + +// get size for indicator string +static int hfp_ag_indicators_string_size(hfp_connection_t * context, int i){ + // template: ("$NAME",($MIN,$MAX)) + return 8 + strlen(get_hfp_ag_indicators(context)[i].name) + + string_len_for_uint32(get_hfp_ag_indicators(context)[i].min_range) + + string_len_for_uint32(get_hfp_ag_indicators(context)[i].min_range); +} + +// store indicator +static void hfp_ag_indicators_string_store(hfp_connection * context, int i, uint8_t * buffer){ + sprintf((char *) buffer, "(\"%s\",(%d,%d)),", + get_hfp_ag_indicators(context)[i].name, + get_hfp_ag_indicators(context)[i].min_range, + get_hfp_ag_indicators(context)[i].max_range); +} + +// structure: header [indicator [comma indicator]] footer +static int hfp_ag_indicators_cmd_generator_num_segments(hfp_connection_t * context){ + int num_indicators = get_hfp_ag_indicators_nr(context); + if (!num_indicators) return 2; + return 3 + (num_indicators-1) * 2; +} + +// get size of individual segment for hfp_ag_retrieve_indicators_cmd +static int hfp_ag_indicators_cmd_generator_get_segment_len(hfp_connection_t * context, int index){ + if (index == 0) { + return strlen(HFP_INDICATOR) + 3; // "\n\r%s:"" + } + index--; + int num_indicators = get_hfp_ag_indicators_nr(context); + int indicator_index = index >> 1; + if ((index & 1) == 0){ + return hfp_ag_indicators_string_size(context, indicator_index); + } + if (indicator_index == num_indicators - 1){ + return 8; // "\r\n\r\nOK\r\n" + } + return 1; // comma +} + +static void hgp_ag_indicators_cmd_generator_store_segment(hfp_connection_t * context, int index, uint8_t * buffer){ + if (index == 0){ + *buffer++ = '\n'; + *buffer++ = '\r'; + int len = strlen(HFP_INDICATOR); + memcpy(buffer, HFP_INDICATOR, len); + buffer += len; + *buffer++ = ':'; + return; + } + index--; + int num_indicators = get_hfp_ag_indicators_nr(context); + int indicator_index = index >> 1; + if ((index & 1) == 0){ + hfp_ag_indicators_string_store(context, indicator_index, buffer); + return; + } + if (indicator_index == num_indicators-1){ + memcpy(buffer, "\r\n\r\nOK\r\n", 8); + return; + } + *buffer = ','; +} + static int hfp_ag_indicators_join(char * buffer, int buffer_size, hfp_connection_t * context){ if (buffer_size < get_hfp_ag_indicators_nr(context) * (1 + sizeof(hfp_ag_indicator_t))) return 0; int i; @@ -336,6 +414,28 @@ static int hfp_ag_retrieve_indicators_cmd(uint16_t cid, hfp_connection_t * conte return send_str_over_rfcomm(cid, buffer); } +// returns next segment to store +static int hfp_ag_retrieve_indicators_cmd_via_generator(uint16_t cid, hfp_connection_t * context, int start_segment){ + // assumes: can send now == true + // assumes: num segments > 0 + rfcomm_reserve_packet_buffer(); + int mtu = rfcomm_get_max_frame_size(cid); + uint8_t * data = rfcomm_get_outgoing_buffer(); + int offset = 0; + int segment = start_segment; + int num_segments = hfp_ag_indicators_cmd_generator_num_segments(context); + while (segment < num_segments){ + int segment_len = hfp_ag_indicators_cmd_generator_get_segment_len(context, segment); + if (offset + segment_len <= mtu){ + hgp_ag_indicators_cmd_generator_store_segment(context, segment, data+offset); + offset += segment_len; + segment++; + } + } + rfcomm_send_prepared(cid, offset); + return segment; +} + static int hfp_ag_retrieve_indicators_status_cmd(uint16_t cid){ char buffer[40]; int offset = snprintf(buffer, sizeof(buffer), "\r\n%s:", HFP_INDICATOR); @@ -586,10 +686,21 @@ static int hfp_ag_run_for_context_service_level_connection(hfp_connection_t * co return done; case HFP_CMD_RETRIEVE_AG_INDICATORS: - if (context->state != HFP_W4_RETRIEVE_INDICATORS) break; - context->state = HFP_W4_RETRIEVE_INDICATORS_STATUS; - hfp_ag_retrieve_indicators_cmd(context->rfcomm_cid, context); - return 1; + if (context->state == HFP_W4_RETRIEVE_INDICATORS) { + context->command = HFP_CMD_NONE; // prevent reentrance + int next_segment = hfp_ag_retrieve_indicators_cmd_via_generator(context->rfcomm_cid, context, context->send_ag_indicators_segment); + if (next_segment < hfp_ag_indicators_cmd_generator_num_segments(context)){ + // prepare sending of next segment + context->send_ag_indicators_segment = next_segment; + context->command = HFP_CMD_RETRIEVE_AG_INDICATORS; + } else { + // done, go to next state + context->send_ag_indicators_segment = 0; + context->state = HFP_W4_RETRIEVE_INDICATORS_STATUS; + } + return 1; + } + break; case HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS: if (context->state != HFP_W4_RETRIEVE_INDICATORS_STATUS) break; @@ -1593,6 +1704,7 @@ static void hfp_handle_rfcomm_data(uint8_t packet_type, uint16_t channel, uint8_ case HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS: // expected by SLC state machine if (context->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) break; + context->send_ag_indicators_segment = 0; context->send_ag_status_indicators = 1; break; case HFP_CMD_LIST_CURRENT_CALLS: From b040a000e8bc03b75e53ff5077b79b9152634d7e Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Fri, 18 Dec 2015 15:14:14 +0100 Subject: [PATCH 3/5] hfp: send ag indicators status on request, delete old code --- src/hfp_ag.c | 33 +-------------------------------- 1 file changed, 1 insertion(+), 32 deletions(-) diff --git a/src/hfp_ag.c b/src/hfp_ag.c index 296316fed..d204f568b 100644 --- a/src/hfp_ag.c +++ b/src/hfp_ag.c @@ -334,25 +334,6 @@ static void hgp_ag_indicators_cmd_generator_store_segment(hfp_connection_t * con *buffer = ','; } -static int hfp_ag_indicators_join(char * buffer, int buffer_size, hfp_connection_t * context){ - if (buffer_size < get_hfp_ag_indicators_nr(context) * (1 + sizeof(hfp_ag_indicator_t))) return 0; - int i; - int offset = 0; - for (i = 0; i < get_hfp_ag_indicators_nr(context)-1; i++) { - offset += snprintf(buffer+offset, buffer_size-offset, "(\"%s\",(%d,%d)),", - get_hfp_ag_indicators(context)[i].name, - get_hfp_ag_indicators(context)[i].min_range, - get_hfp_ag_indicators(context)[i].max_range); - } - if ( i < get_hfp_ag_indicators_nr(context)){ - offset += snprintf(buffer+offset, buffer_size-offset, "(\"%s\",(%d,%d))", - get_hfp_ag_indicators(context)[i].name, - get_hfp_ag_indicators(context)[i].min_range, - get_hfp_ag_indicators(context)[i].max_range); - } - return offset; -} - static int hfp_hf_indicators_join(char * buffer, int buffer_size){ if (buffer_size < hfp_ag_indicators_nr * 3) return 0; int i; @@ -402,18 +383,6 @@ static int hfp_ag_call_services_join(char * buffer, int buffer_size){ return offset; } -static int hfp_ag_retrieve_indicators_cmd(uint16_t cid, hfp_connection_t * context){ - char buffer[250]; - int offset = snprintf(buffer, sizeof(buffer), "\r\n%s:", HFP_INDICATOR); - offset += hfp_ag_indicators_join(buffer+offset, sizeof(buffer)-offset, context); - - buffer[offset] = 0; - - offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n\r\nOK\r\n"); - buffer[offset] = 0; - return send_str_over_rfcomm(cid, buffer); -} - // returns next segment to store static int hfp_ag_retrieve_indicators_cmd_via_generator(uint16_t cid, hfp_connection_t * context, int start_segment){ // assumes: can send now == true @@ -1588,7 +1557,7 @@ static void hfp_run_for_context(hfp_connection_t *context){ if (context->send_ag_status_indicators){ context->send_ag_status_indicators = 0; - hfp_ag_retrieve_indicators_cmd(context->rfcomm_cid, context); + hfp_ag_retrieve_indicators_status_cmd(context->rfcomm_cid); return; } From e81f58c7425a92469f1e4701d920db1e8ea851c8 Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Fri, 18 Dec 2015 15:29:36 +0100 Subject: [PATCH 4/5] hfp: generalized hfp ag cmd generator --- src/hfp_ag.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/hfp_ag.c b/src/hfp_ag.c index d204f568b..4b4de8e08 100644 --- a/src/hfp_ag.c +++ b/src/hfp_ag.c @@ -383,8 +383,11 @@ static int hfp_ag_call_services_join(char * buffer, int buffer_size){ return offset; } -// returns next segment to store -static int hfp_ag_retrieve_indicators_cmd_via_generator(uint16_t cid, hfp_connection_t * context, int start_segment){ +static int hfp_ag_cmd_via_generator(uint16_t cid, hfp_connection_t * context, + int start_segment, int num_segments, + int (*get_segment_len)(hfp_connection_t * context, int segment), + void (*store_segment) (hfp_connection_t * context, int segment, uint8_t * buffer)){ + // assumes: can send now == true // assumes: num segments > 0 rfcomm_reserve_packet_buffer(); @@ -392,11 +395,10 @@ static int hfp_ag_retrieve_indicators_cmd_via_generator(uint16_t cid, hfp_connec uint8_t * data = rfcomm_get_outgoing_buffer(); int offset = 0; int segment = start_segment; - int num_segments = hfp_ag_indicators_cmd_generator_num_segments(context); while (segment < num_segments){ - int segment_len = hfp_ag_indicators_cmd_generator_get_segment_len(context, segment); + int segment_len = get_segment_len(context, segment); if (offset + segment_len <= mtu){ - hgp_ag_indicators_cmd_generator_store_segment(context, segment, data+offset); + store_segment(context, segment, data+offset); offset += segment_len; segment++; } @@ -405,6 +407,13 @@ static int hfp_ag_retrieve_indicators_cmd_via_generator(uint16_t cid, hfp_connec return segment; } +// returns next segment to store +static int hfp_ag_retrieve_indicators_cmd_via_generator(uint16_t cid, hfp_connection_t * context, int start_segment){ + int num_segments = hfp_ag_indicators_cmd_generator_num_segments(context); + return hfp_ag_cmd_via_generator(cid, context, start_segment, num_segments, + hfp_ag_indicators_cmd_generator_get_segment_len, hgp_ag_indicators_cmd_generator_store_segment); +} + static int hfp_ag_retrieve_indicators_status_cmd(uint16_t cid){ char buffer[40]; int offset = snprintf(buffer, sizeof(buffer), "\r\n%s:", HFP_INDICATOR); From 47c8cf6f281f4bc441bc48e0200ea5ae499bf29f Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Fri, 18 Dec 2015 15:31:27 +0100 Subject: [PATCH 5/5] hfp: use buffer smaller than mimimum rfcomm mtu for CHLD --- src/hfp_ag.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hfp_ag.c b/src/hfp_ag.c index 4b4de8e08..7a15fb353 100644 --- a/src/hfp_ag.c +++ b/src/hfp_ag.c @@ -433,7 +433,7 @@ static int hfp_ag_set_indicator_status_update_cmd(uint16_t cid, uint8_t activate static int hfp_ag_retrieve_can_hold_call_cmd(uint16_t cid){ - char buffer[100]; + char buffer[40]; int offset = snprintf(buffer, sizeof(buffer), "\r\n%s:", HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES); offset += hfp_ag_call_services_join(buffer+offset, sizeof(buffer)-offset);