mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-04-16 08:42:28 +00:00
hfp: hf parser test
This commit is contained in:
parent
daf37df633
commit
35ffcaae5b
143
src/hfp.c
143
src/hfp.c
@ -47,6 +47,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <btstack/hci_cmds.h>
|
||||
#include <btstack/run_loop.h>
|
||||
@ -58,7 +59,6 @@
|
||||
#include "sdp_query_rfcomm.h"
|
||||
#include "sdp.h"
|
||||
#include "debug.h"
|
||||
#include "hfp_ag.h"
|
||||
|
||||
#define HFP_HF_FEATURES_SIZE 10
|
||||
#define HFP_AG_FEATURES_SIZE 12
|
||||
@ -115,9 +115,7 @@ int send_str_over_rfcomm(uint16_t cid, char * command){
|
||||
int err = rfcomm_send_internal(cid, (uint8_t*) command, strlen(command));
|
||||
if (err){
|
||||
printf("rfcomm_send_internal -> error 0X%02x", err);
|
||||
} else {
|
||||
printf("\nSent %s", command);
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -161,6 +159,18 @@ int join(char * buffer, int buffer_size, uint8_t * values, int values_nr){
|
||||
return offset;
|
||||
}
|
||||
|
||||
int join_bitmap(char * buffer, int buffer_size, uint32_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++) {
|
||||
offset += snprintf(buffer+offset, buffer_size-offset, "%d,", get_bit(values,i)); // puts string into buffer
|
||||
}
|
||||
if (i<values_nr){
|
||||
offset += snprintf(buffer+offset, buffer_size-offset, "%d", get_bit(values,i));
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
void hfp_emit_event(hfp_callback_t callback, uint8_t event_subtype, uint8_t value){
|
||||
if (!callback) return;
|
||||
@ -189,7 +199,7 @@ hfp_connection_t * get_hfp_connection_context_for_rfcomm_cid(uint16_t cid){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static hfp_connection_t * get_hfp_connection_context_for_bd_addr(bd_addr_t bd_addr){
|
||||
hfp_connection_t * get_hfp_connection_context_for_bd_addr(bd_addr_t bd_addr){
|
||||
linked_list_iterator_t it;
|
||||
linked_list_iterator_init(&it, hfp_get_connections());
|
||||
while (linked_list_iterator_has_next(&it)){
|
||||
@ -201,7 +211,7 @@ static hfp_connection_t * get_hfp_connection_context_for_bd_addr(bd_addr_t bd_ad
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hfp_connection_t * get_hfp_connection_context_for_handle(uint16_t handle){
|
||||
static hfp_connection_t * get_hfp_connection_context_for_handle(uint16_t handle){
|
||||
linked_list_iterator_t it;
|
||||
linked_list_iterator_init(&it, hfp_get_connections());
|
||||
while (linked_list_iterator_has_next(&it)){
|
||||
@ -220,15 +230,12 @@ static hfp_connection_t * create_hfp_connection_context(){
|
||||
memset(context,0, sizeof(hfp_connection_t));
|
||||
|
||||
context->state = HFP_IDLE;
|
||||
context->line_size = 0;
|
||||
context->parser_state = HFP_PARSER_CMD_HEADER;
|
||||
context->command = HFP_CMD_NONE;
|
||||
|
||||
context->negotiated_codec = HFP_CODEC_CVSD;
|
||||
context->remote_supported_features = 0;
|
||||
context->remote_indicators_update_enabled = 0;
|
||||
|
||||
context->ag_indicators_nr = 0;
|
||||
context->enable_status_update_for_ag_indicators = 0xFF;
|
||||
context->change_enable_status_update_for_individual_ag_indicators = 0xFF;
|
||||
|
||||
linked_list_add(&hfp_connections, (linked_item_t*)context);
|
||||
return context;
|
||||
@ -451,11 +458,18 @@ void hfp_handle_hci_event(hfp_callback_t callback, uint8_t packet_type, uint8_t
|
||||
|
||||
void update_command(hfp_connection_t * context);
|
||||
|
||||
uint32_t fromBinary(char *s) {
|
||||
return (uint32_t) strtol(s, NULL, 2);
|
||||
}
|
||||
|
||||
void hfp_parse(hfp_connection_t * context, uint8_t byte){
|
||||
int i;
|
||||
int value;
|
||||
|
||||
if (byte == ' ') return;
|
||||
if ( (byte == '\n' || byte == '\r') && context->parser_state > HFP_PARSER_CMD_SEQUENCE) return;
|
||||
|
||||
if (context->line_size == 0 && (byte == '\n' || byte == '\r')) return;
|
||||
if ((byte == '\n' || byte == '\r') && (context->parser_state > HFP_PARSER_CMD_SEQUENCE && context->parser_state != HFP_PARSER_CMD_INITITAL_STATE_GENERIC_STATUS_INDICATORS) )return;
|
||||
//printf("%c", byte);
|
||||
switch (context->parser_state){
|
||||
case HFP_PARSER_CMD_HEADER: // header
|
||||
if (byte == ':' || byte == '='){
|
||||
@ -466,10 +480,11 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){
|
||||
return;
|
||||
}
|
||||
if (byte == '\n' || byte == '\r'){
|
||||
// received OK
|
||||
context->line_buffer[context->line_size] = 0;
|
||||
if (context->line_size == 2){
|
||||
update_command(context);
|
||||
}
|
||||
context->line_size = 0;
|
||||
update_command(context);
|
||||
return;
|
||||
}
|
||||
context->line_buffer[context->line_size++] = byte;
|
||||
@ -488,41 +503,68 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){
|
||||
|
||||
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]);
|
||||
|
||||
switch (context->command){
|
||||
case HFP_CMD_SUPPORTED_FEATURES:
|
||||
context->remote_supported_features = 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 (context->line_buffer[i] == '1'){
|
||||
context->remote_supported_features = store_bit(context->remote_supported_features,15-i,1);
|
||||
}
|
||||
}
|
||||
// printf("Received supported feature %d\n", context->remote_supported_features);
|
||||
context->parser_state = HFP_PARSER_CMD_HEADER;
|
||||
break;
|
||||
case HFP_W4_RETRIEVE_INDICATORS:
|
||||
case HFP_CMD_AVAILABLE_CODECS:
|
||||
// printf("Received codec %s\n", context->line_buffer);
|
||||
context->remote_codecs[context->remote_codecs_nr] = (uint16_t)atoi((char*)context->line_buffer);
|
||||
context->remote_codecs_nr++;
|
||||
break;
|
||||
case HFP_W4_RETRIEVE_INDICATORS_STATUS:
|
||||
printf("Indicator with status: %s\n", context->line_buffer);
|
||||
case HFP_CMD_INDICATOR_STATUS:
|
||||
// printf("Indicator %d with status: %s\n", context->parser_item_index+1, context->line_buffer);
|
||||
context->ag_indicators[context->parser_item_index].status = atoi((char *) context->line_buffer);
|
||||
context->parser_item_index++;
|
||||
break;
|
||||
case HFP_W4_RETRIEVE_CAN_HOLD_CALL:
|
||||
printf("Support call hold: %s\n", context->line_buffer);
|
||||
case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE:
|
||||
if (context->parser_item_index == 3){
|
||||
printf("Enable indicators: %s\n", context->line_buffer);
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
context->enable_status_update_for_ag_indicators = (uint8_t) value;
|
||||
}
|
||||
break;
|
||||
case HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS: // comma separated ints
|
||||
printf("Generic status indicator: %s\n", context->line_buffer);
|
||||
case HFP_CMD_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE:
|
||||
value = atoi((char *)&context->line_buffer[0]);
|
||||
printf("Indicator %d status: %d\n", context->ag_indicators_nr, value);
|
||||
store_bit(context->ag_indicators_status_update_bitmap, context->ag_indicators_nr, (uint8_t)value);
|
||||
break;
|
||||
case HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS:
|
||||
printf("Generic status indicator: %s, ", context->line_buffer);
|
||||
case HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES:
|
||||
// printf("Support call hold: %s\n", context->line_buffer);
|
||||
if (context->line_size > 2 ) break;
|
||||
strcpy((char *)context->remote_call_services[context->remote_call_services_nr].name, (char *)context->line_buffer);
|
||||
context->remote_call_services_nr++;
|
||||
break;
|
||||
case HFP_CMD_GENERIC_STATUS_INDICATOR:
|
||||
context->generic_status_indicators[context->generic_status_indicators_nr].uuid = (uint16_t)atoi((char*)context->line_buffer);
|
||||
context->generic_status_indicators_nr++;
|
||||
break;
|
||||
case HFP_CMD_GENERIC_STATUS_INDICATOR_STATE:
|
||||
printf("HFP_CMD_GENERIC_STATUS_INDICATOR_STATE %s, %d\n", context->line_buffer, context->command);
|
||||
context->parser_state = HFP_PARSER_CMD_INITITAL_STATE_GENERIC_STATUS_INDICATORS;
|
||||
context->generic_status_indicator_state_index = (uint8_t)atoi((char*)context->line_buffer);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
context->line_size = 0;
|
||||
|
||||
if (byte == '\n' || byte == '\r'){
|
||||
context->parser_state = HFP_PARSER_CMD_HEADER;
|
||||
context->parser_item_index = 0;
|
||||
break;
|
||||
}
|
||||
if (byte == ')' && context->state == HFP_W4_RETRIEVE_CAN_HOLD_CALL){ // tuple separated mit comma
|
||||
if (byte == ')' && context->command == HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES){ // tuple separated mit comma
|
||||
context->parser_state = HFP_PARSER_CMD_HEADER;
|
||||
context->parser_item_index = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -530,20 +572,31 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){
|
||||
context->line_buffer[context->line_size++] = byte;
|
||||
break;
|
||||
case HFP_PARSER_CMD_INITITAL_STATE_GENERIC_STATUS_INDICATORS:
|
||||
context->line_buffer[context->line_size] = 0;
|
||||
printf("HFP_PARSER_CMD_INITITAL_STATE_GENERIC_STATUS_INDICATORS 1 %s\n", context->line_buffer);
|
||||
if (byte == ',') break;
|
||||
printf("HFP_PARSER_CMD_INITITAL_STATE_GENERIC_STATUS_INDICATORS 2 %s\n", context->line_buffer);
|
||||
if (byte == '\n' || byte == '\r'){
|
||||
printf("HFP_PARSER_CMD_INITITAL_STATE_GENERIC_STATUS_INDICATORS 4%s\n", context->line_buffer);
|
||||
|
||||
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);
|
||||
context->generic_status_indicators[context->generic_status_indicator_state_index].state = (uint8_t)atoi((char*)context->line_buffer);
|
||||
break;
|
||||
}
|
||||
context->line_buffer[context->line_size++] = byte;
|
||||
printf("HFP_PARSER_CMD_INITITAL_STATE_GENERIC_STATUS_INDICATORS 3 %s\n", context->line_buffer);
|
||||
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;
|
||||
//printf("Indicator %d: %s (", context->ag_indicators_nr+1, context->line_buffer);
|
||||
strcpy((char *)context->ag_indicators[context->ag_indicators_nr].name, (char *)context->line_buffer);
|
||||
context->ag_indicators[context->ag_indicators_nr].index = context->ag_indicators_nr+1;
|
||||
break;
|
||||
}
|
||||
if (byte == '('){ // parse indicator range
|
||||
@ -556,7 +609,8 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){
|
||||
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]));
|
||||
//printf("%d, ", atoi((char *)&context->line_buffer[0]));
|
||||
context->ag_indicators[context->ag_indicators_nr].min_range = atoi((char *)context->line_buffer);
|
||||
context->line_size = 0;
|
||||
break;
|
||||
}
|
||||
@ -566,14 +620,14 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){
|
||||
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]));
|
||||
//printf("%d)\n", atoi((char *)&context->line_buffer[0]));
|
||||
context->ag_indicators[context->ag_indicators_nr].max_range = atoi((char *)context->line_buffer);
|
||||
context->line_size = 0;
|
||||
context->ag_indicators_nr+=1;
|
||||
context->ag_indicators_nr++;
|
||||
break;
|
||||
}
|
||||
//
|
||||
|
||||
context->line_buffer[context->line_size++] = byte;
|
||||
break;
|
||||
|
||||
@ -590,7 +644,7 @@ void hfp_establish_service_level_connection(bd_addr_t bd_addr, uint16_t service_
|
||||
log_info("hfp_connect %s, context %p", bd_addr_to_str(bd_addr), context);
|
||||
|
||||
if (!context) {
|
||||
log_error("hfp_connect for addr %s failed", bd_addr_to_str(bd_addr));
|
||||
log_error("hfp_establish_service_level_connection for addr %s failed", bd_addr_to_str(bd_addr));
|
||||
return;
|
||||
}
|
||||
if (context->state != HFP_IDLE) return;
|
||||
@ -602,11 +656,10 @@ void hfp_establish_service_level_connection(bd_addr_t bd_addr, uint16_t service_
|
||||
sdp_query_rfcomm_channel_and_name_for_uuid(context->remote_addr, service_uuid);
|
||||
}
|
||||
|
||||
hfp_connection_t * hfp_release_service_level_connection(bd_addr_t bd_addr){
|
||||
hfp_connection_t * context = get_hfp_connection_context_for_bd_addr(bd_addr);
|
||||
void hfp_release_service_level_connection(hfp_connection_t * context){
|
||||
if (!context) {
|
||||
log_error("hfp_disconnect for addr %s failed", bd_addr_to_str(bd_addr));
|
||||
return NULL;
|
||||
log_error("hfp_release_service_level_connection failed");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (context->state){
|
||||
@ -619,7 +672,7 @@ hfp_connection_t * hfp_release_service_level_connection(bd_addr_t bd_addr){
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return context;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
70
src/hfp.h
70
src/hfp.h
@ -99,14 +99,16 @@ extern "C" {
|
||||
#define HFP_MAX_NUM_CODECS 20
|
||||
#define HFP_MAX_NUM_AG_INDICATORS 20
|
||||
#define HFP_MAX_NUM_HF_INDICATORS 20
|
||||
#define HFP_MAX_INDICATOR_DESC_SIZE 10
|
||||
#define HFP_MAX_INDICATOR_DESC_SIZE 20
|
||||
|
||||
#define HFP_SUPPORTED_FEATURES "+BRSF"
|
||||
#define HFP_AVAILABLE_CODECS "+BAC"
|
||||
#define HFP_INDICATOR "+CIND"
|
||||
#define HFP_ENABLE_INDICATOR_STATUS_UPDATE "+CMER"
|
||||
#define HFP_ENABLE_STATUS_UPDATE_FOR_AG_INDICATORS "+CMER"
|
||||
#define HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS "+BIA"
|
||||
#define HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES "+CHLD"
|
||||
#define HFP_GENERIC_STATUS_INDICATOR "+BIND"
|
||||
|
||||
#define HFP_OK "OK"
|
||||
|
||||
// Codecs
|
||||
@ -119,9 +121,13 @@ typedef enum {
|
||||
HFP_CMD_SUPPORTED_FEATURES,
|
||||
HFP_CMD_AVAILABLE_CODECS,
|
||||
HFP_CMD_INDICATOR,
|
||||
HFP_CMD_INDICATOR_STATUS, // 5
|
||||
HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE,
|
||||
HFP_CMD_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE,
|
||||
HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES,
|
||||
HFP_CMD_GENERIC_STATUS_INDICATOR
|
||||
HFP_CMD_LIST_GENERIC_STATUS_INDICATOR,
|
||||
HFP_CMD_GENERIC_STATUS_INDICATOR, // 10
|
||||
HFP_CMD_GENERIC_STATUS_INDICATOR_STATE,
|
||||
} hfp_command_t;
|
||||
|
||||
typedef enum {
|
||||
@ -180,7 +186,7 @@ typedef struct{
|
||||
uint16_t uuid;
|
||||
uint8_t state;
|
||||
uint8_t initial_state;
|
||||
} hfp_hf_indicator_t;
|
||||
} hfp_generic_status_indicators_t;
|
||||
|
||||
typedef struct{
|
||||
uint8_t index;
|
||||
@ -190,36 +196,56 @@ typedef struct{
|
||||
uint8_t status;
|
||||
} hfp_ag_indicator_t;
|
||||
|
||||
typedef struct{
|
||||
char name[3];
|
||||
} hfp_call_service_t;
|
||||
|
||||
typedef struct hfp_connection {
|
||||
linked_item_t item;
|
||||
hfp_state_t state;
|
||||
|
||||
hfp_command_t command;
|
||||
hfp_parser_state_t parser_state;
|
||||
|
||||
uint8_t line_buffer[HFP_MAX_INDICATOR_DESC_SIZE];
|
||||
int line_size;
|
||||
|
||||
bd_addr_t remote_addr;
|
||||
uint16_t con_handle;
|
||||
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;
|
||||
|
||||
uint32_t remote_indicators_status;
|
||||
hfp_state_t state;
|
||||
|
||||
// used during service level connection establishment
|
||||
hfp_command_t command;
|
||||
hfp_parser_state_t parser_state;
|
||||
int parser_item_index;
|
||||
uint8_t line_buffer[HFP_MAX_INDICATOR_DESC_SIZE];
|
||||
int line_size;
|
||||
|
||||
uint32_t remote_supported_features;
|
||||
int remote_codecs_nr;
|
||||
uint16_t remote_codecs[HFP_MAX_INDICATOR_DESC_SIZE];
|
||||
int ag_indicators_nr;
|
||||
hfp_ag_indicator_t ag_indicators[HFP_MAX_INDICATOR_DESC_SIZE];
|
||||
int remote_call_services_nr;
|
||||
hfp_call_service_t remote_call_services[HFP_MAX_INDICATOR_DESC_SIZE];
|
||||
int generic_status_indicators_nr;
|
||||
hfp_generic_status_indicators_t generic_status_indicators[HFP_MAX_INDICATOR_DESC_SIZE];
|
||||
uint8_t generic_status_indicator_state_index;
|
||||
|
||||
// TODO: put in a bitmap
|
||||
// 0 = deactivate, 1 = activate, 0xff = do nothing
|
||||
uint8_t wait_ok;
|
||||
hfp_command_t sent_command;
|
||||
uint8_t enable_status_update_for_ag_indicators;
|
||||
uint8_t change_enable_status_update_for_individual_ag_indicators;
|
||||
|
||||
uint32_t ag_indicators_status_update_bitmap;
|
||||
|
||||
|
||||
// Retrieved during service level connection establishment, not used yet
|
||||
uint8_t negotiated_codec;
|
||||
} hfp_connection_t;
|
||||
|
||||
// UTILS_START : TODO move to utils
|
||||
int send_str_over_rfcomm(uint16_t cid, char * command);
|
||||
int join(char * buffer, int buffer_size, uint8_t * values, int values_nr);
|
||||
int join_bitmap(char * buffer, int buffer_size, uint32_t values, int values_nr);
|
||||
int get_bit(uint16_t bitmap, int position);
|
||||
int store_bit(uint32_t bitmap, int position, uint8_t value);
|
||||
// UTILS_END
|
||||
@ -228,12 +254,14 @@ void hfp_create_sdp_record(uint8_t * service, uint16_t service_uuid, int rfcomm_
|
||||
void hfp_handle_hci_event(hfp_callback_t callback, uint8_t packet_type, uint8_t *packet, uint16_t size);
|
||||
void hfp_emit_event(hfp_callback_t callback, uint8_t event_subtype, uint8_t value);
|
||||
hfp_connection_t * get_hfp_connection_context_for_rfcomm_cid(uint16_t cid);
|
||||
hfp_connection_t * get_hfp_connection_context_for_bd_addr(bd_addr_t bd_addr);
|
||||
|
||||
linked_list_t * hfp_get_connections();
|
||||
void hfp_parse(hfp_connection_t * context, uint8_t byte);
|
||||
|
||||
void hfp_init(uint16_t rfcomm_channel_nr);
|
||||
void hfp_establish_service_level_connection(bd_addr_t bd_addr, uint16_t service_uuid);
|
||||
hfp_connection_t * hfp_release_service_level_connection(bd_addr_t bd_addr);
|
||||
void hfp_release_service_level_connection(hfp_connection_t * connection);
|
||||
|
||||
|
||||
const char * hfp_hf_feature(int index);
|
||||
|
55
src/hfp_ag.c
55
src/hfp_ag.c
@ -257,43 +257,47 @@ int hfp_ag_retrieve_initital_supported_generic_status_indicators_cmd(uint16_t ci
|
||||
|
||||
void update_command(hfp_connection_t * context){
|
||||
context->command = HFP_CMD_NONE;
|
||||
|
||||
printf("Received %s\n", context->line_buffer);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (strncmp((char *)context->line_buffer+2, HFP_INDICATOR, strlen(HFP_INDICATOR)) == 0){
|
||||
printf("Received AT+CIND\n");
|
||||
context->command = HFP_CMD_INDICATOR;
|
||||
if (strncmp((char *)context->line_buffer+strlen(HFP_INDICATOR)+2, "?", 1) == 0){
|
||||
context->command = HFP_CMD_INDICATOR_STATUS;
|
||||
} else {
|
||||
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");
|
||||
if (strncmp((char *)context->line_buffer+2, HFP_ENABLE_STATUS_UPDATE_FOR_AG_INDICATORS, strlen(HFP_ENABLE_STATUS_UPDATE_FOR_AG_INDICATORS)) == 0){
|
||||
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;
|
||||
}
|
||||
|
||||
if (strncmp((char *)context->line_buffer+2, HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS, strlen(HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS)) == 0){
|
||||
context->command = HFP_CMD_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -332,22 +336,15 @@ void hfp_run_for_context(hfp_connection_t *context){
|
||||
hfp_ag_retrieve_indicators_cmd(context->rfcomm_cid);
|
||||
context->state = HFP_W4_RETRIEVE_INDICATORS_STATUS;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case HFP_CMD_INDICATOR_STATUS:
|
||||
switch(context->state){
|
||||
case HFP_W4_RETRIEVE_INDICATORS_STATUS:
|
||||
hfp_ag_retrieve_indicators_status_cmd(context->rfcomm_cid);
|
||||
if (context->remote_indicators_update_enabled == 0){
|
||||
context->state = HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE;
|
||||
break;
|
||||
}
|
||||
if (has_call_waiting_and_3way_calling_feature(context)){
|
||||
context->state = HFP_W4_RETRIEVE_CAN_HOLD_CALL;
|
||||
break;
|
||||
}
|
||||
if (has_hf_indicators_feature(context)){
|
||||
context->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS;
|
||||
break;
|
||||
}
|
||||
context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
|
||||
hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0);
|
||||
context->state = HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -368,6 +365,9 @@ void hfp_run_for_context(hfp_connection_t *context){
|
||||
context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
|
||||
hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0);
|
||||
break;
|
||||
case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
|
||||
// TODO
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -407,6 +407,10 @@ void hfp_run_for_context(hfp_connection_t *context){
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case HFP_CMD_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE:
|
||||
|
||||
break;
|
||||
|
||||
case HFP_CMD_NONE:
|
||||
switch(context->state){
|
||||
case HFP_W2_DISCONNECT_RFCOMM:
|
||||
@ -432,6 +436,7 @@ static void hfp_handle_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8
|
||||
context->state = HFP_W4_EXCHANGE_SUPPORTED_FEATURES;
|
||||
}
|
||||
|
||||
printf("hfp_handle_rfcomm_event %s\n", &packet[0]);
|
||||
packet[size] = 0;
|
||||
int pos;
|
||||
for (pos = 0; pos < size ; pos++){
|
||||
@ -500,9 +505,9 @@ void hfp_ag_establish_service_level_connection(bd_addr_t bd_addr){
|
||||
hfp_establish_service_level_connection(bd_addr, SDP_Handsfree);
|
||||
}
|
||||
|
||||
// TODO trigger release audio connection
|
||||
void hfp_ag_release_service_level_connection(bd_addr_t bd_addr){
|
||||
hfp_connection_t * connection = hfp_release_service_level_connection(bd_addr);
|
||||
hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
|
||||
hfp_release_service_level_connection(connection);
|
||||
hfp_run_for_context(connection);
|
||||
}
|
||||
|
||||
|
105
src/hfp_hf.c
105
src/hfp_hf.c
@ -142,13 +142,21 @@ 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, uint8_t activate){
|
||||
int hfp_hs_activate_status_update_for_all_ag_indicators_cmd(uint16_t cid, uint8_t activate){
|
||||
char buffer[20];
|
||||
sprintf(buffer, "AT%s=3,0,0,%d\r\n", HFP_ENABLE_INDICATOR_STATUS_UPDATE, activate);
|
||||
sprintf(buffer, "AT%s=3,0,0,%d\r\n", HFP_ENABLE_STATUS_UPDATE_FOR_AG_INDICATORS, activate);
|
||||
// printf("toggle_indicator_status_update %s\n", buffer);
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
int hfp_hs_activate_status_update_for_ag_indicator_cmd(uint16_t cid, uint32_t indicators_status, int indicators_nr, uint8_t activate){
|
||||
char buffer[20];
|
||||
int offset = snprintf(buffer, sizeof(buffer), "AT%s=", HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS);
|
||||
offset += join_bitmap(buffer+offset, sizeof(buffer)-offset, indicators_status, 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_can_hold_call_cmd(uint16_t cid){
|
||||
char buffer[20];
|
||||
@ -197,13 +205,15 @@ static void hfp_run_for_context(hfp_connection_t * context){
|
||||
case HFP_RETRIEVE_INDICATORS:
|
||||
hfp_hs_retrieve_indicators_cmd(context->rfcomm_cid);
|
||||
context->state = HFP_W4_RETRIEVE_INDICATORS;
|
||||
context->sent_command = HFP_CMD_INDICATOR;
|
||||
break;
|
||||
case HFP_RETRIEVE_INDICATORS_STATUS:
|
||||
hfp_hs_retrieve_indicators_status_cmd(context->rfcomm_cid);
|
||||
context->state = HFP_W4_RETRIEVE_INDICATORS_STATUS;
|
||||
context->sent_command = HFP_CMD_INDICATOR_STATUS;
|
||||
break;
|
||||
case HFP_ENABLE_INDICATORS_STATUS_UPDATE:
|
||||
hfp_hs_toggle_indicator_status_update_cmd(context->rfcomm_cid, 1);
|
||||
hfp_hs_activate_status_update_for_all_ag_indicators_cmd(context->rfcomm_cid, 1);
|
||||
context->state = HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE;
|
||||
break;
|
||||
case HFP_RETRIEVE_CAN_HOLD_CALL:
|
||||
@ -213,22 +223,39 @@ static void hfp_run_for_context(hfp_connection_t * context){
|
||||
case HFP_LIST_GENERIC_STATUS_INDICATORS:
|
||||
hfp_hs_list_supported_generic_status_indicators_cmd(context->rfcomm_cid);
|
||||
context->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS;
|
||||
context->sent_command = HFP_CMD_LIST_GENERIC_STATUS_INDICATOR;
|
||||
break;
|
||||
case HFP_RETRIEVE_GENERIC_STATUS_INDICATORS:
|
||||
hfp_hs_retrieve_supported_generic_status_indicators_cmd(context->rfcomm_cid);
|
||||
context->state = HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS;
|
||||
context->sent_command = HFP_CMD_GENERIC_STATUS_INDICATOR;
|
||||
break;
|
||||
case HFP_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS:
|
||||
hfp_hs_list_initital_supported_generic_status_indicators_cmd(context->rfcomm_cid);
|
||||
context->state = HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS;
|
||||
break;
|
||||
case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
|
||||
hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0);
|
||||
context->sent_command = HFP_CMD_GENERIC_STATUS_INDICATOR_STATE;
|
||||
break;
|
||||
case HFP_W2_DISCONNECT_RFCOMM:
|
||||
context->state = HFP_W4_RFCOMM_DISCONNECTED;
|
||||
rfcomm_disconnect_internal(context->rfcomm_cid);
|
||||
break;
|
||||
case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
|
||||
if (context->wait_ok == 1) return;
|
||||
|
||||
if (context->enable_status_update_for_ag_indicators != 0xFF){
|
||||
hfp_hs_activate_status_update_for_all_ag_indicators_cmd(context->rfcomm_cid, context->enable_status_update_for_ag_indicators);
|
||||
context->wait_ok = 1;
|
||||
break;
|
||||
};
|
||||
if (context->change_enable_status_update_for_individual_ag_indicators != 0xFF){
|
||||
hfp_hs_activate_status_update_for_ag_indicator_cmd(context->rfcomm_cid,
|
||||
context->ag_indicators_status_update_bitmap,
|
||||
context->ag_indicators_nr,
|
||||
context->change_enable_status_update_for_individual_ag_indicators);
|
||||
context->wait_ok = 1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -249,19 +276,19 @@ void update_command(hfp_connection_t * context){
|
||||
}
|
||||
|
||||
if (strncmp((char *)context->line_buffer, HFP_INDICATOR, strlen(HFP_INDICATOR)) == 0){
|
||||
printf("Received +CIND\n");
|
||||
context->command = HFP_CMD_INDICATOR;
|
||||
printf("Received +CIND, %d\n", context->sent_command);
|
||||
context->command = context->sent_command;
|
||||
context->sent_command = HFP_CMD_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (strncmp((char *)context->line_buffer, HFP_AVAILABLE_CODECS, strlen(HFP_AVAILABLE_CODECS)) == 0){
|
||||
printf("Received +BAC\n");
|
||||
context->command = HFP_CMD_AVAILABLE_CODECS;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strncmp((char *)context->line_buffer, HFP_ENABLE_INDICATOR_STATUS_UPDATE, strlen(HFP_ENABLE_INDICATOR_STATUS_UPDATE)) == 0){
|
||||
if (strncmp((char *)context->line_buffer, HFP_ENABLE_STATUS_UPDATE_FOR_AG_INDICATORS, strlen(HFP_ENABLE_STATUS_UPDATE_FOR_AG_INDICATORS)) == 0){
|
||||
printf("Received +CMER\n");
|
||||
context->command = HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE;
|
||||
return;
|
||||
@ -275,9 +302,17 @@ void update_command(hfp_connection_t * context){
|
||||
|
||||
if (strncmp((char *)context->line_buffer, HFP_GENERIC_STATUS_INDICATOR, strlen(HFP_GENERIC_STATUS_INDICATOR)) == 0){
|
||||
printf("Received +BIND\n");
|
||||
context->command = HFP_CMD_GENERIC_STATUS_INDICATOR;
|
||||
context->command = context->sent_command;
|
||||
printf("Received +BIND %d\n", context->sent_command);
|
||||
return;
|
||||
}
|
||||
|
||||
if (strncmp((char *)context->line_buffer, HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS, strlen(HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS)) == 0){
|
||||
printf("Received +BIA\n");
|
||||
context->command = HFP_CMD_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE;
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -300,21 +335,9 @@ void handle_switch_on_ok(hfp_connection_t *context){
|
||||
break;
|
||||
|
||||
case HFP_W4_RETRIEVE_INDICATORS_STATUS:
|
||||
if (context->remote_indicators_update_enabled == 0){
|
||||
context->state = HFP_ENABLE_INDICATORS_STATUS_UPDATE;
|
||||
break;
|
||||
}
|
||||
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_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
|
||||
context->state = HFP_ENABLE_INDICATORS_STATUS_UPDATE;
|
||||
break;
|
||||
|
||||
|
||||
case HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE:
|
||||
if (has_call_waiting_and_3way_calling_feature(context)){
|
||||
context->state = HFP_RETRIEVE_CAN_HOLD_CALL;
|
||||
@ -325,6 +348,7 @@ void handle_switch_on_ok(hfp_connection_t *context){
|
||||
break;
|
||||
}
|
||||
context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
|
||||
hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0);
|
||||
break;
|
||||
|
||||
case HFP_W4_RETRIEVE_CAN_HOLD_CALL:
|
||||
@ -333,7 +357,8 @@ void handle_switch_on_ok(hfp_connection_t *context){
|
||||
break;
|
||||
}
|
||||
context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
|
||||
break;
|
||||
hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0);
|
||||
break;
|
||||
|
||||
case HFP_W4_LIST_GENERIC_STATUS_INDICATORS:
|
||||
context->state = HFP_RETRIEVE_GENERIC_STATUS_INDICATORS;
|
||||
@ -346,8 +371,12 @@ void handle_switch_on_ok(hfp_connection_t *context){
|
||||
case HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS:
|
||||
printf("Supported initial state generic status indicators \n");
|
||||
context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
|
||||
hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0);
|
||||
break;
|
||||
|
||||
case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
|
||||
context->wait_ok = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@ -421,16 +450,30 @@ void hfp_hf_establish_service_level_connection(bd_addr_t bd_addr){
|
||||
}
|
||||
|
||||
void hfp_hf_release_service_level_connection(bd_addr_t bd_addr){
|
||||
hfp_connection_t * connection = hfp_release_service_level_connection(bd_addr);
|
||||
hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
|
||||
hfp_release_service_level_connection(connection);
|
||||
hfp_run_for_context(connection);
|
||||
}
|
||||
|
||||
void hfp_hf_transfer_registration_status(bd_addr_t bd_addr){
|
||||
|
||||
void hfp_hf_enable_status_update_for_all_ag_indicators(bd_addr_t bd_addr, uint8_t enable){
|
||||
hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
|
||||
if (!connection){
|
||||
log_error("HFP HF: connection doesn't exist.");
|
||||
return;
|
||||
}
|
||||
connection->enable_status_update_for_ag_indicators = 1;
|
||||
hfp_run_for_context(connection);
|
||||
}
|
||||
|
||||
void hfp_hf_activate_ag_indicator(bd_addr_t bd_addr){
|
||||
|
||||
void hfp_hf_enable_status_update_for_ag_indicator(bd_addr_t bd_addr, uint32_t indicators_status_bitmap, uint8_t enable){
|
||||
hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
|
||||
if (!connection){
|
||||
log_error("HFP HF: connection doesn't exist.");
|
||||
return;
|
||||
}
|
||||
connection->change_enable_status_update_for_individual_ag_indicators = 1;
|
||||
connection->ag_indicators_status_update_bitmap = indicators_status_bitmap;
|
||||
hfp_run_for_context(connection);
|
||||
}
|
||||
|
||||
void hfp_hf_transfer_signal_strength_indication(bd_addr_t bd_addr){
|
||||
|
@ -91,14 +91,14 @@ void hfp_hf_establish_service_level_connection(bd_addr_t bd_addr);
|
||||
void hfp_hf_release_service_level_connection(bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief Enable registration status update in the AG.
|
||||
* @brief Deactivate/reactivate status update for all indicators in the AG.
|
||||
*/
|
||||
void hfp_hf_transfer_registration_status(bd_addr_t bd_addr);
|
||||
void hfp_hf_enable_status_update_for_all_ag_indicators(bd_addr_t bd_addr, uint8_t enable);
|
||||
|
||||
/**
|
||||
* @brief Deactivate/reactivate individual indicators in the AG.
|
||||
* @brief Deactivate/reactivate status update for the individual indicators in the AG using bitmap.
|
||||
*/
|
||||
void hfp_hf_activate_ag_indicator(bd_addr_t bd_addr);
|
||||
void hfp_hf_enable_status_update_for_ag_indicator(bd_addr_t bd_addr, uint32_t indicators_status_bitmap, uint8_t enable);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -99,7 +99,7 @@ uint16_t l2cap_create_signaling_internal(uint8_t * acl_buffer, hci_con_handle_t
|
||||
uint16_t pos = 12;
|
||||
// skip AMP commands
|
||||
if (cmd >= CONNECTION_PARAMETER_UPDATE_REQUEST){
|
||||
cmd -= 6;
|
||||
cmd = (L2CAP_SIGNALING_COMMANDS) (((int) cmd) - 6);
|
||||
}
|
||||
const char *format = l2cap_signaling_commands_format[cmd-1];
|
||||
uint16_t word;
|
||||
|
54
test/hfp/Makefile
Normal file
54
test/hfp/Makefile
Normal file
@ -0,0 +1,54 @@
|
||||
CC=g++
|
||||
|
||||
# Makefile for libusb based PTS tests
|
||||
BTSTACK_ROOT = ../..
|
||||
POSIX_ROOT= ${BTSTACK_ROOT}/platforms/posix
|
||||
CPPUTEST_HOME = ${BTSTACK_ROOT}/test/cpputest
|
||||
|
||||
COMMON = \
|
||||
btstack_memory.c \
|
||||
linked_list.c \
|
||||
memory_pool.c \
|
||||
run_loop.c \
|
||||
run_loop_posix.c \
|
||||
hci.c \
|
||||
hci_cmds.c \
|
||||
hci_dump.c \
|
||||
l2cap.c \
|
||||
l2cap_signaling.c \
|
||||
rfcomm.c \
|
||||
remote_device_db_memory.c \
|
||||
sdp_util.c \
|
||||
utils.c \
|
||||
hfp.c \
|
||||
hfp_hf.c \
|
||||
sdp_client.c \
|
||||
sdp_parser.c \
|
||||
sdp_query_util.c \
|
||||
sdp_query_rfcomm.c \
|
||||
sdp.c \
|
||||
|
||||
|
||||
COMMON_OBJ = $(COMMON:.c=.o)
|
||||
|
||||
# CC = gcc-fsf-4.9
|
||||
CFLAGS = -g -Wall -I. -I../ -I${BTSTACK_ROOT}/src -I${BTSTACK_ROOT}/include
|
||||
# CFLAGS += -Werror
|
||||
|
||||
VPATH += ${BTSTACK_ROOT}/src
|
||||
VPATH += ${BTSTACK_ROOT}/ble
|
||||
VPATH += ${BTSTACK_ROOT}/platforms/posix/src
|
||||
|
||||
CFLAGS = -g -Wall -I. -I../ -I${BTSTACK_ROOT}/src -I${BTSTACK_ROOT}/include -I${BTSTACK_ROOT}/ble
|
||||
LDFLAGS += -lCppUTest -lCppUTestExt
|
||||
|
||||
|
||||
EXAMPLES = hfp_hf_parser_test
|
||||
|
||||
all: ${BTSTACK_ROOT}/include/btstack/version.h ${EXAMPLES}
|
||||
|
||||
clean:
|
||||
rm -rf *.o $(EXAMPLES) *.dSYM
|
||||
|
||||
hfp_hf_parser_test: ${COMMON_OBJ} hfp.o hfp_hf_parser_test.c
|
||||
${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@
|
207
test/hfp/hfp_hf_parser_test.c
Normal file
207
test/hfp/hfp_hf_parser_test.c
Normal file
@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright (C) 2014 BlueKitchen GmbH
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
* 4. Any redistribution, use, or modification is done solely for
|
||||
* personal benefit and not for any commercial purpose or for
|
||||
* monetary gain.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
|
||||
* RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* Please inquire about commercial licensing options at
|
||||
* contact@bluekitchen-gmbh.com
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "CppUTest/TestHarness.h"
|
||||
#include "CppUTest/CommandLineTestRunner.h"
|
||||
|
||||
#include "hfp.h"
|
||||
|
||||
void hfp_parse(hfp_connection_t * context, uint8_t byte);
|
||||
|
||||
static hfp_connection_t context;
|
||||
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},
|
||||
};
|
||||
|
||||
TEST_GROUP(HFPParser){
|
||||
char packet[200];
|
||||
int pos;
|
||||
int offset;
|
||||
|
||||
void parser_init(hfp_connection_t * context){
|
||||
context->parser_state = HFP_PARSER_CMD_HEADER;
|
||||
context->parser_item_index = 0;
|
||||
context->line_size = 0;
|
||||
context->ag_indicators_nr = 0;
|
||||
context->remote_codecs_nr = 0;
|
||||
memset(packet,0, sizeof(packet));
|
||||
}
|
||||
|
||||
void setup(void){
|
||||
parser_init(&context);
|
||||
}
|
||||
};
|
||||
|
||||
TEST(HFPParser, HFP_HF_OK){
|
||||
sprintf(packet, "\r\n%s\r\n", HFP_OK);
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
}
|
||||
CHECK_EQUAL(HFP_CMD_OK, context.command);
|
||||
}
|
||||
|
||||
TEST(HFPParser, HFP_HF_SUPPORTED_FEATURES){
|
||||
sprintf(packet, "\r\n%s:0000001111101111\r\n", HFP_SUPPORTED_FEATURES);
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
}
|
||||
CHECK_EQUAL(HFP_CMD_SUPPORTED_FEATURES, context.command);
|
||||
CHECK_EQUAL(1007, context.remote_supported_features);
|
||||
}
|
||||
|
||||
TEST(HFPParser, HFP_HF_AVAILABLE_CODECS){
|
||||
sprintf(packet, "\r\n%s:0,1,2\r\n", HFP_AVAILABLE_CODECS);
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
}
|
||||
CHECK_EQUAL(HFP_CMD_AVAILABLE_CODECS, context.command);
|
||||
CHECK_EQUAL(3, context.remote_codecs_nr);
|
||||
for (pos = 0; pos < 3; pos++){
|
||||
CHECK_EQUAL(pos, context.remote_codecs[pos]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HFPParser, HFP_HF_INDICATORS){
|
||||
offset = 0;
|
||||
offset += snprintf(packet, sizeof(packet), "%s:", HFP_INDICATOR);
|
||||
for (pos = 0; pos < ag_indicators_nr - 1; pos++){
|
||||
offset += snprintf(packet+offset, sizeof(packet)-offset, "\"%s\", (%d, %d),", ag_indicators[pos].name, ag_indicators[pos].min_range, ag_indicators[pos].max_range);
|
||||
}
|
||||
offset += snprintf(packet+offset, sizeof(packet)-offset, "\"%s\", (%d, %d)\r\n", ag_indicators[pos].name, ag_indicators[pos].min_range, ag_indicators[pos].max_range);
|
||||
|
||||
context.sent_command = HFP_CMD_INDICATOR;
|
||||
context.ag_indicators_nr = 0;
|
||||
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
}
|
||||
CHECK_EQUAL(HFP_CMD_INDICATOR, context.command);
|
||||
CHECK_EQUAL(ag_indicators_nr, context.ag_indicators_nr);
|
||||
for (pos = 0; pos < ag_indicators_nr; pos++){
|
||||
CHECK_EQUAL(ag_indicators[pos].index, context.ag_indicators[pos].index);
|
||||
CHECK_EQUAL(0, strcmp(ag_indicators[pos].name, context.ag_indicators[pos].name));
|
||||
CHECK_EQUAL(ag_indicators[pos].min_range, context.ag_indicators[pos].min_range);
|
||||
CHECK_EQUAL(ag_indicators[pos].max_range, context.ag_indicators[pos].max_range);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HFPParser, HFP_HF_INDICATOR_STATUS){
|
||||
// send status
|
||||
offset = 0;
|
||||
offset += snprintf(packet, sizeof(packet), "%s:", HFP_INDICATOR);
|
||||
for (pos = 0; pos < ag_indicators_nr - 1; pos++){
|
||||
offset += snprintf(packet+offset, sizeof(packet)-offset, "%d,", ag_indicators[pos].status);
|
||||
}
|
||||
offset += snprintf(packet+offset, sizeof(packet)-offset, "%d\r\n", ag_indicators[pos].status);
|
||||
|
||||
context.sent_command = HFP_CMD_INDICATOR_STATUS;
|
||||
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
}
|
||||
|
||||
CHECK_EQUAL(HFP_CMD_INDICATOR_STATUS, context.command);
|
||||
for (pos = 0; pos < ag_indicators_nr; pos++){
|
||||
CHECK_EQUAL(ag_indicators[pos].status, context.ag_indicators[pos].status);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HFPParser, HFP_HF_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES){
|
||||
sprintf(packet, "\r\n%s:(1,1x,2,2x,3)\r\n", HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES);
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
}
|
||||
CHECK_EQUAL(HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES, context.command);
|
||||
CHECK_EQUAL(5, context.remote_call_services_nr);
|
||||
|
||||
CHECK_EQUAL(0, strcmp("1", (char*)context.remote_call_services[0].name));
|
||||
CHECK_EQUAL(0, strcmp("1x", (char*)context.remote_call_services[1].name));
|
||||
CHECK_EQUAL(0, strcmp("2", (char*)context.remote_call_services[2].name));
|
||||
CHECK_EQUAL(0, strcmp("2x", (char*)context.remote_call_services[3].name));
|
||||
CHECK_EQUAL(0, strcmp("3", (char*)context.remote_call_services[4].name));
|
||||
}
|
||||
|
||||
TEST(HFPParser, HFP_HF_GENERIC_STATUS_INDICATOR){
|
||||
sprintf(packet, "\r\n%s:0,1\r\n", HFP_GENERIC_STATUS_INDICATOR);
|
||||
context.sent_command = HFP_CMD_GENERIC_STATUS_INDICATOR;
|
||||
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
}
|
||||
|
||||
CHECK_EQUAL(HFP_CMD_GENERIC_STATUS_INDICATOR, context.command);
|
||||
CHECK_EQUAL(2, context.generic_status_indicators_nr);
|
||||
|
||||
for (pos = 0; pos < context.generic_status_indicators_nr; pos++){
|
||||
CHECK_EQUAL(pos, context.generic_status_indicators[pos].uuid);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HFPParser, HFP_HF_GENERIC_STATUS_INDICATOR_STATE){
|
||||
sprintf(packet, "\r\n%s:0,1\r\n", HFP_GENERIC_STATUS_INDICATOR);
|
||||
context.sent_command = HFP_CMD_GENERIC_STATUS_INDICATOR_STATE;
|
||||
|
||||
for (pos = 0; pos < strlen(packet); pos++){
|
||||
hfp_parse(&context, packet[pos]);
|
||||
}
|
||||
|
||||
CHECK_EQUAL(HFP_CMD_GENERIC_STATUS_INDICATOR_STATE, context.command);
|
||||
CHECK_EQUAL(1, context.generic_status_indicators[0].state);
|
||||
}
|
||||
|
||||
// TEST(HFPParser, HFP_AG_ENABLE_INDICATOR_STATUS_UPDATE){
|
||||
// }
|
||||
|
||||
// TEST(HFPParser, HFP_AG_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE){
|
||||
// }
|
||||
|
||||
int main (int argc, const char * argv[]){
|
||||
return CommandLineTestRunner::RunAllTests(argc, argv);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user