hfp: use mock to test state machines

This commit is contained in:
Milanka Ringwald 2015-08-26 18:31:31 +02:00
parent 99f65fee91
commit 1238101111
5 changed files with 434 additions and 49 deletions

1
test/hfp/.gitignore vendored
View File

@ -1,2 +1,3 @@
hfp_hf_client_test
hfp_ag_parser_test
hfp_hf_parser_test

View File

@ -25,9 +25,22 @@ COMMON = \
sdp_query_util.c \
sdp_query_rfcomm.c \
sdp.c \
mock.c \
MOCK = \
btstack_memory.c \
linked_list.c \
memory_pool.c \
remote_device_db_memory.c \
hci_cmds.c \
hci_dump.c \
sdp_util.c \
utils.c \
mock.c \
COMMON_OBJ = $(COMMON:.c=.o)
MOCK_OBJ = $(MOCK:.c=.o)
# CC = gcc-fsf-4.9
CFLAGS = -g -Wall -I. -I../ -I${BTSTACK_ROOT}/src -I${BTSTACK_ROOT}/include
@ -41,7 +54,8 @@ CFLAGS = -g -Wall -I. -I../ -I${BTSTACK_ROOT}/src -I${BTSTACK_ROOT}/include -I$
LDFLAGS += -lCppUTest -lCppUTestExt
EXAMPLES = hfp_ag_parser_test hfp_hf_parser_test
EXAMPLES = hfp_hf_client_test
# hfp_ag_parser_test hfp_hf_parser_test
all: ${BTSTACK_ROOT}/include/btstack/version.h ${EXAMPLES}
@ -54,6 +68,10 @@ hfp_ag_parser_test: ${COMMON_OBJ} hfp_ag.o hfp.o hfp_ag_parser_test.c
hfp_hf_parser_test: ${COMMON_OBJ} hfp_hf.o hfp.o hfp_hf_parser_test.c
${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@
hfp_hf_client_test: ${MOCK_OBJ} hfp_hf.o hfp.o hfp_hf_client_test.c
${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@
test: all
./hfp_ag_parser_test
./hfp_hf_parser_test
./hfp_hf_client_test

View File

@ -0,0 +1,246 @@
/*
* 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
*
*/
// *****************************************************************************
//
// Minimal test for HSP Headset (!! UNDER DEVELOPMENT !!)
//
// *****************************************************************************
#include "btstack-config.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "CppUTest/TestHarness.h"
#include "CppUTest/CommandLineTestRunner.h"
#include <btstack/hci_cmds.h>
#include <btstack/run_loop.h>
#include <btstack/sdp_util.h>
#include "hci.h"
#include "l2cap.h"
#include "rfcomm.h"
#include "sdp.h"
#include "sdp_parser.h"
#include "debug.h"
#include "hfp_hf.h"
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 phone_addr = {0xD8,0xBb,0x2C,0xDf,0xF1,0x08};
static bd_addr_t device_addr;
static uint8_t codecs[1] = {HFP_CODEC_CVSD};
static uint16_t indicators[1] = {0x01};
// prototypes
static void show_usage();
uint8_t * get_rfcomm_payload();
uint16_t get_rfcomm_payload_len();
void inject_rfcomm_command(uint8_t * payload, int len);
// Testig User Interface
static void show_usage(void){
printf("\n--- Bluetooth HFP Hands-Free (HF) unit Test Console ---\n");
printf("---\n");
printf("y - use PTS module as Audiogateway\n");
printf("z - use iPhone as Audiogateway\n");
printf("h - establish HFP connection to device\n");
printf("H - release HFP connection to device\n");
printf("a - establish Audio connection to device\n");
printf("A - release Audio connection to device\n");
printf("b - establish AUDIO connection\n");
printf("B - release AUDIO connection\n");
printf("d - enable registration status update\n");
printf("D - disable registration status update\n");
printf("e - enable HFP AG registration status update for individual indicators\n");
printf("f - query network operator\n");
printf("g - enable reporting of the extended AG error result code\n");
printf("G - disable reporting of the extended AG error result code\n");
printf("---\n");
printf("Ctrl-c - exit\n");
printf("---\n");
}
static int process(char cmd){
switch (cmd){
case 'a':
memcpy(device_addr, pts_addr, 6);
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 'A':
printf("Release Audio service level connection.\n");
hfp_hf_release_audio_connection(device_addr);
break;
case 'h':
memcpy(device_addr, pts_addr, 6);
printf("Establish HFP 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 'H':
printf("Release HFP service level connection.\n");
hfp_hf_release_service_level_connection(device_addr);
break;
case 'b':
printf("Establish Audio connection %s...\n", bd_addr_to_str(device_addr));
hfp_hf_establish_audio_connection(device_addr);
break;
case 'B':
printf("Release Audio connection.\n");
hfp_hf_release_audio_connection(device_addr);
break;
case 'd':
printf("Enable HFP AG registration status update.\n");
hfp_hf_enable_status_update_for_all_ag_indicators(device_addr, 1);
case 'D':
printf("Disable HFP AG registration status update.\n");
hfp_hf_enable_status_update_for_all_ag_indicators(device_addr, 0);
break;
case 'e':
printf("Enable HFP AG registration status update for individual indicators.\n");
hfp_hf_enable_status_update_for_individual_ag_indicators(device_addr, 63);
break;
case 'f':
printf("Query network operator.\n");
hfp_hf_query_operator_selection(device_addr);
break;
case 'g':
printf("Enable reporting of the extended AG error result code.\n");
hfp_hf_enable_report_extended_audio_gateway_error_result_code(device_addr, 1);
break;
case 'G':
printf("Disable reporting of the extended AG error result code.\n");
hfp_hf_enable_report_extended_audio_gateway_error_result_code(device_addr, 0);
break;
case 'y':
memcpy(device_addr, phone_addr, 6);
printf("Use iPhone %s as Audiogateway.\n", bd_addr_to_str(device_addr));
break;
case 'z':
memcpy(device_addr, pts_addr, 6);
printf("Use PTS module %s as Audiogateway.\n", bd_addr_to_str(device_addr));
break;
default:
show_usage();
break;
}
return 0;
}
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){
printf("ERROR, status: %u\n", event[3]);
return;
}
switch (event[2]) {
case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
printf("Service level connection established.\n\n");
break;
case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED:
printf("Service level connection released.\n\n");
break;
case HFP_SUBEVENT_COMPLETE:
printf("HFP_SUBEVENT_COMPLETE.\n\n");
break;
case HFP_SUBEVENT_AG_INDICATOR_STATUS_CHANGED:
printf("AG_INDICATOR_STATUS_CHANGED, AG indicator index: %d, status: %d\n", 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;
default:
printf("event not handled %u\n", event[2]);
break;
}
}
static int expected_rfcomm_command(const char * cmd){
printf("%s\n", get_rfcomm_payload());
return strcmp((char *)cmd, (char *)get_rfcomm_payload());
}
static void verify_expected_rfcomm_command(const char * cmd){
CHECK_EQUAL(expected_rfcomm_command(cmd),0);
}
const char hf_supported_features[] = "AT+BRSF=438\r\n";
const char ag_supported_features[] = "\r\n+BRSF=1007\r\n\r\nOK\r\n";
TEST_GROUP(HandsfreeClient){
void setup(void){
process('y');
}
};
TEST(HandsfreeClient, HFAudioConnection){
process('a');
verify_expected_rfcomm_command(hf_supported_features);
inject_rfcomm_command((uint8_t*)ag_supported_features, strlen(ag_supported_features));
}
int main (int argc, const char * argv[]){
hfp_hf_init(rfcomm_channel_nr, 438, indicators, sizeof(indicators)/sizeof(uint16_t), 1);
hfp_hf_set_codecs(codecs, sizeof(codecs));
hfp_hf_register_packet_handler(packet_handler);
return CommandLineTestRunner::RunAllTests(argc, argv);
}

125
test/hfp/mock.c Normal file
View File

@ -0,0 +1,125 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <btstack/btstack.h>
// #include "att.h"
#include "hci.h"
#include "hci_dump.h"
#include "sdp_query_rfcomm.h"
#include "rfcomm.h"
static void *registered_sdp_app_context;
static uint8_t sdp_rfcomm_channel_nr = 1;
const char sdp_rfcomm_service_name[] = "BTstackMock";
static rfcomm_channel_t rfcomm_channel;
static uint16_t rfcomm_cid = 1;
static uint8_t rfcomm_payload[200];
static uint16_t rfcomm_payload_len;
void * active_connection;
void (*registered_rfcomm_packet_handler)(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
void (*registered_sdp_app_callback)(sdp_query_event_t * event, void * context);
uint8_t * get_rfcomm_payload(){
return &rfcomm_payload[0];
}
uint16_t get_rfcomm_payload_len(){
return rfcomm_payload_len;
}
void inject_rfcomm_command(uint8_t * data, int len){
memset(&rfcomm_payload, 0, 200);
rfcomm_payload_len = len;
memcpy((char*)&rfcomm_payload[0], data, rfcomm_payload_len);
(*registered_rfcomm_packet_handler)(active_connection, RFCOMM_DATA_PACKET, rfcomm_cid, (uint8_t *) &rfcomm_payload[0], rfcomm_payload_len);
}
int rfcomm_send_internal(uint16_t rfcomm_cid, uint8_t *data, uint16_t len){
// printf("rfcomm_send_internal\n");
memset(&rfcomm_payload, 0, 200);
rfcomm_payload_len = len;
memcpy((char*)&rfcomm_payload, data, rfcomm_payload_len);
return 0;
}
int hci_send_cmd(const hci_cmd_t *cmd, ...){
printf("hci_send_cmd opcode 0x%02x\n", cmd->opcode);
return 0;
}
void sdp_query_rfcomm_register_callback(void(*sdp_app_callback)(sdp_query_event_t * event, void * context), void * context){
registered_sdp_app_callback = sdp_app_callback;
registered_sdp_app_context = context;
}
static void sdp_query_complete_response(uint8_t status){
sdp_query_complete_event_t complete_event = {
SDP_QUERY_COMPLETE,
status
};
(*registered_sdp_app_callback)((sdp_query_event_t*)&complete_event, registered_sdp_app_context);
}
static void sdp_query_rfcomm_service_response(uint8_t status){
sdp_query_rfcomm_service_event_t service_event = {
SDP_QUERY_RFCOMM_SERVICE,
sdp_rfcomm_channel_nr,
(uint8_t *)sdp_rfcomm_service_name
};
(*registered_sdp_app_callback)((sdp_query_event_t*)&service_event, registered_sdp_app_context);
}
void sdp_query_rfcomm_channel_and_name_for_uuid(bd_addr_t remote, uint16_t uuid){
// printf("sdp_query_rfcomm_channel_and_name_for_uuid %p\n", registered_sdp_app_callback);
sdp_query_rfcomm_service_response(0);
sdp_query_complete_response(0);
}
void rfcomm_create_channel_internal(void * connection, bd_addr_t addr, uint8_t channel){
// RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE
// printf("rfcomm_create_channel_internal\n");
active_connection = connection;
uint8_t event[16];
uint8_t pos = 0;
event[pos++] = RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE;
event[pos++] = sizeof(event) - 2;
event[pos++] = 0;
bt_flip_addr(&event[pos], addr); pos += 6;
bt_store_16(event, pos, 1); pos += 2;
event[pos++] = 0;
bt_store_16(event, pos, rfcomm_cid); pos += 2; // channel ID
bt_store_16(event, pos, 200); pos += 2; // max frame size
(*registered_rfcomm_packet_handler)(connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, pos);
}
void rfcomm_disconnect_internal(uint16_t rfcomm_cid){
printf("rfcomm_disconnect_internal\n");
}
void rfcomm_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)){
registered_rfcomm_packet_handler = handler;
}
void rfcomm_register_service_internal(void * connection, uint8_t channel, uint16_t max_frame_size){
printf("rfcomm_register_service_internal\n");
}
void sdp_query_rfcomm_channel_and_name_for_search_pattern(bd_addr_t remote, uint8_t * des_serviceSearchPattern){
printf("sdp_query_rfcomm_channel_and_name_for_search_pattern\n");
}
void rfcomm_accept_connection_internal(uint16_t rfcomm_cid){
printf("rfcomm_accept_connection_internal \n");
}

View File

@ -81,45 +81,35 @@ static uint16_t indicators[1] = {0x01};
char cmd;
uint8_t hfp_enable_extended_audio_gateway_error_report = 1;
uint8_t hfp_enable_status_update_for_all_ag_indicators = 1;
// prototypes
static void show_usage();
static void reset_pst_flags(){
hfp_enable_extended_audio_gateway_error_report = 1;
hfp_enable_status_update_for_all_ag_indicators = 1;
}
// Testig User Interface
static void show_usage(void){
printf("\n--- Bluetooth HFP Hands-Free (HF) unit Test Console ---\n");
printf("---\n");
printf("y - use PTS module as Audiogateway\n");
printf("z - use iPhone as Audiogateway\n");
printf("h - establish HFP connection to device\n");
printf("H - release HFP connection to device\n");
printf("a - establish HFP connection to PTS module\n");
printf("A - release HFP connection to PTS module\n");
printf("a - establish Audio connection to device\n");
printf("A - release Audio connection to device\n");
printf("b - establish AUDIO connection\n");
printf("B - release AUDIO connection\n");
printf("z - establish HFP connection to local mac\n");
printf("Z - release HFP connection to local mac\n");
printf("d - enable registration status update\n");
printf("D - disable registration status update\n");
if (hfp_enable_status_update_for_all_ag_indicators){
printf("d - enable registration status update\n");
} else {
printf("d - disable registration status update\n");
}
printf("e - enable HFP AG registration status update for individual indicators\n");
printf("f - query network operator\n");
if (hfp_enable_extended_audio_gateway_error_report){
printf("g - enable reporting of the extended AG error result code\n");
} else {
printf("g - disable reporting of the extended AG error result code\n");
}
printf("g - enable reporting of the extended AG error result code\n");
printf("G - disable reporting of the extended AG error result code\n");
printf("---\n");
printf("Ctrl-c - exit\n");
printf("---\n");
@ -130,20 +120,20 @@ static int stdin_process(struct data_source *ds){
switch (cmd){
case 'a':
memcpy(device_addr, pts_addr, 6);
printf("Establish HFP service level connection to PTS module %s...\n", bd_addr_to_str(device_addr));
hfp_hf_establish_service_level_connection(device_addr);
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 'A':
printf("Release HFP service level connection.\n");
hfp_hf_release_service_level_connection(device_addr);
printf("Release Audio service level connection.\n");
hfp_hf_release_audio_connection(device_addr);
break;
case 'z':
memcpy(device_addr, phone_addr, 6);
printf("Establish HFP service level connection to %s...\n", bd_addr_to_str(device_addr));
case 'h':
memcpy(device_addr, pts_addr, 6);
printf("Establish HFP 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 'Z':
printf("Release HFP service level connection to %s...\n", bd_addr_to_str(device_addr));
case 'H':
printf("Release HFP service level connection.\n");
hfp_hf_release_service_level_connection(device_addr);
break;
case 'b':
@ -154,15 +144,12 @@ static int stdin_process(struct data_source *ds){
printf("Release Audio connection.\n");
hfp_hf_release_audio_connection(device_addr);
break;
case 'd':
if (hfp_enable_status_update_for_all_ag_indicators){
printf("Enable HFP AG registration status update.\n");
} else {
printf("Disable HFP AG registration status update.\n");
}
hfp_hf_enable_status_update_for_all_ag_indicators(device_addr, hfp_enable_status_update_for_all_ag_indicators);
hfp_enable_status_update_for_all_ag_indicators = !hfp_enable_status_update_for_all_ag_indicators;
printf("Enable HFP AG registration status update.\n");
hfp_hf_enable_status_update_for_all_ag_indicators(device_addr, 1);
case 'D':
printf("Disable HFP AG registration status update.\n");
hfp_hf_enable_status_update_for_all_ag_indicators(device_addr, 0);
break;
case 'e':
printf("Enable HFP AG registration status update for individual indicators.\n");
@ -173,14 +160,23 @@ static int stdin_process(struct data_source *ds){
hfp_hf_query_operator_selection(device_addr);
break;
case 'g':
if (hfp_enable_extended_audio_gateway_error_report){
printf("Enable reporting of the extended AG error result code.\n");
} else {
printf("Disable reporting of the extended AG error result code.\n");
}
hfp_hf_enable_report_extended_audio_gateway_error_result_code(device_addr, hfp_enable_extended_audio_gateway_error_report);
hfp_enable_extended_audio_gateway_error_report = !hfp_enable_extended_audio_gateway_error_report;
printf("Enable reporting of the extended AG error result code.\n");
hfp_hf_enable_report_extended_audio_gateway_error_result_code(device_addr, 1);
break;
case 'G':
printf("Disable reporting of the extended AG error result code.\n");
hfp_hf_enable_report_extended_audio_gateway_error_result_code(device_addr, 0);
break;
case 'y':
memcpy(device_addr, phone_addr, 6);
printf("Use iPhone %s as Audiogateway.\n", bd_addr_to_str(device_addr));
break;
case 'z':
memcpy(device_addr, pts_addr, 6);
printf("Use PTS module %s as Audiogateway.\n", bd_addr_to_str(device_addr));
break;
default:
show_usage();
break;
@ -202,7 +198,6 @@ void packet_handler(uint8_t * event, uint16_t event_size){
break;
case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED:
printf("Service level connection released.\n\n");
reset_pst_flags();
break;
case HFP_SUBEVENT_COMPLETE:
switch (cmd){