hfp features, fixed queries

This commit is contained in:
Milanka Ringwald 2015-07-17 11:14:34 +02:00
parent 45615488a3
commit 09ff3143db
4 changed files with 123 additions and 64 deletions

View File

@ -60,16 +60,63 @@
#include "debug.h"
#include "hfp_ag.h"
#define HFP_HF_FEATURES_SIZE 10
#define HFP_AG_FEATURES_SIZE 12
static const char * hfp_hf_features[] = {
"EC and/or NR function",
"Three-way calling",
"CLI presentation capability",
"Voice recognition activation",
"Remote volume control",
"Enhanced call status",
"Enhanced call control",
"Codec negotiation",
"HF Indicators",
"eSCO S4 (and T2) Settings Supported",
"Reserved for future definition"
};
static const char * hfp_ag_features[] = {
"Three-way calling",
"EC and/or NR function",
"Voice recognition function",
"In-band ring tone capability",
"Attach a number to a voice tag",
"Ability to reject a call",
"Enhanced call status",
"Enhanced call control",
"Extended Error Result Codes",
"Codec negotiation",
"HF Indicators",
"eSCO S4 (and T2) Settings Supported",
"Reserved for future definition"
};
static hfp_callback_t hfp_callback;
static linked_list_t hfp_connections = NULL;
const char * hfp_hf_feature(int index){
if (index > HFP_HF_FEATURES_SIZE){
return hfp_hf_features[HFP_HF_FEATURES_SIZE];
}
return hfp_hf_features[index];
}
const char * hfp_ag_feature(int index){
if (index > HFP_AG_FEATURES_SIZE){
return hfp_ag_features[HFP_AG_FEATURES_SIZE];
}
return hfp_ag_features[index];
}
int send_str_over_rfcomm(uint16_t cid, char * command){
// if (!rfcomm_can_send_packet_now(cid)) return 1;
int err = rfcomm_send_internal(cid, (uint8_t*) command, strlen(command));
if (err){
printf("rfcomm_send_internal -> error 0X%02x", err);
} else {
printf("Sent %s", command);
printf("\nSent %s", command);
}
return err;
}

View File

