From 8f74874871a19a5feb3d2012d4a3b8ee744e2fe5 Mon Sep 17 00:00:00 2001 From: "mila@ringwald.ch" Date: Thu, 5 Mar 2015 16:23:58 +0000 Subject: [PATCH] hsp ag & hs pass pts tests --- example/embedded/hsp_ag.c | 54 ++++++------ example/embedded/hsp_ag.h | 9 +- example/embedded/hsp_ag_test.c | 15 ++-- example/embedded/hsp_hs.c | 153 +++++++++++++++++++++------------ example/embedded/hsp_hs.h | 7 ++ example/embedded/hsp_hs_test.c | 152 ++++++++++++++++++++++++++++++-- 6 files changed, 293 insertions(+), 97 deletions(-) diff --git a/example/embedded/hsp_ag.c b/example/embedded/hsp_ag.c index da8dce535..ecea18540 100644 --- a/example/embedded/hsp_ag.c +++ b/example/embedded/hsp_ag.c @@ -62,8 +62,8 @@ #define RFCOMM_SERVER_CHANNEL 1 -#define HSP_HS_BUTTON_PRESS "AT+CKPD=200\r" -#define HSP_HS_AT_CKPD "AT+CKPD\r" +#define HSP_HS_BUTTON_PRESS "AT+CKPD=200\r\n" +#define HSP_HS_AT_CKPD "AT+CKPD\r\n" #define HSP_AG_OK "\r\nOK\r\n" #define HSP_AG_ERROR "\r\nERROR\r\n" #define HSP_AG_RING "\r\nRING\r\n" @@ -91,8 +91,8 @@ static int ag_speaker_gain = -1; static uint8_t ag_ring = 0; static uint8_t ag_send_ok = 0; static uint8_t ag_send_error = 0; -static uint8_t ag_in_band_ring_tone = 0; static uint8_t ag_num_button_press_received = 0; +static uint8_t ag_support_custom_commands = 0; typedef enum { HSP_IDLE, @@ -206,10 +206,6 @@ void hsp_ag_create_service(uint8_t * service, int rfcomm_channel_nr, const char } } - -// remote audio volume control -// AG +VGM=13 [0..15] ; HS AT+VGM=6 | AG OK - static int send_str_over_rfcomm(uint16_t cid, char * command){ if (!rfcomm_can_send_packet_now(rfcomm_cid)) return 1; int err = rfcomm_send_internal(cid, (uint8_t*) command, strlen(command)); @@ -221,6 +217,16 @@ static int send_str_over_rfcomm(uint16_t cid, char * command){ return err; } +void hsp_ag_support_custom_commands(int enable){ + ag_support_custom_commands = enable; +} + +int hsp_ag_send_result(char * result){ + if (!ag_support_custom_commands) return 1; + return send_str_over_rfcomm(rfcomm_cid, result); +} + + static void hsp_ag_reset_state(){ hsp_state = HSP_IDLE; @@ -233,10 +239,10 @@ static void hsp_ag_reset_state(){ ag_ring = 0; ag_num_button_press_received = 0; + ag_support_custom_commands = 0; ag_microphone_gain = -1; ag_speaker_gain = -1; - ag_in_band_ring_tone = 0; } void hsp_ag_init(uint8_t rfcomm_channel_nr){ @@ -253,12 +259,6 @@ void hsp_ag_init(uint8_t rfcomm_channel_nr){ hsp_ag_reset_state(); } - -void hsp_ag_enable_in_band_ring_tone(int enabled){ - // send is not yet implemented - ag_in_band_ring_tone = enabled; -} - void hsp_ag_connect(bd_addr_t bd_addr){ if (hsp_state != HSP_IDLE) return; hsp_state = HSP_SDP_QUERY_RFCOMM_CHANNEL; @@ -364,11 +364,6 @@ static void hsp_run(){ break; } - if (ag_in_band_ring_tone){ - log_error("in_band_ring_tone: send is not yet implemented"); - break; - } - if (!ag_num_button_press_received) break; err = send_str_over_rfcomm(rfcomm_cid, HSP_AG_OK); @@ -422,7 +417,12 @@ static void hsp_run(){ static void packet_handler (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ // printf("packet_handler type %u, packet[0] %x\n", packet_type, packet[0]); if (packet_type == RFCOMM_DATA_PACKET){ - if (strncmp((char *)packet, HSP_HS_BUTTON_PRESS, 7) == 0){ + while (size > 0 && (packet[0] == '\n' || packet[0] == '\r')){ + size--; + packet++; + } + + if (strncmp((char *)packet, HSP_HS_BUTTON_PRESS, strlen(HSP_HS_BUTTON_PRESS)) == 0){ printf("Received button press %s\n", HSP_HS_BUTTON_PRESS); ag_num_button_press_received++; ag_send_ok = 1; @@ -430,21 +430,18 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha ag_num_button_press_received = 0; hsp_state = HSP_W2_DISCONNECT_SCO; } - } else if (strncmp((char *)packet, HSP_HS_MICROPHONE_GAIN, 7) == 0){ - uint8_t gain = (uint8_t)atoi((char*)&packet[7]); + } else if (strncmp((char *)packet, HSP_HS_MICROPHONE_GAIN, strlen(HSP_HS_MICROPHONE_GAIN)) == 0){ + uint8_t gain = (uint8_t)atoi((char*)&packet[strlen(HSP_HS_MICROPHONE_GAIN)]); ag_send_ok = 1; emit_event(HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED, gain); - } else if (strncmp((char *)packet, HSP_HS_SPEAKER_GAIN, 7) == 0){ - uint8_t gain = (uint8_t)atoi((char*)&packet[7]); + } else if (strncmp((char *)packet, HSP_HS_SPEAKER_GAIN, strlen(HSP_HS_SPEAKER_GAIN)) == 0){ + uint8_t gain = (uint8_t)atoi((char*)&packet[strlen(HSP_HS_SPEAKER_GAIN)]); ag_send_ok = 1; emit_event(HSP_SUBEVENT_SPEAKER_GAIN_CHANGED, gain); } else if (strncmp((char *)packet, "AT+", 3) == 0){ ag_send_error = 1; - } - - if (ag_send_error){ if (!hsp_ag_callback) return; // re-use incoming buffer to avoid reserving large buffers - ugly but efficient uint8_t * event = packet - 3; @@ -453,6 +450,7 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha event[2] = HSP_SUBEVENT_HS_COMMAND; (*hsp_ag_callback)(event, size+3); } + hsp_run(); return; } @@ -521,8 +519,8 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha hsp_state = HSP_W2_DISCONNECT_SCO; break; } - hsp_state = HSP_ACTIVE; + hsp_state = HSP_ACTIVE; emit_event(HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE, 0); break; } diff --git a/example/embedded/hsp_ag.h b/example/embedded/hsp_ag.h index de4183775..9f89fb210 100644 --- a/example/embedded/hsp_ag.h +++ b/example/embedded/hsp_ag.h @@ -61,8 +61,6 @@ void hsp_ag_init(uint8_t rfcomm_channel_nr); void hsp_ag_connect(bd_addr_t bd_addr); void hsp_ag_disconnect(); -void hsp_ag_enable_in_band_ring_tone(int enabled); - // +VGM=[0..15] void hsp_ag_set_microphone_gain(uint8_t gain); // +VGS=[0..15] @@ -71,6 +69,13 @@ void hsp_ag_set_speaker_gain(uint8_t gain); void hsp_ag_start_ringing(); void hsp_ag_stop_ringing(); +void hsp_ag_support_custom_commands(int enable); + +// When support custom commands is enabled, AG will send HSP_SUBEVENT_HS_COMMAND. +// On occurance of this event, client's packet handler must send the result back +// by calling hsp_ag_send_result function. +int hsp_ag_send_result(char * result); + #if defined __cplusplus } #endif diff --git a/example/embedded/hsp_ag_test.c b/example/embedded/hsp_ag_test.c index 1aadcb399..98a9304fc 100644 --- a/example/embedded/hsp_ag_test.c +++ b/example/embedded/hsp_ag_test.c @@ -82,12 +82,11 @@ static void show_usage(); static data_source_t stdin_source; static void show_usage(){ - printf("\n--- Bluetooth HSP AudioGateway Test Console ---\n"); printf("---\n"); printf("p - establish audio connection to PTS module\n"); printf("e - establish audio connection to Bluetooth Speaker\n"); - printf("d - release audio connection from Bluetooth Speaker\n"); + printf("d - release audio connection\n"); printf("m - set microphone gain 8\n"); printf("M - set microphone gain 15\n"); printf("o - set speaker gain 0\n"); @@ -114,7 +113,7 @@ static int stdin_process(struct data_source *ds){ hsp_ag_connect(bt_speaker_addr); break; case 'd': - printf("Releasing audio connection from Bluetooth Speaker %s...\n", bd_addr_to_str(bt_speaker_addr)); + printf("Releasing audio connection\n"); hsp_ag_disconnect(); break; case 'm': @@ -154,7 +153,6 @@ static int stdin_process(struct data_source *ds){ } static void setup_cli(){ - struct termios term = {0}; if (tcgetattr(0, &term) < 0) perror("tcsetattr()"); @@ -177,14 +175,14 @@ void packet_handler(uint8_t * event, uint16_t event_size){ switch (event[2]) { case HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE: if (event[3] == 0){ - printf("Audio connection established.\n"); + printf("Audio connection established.\n\n"); } else { printf("Audio connection establishment failed with status %u\n", event[3]); } break; case HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE: if (event[3] == 0){ - printf("Audio connection released.\n"); + printf("Audio connection released.\n\n"); } else { printf("Audio connection releasing failed with status %u\n", event[3]); } @@ -199,7 +197,7 @@ void packet_handler(uint8_t * event, uint16_t event_size){ memset(hs_cmd_buffer, 0, sizeof(hs_cmd_buffer)); int size = event_size <= sizeof(hs_cmd_buffer)? event_size : sizeof(hs_cmd_buffer); memcpy(hs_cmd_buffer, &event[3], size - 1); - printf("Received command: \"%s\"\n", hs_cmd_buffer); + printf("Received custom command: \"%s\". \nExit code or call hsp_ag_send_result.\n", hs_cmd_buffer); break; } default: @@ -214,10 +212,11 @@ int btstack_main(int argc, const char * argv[]){ hsp_ag_init(rfcomm_channel_nr); hsp_ag_register_packet_handler(packet_handler); - // turn on! + sdp_init(); sdp_register_service_internal(NULL, (uint8_t *)hsp_service_buffer); + // turn on! hci_power_control(HCI_POWER_ON); setup_cli(); diff --git a/example/embedded/hsp_hs.c b/example/embedded/hsp_hs.c index e0df43ab7..635b9d6f6 100644 --- a/example/embedded/hsp_hs.c +++ b/example/embedded/hsp_hs.c @@ -60,16 +60,17 @@ #include "debug.h" #include "hsp_hs.h" -#define HSP_HS_BUTTON_PRESS "AT+CKPD=200\r" -#define HSP_HS_AT_CKPD "AT+CKPD\r" -#define HSP_AG_OK "\r\nOK\r\n" -#define HSP_AG_ERROR "\r\nERROR\r\n" -#define HSP_AG_RING "\r\nRING\r\n" -#define HSP_MICROPHONE_GAIN "+VGM" -#define HSP_SPEAKER_GAIN "+VGS" -#define HSP_HS_MICROPHONE_GAIN "AT+VGM=" -#define HSP_HS_SPEAKER_GAIN "AT+VGS=" +#define HSP_AG_OK "OK" +#define HSP_AG_ERROR "ERROR" +#define HSP_AG_RING "RING" +#define HSP_MICROPHONE_GAIN "+VGM=" +#define HSP_SPEAKER_GAIN "+VGS=" + +#define HSP_HS_BUTTON_PRESS "AT+CKPD=200\r\n" +#define HSP_HS_AT_CKPD "AT+CKPD=200\r\n" +#define HSP_HS_MICROPHONE_GAIN "AT+VGM" +#define HSP_HS_SPEAKER_GAIN "AT+VGS" static const char default_hsp_hs_service_name[] = "Headset"; @@ -87,10 +88,9 @@ static int hs_microphone_gain = -1; static int hs_speaker_gain = -1; static uint8_t hs_send_button_press = 0; -static uint8_t hs_send_at_cpkd = 0; static uint8_t hs_ok_received = 0; static uint8_t hs_ring_received = 0; - +static uint8_t hs_support_custom_indications = 0; typedef enum { @@ -98,6 +98,7 @@ typedef enum { HSP_SDP_QUERY_RFCOMM_CHANNEL, HSP_W4_SDP_QUERY_COMPLETE, HSP_W4_RFCOMM_CONNECTED, + HSP_W4_USER_ACTION, HSP_W2_CONNECT_SCO, HSP_W4_SCO_CONNECTED, HSP_ACTIVE, @@ -124,11 +125,15 @@ void hsp_hs_register_packet_handler(hsp_hs_callback_t callback){ hsp_hs_callback = callback; } -static void emit_event(uint8_t * event, uint16_t size){ +static void emit_event(uint8_t event_subtype, uint8_t value){ if (!hsp_hs_callback) return; - (*hsp_hs_callback)(event, size); + uint8_t event[4]; + event[0] = HCI_EVENT_HSP_META; + event[1] = sizeof(event) - 2; + event[2] = event_subtype; + event[3] = value; // status 0 == OK + (*hsp_hs_callback)(event, sizeof(event)); } - // remote audio volume control // AG +VGM=13 [0..15] ; HS AT+VGM=6 | AG OK @@ -141,6 +146,18 @@ static int send_str_over_rfcomm(uint16_t cid, char * command){ return err; } +void hsp_hs_support_custom_indications(int enable){ + hs_support_custom_indications = enable; +} + +// When support custom commands is enabled, AG will send HSP_SUBEVENT_HS_COMMAND. +// On occurance of this event, client's packet handler must send the result back +// by calling hsp_hs_send_result function. +int hsp_hs_send_result(char * result){ + if (!hs_support_custom_indications) return 1; + return send_str_over_rfcomm(rfcomm_cid, result); +} + void hsp_hs_create_service(uint8_t * service, int rfcomm_channel_nr, const char * name, uint8_t have_remote_audio_control){ uint8_t* attribute; @@ -224,11 +241,9 @@ static void hsp_hs_reset_state(){ hs_speaker_gain = -1; hs_send_button_press = 0; - hs_send_at_cpkd = 0; - hs_ok_received = 0; hs_ring_received = 0; - // TODO + hs_support_custom_indications = 0; } void hsp_hs_init(uint8_t rfcomm_channel_nr){ @@ -256,11 +271,12 @@ void hsp_hs_connect(bd_addr_t bd_addr){ void hsp_hs_disconnect(bd_addr_t bd_addr){ switch (hsp_state){ case HSP_ACTIVE: - hsp_state = HSP_W2_DISCONNECT_SCO; - hs_send_at_cpkd = 1; + printf("HSP_W4_USER_ACTION\n"); + hsp_state = HSP_W4_USER_ACTION; + hs_send_button_press = 1; break; - case HSP_W4_RFCOMM_CONNECTED: + printf("HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN \n"); hsp_state = HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN; break; default: @@ -296,15 +312,18 @@ static void hsp_run(){ hs_ring_received = 0; hs_send_button_press = 1; } - - if (hs_send_at_cpkd){ - int err = send_str_over_rfcomm(rfcomm_cid, HSP_HS_AT_CKPD); - if (!err) hs_send_at_cpkd = 0; - return; + + if (hs_ok_received){ + hs_ok_received = 0; } - + if (hs_send_button_press){ - int err = send_str_over_rfcomm(rfcomm_cid, HSP_HS_BUTTON_PRESS); + int err = 0; + if (hsp_state == HSP_W4_USER_ACTION){ + err = send_str_over_rfcomm(rfcomm_cid, HSP_HS_AT_CKPD); + } else { + err = send_str_over_rfcomm(rfcomm_cid, HSP_HS_BUTTON_PRESS); + } if (!err) hs_send_button_press = 0; return; } @@ -316,36 +335,32 @@ static void hsp_run(){ break; case HSP_W2_CONNECT_SCO: - if (hs_ok_received){ - hs_ok_received = 0; - hsp_state = HSP_W4_SCO_CONNECTED; - } + hsp_state = HSP_W4_SCO_CONNECTED; break; case HSP_W2_DISCONNECT_SCO: - if (hs_ok_received){ - hs_ok_received = 0; - hsp_state = HSP_W4_SCO_DISCONNECTED; - } + hsp_state = HSP_W4_SCO_DISCONNECTED; break; - + case HSP_ACTIVE: - - if (hs_microphone_gain >= 0){ - char buffer[10]; - sprintf(buffer, "%s=%d\r", HSP_HS_MICROPHONE_GAIN, hs_microphone_gain); + if (hs_ok_received) break; + + if (hs_microphone_gain >= 0){ + char buffer[20]; + sprintf(buffer, "%s=%d\r\n", HSP_HS_MICROPHONE_GAIN, hs_microphone_gain); err = send_str_over_rfcomm(rfcomm_cid, buffer); if (!err) hs_microphone_gain = -1; break; } if (hs_speaker_gain >= 0){ - char buffer[10]; - sprintf(buffer, "%s=%d\r", HSP_HS_SPEAKER_GAIN, hs_speaker_gain); + char buffer[20]; + sprintf(buffer, "%s=%d\r\n", HSP_HS_SPEAKER_GAIN, hs_speaker_gain); err = send_str_over_rfcomm(rfcomm_cid, buffer); if (!err) hs_speaker_gain = -1; break; } + break; default: break; @@ -356,17 +371,39 @@ static void hsp_run(){ static void packet_handler (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ // printf("packet_handler type %u, packet[0] %x\n", packet_type, packet[0]); if (packet_type == RFCOMM_DATA_PACKET){ + while (size > 0 && (packet[0] == '\n' || packet[0] == '\r')){ + size--; + packet++; + } if (strncmp((char *)packet, HSP_AG_RING, strlen(HSP_AG_RING)) == 0){ - printf("Received RING %s\n", HSP_AG_RING); hs_ring_received = 1; } if (strncmp((char *)packet, HSP_AG_OK, strlen(HSP_AG_OK)) == 0){ - printf("Received OK %s\n", HSP_AG_OK); hs_ok_received = 1; - } else if (strncmp((char *)packet, HSP_MICROPHONE_GAIN, strlen(HSP_MICROPHONE_GAIN)) == 0 || - strncmp((char *)packet, HSP_SPEAKER_GAIN, strlen(HSP_SPEAKER_GAIN)) == 0){ - printf("Received changed gain info %c\n", packet[8]); + switch (hsp_state){ + case HSP_W4_RFCOMM_CONNECTED: + hsp_state = HSP_W2_CONNECT_SCO; + break; + case HSP_W4_USER_ACTION: + hsp_state = HSP_W2_DISCONNECT_SCO; + break; + default: + break; + } + } else if (strncmp((char *)packet, HSP_MICROPHONE_GAIN, strlen(HSP_MICROPHONE_GAIN)) == 0){ + uint8_t gain = (uint8_t)atoi((char*)&packet[strlen(HSP_MICROPHONE_GAIN)]); + emit_event(HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED, gain); + + } else if (strncmp((char *)packet, HSP_SPEAKER_GAIN, strlen(HSP_SPEAKER_GAIN)) == 0){ + uint8_t gain = (uint8_t)atoi((char*)&packet[strlen(HSP_SPEAKER_GAIN)]); + emit_event(HSP_SUBEVENT_SPEAKER_GAIN_CHANGED, gain); } else { - log_info("Received not yet supported command.\n"); + if (!hsp_hs_callback) return; + // re-use incoming buffer to avoid reserving large buffers - ugly but efficient + uint8_t * event = packet - 3; + event[0] = HCI_EVENT_HSP_META; + event[1] = size + 1; + event[2] = HSP_SUBEVENT_AG_INDICATION; + (*hsp_hs_callback)(event, size+3); } hsp_run(); return; @@ -381,7 +418,7 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha case BTSTACK_EVENT_STATE: // bt stack activated, get started if (packet[2] == HCI_STATE_WORKING){ - hsp_hs_connect(remote); + printf("BTstack activated, get started .\n"); } break; @@ -436,7 +473,9 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha hsp_state = HSP_W2_DISCONNECT_SCO; break; } + hsp_state = HSP_ACTIVE; + emit_event(HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE, 0); break; } @@ -448,7 +487,8 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha rfcomm_cid = READ_BT_16(packet, 9); printf("RFCOMM channel %u requested for %s\n", packet[8], bd_addr_to_str(event_addr)); rfcomm_accept_connection_internal(rfcomm_cid); - hsp_state = HSP_W2_CONNECT_SCO; + + hsp_state = HSP_W4_RFCOMM_CONNECTED; hs_send_button_press = 1; break; @@ -458,6 +498,7 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha if (packet[2]) { printf("RFCOMM channel open failed, status %u\n", packet[2]); hsp_hs_reset_state(); + emit_event(HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE, packet[2]); } else { // data: event(8) , len(8), status (8), address (48), handle (16), server channel(8), rfcomm_cid(16), max frame size(16) rfcomm_handle = READ_BT_16(packet, 9); @@ -468,7 +509,7 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha switch (hsp_state){ case HSP_W4_RFCOMM_CONNECTED: hsp_state = HSP_W2_CONNECT_SCO; - hs_send_at_cpkd = 1; + hs_send_button_press = 1; break; case HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN: hsp_state = HSP_W2_DISCONNECT_RFCOMM; @@ -483,22 +524,26 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha break; case HCI_EVENT_DISCONNECTION_COMPLETE: + printf("HCI_EVENT_DISCONNECTION_COMPLETE \n"); if (hsp_state != HSP_W4_SCO_DISCONNECTED){ - log_info("received gap disconnect in wrong hsp state"); + printf("received gap disconnect in wrong hsp state"); } handle = READ_BT_16(packet,3); if (handle == sco_handle){ sco_handle = 0; - hsp_state = HSP_W4_RFCOMM_DISCONNECTED; + hsp_state = HSP_W2_DISCONNECT_RFCOMM; + printf(" HSP_W2_DISCONNECT_RFCOMM\n"); break; } break; case RFCOMM_EVENT_CHANNEL_CLOSED: + printf(" RFCOMM_EVENT_CHANNEL_CLOSED\n"); if (hsp_state != HSP_W4_RFCOMM_DISCONNECTED){ - log_info("received RFCOMM disconnect in wrong hsp state"); + printf("received RFCOMM disconnect in wrong hsp state"); } printf("RFCOMM channel closed\n"); hsp_hs_reset_state(); + emit_event(HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE,0); break; default: break; diff --git a/example/embedded/hsp_hs.h b/example/embedded/hsp_hs.h index d1e7771d2..ff4b24730 100644 --- a/example/embedded/hsp_hs.h +++ b/example/embedded/hsp_hs.h @@ -66,6 +66,13 @@ void hsp_hs_set_microphone_gain(uint8_t gain); // AT+VGS=[0..15] void hsp_hs_set_speaker_gain(uint8_t gain); +void hsp_hs_support_custom_indications(int enable); + +// When support custom commands is enabled, AG will send HSP_SUBEVENT_AG_INDICATION. +// On occurance of this event, client's packet handler must send the result back +// by calling hsp_hs_send_result function. +int hsp_hs_send_result(char * indication); + #if defined __cplusplus } #endif diff --git a/example/embedded/hsp_hs_test.c b/example/embedded/hsp_hs_test.c index 2889e6644..26879c17f 100644 --- a/example/embedded/hsp_hs_test.c +++ b/example/embedded/hsp_hs_test.c @@ -47,9 +47,20 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include #include +#include #include "hci.h" #include "l2cap.h" @@ -59,24 +70,155 @@ const uint8_t hsp_service_buffer[150]; const uint8_t rfcomm_channel_nr = 1; -const char hsp_ag_service_name[] = "Headset Test"; +const char hsp_hs_service_name[] = "Headset Test"; + +static bd_addr_t pts_addr = {0x00,0x1b,0xDC,0x07,0x32,0xEF}; +static bd_addr_t local_mac = {0x04, 0x0C, 0xCE, 0xE4, 0x85, 0xD3}; + +static char hs_cmd_buffer[100]; + +// prototypes +static void show_usage(); + + +// Testig User Interface +static data_source_t stdin_source; + +static void show_usage(){ + printf("\n--- Bluetooth HSP Headset Test Console ---\n"); + printf("---\n"); + printf("p - establish audio connection to PTS module\n"); + printf("e - establish audio connection to local mac\n"); + printf("d - release audio connection from Bluetooth Speaker\n"); + printf("z - set microphone gain 0\n"); + printf("m - set microphone gain 8\n"); + printf("M - set microphone gain 15\n"); + printf("o - set speaker gain 0\n"); + printf("s - set speaker gain 8\n"); + printf("S - set speaker gain 15\n"); + printf("---\n"); + printf("Ctrl-c - exit\n"); + printf("---\n"); +} + +static int stdin_process(struct data_source *ds){ + char buffer; + read(ds->fd, &buffer, 1); + + switch (buffer){ + case 'p': + printf("Establishing audio connection to PTS module %s...\n", bd_addr_to_str(pts_addr)); + hsp_hs_connect(pts_addr); + break; + case 'e': + printf("Establishing audio connection to local mac %s...\n", bd_addr_to_str(local_mac)); + hsp_hs_connect(local_mac); + break; + case 'd': + printf("Releasing audio connection.\n"); + hsp_hs_disconnect(); + break; + case 'z': + printf("Setting microphone gain 0\n"); + hsp_hs_set_microphone_gain(0); + break; + case 'm': + printf("Setting microphone gain 8\n"); + hsp_hs_set_microphone_gain(8); + break; + case 'M': + printf("Setting microphone gain 15\n"); + hsp_hs_set_microphone_gain(15); + break; + case 'o': + printf("Setting speaker gain 0\n"); + hsp_hs_set_speaker_gain(0); + break; + case 's': + printf("Setting speaker gain 8\n"); + hsp_hs_set_speaker_gain(8); + break; + case 'S': + printf("Setting speaker gain 15\n"); + hsp_hs_set_speaker_gain(15); + break; + default: + show_usage(); + break; + } + + return 0; +} + + +static void setup_cli(){ + struct termios term = {0}; + if (tcgetattr(0, &term) < 0) + perror("tcsetattr()"); + term.c_lflag &= ~ICANON; + term.c_lflag &= ~ECHO; + term.c_cc[VMIN] = 1; + term.c_cc[VTIME] = 0; + if (tcsetattr(0, TCSANOW, &term) < 0) + perror("tcsetattr ICANON"); + + stdin_source.fd = 0; // stdin + stdin_source.process = &stdin_process; + run_loop_add_data_source(&stdin_source); + + show_usage(); +} void packet_handler(uint8_t * event, uint16_t event_size){ - + switch (event[2]) { + case HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE: + if (event[3] == 0){ + printf("Audio connection established.\n\n"); + } else { + printf("Audio connection establishment failed with status %u\n", event[3]); + } + break; + case HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE: + if (event[3] == 0){ + printf("Audio connection released.\n\n"); + } else { + printf("Audio connection releasing failed with status %u\n", event[3]); + } + break; + case HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED: + printf("Received microphone gain change %d\n", event[3]); + break; + case HSP_SUBEVENT_SPEAKER_GAIN_CHANGED: + printf("Received speaker gain change %d\n", event[3]); + break; + case HSP_SUBEVENT_AG_INDICATION: + memset(hs_cmd_buffer, 0, sizeof(hs_cmd_buffer)); + int size = event_size <= sizeof(hs_cmd_buffer)? event_size : sizeof(hs_cmd_buffer); + memcpy(hs_cmd_buffer, &event[3], size - 1); + printf("Received custom indication: \"%s\". \nExit code or call hsp_hs_send_result.\n", hs_cmd_buffer); + break; + default: + printf("event not handled %u\n", event[2]); + break; + } } int btstack_main(int argc, const char * argv[]){ // init SDP, create record for SPP and register with SDP memset((uint8_t *)hsp_service_buffer, 0, sizeof(hsp_service_buffer)); - hsp_hs_create_service((uint8_t *)hsp_service_buffer, rfcomm_channel_nr, hsp_ag_service_name, 0); + hsp_hs_create_service((uint8_t *)hsp_service_buffer, rfcomm_channel_nr, hsp_hs_service_name, 0); + + hsp_hs_init(rfcomm_channel_nr); + hsp_hs_register_packet_handler(packet_handler); sdp_init(); sdp_register_service_internal(NULL, (uint8_t *)hsp_service_buffer); - hsp_hs_init(rfcomm_channel_nr); - hsp_hs_register_packet_handler(packet_handler); // turn on! hci_power_control(HCI_POWER_ON); + + setup_cli(); + // go! run_loop_execute(); return 0;