mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-30 16:20:24 +00:00
Merge branch 'master' of https://github.com/bluekitchen/btstack
This commit is contained in:
commit
cae709b1c0
80
src/hfp.c
80
src/hfp.c
@ -60,41 +60,83 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
void join(char * buffer, int buffer_size, int buffer_offset, uint8_t * values, int values_nr, int value_size){
|
||||
int req_size = values_nr * (value_size + 1);
|
||||
if (buffer_size - buffer_offset < req_size ) {
|
||||
log_error("join: buffer too small (size: %u. req: %u)", buffer_size, req_size);
|
||||
return;
|
||||
void join(char * buffer, int buffer_size, uint8_t * values, int values_nr){
|
||||
if (buffer_size < values_nr * 3) return;
|
||||
int i;
|
||||
int offset = 0;
|
||||
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;
|
||||
int i,j,k;
|
||||
k = 0;
|
||||
for (i = 0; i < values_nr-1; i++){
|
||||
for (j=0; j<value_size; j++){
|
||||
buffer[pos++] = values[k++];
|
||||
}
|
||||
buffer[pos++] = ',';
|
||||
if (i<values_nr){
|
||||
offset += snprintf(buffer+offset, buffer_size-offset, "%d", values[i]);
|
||||
}
|
||||
for (j=0; j<value_size; j++){
|
||||
buffer[pos++] = values[k++];
|
||||
}
|
||||
buffer[pos] = '\0';
|
||||
|
||||
offset += snprintf(buffer+offset, buffer_size-offset, "\r\n");
|
||||
buffer[offset] = 0;
|
||||
}
|
||||
|
||||
|
||||
static void hfp_emit_event(hfp_callback_t callback, uint8_t event_subtype, uint8_t value){
|
||||
if (!callback) return;
|
||||
uint8_t event[4];
|
||||
@ -141,7 +183,7 @@ static hfp_connection_t * create_hfp_connection_context(){
|
||||
context->state = HFP_IDLE;
|
||||
context->line_size = 0;
|
||||
|
||||
context->negotiated_codec = HFP_Codec_CSVD;
|
||||
context->negotiated_codec = HFP_Codec_CVSD;
|
||||
context->remote_supported_features = 0;
|
||||
context->remote_indicators_update_enabled = 0;
|
||||
context->remote_indicators_nr = 0;
|
||||
|
18
src/hfp.h
18
src/hfp.h
@ -94,18 +94,18 @@ extern "C" {
|
||||
#define HFP_Generic_Status_Indicator "+BIND"
|
||||
#define HFP_OK "OK"
|
||||
|
||||
#define HFP_Codec_CSVD 0x01
|
||||
#define HFP_Codec_CVSD 0x01
|
||||
#define HFP_Codec_mSBC 0x02
|
||||
|
||||
|
||||
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);
|
||||
@ -206,7 +207,10 @@ linked_list_t * hfp_get_connections();
|
||||
|
||||
// TODO: move to utils
|
||||
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_ag_feature(int index);
|
||||
|
||||
#if defined __cplusplus
|
||||
}
|
||||
|
205
src/hfp_hf.c
205
src/hfp_hf.c
@ -71,6 +71,33 @@ 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_codec_negotiation_feature(hfp_connection_t * connection){
|
||||
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 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);
|
||||
|
||||
@ -81,11 +108,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;
|
||||
@ -104,8 +126,8 @@ int hfp_hs_exchange_supported_features_cmd(uint16_t cid){
|
||||
|
||||
int hfp_hs_retrieve_codec_cmd(uint16_t cid){
|
||||
char buffer[30];
|
||||
int buffer_offset = sprintf(buffer, "AT%s=", HFP_Available_Codecs);
|
||||
join(buffer, sizeof(buffer), buffer_offset, hfp_codecs, hfp_codecs_nr, 1);
|
||||
int buffer_offset = snprintf(buffer, sizeof(buffer), "AT%s=", HFP_Available_Codecs);
|
||||
join(buffer+buffer_offset, sizeof(buffer)-buffer_offset, hfp_codecs, hfp_codecs_nr);
|
||||
// printf("retrieve_codec %s\n", buffer);
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
@ -125,16 +147,17 @@ 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);
|
||||
sprintf(buffer, "AT%s=?\r\n", HFP_Support_Call_Hold_And_Multiparty_Services);
|
||||
// printf("retrieve_can_hold_call %s\n", buffer);
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
@ -142,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){
|
||||
char buffer[30];
|
||||
int buffer_offset = sprintf(buffer, "AT%s=", HFP_Generic_Status_Indicator);
|
||||
join(buffer, sizeof(buffer), buffer_offset, hfp_indicators, hfp_indicators_nr, 2);
|
||||
int buffer_offset = snprintf(buffer, sizeof(buffer), "AT%s=", HFP_Generic_Status_Indicator);
|
||||
join(buffer+buffer_offset, sizeof(buffer)-buffer_offset, hfp_indicators, hfp_indicators_nr);
|
||||
// printf("list_supported_generic_status_indicators %s\n", buffer);
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
@ -162,26 +185,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:
|
||||
@ -189,9 +197,13 @@ static void hfp_run_for_context(hfp_connection_t * connection){
|
||||
if (!err) connection->state = HFP_W4_EXCHANGE_SUPPORTED_FEATURES;
|
||||
break;
|
||||
case HFP_NOTIFY_ON_CODECS:
|
||||
err = hfp_hs_retrieve_codec_cmd(connection->rfcomm_cid);
|
||||
if (!err) connection->state = HFP_W4_NOTIFY_ON_CODECS;
|
||||
break;
|
||||
if (has_codec_negotiation_feature(connection)){
|
||||
err = hfp_hs_retrieve_codec_cmd(connection->rfcomm_cid);
|
||||
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:
|
||||
err = hfp_hs_retrieve_indicators_cmd(connection->rfcomm_cid);
|
||||
if (!err) connection->state = HFP_W4_RETRIEVE_INDICATORS;
|
||||
@ -202,18 +214,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 +261,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++){
|
||||
@ -258,7 +287,7 @@ void hfp_parse_indicators(hfp_connection_t * context, uint8_t *packet, uint16_t
|
||||
i = 0;
|
||||
break;
|
||||
case 3: // min-range
|
||||
if (byte == ','){
|
||||
if (byte == ',' || byte == '-'){
|
||||
state++;
|
||||
min_range[i] = 0;
|
||||
i = 0;
|
||||
@ -284,7 +313,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));
|
||||
@ -293,39 +322,58 @@ 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){
|
||||
int offset = 0;
|
||||
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;
|
||||
|
||||
case HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS:
|
||||
context->state = HFP_ACTIVE;
|
||||
printf(" state Active! \n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
context->wait_ok = 0;
|
||||
return context;
|
||||
}
|
||||
}
|
||||
@ -333,24 +381,18 @@ 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);
|
||||
if (has_codec_negotiation_feature(context)){
|
||||
context->state = HFP_NOTIFY_ON_CODECS;
|
||||
} else {
|
||||
context->state = HFP_RETRIEVE_INDICATORS;
|
||||
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));
|
||||
}
|
||||
}
|
||||
context->state = HFP_NOTIFY_ON_CODECS;
|
||||
context->wait_ok = 1;
|
||||
return context;
|
||||
}
|
||||
|
||||
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 +400,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;
|
||||
}
|
||||
@ -372,29 +413,31 @@ 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){
|
||||
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;
|
||||
return context;
|
||||
}
|
||||
|
||||
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], ",");
|
||||
|
||||
int pos = 0;
|
||||
|
||||
switch (context->state){
|
||||
case HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS:
|
||||
while (token){
|
||||
printf("%s\n", token);
|
||||
context->remote_hf_indicators[pos++] = atoi(token);
|
||||
token = strtok(NULL, ",");
|
||||
}
|
||||
context->remote_hf_indicators_nr = pos;
|
||||
printf("Supported generic status indicators \n");
|
||||
hfp_parse_comma_separated_tuple(context, &packet[offset], size-offset);
|
||||
context->remote_hf_indicators_status = 0;
|
||||
context->state = HFP_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS;
|
||||
break;
|
||||
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);
|
||||
int status = atoi(strtok(NULL, ","));
|
||||
if (!status) break;
|
||||
|
@ -74,7 +74,7 @@ const char hfp_hf_service_name[] = "BTstack HF Test";
|
||||
|
||||
static bd_addr_t pts_addr = {0x00,0x1b,0xDC,0x07,0x32,0xEF};
|
||||
static bd_addr_t local_mac = {0x04, 0x0C, 0xCE, 0xE4, 0x85, 0xD3};
|
||||
|
||||
static bd_addr_t phone = {0xD8,0xBb,0x2C,0xDf,0xF1,0x08};
|
||||
// prototypes
|
||||
static void show_usage();
|
||||
|
||||
@ -101,8 +101,8 @@ static int stdin_process(struct data_source *ds){
|
||||
hfp_hf_connect(pts_addr);
|
||||
break;
|
||||
case 'e':
|
||||
printf("Establishing HFP connection to local mac %s...\n", bd_addr_to_str(local_mac));
|
||||
hfp_hf_connect(local_mac);
|
||||
printf("Establishing HFP connection to %s...\n", bd_addr_to_str(phone));
|
||||
hfp_hf_connect(phone);
|
||||
break;
|
||||
case 'd':
|
||||
printf("Releasing HFP connection.\n");
|
||||
@ -126,14 +126,14 @@ void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
|
||||
int btstack_main(int argc, const char * argv[]){
|
||||
// init L2CAP
|
||||
uint8_t codecs[1] = {HFP_Codec_CSVD};
|
||||
uint8_t codecs[1] = {HFP_Codec_CVSD};
|
||||
uint16_t indicators[1] = {0x01};
|
||||
|
||||
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, 182, codecs, sizeof(codecs), indicators, sizeof(indicators)/sizeof(uint16_t), 1);
|
||||
|
||||
hfp_register_packet_handler(packet_handler);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user