mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-25 16:43:28 +00:00
hfp tested with mac und iphone, without generic indicators
This commit is contained in:
parent
9e60d66a64
commit
17c0eace3b
31
src/hfp.c
31
src/hfp.c
@ -121,27 +121,22 @@ int send_str_over_rfcomm(uint16_t cid, char * command){
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
void join(char * buffer, int buffer_size, int buffer_offset, uint8_t * values, int values_nr, int value_size){
|
void join(char * buffer, int buffer_size, uint8_t * values, int values_nr){
|
||||||
int req_size = values_nr * (value_size + 1);
|
if (buffer_size < values_nr * 3) return;
|
||||||
if (buffer_size - buffer_offset < req_size ) {
|
int i;
|
||||||
log_error("join: buffer too small (size: %u. req: %u)", buffer_size, req_size);
|
int offset = 0;
|
||||||
return;
|
for (i = 0; i < values_nr-1; i++) {
|
||||||
|
offset += snprintf(buffer+offset, buffer_size-offset, "%d,", values[i]); // puts string into buffer
|
||||||
}
|
}
|
||||||
int pos = buffer_offset;
|
if (i<values_nr){
|
||||||
int i,j,k;
|
offset += snprintf(buffer+offset, buffer_size-offset, "%d", values[i]);
|
||||||
k = 0;
|
|
||||||
for (i = 0; i < values_nr-1; i++){
|
|
||||||
for (j=0; j<value_size; j++){
|
|
||||||
buffer[pos++] = values[k++];
|
|
||||||
}
|
|
||||||
buffer[pos++] = ',';
|
|
||||||
}
|
}
|
||||||
for (j=0; j<value_size; j++){
|
|
||||||
buffer[pos++] = values[k++];
|
offset += snprintf(buffer+offset, buffer_size-offset, "\r\n");
|
||||||
}
|
buffer[offset] = 0;
|
||||||
buffer[pos] = '\0';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void hfp_emit_event(hfp_callback_t callback, uint8_t event_subtype, uint8_t value){
|
static void hfp_emit_event(hfp_callback_t callback, uint8_t event_subtype, uint8_t value){
|
||||||
if (!callback) return;
|
if (!callback) return;
|
||||||
uint8_t event[4];
|
uint8_t event[4];
|
||||||
@ -188,7 +183,7 @@ static hfp_connection_t * create_hfp_connection_context(){
|
|||||||
context->state = HFP_IDLE;
|
context->state = HFP_IDLE;
|
||||||
context->line_size = 0;
|
context->line_size = 0;
|
||||||
|
|
||||||
context->negotiated_codec = HFP_Codec_CSVD;
|
context->negotiated_codec = HFP_Codec_CVSD;
|
||||||
context->remote_supported_features = 0;
|
context->remote_supported_features = 0;
|
||||||
context->remote_indicators_update_enabled = 0;
|
context->remote_indicators_update_enabled = 0;
|
||||||
context->remote_indicators_nr = 0;
|
context->remote_indicators_nr = 0;
|
||||||
|
@ -207,7 +207,7 @@ linked_list_t * hfp_get_connections();
|
|||||||
|
|
||||||
// TODO: move to utils
|
// TODO: move to utils
|
||||||
int send_str_over_rfcomm(uint16_t cid, char * command);
|
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);
|
void join(char * buffer, int buffer_size, uint8_t * values, int values_nr);
|
||||||
|
|
||||||
const char * hfp_hf_feature(int index);
|
const char * hfp_hf_feature(int index);
|
||||||
const char * hfp_ag_feature(int index);
|
const char * hfp_ag_feature(int index);
|
||||||
|
101
src/hfp_hf.c
101
src/hfp_hf.c
@ -75,16 +75,28 @@ static int get_bit(uint16_t bitmap, int position){
|
|||||||
return (bitmap >> position) & 1;
|
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){
|
int has_codec_negotiation_feature(hfp_connection_t * connection){
|
||||||
return get_bit(hfp_supported_features,7) && get_bit(connection->remote_supported_features,9);
|
int hf = get_bit(hfp_supported_features,7);
|
||||||
|
int ag = get_bit(connection->remote_supported_features,9);
|
||||||
|
printf("\ncodec_negotiation_feature: HF %d, AG %d\n", hf, ag);
|
||||||
|
return hf && ag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int has_call_waiting_and_3way_calling_feature(hfp_connection_t * connection){
|
||||||
|
int hf = get_bit(hfp_supported_features,1);
|
||||||
|
int ag = get_bit(connection->remote_supported_features,0);
|
||||||
|
printf("\n3way_calling_feature: HF %d, AG %d\n", hf, ag);
|
||||||
|
return hf && ag;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int has_hf_indicators_feature(hfp_connection_t * connection){
|
int has_hf_indicators_feature(hfp_connection_t * connection){
|
||||||
return get_bit(hfp_supported_features,8) && get_bit(connection->remote_supported_features,10);
|
|
||||||
|
int hf = get_bit(hfp_supported_features,8);
|
||||||
|
int ag = get_bit(connection->remote_supported_features,10);
|
||||||
|
printf("\nhf_indicators_feature: HF %d, AG %d\n", hf, ag);
|
||||||
|
return hf && ag;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
|
static void packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
|
||||||
@ -114,8 +126,8 @@ int hfp_hs_exchange_supported_features_cmd(uint16_t cid){
|
|||||||
|
|
||||||
int hfp_hs_retrieve_codec_cmd(uint16_t cid){
|
int hfp_hs_retrieve_codec_cmd(uint16_t cid){
|
||||||
char buffer[30];
|
char buffer[30];
|
||||||
int buffer_offset = sprintf(buffer, "AT%s=", HFP_Available_Codecs);
|
int buffer_offset = snprintf(buffer, sizeof(buffer), "AT%s=", HFP_Available_Codecs);
|
||||||
join(buffer, sizeof(buffer), buffer_offset, hfp_codecs, hfp_codecs_nr, 1);
|
join(buffer+buffer_offset, sizeof(buffer)-buffer_offset, hfp_codecs, hfp_codecs_nr);
|
||||||
// printf("retrieve_codec %s\n", buffer);
|
// printf("retrieve_codec %s\n", buffer);
|
||||||
return send_str_over_rfcomm(cid, buffer);
|
return send_str_over_rfcomm(cid, buffer);
|
||||||
}
|
}
|
||||||
@ -145,7 +157,7 @@ int hfp_hs_toggle_indicator_status_update_cmd(uint16_t cid, uint8_t activate){
|
|||||||
|
|
||||||
int hfp_hs_retrieve_can_hold_call_cmd(uint16_t cid){
|
int hfp_hs_retrieve_can_hold_call_cmd(uint16_t cid){
|
||||||
char buffer[20];
|
char buffer[20];
|
||||||
sprintf(buffer, "AT%s\r\n", HFP_Support_Call_Hold_And_Multiparty_Services);
|
sprintf(buffer, "AT%s=?\r\n", HFP_Support_Call_Hold_And_Multiparty_Services);
|
||||||
// printf("retrieve_can_hold_call %s\n", buffer);
|
// printf("retrieve_can_hold_call %s\n", buffer);
|
||||||
return send_str_over_rfcomm(cid, buffer);
|
return send_str_over_rfcomm(cid, buffer);
|
||||||
}
|
}
|
||||||
@ -153,8 +165,8 @@ int hfp_hs_retrieve_can_hold_call_cmd(uint16_t cid){
|
|||||||
|
|
||||||
int hfp_hs_list_supported_generic_status_indicators_cmd(uint16_t cid){
|
int hfp_hs_list_supported_generic_status_indicators_cmd(uint16_t cid){
|
||||||
char buffer[30];
|
char buffer[30];
|
||||||
int buffer_offset = sprintf(buffer, "AT%s=", HFP_Generic_Status_Indicator);
|
int buffer_offset = snprintf(buffer, sizeof(buffer), "AT%s=", HFP_Generic_Status_Indicator);
|
||||||
join(buffer, sizeof(buffer), buffer_offset, hfp_indicators, hfp_indicators_nr, 2);
|
join(buffer+buffer_offset, sizeof(buffer)-buffer_offset, hfp_indicators, hfp_indicators_nr);
|
||||||
// printf("list_supported_generic_status_indicators %s\n", buffer);
|
// printf("list_supported_generic_status_indicators %s\n", buffer);
|
||||||
return send_str_over_rfcomm(cid, buffer);
|
return send_str_over_rfcomm(cid, buffer);
|
||||||
}
|
}
|
||||||
@ -185,9 +197,13 @@ static void hfp_run_for_context(hfp_connection_t * connection){
|
|||||||
if (!err) connection->state = HFP_W4_EXCHANGE_SUPPORTED_FEATURES;
|
if (!err) connection->state = HFP_W4_EXCHANGE_SUPPORTED_FEATURES;
|
||||||
break;
|
break;
|
||||||
case HFP_NOTIFY_ON_CODECS:
|
case HFP_NOTIFY_ON_CODECS:
|
||||||
err = hfp_hs_retrieve_codec_cmd(connection->rfcomm_cid);
|
if (has_codec_negotiation_feature(connection)){
|
||||||
if (!err) connection->state = HFP_W4_NOTIFY_ON_CODECS;
|
err = hfp_hs_retrieve_codec_cmd(connection->rfcomm_cid);
|
||||||
break;
|
if (!err) connection->state = HFP_W4_NOTIFY_ON_CODECS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
printf("fall through to HFP_RETRIEVE_INDICATORS (no codec feature)\n");
|
||||||
|
connection->state = HFP_RETRIEVE_INDICATORS;
|
||||||
case HFP_RETRIEVE_INDICATORS:
|
case HFP_RETRIEVE_INDICATORS:
|
||||||
err = hfp_hs_retrieve_indicators_cmd(connection->rfcomm_cid);
|
err = hfp_hs_retrieve_indicators_cmd(connection->rfcomm_cid);
|
||||||
if (!err) connection->state = HFP_W4_RETRIEVE_INDICATORS;
|
if (!err) connection->state = HFP_W4_RETRIEVE_INDICATORS;
|
||||||
@ -306,10 +322,38 @@ void hfp_parse_indicators_status(hfp_connection_t * context, uint8_t *packet, ui
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hfp_parse_comma_separated_tuple(hfp_connection_t * context, uint8_t *packet, uint16_t size){
|
||||||
|
char feature[5];
|
||||||
|
int i, pos;
|
||||||
|
int state = 0;
|
||||||
|
for (pos = 0; pos < size; pos++){
|
||||||
|
uint8_t byte = packet[pos];
|
||||||
|
|
||||||
|
switch (state){
|
||||||
|
case 0: // pre-feature
|
||||||
|
if (byte != '(') break;
|
||||||
|
state++;
|
||||||
|
i = 0;
|
||||||
|
break;
|
||||||
|
case 1: // feature
|
||||||
|
if (byte == ',' || byte == ')'){
|
||||||
|
feature[i] = 0;
|
||||||
|
printf("call_hold_and_multiparty value: %s\n", feature);
|
||||||
|
i = 0;
|
||||||
|
if (byte == ')') state++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
feature[i++] = byte;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
hfp_connection_t * handle_message(hfp_connection_t * context, uint8_t *packet, uint16_t size){
|
hfp_connection_t * handle_message(hfp_connection_t * context, uint8_t *packet, uint16_t size){
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
printf("Parsed %s, state %u\n", (char *)packet, context->state);
|
|
||||||
|
|
||||||
if (context->wait_ok){
|
if (context->wait_ok){
|
||||||
if (strncmp((char *)packet, HFP_OK, strlen(HFP_OK)) == 0){
|
if (strncmp((char *)packet, HFP_OK, strlen(HFP_OK)) == 0){
|
||||||
context->wait_ok = 0;
|
context->wait_ok = 0;
|
||||||
@ -326,7 +370,6 @@ hfp_connection_t * handle_message(hfp_connection_t * context, uint8_t *packet, u
|
|||||||
|
|
||||||
case HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS:
|
case HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS:
|
||||||
context->state = HFP_ACTIVE;
|
context->state = HFP_ACTIVE;
|
||||||
printf(" state Active! \n");
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -344,11 +387,7 @@ hfp_connection_t * handle_message(hfp_connection_t * context, uint8_t *packet, u
|
|||||||
printf("AG supported feature: %s\n", hfp_ag_feature(i));
|
printf("AG supported feature: %s\n", hfp_ag_feature(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (has_codec_negotiation_feature(context)){
|
context->state = HFP_NOTIFY_ON_CODECS;
|
||||||
context->state = HFP_NOTIFY_ON_CODECS;
|
|
||||||
} else {
|
|
||||||
context->state = HFP_RETRIEVE_INDICATORS;
|
|
||||||
}
|
|
||||||
context->wait_ok = 1;
|
context->wait_ok = 1;
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
@ -374,8 +413,8 @@ hfp_connection_t * handle_message(hfp_connection_t * context, uint8_t *packet, u
|
|||||||
|
|
||||||
if (strncmp((char *)packet, HFP_Support_Call_Hold_And_Multiparty_Services, strlen(HFP_Support_Call_Hold_And_Multiparty_Services)) == 0){
|
if (strncmp((char *)packet, HFP_Support_Call_Hold_And_Multiparty_Services, strlen(HFP_Support_Call_Hold_And_Multiparty_Services)) == 0){
|
||||||
offset = strlen(HFP_Support_Call_Hold_And_Multiparty_Services) + 1; // +1 for =
|
offset = strlen(HFP_Support_Call_Hold_And_Multiparty_Services) + 1; // +1 for =
|
||||||
printf("AT+CHLD %s, offset %u, size %u\n", (char *)&packet[offset], offset, size);
|
hfp_parse_comma_separated_tuple(context, &packet[offset], size-offset);
|
||||||
|
context->state = HFP_LIST_GENERIC_STATUS_INDICATORS;
|
||||||
context->wait_ok = 1;
|
context->wait_ok = 1;
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
@ -386,23 +425,19 @@ hfp_connection_t * handle_message(hfp_connection_t * context, uint8_t *packet, u
|
|||||||
* 0x01 Enhanced Safety, on/off
|
* 0x01 Enhanced Safety, on/off
|
||||||
* 0x02 Battery Level, 0-100
|
* 0x02 Battery Level, 0-100
|
||||||
*/
|
*/
|
||||||
|
|
||||||
offset = strlen(HFP_Generic_Status_Indicator) + 1; // +1 for =
|
offset = strlen(HFP_Generic_Status_Indicator) + 1; // +1 for =
|
||||||
char * token = strtok((char*)&packet[offset], ",");
|
|
||||||
|
|
||||||
int pos = 0;
|
|
||||||
switch (context->state){
|
switch (context->state){
|
||||||
case HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS:
|
case HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS:
|
||||||
while (token){
|
printf("Supported generic status indicators \n");
|
||||||
printf("%s\n", token);
|
hfp_parse_comma_separated_tuple(context, &packet[offset], size-offset);
|
||||||
context->remote_hf_indicators[pos++] = atoi(token);
|
|
||||||
token = strtok(NULL, ",");
|
|
||||||
}
|
|
||||||
context->remote_hf_indicators_nr = pos;
|
|
||||||
context->remote_hf_indicators_status = 0;
|
context->remote_hf_indicators_status = 0;
|
||||||
context->state = HFP_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS;
|
context->state = HFP_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS;
|
||||||
break;
|
break;
|
||||||
case HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS:{
|
case HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS:{
|
||||||
|
printf("Supported initial state generic status indicators \n");
|
||||||
|
char * token = strtok((char*)&packet[offset], ",");
|
||||||
|
|
||||||
uint16_t indicator = atoi(token);
|
uint16_t indicator = atoi(token);
|
||||||
int status = atoi(strtok(NULL, ","));
|
int status = atoi(strtok(NULL, ","));
|
||||||
if (!status) break;
|
if (!status) break;
|
||||||
|
@ -133,7 +133,7 @@ int btstack_main(int argc, const char * argv[]){
|
|||||||
rfcomm_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, 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, 182, codecs, sizeof(codecs), indicators, sizeof(indicators)/sizeof(uint16_t), 1);
|
||||||
|
|
||||||
hfp_register_packet_handler(packet_handler);
|
hfp_register_packet_handler(packet_handler);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user