mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-04-16 08:42:28 +00:00
Merge branch 'master' into ble-api-cleanup
This commit is contained in:
commit
ce263fc808
@ -689,7 +689,14 @@
|
||||
#define HFP_SUBEVENT_PLACE_CALL_WITH_NUMBER 0x0D
|
||||
#define HFP_SUBEVENT_REDIAL_LAST_NUMBER 0x0E
|
||||
#define HFP_SUBEVENT_ATTACH_NUMBER_TO_VOICE_TAG 0x0F
|
||||
#define HFP_SUBEVENT_TRANSMIT_DTMF_CODES 0x10
|
||||
#define HFP_SUBEVENT_NUMBER_FOR_VOICE_TAG 0x10
|
||||
#define HFP_SUBEVENT_TRANSMIT_DTMF_CODES 0x11
|
||||
#define HFP_SUBEVENT_TRANSMIT_STATUS_OF_CURRENT_CALL 0x12
|
||||
#define HFP_SUBEVENT_CALL_ANSWERED 0x13
|
||||
#define HFP_SUBEVENT_CONFERENCE_CALL 0x14
|
||||
#define HFP_SUBEVENT_RING 0x15
|
||||
#define HFP_SUBEVENT_SPEAKER_VOLUME 0x16
|
||||
#define HFP_SUBEVENT_MICROPHONE_VOLUME 0x17
|
||||
|
||||
// ANCS Client
|
||||
#define ANCS_CLIENT_CONNECTED 0xF0
|
||||
|
@ -101,6 +101,7 @@ static int hfp_generic_status_indicators_nr = 0;
|
||||
static hfp_generic_status_indicator_t hfp_generic_status_indicators[HFP_MAX_NUM_HF_INDICATORS];
|
||||
|
||||
static linked_list_t hfp_connections = NULL;
|
||||
static void parse_sequence(hfp_connection_t * context);
|
||||
|
||||
hfp_generic_status_indicator_t * get_hfp_generic_status_indicators(void){
|
||||
return (hfp_generic_status_indicator_t *) &hfp_generic_status_indicators;
|
||||
@ -272,7 +273,7 @@ void hfp_reset_context_flags(hfp_connection_t * context){
|
||||
context->ok_pending = 0;
|
||||
context->send_error = 0;
|
||||
|
||||
context->keep_separator = 0;
|
||||
context->keep_byte = 0;
|
||||
|
||||
context->change_status_update_for_individual_ag_indicators = 0;
|
||||
context->operator_name_changed = 0;
|
||||
@ -515,12 +516,38 @@ void hfp_handle_hci_event(hfp_callback_t callback, uint8_t packet_type, uint8_t
|
||||
break;
|
||||
|
||||
case HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE:{
|
||||
|
||||
bt_flip_addr(event_addr, &packet[5]);
|
||||
int index = 2;
|
||||
uint8_t status = packet[index++];
|
||||
|
||||
if (status != 0){
|
||||
log_error("(e)SCO Connection is not established, status %u", status);
|
||||
log_error("(e)SCO Connection failed status %u", status);
|
||||
// if outgoing && link_setting != d0 && appropriate error
|
||||
if (status != 0x11 && status != 0x1f) break; // invalid params / unspecified error
|
||||
context = get_hfp_connection_context_for_bd_addr(event_addr);
|
||||
if (!context) break;
|
||||
switch (context->link_setting){
|
||||
case HFP_LINK_SETTINGS_D0:
|
||||
return; // no other option left
|
||||
case HFP_LINK_SETTINGS_D1:
|
||||
// context->link_setting = HFP_LINK_SETTINGS_D0;
|
||||
// break;
|
||||
case HFP_LINK_SETTINGS_S1:
|
||||
// context->link_setting = HFP_LINK_SETTINGS_D1;
|
||||
// break;
|
||||
case HFP_LINK_SETTINGS_S2:
|
||||
case HFP_LINK_SETTINGS_S3:
|
||||
case HFP_LINK_SETTINGS_S4:
|
||||
// context->link_setting = HFP_LINK_SETTINGS_S1;
|
||||
// break;
|
||||
case HFP_LINK_SETTINGS_T1:
|
||||
case HFP_LINK_SETTINGS_T2:
|
||||
// context->link_setting = HFP_LINK_SETTINGS_S3;
|
||||
context->link_setting = HFP_LINK_SETTINGS_D0;
|
||||
break;
|
||||
}
|
||||
context->establish_audio_connection = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -612,7 +639,13 @@ void hfp_handle_hci_event(hfp_callback_t callback, uint8_t packet_type, uint8_t
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
case HCI_EVENT_INQUIRY_RESULT:
|
||||
case HCI_EVENT_INQUIRY_RESULT_WITH_RSSI:
|
||||
case HCI_EVENT_INQUIRY_COMPLETE:
|
||||
case BTSTACK_EVENT_REMOTE_NAME_CACHED:
|
||||
case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE:
|
||||
// forward inquiry events to app - TODO: replace with new event handler architecture
|
||||
(*callback)(packet, size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -621,8 +654,16 @@ void hfp_handle_hci_event(hfp_callback_t callback, uint8_t packet_type, uint8_t
|
||||
static hfp_command_t parse_command(const char * line_buffer, int isHandsFree){
|
||||
int offset = isHandsFree ? 0 : 2;
|
||||
|
||||
if (strncmp(line_buffer+offset, HFP_LIST_CURRENT_CALLS, strlen(HFP_LIST_CURRENT_CALLS)) == 0){
|
||||
return HFP_CMD_LIST_CURRENT_CALLS;
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+offset, HFP_SUBSCRIBER_NUMBER_INFORMATION, strlen(HFP_SUBSCRIBER_NUMBER_INFORMATION)) == 0){
|
||||
return HFP_CMD_GET_SUBSCRIBER_NUMBER_INFORMATION;
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+offset, HFP_PHONE_NUMBER_FOR_VOICE_TAG, strlen(HFP_PHONE_NUMBER_FOR_VOICE_TAG)) == 0){
|
||||
if (isHandsFree) return HFP_CMD_AG_SEND_PHONE_NUMBER;
|
||||
if (isHandsFree) return HFP_CMD_AG_SENT_PHONE_NUMBER;
|
||||
return HFP_CMD_HF_REQUEST_PHONE_NUMBER;
|
||||
}
|
||||
|
||||
@ -655,7 +696,7 @@ static hfp_command_t parse_command(const char * line_buffer, int isHandsFree){
|
||||
return HFP_CMD_CALL_PHONE_NUMBER;
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer, HFP_REDIAL_LAST_NUMBER, strlen(HFP_REDIAL_LAST_NUMBER)) == 0){
|
||||
if (strncmp(line_buffer+offset, HFP_REDIAL_LAST_NUMBER, strlen(HFP_REDIAL_LAST_NUMBER)) == 0){
|
||||
return HFP_CMD_REDIAL_LAST_NUMBER;
|
||||
}
|
||||
|
||||
@ -671,6 +712,10 @@ static hfp_command_t parse_command(const char * line_buffer, int isHandsFree){
|
||||
return HFP_CMD_ERROR;
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+offset, HFP_RING, strlen(HFP_RING)) == 0){
|
||||
return HFP_CMD_RING;
|
||||
}
|
||||
|
||||
if (isHandsFree && strncmp(line_buffer+offset, HFP_OK, strlen(HFP_OK)) == 0){
|
||||
return HFP_CMD_OK;
|
||||
}
|
||||
@ -679,6 +724,20 @@ static hfp_command_t parse_command(const char * line_buffer, int isHandsFree){
|
||||
return HFP_CMD_SUPPORTED_FEATURES;
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+offset, HFP_TRANSFER_HF_INDICATOR_STATUS, strlen(HFP_TRANSFER_HF_INDICATOR_STATUS)) == 0){
|
||||
return HFP_CMD_HF_INDICATOR_STATUS;
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+offset, HFP_RESPONSE_AND_HOLD, strlen(HFP_RESPONSE_AND_HOLD)) == 0){
|
||||
if (strncmp(line_buffer+strlen(HFP_RESPONSE_AND_HOLD)+offset, "?", 1) == 0){
|
||||
return HFP_CMD_RESPONSE_AND_HOLD_QUERY;
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+strlen(HFP_RESPONSE_AND_HOLD)+offset, "=", 1) == 0){
|
||||
return HFP_CMD_RESPONSE_AND_HOLD_COMMAND;
|
||||
}
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+offset, HFP_INDICATOR, strlen(HFP_INDICATOR)) == 0){
|
||||
if (strncmp(line_buffer+strlen(HFP_INDICATOR)+offset, "?", 1) == 0){
|
||||
return HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS;
|
||||
@ -784,13 +843,8 @@ static hfp_command_t parse_command(const char * line_buffer, int isHandsFree){
|
||||
return HFP_CMD_NONE;
|
||||
}
|
||||
|
||||
#if 0
|
||||
uint32_t fromBinary(char *s) {
|
||||
return (uint32_t) strtol(s, NULL, 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void hfp_parser_store_byte(hfp_connection_t * context, uint8_t byte){
|
||||
// printf("hfp_parser_store_byte %c at pos %u\n", (char) byte, context->line_size);
|
||||
// TODO: add limit
|
||||
context->line_buffer[context->line_size++] = byte;
|
||||
context->line_buffer[context->line_size] = 0;
|
||||
@ -808,7 +862,7 @@ static int hfp_parser_is_end_of_header(uint8_t byte){
|
||||
}
|
||||
|
||||
static int hfp_parser_found_separator(hfp_connection_t * context, uint8_t byte){
|
||||
if (context->keep_separator == 1) return 1;
|
||||
if (context->keep_byte == 1) return 1;
|
||||
|
||||
int found_separator = byte == ',' || byte == '\n'|| byte == '\r'||
|
||||
byte == ')' || byte == '(' || byte == ':' ||
|
||||
@ -826,22 +880,20 @@ static void hfp_parser_next_state(hfp_connection_t * context, uint8_t byte){
|
||||
switch (context->parser_state){
|
||||
case HFP_PARSER_CMD_HEADER:
|
||||
context->parser_state = HFP_PARSER_CMD_SEQUENCE;
|
||||
if (context->keep_separator == 1){
|
||||
if (context->keep_byte == 1){
|
||||
hfp_parser_store_byte(context, byte);
|
||||
context->keep_separator = 0;
|
||||
context->keep_byte = 0;
|
||||
}
|
||||
break;
|
||||
case HFP_PARSER_CMD_SEQUENCE:
|
||||
switch (context->command){
|
||||
case HFP_CMD_AG_SENT_PHONE_NUMBER:
|
||||
case HFP_CMD_TRANSFER_AG_INDICATOR_STATUS:
|
||||
case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME:
|
||||
case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT:
|
||||
context->parser_state = HFP_PARSER_SECOND_ITEM;
|
||||
break;
|
||||
case HFP_CMD_RETRIEVE_AG_INDICATORS:
|
||||
context->parser_state = HFP_PARSER_SECOND_ITEM;
|
||||
break;
|
||||
case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS_STATE:
|
||||
case HFP_CMD_HF_INDICATOR_STATUS:
|
||||
context->parser_state = HFP_PARSER_SECOND_ITEM;
|
||||
break;
|
||||
default:
|
||||
@ -862,8 +914,6 @@ static void hfp_parser_next_state(hfp_connection_t * context, uint8_t byte){
|
||||
}
|
||||
|
||||
void hfp_parse(hfp_connection_t * context, uint8_t byte, int isHandsFree){
|
||||
int value;
|
||||
|
||||
// handle ATD<dial_string>;
|
||||
if (strncmp((const char*)context->line_buffer, HFP_CALL_PHONE_NUMBER, strlen(HFP_CALL_PHONE_NUMBER)) == 0){
|
||||
// check for end-of-line or ';'
|
||||
@ -879,11 +929,21 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte, int isHandsFree){
|
||||
|
||||
// TODO: handle space inside word
|
||||
if (byte == ' ' && context->parser_state > HFP_PARSER_CMD_HEADER) return;
|
||||
|
||||
if (byte == ',' && context->command == HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE){
|
||||
if (context->line_size == 0){
|
||||
context->line_buffer[0] = 0;
|
||||
context->ignore_value = 1;
|
||||
parse_sequence(context);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hfp_parser_found_separator(context, byte)){
|
||||
hfp_parser_store_byte(context, byte);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (hfp_parser_is_end_of_line(byte)) {
|
||||
if (hfp_parser_is_buffer_empty(context)){
|
||||
context->parser_state = HFP_PARSER_CMD_HEADER;
|
||||
@ -891,23 +951,27 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte, int isHandsFree){
|
||||
}
|
||||
if (hfp_parser_is_buffer_empty(context)) return;
|
||||
|
||||
|
||||
switch (context->parser_state){
|
||||
case HFP_PARSER_CMD_HEADER: // header
|
||||
if (byte == '='){
|
||||
context->keep_separator = 1;
|
||||
context->keep_byte = 1;
|
||||
hfp_parser_store_byte(context, byte);
|
||||
return;
|
||||
}
|
||||
|
||||
if (byte == '?'){
|
||||
context->keep_separator = 0;
|
||||
context->keep_byte = 0;
|
||||
hfp_parser_store_byte(context, byte);
|
||||
return;
|
||||
}
|
||||
// printf(" parse header 2 %s, keep separator $ %d\n", context->line_buffer, context->keep_separator);
|
||||
if (hfp_parser_is_end_of_header(byte) || context->keep_separator == 1){
|
||||
// printf(" parse header 3 %s, keep separator $ %d\n", context->line_buffer, context->keep_separator);
|
||||
|
||||
if (byte == ','){
|
||||
context->resolve_byte = 1;
|
||||
}
|
||||
|
||||
// printf(" parse header 2 %s, keep separator $ %d\n", context->line_buffer, context->keep_byte);
|
||||
if (hfp_parser_is_end_of_header(byte) || context->keep_byte == 1){
|
||||
// printf(" parse header 3 %s, keep separator $ %d\n", context->line_buffer, context->keep_byte);
|
||||
char * line_buffer = (char *)context->line_buffer;
|
||||
context->command = parse_command(line_buffer, isHandsFree);
|
||||
|
||||
@ -936,135 +1000,17 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte, int isHandsFree){
|
||||
}
|
||||
break;
|
||||
|
||||
case HFP_PARSER_CMD_SEQUENCE: // parse comma separated sequence, ignore breacktes
|
||||
switch (context->command){
|
||||
case HFP_CMD_SET_MICROPHONE_GAIN:
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
context->microphone_gain = value;
|
||||
log_info("hfp parse HFP_CMD_SET_MICROPHONE_GAIN %d\n", value);
|
||||
break;
|
||||
case HFP_CMD_SET_SPEAKER_GAIN:
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
context->speaker_gain = value;
|
||||
log_info("hfp parse HFP_CMD_SET_SPEAKER_GAIN %d\n", value);
|
||||
break;
|
||||
case HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION:
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
context->ag_activate_voice_recognition = value;
|
||||
log_info("hfp parse HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION %d\n", value);
|
||||
break;
|
||||
case HFP_CMD_TURN_OFF_EC_AND_NR:
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
context->ag_echo_and_noise_reduction = value;
|
||||
log_info("hfp parse HFP_CMD_TURN_OFF_EC_AND_NR %d\n", value);
|
||||
break;
|
||||
case HFP_CMD_CHANGE_IN_BAND_RING_TONE_SETTING:
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
context->remote_supported_features = store_bit(context->remote_supported_features, HFP_AGSF_IN_BAND_RING_TONE, value);
|
||||
log_info("hfp parse HFP_CHANGE_IN_BAND_RING_TONE_SETTING %d\n", value);
|
||||
break;
|
||||
case HFP_CMD_HF_CONFIRMED_CODEC:
|
||||
context->codec_confirmed = atoi((char*)context->line_buffer);
|
||||
log_info("hfp parse HFP_CMD_HF_CONFIRMED_CODEC %d\n", context->codec_confirmed);
|
||||
break;
|
||||
case HFP_CMD_AG_SUGGESTED_CODEC:
|
||||
context->suggested_codec = atoi((char*)context->line_buffer);
|
||||
log_info("hfp parse HFP_CMD_AG_SUGGESTED_CODEC %d\n", context->suggested_codec);
|
||||
break;
|
||||
case HFP_CMD_SUPPORTED_FEATURES:
|
||||
context->remote_supported_features = atoi((char*)context->line_buffer);
|
||||
log_info("Parsed supported feature %d\n", context->remote_supported_features);
|
||||
break;
|
||||
case HFP_CMD_AVAILABLE_CODECS:
|
||||
log_info("Parsed codec %s\n", context->line_buffer);
|
||||
context->remote_codecs[context->parser_item_index] = (uint16_t)atoi((char*)context->line_buffer);
|
||||
context->parser_item_index++;
|
||||
context->remote_codecs_nr = context->parser_item_index;
|
||||
break;
|
||||
case HFP_CMD_RETRIEVE_AG_INDICATORS:
|
||||
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;
|
||||
log_info("Indicator %d: %s (", context->ag_indicators_nr+1, context->line_buffer);
|
||||
break;
|
||||
case HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS:
|
||||
log_info("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->parser_item_index++;
|
||||
break;
|
||||
case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE:
|
||||
context->parser_item_index++;
|
||||
if (context->parser_item_index != 4) break;
|
||||
log_info("Parsed Enable indicators: %s\n", context->line_buffer);
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
context->enable_status_update_for_ag_indicators = (uint8_t) value;
|
||||
break;
|
||||
case HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES:
|
||||
log_info("Parsed Support call hold: %s\n", context->line_buffer);
|
||||
if (context->line_size > 2 ) break;
|
||||
strcpy((char *)context->remote_call_services[context->remote_call_services_nr].name, (char *)context->line_buffer);
|
||||
context->remote_call_services_nr++;
|
||||
break;
|
||||
case HFP_CMD_LIST_GENERIC_STATUS_INDICATORS:
|
||||
case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS:
|
||||
log_info("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->parser_item_index++;
|
||||
context->generic_status_indicators_nr = context->parser_item_index;
|
||||
break;
|
||||
case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS_STATE:
|
||||
// HF parses inital AG gen. ind. state
|
||||
log_info("Parsed List generic status indicator %s state: ", context->line_buffer);
|
||||
context->parser_item_index = (uint8_t)atoi((char*)context->line_buffer);
|
||||
break;
|
||||
case HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE:
|
||||
// AG parses new gen. ind. state
|
||||
log_info("Parsed Enable ag indicator state: %s\n", context->line_buffer);
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
if (!context->ag_indicators[context->parser_item_index].mandatory){
|
||||
context->ag_indicators[context->parser_item_index].enabled = value;
|
||||
}
|
||||
context->parser_item_index++;
|
||||
break;
|
||||
case HFP_CMD_TRANSFER_AG_INDICATOR_STATUS:
|
||||
// indicators are indexed starting with 1
|
||||
context->parser_item_index = atoi((char *)&context->line_buffer[0]) - 1;
|
||||
log_info("Parsed status of the AG indicator %d, status ", context->parser_item_index);
|
||||
break;
|
||||
case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME:
|
||||
context->network_operator.mode = atoi((char *)&context->line_buffer[0]);
|
||||
log_info("Parsed network operator mode: %d, ", context->network_operator.mode);
|
||||
break;
|
||||
case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT:
|
||||
if (context->line_buffer[0] == '3'){
|
||||
log_info("Parsed Set network operator format : %s, ", context->line_buffer);
|
||||
break;
|
||||
}
|
||||
// TODO emit ERROR, wrong format
|
||||
log_info("ERROR Set network operator format: index %s not supported\n", context->line_buffer);
|
||||
break;
|
||||
case HFP_CMD_ERROR:
|
||||
break;
|
||||
case HFP_CMD_EXTENDED_AUDIO_GATEWAY_ERROR:
|
||||
context->extended_audio_gateway_error = (uint8_t)atoi((char*)context->line_buffer);
|
||||
break;
|
||||
case HFP_CMD_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR:
|
||||
context->enable_extended_audio_gateway_error_report = (uint8_t)atoi((char*)context->line_buffer);
|
||||
context->ok_pending = 1;
|
||||
context->extended_audio_gateway_error = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
case HFP_PARSER_CMD_SEQUENCE:
|
||||
parse_sequence(context);
|
||||
break;
|
||||
|
||||
case HFP_PARSER_SECOND_ITEM:
|
||||
switch (context->command){
|
||||
case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME:
|
||||
printf("format %s, ", context->line_buffer);
|
||||
log_info("format %s, ", context->line_buffer);
|
||||
context->network_operator.format = atoi((char *)&context->line_buffer[0]);
|
||||
break;
|
||||
case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT:
|
||||
printf("format %s \n", context->line_buffer);
|
||||
log_info("format %s \n", context->line_buffer);
|
||||
context->network_operator.format = atoi((char *)&context->line_buffer[0]);
|
||||
break;
|
||||
case HFP_CMD_LIST_GENERIC_STATUS_INDICATORS:
|
||||
@ -1074,13 +1020,16 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte, int isHandsFree){
|
||||
break;
|
||||
case HFP_CMD_TRANSFER_AG_INDICATOR_STATUS:
|
||||
context->ag_indicators[context->parser_item_index].status = (uint8_t)atoi((char*)context->line_buffer);
|
||||
printf("%d \n", context->ag_indicators[context->parser_item_index].status);
|
||||
log_info("%d \n", context->ag_indicators[context->parser_item_index].status);
|
||||
context->ag_indicators[context->parser_item_index].status_changed = 1;
|
||||
break;
|
||||
case HFP_CMD_RETRIEVE_AG_INDICATORS:
|
||||
context->ag_indicators[context->parser_item_index].min_range = atoi((char *)context->line_buffer);
|
||||
log_info("%s, ", context->line_buffer);
|
||||
break;
|
||||
case HFP_CMD_AG_SENT_PHONE_NUMBER:
|
||||
context->bnip_type = (uint8_t)atoi((char*)context->line_buffer);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -1104,6 +1053,153 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte, int isHandsFree){
|
||||
break;
|
||||
}
|
||||
hfp_parser_next_state(context, byte);
|
||||
|
||||
if (context->resolve_byte && context->command == HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE){
|
||||
context->resolve_byte = 0;
|
||||
context->ignore_value = 1;
|
||||
parse_sequence(context);
|
||||
context->line_buffer[0] = 0;
|
||||
context->line_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_sequence(hfp_connection_t * context){
|
||||
int value;
|
||||
switch (context->command){
|
||||
case HFP_CMD_SET_MICROPHONE_GAIN:
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
context->microphone_gain = value;
|
||||
log_info("hfp parse HFP_CMD_SET_MICROPHONE_GAIN %d\n", value);
|
||||
break;
|
||||
case HFP_CMD_SET_SPEAKER_GAIN:
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
context->speaker_gain = value;
|
||||
log_info("hfp parse HFP_CMD_SET_SPEAKER_GAIN %d\n", value);
|
||||
break;
|
||||
case HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION:
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
context->ag_activate_voice_recognition = value;
|
||||
log_info("hfp parse HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION %d\n", value);
|
||||
break;
|
||||
case HFP_CMD_TURN_OFF_EC_AND_NR:
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
context->ag_echo_and_noise_reduction = value;
|
||||
log_info("hfp parse HFP_CMD_TURN_OFF_EC_AND_NR %d\n", value);
|
||||
break;
|
||||
case HFP_CMD_CHANGE_IN_BAND_RING_TONE_SETTING:
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
context->remote_supported_features = store_bit(context->remote_supported_features, HFP_AGSF_IN_BAND_RING_TONE, value);
|
||||
log_info("hfp parse HFP_CHANGE_IN_BAND_RING_TONE_SETTING %d\n", value);
|
||||
break;
|
||||
case HFP_CMD_HF_CONFIRMED_CODEC:
|
||||
context->codec_confirmed = atoi((char*)context->line_buffer);
|
||||
log_info("hfp parse HFP_CMD_HF_CONFIRMED_CODEC %d\n", context->codec_confirmed);
|
||||
break;
|
||||
case HFP_CMD_AG_SUGGESTED_CODEC:
|
||||
context->suggested_codec = atoi((char*)context->line_buffer);
|
||||
log_info("hfp parse HFP_CMD_AG_SUGGESTED_CODEC %d\n", context->suggested_codec);
|
||||
break;
|
||||
case HFP_CMD_SUPPORTED_FEATURES:
|
||||
context->remote_supported_features = atoi((char*)context->line_buffer);
|
||||
log_info("Parsed supported feature %d\n", context->remote_supported_features);
|
||||
break;
|
||||
case HFP_CMD_AVAILABLE_CODECS:
|
||||
log_info("Parsed codec %s\n", context->line_buffer);
|
||||
context->remote_codecs[context->parser_item_index] = (uint16_t)atoi((char*)context->line_buffer);
|
||||
context->parser_item_index++;
|
||||
context->remote_codecs_nr = context->parser_item_index;
|
||||
break;
|
||||
case HFP_CMD_RETRIEVE_AG_INDICATORS:
|
||||
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;
|
||||
log_info("Indicator %d: %s (", context->ag_indicators_nr+1, context->line_buffer);
|
||||
break;
|
||||
case HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS:
|
||||
log_info("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->parser_item_index++;
|
||||
break;
|
||||
case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE:
|
||||
context->parser_item_index++;
|
||||
if (context->parser_item_index != 4) break;
|
||||
log_info("Parsed Enable indicators: %s\n", context->line_buffer);
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
context->enable_status_update_for_ag_indicators = (uint8_t) value;
|
||||
break;
|
||||
case HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES:
|
||||
log_info("Parsed Support call hold: %s\n", context->line_buffer);
|
||||
if (context->line_size > 2 ) break;
|
||||
strcpy((char *)context->remote_call_services[context->remote_call_services_nr].name, (char *)context->line_buffer);
|
||||
context->remote_call_services_nr++;
|
||||
break;
|
||||
case HFP_CMD_LIST_GENERIC_STATUS_INDICATORS:
|
||||
case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS:
|
||||
log_info("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->parser_item_index++;
|
||||
context->generic_status_indicators_nr = context->parser_item_index;
|
||||
break;
|
||||
case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS_STATE:
|
||||
// HF parses inital AG gen. ind. state
|
||||
log_info("Parsed List generic status indicator %s state: ", context->line_buffer);
|
||||
context->parser_item_index = (uint8_t)atoi((char*)context->line_buffer);
|
||||
break;
|
||||
case HFP_CMD_HF_INDICATOR_STATUS:
|
||||
context->parser_indicator_index = (uint8_t)atoi((char*)context->line_buffer);
|
||||
log_info("Parsed HF indicator index %u", context->parser_indicator_index);
|
||||
break;
|
||||
case HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE:
|
||||
// AG parses new gen. ind. state
|
||||
if (context->ignore_value){
|
||||
context->ignore_value = 0;
|
||||
log_info("Parsed Enable AG indicator pos %u('%s') - unchanged (stays %u)\n", context->parser_item_index,
|
||||
context->ag_indicators[context->parser_item_index].name, context->ag_indicators[context->parser_item_index].enabled);
|
||||
}
|
||||
else if (context->ag_indicators[context->parser_item_index].mandatory){
|
||||
log_info("Parsed Enable AG indicator pos %u('%s') - ignore (mandatory)\n",
|
||||
context->parser_item_index, context->ag_indicators[context->parser_item_index].name);
|
||||
} else {
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
context->ag_indicators[context->parser_item_index].enabled = value;
|
||||
log_info("Parsed Enable AG indicator pos %u('%s'): %u\n", context->parser_item_index,
|
||||
context->ag_indicators[context->parser_item_index].name, value);
|
||||
}
|
||||
context->parser_item_index++;
|
||||
break;
|
||||
case HFP_CMD_TRANSFER_AG_INDICATOR_STATUS:
|
||||
// indicators are indexed starting with 1
|
||||
context->parser_item_index = atoi((char *)&context->line_buffer[0]) - 1;
|
||||
log_info("Parsed status of the AG indicator %d, status ", context->parser_item_index);
|
||||
break;
|
||||
case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME:
|
||||
context->network_operator.mode = atoi((char *)&context->line_buffer[0]);
|
||||
log_info("Parsed network operator mode: %d, ", context->network_operator.mode);
|
||||
break;
|
||||
case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT:
|
||||
if (context->line_buffer[0] == '3'){
|
||||
log_info("Parsed Set network operator format : %s, ", context->line_buffer);
|
||||
break;
|
||||
}
|
||||
// TODO emit ERROR, wrong format
|
||||
log_info("ERROR Set network operator format: index %s not supported\n", context->line_buffer);
|
||||
break;
|
||||
case HFP_CMD_ERROR:
|
||||
break;
|
||||
case HFP_CMD_EXTENDED_AUDIO_GATEWAY_ERROR:
|
||||
context->extended_audio_gateway_error = (uint8_t)atoi((char*)context->line_buffer);
|
||||
break;
|
||||
case HFP_CMD_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR:
|
||||
context->enable_extended_audio_gateway_error_report = (uint8_t)atoi((char*)context->line_buffer);
|
||||
context->ok_pending = 1;
|
||||
context->extended_audio_gateway_error = 0;
|
||||
break;
|
||||
case HFP_CMD_AG_SENT_PHONE_NUMBER:
|
||||
strncpy(context->bnip_number, (char *)context->line_buffer, sizeof(context->bnip_number));
|
||||
context->bnip_number[sizeof(context->bnip_number)-1] = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void hfp_init(uint16_t rfcomm_channel_nr){
|
||||
@ -1171,4 +1267,24 @@ void hfp_release_audio_connection(hfp_connection_t * context){
|
||||
context->release_audio_connection = 1;
|
||||
}
|
||||
|
||||
static const struct link_settings {
|
||||
const uint16_t max_latency;
|
||||
const uint8_t retransmission_effort;
|
||||
const uint16_t packet_types;
|
||||
} hfp_link_settings [] = {
|
||||
{ 0xffff, 0xff, 0x03c1 }, // HFP_LINK_SETTINGS_D0, HV1
|
||||
{ 0xffff, 0xff, 0x03c4 }, // HFP_LINK_SETTINGS_D1, HV3
|
||||
{ 0x0007, 0x01, 0x03c8 }, // HFP_LINK_SETTINGS_S1, EV3
|
||||
{ 0x0007, 0x01, 0x0380 }, // HFP_LINK_SETTINGS_S2, 2-EV3
|
||||
{ 0x000a, 0x01, 0x0380 }, // HFP_LINK_SETTINGS_S3, 2-EV3
|
||||
{ 0x000c, 0x02, 0x0380 }, // HFP_LINK_SETTINGS_S4, 2-EV3
|
||||
{ 0x0008, 0x02, 0x03c8 }, // HFP_LINK_SETTINGS_T1, EV3
|
||||
{ 0x000d, 0x02, 0x0380 } // HFP_LINK_SETTINGS_T2, 2-EV3
|
||||
};
|
||||
|
||||
void hfp_setup_synchronous_connection(hci_con_handle_t handle, hfp_link_setttings_t setting){
|
||||
// all packet types, fixed bandwidth
|
||||
log_info("hfp_setup_synchronous_connection using setting nr %u", setting);
|
||||
hci_send_cmd(&hci_setup_synchronous_connection, handle, 8000, 8000, hfp_link_settings[setting].max_latency,
|
||||
hci_get_sco_voice_setting(), hfp_link_settings[setting].retransmission_effort, hfp_link_settings[setting].packet_types); // all types 0x003f, only 2-ev3 0x380
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ extern "C" {
|
||||
#define HFP_HFSF_VOICE_RECOGNITION_FUNCTION 3
|
||||
#define HFP_HFSF_CODEC_NEGOTIATION 7
|
||||
#define HFP_HFSF_HF_INDICATORS 8
|
||||
#define HFP_HFSF_ESCO 9
|
||||
#define HFP_HFSF_ESCO_S4 9
|
||||
|
||||
/* AG Supported Features:
|
||||
0: Three-way calling
|
||||
@ -94,7 +94,7 @@ extern "C" {
|
||||
#define HFP_AGSF_IN_BAND_RING_TONE 3
|
||||
#define HFP_AGSF_CODEC_NEGOTIATION 9
|
||||
#define HFP_AGSF_HF_INDICATORS 10
|
||||
#define HFP_AGSF_ESCO 11
|
||||
#define HFP_AGSF_ESCO_S4 11
|
||||
|
||||
#define HFP_DEFAULT_HF_SUPPORTED_FEATURES 0x0000
|
||||
#define HFP_DEFAULT_AG_SUPPORTED_FEATURES 0x0009
|
||||
@ -114,6 +114,7 @@ extern "C" {
|
||||
#define HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES "+CHLD"
|
||||
#define HFP_GENERIC_STATUS_INDICATOR "+BIND"
|
||||
#define HFP_TRANSFER_AG_INDICATOR_STATUS "+CIEV" // +CIEV: <index>,<value>
|
||||
#define HFP_TRANSFER_HF_INDICATOR_STATUS "+BIEV" // +BIEC: <index>,<value>
|
||||
#define HFP_QUERY_OPERATOR_SELECTION "+COPS" // +COPS: <mode>,0,<opearator>
|
||||
#define HFP_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR "+CMEE"
|
||||
#define HFP_EXTENDED_AUDIO_GATEWAY_ERROR "+CME ERROR"
|
||||
@ -123,18 +124,20 @@ extern "C" {
|
||||
#define HFP_HANG_UP_CALL "+CHUP"
|
||||
#define HFP_CHANGE_IN_BAND_RING_TONE_SETTING "+BSIR"
|
||||
#define HFP_CALL_PHONE_NUMBER "ATD"
|
||||
#define HFP_REDIAL_LAST_NUMBER "AT+BLDN"
|
||||
#define HFP_REDIAL_LAST_NUMBER "+BLDN"
|
||||
#define HFP_TURN_OFF_EC_AND_NR "+NREC" // EC (Echo CAnceling), NR (Noise Reduction)
|
||||
#define HFP_ACTIVATE_VOICE_RECOGNITION "+BVRA" // EC (Echo CAnceling), NR (Noise Reduction)
|
||||
#define HFP_SET_MICROPHONE_GAIN "+VGM"
|
||||
#define HFP_SET_SPEAKER_GAIN "+VGS"
|
||||
|
||||
#define HFP_PHONE_NUMBER_FOR_VOICE_TAG "+BINP"
|
||||
#define HFP_TRANSMIT_DTMF_CODES "+VTS"
|
||||
|
||||
#define HFP_SUBSCRIBER_NUMBER_INFORMATION "+CNUM"
|
||||
#define HFP_LIST_CURRENT_CALLS "+CLCC"
|
||||
#define HFP_RESPONSE_AND_HOLD "+BTRH"
|
||||
|
||||
#define HFP_OK "OK"
|
||||
#define HFP_ERROR "ERROR"
|
||||
#define HFP_RING "RING"
|
||||
|
||||
// Codecs
|
||||
#define HFP_CODEC_CVSD 0x01
|
||||
@ -145,6 +148,7 @@ typedef enum {
|
||||
HFP_CMD_ERROR,
|
||||
HFP_CMD_UNKNOWN,
|
||||
HFP_CMD_OK,
|
||||
HFP_CMD_RING,
|
||||
HFP_CMD_SUPPORTED_FEATURES,
|
||||
HFP_CMD_AVAILABLE_CODECS,
|
||||
|
||||
@ -183,10 +187,15 @@ typedef enum {
|
||||
HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION,
|
||||
HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION,
|
||||
HFP_CMD_HF_REQUEST_PHONE_NUMBER,
|
||||
HFP_CMD_AG_SEND_PHONE_NUMBER,
|
||||
HFP_CMD_AG_SENT_PHONE_NUMBER,
|
||||
HFP_CMD_TRANSMIT_DTMF_CODES,
|
||||
HFP_CMD_SET_MICROPHONE_GAIN,
|
||||
HFP_CMD_SET_SPEAKER_GAIN
|
||||
HFP_CMD_SET_SPEAKER_GAIN,
|
||||
HFP_CMD_GET_SUBSCRIBER_NUMBER_INFORMATION,
|
||||
HFP_CMD_LIST_CURRENT_CALLS,
|
||||
HFP_CMD_RESPONSE_AND_HOLD_QUERY,
|
||||
HFP_CMD_RESPONSE_AND_HOLD_COMMAND,
|
||||
HFP_CMD_HF_INDICATOR_STATUS
|
||||
} hfp_command_t;
|
||||
|
||||
|
||||
@ -255,9 +264,16 @@ typedef enum {
|
||||
HFP_AG_OUTGOING_CALL_RINGING,
|
||||
HFP_AG_OUTGOING_CALL_ESTABLISHED,
|
||||
HFP_AG_OUTGOING_REDIAL_INITIATED,
|
||||
HFP_AG_HELD_CALL_JOINED_BY_AG,
|
||||
HFP_AG_TERMINATE_CALL_BY_AG,
|
||||
HFP_AG_TERMINATE_CALL_BY_HF,
|
||||
HFP_AG_CALL_DROPPED,
|
||||
HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_AG,
|
||||
HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_AG,
|
||||
HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_AG,
|
||||
HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_HF,
|
||||
HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_HF,
|
||||
HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_HF,
|
||||
} hfp_ag_call_event_t;
|
||||
|
||||
|
||||
@ -325,6 +341,7 @@ typedef enum {
|
||||
HFP_CODECS_W4_AG_COMMON_CODEC,
|
||||
HFP_CODECS_AG_SENT_COMMON_CODEC,
|
||||
HFP_CODECS_AG_RESEND_COMMON_CODEC,
|
||||
HFP_CODECS_HF_CONFIRMED_CODEC,
|
||||
HFP_CODECS_EXCHANGED,
|
||||
HFP_CODECS_ERROR
|
||||
} hfp_codecs_state_t;
|
||||
@ -343,6 +360,58 @@ typedef enum {
|
||||
HFP_CALL_OUTGOING_RINGING
|
||||
} hfp_call_state_t;
|
||||
|
||||
typedef enum{
|
||||
HFP_ENHANCED_CALL_DIR_OUTGOING,
|
||||
HFP_ENHANCED_CALL_DIR_INCOMING
|
||||
} hfp_enhanced_call_dir_t;
|
||||
|
||||
typedef enum{
|
||||
HFP_ENHANCED_CALL_STATUS_ACTIVE,
|
||||
HFP_ENHANCED_CALL_STATUS_HELD,
|
||||
HFP_ENHANCED_CALL_STATUS_OUTGOING_DIALING,
|
||||
HFP_ENHANCED_CALL_STATUS_OUTGOING_ALERTING,
|
||||
HFP_ENHANCED_CALL_STATUS_INCOMING,
|
||||
HFP_ENHANCED_CALL_STATUS_INCOMING_WAITING,
|
||||
HFP_ENHANCED_CALL_STATUS_CALL_HELD_BY_RESPONSE_AND_HOLD
|
||||
} hfp_enhanced_call_status_t;
|
||||
|
||||
typedef enum{
|
||||
HFP_ENHANCED_CALL_MODE_VOICE,
|
||||
HFP_ENHANCED_CALL_MODE_DATA,
|
||||
HFP_ENHANCED_CALL_MODE_FAX
|
||||
} hfp_enhanced_call_mode_t;
|
||||
|
||||
typedef enum{
|
||||
HFP_ENHANCED_CALL_MPTY_NOT_A_CONFERENCE_CALL,
|
||||
HFP_ENHANCED_CALL_MPTY_CONFERENCE_CALL
|
||||
} hfp_enhanced_call_mpty_t;
|
||||
|
||||
typedef enum {
|
||||
HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD = 0,
|
||||
HFP_RESPONSE_AND_HOLD_HELD_INCOMING_ACCEPTED,
|
||||
HFP_RESPONSE_AND_HOLD_HELD_INCOMING_REJECTED
|
||||
} hfp_response_and_hold_state_t;
|
||||
|
||||
typedef enum {
|
||||
HFP_HF_QUERY_OPERATOR_FORMAT_NOT_SET = 0,
|
||||
HFP_HF_QUERY_OPERATOR_SET_FORMAT,
|
||||
HFP_HF_QUERY_OPERATOR_W4_SET_FORMAT_OK,
|
||||
HFP_HF_QUERY_OPERATOR_FORMAT_SET,
|
||||
HFP_HF_QUERY_OPERATOR_SEND_QUERY,
|
||||
HPF_HF_QUERY_OPERATOR_W4_RESULT
|
||||
} hfp_hf_query_operator_state_t;
|
||||
|
||||
typedef enum {
|
||||
HFP_LINK_SETTINGS_D0 = 0,
|
||||
HFP_LINK_SETTINGS_D1,
|
||||
HFP_LINK_SETTINGS_S1,
|
||||
HFP_LINK_SETTINGS_S2,
|
||||
HFP_LINK_SETTINGS_S3,
|
||||
HFP_LINK_SETTINGS_S4,
|
||||
HFP_LINK_SETTINGS_T1,
|
||||
HFP_LINK_SETTINGS_T2
|
||||
} hfp_link_setttings_t;
|
||||
|
||||
typedef enum{
|
||||
HFP_NONE_SM,
|
||||
HFP_SLC_SM,
|
||||
@ -403,6 +472,7 @@ typedef struct hfp_connection {
|
||||
hfp_command_t command;
|
||||
hfp_parser_state_t parser_state;
|
||||
int parser_item_index;
|
||||
int parser_indicator_index;
|
||||
uint8_t line_buffer[HFP_MAX_INDICATOR_DESC_SIZE];
|
||||
int line_size;
|
||||
|
||||
@ -436,7 +506,9 @@ typedef struct hfp_connection {
|
||||
// uint8_t send_ok;
|
||||
uint8_t send_error;
|
||||
|
||||
uint8_t keep_separator;
|
||||
uint8_t keep_byte;
|
||||
uint8_t ignore_value;
|
||||
uint8_t resolve_byte;
|
||||
|
||||
uint8_t change_status_update_for_individual_ag_indicators;
|
||||
uint8_t operator_name_changed;
|
||||
@ -448,14 +520,12 @@ typedef struct hfp_connection {
|
||||
uint8_t suggested_codec;
|
||||
uint8_t codec_confirmed;
|
||||
|
||||
hfp_link_setttings_t link_setting;
|
||||
|
||||
uint8_t establish_audio_connection;
|
||||
uint8_t release_audio_connection;
|
||||
|
||||
uint8_t change_in_band_ring_tone_setting;
|
||||
uint8_t ag_ring;
|
||||
uint8_t ag_send_clip;
|
||||
uint8_t ag_echo_and_noise_reduction;
|
||||
uint8_t ag_activate_voice_recognition;
|
||||
timer_source_t hfp_timeout;
|
||||
|
||||
uint8_t microphone_gain;
|
||||
uint8_t send_microphone_gain;
|
||||
@ -464,7 +534,50 @@ typedef struct hfp_connection {
|
||||
uint8_t send_speaker_gain;
|
||||
|
||||
uint8_t send_phone_number_for_voice_tag;
|
||||
timer_source_t hfp_timeout;
|
||||
uint8_t send_ag_status_indicators;
|
||||
uint8_t send_response_and_hold_active;
|
||||
uint8_t send_response_and_hold_status;
|
||||
|
||||
// AG only
|
||||
uint8_t change_in_band_ring_tone_setting;
|
||||
uint8_t ag_ring;
|
||||
uint8_t ag_send_clip;
|
||||
uint8_t ag_echo_and_noise_reduction;
|
||||
uint8_t ag_activate_voice_recognition;
|
||||
uint8_t send_subscriber_number;
|
||||
uint8_t next_subscriber_number_to_send;
|
||||
|
||||
int send_status_of_current_calls;
|
||||
|
||||
// HF only
|
||||
hfp_hf_query_operator_state_t hf_query_operator_state;
|
||||
uint8_t hf_answer_incoming_call;
|
||||
uint8_t hf_initiate_outgoing_call;
|
||||
uint8_t hf_initiate_memory_dialing;
|
||||
uint8_t hf_initiate_redial_last_number;
|
||||
|
||||
uint8_t hf_send_clip_enable;
|
||||
uint8_t hf_send_chup;
|
||||
uint8_t hf_send_chld_0;
|
||||
uint8_t hf_send_chld_1;
|
||||
uint8_t hf_send_chld_2;
|
||||
uint8_t hf_send_chld_3;
|
||||
uint8_t hf_send_chld_4;
|
||||
char hf_send_dtmf_code;
|
||||
uint8_t hf_send_binp;
|
||||
uint8_t hf_activate_call_waiting_notification;
|
||||
uint8_t hf_deactivate_call_waiting_notification;
|
||||
|
||||
uint8_t hf_activate_calling_line_notification;
|
||||
uint8_t hf_deactivate_calling_line_notification;
|
||||
uint8_t hf_activate_echo_canceling_and_noise_reduction;
|
||||
uint8_t hf_deactivate_echo_canceling_and_noise_reduction;
|
||||
uint8_t hf_activate_voice_recognition_notification;
|
||||
uint8_t hf_deactivate_voice_recognition_notification;
|
||||
|
||||
uint8_t bnip_type; // 0 == not set
|
||||
char bnip_number[25]; //
|
||||
|
||||
} hfp_connection_t;
|
||||
|
||||
// UTILS_START : TODO move to utils
|
||||
@ -498,6 +611,8 @@ void hfp_reset_context_flags(hfp_connection_t * context);
|
||||
|
||||
void hfp_release_audio_connection(hfp_connection_t * context);
|
||||
|
||||
void hfp_setup_synchronous_connection(hci_con_handle_t handle, hfp_link_setttings_t link_settings);
|
||||
|
||||
const char * hfp_hf_feature(int index);
|
||||
const char * hfp_ag_feature(int index);
|
||||
|
||||
|
@ -79,13 +79,21 @@ static hfp_callback_t hfp_callback;
|
||||
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;
|
||||
static hfp_response_and_hold_state_t hfp_ag_response_and_hold_state;
|
||||
static int hfp_ag_response_and_hold_active = 0;
|
||||
|
||||
// CLIP feature
|
||||
static uint8_t clip_type; // 0 == not set
|
||||
static char clip_number[25]; //
|
||||
|
||||
// Subcriber information entries
|
||||
static hfp_phone_number_t * subscriber_numbers = NULL;
|
||||
static int subscriber_numbers_count = 0;
|
||||
|
||||
static void packet_handler(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_ag_setup_audio_connection(hfp_connection_t * connection);
|
||||
static void hfp_ag_hf_start_ringing(hfp_connection_t * context);
|
||||
|
||||
hfp_generic_status_indicator_t * get_hfp_generic_status_indicators();
|
||||
int get_hfp_generic_status_indicators_nr();
|
||||
@ -94,7 +102,6 @@ void set_hfp_ag_indicators(hfp_ag_indicator_t * indicators, int indicator_nr);
|
||||
int get_hfp_ag_indicators_nr(hfp_connection_t * context);
|
||||
hfp_ag_indicator_t * get_hfp_ag_indicators(hfp_connection_t * context);
|
||||
|
||||
|
||||
hfp_ag_indicator_t * get_hfp_ag_indicators(hfp_connection_t * context){
|
||||
// TODO: save only value, and value changed in the context?
|
||||
if (context->ag_indicators_nr != hfp_ag_indicators_nr){
|
||||
@ -216,12 +223,17 @@ static int hfp_ag_send_clip(uint16_t cid){
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
static int hfp_ag_send_phone_number_for_voice_tag_cmd(uint16_t cid){
|
||||
static int hfp_send_subscriber_number_cmd(uint16_t cid, uint8_t type, const char * number){
|
||||
char buffer[50];
|
||||
sprintf(buffer, "\r\n%s:%s\r\n", HFP_PHONE_NUMBER_FOR_VOICE_TAG, clip_number);
|
||||
sprintf(buffer, "\r\n%s: ,\"%s\",%u, , \r\n", HFP_SUBSCRIBER_NUMBER_INFORMATION, number, type);
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
static int hfp_ag_send_phone_number_for_voice_tag_cmd(uint16_t cid){
|
||||
char buffer[50];
|
||||
sprintf(buffer, "\r\n%s: %s\r\n", HFP_PHONE_NUMBER_FOR_VOICE_TAG, clip_number);
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
|
||||
static int hfp_ag_send_call_waiting_notification(uint16_t cid){
|
||||
if (!clip_type){
|
||||
@ -422,6 +434,12 @@ static int hfp_ag_set_microphone_gain_cmd(uint16_t cid, uint8_t gain){
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
static int hfp_ag_set_response_and_hold(uint16_t cid, int state){
|
||||
char buffer[30];
|
||||
sprintf(buffer, "\r\n%s: %d\r\n", HFP_RESPONSE_AND_HOLD, state);
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
|
||||
static uint8_t hfp_ag_suggest_codec(hfp_connection_t *context){
|
||||
int i,j;
|
||||
@ -510,14 +528,33 @@ static int codecs_exchange_state_machine(hfp_connection_t * context){
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hfp_init_link_settings(hfp_connection_t * context){
|
||||
// determine highest possible link setting
|
||||
context->link_setting = HFP_LINK_SETTINGS_D1;
|
||||
if (hci_remote_eSCO_supported(context->con_handle)){
|
||||
context->link_setting = HFP_LINK_SETTINGS_S3;
|
||||
if ((context->remote_supported_features & (1<<HFP_HFSF_ESCO_S4))
|
||||
&& (hfp_supported_features & (1<<HFP_AGSF_ESCO_S4))){
|
||||
context->link_setting = HFP_LINK_SETTINGS_S4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void hfp_ag_slc_established(hfp_connection_t * context){
|
||||
context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
|
||||
hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0);
|
||||
|
||||
hfp_init_link_settings(context);
|
||||
|
||||
// if active call exist, set per-connection state active, too (when audio is on)
|
||||
if (hfp_ag_call_state == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT){
|
||||
context->call_state = HFP_CALL_W4_AUDIO_CONNECTION_FOR_ACTIVE;
|
||||
}
|
||||
// if AG is ringing, also start ringing on the HF
|
||||
if (hfp_ag_call_state == HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS &&
|
||||
hfp_ag_callsetup_state == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS){
|
||||
hfp_ag_hf_start_ringing(context);
|
||||
}
|
||||
}
|
||||
|
||||
static int hfp_ag_run_for_context_service_level_connection(hfp_connection_t * context){
|
||||
@ -576,10 +613,11 @@ static int hfp_ag_run_for_context_service_level_connection(hfp_connection_t * co
|
||||
if (context->state != HFP_W4_RETRIEVE_CAN_HOLD_CALL) break;
|
||||
if (has_hf_indicators_feature(context)){
|
||||
context->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS;
|
||||
} else {
|
||||
hfp_ag_slc_established(context);
|
||||
}
|
||||
hfp_ag_retrieve_can_hold_call_cmd(context->rfcomm_cid);
|
||||
if (!has_hf_indicators_feature(context)){
|
||||
hfp_ag_slc_established(context);
|
||||
}
|
||||
return 1;
|
||||
|
||||
case HFP_CMD_LIST_GENERIC_STATUS_INDICATORS:
|
||||
@ -649,15 +687,14 @@ static int hfp_ag_run_for_context_service_level_connection_queries(hfp_connectio
|
||||
return 1;
|
||||
}
|
||||
case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE:
|
||||
printf("TODO\n");
|
||||
break;
|
||||
hfp_ag_ok(context->rfcomm_cid);
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hfp_ag_run_for_audio_connection(hfp_connection_t * context){
|
||||
if (context->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED ||
|
||||
context->state > HFP_W2_DISCONNECT_SCO) return 0;
|
||||
@ -681,9 +718,8 @@ static int hfp_ag_run_for_audio_connection(hfp_connection_t * context){
|
||||
if (context->establish_audio_connection){
|
||||
context->state = HFP_W4_SCO_CONNECTED;
|
||||
context->establish_audio_connection = 0;
|
||||
hci_send_cmd(&hci_setup_synchronous_connection, context->con_handle, 8000, 8000, 0xFFFF, hci_get_sco_voice_setting(), 0xFF, 0x003F);
|
||||
hfp_setup_synchronous_connection(context->con_handle, context->link_setting);
|
||||
return 1;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -732,13 +768,13 @@ static void hfp_timeout_stop(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);
|
||||
} else {
|
||||
hfp_timeout_start(context);
|
||||
context->ag_ring = 1;
|
||||
context->ag_send_clip = clip_type && context->clip_enabled;
|
||||
context->call_state = HFP_CALL_RINGING;
|
||||
hfp_emit_event(hfp_callback, HFP_SUBEVENT_START_RINGINIG, 0);
|
||||
}
|
||||
@ -894,6 +930,7 @@ static void hfp_ag_trigger_terminate_call(void){
|
||||
if (connection->call_state == HFP_CALL_IDLE) continue;
|
||||
connection->call_state = HFP_CALL_IDLE;
|
||||
connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, call_indicator_index, 1);
|
||||
connection->release_audio_connection = 1;
|
||||
hfp_run_for_context(connection);
|
||||
}
|
||||
hfp_emit_event(hfp_callback, HFP_SUBEVENT_CALL_TERMINATED, 0);
|
||||
@ -947,12 +984,25 @@ static hfp_connection_t * hfp_ag_connection_for_call_state(hfp_call_state_t call
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void hfp_ag_send_response_and_hold_state(void){
|
||||
linked_list_iterator_t it;
|
||||
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);
|
||||
connection->send_response_and_hold_status = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int call_setup_state_machine(hfp_connection_t * connection){
|
||||
int indicator_index;
|
||||
switch (connection->call_state){
|
||||
case HFP_CALL_W4_AUDIO_CONNECTION_FOR_IN_BAND_RING:
|
||||
if (connection->state != HFP_AUDIO_CONNECTION_ESTABLISHED) return 0;
|
||||
// we got event: audio connection established
|
||||
hfp_timeout_start(connection);
|
||||
connection->ag_ring = 1;
|
||||
connection->ag_send_clip = clip_type && connection->clip_enabled;
|
||||
connection->call_state = HFP_CALL_RINGING;
|
||||
connection->call_state = HFP_CALL_RINGING;
|
||||
hfp_emit_event(hfp_callback, HFP_SUBEVENT_START_RINGINIG, 0);
|
||||
break;
|
||||
@ -1024,10 +1074,8 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
|
||||
printf("AG: current call is placed on hold, incoming call gets active\n");
|
||||
hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
|
||||
hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED);
|
||||
// TODO: update AG indicators for all connections
|
||||
// context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1);
|
||||
// context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, callheld_indicator_index, 1);
|
||||
// context->call_state = HFP_CALL_ACTIVE;
|
||||
hfp_ag_transfer_callsetup_state();
|
||||
hfp_ag_transfer_callheld_state();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -1035,6 +1083,25 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case HFP_AG_HELD_CALL_JOINED_BY_AG:
|
||||
switch (hfp_ag_call_state){
|
||||
case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT:
|
||||
switch (hfp_ag_callheld_state){
|
||||
case HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED:
|
||||
printf("AG: joining held call with active call\n");
|
||||
hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_NO_CALLS_HELD);
|
||||
hfp_ag_transfer_callheld_state();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF:
|
||||
// clear CLIP
|
||||
clip_type = 0;
|
||||
@ -1046,6 +1113,7 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
|
||||
hfp_ag_set_call_state(HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT);
|
||||
hfp_ag_hf_accept_call(connection);
|
||||
printf("HF answers call, accept call by GSM\n");
|
||||
hfp_emit_event(hfp_callback, HFP_CMD_CALL_ANSWERED, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -1056,6 +1124,76 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
|
||||
}
|
||||
break;
|
||||
|
||||
case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_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){
|
||||
case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS:
|
||||
hfp_ag_response_and_hold_active = 1;
|
||||
hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD;
|
||||
hfp_ag_send_response_and_hold_state();
|
||||
// as with regualr call
|
||||
hfp_ag_set_call_state(HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT);
|
||||
hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
|
||||
hfp_ag_ag_accept_call();
|
||||
printf("AG response and hold - hold by AG\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_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){
|
||||
case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS:
|
||||
hfp_ag_response_and_hold_active = 1;
|
||||
hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD;
|
||||
hfp_ag_send_response_and_hold_state();
|
||||
// as with regualr call
|
||||
hfp_ag_set_call_state(HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT);
|
||||
hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
|
||||
hfp_ag_hf_accept_call(connection);
|
||||
printf("AG response and hold - hold by HF\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_AG:
|
||||
case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_HF:
|
||||
if (!hfp_ag_response_and_hold_active) break;
|
||||
if (hfp_ag_response_and_hold_state != HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD) break;
|
||||
hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_HELD_INCOMING_ACCEPTED;
|
||||
hfp_ag_send_response_and_hold_state();
|
||||
printf("Held Call accepted and active\n");
|
||||
break;
|
||||
|
||||
case HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_AG:
|
||||
case HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_HF:
|
||||
if (!hfp_ag_response_and_hold_active) break;
|
||||
if (hfp_ag_response_and_hold_state != HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD) break;
|
||||
hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_HELD_INCOMING_REJECTED;
|
||||
hfp_ag_send_response_and_hold_state();
|
||||
// from terminate by ag
|
||||
hfp_ag_set_call_state(HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS);
|
||||
hfp_ag_trigger_terminate_call();
|
||||
break;
|
||||
|
||||
case HFP_AG_TERMINATE_CALL_BY_HF:
|
||||
// clear CLIP
|
||||
clip_type = 0;
|
||||
@ -1131,6 +1269,10 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
|
||||
hfp_ag_transfer_callsetup_state();
|
||||
break;
|
||||
case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT:
|
||||
if (hfp_ag_response_and_hold_active) {
|
||||
hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_HELD_INCOMING_REJECTED;
|
||||
hfp_ag_send_response_and_hold_state();
|
||||
}
|
||||
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);
|
||||
hfp_ag_trigger_terminate_call();
|
||||
@ -1220,6 +1362,7 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connect
|
||||
hfp_ag_transfer_callheld_state();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -1229,6 +1372,11 @@ static void hfp_run_for_context(hfp_connection_t *context){
|
||||
if (!context) return;
|
||||
if (!rfcomm_can_send_packet_now(context->rfcomm_cid)) return;
|
||||
|
||||
if (context->send_status_of_current_calls){
|
||||
hfp_emit_event(hfp_callback, HFP_SUBEVENT_TRANSMIT_STATUS_OF_CURRENT_CALL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (context->command == HFP_CMD_UNKNOWN){
|
||||
context->ok_pending = 0;
|
||||
context->send_error = 0;
|
||||
@ -1237,13 +1385,6 @@ static void hfp_run_for_context(hfp_connection_t *context){
|
||||
return;
|
||||
}
|
||||
|
||||
if (context->ok_pending){
|
||||
context->ok_pending = 0;
|
||||
context->command = HFP_CMD_NONE;
|
||||
hfp_ag_ok(context->rfcomm_cid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (context->send_error){
|
||||
context->send_error = 0;
|
||||
context->command = HFP_CMD_NONE;
|
||||
@ -1251,12 +1392,36 @@ static void hfp_run_for_context(hfp_connection_t *context){
|
||||
return;
|
||||
}
|
||||
|
||||
// note: before update AG indicators and ok_pending
|
||||
if (context->send_response_and_hold_status){
|
||||
context->send_response_and_hold_status = 0;
|
||||
hfp_ag_set_response_and_hold(context->rfcomm_cid, hfp_ag_response_and_hold_state);
|
||||
return;
|
||||
}
|
||||
|
||||
if (context->send_response_and_hold_active){
|
||||
context->send_response_and_hold_active = 0;
|
||||
hfp_ag_set_response_and_hold(context->rfcomm_cid, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (context->ok_pending){
|
||||
context->ok_pending = 0;
|
||||
context->command = HFP_CMD_NONE;
|
||||
hfp_ag_ok(context->rfcomm_cid);
|
||||
return;
|
||||
}
|
||||
|
||||
// update AG indicators
|
||||
if (context->ag_indicators_status_update_bitmap){
|
||||
int i;
|
||||
for (i=0;i<context->ag_indicators_nr;i++){
|
||||
if (get_bit(context->ag_indicators_status_update_bitmap, i)){
|
||||
context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, i, 0);
|
||||
if (!context->enable_status_update_for_ag_indicators) {
|
||||
log_info("+CMER:3,0,0,0 - not sending update for '%s'", hfp_ag_indicators[i].name);
|
||||
break;
|
||||
}
|
||||
hfp_ag_transfer_ag_indicators_status_cmd(context->rfcomm_cid, &hfp_ag_indicators[i]);
|
||||
return;
|
||||
}
|
||||
@ -1285,6 +1450,18 @@ static void hfp_run_for_context(hfp_connection_t *context){
|
||||
return;
|
||||
}
|
||||
|
||||
if (context->send_subscriber_number){
|
||||
if (context->next_subscriber_number_to_send < subscriber_numbers_count){
|
||||
hfp_phone_number_t phone = subscriber_numbers[context->next_subscriber_number_to_send++];
|
||||
hfp_send_subscriber_number_cmd(context->rfcomm_cid, phone.type, phone.number);
|
||||
} else {
|
||||
context->send_subscriber_number = 0;
|
||||
context->next_subscriber_number_to_send = 0;
|
||||
hfp_ag_ok(context->rfcomm_cid);
|
||||
}
|
||||
context->command = HFP_CMD_NONE;
|
||||
}
|
||||
|
||||
if (context->send_microphone_gain){
|
||||
context->send_microphone_gain = 0;
|
||||
context->command = HFP_CMD_NONE;
|
||||
@ -1299,6 +1476,12 @@ static void hfp_run_for_context(hfp_connection_t *context){
|
||||
return;
|
||||
}
|
||||
|
||||
if (context->send_ag_status_indicators){
|
||||
context->send_ag_status_indicators = 0;
|
||||
hfp_ag_retrieve_indicators_cmd(context->rfcomm_cid, context);
|
||||
return;
|
||||
}
|
||||
|
||||
int done = hfp_ag_run_for_context_service_level_connection(context);
|
||||
if (!done){
|
||||
done = hfp_ag_run_for_context_service_level_connection_queries(context);
|
||||
@ -1327,6 +1510,16 @@ static void hfp_run_for_context(hfp_connection_t *context){
|
||||
context->command = HFP_CMD_NONE;
|
||||
}
|
||||
}
|
||||
static hfp_generic_status_indicator_t *get_hf_indicator_by_number(int number){
|
||||
int i;
|
||||
for (i=0;i< get_hfp_generic_status_indicators_nr();i++){
|
||||
hfp_generic_status_indicator_t * indicator = &get_hfp_generic_status_indicators()[i];
|
||||
if (indicator->uuid == number){
|
||||
return indicator;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void hfp_handle_rfcomm_data(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
||||
hfp_connection_t * context = get_hfp_connection_context_for_rfcomm_cid(channel);
|
||||
@ -1335,7 +1528,81 @@ static void hfp_handle_rfcomm_data(uint8_t packet_type, uint16_t channel, uint8_
|
||||
for (pos = 0; pos < size ; pos++){
|
||||
hfp_parse(context, packet[pos], 0);
|
||||
}
|
||||
hfp_generic_status_indicator_t * indicator;
|
||||
int value;
|
||||
switch(context->command){
|
||||
case HFP_CMD_RESPONSE_AND_HOLD_QUERY:
|
||||
if (hfp_ag_response_and_hold_active){
|
||||
context->send_response_and_hold_active = 1;
|
||||
}
|
||||
context->ok_pending = 1;
|
||||
break;
|
||||
case HFP_CMD_RESPONSE_AND_HOLD_COMMAND:
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
printf("HF Response and Hold: %u\n", value);
|
||||
switch(value){
|
||||
case HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD:
|
||||
hfp_ag_call_sm(HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_HF, context);
|
||||
break;
|
||||
case HFP_RESPONSE_AND_HOLD_HELD_INCOMING_ACCEPTED:
|
||||
hfp_ag_call_sm(HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_HF, context);
|
||||
break;
|
||||
case HFP_RESPONSE_AND_HOLD_HELD_INCOMING_REJECTED:
|
||||
hfp_ag_call_sm(HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_HF, context);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
context->ok_pending = 1;
|
||||
break;
|
||||
case HFP_CMD_HF_INDICATOR_STATUS:
|
||||
context->command = HFP_CMD_NONE;
|
||||
// find indicator by assigned number
|
||||
indicator = get_hf_indicator_by_number(context->parser_indicator_index);
|
||||
if (!indicator){
|
||||
context->send_error = 1;
|
||||
break;
|
||||
}
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
switch (indicator->uuid){
|
||||
case 1: // enhanced security
|
||||
if (value > 1) {
|
||||
context->send_error = 1;
|
||||
return;
|
||||
}
|
||||
printf("HF Indicator 'enhanced security' set to %u\n", value);
|
||||
break;
|
||||
case 2: // battery level
|
||||
if (value > 100){
|
||||
context->send_error = 1;
|
||||
return;
|
||||
}
|
||||
printf("HF Indicator 'battery' set to %u\n", value);
|
||||
break;
|
||||
default:
|
||||
printf("HF Indicator unknown set to %u\n", value);
|
||||
break;
|
||||
}
|
||||
context->ok_pending = 1;
|
||||
break;
|
||||
case HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS:
|
||||
// expected by SLC state machine
|
||||
if (context->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) break;
|
||||
context->send_ag_status_indicators = 1;
|
||||
break;
|
||||
case HFP_CMD_LIST_CURRENT_CALLS:
|
||||
context->command = HFP_CMD_NONE;
|
||||
context->send_status_of_current_calls = 1;
|
||||
hfp_emit_event(hfp_callback, HFP_SUBEVENT_TRANSMIT_STATUS_OF_CURRENT_CALL, 0);
|
||||
break;
|
||||
case HFP_CMD_GET_SUBSCRIBER_NUMBER_INFORMATION:
|
||||
if (subscriber_numbers_count == 0){
|
||||
hfp_ag_ok(context->rfcomm_cid);
|
||||
break;
|
||||
}
|
||||
context->next_subscriber_number_to_send = 0;
|
||||
context->send_subscriber_number = 1;
|
||||
break;
|
||||
case HFP_CMD_TRANSMIT_DTMF_CODES:
|
||||
context->command = HFP_CMD_NONE;
|
||||
hfp_emit_string_event(hfp_callback, HFP_SUBEVENT_TRANSMIT_DTMF_CODES, (const char *) &context->line_buffer[0]);
|
||||
@ -1420,6 +1687,7 @@ static void hfp_handle_rfcomm_data(uint8_t packet_type, uint16_t channel, uint8_
|
||||
printf("AG: Join 3-way-call\n");
|
||||
hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_NO_CALLS_HELD);
|
||||
context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, callheld_indicator_index, 1);
|
||||
hfp_emit_event(hfp_callback, HFP_SUBEVENT_CONFERENCE_CALL, 0);
|
||||
}
|
||||
context->call_state = HFP_CALL_ACTIVE;
|
||||
break;
|
||||
@ -1641,6 +1909,10 @@ void hfp_ag_answer_incoming_call(void){
|
||||
hfp_ag_call_sm(HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG, NULL);
|
||||
}
|
||||
|
||||
void hfp_ag_join_held_call(void){
|
||||
hfp_ag_call_sm(HFP_AG_HELD_CALL_JOINED_BY_AG, NULL);
|
||||
}
|
||||
|
||||
void hfp_ag_terminate_call(void){
|
||||
hfp_ag_call_sm(HFP_AG_TERMINATE_CALL_BY_AG, NULL);
|
||||
}
|
||||
@ -1660,15 +1932,34 @@ void hfp_ag_outgoing_call_rejected(void){
|
||||
void hfp_ag_outgoing_call_accepted(void){
|
||||
hfp_ag_call_sm(HFP_AG_OUTGOING_CALL_ACCEPTED, NULL);
|
||||
}
|
||||
|
||||
void hfp_ag_hold_incoming_call(void){
|
||||
hfp_ag_call_sm(HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_AG, NULL);
|
||||
}
|
||||
|
||||
void hfp_ag_accept_held_incoming_call(void) {
|
||||
hfp_ag_call_sm(HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_AG, NULL);
|
||||
}
|
||||
|
||||
void hfp_ag_reject_held_incoming_call(void){
|
||||
hfp_ag_call_sm(HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_AG, NULL);
|
||||
}
|
||||
|
||||
static void hfp_ag_set_ag_indicator(const char * name, int value){
|
||||
int indicator_index = get_ag_indicator_index_for_name(name);
|
||||
if (indicator_index < 0) return;
|
||||
hfp_ag_indicators[indicator_index].status = value;
|
||||
|
||||
|
||||
linked_list_iterator_t it;
|
||||
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->ag_indicators[indicator_index].enabled) {
|
||||
log_info("AG indicator '%s' changed to %u but not enabled", hfp_ag_indicators[indicator_index].name, value);
|
||||
continue;
|
||||
}
|
||||
log_info("AG indicator '%s' changed to %u, request transfer statur", hfp_ag_indicators[indicator_index].name, value);
|
||||
connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, indicator_index, 1);
|
||||
hfp_run_for_context(connection);
|
||||
}
|
||||
@ -1733,6 +2024,7 @@ void hfp_ag_set_microphone_gain(bd_addr_t bd_addr, int gain){
|
||||
connection->microphone_gain = gain;
|
||||
connection->send_microphone_gain = 1;
|
||||
}
|
||||
hfp_run_for_context(connection);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1744,6 +2036,7 @@ void hfp_ag_set_speaker_gain(bd_addr_t bd_addr, int gain){
|
||||
connection->speaker_gain = gain;
|
||||
connection->send_speaker_gain = 1;
|
||||
}
|
||||
hfp_run_for_context(connection);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1765,3 +2058,30 @@ void hfp_ag_send_dtmf_code_done(bd_addr_t bd_addr){
|
||||
connection->ok_pending = 1;
|
||||
}
|
||||
|
||||
void hfp_ag_set_subcriber_number_information(hfp_phone_number_t * numbers, int numbers_count){
|
||||
subscriber_numbers = numbers;
|
||||
subscriber_numbers_count = numbers_count;
|
||||
}
|
||||
|
||||
void hfp_ag_send_current_call_status(bd_addr_t bd_addr, int idx, hfp_enhanced_call_dir_t dir,
|
||||
hfp_enhanced_call_status_t status, hfp_enhanced_call_mode_t mode,
|
||||
hfp_enhanced_call_mpty_t mpty, uint8_t type, const char * number){
|
||||
|
||||
hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
|
||||
|
||||
char buffer[100];
|
||||
int offset = snprintf(buffer, sizeof(buffer), "\r\n%s: %d,%d,%d,%d,%d", HFP_LIST_CURRENT_CALLS, idx, dir, status, mode, mpty);
|
||||
if (number){
|
||||
offset += snprintf(buffer+offset, sizeof(buffer)-offset, ", \"%s\",%u", number, type);
|
||||
}
|
||||
snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n");
|
||||
send_str_over_rfcomm(connection->rfcomm_cid, buffer);
|
||||
}
|
||||
|
||||
|
||||
void hfp_ag_send_current_call_status_done(bd_addr_t bd_addr){
|
||||
hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
|
||||
connection->ok_pending = 1;
|
||||
connection->send_status_of_current_calls = 0;
|
||||
}
|
||||
|
||||
|
@ -54,6 +54,10 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/* API_START */
|
||||
typedef struct {
|
||||
uint8_t type;
|
||||
const char * number;
|
||||
} hfp_phone_number_t;
|
||||
|
||||
/**
|
||||
* @brief Create HFP Audio Gateway (AG) SDP service record.
|
||||
@ -208,7 +212,12 @@ void hfp_ag_call_dropped(void);
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void hfp_ag_answer_incoming_call(void);
|
||||
void hfp_ag_answer_incoming_call(void);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void hfp_ag_join_held_call(void);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
@ -266,6 +275,38 @@ void hfp_ag_reject_phone_number_for_voice_tag(bd_addr_t bd_addr);
|
||||
*/
|
||||
void hfp_ag_send_dtmf_code_done(bd_addr_t bd_addr);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void hfp_ag_set_subcriber_number_information(hfp_phone_number_t * numbers, int numbers_count);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void hfp_ag_send_current_call_status(bd_addr_t bd_addr, int idx, hfp_enhanced_call_dir_t dir,
|
||||
hfp_enhanced_call_status_t status, hfp_enhanced_call_mode_t mode,
|
||||
hfp_enhanced_call_mpty_t mpty, uint8_t type, const char * number);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void hfp_ag_send_current_call_status_done(bd_addr_t bd_addr);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void hfp_ag_hold_incoming_call(void);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void hfp_ag_accept_held_incoming_call(void);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void hfp_ag_reject_held_incoming_call(void);
|
||||
|
||||
/* API_END */
|
||||
|
||||
#if defined __cplusplus
|
||||
|
1011
src/classic/hfp_hf.c
1011
src/classic/hfp_hf.c
File diff suppressed because it is too large
Load Diff
@ -84,7 +84,6 @@ void hfp_hf_register_packet_handler(hfp_callback_t callback);
|
||||
*/
|
||||
void hfp_hf_establish_service_level_connection(bd_addr_t bd_addr);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Release the RFCOMM channel and the audio connection between the HF and the AG.
|
||||
* TODO: trigger release of the audio connection
|
||||
@ -94,12 +93,13 @@ void hfp_hf_release_service_level_connection(bd_addr_t bd_addr);
|
||||
/**
|
||||
* @brief Deactivate/reactivate status update for all indicators in the AG.
|
||||
*/
|
||||
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);
|
||||
void hfp_hf_disable_status_update_for_all_ag_indicators(bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief Deactivate/reactivate status update for the individual indicators in the AG using bitmap.
|
||||
*/
|
||||
void hfp_hf_enable_status_update_for_individual_ag_indicators(bd_addr_t bd_addr, uint32_t indicators_status_bitmap);
|
||||
void hfp_hf_set_status_update_for_individual_ag_indicators(bd_addr_t bd_addr, uint32_t indicators_status_bitmap);
|
||||
|
||||
|
||||
/**
|
||||
@ -136,7 +136,8 @@ void hfp_hf_query_operator_selection(bd_addr_t bd_addr);
|
||||
* - +CME ERROR: 31 - network Timeout.
|
||||
* - +CME ERROR: 32 - network not allowed – Emergency calls only
|
||||
*/
|
||||
void hfp_hf_enable_report_extended_audio_gateway_error_result_code(bd_addr_t bd_addr, uint8_t enable);
|
||||
void hfp_hf_enable_report_extended_audio_gateway_error_result_code(bd_addr_t bd_addr);
|
||||
void hfp_hf_disable_report_extended_audio_gateway_error_result_code(bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
@ -148,6 +149,121 @@ void hfp_hf_establish_audio_connection(bd_addr_t bd_addr);
|
||||
*/
|
||||
void hfp_hf_release_audio_connection(bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void hfp_hf_answer_incoming_call(bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void hfp_hf_reject_call(bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void hfp_hf_user_busy(bd_addr_t addr);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void hfp_hf_end_active_and_accept_other(bd_addr_t addr);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void hfp_hf_swap_calls(bd_addr_t addr);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void hfp_hf_join_held_call(bd_addr_t addr);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void hfp_hf_connect_calls(bd_addr_t addr);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void hfp_hf_terminate_call(bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void hfp_hf_dial_number(bd_addr_t bd_addr, char * number);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void hfp_hf_dial_memory(bd_addr_t bd_addr, char * number);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void hfp_hf_redial_last_number(bd_addr_t bd_addr);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void hfp_hf_activate_call_waiting_notification(bd_addr_t bd_addr);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void hfp_hf_deactivate_call_waiting_notification(bd_addr_t bd_addr);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void hfp_hf_activate_calling_line_notification(bd_addr_t bd_addr);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void hfp_hf_deactivate_calling_line_notification(bd_addr_t bd_addr);
|
||||
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void hfp_hf_activate_echo_canceling_and_noise_reduction(bd_addr_t bd_addr);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void hfp_hf_deactivate_echo_canceling_and_noise_reduction(bd_addr_t bd_addr);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void hfp_hf_activate_voice_recognition_notification(bd_addr_t bd_addr);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void hfp_hf_deactivate_voice_recognition_notification(bd_addr_t bd_addr);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void hfp_hf_set_microphone_gain(bd_addr_t bd_addr, int gain);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void hfp_hf_set_speaker_gain(bd_addr_t bd_addr, int gain);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void hfp_hf_send_dtmf_code(bd_addr_t bd_addr, char code);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void hfp_hf_request_phone_number_for_voice_tag(bd_addr_t addr);
|
||||
|
||||
/* API_END */
|
||||
|
||||
|
27
src/hci.c
27
src/hci.c
@ -1330,6 +1330,10 @@ static void event_handler(uint8_t *packet, int size){
|
||||
}
|
||||
conn->role = HCI_ROLE_SLAVE;
|
||||
conn->state = RECEIVED_CONNECTION_REQUEST;
|
||||
// store info about eSCO
|
||||
if (link_type == 0x02){
|
||||
conn->remote_supported_feature_eSCO = 1;
|
||||
}
|
||||
hci_run();
|
||||
break;
|
||||
|
||||
@ -1403,9 +1407,12 @@ static void event_handler(uint8_t *packet, int size){
|
||||
if (features[6] & (1 << 3)){
|
||||
conn->bonding_flags |= BONDING_REMOTE_SUPPORTS_SSP;
|
||||
}
|
||||
if (features[3] & (1<<7)){
|
||||
conn->remote_supported_feature_eSCO = 1;
|
||||
}
|
||||
}
|
||||
conn->bonding_flags |= BONDING_RECEIVED_REMOTE_FEATURES;
|
||||
log_info("HCI_EVENT_READ_REMOTE_SUPPORTED_FEATURES_COMPLETE, bonding flags %x", conn->bonding_flags);
|
||||
log_info("HCI_EVENT_READ_REMOTE_SUPPORTED_FEATURES_COMPLETE, bonding flags %x, eSCO %u", conn->bonding_flags, conn->remote_supported_feature_eSCO);
|
||||
if (conn->bonding_flags & BONDING_DEDICATED){
|
||||
conn->bonding_flags |= BONDING_SEND_AUTHENTICATE_REQUEST;
|
||||
}
|
||||
@ -2319,13 +2326,20 @@ void hci_run(void){
|
||||
return;
|
||||
|
||||
case RECEIVED_CONNECTION_REQUEST:
|
||||
log_info("sending hci_accept_connection_request");
|
||||
log_info("sending hci_accept_connection_request, remote eSCO %u", connection->remote_supported_feature_eSCO);
|
||||
connection->state = ACCEPTED_CONNECTION_REQUEST;
|
||||
connection->role = HCI_ROLE_SLAVE;
|
||||
if (connection->address_type == BD_ADDR_TYPE_CLASSIC){
|
||||
hci_send_cmd(&hci_accept_connection_request, connection->address, 1);
|
||||
} else {
|
||||
hci_send_cmd(&hci_accept_synchronous_connection, connection->address, 8000, 8000, 0xFFFF, hci_stack->sco_voice_setting, 0xFF, 0x003F);
|
||||
// remote supported feature eSCO is set if link type is eSCO
|
||||
if (connection->remote_supported_feature_eSCO){
|
||||
// eSCO: S4 - max latency == transmission interval = 0x000c == 12 ms,
|
||||
hci_send_cmd(&hci_accept_synchronous_connection, connection->address, 8000, 8000, 0x000c, hci_stack->sco_voice_setting, 0x02, 0x388);
|
||||
} else {
|
||||
// SCO: max latency, retransmission interval: N/A. any packet type
|
||||
hci_send_cmd(&hci_accept_synchronous_connection, connection->address, 8000, 8000, 0xffff, hci_stack->sco_voice_setting, 0xff, 0x003f);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
@ -2889,6 +2903,13 @@ void hci_emit_dedicated_bonding_result(bd_addr_t address, uint8_t status){
|
||||
hci_stack->packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
|
||||
}
|
||||
|
||||
// query if remote side supports eSCO
|
||||
int hci_remote_eSCO_supported(hci_con_handle_t con_handle){
|
||||
hci_connection_t * connection = hci_connection_for_handle(con_handle);
|
||||
if (!connection) return 0;
|
||||
return connection->remote_supported_feature_eSCO;
|
||||
}
|
||||
|
||||
// query if remote side supports SSP
|
||||
int hci_remote_ssp_supported(hci_con_handle_t con_handle){
|
||||
hci_connection_t * connection = hci_connection_for_handle(con_handle);
|
||||
|
@ -373,6 +373,9 @@ typedef struct {
|
||||
//
|
||||
link_key_type_t link_key_type;
|
||||
|
||||
// remote supported features
|
||||
uint8_t remote_supported_feature_eSCO;
|
||||
|
||||
// errands
|
||||
uint32_t authentication_flags;
|
||||
|
||||
@ -710,6 +713,8 @@ void hci_disconnect_security_block(hci_con_handle_t con_handle);
|
||||
// send complete CMD packet
|
||||
int hci_send_cmd_packet(uint8_t *packet, int size);
|
||||
|
||||
// query if remote side supports eSCO
|
||||
int hci_remote_eSCO_supported(hci_con_handle_t con_handle);
|
||||
|
||||
/* API_START */
|
||||
|
||||
|
@ -91,7 +91,7 @@ TEST_GROUP(HFPParser){
|
||||
|
||||
TEST(HFPParser, HFP_AG_SUPPORTED_FEATURES){
|
||||
sprintf(packet, "\r\nAT%s=159\r\n", HFP_SUPPORTED_FEATURES);
|
||||
context.keep_separator = 0;
|
||||
//context.keep_separator = 0;
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos], 0);
|
||||
}
|
||||
@ -167,19 +167,65 @@ TEST(HFPParser, HFP_AG_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE){
|
||||
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], 0);
|
||||
// }
|
||||
TEST(HFPParser, HFP_AG_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE_OPT_VALUES3){
|
||||
set_hfp_ag_indicators((hfp_ag_indicator_t *)&hfp_ag_indicators, hfp_ag_indicators_nr);
|
||||
context.ag_indicators_nr = hfp_ag_indicators_nr;
|
||||
memcpy(context.ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t));
|
||||
|
||||
// CHECK_EQUAL(HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE, context.command);
|
||||
sprintf(packet, "\r\nAT%s=,1,,,,,1\r\n",
|
||||
HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS);
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos], 0);
|
||||
}
|
||||
|
||||
// for (pos = 0; pos < hfp_ag_indicators_nr; pos++){
|
||||
// CHECK_EQUAL(get_hfp_ag_indicators(&context)[pos].enabled, 1);
|
||||
// CHECK_EQUAL(context.ag_indicators[pos].enabled, 1);
|
||||
// }
|
||||
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(&context)[pos].index, hfp_ag_indicators[pos].index);
|
||||
CHECK_EQUAL(get_hfp_ag_indicators(&context)[pos].enabled, hfp_ag_indicators[pos].enabled);
|
||||
CHECK_EQUAL(context.ag_indicators[pos].index, hfp_ag_indicators[pos].index);
|
||||
CHECK_EQUAL(context.ag_indicators[pos].enabled, hfp_ag_indicators[pos].enabled);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HFPParser, HFP_AG_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE_OPT_VALUES2){
|
||||
set_hfp_ag_indicators((hfp_ag_indicator_t *)&hfp_ag_indicators, hfp_ag_indicators_nr);
|
||||
context.ag_indicators_nr = hfp_ag_indicators_nr;
|
||||
memcpy(context.ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t));
|
||||
|
||||
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], 0);
|
||||
}
|
||||
|
||||
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(&context)[pos].enabled, 1);
|
||||
CHECK_EQUAL(context.ag_indicators[pos].enabled, 1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HFPParser, HFP_AG_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE_OPT_VALUES1){
|
||||
set_hfp_ag_indicators((hfp_ag_indicator_t *)&hfp_ag_indicators, hfp_ag_indicators_nr);
|
||||
context.ag_indicators_nr = hfp_ag_indicators_nr;
|
||||
memcpy(context.ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t));
|
||||
|
||||
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], 0);
|
||||
}
|
||||
|
||||
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(&context)[pos].enabled, 1);
|
||||
CHECK_EQUAL(context.ag_indicators[pos].enabled, 1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HFPParser, HFP_AG_HF_QUERY_OPERATOR_SELECTION){
|
||||
|
@ -71,10 +71,18 @@ const uint8_t rfcomm_channel_nr = 1;
|
||||
static bd_addr_t device_addr = {0xD8,0xBb,0x2C,0xDf,0xF1,0x08};
|
||||
|
||||
static uint8_t codecs[2] = {1,2};
|
||||
static uint8_t default_codecs[2] = {1};
|
||||
static uint16_t indicators[1] = {0x01};
|
||||
|
||||
static uint8_t service_level_connection_established = 0;
|
||||
static uint8_t codecs_connection_established = 0;
|
||||
static uint8_t audio_connection_established = 0;
|
||||
static uint8_t start_ringing = 0;
|
||||
static uint8_t stop_ringing = 0;
|
||||
static uint8_t call_termiated = 0;
|
||||
|
||||
static int supported_features_with_codec_negotiation = 438; // 0001 1011 0110
|
||||
static int supported_features_without_codec_negotiation = 310; // 0001 0011 0110
|
||||
|
||||
int expected_rfcomm_command(const char * cmd){
|
||||
char * ag_cmd = (char *)get_rfcomm_payload();
|
||||
@ -143,28 +151,37 @@ void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
|
||||
printf("\n** SLC established **\n\n");
|
||||
service_level_connection_established = 1;
|
||||
codecs_connection_established = 0;
|
||||
audio_connection_established = 0;
|
||||
break;
|
||||
case HFP_SUBEVENT_CODECS_CONNECTION_COMPLETE:
|
||||
printf("\n** CC established **\n\n");
|
||||
codecs_connection_established = 1;
|
||||
audio_connection_established = 0;
|
||||
break;
|
||||
|
||||
case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED:
|
||||
printf("\n** SLC released **\n\n");
|
||||
service_level_connection_established = 0;
|
||||
break;
|
||||
|
||||
case HFP_SUBEVENT_COMPLETE:
|
||||
printf("HFP_SUBEVENT_COMPLETE.\n\n");
|
||||
case HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED:
|
||||
printf("\n** AC established **\n\n");
|
||||
audio_connection_established = 1;
|
||||
break;
|
||||
case HFP_SUBEVENT_AG_INDICATOR_STATUS_CHANGED:
|
||||
printf("AG_INDICATOR_STATUS_CHANGED, AG indicator index: %d, status: %d\n", event[4], event[5]);
|
||||
case HFP_SUBEVENT_AUDIO_CONNECTION_RELEASED:
|
||||
printf("\n** AC released **\n\n");
|
||||
audio_connection_established = 0;
|
||||
break;
|
||||
case HFP_SUBEVENT_NETWORK_OPERATOR_CHANGED:
|
||||
printf("NETWORK_OPERATOR_CHANGED, operator mode: %d, format: %d, name: %s\n", event[4], event[5], (char *) &event[6]);
|
||||
case HFP_SUBEVENT_START_RINGINIG:
|
||||
printf("\n** Start ringing **\n\n");
|
||||
start_ringing = 1;
|
||||
break;
|
||||
case HFP_SUBEVENT_EXTENDED_AUDIO_GATEWAY_ERROR:
|
||||
if (event[4])
|
||||
printf("EXTENDED_AUDIO_GATEWAY_ERROR_REPORT, status : %d\n", event[3]);
|
||||
case HFP_SUBEVENT_STOP_RINGINIG:
|
||||
printf("\n** Stop ringing **\n\n");
|
||||
stop_ringing = 1;
|
||||
start_ringing = 0;
|
||||
break;
|
||||
case HFP_SUBEVENT_CALL_TERMINATED:
|
||||
call_termiated = 1;
|
||||
break;
|
||||
default:
|
||||
printf("event not handled %u\n", event[2]);
|
||||
@ -179,14 +196,22 @@ TEST_GROUP(HFPClient){
|
||||
void setup(void){
|
||||
service_level_connection_established = 0;
|
||||
codecs_connection_established = 0;
|
||||
audio_connection_established = 0;
|
||||
start_ringing = 0;
|
||||
stop_ringing = 0;
|
||||
call_termiated = 0;
|
||||
|
||||
hfp_hf_init(rfcomm_channel_nr, supported_features_with_codec_negotiation, indicators, sizeof(indicators)/sizeof(uint16_t), 1);
|
||||
hfp_hf_set_codecs(codecs, sizeof(codecs));
|
||||
}
|
||||
|
||||
void teardown(void){
|
||||
if (service_level_connection_established){
|
||||
hfp_hf_release_service_level_connection(device_addr);
|
||||
CHECK_EQUAL(service_level_connection_established, 0);
|
||||
}
|
||||
hfp_hf_release_audio_connection(device_addr);
|
||||
hfp_hf_release_service_level_connection(device_addr);
|
||||
|
||||
service_level_connection_established = 0;
|
||||
codecs_connection_established = 0;
|
||||
audio_connection_established = 0;
|
||||
}
|
||||
|
||||
void setup_hfp_service_level_connection(char ** test_steps, int nr_test_steps){
|
||||
@ -202,6 +227,20 @@ TEST_GROUP(HFPClient){
|
||||
|
||||
};
|
||||
|
||||
TEST(HFPClient, HFAudioConnectionEstablishedWithoutCodecNegotiation){
|
||||
hfp_hf_init(rfcomm_channel_nr, supported_features_without_codec_negotiation, indicators, sizeof(indicators)/sizeof(uint16_t), 1);
|
||||
hfp_hf_set_codecs(default_codecs, 1);
|
||||
|
||||
setup_hfp_service_level_connection(hfp_slc_tests()[1].test, hfp_slc_tests()[1].len);
|
||||
CHECK_EQUAL(service_level_connection_established, 1);
|
||||
|
||||
setup_hfp_codecs_connection(default_cc_setup(), default_cc_setup_size());
|
||||
CHECK_EQUAL(codecs_connection_established, 1);
|
||||
|
||||
hfp_hf_establish_audio_connection(device_addr);
|
||||
hfp_hf_release_audio_connection(device_addr);
|
||||
CHECK_EQUAL(audio_connection_established, 0);
|
||||
}
|
||||
|
||||
TEST(HFPClient, HFCodecsConnectionEstablished){
|
||||
for (int i = 0; i < cc_tests_size(); i++){
|
||||
@ -231,9 +270,6 @@ TEST(HFPClient, HFServiceLevelConnectionEstablished){
|
||||
|
||||
|
||||
int main (int argc, const char * argv[]){
|
||||
hfp_hf_init(rfcomm_channel_nr, 438, indicators, sizeof(indicators)/sizeof(uint16_t), 1);
|
||||
hfp_hf_set_codecs(codecs, sizeof(codecs));
|
||||
hfp_hf_register_packet_handler(packet_handler);
|
||||
|
||||
return CommandLineTestRunner::RunAllTests(argc, argv);
|
||||
}
|
||||
|
@ -79,6 +79,15 @@ static uint16_t handle = -1;
|
||||
static int memory_1_enabled = 1;
|
||||
static int last_number_exists = 1;
|
||||
|
||||
static int current_call_index = 0;
|
||||
static hfp_enhanced_call_dir_t current_call_dir;
|
||||
static int current_call_exists_a = 0;
|
||||
static int current_call_exists_b = 0;
|
||||
static hfp_enhanced_call_status_t current_call_status_a;
|
||||
static hfp_enhanced_call_status_t current_call_status_b;
|
||||
static hfp_enhanced_call_mpty_t current_call_mpty = HFP_ENHANCED_CALL_MPTY_NOT_A_CONFERENCE_CALL;
|
||||
|
||||
|
||||
static int ag_indicators_nr = 7;
|
||||
static hfp_ag_indicator_t ag_indicators[] = {
|
||||
// index, name, min range, max range, status, mandatory, enabled, status changed
|
||||
@ -86,8 +95,8 @@ static hfp_ag_indicator_t ag_indicators[] = {
|
||||
{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},
|
||||
{5, "signal", 0, 5, 5, 0, 1, 0},
|
||||
{6, "roam", 0, 1, 0, 0, 1, 0},
|
||||
{7, "callheld", 0, 2, 0, 1, 1, 0}
|
||||
};
|
||||
|
||||
@ -104,6 +113,168 @@ char cmd;
|
||||
// prototypes
|
||||
static void show_usage();
|
||||
|
||||
// GAP INQUIRY
|
||||
|
||||
#define MAX_DEVICES 10
|
||||
enum DEVICE_STATE { REMOTE_NAME_REQUEST, REMOTE_NAME_INQUIRED, REMOTE_NAME_FETCHED };
|
||||
struct device {
|
||||
bd_addr_t address;
|
||||
uint16_t clockOffset;
|
||||
uint32_t classOfDevice;
|
||||
uint8_t pageScanRepetitionMode;
|
||||
uint8_t rssi;
|
||||
enum DEVICE_STATE state;
|
||||
};
|
||||
|
||||
#define INQUIRY_INTERVAL 5
|
||||
struct device devices[MAX_DEVICES];
|
||||
int deviceCount = 0;
|
||||
|
||||
|
||||
enum STATE {INIT, W4_INQUIRY_MODE_COMPLETE, ACTIVE} ;
|
||||
enum STATE state = INIT;
|
||||
|
||||
|
||||
static int getDeviceIndexForAddress( bd_addr_t addr){
|
||||
int j;
|
||||
for (j=0; j< deviceCount; j++){
|
||||
if (BD_ADDR_CMP(addr, devices[j].address) == 0){
|
||||
return j;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void start_scan(void){
|
||||
printf("Starting inquiry scan..\n");
|
||||
hci_send_cmd(&hci_inquiry, HCI_INQUIRY_LAP, INQUIRY_INTERVAL, 0);
|
||||
}
|
||||
|
||||
static int has_more_remote_name_requests(void){
|
||||
int i;
|
||||
for (i=0;i<deviceCount;i++) {
|
||||
if (devices[i].state == REMOTE_NAME_REQUEST) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void do_next_remote_name_request(void){
|
||||
int i;
|
||||
for (i=0;i<deviceCount;i++) {
|
||||
// remote name request
|
||||
if (devices[i].state == REMOTE_NAME_REQUEST){
|
||||
devices[i].state = REMOTE_NAME_INQUIRED;
|
||||
printf("Get remote name of %s...\n", bd_addr_to_str(devices[i].address));
|
||||
hci_send_cmd(&hci_remote_name_request, devices[i].address,
|
||||
devices[i].pageScanRepetitionMode, 0, devices[i].clockOffset | 0x8000);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void continue_remote_names(void){
|
||||
// don't get remote names for testing
|
||||
if (has_more_remote_name_requests()){
|
||||
do_next_remote_name_request();
|
||||
return;
|
||||
}
|
||||
// try to find PTS
|
||||
int i;
|
||||
for (i=0;i<deviceCount;i++){
|
||||
if (memcmp(devices[i].address, device_addr, 6) == 0){
|
||||
printf("Inquiry scan over, successfully found PTS at index %u\nReady to connect to it.\n", i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
printf("Inquiry scan over but PTS not found :(\n");
|
||||
}
|
||||
|
||||
static void inquiry_packet_handler (uint8_t packet_type, uint8_t *packet, uint16_t size){
|
||||
bd_addr_t addr;
|
||||
int i;
|
||||
int numResponses;
|
||||
int index;
|
||||
|
||||
// printf("packet_handler: pt: 0x%02x, packet[0]: 0x%02x\n", packet_type, packet[0]);
|
||||
if (packet_type != HCI_EVENT_PACKET) return;
|
||||
|
||||
uint8_t event = packet[0];
|
||||
|
||||
switch(event){
|
||||
case HCI_EVENT_INQUIRY_RESULT:
|
||||
case HCI_EVENT_INQUIRY_RESULT_WITH_RSSI:{
|
||||
numResponses = packet[2];
|
||||
int offset = 3;
|
||||
for (i=0; i<numResponses && deviceCount < MAX_DEVICES;i++){
|
||||
bt_flip_addr(addr, &packet[offset]);
|
||||
offset += 6;
|
||||
index = getDeviceIndexForAddress(addr);
|
||||
if (index >= 0) continue; // already in our list
|
||||
memcpy(devices[deviceCount].address, addr, 6);
|
||||
|
||||
devices[deviceCount].pageScanRepetitionMode = packet[offset];
|
||||
offset += 1;
|
||||
|
||||
if (event == HCI_EVENT_INQUIRY_RESULT){
|
||||
offset += 2; // Reserved + Reserved
|
||||
devices[deviceCount].classOfDevice = READ_BT_24(packet, offset);
|
||||
offset += 3;
|
||||
devices[deviceCount].clockOffset = READ_BT_16(packet, offset) & 0x7fff;
|
||||
offset += 2;
|
||||
devices[deviceCount].rssi = 0;
|
||||
} else {
|
||||
offset += 1; // Reserved
|
||||
devices[deviceCount].classOfDevice = READ_BT_24(packet, offset);
|
||||
offset += 3;
|
||||
devices[deviceCount].clockOffset = READ_BT_16(packet, offset) & 0x7fff;
|
||||
offset += 2;
|
||||
devices[deviceCount].rssi = packet[offset];
|
||||
offset += 1;
|
||||
}
|
||||
devices[deviceCount].state = REMOTE_NAME_REQUEST;
|
||||
printf("Device #%u found: %s with COD: 0x%06x, pageScan %d, clock offset 0x%04x, rssi 0x%02x\n",
|
||||
deviceCount, bd_addr_to_str(addr),
|
||||
devices[deviceCount].classOfDevice, devices[deviceCount].pageScanRepetitionMode,
|
||||
devices[deviceCount].clockOffset, devices[deviceCount].rssi);
|
||||
deviceCount++;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case HCI_EVENT_INQUIRY_COMPLETE:
|
||||
for (i=0;i<deviceCount;i++) {
|
||||
// retry remote name request
|
||||
if (devices[i].state == REMOTE_NAME_INQUIRED)
|
||||
devices[i].state = REMOTE_NAME_REQUEST;
|
||||
}
|
||||
continue_remote_names();
|
||||
break;
|
||||
|
||||
case BTSTACK_EVENT_REMOTE_NAME_CACHED:
|
||||
bt_flip_addr(addr, &packet[3]);
|
||||
printf("Cached remote name for %s: '%s'\n", bd_addr_to_str(addr), &packet[9]);
|
||||
break;
|
||||
|
||||
case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE:
|
||||
bt_flip_addr(addr, &packet[3]);
|
||||
index = getDeviceIndexForAddress(addr);
|
||||
if (index >= 0) {
|
||||
if (packet[2] == 0) {
|
||||
printf("Name: '%s'\n", &packet[9]);
|
||||
devices[index].state = REMOTE_NAME_FETCHED;
|
||||
} else {
|
||||
printf("Failed to get name: page timeout\n");
|
||||
}
|
||||
}
|
||||
continue_remote_names();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
// GAP INQUIRY END
|
||||
|
||||
// Testig User Interface
|
||||
static void show_usage(void){
|
||||
printf("\n--- Bluetooth HFP Hands-Free (HF) unit Test Console ---\n");
|
||||
@ -155,7 +326,22 @@ static void show_usage(void){
|
||||
printf("n - Disable Voice Regocnition\n");
|
||||
printf("N - Enable Voice Recognition\n");
|
||||
|
||||
printf("o - Set speaker volume to 0 (minimum)\n");
|
||||
printf("O - Set speaker volume to 9 (default)\n");
|
||||
printf("p - Set speaker volume to 12 (higher)\n");
|
||||
printf("P - Set speaker volume to 15 (maximum)\n");
|
||||
|
||||
printf("q - Set microphone gain to 0 (minimum)\n");
|
||||
printf("Q - Set microphone gain to 9 (default)\n");
|
||||
printf("s - Set microphone gain to 12 (higher)\n");
|
||||
printf("S - Set microphone gain to 15 (maximum)\n");
|
||||
|
||||
printf("t - terminate connection\n");
|
||||
printf("u - join held call\n");
|
||||
printf("v - discover nearby HF units\n");
|
||||
printf("w - put incoming call on hold (Response and Hold)\n");
|
||||
printf("x - accept held incoming call (Response and Hold)\n");
|
||||
printf("X - reject held incoming call (Response and Hold)\n");
|
||||
|
||||
printf("---\n");
|
||||
printf("Ctrl-c - exit\n");
|
||||
@ -193,11 +379,17 @@ static int stdin_process(struct data_source *ds){
|
||||
break;
|
||||
case 'c':
|
||||
printf("Simulate incoming call from 1234567\n");
|
||||
current_call_exists_a = 1;
|
||||
current_call_status_a = HFP_ENHANCED_CALL_STATUS_INCOMING;
|
||||
current_call_dir = HFP_ENHANCED_CALL_DIR_INCOMING;
|
||||
hfp_ag_set_clip(129, "1234567");
|
||||
hfp_ag_incoming_call();
|
||||
break;
|
||||
case 'm':
|
||||
printf("Simulate incoming call from 7654321\n");
|
||||
current_call_exists_b = 1;
|
||||
current_call_status_b = HFP_ENHANCED_CALL_STATUS_INCOMING;
|
||||
current_call_dir = HFP_ENHANCED_CALL_DIR_INCOMING;
|
||||
hfp_ag_set_clip(129, "7654321");
|
||||
hfp_ag_incoming_call();
|
||||
break;
|
||||
@ -211,6 +403,12 @@ static int stdin_process(struct data_source *ds){
|
||||
break;
|
||||
case 'e':
|
||||
printf("Answer call on AG\n");
|
||||
if (current_call_status_a == HFP_ENHANCED_CALL_STATUS_INCOMING){
|
||||
current_call_status_a = HFP_ENHANCED_CALL_STATUS_ACTIVE;
|
||||
}
|
||||
if (current_call_status_b == HFP_ENHANCED_CALL_STATUS_INCOMING){
|
||||
current_call_status_b = HFP_ENHANCED_CALL_STATUS_ACTIVE;
|
||||
}
|
||||
hfp_ag_answer_incoming_call();
|
||||
break;
|
||||
case 'E':
|
||||
@ -281,6 +479,38 @@ static int stdin_process(struct data_source *ds){
|
||||
printf("Enable Voice Recognition\n");
|
||||
hfp_ag_activate_voice_recognition(device_addr, 1);
|
||||
break;
|
||||
case 'o':
|
||||
printf("Set speaker gain to 0 (minimum)\n");
|
||||
hfp_ag_set_speaker_gain(device_addr, 0);
|
||||
break;
|
||||
case 'O':
|
||||
printf("Set speaker gain to 9 (default)\n");
|
||||
hfp_ag_set_speaker_gain(device_addr, 9);
|
||||
break;
|
||||
case 'p':
|
||||
printf("Set speaker gain to 12 (higher)\n");
|
||||
hfp_ag_set_speaker_gain(device_addr, 12);
|
||||
break;
|
||||
case 'P':
|
||||
printf("Set speaker gain to 15 (maximum)\n");
|
||||
hfp_ag_set_speaker_gain(device_addr, 15);
|
||||
break;
|
||||
case 'q':
|
||||
printf("Set microphone gain to 0\n");
|
||||
hfp_ag_set_microphone_gain(device_addr, 0);
|
||||
break;
|
||||
case 'Q':
|
||||
printf("Set microphone gain to 9\n");
|
||||
hfp_ag_set_microphone_gain(device_addr, 9);
|
||||
break;
|
||||
case 's':
|
||||
printf("Set microphone gain to 12\n");
|
||||
hfp_ag_set_microphone_gain(device_addr, 12);
|
||||
break;
|
||||
case 'S':
|
||||
printf("Set microphone gain to 15\n");
|
||||
hfp_ag_set_microphone_gain(device_addr, 15);
|
||||
break;
|
||||
case 'R':
|
||||
printf("Enable in-band ring tone\n");
|
||||
hfp_ag_set_use_in_band_ring_tone(1);
|
||||
@ -288,6 +518,27 @@ static int stdin_process(struct data_source *ds){
|
||||
case 't':
|
||||
printf("Terminate HCI connection.\n");
|
||||
gap_disconnect(handle);
|
||||
break;
|
||||
case 'u':
|
||||
printf("Join held call\n");
|
||||
current_call_mpty = HFP_ENHANCED_CALL_MPTY_CONFERENCE_CALL;
|
||||
hfp_ag_join_held_call();
|
||||
break;
|
||||
case 'v':
|
||||
start_scan();
|
||||
break;
|
||||
case 'w':
|
||||
printf("AG: Put incoming call on hold (Response and Hold)\n");
|
||||
hfp_ag_hold_incoming_call();
|
||||
break;
|
||||
case 'x':
|
||||
printf("AG: Accept held incoming call (Response and Hold)\n");
|
||||
hfp_ag_accept_held_incoming_call();
|
||||
break;
|
||||
case 'X':
|
||||
printf("AG: Reject held incoming call (Response and Hold)\n");
|
||||
hfp_ag_reject_held_incoming_call();
|
||||
break;
|
||||
default:
|
||||
show_usage();
|
||||
break;
|
||||
@ -305,8 +556,31 @@ static void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event[0]){
|
||||
case RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE:
|
||||
handle = READ_BT_16(event, 9);
|
||||
printf("RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE received for handle 0x%04x\n", handle);
|
||||
return;
|
||||
|
||||
case HCI_EVENT_INQUIRY_RESULT:
|
||||
case HCI_EVENT_INQUIRY_RESULT_WITH_RSSI:
|
||||
case HCI_EVENT_INQUIRY_COMPLETE:
|
||||
case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE:
|
||||
inquiry_packet_handler(HCI_EVENT_PACKET, event, event_size);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (event[0] != HCI_EVENT_HFP_META) return;
|
||||
if (event[3] && event[2] != HFP_SUBEVENT_PLACE_CALL_WITH_NUMBER){
|
||||
|
||||
if (event[3]
|
||||
&& event[2] != HFP_SUBEVENT_PLACE_CALL_WITH_NUMBER
|
||||
&& event[2] != HFP_SUBEVENT_ATTACH_NUMBER_TO_VOICE_TAG
|
||||
&& event[2] != HFP_SUBEVENT_TRANSMIT_DTMF_CODES
|
||||
&& event[2] != HFP_SUBEVENT_TRANSMIT_STATUS_OF_CURRENT_CALL){
|
||||
printf("ERROR, status: %u\n", event[3]);
|
||||
return;
|
||||
}
|
||||
@ -357,24 +631,64 @@ static void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
hfp_ag_outgoing_call_rejected();
|
||||
}
|
||||
break;
|
||||
|
||||
case HFP_SUBEVENT_ATTACH_NUMBER_TO_VOICE_TAG:
|
||||
printf("\n** Attach number to voice tag. Sending '1234567\n");
|
||||
hfp_ag_send_phone_number_for_voice_tag(device_addr, "1234567");
|
||||
break;
|
||||
case HFP_SUBEVENT_TRANSMIT_DTMF_CODES:
|
||||
printf("\n** Send DTMF Codes: '%s'\n", &event[3]);
|
||||
hfp_ag_send_dtmf_code_done(device_addr);
|
||||
break;
|
||||
case HFP_SUBEVENT_TRANSMIT_STATUS_OF_CURRENT_CALL:
|
||||
if (current_call_index == 0 && current_call_exists_a){
|
||||
hfp_ag_send_current_call_status(device_addr, 1, current_call_dir, current_call_status_a,
|
||||
HFP_ENHANCED_CALL_MODE_VOICE, current_call_mpty, 129, "1234567");
|
||||
current_call_index = 1;
|
||||
break;
|
||||
}
|
||||
if (current_call_index == 1 && current_call_exists_b){
|
||||
hfp_ag_send_current_call_status(device_addr, 2, current_call_dir, current_call_status_b,
|
||||
HFP_ENHANCED_CALL_MODE_VOICE, current_call_mpty, 129, "7654321");
|
||||
current_call_index = 2;
|
||||
break;
|
||||
}
|
||||
hfp_ag_send_current_call_status_done(device_addr);
|
||||
break;
|
||||
case HFP_CMD_CALL_ANSWERED:
|
||||
printf("Call answered by HF\n");
|
||||
if (current_call_status_a == HFP_ENHANCED_CALL_STATUS_INCOMING){
|
||||
current_call_status_a = HFP_ENHANCED_CALL_STATUS_ACTIVE;
|
||||
}
|
||||
if (current_call_status_b == HFP_ENHANCED_CALL_STATUS_INCOMING){
|
||||
current_call_status_b = HFP_ENHANCED_CALL_STATUS_ACTIVE;
|
||||
}
|
||||
break;
|
||||
case HFP_SUBEVENT_CONFERENCE_CALL:
|
||||
current_call_mpty = HFP_ENHANCED_CALL_MPTY_CONFERENCE_CALL;
|
||||
current_call_status_a = HFP_ENHANCED_CALL_STATUS_ACTIVE;
|
||||
current_call_status_b = HFP_ENHANCED_CALL_STATUS_ACTIVE;
|
||||
break;
|
||||
default:
|
||||
// printf("event not handled %u\n", event[2]);
|
||||
printf("Event not handled %u\n", event[2]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static hfp_phone_number_t subscriber_number = {
|
||||
129, "225577"
|
||||
};
|
||||
|
||||
int btstack_main(int argc, const char * argv[]);
|
||||
int btstack_main(int argc, const char * argv[]){
|
||||
// init L2CAP
|
||||
l2cap_init();
|
||||
rfcomm_init();
|
||||
|
||||
hfp_ag_init(rfcomm_channel_nr, 0x3ef | (1<<HFP_AGSF_HF_INDICATORS), codecs, sizeof(codecs),
|
||||
hfp_ag_init(rfcomm_channel_nr, 0x3ef | (1<<HFP_AGSF_HF_INDICATORS) | (1<<HFP_AGSF_ESCO_S4), codecs, sizeof(codecs),
|
||||
ag_indicators, ag_indicators_nr,
|
||||
hf_indicators, hf_indicators_nr,
|
||||
call_hold_services, call_hold_services_nr);
|
||||
|
||||
hfp_ag_set_subcriber_number_information(&subscriber_number, 1);
|
||||
hfp_ag_register_packet_handler(packet_handler);
|
||||
|
||||
// init SDP, create record for SPP and register with SDP
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 BlueKitchen GmbH
|
||||
*
|
||||
@ -76,6 +77,7 @@ static bd_addr_t pts_addr = {0x00,0x1b,0xDC,0x07,0x32,0xEF};
|
||||
static bd_addr_t phone_addr = {0xD8,0xBb,0x2C,0xDf,0xF1,0x08};
|
||||
|
||||
static bd_addr_t device_addr;
|
||||
static uint16_t handle = -1;
|
||||
static uint8_t codecs[] = {HFP_CODEC_CVSD, HFP_CODEC_MSBC};
|
||||
static uint16_t indicators[1] = {0x01};
|
||||
|
||||
@ -88,28 +90,70 @@ static void show_usage();
|
||||
static void show_usage(void){
|
||||
printf("\n--- Bluetooth HFP Hands-Free (HF) unit Test Console ---\n");
|
||||
printf("---\n");
|
||||
printf("y - use PTS module as Audiogateway\n");
|
||||
|
||||
printf("z - use iPhone as Audiogateway\n");
|
||||
|
||||
printf("h - establish HFP connection to device\n");
|
||||
printf("H - release HFP connection to device\n");
|
||||
printf("a - establish SLC connection to device\n");
|
||||
printf("A - release SLC connection to device\n");
|
||||
|
||||
printf("a - establish Audio connection to device\n");
|
||||
printf("A - release Audio connection to device\n");
|
||||
printf("b - establish Audio connection\n");
|
||||
printf("B - release Audio connection\n");
|
||||
|
||||
printf("b - establish AUDIO connection\n");
|
||||
printf("B - release AUDIO connection\n");
|
||||
printf("c - disable registration status update for all AG indicators\n");
|
||||
printf("C - enable registration status update for all AG indicators\n");
|
||||
|
||||
printf("d - enable registration status update\n");
|
||||
printf("D - disable registration status update\n");
|
||||
printf("d - query network operator.\n");
|
||||
printf("D - set HFP AG registration status update for individual indicators\n");
|
||||
|
||||
printf("e - disable reporting of the extended AG error result code\n");
|
||||
printf("E - enable reporting of the extended AG error result code\n");
|
||||
|
||||
printf("e - enable HFP AG registration status update for individual indicators\n");
|
||||
printf("f - answer incoming call\n");
|
||||
printf("F - Hangup call\n");
|
||||
|
||||
printf("g - query network operator name\n");
|
||||
printf("G - reject call\n");
|
||||
|
||||
printf("i - dial 1234567\n");
|
||||
printf("I - dial 7654321\n");
|
||||
|
||||
printf("f - query network operator\n");
|
||||
printf("j - dial #1\n");
|
||||
printf("J - dial #99\n");
|
||||
|
||||
printf("g - enable reporting of the extended AG error result code\n");
|
||||
printf("G - disable reporting of the extended AG error result code\n");
|
||||
printf("k - deactivate call waiting notification\n");
|
||||
printf("K - activate call waiting notification\n");
|
||||
|
||||
printf("l - deactivate calling line notification\n");
|
||||
printf("L - activate calling line notification\n");
|
||||
|
||||
printf("m - deactivate echo canceling and noise reduction\n");
|
||||
printf("M - activate echo canceling and noise reduction\n");
|
||||
|
||||
printf("n - deactivate voice recognition\n");
|
||||
printf("N - activate voice recognition\n");
|
||||
|
||||
printf("o - Set speaker volume to 0 (minimum)\n");
|
||||
printf("O - Set speaker volume to 9 (default)\n");
|
||||
printf("p - Set speaker volume to 12 (higher)\n");
|
||||
printf("P - Set speaker volume to 15 (maximum)\n");
|
||||
|
||||
printf("q - Set microphone gain to 0 (minimum)\n");
|
||||
printf("Q - Set microphone gain to 9 (default)\n");
|
||||
printf("s - Set microphone gain to 12 (higher)\n");
|
||||
printf("S - Set microphone gain to 15 (maximum)\n");
|
||||
|
||||
printf("t - terminate connection\n");
|
||||
|
||||
printf("u - send 'user busy' (Three-Way Call 0)\n");
|
||||
printf("U - end active call and accept other call' (Three-Way Call 1)\n");
|
||||
printf("v - Swap active call and hold/waiting call (Three-Way Call 2)\n");
|
||||
printf("V - Join held call (Three-Way Call 3)\n");
|
||||
printf("w - Connect calls (Three-Way Call 4)\n");
|
||||
printf("W - redial\n");
|
||||
printf("0123456789#*-+ - send DTMF dial tones\n");
|
||||
|
||||
printf("x - request phone number for voice tag\n");
|
||||
|
||||
printf("---\n");
|
||||
printf("Ctrl-c - exit\n");
|
||||
printf("---\n");
|
||||
@ -117,64 +161,184 @@ static void show_usage(void){
|
||||
|
||||
static int stdin_process(struct data_source *ds){
|
||||
read(ds->fd, &cmd, 1);
|
||||
|
||||
if (cmd >= '0' && cmd <= '9'){
|
||||
printf("DTMF Code: %c\n", cmd);
|
||||
hfp_hf_send_dtmf_code(device_addr, cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (cmd){
|
||||
case '#':
|
||||
case '-':
|
||||
case '+':
|
||||
case '*':
|
||||
printf("DTMF Code: %c\n", cmd);
|
||||
hfp_hf_send_dtmf_code(device_addr, cmd);
|
||||
break;
|
||||
case 'a':
|
||||
printf("Establish Audio connection to device with Bluetooth address %s...\n", bd_addr_to_str(device_addr));
|
||||
hfp_hf_establish_audio_connection(device_addr);
|
||||
break;
|
||||
case 'A':
|
||||
printf("Release Audio service level connection.\n");
|
||||
hfp_hf_release_audio_connection(device_addr);
|
||||
break;
|
||||
case 'h':
|
||||
printf("Establish HFP service level connection to device with Bluetooth address %s...\n", bd_addr_to_str(device_addr));
|
||||
printf("Establish Service level connection to device with Bluetooth address %s...\n", bd_addr_to_str(device_addr));
|
||||
hfp_hf_establish_service_level_connection(device_addr);
|
||||
break;
|
||||
case 'H':
|
||||
printf("Release HFP service level connection.\n");
|
||||
case 'A':
|
||||
printf("Release Service level connection.\n");
|
||||
hfp_hf_release_service_level_connection(device_addr);
|
||||
break;
|
||||
case 'b':
|
||||
printf("Establish Audio connection %s...\n", bd_addr_to_str(device_addr));
|
||||
printf("Establish Audio connection to device with Bluetooth address %s...\n", bd_addr_to_str(device_addr));
|
||||
hfp_hf_establish_audio_connection(device_addr);
|
||||
break;
|
||||
case 'B':
|
||||
printf("Release Audio connection.\n");
|
||||
printf("Release Audio service level connection.\n");
|
||||
hfp_hf_release_audio_connection(device_addr);
|
||||
break;
|
||||
case 'd':
|
||||
printf("Enable HFP AG registration status update.\n");
|
||||
hfp_hf_enable_status_update_for_all_ag_indicators(device_addr, 1);
|
||||
case 'C':
|
||||
printf("Enable registration status update for all AG indicators.\n");
|
||||
hfp_hf_enable_status_update_for_all_ag_indicators(device_addr);
|
||||
case 'c':
|
||||
printf("Disable registration status update for all AG indicators.\n");
|
||||
hfp_hf_disable_status_update_for_all_ag_indicators(device_addr);
|
||||
break;
|
||||
case 'D':
|
||||
printf("Disable HFP AG registration status update.\n");
|
||||
hfp_hf_enable_status_update_for_all_ag_indicators(device_addr, 0);
|
||||
printf("Set HFP AG registration status update for individual indicators (0111111).\n");
|
||||
hfp_hf_set_status_update_for_individual_ag_indicators(device_addr, 63);
|
||||
break;
|
||||
case 'e':
|
||||
printf("Enable HFP AG registration status update for individual indicators.\n");
|
||||
hfp_hf_enable_status_update_for_individual_ag_indicators(device_addr, 63);
|
||||
break;
|
||||
case 'f':
|
||||
case 'd':
|
||||
printf("Query network operator.\n");
|
||||
hfp_hf_query_operator_selection(device_addr);
|
||||
break;
|
||||
case 'g':
|
||||
case 'E':
|
||||
printf("Enable reporting of the extended AG error result code.\n");
|
||||
hfp_hf_enable_report_extended_audio_gateway_error_result_code(device_addr, 1);
|
||||
hfp_hf_enable_report_extended_audio_gateway_error_result_code(device_addr);
|
||||
break;
|
||||
case 'e':
|
||||
printf("Disable reporting of the extended AG error result code.\n");
|
||||
hfp_hf_disable_report_extended_audio_gateway_error_result_code(device_addr);
|
||||
break;
|
||||
case 'f':
|
||||
printf("Answer incoming call.\n");
|
||||
hfp_hf_answer_incoming_call(device_addr);
|
||||
break;
|
||||
case 'F':
|
||||
printf("Hangup call.\n");
|
||||
hfp_hf_terminate_call(device_addr);
|
||||
break;
|
||||
case 'G':
|
||||
printf("Disable reporting of the extended AG error result code.\n");
|
||||
hfp_hf_enable_report_extended_audio_gateway_error_result_code(device_addr, 0);
|
||||
printf("Reject call.\n");
|
||||
hfp_hf_reject_call(device_addr);
|
||||
break;
|
||||
case 'g':
|
||||
printf("Query operator.\n");
|
||||
hfp_hf_query_operator_selection(device_addr);
|
||||
break;
|
||||
case 't':
|
||||
printf("Terminate HCI connection.\n");
|
||||
gap_disconnect(handle);
|
||||
break;
|
||||
|
||||
case 'y':
|
||||
memcpy(device_addr, phone_addr, 6);
|
||||
printf("Use iPhone %s as Audiogateway.\n", bd_addr_to_str(device_addr));
|
||||
break;
|
||||
case 'z':
|
||||
memcpy(device_addr, pts_addr, 6);
|
||||
printf("Use PTS module %s as Audiogateway.\n", bd_addr_to_str(device_addr));
|
||||
case 'i':
|
||||
printf("Dial 1234567\n");
|
||||
hfp_hf_dial_number(device_addr, "1234567");
|
||||
break;
|
||||
case 'I':
|
||||
printf("Dial 7654321\n");
|
||||
hfp_hf_dial_number(device_addr, "7654321");
|
||||
break;
|
||||
case 'j':
|
||||
printf("Dial #1\n");
|
||||
hfp_hf_dial_memory(device_addr,"1");
|
||||
break;
|
||||
case 'J':
|
||||
printf("Dial #99\n");
|
||||
hfp_hf_dial_memory(device_addr,"99");
|
||||
break;
|
||||
case 'k':
|
||||
printf("Deactivate call waiting notification\n");
|
||||
hfp_hf_deactivate_call_waiting_notification(device_addr);
|
||||
break;
|
||||
case 'K':
|
||||
printf("Activate call waiting notification\n");
|
||||
hfp_hf_activate_call_waiting_notification(device_addr);
|
||||
break;
|
||||
case 'l':
|
||||
printf("Deactivate calling line notification\n");
|
||||
hfp_hf_deactivate_calling_line_notification(device_addr);
|
||||
break;
|
||||
case 'L':
|
||||
printf("Activate calling line notification\n");
|
||||
hfp_hf_activate_calling_line_notification(device_addr);
|
||||
break;
|
||||
case 'm':
|
||||
printf("Deactivate echo canceling and noise reduction\n");
|
||||
hfp_hf_deactivate_echo_canceling_and_noise_reduction(device_addr);
|
||||
break;
|
||||
case 'M':
|
||||
printf("Activate echo canceling and noise reduction\n");
|
||||
hfp_hf_activate_echo_canceling_and_noise_reduction(device_addr);
|
||||
break;
|
||||
case 'n':
|
||||
printf("Deactivate voice recognition\n");
|
||||
hfp_hf_deactivate_voice_recognition_notification(device_addr);
|
||||
break;
|
||||
case 'N':
|
||||
printf("Activate voice recognition\n");
|
||||
hfp_hf_activate_voice_recognition_notification(device_addr);
|
||||
break;
|
||||
case 'o':
|
||||
printf("Set speaker gain to 0 (minimum)\n");
|
||||
hfp_hf_set_speaker_gain(device_addr, 0);
|
||||
break;
|
||||
case 'O':
|
||||
printf("Set speaker gain to 9 (default)\n");
|
||||
hfp_hf_set_speaker_gain(device_addr, 9);
|
||||
break;
|
||||
case 'p':
|
||||
printf("Set speaker gain to 12 (higher)\n");
|
||||
hfp_hf_set_speaker_gain(device_addr, 12);
|
||||
break;
|
||||
case 'P':
|
||||
printf("Set speaker gain to 15 (maximum)\n");
|
||||
hfp_hf_set_speaker_gain(device_addr, 15);
|
||||
break;
|
||||
case 'q':
|
||||
printf("Set microphone gain to 0\n");
|
||||
hfp_hf_set_microphone_gain(device_addr, 0);
|
||||
break;
|
||||
case 'Q':
|
||||
printf("Set microphone gain to 9\n");
|
||||
hfp_hf_set_microphone_gain(device_addr, 9);
|
||||
break;
|
||||
case 'u':
|
||||
printf("Send 'user busy' (Three-Way Call 0)\n");
|
||||
hfp_hf_user_busy(device_addr);
|
||||
break;
|
||||
case 'U':
|
||||
printf("End active call and accept waiting/held call (Three-Way Call 1)\n");
|
||||
hfp_hf_end_active_and_accept_other(device_addr);
|
||||
break;
|
||||
case 'v':
|
||||
printf("Swap active call and hold/waiting call (Three-Way Call 2)\n");
|
||||
hfp_hf_swap_calls(device_addr);
|
||||
break;
|
||||
case 'V':
|
||||
printf("Join hold call (Three-Way Call 3)\n");
|
||||
hfp_hf_join_held_call(device_addr);
|
||||
break;
|
||||
case 'w':
|
||||
printf("Connect calls (Three-Way Call 4)\n");
|
||||
hfp_hf_connect_calls(device_addr);
|
||||
break;
|
||||
case 'W':
|
||||
printf("Redial\n");
|
||||
hfp_hf_redial_last_number(device_addr);
|
||||
break;
|
||||
case 'x':
|
||||
printf("Request phone number for voice tag\n");
|
||||
hfp_hf_request_phone_number_for_voice_tag(device_addr);
|
||||
break;
|
||||
|
||||
default:
|
||||
show_usage();
|
||||
break;
|
||||
@ -185,8 +349,17 @@ static int stdin_process(struct data_source *ds){
|
||||
|
||||
|
||||
static void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
if (event[0] == RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE){
|
||||
handle = READ_BT_16(event, 9);
|
||||
printf("RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE received for handle 0x%04x\n", handle);
|
||||
return;
|
||||
}
|
||||
if (event[0] != HCI_EVENT_HFP_META) return;
|
||||
if (event[3] && event[2] != HFP_SUBEVENT_EXTENDED_AUDIO_GATEWAY_ERROR){
|
||||
if (event[3]
|
||||
&& event[2] != HFP_SUBEVENT_EXTENDED_AUDIO_GATEWAY_ERROR
|
||||
&& event[2] != HFP_SUBEVENT_NUMBER_FOR_VOICE_TAG
|
||||
&& event[2] != HFP_SUBEVENT_SPEAKER_VOLUME
|
||||
&& event[2] != HFP_SUBEVENT_MICROPHONE_VOLUME){
|
||||
printf("ERROR, status: %u\n", event[3]);
|
||||
return;
|
||||
}
|
||||
@ -197,6 +370,12 @@ static void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED:
|
||||
printf("Service level connection released.\n\n");
|
||||
break;
|
||||
case HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED:
|
||||
printf("\n** Audio connection established **\n");
|
||||
break;
|
||||
case HFP_SUBEVENT_AUDIO_CONNECTION_RELEASED:
|
||||
printf("\n** Audio connection released **\n");
|
||||
break;
|
||||
case HFP_SUBEVENT_COMPLETE:
|
||||
switch (cmd){
|
||||
case 'd':
|
||||
@ -209,7 +388,7 @@ static void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
}
|
||||
break;
|
||||
case HFP_SUBEVENT_AG_INDICATOR_STATUS_CHANGED:
|
||||
printf("AG_INDICATOR_STATUS_CHANGED, AG indicator index: %d, status: %d\n", event[4], event[5]);
|
||||
printf("AG_INDICATOR_STATUS_CHANGED, AG indicator '%s' (index: %d) to: %d\n", (const char*) &event[6], event[4], event[5]);
|
||||
break;
|
||||
case HFP_SUBEVENT_NETWORK_OPERATOR_CHANGED:
|
||||
printf("NETWORK_OPERATOR_CHANGED, operator mode: %d, format: %d, name: %s\n", event[4], event[5], (char *) &event[6]);
|
||||
@ -218,6 +397,18 @@ static void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
if (event[4])
|
||||
printf("EXTENDED_AUDIO_GATEWAY_ERROR_REPORT, status : %d\n", event[3]);
|
||||
break;
|
||||
case HFP_SUBEVENT_RING:
|
||||
printf("** Ring **\n");
|
||||
break;
|
||||
case HFP_SUBEVENT_NUMBER_FOR_VOICE_TAG:
|
||||
printf("Phone number for voice tag: %s\n", (const char *) &event[3]);
|
||||
break;
|
||||
case HFP_SUBEVENT_SPEAKER_VOLUME:
|
||||
printf("Speaker volume: %u\n", event[3]);
|
||||
break;
|
||||
case HFP_SUBEVENT_MICROPHONE_VOLUME:
|
||||
printf("Microphone volume: %u\n", event[3]);
|
||||
break;
|
||||
default:
|
||||
printf("event not handled %u\n", event[2]);
|
||||
break;
|
||||
@ -231,7 +422,7 @@ int btstack_main(int argc, const char * argv[]){
|
||||
rfcomm_init();
|
||||
|
||||
// hfp_hf_init(rfcomm_channel_nr, HFP_DEFAULT_HF_SUPPORTED_FEATURES, codecs, sizeof(codecs), indicators, sizeof(indicators)/sizeof(uint16_t), 1);
|
||||
hfp_hf_init(rfcomm_channel_nr, 438, indicators, sizeof(indicators)/sizeof(uint16_t), 1);
|
||||
hfp_hf_init(rfcomm_channel_nr, 438 | (1<<HFP_HFSF_ESCO_S4) | (1<<HFP_HFSF_EC_NR_FUNCTION), indicators, sizeof(indicators)/sizeof(uint16_t), 1);
|
||||
hfp_hf_set_codecs(codecs, sizeof(codecs));
|
||||
|
||||
hfp_hf_register_packet_handler(packet_handler);
|
||||
@ -242,6 +433,9 @@ int btstack_main(int argc, const char * argv[]){
|
||||
hfp_hf_create_sdp_record((uint8_t *)hfp_service_buffer, 0x10006, rfcomm_channel_nr, hfp_hf_service_name, 0);
|
||||
sdp_register_service((uint8_t *)hfp_service_buffer);
|
||||
|
||||
// pre-select pts
|
||||
memcpy(device_addr, pts_addr, 6);
|
||||
|
||||
// turn on!
|
||||
hci_power_control(HCI_POWER_ON);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user