mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-25 16:43:28 +00:00
Merge branch 'master' into develop
This commit is contained in:
commit
0f78faa83f
@ -1,4 +1,5 @@
|
||||
**_Note: Major API Changes. For older projects, you may use the [v0.9 branch](https://github.com/bluekitchen/btstack/tree/v0.9)_**
|
||||
**_Note: Major API Changes. For older projects, you may use the [v0.9 branch](https://github.com/bluekitchen/btstack/tree/v0.9).
|
||||
Please see [Migration notes](https://github.com/bluekitchen/btstack/blob/master/doc/manual/docs/appendix/migration.md)_**
|
||||
|
||||
# Welcome to BTstack
|
||||
|
||||
@ -26,8 +27,8 @@ It has been qualified with the the Bluetooth SIG for GAP, IOP, HFP, HSP, SPP, PA
|
||||
GATT, SM of the Bluetooth 4.2 LE Central and Peripheral roles (QD ID 25340).
|
||||
|
||||
## Documentation
|
||||
- [HTML](http://bluekitchen-gmbh.com/btstack/v1.0)
|
||||
- [PDF](http://bluekitchen-gmbh.com/btstack_v1.0.pdf)
|
||||
- [HTML](http://bluekitchen-gmbh.com/btstack)
|
||||
- [PDF](http://bluekitchen-gmbh.com/btstack.pdf)
|
||||
|
||||
## Supported Protocols
|
||||
* L2CAP
|
||||
|
@ -61,14 +61,29 @@
|
||||
#endif
|
||||
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
uint8_t hfp_service_buffer[150];
|
||||
const uint8_t rfcomm_channel_nr = 1;
|
||||
const char hfp_ag_service_name[] = "BTstack HFP AG Test";
|
||||
|
||||
static bd_addr_t device_addr = {0x00,0x15,0x83,0x5F,0x9D,0x46};
|
||||
// PTS
|
||||
// static bd_addr_t device_addr = {0x00,0x15,0x83,0x5F,0x9D,0x46};
|
||||
// BT-201
|
||||
static bd_addr_t device_addr = {0x00, 0x07, 0xB0, 0x83, 0x02, 0x5E};
|
||||
|
||||
static uint8_t codecs[1] = {HFP_CODEC_CVSD};
|
||||
static uint16_t handle = -1;
|
||||
static hci_con_handle_t sco_handle;
|
||||
static int memory_1_enabled = 1;
|
||||
|
||||
static int ag_indicators_nr = 7;
|
||||
@ -189,7 +204,7 @@ static void inquiry_packet_handler (uint8_t packet_type, uint8_t *packet, uint16
|
||||
numResponses = hci_event_inquiry_result_get_num_responses(packet);
|
||||
int offset = 3;
|
||||
for (i=0; i<numResponses && deviceCount < MAX_DEVICES;i++){
|
||||
reverse_bd_addr(addr, &packet[offset]);
|
||||
reverse_bd_addr(&packet[offset], addr);
|
||||
offset += 6;
|
||||
index = getDeviceIndexForAddress(addr);
|
||||
if (index >= 0) continue; // already in our list
|
||||
@ -234,7 +249,7 @@ static void inquiry_packet_handler (uint8_t packet_type, uint8_t *packet, uint16
|
||||
break;
|
||||
|
||||
case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE:
|
||||
reverse_bd_addr(addr, &packet[3]);
|
||||
reverse_bd_addr(&packet[3], addr);
|
||||
index = getDeviceIndexForAddress(addr);
|
||||
if (index >= 0) {
|
||||
if (packet[2] == 0) {
|
||||
@ -259,10 +274,13 @@ static void show_usage(void);
|
||||
|
||||
// Testig User Interface
|
||||
static void show_usage(void){
|
||||
printf("\n--- Bluetooth HFP Audiogateway (AG) unit Test Console ---\n");
|
||||
bd_addr_t iut_address;
|
||||
gap_local_bd_addr(iut_address);
|
||||
|
||||
printf("\n--- Bluetooth HFP Audiogateway (AG) unit Test Console %s ---\n", bd_addr_to_str(iut_address));
|
||||
printf("---\n");
|
||||
|
||||
printf("a - establish HFP connection to PTS module\n");
|
||||
printf("a - establish HFP connection to PTS module %s\n", bd_addr_to_str(device_addr));
|
||||
// printf("A - release HFP connection to PTS module\n");
|
||||
|
||||
printf("b - establish AUDIO connection\n");
|
||||
@ -514,7 +532,7 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac
|
||||
break;
|
||||
case 't':
|
||||
log_info("USER:\'%c\'", cmd);
|
||||
printf("Terminate HCI connection.\n");
|
||||
printf("Terminate HCI connection. 0x%2x\n", handle);
|
||||
gap_disconnect(handle);
|
||||
break;
|
||||
case 'u':
|
||||
@ -547,77 +565,122 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac
|
||||
}
|
||||
#endif
|
||||
|
||||
static void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
switch (event[0]){
|
||||
case HCI_EVENT_INQUIRY_RESULT:
|
||||
case HCI_EVENT_INQUIRY_RESULT_WITH_RSSI:
|
||||
case HCI_EVENT_INQUIRY_COMPLETE:
|
||||
case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE:
|
||||
inquiry_packet_handler(HCI_EVENT_PACKET, event, event_size);
|
||||
break;
|
||||
#define SCO_REPORT_PERIOD 100
|
||||
static void send_sco_data(void){
|
||||
if (!sco_handle) return;
|
||||
|
||||
const int sco_packet_length = hci_get_sco_packet_length();
|
||||
const int sco_payload_length = sco_packet_length - 3;
|
||||
const int frames_per_packet = sco_payload_length; // for 8-bit data. for 16-bit data it's /2
|
||||
|
||||
default:
|
||||
break;
|
||||
hci_reserve_packet_buffer();
|
||||
uint8_t * sco_packet = hci_get_outgoing_packet_buffer();
|
||||
// set handle + flags
|
||||
little_endian_store_16(sco_packet, 0, sco_handle);
|
||||
// set len
|
||||
sco_packet[2] = sco_payload_length;
|
||||
int i;
|
||||
for (i=0;i<frames_per_packet;i++){
|
||||
sco_packet[3+i] = sine[phase];
|
||||
phase++;
|
||||
if (phase >= sizeof(sine)) phase = 0;
|
||||
}
|
||||
hci_send_sco_packet_buffer(sco_packet_length);
|
||||
|
||||
// request another send event
|
||||
hci_request_sco_can_send_now_event();
|
||||
|
||||
if (event[0] != HCI_EVENT_HFP_META) return;
|
||||
static int count = 0;
|
||||
count++;
|
||||
if ((count % SCO_REPORT_PERIOD) == 0) printf("Sent %u\n", count);
|
||||
}
|
||||
|
||||
if (event[3]
|
||||
&& event[2] != HFP_SUBEVENT_PLACE_CALL_WITH_NUMBER
|
||||
&& event[2] != HFP_SUBEVENT_ATTACH_NUMBER_TO_VOICE_TAG
|
||||
&& event[2] != HFP_SUBEVENT_TRANSMIT_DTMF_CODES){
|
||||
printf("ERROR, status: %u\n", event[3]);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event[2]) {
|
||||
case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
|
||||
handle = hfp_subevent_service_level_connection_established_get_con_handle(event);
|
||||
printf("Service level connection established.\n");
|
||||
break;
|
||||
case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED:
|
||||
printf("Service level connection released.\n");
|
||||
break;
|
||||
case HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED:
|
||||
printf("\n** Audio connection established **\n");
|
||||
break;
|
||||
case HFP_SUBEVENT_AUDIO_CONNECTION_RELEASED:
|
||||
printf("\n** Audio connection released **\n");
|
||||
break;
|
||||
case HFP_SUBEVENT_START_RINGINIG:
|
||||
printf("\n** Start Ringing **\n");
|
||||
break;
|
||||
case HFP_SUBEVENT_STOP_RINGINIG:
|
||||
printf("\n** Stop Ringing **\n");
|
||||
break;
|
||||
case HFP_SUBEVENT_PLACE_CALL_WITH_NUMBER:
|
||||
printf("\n** Outgoing call '%s' **\n", hfp_subevent_place_call_with_number_get_number(event));
|
||||
// validate number
|
||||
if ( strcmp("1234567", hfp_subevent_place_call_with_number_get_number(event)) == 0
|
||||
|| strcmp("7654321", hfp_subevent_place_call_with_number_get_number(event)) == 0
|
||||
|| (memory_1_enabled && strcmp(">1", hfp_subevent_place_call_with_number_get_number(event)) == 0)){
|
||||
printf("Dialstring valid: accept call\n");
|
||||
hfp_ag_outgoing_call_accepted();
|
||||
} else {
|
||||
printf("Dialstring invalid: reject call\n");
|
||||
hfp_ag_outgoing_call_rejected();
|
||||
static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t event_size){
|
||||
switch (packet_type){
|
||||
case HCI_EVENT_PACKET:
|
||||
switch (event[0]){
|
||||
case HCI_EVENT_INQUIRY_RESULT:
|
||||
case HCI_EVENT_INQUIRY_RESULT_WITH_RSSI:
|
||||
case HCI_EVENT_INQUIRY_COMPLETE:
|
||||
case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE:
|
||||
inquiry_packet_handler(HCI_EVENT_PACKET, event, event_size);
|
||||
break;
|
||||
case HCI_EVENT_SCO_CAN_SEND_NOW:
|
||||
send_sco_data();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (event[0] != HCI_EVENT_HFP_META) return;
|
||||
|
||||
if (event[3]
|
||||
&& event[2] != HFP_SUBEVENT_PLACE_CALL_WITH_NUMBER
|
||||
&& event[2] != HFP_SUBEVENT_ATTACH_NUMBER_TO_VOICE_TAG
|
||||
&& event[2] != HFP_SUBEVENT_TRANSMIT_DTMF_CODES){
|
||||
printf("ERROR, status: %u\n", event[3]);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event[2]) {
|
||||
case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
|
||||
handle = hfp_subevent_service_level_connection_established_get_con_handle(event);
|
||||
printf("Service level connection established.\n");
|
||||
break;
|
||||
case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED:
|
||||
printf("Service level connection released.\n");
|
||||
sco_handle = 0;
|
||||
break;
|
||||
case HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED:
|
||||
if (hfp_subevent_audio_connection_established_get_status(event)){
|
||||
printf("Audio connection establishment failed with status %u\n", hfp_subevent_audio_connection_established_get_status(event));
|
||||
sco_handle = 0;
|
||||
} else {
|
||||
sco_handle = hfp_subevent_audio_connection_established_get_handle(event);
|
||||
printf("Audio connection established with SCO handle 0x%04x.\n", sco_handle);
|
||||
hci_request_sco_can_send_now_event();
|
||||
}
|
||||
break;
|
||||
case HFP_SUBEVENT_AUDIO_CONNECTION_RELEASED:
|
||||
printf("\n** Audio connection released **\n");
|
||||
sco_handle = 0;
|
||||
break;
|
||||
case HFP_SUBEVENT_START_RINGINIG:
|
||||
printf("\n** Start Ringing **\n");
|
||||
break;
|
||||
case HFP_SUBEVENT_STOP_RINGINIG:
|
||||
printf("\n** Stop Ringing **\n");
|
||||
break;
|
||||
case HFP_SUBEVENT_PLACE_CALL_WITH_NUMBER:
|
||||
printf("\n** Outgoing call '%s' **\n", hfp_subevent_place_call_with_number_get_number(event));
|
||||
// validate number
|
||||
if ( strcmp("1234567", hfp_subevent_place_call_with_number_get_number(event)) == 0
|
||||
|| strcmp("7654321", hfp_subevent_place_call_with_number_get_number(event)) == 0
|
||||
|| (memory_1_enabled && strcmp(">1", hfp_subevent_place_call_with_number_get_number(event)) == 0)){
|
||||
printf("Dialstring valid: accept call\n");
|
||||
hfp_ag_outgoing_call_accepted();
|
||||
} else {
|
||||
printf("Dialstring invalid: reject call\n");
|
||||
hfp_ag_outgoing_call_rejected();
|
||||
}
|
||||
break;
|
||||
|
||||
case HFP_SUBEVENT_ATTACH_NUMBER_TO_VOICE_TAG:
|
||||
printf("\n** Attach number to voice tag. Sending '1234567\n");
|
||||
hfp_ag_send_phone_number_for_voice_tag(device_addr, "1234567");
|
||||
break;
|
||||
case HFP_SUBEVENT_TRANSMIT_DTMF_CODES:
|
||||
printf("\n** Send DTMF Codes: '%s'\n", hfp_subevent_transmit_dtmf_codes_get_dtmf(event));
|
||||
hfp_ag_send_dtmf_code_done(device_addr);
|
||||
break;
|
||||
case HFP_SUBEVENT_CALL_ANSWERED:
|
||||
printf("Call answered by HF\n");
|
||||
break;
|
||||
default:
|
||||
printf("Event not handled %u\n", event[2]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case HFP_SUBEVENT_ATTACH_NUMBER_TO_VOICE_TAG:
|
||||
printf("\n** Attach number to voice tag. Sending '1234567\n");
|
||||
hfp_ag_send_phone_number_for_voice_tag(device_addr, "1234567");
|
||||
break;
|
||||
case HFP_SUBEVENT_TRANSMIT_DTMF_CODES:
|
||||
printf("\n** Send DTMF Codes: '%s'\n", hfp_subevent_transmit_dtmf_codes_get_dtmf(event));
|
||||
hfp_ag_send_dtmf_code_done(device_addr);
|
||||
break;
|
||||
case HFP_SUBEVENT_CALL_ANSWERED:
|
||||
printf("Call answered by HF\n");
|
||||
break;
|
||||
default:
|
||||
printf("Event not handled %u\n", event[2]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -639,22 +702,26 @@ static hfp_phone_number_t subscriber_number = {
|
||||
|
||||
int btstack_main(int argc, const char * argv[]);
|
||||
int btstack_main(int argc, const char * argv[]){
|
||||
// HFP HS address is hardcoded, please change it
|
||||
// init L2CAP
|
||||
l2cap_init();
|
||||
rfcomm_init();
|
||||
sdp_init();
|
||||
|
||||
gap_discoverable_control(1);
|
||||
|
||||
// L2CAP
|
||||
l2cap_init();
|
||||
|
||||
// HFP
|
||||
rfcomm_init();
|
||||
hfp_ag_init(rfcomm_channel_nr);
|
||||
hfp_ag_init_supported_features(0x3ef | (1<<HFP_AGSF_HF_INDICATORS) | (1<<HFP_AGSF_ESCO_S4));
|
||||
hfp_ag_init_codecs(sizeof(codecs), codecs);
|
||||
hfp_ag_init_ag_indicators(ag_indicators_nr, ag_indicators);
|
||||
hfp_ag_init_hf_indicators(hf_indicators_nr, hf_indicators);
|
||||
hfp_ag_init_call_hold_services(call_hold_services_nr, call_hold_services);
|
||||
|
||||
hfp_ag_set_subcriber_number_information(&subscriber_number, 1);
|
||||
hfp_ag_register_packet_handler(packet_handler);
|
||||
hfp_ag_register_packet_handler(&packet_handler);
|
||||
hci_register_sco_packet_handler(&packet_handler);
|
||||
|
||||
// SDP Server
|
||||
sdp_init();
|
||||
memset(hfp_service_buffer, 0, sizeof(hfp_service_buffer));
|
||||
hfp_ag_create_sdp_record( hfp_service_buffer, 0x10001, rfcomm_channel_nr, hfp_ag_service_name, 0, 0);
|
||||
printf("SDP service record size: %u\n", de_get_len( hfp_service_buffer));
|
||||
|
@ -85,7 +85,7 @@ static void show_usage(void){
|
||||
printf("\n--- Bluetooth HFP Hands-Free (HF) unit Test Console ---\n");
|
||||
printf("---\n");
|
||||
|
||||
printf("a - establish SLC connection to device\n");
|
||||
printf("a - establish SLC connection to device %s\n", bd_addr_to_str(device_addr));
|
||||
printf("A - release SLC connection to device\n");
|
||||
|
||||
printf("b - establish Audio connection\n");
|
||||
@ -444,7 +444,7 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac
|
||||
}
|
||||
#endif
|
||||
|
||||
static void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t event_size){
|
||||
if (event[0] != HCI_EVENT_HFP_META) return;
|
||||
|
||||
switch (event[2]) {
|
||||
|
@ -215,77 +215,84 @@ static void send_sco_data(void){
|
||||
hci_request_sco_can_send_now_event();
|
||||
|
||||
static int count = 0;
|
||||
count++;
|
||||
if ((count & SCO_REPORT_PERIOD) == 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){
|
||||
return;
|
||||
static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t event_size){
|
||||
|
||||
static int count = 0;
|
||||
count++;
|
||||
if ((count & SCO_REPORT_PERIOD)) return;
|
||||
printf("SCO packets %u\n", count);
|
||||
}
|
||||
|
||||
static void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
switch (event[0]) {
|
||||
case BTSTACK_EVENT_STATE:
|
||||
if (event[2] != HCI_STATE_WORKING) break;
|
||||
show_usage();
|
||||
switch (packet_type){
|
||||
|
||||
case HCI_SCO_DATA_PACKET:
|
||||
count++;
|
||||
if ((count & SCO_REPORT_PERIOD)) return;
|
||||
printf("SCO packets received: %u\n", count);
|
||||
break;
|
||||
case HCI_EVENT_SCO_CAN_SEND_NOW:
|
||||
send_sco_data();
|
||||
break;
|
||||
case HCI_EVENT_HSP_META:
|
||||
switch (event[2]) {
|
||||
case HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE:
|
||||
if (hsp_subevent_rfcomm_connection_complete_get_status(event)){
|
||||
printf("RFCOMM connection establishement failed with status %u\n", hsp_subevent_audio_connection_complete_get_handle(event));
|
||||
} else {
|
||||
printf("RFCOMM connection established.\n");
|
||||
}
|
||||
|
||||
case HCI_EVENT_PACKET:
|
||||
switch (event[0]) {
|
||||
case BTSTACK_EVENT_STATE:
|
||||
if (event[2] != HCI_STATE_WORKING) break;
|
||||
show_usage();
|
||||
break;
|
||||
case HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE:
|
||||
if (hsp_subevent_rfcomm_disconnection_complete_get_status(event)){
|
||||
printf("RFCOMM disconnection failed with status %u.\n", hsp_subevent_rfcomm_disconnection_complete_get_status(event));
|
||||
} else {
|
||||
printf("RFCOMM disconnected.\n");
|
||||
case HCI_EVENT_SCO_CAN_SEND_NOW:
|
||||
send_sco_data();
|
||||
break;
|
||||
case HCI_EVENT_HSP_META:
|
||||
switch (event[2]) {
|
||||
case HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE:
|
||||
if (hsp_subevent_rfcomm_connection_complete_get_status(event)){
|
||||
printf("RFCOMM connection establishement failed with status %u\n", hsp_subevent_rfcomm_connection_complete_get_status(event));
|
||||
} else {
|
||||
printf("RFCOMM connection established.\n");
|
||||
}
|
||||
break;
|
||||
case HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE:
|
||||
if (hsp_subevent_rfcomm_disconnection_complete_get_status(event)){
|
||||
printf("RFCOMM disconnection failed with status %u.\n", hsp_subevent_rfcomm_disconnection_complete_get_status(event));
|
||||
} else {
|
||||
printf("RFCOMM disconnected.\n");
|
||||
}
|
||||
break;
|
||||
case HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE:
|
||||
if (hsp_subevent_audio_connection_complete_get_status(event)){
|
||||
printf("Audio connection establishment failed with status %u\n", hsp_subevent_audio_connection_complete_get_status(event));
|
||||
sco_handle = 0;
|
||||
} else {
|
||||
sco_handle = hsp_subevent_audio_connection_complete_get_handle(event);
|
||||
printf("Audio connection established with SCO handle 0x%04x.\n", sco_handle);
|
||||
hci_request_sco_can_send_now_event();
|
||||
}
|
||||
break;
|
||||
case HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE:
|
||||
if (hsp_subevent_audio_disconnection_complete_get_status(event)){
|
||||
printf("Audio connection releasing failed with status %u\n", hsp_subevent_audio_disconnection_complete_get_status(event));
|
||||
} else {
|
||||
printf("Audio connection released.\n\n");
|
||||
sco_handle = 0;
|
||||
}
|
||||
break;
|
||||
case HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED:
|
||||
printf("Received microphone gain change %d\n", hsp_subevent_microphone_gain_changed_get_gain(event));
|
||||
break;
|
||||
case HSP_SUBEVENT_SPEAKER_GAIN_CHANGED:
|
||||
printf("Received speaker gain change %d\n", hsp_subevent_speaker_gain_changed_get_gain(event));
|
||||
break;
|
||||
case HSP_SUBEVENT_HS_COMMAND:{
|
||||
memset(hs_cmd_buffer, 0, sizeof(hs_cmd_buffer));
|
||||
int cmd_length = hsp_subevent_hs_command_get_value_length(event);
|
||||
int size = cmd_length <= sizeof(hs_cmd_buffer)? cmd_length : sizeof(hs_cmd_buffer);
|
||||
memcpy(hs_cmd_buffer, hsp_subevent_hs_command_get_value(event), size - 1);
|
||||
printf("Received custom command: \"%s\". \nExit code or call hsp_ag_send_result.\n", hs_cmd_buffer);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("event not handled %u\n", event[2]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE:
|
||||
if (hsp_subevent_audio_connection_complete_get_status(event)){
|
||||
printf("Audio connection establishment failed with status %u\n", hsp_subevent_audio_connection_complete_get_status(event));
|
||||
sco_handle = 0;
|
||||
} else {
|
||||
sco_handle = hsp_subevent_audio_connection_complete_get_handle(event);
|
||||
printf("Audio connection established with SCO handle 0x%04x.\n", sco_handle);
|
||||
hci_request_sco_can_send_now_event();
|
||||
}
|
||||
break;
|
||||
case HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE:
|
||||
if (hsp_subevent_audio_disconnection_complete_get_status(event)){
|
||||
printf("Audio connection releasing failed with status %u\n", hsp_subevent_audio_disconnection_complete_get_status(event));
|
||||
} else {
|
||||
printf("Audio connection released.\n\n");
|
||||
sco_handle = 0;
|
||||
}
|
||||
break;
|
||||
case HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED:
|
||||
printf("Received microphone gain change %d\n", hsp_subevent_microphone_gain_changed_get_gain(event));
|
||||
break;
|
||||
case HSP_SUBEVENT_SPEAKER_GAIN_CHANGED:
|
||||
printf("Received speaker gain change %d\n", hsp_subevent_speaker_gain_changed_get_gain(event));
|
||||
break;
|
||||
case HSP_SUBEVENT_HS_COMMAND:{
|
||||
memset(hs_cmd_buffer, 0, sizeof(hs_cmd_buffer));
|
||||
int cmd_length = hsp_subevent_hs_command_get_value_length(event);
|
||||
int size = cmd_length <= sizeof(hs_cmd_buffer)? cmd_length : sizeof(hs_cmd_buffer);
|
||||
memcpy(hs_cmd_buffer, hsp_subevent_hs_command_get_value(event), size - 1);
|
||||
printf("Received custom command: \"%s\". \nExit code or call hsp_ag_send_result.\n", hs_cmd_buffer);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("event not handled %u\n", event[2]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -312,8 +319,6 @@ static 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[]){
|
||||
|
||||
hci_register_sco_packet_handler(&sco_packet_handler);
|
||||
|
||||
l2cap_init();
|
||||
|
||||
sdp_init();
|
||||
@ -326,7 +331,8 @@ int btstack_main(int argc, const char * argv[]){
|
||||
rfcomm_init();
|
||||
|
||||
hsp_ag_init(rfcomm_channel_nr);
|
||||
hsp_ag_register_packet_handler(packet_handler);
|
||||
hsp_ag_register_packet_handler(&packet_handler);
|
||||
hci_register_sco_packet_handler(&packet_handler);
|
||||
|
||||
#ifdef HAVE_POSIX_STDIN
|
||||
btstack_stdin_setup(stdin_process);
|
||||
|
@ -216,94 +216,93 @@ static void send_sco_data(void){
|
||||
|
||||
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;
|
||||
// hexdumpf(packet, size);
|
||||
count++;
|
||||
if ((count & SCO_REPORT_PERIOD)) return;
|
||||
printf("SCO packets %u\n", count);
|
||||
}
|
||||
|
||||
static void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
switch (event[0]) {
|
||||
case BTSTACK_EVENT_STATE:
|
||||
if (btstack_event_state_get_state(event) != HCI_STATE_WORKING) break;
|
||||
show_usage();
|
||||
static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t event_size){
|
||||
static int sco_rev_count = 0;
|
||||
switch (packet_type){
|
||||
case HCI_SCO_DATA_PACKET:
|
||||
sco_rev_count++;
|
||||
if ((sco_rev_count & SCO_REPORT_PERIOD)) break;
|
||||
printf("SCO packets received: %u\n", sco_rev_count);
|
||||
break;
|
||||
case HCI_EVENT_SCO_CAN_SEND_NOW:
|
||||
send_sco_data();
|
||||
break;
|
||||
case HCI_EVENT_HSP_META:
|
||||
switch (event[2]) {
|
||||
case HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE:
|
||||
if (hsp_subevent_rfcomm_connection_complete_get_status(event)){
|
||||
printf("RFCOMM connection establishement failed with status %u\n", hsp_subevent_audio_connection_complete_get_handle(event));
|
||||
} else {
|
||||
printf("RFCOMM connection established.\n");
|
||||
}
|
||||
case HCI_EVENT_PACKET:
|
||||
switch (event[0]) {
|
||||
case BTSTACK_EVENT_STATE:
|
||||
if (btstack_event_state_get_state(event) != HCI_STATE_WORKING) break;
|
||||
show_usage();
|
||||
break;
|
||||
case HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE:
|
||||
if (hsp_subevent_rfcomm_disconnection_complete_get_status(event)){
|
||||
printf("RFCOMM disconnection failed with status %u.\n", hsp_subevent_rfcomm_disconnection_complete_get_status(event));
|
||||
} else {
|
||||
printf("RFCOMM disconnected.\n");
|
||||
}
|
||||
case HCI_EVENT_SCO_CAN_SEND_NOW:
|
||||
send_sco_data();
|
||||
break;
|
||||
case HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE:
|
||||
if (hsp_subevent_audio_connection_complete_get_status(event)){
|
||||
printf("Audio connection establishment failed with status %u\n", hsp_subevent_audio_connection_complete_get_status(event));
|
||||
sco_handle = 0;
|
||||
} else {
|
||||
sco_handle = hsp_subevent_audio_connection_complete_get_handle(event);
|
||||
printf("Audio connection established with SCO handle 0x%04x.\n", sco_handle);
|
||||
hci_request_sco_can_send_now_event();
|
||||
}
|
||||
break;
|
||||
case HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE:
|
||||
if (hsp_subevent_audio_disconnection_complete_get_status(event)){
|
||||
printf("Audio connection releasing failed with status %u\n", hsp_subevent_audio_disconnection_complete_get_status(event));
|
||||
} else {
|
||||
printf("Audio connection released.\n\n");
|
||||
sco_handle = 0;
|
||||
}
|
||||
break;
|
||||
case HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED:
|
||||
printf("Received microphone gain change %d\n", hsp_subevent_microphone_gain_changed_get_gain(event));
|
||||
break;
|
||||
case HSP_SUBEVENT_SPEAKER_GAIN_CHANGED:
|
||||
printf("Received speaker gain change %d\n", hsp_subevent_speaker_gain_changed_get_gain(event));
|
||||
break;
|
||||
case HSP_SUBEVENT_RING:
|
||||
printf("HS: RING RING!\n");
|
||||
break;
|
||||
case HSP_SUBEVENT_AG_INDICATION: {
|
||||
memset(hs_cmd_buffer, 0, sizeof(hs_cmd_buffer));
|
||||
int size = hsp_subevent_ag_indication_get_value_length(event);
|
||||
if (size >= sizeof(hs_cmd_buffer)-1){
|
||||
size = sizeof(hs_cmd_buffer)-1;
|
||||
}
|
||||
memcpy(hs_cmd_buffer, hsp_subevent_ag_indication_get_value(event), size);
|
||||
printf("Received custom indication: \"%s\". \nExit code or call hsp_hs_send_result.\n", hs_cmd_buffer);
|
||||
case HCI_EVENT_HSP_META:
|
||||
switch (event[2]) {
|
||||
case HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE:
|
||||
if (hsp_subevent_rfcomm_connection_complete_get_status(event)){
|
||||
printf("RFCOMM connection establishement failed with status %u\n", hsp_subevent_rfcomm_connection_complete_get_status(event));
|
||||
} else {
|
||||
printf("RFCOMM connection established.\n");
|
||||
}
|
||||
break;
|
||||
case HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE:
|
||||
if (hsp_subevent_rfcomm_disconnection_complete_get_status(event)){
|
||||
printf("RFCOMM disconnection failed with status %u.\n", hsp_subevent_rfcomm_disconnection_complete_get_status(event));
|
||||
} else {
|
||||
printf("RFCOMM disconnected.\n");
|
||||
}
|
||||
break;
|
||||
case HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE:
|
||||
if (hsp_subevent_audio_connection_complete_get_status(event)){
|
||||
printf("Audio connection establishment failed with status %u\n", hsp_subevent_audio_connection_complete_get_status(event));
|
||||
sco_handle = 0;
|
||||
} else {
|
||||
sco_handle = hsp_subevent_audio_connection_complete_get_handle(event);
|
||||
printf("Audio connection established with SCO handle 0x%04x.\n", sco_handle);
|
||||
hci_request_sco_can_send_now_event();
|
||||
}
|
||||
break;
|
||||
case HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE:
|
||||
if (hsp_subevent_audio_disconnection_complete_get_status(event)){
|
||||
printf("Audio connection releasing failed with status %u\n", hsp_subevent_audio_disconnection_complete_get_status(event));
|
||||
} else {
|
||||
printf("Audio connection released.\n\n");
|
||||
sco_handle = 0;
|
||||
}
|
||||
break;
|
||||
case HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED:
|
||||
printf("Received microphone gain change %d\n", hsp_subevent_microphone_gain_changed_get_gain(event));
|
||||
break;
|
||||
case HSP_SUBEVENT_SPEAKER_GAIN_CHANGED:
|
||||
printf("Received speaker gain change %d\n", hsp_subevent_speaker_gain_changed_get_gain(event));
|
||||
break;
|
||||
case HSP_SUBEVENT_RING:
|
||||
printf("HS: RING RING!\n");
|
||||
break;
|
||||
case HSP_SUBEVENT_AG_INDICATION: {
|
||||
memset(hs_cmd_buffer, 0, sizeof(hs_cmd_buffer));
|
||||
int size = hsp_subevent_ag_indication_get_value_length(event);
|
||||
if (size >= sizeof(hs_cmd_buffer)-1){
|
||||
size = sizeof(hs_cmd_buffer)-1;
|
||||
}
|
||||
memcpy(hs_cmd_buffer, hsp_subevent_ag_indication_get_value(event), size);
|
||||
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;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf("event not handled %u\n", event[2]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_hci_event(uint8_t packet_type, uint16_t channel, uint8_t * packet, uint16_t size){
|
||||
packet_handler(packet, size);
|
||||
}
|
||||
|
||||
/* @section Main Application Setup
|
||||
*
|
||||
* @text Listing MainConfiguration shows main application code.
|
||||
@ -323,9 +322,9 @@ int btstack_main(int argc, const char * argv[]);
|
||||
int btstack_main(int argc, const char * argv[]){
|
||||
|
||||
// register for HCI events
|
||||
hci_event_callback_registration.callback = &handle_hci_event;
|
||||
hci_event_callback_registration.callback = &packet_handler;
|
||||
hci_add_event_handler(&hci_event_callback_registration);
|
||||
hci_register_sco_packet_handler(&sco_packet_handler);
|
||||
hci_register_sco_packet_handler(&packet_handler);
|
||||
|
||||
l2cap_init();
|
||||
|
||||
|
@ -67,6 +67,7 @@ typedef enum {
|
||||
H4_W4_PACKET_TYPE = 1,
|
||||
H4_W4_EVENT_HEADER,
|
||||
H4_W4_ACL_HEADER,
|
||||
H4_W4_SCO_HEADER,
|
||||
H4_W4_PAYLOAD,
|
||||
H4_PACKET_RECEIVED
|
||||
} H4_STATE;
|
||||
@ -172,13 +173,17 @@ static void h4_block_received(void){
|
||||
switch (h4_state) {
|
||||
case H4_W4_PACKET_TYPE:
|
||||
switch (hci_packet[0]) {
|
||||
case HCI_EVENT_PACKET:
|
||||
h4_state = H4_W4_EVENT_HEADER;
|
||||
bytes_to_read = HCI_EVENT_HEADER_SIZE;
|
||||
break;
|
||||
case HCI_ACL_DATA_PACKET:
|
||||
h4_state = H4_W4_ACL_HEADER;
|
||||
bytes_to_read = HCI_ACL_HEADER_SIZE;
|
||||
break;
|
||||
case HCI_EVENT_PACKET:
|
||||
h4_state = H4_W4_EVENT_HEADER;
|
||||
bytes_to_read = HCI_EVENT_HEADER_SIZE;
|
||||
case HCI_SCO_DATA_PACKET:
|
||||
h4_state = H4_W4_SCO_HEADER;
|
||||
bytes_to_read = HCI_SCO_HEADER_SIZE;
|
||||
break;
|
||||
default:
|
||||
log_error("h4_process: invalid packet type 0x%02x", hci_packet[0]);
|
||||
@ -210,7 +215,16 @@ static void h4_block_received(void){
|
||||
}
|
||||
h4_state = H4_W4_PAYLOAD;
|
||||
break;
|
||||
|
||||
|
||||
case H4_W4_SCO_HEADER:
|
||||
bytes_to_read = hci_packet[2];
|
||||
if (bytes_to_read == 0) {
|
||||
h4_state = H4_PACKET_RECEIVED;
|
||||
break;
|
||||
}
|
||||
h4_state = H4_W4_PAYLOAD;
|
||||
break;
|
||||
|
||||
case H4_W4_PAYLOAD:
|
||||
h4_state = H4_PACKET_RECEIVED;
|
||||
bytes_to_read = 0;
|
||||
|
@ -904,9 +904,10 @@ typedef uint8_t sm_key_t[16];
|
||||
#define HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED 0x02
|
||||
|
||||
/**
|
||||
* @format 11
|
||||
* @format 11H
|
||||
* @param subevent_code
|
||||
* @param status 0 == OK
|
||||
* @param handle
|
||||
*/
|
||||
#define HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED 0x03
|
||||
|
||||
|
@ -2660,6 +2660,15 @@ static inline hci_con_handle_t hfp_subevent_service_level_connection_established
|
||||
static inline uint8_t hfp_subevent_audio_connection_established_get_status(const uint8_t * event){
|
||||
return event[3];
|
||||
}
|
||||
/**
|
||||
* @brief Get field handle from event HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED
|
||||
* @param event packet
|
||||
* @return handle
|
||||
* @note: btstack_type H
|
||||
*/
|
||||
static inline hci_con_handle_t hfp_subevent_audio_connection_established_get_handle(const uint8_t * event){
|
||||
return little_endian_read_16(event, 4);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
@ -96,10 +96,12 @@ static const char * hfp_ag_features[] = {
|
||||
|
||||
static btstack_linked_list_t hfp_connections = NULL;
|
||||
static void parse_sequence(hfp_connection_t * context);
|
||||
static hfp_callback_t hfp_callback;
|
||||
static btstack_packet_handler_t hfp_callback;
|
||||
static btstack_packet_handler_t rfcomm_packet_handler;
|
||||
|
||||
void hfp_set_callback(hfp_callback_t callback){
|
||||
static hfp_connection_t * sco_establishment_active;
|
||||
|
||||
void hfp_set_callback(btstack_packet_handler_t callback){
|
||||
hfp_callback = callback;
|
||||
}
|
||||
|
||||
@ -184,26 +186,26 @@ int join_bitmap(char * buffer, int buffer_size, uint32_t values, int values_nr){
|
||||
return offset;
|
||||
}
|
||||
|
||||
void hfp_emit_simple_event(hfp_callback_t callback, uint8_t event_subtype){
|
||||
void hfp_emit_simple_event(btstack_packet_handler_t callback, uint8_t event_subtype){
|
||||
if (!callback) return;
|
||||
uint8_t event[3];
|
||||
event[0] = HCI_EVENT_HFP_META;
|
||||
event[1] = sizeof(event) - 2;
|
||||
event[2] = event_subtype;
|
||||
(*callback)(event, sizeof(event));
|
||||
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
|
||||
void hfp_emit_event(hfp_callback_t callback, uint8_t event_subtype, uint8_t value){
|
||||
void hfp_emit_event(btstack_packet_handler_t callback, uint8_t event_subtype, uint8_t value){
|
||||
if (!callback) return;
|
||||
uint8_t event[4];
|
||||
event[0] = HCI_EVENT_HFP_META;
|
||||
event[1] = sizeof(event) - 2;
|
||||
event[2] = event_subtype;
|
||||
event[3] = value; // status 0 == OK
|
||||
(*callback)(event, sizeof(event));
|
||||
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
|
||||
void hfp_emit_connection_event(hfp_callback_t callback, uint8_t event_subtype, uint8_t status, hci_con_handle_t con_handle){
|
||||
void hfp_emit_connection_event(btstack_packet_handler_t callback, uint8_t event_subtype, uint8_t status, hci_con_handle_t con_handle){
|
||||
if (!callback) return;
|
||||
uint8_t event[6];
|
||||
event[0] = HCI_EVENT_HFP_META;
|
||||
@ -211,10 +213,10 @@ void hfp_emit_connection_event(hfp_callback_t callback, uint8_t event_subtype, u
|
||||
event[2] = event_subtype;
|
||||
event[3] = status; // status 0 == OK
|
||||
little_endian_store_16(event, 4, con_handle);
|
||||
(*callback)(event, sizeof(event));
|
||||
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
|
||||
void hfp_emit_string_event(hfp_callback_t callback, uint8_t event_subtype, const char * value){
|
||||
void hfp_emit_string_event(btstack_packet_handler_t callback, uint8_t event_subtype, const char * value){
|
||||
if (!callback) return;
|
||||
uint8_t event[40];
|
||||
event[0] = HCI_EVENT_HFP_META;
|
||||
@ -223,7 +225,7 @@ void hfp_emit_string_event(hfp_callback_t callback, uint8_t event_subtype, const
|
||||
int size = (strlen(value) < sizeof(event) - 4) ? strlen(value) : sizeof(event) - 4;
|
||||
strncpy((char*)&event[3], value, size);
|
||||
event[3 + size] = 0;
|
||||
(*callback)(event, sizeof(event));
|
||||
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
|
||||
btstack_linked_list_t * hfp_get_connections(void){
|
||||
@ -438,13 +440,48 @@ static void handle_query_rfcomm_event(uint8_t packet_type, uint16_t channel, uin
|
||||
}
|
||||
}
|
||||
|
||||
static void hfp_handle_failed_sco_connection(uint8_t status){
|
||||
|
||||
if (!sco_establishment_active){
|
||||
log_error("(e)SCO Connection failed but not started by us");
|
||||
return;
|
||||
}
|
||||
log_error("(e)SCO Connection failed status 0x%02x", status);
|
||||
|
||||
// invalid params / unspecified error
|
||||
if (status != 0x11 && status != 0x1f) return;
|
||||
|
||||
switch (sco_establishment_active->link_setting){
|
||||
case HFP_LINK_SETTINGS_D0:
|
||||
return; // no other option left
|
||||
case HFP_LINK_SETTINGS_D1:
|
||||
sco_establishment_active->link_setting = HFP_LINK_SETTINGS_D0;
|
||||
break;
|
||||
case HFP_LINK_SETTINGS_S1:
|
||||
sco_establishment_active->link_setting = HFP_LINK_SETTINGS_D1;
|
||||
break;
|
||||
case HFP_LINK_SETTINGS_S2:
|
||||
case HFP_LINK_SETTINGS_S3:
|
||||
case HFP_LINK_SETTINGS_S4:
|
||||
sco_establishment_active->link_setting = HFP_LINK_SETTINGS_S1;
|
||||
break;
|
||||
case HFP_LINK_SETTINGS_T1:
|
||||
case HFP_LINK_SETTINGS_T2:
|
||||
sco_establishment_active->link_setting = HFP_LINK_SETTINGS_S3;
|
||||
break;
|
||||
}
|
||||
sco_establishment_active->establish_audio_connection = 1;
|
||||
sco_establishment_active = 0;
|
||||
}
|
||||
|
||||
|
||||
void hfp_handle_hci_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
||||
bd_addr_t event_addr;
|
||||
uint16_t rfcomm_cid, handle;
|
||||
hfp_connection_t * hfp_connection = NULL;
|
||||
uint8_t status;
|
||||
|
||||
// printf("AG packet_handler type %u, event type %x, size %u\n", packet_type, hci_event_packet_get_type(packet), size);
|
||||
log_info("AG packet_handler type %u, event type %x, size %u", packet_type, hci_event_packet_get_type(packet), size);
|
||||
|
||||
switch (hci_event_packet_get_type(packet)) {
|
||||
|
||||
@ -490,9 +527,19 @@ void hfp_handle_hci_event(uint8_t packet_type, uint16_t channel, uint8_t *packet
|
||||
default:
|
||||
break;
|
||||
}
|
||||
rfcomm_request_can_send_now_event(hfp_connection->rfcomm_cid);
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_EVENT_COMMAND_STATUS:
|
||||
if (hci_event_command_status_get_command_opcode(packet) == hci_setup_synchronous_connection.opcode) {
|
||||
status = hci_event_command_status_get_status(packet);
|
||||
if (status) {
|
||||
hfp_handle_failed_sco_connection(hci_event_command_status_get_status(packet));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE:{
|
||||
|
||||
reverse_bd_addr(&packet[5], event_addr);
|
||||
@ -500,32 +547,7 @@ void hfp_handle_hci_event(uint8_t packet_type, uint16_t channel, uint8_t *packet
|
||||
status = packet[index++];
|
||||
|
||||
if (status != 0){
|
||||
log_error("(e)SCO Connection failed status %u", status);
|
||||
// if outgoing && link_setting != d0 && appropriate error
|
||||
if (status != 0x11 && status != 0x1f) break; // invalid params / unspecified error
|
||||
hfp_connection = get_hfp_connection_context_for_bd_addr(event_addr);
|
||||
if (!hfp_connection) break;
|
||||
switch (hfp_connection->link_setting){
|
||||
case HFP_LINK_SETTINGS_D0:
|
||||
return; // no other option left
|
||||
case HFP_LINK_SETTINGS_D1:
|
||||
// hfp_connection->link_setting = HFP_LINK_SETTINGS_D0;
|
||||
// break;
|
||||
case HFP_LINK_SETTINGS_S1:
|
||||
// hfp_connection->link_setting = HFP_LINK_SETTINGS_D1;
|
||||
// break;
|
||||
case HFP_LINK_SETTINGS_S2:
|
||||
case HFP_LINK_SETTINGS_S3:
|
||||
case HFP_LINK_SETTINGS_S4:
|
||||
// hfp_connection->link_setting = HFP_LINK_SETTINGS_S1;
|
||||
// break;
|
||||
case HFP_LINK_SETTINGS_T1:
|
||||
case HFP_LINK_SETTINGS_T2:
|
||||
// hfp_connection->link_setting = HFP_LINK_SETTINGS_S3;
|
||||
hfp_connection->link_setting = HFP_LINK_SETTINGS_D0;
|
||||
break;
|
||||
}
|
||||
hfp_connection->establish_audio_connection = 1;
|
||||
hfp_handle_failed_sco_connection(status);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1331,10 +1353,12 @@ static const struct link_settings {
|
||||
{ 0x000d, 0x02, 0x0380 } // HFP_LINK_SETTINGS_T2, 2-EV3
|
||||
};
|
||||
|
||||
void hfp_setup_synchronous_connection(hci_con_handle_t handle, hfp_link_setttings_t setting){
|
||||
void hfp_setup_synchronous_connection(hfp_connection_t * hfp_connection){
|
||||
// all packet types, fixed bandwidth
|
||||
int setting = hfp_connection->link_setting;
|
||||
log_info("hfp_setup_synchronous_connection using setting nr %u", setting);
|
||||
hci_send_cmd(&hci_setup_synchronous_connection, handle, 8000, 8000, hfp_link_settings[setting].max_latency,
|
||||
sco_establishment_active = hfp_connection;
|
||||
hci_send_cmd(&hci_setup_synchronous_connection, hfp_connection->acl_handle, 8000, 8000, hfp_link_settings[setting].max_latency,
|
||||
hci_get_sco_voice_setting(), hfp_link_settings[setting].retransmission_effort, hfp_link_settings[setting].packet_types); // all types 0x003f, only 2-ev3 0x380
|
||||
}
|
||||
|
||||
|
@ -432,8 +432,6 @@ typedef enum{
|
||||
HFP_CALL_SM
|
||||
} hfp_state_machine_t;
|
||||
|
||||
typedef void (*hfp_callback_t)(uint8_t * event, uint16_t event_size);
|
||||
|
||||
typedef struct{
|
||||
uint16_t uuid;
|
||||
uint8_t state; // enabled
|
||||
@ -621,16 +619,16 @@ int get_bit(uint16_t bitmap, int position);
|
||||
int store_bit(uint32_t bitmap, int position, uint8_t value);
|
||||
// UTILS_END
|
||||
|
||||
void hfp_set_callback(hfp_callback_t callback);
|
||||
void hfp_set_callback(btstack_packet_handler_t callback);
|
||||
|
||||
void hfp_set_packet_handler_for_rfcomm_connections(btstack_packet_handler_t handler);
|
||||
|
||||
void hfp_create_sdp_record(uint8_t * service, uint32_t service_record_handle, uint16_t service_uuid, int rfcomm_channel_nr, const char * name);
|
||||
void hfp_handle_hci_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
|
||||
void hfp_emit_event(hfp_callback_t callback, uint8_t event_subtype, uint8_t value);
|
||||
void hfp_emit_simple_event(hfp_callback_t callback, uint8_t event_subtype);
|
||||
void hfp_emit_string_event(hfp_callback_t callback, uint8_t event_subtype, const char * value);
|
||||
void hfp_emit_connection_event(hfp_callback_t callback, uint8_t event_subtype, uint8_t status, hci_con_handle_t con_handle);
|
||||
void hfp_emit_event(btstack_packet_handler_t callback, uint8_t event_subtype, uint8_t value);
|
||||
void hfp_emit_simple_event(btstack_packet_handler_t callback, uint8_t event_subtype);
|
||||
void hfp_emit_string_event(btstack_packet_handler_t callback, uint8_t event_subtype, const char * value);
|
||||
void hfp_emit_connection_event(btstack_packet_handler_t callback, uint8_t event_subtype, uint8_t status, hci_con_handle_t con_handle);
|
||||
|
||||
hfp_connection_t * get_hfp_connection_context_for_rfcomm_cid(uint16_t cid);
|
||||
hfp_connection_t * get_hfp_connection_context_for_bd_addr(bd_addr_t bd_addr);
|
||||
@ -645,7 +643,7 @@ void hfp_reset_context_flags(hfp_connection_t * connection);
|
||||
|
||||
void hfp_release_audio_connection(hfp_connection_t * connection);
|
||||
|
||||
void hfp_setup_synchronous_connection(hci_con_handle_t handle, hfp_link_setttings_t link_settings);
|
||||
void hfp_setup_synchronous_connection(hfp_connection_t * connection);
|
||||
|
||||
const char * hfp_hf_feature(int index);
|
||||
const char * hfp_ag_feature(int index);
|
||||
|
@ -95,7 +95,7 @@ static hfp_generic_status_indicator_t hfp_generic_status_indicators[HFP_MAX_NUM_
|
||||
|
||||
static int hfp_ag_call_hold_services_nr = 0;
|
||||
static char *hfp_ag_call_hold_services[6];
|
||||
static hfp_callback_t hfp_callback;
|
||||
static btstack_packet_handler_t hfp_callback;
|
||||
|
||||
static hfp_response_and_hold_state_t hfp_ag_response_and_hold_state;
|
||||
static int hfp_ag_response_and_hold_active = 0;
|
||||
@ -149,7 +149,7 @@ static int get_ag_indicator_index_for_name(const char * name){
|
||||
}
|
||||
|
||||
|
||||
void hfp_ag_register_packet_handler(hfp_callback_t callback){
|
||||
void hfp_ag_register_packet_handler(btstack_packet_handler_t callback){
|
||||
if (callback == NULL){
|
||||
log_error("hfp_ag_register_packet_handler called with NULL callback");
|
||||
return;
|
||||
@ -557,7 +557,6 @@ static int codecs_exchange_state_machine(hfp_connection_t * hfp_connection){
|
||||
|
||||
switch (hfp_connection->command){
|
||||
case HFP_CMD_AVAILABLE_CODECS:
|
||||
//printf("HFP_CODECS_RECEIVED_LIST \n");
|
||||
if (hfp_connection->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED){
|
||||
hfp_connection->codecs_state = HFP_CODECS_RECEIVED_LIST;
|
||||
hfp_ag_ok(hfp_connection->rfcomm_cid);
|
||||
@ -576,20 +575,17 @@ static int codecs_exchange_state_machine(hfp_connection_t * hfp_connection){
|
||||
return 1;
|
||||
|
||||
case HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP:
|
||||
//printf(" HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP \n");
|
||||
hfp_connection->codecs_state = HFP_CODECS_RECEIVED_TRIGGER_CODEC_EXCHANGE;
|
||||
hfp_ag_ok(hfp_connection->rfcomm_cid);
|
||||
return 1;
|
||||
|
||||
case HFP_CMD_AG_SEND_COMMON_CODEC:
|
||||
//printf(" HFP_CMD_AG_SEND_COMMON_CODEC \n");
|
||||
hfp_connection->codecs_state = HFP_CODECS_AG_SENT_COMMON_CODEC;
|
||||
hfp_connection->suggested_codec = hfp_ag_suggest_codec(hfp_connection);
|
||||
hfp_ag_cmd_suggest_codec(hfp_connection->rfcomm_cid, hfp_connection->suggested_codec);
|
||||
return 1;
|
||||
|
||||
case HFP_CMD_HF_CONFIRMED_CODEC:
|
||||
//printf("HFP_CMD_HF_CONFIRMED_CODEC \n");
|
||||
if (hfp_connection->codec_confirmed != hfp_connection->suggested_codec){
|
||||
hfp_connection->codecs_state = HFP_CODECS_ERROR;
|
||||
hfp_ag_error(hfp_connection->rfcomm_cid);
|
||||
@ -636,9 +632,9 @@ static void hfp_ag_slc_established(hfp_connection_t * hfp_connection){
|
||||
}
|
||||
|
||||
static int hfp_ag_run_for_context_service_level_connection(hfp_connection_t * hfp_connection){
|
||||
log_info("hfp_ag_run_for_context_service_level_connection state %u, command %u", hfp_connection->state, hfp_connection->command);
|
||||
if (hfp_connection->state >= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return 0;
|
||||
int done = 0;
|
||||
// printf(" -> State machine: SLC\n");
|
||||
switch(hfp_connection->command){
|
||||
case HFP_CMD_SUPPORTED_FEATURES:
|
||||
switch(hfp_connection->state){
|
||||
@ -665,18 +661,9 @@ static int hfp_ag_run_for_context_service_level_connection(hfp_connection_t * hf
|
||||
|
||||
case HFP_CMD_RETRIEVE_AG_INDICATORS:
|
||||
if (hfp_connection->state == HFP_W4_RETRIEVE_INDICATORS) {
|
||||
hfp_connection->command = HFP_CMD_NONE; // prevent reentrance
|
||||
int next_segment = hfp_ag_retrieve_indicators_cmd_via_generator(hfp_connection->rfcomm_cid, hfp_connection, hfp_connection->send_ag_indicators_segment);
|
||||
if (next_segment < hfp_ag_indicators_cmd_generator_num_segments(hfp_connection)){
|
||||
// prepare sending of next segment
|
||||
hfp_connection->send_ag_indicators_segment = next_segment;
|
||||
hfp_connection->command = HFP_CMD_RETRIEVE_AG_INDICATORS;
|
||||
} else {
|
||||
// done, go to next state
|
||||
hfp_connection->send_ag_indicators_segment = 0;
|
||||
hfp_connection->state = HFP_W4_RETRIEVE_INDICATORS_STATUS;
|
||||
}
|
||||
return 1;
|
||||
// HF requested AG Indicators and we did expect it
|
||||
hfp_connection->state = HFP_RETRIEVE_INDICATORS;
|
||||
// continue below in state switch
|
||||
}
|
||||
break;
|
||||
|
||||
@ -729,16 +716,35 @@ static int hfp_ag_run_for_context_service_level_connection(hfp_connection_t * hf
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (hfp_connection->state){
|
||||
case HFP_RETRIEVE_INDICATORS: {
|
||||
int next_segment = hfp_ag_retrieve_indicators_cmd_via_generator(hfp_connection->rfcomm_cid, hfp_connection, hfp_connection->send_ag_indicators_segment);
|
||||
int num_segments = hfp_ag_indicators_cmd_generator_num_segments(hfp_connection);
|
||||
log_info("HFP_CMD_RETRIEVE_AG_INDICATORS next segment %u, num_segments %u", next_segment, num_segments);
|
||||
if (next_segment < num_segments){
|
||||
// prepare sending of next segment
|
||||
hfp_connection->send_ag_indicators_segment = next_segment;
|
||||
log_info("HFP_CMD_RETRIEVE_AG_INDICATORS more. command %u, next seg %u", hfp_connection->command, next_segment);
|
||||
} else {
|
||||
// done, go to next state
|
||||
hfp_connection->send_ag_indicators_segment = 0;
|
||||
hfp_connection->state = HFP_W4_RETRIEVE_INDICATORS_STATUS;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
static int hfp_ag_run_for_context_service_level_connection_queries(hfp_connection_t * hfp_connection){
|
||||
// if (hfp_connection->state != HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return 0;
|
||||
|
||||
|
||||
int done = codecs_exchange_state_machine(hfp_connection);
|
||||
if (done) return done;
|
||||
|
||||
// printf(" -> State machine: SLC Queries\n");
|
||||
switch(hfp_connection->command){
|
||||
case HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION:
|
||||
hfp_supported_features = store_bit(hfp_supported_features, HFP_AGSF_VOICE_RECOGNITION_FUNCTION, hfp_connection->ag_activate_voice_recognition);
|
||||
@ -801,13 +807,12 @@ static int hfp_ag_run_for_audio_connection(hfp_connection_t * hfp_connection){
|
||||
// run codecs exchange
|
||||
int done = codecs_exchange_state_machine(hfp_connection);
|
||||
if (done) return done;
|
||||
// printf(" -> State machine: Audio hfp_connection\n");
|
||||
|
||||
if (hfp_connection->codecs_state != HFP_CODECS_EXCHANGED) return done;
|
||||
if (hfp_connection->establish_audio_connection){
|
||||
hfp_connection->state = HFP_W4_SCO_CONNECTED;
|
||||
hfp_connection->establish_audio_connection = 0;
|
||||
hfp_setup_synchronous_connection(hfp_connection->acl_handle, hfp_connection->link_setting);
|
||||
hfp_setup_synchronous_connection(hfp_connection);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@ -1610,9 +1615,15 @@ static void hfp_ag_send_call_status(hfp_connection_t * hfp_connection, int call_
|
||||
}
|
||||
|
||||
static void hfp_run_for_context(hfp_connection_t *hfp_connection){
|
||||
|
||||
log_info("hfp_run_for_context %p", hfp_connection);
|
||||
|
||||
if (!hfp_connection) return;
|
||||
|
||||
if (!hfp_connection->rfcomm_cid) return;
|
||||
|
||||
if (!rfcomm_can_send_packet_now(hfp_connection->rfcomm_cid)) {
|
||||
log_info("hfp_run_for_context: request can send for 0x%02x", hfp_connection->rfcomm_cid);
|
||||
rfcomm_request_can_send_now_event(hfp_connection->rfcomm_cid);
|
||||
return;
|
||||
}
|
||||
@ -1763,6 +1774,10 @@ static void hfp_run_for_context(hfp_connection_t *hfp_connection){
|
||||
if (done){
|
||||
hfp_connection->command = HFP_CMD_NONE;
|
||||
}
|
||||
//
|
||||
if (done) {
|
||||
rfcomm_request_can_send_now_event(hfp_connection->rfcomm_cid);
|
||||
}
|
||||
}
|
||||
|
||||
static hfp_generic_status_indicator_t *get_hf_indicator_by_number(int number){
|
||||
@ -2037,8 +2052,6 @@ void hfp_ag_init(uint16_t rfcomm_channel_nr){
|
||||
hci_event_callback_registration.callback = &packet_handler;
|
||||
hci_add_event_handler(&hci_event_callback_registration);
|
||||
|
||||
l2cap_init();
|
||||
|
||||
rfcomm_register_service(&packet_handler, rfcomm_channel_nr, 0xffff);
|
||||
|
||||
hfp_ag_response_and_hold_active = 0;
|
||||
|
@ -115,7 +115,7 @@ void hfp_ag_init_call_hold_services(int call_hold_services_nr, const char * call
|
||||
* @brief Register callback for the HFP Audio Gateway (AG) client.
|
||||
* @param callback
|
||||
*/
|
||||
void hfp_ag_register_packet_handler(hfp_callback_t callback);
|
||||
void hfp_ag_register_packet_handler(btstack_packet_handler_t callback);
|
||||
|
||||
/**
|
||||
* @brief Enable in-band ring tone.
|
||||
|
@ -74,7 +74,7 @@ static uint32_t hfp_indicators_value[HFP_MAX_NUM_HF_INDICATORS];
|
||||
static uint8_t hfp_hf_speaker_gain = 9;
|
||||
static uint8_t hfp_hf_microphone_gain = 9;
|
||||
|
||||
static hfp_callback_t hfp_callback;
|
||||
static btstack_packet_handler_t hfp_callback;
|
||||
|
||||
static hfp_call_status_t hfp_call_status;
|
||||
static hfp_callsetup_status_t hfp_callsetup_status;
|
||||
@ -84,7 +84,7 @@ static char phone_number[25];
|
||||
|
||||
static btstack_packet_callback_registration_t hci_event_callback_registration;
|
||||
|
||||
void hfp_hf_register_packet_handler(hfp_callback_t callback){
|
||||
void hfp_hf_register_packet_handler(btstack_packet_handler_t callback){
|
||||
hfp_callback = callback;
|
||||
if (callback == NULL){
|
||||
log_error("hfp_hf_register_packet_handler called with NULL callback");
|
||||
@ -94,7 +94,7 @@ void hfp_hf_register_packet_handler(hfp_callback_t callback){
|
||||
hfp_set_callback(callback);
|
||||
}
|
||||
|
||||
static void hfp_hf_emit_subscriber_information(hfp_callback_t callback, uint8_t event_subtype, uint8_t status, uint8_t bnip_type, const char * bnip_number){
|
||||
static void hfp_hf_emit_subscriber_information(btstack_packet_handler_t callback, uint8_t event_subtype, uint8_t status, uint8_t bnip_type, const char * bnip_number){
|
||||
if (!callback) return;
|
||||
uint8_t event[31];
|
||||
event[0] = HCI_EVENT_HFP_META;
|
||||
@ -105,10 +105,10 @@ static void hfp_hf_emit_subscriber_information(hfp_callback_t callback, uint8_t
|
||||
int size = (strlen(bnip_number) < sizeof(event) - 6) ? strlen(bnip_number) : sizeof(event) - 6;
|
||||
strncpy((char*)&event[5], bnip_number, size);
|
||||
event[5 + size] = 0;
|
||||
(*callback)(event, sizeof(event));
|
||||
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
|
||||
static void hfp_hf_emit_type_and_number(hfp_callback_t callback, uint8_t event_subtype, uint8_t bnip_type, const char * bnip_number){
|
||||
static void hfp_hf_emit_type_and_number(btstack_packet_handler_t callback, uint8_t event_subtype, uint8_t bnip_type, const char * bnip_number){
|
||||
if (!callback) return;
|
||||
uint8_t event[30];
|
||||
event[0] = HCI_EVENT_HFP_META;
|
||||
@ -118,10 +118,10 @@ static void hfp_hf_emit_type_and_number(hfp_callback_t callback, uint8_t event_s
|
||||
int size = (strlen(bnip_number) < sizeof(event) - 5) ? strlen(bnip_number) : sizeof(event) - 5;
|
||||
strncpy((char*)&event[4], bnip_number, size);
|
||||
event[4 + size] = 0;
|
||||
(*callback)(event, sizeof(event));
|
||||
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
|
||||
static void hfp_hf_emit_enhanced_call_status(hfp_callback_t callback, uint8_t clcc_idx, uint8_t clcc_dir,
|
||||
static void hfp_hf_emit_enhanced_call_status(btstack_packet_handler_t callback, uint8_t clcc_idx, uint8_t clcc_dir,
|
||||
uint8_t clcc_status, uint8_t clcc_mpty, uint8_t bnip_type, const char * bnip_number){
|
||||
if (!callback) return;
|
||||
uint8_t event[35];
|
||||
@ -136,7 +136,7 @@ static void hfp_hf_emit_enhanced_call_status(hfp_callback_t callback, uint8_t cl
|
||||
int size = (strlen(bnip_number) < sizeof(event) - 10) ? strlen(bnip_number) : sizeof(event) - 10;
|
||||
strncpy((char*)&event[9], bnip_number, size);
|
||||
event[9 + size] = 0;
|
||||
(*callback)(event, sizeof(event));
|
||||
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
|
||||
static int hfp_hf_supports_codec(uint8_t codec){
|
||||
@ -373,7 +373,7 @@ static int hfp_hf_send_clcc(uint16_t cid){
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
static void hfp_emit_ag_indicator_event(hfp_callback_t callback, hfp_ag_indicator_t indicator){
|
||||
static void hfp_emit_ag_indicator_event(btstack_packet_handler_t callback, hfp_ag_indicator_t indicator){
|
||||
if (!callback) return;
|
||||
uint8_t event[5+HFP_MAX_INDICATOR_DESC_SIZE+1];
|
||||
event[0] = HCI_EVENT_HFP_META;
|
||||
@ -383,10 +383,10 @@ static void hfp_emit_ag_indicator_event(hfp_callback_t callback, hfp_ag_indicato
|
||||
event[4] = indicator.status;
|
||||
strncpy((char*)&event[5], indicator.name, HFP_MAX_INDICATOR_DESC_SIZE);
|
||||
event[5+HFP_MAX_INDICATOR_DESC_SIZE] = 0;
|
||||
(*callback)(event, sizeof(event));
|
||||
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
|
||||
static void hfp_emit_network_operator_event(hfp_callback_t callback, hfp_network_opearator_t network_operator){
|
||||
static void hfp_emit_network_operator_event(btstack_packet_handler_t callback, hfp_network_opearator_t network_operator){
|
||||
if (!callback) return;
|
||||
uint8_t event[24];
|
||||
event[0] = HCI_EVENT_HFP_META;
|
||||
@ -395,7 +395,7 @@ static void hfp_emit_network_operator_event(hfp_callback_t callback, hfp_network
|
||||
event[3] = network_operator.mode;
|
||||
event[4] = network_operator.format;
|
||||
strcpy((char*)&event[5], network_operator.name);
|
||||
(*callback)(event, sizeof(event));
|
||||
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
|
||||
static int hfp_hf_run_for_context_service_level_connection(hfp_connection_t * hfp_connection){
|
||||
@ -566,7 +566,7 @@ static int hfp_hf_run_for_audio_connection(hfp_connection_t * hfp_connection){
|
||||
if (hfp_connection->establish_audio_connection){
|
||||
hfp_connection->state = HFP_W4_SCO_CONNECTED;
|
||||
hfp_connection->establish_audio_connection = 0;
|
||||
hfp_setup_synchronous_connection(hfp_connection->acl_handle, hfp_connection->link_setting);
|
||||
hfp_setup_synchronous_connection(hfp_connection);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1083,8 +1083,6 @@ void hfp_hf_init(uint16_t rfcomm_channel_nr){
|
||||
hci_event_callback_registration.callback = &packet_handler;
|
||||
hci_add_event_handler(&hci_event_callback_registration);
|
||||
|
||||
l2cap_init();
|
||||
|
||||
rfcomm_register_service(packet_handler, rfcomm_channel_nr, 0xffff);
|
||||
|
||||
hfp_set_packet_handler_for_rfcomm_connections(&packet_handler);
|
||||
|
@ -95,7 +95,7 @@ void hfp_hf_init_hf_indicators(int indicators_nr, uint16_t * indicators);
|
||||
* @brief Register callback for the HFP Hands-Free (HF) client.
|
||||
* @param callback
|
||||
*/
|
||||
void hfp_hf_register_packet_handler(hfp_callback_t callback);
|
||||
void hfp_hf_register_packet_handler(btstack_packet_handler_t callback);
|
||||
|
||||
/**
|
||||
* @brief Establish RFCOMM connection with the AG with given Bluetooth address,
|
||||
|
@ -124,15 +124,15 @@ typedef enum {
|
||||
static hsp_state_t hsp_state = HSP_IDLE;
|
||||
|
||||
|
||||
static hsp_ag_callback_t hsp_ag_callback;
|
||||
static btstack_packet_handler_t hsp_ag_callback;
|
||||
|
||||
static void hsp_run(void);
|
||||
static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
|
||||
static void handle_query_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
|
||||
|
||||
static void dummy_notify(uint8_t * event, uint16_t size){}
|
||||
static void dummy_notify(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t size){}
|
||||
|
||||
void hsp_ag_register_packet_handler(hsp_ag_callback_t callback){
|
||||
void hsp_ag_register_packet_handler(btstack_packet_handler_t callback){
|
||||
if (callback == NULL){
|
||||
callback = &dummy_notify;
|
||||
}
|
||||
@ -146,7 +146,7 @@ static void emit_event(uint8_t event_subtype, uint8_t value){
|
||||
event[1] = sizeof(event) - 2;
|
||||
event[2] = event_subtype;
|
||||
event[3] = value; // status 0 == OK
|
||||
(*hsp_ag_callback)(event, sizeof(event));
|
||||
(*hsp_ag_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
|
||||
static void emit_event_audio_connected(uint8_t status, uint16_t handle){
|
||||
@ -157,7 +157,7 @@ static void emit_event_audio_connected(uint8_t status, uint16_t handle){
|
||||
event[2] = HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE;
|
||||
event[3] = status;
|
||||
little_endian_store_16(event, 4, handle);
|
||||
(*hsp_ag_callback)(event, sizeof(event));
|
||||
(*hsp_ag_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
|
||||
void hsp_ag_create_sdp_record(uint8_t * service, uint32_t service_record_handle, int rfcomm_channel_nr, const char * name){
|
||||
@ -554,7 +554,7 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
|
||||
event[1] = size + 2;
|
||||
event[2] = HSP_SUBEVENT_HS_COMMAND;
|
||||
event[3] = size;
|
||||
(*hsp_ag_callback)(event, size+4);
|
||||
(*hsp_ag_callback)(HCI_EVENT_PACKET, 0, event, size+4);
|
||||
}
|
||||
|
||||
hsp_run();
|
||||
|
@ -54,23 +54,6 @@ extern "C" {
|
||||
|
||||
/* API_START */
|
||||
|
||||
/**
|
||||
* @brief Packet handler for HSP Audio Gateway (AG) events.
|
||||
*
|
||||
* The HSP AG event has type HCI_EVENT_HSP_META with following subtypes:
|
||||
* - HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE
|
||||
* - HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE
|
||||
* - HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE
|
||||
* - HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE
|
||||
* - HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED
|
||||
* - HSP_SUBEVENT_SPEAKER_GAIN_CHANGED
|
||||
* - HSP_SUBEVENT_HS_COMMAND
|
||||
*
|
||||
* @param event See include/btstack/hci_cmds.h
|
||||
* @param event_size
|
||||
*/
|
||||
typedef void (*hsp_ag_callback_t)(uint8_t * event, uint16_t event_size);
|
||||
|
||||
/**
|
||||
* @brief Set up HSP AG.
|
||||
* @param rfcomm_channel_nr
|
||||
@ -88,9 +71,19 @@ void hsp_ag_create_sdp_record(uint8_t * service, uint32_t service_record_handle,
|
||||
|
||||
/**
|
||||
* @brief Register packet handler to receive HSP AG events.
|
||||
|
||||
* The HSP AG event has type HCI_EVENT_HSP_META with following subtypes:
|
||||
* - HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE
|
||||
* - HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE
|
||||
* - HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE
|
||||
* - HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE
|
||||
* - HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED
|
||||
* - HSP_SUBEVENT_SPEAKER_GAIN_CHANGED
|
||||
* - HSP_SUBEVENT_HS_COMMAND
|
||||
*
|
||||
* @param callback
|
||||
*/
|
||||
void hsp_ag_register_packet_handler(hsp_ag_callback_t callback);
|
||||
void hsp_ag_register_packet_handler(btstack_packet_handler_t callback);
|
||||
|
||||
/**
|
||||
* @brief Connect to HSP Headset.
|
||||
|
@ -123,10 +123,10 @@ static void hsp_run(void);
|
||||
static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
|
||||
static void handle_query_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
|
||||
|
||||
static hsp_hs_callback_t hsp_hs_callback;
|
||||
static void dummy_notify(uint8_t * event, uint16_t size){}
|
||||
static btstack_packet_handler_t hsp_hs_callback;
|
||||
static void dummy_notify(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t size){}
|
||||
|
||||
void hsp_hs_register_packet_handler(hsp_hs_callback_t callback){
|
||||
void hsp_hs_register_packet_handler(btstack_packet_handler_t callback){
|
||||
if (callback == NULL){
|
||||
callback = &dummy_notify;
|
||||
}
|
||||
@ -140,7 +140,7 @@ static void emit_event(uint8_t event_subtype, uint8_t value){
|
||||
event[1] = sizeof(event) - 2;
|
||||
event[2] = event_subtype;
|
||||
event[3] = value; // status 0 == OK
|
||||
(*hsp_hs_callback)(event, sizeof(event));
|
||||
(*hsp_hs_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
|
||||
static void emit_ring_event(void){
|
||||
@ -149,7 +149,7 @@ static void emit_ring_event(void){
|
||||
event[0] = HCI_EVENT_HSP_META;
|
||||
event[1] = sizeof(event) - 2;
|
||||
event[2] = HSP_SUBEVENT_RING;
|
||||
(*hsp_hs_callback)(event, sizeof(event));
|
||||
(*hsp_hs_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
|
||||
static void emit_event_audio_connected(uint8_t status, uint16_t handle){
|
||||
@ -160,7 +160,7 @@ static void emit_event_audio_connected(uint8_t status, uint16_t handle){
|
||||
event[2] = HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE;
|
||||
event[3] = status;
|
||||
little_endian_store_16(event, 4, handle);
|
||||
(*hsp_hs_callback)(event, sizeof(event));
|
||||
(*hsp_hs_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
|
||||
// remote audio volume control
|
||||
@ -276,9 +276,6 @@ void hsp_hs_init(uint8_t rfcomm_channel_nr){
|
||||
hci_event_callback_registration.callback = &packet_handler;
|
||||
hci_add_event_handler(&hci_event_callback_registration);
|
||||
|
||||
// init L2CAP
|
||||
l2cap_init();
|
||||
|
||||
rfcomm_init();
|
||||
rfcomm_register_service(packet_handler, rfcomm_channel_nr, 0xffff); // reserved channel, mtu limited by l2cap
|
||||
|
||||
@ -477,7 +474,7 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
|
||||
event[1] = size + 2;
|
||||
event[2] = HSP_SUBEVENT_AG_INDICATION;
|
||||
event[3] = size;
|
||||
(*hsp_hs_callback)(event, size+4);
|
||||
(*hsp_hs_callback)(HCI_EVENT_PACKET, 0, event, size+4);
|
||||
}
|
||||
hsp_run();
|
||||
return;
|
||||
@ -590,7 +587,7 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
|
||||
|
||||
case RFCOMM_EVENT_CHANNEL_CLOSED:
|
||||
hsp_hs_reset_state();
|
||||
hsp_hs_callback(packet, size);
|
||||
hsp_hs_callback(HCI_EVENT_PACKET, 0, packet, size);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -54,24 +54,6 @@ extern "C" {
|
||||
|
||||
/* API_START */
|
||||
|
||||
/**
|
||||
* @brief Packet handler for HSP Headset (HS) events.
|
||||
*
|
||||
* The HSP HS event has type HCI_EVENT_HSP_META with following subtypes:
|
||||
* - HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE
|
||||
* - HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE
|
||||
* - HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE
|
||||
* - HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE
|
||||
* - HSP_SUBEVENT_RING
|
||||
* - HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED
|
||||
* - HSP_SUBEVENT_SPEAKER_GAIN_CHANGED
|
||||
* - HSP_SUBEVENT_AG_INDICATION
|
||||
*
|
||||
* @param event See include/btstack/hci_cmds.h
|
||||
* @param event_size
|
||||
*/
|
||||
typedef void (*hsp_hs_callback_t)(uint8_t * event, uint16_t event_size);
|
||||
|
||||
/**
|
||||
* @brief Set up HSP HS.
|
||||
* @param rfcomm_channel_nr
|
||||
@ -89,9 +71,20 @@ void hsp_hs_create_sdp_record(uint8_t * service, uint32_t service_record_handle,
|
||||
|
||||
/**
|
||||
* @brief Register packet handler to receive HSP HS events.
|
||||
*
|
||||
* The HSP HS event has type HCI_EVENT_HSP_META with following subtypes:
|
||||
* - HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE
|
||||
* - HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE
|
||||
* - HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE
|
||||
* - HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE
|
||||
* - HSP_SUBEVENT_RING
|
||||
* - HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED
|
||||
* - HSP_SUBEVENT_SPEAKER_GAIN_CHANGED
|
||||
* - HSP_SUBEVENT_AG_INDICATION
|
||||
*
|
||||
* @param callback
|
||||
*/
|
||||
void hsp_hs_register_packet_handler(hsp_hs_callback_t callback);
|
||||
void hsp_hs_register_packet_handler(btstack_packet_handler_t callback);
|
||||
|
||||
/**
|
||||
* @brief Connect to HSP Audio Gateway.
|
||||
|
10
src/hci.c
10
src/hci.c
@ -1860,7 +1860,7 @@ static void event_handler(uint8_t *packet, int size){
|
||||
|
||||
static void sco_handler(uint8_t * packet, uint16_t size){
|
||||
if (!hci_stack->sco_packet_handler) return;
|
||||
hci_stack->sco_packet_handler(HCI_SCO_DATA_PACKET, packet, size);
|
||||
hci_stack->sco_packet_handler(HCI_SCO_DATA_PACKET, 0, packet, size);
|
||||
}
|
||||
|
||||
static void packet_handler(uint8_t packet_type, uint8_t *packet, uint16_t size){
|
||||
@ -1888,14 +1888,14 @@ void hci_add_event_handler(btstack_packet_callback_registration_t * callback_han
|
||||
|
||||
|
||||
/** Register HCI packet handlers */
|
||||
void hci_register_acl_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size)){
|
||||
void hci_register_acl_packet_handler(btstack_packet_handler_t handler){
|
||||
hci_stack->acl_packet_handler = handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Registers a packet handler for SCO data. Used for HSP and HFP profiles.
|
||||
*/
|
||||
void hci_register_sco_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size)){
|
||||
void hci_register_sco_packet_handler(btstack_packet_handler_t handler){
|
||||
hci_stack->sco_packet_handler = handler;
|
||||
}
|
||||
|
||||
@ -2974,7 +2974,7 @@ static void hci_emit_event(uint8_t * event, uint16_t size, int dump){
|
||||
|
||||
static void hci_emit_acl_packet(uint8_t * packet, uint16_t size){
|
||||
if (!hci_stack->acl_packet_handler) return;
|
||||
hci_stack->acl_packet_handler(HCI_ACL_DATA_PACKET, packet, size);
|
||||
hci_stack->acl_packet_handler(HCI_ACL_DATA_PACKET, 0, packet, size);
|
||||
}
|
||||
|
||||
static void hci_notify_if_sco_can_send_now(void){
|
||||
@ -2984,7 +2984,7 @@ static void hci_notify_if_sco_can_send_now(void){
|
||||
hci_stack->sco_waiting_for_can_send_now = 0;
|
||||
uint8_t event[2] = { HCI_EVENT_SCO_CAN_SEND_NOW, 0 };
|
||||
hci_dump_packet(HCI_EVENT_PACKET, 1, event, sizeof(event));
|
||||
hci_stack->sco_packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
|
||||
hci_stack->sco_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -520,10 +520,10 @@ typedef struct {
|
||||
btstack_linked_list_t connections;
|
||||
|
||||
/* callback to L2CAP layer */
|
||||
void (*acl_packet_handler)(uint8_t packet_type, uint8_t *packet, uint16_t size);
|
||||
btstack_packet_handler_t acl_packet_handler;
|
||||
|
||||
/* callback for SCO data */
|
||||
void (*sco_packet_handler)(uint8_t packet_type, uint8_t *packet, uint16_t size);
|
||||
btstack_packet_handler_t sco_packet_handler;
|
||||
|
||||
/* callbacks for events */
|
||||
btstack_linked_list_t event_handlers;
|
||||
@ -721,12 +721,12 @@ void hci_add_event_handler(btstack_packet_callback_registration_t * callback_han
|
||||
/**
|
||||
* @brief Registers a packet handler for ACL data. Used by L2CAP
|
||||
*/
|
||||
void hci_register_acl_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size));
|
||||
void hci_register_acl_packet_handler(btstack_packet_handler_t handler);
|
||||
|
||||
/**
|
||||
* @brief Registers a packet handler for SCO data. Used for HSP and HFP profiles.
|
||||
*/
|
||||
void hci_register_sco_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size));
|
||||
void hci_register_sco_packet_handler(btstack_packet_handler_t handler);
|
||||
|
||||
|
||||
// Sending HCI Commands
|
||||
|
12
src/l2cap.c
12
src/l2cap.c
@ -82,7 +82,7 @@ static void l2cap_emit_channel_closed(l2cap_channel_t *channel);
|
||||
static void l2cap_emit_connection_request(l2cap_channel_t *channel);
|
||||
static int l2cap_channel_ready_for_open(l2cap_channel_t *channel);
|
||||
static void l2cap_hci_event_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
|
||||
static void l2cap_acl_handler(uint8_t packet_type, uint8_t *packet, uint16_t size );
|
||||
static void l2cap_acl_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size );
|
||||
static void l2cap_notify_channel_can_send(void);
|
||||
|
||||
typedef struct l2cap_fixed_channel {
|
||||
@ -1381,7 +1381,7 @@ static void l2cap_signaling_handler_dispatch( hci_con_handle_t handle, uint8_t *
|
||||
}
|
||||
}
|
||||
|
||||
static void l2cap_acl_handler(uint8_t packet_type, uint8_t *packet, uint16_t size ){
|
||||
static void l2cap_acl_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size ){
|
||||
|
||||
// Get Channel ID
|
||||
uint16_t channel_id = READ_L2CAP_CHANNEL_ID(packet);
|
||||
@ -1487,9 +1487,9 @@ static void l2cap_acl_handler(uint8_t packet_type, uint8_t *packet, uint16_t siz
|
||||
|
||||
default: {
|
||||
// Find channel for this channel_id and connection handle
|
||||
l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(channel_id);
|
||||
if (channel) {
|
||||
l2cap_dispatch_to_channel(channel, L2CAP_DATA_PACKET, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
|
||||
l2cap_channel_t * l2cap_channel = l2cap_get_channel_for_local_cid(channel_id);
|
||||
if (l2cap_channel) {
|
||||
l2cap_dispatch_to_channel(l2cap_channel, L2CAP_DATA_PACKET, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1499,7 +1499,7 @@ static void l2cap_acl_handler(uint8_t packet_type, uint8_t *packet, uint16_t siz
|
||||
}
|
||||
|
||||
// finalize closed channel - l2cap_handle_disconnect_request & DISCONNECTION_RESPONSE
|
||||
void l2cap_finialize_channel_close(l2cap_channel_t *channel){
|
||||
void l2cap_finialize_channel_close(l2cap_channel_t * channel){
|
||||
channel->state = L2CAP_STATE_CLOSED;
|
||||
l2cap_emit_channel_closed(channel);
|
||||
// discard channel
|
||||
|
@ -346,7 +346,8 @@ static void simulate_test_sequence(hfp_test_item_t * test_item){
|
||||
}
|
||||
}
|
||||
|
||||
void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t event_size){
|
||||
|
||||
if (event[0] != HCI_EVENT_HFP_META) return;
|
||||
|
||||
if (event[3]
|
||||
|
@ -391,7 +391,7 @@ void simulate_test_sequence(hfp_test_item_t * test_item){
|
||||
}
|
||||
}
|
||||
|
||||
void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t event_size){
|
||||
if (event[0] != HCI_EVENT_HFP_META) return;
|
||||
|
||||
switch (event[2]) {
|
||||
|
@ -570,7 +570,7 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac
|
||||
}
|
||||
|
||||
|
||||
static void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t event_size){
|
||||
switch (event[0]){
|
||||
case HCI_EVENT_INQUIRY_RESULT:
|
||||
case HCI_EVENT_INQUIRY_RESULT_WITH_RSSI:
|
||||
|
@ -462,7 +462,7 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac
|
||||
}
|
||||
|
||||
|
||||
static void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t event_size){
|
||||
if (event[0] != HCI_EVENT_HFP_META) return;
|
||||
|
||||
switch (event[2]) {
|
||||
|
@ -154,7 +154,7 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac
|
||||
}
|
||||
|
||||
// Audio Gateway routines
|
||||
static void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t event_size){
|
||||
switch (event[2]) {
|
||||
case HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE:
|
||||
if (event[3] == 0){
|
||||
|
@ -159,7 +159,7 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac
|
||||
}
|
||||
}
|
||||
|
||||
static void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t event_size){
|
||||
// printf("Packet handler event 0x%02x\n", event[0]);
|
||||
switch (event[0]) {
|
||||
case BTSTACK_EVENT_STATE:
|
||||
|
Loading…
x
Reference in New Issue
Block a user