hfp: fix indicators parsing, add test for set ag status update enable

This commit is contained in:
Milanka Ringwald 2015-08-12 15:53:55 +02:00
parent 588247dfaa
commit 2bd0c9beb6
6 changed files with 77 additions and 46 deletions

View File

@ -615,7 +615,7 @@ 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_OK 0x03
// ANCS Client // ANCS Client
#define ANCS_CLIENT_CONNECTED 0xF0 #define ANCS_CLIENT_CONNECTED 0xF0

View File

@ -484,11 +484,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 +500,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,11 +519,19 @@ 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;
switch (context->command){ switch (context->command){
case HFP_CMD_INDICATOR:
if (byte == ')'){
context->parser_state = HFP_PARSER_CMD_SEQUENCE;
context->parser_item_index = 0;
context->line_size = 0;
break;
}
break;
case HFP_CMD_SUPPORTED_FEATURES: case HFP_CMD_SUPPORTED_FEATURES:
context->remote_supported_features = 0; context->remote_supported_features = 0;
for (i=0; i<16; i++){ for (i=0; i<16; i++){
@ -531,24 +539,23 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){
context->remote_supported_features = store_bit(context->remote_supported_features,15-i,1); 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,24 +563,31 @@ 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_INITITAL_STATE_GENERIC_STATUS_INDICATORS;
context->generic_status_indicator_state_index = (uint8_t)atoi((char*)context->line_buffer); context->generic_status_indicator_state_index = (uint8_t)atoi((char*)context->line_buffer);
break; break;
case HFP_CMD_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE: case HFP_CMD_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE:
// AG parses new gen. ind. state // AG parses new gen. ind. state
printf("Parsed Enable generic status indicator state: %s\n", context->line_buffer);
value = atoi((char *)&context->line_buffer[0]); value = atoi((char *)&context->line_buffer[0]);
context->generic_status_indicators[context->parser_item_index].state = value; context->generic_status_indicators[context->parser_item_index].state = value;
context->parser_item_index++; context->parser_item_index++;
@ -584,11 +598,7 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){
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;
@ -604,7 +614,7 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){
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 [0-dissabled, 1-enabled]\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); context->generic_status_indicators[context->generic_status_indicator_state_index].state = (uint8_t)atoi((char*)context->line_buffer);
break; break;
@ -613,10 +623,11 @@ void hfp_parse(hfp_connection_t * context, uint8_t 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 +639,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,10 +652,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_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++;

View File

@ -105,7 +105,7 @@ 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" // list of [0,1] for every AG indicator
#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"
@ -225,6 +225,7 @@ 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_indicators_t generic_status_indicators[HFP_MAX_INDICATOR_DESC_SIZE];
uint8_t generic_status_indicator_state_index; uint8_t generic_status_indicator_state_index;

View File

@ -157,10 +157,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;
} }

View File

@ -317,6 +317,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 +377,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_OK, 0);
break; break;
default: default:
break; break;
@ -391,6 +394,7 @@ 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]);

View File

@ -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,21 +100,25 @@ 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; break;
case 'r':
printf("Enabling HFP AG registration status update.\n");
hfp_hf_enable_status_update_for_all_ag_indicators(device_addr, 1);
default: default:
show_usage(); show_usage();
break; break;
@ -121,20 +130,24 @@ 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_OK:
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;
default: default:
@ -164,7 +177,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;
} }