mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-01-25 18:35:17 +00:00
Merge branch 'master' of https://github.com/bluekitchen/btstack
This commit is contained in:
commit
d11d38848c
160
src/hfp.c
160
src/hfp.c
@ -121,8 +121,8 @@ int send_str_over_rfcomm(uint16_t cid, char * command){
|
||||
return err;
|
||||
}
|
||||
|
||||
void join(char * buffer, int buffer_size, uint8_t * values, int values_nr){
|
||||
if (buffer_size < values_nr * 3) return;
|
||||
int join(char * buffer, int buffer_size, uint8_t * values, int values_nr){
|
||||
if (buffer_size < values_nr * 3) return 0;
|
||||
int i;
|
||||
int offset = 0;
|
||||
for (i = 0; i < values_nr-1; i++) {
|
||||
@ -131,9 +131,7 @@ void join(char * buffer, int buffer_size, uint8_t * values, int values_nr){
|
||||
if (i<values_nr){
|
||||
offset += snprintf(buffer+offset, buffer_size-offset, "%d", values[i]);
|
||||
}
|
||||
|
||||
offset += snprintf(buffer+offset, buffer_size-offset, "\r\n");
|
||||
buffer[offset] = 0;
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
||||
@ -188,8 +186,8 @@ static hfp_connection_t * create_hfp_connection_context(){
|
||||
context->negotiated_codec = HFP_CODEC_CVSD;
|
||||
context->remote_supported_features = 0;
|
||||
context->remote_indicators_update_enabled = 0;
|
||||
context->remote_indicators_nr = 0;
|
||||
context->remote_indicators_status = 0;
|
||||
|
||||
context->ag_indicators_nr = 0;
|
||||
|
||||
linked_list_add(&hfp_connections, (linked_item_t*)context);
|
||||
return context;
|
||||
@ -413,6 +411,140 @@ hfp_connection_t * hfp_handle_hci_event(uint8_t packet_type, uint8_t *packet, ui
|
||||
return context;
|
||||
}
|
||||
|
||||
void update_command(hfp_connection_t * context);
|
||||
|
||||
void hfp_parse(hfp_connection_t * context, uint8_t byte){
|
||||
int i;
|
||||
if (byte == ' ') return;
|
||||
if ( (byte == '\n' || byte == '\r') && context->parser_state > HFP_PARSER_CMD_SEQUENCE) return;
|
||||
|
||||
switch (context->parser_state){
|
||||
case HFP_PARSER_CMD_HEADER: // header
|
||||
if (byte == ':'){
|
||||
context->parser_state = HFP_PARSER_CMD_SEQUENCE;
|
||||
context->line_buffer[context->line_size] = 0;
|
||||
context->line_size = 0;
|
||||
update_command(context);
|
||||
return;
|
||||
}
|
||||
if (byte == '\n' || byte == '\r'){
|
||||
// received OK
|
||||
context->line_buffer[context->line_size] = 0;
|
||||
context->line_size = 0;
|
||||
update_command(context);
|
||||
return;
|
||||
}
|
||||
context->line_buffer[context->line_size++] = byte;
|
||||
break;
|
||||
|
||||
case HFP_PARSER_CMD_SEQUENCE: // parse comma separated sequence, ignore breacktes
|
||||
if (byte == '"'){ // indicators
|
||||
context->parser_state = HFP_PARSER_CMD_INDICATOR_NAME;
|
||||
context->line_size = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (byte == '(' ){ // tuple separated mit comma
|
||||
break;
|
||||
}
|
||||
|
||||
if (byte == ',' || byte == '\n' || byte == '\r' || byte == ')'){
|
||||
context->line_buffer[context->line_size] = 0;
|
||||
context->line_size = 0;
|
||||
switch (context->state){
|
||||
case HFP_W4_EXCHANGE_SUPPORTED_FEATURES:
|
||||
context->remote_supported_features = atoi((char *)&context->line_buffer[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->command = HFP_CMD_NONE;
|
||||
context->parser_state = HFP_PARSER_CMD_HEADER;
|
||||
break;
|
||||
case HFP_W4_RETRIEVE_INDICATORS:
|
||||
break;
|
||||
case HFP_W4_RETRIEVE_INDICATORS_STATUS:
|
||||
printf("Indicator with status: %s\n", context->line_buffer);
|
||||
break;
|
||||
case HFP_W4_RETRIEVE_CAN_HOLD_CALL:
|
||||
printf("Support call hold: %s\n", context->line_buffer);
|
||||
break;
|
||||
case HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS: // comma separated ints
|
||||
printf("Generic status indicator: %s\n", context->line_buffer);
|
||||
break;
|
||||
case HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS:
|
||||
printf("Generic status indicator: %s, ", context->line_buffer);
|
||||
context->parser_state = HFP_PARSER_CMD_INITITAL_STATE_GENERIC_STATUS_INDICATORS;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (byte == '\n' || byte == '\r'){
|
||||
context->command = HFP_CMD_NONE;
|
||||
context->parser_state = HFP_PARSER_CMD_HEADER;
|
||||
break;
|
||||
}
|
||||
if (byte == ')' && context->state == HFP_W4_RETRIEVE_CAN_HOLD_CALL){ // tuple separated mit comma
|
||||
context->command = HFP_CMD_NONE;
|
||||
context->parser_state = HFP_PARSER_CMD_HEADER;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
context->line_buffer[context->line_size++] = byte;
|
||||
break;
|
||||
case HFP_PARSER_CMD_INITITAL_STATE_GENERIC_STATUS_INDICATORS:
|
||||
if (byte == '\n' || byte == '\r'){
|
||||
context->line_buffer[context->line_size] = 0;
|
||||
context->line_size = 0;
|
||||
context->command = HFP_CMD_NONE;
|
||||
context->parser_state = HFP_PARSER_CMD_HEADER;
|
||||
printf("status %s [0-dissabled, 1-enabled]\n", context->line_buffer);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case HFP_PARSER_CMD_INDICATOR_NAME: // parse indicator name
|
||||
if (byte == '"'){
|
||||
context->line_buffer[context->line_size] = 0;
|
||||
printf("Indicator %d: %s (", context->ag_indicators_nr, context->line_buffer);
|
||||
context->line_size = 0;
|
||||
break;
|
||||
}
|
||||
if (byte == '('){ // parse indicator range
|
||||
context->parser_state = HFP_PARSER_CMD_INDICATOR_MIN_RANGE;
|
||||
break;
|
||||
}
|
||||
context->line_buffer[context->line_size++] = byte;
|
||||
break;
|
||||
case HFP_PARSER_CMD_INDICATOR_MIN_RANGE:
|
||||
if (byte == ',' || byte == '-'){ // end min_range
|
||||
context->parser_state = HFP_PARSER_CMD_INDICATOR_MAX_RANGE;
|
||||
context->line_buffer[context->line_size] = 0;
|
||||
printf("%d, ", atoi((char *)&context->line_buffer[0]));
|
||||
context->line_size = 0;
|
||||
break;
|
||||
}
|
||||
// min. range
|
||||
context->line_buffer[context->line_size++] = byte;
|
||||
break;
|
||||
case HFP_PARSER_CMD_INDICATOR_MAX_RANGE:
|
||||
if (byte == ')'){ // end max_range
|
||||
context->parser_state = HFP_PARSER_CMD_SEQUENCE;
|
||||
|
||||
context->line_buffer[context->line_size] = 0;
|
||||
printf("%d)\n", atoi((char *)&context->line_buffer[0]));
|
||||
context->line_size = 0;
|
||||
context->ag_indicators_nr+=1;
|
||||
break;
|
||||
}
|
||||
//
|
||||
context->line_buffer[context->line_size++] = byte;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void hfp_init(uint16_t rfcomm_channel_nr){
|
||||
rfcomm_register_service_internal(NULL, rfcomm_channel_nr, 0xffff);
|
||||
sdp_query_rfcomm_register_callback(handle_query_rfcomm_event, NULL);
|
||||
@ -447,3 +579,17 @@ void hfp_set_codec(hfp_connection_t * context, uint8_t *packet, uint16_t size){
|
||||
}
|
||||
printf("Negotiated Codec 0x%02x\n", context->negotiated_codec);
|
||||
}
|
||||
|
||||
// UTILS
|
||||
int get_bit(uint16_t bitmap, int position){
|
||||
return (bitmap >> position) & 1;
|
||||
}
|
||||
|
||||
int store_bit(uint32_t bitmap, int position, uint8_t value){
|
||||
if (value){
|
||||
bitmap |= 1 << position;
|
||||
} else {
|
||||
bitmap &= ~ (1 << position);
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
35
src/hfp.h
35
src/hfp.h
@ -97,8 +97,9 @@ extern "C" {
|
||||
#define HFP_DEFAULT_AG_SUPPORTED_FEATURES 0x0009
|
||||
|
||||
#define HFP_MAX_NUM_CODECS 20
|
||||
#define HFP_MAX_NUM_INDICATORS 20
|
||||
#define HFP_MAX_INDICATOR_DESC_SIZE 200 // TODO: change to 10
|
||||
#define HFP_MAX_NUM_AG_INDICATORS 20
|
||||
#define HFP_MAX_NUM_HF_INDICATORS 20
|
||||
#define HFP_MAX_INDICATOR_DESC_SIZE 10
|
||||
|
||||
#define HFP_SUPPORTED_FEATURES "+BRSF"
|
||||
#define HFP_AVAILABLE_CODECS "+BAC"
|
||||
@ -175,6 +176,19 @@ typedef enum {
|
||||
|
||||
typedef void (*hfp_callback_t)(uint8_t * event, uint16_t event_size);
|
||||
|
||||
typedef struct{
|
||||
uint16_t uuid;
|
||||
uint8_t state;
|
||||
uint8_t initial_state;
|
||||
} hfp_hf_indicator_t;
|
||||
|
||||
typedef struct{
|
||||
uint8_t index;
|
||||
char name[HFP_MAX_INDICATOR_DESC_SIZE];
|
||||
uint8_t min_range;
|
||||
uint8_t max_range;
|
||||
uint8_t status;
|
||||
} hfp_ag_indicator_t;
|
||||
|
||||
typedef struct hfp_connection {
|
||||
linked_item_t item;
|
||||
@ -191,19 +205,13 @@ typedef struct hfp_connection {
|
||||
uint16_t rfcomm_channel_nr;
|
||||
uint16_t rfcomm_cid;
|
||||
|
||||
int ag_indicators_nr;
|
||||
|
||||
// Retrieved during connection setup, not used yet
|
||||
uint8_t negotiated_codec;
|
||||
|
||||
uint32_t remote_supported_features;
|
||||
uint8_t remote_indicators_update_enabled;
|
||||
int remote_indicators_nr;
|
||||
char remote_indicators[20][HFP_MAX_INDICATOR_DESC_SIZE];
|
||||
int remote_indicators_range[20][2];
|
||||
|
||||
uint32_t remote_indicators_status;
|
||||
|
||||
uint8_t remote_hf_indicators_nr;
|
||||
uint16_t remote_hf_indicators[20];
|
||||
uint32_t remote_hf_indicators_status;
|
||||
|
||||
hfp_callback_t callback;
|
||||
} hfp_connection_t;
|
||||
@ -217,10 +225,13 @@ void hfp_connect(bd_addr_t bd_addr, uint16_t service_uuid);
|
||||
|
||||
hfp_connection_t * provide_hfp_connection_context_for_rfcomm_cid(uint16_t cid);
|
||||
linked_list_t * hfp_get_connections();
|
||||
void hfp_parse(hfp_connection_t * context, uint8_t byte);
|
||||
|
||||
// TODO: move to utils
|
||||
int send_str_over_rfcomm(uint16_t cid, char * command);
|
||||
void join(char * buffer, int buffer_size, uint8_t * values, int values_nr);
|
||||
int join(char * buffer, int buffer_size, uint8_t * values, int values_nr);
|
||||
int get_bit(uint16_t bitmap, int position);
|
||||
int store_bit(uint32_t bitmap, int position, uint8_t value);
|
||||
|
||||
const char * hfp_hf_feature(int index);
|
||||
const char * hfp_ag_feature(int index);
|
||||
|
299
src/hfp_ag.c
299
src/hfp_ag.c
@ -62,10 +62,19 @@
|
||||
#include "hfp_ag.h"
|
||||
|
||||
static const char default_hfp_ag_service_name[] = "Voice gateway";
|
||||
static uint16_t hfp_supported_features = HFP_DEFAULT_HF_SUPPORTED_FEATURES;
|
||||
static uint16_t hfp_supported_features = HFP_DEFAULT_AG_SUPPORTED_FEATURES;
|
||||
static uint8_t hfp_codecs_nr = 0;
|
||||
static uint8_t hfp_codecs[HFP_MAX_NUM_CODECS];
|
||||
|
||||
static uint8_t hfp_hf_indicators_nr = 0;
|
||||
static hfp_hf_indicator_t hfp_hf_indicators[HFP_MAX_NUM_HF_INDICATORS];
|
||||
|
||||
static int hfp_ag_indicators_nr = 0;
|
||||
static hfp_ag_indicator_t hfp_ag_indicators[HFP_MAX_NUM_AG_INDICATORS];
|
||||
|
||||
static int hfp_ag_call_hold_services_nr = 0;
|
||||
static char *hfp_ag_call_hold_services[6];
|
||||
|
||||
static void packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
|
||||
|
||||
void hfp_ag_create_service(uint8_t * service, int rfcomm_channel_nr, const char * name, uint8_t ability_to_reject_call, uint16_t supported_features){
|
||||
@ -82,54 +91,295 @@ void hfp_ag_create_service(uint8_t * service, int rfcomm_channel_nr, const char
|
||||
*/
|
||||
}
|
||||
|
||||
static void hfp_run(hfp_connection_t * connection){
|
||||
if (!connection) return;
|
||||
int hfp_ag_exchange_supported_features_cmd(uint16_t cid){
|
||||
char buffer[20];
|
||||
sprintf(buffer, "%s=%d\r\nOK\r\n", HFP_SUPPORTED_FEATURES, hfp_supported_features);
|
||||
// printf("exchange_supported_features %s\n", buffer);
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
int hfp_ag_ok(uint16_t cid){
|
||||
char buffer[5];
|
||||
sprintf(buffer, "OK\r\n");
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
int hfp_ag_retrieve_codec_cmd(uint16_t cid){
|
||||
return hfp_ag_ok(cid);
|
||||
}
|
||||
|
||||
int hfp_ag_indicators_join(char * buffer, int buffer_size){
|
||||
if (buffer_size < hfp_ag_indicators_nr * (1 + sizeof(hfp_ag_indicator_t))) return 0;
|
||||
int i;
|
||||
int offset = 0;
|
||||
for (i = 0; i < hfp_ag_indicators_nr-1; i++) {
|
||||
offset += snprintf(buffer+offset, buffer_size-offset, "\"%s\",(%d,%d),", hfp_ag_indicators[i].name, hfp_ag_indicators[i].min_range, hfp_ag_indicators[i].max_range);;
|
||||
}
|
||||
if (i<hfp_ag_indicators_nr){
|
||||
offset += snprintf(buffer+offset, buffer_size-offset, "\"%s\",(%d,%d)", hfp_ag_indicators[i].name, hfp_ag_indicators[i].min_range, hfp_ag_indicators[i].max_range);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
int hfp_hf_indicators_join(char * buffer, int buffer_size){
|
||||
if (buffer_size < hfp_ag_indicators_nr * 3) return 0;
|
||||
int i;
|
||||
int offset = 0;
|
||||
for (i = 0; i < hfp_ag_indicators_nr-1; i++) {
|
||||
offset += snprintf(buffer+offset, buffer_size-offset, "%d,", hfp_hf_indicators[i].uuid);
|
||||
}
|
||||
if (i<hfp_ag_indicators_nr){
|
||||
offset += snprintf(buffer+offset, buffer_size-offset, "%d,", hfp_hf_indicators[i].uuid);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
int hfp_hf_indicators_initial_status_join(char * buffer, int buffer_size){
|
||||
if (buffer_size < hfp_hf_indicators_nr * 3) return 0;
|
||||
int i;
|
||||
int offset = 0;
|
||||
for (i = 0; i < hfp_hf_indicators_nr; i++) {
|
||||
offset += snprintf(buffer+offset, buffer_size-offset, "%s=%d,%d\r\n", HFP_GENERIC_STATUS_INDICATOR, hfp_hf_indicators[i].uuid, hfp_hf_indicators[i].initial_state);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
int hfp_ag_indicators_status_join(char * buffer, int buffer_size){
|
||||
if (buffer_size < hfp_ag_indicators_nr * 3) return 0;
|
||||
int i;
|
||||
int offset = 0;
|
||||
for (i = 0; i < hfp_ag_indicators_nr-1; i++) {
|
||||
offset += snprintf(buffer+offset, buffer_size-offset, "%d,", hfp_ag_indicators[i].status);
|
||||
}
|
||||
if (i<hfp_ag_indicators_nr){
|
||||
offset += snprintf(buffer+offset, buffer_size-offset, "%d", hfp_ag_indicators[i].status);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
int hfp_ag_call_services_join(char * buffer, int buffer_size){
|
||||
if (buffer_size < hfp_ag_call_hold_services_nr * 3) return 0;
|
||||
int i;
|
||||
int offset = 0;
|
||||
for (i = 0; i < hfp_ag_call_hold_services_nr-1; i++) {
|
||||
offset += snprintf(buffer+offset, buffer_size-offset, "%s,", hfp_ag_call_hold_services[i]);
|
||||
}
|
||||
if (i<hfp_ag_call_hold_services_nr){
|
||||
offset += snprintf(buffer+offset, buffer_size-offset, "%s", hfp_ag_call_hold_services[i]);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
int hfp_ag_retrieve_indicators_cmd(uint16_t cid){
|
||||
char buffer[150];
|
||||
int offset = snprintf(buffer, sizeof(buffer), "%s=", HFP_INDICATOR);
|
||||
offset += hfp_ag_indicators_join(buffer+offset, sizeof(buffer)-offset);
|
||||
offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\nOK\r\n");
|
||||
buffer[offset] = 0;
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
int hfp_ag_retrieve_indicators_status_cmd(uint16_t cid){
|
||||
char buffer[20];
|
||||
int offset = snprintf(buffer, sizeof(buffer), "%s=", HFP_INDICATOR);
|
||||
offset += hfp_ag_indicators_status_join(buffer+offset, sizeof(buffer)-offset);
|
||||
offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\nOK\r\n");
|
||||
buffer[offset] = 0;
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
int hfp_ag_toggle_indicator_status_update_cmd(uint16_t cid, uint8_t activate){
|
||||
// AT%s=3,0,0,%d\r\n
|
||||
return hfp_ag_ok(cid);
|
||||
}
|
||||
|
||||
|
||||
int hfp_ag_retrieve_can_hold_call_cmd(uint16_t cid){
|
||||
char buffer[20];
|
||||
int offset = snprintf(buffer, sizeof(buffer), "%s=", HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES);
|
||||
offset += hfp_ag_call_services_join(buffer+offset, sizeof(buffer)-offset);
|
||||
offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\nOK\r\n");
|
||||
buffer[offset] = 0;
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
|
||||
int hfp_ag_list_supported_generic_status_indicators_cmd(uint16_t cid){
|
||||
return hfp_ag_ok(cid);
|
||||
}
|
||||
|
||||
int hfp_ag_retrieve_supported_generic_status_indicators_cmd(uint16_t cid){
|
||||
char buffer[30];
|
||||
int offset = snprintf(buffer, sizeof(buffer), "%s=", HFP_GENERIC_STATUS_INDICATOR);
|
||||
offset += hfp_hf_indicators_join(buffer+offset, sizeof(buffer)-offset);
|
||||
offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\nOK\r\n");
|
||||
buffer[offset] = 0;
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
int hfp_ag_list_initital_supported_generic_status_indicators_cmd(uint16_t cid){
|
||||
char buffer[30];
|
||||
int offset = hfp_hf_indicators_initial_status_join(buffer, sizeof(buffer));
|
||||
offset += snprintf(buffer+offset, sizeof(buffer)-offset, "OK\r\n");
|
||||
buffer[offset] = 0;
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
|
||||
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 );
|
||||
if (!rfcomm_can_send_packet_now(connection->rfcomm_cid)) return;
|
||||
|
||||
switch (connection->state){
|
||||
case HFP_EXCHANGE_SUPPORTED_FEATURES:
|
||||
|
||||
hfp_ag_exchange_supported_features_cmd(connection->rfcomm_cid);
|
||||
connection->state = HFP_W4_EXCHANGE_SUPPORTED_FEATURES;
|
||||
break;
|
||||
case HFP_NOTIFY_ON_CODECS:
|
||||
hfp_ag_retrieve_codec_cmd(connection->rfcomm_cid);
|
||||
connection->state = HFP_W4_NOTIFY_ON_CODECS;
|
||||
break;
|
||||
case HFP_RETRIEVE_INDICATORS:
|
||||
hfp_ag_retrieve_indicators_cmd(connection->rfcomm_cid);
|
||||
connection->state = HFP_W4_RETRIEVE_INDICATORS;
|
||||
break;
|
||||
case HFP_RETRIEVE_INDICATORS_STATUS:
|
||||
hfp_ag_retrieve_indicators_status_cmd(connection->rfcomm_cid);
|
||||
connection->state = HFP_W4_RETRIEVE_INDICATORS_STATUS;
|
||||
break;
|
||||
case HFP_ENABLE_INDICATORS_STATUS_UPDATE:
|
||||
hfp_ag_toggle_indicator_status_update_cmd(connection->rfcomm_cid, 1);
|
||||
connection->state = HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE;
|
||||
break;
|
||||
case HFP_RETRIEVE_CAN_HOLD_CALL:
|
||||
hfp_ag_retrieve_can_hold_call_cmd(connection->rfcomm_cid);
|
||||
connection->state = HFP_W4_RETRIEVE_CAN_HOLD_CALL;
|
||||
break;
|
||||
case HFP_LIST_GENERIC_STATUS_INDICATORS:
|
||||
hfp_ag_list_supported_generic_status_indicators_cmd(connection->rfcomm_cid);
|
||||
connection->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS;
|
||||
break;
|
||||
case HFP_RETRIEVE_GENERIC_STATUS_INDICATORS:
|
||||
hfp_ag_retrieve_supported_generic_status_indicators_cmd(connection->rfcomm_cid);
|
||||
connection->state = HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS;
|
||||
break;
|
||||
case HFP_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS:
|
||||
hfp_ag_list_initital_supported_generic_status_indicators_cmd(connection->rfcomm_cid);
|
||||
connection->state = HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS;
|
||||
break;
|
||||
case HFP_ACTIVE:
|
||||
printf("HFP_ACTIVE\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
hfp_connection_t * hfp_handle_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
||||
hfp_connection_t * context = provide_hfp_connection_context_for_rfcomm_cid(channel);
|
||||
if (!context) return NULL;
|
||||
while (size > 0 && (packet[0] == '\n' || packet[0] == '\r')){
|
||||
size--;
|
||||
packet++;
|
||||
void update_command(hfp_connection_t * context){
|
||||
context->command = HFP_CMD_NONE;
|
||||
|
||||
if (strncmp((char *)context->line_buffer+2, HFP_SUPPORTED_FEATURES, strlen(HFP_SUPPORTED_FEATURES)) == 0){
|
||||
printf("Received AT+BRSF\n");
|
||||
context->command = HFP_CMD_SUPPORTED_FEATURES;
|
||||
return;
|
||||
}
|
||||
|
||||
return context;
|
||||
if (strncmp((char *)context->line_buffer+2, HFP_INDICATOR, strlen(HFP_INDICATOR)) == 0){
|
||||
printf("Received AT+CIND\n");
|
||||
context->command = HFP_CMD_INDICATOR;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (strncmp((char *)context->line_buffer+2, HFP_AVAILABLE_CODECS, strlen(HFP_AVAILABLE_CODECS)) == 0){
|
||||
printf("Received AT+BAC\n");
|
||||
context->command = HFP_CMD_AVAILABLE_CODECS;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strncmp((char *)context->line_buffer+2, HFP_ENABLE_INDICATOR_STATUS_UPDATE, strlen(HFP_ENABLE_INDICATOR_STATUS_UPDATE)) == 0){
|
||||
printf("Received AT+CMER\n");
|
||||
context->command = HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strncmp((char *)context->line_buffer+2, HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES, strlen(HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES)) == 0){
|
||||
printf("Received AT+CHLD\n");
|
||||
context->command = HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strncmp((char *)context->line_buffer+2, HFP_GENERIC_STATUS_INDICATOR, strlen(HFP_GENERIC_STATUS_INDICATOR)) == 0){
|
||||
printf("Received AT+BIND\n");
|
||||
context->command = HFP_CMD_GENERIC_STATUS_INDICATOR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void handle_switch_on_ok(hfp_connection_t *context){
|
||||
printf("handle switch on OK\n");
|
||||
switch (context->state){
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// done
|
||||
context->command = HFP_CMD_NONE;
|
||||
}
|
||||
|
||||
static void hfp_handle_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
||||
hfp_connection_t * context = provide_hfp_connection_context_for_rfcomm_cid(channel);
|
||||
if (!context) return;
|
||||
|
||||
packet[size] = 0;
|
||||
int pos;
|
||||
for (pos = 0; pos < size ; pos++){
|
||||
hfp_parse(context, packet[pos]);
|
||||
|
||||
// trigger next action after CMD received
|
||||
if (context->command != HFP_CMD_OK) continue;
|
||||
handle_switch_on_ok(context);
|
||||
}
|
||||
}
|
||||
|
||||
static void hfp_run(){
|
||||
linked_list_iterator_t it;
|
||||
linked_list_iterator_init(&it, hfp_get_connections());
|
||||
while (linked_list_iterator_has_next(&it)){
|
||||
hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it);
|
||||
hfp_run_for_context(connection);
|
||||
}
|
||||
}
|
||||
|
||||
static void packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
||||
// printf("packet_handler type %u, packet[0] %x\n", packet_type, packet[0]);
|
||||
hfp_connection_t * context = NULL;
|
||||
|
||||
switch (packet_type){
|
||||
case RFCOMM_DATA_PACKET:
|
||||
context = hfp_handle_rfcomm_event(packet_type, channel, packet, size);
|
||||
hfp_handle_rfcomm_event(packet_type, channel, packet, size);
|
||||
break;
|
||||
case HCI_EVENT_PACKET:
|
||||
context = hfp_handle_hci_event(packet_type, packet, size);
|
||||
hfp_handle_hci_event(packet_type, packet, size);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
hfp_run(context);
|
||||
hfp_run();
|
||||
}
|
||||
|
||||
void hfp_ag_init(uint16_t rfcomm_channel_nr, uint32_t supported_features, uint8_t * codecs, int codecs_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_hf_indicator_t * hf_indicators, int hf_indicators_nr,
|
||||
char *call_hold_services[], int call_hold_services_nr){
|
||||
if (codecs_nr > HFP_MAX_NUM_CODECS){
|
||||
log_error("hfp_init: codecs_nr (%d) > HFP_MAX_NUM_CODECS (%d)", codecs_nr, HFP_MAX_NUM_CODECS);
|
||||
return;
|
||||
}
|
||||
hfp_init(rfcomm_channel_nr);
|
||||
rfcomm_register_packet_handler(packet_handler);
|
||||
// connection->codecs = codecs;
|
||||
hfp_init(rfcomm_channel_nr);
|
||||
|
||||
hfp_supported_features = supported_features;
|
||||
hfp_codecs_nr = codecs_nr;
|
||||
|
||||
@ -137,6 +387,15 @@ void hfp_ag_init(uint16_t rfcomm_channel_nr, uint32_t supported_features, uint8_
|
||||
for (i=0; i<codecs_nr; i++){
|
||||
hfp_codecs[i] = codecs[i];
|
||||
}
|
||||
|
||||
hfp_ag_indicators_nr = ag_indicators_nr;
|
||||
memcpy(hfp_ag_indicators, ag_indicators, ag_indicators_nr * sizeof(hfp_ag_indicator_t));
|
||||
|
||||
hfp_hf_indicators_nr = hf_indicators_nr;
|
||||
memcpy(hfp_hf_indicators, hf_indicators, hf_indicators_nr * sizeof(hfp_hf_indicator_t));
|
||||
|
||||
hfp_ag_call_hold_services_nr = call_hold_services_nr;
|
||||
memcpy(hfp_ag_call_hold_services, call_hold_services, sizeof(char *));
|
||||
}
|
||||
|
||||
void hfp_ag_connect(bd_addr_t bd_addr){
|
||||
|
@ -53,8 +53,13 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void hfp_ag_create_service(uint8_t * service, int rfcomm_channel_nr, const char * name, uint8_t ability_to_reject_call, uint16_t supported_features);
|
||||
void hfp_ag_init(uint16_t rfcomm_channel_nr, uint32_t supported_features, uint8_t * codecs, int num_codecs);
|
||||
void hfp_ag_create_service(uint8_t * service, int rfcomm_channel_nr, const char * name, uint8_t ability_to_reject_call, uint16_t supported_features);;
|
||||
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_hf_indicator_t * hf_indicators, int hf_indicators_nr,
|
||||
char *call_hold_services[], int call_hold_services_nr);
|
||||
|
||||
void hfp_ag_connect(bd_addr_t bd_addr);
|
||||
void hfp_ag_disconnect(bd_addr_t bd_addr);
|
||||
|
||||
|
168
src/hfp_hf.c
168
src/hfp_hf.c
@ -71,10 +71,6 @@ 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, HFP_HFSF_CODEC_NEGOTIATION);
|
||||
@ -104,14 +100,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 store_bit(uint32_t bitmap, int position, uint8_t value){
|
||||
if (value){
|
||||
bitmap |= 1 << position;
|
||||
} else {
|
||||
bitmap &= ~ (1 << position);
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
int hfp_hs_exchange_supported_features_cmd(uint16_t cid){
|
||||
char buffer[20];
|
||||
@ -122,13 +110,13 @@ 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 = 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);
|
||||
int offset = snprintf(buffer, sizeof(buffer), "AT%s=", HFP_AVAILABLE_CODECS);
|
||||
offset += join(buffer+offset, sizeof(buffer)-offset, hfp_codecs, hfp_codecs_nr);
|
||||
offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n");
|
||||
buffer[offset] = 0;
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
|
||||
int hfp_hs_retrieve_indicators_cmd(uint16_t cid){
|
||||
char buffer[20];
|
||||
sprintf(buffer, "AT%s=?\r\n", HFP_INDICATOR);
|
||||
@ -158,18 +146,18 @@ int hfp_hs_retrieve_can_hold_call_cmd(uint16_t cid){
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
|
||||
int hfp_hs_list_supported_generic_status_indicators_cmd(uint16_t cid){
|
||||
char buffer[30];
|
||||
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);
|
||||
int offset = snprintf(buffer, sizeof(buffer), "AT%s=", HFP_GENERIC_STATUS_INDICATOR);
|
||||
offset += join(buffer+offset, sizeof(buffer)-offset, hfp_indicators, hfp_indicators_nr);
|
||||
offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n");
|
||||
buffer[offset] = 0;
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
int hfp_hs_retrieve_supported_generic_status_indicators_cmd(uint16_t cid){
|
||||
char buffer[20];
|
||||
sprintf(buffer, "AT%s=?\r\rn", HFP_GENERIC_STATUS_INDICATOR);
|
||||
sprintf(buffer, "AT%s=?\r\n", HFP_GENERIC_STATUS_INDICATOR);
|
||||
// printf("retrieve_supported_generic_status_indicators %s\n", buffer);
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
@ -277,138 +265,6 @@ void update_command(hfp_connection_t * context){
|
||||
}
|
||||
}
|
||||
|
||||
static void hfp_parse(hfp_connection_t * context, uint8_t byte){
|
||||
int i;
|
||||
if (byte == ' ') return;
|
||||
if ( (byte == '\n' || byte == '\r') && context->parser_state > HFP_PARSER_CMD_SEQUENCE) return;
|
||||
|
||||
switch (context->parser_state){
|
||||
case HFP_PARSER_CMD_HEADER: // header
|
||||
if (byte == ':'){
|
||||
context->parser_state = HFP_PARSER_CMD_SEQUENCE;
|
||||
context->line_buffer[context->line_size] = 0;
|
||||
context->line_size = 0;
|
||||
update_command(context);
|
||||
return;
|
||||
}
|
||||
if (byte == '\n' || byte == '\r'){
|
||||
// received OK
|
||||
context->line_buffer[context->line_size] = 0;
|
||||
context->line_size = 0;
|
||||
update_command(context);
|
||||
return;
|
||||
}
|
||||
context->line_buffer[context->line_size++] = byte;
|
||||
break;
|
||||
|
||||
case HFP_PARSER_CMD_SEQUENCE: // parse comma separated sequence, ignore breacktes
|
||||
if (byte == '"'){ // indicators
|
||||
context->parser_state = HFP_PARSER_CMD_INDICATOR_NAME;
|
||||
context->line_size = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (byte == '(' ){ // tuple separated mit comma
|
||||
break;
|
||||
}
|
||||
|
||||
if (byte == ',' || byte == '\n' || byte == '\r' || byte == ')'){
|
||||
context->line_buffer[context->line_size] = 0;
|
||||
context->line_size = 0;
|
||||
switch (context->state){
|
||||
case HFP_W4_EXCHANGE_SUPPORTED_FEATURES:
|
||||
context->remote_supported_features = atoi((char *)&context->line_buffer[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->command = HFP_CMD_NONE;
|
||||
context->parser_state = HFP_PARSER_CMD_HEADER;
|
||||
break;
|
||||
case HFP_W4_RETRIEVE_INDICATORS:
|
||||
break;
|
||||
case HFP_W4_RETRIEVE_INDICATORS_STATUS:
|
||||
printf("Indicator with status: %s\n", context->line_buffer);
|
||||
break;
|
||||
case HFP_W4_RETRIEVE_CAN_HOLD_CALL:
|
||||
printf("Support call hold: %s\n", context->line_buffer);
|
||||
break;
|
||||
case HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS: // comma separated ints
|
||||
printf("Generic status indicator: %s\n", context->line_buffer);
|
||||
break;
|
||||
case HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS:
|
||||
printf("Generic status indicator: %s, ", context->line_buffer);
|
||||
context->parser_state = HFP_PARSER_CMD_INITITAL_STATE_GENERIC_STATUS_INDICATORS;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (byte == '\n' || byte == '\r'){
|
||||
context->command = HFP_CMD_NONE;
|
||||
context->parser_state = HFP_PARSER_CMD_HEADER;
|
||||
break;
|
||||
}
|
||||
if (byte == ')' && context->state == HFP_W4_RETRIEVE_CAN_HOLD_CALL){ // tuple separated mit comma
|
||||
context->command = HFP_CMD_NONE;
|
||||
context->parser_state = HFP_PARSER_CMD_HEADER;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
context->line_buffer[context->line_size++] = byte;
|
||||
break;
|
||||
case HFP_PARSER_CMD_INITITAL_STATE_GENERIC_STATUS_INDICATORS:
|
||||
if (byte == '\n' || byte == '\r'){
|
||||
context->line_buffer[context->line_size] = 0;
|
||||
context->line_size = 0;
|
||||
context->command = HFP_CMD_NONE;
|
||||
context->parser_state = HFP_PARSER_CMD_HEADER;
|
||||
printf("status %s [0-dissabled, 1-enabled]\n", context->line_buffer);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case HFP_PARSER_CMD_INDICATOR_NAME: // parse indicator name
|
||||
if (byte == '"'){
|
||||
context->line_buffer[context->line_size] = 0;
|
||||
printf("Indicator %d: %s (", context->remote_indicators_nr, context->line_buffer);
|
||||
context->line_size = 0;
|
||||
break;
|
||||
}
|
||||
if (byte == '('){ // parse indicator range
|
||||
context->parser_state = HFP_PARSER_CMD_INDICATOR_MIN_RANGE;
|
||||
break;
|
||||
}
|
||||
context->line_buffer[context->line_size++] = byte;
|
||||
break;
|
||||
case HFP_PARSER_CMD_INDICATOR_MIN_RANGE:
|
||||
if (byte == ',' || byte == '-'){ // end min_range
|
||||
context->parser_state = HFP_PARSER_CMD_INDICATOR_MAX_RANGE;
|
||||
context->line_buffer[context->line_size] = 0;
|
||||
printf("%d, ", atoi((char *)&context->line_buffer[0]));
|
||||
context->line_size = 0;
|
||||
break;
|
||||
}
|
||||
// min. range
|
||||
context->line_buffer[context->line_size++] = byte;
|
||||
break;
|
||||
case HFP_PARSER_CMD_INDICATOR_MAX_RANGE:
|
||||
if (byte == ')'){ // end max_range
|
||||
context->parser_state = HFP_PARSER_CMD_SEQUENCE;
|
||||
|
||||
context->line_buffer[context->line_size] = 0;
|
||||
printf("%d)\n", atoi((char *)&context->line_buffer[0]));
|
||||
context->line_size = 0;
|
||||
context->remote_indicators_nr+=1;
|
||||
break;
|
||||
}
|
||||
//
|
||||
context->line_buffer[context->line_size++] = byte;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void handle_switch_on_ok(hfp_connection_t *context){
|
||||
printf("handle switch on OK\n");
|
||||
@ -533,12 +389,10 @@ void hfp_hf_init(uint16_t rfcomm_channel_nr, uint32_t supported_features, uint8_
|
||||
rfcomm_register_packet_handler(packet_handler);
|
||||
hfp_init(rfcomm_channel_nr);
|
||||
|
||||
int i;
|
||||
|
||||
// connection->codecs = codecs;
|
||||
hfp_supported_features = supported_features;
|
||||
|
||||
hfp_codecs_nr = codecs_nr;
|
||||
|
||||
int i;
|
||||
for (i=0; i<codecs_nr; i++){
|
||||
hfp_codecs[i] = codecs[i];
|
||||
}
|
||||
|
@ -37,12 +37,10 @@
|
||||
|
||||
// *****************************************************************************
|
||||
//
|
||||
// Minimal test for HSP Headset (!! UNDER DEVELOPMENT !!)
|
||||
// Minimal test for HSP Audio Gateway (!! UNDER DEVELOPMENT !!)
|
||||
//
|
||||
// *****************************************************************************
|
||||
|
||||
#include "btstack-config.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -67,26 +65,47 @@
|
||||
#include "debug.h"
|
||||
#include "hfp_ag.h"
|
||||
#include "stdin_support.h"
|
||||
|
||||
|
||||
const uint32_t hfp_service_buffer[150/4]; // implicit alignment to 4-byte memory address
|
||||
const uint8_t rfcomm_channel_nr = 1;
|
||||
const char hfp_ag_service_name[] = "Headset Test";
|
||||
const char hfp_ag_service_name[] = "BTstack HFP AG 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 speaker = {0x00, 0x21, 0x3C, 0xAC, 0xF7, 0x38};
|
||||
static uint8_t codecs[1] = {HFP_CODEC_CVSD};
|
||||
|
||||
static int ag_indicators_nr = 7;
|
||||
static hfp_ag_indicator_t ag_indicators[] = {
|
||||
{1, "service", 0, 1, 1},
|
||||
{2, "call", 0, 1, 0},
|
||||
{3, "callsetup", 0, 3, 0},
|
||||
{4, "battchg", 0, 5, 3},
|
||||
{5, "signal", 0, 5, 5},
|
||||
{6, "roam", 0, 1, 0},
|
||||
{7, "callheld", 0, 2, 0},
|
||||
};
|
||||
|
||||
static int call_hold_services_nr = 5;
|
||||
static char* call_hold_services[] = {"1", "1x", "2", "2x", "3"};
|
||||
|
||||
static int hf_indicators_nr = 2;
|
||||
static hfp_hf_indicator_t hf_indicators[] = {
|
||||
{1, 1, 1},
|
||||
{2, 1, 1},
|
||||
};
|
||||
|
||||
// prototypes
|
||||
static void show_usage();
|
||||
|
||||
static void show_usage(void);
|
||||
|
||||
// Testig User Interface
|
||||
static void show_usage(void){
|
||||
printf("\n--- Bluetooth HFP Audio Gateway (AG) unit Test Console ---\n");
|
||||
printf("\n--- Bluetooth HFP Hands-Free (HF) unit Test Console ---\n");
|
||||
printf("---\n");
|
||||
printf("p - establish audio connection to PTS module\n");
|
||||
printf("e - establish audio connection to local mac\n");
|
||||
printf("d - release audio connection from Bluetooth Speaker\n");
|
||||
printf("p - establish HFP connection to PTS module\n");
|
||||
printf("e - establish HFP connection to local mac\n");
|
||||
printf("d - release HFP connection\n");
|
||||
printf("---\n");
|
||||
printf("Ctrl-c - exit\n");
|
||||
printf("---\n");
|
||||
@ -95,18 +114,17 @@ static void show_usage(void){
|
||||
static int stdin_process(struct data_source *ds){
|
||||
char buffer;
|
||||
read(ds->fd, &buffer, 1);
|
||||
|
||||
switch (buffer){
|
||||
case 'p':
|
||||
printf("Establishing audio connection to PTS module %s...\n", bd_addr_to_str(pts_addr));
|
||||
printf("Establishing HFP connection to PTS module %s...\n", bd_addr_to_str(pts_addr));
|
||||
hfp_ag_connect(pts_addr);
|
||||
break;
|
||||
case 'e':
|
||||
printf("Establishing audio connection to local mac %s...\n", bd_addr_to_str(local_mac));
|
||||
hfp_ag_connect(local_mac);
|
||||
printf("Establishing HFP connection to %s...\n", bd_addr_to_str(speaker));
|
||||
hfp_ag_connect(speaker);
|
||||
break;
|
||||
case 'd':
|
||||
printf("Releasing audio connection.\n");
|
||||
printf("Releasing HFP connection.\n");
|
||||
hfp_ag_disconnect(pts_addr);
|
||||
break;
|
||||
default:
|
||||
@ -125,26 +143,31 @@ void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int btstack_main(int argc, const char * argv[]){
|
||||
// init L2CAP
|
||||
l2cap_init();
|
||||
rfcomm_init();
|
||||
|
||||
// TODO: hfp_ag_init(rfcomm_channel_nr);
|
||||
hfp_ag_init(rfcomm_channel_nr, 438, codecs, sizeof(codecs),
|
||||
ag_indicators, ag_indicators_nr,
|
||||
hf_indicators, hf_indicators_nr,
|
||||
call_hold_services, call_hold_services_nr);
|
||||
|
||||
hfp_register_packet_handler(packet_handler);
|
||||
|
||||
|
||||
sdp_init();
|
||||
|
||||
// init SDP, create record for SPP and register with SDP
|
||||
memset((uint8_t *)hfp_service_buffer, 0, sizeof(hfp_service_buffer));
|
||||
hfp_ag_create_service((uint8_t *)hfp_service_buffer, rfcomm_channel_nr, hfp_ag_service_name, 0, 0);
|
||||
|
||||
sdp_register_service_internal(NULL, (uint8_t *)hfp_service_buffer);
|
||||
|
||||
|
||||
// turn on!
|
||||
hci_power_control(HCI_POWER_ON);
|
||||
|
||||
btstack_stdin_setup(stdin_process);
|
||||
|
||||
printf("Establishing HFP connection to %s...\n", bd_addr_to_str(speaker));
|
||||
hfp_ag_connect(speaker);
|
||||
return 0;
|
||||
}
|
||||
|
@ -70,11 +70,14 @@
|
||||
|
||||
const uint32_t hfp_service_buffer[150/4]; // implicit alignment to 4-byte memory address
|
||||
const uint8_t rfcomm_channel_nr = 1;
|
||||
const char hfp_hf_service_name[] = "BTstack HF Test";
|
||||
const char hfp_hf_service_name[] = "BTstack HFP 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};
|
||||
static uint8_t codecs[1] = {HFP_CODEC_CVSD};
|
||||
static uint16_t indicators[1] = {0x01};
|
||||
|
||||
// prototypes
|
||||
static void show_usage();
|
||||
|
||||
@ -94,7 +97,6 @@ static void show_usage(void){
|
||||
static int stdin_process(struct data_source *ds){
|
||||
char buffer;
|
||||
read(ds->fd, &buffer, 1);
|
||||
|
||||
switch (buffer){
|
||||
case 'p':
|
||||
printf("Establishing HFP connection to PTS module %s...\n", bd_addr_to_str(pts_addr));
|
||||
@ -126,9 +128,6 @@ 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_CVSD};
|
||||
uint16_t indicators[1] = {0x01};
|
||||
|
||||
l2cap_init();
|
||||
rfcomm_init();
|
||||
|
||||
@ -147,6 +146,7 @@ int btstack_main(int argc, const char * argv[]){
|
||||
hci_power_control(HCI_POWER_ON);
|
||||
|
||||
btstack_stdin_setup(stdin_process);
|
||||
|
||||
// printf("Establishing HFP connection to %s...\n", bd_addr_to_str(phone));
|
||||
// hfp_hf_connect(phone);
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user