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;
}
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){
return HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES;
}

View File

@ -106,6 +106,7 @@ extern "C" {
#define HFP_AVAILABLE_CODECS "+BAC"
#define HFP_INDICATOR "+CIND"
#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_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES "+CHLD"
#define HFP_GENERIC_STATUS_INDICATOR "+BIND"
@ -142,6 +143,7 @@ typedef enum {
HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE,
HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE,
HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES,
HFP_CMD_ENABLE_CLIP,
HFP_CMD_LIST_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
uint8_t negotiated_codec;
// HF -> AG configuration
uint8_t clip_enabled;
// TODO: put these bit flags in a bitmap
uint8_t ok_pending;
// uint8_t send_ok;
@ -424,6 +429,7 @@ typedef struct hfp_connection {
uint8_t run_call_state_machine;
uint8_t change_in_band_ring_tone_setting;
uint8_t ag_ring;
uint8_t ag_send_clip;
timer_source_t hfp_timeout;
} 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_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 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");
}
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){
char buffer[10];
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);
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_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){
hfp_timeout_start(context);
context->ag_ring = 1;
context->ag_send_clip = clip_type && context->clip_enabled;
if (use_in_band_tone()){
context->call_state = HFP_CALL_W4_AUDIO_CONNECTION_FOR_IN_BAND_RING;
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){
context->ag_ring = 0;
context->ag_send_clip = 0;
hfp_timeout_stop(context);
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());
while (linked_list_iterator_has_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);
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;
}
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());
while (linked_list_iterator_has_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);
connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1);
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;
case HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG:
// clear CLIP
clip_type = 0;
switch (hfp_ag_call_state){
case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
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;
case HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF:
// clear CLIP
clip_type = 0;
switch (hfp_ag_call_state){
case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
switch (hfp_ag_callsetup_state){
@ -934,7 +951,9 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
break;
case HFP_AG_TERMINATE_CALL_BY_HF:
switch (hfp_ag_call_state){
// clear CLIP
clip_type = 0;
switch (hfp_ag_call_state){
case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
switch (hfp_ag_callsetup_state){
case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS:
@ -962,7 +981,9 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
break;
case HFP_AG_TERMINATE_CALL_BY_AG:
switch (hfp_ag_call_state){
// clear CLIP
clip_type = 0;
switch (hfp_ag_call_state){
case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
switch (hfp_ag_callsetup_state){
case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS:
@ -984,7 +1005,9 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
}
break;
case HFP_AG_CALL_DROPPED:
switch (hfp_ag_call_state){
// clear CLIP
clip_type = 0;
switch (hfp_ag_call_state){
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_call_state(HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS);
@ -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_transfer_callsetup_state();
break;
case HFP_AG_OUTGOING_CALL_ESTABLISHED:
switch (hfp_ag_call_state){
case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
@ -1110,6 +1134,13 @@ static void hfp_run_for_context(hfp_connection_t *context){
hfp_ag_ring(context->rfcomm_cid);
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);
if (!done){
@ -1125,7 +1156,7 @@ static void hfp_run_for_context(hfp_connection_t *context){
}
if (context->command == HFP_CMD_NONE && !done){
log_info("context->command == HFP_CMD_NONE");
// log_info("context->command == HFP_CMD_NONE");
switch(context->state){
case HFP_W2_DISCONNECT_RFCOMM:
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){
case HFP_CMD_CALL_ANSWERED:
context->command = HFP_CMD_NONE;
printf("HFP: ATA\n");
hfp_ag_call_sm(HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF, context);
break;
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:
context->command = HFP_CMD_NONE;
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:
break;
}
@ -1315,6 +1353,16 @@ void hfp_ag_incoming_call(void){
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){
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);
/**
* @brief number is stored.
*/
void hfp_ag_set_clip(uint8_t type, const char * number);
/**
* @brief
*/

View File

@ -187,6 +187,7 @@ static int stdin_process(struct data_source *ds){
break;
case 'c':
printf("Simulate incoming call\n");
hfp_ag_set_clip(129, "1234567");
hfp_ag_incoming_call();
break;
case 'C':
@ -237,6 +238,14 @@ static int stdin_process(struct data_source *ds){
printf("Set battery level to 5\n");
hfp_ag_set_battery_level(5);
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':
printf("Memory 1 cleared\n");
memory_1_enabled = 0;
@ -253,14 +262,6 @@ static int stdin_process(struct data_source *ds){
printf("Last dialed number set\n");
last_number_exists = 1;
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':
printf("Enable in-band ring tone\n");
hfp_ag_set_use_in_band_ring_tone(1);