Merge branch 'master' into develop

This commit is contained in:
Matthias Ringwald 2016-05-02 17:36:41 +02:00
commit 0f78faa83f
27 changed files with 506 additions and 392 deletions

View File

@ -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 # 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). GATT, SM of the Bluetooth 4.2 LE Central and Peripheral roles (QD ID 25340).
## Documentation ## Documentation
- [HTML](http://bluekitchen-gmbh.com/btstack/v1.0) - [HTML](http://bluekitchen-gmbh.com/btstack)
- [PDF](http://bluekitchen-gmbh.com/btstack_v1.0.pdf) - [PDF](http://bluekitchen-gmbh.com/btstack.pdf)
## Supported Protocols ## Supported Protocols
* L2CAP * L2CAP

View File

@ -61,14 +61,29 @@
#endif #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]; uint8_t hfp_service_buffer[150];
const uint8_t rfcomm_channel_nr = 1; const uint8_t rfcomm_channel_nr = 1;
const char hfp_ag_service_name[] = "BTstack HFP AG Test"; 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 uint8_t codecs[1] = {HFP_CODEC_CVSD};
static uint16_t handle = -1; static uint16_t handle = -1;
static hci_con_handle_t sco_handle;
static int memory_1_enabled = 1; static int memory_1_enabled = 1;
static int ag_indicators_nr = 7; 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); numResponses = hci_event_inquiry_result_get_num_responses(packet);
int offset = 3; int offset = 3;
for (i=0; i<numResponses && deviceCount < MAX_DEVICES;i++){ for (i=0; i<numResponses && deviceCount < MAX_DEVICES;i++){
reverse_bd_addr(addr, &packet[offset]); reverse_bd_addr(&packet[offset], addr);
offset += 6; offset += 6;
index = getDeviceIndexForAddress(addr); index = getDeviceIndexForAddress(addr);
if (index >= 0) continue; // already in our list 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; break;
case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE: case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE:
reverse_bd_addr(addr, &packet[3]); reverse_bd_addr(&packet[3], addr);
index = getDeviceIndexForAddress(addr); index = getDeviceIndexForAddress(addr);
if (index >= 0) { if (index >= 0) {
if (packet[2] == 0) { if (packet[2] == 0) {
@ -259,10 +274,13 @@ static void show_usage(void);
// Testig User Interface // Testig User Interface
static void show_usage(void){ 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("---\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("A - release HFP connection to PTS module\n");
printf("b - establish AUDIO connection\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; break;
case 't': case 't':
log_info("USER:\'%c\'", cmd); log_info("USER:\'%c\'", cmd);
printf("Terminate HCI connection.\n"); printf("Terminate HCI connection. 0x%2x\n", handle);
gap_disconnect(handle); gap_disconnect(handle);
break; break;
case 'u': case 'u':
@ -547,77 +565,122 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac
} }
#endif #endif
static void packet_handler(uint8_t * event, uint16_t event_size){ #define SCO_REPORT_PERIOD 100
switch (event[0]){ static void send_sco_data(void){
case HCI_EVENT_INQUIRY_RESULT: if (!sco_handle) return;
case HCI_EVENT_INQUIRY_RESULT_WITH_RSSI:
case HCI_EVENT_INQUIRY_COMPLETE: const int sco_packet_length = hci_get_sco_packet_length();
case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE: const int sco_payload_length = sco_packet_length - 3;
inquiry_packet_handler(HCI_EVENT_PACKET, event, event_size); const int frames_per_packet = sco_payload_length; // for 8-bit data. for 16-bit data it's /2
break;
default: hci_reserve_packet_buffer();
break; 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] static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t event_size){
&& event[2] != HFP_SUBEVENT_PLACE_CALL_WITH_NUMBER switch (packet_type){
&& event[2] != HFP_SUBEVENT_ATTACH_NUMBER_TO_VOICE_TAG case HCI_EVENT_PACKET:
&& event[2] != HFP_SUBEVENT_TRANSMIT_DTMF_CODES){ switch (event[0]){
printf("ERROR, status: %u\n", event[3]); case HCI_EVENT_INQUIRY_RESULT:
return; case HCI_EVENT_INQUIRY_RESULT_WITH_RSSI:
} case HCI_EVENT_INQUIRY_COMPLETE:
case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE:
switch (event[2]) { inquiry_packet_handler(HCI_EVENT_PACKET, event, event_size);
case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED: break;
handle = hfp_subevent_service_level_connection_established_get_con_handle(event); case HCI_EVENT_SCO_CAN_SEND_NOW:
printf("Service level connection established.\n"); send_sco_data();
break; break;
case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED: default:
printf("Service level connection released.\n"); break;
break; }
case HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED:
printf("\n** Audio connection established **\n"); if (event[0] != HCI_EVENT_HFP_META) return;
break;
case HFP_SUBEVENT_AUDIO_CONNECTION_RELEASED: if (event[3]
printf("\n** Audio connection released **\n"); && event[2] != HFP_SUBEVENT_PLACE_CALL_WITH_NUMBER
break; && event[2] != HFP_SUBEVENT_ATTACH_NUMBER_TO_VOICE_TAG
case HFP_SUBEVENT_START_RINGINIG: && event[2] != HFP_SUBEVENT_TRANSMIT_DTMF_CODES){
printf("\n** Start Ringing **\n"); printf("ERROR, status: %u\n", event[3]);
break; return;
case HFP_SUBEVENT_STOP_RINGINIG: }
printf("\n** Stop Ringing **\n");
break; switch (event[2]) {
case HFP_SUBEVENT_PLACE_CALL_WITH_NUMBER: case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
printf("\n** Outgoing call '%s' **\n", hfp_subevent_place_call_with_number_get_number(event)); handle = hfp_subevent_service_level_connection_established_get_con_handle(event);
// validate number printf("Service level connection established.\n");
if ( strcmp("1234567", hfp_subevent_place_call_with_number_get_number(event)) == 0 break;
|| strcmp("7654321", hfp_subevent_place_call_with_number_get_number(event)) == 0 case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED:
|| (memory_1_enabled && strcmp(">1", hfp_subevent_place_call_with_number_get_number(event)) == 0)){ printf("Service level connection released.\n");
printf("Dialstring valid: accept call\n"); sco_handle = 0;
hfp_ag_outgoing_call_accepted(); break;
} else { case HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED:
printf("Dialstring invalid: reject call\n"); if (hfp_subevent_audio_connection_established_get_status(event)){
hfp_ag_outgoing_call_rejected(); 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: default:
printf("Event not handled %u\n", event[2]);
break; 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[]);
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(rfcomm_channel_nr);
hfp_ag_init_supported_features(0x3ef | (1<<HFP_AGSF_HF_INDICATORS) | (1<<HFP_AGSF_ESCO_S4)); 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_codecs(sizeof(codecs), codecs);
hfp_ag_init_ag_indicators(ag_indicators_nr, ag_indicators); hfp_ag_init_ag_indicators(ag_indicators_nr, ag_indicators);
hfp_ag_init_hf_indicators(hf_indicators_nr, hf_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_init_call_hold_services(call_hold_services_nr, call_hold_services);
hfp_ag_set_subcriber_number_information(&subscriber_number, 1); 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)); 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); 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)); printf("SDP service record size: %u\n", de_get_len( hfp_service_buffer));

View File

@ -85,7 +85,7 @@ static void show_usage(void){
printf("\n--- Bluetooth HFP Hands-Free (HF) unit Test Console ---\n"); printf("\n--- Bluetooth HFP Hands-Free (HF) unit Test Console ---\n");
printf("---\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("A - release SLC connection to device\n");
printf("b - establish Audio connection\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 #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; if (event[0] != HCI_EVENT_HFP_META) return;
switch (event[2]) { switch (event[2]) {

View File

@ -215,77 +215,84 @@ static void send_sco_data(void){
hci_request_sco_can_send_now_event(); hci_request_sco_can_send_now_event();
static int count = 0; 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){ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t event_size){
return;
static int count = 0; 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 (packet_type){
switch (event[0]) {
case BTSTACK_EVENT_STATE: case HCI_SCO_DATA_PACKET:
if (event[2] != HCI_STATE_WORKING) break; count++;
show_usage(); if ((count & SCO_REPORT_PERIOD)) return;
printf("SCO packets received: %u\n", count);
break; break;
case HCI_EVENT_SCO_CAN_SEND_NOW:
send_sco_data(); case HCI_EVENT_PACKET:
break; switch (event[0]) {
case HCI_EVENT_HSP_META: case BTSTACK_EVENT_STATE:
switch (event[2]) { if (event[2] != HCI_STATE_WORKING) break;
case HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE: show_usage();
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");
}
break; break;
case HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE: case HCI_EVENT_SCO_CAN_SEND_NOW:
if (hsp_subevent_rfcomm_disconnection_complete_get_status(event)){ send_sco_data();
printf("RFCOMM disconnection failed with status %u.\n", hsp_subevent_rfcomm_disconnection_complete_get_status(event)); break;
} else { case HCI_EVENT_HSP_META:
printf("RFCOMM disconnected.\n"); 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; 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: default:
printf("event not handled %u\n", event[2]);
break; break;
} }
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[]);
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(); l2cap_init();
sdp_init(); sdp_init();
@ -326,7 +331,8 @@ int btstack_main(int argc, const char * argv[]){
rfcomm_init(); rfcomm_init();
hsp_ag_init(rfcomm_channel_nr); 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 #ifdef HAVE_POSIX_STDIN
btstack_stdin_setup(stdin_process); btstack_stdin_setup(stdin_process);

View File

@ -216,94 +216,93 @@ static void send_sco_data(void){
static int count = 0; static int count = 0;
count++; 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 void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t event_size){
static int count = 0; static int sco_rev_count = 0;
// hexdumpf(packet, size); switch (packet_type){
count++; case HCI_SCO_DATA_PACKET:
if ((count & SCO_REPORT_PERIOD)) return; sco_rev_count++;
printf("SCO packets %u\n", count); if ((sco_rev_count & SCO_REPORT_PERIOD)) break;
} printf("SCO packets received: %u\n", sco_rev_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();
break; break;
case HCI_EVENT_SCO_CAN_SEND_NOW: case HCI_EVENT_PACKET:
send_sco_data(); switch (event[0]) {
break; case BTSTACK_EVENT_STATE:
case HCI_EVENT_HSP_META: if (btstack_event_state_get_state(event) != HCI_STATE_WORKING) break;
switch (event[2]) { show_usage();
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");
}
break; break;
case HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE: case HCI_EVENT_SCO_CAN_SEND_NOW:
if (hsp_subevent_rfcomm_disconnection_complete_get_status(event)){ send_sco_data();
printf("RFCOMM disconnection failed with status %u.\n", hsp_subevent_rfcomm_disconnection_complete_get_status(event));
} else {
printf("RFCOMM disconnected.\n");
}
break; break;
case HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE: case HCI_EVENT_HSP_META:
if (hsp_subevent_audio_connection_complete_get_status(event)){ switch (event[2]) {
printf("Audio connection establishment failed with status %u\n", hsp_subevent_audio_connection_complete_get_status(event)); case HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE:
sco_handle = 0; if (hsp_subevent_rfcomm_connection_complete_get_status(event)){
} else { printf("RFCOMM connection establishement failed with status %u\n", hsp_subevent_rfcomm_connection_complete_get_status(event));
sco_handle = hsp_subevent_audio_connection_complete_get_handle(event); } else {
printf("Audio connection established with SCO handle 0x%04x.\n", sco_handle); printf("RFCOMM connection established.\n");
hci_request_sco_can_send_now_event(); }
} break;
break; case HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE:
case HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE: if (hsp_subevent_rfcomm_disconnection_complete_get_status(event)){
if (hsp_subevent_audio_disconnection_complete_get_status(event)){ printf("RFCOMM disconnection failed with status %u.\n", hsp_subevent_rfcomm_disconnection_complete_get_status(event));
printf("Audio connection releasing failed with status %u\n", hsp_subevent_audio_disconnection_complete_get_status(event)); } else {
} else { printf("RFCOMM disconnected.\n");
printf("Audio connection released.\n\n"); }
sco_handle = 0; break;
} case HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE:
break; if (hsp_subevent_audio_connection_complete_get_status(event)){
case HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED: printf("Audio connection establishment failed with status %u\n", hsp_subevent_audio_connection_complete_get_status(event));
printf("Received microphone gain change %d\n", hsp_subevent_microphone_gain_changed_get_gain(event)); sco_handle = 0;
break; } else {
case HSP_SUBEVENT_SPEAKER_GAIN_CHANGED: sco_handle = hsp_subevent_audio_connection_complete_get_handle(event);
printf("Received speaker gain change %d\n", hsp_subevent_speaker_gain_changed_get_gain(event)); printf("Audio connection established with SCO handle 0x%04x.\n", sco_handle);
break; hci_request_sco_can_send_now_event();
case HSP_SUBEVENT_RING: }
printf("HS: RING RING!\n"); break;
break; case HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE:
case HSP_SUBEVENT_AG_INDICATION: { if (hsp_subevent_audio_disconnection_complete_get_status(event)){
memset(hs_cmd_buffer, 0, sizeof(hs_cmd_buffer)); printf("Audio connection releasing failed with status %u\n", hsp_subevent_audio_disconnection_complete_get_status(event));
int size = hsp_subevent_ag_indication_get_value_length(event); } else {
if (size >= sizeof(hs_cmd_buffer)-1){ printf("Audio connection released.\n\n");
size = sizeof(hs_cmd_buffer)-1; sco_handle = 0;
} }
memcpy(hs_cmd_buffer, hsp_subevent_ag_indication_get_value(event), size); break;
printf("Received custom indication: \"%s\". \nExit code or call hsp_hs_send_result.\n", hs_cmd_buffer); 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; break;
default: default:
printf("event not handled %u\n", event[2]);
break; break;
} }
break;
default: default:
break; 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 /* @section Main Application Setup
* *
* @text Listing MainConfiguration shows main application code. * @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[]){ int btstack_main(int argc, const char * argv[]){
// register for HCI events // 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_add_event_handler(&hci_event_callback_registration);
hci_register_sco_packet_handler(&sco_packet_handler); hci_register_sco_packet_handler(&packet_handler);
l2cap_init(); l2cap_init();

View File

@ -67,6 +67,7 @@ typedef enum {
H4_W4_PACKET_TYPE = 1, H4_W4_PACKET_TYPE = 1,
H4_W4_EVENT_HEADER, H4_W4_EVENT_HEADER,
H4_W4_ACL_HEADER, H4_W4_ACL_HEADER,
H4_W4_SCO_HEADER,
H4_W4_PAYLOAD, H4_W4_PAYLOAD,
H4_PACKET_RECEIVED H4_PACKET_RECEIVED
} H4_STATE; } H4_STATE;
@ -172,13 +173,17 @@ static void h4_block_received(void){
switch (h4_state) { switch (h4_state) {
case H4_W4_PACKET_TYPE: case H4_W4_PACKET_TYPE:
switch (hci_packet[0]) { 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: case HCI_ACL_DATA_PACKET:
h4_state = H4_W4_ACL_HEADER; h4_state = H4_W4_ACL_HEADER;
bytes_to_read = HCI_ACL_HEADER_SIZE; bytes_to_read = HCI_ACL_HEADER_SIZE;
break; break;
case HCI_EVENT_PACKET: case HCI_SCO_DATA_PACKET:
h4_state = H4_W4_EVENT_HEADER; h4_state = H4_W4_SCO_HEADER;
bytes_to_read = HCI_EVENT_HEADER_SIZE; bytes_to_read = HCI_SCO_HEADER_SIZE;
break; break;
default: default:
log_error("h4_process: invalid packet type 0x%02x", hci_packet[0]); 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; h4_state = H4_W4_PAYLOAD;
break; 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: case H4_W4_PAYLOAD:
h4_state = H4_PACKET_RECEIVED; h4_state = H4_PACKET_RECEIVED;
bytes_to_read = 0; bytes_to_read = 0;

View File

@ -904,9 +904,10 @@ typedef uint8_t sm_key_t[16];
#define HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED 0x02 #define HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED 0x02
/** /**
* @format 11 * @format 11H
* @param subevent_code * @param subevent_code
* @param status 0 == OK * @param status 0 == OK
* @param handle
*/ */
#define HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED 0x03 #define HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED 0x03

View File

@ -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){ static inline uint8_t hfp_subevent_audio_connection_established_get_status(const uint8_t * event){
return event[3]; 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);
}
/** /**

View File

@ -96,10 +96,12 @@ static const char * hfp_ag_features[] = {
static btstack_linked_list_t hfp_connections = NULL; static btstack_linked_list_t hfp_connections = NULL;
static void parse_sequence(hfp_connection_t * context); 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; 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; hfp_callback = callback;
} }
@ -184,26 +186,26 @@ int join_bitmap(char * buffer, int buffer_size, uint32_t values, int values_nr){
return offset; 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; if (!callback) return;
uint8_t event[3]; uint8_t event[3];
event[0] = HCI_EVENT_HFP_META; event[0] = HCI_EVENT_HFP_META;
event[1] = sizeof(event) - 2; event[1] = sizeof(event) - 2;
event[2] = event_subtype; 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; if (!callback) return;
uint8_t event[4]; uint8_t event[4];
event[0] = HCI_EVENT_HFP_META; event[0] = HCI_EVENT_HFP_META;
event[1] = sizeof(event) - 2; event[1] = sizeof(event) - 2;
event[2] = event_subtype; event[2] = event_subtype;
event[3] = value; // status 0 == OK 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; if (!callback) return;
uint8_t event[6]; uint8_t event[6];
event[0] = HCI_EVENT_HFP_META; 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[2] = event_subtype;
event[3] = status; // status 0 == OK event[3] = status; // status 0 == OK
little_endian_store_16(event, 4, con_handle); 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; if (!callback) return;
uint8_t event[40]; uint8_t event[40];
event[0] = HCI_EVENT_HFP_META; 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; int size = (strlen(value) < sizeof(event) - 4) ? strlen(value) : sizeof(event) - 4;
strncpy((char*)&event[3], value, size); strncpy((char*)&event[3], value, size);
event[3 + size] = 0; event[3 + size] = 0;
(*callback)(event, sizeof(event)); (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
} }
btstack_linked_list_t * hfp_get_connections(void){ 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){ void hfp_handle_hci_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
bd_addr_t event_addr; bd_addr_t event_addr;
uint16_t rfcomm_cid, handle; uint16_t rfcomm_cid, handle;
hfp_connection_t * hfp_connection = NULL; hfp_connection_t * hfp_connection = NULL;
uint8_t status; 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)) { 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: default:
break; break;
} }
rfcomm_request_can_send_now_event(hfp_connection->rfcomm_cid);
} }
break; 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:{ case HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE:{
reverse_bd_addr(&packet[5], event_addr); 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++]; status = packet[index++];
if (status != 0){ if (status != 0){
log_error("(e)SCO Connection failed status %u", status); hfp_handle_failed_sco_connection(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;
break; break;
} }
@ -1331,10 +1353,12 @@ static const struct link_settings {
{ 0x000d, 0x02, 0x0380 } // HFP_LINK_SETTINGS_T2, 2-EV3 { 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 // all packet types, fixed bandwidth
int setting = hfp_connection->link_setting;
log_info("hfp_setup_synchronous_connection using setting nr %u", 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 hci_get_sco_voice_setting(), hfp_link_settings[setting].retransmission_effort, hfp_link_settings[setting].packet_types); // all types 0x003f, only 2-ev3 0x380
} }

View File

@ -432,8 +432,6 @@ typedef enum{
HFP_CALL_SM HFP_CALL_SM
} hfp_state_machine_t; } hfp_state_machine_t;
typedef void (*hfp_callback_t)(uint8_t * event, uint16_t event_size);
typedef struct{ typedef struct{
uint16_t uuid; uint16_t uuid;
uint8_t state; // enabled 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); int store_bit(uint32_t bitmap, int position, uint8_t value);
// UTILS_END // 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_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_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_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_event(btstack_packet_handler_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_simple_event(btstack_packet_handler_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_string_event(btstack_packet_handler_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_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_rfcomm_cid(uint16_t cid);
hfp_connection_t * get_hfp_connection_context_for_bd_addr(bd_addr_t bd_addr); 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_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_hf_feature(int index);
const char * hfp_ag_feature(int index); const char * hfp_ag_feature(int index);

View File

@ -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 int hfp_ag_call_hold_services_nr = 0;
static char *hfp_ag_call_hold_services[6]; 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 hfp_response_and_hold_state_t hfp_ag_response_and_hold_state;
static int hfp_ag_response_and_hold_active = 0; 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){ if (callback == NULL){
log_error("hfp_ag_register_packet_handler called with NULL callback"); log_error("hfp_ag_register_packet_handler called with NULL callback");
return; return;
@ -557,7 +557,6 @@ static int codecs_exchange_state_machine(hfp_connection_t * hfp_connection){
switch (hfp_connection->command){ switch (hfp_connection->command){
case HFP_CMD_AVAILABLE_CODECS: case HFP_CMD_AVAILABLE_CODECS:
//printf("HFP_CODECS_RECEIVED_LIST \n");
if (hfp_connection->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED){ if (hfp_connection->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED){
hfp_connection->codecs_state = HFP_CODECS_RECEIVED_LIST; hfp_connection->codecs_state = HFP_CODECS_RECEIVED_LIST;
hfp_ag_ok(hfp_connection->rfcomm_cid); hfp_ag_ok(hfp_connection->rfcomm_cid);
@ -576,20 +575,17 @@ static int codecs_exchange_state_machine(hfp_connection_t * hfp_connection){
return 1; return 1;
case HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP: 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_connection->codecs_state = HFP_CODECS_RECEIVED_TRIGGER_CODEC_EXCHANGE;
hfp_ag_ok(hfp_connection->rfcomm_cid); hfp_ag_ok(hfp_connection->rfcomm_cid);
return 1; return 1;
case HFP_CMD_AG_SEND_COMMON_CODEC: 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->codecs_state = HFP_CODECS_AG_SENT_COMMON_CODEC;
hfp_connection->suggested_codec = hfp_ag_suggest_codec(hfp_connection); hfp_connection->suggested_codec = hfp_ag_suggest_codec(hfp_connection);
hfp_ag_cmd_suggest_codec(hfp_connection->rfcomm_cid, hfp_connection->suggested_codec); hfp_ag_cmd_suggest_codec(hfp_connection->rfcomm_cid, hfp_connection->suggested_codec);
return 1; return 1;
case HFP_CMD_HF_CONFIRMED_CODEC: case HFP_CMD_HF_CONFIRMED_CODEC:
//printf("HFP_CMD_HF_CONFIRMED_CODEC \n");
if (hfp_connection->codec_confirmed != hfp_connection->suggested_codec){ if (hfp_connection->codec_confirmed != hfp_connection->suggested_codec){
hfp_connection->codecs_state = HFP_CODECS_ERROR; hfp_connection->codecs_state = HFP_CODECS_ERROR;
hfp_ag_error(hfp_connection->rfcomm_cid); 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){ 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; if (hfp_connection->state >= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return 0;
int done = 0; int done = 0;
// printf(" -> State machine: SLC\n");
switch(hfp_connection->command){ switch(hfp_connection->command){
case HFP_CMD_SUPPORTED_FEATURES: case HFP_CMD_SUPPORTED_FEATURES:
switch(hfp_connection->state){ 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: case HFP_CMD_RETRIEVE_AG_INDICATORS:
if (hfp_connection->state == HFP_W4_RETRIEVE_INDICATORS) { if (hfp_connection->state == HFP_W4_RETRIEVE_INDICATORS) {
hfp_connection->command = HFP_CMD_NONE; // prevent reentrance // HF requested AG Indicators and we did expect it
int next_segment = hfp_ag_retrieve_indicators_cmd_via_generator(hfp_connection->rfcomm_cid, hfp_connection, hfp_connection->send_ag_indicators_segment); hfp_connection->state = HFP_RETRIEVE_INDICATORS;
if (next_segment < hfp_ag_indicators_cmd_generator_num_segments(hfp_connection)){ // continue below in state switch
// 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;
} }
break; break;
@ -729,16 +716,35 @@ static int hfp_ag_run_for_context_service_level_connection(hfp_connection_t * hf
default: default:
break; 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; return done;
} }
static int hfp_ag_run_for_context_service_level_connection_queries(hfp_connection_t * hfp_connection){ 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); int done = codecs_exchange_state_machine(hfp_connection);
if (done) return done; if (done) return done;
// printf(" -> State machine: SLC Queries\n");
switch(hfp_connection->command){ switch(hfp_connection->command){
case HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION: 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); 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 // run codecs exchange
int done = codecs_exchange_state_machine(hfp_connection); int done = codecs_exchange_state_machine(hfp_connection);
if (done) return done; if (done) return done;
// printf(" -> State machine: Audio hfp_connection\n");
if (hfp_connection->codecs_state != HFP_CODECS_EXCHANGED) return done; if (hfp_connection->codecs_state != HFP_CODECS_EXCHANGED) return done;
if (hfp_connection->establish_audio_connection){ if (hfp_connection->establish_audio_connection){
hfp_connection->state = HFP_W4_SCO_CONNECTED; hfp_connection->state = HFP_W4_SCO_CONNECTED;
hfp_connection->establish_audio_connection = 0; 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 1;
} }
return 0; 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){ 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) return;
if (!hfp_connection->rfcomm_cid) return; if (!hfp_connection->rfcomm_cid) return;
if (!rfcomm_can_send_packet_now(hfp_connection->rfcomm_cid)) { 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); rfcomm_request_can_send_now_event(hfp_connection->rfcomm_cid);
return; return;
} }
@ -1763,6 +1774,10 @@ static void hfp_run_for_context(hfp_connection_t *hfp_connection){
if (done){ if (done){
hfp_connection->command = HFP_CMD_NONE; 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){ 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_event_callback_registration.callback = &packet_handler;
hci_add_event_handler(&hci_event_callback_registration); hci_add_event_handler(&hci_event_callback_registration);
l2cap_init();
rfcomm_register_service(&packet_handler, rfcomm_channel_nr, 0xffff); rfcomm_register_service(&packet_handler, rfcomm_channel_nr, 0xffff);
hfp_ag_response_and_hold_active = 0; hfp_ag_response_and_hold_active = 0;

View File

@ -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. * @brief Register callback for the HFP Audio Gateway (AG) client.
* @param callback * @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. * @brief Enable in-band ring tone.

View File

@ -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_speaker_gain = 9;
static uint8_t hfp_hf_microphone_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_call_status_t hfp_call_status;
static hfp_callsetup_status_t hfp_callsetup_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; 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; hfp_callback = callback;
if (callback == NULL){ if (callback == NULL){
log_error("hfp_hf_register_packet_handler called with NULL callback"); 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); 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; if (!callback) return;
uint8_t event[31]; uint8_t event[31];
event[0] = HCI_EVENT_HFP_META; 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; int size = (strlen(bnip_number) < sizeof(event) - 6) ? strlen(bnip_number) : sizeof(event) - 6;
strncpy((char*)&event[5], bnip_number, size); strncpy((char*)&event[5], bnip_number, size);
event[5 + size] = 0; 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; if (!callback) return;
uint8_t event[30]; uint8_t event[30];
event[0] = HCI_EVENT_HFP_META; 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; int size = (strlen(bnip_number) < sizeof(event) - 5) ? strlen(bnip_number) : sizeof(event) - 5;
strncpy((char*)&event[4], bnip_number, size); strncpy((char*)&event[4], bnip_number, size);
event[4 + size] = 0; 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){ uint8_t clcc_status, uint8_t clcc_mpty, uint8_t bnip_type, const char * bnip_number){
if (!callback) return; if (!callback) return;
uint8_t event[35]; 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; int size = (strlen(bnip_number) < sizeof(event) - 10) ? strlen(bnip_number) : sizeof(event) - 10;
strncpy((char*)&event[9], bnip_number, size); strncpy((char*)&event[9], bnip_number, size);
event[9 + size] = 0; 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){ 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); 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; if (!callback) return;
uint8_t event[5+HFP_MAX_INDICATOR_DESC_SIZE+1]; uint8_t event[5+HFP_MAX_INDICATOR_DESC_SIZE+1];
event[0] = HCI_EVENT_HFP_META; 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; event[4] = indicator.status;
strncpy((char*)&event[5], indicator.name, HFP_MAX_INDICATOR_DESC_SIZE); strncpy((char*)&event[5], indicator.name, HFP_MAX_INDICATOR_DESC_SIZE);
event[5+HFP_MAX_INDICATOR_DESC_SIZE] = 0; 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; if (!callback) return;
uint8_t event[24]; uint8_t event[24];
event[0] = HCI_EVENT_HFP_META; 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[3] = network_operator.mode;
event[4] = network_operator.format; event[4] = network_operator.format;
strcpy((char*)&event[5], network_operator.name); 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){ 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){ if (hfp_connection->establish_audio_connection){
hfp_connection->state = HFP_W4_SCO_CONNECTED; hfp_connection->state = HFP_W4_SCO_CONNECTED;
hfp_connection->establish_audio_connection = 0; 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 1;
} }
@ -1083,8 +1083,6 @@ void hfp_hf_init(uint16_t rfcomm_channel_nr){
hci_event_callback_registration.callback = &packet_handler; hci_event_callback_registration.callback = &packet_handler;
hci_add_event_handler(&hci_event_callback_registration); hci_add_event_handler(&hci_event_callback_registration);
l2cap_init();
rfcomm_register_service(packet_handler, rfcomm_channel_nr, 0xffff); rfcomm_register_service(packet_handler, rfcomm_channel_nr, 0xffff);
hfp_set_packet_handler_for_rfcomm_connections(&packet_handler); hfp_set_packet_handler_for_rfcomm_connections(&packet_handler);

View File

@ -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. * @brief Register callback for the HFP Hands-Free (HF) client.
* @param callback * @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, * @brief Establish RFCOMM connection with the AG with given Bluetooth address,

View File

@ -124,15 +124,15 @@ typedef enum {
static hsp_state_t hsp_state = HSP_IDLE; 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 hsp_run(void);
static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 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 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){ if (callback == NULL){
callback = &dummy_notify; callback = &dummy_notify;
} }
@ -146,7 +146,7 @@ static void emit_event(uint8_t event_subtype, uint8_t value){
event[1] = sizeof(event) - 2; event[1] = sizeof(event) - 2;
event[2] = event_subtype; event[2] = event_subtype;
event[3] = value; // status 0 == OK 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){ 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[2] = HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE;
event[3] = status; event[3] = status;
little_endian_store_16(event, 4, handle); 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){ 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[1] = size + 2;
event[2] = HSP_SUBEVENT_HS_COMMAND; event[2] = HSP_SUBEVENT_HS_COMMAND;
event[3] = size; event[3] = size;
(*hsp_ag_callback)(event, size+4); (*hsp_ag_callback)(HCI_EVENT_PACKET, 0, event, size+4);
} }
hsp_run(); hsp_run();

View File

@ -54,23 +54,6 @@ extern "C" {
/* API_START */ /* 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. * @brief Set up HSP AG.
* @param rfcomm_channel_nr * @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. * @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 * @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. * @brief Connect to HSP Headset.

View File

@ -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 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 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 btstack_packet_handler_t hsp_hs_callback;
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_hs_register_packet_handler(hsp_hs_callback_t callback){ void hsp_hs_register_packet_handler(btstack_packet_handler_t callback){
if (callback == NULL){ if (callback == NULL){
callback = &dummy_notify; callback = &dummy_notify;
} }
@ -140,7 +140,7 @@ static void emit_event(uint8_t event_subtype, uint8_t value){
event[1] = sizeof(event) - 2; event[1] = sizeof(event) - 2;
event[2] = event_subtype; event[2] = event_subtype;
event[3] = value; // status 0 == OK 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){ static void emit_ring_event(void){
@ -149,7 +149,7 @@ static void emit_ring_event(void){
event[0] = HCI_EVENT_HSP_META; event[0] = HCI_EVENT_HSP_META;
event[1] = sizeof(event) - 2; event[1] = sizeof(event) - 2;
event[2] = HSP_SUBEVENT_RING; 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){ 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[2] = HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE;
event[3] = status; event[3] = status;
little_endian_store_16(event, 4, handle); 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 // 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_event_callback_registration.callback = &packet_handler;
hci_add_event_handler(&hci_event_callback_registration); hci_add_event_handler(&hci_event_callback_registration);
// init L2CAP
l2cap_init();
rfcomm_init(); rfcomm_init();
rfcomm_register_service(packet_handler, rfcomm_channel_nr, 0xffff); // reserved channel, mtu limited by l2cap 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[1] = size + 2;
event[2] = HSP_SUBEVENT_AG_INDICATION; event[2] = HSP_SUBEVENT_AG_INDICATION;
event[3] = size; event[3] = size;
(*hsp_hs_callback)(event, size+4); (*hsp_hs_callback)(HCI_EVENT_PACKET, 0, event, size+4);
} }
hsp_run(); hsp_run();
return; return;
@ -590,7 +587,7 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
case RFCOMM_EVENT_CHANNEL_CLOSED: case RFCOMM_EVENT_CHANNEL_CLOSED:
hsp_hs_reset_state(); hsp_hs_reset_state();
hsp_hs_callback(packet, size); hsp_hs_callback(HCI_EVENT_PACKET, 0, packet, size);
break; break;
default: default:

View File

@ -54,24 +54,6 @@ extern "C" {
/* API_START */ /* 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. * @brief Set up HSP HS.
* @param rfcomm_channel_nr * @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. * @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 * @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. * @brief Connect to HSP Audio Gateway.

View File

@ -1860,7 +1860,7 @@ static void event_handler(uint8_t *packet, int size){
static void sco_handler(uint8_t * packet, uint16_t size){ static void sco_handler(uint8_t * packet, uint16_t size){
if (!hci_stack->sco_packet_handler) return; 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){ 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 */ /** 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; hci_stack->acl_packet_handler = handler;
} }
/** /**
* @brief Registers a packet handler for SCO data. Used for HSP and HFP profiles. * @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; 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){ static void hci_emit_acl_packet(uint8_t * packet, uint16_t size){
if (!hci_stack->acl_packet_handler) return; 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){ 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; hci_stack->sco_waiting_for_can_send_now = 0;
uint8_t event[2] = { HCI_EVENT_SCO_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_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));
} }
} }

View File

@ -520,10 +520,10 @@ typedef struct {
btstack_linked_list_t connections; btstack_linked_list_t connections;
/* callback to L2CAP layer */ /* 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 */ /* 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 */ /* callbacks for events */
btstack_linked_list_t event_handlers; 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 * @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. * @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 // Sending HCI Commands

View File

@ -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 void l2cap_emit_connection_request(l2cap_channel_t *channel);
static int l2cap_channel_ready_for_open(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_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); static void l2cap_notify_channel_can_send(void);
typedef struct l2cap_fixed_channel { 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 // Get Channel ID
uint16_t channel_id = READ_L2CAP_CHANNEL_ID(packet); 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: { default: {
// Find channel for this channel_id and connection handle // Find channel for this channel_id and connection handle
l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(channel_id); l2cap_channel_t * l2cap_channel = l2cap_get_channel_for_local_cid(channel_id);
if (channel) { if (l2cap_channel) {
l2cap_dispatch_to_channel(channel, L2CAP_DATA_PACKET, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER); l2cap_dispatch_to_channel(l2cap_channel, L2CAP_DATA_PACKET, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
} }
break; 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 // 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; channel->state = L2CAP_STATE_CLOSED;
l2cap_emit_channel_closed(channel); l2cap_emit_channel_closed(channel);
// discard channel // discard channel

View File

@ -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[0] != HCI_EVENT_HFP_META) return;
if (event[3] if (event[3]

View File

@ -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; if (event[0] != HCI_EVENT_HFP_META) return;
switch (event[2]) { switch (event[2]) {

View File

@ -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]){ switch (event[0]){
case HCI_EVENT_INQUIRY_RESULT: case HCI_EVENT_INQUIRY_RESULT:
case HCI_EVENT_INQUIRY_RESULT_WITH_RSSI: case HCI_EVENT_INQUIRY_RESULT_WITH_RSSI:

View File

@ -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; if (event[0] != HCI_EVENT_HFP_META) return;
switch (event[2]) { switch (event[2]) {

View File

@ -154,7 +154,7 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac
} }
// Audio Gateway routines // 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]) { switch (event[2]) {
case HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE: case HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE:
if (event[3] == 0){ if (event[3] == 0){

View File

@ -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]); // printf("Packet handler event 0x%02x\n", event[0]);
switch (event[0]) { switch (event[0]) {
case BTSTACK_EVENT_STATE: case BTSTACK_EVENT_STATE: