mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-04-01 04:20:33 +00:00
Merge branch 'master' of https://github.com/bluekitchen/btstack
This commit is contained in:
commit
1e55828247
@ -622,7 +622,8 @@ extern "C" {
|
|||||||
|
|
||||||
#define HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED 0x01
|
#define HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED 0x01
|
||||||
#define HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED 0x02
|
#define HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED 0x02
|
||||||
|
#define HFP_SUBEVENT_COMPLETE 0x03
|
||||||
|
#define HFP_SUBEVENT_AG_INDICATOR_STATUS_CHANGED 0x04
|
||||||
|
|
||||||
// ANCS Client
|
// ANCS Client
|
||||||
#define ANCS_CLIENT_CONNECTED 0xF0
|
#define ANCS_CLIENT_CONNECTED 0xF0
|
||||||
|
128
src/hfp.c
128
src/hfp.c
@ -94,22 +94,22 @@ static const char * hfp_ag_features[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static int hfp_generic_status_indicators_nr = 0;
|
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;
|
static linked_list_t hfp_connections = NULL;
|
||||||
|
|
||||||
hfp_generic_status_indicators_t * get_hfp_generic_status_indicators(){
|
hfp_generic_status_indicator_t * get_hfp_generic_status_indicators(){
|
||||||
return (hfp_generic_status_indicators_t *) &hfp_generic_status_indicators;
|
return (hfp_generic_status_indicator_t *) &hfp_generic_status_indicators;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_hfp_generic_status_indicators_nr(){
|
int get_hfp_generic_status_indicators_nr(){
|
||||||
return 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;
|
if (indicator_nr > HFP_MAX_NUM_HF_INDICATORS) return;
|
||||||
hfp_generic_status_indicators_nr = indicator_nr;
|
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){
|
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){
|
int join_bitmap(char * buffer, int buffer_size, uint32_t values, int values_nr){
|
||||||
if (buffer_size < values_nr * 3) return 0;
|
if (buffer_size < values_nr * 3) return 0;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
for (i = 0; i < values_nr-1; i++) {
|
for (i = 0; i < values_nr-1; i++) {
|
||||||
offset += snprintf(buffer+offset, buffer_size-offset, "%d,", get_bit(values,i)); // puts string into buffer
|
offset += snprintf(buffer+offset, buffer_size-offset, "%d,", get_bit(values,i)); // puts string into buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i<values_nr){
|
if (i<values_nr){
|
||||||
offset += snprintf(buffer+offset, buffer_size-offset, "%d", get_bit(values,i));
|
offset += snprintf(buffer+offset, buffer_size-offset, "%d", get_bit(values,i));
|
||||||
}
|
}
|
||||||
@ -251,10 +253,9 @@ static hfp_connection_t * create_hfp_connection_context(){
|
|||||||
context->negotiated_codec = HFP_CODEC_CVSD;
|
context->negotiated_codec = HFP_CODEC_CVSD;
|
||||||
|
|
||||||
context->enable_status_update_for_ag_indicators = 0xFF;
|
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;
|
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);
|
linked_list_add(&hfp_connections, (linked_item_t*)context);
|
||||||
return 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);
|
rfcomm_cid = READ_BT_16(packet,2);
|
||||||
context = get_hfp_connection_context_for_rfcomm_cid(rfcomm_cid);
|
context = get_hfp_connection_context_for_rfcomm_cid(rfcomm_cid);
|
||||||
if (!context) break;
|
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);
|
remove_hfp_connection_context(context);
|
||||||
hfp_emit_event(callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED, 0);
|
hfp_emit_event(callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED, 0);
|
||||||
break;
|
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);
|
handle = READ_BT_16(packet,3);
|
||||||
context = get_hfp_connection_context_for_handle(handle);
|
context = get_hfp_connection_context_for_handle(handle);
|
||||||
if (!context) break;
|
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]);
|
hfp_emit_event(callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED, packet[2]);
|
||||||
remove_hfp_connection_context(context);
|
remove_hfp_connection_context(context);
|
||||||
break;
|
break;
|
||||||
@ -484,11 +496,10 @@ uint32_t fromBinary(char *s) {
|
|||||||
void hfp_parse(hfp_connection_t * context, uint8_t byte){
|
void hfp_parse(hfp_connection_t * context, uint8_t byte){
|
||||||
int i;
|
int i;
|
||||||
int value;
|
int value;
|
||||||
|
context->line_buffer[context->line_size] = 0;
|
||||||
|
|
||||||
if (byte == ' ') return;
|
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){
|
switch (context->parser_state){
|
||||||
case HFP_PARSER_CMD_HEADER: // header
|
case HFP_PARSER_CMD_HEADER: // header
|
||||||
if (byte == ':' || byte == '='){
|
if (byte == ':' || byte == '='){
|
||||||
@ -501,6 +512,7 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){
|
|||||||
if (byte == '\n' || byte == '\r'){
|
if (byte == '\n' || byte == '\r'){
|
||||||
context->line_buffer[context->line_size] = 0;
|
context->line_buffer[context->line_size] = 0;
|
||||||
if (context->line_size == 2){
|
if (context->line_size == 2){
|
||||||
|
printf("Parsed OK\n");
|
||||||
update_command(context);
|
update_command(context);
|
||||||
}
|
}
|
||||||
context->line_size = 0;
|
context->line_size = 0;
|
||||||
@ -519,7 +531,7 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){
|
|||||||
if (byte == '(' ){ // tuple separated mit comma
|
if (byte == '(' ){ // tuple separated mit comma
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (byte == ',' || byte == '\n' || byte == '\r' || byte == ')'){
|
if (byte == ',' || byte == '\n' || byte == '\r' || byte == ')'){
|
||||||
context->line_buffer[context->line_size] = 0;
|
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);
|
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;
|
context->parser_state = HFP_PARSER_CMD_HEADER;
|
||||||
break;
|
break;
|
||||||
case HFP_CMD_AVAILABLE_CODECS:
|
case HFP_CMD_AVAILABLE_CODECS:
|
||||||
// printf("Received codec %s\n", context->line_buffer);
|
printf("Parsed codec %s\n", context->line_buffer);
|
||||||
// context->remote_codecs[context->remote_codecs_nr] = (uint16_t)atoi((char*)context->line_buffer);
|
|
||||||
context->remote_codecs[context->parser_item_index] = (uint16_t)atoi((char*)context->line_buffer);
|
context->remote_codecs[context->parser_item_index] = (uint16_t)atoi((char*)context->line_buffer);
|
||||||
context->parser_item_index++;
|
context->parser_item_index++;
|
||||||
context->remote_codecs_nr = context->parser_item_index;
|
context->remote_codecs_nr = context->parser_item_index;
|
||||||
break;
|
break;
|
||||||
case HFP_CMD_INDICATOR_STATUS:
|
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->ag_indicators[context->parser_item_index].status = atoi((char *) context->line_buffer);
|
||||||
context->parser_item_index++;
|
context->parser_item_index++;
|
||||||
break;
|
break;
|
||||||
case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE:
|
case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE:
|
||||||
if (context->parser_item_index == 3){
|
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]);
|
value = atoi((char *)&context->line_buffer[0]);
|
||||||
context->enable_status_update_for_ag_indicators = (uint8_t) value;
|
context->enable_status_update_for_ag_indicators = (uint8_t) value;
|
||||||
} else {
|
} else {
|
||||||
@ -556,39 +567,50 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES:
|
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;
|
if (context->line_size > 2 ) break;
|
||||||
strcpy((char *)context->remote_call_services[context->remote_call_services_nr].name, (char *)context->line_buffer);
|
strcpy((char *)context->remote_call_services[context->remote_call_services_nr].name, (char *)context->line_buffer);
|
||||||
context->remote_call_services_nr++;
|
context->remote_call_services_nr++;
|
||||||
|
|
||||||
|
if (byte == ')'){
|
||||||
|
context->parser_state = HFP_PARSER_CMD_HEADER;
|
||||||
|
context->parser_item_index = 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case HFP_CMD_GENERIC_STATUS_INDICATOR:
|
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->generic_status_indicators[context->parser_item_index].uuid = (uint16_t)atoi((char*)context->line_buffer);
|
||||||
context->parser_item_index++;
|
context->parser_item_index++;
|
||||||
context->generic_status_indicators_nr = context->parser_item_index;
|
context->generic_status_indicators_nr = context->parser_item_index;
|
||||||
break;
|
break;
|
||||||
case HFP_CMD_GENERIC_STATUS_INDICATOR_STATE:
|
case HFP_CMD_GENERIC_STATUS_INDICATOR_STATE:
|
||||||
// HF parses inital AG gen. ind. 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->parser_state = HFP_PARSER_CMD_INDICATOR_STATUS;
|
||||||
context->generic_status_indicator_state_index = (uint8_t)atoi((char*)context->line_buffer);
|
context->parser_item_index = (uint8_t)atoi((char*)context->line_buffer);
|
||||||
break;
|
break;
|
||||||
case HFP_CMD_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE:
|
case HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE:
|
||||||
// AG parses new gen. ind. state
|
// AG parses new gen. ind. state
|
||||||
|
printf("Parsed Enable ag indicator state: %s\n", context->line_buffer);
|
||||||
value = atoi((char *)&context->line_buffer[0]);
|
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++;
|
context->parser_item_index++;
|
||||||
break;
|
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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
context->line_size = 0;
|
context->line_size = 0;
|
||||||
|
|
||||||
if (byte == '\n' || byte == '\r'){
|
if (byte == '\n' || byte == '\r'){
|
||||||
context->parser_state = HFP_PARSER_CMD_HEADER;
|
printf("parse done 1, state %d\n", context->parser_state);
|
||||||
context->parser_item_index = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (byte == ')' && context->command == HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES){ // tuple separated mit comma
|
|
||||||
context->parser_state = HFP_PARSER_CMD_HEADER;
|
context->parser_state = HFP_PARSER_CMD_HEADER;
|
||||||
context->parser_item_index = 0;
|
context->parser_item_index = 0;
|
||||||
break;
|
break;
|
||||||
@ -597,26 +619,37 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){
|
|||||||
}
|
}
|
||||||
context->line_buffer[context->line_size++] = byte;
|
context->line_buffer[context->line_size++] = byte;
|
||||||
break;
|
break;
|
||||||
case HFP_PARSER_CMD_INITITAL_STATE_GENERIC_STATUS_INDICATORS:
|
case HFP_PARSER_CMD_INDICATOR_STATUS:
|
||||||
context->line_buffer[context->line_size] = 0;
|
context->line_buffer[context->line_size] = 0;
|
||||||
if (byte == ',') break;
|
if (byte == ',') break;
|
||||||
if (byte == '\n' || byte == '\r'){
|
if (byte == '\n' || byte == '\r'){
|
||||||
context->line_buffer[context->line_size] = 0;
|
context->line_buffer[context->line_size] = 0;
|
||||||
context->line_size = 0;
|
context->line_size = 0;
|
||||||
context->parser_state = HFP_PARSER_CMD_HEADER;
|
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
|
// 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;
|
break;
|
||||||
}
|
}
|
||||||
context->line_buffer[context->line_size++] = byte;
|
context->line_buffer[context->line_size++] = byte;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HFP_PARSER_CMD_INDICATOR_NAME: // parse indicator name
|
case HFP_PARSER_CMD_INDICATOR_NAME: // parse indicator name
|
||||||
|
//if (byte == '\n' || byte == '\r') return;
|
||||||
if (byte == '"'){
|
if (byte == '"'){
|
||||||
context->line_buffer[context->line_size] = 0;
|
context->line_buffer[context->line_size] = 0;
|
||||||
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);
|
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;
|
context->ag_indicators[context->parser_item_index].index = context->parser_item_index+1;
|
||||||
break;
|
break;
|
||||||
@ -628,10 +661,11 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){
|
|||||||
context->line_buffer[context->line_size++] = byte;
|
context->line_buffer[context->line_size++] = byte;
|
||||||
break;
|
break;
|
||||||
case HFP_PARSER_CMD_INDICATOR_MIN_RANGE:
|
case HFP_PARSER_CMD_INDICATOR_MIN_RANGE:
|
||||||
|
//if (byte == '\n' || byte == '\r') return;
|
||||||
if (byte == ',' || byte == '-'){ // end min_range
|
if (byte == ',' || byte == '-'){ // end min_range
|
||||||
context->parser_state = HFP_PARSER_CMD_INDICATOR_MAX_RANGE;
|
context->parser_state = HFP_PARSER_CMD_INDICATOR_MAX_RANGE;
|
||||||
context->line_buffer[context->line_size] = 0;
|
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->ag_indicators[context->parser_item_index].min_range = atoi((char *)context->line_buffer);
|
||||||
context->line_size = 0;
|
context->line_size = 0;
|
||||||
break;
|
break;
|
||||||
@ -640,14 +674,16 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){
|
|||||||
context->line_buffer[context->line_size++] = byte;
|
context->line_buffer[context->line_size++] = byte;
|
||||||
break;
|
break;
|
||||||
case HFP_PARSER_CMD_INDICATOR_MAX_RANGE:
|
case HFP_PARSER_CMD_INDICATOR_MAX_RANGE:
|
||||||
|
//if (byte == '\n' || byte == '\r') return;
|
||||||
if (byte == ')'){ // end max_range
|
if (byte == ')'){ // end max_range
|
||||||
context->parser_state = HFP_PARSER_CMD_SEQUENCE;
|
context->parser_state = HFP_PARSER_CMD_SEQUENCE;
|
||||||
context->line_buffer[context->line_size] = 0;
|
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->ag_indicators[context->parser_item_index].max_range = atoi((char *)context->line_buffer);
|
||||||
context->line_size = 0;
|
context->line_size = 0;
|
||||||
context->parser_item_index++;
|
context->parser_item_index++;
|
||||||
context->ag_indicators_nr = context->parser_item_index;
|
context->ag_indicators_nr = context->parser_item_index;
|
||||||
|
printf("parser ag nr %d \n", context->ag_indicators_nr);
|
||||||
break;
|
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));
|
log_error("hfp_establish_service_level_connection for addr %s failed", bd_addr_to_str(bd_addr));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (context->state != HFP_IDLE) return;
|
switch (context->state){
|
||||||
|
case HFP_W2_DISCONNECT_RFCOMM:
|
||||||
memcpy(context->remote_addr, bd_addr, 6);
|
context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
|
||||||
context->state = HFP_W4_SDP_QUERY_COMPLETE;
|
return;
|
||||||
|
case HFP_W4_RFCOMM_DISCONNECTED:
|
||||||
connection_doing_sdp_query = context;
|
context->state = HFP_W4_RFCOMM_DISCONNECTED_AND_RESTART;
|
||||||
sdp_query_rfcomm_channel_and_name_for_uuid(context->remote_addr, service_uuid);
|
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){
|
void hfp_release_service_level_connection(hfp_connection_t * context){
|
||||||
|
26
src/hfp.h
26
src/hfp.h
@ -105,11 +105,13 @@ extern "C" {
|
|||||||
#define HFP_AVAILABLE_CODECS "+BAC"
|
#define HFP_AVAILABLE_CODECS "+BAC"
|
||||||
#define HFP_INDICATOR "+CIND"
|
#define HFP_INDICATOR "+CIND"
|
||||||
#define HFP_ENABLE_STATUS_UPDATE_FOR_AG_INDICATORS "+CMER"
|
#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:<enabled>,,<enabled>,,,<enabled>
|
||||||
#define HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES "+CHLD"
|
#define HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES "+CHLD"
|
||||||
#define HFP_GENERIC_STATUS_INDICATOR "+BIND"
|
#define HFP_GENERIC_STATUS_INDICATOR "+BIND"
|
||||||
|
#define HFP_TRANSFER_AG_INDICATOR_STATUS "+CIEV" // +CIEV: <index>,<value>
|
||||||
|
|
||||||
#define HFP_OK "OK"
|
#define HFP_OK "OK"
|
||||||
|
#define HFP_ERROR "ERROR"
|
||||||
|
|
||||||
// Codecs
|
// Codecs
|
||||||
#define HFP_CODEC_CVSD 0x01
|
#define HFP_CODEC_CVSD 0x01
|
||||||
@ -117,17 +119,19 @@ extern "C" {
|
|||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
HFP_CMD_NONE = 0,
|
HFP_CMD_NONE = 0,
|
||||||
|
HFP_CMD_ERROR,
|
||||||
HFP_CMD_OK,
|
HFP_CMD_OK,
|
||||||
HFP_CMD_SUPPORTED_FEATURES,
|
HFP_CMD_SUPPORTED_FEATURES,
|
||||||
HFP_CMD_AVAILABLE_CODECS,
|
HFP_CMD_AVAILABLE_CODECS,
|
||||||
HFP_CMD_INDICATOR,
|
HFP_CMD_INDICATOR,
|
||||||
HFP_CMD_INDICATOR_STATUS, // 5
|
HFP_CMD_INDICATOR_STATUS, // 5
|
||||||
HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE,
|
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_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES,
|
||||||
HFP_CMD_LIST_GENERIC_STATUS_INDICATOR,
|
HFP_CMD_LIST_GENERIC_STATUS_INDICATOR,
|
||||||
HFP_CMD_GENERIC_STATUS_INDICATOR, // 10
|
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;
|
} hfp_command_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -136,7 +140,7 @@ typedef enum {
|
|||||||
HFP_PARSER_CMD_INDICATOR_NAME,
|
HFP_PARSER_CMD_INDICATOR_NAME,
|
||||||
HFP_PARSER_CMD_INDICATOR_MIN_RANGE,
|
HFP_PARSER_CMD_INDICATOR_MIN_RANGE,
|
||||||
HFP_PARSER_CMD_INDICATOR_MAX_RANGE,
|
HFP_PARSER_CMD_INDICATOR_MAX_RANGE,
|
||||||
HFP_PARSER_CMD_INITITAL_STATE_GENERIC_STATUS_INDICATORS
|
HFP_PARSER_CMD_INDICATOR_STATUS
|
||||||
} hfp_parser_state_t;
|
} hfp_parser_state_t;
|
||||||
|
|
||||||
|
|
||||||
@ -177,6 +181,7 @@ typedef enum {
|
|||||||
|
|
||||||
HFP_W2_DISCONNECT_RFCOMM,
|
HFP_W2_DISCONNECT_RFCOMM,
|
||||||
HFP_W4_RFCOMM_DISCONNECTED,
|
HFP_W4_RFCOMM_DISCONNECTED,
|
||||||
|
HFP_W4_RFCOMM_DISCONNECTED_AND_RESTART,
|
||||||
HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN
|
HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN
|
||||||
} hfp_state_t;
|
} hfp_state_t;
|
||||||
|
|
||||||
@ -185,7 +190,7 @@ typedef void (*hfp_callback_t)(uint8_t * event, uint16_t event_size);
|
|||||||
typedef struct{
|
typedef struct{
|
||||||
uint16_t uuid;
|
uint16_t uuid;
|
||||||
uint8_t state; // enabled
|
uint8_t state; // enabled
|
||||||
} hfp_generic_status_indicators_t;
|
} hfp_generic_status_indicator_t;
|
||||||
|
|
||||||
typedef struct{
|
typedef struct{
|
||||||
uint8_t index;
|
uint8_t index;
|
||||||
@ -193,7 +198,9 @@ typedef struct{
|
|||||||
uint8_t min_range;
|
uint8_t min_range;
|
||||||
uint8_t max_range;
|
uint8_t max_range;
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
|
uint8_t mandatory;
|
||||||
uint8_t enabled;
|
uint8_t enabled;
|
||||||
|
uint8_t status_changed;
|
||||||
} hfp_ag_indicator_t;
|
} hfp_ag_indicator_t;
|
||||||
|
|
||||||
typedef struct{
|
typedef struct{
|
||||||
@ -209,7 +216,9 @@ typedef struct hfp_connection {
|
|||||||
uint16_t rfcomm_cid;
|
uint16_t rfcomm_cid;
|
||||||
|
|
||||||
hfp_state_t state;
|
hfp_state_t state;
|
||||||
|
// needed for reestablishing connection
|
||||||
|
uint16_t service_uuid;
|
||||||
|
|
||||||
// used during service level connection establishment
|
// used during service level connection establishment
|
||||||
hfp_command_t command;
|
hfp_command_t command;
|
||||||
hfp_parser_state_t parser_state;
|
hfp_parser_state_t parser_state;
|
||||||
@ -225,8 +234,9 @@ typedef struct hfp_connection {
|
|||||||
int remote_call_services_nr;
|
int remote_call_services_nr;
|
||||||
hfp_call_service_t remote_call_services[HFP_MAX_INDICATOR_DESC_SIZE];
|
hfp_call_service_t remote_call_services[HFP_MAX_INDICATOR_DESC_SIZE];
|
||||||
|
|
||||||
|
// TODO: use bitmap.
|
||||||
int generic_status_indicators_nr;
|
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 generic_status_indicator_state_index;
|
||||||
uint8_t enable_status_update_for_ag_indicators;
|
uint8_t enable_status_update_for_ag_indicators;
|
||||||
|
|
||||||
@ -234,7 +244,7 @@ typedef struct hfp_connection {
|
|||||||
// 0 = deactivate, 1 = activate, 0xff = do nothing
|
// 0 = deactivate, 1 = activate, 0xff = do nothing
|
||||||
uint8_t wait_ok;
|
uint8_t wait_ok;
|
||||||
hfp_command_t sent_command;
|
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;
|
uint32_t ag_indicators_status_update_bitmap;
|
||||||
|
|
||||||
|
56
src/hfp_ag.c
56
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);
|
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();
|
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){
|
hfp_ag_indicator_t * get_hfp_ag_indicators(){
|
||||||
int i;
|
return (hfp_ag_indicator_t *)&hfp_ag_indicators;
|
||||||
if (indicator_nr > HFP_MAX_NUM_AG_INDICATORS) return;
|
}
|
||||||
for (i = 0; i<indicator_nr; i++){
|
int get_hfp_ag_indicators_nr(){
|
||||||
hfp_ag_indicators[i].status = indicators[i].status;
|
return hfp_ag_indicators_nr;
|
||||||
hfp_ag_indicators[i].min_range = indicators[i].min_range;
|
}
|
||||||
hfp_ag_indicators[i].max_range = indicators[i].max_range;
|
void set_hfp_ag_indicators(hfp_ag_indicator_t * indicators, int indicator_nr){
|
||||||
strcpy(hfp_ag_indicators[i].name, indicators[i].name);
|
memcpy(hfp_ag_indicators, indicators, indicator_nr * sizeof(hfp_ag_indicator_t));
|
||||||
|
|
||||||
}
|
|
||||||
hfp_ag_indicators_nr = indicator_nr;
|
hfp_ag_indicators_nr = indicator_nr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,10 +155,10 @@ int hfp_ag_indicators_join(char * buffer, int buffer_size){
|
|||||||
int i;
|
int i;
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
for (i = 0; i < hfp_ag_indicators_nr-1; i++) {
|
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 (i<hfp_ag_indicators_nr){
|
if (i<hfp_ag_indicators_nr){
|
||||||
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);
|
||||||
}
|
}
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
@ -269,6 +267,12 @@ int hfp_ag_retrieve_initital_supported_generic_status_indicators_cmd(uint16_t ci
|
|||||||
return send_str_over_rfcomm(cid, buffer);
|
return send_str_over_rfcomm(cid, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int hfp_ag_transfer_ag_indicators_status_cmd(uint16_t cid, hfp_ag_indicator_t indicator){
|
||||||
|
char buffer[20];
|
||||||
|
sprintf(buffer, "\r\n%s:%d,%d", HFP_TRANSFER_AG_INDICATOR_STATUS, indicator.index, indicator.status);
|
||||||
|
return send_str_over_rfcomm(cid, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void update_command(hfp_connection_t * context){
|
void update_command(hfp_connection_t * context){
|
||||||
context->command = HFP_CMD_NONE;
|
context->command = 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){
|
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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -320,6 +324,21 @@ void hfp_run_for_context(hfp_connection_t *context){
|
|||||||
if (!context) return;
|
if (!context) return;
|
||||||
if (!rfcomm_can_send_packet_now(context->rfcomm_cid)) 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){
|
switch(context->command){
|
||||||
case HFP_CMD_SUPPORTED_FEATURES:
|
case HFP_CMD_SUPPORTED_FEATURES:
|
||||||
switch(context->state){
|
switch(context->state){
|
||||||
@ -422,10 +441,7 @@ void hfp_run_for_context(hfp_connection_t *context){
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case HFP_CMD_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE:
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HFP_CMD_NONE:
|
case HFP_CMD_NONE:
|
||||||
switch(context->state){
|
switch(context->state){
|
||||||
case HFP_W2_DISCONNECT_RFCOMM:
|
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,
|
void hfp_ag_init(uint16_t rfcomm_channel_nr, uint32_t supported_features,
|
||||||
uint8_t * codecs, int codecs_nr,
|
uint8_t * codecs, int codecs_nr,
|
||||||
hfp_ag_indicator_t * ag_indicators, int ag_indicators_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){
|
char *call_hold_services[], int call_hold_services_nr){
|
||||||
if (codecs_nr > HFP_MAX_NUM_CODECS){
|
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);
|
log_error("hfp_init: codecs_nr (%d) > HFP_MAX_NUM_CODECS (%d)", codecs_nr, HFP_MAX_NUM_CODECS);
|
||||||
|
@ -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,
|
void hfp_ag_init(uint16_t rfcomm_channel_nr, uint32_t supported_features,
|
||||||
uint8_t * codecs, int codecs_nr,
|
uint8_t * codecs, int codecs_nr,
|
||||||
hfp_ag_indicator_t * ag_indicators, int ag_indicators_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);
|
char *call_hold_services[], int call_hold_services_nr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
63
src/hfp_hf.c
63
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);
|
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){
|
int hfp_hs_activate_status_update_for_ag_indicator_cmd(uint16_t cid, uint32_t indicators_status, int indicators_nr){
|
||||||
char buffer[20];
|
char buffer[50];
|
||||||
int offset = snprintf(buffer, sizeof(buffer), "AT%s=", HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS);
|
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 += join_bitmap(buffer+offset, sizeof(buffer)-offset, indicators_status, indicators_nr);
|
||||||
offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n");
|
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);
|
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){
|
static void hfp_run_for_context(hfp_connection_t * context){
|
||||||
if (!context) return;
|
if (!context) return;
|
||||||
// printf("hfp send cmd: context %p, RFCOMM cid %u \n", context, context->rfcomm_cid );
|
// 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;
|
context->state = HFP_W4_RFCOMM_DISCONNECTED;
|
||||||
rfcomm_disconnect_internal(context->rfcomm_cid);
|
rfcomm_disconnect_internal(context->rfcomm_cid);
|
||||||
break;
|
break;
|
||||||
case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
|
case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED:{
|
||||||
if (context->wait_ok == 1) return;
|
if (context->wait_ok == 1) return;
|
||||||
|
|
||||||
if (context->enable_status_update_for_ag_indicators != 0xFF){
|
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);
|
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->wait_ok = 1;
|
||||||
|
context->enable_status_update_for_ag_indicators = 0xFF;
|
||||||
break;
|
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,
|
hfp_hs_activate_status_update_for_ag_indicator_cmd(context->rfcomm_cid,
|
||||||
context->ag_indicators_status_update_bitmap,
|
context->ag_indicators_status_update_bitmap,
|
||||||
context->ag_indicators_nr,
|
context->ag_indicators_nr);
|
||||||
context->change_enable_status_update_for_individual_ag_indicators);
|
|
||||||
context->wait_ok = 1;
|
context->wait_ok = 1;
|
||||||
|
context->change_status_update_for_individual_ag_indicators = 0;
|
||||||
break;
|
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;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -263,6 +283,11 @@ static void hfp_run_for_context(hfp_connection_t * context){
|
|||||||
|
|
||||||
void update_command(hfp_connection_t * context){
|
void update_command(hfp_connection_t * context){
|
||||||
context->command = HFP_CMD_NONE;
|
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){
|
if (strncmp((char *)context->line_buffer, HFP_OK, strlen(HFP_OK)) == 0){
|
||||||
context->command = HFP_CMD_OK;
|
context->command = HFP_CMD_OK;
|
||||||
printf("Received OK\n");
|
printf("Received OK\n");
|
||||||
@ -307,9 +332,9 @@ void update_command(hfp_connection_t * context){
|
|||||||
return;
|
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){
|
if (strncmp((char *)context->line_buffer, HFP_TRANSFER_AG_INDICATOR_STATUS, strlen(HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS)) == 0){
|
||||||
printf("Received +BIA\n");
|
printf("Received +CIEV\n");
|
||||||
context->command = HFP_CMD_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE;
|
context->command = HFP_CMD_TRANSFER_AG_INDICATOR_STATUS;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,6 +342,7 @@ void update_command(hfp_connection_t * context){
|
|||||||
|
|
||||||
|
|
||||||
void handle_switch_on_ok(hfp_connection_t *context){
|
void handle_switch_on_ok(hfp_connection_t *context){
|
||||||
|
// printf("switch on ok\n");
|
||||||
switch (context->state){
|
switch (context->state){
|
||||||
case HFP_W4_EXCHANGE_SUPPORTED_FEATURES:
|
case HFP_W4_EXCHANGE_SUPPORTED_FEATURES:
|
||||||
if (has_codec_negotiation_feature(context)){
|
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:
|
case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
|
||||||
context->wait_ok = 0;
|
context->wait_ok = 0;
|
||||||
|
hfp_emit_event(hfp_callback, HFP_SUBEVENT_COMPLETE, 0);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -391,10 +419,20 @@ static void hfp_handle_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8
|
|||||||
|
|
||||||
packet[size] = 0;
|
packet[size] = 0;
|
||||||
int pos;
|
int pos;
|
||||||
|
printf("parse command: %s, state: %d\n", packet, context->parser_state);
|
||||||
for (pos = 0; pos < size ; pos++){
|
for (pos = 0; pos < size ; pos++){
|
||||||
hfp_parse(context, packet[pos]);
|
hfp_parse(context, packet[pos]);
|
||||||
|
|
||||||
// trigger next action after CMD received
|
// 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;
|
if (context->command != HFP_CMD_OK) continue;
|
||||||
handle_switch_on_ok(context);
|
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){
|
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);
|
hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
|
||||||
if (!connection){
|
if (!connection){
|
||||||
log_error("HFP HF: connection doesn't exist.");
|
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);
|
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);
|
hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
|
||||||
if (!connection){
|
if (!connection){
|
||||||
log_error("HFP HF: connection doesn't exist.");
|
log_error("HFP HF: connection doesn't exist.");
|
||||||
return;
|
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;
|
connection->ag_indicators_status_update_bitmap = indicators_status_bitmap;
|
||||||
hfp_run_for_context(connection);
|
hfp_run_for_context(connection);
|
||||||
}
|
}
|
||||||
|
@ -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.
|
* @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);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -47,17 +47,33 @@
|
|||||||
#include "hfp.h"
|
#include "hfp.h"
|
||||||
|
|
||||||
void hfp_parse(hfp_connection_t * context, uint8_t byte);
|
void hfp_parse(hfp_connection_t * context, uint8_t byte);
|
||||||
hfp_generic_status_indicators_t * get_hfp_generic_status_indicators();
|
hfp_generic_status_indicator_t * get_hfp_generic_status_indicators();
|
||||||
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);
|
||||||
|
|
||||||
|
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 int hf_indicators_nr = 3;
|
||||||
static hfp_generic_status_indicators_t hf_indicators[] = {
|
static hfp_generic_status_indicator_t hf_indicators[] = {
|
||||||
{1, 1},
|
{1, 1},
|
||||||
{2, 1},
|
{2, 1},
|
||||||
{3, 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;
|
static hfp_connection_t context;
|
||||||
|
|
||||||
TEST_GROUP(HFPParser){
|
TEST_GROUP(HFPParser){
|
||||||
@ -123,29 +139,46 @@ TEST(HFPParser, HFP_AG_ENABLE_INDICATOR_STATUS_UPDATE){
|
|||||||
|
|
||||||
|
|
||||||
TEST(HFPParser, HFP_AG_ENABLE_INDIVIDUAL_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);
|
set_hfp_ag_indicators((hfp_ag_indicator_t *)&hfp_ag_indicators, hfp_ag_indicators_nr);
|
||||||
context.generic_status_indicators_nr = hf_indicators_nr;
|
context.ag_indicators_nr = hfp_ag_indicators_nr;
|
||||||
memcpy(context.generic_status_indicators, hf_indicators, hf_indicators_nr * sizeof(hfp_generic_status_indicators_t));
|
memcpy(context.ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t));
|
||||||
|
|
||||||
for (pos = 0; pos < hf_indicators_nr; pos++){
|
for (pos = 0; pos < hfp_ag_indicators_nr; pos++){
|
||||||
CHECK_EQUAL(get_hfp_generic_status_indicators()[pos].uuid, hf_indicators[pos].uuid);
|
CHECK_EQUAL(get_hfp_ag_indicators()[pos].index, hfp_ag_indicators[pos].index);
|
||||||
CHECK_EQUAL(get_hfp_generic_status_indicators()[pos].state, hf_indicators[pos].state);
|
CHECK_EQUAL(get_hfp_ag_indicators()[pos].enabled, hfp_ag_indicators[pos].enabled);
|
||||||
CHECK_EQUAL(context.generic_status_indicators[pos].uuid, hf_indicators[pos].uuid);
|
CHECK_EQUAL(context.ag_indicators[pos].index, hfp_ag_indicators[pos].index);
|
||||||
CHECK_EQUAL(context.generic_status_indicators[pos].state, hf_indicators[pos].state);
|
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);
|
HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS);
|
||||||
for (pos = 0; pos < strlen(packet); pos++){
|
for (pos = 0; pos < strlen(packet); pos++){
|
||||||
hfp_parse(&context, 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++){
|
for (pos = 0; pos < hfp_ag_indicators_nr; pos++){
|
||||||
CHECK_EQUAL(get_hfp_generic_status_indicators()[pos].state, 1);
|
if (get_hfp_ag_indicators()[pos].mandatory){
|
||||||
CHECK_EQUAL(context.generic_status_indicators[pos].state, 0);
|
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[]){
|
int main (int argc, const char * argv[]){
|
||||||
|
@ -49,15 +49,16 @@
|
|||||||
void hfp_parse(hfp_connection_t * context, uint8_t byte);
|
void hfp_parse(hfp_connection_t * context, uint8_t byte);
|
||||||
|
|
||||||
static hfp_connection_t context;
|
static hfp_connection_t context;
|
||||||
static int ag_indicators_nr = 7;
|
static int hfp_ag_indicators_nr = 7;
|
||||||
static hfp_ag_indicator_t ag_indicators[] = {
|
static hfp_ag_indicator_t hfp_ag_indicators[] = {
|
||||||
{1, "service", 0, 1, 1},
|
// index, name, min range, max range, status, mandatory, enabled, status changed
|
||||||
{2, "call", 0, 1, 0},
|
{1, "service", 0, 1, 1, 0, 0, 0},
|
||||||
{3, "callsetup", 0, 3, 0},
|
{2, "call", 0, 1, 0, 1, 1, 0},
|
||||||
{4, "battchg", 0, 5, 3},
|
{3, "callsetup", 0, 3, 0, 1, 1, 0},
|
||||||
{5, "signal", 0, 5, 5},
|
{4, "battchg", 0, 5, 3, 0, 0, 0},
|
||||||
{6, "roam", 0, 1, 0},
|
{5, "signal", 0, 5, 5, 0, 0, 0},
|
||||||
{7, "callheld", 0, 2, 0},
|
{6, "roam", 0, 1, 0, 0, 0, 0},
|
||||||
|
{7, "callheld", 0, 2, 0, 1, 1, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_GROUP(HFPParser){
|
TEST_GROUP(HFPParser){
|
||||||
@ -95,10 +96,10 @@ TEST(HFPParser, HFP_HF_SUPPORTED_FEATURES){
|
|||||||
TEST(HFPParser, HFP_HF_INDICATORS){
|
TEST(HFPParser, HFP_HF_INDICATORS){
|
||||||
offset = 0;
|
offset = 0;
|
||||||
offset += snprintf(packet, sizeof(packet), "%s:", HFP_INDICATOR);
|
offset += snprintf(packet, sizeof(packet), "%s:", HFP_INDICATOR);
|
||||||
for (pos = 0; pos < ag_indicators_nr - 1; pos++){
|
for (pos = 0; pos < hfp_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);
|
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;
|
context.sent_command = HFP_CMD_INDICATOR;
|
||||||
|
|
||||||
@ -106,12 +107,12 @@ TEST(HFPParser, HFP_HF_INDICATORS){
|
|||||||
hfp_parse(&context, packet[pos]);
|
hfp_parse(&context, packet[pos]);
|
||||||
}
|
}
|
||||||
CHECK_EQUAL(HFP_CMD_INDICATOR, context.command);
|
CHECK_EQUAL(HFP_CMD_INDICATOR, context.command);
|
||||||
CHECK_EQUAL(ag_indicators_nr, context.ag_indicators_nr);
|
CHECK_EQUAL(hfp_ag_indicators_nr, context.ag_indicators_nr);
|
||||||
for (pos = 0; pos < ag_indicators_nr; pos++){
|
for (pos = 0; pos < hfp_ag_indicators_nr; pos++){
|
||||||
CHECK_EQUAL(ag_indicators[pos].index, context.ag_indicators[pos].index);
|
CHECK_EQUAL(hfp_ag_indicators[pos].index, context.ag_indicators[pos].index);
|
||||||
CHECK_EQUAL(0, strcmp(ag_indicators[pos].name, context.ag_indicators[pos].name));
|
CHECK_EQUAL(0, strcmp(hfp_ag_indicators[pos].name, context.ag_indicators[pos].name));
|
||||||
CHECK_EQUAL(ag_indicators[pos].min_range, context.ag_indicators[pos].min_range);
|
CHECK_EQUAL(hfp_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[pos].max_range, context.ag_indicators[pos].max_range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,10 +120,10 @@ TEST(HFPParser, HFP_HF_INDICATOR_STATUS){
|
|||||||
// send status
|
// send status
|
||||||
offset = 0;
|
offset = 0;
|
||||||
offset += snprintf(packet, sizeof(packet), "%s:", HFP_INDICATOR);
|
offset += snprintf(packet, sizeof(packet), "%s:", HFP_INDICATOR);
|
||||||
for (pos = 0; pos < ag_indicators_nr - 1; pos++){
|
for (pos = 0; pos < hfp_ag_indicators_nr - 1; pos++){
|
||||||
offset += snprintf(packet+offset, sizeof(packet)-offset, "%d,", ag_indicators[pos].status);
|
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;
|
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);
|
CHECK_EQUAL(HFP_CMD_INDICATOR_STATUS, context.command);
|
||||||
for (pos = 0; pos < ag_indicators_nr; pos++){
|
for (pos = 0; pos < hfp_ag_indicators_nr; pos++){
|
||||||
CHECK_EQUAL(ag_indicators[pos].status, context.ag_indicators[pos].status);
|
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);
|
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[]){
|
int main (int argc, const char * argv[]){
|
||||||
return CommandLineTestRunner::RunAllTests(argc, argv);
|
return CommandLineTestRunner::RunAllTests(argc, argv);
|
||||||
}
|
}
|
||||||
|
@ -78,20 +78,21 @@ static uint8_t codecs[1] = {HFP_CODEC_CVSD};
|
|||||||
|
|
||||||
static int ag_indicators_nr = 7;
|
static int ag_indicators_nr = 7;
|
||||||
static hfp_ag_indicator_t ag_indicators[] = {
|
static hfp_ag_indicator_t ag_indicators[] = {
|
||||||
{1, "service", 0, 1, 1},
|
// index, name, min range, max range, status, mandatory, enabled, status changed
|
||||||
{2, "call", 0, 1, 0},
|
{1, "service", 0, 1, 1, 0, 0, 0},
|
||||||
{3, "callsetup", 0, 3, 0},
|
{2, "call", 0, 1, 0, 1, 1, 0},
|
||||||
{4, "battchg", 0, 5, 3},
|
{3, "callsetup", 0, 3, 0, 1, 1, 0},
|
||||||
{5, "signal", 0, 5, 5},
|
{4, "battchg", 0, 5, 3, 0, 0, 0},
|
||||||
{6, "roam", 0, 1, 0},
|
{5, "signal", 0, 5, 5, 0, 0, 0},
|
||||||
{7, "callheld", 0, 2, 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 int call_hold_services_nr = 5;
|
||||||
static char* call_hold_services[] = {"1", "1x", "2", "2x", "3"};
|
static char* call_hold_services[] = {"1", "1x", "2", "2x", "3"};
|
||||||
|
|
||||||
static int hf_indicators_nr = 2;
|
static int hf_indicators_nr = 2;
|
||||||
static hfp_generic_status_indicators_t hf_indicators[] = {
|
static hfp_generic_status_indicator_t hf_indicators[] = {
|
||||||
{1, 1},
|
{1, 1},
|
||||||
{2, 1},
|
{2, 1},
|
||||||
};
|
};
|
||||||
|
@ -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 pts_addr = {0x00,0x1b,0xDC,0x07,0x32,0xEF};
|
||||||
static bd_addr_t local_mac = {0x04, 0x0C, 0xCE, 0xE4, 0x85, 0xD3};
|
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 uint8_t codecs[1] = {HFP_CODEC_CVSD};
|
||||||
static uint16_t indicators[1] = {0x01};
|
static uint16_t indicators[1] = {0x01};
|
||||||
|
|
||||||
|
char cmd;
|
||||||
|
|
||||||
// prototypes
|
// prototypes
|
||||||
static void show_usage();
|
static void show_usage();
|
||||||
|
|
||||||
@ -88,6 +92,7 @@ static void show_usage(void){
|
|||||||
printf("---\n");
|
printf("---\n");
|
||||||
printf("p - establish HFP connection to PTS module\n");
|
printf("p - establish HFP connection to PTS module\n");
|
||||||
printf("e - establish HFP connection to local mac\n");
|
printf("e - establish HFP connection to local mac\n");
|
||||||
|
printf("r - enable registration status update\n");
|
||||||
printf("d - release HFP connection\n");
|
printf("d - release HFP connection\n");
|
||||||
printf("---\n");
|
printf("---\n");
|
||||||
printf("Ctrl-c - exit\n");
|
printf("Ctrl-c - exit\n");
|
||||||
@ -95,20 +100,29 @@ static void show_usage(void){
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int stdin_process(struct data_source *ds){
|
static int stdin_process(struct data_source *ds){
|
||||||
char buffer;
|
read(ds->fd, &cmd, 1);
|
||||||
read(ds->fd, &buffer, 1);
|
switch (cmd){
|
||||||
switch (buffer){
|
|
||||||
case 'p':
|
case 'p':
|
||||||
printf("Establishing HFP service level connection to PTS module %s...\n", bd_addr_to_str(pts_addr));
|
memcpy(device_addr, pts_addr, 6);
|
||||||
hfp_hf_establish_service_level_connection(pts_addr);
|
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;
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
printf("Establishing HFP service level connection to %s...\n", bd_addr_to_str(phone));
|
memcpy(device_addr, phone_addr, 6);
|
||||||
hfp_hf_establish_service_level_connection(phone);
|
printf("Establishing HFP service level connection to %s...\n", bd_addr_to_str(device_addr));
|
||||||
|
hfp_hf_establish_service_level_connection(device_addr);
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
printf("Releasing HFP service level connection.\n");
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
show_usage();
|
show_usage();
|
||||||
@ -121,22 +135,29 @@ static int stdin_process(struct data_source *ds){
|
|||||||
|
|
||||||
void packet_handler(uint8_t * event, uint16_t event_size){
|
void packet_handler(uint8_t * event, uint16_t event_size){
|
||||||
if (event[0] != HCI_EVENT_HFP_META) return;
|
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]) {
|
switch (event[2]) {
|
||||||
case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
|
case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
|
||||||
if (event[3] == 0){
|
printf("Service level connection established.\n\n");
|
||||||
printf("Service level connection established.\n\n");
|
|
||||||
} else {
|
|
||||||
printf("Service level connection establishment failed with status %u\n", event[3]);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED:
|
case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED:
|
||||||
if (event[3] == 0){
|
printf("Service level connection released.\n\n");
|
||||||
printf("Service level connection released.\n\n");
|
break;
|
||||||
} else {
|
case HFP_SUBEVENT_COMPLETE:
|
||||||
printf("Service level connection releasing failed with status %u\n", event[3]);
|
switch (cmd){
|
||||||
|
case 'r':
|
||||||
|
printf("HFP AG registration status update enabled.\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
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:
|
default:
|
||||||
printf("event not handled %u\n", event[2]);
|
printf("event not handled %u\n", event[2]);
|
||||||
break;
|
break;
|
||||||
@ -164,7 +185,7 @@ int btstack_main(int argc, const char * argv[]){
|
|||||||
hci_power_control(HCI_POWER_ON);
|
hci_power_control(HCI_POWER_ON);
|
||||||
|
|
||||||
btstack_stdin_setup(stdin_process);
|
btstack_stdin_setup(stdin_process);
|
||||||
// printf("Establishing HFP connection to %s...\n", bd_addr_to_str(phone));
|
// printf("Establishing HFP connection to %s...\n", bd_addr_to_str(phone_addr));
|
||||||
// hfp_hf_connect(phone);
|
// hfp_hf_connect(phone_addr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user