mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-04-07 16:20:19 +00:00
Merge branch 'master' into ble-api-cleanup
This commit is contained in:
commit
a0ffb263e0
@ -142,10 +142,16 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
|
||||
/* @text In INIT, an inquiry scan is started, and the application transits to
|
||||
* ACTIVE state.
|
||||
*/
|
||||
case INIT:
|
||||
if (packet[2] == HCI_STATE_WORKING) {
|
||||
start_scan();
|
||||
state = ACTIVE;
|
||||
case INIT:
|
||||
switch(event){
|
||||
case BTSTACK_EVENT_STATE:
|
||||
if (packet[2] == HCI_STATE_WORKING){
|
||||
start_scan();
|
||||
state = ACTIVE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -128,9 +128,15 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
|
||||
switch(state){
|
||||
|
||||
case INIT:
|
||||
if (packet[2] == HCI_STATE_WORKING) {
|
||||
hci_send_cmd(&hci_write_inquiry_mode, 0x01); // with RSSI
|
||||
state = W4_INQUIRY_MODE_COMPLETE;
|
||||
switch(event){
|
||||
case BTSTACK_EVENT_STATE:
|
||||
if (packet[2] == HCI_STATE_WORKING){
|
||||
hci_send_cmd(&hci_write_inquiry_mode, 0x01); // with RSSI
|
||||
state = W4_INQUIRY_MODE_COMPLETE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -110,18 +110,6 @@ void hfp_set_callback(hfp_callback_t callback){
|
||||
hfp_callback = callback;
|
||||
}
|
||||
|
||||
hfp_generic_status_indicator_t * get_hfp_generic_status_indicators(void){
|
||||
return (hfp_generic_status_indicator_t *) &hfp_generic_status_indicators;
|
||||
}
|
||||
int get_hfp_generic_status_indicators_nr(void){
|
||||
return hfp_generic_status_indicators_nr;
|
||||
}
|
||||
void set_hfp_generic_status_indicators(hfp_generic_status_indicator_t * indicators, int indicator_nr){
|
||||
if (indicator_nr > HFP_MAX_NUM_HF_INDICATORS) return;
|
||||
hfp_generic_status_indicators_nr = indicator_nr;
|
||||
memcpy(hfp_generic_status_indicators, indicators, indicator_nr * sizeof(hfp_generic_status_indicator_t));
|
||||
}
|
||||
|
||||
const char * hfp_hf_feature(int index){
|
||||
if (index > HFP_HF_FEATURES_SIZE){
|
||||
return hfp_hf_features[HFP_HF_FEATURES_SIZE];
|
||||
@ -147,17 +135,17 @@ int send_str_over_rfcomm(uint16_t cid, char * command){
|
||||
}
|
||||
|
||||
#if 0
|
||||
void hfp_set_codec(hfp_connection_t * context, uint8_t *packet, uint16_t size){
|
||||
void hfp_set_codec(hfp_connection_t * hfp_connection, uint8_t *packet, uint16_t size){
|
||||
// parse available codecs
|
||||
int pos = 0;
|
||||
int i;
|
||||
for (i=0; i<size; i++){
|
||||
pos+=8;
|
||||
if (packet[pos] > context->negotiated_codec){
|
||||
context->negotiated_codec = packet[pos];
|
||||
if (packet[pos] > hfp_connection->negotiated_codec){
|
||||
hfp_connection->negotiated_codec = packet[pos];
|
||||
}
|
||||
}
|
||||
printf("Negotiated Codec 0x%02x\n", context->negotiated_codec);
|
||||
printf("Negotiated Codec 0x%02x\n", hfp_connection->negotiated_codec);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -203,6 +191,15 @@ int join_bitmap(char * buffer, int buffer_size, uint32_t values, int values_nr){
|
||||
return offset;
|
||||
}
|
||||
|
||||
void hfp_emit_simple_event(hfp_callback_t callback, uint8_t event_subtype){
|
||||
if (!callback) return;
|
||||
uint8_t event[3];
|
||||
event[0] = HCI_EVENT_HFP_META;
|
||||
event[1] = sizeof(event) - 2;
|
||||
event[2] = event_subtype;
|
||||
(*callback)(event, sizeof(event));
|
||||
}
|
||||
|
||||
void hfp_emit_event(hfp_callback_t callback, uint8_t event_subtype, uint8_t value){
|
||||
if (!callback) return;
|
||||
uint8_t event[4];
|
||||
@ -244,9 +241,9 @@ hfp_connection_t * get_hfp_connection_context_for_rfcomm_cid(uint16_t cid){
|
||||
btstack_linked_list_iterator_t it;
|
||||
btstack_linked_list_iterator_init(&it, hfp_get_connections());
|
||||
while (btstack_linked_list_iterator_has_next(&it)){
|
||||
hfp_connection_t * connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it);
|
||||
if (connection->rfcomm_cid == cid){
|
||||
return connection;
|
||||
hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it);
|
||||
if (hfp_connection->rfcomm_cid == cid){
|
||||
return hfp_connection;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
@ -256,9 +253,9 @@ hfp_connection_t * get_hfp_connection_context_for_bd_addr(bd_addr_t bd_addr){
|
||||
btstack_linked_list_iterator_t it;
|
||||
btstack_linked_list_iterator_init(&it, hfp_get_connections());
|
||||
while (btstack_linked_list_iterator_has_next(&it)){
|
||||
hfp_connection_t * connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it);
|
||||
if (memcmp(connection->remote_addr, bd_addr, 6) == 0) {
|
||||
return connection;
|
||||
hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it);
|
||||
if (memcmp(hfp_connection->remote_addr, bd_addr, 6) == 0) {
|
||||
return hfp_connection;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
@ -268,69 +265,68 @@ hfp_connection_t * get_hfp_connection_context_for_sco_handle(uint16_t handle){
|
||||
btstack_linked_list_iterator_t it;
|
||||
btstack_linked_list_iterator_init(&it, hfp_get_connections());
|
||||
while (btstack_linked_list_iterator_has_next(&it)){
|
||||
hfp_connection_t * connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it);
|
||||
if (connection->sco_handle == handle){
|
||||
return connection;
|
||||
hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it);
|
||||
if (hfp_connection->sco_handle == handle){
|
||||
return hfp_connection;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void hfp_reset_context_flags(hfp_connection_t * context){
|
||||
if (!context) return;
|
||||
context->ok_pending = 0;
|
||||
context->send_error = 0;
|
||||
void hfp_reset_context_flags(hfp_connection_t * hfp_connection){
|
||||
if (!hfp_connection) return;
|
||||
hfp_connection->ok_pending = 0;
|
||||
hfp_connection->send_error = 0;
|
||||
|
||||
context->keep_byte = 0;
|
||||
hfp_connection->keep_byte = 0;
|
||||
|
||||
context->change_status_update_for_individual_ag_indicators = 0;
|
||||
context->operator_name_changed = 0;
|
||||
hfp_connection->change_status_update_for_individual_ag_indicators = 0;
|
||||
hfp_connection->operator_name_changed = 0;
|
||||
|
||||
context->enable_extended_audio_gateway_error_report = 0;
|
||||
context->extended_audio_gateway_error = 0;
|
||||
hfp_connection->enable_extended_audio_gateway_error_report = 0;
|
||||
hfp_connection->extended_audio_gateway_error = 0;
|
||||
|
||||
// establish codecs connection
|
||||
context->suggested_codec = 0;
|
||||
context->negotiated_codec = 0;
|
||||
context->codec_confirmed = 0;
|
||||
// establish codecs hfp_connection
|
||||
hfp_connection->suggested_codec = 0;
|
||||
hfp_connection->negotiated_codec = 0;
|
||||
hfp_connection->codec_confirmed = 0;
|
||||
|
||||
context->establish_audio_connection = 0;
|
||||
hfp_connection->establish_audio_connection = 0;
|
||||
hfp_connection->call_waiting_notification_enabled = 0;
|
||||
hfp_connection->command = HFP_CMD_NONE;
|
||||
hfp_connection->enable_status_update_for_ag_indicators = 0xFF;
|
||||
}
|
||||
|
||||
static hfp_connection_t * create_hfp_connection_context(){
|
||||
hfp_connection_t * context = btstack_memory_hfp_connection_get();
|
||||
if (!context) return NULL;
|
||||
hfp_connection_t * hfp_connection = btstack_memory_hfp_connection_get();
|
||||
if (!hfp_connection) return NULL;
|
||||
// init state
|
||||
memset(context,0, sizeof(hfp_connection_t));
|
||||
memset(hfp_connection,0, sizeof(hfp_connection_t));
|
||||
|
||||
context->state = HFP_IDLE;
|
||||
context->call_state = HFP_CALL_IDLE;
|
||||
context->codecs_state = HFP_CODECS_IDLE;
|
||||
hfp_connection->state = HFP_IDLE;
|
||||
hfp_connection->call_state = HFP_CALL_IDLE;
|
||||
hfp_connection->codecs_state = HFP_CODECS_IDLE;
|
||||
|
||||
context->parser_state = HFP_PARSER_CMD_HEADER;
|
||||
context->command = HFP_CMD_NONE;
|
||||
context->negotiated_codec = 0;
|
||||
hfp_connection->parser_state = HFP_PARSER_CMD_HEADER;
|
||||
hfp_connection->command = HFP_CMD_NONE;
|
||||
|
||||
context->enable_status_update_for_ag_indicators = 0xFF;
|
||||
hfp_reset_context_flags(hfp_connection);
|
||||
|
||||
context->generic_status_indicators_nr = hfp_generic_status_indicators_nr;
|
||||
memcpy(context->generic_status_indicators, hfp_generic_status_indicators, hfp_generic_status_indicators_nr * sizeof(hfp_generic_status_indicator_t));
|
||||
|
||||
btstack_linked_list_add(&hfp_connections, (btstack_linked_item_t*)context);
|
||||
return context;
|
||||
btstack_linked_list_add(&hfp_connections, (linked_item_t*)hfp_connection);
|
||||
return hfp_connection;
|
||||
}
|
||||
|
||||
static void remove_hfp_connection_context(hfp_connection_t * context){
|
||||
btstack_linked_list_remove(&hfp_connections, (btstack_linked_item_t*)context);
|
||||
static void remove_hfp_connection_context(hfp_connection_t * hfp_connection){
|
||||
btstack_linked_list_remove(&hfp_connections, (btstack_linked_item_t*) hfp_connection);
|
||||
}
|
||||
|
||||
static hfp_connection_t * provide_hfp_connection_context_for_bd_addr(bd_addr_t bd_addr){
|
||||
hfp_connection_t * context = get_hfp_connection_context_for_bd_addr(bd_addr);
|
||||
if (context) return context;
|
||||
context = create_hfp_connection_context();
|
||||
printf("created context for address %s\n", bd_addr_to_str(bd_addr));
|
||||
memcpy(context->remote_addr, bd_addr, 6);
|
||||
return context;
|
||||
hfp_connection_t * hfp_connection = get_hfp_connection_context_for_bd_addr(bd_addr);
|
||||
if (hfp_connection) return hfp_connection;
|
||||
hfp_connection = create_hfp_connection_context();
|
||||
printf("created hfp_connection for address %s\n", bd_addr_to_str(bd_addr));
|
||||
memcpy(hfp_connection->remote_addr, bd_addr, 6);
|
||||
return hfp_connection;
|
||||
}
|
||||
|
||||
/* @param network.
|
||||
@ -426,24 +422,24 @@ static void handle_hci_event(uint8_t packet_type, uint16_t channel, uint8_t *pac
|
||||
}
|
||||
|
||||
static void handle_query_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
||||
hfp_connection_t * connection = connection_doing_sdp_query;
|
||||
hfp_connection_t * hfp_connection = connection_doing_sdp_query;
|
||||
|
||||
if ( connection->state != HFP_W4_SDP_EVENT_QUERY_COMPLETE) return;
|
||||
if ( hfp_connection->state != HFP_W4_SDP_EVENT_QUERY_COMPLETE) return;
|
||||
|
||||
switch (hci_event_packet_get_type(packet)){
|
||||
case SDP_EVENT_QUERY_RFCOMM_SERVICE:
|
||||
if (!connection) {
|
||||
if (!hfp_connection) {
|
||||
log_error("handle_query_rfcomm_event alloc connection for RFCOMM port %u failed", sdp_event_query_rfcomm_service_get_rfcomm_channel(packet));
|
||||
return;
|
||||
}
|
||||
connection->rfcomm_channel_nr = sdp_event_query_rfcomm_service_get_rfcomm_channel(packet);
|
||||
hfp_connection->rfcomm_channel_nr = sdp_event_query_rfcomm_service_get_rfcomm_channel(packet);
|
||||
break;
|
||||
case SDP_EVENT_QUERY_COMPLETE:
|
||||
connection_doing_sdp_query = NULL;
|
||||
if (connection->rfcomm_channel_nr > 0){
|
||||
connection->state = HFP_W4_RFCOMM_CONNECTED;
|
||||
log_info("HFP: SDP_EVENT_QUERY_COMPLETE context %p, addr %s, state %d", connection, bd_addr_to_str( connection->remote_addr), connection->state);
|
||||
rfcomm_create_channel(handle_hci_event, connection->remote_addr, connection->rfcomm_channel_nr, NULL);
|
||||
if (hfp_connection->rfcomm_channel_nr > 0){
|
||||
hfp_connection->state = HFP_W4_RFCOMM_CONNECTED;
|
||||
log_info("HFP: SDP_EVENT_QUERY_COMPLETE context %p, addr %s, state %d", hfp_connection, bd_addr_to_str( hfp_connection->remote_addr), hfp_connection->state);
|
||||
rfcomm_create_channel(handle_hci_event, hfp_connection->remote_addr, hfp_connection->rfcomm_channel_nr, NULL);
|
||||
break;
|
||||
}
|
||||
log_info("rfcomm service not found, status %u.", sdp_event_query_complete_get_status(packet));
|
||||
@ -456,7 +452,7 @@ static void handle_query_rfcomm_event(uint8_t packet_type, uint16_t channel, uin
|
||||
void hfp_handle_hci_event(uint8_t packet_type, uint8_t *packet, uint16_t size){
|
||||
bd_addr_t event_addr;
|
||||
uint16_t rfcomm_cid, handle;
|
||||
hfp_connection_t * context = NULL;
|
||||
hfp_connection_t * hfp_connection = NULL;
|
||||
|
||||
// printf("AG packet_handler type %u, event type %x, size %u\n", packet_type, hci_event_packet_get_type(packet), size);
|
||||
|
||||
@ -744,10 +740,12 @@ static hfp_command_t parse_command(const char * line_buffer, int isHandsFree){
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+offset, HFP_ENABLE_CLIP, strlen(HFP_ENABLE_CLIP)) == 0){
|
||||
if (isHandsFree) return HFP_CMD_AG_SENT_CLIP_INFORMATION;
|
||||
return HFP_CMD_ENABLE_CLIP;
|
||||
}
|
||||
|
||||
if (strncmp(line_buffer+offset, HFP_ENABLE_CALL_WAITING_NOTIFICATION, strlen(HFP_ENABLE_CALL_WAITING_NOTIFICATION)) == 0){
|
||||
if (isHandsFree) return HFP_CMD_AG_SENT_CALL_WAITING_NOTIFICATION_UPDATE;
|
||||
return HFP_CMD_ENABLE_CALL_WAITING_NOTIFICATION;
|
||||
}
|
||||
|
||||
@ -831,14 +829,14 @@ static hfp_command_t parse_command(const char * line_buffer, int isHandsFree){
|
||||
return HFP_CMD_NONE;
|
||||
}
|
||||
|
||||
static void hfp_parser_store_byte(hfp_connection_t * context, uint8_t byte){
|
||||
static void hfp_parser_store_byte(hfp_connection_t * hfp_connection, 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;
|
||||
hfp_connection->line_buffer[hfp_connection->line_size++] = byte;
|
||||
hfp_connection->line_buffer[hfp_connection->line_size] = 0;
|
||||
}
|
||||
static int hfp_parser_is_buffer_empty(hfp_connection_t * context){
|
||||
return context->line_size == 0;
|
||||
static int hfp_parser_is_buffer_empty(hfp_connection_t * hfp_connection){
|
||||
return hfp_connection->line_size == 0;
|
||||
}
|
||||
|
||||
static int hfp_parser_is_end_of_line(uint8_t byte){
|
||||
@ -849,8 +847,8 @@ static int hfp_parser_is_end_of_header(uint8_t byte){
|
||||
return hfp_parser_is_end_of_line(byte) || byte == ':' || byte == '?';
|
||||
}
|
||||
|
||||
static int hfp_parser_found_separator(hfp_connection_t * context, uint8_t byte){
|
||||
if (context->keep_byte == 1) return 1;
|
||||
static int hfp_parser_found_separator(hfp_connection_t * hfp_connection, uint8_t byte){
|
||||
if (hfp_connection->keep_byte == 1) return 1;
|
||||
|
||||
int found_separator = byte == ',' || byte == '\n'|| byte == '\r'||
|
||||
byte == ')' || byte == '(' || byte == ':' ||
|
||||
@ -858,129 +856,131 @@ static int hfp_parser_found_separator(hfp_connection_t * context, uint8_t byte){
|
||||
return found_separator;
|
||||
}
|
||||
|
||||
static void hfp_parser_next_state(hfp_connection_t * context, uint8_t byte){
|
||||
context->line_size = 0;
|
||||
static void hfp_parser_next_state(hfp_connection_t * hfp_connection, uint8_t byte){
|
||||
hfp_connection->line_size = 0;
|
||||
if (hfp_parser_is_end_of_line(byte)){
|
||||
context->parser_item_index = 0;
|
||||
context->parser_state = HFP_PARSER_CMD_HEADER;
|
||||
hfp_connection->parser_item_index = 0;
|
||||
hfp_connection->parser_state = HFP_PARSER_CMD_HEADER;
|
||||
return;
|
||||
}
|
||||
switch (context->parser_state){
|
||||
switch (hfp_connection->parser_state){
|
||||
case HFP_PARSER_CMD_HEADER:
|
||||
context->parser_state = HFP_PARSER_CMD_SEQUENCE;
|
||||
if (context->keep_byte == 1){
|
||||
hfp_parser_store_byte(context, byte);
|
||||
context->keep_byte = 0;
|
||||
hfp_connection->parser_state = HFP_PARSER_CMD_SEQUENCE;
|
||||
if (hfp_connection->keep_byte == 1){
|
||||
hfp_parser_store_byte(hfp_connection, byte);
|
||||
hfp_connection->keep_byte = 0;
|
||||
}
|
||||
break;
|
||||
case HFP_PARSER_CMD_SEQUENCE:
|
||||
switch (context->command){
|
||||
switch (hfp_connection->command){
|
||||
case HFP_CMD_AG_SENT_PHONE_NUMBER:
|
||||
case HFP_CMD_AG_SENT_CALL_WAITING_NOTIFICATION_UPDATE:
|
||||
case HFP_CMD_AG_SENT_CLIP_INFORMATION:
|
||||
case HFP_CMD_TRANSFER_AG_INDICATOR_STATUS:
|
||||
case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME:
|
||||
case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT:
|
||||
case HFP_CMD_RETRIEVE_AG_INDICATORS:
|
||||
case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS_STATE:
|
||||
case HFP_CMD_HF_INDICATOR_STATUS:
|
||||
context->parser_state = HFP_PARSER_SECOND_ITEM;
|
||||
hfp_connection->parser_state = HFP_PARSER_SECOND_ITEM;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case HFP_PARSER_SECOND_ITEM:
|
||||
context->parser_state = HFP_PARSER_THIRD_ITEM;
|
||||
hfp_connection->parser_state = HFP_PARSER_THIRD_ITEM;
|
||||
break;
|
||||
case HFP_PARSER_THIRD_ITEM:
|
||||
if (context->command == HFP_CMD_RETRIEVE_AG_INDICATORS){
|
||||
context->parser_state = HFP_PARSER_CMD_SEQUENCE;
|
||||
if (hfp_connection->command == HFP_CMD_RETRIEVE_AG_INDICATORS){
|
||||
hfp_connection->parser_state = HFP_PARSER_CMD_SEQUENCE;
|
||||
break;
|
||||
}
|
||||
context->parser_state = HFP_PARSER_CMD_HEADER;
|
||||
hfp_connection->parser_state = HFP_PARSER_CMD_HEADER;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void hfp_parse(hfp_connection_t * context, uint8_t byte, int isHandsFree){
|
||||
void hfp_parse(hfp_connection_t * hfp_connection, uint8_t byte, int isHandsFree){
|
||||
// handle ATD<dial_string>;
|
||||
if (strncmp((const char*)context->line_buffer, HFP_CALL_PHONE_NUMBER, strlen(HFP_CALL_PHONE_NUMBER)) == 0){
|
||||
if (strncmp((const char*)hfp_connection->line_buffer, HFP_CALL_PHONE_NUMBER, strlen(HFP_CALL_PHONE_NUMBER)) == 0){
|
||||
// check for end-of-line or ';'
|
||||
if (byte == ';' || hfp_parser_is_end_of_line(byte)){
|
||||
context->line_buffer[context->line_size] = 0;
|
||||
context->line_size = 0;
|
||||
context->command = HFP_CMD_CALL_PHONE_NUMBER;
|
||||
hfp_connection->line_buffer[hfp_connection->line_size] = 0;
|
||||
hfp_connection->line_size = 0;
|
||||
hfp_connection->command = HFP_CMD_CALL_PHONE_NUMBER;
|
||||
} else {
|
||||
context->line_buffer[context->line_size++] = byte;
|
||||
hfp_connection->line_buffer[hfp_connection->line_size++] = byte;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: handle space inside word
|
||||
if (byte == ' ' && context->parser_state > HFP_PARSER_CMD_HEADER) return;
|
||||
if (byte == ' ' && hfp_connection->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);
|
||||
if (byte == ',' && hfp_connection->command == HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE){
|
||||
if (hfp_connection->line_size == 0){
|
||||
hfp_connection->line_buffer[0] = 0;
|
||||
hfp_connection->ignore_value = 1;
|
||||
parse_sequence(hfp_connection);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hfp_parser_found_separator(context, byte)){
|
||||
hfp_parser_store_byte(context, byte);
|
||||
if (!hfp_parser_found_separator(hfp_connection, byte)){
|
||||
hfp_parser_store_byte(hfp_connection, byte);
|
||||
return;
|
||||
}
|
||||
|
||||
if (hfp_parser_is_end_of_line(byte)) {
|
||||
if (hfp_parser_is_buffer_empty(context)){
|
||||
context->parser_state = HFP_PARSER_CMD_HEADER;
|
||||
if (hfp_parser_is_buffer_empty(hfp_connection)){
|
||||
hfp_connection->parser_state = HFP_PARSER_CMD_HEADER;
|
||||
}
|
||||
}
|
||||
if (hfp_parser_is_buffer_empty(context)) return;
|
||||
if (hfp_parser_is_buffer_empty(hfp_connection)) return;
|
||||
|
||||
switch (context->parser_state){
|
||||
switch (hfp_connection->parser_state){
|
||||
case HFP_PARSER_CMD_HEADER: // header
|
||||
if (byte == '='){
|
||||
context->keep_byte = 1;
|
||||
hfp_parser_store_byte(context, byte);
|
||||
hfp_connection->keep_byte = 1;
|
||||
hfp_parser_store_byte(hfp_connection, byte);
|
||||
return;
|
||||
}
|
||||
|
||||
if (byte == '?'){
|
||||
context->keep_byte = 0;
|
||||
hfp_parser_store_byte(context, byte);
|
||||
hfp_connection->keep_byte = 0;
|
||||
hfp_parser_store_byte(hfp_connection, byte);
|
||||
return;
|
||||
}
|
||||
|
||||
if (byte == ','){
|
||||
context->resolve_byte = 1;
|
||||
hfp_connection->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);
|
||||
// printf(" parse header 2 %s, keep separator $ %d\n", hfp_connection->line_buffer, hfp_connection->keep_byte);
|
||||
if (hfp_parser_is_end_of_header(byte) || hfp_connection->keep_byte == 1){
|
||||
// printf(" parse header 3 %s, keep separator $ %d\n", hfp_connection->line_buffer, hfp_connection->keep_byte);
|
||||
char * line_buffer = (char *)hfp_connection->line_buffer;
|
||||
hfp_connection->command = parse_command(line_buffer, isHandsFree);
|
||||
|
||||
/* resolve command name according to context */
|
||||
if (context->command == HFP_CMD_UNKNOWN){
|
||||
switch(context->state){
|
||||
/* resolve command name according to hfp_connection */
|
||||
if (hfp_connection->command == HFP_CMD_UNKNOWN){
|
||||
switch(hfp_connection->state){
|
||||
case HFP_W4_LIST_GENERIC_STATUS_INDICATORS:
|
||||
context->command = HFP_CMD_LIST_GENERIC_STATUS_INDICATORS;
|
||||
hfp_connection->command = HFP_CMD_LIST_GENERIC_STATUS_INDICATORS;
|
||||
break;
|
||||
case HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS:
|
||||
context->command = HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS;
|
||||
hfp_connection->command = HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS;
|
||||
break;
|
||||
case HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS:
|
||||
context->command = HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS_STATE;
|
||||
hfp_connection->command = HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS_STATE;
|
||||
break;
|
||||
case HFP_W4_RETRIEVE_INDICATORS_STATUS:
|
||||
context->command = HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS;
|
||||
hfp_connection->command = HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS;
|
||||
break;
|
||||
case HFP_W4_RETRIEVE_INDICATORS:
|
||||
context->send_ag_indicators_segment = 0;
|
||||
context->command = HFP_CMD_RETRIEVE_AG_INDICATORS;
|
||||
hfp_connection->send_ag_indicators_segment = 0;
|
||||
hfp_connection->command = HFP_CMD_RETRIEVE_AG_INDICATORS;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -990,34 +990,36 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte, int isHandsFree){
|
||||
break;
|
||||
|
||||
case HFP_PARSER_CMD_SEQUENCE:
|
||||
parse_sequence(context);
|
||||
parse_sequence(hfp_connection);
|
||||
break;
|
||||
case HFP_PARSER_SECOND_ITEM:
|
||||
switch (context->command){
|
||||
switch (hfp_connection->command){
|
||||
case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME:
|
||||
log_info("format %s, ", context->line_buffer);
|
||||
context->network_operator.format = atoi((char *)&context->line_buffer[0]);
|
||||
log_info("format %s, ", hfp_connection->line_buffer);
|
||||
hfp_connection->network_operator.format = atoi((char *)&hfp_connection->line_buffer[0]);
|
||||
break;
|
||||
case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT:
|
||||
log_info("format %s \n", context->line_buffer);
|
||||
context->network_operator.format = atoi((char *)&context->line_buffer[0]);
|
||||
log_info("format %s \n", hfp_connection->line_buffer);
|
||||
hfp_connection->network_operator.format = atoi((char *)&hfp_connection->line_buffer[0]);
|
||||
break;
|
||||
case HFP_CMD_LIST_GENERIC_STATUS_INDICATORS:
|
||||
case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS:
|
||||
case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS_STATE:
|
||||
context->generic_status_indicators[context->parser_item_index].state = (uint8_t)atoi((char*)context->line_buffer);
|
||||
hfp_connection->generic_status_indicators[hfp_connection->parser_item_index].state = (uint8_t)atoi((char*)hfp_connection->line_buffer);
|
||||
break;
|
||||
case HFP_CMD_TRANSFER_AG_INDICATOR_STATUS:
|
||||
context->ag_indicators[context->parser_item_index].status = (uint8_t)atoi((char*)context->line_buffer);
|
||||
log_info("%d \n", context->ag_indicators[context->parser_item_index].status);
|
||||
context->ag_indicators[context->parser_item_index].status_changed = 1;
|
||||
hfp_connection->ag_indicators[hfp_connection->parser_item_index].status = (uint8_t)atoi((char*)hfp_connection->line_buffer);
|
||||
log_info("%d \n", hfp_connection->ag_indicators[hfp_connection->parser_item_index].status);
|
||||
hfp_connection->ag_indicators[hfp_connection->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);
|
||||
hfp_connection->ag_indicators[hfp_connection->parser_item_index].min_range = atoi((char *)hfp_connection->line_buffer);
|
||||
log_info("%s, ", hfp_connection->line_buffer);
|
||||
break;
|
||||
case HFP_CMD_AG_SENT_PHONE_NUMBER:
|
||||
context->bnip_type = (uint8_t)atoi((char*)context->line_buffer);
|
||||
case HFP_CMD_AG_SENT_CALL_WAITING_NOTIFICATION_UPDATE:
|
||||
case HFP_CMD_AG_SENT_CLIP_INFORMATION:
|
||||
hfp_connection->bnip_type = (uint8_t)atoi((char*)hfp_connection->line_buffer);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -1025,236 +1027,239 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte, int isHandsFree){
|
||||
break;
|
||||
|
||||
case HFP_PARSER_THIRD_ITEM:
|
||||
switch (context->command){
|
||||
switch (hfp_connection->command){
|
||||
case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME:
|
||||
strcpy(context->network_operator.name, (char *)context->line_buffer);
|
||||
log_info("name %s\n", context->line_buffer);
|
||||
strcpy(hfp_connection->network_operator.name, (char *)hfp_connection->line_buffer);
|
||||
log_info("name %s\n", hfp_connection->line_buffer);
|
||||
break;
|
||||
case HFP_CMD_RETRIEVE_AG_INDICATORS:
|
||||
context->ag_indicators[context->parser_item_index].max_range = atoi((char *)context->line_buffer);
|
||||
context->parser_item_index++;
|
||||
context->ag_indicators_nr = context->parser_item_index;
|
||||
log_info("%s)\n", context->line_buffer);
|
||||
hfp_connection->ag_indicators[hfp_connection->parser_item_index].max_range = atoi((char *)hfp_connection->line_buffer);
|
||||
hfp_connection->parser_item_index++;
|
||||
hfp_connection->ag_indicators_nr = hfp_connection->parser_item_index;
|
||||
log_info("%s)\n", hfp_connection->line_buffer);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
hfp_parser_next_state(context, byte);
|
||||
hfp_parser_next_state(hfp_connection, 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;
|
||||
if (hfp_connection->resolve_byte && hfp_connection->command == HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE){
|
||||
hfp_connection->resolve_byte = 0;
|
||||
hfp_connection->ignore_value = 1;
|
||||
parse_sequence(hfp_connection);
|
||||
hfp_connection->line_buffer[0] = 0;
|
||||
hfp_connection->line_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_sequence(hfp_connection_t * context){
|
||||
static void parse_sequence(hfp_connection_t * hfp_connection){
|
||||
int value;
|
||||
switch (context->command){
|
||||
switch (hfp_connection->command){
|
||||
case HFP_CMD_SET_GENERIC_STATUS_INDICATOR_STATUS:
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
value = atoi((char *)&hfp_connection->line_buffer[0]);
|
||||
int i;
|
||||
switch (context->parser_item_index){
|
||||
switch (hfp_connection->parser_item_index){
|
||||
case 0:
|
||||
for (i=0;i<context->generic_status_indicators_nr;i++){
|
||||
if (context->generic_status_indicators[i].uuid == value){
|
||||
context->parser_indicator_index = i;
|
||||
for (i=0;i<hfp_connection->generic_status_indicators_nr;i++){
|
||||
if (hfp_connection->generic_status_indicators[i].uuid == value){
|
||||
hfp_connection->parser_indicator_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (context->parser_indicator_index <0) break;
|
||||
context->generic_status_indicators[context->parser_indicator_index].state = value;
|
||||
if (hfp_connection->parser_indicator_index <0) break;
|
||||
hfp_connection->generic_status_indicators[hfp_connection->parser_indicator_index].state = value;
|
||||
log_info("HFP_CMD_SET_GENERIC_STATUS_INDICATOR_STATUS set indicator at index %u, to %u\n",
|
||||
context->parser_item_index, value);
|
||||
hfp_connection->parser_item_index, value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
context->parser_item_index++;
|
||||
hfp_connection->parser_item_index++;
|
||||
break;
|
||||
|
||||
case HFP_CMD_GET_SUBSCRIBER_NUMBER_INFORMATION:
|
||||
switch(context->parser_item_index){
|
||||
switch(hfp_connection->parser_item_index){
|
||||
case 0:
|
||||
strncpy(context->bnip_number, (char *)context->line_buffer, sizeof(context->bnip_number));
|
||||
context->bnip_number[sizeof(context->bnip_number)-1] = 0;
|
||||
strncpy(hfp_connection->bnip_number, (char *)hfp_connection->line_buffer, sizeof(hfp_connection->bnip_number));
|
||||
hfp_connection->bnip_number[sizeof(hfp_connection->bnip_number)-1] = 0;
|
||||
break;
|
||||
case 1:
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
context->bnip_type = value;
|
||||
value = atoi((char *)&hfp_connection->line_buffer[0]);
|
||||
hfp_connection->bnip_type = value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
context->parser_item_index++;
|
||||
hfp_connection->parser_item_index++;
|
||||
break;
|
||||
case HFP_CMD_LIST_CURRENT_CALLS:
|
||||
switch(context->parser_item_index){
|
||||
switch(hfp_connection->parser_item_index){
|
||||
case 0:
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
context->clcc_idx = value;
|
||||
value = atoi((char *)&hfp_connection->line_buffer[0]);
|
||||
hfp_connection->clcc_idx = value;
|
||||
break;
|
||||
case 1:
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
context->clcc_dir = value;
|
||||
value = atoi((char *)&hfp_connection->line_buffer[0]);
|
||||
hfp_connection->clcc_dir = value;
|
||||
break;
|
||||
case 2:
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
context->clcc_status = value;
|
||||
value = atoi((char *)&hfp_connection->line_buffer[0]);
|
||||
hfp_connection->clcc_status = value;
|
||||
break;
|
||||
case 3:
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
context->clcc_mpty = value;
|
||||
value = atoi((char *)&hfp_connection->line_buffer[0]);
|
||||
hfp_connection->clcc_mpty = value;
|
||||
break;
|
||||
case 4:
|
||||
strncpy(context->bnip_number, (char *)context->line_buffer, sizeof(context->bnip_number));
|
||||
context->bnip_number[sizeof(context->bnip_number)-1] = 0;
|
||||
strncpy(hfp_connection->bnip_number, (char *)hfp_connection->line_buffer, sizeof(hfp_connection->bnip_number));
|
||||
hfp_connection->bnip_number[sizeof(hfp_connection->bnip_number)-1] = 0;
|
||||
break;
|
||||
case 5:
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
context->bnip_type = value;
|
||||
value = atoi((char *)&hfp_connection->line_buffer[0]);
|
||||
hfp_connection->bnip_type = value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
context->parser_item_index++;
|
||||
hfp_connection->parser_item_index++;
|
||||
break;
|
||||
case HFP_CMD_SET_MICROPHONE_GAIN:
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
context->microphone_gain = value;
|
||||
value = atoi((char *)&hfp_connection->line_buffer[0]);
|
||||
hfp_connection->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;
|
||||
value = atoi((char *)&hfp_connection->line_buffer[0]);
|
||||
hfp_connection->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;
|
||||
value = atoi((char *)&hfp_connection->line_buffer[0]);
|
||||
hfp_connection->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;
|
||||
value = atoi((char *)&hfp_connection->line_buffer[0]);
|
||||
hfp_connection->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);
|
||||
value = atoi((char *)&hfp_connection->line_buffer[0]);
|
||||
hfp_connection->remote_supported_features = store_bit(hfp_connection->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);
|
||||
hfp_connection->codec_confirmed = atoi((char*)hfp_connection->line_buffer);
|
||||
log_info("hfp parse HFP_CMD_HF_CONFIRMED_CODEC %d\n", hfp_connection->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);
|
||||
hfp_connection->suggested_codec = atoi((char*)hfp_connection->line_buffer);
|
||||
log_info("hfp parse HFP_CMD_AG_SUGGESTED_CODEC %d\n", hfp_connection->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);
|
||||
hfp_connection->remote_supported_features = atoi((char*)hfp_connection->line_buffer);
|
||||
log_info("Parsed supported feature %d\n", hfp_connection->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;
|
||||
log_info("Parsed codec %s\n", hfp_connection->line_buffer);
|
||||
hfp_connection->remote_codecs[hfp_connection->parser_item_index] = (uint16_t)atoi((char*)hfp_connection->line_buffer);
|
||||
hfp_connection->parser_item_index++;
|
||||
hfp_connection->remote_codecs_nr = hfp_connection->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);
|
||||
strcpy((char *)hfp_connection->ag_indicators[hfp_connection->parser_item_index].name, (char *)hfp_connection->line_buffer);
|
||||
hfp_connection->ag_indicators[hfp_connection->parser_item_index].index = hfp_connection->parser_item_index+1;
|
||||
log_info("Indicator %d: %s (", hfp_connection->ag_indicators_nr+1, hfp_connection->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++;
|
||||
log_info("Parsed Indicator %d with status: %s\n", hfp_connection->parser_item_index+1, hfp_connection->line_buffer);
|
||||
hfp_connection->ag_indicators[hfp_connection->parser_item_index].status = atoi((char *) hfp_connection->line_buffer);
|
||||
hfp_connection->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;
|
||||
hfp_connection->parser_item_index++;
|
||||
if (hfp_connection->parser_item_index != 4) break;
|
||||
log_info("Parsed Enable indicators: %s\n", hfp_connection->line_buffer);
|
||||
value = atoi((char *)&hfp_connection->line_buffer[0]);
|
||||
hfp_connection->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++;
|
||||
log_info("Parsed Support call hold: %s\n", hfp_connection->line_buffer);
|
||||
if (hfp_connection->line_size > 2 ) break;
|
||||
strcpy((char *)hfp_connection->remote_call_services[hfp_connection->remote_call_services_nr].name, (char *)hfp_connection->line_buffer);
|
||||
hfp_connection->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;
|
||||
log_info("Parsed Generic status indicator: %s\n", hfp_connection->line_buffer);
|
||||
hfp_connection->generic_status_indicators[hfp_connection->parser_item_index].uuid = (uint16_t)atoi((char*)hfp_connection->line_buffer);
|
||||
hfp_connection->parser_item_index++;
|
||||
hfp_connection->generic_status_indicators_nr = hfp_connection->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);
|
||||
log_info("Parsed List generic status indicator %s state: ", hfp_connection->line_buffer);
|
||||
hfp_connection->parser_item_index = (uint8_t)atoi((char*)hfp_connection->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);
|
||||
hfp_connection->parser_indicator_index = (uint8_t)atoi((char*)hfp_connection->line_buffer);
|
||||
log_info("Parsed HF indicator index %u", hfp_connection->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);
|
||||
if (hfp_connection->ignore_value){
|
||||
hfp_connection->ignore_value = 0;
|
||||
log_info("Parsed Enable AG indicator pos %u('%s') - unchanged (stays %u)\n", hfp_connection->parser_item_index,
|
||||
hfp_connection->ag_indicators[hfp_connection->parser_item_index].name, hfp_connection->ag_indicators[hfp_connection->parser_item_index].enabled);
|
||||
}
|
||||
else if (context->ag_indicators[context->parser_item_index].mandatory){
|
||||
else if (hfp_connection->ag_indicators[hfp_connection->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);
|
||||
hfp_connection->parser_item_index, hfp_connection->ag_indicators[hfp_connection->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);
|
||||
value = atoi((char *)&hfp_connection->line_buffer[0]);
|
||||
hfp_connection->ag_indicators[hfp_connection->parser_item_index].enabled = value;
|
||||
log_info("Parsed Enable AG indicator pos %u('%s'): %u\n", hfp_connection->parser_item_index,
|
||||
hfp_connection->ag_indicators[hfp_connection->parser_item_index].name, value);
|
||||
}
|
||||
context->parser_item_index++;
|
||||
hfp_connection->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);
|
||||
hfp_connection->parser_item_index = atoi((char *)&hfp_connection->line_buffer[0]) - 1;
|
||||
log_info("Parsed status of the AG indicator %d, status ", hfp_connection->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);
|
||||
hfp_connection->network_operator.mode = atoi((char *)&hfp_connection->line_buffer[0]);
|
||||
log_info("Parsed network operator mode: %d, ", hfp_connection->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);
|
||||
if (hfp_connection->line_buffer[0] == '3'){
|
||||
log_info("Parsed Set network operator format : %s, ", hfp_connection->line_buffer);
|
||||
break;
|
||||
}
|
||||
// TODO emit ERROR, wrong format
|
||||
log_info("ERROR Set network operator format: index %s not supported\n", context->line_buffer);
|
||||
log_info("ERROR Set network operator format: index %s not supported\n", hfp_connection->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);
|
||||
hfp_connection->extended_audio_gateway_error = 1;
|
||||
hfp_connection->extended_audio_gateway_error_value = (uint8_t)atoi((char*)hfp_connection->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;
|
||||
hfp_connection->enable_extended_audio_gateway_error_report = (uint8_t)atoi((char*)hfp_connection->line_buffer);
|
||||
hfp_connection->ok_pending = 1;
|
||||
hfp_connection->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;
|
||||
case HFP_CMD_AG_SENT_CALL_WAITING_NOTIFICATION_UPDATE:
|
||||
case HFP_CMD_AG_SENT_CLIP_INFORMATION:
|
||||
strncpy(hfp_connection->bnip_number, (char *)hfp_connection->line_buffer, sizeof(hfp_connection->bnip_number));
|
||||
hfp_connection->bnip_number[sizeof(hfp_connection->bnip_number)-1] = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -1262,63 +1267,64 @@ static void parse_sequence(hfp_connection_t * context){
|
||||
}
|
||||
|
||||
void hfp_establish_service_level_connection(bd_addr_t bd_addr, uint16_t service_uuid){
|
||||
hfp_connection_t * context = provide_hfp_connection_context_for_bd_addr(bd_addr);
|
||||
log_info("hfp_connect %s, context %p", bd_addr_to_str(bd_addr), context);
|
||||
hfp_connection_t * hfp_connection = provide_hfp_connection_context_for_bd_addr(bd_addr);
|
||||
log_info("hfp_connect %s, hfp_connection %p", bd_addr_to_str(bd_addr), hfp_connection);
|
||||
|
||||
if (!context) {
|
||||
if (!hfp_connection) {
|
||||
log_error("hfp_establish_service_level_connection for addr %s failed", bd_addr_to_str(bd_addr));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (context->state){
|
||||
switch (hfp_connection->state){
|
||||
case HFP_W2_DISCONNECT_RFCOMM:
|
||||
context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
|
||||
hfp_connection->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
|
||||
return;
|
||||
case HFP_W4_RFCOMM_DISCONNECTED:
|
||||
context->state = HFP_W4_RFCOMM_DISCONNECTED_AND_RESTART;
|
||||
hfp_connection->state = HFP_W4_RFCOMM_DISCONNECTED_AND_RESTART;
|
||||
return;
|
||||
case HFP_IDLE:
|
||||
memcpy(context->remote_addr, bd_addr, 6);
|
||||
context->state = HFP_W4_SDP_EVENT_QUERY_COMPLETE;
|
||||
connection_doing_sdp_query = context;
|
||||
context->service_uuid = service_uuid;
|
||||
sdp_query_rfcomm_channel_and_name_for_uuid(&handle_query_rfcomm_event, context->remote_addr, service_uuid);
|
||||
memcpy(hfp_connection->remote_addr, bd_addr, 6);
|
||||
hfp_connection->state = HFP_W4_SDP_EVENT_QUERY_COMPLETE;
|
||||
connection_doing_sdp_query = hfp_connection;
|
||||
hfp_connection->service_uuid = service_uuid;
|
||||
sdp_query_rfcomm_channel_and_name_for_uuid(&handle_query_rfcomm_event, hfp_connection->remote_addr, service_uuid);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void hfp_release_service_level_connection(hfp_connection_t * context){
|
||||
if (!context) return;
|
||||
|
||||
if (context->state < HFP_W4_RFCOMM_CONNECTED){
|
||||
context->state = HFP_IDLE;
|
||||
void hfp_release_service_level_connection(hfp_connection_t * hfp_connection){
|
||||
if (!hfp_connection) return;
|
||||
hfp_release_audio_connection(hfp_connection);
|
||||
|
||||
if (hfp_connection->state < HFP_W4_RFCOMM_CONNECTED){
|
||||
hfp_connection->state = HFP_IDLE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (context->state == HFP_W4_RFCOMM_CONNECTED){
|
||||
context->state = HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN;
|
||||
if (hfp_connection->state == HFP_W4_RFCOMM_CONNECTED){
|
||||
hfp_connection->state = HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN;
|
||||
return;
|
||||
}
|
||||
|
||||
if (context->state < HFP_W4_SCO_CONNECTED){
|
||||
context->state = HFP_W2_DISCONNECT_RFCOMM;
|
||||
if (hfp_connection->state < HFP_W4_SCO_CONNECTED){
|
||||
hfp_connection->state = HFP_W2_DISCONNECT_RFCOMM;
|
||||
return;
|
||||
}
|
||||
|
||||
if (context->state < HFP_W4_SCO_DISCONNECTED){
|
||||
context->state = HFP_W2_DISCONNECT_SCO;
|
||||
if (hfp_connection->state < HFP_W4_SCO_DISCONNECTED){
|
||||
hfp_connection->state = HFP_W2_DISCONNECT_SCO;
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void hfp_release_audio_connection(hfp_connection_t * context){
|
||||
if (!context) return;
|
||||
if (context->state >= HFP_W2_DISCONNECT_SCO) return;
|
||||
context->release_audio_connection = 1;
|
||||
void hfp_release_audio_connection(hfp_connection_t * hfp_connection){
|
||||
if (!hfp_connection) return;
|
||||
if (hfp_connection->state >= HFP_W2_DISCONNECT_SCO) return;
|
||||
hfp_connection->release_audio_connection = 1;
|
||||
}
|
||||
|
||||
static const struct link_settings {
|
||||
|
@ -37,7 +37,7 @@
|
||||
|
||||
// *****************************************************************************
|
||||
//
|
||||
// HFP Hands-Free (HF) unit and Audio-Gateway Commons
|
||||
// HFP Hands-Free (HF) unit and Audio Gateway Commons
|
||||
//
|
||||
// *****************************************************************************
|
||||
|
||||
@ -159,7 +159,9 @@ typedef enum {
|
||||
HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE,
|
||||
HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES,
|
||||
HFP_CMD_ENABLE_CLIP,
|
||||
HFP_CMD_AG_SENT_CLIP_INFORMATION,
|
||||
HFP_CMD_ENABLE_CALL_WAITING_NOTIFICATION,
|
||||
HFP_CMD_AG_SENT_CALL_WAITING_NOTIFICATION_UPDATE,
|
||||
|
||||
HFP_CMD_LIST_GENERIC_STATUS_INDICATORS,
|
||||
HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS,
|
||||
@ -297,7 +299,7 @@ typedef enum {
|
||||
typedef enum {
|
||||
HFP_IDLE = 0, //0
|
||||
HFP_SDP_QUERY_RFCOMM_CHANNEL,
|
||||
HFP_W4_SDP_EVENT_QUERY_COMPLETE,
|
||||
HFP_W4_SDP_QUERY_COMPLETE,
|
||||
HFP_W4_RFCOMM_CONNECTED,
|
||||
|
||||
HFP_EXCHANGE_SUPPORTED_FEATURES,
|
||||
@ -526,6 +528,7 @@ typedef struct hfp_connection {
|
||||
uint8_t operator_name_changed;
|
||||
|
||||
uint8_t enable_extended_audio_gateway_error_report;
|
||||
uint8_t extended_audio_gateway_error_value;
|
||||
uint8_t extended_audio_gateway_error;
|
||||
|
||||
// establish codecs connection
|
||||
@ -556,6 +559,7 @@ typedef struct hfp_connection {
|
||||
uint8_t ag_send_clip;
|
||||
uint8_t ag_echo_and_noise_reduction;
|
||||
uint8_t ag_activate_voice_recognition;
|
||||
uint8_t ag_notify_incoming_call_waiting;
|
||||
uint8_t send_subscriber_number;
|
||||
uint8_t next_subscriber_number_to_send;
|
||||
|
||||
@ -568,6 +572,7 @@ typedef struct hfp_connection {
|
||||
uint8_t hf_initiate_outgoing_call;
|
||||
uint8_t hf_initiate_memory_dialing;
|
||||
uint8_t hf_initiate_redial_last_number;
|
||||
int memory_id;
|
||||
|
||||
uint8_t hf_send_clip_enable;
|
||||
uint8_t hf_send_chup;
|
||||
@ -602,7 +607,7 @@ typedef struct hfp_connection {
|
||||
uint8_t clcc_mpty;
|
||||
|
||||
uint8_t call_index;
|
||||
// also used for CLCC if set
|
||||
// also used for CLCC, CCWA, CLIP if set
|
||||
uint8_t bnip_type; // 0 == not set
|
||||
char bnip_number[25]; //
|
||||
|
||||
@ -621,24 +626,21 @@ void hfp_set_callback(hfp_callback_t callback);
|
||||
void hfp_create_sdp_record(uint8_t * service, uint32_t service_record_handle, uint16_t service_uuid, int rfcomm_channel_nr, const char * name);
|
||||
void hfp_handle_hci_event(uint8_t packet_type, uint8_t *packet, uint16_t size);
|
||||
void hfp_emit_event(hfp_callback_t callback, uint8_t event_subtype, uint8_t value);
|
||||
void hfp_emit_simple_event(hfp_callback_t callback, uint8_t event_subtype);
|
||||
void hfp_emit_string_event(hfp_callback_t callback, uint8_t event_subtype, const char * value);
|
||||
|
||||
hfp_connection_t * get_hfp_connection_context_for_rfcomm_cid(uint16_t cid);
|
||||
hfp_connection_t * get_hfp_connection_context_for_bd_addr(bd_addr_t bd_addr);
|
||||
hfp_connection_t * get_hfp_connection_context_for_sco_handle(uint16_t handle);
|
||||
|
||||
int get_hfp_generic_status_indicators_nr(void);
|
||||
hfp_generic_status_indicator_t * get_hfp_generic_status_indicators(void);
|
||||
void set_hfp_generic_status_indicators(hfp_generic_status_indicator_t * indicators, int indicator_nr);
|
||||
|
||||
btstack_linked_list_t * hfp_get_connections(void);
|
||||
void hfp_parse(hfp_connection_t * context, uint8_t byte, int isHandsFree);
|
||||
void hfp_parse(hfp_connection_t * connection, uint8_t byte, int isHandsFree);
|
||||
|
||||
void hfp_establish_service_level_connection(bd_addr_t bd_addr, uint16_t service_uuid);
|
||||
void hfp_release_service_level_connection(hfp_connection_t * connection);
|
||||
void hfp_reset_context_flags(hfp_connection_t * context);
|
||||
void hfp_reset_context_flags(hfp_connection_t * connection);
|
||||
|
||||
void hfp_release_audio_connection(hfp_connection_t * context);
|
||||
void hfp_release_audio_connection(hfp_connection_t * connection);
|
||||
|
||||
void hfp_setup_synchronous_connection(hci_con_handle_t handle, hfp_link_setttings_t link_settings);
|
||||
|
||||
|
1163
src/classic/hfp_ag.c
1163
src/classic/hfp_ag.c
File diff suppressed because it is too large
Load Diff
@ -62,26 +62,64 @@ typedef struct {
|
||||
|
||||
/**
|
||||
* @brief Create HFP Audio Gateway (AG) SDP service record.
|
||||
* @param service
|
||||
* @param rfcomm_channel_nr
|
||||
* @param name
|
||||
* @param ability_to_reject_call
|
||||
* @param suported_features 32-bit bitmap, see HFP_AGSF_* values in hfp.h
|
||||
*/
|
||||
void hfp_ag_create_sdp_record(uint8_t * service, uint32_t service_record_handle, int rfcomm_channel_nr, const char * name, uint8_t ability_to_reject_call, uint16_t supported_features);;
|
||||
|
||||
/**
|
||||
* @brief Intialize HFP Audio Gateway (AG) device.
|
||||
* TODO: move optional params into setters
|
||||
* @brief Set up HFP Audio Gateway (AG) device without additional supported features.
|
||||
* @param rfcomm_channel_nr
|
||||
*/
|
||||
void hfp_ag_init(uint16_t rfcomm_channel_nr, uint32_t supported_features,
|
||||
uint8_t * codecs, int codecs_nr,
|
||||
hfp_ag_indicator_t * ag_indicators, int ag_indicators_nr,
|
||||
hfp_generic_status_indicator_t * hf_indicators, int hf_indicators_nr,
|
||||
const char *call_hold_services[], int call_hold_services_nr);
|
||||
void hfp_ag_init(uint16_t rfcomm_channel_nr);
|
||||
|
||||
/**
|
||||
* @brief Set codecs.
|
||||
* @param codecs_nr
|
||||
* @param codecs
|
||||
*/
|
||||
void hfp_ag_init_codecs(int codecs_nr, uint8_t * codecs);
|
||||
|
||||
/**
|
||||
* @brief Set supported features.
|
||||
* @param supported_features 32-bit bitmap, see HFP_AGSF_* values in hfp.h
|
||||
*/
|
||||
void hfp_ag_init_supported_features(uint32_t supported_features);
|
||||
|
||||
/**
|
||||
* @brief Set AG indicators.
|
||||
* @param indicators_nr
|
||||
* @param indicators
|
||||
*/
|
||||
void hfp_ag_init_ag_indicators(int ag_indicators_nr, hfp_ag_indicator_t * ag_indicators);
|
||||
|
||||
/**
|
||||
* @brief Set HF indicators.
|
||||
* @param indicators_nr
|
||||
* @param indicators
|
||||
*/
|
||||
void hfp_ag_init_hf_indicators(int hf_indicators_nr, hfp_generic_status_indicator_t * hf_indicators);
|
||||
|
||||
/**
|
||||
* @brief Set Call Hold services.
|
||||
* @param indicators_nr
|
||||
* @param indicators
|
||||
*/
|
||||
void hfp_ag_init_call_hold_services(int call_hold_services_nr, const char * call_hold_services[]);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Register callback for the HFP Audio Gateway (AG) client.
|
||||
* @param callback
|
||||
*/
|
||||
void hfp_ag_register_packet_handler(hfp_callback_t callback);
|
||||
|
||||
/**
|
||||
* @brief Enable in-band ring tone
|
||||
* @brief Enable in-band ring tone.
|
||||
* @param use_in_band_ring_tone
|
||||
*/
|
||||
void hfp_ag_set_use_in_band_ring_tone(int use_in_band_ring_tone);
|
||||
|
||||
@ -96,152 +134,192 @@ void hfp_ag_set_use_in_band_ring_tone(int use_in_band_ring_tone);
|
||||
* - accept the information about available codecs in the Hands-Free (HF), if sent
|
||||
* - report own information describing the call hold and multiparty services, if possible
|
||||
* - report which HF indicators are enabled on the AG, if possible
|
||||
* The status of SLC connection establishment is reported via
|
||||
* HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED.
|
||||
*
|
||||
* @param bd_addr Bluetooth address of the HF
|
||||
*/
|
||||
void hfp_ag_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 ??
|
||||
* If the audio connection exists, it will be released.
|
||||
* The status of releasing the SLC connection is reported via
|
||||
* HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED.
|
||||
*
|
||||
* @param bd_addr Bluetooth address of the HF
|
||||
*/
|
||||
void hfp_ag_release_service_level_connection(bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @brief Establish audio connection.
|
||||
* The status of Audio connection establishment is reported via is reported via
|
||||
* HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE.
|
||||
* @param bd_addr Bluetooth address of the HF
|
||||
*/
|
||||
void hfp_ag_establish_audio_connection(bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @brief Release audio connection.
|
||||
* The status of releasing the Audio connection is reported via is reported via
|
||||
* HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE.
|
||||
* @param bd_addr Bluetooth address of the HF
|
||||
*/
|
||||
void hfp_ag_release_audio_connection(bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @brief Put the current call on hold, if it exists, and accept incoming call.
|
||||
*/
|
||||
void hfp_ag_answer_incoming_call(void);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @brief Join held call with active call.
|
||||
*/
|
||||
void hfp_ag_join_held_call(void);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @brief Reject incoming call, if exists, or terminate active call.
|
||||
*/
|
||||
void hfp_ag_terminate_call(void);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Put incoming call on hold.
|
||||
*/
|
||||
void hfp_ag_hold_incoming_call(void);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Accept the held incoming call.
|
||||
*/
|
||||
void hfp_ag_accept_held_incoming_call(void);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Reject the held incoming call.
|
||||
*/
|
||||
void hfp_ag_reject_held_incoming_call(void);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Set microphone gain.
|
||||
* @param bd_addr Bluetooth address of the HF
|
||||
* @param gain Valid range: [0,15]
|
||||
*/
|
||||
void hfp_ag_set_microphone_gain(bd_addr_t bd_addr, int gain);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Set speaker gain.
|
||||
* @param bd_addr Bluetooth address of the HF
|
||||
* @param gain Valid range: [0,15]
|
||||
*/
|
||||
void hfp_ag_set_speaker_gain(bd_addr_t bd_addr, int gain);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Set battery level.
|
||||
* @param level Valid range: [0,5]
|
||||
*/
|
||||
void hfp_ag_set_battery_level(int level);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Clear last dialed number.
|
||||
*/
|
||||
void hfp_ag_clear_last_dialed_number(void);
|
||||
|
||||
/*
|
||||
* @brief Notify the HF that an incoming call is waiting
|
||||
* during an ongoing call. The notification will be sent only if the HF has
|
||||
* has previously enabled the "Call Waiting notification" in the AG.
|
||||
* @param bd_addr Bluetooth address of the HF
|
||||
*/
|
||||
void hfp_ag_notify_incoming_call_waiting(bd_addr_t bd_addr);
|
||||
|
||||
// Voice Recognition
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Activate voice recognition.
|
||||
* @param bd_addr Bluetooth address of the HF
|
||||
* @param activate
|
||||
*/
|
||||
void hfp_ag_activate_voice_recognition(bd_addr_t bd_addr, int activate);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Send a phone number back to the HF.
|
||||
* @param bd_addr Bluetooth address of the HF
|
||||
* @param phone_number
|
||||
*/
|
||||
void hfp_ag_send_phone_number_for_voice_tag(bd_addr_t bd_addr, const char * number);
|
||||
void hfp_ag_send_phone_number_for_voice_tag(bd_addr_t bd_addr, const char * phone_number);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Reject sending a phone number to the HF.
|
||||
* @param bd_addr Bluetooth address of the HF
|
||||
*/
|
||||
void hfp_ag_reject_phone_number_for_voice_tag(bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief Store phone number with initiated call.
|
||||
* @param type
|
||||
* @param number
|
||||
*/
|
||||
void hfp_ag_set_clip(uint8_t type, const char * number);
|
||||
|
||||
|
||||
// Cellular Actions
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @brief Pass the accept incoming call event to the AG.
|
||||
*/
|
||||
void hfp_ag_incoming_call(void);
|
||||
|
||||
/**
|
||||
* @brief number is stored.
|
||||
*/
|
||||
void hfp_ag_set_clip(uint8_t type, const char * number);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @brief Pass the reject outgoing call event to the AG.
|
||||
*/
|
||||
void hfp_ag_outgoing_call_rejected(void);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @brief Pass the accept outgoing call event to the AG.
|
||||
*/
|
||||
void hfp_ag_outgoing_call_accepted(void);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @brief Pass the outgoing call ringing event to the AG.
|
||||
*/
|
||||
void hfp_ag_outgoing_call_ringing(void);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @brief Pass the outgoing call established event to the AG.
|
||||
*/
|
||||
void hfp_ag_outgoing_call_established(void);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @brief Pass the call droped event to the AG.
|
||||
*/
|
||||
void hfp_ag_call_dropped(void);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Set network registration status.
|
||||
* @param status 0 - not registered, 1 - registered
|
||||
*/
|
||||
void hfp_ag_set_registration_status(int status);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Set network signal strength.
|
||||
* @param strength [0-5]
|
||||
*/
|
||||
void hfp_ag_set_signal_strength(int strength);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Set roaming status.
|
||||
* @param status 0 - no roaming, 1 - roaming active
|
||||
*/
|
||||
void hfp_ag_set_roaming_status(int status);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Set subcriber number information, e.g. the phone number
|
||||
* @param numbers
|
||||
* @param numbers_count
|
||||
*/
|
||||
void hfp_ag_set_subcriber_number_information(hfp_phone_number_t * numbers, int numbers_count);
|
||||
|
||||
/*
|
||||
* @brief Called by cellular unit after a DTMF code was transmitted, so that the next one can be emitted
|
||||
* @brief Called by cellular unit after a DTMF code was transmitted, so that the next one can be emitted.
|
||||
* @param bd_addr Bluetooth address of the HF
|
||||
*/
|
||||
void hfp_ag_send_dtmf_code_done(bd_addr_t bd_addr);
|
||||
|
||||
@ -272,6 +350,9 @@ void hfp_ag_send_dtmf_code_done(bd_addr_t bd_addr);
|
||||
* - +CME ERROR: 30 - no network service
|
||||
* - +CME ERROR: 31 - network Timeout.
|
||||
* - +CME ERROR: 32 - network not allowed – Emergency calls only
|
||||
*
|
||||
* @param bd_addr Bluetooth address of the HF
|
||||
* @param error
|
||||
*/
|
||||
void hfp_ag_report_extended_audio_gateway_error_result_code(bd_addr_t bd_addr, hfp_cme_error_t error);
|
||||
|
||||
|
1092
src/classic/hfp_hf.c
1092
src/classic/hfp_hf.c
File diff suppressed because it is too large
Load Diff
@ -57,262 +57,361 @@ extern "C" {
|
||||
|
||||
/**
|
||||
* @brief Create HFP Hands-Free (HF) SDP service record.
|
||||
* @param service
|
||||
* @param rfcomm_channel_nr
|
||||
* @param name
|
||||
* @param suported_features 32-bit bitmap, see HFP_HFSF_* values in hfp.h
|
||||
*/
|
||||
void hfp_hf_create_sdp_record(uint8_t * service, uint32_t service_record_handle, int rfcomm_channel_nr, const char * name, uint16_t supported_features);
|
||||
|
||||
/**
|
||||
* @brief Intialize HFP Hands-Free (HF) device.
|
||||
* TODO: move optional params into setters
|
||||
* @brief Set up HFP Hands-Free (HF) device without additional supported features.
|
||||
* @param rfcomm_channel_nr
|
||||
*/
|
||||
void hfp_hf_init(uint16_t rfcomm_channel_nr, uint32_t supported_features, uint16_t * indicators, int indicators_nr, uint32_t indicators_status);
|
||||
void hfp_hf_init(uint16_t rfcomm_channel_nr);
|
||||
|
||||
void hfp_hf_set_codecs(uint8_t * codecs, int codecs_nr);
|
||||
/**
|
||||
* @brief Set codecs.
|
||||
* @param codecs_nr
|
||||
* @param codecs
|
||||
*/
|
||||
void hfp_hf_init_codecs(int codecs_nr, uint8_t * codecs);
|
||||
|
||||
/**
|
||||
* @brief Set supported features.
|
||||
* @param supported_features 32-bit bitmap, see HFP_HFSF_* values in hfp.h
|
||||
*/
|
||||
void hfp_hf_init_supported_features(uint32_t supported_features);
|
||||
|
||||
/**
|
||||
* @brief Set HF indicators.
|
||||
* @param indicators_nr
|
||||
* @param indicators
|
||||
*/
|
||||
void hfp_hf_init_hf_indicators(int indicators_nr, uint16_t * indicators);
|
||||
|
||||
void hfp_hf_set_supported_features(uint32_t supported_features);
|
||||
|
||||
/**
|
||||
* @brief Register callback for the HFP Hands-Free (HF) client.
|
||||
* @param callback
|
||||
*/
|
||||
void hfp_hf_register_packet_handler(hfp_callback_t callback);
|
||||
|
||||
/**
|
||||
* @brief Establish RFCOMM connection, and perform service level connection agreement:
|
||||
* - exchange of supported features
|
||||
* @brief Establish RFCOMM connection with the AG with given Bluetooth address,
|
||||
* and perform service level connection (SLC) agreement:
|
||||
* - exchange supported features
|
||||
* - retrieve Audio Gateway (AG) indicators and their status
|
||||
* - enable indicator status update in the AG
|
||||
* - notify the AG about its own available codecs, if possible
|
||||
* - retrieve the AG information describing the call hold and multiparty services, if possible
|
||||
* - retrieve which HF indicators are enabled on the AG, if possible
|
||||
* The status of SLC connection establishment is reported via
|
||||
* HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED.
|
||||
*
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
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
|
||||
* The status of releasing the SLC connection is reported via
|
||||
* HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED.
|
||||
*
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
void hfp_hf_release_service_level_connection(bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief Deactivate/reactivate status update for all indicators in the AG.
|
||||
* @brief Enable status update for all indicators in the AG.
|
||||
* The status field of the HFP_SUBEVENT_COMPLETE reports if the command was accepted.
|
||||
* The status of an AG indicator is reported via HFP_SUBEVENT_AG_INDICATOR_STATUS_CHANGED.
|
||||
*
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
void hfp_hf_enable_status_update_for_all_ag_indicators(bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief Disable status update for all indicators in the AG.
|
||||
* The status field of the HFP_SUBEVENT_COMPLETE reports if the command was accepted.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
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.
|
||||
* @brief Enable or disable status update for the individual indicators in the AG using bitmap.
|
||||
* The status field of the HFP_SUBEVENT_COMPLETE reports if the command was accepted.
|
||||
* The status of an AG indicator is reported via HFP_SUBEVENT_AG_INDICATOR_STATUS_CHANGED.
|
||||
*
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
* @param indicators_status_bitmap 32-bit bitmap, 0 - indicator is disabled, 1 - indicator is enabled
|
||||
*/
|
||||
void hfp_hf_set_status_update_for_individual_ag_indicators(bd_addr_t bd_addr, uint32_t indicators_status_bitmap);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Find out the name of the currently selected Network operator by AG.
|
||||
* The name is restricted to max 16 characters.
|
||||
*
|
||||
* TODO: what is the result of this?
|
||||
* @brief Query the name of the currently selected Network operator by AG.
|
||||
*
|
||||
* The name is restricted to max 16 characters. The result is reported via
|
||||
* HFP_SUBEVENT_NETWORK_OPERATOR_CHANGED subtype
|
||||
* containing network operator mode, format and name.
|
||||
* If no operator is selected, format and operator are omitted.
|
||||
*
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
void hfp_hf_query_operator_selection(bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief Enable/disable Extended Audio Gateway Error result codes in the AG.
|
||||
* @brief Enable Extended Audio Gateway Error result codes in the AG.
|
||||
* Whenever there is an error relating to the functionality of the AG as a
|
||||
* result of AT command, the AG shall send +CME ERROR:
|
||||
* - +CME ERROR: 0 - AG failure
|
||||
* - +CME ERROR: 1 - no connection to phone
|
||||
* - +CME ERROR: 3 - operation not allowed
|
||||
* - +CME ERROR: 4 - operation not supported
|
||||
* - +CME ERROR: 5 - PH-SIM PIN required
|
||||
* - +CME ERROR: 10 - SIM not inserted
|
||||
* - +CME ERROR: 11 - SIM PIN required
|
||||
* - +CME ERROR: 12 - SIM PUK required
|
||||
* - +CME ERROR: 13 - SIM failure
|
||||
* - +CME ERROR: 14 - SIM busy
|
||||
* - +CME ERROR: 16 - incorrect password
|
||||
* - +CME ERROR: 17 - SIM PIN2 required
|
||||
* - +CME ERROR: 18 - SIM PUK2 required
|
||||
* - +CME ERROR: 20 - memory full
|
||||
* - +CME ERROR: 21 - invalid index
|
||||
* - +CME ERROR: 23 - memory failure
|
||||
* - +CME ERROR: 24 - text string too long
|
||||
* - +CME ERROR: 25 - invalid characters in text string
|
||||
* - +CME ERROR: 26 - dial string too long
|
||||
* - +CME ERROR: 27 - invalid characters in dial string
|
||||
* - +CME ERROR: 30 - no network service
|
||||
* - +CME ERROR: 31 - network Timeout.
|
||||
* - +CME ERROR: 32 - network not allowed – Emergency calls only
|
||||
* result of AT command, the AG shall send +CME ERROR. This error is reported via
|
||||
* HFP_SUBEVENT_EXTENDED_AUDIO_GATEWAY_ERROR, see hfp_cme_error_t in hfp.h
|
||||
*
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
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
|
||||
* @brief Disable Extended Audio Gateway Error result codes in the AG.
|
||||
*
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
void hfp_hf_disable_report_extended_audio_gateway_error_result_code(bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief Establish audio connection.
|
||||
* The status of audio connection establishment is reported via
|
||||
* HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
void hfp_hf_establish_audio_connection(bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @brief Release audio connection.
|
||||
* The status of releasing of the audio connection is reported via
|
||||
* HFP_SUBEVENT_AUDIO_CONNECTION_RELEASED.
|
||||
*
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
void hfp_hf_release_audio_connection(bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @brief Answer incoming call.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
void hfp_hf_answer_incoming_call(bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @brief Reject incoming call.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
void hfp_hf_reject_call(bd_addr_t bd_addr);
|
||||
void hfp_hf_reject_incoming_call(bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @brief Release all held calls or sets User Determined User Busy (UDUB) for a waiting call.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
void hfp_hf_user_busy(bd_addr_t addr);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @brief Release all active calls (if any exist) and accepts the other (held or waiting) call.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
void hfp_hf_end_active_and_accept_other(bd_addr_t addr);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @brief Place all active calls (if any exist) on hold and accepts the other (held or waiting) call.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
void hfp_hf_swap_calls(bd_addr_t addr);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @brief Add a held call to the conversation.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
void hfp_hf_join_held_call(bd_addr_t addr);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @brief Connect the two calls and disconnects the subscriber from both calls (Explicit Call
|
||||
Transfer).
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
void hfp_hf_connect_calls(bd_addr_t addr);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @brief Terminate an incoming or an outgoing call.
|
||||
* HFP_SUBEVENT_CALL_TERMINATED is sent upon call termination.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
void hfp_hf_terminate_call(bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @brief Initiate outgoing voice call by providing the destination phone number to the AG.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
* @param number
|
||||
*/
|
||||
void hfp_hf_dial_number(bd_addr_t bd_addr, char * number);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* TODO: use int for number instead of string?
|
||||
* @brief Initiate outgoing voice call using the memory dialing feature of the AG.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
* @param memory_id
|
||||
*/
|
||||
void hfp_hf_dial_memory(bd_addr_t bd_addr, char * number);
|
||||
void hfp_hf_dial_memory(bd_addr_t bd_addr, int memory_id);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @brief Initiate outgoing voice call by recalling the last number dialed by the AG.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
void hfp_hf_redial_last_number(bd_addr_t bd_addr);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Enable the “Call Waiting notification” function in the AG.
|
||||
* The AG shall send the corresponding result code to the HF whenever
|
||||
* an incoming call is waiting during an ongoing call. In that event,
|
||||
* the HFP_SUBEVENT_CALL_WAITING_NOTIFICATION is emitted.
|
||||
*
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
void hfp_hf_activate_call_waiting_notification(bd_addr_t bd_addr);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Disable the “Call Waiting notification” function in the AG.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
void hfp_hf_deactivate_call_waiting_notification(bd_addr_t bd_addr);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Enable the “Calling Line Identification notification” function in the AG.
|
||||
* The AG shall issue the corresponding result code just after every RING indication,
|
||||
* when the HF is alerted in an incoming call. In that event,
|
||||
* the HFP_SUBEVENT_CALLING_LINE_INDETIFICATION_NOTIFICATION is emitted.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
void hfp_hf_activate_calling_line_notification(bd_addr_t bd_addr);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Disable the “Calling Line Identification notification” function in the AG.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
void hfp_hf_deactivate_calling_line_notification(bd_addr_t bd_addr);
|
||||
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Activate echo canceling and noise reduction in the AG. By default,
|
||||
* if the AG supports its own embedded echo canceling and/or noise reduction
|
||||
* functions, it shall have them activated until this function is called.
|
||||
* If the AG does not support any echo canceling and noise reduction functions,
|
||||
* it shall respond with the ERROR indicator (TODO)
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
void hfp_hf_activate_echo_canceling_and_noise_reduction(bd_addr_t bd_addr);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Deactivate echo canceling and noise reduction in the AG.
|
||||
*/
|
||||
void hfp_hf_deactivate_echo_canceling_and_noise_reduction(bd_addr_t bd_addr);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Activate voice recognition function.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
void hfp_hf_activate_voice_recognition_notification(bd_addr_t bd_addr);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Dectivate voice recognition function.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
void hfp_hf_deactivate_voice_recognition_notification(bd_addr_t bd_addr);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Set microphone gain.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
* @param gain Valid range: [0,15]
|
||||
*/
|
||||
void hfp_hf_set_microphone_gain(bd_addr_t bd_addr, int gain);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Set speaker gain.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
* @param gain Valid range: [0,15]
|
||||
*/
|
||||
void hfp_hf_set_speaker_gain(bd_addr_t bd_addr, int gain);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Instruct the AG to transmit a DTMF code.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
* @param dtmf_code
|
||||
*/
|
||||
void hfp_hf_send_dtmf_code(bd_addr_t bd_addr, char code);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Read numbers from the AG for the purpose of creating
|
||||
* a unique voice tag and storing the number and its linked voice
|
||||
* tag in the HF’s memory.
|
||||
* The number is reported via HFP_SUBEVENT_NUMBER_FOR_VOICE_TAG.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
void hfp_hf_request_phone_number_for_voice_tag(bd_addr_t addr);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Query the list of current calls in AG.
|
||||
* The result is received via HFP_SUBEVENT_ENHANCED_CALL_STATUS.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
void hfp_hf_query_current_call_status(bd_addr_t addr);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Release a call with index in the AG.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
* @param index
|
||||
*/
|
||||
void hfp_hf_release_call_with_index(bd_addr_t addr, int index);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Place all parties of a multiparty call on hold with the
|
||||
* exception of the specified call.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
* @param index
|
||||
*/
|
||||
void hfp_hf_private_consultation_with_call(bd_addr_t addr, int index);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Query the status of the “Response and Hold” state of the AG.
|
||||
* The result is reported via HFP_SUBEVENT_RESPONSE_AND_HOLD_STATUS.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
void hfp_hf_rrh_query_status(bd_addr_t addr);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Put an incoming call on hold in the AG.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
void hfp_hf_rrh_hold_call(bd_addr_t addr);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Accept held incoming call in the AG.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
void hfp_hf_rrh_accept_held_call(bd_addr_t addr);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Reject held incoming call in the AG.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
void hfp_hf_rrh_reject_held_call(bd_addr_t addr);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Query the AG subscriber number.
|
||||
* The result is reported via HFP_SUBEVENT_SUBSCRIBER_NUMBER_INFORMATION.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
*/
|
||||
void hfp_hf_query_subscriber_number(bd_addr_t addr);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* @brief Set HF indicator.
|
||||
* @param bd_addr Bluetooth address of the AG
|
||||
* @param assigned_number
|
||||
* @param value
|
||||
*/
|
||||
void hfp_hf_set_hf_indicator(bd_addr_t addr, int assigned_number, int value);
|
||||
|
||||
|
@ -161,7 +161,7 @@ static int hsp_hs_send_str_over_rfcomm(uint16_t cid, const char * command){
|
||||
if (!rfcomm_can_send_packet_now(rfcomm_cid)) return 1;
|
||||
int err = rfcomm_send(cid, (uint8_t*) command, strlen(command));
|
||||
if (err){
|
||||
printf("rfcomm_send -> error 0X%02x", err);
|
||||
log_info("rfcomm_send_internal -> error 0X%02x", err);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
@ -288,12 +288,10 @@ void hsp_hs_connect(bd_addr_t bd_addr){
|
||||
void hsp_hs_disconnect(bd_addr_t bd_addr){
|
||||
switch (hsp_state){
|
||||
case HSP_ACTIVE:
|
||||
printf("HSP_W4_USER_ACTION\n");
|
||||
hsp_state = HSP_W4_USER_ACTION;
|
||||
hs_send_button_press = 1;
|
||||
break;
|
||||
case HSP_W4_RFCOMM_CONNECTED:
|
||||
printf("HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN \n");
|
||||
hsp_state = HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN;
|
||||
break;
|
||||
default:
|
||||
@ -305,7 +303,7 @@ void hsp_hs_disconnect(bd_addr_t bd_addr){
|
||||
|
||||
void hsp_hs_set_microphone_gain(uint8_t gain){
|
||||
if (gain < 0 || gain >15) {
|
||||
printf("Gain must be in interval [0..15], it is given %d\n", gain);
|
||||
log_info("Gain must be in interval [0..15], it is given %d", gain);
|
||||
return;
|
||||
}
|
||||
hs_microphone_gain = gain;
|
||||
@ -315,7 +313,7 @@ void hsp_hs_set_microphone_gain(uint8_t gain){
|
||||
// AG +VGS=5 [0..15] ; HS AT+VGM=6 | AG OK
|
||||
void hsp_hs_set_speaker_gain(uint8_t gain){
|
||||
if (gain < 0 || gain >15) {
|
||||
printf("Gain must be in interval [0..15], it is given %d\n", gain);
|
||||
log_info("Gain must be in interval [0..15], it is given %d", gain);
|
||||
return;
|
||||
}
|
||||
hs_speaker_gain = gain;
|
||||
@ -393,7 +391,6 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
|
||||
if (strncmp((char *)packet, HSP_AG_RING, strlen(HSP_AG_RING)) == 0){
|
||||
emit_ring_event();
|
||||
} else if (strncmp((char *)packet, HSP_AG_OK, strlen(HSP_AG_OK)) == 0){
|
||||
printf("OK RECEIVED\n");
|
||||
switch (hsp_state){
|
||||
case HSP_W4_RFCOMM_CONNECTED:
|
||||
hsp_state = HSP_W2_CONNECT_SCO;
|
||||
@ -437,20 +434,6 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
|
||||
uint16_t handle;
|
||||
|
||||
switch (event) {
|
||||
case BTSTACK_EVENT_STATE:
|
||||
// bt stack activated, get started
|
||||
if (packet[2] == HCI_STATE_WORKING){
|
||||
printf("BTstack activated, get started .\n");
|
||||
}
|
||||
hsp_hs_callback(packet, size);
|
||||
break;
|
||||
|
||||
case HCI_EVENT_PIN_CODE_REQUEST:
|
||||
// inform about pin code request
|
||||
printf("Pin code request - using '0000'\n\r");
|
||||
reverse_bd_addr(&packet[2], event_addr);
|
||||
hci_send_cmd(&hci_pin_code_request_reply, &event_addr, 4, "0000");
|
||||
break;
|
||||
case HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE:{
|
||||
int index = 2;
|
||||
uint8_t status = packet[index++];
|
||||
@ -475,14 +458,14 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
|
||||
}
|
||||
switch (link_type){
|
||||
case 0x00:
|
||||
printf("SCO Connection established. \n");
|
||||
log_info("SCO Connection established.");
|
||||
if (transmission_interval != 0) log_error("SCO Connection: transmission_interval not zero: %d.", transmission_interval);
|
||||
if (retransmission_interval != 0) log_error("SCO Connection: retransmission_interval not zero: %d.", retransmission_interval);
|
||||
if (rx_packet_length != 0) log_error("SCO Connection: rx_packet_length not zero: %d.", rx_packet_length);
|
||||
if (tx_packet_length != 0) log_error("SCO Connection: tx_packet_length not zero: %d.", tx_packet_length);
|
||||
break;
|
||||
case 0x02:
|
||||
printf("eSCO Connection established. \n");
|
||||
log_info("eSCO Connection established.");
|
||||
break;
|
||||
default:
|
||||
log_error("(e)SCO reserved link_type 0x%2x", link_type);
|
||||
@ -511,17 +494,17 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
|
||||
|
||||
reverse_bd_addr(&packet[2], event_addr);
|
||||
rfcomm_cid = little_endian_read_16(packet, 9);
|
||||
printf("RFCOMM channel %u requested for %s\n", packet[8], bd_addr_to_str(event_addr));
|
||||
log_info("RFCOMM channel %u requested for %s", packet[8], bd_addr_to_str(event_addr));
|
||||
rfcomm_accept_connection(rfcomm_cid);
|
||||
|
||||
hsp_state = HSP_W4_RFCOMM_CONNECTED;
|
||||
break;
|
||||
|
||||
case RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE:
|
||||
printf("RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE packet_handler type %u\n", packet_type);
|
||||
// printf("RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE packet_handler type %u, packet[0] %x\n", packet_type, packet[0]);
|
||||
// data: event(8), len(8), status (8), address (48), handle(16), server channel(8), rfcomm_cid(16), max frame size(16)
|
||||
if (packet[2]) {
|
||||
printf("RFCOMM channel open failed, status %u\n", packet[2]);
|
||||
log_info("RFCOMM channel open failed, status %u", packet[2]);
|
||||
hsp_hs_reset_state();
|
||||
emit_event(HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE, packet[2]);
|
||||
hs_outgoing_connection = 0;
|
||||
@ -530,7 +513,7 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
|
||||
rfcomm_handle = little_endian_read_16(packet, 9);
|
||||
rfcomm_cid = little_endian_read_16(packet, 12);
|
||||
mtu = little_endian_read_16(packet, 14);
|
||||
printf("RFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u\n", rfcomm_cid, mtu);
|
||||
log_info("RFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u", rfcomm_cid, mtu);
|
||||
|
||||
if (hs_outgoing_connection){
|
||||
hs_outgoing_connection = 0;
|
||||
@ -559,12 +542,10 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
|
||||
if (handle == sco_handle){
|
||||
sco_handle = 0;
|
||||
hsp_state = HSP_W2_DISCONNECT_RFCOMM;
|
||||
printf(" HSP_W2_DISCONNECT_RFCOMM\n");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case RFCOMM_EVENT_CHANNEL_CLOSED:
|
||||
printf("RFCOMM channel closed\n");
|
||||
hsp_hs_reset_state();
|
||||
emit_event(HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE,0);
|
||||
break;
|
||||
@ -578,18 +559,17 @@ static void handle_query_rfcomm_event(uint8_t packet_type, uint16_t channel, uin
|
||||
switch (hci_event_packet_get_type(packet)){
|
||||
case SDP_EVENT_QUERY_RFCOMM_SERVICE:
|
||||
channel_nr = sdp_event_query_rfcomm_service_get_rfcomm_channel(packet);
|
||||
printf("** Service name: '%s', RFCOMM port %u\n", sdp_event_query_rfcomm_service_get_name(packet), channel_nr);
|
||||
log_info("** Service name: '%s', RFCOMM port %u", ve->service_name, channel_nr);
|
||||
break;
|
||||
case SDP_EVENT_QUERY_COMPLETE:
|
||||
if (channel_nr > 0){
|
||||
hsp_state = HSP_W4_RFCOMM_CONNECTED;
|
||||
printf("RFCOMM create channel.\n");
|
||||
log_info("RFCOMM create channel");
|
||||
rfcomm_create_channel(packet_handler, remote, channel_nr, NULL);
|
||||
break;
|
||||
}
|
||||
hsp_hs_reset_state();
|
||||
printf("Service not found, status %u.\n", sdp_event_query_complete_get_status(packet));
|
||||
exit(0);
|
||||
log_info("Service not found, status %u.", sdp_event_query_complete_get_status(packet));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
280
src/sdp_parser.c
Normal file
280
src/sdp_parser.c
Normal file
@ -0,0 +1,280 @@
|
||||
/*
|
||||
* Copyright (C) 2014 BlueKitchen GmbH
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
* 4. Any redistribution, use, or modification is done solely for
|
||||
* personal benefit and not for any commercial purpose or for
|
||||
* monetary gain.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
|
||||
* RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* Please inquire about commercial licensing options at
|
||||
* contact@bluekitchen-gmbh.com
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* sdp_parser.c
|
||||
*/
|
||||
#include <btstack/hci_cmds.h>
|
||||
#include "sdp_parser.h"
|
||||
#include "debug.h"
|
||||
|
||||
typedef enum {
|
||||
GET_LIST_LENGTH = 1,
|
||||
GET_RECORD_LENGTH,
|
||||
GET_ATTRIBUTE_ID_HEADER_LENGTH,
|
||||
GET_ATTRIBUTE_ID,
|
||||
GET_ATTRIBUTE_VALUE_LENGTH,
|
||||
GET_ATTRIBUTE_VALUE
|
||||
} state_t;
|
||||
|
||||
static state_t state = GET_LIST_LENGTH;
|
||||
static uint16_t attribute_id = 0;
|
||||
static uint16_t attribute_bytes_received = 0;
|
||||
static uint16_t attribute_bytes_delivered = 0;
|
||||
static uint16_t list_offset = 0;
|
||||
static uint16_t list_size;
|
||||
static uint16_t record_offset = 0;
|
||||
static uint16_t record_size;
|
||||
static uint16_t attribute_value_size;
|
||||
static int record_counter = 0;
|
||||
|
||||
#ifdef HAVE_SDP_EXTRA_QUERIES
|
||||
static uint32_t record_handle;
|
||||
#endif
|
||||
|
||||
static void (*sdp_query_callback)(sdp_query_event_t * event);
|
||||
|
||||
// Low level parser
|
||||
static de_state_t de_header_state;
|
||||
|
||||
|
||||
void de_state_init(de_state_t * de_state){
|
||||
de_state->in_state_GET_DE_HEADER_LENGTH = 1;
|
||||
de_state->addon_header_bytes = 0;
|
||||
de_state->de_size = 0;
|
||||
de_state->de_offset = 0;
|
||||
}
|
||||
|
||||
int de_state_size(uint8_t eventByte, de_state_t *de_state){
|
||||
if (de_state->in_state_GET_DE_HEADER_LENGTH){
|
||||
de_state->addon_header_bytes = de_get_header_size(&eventByte) - 1;
|
||||
de_state->de_size = 0;
|
||||
de_state->de_offset = 0;
|
||||
|
||||
if (de_state->addon_header_bytes == 0){
|
||||
de_state->de_size = de_get_data_size(&eventByte);
|
||||
if (de_state->de_size == 0) {
|
||||
log_error(" ERROR: ID size is zero");
|
||||
}
|
||||
// log_info("Data element payload is %d bytes.", de_state->de_size);
|
||||
return 1;
|
||||
}
|
||||
de_state->in_state_GET_DE_HEADER_LENGTH = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (de_state->addon_header_bytes > 0){
|
||||
de_state->de_size = (de_state->de_size << 8) | eventByte;
|
||||
de_state->addon_header_bytes--;
|
||||
}
|
||||
if (de_state->addon_header_bytes > 0) return 0;
|
||||
// log_info("Data element payload is %d bytes.", de_state->de_size);
|
||||
de_state->in_state_GET_DE_HEADER_LENGTH = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void dummy_notify(sdp_query_event_t* event){}
|
||||
|
||||
void sdp_parser_register_callback(void (*sdp_callback)(sdp_query_event_t* event)){
|
||||
sdp_query_callback = dummy_notify;
|
||||
if (sdp_callback != NULL){
|
||||
sdp_query_callback = sdp_callback;
|
||||
}
|
||||
}
|
||||
|
||||
static void parse(uint8_t eventByte){
|
||||
// count all bytes
|
||||
list_offset++;
|
||||
record_offset++;
|
||||
|
||||
// log_info(" parse BYTE_RECEIVED %02x", eventByte);
|
||||
switch(state){
|
||||
case GET_LIST_LENGTH:
|
||||
if (!de_state_size(eventByte, &de_header_state)) break;
|
||||
list_offset = de_header_state.de_offset;
|
||||
list_size = de_header_state.de_size;
|
||||
// log_info("parser: List offset %u, list size %u", list_offset, list_size);
|
||||
|
||||
record_counter = 0;
|
||||
state = GET_RECORD_LENGTH;
|
||||
break;
|
||||
|
||||
case GET_RECORD_LENGTH:
|
||||
// check size
|
||||
if (!de_state_size(eventByte, &de_header_state)) break;
|
||||
// log_info("parser: Record payload is %d bytes.", de_header_state.de_size);
|
||||
record_offset = de_header_state.de_offset;
|
||||
record_size = de_header_state.de_size;
|
||||
state = GET_ATTRIBUTE_ID_HEADER_LENGTH;
|
||||
break;
|
||||
|
||||
case GET_ATTRIBUTE_ID_HEADER_LENGTH:
|
||||
if (!de_state_size(eventByte, &de_header_state)) break;
|
||||
attribute_id = 0;
|
||||
log_info("ID data is stored in %d bytes.", (int) de_header_state.de_size);
|
||||
state = GET_ATTRIBUTE_ID;
|
||||
break;
|
||||
|
||||
case GET_ATTRIBUTE_ID:
|
||||
attribute_id = (attribute_id << 8) | eventByte;
|
||||
de_header_state.de_size--;
|
||||
if (de_header_state.de_size > 0) break;
|
||||
log_info("parser: Attribute ID: %04x.", attribute_id);
|
||||
|
||||
state = GET_ATTRIBUTE_VALUE_LENGTH;
|
||||
attribute_bytes_received = 0;
|
||||
attribute_bytes_delivered = 0;
|
||||
attribute_value_size = 0;
|
||||
de_state_init(&de_header_state);
|
||||
break;
|
||||
|
||||
case GET_ATTRIBUTE_VALUE_LENGTH:
|
||||
attribute_bytes_received++;
|
||||
{
|
||||
sdp_query_attribute_value_event_t attribute_value_event = {
|
||||
SDP_QUERY_ATTRIBUTE_VALUE,
|
||||
record_counter,
|
||||
attribute_id,
|
||||
attribute_value_size,
|
||||
attribute_bytes_delivered++,
|
||||
eventByte
|
||||
};
|
||||
(*sdp_query_callback)((sdp_query_event_t*)&attribute_value_event);
|
||||
}
|
||||
if (!de_state_size(eventByte, &de_header_state)) break;
|
||||
|
||||
attribute_value_size = de_header_state.de_size + attribute_bytes_received;
|
||||
|
||||
state = GET_ATTRIBUTE_VALUE;
|
||||
break;
|
||||
|
||||
case GET_ATTRIBUTE_VALUE:
|
||||
attribute_bytes_received++;
|
||||
{
|
||||
sdp_query_attribute_value_event_t attribute_value_event = {
|
||||
SDP_QUERY_ATTRIBUTE_VALUE,
|
||||
record_counter,
|
||||
attribute_id,
|
||||
attribute_value_size,
|
||||
attribute_bytes_delivered++,
|
||||
eventByte
|
||||
};
|
||||
|
||||
(*sdp_query_callback)((sdp_query_event_t*)&attribute_value_event);
|
||||
}
|
||||
// log_info("paser: attribute_bytes_received %u, attribute_value_size %u", attribute_bytes_received, attribute_value_size);
|
||||
|
||||
if (attribute_bytes_received < attribute_value_size) break;
|
||||
// log_info("parser: Record offset %u, record size %u", record_offset, record_size);
|
||||
if (record_offset != record_size){
|
||||
state = GET_ATTRIBUTE_ID_HEADER_LENGTH;
|
||||
// log_info("Get next attribute");
|
||||
break;
|
||||
}
|
||||
record_offset = 0;
|
||||
// log_info("parser: List offset %u, list size %u", list_offset, list_size);
|
||||
|
||||
if (list_size > 0 && list_offset != list_size){
|
||||
record_counter++;
|
||||
state = GET_RECORD_LENGTH;
|
||||
log_info("parser: END_OF_RECORD");
|
||||
break;
|
||||
}
|
||||
list_offset = 0;
|
||||
de_state_init(&de_header_state);
|
||||
state = GET_LIST_LENGTH;
|
||||
record_counter = 0;
|
||||
log_info("parser: END_OF_RECORD & DONE");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void sdp_parser_init(void){
|
||||
// init
|
||||
de_state_init(&de_header_state);
|
||||
state = GET_LIST_LENGTH;
|
||||
list_offset = 0;
|
||||
record_offset = 0;
|
||||
record_counter = 0;
|
||||
}
|
||||
|
||||
void sdp_parser_handle_chunk(uint8_t * data, uint16_t size){
|
||||
int i;
|
||||
for (i=0;i<size;i++){
|
||||
parse(data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_SDP_EXTRA_QUERIES
|
||||
void sdp_parser_init_service_attribute_search(void){
|
||||
// init
|
||||
de_state_init(&de_header_state);
|
||||
state = GET_RECORD_LENGTH;
|
||||
list_offset = 0;
|
||||
record_offset = 0;
|
||||
record_counter = 0;
|
||||
}
|
||||
|
||||
void sdp_parser_init_service_search(void){
|
||||
record_offset = 0;
|
||||
}
|
||||
|
||||
void sdp_parser_handle_service_search(uint8_t * data, uint16_t total_count, uint16_t record_handle_count){
|
||||
int i;
|
||||
for (i=0;i<record_handle_count;i++){
|
||||
record_handle = READ_NET_32(data, i*4);
|
||||
record_counter++;
|
||||
sdp_query_service_record_handle_event_t service_record_handle_event = {
|
||||
SDP_QUERY_SERVICE_RECORD_HANDLE,
|
||||
total_count,
|
||||
(uint16_t) record_counter,
|
||||
record_handle
|
||||
};
|
||||
(*sdp_query_callback)((sdp_query_event_t*)&service_record_handle_event);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void sdp_parser_handle_done(uint8_t status){
|
||||
sdp_query_complete_event_t complete_event = {
|
||||
SDP_QUERY_COMPLETE,
|
||||
status
|
||||
};
|
||||
(*sdp_query_callback)((sdp_query_event_t*)&complete_event);
|
||||
}
|
@ -4,7 +4,7 @@ CC = g++
|
||||
|
||||
BTSTACK_ROOT = ../..
|
||||
|
||||
CFLAGS = -DUNIT_TEST -x c++ -g -Wall -I. -I../ -I${BTSTACK_ROOT}/src -I${BTSTACK_ROOT}/ble -I${BTSTACK_ROOT}/include
|
||||
CFLAGS = -DUNIT_TEST -x c++ -g -Wall -Wnarrowing -Wconversion-null -I. -I../ -I${BTSTACK_ROOT}/src -I${BTSTACK_ROOT}/ble -I${BTSTACK_ROOT}/include
|
||||
LDFLAGS += -lCppUTest -lCppUTestExt
|
||||
|
||||
VPATH += ${BTSTACK_ROOT}/src
|
||||
|
@ -24,8 +24,8 @@ uint16_t get_gatt_client_handle(void){
|
||||
}
|
||||
|
||||
void mock_simulate_command_complete(const hci_cmd_t *cmd){
|
||||
uint8_t packet[] = {HCI_EVENT_COMMAND_COMPLETE, 4, 1, cmd->opcode & 0xff, cmd->opcode >> 8, 0};
|
||||
registered_hci_event_handler(HCI_EVENT_PACKET, 0, (uint8_t *)&packet, sizeof(packet));
|
||||
uint8_t packet[] = {HCI_EVENT_COMMAND_COMPLETE, 4, 1, (uint8_t) (cmd->opcode & 0xff), (uint8_t) (cmd->opcode >> 8), 0};
|
||||
registered_hci_event_handler(HCI_EVENT_PACKET, NULL, (uint8_t *)&packet, sizeof(packet));
|
||||
}
|
||||
|
||||
void mock_simulate_hci_state_working(void){
|
||||
|
@ -43,7 +43,7 @@ COMMON_OBJ = $(COMMON:.c=.o)
|
||||
MOCK_OBJ = $(MOCK:.c=.o)
|
||||
|
||||
# CC = gcc-fsf-4.9
|
||||
CFLAGS = -g -Wall \
|
||||
CFLAGS = -g -Wall -Wmissing-prototype -Wnarrowing \
|
||||
-I. \
|
||||
-I.. \
|
||||
-I${BTSTACK_ROOT}/src
|
||||
|
@ -361,8 +361,7 @@ void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
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){
|
||||
&& event[2] != HFP_SUBEVENT_TRANSMIT_DTMF_CODES){
|
||||
printf("ERROR, status: %u\n", event[3]);
|
||||
return;
|
||||
}
|
||||
@ -417,11 +416,12 @@ void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
|
||||
TEST_GROUP(HFPClient){
|
||||
void setup(void){
|
||||
hfp_ag_init(rfcomm_channel_nr, supported_features_with_codec_negotiation,
|
||||
codecs, sizeof(codecs),
|
||||
ag_indicators, ag_indicators_nr,
|
||||
hf_indicators, hf_indicators_nr,
|
||||
call_hold_services, call_hold_services_nr);
|
||||
hfp_ag_init(rfcomm_channel_nr);
|
||||
hfp_ag_init_supported_features(supported_features_with_codec_negotiation);
|
||||
hfp_ag_init_codecs(sizeof(codecs), codecs);
|
||||
hfp_ag_init_ag_indicators(ag_indicators_nr, ag_indicators);
|
||||
hfp_ag_init_hf_indicators(hf_indicators_nr, hf_indicators);
|
||||
hfp_ag_init_call_hold_services(call_hold_services_nr, call_hold_services);
|
||||
}
|
||||
|
||||
void teardown(void){
|
||||
|
@ -47,12 +47,8 @@
|
||||
#include "classic/hfp.h"
|
||||
|
||||
void hfp_parse(hfp_connection_t * context, uint8_t byte, int isHandsFree);
|
||||
hfp_generic_status_indicator_t * get_hfp_generic_status_indicators();
|
||||
void set_hfp_generic_status_indicators(hfp_generic_status_indicator_t * indicators, int indicator_nr);
|
||||
|
||||
hfp_ag_indicator_t * get_hfp_ag_indicators(hfp_connection_t * context);
|
||||
int get_hfp_ag_indicators_nr(hfp_connection_t * context);
|
||||
void set_hfp_ag_indicators(hfp_ag_indicator_t * indicators, int indicator_nr);
|
||||
hfp_ag_indicator_t * hfp_ag_get_ag_indicators(hfp_connection_t * hfp_connection);
|
||||
|
||||
// static int hf_indicators_nr = 3;
|
||||
// static hfp_generic_status_indicator_t hf_indicators[] = {
|
||||
@ -78,8 +74,7 @@ static hfp_connection_t context;
|
||||
|
||||
TEST_GROUP(HFPParser){
|
||||
char packet[200];
|
||||
int pos;
|
||||
int offset;
|
||||
uint16_t pos;
|
||||
|
||||
void setup(void){
|
||||
context.parser_state = HFP_PARSER_CMD_HEADER;
|
||||
@ -140,13 +135,13 @@ TEST(HFPParser, HFP_AG_ENABLE_INDICATOR_STATUS_UPDATE){
|
||||
|
||||
|
||||
TEST(HFPParser, HFP_AG_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE){
|
||||
set_hfp_ag_indicators((hfp_ag_indicator_t *)&hfp_ag_indicators, hfp_ag_indicators_nr);
|
||||
hfp_ag_init_ag_indicators(hfp_ag_indicators_nr, (hfp_ag_indicator_t *)&hfp_ag_indicators);
|
||||
context.ag_indicators_nr = hfp_ag_indicators_nr;
|
||||
memcpy(context.ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t));
|
||||
|
||||
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(hfp_ag_get_ag_indicators(&context)[pos].index, hfp_ag_indicators[pos].index);
|
||||
CHECK_EQUAL(hfp_ag_get_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);
|
||||
}
|
||||
@ -159,18 +154,18 @@ TEST(HFPParser, HFP_AG_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE){
|
||||
CHECK_EQUAL(HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE, context.command);
|
||||
|
||||
for (pos = 0; pos < hfp_ag_indicators_nr; pos++){
|
||||
if (get_hfp_ag_indicators(&context)[pos].mandatory){
|
||||
CHECK_EQUAL(get_hfp_ag_indicators(&context)[pos].enabled, 1);
|
||||
if (hfp_ag_get_ag_indicators(&context)[pos].mandatory){
|
||||
CHECK_EQUAL(hfp_ag_get_ag_indicators(&context)[pos].enabled, 1);
|
||||
CHECK_EQUAL(context.ag_indicators[pos].enabled, 1);
|
||||
} else {
|
||||
CHECK_EQUAL(get_hfp_ag_indicators(&context)[pos].enabled, 0);
|
||||
CHECK_EQUAL(hfp_ag_get_ag_indicators(&context)[pos].enabled, 0);
|
||||
CHECK_EQUAL(context.ag_indicators[pos].enabled, 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);
|
||||
hfp_ag_init_ag_indicators(hfp_ag_indicators_nr, (hfp_ag_indicator_t *)&hfp_ag_indicators);
|
||||
context.ag_indicators_nr = hfp_ag_indicators_nr;
|
||||
memcpy(context.ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t));
|
||||
|
||||
@ -183,15 +178,15 @@ TEST(HFPParser, HFP_AG_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE_OPT_VALUES3){
|
||||
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(hfp_ag_get_ag_indicators(&context)[pos].index, hfp_ag_indicators[pos].index);
|
||||
CHECK_EQUAL(hfp_ag_get_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);
|
||||
hfp_ag_init_ag_indicators(hfp_ag_indicators_nr, (hfp_ag_indicator_t *)&hfp_ag_indicators);
|
||||
context.ag_indicators_nr = hfp_ag_indicators_nr;
|
||||
memcpy(context.ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t));
|
||||
|
||||
@ -204,13 +199,13 @@ TEST(HFPParser, HFP_AG_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE_OPT_VALUES2){
|
||||
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(hfp_ag_get_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);
|
||||
hfp_ag_init_ag_indicators(hfp_ag_indicators_nr, (hfp_ag_indicator_t *)&hfp_ag_indicators);
|
||||
context.ag_indicators_nr = hfp_ag_indicators_nr;
|
||||
memcpy(context.ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t));
|
||||
|
||||
@ -223,7 +218,7 @@ TEST(HFPParser, HFP_AG_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE_OPT_VALUES1){
|
||||
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(hfp_ag_get_ag_indicators(&context)[pos].enabled, 1);
|
||||
CHECK_EQUAL(context.ag_indicators[pos].enabled, 1);
|
||||
}
|
||||
}
|
||||
|
@ -148,8 +148,8 @@ static void user_command(char cmd){
|
||||
hfp_hf_terminate_call(device_addr);
|
||||
break;
|
||||
case 'G':
|
||||
printf("Reject call.\n");
|
||||
hfp_hf_reject_call(device_addr);
|
||||
printf("Reject incoming call.\n");
|
||||
hfp_hf_reject_incoming_call(device_addr);
|
||||
break;
|
||||
case 'g':
|
||||
printf("Query operator.\n");
|
||||
@ -169,11 +169,11 @@ static void user_command(char cmd){
|
||||
break;
|
||||
case 'j':
|
||||
printf("Dial #1\n");
|
||||
hfp_hf_dial_memory(device_addr, (char *)"1");
|
||||
hfp_hf_dial_memory(device_addr, 1);
|
||||
break;
|
||||
case 'J':
|
||||
printf("Dial #99\n");
|
||||
hfp_hf_dial_memory(device_addr, (char *)"99");
|
||||
hfp_hf_dial_memory(device_addr, 99);
|
||||
break;
|
||||
case 'k':
|
||||
printf("Deactivate call waiting notification\n");
|
||||
@ -337,7 +337,7 @@ void simulate_test_sequence(hfp_test_item_t * test_item){
|
||||
sscanf(&expected_cmd[7],"%d,%d", &parsed_codecs[0], &parsed_codecs[1]);
|
||||
new_codecs[0] = parsed_codecs[0];
|
||||
new_codecs[1] = parsed_codecs[1];
|
||||
hfp_hf_set_codecs((uint8_t*)new_codecs, 2);
|
||||
hfp_hf_init_codecs(2, (uint8_t*)new_codecs);
|
||||
while (has_more_hfp_hf_commands()){
|
||||
// empty rfcomm payload buffer
|
||||
get_next_hfp_hf_command();
|
||||
@ -348,7 +348,9 @@ void simulate_test_sequence(hfp_test_item_t * test_item){
|
||||
sscanf(&expected_cmd[8],"%d", &supported_features);
|
||||
printf("Call hfp_hf_init with SF %d\n", supported_features);
|
||||
hfp_hf_release_service_level_connection(device_addr);
|
||||
hfp_hf_init(rfcomm_channel_nr, supported_features, indicators, sizeof(indicators)/sizeof(uint16_t), 1);
|
||||
|
||||
hfp_hf_init_supported_features(supported_features);
|
||||
|
||||
user_command('a');
|
||||
while (has_more_hfp_hf_commands()){
|
||||
// empty rfcomm payload buffer
|
||||
@ -391,14 +393,6 @@ void simulate_test_sequence(hfp_test_item_t * test_item){
|
||||
|
||||
void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
if (event[0] != HCI_EVENT_HFP_META) return;
|
||||
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;
|
||||
}
|
||||
|
||||
switch (event[2]) {
|
||||
case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
|
||||
@ -440,10 +434,10 @@ void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
printf("HFP AG HFP_SUBEVENT_COMPLETE.\n");
|
||||
break;
|
||||
case HFP_SUBEVENT_AG_INDICATOR_STATUS_CHANGED:
|
||||
printf("AG_INDICATOR_STATUS_CHANGED, AG indicator '%s' (index: %d) to: %d\n", (const char*) &event[6], event[4], event[5]);
|
||||
printf("AG_INDICATOR_STATUS_CHANGED, AG indicator '%s' (index: %d) to: %d\n", (const char*) &event[5], event[3], event[4]);
|
||||
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]);
|
||||
printf("NETWORK_OPERATOR_CHANGED, operator mode: %d, format: %d, name: %s\n", event[3], event[4], (char *) &event[5]);
|
||||
break;
|
||||
case HFP_SUBEVENT_EXTENDED_AUDIO_GATEWAY_ERROR:
|
||||
if (event[4])
|
||||
@ -478,8 +472,11 @@ TEST_GROUP(HFPClient){
|
||||
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));
|
||||
hfp_hf_init(rfcomm_channel_nr);
|
||||
hfp_hf_init_supported_features(supported_features_with_codec_negotiation);
|
||||
hfp_hf_init_hf_indicators(sizeof(indicators)/sizeof(uint16_t), indicators);
|
||||
|
||||
hfp_hf_init_codecs(sizeof(codecs), codecs);
|
||||
}
|
||||
|
||||
void teardown(void){
|
||||
|
@ -239,7 +239,7 @@ TEST(HFPParser, HFP_HF_EXTENDED_AUDIO_GATEWAY_ERROR){
|
||||
}
|
||||
|
||||
CHECK_EQUAL(context.command, HFP_CMD_EXTENDED_AUDIO_GATEWAY_ERROR);
|
||||
CHECK_EQUAL(context.extended_audio_gateway_error, HFP_CME_ERROR_NO_NETWORK_SERVICE);
|
||||
CHECK_EQUAL(context.extended_audio_gateway_error_value, HFP_CME_ERROR_NO_NETWORK_SERVICE);
|
||||
}
|
||||
|
||||
|
||||
|
@ -599,8 +599,7 @@ static void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
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){
|
||||
&& event[2] != HFP_SUBEVENT_TRANSMIT_DTMF_CODES){
|
||||
printf("ERROR, status: %u\n", event[3]);
|
||||
return;
|
||||
}
|
||||
@ -665,10 +664,13 @@ int btstack_main(int argc, const char * argv[]){
|
||||
l2cap_init();
|
||||
rfcomm_init();
|
||||
|
||||
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_init(rfcomm_channel_nr);
|
||||
hfp_ag_init_supported_features(0x3ef | (1<<HFP_AGSF_HF_INDICATORS) | (1<<HFP_AGSF_ESCO_S4));
|
||||
hfp_ag_init_codecs(sizeof(codecs), codecs);
|
||||
hfp_ag_init_ag_indicators(ag_indicators_nr, ag_indicators);
|
||||
hfp_ag_init_hf_indicators(hf_indicators_nr, hf_indicators);
|
||||
hfp_ag_init_call_hold_services(call_hold_services_nr, call_hold_services);
|
||||
|
||||
hfp_ag_set_subcriber_number_information(&subscriber_number, 1);
|
||||
hfp_ag_register_packet_handler(packet_handler);
|
||||
|
||||
|
@ -113,7 +113,7 @@ static void show_usage(void){
|
||||
printf("F - Hangup call\n");
|
||||
|
||||
printf("g - query network operator name\n");
|
||||
printf("G - reject call\n");
|
||||
printf("G - reject incoming call\n");
|
||||
|
||||
printf("i - dial 1234567\n");
|
||||
printf("I - dial 7654321\n");
|
||||
@ -252,8 +252,8 @@ static int stdin_process(struct btstack_data_source *ds){
|
||||
break;
|
||||
case 'G':
|
||||
log_info("USER:\'%c\'", cmd);
|
||||
printf("Reject call.\n");
|
||||
hfp_hf_reject_call(device_addr);
|
||||
printf("Reject incoming call.\n");
|
||||
hfp_hf_reject_incoming_call(device_addr);
|
||||
break;
|
||||
case 'g':
|
||||
log_info("USER:\'%c\'", cmd);
|
||||
@ -278,12 +278,12 @@ static int stdin_process(struct btstack_data_source *ds){
|
||||
case 'j':
|
||||
log_info("USER:\'%c\'", cmd);
|
||||
printf("Dial #1\n");
|
||||
hfp_hf_dial_memory(device_addr,"1");
|
||||
hfp_hf_dial_memory(device_addr,1);
|
||||
break;
|
||||
case 'J':
|
||||
log_info("USER:\'%c\'", cmd);
|
||||
printf("Dial #99\n");
|
||||
hfp_hf_dial_memory(device_addr,"99");
|
||||
hfp_hf_dial_memory(device_addr,99);
|
||||
break;
|
||||
case 'k':
|
||||
log_info("USER:\'%c\'", cmd);
|
||||
@ -467,14 +467,7 @@ static void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
return;
|
||||
}
|
||||
if (event[0] != HCI_EVENT_HFP_META) return;
|
||||
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;
|
||||
}
|
||||
|
||||
switch (event[2]) {
|
||||
case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
|
||||
printf("Service level connection established.\n\n");
|
||||
@ -500,10 +493,10 @@ 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 '%s' (index: %d) to: %d\n", (const char*) &event[6], event[4], event[5]);
|
||||
printf("AG_INDICATOR_STATUS_CHANGED, AG indicator '%s' (index: %d) to: %d\n", (const char*) &event[5], event[3], event[4]);
|
||||
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]);
|
||||
printf("NETWORK_OPERATOR_CHANGED, operator mode: %d, format: %d, name: %s\n", event[3], event[4], (char *) &event[5]);
|
||||
break;
|
||||
case HFP_SUBEVENT_EXTENDED_AUDIO_GATEWAY_ERROR:
|
||||
if (event[4])
|
||||
@ -534,8 +527,10 @@ 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 | (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_init(rfcomm_channel_nr);
|
||||
hfp_hf_init_supported_features(438 | (1<<HFP_HFSF_ESCO_S4) | (1<<HFP_HFSF_EC_NR_FUNCTION));
|
||||
hfp_hf_init_hf_indicators(sizeof(indicators)/sizeof(uint16_t), indicators);
|
||||
hfp_hf_init_codecs(sizeof(codecs), codecs);
|
||||
|
||||
hfp_hf_register_packet_handler(packet_handler);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user