@ -99,13 +99,13 @@ extern "C" {
typedef enum {
HFP_IDLE,
HFP_IDLE = 0, //50
HFP_SDP_QUERY_RFCOMM_CHANNEL,
HFP_W4_SDP_QUERY_COMPLETE,
HFP_W4_RFCOMM_CONNECTED,
HFP_EXCHANGE_SUPPORTED_FEATURES,
HFP_W4_EXCHANGE_SUPPORTED_FEATURES,
HFP_W4_EXCHANGE_SUPPORTED_FEATURES, // 5
HFP_NOTIFY_ON_CODECS,
HFP_W4_NOTIFY_ON_CODECS,
@ -113,14 +113,14 @@ typedef enum {
HFP_RETRIEVE_INDICATORS,
HFP_W4_RETRIEVE_INDICATORS,
HFP_RETRIEVE_INDICATORS_STATUS,
HFP_RETRIEVE_INDICATORS_STATUS, // 10
HFP_W4_RETRIEVE_INDICATORS_STATUS,
HFP_ENABLE_INDICATORS_STATUS_UPDATE,
HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE,
HFP_RETRIEVE_CAN_HOLD_CALL,
HFP_W4_RETRIEVE_CAN_HOLD_CALL,
HFP_W4_RETRIEVE_CAN_HOLD_CALL, // 15
HFP_LIST_GENERIC_STATUS_INDICATORS,
HFP_W4_LIST_GENERIC_STATUS_INDICATORS,
@ -128,7 +128,7 @@ typedef enum {
HFP_RETRIEVE_GENERIC_STATUS_INDICATORS,
HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS,
HFP_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS,
HFP_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS, // 20
HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS,
HFP_ACTIVE,
@ -195,6 +195,7 @@ typedef struct hfp_connection {
hfp_callback_t callback;
} hfp_connection_t;
void hfp_create_service(uint8_t * service, uint16_t service_uuid, int rfcomm_channel_nr, const char * name, uint16_t supported_features);
void hfp_register_packet_handler(hfp_callback_t callback);
hfp_connection_t * hfp_handle_hci_event(uint8_t packet_type, uint8_t *packet, uint16_t size);
@ -208,6 +209,9 @@ linked_list_t * hfp_get_connections();
int send_str_over_rfcomm(uint16_t cid, char * command);
void join(char * buffer, int buffer_size, int buffer_offset, uint8_t * values, int values_nr, int value_size);
const char * hfp_hf_feature(int index);
const char * hfp_ag_feature(int index);
#if defined __cplusplus
}
#endif

View File

@ -71,6 +71,21 @@ static uint8_t hfp_indicators_nr = 0;
static uint8_t hfp_indicators[HFP_MAX_NUM_INDICATORS];
static uint8_t hfp_indicators_status;
static int get_bit(uint16_t bitmap, int position){
return (bitmap >> position) & 1;
}
int has_call_waiting_and_3way_calling_feature(hfp_connection_t * connection){
return get_bit(hfp_supported_features,1) && get_bit(connection->remote_supported_features,0);
}
int has_codec_negotiation_feature(hfp_connection_t * connection){
return get_bit(hfp_supported_features,7) && get_bit(connection->remote_supported_features,9);
}
int has_hf_indicators_feature(hfp_connection_t * connection){
return get_bit(hfp_supported_features,8) && get_bit(connection->remote_supported_features,10);
}
static void packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
@ -81,11 +96,6 @@ void hfp_hf_create_service(uint8_t * service, int rfcomm_channel_nr, const char
hfp_create_service(service, SDP_Handsfree, rfcomm_channel_nr, name, supported_features);
}
static int get_bit(uint16_t bitmap, int position){
return (bitmap >> position) & 1;
}
static int store_bit(uint32_t bitmap, int position, uint8_t value){
if (value){
bitmap |= 1 << position;
@ -125,13 +135,14 @@ int hfp_hs_retrieve_indicators_status_cmd(uint16_t cid){
return send_str_over_rfcomm(cid, buffer);
}
int hfp_hs_toggle_indicator_status_update_cmd(uint16_t cid){
int hfp_hs_toggle_indicator_status_update_cmd(uint16_t cid, uint8_t activate){
char buffer[20];
sprintf(buffer, "AT%s\r\n", HFP_Enable_Indicator_Status_Update);
sprintf(buffer, "AT%s=3,0,0,%d\r\n", HFP_Enable_Indicator_Status_Update, activate);
// printf("toggle_indicator_status_update %s\n", buffer);
return send_str_over_rfcomm(cid, buffer);
}
int hfp_hs_retrieve_can_hold_call_cmd(uint16_t cid){
char buffer[20];
sprintf(buffer, "AT%s\r\n", HFP_Support_Call_Hold_And_Multiparty_Services);
@ -162,26 +173,11 @@ int hfp_hs_list_initital_supported_generic_status_indicators_cmd(uint16_t cid){
return send_str_over_rfcomm(cid, buffer);
}
// TODO: +CIEV service, call, call setup change => new indicator value
// TODO: AT+CMER => disable ind. status update
int has_call_waiting_and_3way_calling_feature(hfp_connection_t * connection){
return get_bit(hfp_supported_features,1) && get_bit(connection->remote_supported_features,0);
}
int has_codec_negotiation_feature(hfp_connection_t * connection){
return get_bit(hfp_supported_features,7) && get_bit(connection->remote_supported_features,9);
}
int has_hf_indicators_feature(hfp_connection_t * connection){
return get_bit(hfp_supported_features,8) && get_bit(connection->remote_supported_features,10);
}
static void hfp_run_for_context(hfp_connection_t * connection){
if (!connection) return;
printf("hfp send cmd: context %p, RFCOMM cid %u\n", connection, connection->rfcomm_cid );
// printf("hfp send cmd: context %p, RFCOMM cid %u \n", connection, connection->rfcomm_cid );
if (!rfcomm_can_send_packet_now(connection->rfcomm_cid)) return;
int err = 0;
switch (connection->state){
case HFP_EXCHANGE_SUPPORTED_FEATURES:
@ -202,18 +198,35 @@ static void hfp_run_for_context(hfp_connection_t * connection){
break;
case HFP_ENABLE_INDICATORS_STATUS_UPDATE:
if (connection->remote_indicators_update_enabled == 0){
err = hfp_hs_toggle_indicator_status_update_cmd(connection->rfcomm_cid);
if (!err) connection->state = HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE;
err = hfp_hs_toggle_indicator_status_update_cmd(connection->rfcomm_cid, 1);
if (!err) {
connection->state = HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE;
connection->wait_ok = 1;
}
break;
}
break;
printf("fall through to HFP_RETRIEVE_CAN_HOLD_CALL\n");
connection->state = HFP_RETRIEVE_CAN_HOLD_CALL;
case HFP_RETRIEVE_CAN_HOLD_CALL:
err = hfp_hs_retrieve_can_hold_call_cmd(connection->rfcomm_cid);
if (!err) connection->state = HFP_W4_RETRIEVE_CAN_HOLD_CALL;
break;
if (has_call_waiting_and_3way_calling_feature(connection)){
err = hfp_hs_retrieve_can_hold_call_cmd(connection->rfcomm_cid);
if (!err) connection->state = HFP_W4_RETRIEVE_CAN_HOLD_CALL;
break;
}
printf("fall through to HFP_LIST_GENERIC_STATUS_INDICATORS (no CAN_HOLD_CALL feature)\n");
connection->state = HFP_LIST_GENERIC_STATUS_INDICATORS;
case HFP_LIST_GENERIC_STATUS_INDICATORS:
err = hfp_hs_list_supported_generic_status_indicators_cmd(connection->rfcomm_cid);
if (!err) connection->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS;
if (has_hf_indicators_feature(connection)){
err = hfp_hs_list_supported_generic_status_indicators_cmd(connection->rfcomm_cid);
if (!err) connection->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS;
break;
}
printf("fall through to HFP_ACTIVE (no hf indicators feature)\n");
connection->state = HFP_ACTIVE;
case HFP_ACTIVE:
printf("HFP_ACTIVE\n");
break;
case HFP_RETRIEVE_GENERIC_STATUS_INDICATORS:
err = hfp_hs_retrieve_supported_generic_status_indicators_cmd(connection->rfcomm_cid);
if (!err) connection->state = HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS;
@ -232,7 +245,7 @@ void hfp_parse_indicators(hfp_connection_t * context, uint8_t *packet, uint16_t
char min_range[3];
char max_range[3];
int i, pos;
int index = 0;
int index = 1;
int state = 0;
for (pos = 0; pos < size; pos++){
@ -284,7 +297,7 @@ void hfp_parse_indicators(hfp_connection_t * context, uint8_t *packet, uint16_t
}
void hfp_parse_indicators_status(hfp_connection_t * context, uint8_t *packet, uint16_t size){
int index = 0;
int index = 1;
char * token = strtok((char*)&packet[0], ",");
while (token){
printf("Indicator %d status: %d \n", index, atoi(token));
@ -295,25 +308,18 @@ void hfp_parse_indicators_status(hfp_connection_t * context, uint8_t *packet, ui
hfp_connection_t * handle_message(hfp_connection_t * context, uint8_t *packet, uint16_t size){
int offset = 0;
printf("Parsed %s, state %u\n", (char *)packet, context->state);
if (context->wait_ok){
if (strncmp((char *)packet, HFP_OK, strlen(HFP_OK)) == 0){
printf("Parsed %s\n", HFP_OK);
context->wait_ok = 0;
switch (context->state){
case HFP_W4_NOTIFY_ON_CODECS:
context->state = HFP_RETRIEVE_INDICATORS;
break;
case HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE:
if (has_call_waiting_and_3way_calling_feature(context)){
context->state = HFP_RETRIEVE_CAN_HOLD_CALL;
break;
}
if (has_hf_indicators_feature(context)){
context->state = HFP_LIST_GENERIC_STATUS_INDICATORS;
break;
}
context->state = HFP_RETRIEVE_CAN_HOLD_CALL;
break;
case HFP_W4_LIST_GENERIC_STATUS_INDICATORS:
context->state = HFP_RETRIEVE_GENERIC_STATUS_INDICATORS;
break;
@ -325,7 +331,6 @@ hfp_connection_t * handle_message(hfp_connection_t * context, uint8_t *packet, u
default:
break;
}
context->wait_ok = 0;
return context;
}
}
@ -333,7 +338,12 @@ hfp_connection_t * handle_message(hfp_connection_t * context, uint8_t *packet, u
if (strncmp((char *)packet, HFP_Supported_Features, strlen(HFP_Supported_Features)) == 0){
offset = strlen(HFP_Supported_Features) + 1; // +1 for =
context->remote_supported_features = atoi((char*)&packet[offset]);
printf("Parsed %s: %d (expected 224)\n", HFP_Supported_Features, context->remote_supported_features);
int i = 0;
for (i=0; i<16; i++){
if (get_bit(context->remote_supported_features,i)){
printf("AG supported feature: %s\n", hfp_ag_feature(i));
}
}
if (has_codec_negotiation_feature(context)){
context->state = HFP_NOTIFY_ON_CODECS;
} else {
@ -344,13 +354,6 @@ hfp_connection_t * handle_message(hfp_connection_t * context, uint8_t *packet, u
}
if (strncmp((char *)packet, HFP_Indicator, strlen(HFP_Indicator)) == 0){
// https://www.bluetooth.org/en-us/specification/assigned-numbers/hands-free-profile
/*
* 0x01 Enhanced Safety, on/off
* 0x02 Battery Level, 0-100
*/
// printf("Parsed %s, expected ("service",(0,1)),("call",(0,1)),("callsetup",(0,3)),("callheld",(0,2)),("signal",(0,5)),("roam",(0,1)),("battchg",(0,5))\n", HFP_Indicator);
offset = strlen(HFP_Indicator) + 1;
switch (context->state){
case HFP_W4_RETRIEVE_INDICATORS:
@ -358,11 +361,10 @@ hfp_connection_t * handle_message(hfp_connection_t * context, uint8_t *packet, u
context->remote_indicators_status = 0;
context->state = HFP_RETRIEVE_INDICATORS_STATUS;
break;
case HFP_W4_RETRIEVE_INDICATORS_STATUS:{
case HFP_W4_RETRIEVE_INDICATORS_STATUS:
hfp_parse_indicators_status(context, &packet[offset], size-offset);
context->state = HFP_ENABLE_INDICATORS_STATUS_UPDATE;
break;
}
default:
break;
}
@ -379,6 +381,12 @@ hfp_connection_t * handle_message(hfp_connection_t * context, uint8_t *packet, u
}
if (strncmp((char *)packet, HFP_Generic_Status_Indicator, strlen(HFP_Generic_Status_Indicator)) == 0){
// https://www.bluetooth.org/en-us/specification/assigned-numbers/hands-free-profile
/* HF Indicators
* 0x01 Enhanced Safety, on/off
* 0x02 Battery Level, 0-100
*/
offset = strlen(HFP_Generic_Status_Indicator) + 1; // +1 for =
char * token = strtok((char*)&packet[offset], ",");

View File

@ -132,8 +132,8 @@ int btstack_main(int argc, const char * argv[]){
l2cap_init();
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, 0x0009, codecs, sizeof(codecs), indicators, sizeof(indicators)/sizeof(uint16_t), 1);
// 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, 0x0009, codecs, sizeof(codecs), indicators, sizeof(indicators)/sizeof(uint16_t), 1);
hfp_register_packet_handler(packet_handler);