fix ATA during wait for SCO. support CLIP

This commit is contained in:
Matthias Ringwald 2015-11-22 20:31:17 +01:00
parent 930ca5654e
commit 40a7976ab3
5 changed files with 79 additions and 15 deletions

View File

@ -671,6 +671,10 @@ static hfp_command_t parse_command(const char * line_buffer, int isHandsFree){
return HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE; return HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE;
} }
if (strncmp(line_buffer+offset, HFP_ENABLE_CLIP, strlen(HFP_ENABLE_CLIP)) == 0){
return HFP_CMD_ENABLE_CLIP;
}
if (strncmp(line_buffer+offset, HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES, strlen(HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES)) == 0){ if (strncmp(line_buffer+offset, HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES, strlen(HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES)) == 0){
return HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES; return HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES;
} }

View File

@ -106,6 +106,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_ENABLE_CLIP "+CLIP"
#define HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS "+BIA" // +BIA:<enabled>,,<enabled>,,,<enabled> #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"
@ -142,6 +143,7 @@ typedef enum {
HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE, HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE,
HFP_CMD_ENABLE_INDIVIDUAL_AG_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_ENABLE_CLIP,
HFP_CMD_LIST_GENERIC_STATUS_INDICATORS, HFP_CMD_LIST_GENERIC_STATUS_INDICATORS,
HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS, HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS,
@ -401,6 +403,9 @@ typedef struct hfp_connection {
// Retrieved during service level connection establishment, not used yet // Retrieved during service level connection establishment, not used yet
uint8_t negotiated_codec; uint8_t negotiated_codec;
// HF -> AG configuration
uint8_t clip_enabled;
// TODO: put these bit flags in a bitmap // TODO: put these bit flags in a bitmap
uint8_t ok_pending; uint8_t ok_pending;
// uint8_t send_ok; // uint8_t send_ok;
@ -424,6 +429,7 @@ typedef struct hfp_connection {
uint8_t run_call_state_machine; uint8_t run_call_state_machine;
uint8_t change_in_band_ring_tone_setting; uint8_t change_in_band_ring_tone_setting;
uint8_t ag_ring; uint8_t ag_ring;
uint8_t ag_send_clip;
timer_source_t hfp_timeout; timer_source_t hfp_timeout;
} hfp_connection_t; } hfp_connection_t;

View File

@ -80,6 +80,9 @@ static hfp_call_status_t hfp_ag_call_state;
static hfp_callsetup_status_t hfp_ag_callsetup_state; static hfp_callsetup_status_t hfp_ag_callsetup_state;
static hfp_callheld_status_t hfp_ag_callheld_state; static hfp_callheld_status_t hfp_ag_callheld_state;
// CLIP feature
static uint8_t clip_type; // 0 == not set
static char clip_number[25]; //
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);
static void hfp_run_for_context(hfp_connection_t *context); static void hfp_run_for_context(hfp_connection_t *context);
@ -204,6 +207,12 @@ static int hfp_ag_ring(uint16_t cid){
return send_str_over_rfcomm(cid, (char *) "\r\nRING\r\n"); return send_str_over_rfcomm(cid, (char *) "\r\nRING\r\n");
} }
static int hfp_ag_send_clip(uint16_t cid){
char buffer[50];
sprintf(buffer, "\r\n+CLIP: \"%s\",%u\r\n", clip_number, clip_type);
return send_str_over_rfcomm(cid, buffer);
}
static int hfp_ag_error(uint16_t cid){ static int hfp_ag_error(uint16_t cid){
char buffer[10]; char buffer[10];
sprintf(buffer, "\r\nERROR\r\n"); sprintf(buffer, "\r\nERROR\r\n");
@ -647,6 +656,7 @@ static void hfp_timeout_handler(timer_source_t * timer){
log_info("HFP start ring timeout, con handle 0x%02x", context->con_handle); log_info("HFP start ring timeout, con handle 0x%02x", context->con_handle);
context->ag_ring = 1; context->ag_ring = 1;
context->ag_send_clip = clip_type && context->clip_enabled;
run_loop_set_timer(&context->hfp_timeout, 2000); // 5 seconds timeout run_loop_set_timer(&context->hfp_timeout, 2000); // 5 seconds timeout
run_loop_add_timer(&context->hfp_timeout); run_loop_add_timer(&context->hfp_timeout);
@ -694,6 +704,7 @@ static int incoming_call_state_machine(hfp_connection_t * context){
static void hfp_ag_hf_start_ringing(hfp_connection_t * context){ static void hfp_ag_hf_start_ringing(hfp_connection_t * context){
hfp_timeout_start(context); hfp_timeout_start(context);
context->ag_ring = 1; context->ag_ring = 1;
context->ag_send_clip = clip_type && context->clip_enabled;
if (use_in_band_tone()){ if (use_in_band_tone()){
context->call_state = HFP_CALL_W4_AUDIO_CONNECTION_FOR_IN_BAND_RING; context->call_state = HFP_CALL_W4_AUDIO_CONNECTION_FOR_IN_BAND_RING;
hfp_ag_establish_audio_connection(context->remote_addr); hfp_ag_establish_audio_connection(context->remote_addr);
@ -705,6 +716,7 @@ static void hfp_ag_hf_start_ringing(hfp_connection_t * context){
static void hfp_ag_hf_stop_ringing(hfp_connection_t * context){ static void hfp_ag_hf_stop_ringing(hfp_connection_t * context){
context->ag_ring = 0; context->ag_ring = 0;
context->ag_send_clip = 0;
hfp_timeout_stop(context); hfp_timeout_stop(context);
hfp_emit_event(hfp_callback, HFP_SUBEVENT_STOP_RINGINIG, 0); hfp_emit_event(hfp_callback, HFP_SUBEVENT_STOP_RINGINIG, 0);
} }
@ -764,7 +776,8 @@ static void hfp_ag_hf_accept_call(hfp_connection_t * source){
linked_list_iterator_init(&it, hfp_get_connections()); linked_list_iterator_init(&it, hfp_get_connections());
while (linked_list_iterator_has_next(&it)){ while (linked_list_iterator_has_next(&it)){
hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it);
if (connection->call_state != HFP_CALL_RINGING) continue; if (connection->call_state != HFP_CALL_RINGING &&
connection->call_state != HFP_CALL_W4_AUDIO_CONNECTION_FOR_IN_BAND_RING) continue;
hfp_ag_hf_stop_ringing(connection); hfp_ag_hf_stop_ringing(connection);
connection->run_call_state_machine = 1; connection->run_call_state_machine = 1;
@ -786,7 +799,6 @@ static void hfp_ag_hf_accept_call(hfp_connection_t * source){
connection->call_state = HFP_CALL_IDLE; connection->call_state = HFP_CALL_IDLE;
} }
hfp_run_for_context(connection); hfp_run_for_context(connection);
break; // only single
} }
} }
@ -819,7 +831,8 @@ static void hfp_ag_trigger_reject_call(void){
linked_list_iterator_init(&it, hfp_get_connections()); linked_list_iterator_init(&it, hfp_get_connections());
while (linked_list_iterator_has_next(&it)){ while (linked_list_iterator_has_next(&it)){
hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it);
if (connection->call_state != HFP_CALL_RINGING) continue; if (connection->call_state != HFP_CALL_RINGING &&
connection->call_state != HFP_CALL_W4_AUDIO_CONNECTION_FOR_IN_BAND_RING) continue;
hfp_ag_hf_stop_ringing(connection); hfp_ag_hf_stop_ringing(connection);
connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1); connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1);
connection->run_call_state_machine = 0; connection->run_call_state_machine = 0;
@ -897,6 +910,8 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
break; break;
case HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG: case HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG:
// clear CLIP
clip_type = 0;
switch (hfp_ag_call_state){ switch (hfp_ag_call_state){
case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
switch (hfp_ag_callsetup_state){ switch (hfp_ag_callsetup_state){
@ -915,6 +930,8 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
} }
break; break;
case HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF: case HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF:
// clear CLIP
clip_type = 0;
switch (hfp_ag_call_state){ switch (hfp_ag_call_state){
case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
switch (hfp_ag_callsetup_state){ switch (hfp_ag_callsetup_state){
@ -934,6 +951,8 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
break; break;
case HFP_AG_TERMINATE_CALL_BY_HF: case HFP_AG_TERMINATE_CALL_BY_HF:
// clear CLIP
clip_type = 0;
switch (hfp_ag_call_state){ switch (hfp_ag_call_state){
case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
switch (hfp_ag_callsetup_state){ switch (hfp_ag_callsetup_state){
@ -962,6 +981,8 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
break; break;
case HFP_AG_TERMINATE_CALL_BY_AG: case HFP_AG_TERMINATE_CALL_BY_AG:
// clear CLIP
clip_type = 0;
switch (hfp_ag_call_state){ switch (hfp_ag_call_state){
case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
switch (hfp_ag_callsetup_state){ switch (hfp_ag_callsetup_state){
@ -984,6 +1005,8 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
} }
break; break;
case HFP_AG_CALL_DROPPED: case HFP_AG_CALL_DROPPED:
// clear CLIP
clip_type = 0;
switch (hfp_ag_call_state){ switch (hfp_ag_call_state){
case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT:
hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
@ -1040,6 +1063,7 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE); hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE);
hfp_ag_transfer_callsetup_state(); hfp_ag_transfer_callsetup_state();
break; break;
case HFP_AG_OUTGOING_CALL_ESTABLISHED: case HFP_AG_OUTGOING_CALL_ESTABLISHED:
switch (hfp_ag_call_state){ switch (hfp_ag_call_state){
case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
@ -1111,6 +1135,13 @@ static void hfp_run_for_context(hfp_connection_t *context){
return; return;
} }
if (context->ag_send_clip){
context->ag_send_clip = 0;
context->command = HFP_CMD_NONE;
hfp_ag_send_clip(context->rfcomm_cid);
return;
}
int done = hfp_ag_run_for_context_service_level_connection(context); int done = hfp_ag_run_for_context_service_level_connection(context);
if (!done){ if (!done){
done = hfp_ag_run_for_context_service_level_connection_queries(context); done = hfp_ag_run_for_context_service_level_connection_queries(context);
@ -1125,7 +1156,7 @@ static void hfp_run_for_context(hfp_connection_t *context){
} }
if (context->command == HFP_CMD_NONE && !done){ if (context->command == HFP_CMD_NONE && !done){
log_info("context->command == HFP_CMD_NONE"); // log_info("context->command == HFP_CMD_NONE");
switch(context->state){ switch(context->state){
case HFP_W2_DISCONNECT_RFCOMM: case HFP_W2_DISCONNECT_RFCOMM:
context->state = HFP_W4_RFCOMM_DISCONNECTED; context->state = HFP_W4_RFCOMM_DISCONNECTED;
@ -1150,6 +1181,7 @@ static void hfp_handle_rfcomm_data(uint8_t packet_type, uint16_t channel, uint8_
switch(context->command){ switch(context->command){
case HFP_CMD_CALL_ANSWERED: case HFP_CMD_CALL_ANSWERED:
context->command = HFP_CMD_NONE; context->command = HFP_CMD_NONE;
printf("HFP: ATA\n");
hfp_ag_call_sm(HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF, context); hfp_ag_call_sm(HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF, context);
break; break;
case HFP_CMD_HANG_UP_CALL: case HFP_CMD_HANG_UP_CALL:
@ -1164,6 +1196,12 @@ static void hfp_handle_rfcomm_data(uint8_t packet_type, uint16_t channel, uint8_
case HFP_CMD_REDIAL_LAST_NUMBER: case HFP_CMD_REDIAL_LAST_NUMBER:
context->command = HFP_CMD_NONE; context->command = HFP_CMD_NONE;
hfp_ag_call_sm(HFP_AG_OUTGOING_REDIAL_INITIATED, context); hfp_ag_call_sm(HFP_AG_OUTGOING_REDIAL_INITIATED, context);
case HFP_CMD_ENABLE_CLIP:
context->command = HFP_CMD_NONE;
context->clip_enabled = context->line_buffer[8] != '0';
log_info("hfp: clip set, now: %u", context->clip_enabled);
context->ok_pending = 1;
break;
default: default:
break; break;
} }
@ -1315,6 +1353,16 @@ void hfp_ag_incoming_call(void){
hfp_ag_call_sm(HFP_AG_INCOMING_CALL, NULL); hfp_ag_call_sm(HFP_AG_INCOMING_CALL, NULL);
} }
/**
* @brief number is stored.
*/
void hfp_ag_set_clip(uint8_t type, const char * number){
clip_type = type;
// copy and terminate
strncpy(clip_number, number, sizeof(clip_number));
clip_number[sizeof(clip_number)-1] = '\0';
}
void hfp_ag_call_dropped(void){ void hfp_ag_call_dropped(void){
hfp_ag_call_sm(HFP_AG_CALL_DROPPED, NULL); hfp_ag_call_sm(HFP_AG_CALL_DROPPED, NULL);
} }

View File

@ -175,6 +175,11 @@ void hfp_ag_set_use_in_band_ring_tone(int use_in_band_ring_tone);
*/ */
void hfp_ag_incoming_call(void); void hfp_ag_incoming_call(void);
/**
* @brief number is stored.
*/
void hfp_ag_set_clip(uint8_t type, const char * number);
/** /**
* @brief * @brief
*/ */

View File

@ -187,6 +187,7 @@ static int stdin_process(struct data_source *ds){
break; break;
case 'c': case 'c':
printf("Simulate incoming call\n"); printf("Simulate incoming call\n");
hfp_ag_set_clip(129, "1234567");
hfp_ag_incoming_call(); hfp_ag_incoming_call();
break; break;
case 'C': case 'C':
@ -237,6 +238,14 @@ static int stdin_process(struct data_source *ds){
printf("Set battery level to 5\n"); printf("Set battery level to 5\n");
hfp_ag_set_battery_level(5); hfp_ag_set_battery_level(5);
break; break;
case 'j':
printf("Answering call on remote side\n");
hfp_ag_outgoing_call_established();
break;
case 'r':
printf("Disable in-band ring tone\n");
hfp_ag_set_use_in_band_ring_tone(0);
break;
case 'k': case 'k':
printf("Memory 1 cleared\n"); printf("Memory 1 cleared\n");
memory_1_enabled = 0; memory_1_enabled = 0;
@ -253,14 +262,6 @@ static int stdin_process(struct data_source *ds){
printf("Last dialed number set\n"); printf("Last dialed number set\n");
last_number_exists = 1; last_number_exists = 1;
break; break;
case 'j':
printf("Answering call on remote side\n");
hfp_ag_outgoing_call_established();
break;
case 'r':
printf("Disable in-band ring tone\n");
hfp_ag_set_use_in_band_ring_tone(0);
break;
case 'R': case 'R':
printf("Enable in-band ring tone\n"); printf("Enable in-band ring tone\n");
hfp_ag_set_use_in_band_ring_tone(1); hfp_ag_set_use_in_band_ring_tone(1);