Merge branch 'master' into ble-api-cleanup

This commit is contained in:
Matthias Ringwald 2015-12-09 16:44:26 +01:00
commit 1e35c04d3c
19 changed files with 2102 additions and 491 deletions

View File

@ -125,9 +125,9 @@ static uint16_t ehcill_defer_rx_size = 0;
static uint8_t ehcill_command_to_send;
// H4: packet reader state machine
static H4_STATE h4_state;
static int read_pos;
static int bytes_to_read;
static volatile H4_STATE h4_state;
static int read_pos;
static int bytes_to_read;
// bigger than largest packet
static uint8_t hci_packet_prefixed[HCI_INCOMING_PRE_BUFFER_SIZE + HCI_PACKET_BUFFER_SIZE];
@ -136,8 +136,8 @@ static uint8_t * hci_packet = &hci_packet_prefixed[HCI_INCOMING_PRE_BUFFER_SIZE]
static void (*packet_handler)(uint8_t packet_type, uint8_t *packet, uint16_t size) = dummy_handler;
// H4: tx state
static TX_STATE tx_state;
static int tx_send_packet_sent;
static volatile TX_STATE tx_state; // updated from block_sent callback
static volatile int tx_send_packet_sent; // updated from block_sent callback
static uint8_t * tx_data;
static uint16_t tx_len;
static uint8_t tx_packet_type;
@ -225,11 +225,10 @@ static int h4_close(void *transport_config){
return 0;
}
// potentially called from ISR context
static void h4_block_received(void){
// gpio_set(GPIOB, GPIO_DEBUG_0);
read_pos += bytes_to_read;
read_pos += bytes_to_read;
// act
switch (h4_state) {
@ -300,11 +299,10 @@ static void h4_block_received(void){
static int h4_can_send_packet_now(uint8_t packet_type){
return tx_state == TX_IDLE;
}
static void ehcill_sleep_ack_timer_handler(timer_source_t * timer){
tx_state = TX_W4_EHCILL_SENT;
// gpio_clear(GPIOB, GPIO_DEBUG_1);
hal_uart_dma_send_block(&ehcill_command_to_send, 1);
}
@ -316,6 +314,7 @@ static void ehcill_sleep_ack_timer_setup(void){
embedded_trigger();
}
// potentially called from ISR context
static void h4_block_sent(void){
switch (tx_state){
case TX_W4_HEADER_SENT:
@ -324,22 +323,22 @@ static void h4_block_sent(void){
hal_uart_dma_send_block(tx_data, tx_len);
break;
case TX_W4_PACKET_SENT:
// non-ehcill packet sent, confirm
tx_send_packet_sent = 1;
// send pending ehcill command if neccessary
switch (ehcill_command_to_send){
case EHCILL_GO_TO_SLEEP_ACK:
ehcill_sleep_ack_timer_setup();
tx_send_packet_sent = 1;
break;
case EHCILL_WAKE_UP_IND:
tx_state = TX_W4_EHCILL_SENT;
// gpio_clear(GPIOB, GPIO_DEBUG_1);
hal_uart_dma_send_block(&ehcill_command_to_send, 1);
tx_send_packet_sent = 1;
break;
default:
// trigger run loop
tx_state = TX_DONE;
tx_send_packet_sent = 1;
embedded_trigger();
break;
}
@ -369,6 +368,12 @@ static int h4_process(struct data_source *ds) {
// notify about packet sent
if (tx_send_packet_sent){
// race condition: if tx_state was set after our check, can_send_now will fail, causing a hang
// workaround: assert that tx_state is TX_IDLE if it was just set to done by ISR
if (tx_state == TX_DONE){
tx_state = TX_IDLE;
}
tx_send_packet_sent = 0;
uint8_t event[] = { DAEMON_EVENT_HCI_PACKET_SENT, 0 };
packet_handler(HCI_EVENT_PACKET, &event[0], sizeof(event));

View File

@ -130,6 +130,7 @@ const char * hfp_ag_feature(int index){
}
int send_str_over_rfcomm(uint16_t cid, char * command){
log_info("HFP_TX %s", command);
if (!rfcomm_can_send_packet_now(cid)) return 1;
int err = rfcomm_send_internal(cid, (uint8_t*) command, strlen(command));
if (err){

View File

@ -1523,6 +1523,12 @@ static hfp_generic_status_indicator_t *get_hf_indicator_by_number(int number){
static void hfp_handle_rfcomm_data(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
hfp_connection_t * context = get_hfp_connection_context_for_rfcomm_cid(channel);
if (!context) return;
char last_char = packet[size-1];
packet[size-1] = 0;
log_info("HFP_RX %s", packet);
packet[size-1] = last_char;
int pos;
for (pos = 0; pos < size ; pos++){
hfp_parse(context, packet[pos], 0);
@ -1765,6 +1771,11 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
hfp_run();
}
static void hfp_ag_set_ag_indicators(hfp_ag_indicator_t * ag_indicators, int ag_indicators_nr){
hfp_ag_indicators_nr = ag_indicators_nr;
memcpy(hfp_ag_indicators, ag_indicators, ag_indicators_nr * sizeof(hfp_ag_indicator_t));
}
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,
@ -1789,8 +1800,7 @@ void hfp_ag_init(uint16_t rfcomm_channel_nr, uint32_t supported_features,
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_ag_set_ag_indicators(ag_indicators, ag_indicators_nr);
set_hfp_generic_status_indicators(hf_indicators, hf_indicators_nr);

View File

@ -919,9 +919,12 @@ static void hfp_handle_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8
hfp_connection_t * context = get_hfp_connection_context_for_rfcomm_cid(channel);
if (!context) return;
packet[size] = 0;
char last_char = packet[size-1];
packet[size-1] = 0;
log_info("HFP_RX %s", packet);
packet[size-1] = last_char;
int pos, i, value;
//printf("\nHF received: %s", packet+2);
for (pos = 0; pos < size ; pos++){
hfp_parse(context, packet[pos], 1);
}
@ -1034,8 +1037,6 @@ void hfp_hf_set_codecs(uint8_t * codecs, int codecs_nr){
char buffer[30];
int offset = join(buffer, sizeof(buffer), hfp_codecs, hfp_codecs_nr);
buffer[offset] = 0;
printf("set codecs %s\n", buffer);
linked_list_iterator_t it;
linked_list_iterator_init(&it, hfp_get_connections());
while (linked_list_iterator_has_next(&it)){

View File

@ -406,7 +406,7 @@ static void hsp_run(void){
int gain = ag_microphone_gain;
ag_microphone_gain = -1;
char buffer[10];
sprintf(buffer, "%s=%d\r\n", HSP_MICROPHONE_GAIN, ag_microphone_gain);
sprintf(buffer, "%s=%d\r\n", HSP_MICROPHONE_GAIN, gain);
err = hsp_ag_send_str_over_rfcomm(rfcomm_cid, buffer);
if (err) {
ag_microphone_gain = gain;
@ -418,7 +418,7 @@ static void hsp_run(void){
int gain = ag_speaker_gain;
ag_speaker_gain = -1;
char buffer[10];
sprintf(buffer, "%s=%d\r\n", HSP_SPEAKER_GAIN, ag_speaker_gain);
sprintf(buffer, "%s=%d\r\n", HSP_SPEAKER_GAIN, gain);
err = hsp_ag_send_str_over_rfcomm(rfcomm_cid, buffer);
if (err) {
ag_speaker_gain = gain;

View File

@ -352,7 +352,7 @@ static void hsp_run(void){
int gain = hs_microphone_gain;
hs_microphone_gain = -1;
char buffer[20];
sprintf(buffer, "%s=%d\r\n", HSP_HS_MICROPHONE_GAIN, hs_microphone_gain);
sprintf(buffer, "%s=%d\r\n", HSP_HS_MICROPHONE_GAIN, gain);
err = hsp_hs_send_str_over_rfcomm(rfcomm_cid, buffer);
if (err) {
hs_microphone_gain = gain;
@ -364,7 +364,7 @@ static void hsp_run(void){
int gain = hs_speaker_gain;
hs_speaker_gain = -1;
char buffer[20];
sprintf(buffer, "%s=%d\r\n", HSP_HS_SPEAKER_GAIN, hs_speaker_gain);
sprintf(buffer, "%s=%d\r\n", HSP_HS_SPEAKER_GAIN, gain);
err = hsp_hs_send_str_over_rfcomm(rfcomm_cid, buffer);
if (err) {
hs_speaker_gain = gain;

View File

@ -74,9 +74,6 @@
#include "l2cap.h"
// used for debugging
// #define RFCOMM_LOG_CREDITS
// global rfcomm data
static uint16_t rfcomm_client_cid_generator; // used for client channel IDs
@ -136,20 +133,6 @@ static void rfcomm_emit_channel_opened(rfcomm_channel_t *channel, uint8_t status
(*app_packet_handler)(HCI_EVENT_PACKET, 0, (uint8_t *) event, pos);
}
// data: event(8), len(8), creidts incoming(8), new credits incoming(8), credits outgoing(8)
static inline void rfcomm_emit_credit_status(rfcomm_channel_t * channel) {
#ifdef RFCOMM_LOG_CREDITS
log_info("RFCOMM_LOG_CREDITS incoming %u new_incoming %u outgoing %u", channel->credits_incoming, channel->new_credits_incoming, channel->credits_outgoing);
uint8_t event[5];
event[0] = 0x88;
event[1] = sizeof(event) - 2;
event[2] = channel->credits_incoming;
event[3] = channel->new_credits_incoming;
event[4] = channel->credits_outgoing;
hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
#endif
}
// data: event(8), len(8), rfcomm_cid(16)
static void rfcomm_emit_channel_closed(rfcomm_channel_t * channel) {
log_info("RFCOMM_EVENT_CHANNEL_CLOSED cid 0x%02x", channel->rfcomm_cid);
@ -251,7 +234,6 @@ static void rfcomm_multiplexer_initialize(rfcomm_multiplexer_t *multiplexer){
memset(multiplexer, 0, sizeof(rfcomm_multiplexer_t));
multiplexer->state = RFCOMM_MULTIPLEXER_CLOSED;
multiplexer->l2cap_credits = 0;
multiplexer->fcon = 1;
multiplexer->send_dm_for_dlci = 0;
multiplexer->max_frame_size = rfcomm_max_frame_size_for_l2cap_mtu(l2cap_max_mtu());
@ -466,20 +448,8 @@ static int rfcomm_send_packet_for_multiplexer(rfcomm_multiplexer_t *multiplexer,
}
rfcomm_out_buffer[pos++] = crc8_calc(rfcomm_out_buffer, crc_fields); // calc fcs
int credits_taken = 0;
if (multiplexer->l2cap_credits){
credits_taken++;
multiplexer->l2cap_credits--;
} else {
log_info( "rfcomm_send_packet addr %02x, ctrl %02x size %u without l2cap credits", address, control, pos);
}
int err = l2cap_send_prepared(multiplexer->l2cap_cid, pos);
if (err) {
// undo credit counting
multiplexer->l2cap_credits += credits_taken;
}
return err;
}
@ -502,21 +472,9 @@ static int rfcomm_send_uih_prepared(rfcomm_multiplexer_t *multiplexer, uint8_t d
// UIH frames only calc FCS over address + control (5.1.1)
rfcomm_out_buffer[pos++] = crc8_calc(rfcomm_out_buffer, 2); // calc fcs
int credits_taken = 0;
if (multiplexer->l2cap_credits){
credits_taken++;
multiplexer->l2cap_credits--;
} else {
log_info( "rfcomm_send_uih_prepared addr %02x, ctrl %02x size %u without l2cap credits", address, control, pos);
}
int err = l2cap_send_prepared(multiplexer->l2cap_cid, pos);
if (err) {
// undo credit counting
multiplexer->l2cap_credits += credits_taken;
}
return err;
}
@ -926,8 +884,6 @@ static int rfcomm_multiplexer_hci_event_handler(uint8_t *packet, uint16_t size){
l2cap_cid = READ_BT_16(packet, 2);
multiplexer = rfcomm_multiplexer_for_l2cap_cid(l2cap_cid);
if (!multiplexer) break;
multiplexer->l2cap_credits += packet[4];
// log_info("L2CAP_EVENT_CREDITS: %u (now %u)", packet[4], multiplexer->l2cap_credits);
// new credits, continue with signaling
@ -1180,10 +1136,6 @@ static void rfcomm_hand_out_credits(void){
// log_info("RFCOMM_EVENT_CREDITS: no outgoing credits");
continue;
}
if (!channel->multiplexer->l2cap_credits){
// log_info("RFCOMM_EVENT_CREDITS: no l2cap credits");
continue;
}
// channel open, multiplexer has l2cap credits and we didn't hand out credit before -> go!
// log_info("RFCOMM_EVENT_CREDITS: 1");
channel->packets_granted += 1;
@ -1194,8 +1146,6 @@ static void rfcomm_hand_out_credits(void){
static void rfcomm_channel_send_credits(rfcomm_channel_t *channel, uint8_t credits){
rfcomm_send_uih_credits(channel->multiplexer, channel->dlci, credits);
channel->credits_incoming += credits;
rfcomm_emit_credit_status(channel);
}
static void rfcomm_channel_opened(rfcomm_channel_t *rfChannel){
@ -1261,9 +1211,6 @@ static void rfcomm_channel_packet_handler_uih(rfcomm_multiplexer_t *multiplexer,
if (!channel->incoming_flow_control && channel->credits_incoming < 5){
channel->new_credits_incoming =RFCOMM_CREDITS;
}
rfcomm_emit_credit_status(channel);
// we received new RFCOMM credits, hand them out if possible
rfcomm_hand_out_credits();
}
@ -1547,7 +1494,8 @@ static int rfcomm_channel_ready_for_open(rfcomm_channel_t *channel){
// log_info("rfcomm_channel_ready_for_open state %u, flags needed %04x, current %04x, rf credits %u, l2cap credits %u ", channel->state, RFCOMM_CHANNEL_STATE_VAR_RCVD_MSC_RSP|RFCOMM_CHANNEL_STATE_VAR_SENT_MSC_RSP|RFCOMM_CHANNEL_STATE_VAR_SENT_CREDITS, channel->state_var, channel->credits_outgoing, channel->multiplexer->l2cap_credits);
// if ((channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SENT_MSC_RSP) == 0) return 0;
// if (channel->credits_outgoing == 0) return 0;
log_info("rfcomm_channel_ready_for_open state %u, flags needed %04x, current %04x, rf credits %u, l2cap credits %u ", channel->state, RFCOMM_CHANNEL_STATE_VAR_RCVD_MSC_RSP, channel->state_var, channel->credits_outgoing, channel->multiplexer->l2cap_credits);
log_info("rfcomm_channel_ready_for_open state %u, flags needed %04x, current %04x, rf credits %u",
channel->state, RFCOMM_CHANNEL_STATE_VAR_RCVD_MSC_RSP, channel->state_var, channel->credits_outgoing);
if ((channel->state_var & RFCOMM_CHANNEL_STATE_VAR_RCVD_MSC_RSP) == 0) return 0;
if ((channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SENT_CREDITS) == 0) return 0;
@ -1976,7 +1924,6 @@ int rfcomm_can_send_packet_now(uint16_t rfcomm_cid){
return 1;
}
if (!channel->credits_outgoing) return 0;
if (!channel->packets_granted) return 0;
if ((channel->multiplexer->fcon & 1) == 0) return 0;
return l2cap_can_send_packet_now(channel->multiplexer->l2cap_cid);
@ -1992,11 +1939,6 @@ static int rfcomm_assert_send_valid(rfcomm_channel_t * channel , uint16_t len){
log_info("rfcomm_send_internal cid 0x%02x, no rfcomm outgoing credits!", channel->rfcomm_cid);
return RFCOMM_NO_OUTGOING_CREDITS;
}
if (!channel->packets_granted){
log_info("rfcomm_send_internal cid 0x%02x, no rfcomm credits granted!", channel->rfcomm_cid);
return RFCOMM_NO_OUTGOING_CREDITS;
}
if ((channel->multiplexer->fcon & 1) == 0){
log_info("rfcomm_send_internal cid 0x%02x, aggregate flow off!", channel->rfcomm_cid);

View File

@ -204,7 +204,6 @@ typedef struct {
RFCOMM_MULTIPLEXER_STATE state;
uint16_t l2cap_cid;
uint8_t l2cap_credits;
uint8_t fcon; // only send if fcon & 1, send rsp if fcon & 0x80

View File

@ -239,7 +239,6 @@ static l2cap_channel_t * l2cap_get_channel_for_local_cid(uint16_t local_cid){
int l2cap_can_send_packet_now(uint16_t local_cid){
l2cap_channel_t *channel = l2cap_get_channel_for_local_cid(local_cid);
if (!channel) return 0;
if (!channel->packets_granted) return 0;
return hci_can_send_acl_packet_now(channel->handle);
}
@ -383,17 +382,14 @@ int l2cap_send_prepared(uint16_t local_cid, uint16_t len){
return -1; // TODO: define error
}
if (channel->packets_granted == 0){
log_error("l2cap_send_prepared cid 0x%02x, no credits!", local_cid);
return -1; // TODO: define error
}
if (!hci_can_send_prepared_acl_packet_now(channel->handle)){
log_info("l2cap_send_prepared cid 0x%02x, cannot send", local_cid);
return BTSTACK_ACL_BUFFERS_FULL;
}
--channel->packets_granted;
if (channel->packets_granted){
--channel->packets_granted;
}
log_debug("l2cap_send_prepared cid 0x%02x, handle %u, 1 credit used, credits left %u;",
local_cid, channel->handle, channel->packets_granted);
@ -943,6 +939,9 @@ static void l2cap_event_handler(uint8_t *packet, uint16_t size){
break;
case DAEMON_EVENT_HCI_PACKET_SENT:
l2cap_run(); // try sending signaling packets first
l2cap_hand_out_credits();
linked_list_iterator_init(&it, &l2cap_channels);
while (linked_list_iterator_has_next(&it)){
l2cap_channel_t * channel = (l2cap_channel_t *) linked_list_iterator_next(&it);

View File

@ -5,6 +5,8 @@ BTSTACK_ROOT = ../..
POSIX_ROOT= ${BTSTACK_ROOT}/platform/posix
CPPUTEST_HOME = ${BTSTACK_ROOT}/test/cpputest
include ${BTSTACK_ROOT}/example/embedded/Makefile.inc
COMMON = \
btstack_memory.c \
linked_list.c \

View File

@ -0,0 +1,89 @@
#!/usr/bin/env python
# BlueKitchen GmbH (c) 2014
# primitive dump for PacketLogger format
# APPLE PacketLogger
# typedef struct {
# uint32_t len;
# uint32_t ts_sec;
# uint32_t ts_usec;
# uint8_t type; // 0xfc for note
# }
import re
import sys
import time
import datetime
packet_types = [ "CMD =>", "EVT <=", "ACL =>", "ACL <="]
def read_net_32(f):
a = f.read(1)
b = f.read(1)
c = f.read(1)
d = f.read(1)
return ord(a) << 24 | ord(b) << 16 | ord(c) << 8 | ord(d)
def as_hex(data):
str_list = []
for byte in data:
str_list.append("{0:02x} ".format(ord(byte)))
return ''.join(str_list)
if len(sys.argv) < 2:
print 'Dump PacketLogger file'
print 'Copyright 2014, BlueKitchen GmbH'
print ''
print 'Usage: ', sys.argv[0], 'hci_dump.pklg test_name'
exit(0)
infile = sys.argv[1]
test_name = sys.argv[2]
separator = ""
spaces = " "
print "const char * "+test_name+"[] = {"
with open (infile, 'rb') as fin:
try:
while True:
len = read_net_32(fin)
ts_sec = read_net_32(fin)
ts_usec = read_net_32(fin)
type = ord(fin.read(1))
packet_len = len - 9;
packet = fin.read(packet_len)
time = "[%s.%03u]" % (datetime.datetime.fromtimestamp(ts_sec).strftime("%Y-%m-%d %H:%M:%S"), ts_usec / 1000)
if type == 0xfc:
packet = packet.replace("\n","\\n")
packet = packet.replace("\r","\\r")
packet = packet.replace("\"","\\\"")
parts = re.match('HFP_RX(.*)',packet)
if not parts:
parts = re.match('HFP_TX(.*)',packet)
cmd = 0
if parts:
hfp_cmds = parts.groups()[0].split('\\r\\n')
for cmd in hfp_cmds:
cmd = cmd.strip()
if cmd <> "":
cmd = cmd.replace("\\r","")
print separator+spaces+"\""+cmd+"\"",
separator = ",\n"
else:
parts = re.match('USER:\'(.*)\'.*',packet)
if parts:
cmd = 'USER:'+parts.groups()[0]
print separator+spaces+"\""+cmd+"\"",
separator = ",\n"
except TypeError:
print "\n};\n"
exit(0)
print "\n};\n"

View File

@ -84,8 +84,18 @@ static hfp_ag_indicator_t ag_indicators[] = {
{7, "callheld", 0, 2, 0, 1, 1, 0}
};
static int supported_features_with_codec_negotiation = 1007; // 0011 1110 1111
static int supported_features_without_codec_negotiation = 495; // 0001 1110 1111
hfp_ag_indicator_t ag_indicators_temp[] = {
// index, name, min range, max range, status, mandatory, enabled, status changed
{1, "service", 0, 1, 1, 0, 0, 0},
{2, "call", 0, 1, 0, 1, 1, 0},
{3, "callsetup", 0, 3, 0, 1, 1, 0},
{4, "battchg", 0, 5, 3, 0, 0, 0},
{5, "signal", 0, 5, 5, 0, 0, 0},
{6, "roam", 0, 1, 0, 0, 0, 0},
{7, "callheld", 0, 2, 0, 1, 1, 0}
};
static int supported_features_with_codec_negotiation = 4079; // 0011 1110 1111
static int call_hold_services_nr = 5;
static const char* call_hold_services[] = {"1", "1x", "2", "2x", "3"};
@ -104,41 +114,251 @@ static uint8_t start_ringing = 0;
static uint8_t stop_ringing = 0;
static uint8_t call_termiated = 0;
int expected_rfcomm_command(const char * expected_cmd){
char * ag_cmd = (char *)get_rfcomm_payload();
int ag_len = get_rfcomm_payload_len();
int expected_len = strlen(expected_cmd);
for (int i = 0; i < ag_len; i++){
if ( (ag_cmd+i)[0] == '\r' || (ag_cmd+i)[0] == '\n' ) {
continue;
}
if (strncmp(ag_cmd + i, expected_cmd, expected_len) == 0) return 1;
}
return 0;
static uint16_t handle = -1;
static int memory_1_enabled = 1;
static int last_number_exists = 1;
int has_more_hfp_ag_commands(){
return has_more_hfp_commands(2,2);
}
char * get_next_hfp_ag_command(){
return get_next_hfp_command(2,2);
}
void simulate_test_sequence(char ** test_steps, int nr_test_steps){
int i = 0;
for (i=0; i < nr_test_steps; i++){
char * cmd = test_steps[i];
printf("\n---> NEXT STEP %s\n", cmd);
if (strncmp(cmd, "AT", 2) == 0){
inject_rfcomm_command_to_ag((uint8_t*)cmd, strlen(cmd));
} else if (strncmp(cmd, "NOP", 3) == 0){
inject_rfcomm_command_to_ag((uint8_t*)"NOP",3);
} else {
int expected_cmd = expected_rfcomm_command(cmd);
if (!expected_cmd){
printf("\nError: Expected:'%s', but got:'%s'\n", cmd, (char *)get_rfcomm_payload());
CHECK_EQUAL(expected_cmd,1);
return;
}
printf("AG response verified %s\n\n", cmd);
}
static void user_command(char cmd){
switch (cmd){
case 'a':
printf("Establish HFP service level connection to PTS module %s...\n", bd_addr_to_str(device_addr));
hfp_ag_establish_service_level_connection(device_addr);
break;
case 'A':
printf("Release HFP service level connection.\n");
hfp_ag_release_service_level_connection(device_addr);
break;
case 'b':
printf("Establish Audio connection %s...\n", bd_addr_to_str(device_addr));
hfp_ag_establish_audio_connection(device_addr);
break;
case 'B':
printf("Release Audio connection.\n");
hfp_ag_release_audio_connection(device_addr);
break;
case 'c':
printf("Simulate incoming call from 1234567\n");
// current_call_exists_a = 1;
// current_call_status_a = HFP_ENHANCED_CALL_STATUS_INCOMING;
// current_call_dir = HFP_ENHANCED_CALL_DIR_INCOMING;
hfp_ag_set_clip(129, "1234567");
hfp_ag_incoming_call();
break;
case 'm':
printf("Simulate incoming call from 7654321\n");
// current_call_exists_b = 1;
// current_call_status_b = HFP_ENHANCED_CALL_STATUS_INCOMING;
// current_call_dir = HFP_ENHANCED_CALL_DIR_INCOMING;
hfp_ag_set_clip(129, "7654321");
hfp_ag_incoming_call();
break;
case 'C':
printf("Simulate terminate call\n");
hfp_ag_call_dropped();
break;
case 'd':
printf("Report AG failure\n");
hfp_ag_report_extended_audio_gateway_error_result_code(device_addr, HFP_CME_ERROR_AG_FAILURE);
break;
case 'e':
printf("Answer call on AG\n");
// if (current_call_status_a == HFP_ENHANCED_CALL_STATUS_INCOMING){
// current_call_status_a = HFP_ENHANCED_CALL_STATUS_ACTIVE;
// }
// if (current_call_status_b == HFP_ENHANCED_CALL_STATUS_INCOMING){
// current_call_status_b = HFP_ENHANCED_CALL_STATUS_ACTIVE;
// }
hfp_ag_answer_incoming_call();
break;
case 'E':
printf("Reject call on AG\n");
hfp_ag_terminate_call();
break;
case 'f':
printf("Disable cellular network\n");
hfp_ag_set_registration_status(0);
break;
case 'F':
printf("Enable cellular network\n");
hfp_ag_set_registration_status(1);
break;
case 'g':
printf("Set signal strength to 0\n");
hfp_ag_set_signal_strength(0);
break;
case 'G':
printf("Set signal strength to 5\n");
hfp_ag_set_signal_strength(5);
break;
case 'h':
printf("Disable roaming\n");
hfp_ag_set_roaming_status(0);
break;
case 'H':
printf("Enable roaming\n");
hfp_ag_set_roaming_status(1);
break;
case 'i':
printf("Set battery level to 3\n");
hfp_ag_set_battery_level(3);
break;
case 'I':
printf("Set battery level to 5\n");
hfp_ag_set_battery_level(5);
break;
case 'j':
printf("Answering call on remote side\n");
hfp_ag_outgoing_call_established();
break;
case 'r':
printf("Disable in-band ring tone\n");
hfp_ag_set_use_in_band_ring_tone(0);
break;
case 'k':
printf("Memory 1 cleared\n");
memory_1_enabled = 0;
break;
case 'K':
printf("Memory 1 set\n");
memory_1_enabled = 1;
break;
case 'l':
printf("Last dialed number cleared\n");
last_number_exists = 0;
break;
case 'L':
printf("Last dialed number set\n");
last_number_exists = 1;
break;
case 'n':
printf("Disable Voice Recognition\n");
hfp_ag_activate_voice_recognition(device_addr, 0);
break;
case 'N':
printf("Enable Voice Recognition\n");
hfp_ag_activate_voice_recognition(device_addr, 1);
break;
case 'o':
printf("Set speaker gain to 0 (minimum)\n");
hfp_ag_set_speaker_gain(device_addr, 0);
break;
case 'O':
printf("Set speaker gain to 9 (default)\n");
hfp_ag_set_speaker_gain(device_addr, 9);
break;
case 'p':
printf("Set speaker gain to 12 (higher)\n");
hfp_ag_set_speaker_gain(device_addr, 12);
break;
case 'P':
printf("Set speaker gain to 15 (maximum)\n");
hfp_ag_set_speaker_gain(device_addr, 15);
break;
case 'q':
printf("Set microphone gain to 0\n");
hfp_ag_set_microphone_gain(device_addr, 0);
break;
case 'Q':
printf("Set microphone gain to 9\n");
hfp_ag_set_microphone_gain(device_addr, 9);
break;
case 's':
printf("Set microphone gain to 12\n");
hfp_ag_set_microphone_gain(device_addr, 12);
break;
case 'S':
printf("Set microphone gain to 15\n");
hfp_ag_set_microphone_gain(device_addr, 15);
break;
case 'R':
printf("Enable in-band ring tone\n");
hfp_ag_set_use_in_band_ring_tone(1);
break;
case 't':
printf("Terminate HCI connection.\n");
gap_disconnect(handle);
break;
case 'u':
printf("Join held call\n");
// current_call_mpty = HFP_ENHANCED_CALL_MPTY_CONFERENCE_CALL;
hfp_ag_join_held_call();
break;
case 'v':
// start_scan();
break;
case 'w':
printf("AG: Put incoming call on hold (Response and Hold)\n");
hfp_ag_hold_incoming_call();
break;
case 'x':
printf("AG: Accept held incoming call (Response and Hold)\n");
hfp_ag_accept_held_incoming_call();
break;
case 'X':
printf("AG: Reject held incoming call (Response and Hold)\n");
hfp_ag_reject_held_incoming_call();
break;
default:
printf("AG: undefined user command\n");
break;
}
}
static void simulate_test_sequence(hfp_test_item_t * test_item){
char ** test_steps = test_item->test;
printf("\nSimulate test sequence: \"%s\"\n", test_item->name);
int i = 0;
static char * previous_cmd = NULL;
while (i < test_item->len){
char * expected_cmd = test_steps[i];
int expected_cmd_len = strlen(expected_cmd);
if (strncmp(expected_cmd, "USER:", 5) == 0){
printf("\n---> USER: ");
user_command(expected_cmd[5]);
i++;
} else if (strncmp(expected_cmd, "AT", 2) == 0){
// printf("\n---> NEXT STEP receive from HF: '%s'\n", expected_cmd);
inject_hfp_command_to_ag((uint8_t*)expected_cmd, expected_cmd_len);
i++;
} else {
printf("\n---> NEXT STEP expect from AG: %s\n", expected_cmd);
while (has_more_hfp_ag_commands()){
char * ag_cmd = get_next_hfp_ag_command();
int equal_cmds = strncmp(ag_cmd, expected_cmd, expected_cmd_len) == 0;
if (!equal_cmds){
printf("\nError: Expected:'%s', but got:'%s'\n", expected_cmd, ag_cmd);
CHECK_EQUAL(equal_cmds,1);
return;
}
printf("Verified: '%s'\n", expected_cmd);
previous_cmd = ag_cmd;
i++;
if (i < test_item->len){
expected_cmd = test_steps[i];
expected_cmd_len = strlen(expected_cmd);
}
}
// printf("\n---> NEXT STEP trigger once more AG\n");
inject_hfp_command_to_ag((uint8_t*)"NOP",3);
}
}
}
void packet_handler(uint8_t * event, uint16_t event_size){
if (event[0] != HCI_EVENT_HFP_META) return;
if (event[3] && event[2] != HFP_SUBEVENT_EXTENDED_AUDIO_GATEWAY_ERROR){
@ -181,8 +401,24 @@ void packet_handler(uint8_t * event, uint16_t event_size){
case HFP_SUBEVENT_CALL_TERMINATED:
call_termiated = 1;
break;
case HFP_CMD_CALL_ANSWERED:
//printf("HF answers call, accept call by GSM\n");
break;
case HFP_SUBEVENT_REDIAL_LAST_NUMBER:
printf("\n** Redial last number\n");
if (last_number_exists){
hfp_ag_outgoing_call_accepted();
printf("Last number exists: accept call\n");
// TODO: calling ringing right away leads to callstatus=2 being skipped. don't call for now
// hfp_ag_outgoing_call_ringing();
} else {
printf("Last number missing: reject call\n");
hfp_ag_outgoing_call_rejected();
}
break;
default:
printf("event not handled %u\n", event[2]);
printf("hfp_ag_client_test: event not handled %u\n", event[2]);
break;
}
}
@ -212,121 +448,48 @@ TEST_GROUP(HFPClient){
codecs_connection_established = 0;
audio_connection_established = 0;
}
void setup_hfp_service_level_connection(char ** test_steps, int nr_test_steps){
service_level_connection_established = 0;
hfp_ag_establish_service_level_connection(device_addr);
simulate_test_sequence((char **) test_steps, nr_test_steps);
}
void setup_hfp_codecs_connection(char ** test_steps, int nr_test_steps){
codecs_connection_established = 0;
simulate_test_sequence((char **) test_steps, nr_test_steps);
}
};
// TEST(HFPClient, HFAnswerIncomingCallWithInBandRingToneHFTermiantesCall){
// setup_hfp_service_level_connection(default_slc_setup(), default_slc_setup_size());
// CHECK_EQUAL(service_level_connection_established, 1);
// hfp_ag_set_use_in_band_ring_tone(1);
// hfp_ag_incoming_call();
// simulate_test_sequence(default_ic_setup(), default_ic_setup_size());
// CHECK_EQUAL(audio_connection_established, 1);
// simulate_test_sequence(alert_ic_setup(), alert_ic_setup_size());
// CHECK_EQUAL(stop_ringing, 1);
// simulate_test_sequence(terminate_ic_hf_setup(), terminate_ic_hf_setup_size());
// CHECK_EQUAL(call_termiated,1);
// TEST(HFPClient, PTSRHHTests){
// for (int i = 0; i < hfp_pts_ag_rhh_tests_size(); i++){
// simulate_test_sequence(&hfp_pts_ag_rhh_tests()[i]);
// teardown();
// }
// }
// TEST(HFPClient, HFAnswerIncomingCallWithInBandRingToneAGTerminatesCall){
// setup_hfp_service_level_connection(default_slc_setup(), default_slc_setup_size());
// CHECK_EQUAL(service_level_connection_established, 1);
// hfp_ag_set_use_in_band_ring_tone(1);
// hfp_ag_incoming_call();
// simulate_test_sequence(default_ic_setup(), default_ic_setup_size());
// CHECK_EQUAL(audio_connection_established, 1);
// simulate_test_sequence(alert_ic_setup(), alert_ic_setup_size());
// CHECK_EQUAL(stop_ringing, 1);
// // AG terminates call
// hfp_ag_terminate_call();
// simulate_test_sequence(terminate_ic_ag_setup(), terminate_ic_ag_setup_size());
// CHECK_EQUAL(call_termiated,1);
// TEST(HFPClient, PTSECCTests){
// for (int i = 0; i < hfp_pts_ag_ecc_tests_size(); i++){
// simulate_test_sequence(&hfp_pts_ag_ecc_tests()[i]);
// teardown();
// }
// }
// TEST(HFPClient, PTSECSTests){
// for (int i = 0; i < hfp_pts_ag_ecs_tests_size(); i++){
// simulate_test_sequence(&hfp_pts_ag_ecs_tests()[i]);
// teardown();
// }
// }
TEST(HFPClient, HFAudioConnectionEstablishedWithCodecNegotiation){
setup_hfp_service_level_connection(default_slc_setup(), default_slc_setup_size());
CHECK_EQUAL(service_level_connection_established, 1);
setup_hfp_codecs_connection(default_cc_setup(), default_cc_setup_size());
CHECK_EQUAL(codecs_connection_established, 1);
hfp_ag_establish_audio_connection(device_addr);
CHECK_EQUAL(audio_connection_established, 1);
hfp_ag_release_audio_connection(device_addr);
CHECK_EQUAL(audio_connection_established, 0);
}
TEST(HFPClient, HFAudioConnectionEstablishedWithoutCodecNegotiation){
hfp_ag_init(rfcomm_channel_nr, supported_features_without_codec_negotiation,
codecs, sizeof(codecs),
ag_indicators, ag_indicators_nr,
hf_indicators, hf_indicators_nr,
call_hold_services, call_hold_services_nr);
setup_hfp_service_level_connection(hfp_slc_tests()[1].test, hfp_slc_tests()[1].len);
CHECK_EQUAL(service_level_connection_established, 1);
setup_hfp_codecs_connection(default_cc_setup(), default_cc_setup_size());
CHECK_EQUAL(codecs_connection_established, 1);
hfp_ag_establish_audio_connection(device_addr);
CHECK_EQUAL(audio_connection_established, 1);
hfp_ag_release_audio_connection(device_addr);
CHECK_EQUAL(audio_connection_established, 0);
}
TEST(HFPClient, HFCodecsConnectionEstablished){
for (int i = 0; i < cc_tests_size(); i++){
setup_hfp_service_level_connection(default_slc_setup(), default_slc_setup_size());
CHECK_EQUAL(service_level_connection_established, 1);
setup_hfp_codecs_connection(hfp_cc_tests()[i].test, hfp_cc_tests()[i].len);
CHECK_EQUAL(codecs_connection_established, 1);
TEST(HFPClient, PTSTWCTests){
for (int i = 0; i < hfp_pts_ag_twc_tests_size(); i++){
simulate_test_sequence(&hfp_pts_ag_twc_tests()[i]);
teardown();
}
}
TEST(HFPClient, HFServiceLevelConnectionCommands){
setup_hfp_service_level_connection(default_slc_setup(), default_slc_setup_size());
CHECK_EQUAL(service_level_connection_established, 1);
for (int i = 0; i < slc_cmds_tests_size(); i++){
simulate_test_sequence(hfp_slc_cmds_tests()[i].test, hfp_slc_cmds_tests()[i].len);
TEST(HFPClient, PTSATATests){
for (int i = 0; i < hfp_pts_ag_ata_tests_size(); i++){
simulate_test_sequence(&hfp_pts_ag_ata_tests()[i]);
teardown();
}
}
TEST(HFPClient, HFServiceLevelConnectionEstablishedWithoutCodecNegotiation){
hfp_ag_init(rfcomm_channel_nr, supported_features_without_codec_negotiation,
codecs, sizeof(codecs),
ag_indicators, ag_indicators_nr,
hf_indicators, hf_indicators_nr,
call_hold_services, call_hold_services_nr);
setup_hfp_service_level_connection(hfp_slc_tests()[1].test, hfp_slc_tests()[1].len);
CHECK_EQUAL(service_level_connection_established, 1);
}
TEST(HFPClient, HFServiceLevelConnectionEstablishedWithCodecNegotiation){
setup_hfp_service_level_connection(hfp_slc_tests()[0].test, hfp_slc_tests()[0].len);
CHECK_EQUAL(service_level_connection_established, 1);
TEST(HFPClient, PTSSLCTests){
for (int i = 0; i < hfp_pts_ag_slc_tests_size(); i++){
simulate_test_sequence(&hfp_pts_ag_slc_tests()[i]);
teardown();
}
}
int main (int argc, const char * argv[]){

View File

@ -71,7 +71,6 @@ const uint8_t rfcomm_channel_nr = 1;
static bd_addr_t device_addr = {0xD8,0xBb,0x2C,0xDf,0xF1,0x08};
static uint8_t codecs[2] = {1,2};
static uint8_t default_codecs[2] = {1};
static uint16_t indicators[1] = {0x01};
static uint8_t service_level_connection_established = 0;
@ -81,72 +80,321 @@ static uint8_t start_ringing = 0;
static uint8_t stop_ringing = 0;
static uint8_t call_termiated = 0;
static int supported_features_with_codec_negotiation = 438; // 0001 1011 0110
static int supported_features_without_codec_negotiation = 310; // 0001 0011 0110
static int supported_features_with_codec_negotiation = 438;
int expected_rfcomm_command(const char * cmd){
char * ag_cmd = (char *)get_rfcomm_payload();
int offset = 2;
int cmd_size = strlen(cmd);
static uint16_t handle = -1;
int cmd_found = strncmp(ag_cmd+offset, cmd, cmd_size) == 0;
while (!cmd_found && get_rfcomm_payload_len() - cmd_size >= offset){
offset++;
cmd_found = strncmp(ag_cmd+offset, cmd, cmd_size) == 0;
}
if (!cmd_found) return 0;
// AG cmds that are not followed by OK
if (strncmp(ag_cmd+offset, "+BCS", 4) == 0){
return cmd_found;
}
offset += strlen(cmd)+4;
// printf("cmd found, offset %d, cmd %s\n", offset, ag_cmd+offset);
int ok_found = strncmp(ag_cmd+offset, "OK", 2) == 0;
while (!ok_found && get_rfcomm_payload_len() - 2 >= offset){
offset++;
// printf("cmd found, offset %d, cmd %s\n", offset, ag_cmd+offset);
ok_found = strncmp(ag_cmd+offset, "OK", 2) == 0;
}
// printf("cmd found, ok found %d\n", ok_found);
return cmd_found && ok_found;
char * get_next_hfp_hf_command(){
return get_next_hfp_command(0,2);
}
void simulate_test_sequence(char ** test_steps, int nr_test_steps){
int has_more_hfp_hf_commands(){
return has_more_hfp_commands(0,2);
}
static void user_command(char cmd){
switch (cmd){
case '#':
case '-':
case '+':
case '*':
printf("DTMF Code: %c\n", cmd);
hfp_hf_send_dtmf_code(device_addr, cmd);
break;
case 'a':
printf("Establish Service level connection to device with Bluetooth address %s...\n", bd_addr_to_str(device_addr));
hfp_hf_establish_service_level_connection(device_addr);
break;
case 'A':
printf("Release Service level connection.\n");
hfp_hf_release_service_level_connection(device_addr);
break;
case 'b':
printf("Establish Audio connection to device with Bluetooth address %s...\n", bd_addr_to_str(device_addr));
hfp_hf_establish_audio_connection(device_addr);
break;
case 'B':
printf("Release Audio service level connection.\n");
hfp_hf_release_audio_connection(device_addr);
break;
case 'C':
printf("Enable registration status update for all AG indicators.\n");
hfp_hf_enable_status_update_for_all_ag_indicators(device_addr);
case 'c':
printf("Disable registration status update for all AG indicators.\n");
hfp_hf_disable_status_update_for_all_ag_indicators(device_addr);
break;
case 'D':
printf("Set HFP AG registration status update for individual indicators (0111111).\n");
hfp_hf_set_status_update_for_individual_ag_indicators(device_addr, 63);
break;
case 'd':
printf("Query network operator.\n");
hfp_hf_query_operator_selection(device_addr);
break;
case 'E':
printf("Enable reporting of the extended AG error result code.\n");
hfp_hf_enable_report_extended_audio_gateway_error_result_code(device_addr);
break;
case 'e':
printf("Disable reporting of the extended AG error result code.\n");
hfp_hf_disable_report_extended_audio_gateway_error_result_code(device_addr);
break;
case 'f':
printf("Answer incoming call.\n");
hfp_hf_answer_incoming_call(device_addr);
break;
case 'F':
printf("Hangup call.\n");
hfp_hf_terminate_call(device_addr);
break;
case 'G':
printf("Reject call.\n");
hfp_hf_reject_call(device_addr);
break;
case 'g':
printf("Query operator.\n");
hfp_hf_query_operator_selection(device_addr);
break;
case 't':
printf("Terminate HCI connection.\n");
gap_disconnect(handle);
break;
case 'i':
printf("Dial 1234567\n");
hfp_hf_dial_number(device_addr, (char *)"1234567");
break;
case 'I':
printf("Dial 7654321\n");
hfp_hf_dial_number(device_addr, (char *)"7654321");
break;
case 'j':
printf("Dial #1\n");
hfp_hf_dial_memory(device_addr, (char *)"1");
break;
case 'J':
printf("Dial #99\n");
hfp_hf_dial_memory(device_addr, (char *)"99");
break;
case 'k':
printf("Deactivate call waiting notification\n");
hfp_hf_deactivate_call_waiting_notification(device_addr);
break;
case 'K':
printf("Activate call waiting notification\n");
hfp_hf_activate_call_waiting_notification(device_addr);
break;
case 'l':
printf("Deactivate calling line notification\n");
hfp_hf_deactivate_calling_line_notification(device_addr);
break;
case 'L':
printf("Activate calling line notification\n");
hfp_hf_activate_calling_line_notification(device_addr);
break;
case 'm':
printf("Deactivate echo canceling and noise reduction\n");
hfp_hf_deactivate_echo_canceling_and_noise_reduction(device_addr);
break;
case 'M':
printf("Activate echo canceling and noise reduction\n");
hfp_hf_activate_echo_canceling_and_noise_reduction(device_addr);
break;
case 'n':
printf("Deactivate voice recognition\n");
hfp_hf_deactivate_voice_recognition_notification(device_addr);
break;
case 'N':
printf("Activate voice recognition\n");
hfp_hf_activate_voice_recognition_notification(device_addr);
break;
case 'o':
printf("Set speaker gain to 0 (minimum)\n");
hfp_hf_set_speaker_gain(device_addr, 0);
break;
case 'O':
printf("Set speaker gain to 9 (default)\n");
hfp_hf_set_speaker_gain(device_addr, 9);
break;
case 'p':
printf("Set speaker gain to 12 (higher)\n");
hfp_hf_set_speaker_gain(device_addr, 12);
break;
case 'P':
printf("Set speaker gain to 15 (maximum)\n");
hfp_hf_set_speaker_gain(device_addr, 15);
break;
case 'q':
printf("Set microphone gain to 0\n");
hfp_hf_set_microphone_gain(device_addr, 0);
break;
case 'Q':
printf("Set microphone gain to 9\n");
hfp_hf_set_microphone_gain(device_addr, 9);
break;
case 's':
printf("Set microphone gain to 12\n");
hfp_hf_set_microphone_gain(device_addr, 12);
break;
case 'S':
printf("Set microphone gain to 15\n");
hfp_hf_set_microphone_gain(device_addr, 15);
break;
case 'u':
printf("Send 'user busy' (Three-Way Call 0)\n");
hfp_hf_user_busy(device_addr);
break;
case 'U':
printf("End active call and accept waiting/held call (Three-Way Call 1)\n");
hfp_hf_end_active_and_accept_other(device_addr);
break;
case 'v':
printf("Swap active call and hold/waiting call (Three-Way Call 2)\n");
hfp_hf_swap_calls(device_addr);
break;
case 'V':
printf("Join hold call (Three-Way Call 3)\n");
hfp_hf_join_held_call(device_addr);
break;
case 'w':
printf("Connect calls (Three-Way Call 4)\n");
hfp_hf_connect_calls(device_addr);
break;
case 'W':
printf("Redial\n");
hfp_hf_redial_last_number(device_addr);
break;
case 'x':
printf("Request phone number for voice tag\n");
hfp_hf_request_phone_number_for_voice_tag(device_addr);
break;
case 'X':
printf("Query current call status\n");
hfp_hf_query_current_call_status(device_addr);
break;
case 'y':
printf("Release call with index 2\n");
hfp_hf_release_call_with_index(device_addr, 2);
break;
case 'Y':
printf("Private consulation with call 2\n");
hfp_hf_private_consultation_with_call(device_addr, 2);
break;
case '[':
printf("Query Response and Hold status (RHH ?)\n");
hfp_hf_rrh_query_status(device_addr);
break;
case ']':
printf("Place call in a response and held state (RHH 0)\n");
hfp_hf_rrh_hold_call(device_addr);
break;
case '{':
printf("Accept held call (RHH 1)\n");
hfp_hf_rrh_accept_held_call(device_addr);
break;
case '}':
printf("Reject held call (RHH 2)\n");
hfp_hf_rrh_reject_held_call(device_addr);
break;
case '?':
printf("Query Subscriber Number\n");
hfp_hf_query_subscriber_number(device_addr);
break;
case '!':
printf("Update HF indicator with assigned number 1 (HFI)\n");
hfp_hf_set_hf_indicator(device_addr, 1, 1);
break;
default:
printf("HF: undefined user command\n");
break;
}
}
void simulate_test_sequence(hfp_test_item_t * test_item){
char ** test_steps = test_item->test;
printf("\nSimulate test sequence: \"%s\"\n", test_item->name);
int i = 0;
for (i=0; i < nr_test_steps; i++){
char * cmd = test_steps[i];
printf("\n---> NEXT STEP %s\n", cmd);
if (strncmp(cmd, "AT", 2) == 0){
while ( i < test_item->len){
char * expected_cmd = test_steps[i];
int expected_cmd_len = strlen(expected_cmd);
if (strncmp(expected_cmd, "USER:", 5) == 0){
user_command(expected_cmd[5]);
while (has_more_hfp_hf_commands()){
// empty rfcomm payload buffer
get_next_hfp_hf_command();
}
i++;
} else if (strncmp(expected_cmd, "AT+BAC=", 7) == 0){
int parsed_codecs[2];
uint8_t new_codecs[2];
if (strncmp(cmd, "AT+BAC=", 7) == 0){
printf("Send BAC\n");
sscanf(&cmd[7],"%d,%d", &parsed_codecs[0], &parsed_codecs[1]);
new_codecs[0] = parsed_codecs[0];
new_codecs[1] = parsed_codecs[1];
hfp_hf_set_codecs((uint8_t*)new_codecs, 2);
} else {
printf("Verify\n");
int expected_cmd = expected_rfcomm_command(cmd);
if (expected_cmd){
printf("\nError: Expected:'%s', but got:'%s'", cmd, (char *)get_rfcomm_payload());
return;
}
sscanf(&expected_cmd[7],"%d,%d", &parsed_codecs[0], &parsed_codecs[1]);
new_codecs[0] = parsed_codecs[0];
new_codecs[1] = parsed_codecs[1];
hfp_hf_set_codecs((uint8_t*)new_codecs, 2);
while (has_more_hfp_hf_commands()){
// empty rfcomm payload buffer
get_next_hfp_hf_command();
}
i++;
} else if (strncmp(expected_cmd, "AT+BRSF=", 8) == 0 ){
int supported_features = 0;
sscanf(&expected_cmd[8],"%d", &supported_features);
printf("Call hfp_hf_init with SF %d\n", supported_features);
hfp_hf_init(rfcomm_channel_nr, supported_features, indicators, sizeof(indicators)/sizeof(uint16_t), 1);
user_command('a');
while (has_more_hfp_hf_commands()){
// empty rfcomm payload buffer
get_next_hfp_hf_command();
}
i++;
} else if (strncmp(expected_cmd, "AT+BCC", 6) == 0){
user_command('b');
while (has_more_hfp_hf_commands()){
// empty rfcomm payload buffer
get_next_hfp_hf_command();
}
i++;
} else if (strncmp(expected_cmd, "AT", 2) == 0){
printf("\n---> NEXT STEP expect from HF: %s\n", expected_cmd);
while (has_more_hfp_hf_commands()){
char * ag_cmd = get_next_hfp_hf_command();
//printf("HF response verify %s == %s[%d]\n", expected_cmd, ag_cmd, expected_cmd_len);
int equal_cmds = strncmp(ag_cmd, expected_cmd, expected_cmd_len) == 0;
if (!equal_cmds){
printf("\nError: Expected:'%s', but got:'%s'\n", expected_cmd, ag_cmd);
CHECK_EQUAL(equal_cmds,1);
return;
}
printf("Verified: '%s'\n", expected_cmd);
i++;
if (i < test_item->len){
expected_cmd = test_steps[i];
expected_cmd_len = strlen(expected_cmd);
}
}
} else {
inject_rfcomm_command_to_hf((uint8_t*)cmd, strlen(cmd));
//printf("\n---> NEXT STEP receive from AG: '%s'\n", expected_cmd);
inject_hfp_command_to_hf((uint8_t*)expected_cmd, strlen(expected_cmd));
i++;
}
}
}
void packet_handler(uint8_t * event, uint16_t event_size){
if (event[0] != HCI_EVENT_HFP_META) return;
if (event[3] && event[2] != HFP_SUBEVENT_EXTENDED_AUDIO_GATEWAY_ERROR){
if (event[3]
&& event[2] != HFP_SUBEVENT_EXTENDED_AUDIO_GATEWAY_ERROR
&& event[2] != HFP_SUBEVENT_NUMBER_FOR_VOICE_TAG
&& event[2] != HFP_SUBEVENT_SPEAKER_VOLUME
&& event[2] != HFP_SUBEVENT_MICROPHONE_VOLUME){
printf("ERROR, status: %u\n", event[3]);
return;
}
switch (event[2]) {
case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
printf("\n** SLC established **\n\n");
@ -183,6 +431,31 @@ void packet_handler(uint8_t * event, uint16_t event_size){
case HFP_SUBEVENT_CALL_TERMINATED:
call_termiated = 1;
break;
case HFP_SUBEVENT_COMPLETE:
printf("HFP AG HFP_SUBEVENT_COMPLETE.\n");
break;
case HFP_SUBEVENT_AG_INDICATOR_STATUS_CHANGED:
printf("AG_INDICATOR_STATUS_CHANGED, AG indicator '%s' (index: %d) to: %d\n", (const char*) &event[6], event[4], event[5]);
break;
case HFP_SUBEVENT_NETWORK_OPERATOR_CHANGED:
printf("NETWORK_OPERATOR_CHANGED, operator mode: %d, format: %d, name: %s\n", event[4], event[5], (char *) &event[6]);
break;
case HFP_SUBEVENT_EXTENDED_AUDIO_GATEWAY_ERROR:
if (event[4])
printf("EXTENDED_AUDIO_GATEWAY_ERROR_REPORT, status : %d\n", event[3]);
break;
case HFP_SUBEVENT_RING:
printf("** Ring **\n");
break;
case HFP_SUBEVENT_NUMBER_FOR_VOICE_TAG:
printf("Phone number for voice tag: %s\n", (const char *) &event[3]);
break;
case HFP_SUBEVENT_SPEAKER_VOLUME:
printf("Speaker volume: %u\n", event[3]);
break;
case HFP_SUBEVENT_MICROPHONE_VOLUME:
printf("Microphone volume: %u\n", event[3]);
break;
default:
printf("event not handled %u\n", event[2]);
break;
@ -190,7 +463,6 @@ void packet_handler(uint8_t * event, uint16_t event_size){
}
TEST_GROUP(HFPClient){
void setup(void){
@ -213,61 +485,49 @@ TEST_GROUP(HFPClient){
codecs_connection_established = 0;
audio_connection_established = 0;
}
void setup_hfp_service_level_connection(char ** test_steps, int nr_test_steps){
service_level_connection_established = 0;
hfp_hf_establish_service_level_connection(device_addr);
simulate_test_sequence((char **) test_steps, nr_test_steps);
}
void setup_hfp_codecs_connection(char ** test_steps, int nr_test_steps){
codecs_connection_established = 0;
simulate_test_sequence((char **) test_steps, nr_test_steps);
}
};
TEST(HFPClient, HFAudioConnectionEstablishedWithoutCodecNegotiation){
hfp_hf_init(rfcomm_channel_nr, supported_features_without_codec_negotiation, indicators, sizeof(indicators)/sizeof(uint16_t), 1);
hfp_hf_set_codecs(default_codecs, 1);
setup_hfp_service_level_connection(hfp_slc_tests()[1].test, hfp_slc_tests()[1].len);
CHECK_EQUAL(service_level_connection_established, 1);
setup_hfp_codecs_connection(default_cc_setup(), default_cc_setup_size());
CHECK_EQUAL(codecs_connection_established, 1);
hfp_hf_establish_audio_connection(device_addr);
hfp_hf_release_audio_connection(device_addr);
CHECK_EQUAL(audio_connection_established, 0);
}
TEST(HFPClient, HFCodecsConnectionEstablished){
for (int i = 0; i < cc_tests_size(); i++){
setup_hfp_service_level_connection(default_slc_setup(), default_slc_setup_size());
CHECK_EQUAL(service_level_connection_established, 1);
setup_hfp_codecs_connection(hfp_cc_tests()[i].test, hfp_cc_tests()[i].len);
TEST(HFPClient, PTSRHHTests){
for (int i = 0; i < hfp_pts_hf_rhh_tests_size(); i++){
simulate_test_sequence(&hfp_pts_hf_rhh_tests()[i]);
teardown();
}
}
TEST(HFPClient, HFServiceLevelConnectionCommands){
setup_hfp_service_level_connection(default_slc_setup(), default_slc_setup_size());
CHECK_EQUAL(service_level_connection_established, 1);
for (int i = 0; i < slc_cmds_tests_size(); i++){
simulate_test_sequence(hfp_slc_cmds_tests()[i].test, hfp_slc_cmds_tests()[i].len);
}
}
TEST(HFPClient, HFServiceLevelConnectionEstablished){
for (int i = 0; i < slc_tests_size(); i++){
setup_hfp_service_level_connection(hfp_slc_tests()[i].test, hfp_slc_tests()[i].len);
CHECK_EQUAL(service_level_connection_established, 1);
TEST(HFPClient, PTSECCTests){
for (int i = 0; i < hfp_pts_hf_ecc_tests_size(); i++){
simulate_test_sequence(&hfp_pts_hf_ecc_tests()[i]);
teardown();
}
}
TEST(HFPClient, PTSECSTests){
for (int i = 0; i < hfp_pts_hf_ecs_tests_size(); i++){
simulate_test_sequence(&hfp_pts_hf_ecs_tests()[i]);
teardown();
}
}
TEST(HFPClient, PTSTWCTests){
for (int i = 0; i < hfp_pts_hf_twc_tests_size(); i++){
simulate_test_sequence(&hfp_pts_hf_twc_tests()[i]);
teardown();
}
}
TEST(HFPClient, PTSATATests){
for (int i = 0; i < hfp_pts_hf_ata_tests_size(); i++){
simulate_test_sequence(&hfp_pts_hf_ata_tests()[i]);
teardown();
}
}
TEST(HFPClient, PTSSLCTests){
for (int i = 0; i < hfp_pts_hf_slc_tests_size(); i++){
simulate_test_sequence(&hfp_pts_hf_slc_tests()[i]);
teardown();
}
}
int main (int argc, const char * argv[]){
hfp_hf_register_packet_handler(packet_handler);

View File

@ -61,7 +61,11 @@ static uint16_t rfcomm_cid = 1;
static bd_addr_t dev_addr;
static uint16_t sco_handle = 10;
static uint8_t rfcomm_payload[200];
static uint16_t rfcomm_payload_len;
static uint16_t rfcomm_payload_len = 0;
static uint8_t outgoing_rfcomm_payload[200];
static uint16_t outgoing_rfcomm_payload_len = 0;
void * active_connection;
hfp_connection_t * hfp_context;
@ -76,34 +80,34 @@ uint16_t get_rfcomm_payload_len(){
return rfcomm_payload_len;
}
static void prepare_rfcomm_buffer(uint8_t * data, int len){
if (len <= 0) return;
memset(&rfcomm_payload, 0, 200);
int pos = 0;
static int hfp_command_start_index = 0;
if (strncmp((char*)data, "AT", 2) == 0){
strncpy((char*)&rfcomm_payload[pos], (char*)data, len);
pos += len;
} else {
rfcomm_payload[pos++] = '\r';
rfcomm_payload[pos++] = '\n';
strncpy((char*)&rfcomm_payload[pos], (char*)data, len);
pos += len;
if (memcmp((char*)data, "+BAC", 4) != 0 &&
memcmp((char*)data, "+BCS", 4) != 0){
rfcomm_payload[pos++] = '\r';
rfcomm_payload[pos++] = '\n';
rfcomm_payload[pos++] = 'O';
rfcomm_payload[pos++] = 'K';
}
int has_more_hfp_commands(int start_command_offset, int end_command_offset){
int has_cmd = get_rfcomm_payload_len() - hfp_command_start_index >= 2 + start_command_offset + end_command_offset;
//printf("has more: payload len %d, start %d, has more %d\n", get_rfcomm_payload_len(), hfp_command_start_index, has_cmd);
return has_cmd;
}
char * get_next_hfp_command(int start_command_offset, int end_command_offset){
//printf("get next: payload len %d, start %d\n", get_rfcomm_payload_len(), hfp_command_start_index);
char * data = (char *)(&get_rfcomm_payload()[hfp_command_start_index + start_command_offset]);
int data_len = get_rfcomm_payload_len() - hfp_command_start_index - start_command_offset;
int i;
for (i = 0; i < data_len; i++){
if ( *(data+i) == '\r' || *(data+i) == '\n' ) {
data[i]=0;
// update state
//printf("!!! command %s\n", data);
hfp_command_start_index = hfp_command_start_index + i + start_command_offset + end_command_offset;
return data;
}
}
rfcomm_payload[pos++] = '\r';
rfcomm_payload[pos++] = '\n';
rfcomm_payload[pos] = 0;
rfcomm_payload_len = pos;
}
printf("should not got here\n");
return NULL;
}
static void print_without_newlines(uint8_t *data, uint16_t len){
int found_newline = 0;
@ -129,16 +133,26 @@ extern "C" void l2cap_register_packet_handler(void (*handler)(uint8_t packet_typ
int rfcomm_send_internal(uint16_t rfcomm_cid, uint8_t *data, uint16_t len){
if (strncmp((char*)data, "AT", 2) == 0){
printf("Verify HF state machine response: ");
print_without_newlines(data,len);
} else {
printf("Verify AG state machine response: ");
print_without_newlines(data,len);
}
strncpy((char*)&rfcomm_payload[0], (char*)data, len);
rfcomm_payload_len = len;
return 0;
int start_command_offset = 2;
int end_command_offset = 2;
if (strncmp((char*)data, "AT", 2) == 0){
start_command_offset = 0;
}
if (has_more_hfp_commands(start_command_offset, end_command_offset)){
//printf("Buffer response: ");
strncpy((char*)&rfcomm_payload[rfcomm_payload_len], (char*)data, len);
rfcomm_payload_len += len;
} else {
hfp_command_start_index = 0;
//printf("Copy response: ");
strncpy((char*)&rfcomm_payload[0], (char*)data, len);
rfcomm_payload_len = len;
}
//print_without_newlines(rfcomm_payload,rfcomm_payload_len);
return 0;
}
static void hci_event_sco_complete(){
@ -163,7 +177,7 @@ static void hci_event_sco_complete(){
}
int hci_send_cmd(const hci_cmd_t *cmd, ...){
printf("hci_send_cmd opcode 0x%02x\n", cmd->opcode);
//printf("hci_send_cmd opcode 0x%02x\n", cmd->opcode);
if (cmd->opcode == 0x428){
hci_event_sco_complete();
}
@ -292,28 +306,40 @@ int hci_remote_eSCO_supported(hci_con_handle_t handle){
return 0;
}
void inject_rfcomm_command_to_hf(uint8_t * data, int len){
if (memcmp((char*)data, "AT", 2) == 0) return;
prepare_rfcomm_buffer(data, len);
if (data[0] == '+' || (data[0] == 'O' && data[1] == 'K')){
printf("Send cmd to HF state machine: %s\n", data);
static void add_new_lines_to_hfp_command(uint8_t * data, int len){
if (len <= 0) return;
memset(&outgoing_rfcomm_payload, 0, 200);
int pos = 0;
if (strncmp((char*)data, "AT", 2) == 0){
strncpy((char*)&outgoing_rfcomm_payload[pos], (char*)data, len);
pos += len;
} else {
printf("Trigger HF state machine - %s", data);
outgoing_rfcomm_payload[pos++] = '\r';
outgoing_rfcomm_payload[pos++] = '\n';
strncpy((char*)&outgoing_rfcomm_payload[pos], (char*)data, len);
pos += len;
}
(*registered_rfcomm_packet_handler)(RFCOMM_DATA_PACKET, rfcomm_cid, (uint8_t *) &rfcomm_payload[0], rfcomm_payload_len);
outgoing_rfcomm_payload[pos++] = '\r';
outgoing_rfcomm_payload[pos++] = '\n';
outgoing_rfcomm_payload[pos] = 0;
outgoing_rfcomm_payload_len = pos;
}
void inject_hfp_command_to_hf(uint8_t * data, int len){
if (memcmp((char*)data, "AT", 2) == 0) return;
add_new_lines_to_hfp_command(data, len);
// printf("inject_hfp_command_to_hf to HF: ");
// print_without_newlines(outgoing_rfcomm_payload,outgoing_rfcomm_payload_len);
(*registered_rfcomm_packet_handler)(active_connection, RFCOMM_DATA_PACKET, rfcomm_cid, (uint8_t *) &outgoing_rfcomm_payload[0], outgoing_rfcomm_payload_len);
}
void inject_rfcomm_command_to_ag(uint8_t * data, int len){
void inject_hfp_command_to_ag(uint8_t * data, int len){
if (data[0] == '+') return;
prepare_rfcomm_buffer(data, len);
if (memcmp((char*)data, "AT", 2) == 0){
printf("Send cmd to AG state machine: %s\n", data);
} else {
printf("Trigger AG state machine - %s", data);
}
(*registered_rfcomm_packet_handler)( RFCOMM_DATA_PACKET, rfcomm_cid, (uint8_t *) &rfcomm_payload[0], rfcomm_payload_len);
add_new_lines_to_hfp_command(data, len);
(*registered_rfcomm_packet_handler)(active_connection, RFCOMM_DATA_PACKET, rfcomm_cid, (uint8_t *) &outgoing_rfcomm_payload[0], outgoing_rfcomm_payload_len);
}

View File

@ -50,5 +50,8 @@
uint8_t * get_rfcomm_payload();
uint16_t get_rfcomm_payload_len();
void inject_rfcomm_command_to_ag(uint8_t * data, int len);
void inject_rfcomm_command_to_hf(uint8_t * data, int len);
void inject_hfp_command_to_ag(uint8_t * data, int len);
void inject_hfp_command_to_hf(uint8_t * data, int len);
int has_more_hfp_commands(int start_command_offset, int end_command_offset);
char * get_next_hfp_command(int start_command_offset, int end_command_offset);

File diff suppressed because it is too large Load Diff

View File

@ -47,39 +47,49 @@
#include <string.h>
typedef struct hfp_test_item{
char * name;
char ** test;
int len;
} hfp_test_item_t;
/* Service Level Connection (slc) test sequences */
hfp_test_item_t * hfp_slc_tests();
int slc_tests_size();
char ** default_slc_setup();
int default_slc_setup_size();
/* Service Level Connection (slc) common commands */
hfp_test_item_t * hfp_slc_cmds_tests();
int slc_cmds_tests_size();
char ** default_slc_cmds_setup();
int default_slc_cmds_setup_size();
/* Codecs Connection (cc) test sequences */
int hfp_cc_tests_size();
hfp_test_item_t * hfp_cc_tests();
int cc_tests_size();
char ** default_cc_setup();
int default_cc_setup_size();
hfp_test_item_t * default_hfp_cc_test();
/* Incoming call (ic) test sequences */
char ** default_ic_setup();
int default_ic_setup_size();
/* PTS test sequences - SLC Group */
int hfp_pts_ag_slc_tests_size();
hfp_test_item_t * hfp_pts_ag_slc_tests();
int hfp_pts_hf_slc_tests_size();
hfp_test_item_t * hfp_pts_hf_slc_tests();
char ** alert_ic_setup();
int alert_ic_setup_size();
/* PTS test sequences - ATA Group */
int hfp_pts_ag_ata_tests_size();
hfp_test_item_t * hfp_pts_ag_ata_tests();
int hfp_pts_hf_ata_tests_size();
hfp_test_item_t * hfp_pts_hf_ata_tests();
char ** terminate_ic_ag_setup();
int terminate_ic_ag_setup_size();
/* PTS test sequences - TWC Group */
int hfp_pts_ag_twc_tests_size();
hfp_test_item_t * hfp_pts_ag_twc_tests();
int hfp_pts_hf_twc_tests_size();
hfp_test_item_t * hfp_pts_hf_twc_tests();
char ** terminate_ic_hf_setup();
int terminate_ic_hf_setup_size();
/* PTS test sequences - ECS Group */
int hfp_pts_ag_ecs_tests_size();
hfp_test_item_t * hfp_pts_ag_ecs_tests();
int hfp_pts_hf_ecs_tests_size();
hfp_test_item_t * hfp_pts_hf_ecs_tests();
/* PTS test sequences - ECC Group */
int hfp_pts_ag_ecc_tests_size();
hfp_test_item_t * hfp_pts_ag_ecc_tests();
int hfp_pts_hf_ecc_tests_size();
hfp_test_item_t * hfp_pts_hf_ecc_tests();
/* PTS test sequences - RHH Group */
int hfp_pts_ag_rhh_tests_size();
hfp_test_item_t * hfp_pts_ag_rhh_tests();
int hfp_pts_hf_rhh_tests_size();
hfp_test_item_t * hfp_pts_hf_rhh_tests();

View File

@ -72,7 +72,8 @@ const uint8_t rfcomm_channel_nr = 1;
const char hfp_ag_service_name[] = "BTstack HFP AG Test";
static bd_addr_t device_addr;
static bd_addr_t pts_addr = {0x00,0x1b,0xDC,0x07,0x32,0xEF};
static bd_addr_t pts_addr = {0x00,0x15,0x83,0x5F,0x9D,0x46};
//static bd_addr_t pts_addr = {0x00,0x1b,0xDC,0x07,0x32,0xEF};
static bd_addr_t speaker_addr = {0x00, 0x21, 0x3C, 0xAC, 0xF7, 0x38};
static uint8_t codecs[1] = {HFP_CODEC_CVSD};
static uint16_t handle = -1;
@ -353,31 +354,38 @@ static int stdin_process(struct data_source *ds){
switch (cmd){
case 'a':
memcpy(device_addr, pts_addr, 6);
log_info("USER:\'%c\'", cmd);
printf("Establish HFP service level connection to PTS module %s...\n", bd_addr_to_str(device_addr));
hfp_ag_establish_service_level_connection(device_addr);
break;
case 'A':
log_info("USER:\'%c\'", cmd);
printf("Release HFP service level connection.\n");
hfp_ag_release_service_level_connection(device_addr);
break;
case 'z':
memcpy(device_addr, speaker_addr, 6);
log_info("USER:\'%c\'", cmd);
printf("Establish HFP service level connection to %s...\n", bd_addr_to_str(device_addr));
hfp_ag_establish_service_level_connection(device_addr);
break;
case 'Z':
log_info("USER:\'%c\'", cmd);
printf("Release HFP service level connection to %s...\n", bd_addr_to_str(device_addr));
hfp_ag_release_service_level_connection(device_addr);
break;
case 'b':
log_info("USER:\'%c\'", cmd);
printf("Establish Audio connection %s...\n", bd_addr_to_str(device_addr));
hfp_ag_establish_audio_connection(device_addr);
break;
case 'B':
log_info("USER:\'%c\'", cmd);
printf("Release Audio connection.\n");
hfp_ag_release_audio_connection(device_addr);
break;
case 'c':
log_info("USER:\'%c\'", cmd);
printf("Simulate incoming call from 1234567\n");
current_call_exists_a = 1;
current_call_status_a = HFP_ENHANCED_CALL_STATUS_INCOMING;
@ -386,6 +394,7 @@ static int stdin_process(struct data_source *ds){
hfp_ag_incoming_call();
break;
case 'm':
log_info("USER:\'%c\'", cmd);
printf("Simulate incoming call from 7654321\n");
current_call_exists_b = 1;
current_call_status_b = HFP_ENHANCED_CALL_STATUS_INCOMING;
@ -394,14 +403,17 @@ static int stdin_process(struct data_source *ds){
hfp_ag_incoming_call();
break;
case 'C':
log_info("USER:\'%c\'", cmd);
printf("Simulate terminate call\n");
hfp_ag_call_dropped();
break;
case 'd':
log_info("USER:\'%c\'", cmd);
printf("Report AG failure\n");
hfp_ag_report_extended_audio_gateway_error_result_code(device_addr, HFP_CME_ERROR_AG_FAILURE);
break;
case 'e':
log_info("USER:\'%c\'", cmd);
printf("Answer call on AG\n");
if (current_call_status_a == HFP_ENHANCED_CALL_STATUS_INCOMING){
current_call_status_a = HFP_ENHANCED_CALL_STATUS_ACTIVE;
@ -412,114 +424,142 @@ static int stdin_process(struct data_source *ds){
hfp_ag_answer_incoming_call();
break;
case 'E':
log_info("USER:\'%c\'", cmd);
printf("Reject call on AG\n");
hfp_ag_terminate_call();
break;
case 'f':
log_info("USER:\'%c\'", cmd);
printf("Disable cellular network\n");
hfp_ag_set_registration_status(0);
break;
case 'F':
log_info("USER:\'%c\'", cmd);
printf("Enable cellular network\n");
hfp_ag_set_registration_status(1);
break;
case 'g':
log_info("USER:\'%c\'", cmd);
printf("Set signal strength to 0\n");
hfp_ag_set_signal_strength(0);
break;
case 'G':
log_info("USER:\'%c\'", cmd);
printf("Set signal strength to 5\n");
hfp_ag_set_signal_strength(5);
break;
case 'h':
log_info("USER:\'%c\'", cmd);
printf("Disable roaming\n");
hfp_ag_set_roaming_status(0);
break;
case 'H':
log_info("USER:\'%c\'", cmd);
printf("Enable roaming\n");
hfp_ag_set_roaming_status(1);
break;
case 'i':
log_info("USER:\'%c\'", cmd);
printf("Set battery level to 3\n");
hfp_ag_set_battery_level(3);
break;
case 'I':
log_info("USER:\'%c\'", cmd);
printf("Set battery level to 5\n");
hfp_ag_set_battery_level(5);
break;
case 'j':
log_info("USER:\'%c\'", cmd);
printf("Answering call on remote side\n");
hfp_ag_outgoing_call_established();
break;
case 'r':
log_info("USER:\'%c\'", cmd);
printf("Disable in-band ring tone\n");
hfp_ag_set_use_in_band_ring_tone(0);
break;
case 'k':
log_info("USER:\'%c\'", cmd);
printf("Memory 1 cleared\n");
memory_1_enabled = 0;
break;
case 'K':
log_info("USER:\'%c\'", cmd);
printf("Memory 1 set\n");
memory_1_enabled = 1;
break;
case 'l':
log_info("USER:\'%c\'", cmd);
printf("Last dialed number cleared\n");
last_number_exists = 0;
break;
case 'L':
log_info("USER:\'%c\'", cmd);
printf("Last dialed number set\n");
last_number_exists = 1;
break;
case 'n':
log_info("USER:\'%c\'", cmd);
printf("Disable Voice Recognition\n");
hfp_ag_activate_voice_recognition(device_addr, 0);
break;
case 'N':
log_info("USER:\'%c\'", cmd);
printf("Enable Voice Recognition\n");
hfp_ag_activate_voice_recognition(device_addr, 1);
break;
case 'o':
log_info("USER:\'%c\'", cmd);
printf("Set speaker gain to 0 (minimum)\n");
hfp_ag_set_speaker_gain(device_addr, 0);
break;
case 'O':
log_info("USER:\'%c\'", cmd);
printf("Set speaker gain to 9 (default)\n");
hfp_ag_set_speaker_gain(device_addr, 9);
break;
case 'p':
log_info("USER:\'%c\'", cmd);
printf("Set speaker gain to 12 (higher)\n");
hfp_ag_set_speaker_gain(device_addr, 12);
break;
case 'P':
log_info("USER:\'%c\'", cmd);
printf("Set speaker gain to 15 (maximum)\n");
hfp_ag_set_speaker_gain(device_addr, 15);
break;
case 'q':
log_info("USER:\'%c\'", cmd);
printf("Set microphone gain to 0\n");
hfp_ag_set_microphone_gain(device_addr, 0);
break;
case 'Q':
log_info("USER:\'%c\'", cmd);
printf("Set microphone gain to 9\n");
hfp_ag_set_microphone_gain(device_addr, 9);
break;
case 's':
log_info("USER:\'%c\'", cmd);
printf("Set microphone gain to 12\n");
hfp_ag_set_microphone_gain(device_addr, 12);
break;
case 'S':
log_info("USER:\'%c\'", cmd);
printf("Set microphone gain to 15\n");
hfp_ag_set_microphone_gain(device_addr, 15);
break;
case 'R':
log_info("USER:\'%c\'", cmd);
printf("Enable in-band ring tone\n");
hfp_ag_set_use_in_band_ring_tone(1);
break;
case 't':
log_info("USER:\'%c\'", cmd);
printf("Terminate HCI connection.\n");
gap_disconnect(handle);
break;
case 'u':
log_info("USER:\'%c\'", cmd);
printf("Join held call\n");
current_call_mpty = HFP_ENHANCED_CALL_MPTY_CONFERENCE_CALL;
hfp_ag_join_held_call();
@ -528,14 +568,17 @@ static int stdin_process(struct data_source *ds){
start_scan();
break;
case 'w':
log_info("USER:\'%c\'", cmd);
printf("AG: Put incoming call on hold (Response and Hold)\n");
hfp_ag_hold_incoming_call();
break;
case 'x':
log_info("USER:\'%c\'", cmd);
printf("AG: Accept held incoming call (Response and Hold)\n");
hfp_ag_accept_held_incoming_call();
break;
case 'X':
log_info("USER:\'%c\'", cmd);
printf("AG: Reject held incoming call (Response and Hold)\n");
hfp_ag_reject_held_incoming_call();
break;

View File

@ -73,7 +73,8 @@ const uint32_t hfp_service_buffer[150/4]; // implicit alignment to 4-byte memo
const uint8_t rfcomm_channel_nr = 1;
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 pts_addr = {0x00,0x15,0x83,0x5F,0x9D,0x46};
//static bd_addr_t pts_addr = {0x00,0x1b,0xDC,0x07,0x32,0xEF};
static bd_addr_t phone_addr = {0xD8,0xBb,0x2C,0xDf,0xF1,0x08};
static bd_addr_t device_addr;
@ -186,213 +187,266 @@ static int stdin_process(struct data_source *ds){
case '-':
case '+':
case '*':
log_info("USER:\'%c\'", cmd);
printf("DTMF Code: %c\n", cmd);
hfp_hf_send_dtmf_code(device_addr, cmd);
break;
case 'a':
log_info("USER:\'%c\'", cmd);
printf("Establish Service level connection to device with Bluetooth address %s...\n", bd_addr_to_str(device_addr));
hfp_hf_establish_service_level_connection(device_addr);
break;
case 'A':
log_info("USER:\'%c\'", cmd);
printf("Release Service level connection.\n");
hfp_hf_release_service_level_connection(device_addr);
break;
case 'b':
log_info("USER:\'%c\'", cmd);
printf("Establish Audio connection to device with Bluetooth address %s...\n", bd_addr_to_str(device_addr));
hfp_hf_establish_audio_connection(device_addr);
break;
case 'B':
log_info("USER:\'%c\'", cmd);
printf("Release Audio service level connection.\n");
hfp_hf_release_audio_connection(device_addr);
break;
case 'C':
log_info("USER:\'%c\'", cmd);
printf("Enable registration status update for all AG indicators.\n");
hfp_hf_enable_status_update_for_all_ag_indicators(device_addr);
case 'c':
log_info("USER:\'%c\'", cmd);
printf("Disable registration status update for all AG indicators.\n");
hfp_hf_disable_status_update_for_all_ag_indicators(device_addr);
break;
case 'D':
log_info("USER:\'%c\'", cmd);
printf("Set HFP AG registration status update for individual indicators (0111111).\n");
hfp_hf_set_status_update_for_individual_ag_indicators(device_addr, 63);
break;
case 'd':
log_info("USER:\'%c\'", cmd);
printf("Query network operator.\n");
hfp_hf_query_operator_selection(device_addr);
break;
case 'E':
log_info("USER:\'%c\'", cmd);
printf("Enable reporting of the extended AG error result code.\n");
hfp_hf_enable_report_extended_audio_gateway_error_result_code(device_addr);
break;
case 'e':
log_info("USER:\'%c\'", cmd);
printf("Disable reporting of the extended AG error result code.\n");
hfp_hf_disable_report_extended_audio_gateway_error_result_code(device_addr);
break;
case 'f':
log_info("USER:\'%c\'", cmd);
printf("Answer incoming call.\n");
hfp_hf_answer_incoming_call(device_addr);
break;
case 'F':
log_info("USER:\'%c\'", cmd);
printf("Hangup call.\n");
hfp_hf_terminate_call(device_addr);
break;
case 'G':
log_info("USER:\'%c\'", cmd);
printf("Reject call.\n");
hfp_hf_reject_call(device_addr);
break;
case 'g':
log_info("USER:\'%c\'", cmd);
printf("Query operator.\n");
hfp_hf_query_operator_selection(device_addr);
break;
case 't':
log_info("USER:\'%c\'", cmd);
printf("Terminate HCI connection.\n");
gap_disconnect(handle);
break;
case 'i':
log_info("USER:\'%c\'", cmd);
printf("Dial 1234567\n");
hfp_hf_dial_number(device_addr, "1234567");
break;
case 'I':
log_info("USER:\'%c\'", cmd);
printf("Dial 7654321\n");
hfp_hf_dial_number(device_addr, "7654321");
break;
case 'j':
log_info("USER:\'%c\'", cmd);
printf("Dial #1\n");
hfp_hf_dial_memory(device_addr,"1");
break;
case 'J':
log_info("USER:\'%c\'", cmd);
printf("Dial #99\n");
hfp_hf_dial_memory(device_addr,"99");
break;
case 'k':
log_info("USER:\'%c\'", cmd);
printf("Deactivate call waiting notification\n");
hfp_hf_deactivate_call_waiting_notification(device_addr);
break;
case 'K':
log_info("USER:\'%c\'", cmd);
printf("Activate call waiting notification\n");
hfp_hf_activate_call_waiting_notification(device_addr);
break;
case 'l':
log_info("USER:\'%c\'", cmd);
printf("Deactivate calling line notification\n");
hfp_hf_deactivate_calling_line_notification(device_addr);
break;
case 'L':
log_info("USER:\'%c\'", cmd);
printf("Activate calling line notification\n");
hfp_hf_activate_calling_line_notification(device_addr);
break;
case 'm':
log_info("USER:\'%c\'", cmd);
printf("Deactivate echo canceling and noise reduction\n");
hfp_hf_deactivate_echo_canceling_and_noise_reduction(device_addr);
break;
case 'M':
log_info("USER:\'%c\'", cmd);
printf("Activate echo canceling and noise reduction\n");
hfp_hf_activate_echo_canceling_and_noise_reduction(device_addr);
break;
case 'n':
log_info("USER:\'%c\'", cmd);
printf("Deactivate voice recognition\n");
hfp_hf_deactivate_voice_recognition_notification(device_addr);
break;
case 'N':
log_info("USER:\'%c\'", cmd);
printf("Activate voice recognition\n");
hfp_hf_activate_voice_recognition_notification(device_addr);
break;
case 'o':
log_info("USER:\'%c\'", cmd);
printf("Set speaker gain to 0 (minimum)\n");
hfp_hf_set_speaker_gain(device_addr, 0);
break;
case 'O':
log_info("USER:\'%c\'", cmd);
printf("Set speaker gain to 9 (default)\n");
hfp_hf_set_speaker_gain(device_addr, 9);
break;
case 'p':
log_info("USER:\'%c\'", cmd);
printf("Set speaker gain to 12 (higher)\n");
hfp_hf_set_speaker_gain(device_addr, 12);
break;
case 'P':
log_info("USER:\'%c\'", cmd);
printf("Set speaker gain to 15 (maximum)\n");
hfp_hf_set_speaker_gain(device_addr, 15);
break;
case 'q':
log_info("USER:\'%c\'", cmd);
printf("Set microphone gain to 0\n");
hfp_hf_set_microphone_gain(device_addr, 0);
break;
case 'Q':
log_info("USER:\'%c\'", cmd);
printf("Set microphone gain to 9\n");
hfp_hf_set_microphone_gain(device_addr, 9);
break;
case 's':
log_info("USER:\'%c\'", cmd);
printf("Set microphone gain to 12\n");
hfp_hf_set_microphone_gain(device_addr, 12);
break;
case 'S':
log_info("USER:\'%c\'", cmd);
printf("Set microphone gain to 15\n");
hfp_hf_set_microphone_gain(device_addr, 15);
break;
case 'u':
log_info("USER:\'%c\'", cmd);
printf("Send 'user busy' (Three-Way Call 0)\n");
hfp_hf_user_busy(device_addr);
break;
case 'U':
log_info("USER:\'%c\'", cmd);
printf("End active call and accept waiting/held call (Three-Way Call 1)\n");
hfp_hf_end_active_and_accept_other(device_addr);
break;
case 'v':
log_info("USER:\'%c\'", cmd);
printf("Swap active call and hold/waiting call (Three-Way Call 2)\n");
hfp_hf_swap_calls(device_addr);
break;
case 'V':
log_info("USER:\'%c\'", cmd);
printf("Join hold call (Three-Way Call 3)\n");
hfp_hf_join_held_call(device_addr);
break;
case 'w':
log_info("USER:\'%c\'", cmd);
printf("Connect calls (Three-Way Call 4)\n");
hfp_hf_connect_calls(device_addr);
break;
case 'W':
log_info("USER:\'%c\'", cmd);
printf("Redial\n");
hfp_hf_redial_last_number(device_addr);
break;
case 'x':
log_info("USER:\'%c\'", cmd);
printf("Request phone number for voice tag\n");
hfp_hf_request_phone_number_for_voice_tag(device_addr);
break;
case 'X':
log_info("USER:\'%c\'", cmd);
printf("Query current call status\n");
hfp_hf_query_current_call_status(device_addr);
break;
case 'y':
log_info("USER:\'%c\'", cmd);
printf("Release call with index 2\n");
hfp_hf_release_call_with_index(device_addr, 2);
break;
case 'Y':
log_info("USER:\'%c\'", cmd);
printf("Private consulation with call 2\n");
hfp_hf_private_consultation_with_call(device_addr, 2);
break;
case 'z':
memcpy(device_addr, phone_addr, 6);
log_info("USER:\'%c\'", cmd);
printf("Use iPhone %s as Audiogateway.\n", bd_addr_to_str(device_addr));
break;
case '[':
log_info("USER:\'%c\'", cmd);
printf("Query Response and Hold status (RHH ?)\n");
hfp_hf_rrh_query_status(device_addr);
break;
case ']':
log_info("USER:\'%c\'", cmd);
printf("Place call in a response and held state (RHH 0)\n");
hfp_hf_rrh_hold_call(device_addr);
break;
case '{':
log_info("USER:\'%c\'", cmd);
printf("Accept held call (RHH 1)\n");
hfp_hf_rrh_accept_held_call(device_addr);
break;
case '}':
log_info("USER:\'%c\'", cmd);
printf("Reject held call (RHH 2)\n");
hfp_hf_rrh_reject_held_call(device_addr);
break;
case '?':
log_info("USER:\'%c\'", cmd);
printf("Query Subscriber Number\n");
hfp_hf_query_subscriber_number(device_addr);
break;
case '!':
log_info("USER:\'%c\'", cmd);
printf("Update HF indicator with assigned number 1 (HFI)\n");
hfp_hf_set_hf_indicator(device_addr, 1, 1);
break;