mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-02-13 15:41:17 +00:00
docu & api change HSP HS
This commit is contained in:
parent
ee5d6bf559
commit
4e919b3947
@ -57,6 +57,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <btstack/hci_cmds.h>
|
||||
#include <btstack/run_loop.h>
|
||||
@ -64,20 +65,35 @@
|
||||
|
||||
#include "sdp.h"
|
||||
#include "hsp_hs.h"
|
||||
#include "stdin_support.h"
|
||||
|
||||
#include "hci.h"
|
||||
#include "l2cap.h"
|
||||
#include "rfcomm.h"
|
||||
#include "debug.h"
|
||||
|
||||
#define SCO_REPORT_PERIOD 255
|
||||
|
||||
static uint32_t hsp_service_buffer[150/4]; // implicit alignment to 4-byte memory address
|
||||
static const uint8_t rfcomm_channel_nr = 1;
|
||||
static const char hsp_hs_service_name[] = "Headset Test";
|
||||
static uint16_t sco_handle = 0;
|
||||
|
||||
static char hs_cmd_buffer[100];
|
||||
// static bd_addr_t current_addr = {0x04,0x0C,0xCE,0xE4,0x85,0xD3};
|
||||
static bd_addr_t current_addr = {0x00,0x1b,0xDC,0x07,0x32,0xEF};
|
||||
|
||||
static int phase = 0;
|
||||
|
||||
// input signal: pre-computed sine wave, 160 Hz
|
||||
static const uint8_t sine[] = {
|
||||
0, 15, 31, 46, 61, 74, 86, 97, 107, 114,
|
||||
120, 124, 126, 126, 124, 120, 114, 107, 97, 86,
|
||||
74, 61, 46, 31, 15, 0, 241, 225, 210, 195,
|
||||
182, 170, 159, 149, 142, 136, 132, 130, 130, 132,
|
||||
136, 142, 149, 159, 170, 182, 195, 210, 225, 241,
|
||||
};
|
||||
|
||||
/* @section Audio Transfer Setup
|
||||
*
|
||||
* @text A pre-computed sine wave (160Hz) is used as the input audio signal. 160 Hz.
|
||||
@ -85,8 +101,8 @@ static int phase = 0;
|
||||
*
|
||||
* Tested working setups:
|
||||
* - Ubuntu 14 64-bit, CC2564B connected via FTDI USB-2-UART adapter, 921600 baud
|
||||
* - Ubuntu 14 64-bit, CSR dongle
|
||||
* - OS X 10.11, CSR dongle
|
||||
* - Ubuntu 14 64-bit, CSR USB dongle
|
||||
* - OS X 10.11, CSR USB dongle
|
||||
*
|
||||
* Broken setups:
|
||||
* - OS X 10.11, CC2564B connected via FDTI USB-2-UART adapter, 921600 baud
|
||||
@ -101,15 +117,86 @@ static int phase = 0;
|
||||
*
|
||||
*/
|
||||
|
||||
// input signal: pre-computed sine wave, 160 Hz
|
||||
static const uint8_t sine[] = {
|
||||
0, 15, 31, 46, 61, 74, 86, 97, 107, 114,
|
||||
120, 124, 126, 126, 124, 120, 114, 107, 97, 86,
|
||||
74, 61, 46, 31, 15, 0, 241, 225, 210, 195,
|
||||
182, 170, 159, 149, 142, 136, 132, 130, 130, 132,
|
||||
136, 142, 149, 159, 170, 182, 195, 210, 225, 241,
|
||||
};
|
||||
static void show_usage(void){
|
||||
uint8_t iut_address_type;
|
||||
bd_addr_t iut_address;
|
||||
hci_le_advertisement_address(&iut_address_type, iut_address);
|
||||
|
||||
printf("\n--- Bluetooth HSP Headset Test Console %s ---\n", bd_addr_to_str(iut_address));
|
||||
printf("---\n");
|
||||
printf("c - Connect to %s\n", bd_addr_to_str(current_addr));
|
||||
printf("C - Disconnect\n");
|
||||
printf("a - establish audio connection\n");
|
||||
printf("A - release audio connection\n");
|
||||
printf("b - press user button\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 'c':
|
||||
printf("Connect to %s\n", bd_addr_to_str(current_addr));
|
||||
hsp_hs_connect(current_addr);
|
||||
break;
|
||||
case 'C':
|
||||
printf("Disconnect.\n");
|
||||
hsp_hs_disconnect();
|
||||
break;
|
||||
case 'a':
|
||||
printf("Establish audio connection\n");
|
||||
hsp_hs_establish_audio_connection();
|
||||
break;
|
||||
case 'A':
|
||||
printf("Release audio connection\n");
|
||||
hsp_hs_release_audio_connection();
|
||||
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;
|
||||
case 'b':
|
||||
printf("Press user button\n");
|
||||
hsp_hs_send_button_press();
|
||||
break;
|
||||
default:
|
||||
show_usage();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void try_send_sco(void){
|
||||
if (!sco_handle) return;
|
||||
@ -137,27 +224,28 @@ static void try_send_sco(void){
|
||||
hci_send_sco_packet_buffer(sco_packet_length);
|
||||
static int count = 0;
|
||||
count++;
|
||||
if ((count & 15) == 0) printf("Sent %u\n", count);
|
||||
if ((count & SCO_REPORT_PERIOD) == 0) printf("Sent %u\n", count);
|
||||
}
|
||||
|
||||
static void sco_packet_handler(uint8_t packet_type, uint8_t * packet, uint16_t size){
|
||||
static int count = 0;
|
||||
count++;
|
||||
if ((count & 15)) return;
|
||||
if ((count & SCO_REPORT_PERIOD)) return;
|
||||
printf("SCO packets %u\n", count);
|
||||
// hexdumpf(packet, size);
|
||||
hexdumpf(packet, size);
|
||||
}
|
||||
|
||||
static void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
|
||||
// printf("Packet handler event 0x%02x\n", event[0]);
|
||||
//printf("Packet handler event 0x%02x / BTSTACK_EVENT_STATE 0x%02x\n", event[0], BTSTACK_EVENT_STATE);
|
||||
|
||||
try_send_sco();
|
||||
|
||||
switch (event[0]) {
|
||||
case BTSTACK_EVENT_STATE:
|
||||
if (event[2] != HCI_STATE_WORKING) break;
|
||||
printf("Working!\n");
|
||||
printf("HCI_STATE_WORKING\n");
|
||||
show_usage();
|
||||
break;
|
||||
case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS:
|
||||
// printf("HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS\n");
|
||||
@ -169,6 +257,20 @@ static void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
break;
|
||||
case HCI_EVENT_HSP_META:
|
||||
switch (event[2]) {
|
||||
case HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE:
|
||||
if (event[3] == 0){
|
||||
printf("RFCOMM connection established.\n");
|
||||
} else {
|
||||
printf("RFCOMM connection establishement failed.\n");
|
||||
}
|
||||
break;
|
||||
case HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE:
|
||||
if (event[3] == 0){
|
||||
printf("RFCOMM disconnected.\n");
|
||||
} else {
|
||||
printf("RFCOMM disconnection failed.\n");
|
||||
}
|
||||
break;
|
||||
case HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE:
|
||||
if (event[3] == 0){
|
||||
sco_handle = READ_BT_16(event, 4);
|
||||
@ -222,13 +324,17 @@ static void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
* - The HCI SCO packet handler receives audio data.
|
||||
* - The HSP HS packet handler is used to trigger sending of audio data and commands to the AG. It also receives the AG's answers.
|
||||
*
|
||||
* The stdin_process callback allows for sending commands to the AG.
|
||||
* At the end the Bluetooth stack is started.
|
||||
*/
|
||||
|
||||
/* LISTING_START(MainConfiguration): Setup packet handlers and audio data channel for HSP Headset */
|
||||
int btstack_main(int argc, const char * argv[]);
|
||||
int btstack_main(int argc, const char * argv[]){
|
||||
l2cap_init();
|
||||
rfcomm_init();
|
||||
sdp_init();
|
||||
|
||||
memset((uint8_t *)hsp_service_buffer, 0, sizeof(hsp_service_buffer));
|
||||
hsp_hs_create_sdp_record((uint8_t *)hsp_service_buffer, rfcomm_channel_nr, hsp_hs_service_name, 0);
|
||||
sdp_register_service_internal(NULL, (uint8_t *)hsp_service_buffer);
|
||||
@ -238,10 +344,14 @@ int btstack_main(int argc, const char * argv[]){
|
||||
hsp_hs_init(rfcomm_channel_nr);
|
||||
hsp_hs_register_packet_handler(packet_handler);
|
||||
|
||||
btstack_stdin_setup(stdin_process);
|
||||
|
||||
gap_set_local_name("BTstack HSP HS");
|
||||
hci_discoverable_control(1);
|
||||
hci_ssp_set_io_capability(SSP_IO_CAPABILITY_DISPLAY_YES_NO);
|
||||
// turn on!
|
||||
hci_set_class_of_device(0x240404);
|
||||
|
||||
hci_power_control(HCI_POWER_ON);
|
||||
|
||||
return 0;
|
||||
|
@ -623,34 +623,51 @@ extern "C" {
|
||||
* @param subevent_code
|
||||
* @param status 0 == OK
|
||||
*/
|
||||
#define HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE 0x01
|
||||
#define HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE 0x01
|
||||
|
||||
// data: event(8), len(8), subevent(8), status(8)
|
||||
/**
|
||||
* @format 11
|
||||
* @param subevent_code
|
||||
* @param status 0 == OK
|
||||
*/
|
||||
#define HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE 0x02
|
||||
|
||||
|
||||
// data: event(8), len(8), subevent(8), status(8)
|
||||
/**
|
||||
* @format 11
|
||||
* @param subevent_code
|
||||
* @param status 0 == OK
|
||||
*/
|
||||
#define HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE 0x03
|
||||
|
||||
/**
|
||||
* @format 11
|
||||
* @param subevent_code
|
||||
* @param status 0 == OK
|
||||
*/
|
||||
#define HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE 0x02
|
||||
#define HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE 0x04
|
||||
|
||||
/**
|
||||
* @format 1
|
||||
* @param subevent_code
|
||||
*/
|
||||
#define HSP_SUBEVENT_RING 0x03
|
||||
#define HSP_SUBEVENT_RING 0x05
|
||||
|
||||
/**
|
||||
* @format 11
|
||||
* @param subevent_code
|
||||
* @param gain Valid range: [0,15]
|
||||
*/
|
||||
#define HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED 0x04
|
||||
#define HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED 0x06
|
||||
|
||||
/**
|
||||
* @format 11
|
||||
* @param subevent_code
|
||||
* @param gain Valid range: [0,15]
|
||||
*/
|
||||
#define HSP_SUBEVENT_SPEAKER_GAIN_CHANGED 0x05
|
||||
#define HSP_SUBEVENT_SPEAKER_GAIN_CHANGED 0x07
|
||||
|
||||
/**
|
||||
* @format 1JV
|
||||
@ -658,7 +675,7 @@ extern "C" {
|
||||
* @param value_length
|
||||
* @param value
|
||||
*/
|
||||
#define HSP_SUBEVENT_HS_COMMAND 0x06
|
||||
#define HSP_SUBEVENT_HS_COMMAND 0x08
|
||||
|
||||
/**
|
||||
* @format 1JV
|
||||
@ -666,7 +683,7 @@ extern "C" {
|
||||
* @param value_length
|
||||
* @param value
|
||||
*/
|
||||
#define HSP_SUBEVENT_AG_INDICATION 0x07
|
||||
#define HSP_SUBEVENT_AG_INDICATION 0x09
|
||||
|
||||
|
||||
#define HCI_EVENT_HFP_META 0xE9
|
||||
|
@ -100,7 +100,7 @@ static int hfp_ag_get_ag_indicators_nr(hfp_connection_t * hfp_connection){
|
||||
return hfp_connection->ag_indicators_nr;
|
||||
}
|
||||
|
||||
hfp_ag_indicator_t * hfp_ag_get_ag_indicators(hfp_connection_t * hfp_connection){
|
||||
static hfp_ag_indicator_t * hfp_ag_get_ag_indicators(hfp_connection_t * hfp_connection){
|
||||
// TODO: save only value, and value changed in the hfp_connection?
|
||||
if (hfp_connection->ag_indicators_nr != hfp_ag_indicators_nr){
|
||||
hfp_connection->ag_indicators_nr = hfp_ag_indicators_nr;
|
||||
|
210
src/hsp_hs.c
210
src/hsp_hs.c
@ -87,22 +87,33 @@ static int hs_microphone_gain = -1;
|
||||
static int hs_speaker_gain = -1;
|
||||
|
||||
static uint8_t hs_send_button_press = 0;
|
||||
static uint8_t wait_ok = 0;
|
||||
|
||||
static uint8_t hs_support_custom_indications = 0;
|
||||
static uint8_t hs_outgoing_connection = 0;
|
||||
|
||||
static uint8_t hsp_disconnect_rfcomm = 0;
|
||||
static uint8_t hsp_establish_audio_connection = 0;
|
||||
static uint8_t hsp_release_audio_connection = 0;
|
||||
|
||||
typedef enum {
|
||||
HSP_IDLE,
|
||||
HSP_SDP_QUERY_RFCOMM_CHANNEL,
|
||||
HSP_W4_SDP_QUERY_COMPLETE,
|
||||
HSP_W4_RFCOMM_CONNECTED,
|
||||
HSP_W4_USER_ACTION,
|
||||
|
||||
HSP_RFCOMM_CONNECTION_ESTABLISHED,
|
||||
|
||||
HSP_W2_CONNECT_SCO,
|
||||
HSP_W4_SCO_CONNECTED,
|
||||
HSP_ACTIVE,
|
||||
|
||||
HSP_AUDIO_CONNECTION_ESTABLISHED,
|
||||
|
||||
HSP_W2_DISCONNECT_SCO,
|
||||
HSP_W4_SCO_DISCONNECTED,
|
||||
HSP_W4_SCO_DISCONNECTED,
|
||||
|
||||
HSP_W2_DISCONNECT_RFCOMM,
|
||||
HSP_W4_RFCOMM_DISCONNECTED,
|
||||
HSP_W4_RFCOMM_DISCONNECTED_AND_RESTART,
|
||||
HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN
|
||||
} hsp_state_t;
|
||||
|
||||
@ -156,7 +167,6 @@ static void emit_event_audio_connected(uint8_t status, uint16_t handle){
|
||||
// AG +VGM=13 [0..15] ; HS AT+VGM=6 | AG OK
|
||||
|
||||
static int hsp_hs_send_str_over_rfcomm(uint16_t cid, const char * command){
|
||||
if (!rfcomm_can_send_packet_now(rfcomm_cid)) return 1;
|
||||
int err = rfcomm_send_internal(cid, (uint8_t*) command, strlen(command));
|
||||
if (err){
|
||||
log_info("rfcomm_send_internal -> error 0X%02x", err);
|
||||
@ -248,24 +258,18 @@ void hsp_hs_create_sdp_record(uint8_t * service, int rfcomm_channel_nr, const ch
|
||||
|
||||
static void hsp_hs_reset_state(void){
|
||||
hsp_state = HSP_IDLE;
|
||||
|
||||
rfcomm_cid = 0;
|
||||
rfcomm_handle = 0;
|
||||
sco_handle = 0;
|
||||
|
||||
hs_microphone_gain = -1;
|
||||
hs_speaker_gain = -1;
|
||||
|
||||
hs_send_button_press = 0;
|
||||
wait_ok = 0;
|
||||
hs_support_custom_indications = 0;
|
||||
}
|
||||
|
||||
void hsp_hs_init(uint8_t rfcomm_channel_nr){
|
||||
// init L2CAP
|
||||
l2cap_init();
|
||||
l2cap_register_packet_handler(packet_handler);
|
||||
|
||||
rfcomm_init();
|
||||
rfcomm_register_packet_handler(packet_handler);
|
||||
rfcomm_register_service_internal(NULL, rfcomm_channel_nr, 0xffff); // reserved channel, mtu limited by l2cap
|
||||
|
||||
@ -277,27 +281,59 @@ void hsp_hs_init(uint8_t rfcomm_channel_nr){
|
||||
|
||||
void hsp_hs_connect(bd_addr_t bd_addr){
|
||||
if (hsp_state != HSP_IDLE) return;
|
||||
hs_outgoing_connection = 1;
|
||||
hsp_state = HSP_SDP_QUERY_RFCOMM_CHANNEL;
|
||||
memcpy(remote, bd_addr, 6);
|
||||
hsp_run();
|
||||
}
|
||||
|
||||
void hsp_hs_disconnect(bd_addr_t bd_addr){
|
||||
void hsp_hs_disconnect(void){
|
||||
hsp_hs_release_audio_connection();
|
||||
|
||||
if (hsp_state < HSP_W4_RFCOMM_CONNECTED){
|
||||
hsp_state = HSP_IDLE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (hsp_state == HSP_W4_RFCOMM_CONNECTED){
|
||||
hsp_state = HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN;
|
||||
return;
|
||||
}
|
||||
|
||||
if (hsp_state < HSP_W4_SCO_CONNECTED){
|
||||
hsp_state = HSP_W2_DISCONNECT_RFCOMM;
|
||||
return;
|
||||
}
|
||||
|
||||
if (hsp_state < HSP_W4_SCO_DISCONNECTED){
|
||||
hsp_state = HSP_W2_DISCONNECT_SCO;
|
||||
return;
|
||||
}
|
||||
hsp_disconnect_rfcomm = 1;
|
||||
hsp_run();
|
||||
}
|
||||
|
||||
|
||||
void hsp_hs_establish_audio_connection(void){
|
||||
switch (hsp_state){
|
||||
case HSP_ACTIVE:
|
||||
hsp_state = HSP_W4_USER_ACTION;
|
||||
hs_send_button_press = 1;
|
||||
case HSP_RFCOMM_CONNECTION_ESTABLISHED:
|
||||
hsp_establish_audio_connection = 1;
|
||||
hsp_state = HSP_W4_SCO_CONNECTED;
|
||||
break;
|
||||
case HSP_W4_RFCOMM_CONNECTED:
|
||||
hsp_state = HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
break;
|
||||
}
|
||||
hsp_run();
|
||||
}
|
||||
|
||||
void hsp_hs_release_audio_connection(void){
|
||||
if (hsp_state >= HSP_W2_DISCONNECT_SCO) return;
|
||||
if (hsp_state < HSP_AUDIO_CONNECTION_ESTABLISHED) return;
|
||||
hsp_release_audio_connection = 1;
|
||||
hsp_run();
|
||||
}
|
||||
|
||||
void hsp_hs_set_microphone_gain(uint8_t gain){
|
||||
if (gain < 0 || gain >15) {
|
||||
@ -320,14 +356,34 @@ void hsp_hs_set_speaker_gain(uint8_t gain){
|
||||
|
||||
|
||||
static void hsp_run(void){
|
||||
int err;
|
||||
if (!rfcomm_can_send_packet_now(rfcomm_cid)) return;
|
||||
if (wait_ok) return;
|
||||
|
||||
if (hsp_release_audio_connection){
|
||||
hsp_release_audio_connection = 0;
|
||||
wait_ok = 1;
|
||||
hsp_hs_send_str_over_rfcomm(rfcomm_cid, HSP_HS_AT_CKPD);
|
||||
return;
|
||||
}
|
||||
|
||||
if (hsp_disconnect_rfcomm){
|
||||
hsp_disconnect_rfcomm = 0;
|
||||
hsp_establish_audio_connection = 0;
|
||||
rfcomm_disconnect_internal(rfcomm_cid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (hsp_establish_audio_connection){
|
||||
hsp_establish_audio_connection = 0;
|
||||
wait_ok = 1;
|
||||
hsp_hs_send_str_over_rfcomm(rfcomm_cid, HSP_HS_AT_CKPD);
|
||||
return;
|
||||
}
|
||||
|
||||
if (hs_send_button_press){
|
||||
hs_send_button_press = 0;
|
||||
err = hsp_hs_send_str_over_rfcomm(rfcomm_cid, HSP_HS_AT_CKPD);
|
||||
if (err) {
|
||||
hs_send_button_press = 1;
|
||||
}
|
||||
wait_ok = 1;
|
||||
hsp_hs_send_str_over_rfcomm(rfcomm_cid, HSP_HS_AT_CKPD);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -337,40 +393,27 @@ static void hsp_run(void){
|
||||
sdp_query_rfcomm_channel_and_name_for_uuid(remote, SDP_Headset_AG);
|
||||
break;
|
||||
|
||||
case HSP_W2_CONNECT_SCO:
|
||||
hsp_state = HSP_W4_SCO_CONNECTED;
|
||||
break;
|
||||
|
||||
case HSP_W2_DISCONNECT_SCO:
|
||||
hsp_state = HSP_W4_SCO_DISCONNECTED;
|
||||
break;
|
||||
case HSP_AUDIO_CONNECTION_ESTABLISHED:
|
||||
case HSP_RFCOMM_CONNECTION_ESTABLISHED :
|
||||
|
||||
case HSP_ACTIVE:
|
||||
|
||||
if (hs_microphone_gain >= 0){
|
||||
int gain = hs_microphone_gain;
|
||||
hs_microphone_gain = -1;
|
||||
if (hs_microphone_gain >= 0){
|
||||
char buffer[20];
|
||||
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;
|
||||
}
|
||||
sprintf(buffer, "%s=%d\r\n", HSP_HS_MICROPHONE_GAIN, hs_microphone_gain);
|
||||
hsp_hs_send_str_over_rfcomm(rfcomm_cid, buffer);
|
||||
hs_microphone_gain = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (hs_speaker_gain >= 0){
|
||||
int gain = hs_speaker_gain;
|
||||
hs_speaker_gain = -1;
|
||||
char buffer[20];
|
||||
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;
|
||||
}
|
||||
sprintf(buffer, "%s=%d\r\n", HSP_HS_SPEAKER_GAIN, hs_speaker_gain);
|
||||
hsp_hs_send_str_over_rfcomm(rfcomm_cid, buffer);
|
||||
hs_speaker_gain = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case HSP_W4_RFCOMM_DISCONNECTED:
|
||||
rfcomm_disconnect_internal(rfcomm_cid);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -379,7 +422,7 @@ static void hsp_run(void){
|
||||
|
||||
|
||||
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]);
|
||||
//printf("packet_handler type %u, packet[0] %x\n", packet_type, packet[0]);
|
||||
if (packet_type == RFCOMM_DATA_PACKET){
|
||||
// skip over leading newline
|
||||
while (size > 0 && (packet[0] == '\n' || packet[0] == '\r')){
|
||||
@ -389,16 +432,7 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha
|
||||
if (strncmp((char *)packet, HSP_AG_RING, strlen(HSP_AG_RING)) == 0){
|
||||
emit_ring_event();
|
||||
} else if (strncmp((char *)packet, HSP_AG_OK, strlen(HSP_AG_OK)) == 0){
|
||||
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;
|
||||
}
|
||||
wait_ok = 0;
|
||||
} 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);
|
||||
@ -433,6 +467,7 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha
|
||||
|
||||
switch (event) {
|
||||
case HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE:{
|
||||
if (hsp_state < HSP_RFCOMM_CONNECTION_ESTABLISHED) return;
|
||||
int index = 2;
|
||||
uint8_t status = packet[index++];
|
||||
sco_handle = READ_BT_16(packet, index);
|
||||
@ -452,8 +487,10 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha
|
||||
if (status != 0){
|
||||
log_error("(e)SCO Connection failed, status %u", status);
|
||||
emit_event_audio_connected(status, sco_handle);
|
||||
hsp_state = HSP_RFCOMM_CONNECTION_ESTABLISHED ;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (link_type){
|
||||
case 0x00:
|
||||
log_info("SCO Connection established.");
|
||||
@ -473,16 +510,11 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha
|
||||
" rx_packet_length %u bytes, tx_packet_length %u bytes, air_mode 0x%2x (0x02 == CVSD)", sco_handle,
|
||||
bd_addr_to_str(address), transmission_interval, retransmission_interval, rx_packet_length, tx_packet_length, air_mode);
|
||||
|
||||
if (hsp_state == HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN){
|
||||
hsp_state = HSP_W2_DISCONNECT_SCO;
|
||||
break;
|
||||
}
|
||||
|
||||
// forward event to app
|
||||
hsp_hs_callback(packet, size);
|
||||
|
||||
hsp_state = HSP_ACTIVE;
|
||||
emit_event_audio_connected(0, sco_handle);
|
||||
hsp_state = HSP_AUDIO_CONNECTION_ESTABLISHED;
|
||||
emit_event_audio_connected(status, sco_handle);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -493,43 +525,29 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha
|
||||
bt_flip_addr(event_addr, &packet[2]);
|
||||
rfcomm_cid = READ_BT_16(packet, 9);
|
||||
log_info("RFCOMM channel %u requested for %s", packet[8], bd_addr_to_str(event_addr));
|
||||
rfcomm_accept_connection_internal(rfcomm_cid);
|
||||
|
||||
hsp_state = HSP_W4_RFCOMM_CONNECTED;
|
||||
rfcomm_accept_connection_internal(rfcomm_cid);
|
||||
break;
|
||||
|
||||
case RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE:
|
||||
// printf("RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE packet_handler type %u, packet[0] %x\n", packet_type, packet[0]);
|
||||
// data: event(8), len(8), status (8), address (48), handle(16), server channel(8), rfcomm_cid(16), max frame size(16)
|
||||
if (hsp_state != HSP_W4_RFCOMM_CONNECTED) return;
|
||||
if (packet[2]) {
|
||||
log_info("RFCOMM channel open failed, status %u", packet[2]);
|
||||
hsp_state = HSP_IDLE;
|
||||
hsp_hs_reset_state();
|
||||
emit_event(HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE, packet[2]);
|
||||
hs_outgoing_connection = 0;
|
||||
} 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);
|
||||
rfcomm_cid = READ_BT_16(packet, 12);
|
||||
mtu = READ_BT_16(packet, 14);
|
||||
log_info("RFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u", rfcomm_cid, mtu);
|
||||
|
||||
if (hs_outgoing_connection){
|
||||
hs_outgoing_connection = 0;
|
||||
hs_send_button_press = 1;
|
||||
}
|
||||
|
||||
switch (hsp_state){
|
||||
case HSP_W4_RFCOMM_CONNECTED:
|
||||
hsp_state = HSP_W2_CONNECT_SCO;
|
||||
break;
|
||||
case HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN:
|
||||
hsp_state = HSP_W2_DISCONNECT_RFCOMM;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
log_info("RFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u, handle %02x", rfcomm_cid, mtu, rfcomm_handle);
|
||||
hsp_state = HSP_RFCOMM_CONNECTION_ESTABLISHED;
|
||||
}
|
||||
emit_event(HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE, packet[2]);
|
||||
break;
|
||||
case BTSTACK_EVENT_STATE:
|
||||
case DAEMON_EVENT_HCI_PACKET_SENT:
|
||||
case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS:
|
||||
case RFCOMM_EVENT_CREDITS:
|
||||
@ -540,13 +558,21 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha
|
||||
handle = READ_BT_16(packet,3);
|
||||
if (handle == sco_handle){
|
||||
sco_handle = 0;
|
||||
hsp_state = HSP_W2_DISCONNECT_RFCOMM;
|
||||
hsp_state = HSP_RFCOMM_CONNECTION_ESTABLISHED ;
|
||||
hsp_hs_reset_state();
|
||||
emit_event(HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE,0);
|
||||
break;
|
||||
}
|
||||
if (handle == rfcomm_handle) {
|
||||
rfcomm_handle = 0;
|
||||
hsp_state = HSP_IDLE;
|
||||
hsp_hs_callback(packet, size);
|
||||
hsp_hs_reset_state();
|
||||
}
|
||||
break;
|
||||
case RFCOMM_EVENT_CHANNEL_CLOSED:
|
||||
hsp_hs_reset_state();
|
||||
emit_event(HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE,0);
|
||||
hsp_hs_callback(packet, size);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -569,18 +595,18 @@ static void handle_query_rfcomm_event(sdp_query_event_t * event, void * context)
|
||||
|
||||
if (channel_nr > 0){
|
||||
hsp_state = HSP_W4_RFCOMM_CONNECTED;
|
||||
log_info("RFCOMM create channel.log_info");
|
||||
log_info("HSP: SDP_QUERY_COMPLETE. RFCOMM create channel, addr %s, rfcomm channel nr %d", bd_addr_to_str(remote), channel_nr);
|
||||
rfcomm_create_channel_internal(NULL, remote, channel_nr);
|
||||
break;
|
||||
}
|
||||
hsp_hs_reset_state();
|
||||
log_info("Service not found, status %u.", ce->status);
|
||||
exit(0);
|
||||
log_info("Service not fou nd, status %u.", ce->status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void hsp_hs_send_button_press(void){
|
||||
if (hsp_state < HSP_RFCOMM_CONNECTION_ESTABLISHED || hsp_state >= HSP_W4_RFCOMM_DISCONNECTED) return;
|
||||
hs_send_button_press = 1;
|
||||
hsp_run();
|
||||
}
|
||||
|
28
src/hsp_hs.h
28
src/hsp_hs.h
@ -110,7 +110,27 @@ void hsp_hs_connect(bd_addr_t bd_addr);
|
||||
* Releases the RFCOMM channel.
|
||||
* @param bd_addr
|
||||
*/
|
||||
void hsp_hs_disconnect(bd_addr_t bd_addr);
|
||||
void hsp_hs_disconnect(void);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send button press action. Toggle establish/release of audio connection.
|
||||
*/
|
||||
void hsp_hs_send_button_press(void);
|
||||
|
||||
/**
|
||||
* @brief Triger establishing audio connection.
|
||||
*
|
||||
* @param bd_addr
|
||||
*/
|
||||
void hsp_hs_establish_audio_connection(void);
|
||||
|
||||
/**
|
||||
* @brief Trigger releasing audio connection.
|
||||
*
|
||||
* @param bd_addr
|
||||
*/
|
||||
void hsp_hs_release_audio_connection(void);
|
||||
|
||||
/**
|
||||
* @brief Set microphone gain.
|
||||
@ -130,11 +150,7 @@ void hsp_hs_set_microphone_gain(uint8_t gain);
|
||||
*/
|
||||
void hsp_hs_set_speaker_gain(uint8_t gain);
|
||||
|
||||
/**
|
||||
* @brief Send button press action.
|
||||
* @param gain Valid range: [0,15]
|
||||
*/
|
||||
void hsp_hs_send_button_press(void);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Enable custom indications.
|
||||
|
@ -175,7 +175,7 @@ static int stdin_process(struct data_source *ds){
|
||||
break;
|
||||
case 'd':
|
||||
printf("Releasing audio connection.\n");
|
||||
hsp_hs_disconnect(current_addr);
|
||||
hsp_hs_disconnect();
|
||||
break;
|
||||
case 'z':
|
||||
printf("Setting microphone gain 0\n");
|
||||
@ -245,8 +245,6 @@ static void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
case BTSTACK_EVENT_STATE:
|
||||
if (event[2] != HCI_STATE_WORKING) break;
|
||||
show_usage();
|
||||
// request loopback mode
|
||||
hci_send_cmd(&hci_write_synchronous_flow_control_enable, 1);
|
||||
break;
|
||||
case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS:
|
||||
// printf("HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS\n");
|
||||
|
Loading…
x
Reference in New Issue
Block a user