mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-29 04:20:20 +00:00
hfp: use generator to split ag indicators list into multiple segements
This commit is contained in:
parent
5b69ff6c7f
commit
fbe69a2b49
@ -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:
|
||||
|
@ -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
|
||||
|
120
src/hfp_ag.c
120
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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user