mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-22 16:20:54 +00:00
hsp: ag emits events, added cmd line ag test
This commit is contained in:
parent
74f8acbab3
commit
3099ceee29
@ -75,7 +75,7 @@
|
|||||||
|
|
||||||
static const char default_hsp_ag_service_name[] = "Audio Gateway";
|
static const char default_hsp_ag_service_name[] = "Audio Gateway";
|
||||||
|
|
||||||
static bd_addr_t remote = {0x00, 0x21, 0x3C, 0xAC, 0xF7, 0x38};
|
static bd_addr_t remote;
|
||||||
static uint8_t channel_nr = 0;
|
static uint8_t channel_nr = 0;
|
||||||
|
|
||||||
static uint16_t mtu;
|
static uint16_t mtu;
|
||||||
@ -115,6 +115,11 @@ static hsp_state_t hsp_state = HSP_IDLE;
|
|||||||
|
|
||||||
|
|
||||||
static hsp_ag_callback_t hsp_ag_callback;
|
static hsp_ag_callback_t hsp_ag_callback;
|
||||||
|
|
||||||
|
static void hsp_run();
|
||||||
|
static void packet_handler (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
|
||||||
|
static void handle_query_rfcomm_event(sdp_query_event_t * event, void * context);
|
||||||
|
|
||||||
static void dummy_notify(uint8_t * event, uint16_t size){}
|
static void dummy_notify(uint8_t * event, uint16_t size){}
|
||||||
|
|
||||||
void hsp_ag_register_packet_handler(hsp_ag_callback_t callback){
|
void hsp_ag_register_packet_handler(hsp_ag_callback_t callback){
|
||||||
@ -124,15 +129,16 @@ void hsp_ag_register_packet_handler(hsp_ag_callback_t callback){
|
|||||||
hsp_ag_callback = callback;
|
hsp_ag_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_ag_callback) return;
|
if (!hsp_ag_callback) return;
|
||||||
(*hsp_ag_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_ag_callback)(event, sizeof(event));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hsp_run();
|
|
||||||
static void packet_handler (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
|
|
||||||
static void handle_query_rfcomm_event(sdp_query_event_t * event, void * context);
|
|
||||||
|
|
||||||
void hsp_ag_create_service(uint8_t * service, int rfcomm_channel_nr, const char * name){
|
void hsp_ag_create_service(uint8_t * service, int rfcomm_channel_nr, const char * name){
|
||||||
uint8_t* attribute;
|
uint8_t* attribute;
|
||||||
de_create_sequence(service);
|
de_create_sequence(service);
|
||||||
@ -411,19 +417,30 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha
|
|||||||
ag_send_ok = 1;
|
ag_send_ok = 1;
|
||||||
hsp_timeout_stop();
|
hsp_timeout_stop();
|
||||||
|
|
||||||
} else if (strncmp((char *)packet, HSP_HS_AT_CKPD, 7) == 0){
|
} else if (strncmp((char *)packet, HSP_HS_MICROPHONE_GAIN, 7) == 0){
|
||||||
printf("Received AT+CKPD %s\n", HSP_HS_AT_CKPD);
|
uint8_t gain = (uint8_t)atoi((char*)&packet[8]);
|
||||||
ag_at_ckpd_received = 1;
|
|
||||||
} else if (strncmp((char *)packet, HSP_HS_MICROPHONE_GAIN, 7) == 0 ||
|
|
||||||
strncmp((char *)packet, HSP_HS_SPEAKER_GAIN, 7) == 0){
|
|
||||||
// uint8_t gain = packet[8];
|
|
||||||
// TODO: parse gain
|
|
||||||
printf("Received changed gain info %c\n", packet[8]);
|
|
||||||
ag_send_ok = 1;
|
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[8]);
|
||||||
|
ag_send_ok = 1;
|
||||||
|
emit_event(HSP_SUBEVENT_SPEAKER_GAIN_CHANGED, gain);
|
||||||
|
|
||||||
|
} else if (strncmp((char *)packet, HSP_HS_AT_CKPD, 7) == 0){
|
||||||
|
ag_at_ckpd_received = 1;
|
||||||
} else if (strncmp((char *)packet, "AT+", 3) == 0){
|
} else if (strncmp((char *)packet, "AT+", 3) == 0){
|
||||||
ag_send_error = 1;
|
ag_send_error = 1;
|
||||||
packet[size] = 0;
|
}
|
||||||
printf("Received not yet supported AT command %s...\n", (char*)packet);
|
|
||||||
|
if (ag_at_ckpd_received || 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;
|
||||||
|
event[0] = HCI_EVENT_HSP_META;
|
||||||
|
event[1] = size + 1;
|
||||||
|
event[2] = HSP_SUBEVENT_HS_COMMAND;
|
||||||
|
(*hsp_ag_callback)(event, size+3);
|
||||||
}
|
}
|
||||||
hsp_run();
|
hsp_run();
|
||||||
return;
|
return;
|
||||||
@ -436,10 +453,9 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha
|
|||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case BTSTACK_EVENT_STATE:
|
case BTSTACK_EVENT_STATE:
|
||||||
// bt stack activated, get started
|
// BTstack activated, get started
|
||||||
if (packet[2] == HCI_STATE_WORKING){
|
if (packet[2] == HCI_STATE_WORKING){
|
||||||
printf("Try to connect.\n");
|
printf("BTstack activated, get started .\n");
|
||||||
hsp_ag_connect(remote);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -495,6 +511,8 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
hsp_state = HSP_ACTIVE;
|
hsp_state = HSP_ACTIVE;
|
||||||
|
|
||||||
|
emit_event(HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -517,6 +535,7 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha
|
|||||||
if (packet[2]) {
|
if (packet[2]) {
|
||||||
printf("RFCOMM channel open failed, status %u\n", packet[2]);
|
printf("RFCOMM channel open failed, status %u\n", packet[2]);
|
||||||
hsp_ag_reset_state();
|
hsp_ag_reset_state();
|
||||||
|
emit_event(HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE, packet[2]);
|
||||||
} else {
|
} else {
|
||||||
// data: event(8) , len(8), status (8), address (48), handle (16), server channel(8), rfcomm_cid(16), max frame size(16)
|
// 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);
|
rfcomm_handle = READ_BT_16(packet, 9);
|
||||||
@ -560,6 +579,7 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha
|
|||||||
}
|
}
|
||||||
printf("RFCOMM channel closed\n");
|
printf("RFCOMM channel closed\n");
|
||||||
hsp_ag_reset_state();
|
hsp_ag_reset_state();
|
||||||
|
emit_event(HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE,0);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -588,7 +608,13 @@ static void handle_query_rfcomm_event(sdp_query_event_t * event, void * context)
|
|||||||
}
|
}
|
||||||
hsp_ag_reset_state();
|
hsp_ag_reset_state();
|
||||||
printf("Service not found, status %u.\n", ce->status);
|
printf("Service not found, status %u.\n", ce->status);
|
||||||
exit(0);
|
if (ce->status){
|
||||||
|
emit_event(HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE, ce->status);
|
||||||
|
} else {
|
||||||
|
emit_event(HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE, SDP_SERVICE_NOT_FOUND);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ void hsp_ag_create_service(uint8_t * service, int rfcomm_channel_nr, const char
|
|||||||
|
|
||||||
void hsp_ag_init(uint8_t rfcomm_channel_nr);
|
void hsp_ag_init(uint8_t rfcomm_channel_nr);
|
||||||
void hsp_ag_connect(bd_addr_t bd_addr);
|
void hsp_ag_connect(bd_addr_t bd_addr);
|
||||||
void hsp_ag_disconnect(bd_addr_t bd_addr);
|
void hsp_ag_disconnect();
|
||||||
|
|
||||||
void hsp_ag_enable_in_band_ring_tone(int enabled);
|
void hsp_ag_enable_in_band_ring_tone(int enabled);
|
||||||
|
|
||||||
|
@ -41,14 +41,24 @@
|
|||||||
//
|
//
|
||||||
// *****************************************************************************
|
// *****************************************************************************
|
||||||
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <net/if_arp.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <termios.h>
|
||||||
|
|
||||||
|
|
||||||
#include <btstack/hci_cmds.h>
|
#include <btstack/hci_cmds.h>
|
||||||
#include <btstack/run_loop.h>
|
#include <btstack/run_loop.h>
|
||||||
|
#include <btstack/sdp_util.h>
|
||||||
|
|
||||||
#include "hci.h"
|
#include "hci.h"
|
||||||
#include "l2cap.h"
|
#include "l2cap.h"
|
||||||
@ -56,12 +66,129 @@
|
|||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "hsp_ag.h"
|
#include "hsp_ag.h"
|
||||||
|
|
||||||
const uint8_t hsp_service_buffer[150];
|
static uint8_t hsp_service_buffer[150];
|
||||||
const uint8_t rfcomm_channel_nr = 1;
|
static uint8_t rfcomm_channel_nr = 1;
|
||||||
const char hsp_ag_service_name[] = "Audio Gateway Test";
|
|
||||||
|
|
||||||
|
static uint8_t ag_speaker_gain = 0;
|
||||||
|
static uint8_t ag_microphone_gain = 0;
|
||||||
|
|
||||||
|
static char hsp_ag_service_name[] = "Audio Gateway Test";
|
||||||
|
static bd_addr_t bt_speaker_addr = {0x00, 0x21, 0x3C, 0xAC, 0xF7, 0x38};
|
||||||
|
|
||||||
|
static char hs_cmd_buffer[100];
|
||||||
|
// prototypes
|
||||||
|
static void show_usage();
|
||||||
|
|
||||||
|
|
||||||
|
// Testig User Interface
|
||||||
|
static data_source_t stdin_source;
|
||||||
|
|
||||||
|
static uint8_t next_ag_microphone_gain(){
|
||||||
|
ag_microphone_gain++;
|
||||||
|
if (ag_microphone_gain > 15) ag_microphone_gain = 0;
|
||||||
|
return ag_microphone_gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t next_ag_speaker_gain(){
|
||||||
|
ag_speaker_gain++;
|
||||||
|
if (ag_speaker_gain > 15) ag_speaker_gain = 0;
|
||||||
|
return ag_speaker_gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void show_usage(){
|
||||||
|
|
||||||
|
printf("\n--- Bluetooth HSP AudioGateway Test Console ---\n");
|
||||||
|
printf("---\n");
|
||||||
|
printf("e - establish audio connection to Bluetooth Speaker\n");
|
||||||
|
printf("r - release audio connection from Bluetooth Speaker\n");
|
||||||
|
printf("m - set microphone gain\n");
|
||||||
|
printf("s - set speaker gain\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 'e':
|
||||||
|
printf("Establishing audio connection to Bluetooth Speaker %s...\n", bd_addr_to_str(bt_speaker_addr));
|
||||||
|
hsp_ag_connect(bt_speaker_addr);
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
printf("Releasing audio connection from Bluetooth Speaker %s...\n", bd_addr_to_str(bt_speaker_addr));
|
||||||
|
hsp_ag_disconnect();
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
printf("Setting microphone gain\n");
|
||||||
|
hsp_ag_set_microphone_gain(next_ag_microphone_gain());
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
printf("Setting speaker gain\n");
|
||||||
|
hsp_ag_set_speaker_gain(next_ag_speaker_gain());
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Audio Gateway routines
|
||||||
void packet_handler(uint8_t * event, uint16_t event_size){
|
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");
|
||||||
|
} 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");
|
||||||
|
} 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_HS_COMMAND:{
|
||||||
|
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);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int btstack_main(int argc, const char * argv[]){
|
int btstack_main(int argc, const char * argv[]){
|
||||||
@ -76,6 +203,8 @@ int btstack_main(int argc, const char * argv[]){
|
|||||||
hsp_ag_register_packet_handler(packet_handler);
|
hsp_ag_register_packet_handler(packet_handler);
|
||||||
// turn on!
|
// turn on!
|
||||||
hci_power_control(HCI_POWER_ON);
|
hci_power_control(HCI_POWER_ON);
|
||||||
|
|
||||||
|
setup_cli();
|
||||||
// go!
|
// go!
|
||||||
run_loop_execute();
|
run_loop_execute();
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -59,7 +59,7 @@ void hsp_hs_create_service(uint8_t * service, int rfcomm_channel_nr, const char
|
|||||||
|
|
||||||
void hsp_hs_init(uint8_t rfcomm_channel_nr);
|
void hsp_hs_init(uint8_t rfcomm_channel_nr);
|
||||||
void hsp_hs_connect(bd_addr_t bd_addr);
|
void hsp_hs_connect(bd_addr_t bd_addr);
|
||||||
void hsp_hs_disconnect(bd_addr_t bd_addr);
|
void hsp_hs_disconnect();
|
||||||
|
|
||||||
// AT+VGM=[0..15]
|
// AT+VGM=[0..15]
|
||||||
void hsp_hs_set_microphone_gain(uint8_t gain);
|
void hsp_hs_set_microphone_gain(uint8_t gain);
|
||||||
|
@ -61,7 +61,9 @@ const uint8_t hsp_service_buffer[150];
|
|||||||
const uint8_t rfcomm_channel_nr = 1;
|
const uint8_t rfcomm_channel_nr = 1;
|
||||||
const char hsp_ag_service_name[] = "Headset Test";
|
const char hsp_ag_service_name[] = "Headset Test";
|
||||||
|
|
||||||
void packet_handler(uint8_t * event, uint16_t event_size){}
|
void packet_handler(uint8_t * event, uint16_t event_size){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
int btstack_main(int argc, const char * argv[]){
|
int btstack_main(int argc, const char * argv[]){
|
||||||
// init SDP, create record for SPP and register with SDP
|
// init SDP, create record for SPP and register with SDP
|
||||||
|
@ -591,12 +591,14 @@ extern "C" {
|
|||||||
|
|
||||||
#define HCI_EVENT_HSP_META 0xE8
|
#define HCI_EVENT_HSP_META 0xE8
|
||||||
|
|
||||||
#define HSP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED 0x01
|
#define HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE 0x01
|
||||||
#define HSP_SUBEVENT_AUDIO_CONNECTION_CLOSED 0x02
|
#define HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE 0x02
|
||||||
#define HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED 0x03
|
#define HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED 0x03
|
||||||
#define HSP_SUBEVENT_SPEAKER_GAIN_CHANGED 0x04
|
#define HSP_SUBEVENT_SPEAKER_GAIN_CHANGED 0x04
|
||||||
#define HSP_SUBEVENT_COMMAND 0x05
|
#define HSP_SUBEVENT_HS_COMMAND 0x05
|
||||||
#define HSP_SUBEVENT_INDICATION 0x06
|
#define HSP_SUBEVENT_AG_INDICATION 0x06
|
||||||
|
#define HSP_SUBEVENT_ERROR 0x07
|
||||||
|
#define HSP_SUBEVENT_RING 0x08
|
||||||
|
|
||||||
|
|
||||||
// ANCS Client
|
// ANCS Client
|
||||||
@ -661,6 +663,7 @@ extern "C" {
|
|||||||
|
|
||||||
#define SDP_HANDLE_ALREADY_REGISTERED 0x80
|
#define SDP_HANDLE_ALREADY_REGISTERED 0x80
|
||||||
#define SDP_QUERY_INCOMPLETE 0x81
|
#define SDP_QUERY_INCOMPLETE 0x81
|
||||||
|
#define SDP_SERVICE_NOT_FOUND 0x82
|
||||||
|
|
||||||
#define ATT_HANDLE_VALUE_INDICATION_IN_PORGRESS 0x90
|
#define ATT_HANDLE_VALUE_INDICATION_IN_PORGRESS 0x90
|
||||||
#define ATT_HANDLE_VALUE_INDICATION_TIMEOUT 0x91
|
#define ATT_HANDLE_VALUE_INDICATION_TIMEOUT 0x91
|
||||||
|
Loading…
x
Reference in New Issue
Block a user