Merge branch 'master' into ble-api-cleanup

This commit is contained in:
Matthias Ringwald 2016-02-15 22:06:55 +01:00
commit 66a048ab90
14 changed files with 390 additions and 325 deletions

View File

@ -167,7 +167,7 @@ hsp_hs_test: ${CORE_OBJ} ${COMMON_OBJ} ${SDP_CLIENT} hsp_hs.o hsp_hs_test.c
clean:
rm -f ${EXAMPLES}
rm -f *.o *.out *.hex
rm -f *.o *.out *.hex *.exe
rm -f ancs_client_demo.h profile.h spp_and_le_counter.h
rm -rf *.dSYM
rm -rf ${BTSTACK_ROOT}/ble/*.o

View File

@ -241,7 +241,7 @@ int btstack_main(int argc, const char * argv[]){
sdp_init();
memset(hsp_service_buffer, 0, sizeof(hsp_service_buffer));
hsp_hs_create_service(hsp_service_buffer, 0x10001, rfcomm_channel_nr, hsp_hs_service_name, 0);
hsp_hs_create_sdp_record(hsp_service_buffer, 0x10001, rfcomm_channel_nr, hsp_hs_service_name, 0);
sdp_register_service(hsp_service_buffer);
// turn on!

View File

@ -138,6 +138,10 @@ static struct libusb_transfer *acl_in_transfer[ASYNC_BUFFERS];
#ifdef HAVE_SCO
#ifdef _WIN32
#error "SCO not working on Win32 (Windows 8, libusb 1.0.19, Zadic WinUSB), please uncomment HAVE_SCO in btstack-config.h for now"
#endif
// incoming SCO
static H2_SCO_STATE sco_state;
static uint8_t sco_buffer[255+3 + SCO_PACKET_SIZE];

View File

@ -37,7 +37,7 @@
// *****************************************************************************
//
// Minimal setup for HFP Audio Gateway (AG) unit (!! UNDER DEVELOPMENT !!)
// HFP Audio Gateway (AG) unit
//
// *****************************************************************************

View File

@ -37,7 +37,7 @@
// *****************************************************************************
//
// Minimal setup for HFP Audio Gateway (AG) unit (!! UNDER DEVELOPMENT !!)
// HFP Audio Gateway (AG) unit
//
// *****************************************************************************
@ -80,6 +80,14 @@ void hfp_ag_init(uint16_t rfcomm_channel_nr, uint32_t supported_features,
*/
void hfp_ag_register_packet_handler(hfp_callback_t callback);
/**
* @brief Enable in-band ring tone
*/
void hfp_ag_set_use_in_band_ring_tone(int use_in_band_ring_tone);
// actions used by local device / user
/**
* @brief Establish RFCOMM connection, and perform service level connection agreement:
* - exchange of supported features
@ -93,72 +101,10 @@ void hfp_ag_establish_service_level_connection(bd_addr_t bd_addr);
/**
* @brief Release the RFCOMM channel and the audio connection between the HF and the AG.
* TODO: trigger release of the audio connection
* TODO: trigger release of the audio connection ??
*/
void hfp_ag_release_service_level_connection(bd_addr_t bd_addr);
/**
* @brief Report Extended Audio Gateway Error result codes in the AG.
* Whenever there is an error relating to the functionality of the AG as a
* result of AT command, the AG shall send +CME ERROR:
* - +CME ERROR: 0 - AG failure
* - +CME ERROR: 1 - no connection to phone
* - +CME ERROR: 3 - operation not allowed
* - +CME ERROR: 4 - operation not supported
* - +CME ERROR: 5 - PH-SIM PIN required
* - +CME ERROR: 10 - SIM not inserted
* - +CME ERROR: 11 - SIM PIN required
* - +CME ERROR: 12 - SIM PUK required
* - +CME ERROR: 13 - SIM failure
* - +CME ERROR: 14 - SIM busy
* - +CME ERROR: 16 - incorrect password
* - +CME ERROR: 17 - SIM PIN2 required
* - +CME ERROR: 18 - SIM PUK2 required
* - +CME ERROR: 20 - memory full
* - +CME ERROR: 21 - invalid index
* - +CME ERROR: 23 - memory failure
* - +CME ERROR: 24 - text string too long
* - +CME ERROR: 25 - invalid characters in text string
* - +CME ERROR: 26 - dial string too long
* - +CME ERROR: 27 - invalid characters in dial string
* - +CME ERROR: 30 - no network service
* - +CME ERROR: 31 - network Timeout.
* - +CME ERROR: 32 - network not allowed Emergency calls only
*/
void hfp_ag_report_extended_audio_gateway_error_result_code(bd_addr_t bd_addr, hfp_cme_error_t error);
/**
* @brief Report the change in AG's call status.
* Call status:
* - 0 = No calls (held or active)
* - 1 = Call is present (active or held)
*/
void hfp_ag_transfer_call_status(bd_addr_t bd_addr, hfp_call_status_t status);
/**
* @brief Report the change in AG's call setup status.
* Call setup status:
* - 0 = No call setup in progress
* - 1 = Incoming call setup in progress
* - 2 = Outgoing call setup in dialing state
* - 3 = Outgoing call setup in alerting state
*/
void hfp_ag_transfer_callsetup_status(bd_addr_t bd_addr, hfp_callsetup_status_t status);
/**
* @brief Report the change in AG's held call status.
* Held call status:
* - 0 = No calls held
* - 1 = Call is placed on hold or active/held calls are swapped
* - 2 = Call on hold, no active calls
*/
void hfp_ag_transfer_callheld_status(bd_addr_t bd_addr, hfp_callheld_status_t status);
/**
* @brief
*/
void hfp_ag_negotiate_codecs(bd_addr_t bd_addr);
/**
* @brief
*/
@ -169,11 +115,76 @@ void hfp_ag_establish_audio_connection(bd_addr_t bd_addr);
*/
void hfp_ag_release_audio_connection(bd_addr_t bd_addr);
/**
* @brief
*/
void hfp_ag_answer_incoming_call(void);
/**
* @brief Enable in-band ring tone
* @brief
*/
void hfp_ag_set_use_in_band_ring_tone(int use_in_band_ring_tone);
void hfp_ag_join_held_call(void);
/**
* @brief
*/
void hfp_ag_terminate_call(void);
/*
* @brief
*/
void hfp_ag_hold_incoming_call(void);
/*
* @brief
*/
void hfp_ag_accept_held_incoming_call(void);
/*
* @brief
*/
void hfp_ag_reject_held_incoming_call(void);
/*
* @brief
*/
void hfp_ag_set_microphone_gain(bd_addr_t bd_addr, int gain);
/*
* @brief
*/
void hfp_ag_set_speaker_gain(bd_addr_t bd_addr, int gain);
/*
* @brief
*/
void hfp_ag_set_battery_level(int level);
/*
* @brief
*/
void hfp_ag_clear_last_dialed_number(void);
// Voice Recognition
/*
* @brief
*/
void hfp_ag_activate_voice_recognition(bd_addr_t bd_addr, int activate);
/*
* @brief
*/
void hfp_ag_send_phone_number_for_voice_tag(bd_addr_t bd_addr, const char * number);
/*
* @brief
*/
void hfp_ag_reject_phone_number_for_voice_tag(bd_addr_t bd_addr);
// Cellular Actions
/**
* @brief
@ -209,22 +220,6 @@ void hfp_ag_outgoing_call_established(void);
* @brief
*/
void hfp_ag_call_dropped(void);
/**
* @brief
*/
void hfp_ag_answer_incoming_call(void);
/**
* @brief
*/
void hfp_ag_join_held_call(void);
/**
* @brief
*/
void hfp_ag_terminate_call(void);
/*
* @brief
*/
@ -240,75 +235,49 @@ void hfp_ag_set_signal_strength(int strength);
*/
void hfp_ag_set_roaming_status(int status);
/*
* @brief
*/
void hfp_ag_set_battery_level(int level);
/*
* @brief
*/
void hfp_ag_activate_voice_recognition(bd_addr_t bd_addr, int activate);
/*
* @brief
*/
void hfp_ag_set_microphone_gain(bd_addr_t bd_addr, int gain);
/*
* @brief
*/
void hfp_ag_set_speaker_gain(bd_addr_t bd_addr, int gain);
/*
* @brief
*/
void hfp_ag_send_phone_number_for_voice_tag(bd_addr_t bd_addr, const char * number);
/*
* @brief
*/
void hfp_ag_reject_phone_number_for_voice_tag(bd_addr_t bd_addr);
/*
* @brief
*/
void hfp_ag_send_dtmf_code_done(bd_addr_t bd_addr);
/*
* @brief
*/
void hfp_ag_set_subcriber_number_information(hfp_phone_number_t * numbers, int numbers_count);
/*
* @brief
* @brief Called by cellular unit after a DTMF code was transmitted, so that the next one can be emitted
*/
void hfp_ag_send_dtmf_code_done(bd_addr_t bd_addr);
void hfp_ag_send_current_call_status(bd_addr_t bd_addr, int idx);
/*
* @brief
/**
* @brief Report Extended Audio Gateway Error result codes in the AG.
* Whenever there is an error relating to the functionality of the AG as a
* result of AT command, the AG shall send +CME ERROR:
* - +CME ERROR: 0 - AG failure
* - +CME ERROR: 1 - no connection to phone
* - +CME ERROR: 3 - operation not allowed
* - +CME ERROR: 4 - operation not supported
* - +CME ERROR: 5 - PH-SIM PIN required
* - +CME ERROR: 10 - SIM not inserted
* - +CME ERROR: 11 - SIM PIN required
* - +CME ERROR: 12 - SIM PUK required
* - +CME ERROR: 13 - SIM failure
* - +CME ERROR: 14 - SIM busy
* - +CME ERROR: 16 - incorrect password
* - +CME ERROR: 17 - SIM PIN2 required
* - +CME ERROR: 18 - SIM PUK2 required
* - +CME ERROR: 20 - memory full
* - +CME ERROR: 21 - invalid index
* - +CME ERROR: 23 - memory failure
* - +CME ERROR: 24 - text string too long
* - +CME ERROR: 25 - invalid characters in text string
* - +CME ERROR: 26 - dial string too long
* - +CME ERROR: 27 - invalid characters in dial string
* - +CME ERROR: 30 - no network service
* - +CME ERROR: 31 - network Timeout.
* - +CME ERROR: 32 - network not allowed Emergency calls only
*/
void hfp_ag_hold_incoming_call(void);
/*
* @brief
*/
void hfp_ag_accept_held_incoming_call(void);
/*
* @brief
*/
void hfp_ag_reject_held_incoming_call(void);
/*
* @brief
*/
void hfp_ag_clear_last_dialed_number(void);
void hfp_ag_report_extended_audio_gateway_error_result_code(bd_addr_t bd_addr, hfp_cme_error_t error);
/* API_END */
#if defined __cplusplus
}
#endif

View File

@ -71,69 +71,147 @@ static char clip_number[HFP_GSM_MAX_CALL_NUMBER_SIZE];
static char last_dialed_number[HFP_GSM_MAX_CALL_NUMBER_SIZE];
static void hfp_gsm_handler(hfp_ag_call_event_t event, uint8_t index, uint8_t type, const char * number);
static inline int get_number_active_calls(void);
static void set_callsetup_status(hfp_callsetup_status_t status){
callsetup_status = status;
if (callsetup_status != HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE) return;
int i ;
for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
if (gsm_calls[i].direction == HFP_ENHANCED_CALL_DIR_OUTGOING){
gsm_calls[i].enhanced_status = HFP_ENHANCED_CALL_STATUS_OUTGOING_ALERTING;
}
}
}
static inline void set_enhanced_call_status_active(int index_in_table){
gsm_calls[index_in_table].enhanced_status = HFP_ENHANCED_CALL_STATUS_ACTIVE;
gsm_calls[index_in_table].used_slot = 1;
}
static inline void set_enhanced_call_status_held(int index_in_table){
gsm_calls[index_in_table].enhanced_status = HFP_ENHANCED_CALL_STATUS_HELD;
gsm_calls[index_in_table].used_slot = 1;
}
static inline void set_enhanced_call_status_response_hold(int index_in_table){
gsm_calls[index_in_table].enhanced_status = HFP_ENHANCED_CALL_STATUS_CALL_HELD_BY_RESPONSE_AND_HOLD;
gsm_calls[index_in_table].used_slot = 1;
}
static inline void set_enhanced_call_status_initiated(int index_in_table){
if (gsm_calls[index_in_table].direction == HFP_ENHANCED_CALL_DIR_OUTGOING){
gsm_calls[index_in_table].enhanced_status = HFP_ENHANCED_CALL_STATUS_OUTGOING_DIALING;
} else {
if (get_number_active_calls() > 0){
gsm_calls[index_in_table].enhanced_status = HFP_ENHANCED_CALL_STATUS_INCOMING_WAITING;
} else {
gsm_calls[index_in_table].enhanced_status = HFP_ENHANCED_CALL_STATUS_INCOMING;
}
}
gsm_calls[index_in_table].used_slot = 1;
}
static int get_enhanced_call_status(int index_in_table){
if (!gsm_calls[index_in_table].used_slot) return -1;
return gsm_calls[index_in_table].enhanced_status;
}
static inline int is_enhanced_call_status_active(int index_in_table){
return get_enhanced_call_status(index_in_table) == HFP_ENHANCED_CALL_STATUS_ACTIVE;
}
static inline int is_enhanced_call_status_initiated(int index_in_table){
switch (get_enhanced_call_status(index_in_table)){
case HFP_ENHANCED_CALL_STATUS_OUTGOING_DIALING:
case HFP_ENHANCED_CALL_STATUS_OUTGOING_ALERTING:
case HFP_ENHANCED_CALL_STATUS_INCOMING:
case HFP_ENHANCED_CALL_STATUS_INCOMING_WAITING:
return 1;
default:
return 0;
}
}
static void free_call_slot(int index_in_table){
gsm_calls[index_in_table].used_slot = 0;
}
void hfp_gsm_init(void){
callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
clip_type = 0;
memset(clip_number, 0, sizeof(clip_number));
memset(last_dialed_number, 0, sizeof(last_dialed_number));
memset(gsm_calls, 0, sizeof(gsm_calls));
int i;
for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
gsm_calls[i].status = CALL_NONE;
free_call_slot(i);
}
}
static int get_number_calls_with_status(hfp_gsm_call_status_t status){
static int get_number_calls_with_enhanced_status(hfp_enhanced_call_status_t enhanced_status){
int i, count = 0;
for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
if (gsm_calls[i].status == status) count++;
if (get_enhanced_call_status(i) == enhanced_status) count++;
}
return count;
}
static int get_call_index_with_status(hfp_gsm_call_status_t status){
static int get_call_index_with_enhanced_status(hfp_enhanced_call_status_t enhanced_status){
int i ;
for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
if (gsm_calls[i].status == status) return i;
if (get_enhanced_call_status(i) == enhanced_status) return i;
}
return -1;
}
static inline int get_initiated_call_index(void){
int i ;
for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
if (is_enhanced_call_status_initiated(i)) return i;
}
return -1;
}
static inline int get_next_free_slot(void){
return get_call_index_with_status(CALL_NONE);
int i ;
for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
if (!gsm_calls[i].used_slot) return i;
}
return -1;
}
static inline int get_active_call_index(void){
return get_call_index_with_status(CALL_ACTIVE);
}
static inline int get_initiated_call_index(void){
return get_call_index_with_status(CALL_INITIATED);
return get_call_index_with_enhanced_status(HFP_ENHANCED_CALL_STATUS_ACTIVE);
}
static inline int get_held_call_index(void){
return get_call_index_with_status(CALL_HELD);
return get_call_index_with_enhanced_status(HFP_ENHANCED_CALL_STATUS_HELD);
}
static inline int get_response_held_call_index(void){
return get_call_index_with_status(CALL_RESPONSE_HOLD);
return get_call_index_with_enhanced_status(HFP_ENHANCED_CALL_STATUS_CALL_HELD_BY_RESPONSE_AND_HOLD);
}
static inline int get_number_none_calls(void){
return get_number_calls_with_status(CALL_NONE);
int i, count = 0;
for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
if (!gsm_calls[i].used_slot) count++;
}
return count;
}
static inline int get_number_active_calls(void){
return get_number_calls_with_status(CALL_ACTIVE);
return get_number_calls_with_enhanced_status(HFP_ENHANCED_CALL_STATUS_ACTIVE);
}
static inline int get_number_held_calls(void){
return get_number_calls_with_status(CALL_HELD);
return get_number_calls_with_enhanced_status(HFP_ENHANCED_CALL_STATUS_HELD);
}
static inline int get_number_response_held_calls(void){
return get_number_calls_with_status(CALL_RESPONSE_HOLD);
return get_number_calls_with_enhanced_status(HFP_ENHANCED_CALL_STATUS_CALL_HELD_BY_RESPONSE_AND_HOLD);
}
static int next_call_index(void){
@ -162,8 +240,8 @@ static void delete_call(int delete_index_in_table){
gsm_calls[i].index--;
}
}
gsm_calls[delete_index_in_table].status = CALL_NONE;
free_call_slot(delete_index_in_table);
gsm_calls[delete_index_in_table].clip_type = 0;
gsm_calls[delete_index_in_table].index = 0;
gsm_calls[delete_index_in_table].clip_number[0] = '\0';
@ -175,7 +253,7 @@ static void create_call(hfp_enhanced_call_dir_t direction){
int next_free_slot = get_next_free_slot();
gsm_calls[next_free_slot].direction = direction;
gsm_calls[next_free_slot].index = next_call_index();
gsm_calls[next_free_slot].status = CALL_INITIATED;
set_enhanced_call_status_initiated(next_free_slot);
gsm_calls[next_free_slot].clip_type = 0;
gsm_calls[next_free_slot].clip_number[0] = '\0';
gsm_calls[next_free_slot].mpty = HFP_ENHANCED_CALL_MPTY_NOT_A_CONFERENCE_CALL;
@ -201,27 +279,7 @@ hfp_gsm_call_t * hfp_gsm_call(int call_index){
for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
hfp_gsm_call_t * call = &gsm_calls[i];
if (call->index != call_index) continue;
call->enhanced_status = HFP_ENHANCED_CALL_STATUS_CALL_HELD_BY_RESPONSE_AND_HOLD;
if (call->status == CALL_ACTIVE) call->enhanced_status = HFP_ENHANCED_CALL_STATUS_ACTIVE;
if (call->status == CALL_HELD) call->enhanced_status = HFP_ENHANCED_CALL_STATUS_HELD;
if (call->status == CALL_INITIATED){
if (call->direction == HFP_ENHANCED_CALL_DIR_OUTGOING){
if (callsetup_status == HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE){
call->enhanced_status = HFP_ENHANCED_CALL_STATUS_OUTGOING_ALERTING;
}
call->enhanced_status = HFP_ENHANCED_CALL_STATUS_OUTGOING_DIALING;
} else {
if (get_number_active_calls() > 0){
call->enhanced_status = HFP_ENHANCED_CALL_STATUS_INCOMING_WAITING;
}
call->enhanced_status = HFP_ENHANCED_CALL_STATUS_INCOMING;
}
}
return call;
}
return NULL;
@ -333,14 +391,14 @@ static void hfp_gsm_handler(hfp_ag_call_event_t event, uint8_t index, uint8_t ty
if (current_call_index != -1){
delete_call(current_call_index);
}
callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
break;
case HFP_AG_OUTGOING_CALL_ACCEPTED:
if (current_call_index != -1){
gsm_calls[current_call_index].status = CALL_HELD;
set_enhanced_call_status_held(current_call_index);
}
callsetup_status = HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_DIALING_STATE;
set_callsetup_status(HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_DIALING_STATE);
break;
case HFP_AG_OUTGOING_CALL_RINGING:
@ -348,27 +406,27 @@ static void hfp_gsm_handler(hfp_ag_call_event_t event, uint8_t index, uint8_t ty
log_error("gsm: no active call");
return;
}
callsetup_status = HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE;
set_callsetup_status(HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE);
break;
case HFP_AG_OUTGOING_CALL_ESTABLISHED:
callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
gsm_calls[initiated_call_index].status = CALL_ACTIVE;
set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
set_enhanced_call_status_active(initiated_call_index);
break;
case HFP_AG_INCOMING_CALL:
if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS) break;
callsetup_status = HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS;
set_callsetup_status(HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS);
create_call(HFP_ENHANCED_CALL_DIR_INCOMING);
break;
case HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG:
if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break;
callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
if (hfp_gsm_call_status() == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT){
gsm_calls[current_call_index].status = CALL_HELD;
set_enhanced_call_status_held(current_call_index);
}
gsm_calls[initiated_call_index].status = CALL_ACTIVE;
set_enhanced_call_status_active(initiated_call_index);
break;
case HFP_AG_HELD_CALL_JOINED_BY_AG:
@ -376,14 +434,14 @@ static void hfp_gsm_handler(hfp_ag_call_event_t event, uint8_t index, uint8_t ty
// TODO: is following condition correct? Can we join incoming call before it is answered?
if (callsetup_status == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS){
gsm_calls[initiated_call_index].status = CALL_ACTIVE;
callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
set_enhanced_call_status_active(initiated_call_index);
set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
} else if (hfp_gsm_callheld_status() == HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED) {
gsm_calls[held_call_index].status = CALL_ACTIVE;
set_enhanced_call_status_active(held_call_index);
}
for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
if (gsm_calls[i].status == CALL_ACTIVE){
if (is_enhanced_call_status_active(i)){
gsm_calls[i].mpty = HFP_ENHANCED_CALL_MPTY_CONFERENCE_CALL;
}
}
@ -392,22 +450,22 @@ static void hfp_gsm_handler(hfp_ag_call_event_t event, uint8_t index, uint8_t ty
case HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF:
if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break;
if (hfp_gsm_call_status() != HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS) break;
callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
gsm_calls[initiated_call_index].status = CALL_ACTIVE;
set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
set_enhanced_call_status_active(initiated_call_index);
break;
case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_AG:
case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_HF:
if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break;
if (hfp_gsm_call_status() != HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS) break;
callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
gsm_calls[initiated_call_index].status = CALL_RESPONSE_HOLD;
set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
set_enhanced_call_status_response_hold(initiated_call_index);
break;
case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_AG:
case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_HF:
if (!hfp_gsm_response_held_active()) break;
gsm_calls[get_response_held_call_index()].status = CALL_ACTIVE;
set_enhanced_call_status_active(get_response_held_call_index());
break;
case HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_AG:
@ -420,7 +478,7 @@ static void hfp_gsm_handler(hfp_ag_call_event_t event, uint8_t index, uint8_t ty
case HFP_AG_TERMINATE_CALL_BY_HF:
switch (hfp_gsm_call_status()){
case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
break;
case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT:
delete_call(current_call_index);
@ -432,10 +490,10 @@ static void hfp_gsm_handler(hfp_ag_call_event_t event, uint8_t index, uint8_t ty
switch (hfp_gsm_call_status()){
case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break;
callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
break;
case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT:
callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
delete_call(current_call_index);
break;
default:
@ -444,7 +502,7 @@ static void hfp_gsm_handler(hfp_ag_call_event_t event, uint8_t index, uint8_t ty
break;
case HFP_AG_CALL_DROPPED:
callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
if (hfp_gsm_call_status() != HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT) break;
for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
@ -454,9 +512,9 @@ static void hfp_gsm_handler(hfp_ag_call_event_t event, uint8_t index, uint8_t ty
case HFP_AG_CALL_HOLD_USER_BUSY:
// Held or waiting call gets active,
callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
gsm_calls[initiated_call_index].status = CALL_NONE;
gsm_calls[held_call_index].status = CALL_ACTIVE;
set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
free_call_slot(initiated_call_index);
set_enhanced_call_status_active(held_call_index);
break;
case HFP_AG_CALL_HOLD_RELEASE_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL:
@ -469,41 +527,41 @@ static void hfp_gsm_handler(hfp_ag_call_event_t event, uint8_t index, uint8_t ty
}
} else {
for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
if (gsm_calls[i].status == CALL_ACTIVE){
if (is_enhanced_call_status_active(i)){
delete_call(i);
}
}
}
if (callsetup_status != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS){
gsm_calls[initiated_call_index].status = CALL_ACTIVE;
set_enhanced_call_status_active(initiated_call_index);
} else {
gsm_calls[held_call_index].status = CALL_ACTIVE;
set_enhanced_call_status_active(held_call_index);
}
callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
break;
case HFP_AG_CALL_HOLD_PARK_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL:
for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
if (gsm_calls[i].status == CALL_ACTIVE && gsm_calls[i].index != index){
gsm_calls[i].status = CALL_HELD;
if (is_enhanced_call_status_active(i) && gsm_calls[i].index != index){
set_enhanced_call_status_held(i);
}
}
if (callsetup_status != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS){
gsm_calls[initiated_call_index].status = CALL_ACTIVE;
set_enhanced_call_status_active(initiated_call_index);
} else {
gsm_calls[held_call_index].status = CALL_ACTIVE;
set_enhanced_call_status_active(held_call_index);
}
callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS);
break;
case HFP_AG_CALL_HOLD_ADD_HELD_CALL:
if (hfp_gsm_callheld_status() != HFP_CALLHELD_STATUS_NO_CALLS_HELD){
for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
if (gsm_calls[i].status != CALL_NONE){
gsm_calls[i].status = CALL_ACTIVE;
if (gsm_calls[i].used_slot){
set_enhanced_call_status_active(i);
gsm_calls[i].mpty = HFP_ENHANCED_CALL_MPTY_CONFERENCE_CALL;
}
}

View File

@ -54,20 +54,10 @@ extern "C" {
#endif
/* API_START */
typedef enum{
CALL_NONE,
CALL_INITIATED,
CALL_RESPONSE_HOLD,
CALL_ACTIVE,
CALL_HELD
} hfp_gsm_call_status_t;
typedef struct {
// TODO: use enhanced_status instead of status
hfp_gsm_call_status_t status;
hfp_enhanced_call_dir_t direction;
uint8_t used_slot;
hfp_enhanced_call_status_t enhanced_status;
hfp_enhanced_call_dir_t direction;
hfp_enhanced_call_mode_t mode;
hfp_enhanced_call_mpty_t mpty;
// TODO: sort on drop call, so that index corresponds to table index

View File

@ -37,13 +37,13 @@
// *****************************************************************************
//
// Minimal setup for HFP Hands-Free (HF) unit (!! UNDER DEVELOPMENT !!)
// HFP Hands-Free (HF) unit
//
// *****************************************************************************
#ifndef btstack_hfp_hf_h
#define btstack_hfp_hf_h
#ifndef __BTSTACK_HFP_HF_H
#define __BTSTACK_HFP_HF_H
#include "hci.h"
#include "classic/sdp_query_rfcomm.h"
@ -55,7 +55,6 @@ extern "C" {
/* API_START */
/**
* @brief Create HFP Hands-Free (HF) SDP service record.
*/
@ -66,8 +65,11 @@ void hfp_hf_create_sdp_record(uint8_t * service, uint32_t service_record_handle,
* TODO: move optional params into setters
*/
void hfp_hf_init(uint16_t rfcomm_channel_nr, uint32_t supported_features, uint16_t * indicators, int indicators_nr, uint32_t indicators_status);
void hfp_hf_set_codecs(uint8_t * codecs, int codecs_nr);
void hfp_hf_set_supported_features(uint32_t supported_features);
/**
* @brief Register callback for the HFP Hands-Free (HF) client.
*/
@ -83,7 +85,6 @@ void hfp_hf_register_packet_handler(hfp_callback_t callback);
* - retrieve which HF indicators are enabled on the AG, if possible
*/
void hfp_hf_establish_service_level_connection(bd_addr_t bd_addr);
void hfp_hf_set_supported_features(uint32_t supported_features);
/**
* @brief Release the RFCOMM channel and the audio connection between the HF and the AG.
@ -95,6 +96,7 @@ void hfp_hf_release_service_level_connection(bd_addr_t bd_addr);
* @brief Deactivate/reactivate status update for all indicators in the AG.
*/
void hfp_hf_enable_status_update_for_all_ag_indicators(bd_addr_t bd_addr);
void hfp_hf_disable_status_update_for_all_ag_indicators(bd_addr_t bd_addr);
/**
@ -106,6 +108,8 @@ void hfp_hf_set_status_update_for_individual_ag_indicators(bd_addr_t bd_addr, ui
/**
* @brief Find out the name of the currently selected Network operator by AG.
* The name is restricted to max 16 characters.
*
* TODO: what is the result of this?
*/
void hfp_hf_query_operator_selection(bd_addr_t bd_addr);
@ -196,7 +200,8 @@ void hfp_hf_terminate_call(bd_addr_t bd_addr);
void hfp_hf_dial_number(bd_addr_t bd_addr, char * number);
/**
* @brief
* @brief
* TODO: use int for number instead of string?
*/
void hfp_hf_dial_memory(bd_addr_t bd_addr, char * number);
@ -317,4 +322,4 @@ void hfp_hf_set_hf_indicator(bd_addr_t addr, int assigned_number, int value);
}
#endif
#endif
#endif // __BTSTACK_HFP_HF_H

View File

@ -37,7 +37,7 @@
// *****************************************************************************
//
// Minimal setup for HSP Audio Gateway (!! UNDER DEVELOPMENT !!)
// HSP Audio Gateway
//
// *****************************************************************************
@ -60,8 +60,6 @@
#include "hsp_ag.h"
#include "l2cap.h"
#define RFCOMM_SERVER_CHANNEL 1
#define HSP_HS_BUTTON_PRESS "AT+CKPD=200"
#define HSP_HS_AT_CKPD "AT+CKPD\r\n"
#define HSP_AG_OK "\r\nOK\r\n"
@ -84,8 +82,6 @@ static uint16_t sco_handle = 0;
static uint16_t rfcomm_handle = 0;
static btstack_timer_source_t hs_timeout;
// static uint8_t connection_state = 0;
static int ag_microphone_gain = -1;
static int ag_speaker_gain = -1;
static uint8_t ag_ring = 0;
@ -152,7 +148,7 @@ static void emit_event_audio_connected(uint8_t status, uint16_t handle){
(*hsp_ag_callback)(event, sizeof(event));
}
void hsp_ag_create_service(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){
uint8_t* attribute;
de_create_sequence(service);
@ -223,14 +219,13 @@ static int hsp_ag_send_str_over_rfcomm(uint16_t cid, char * command){
if (!rfcomm_can_send_packet_now(cid)) return 1;
int err = rfcomm_send(cid, (uint8_t*) command, strlen(command));
if (err){
printf("rfcomm_send -> error 0X%02x", err);
log_error("rfcomm_send_internal -> error 0X%02x", err);
return err;
}
printf("Send string: \"%s\"\n", command);
return err;
}
void hsp_ag_support_custom_commands(int enable){
void hsp_ag_enable_custom_commands(int enable){
ag_support_custom_commands = enable;
}
@ -301,7 +296,7 @@ void hsp_ag_disconnect(void){
void hsp_ag_set_microphone_gain(uint8_t gain){
if (gain < 0 || gain >15) {
printf("Gain must be in interval [0..15], it is given %d\n", gain);
log_error("Gain must be in interval [0..15], it is given %d", gain);
return;
}
ag_microphone_gain = gain;
@ -311,7 +306,7 @@ void hsp_ag_set_microphone_gain(uint8_t gain){
// AG +VGS=5 [0..15] ; HS AT+VGM=6 | AG OK
void hsp_ag_set_speaker_gain(uint8_t gain){
if (gain < 0 || gain >15) {
printf("Gain must be in interval [0..15], it is given %d\n", gain);
log_error("Gain must be in interval [0..15], it is given %d", gain);
return;
}
ag_speaker_gain = gain;
@ -371,7 +366,7 @@ static void hsp_run(void){
switch (hsp_state){
case HSP_SDP_QUERY_RFCOMM_CHANNEL:
hsp_state = HSP_W4_SDP_EVENT_QUERY_COMPLETE;
printf("Start SDP query %s, 0x%02x\n", bd_addr_to_str(remote), SDP_HSP);
log_info("Start SDP query %s, 0x%02x", bd_addr_to_str(remote), SDP_HSP);
sdp_query_rfcomm_channel_and_name_for_uuid(remote, SDP_HSP);
break;
@ -446,8 +441,8 @@ static void hsp_run(void){
}
static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
// printf("packet_handler type %u, packet[0] %x\n", packet_type, packet[0]);
static void packet_handler (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
// log_info("packet_handler type %u, packet[0] %x", packet_type, packet[0]);
if (packet_type == RFCOMM_DATA_PACKET){
while (size > 0 && (packet[0] == '\n' || packet[0] == '\r')){
size--;
@ -455,7 +450,7 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
}
if (strncmp((char *)packet, HSP_HS_BUTTON_PRESS, strlen(HSP_HS_BUTTON_PRESS)) == 0){
printf("Received button press %s\n", HSP_HS_BUTTON_PRESS);
log_info("Received button press %s", HSP_HS_BUTTON_PRESS);
ag_num_button_press_received++;
ag_send_ok = 1;
if (hsp_state == HSP_ACTIVE && ag_num_button_press_received >=2){
@ -493,19 +488,6 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
uint16_t handle;
switch (event) {
case BTSTACK_EVENT_STATE:
// BTstack activated, get started
if (packet[2] == HCI_STATE_WORKING){
printf("BTstack activated, get started .\n");
}
break;
case HCI_EVENT_PIN_CODE_REQUEST:
// inform about pin code request
printf("Pin code request - using '0000'\n\r");
reverse_bd_addr(&packet[2], event_addr);
hci_send_cmd(&hci_pin_code_request_reply, &event_addr, 4, "0000");
break;
case HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE:{
int index = 2;
uint8_t status = packet[index++];
@ -530,14 +512,14 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
}
switch (link_type){
case 0x00:
printf("SCO Connection established. \n");
log_info("SCO Connection established.");
if (transmission_interval != 0) log_error("SCO Connection: transmission_interval not zero: %d.", transmission_interval);
if (retransmission_interval != 0) log_error("SCO Connection: retransmission_interval not zero: %d.", retransmission_interval);
if (rx_packet_length != 0) log_error("SCO Connection: rx_packet_length not zero: %d.", rx_packet_length);
if (tx_packet_length != 0) log_error("SCO Connection: tx_packet_length not zero: %d.", tx_packet_length);
break;
case 0x02:
printf("eSCO Connection established. \n");
log_info("eSCO Connection established.");
break;
default:
log_error("(e)SCO reserved link_type 0x%2x", link_type);
@ -563,18 +545,17 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
reverse_bd_addr(&packet[2], event_addr);
rfcomm_cid = little_endian_read_16(packet, 9);
printf("RFCOMM channel %u requested for %s\n", packet[8], bd_addr_to_str(event_addr));
log_info("RFCOMM channel %u requested for %s", packet[8], bd_addr_to_str(event_addr));
rfcomm_accept_connection(rfcomm_cid);
hsp_state = HSP_W4_RFCOMM_CONNECTED;
break;
case RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE:
printf("RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE packet_handler type %u, packet[0] %x\n", packet_type, packet[0]);
log_info("RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE packet_handler type %u, packet[0] %x", packet_type, packet[0]);
// data: event(8), len(8), status (8), address (48), handle(16), server channel(8), rfcomm_cid(16), max frame size(16)
if (packet[2]) {
printf("RFCOMM channel open failed, status %u\n", packet[2]);
log_info("RFCOMM channel open failed, status %u§", packet[2]);
hsp_ag_reset_state();
emit_event(HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE, packet[2]);
} else {
@ -582,7 +563,7 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
rfcomm_handle = little_endian_read_16(packet, 9);
rfcomm_cid = little_endian_read_16(packet, 12);
mtu = little_endian_read_16(packet, 14);
printf("RFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u, state %d\n", rfcomm_cid, mtu, hsp_state);
log_info("RFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u, state %d", rfcomm_cid, mtu, hsp_state);
switch (hsp_state){
case HSP_W4_RFCOMM_CONNECTED:
@ -593,19 +574,16 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
hsp_state = HSP_W2_DISCONNECT_RFCOMM;
break;
default:
printf("no valid state\n");
log_error("no valid state");
break;
}
}
break;
case HCI_EVENT_DISCONNECTION_COMPLETE:
if (hsp_state != HSP_W4_SCO_DISCONNECTED){
log_info("received gap disconnect in wrong hsp state");
}
handle = little_endian_read_16(packet,3);
if (handle == sco_handle){
printf("SCO disconnected, w2 disconnect RFCOMM\n");
log_info("SCO disconnected, w2 disconnect RFCOMM");
sco_handle = 0;
hsp_state = HSP_W2_DISCONNECT_RFCOMM;
break;
@ -613,10 +591,7 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
break;
case RFCOMM_EVENT_CHANNEL_CLOSED:
if (hsp_state != HSP_W4_RFCOMM_DISCONNECTED){
log_info("received RFCOMM disconnect in wrong hsp state");
}
printf("RFCOMM channel closed\n");
log_info("RFCOMM channel closed");
hsp_ag_reset_state();
emit_event(HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE,0);
break;
@ -630,17 +605,17 @@ static void handle_query_rfcomm_event(uint8_t packet_type, uint8_t *packet, uint
switch (packet[0]){
case SDP_EVENT_QUERY_RFCOMM_SERVICE:
channel_nr = sdp_event_query_rfcomm_service_get_rfcomm_channel(packet);
printf("** Service name: '%s', RFCOMM port %u\n", sdp_event_query_rfcomm_service_get_name(packet), channel_nr);
log_info("** Service name: '%s', RFCOMM port %u", sdp_event_query_rfcomm_service_get_name(packet), channel_nr);
break;
case SDP_EVENT_QUERY_COMPLETE:
if (channel_nr > 0){
hsp_state = HSP_W4_RFCOMM_CONNECTED;
printf("RFCOMM create channel. state %d\n", HSP_W4_RFCOMM_CONNECTED);
log_info("RFCOMM create channel. state %d", HSP_W4_RFCOMM_CONNECTED);
rfcomm_create_channel(packet_handler, remote, channel_nr, NULL);
break;
}
hsp_ag_reset_state();
printf("Service not found, status %u.\n", sdp_event_query_complete_get_status(packet));
log_info("Service not found, status %u.\n", sdp_event_query_complete_get_status(packet));
if (sdp_event_query_complete_get_status(packet)){
emit_event(HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE, sdp_event_query_complete_get_status(packet));
} else {

View File

@ -37,7 +37,7 @@
// *****************************************************************************
//
// HSP Audio Gateway (!! UNDER DEVELOPMENT !!)
// HSP Audio Gateway
//
// *****************************************************************************
@ -53,27 +53,36 @@ extern "C" {
#endif
typedef void (*hsp_ag_callback_t)(uint8_t * event, uint16_t event_size);
// Register callback (packet handler) for hsp audio gateway
void hsp_ag_register_packet_handler(hsp_ag_callback_t callback);
void hsp_ag_create_service(uint8_t * service, uint32_t service_record_handle, int rfcomm_channel_nr, const char * name);
void hsp_ag_create_sdp_record(uint8_t * service, int rfcomm_channel_nr, const char * name);
void hsp_ag_init(uint8_t rfcomm_channel_nr);
// Register callback (packet handler) for hsp audio gateway
void hsp_ag_register_packet_handler(hsp_ag_callback_t callback);
void hsp_ag_connect(bd_addr_t bd_addr);
void hsp_ag_disconnect(void);
// +VGM=[0..15]
void hsp_ag_set_microphone_gain(uint8_t gain);
// +VGS=[0..15]
void hsp_ag_set_speaker_gain(uint8_t gain);
void hsp_ag_start_ringing(void);
void hsp_ag_stop_ringing(void);
void hsp_ag_support_custom_commands(int enable);
// When support custom commands is enabled, AG will send HSP_SUBEVENT_HS_COMMAND.
// When support custom commands is enabled, AG will emit HSP_SUBEVENT_HS_COMMAND.
// On occurance of this event, client's packet handler must send the result back
// by calling hsp_ag_send_result function.
void hsp_ag_enable_custom_commands(int enable);
int hsp_ag_send_result(char * result);
#if defined __cplusplus

View File

@ -37,7 +37,7 @@
// *****************************************************************************
//
// Minimal setup for HSP Headset (!! UNDER DEVELOPMENT !!)
// HSP Headset
//
// *****************************************************************************
@ -156,20 +156,17 @@ static int hsp_hs_send_str_over_rfcomm(uint16_t cid, const char * command){
return err;
}
void hsp_hs_support_custom_indications(int enable){
void hsp_hs_enable_custom_indications(int enable){
hs_support_custom_indications = enable;
}
// When support custom commands is enabled, AG will send HSP_SUBEVENT_HS_COMMAND.
// On occurance of this event, client's packet handler must send the result back
// by calling hsp_hs_send_result function.
int hsp_hs_send_result(char * result){
int hsp_hs_send_result(const char * result){
if (!hs_support_custom_indications) return 1;
return hsp_hs_send_str_over_rfcomm(rfcomm_cid, result);
}
void hsp_hs_create_service(uint8_t * service, uint32_t service_record_handle, int rfcomm_channel_nr, const char * name, uint8_t have_remote_audio_control){
void hsp_hs_create_sdp_record(uint8_t * service, int rfcomm_channel_nr, const char * name, uint8_t have_remote_audio_control){
uint8_t* attribute;
de_create_sequence(service);
@ -549,10 +546,6 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
break;
case HCI_EVENT_DISCONNECTION_COMPLETE:
printf("HCI_EVENT_DISCONNECTION_COMPLETE \n");
// if (hsp_state != HSP_W4_SCO_DISCONNECTED){
// printf("received gap disconnect in wrong hsp state\n");
// }
handle = little_endian_read_16(packet,3);
if (handle == sco_handle){
sco_handle = 0;
@ -562,10 +555,6 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
}
break;
case RFCOMM_EVENT_CHANNEL_CLOSED:
printf("RFCOMM_EVENT_CHANNEL_CLOSED\n");
// if (hsp_state != HSP_W4_RFCOMM_DISCONNECTED){
// printf("received RFCOMM disconnect in wrong hsp state\n");
// }
printf("RFCOMM channel closed\n");
hsp_hs_reset_state();
emit_event(HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE,0);
@ -596,7 +585,7 @@ static void handle_query_rfcomm_event(uint8_t packet_type, uint8_t *packet, uint
}
}
void hsp_hs_press_button(void){
void hsp_hs_send_button_press(void){
hs_send_button_press = 1;
hsp_run();
}

View File

@ -37,7 +37,7 @@
// *****************************************************************************
//
// HSP Headset (!! UNDER DEVELOPMENT !!)
// HSP Headset
//
// *****************************************************************************
@ -52,28 +52,94 @@
extern "C" {
#endif
typedef void (*hsp_hs_callback_t)(uint8_t * event, uint16_t event_size);
// Register callback (packet handler) for hsp headset
void hsp_hs_register_packet_handler(hsp_hs_callback_t callback);
void hsp_hs_create_service(uint8_t * service, uint32_t service_record_handle, int rfcomm_channel_nr, const char * name, uint8_t have_remote_audio_control);
/* 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_ERROR
* - 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
*/
typedef void (*hsp_hs_callback_t)(uint8_t * event, uint16_t event_size);
/**
* @brief Set up HSP HS
* @param rfcomm_channel_nr
*/
void hsp_hs_init(uint8_t rfcomm_channel_nr);
/**
* @brief Create HSP Headset (HS) SDP service record. have_remote_audio_control?
*/
void hsp_hs_create_sdp_record(uint8_t * service, uint32_t service_record_handle, int rfcomm_channel_nr, const char * name, uint8_t have_remote_audio_control);
/**
* @brief Register packet handler to receive HSP HS events.
*/
void hsp_hs_register_packet_handler(hsp_hs_callback_t callback);
/**
* @brief Connect to HSP Audio Gateway
*
* Perform SDP query for an RFCOMM service on a remote device,
* and establish an RFCOMM connection if such service is found. The reception of the
* HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE or
* HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE event
* indicate if the connection is successfully established or not.
*/
void hsp_hs_connect(bd_addr_t bd_addr);
/**
* @brief Disconnect from HSP Audio Gateway
*
* Releases the RFCOMM channel.
*/
void hsp_hs_disconnect(bd_addr_t bd_addr);
// AT+VGM=[0..15]
/**
* @brief Set microphone gain.
*
* The new gain value will be confirmed by the HSP Audio Gateway.
* A HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED event will be received.
* @param gain - valid range: [0,15]
*/
void hsp_hs_set_microphone_gain(uint8_t gain);
// AT+VGS=[0..15]
/**
* @brief Set speaker gain.
*
* The new gain value will be confirmed by the HSP Audio Gateway.
* A HSP_SUBEVENT_SPEAKER_GAIN_CHANGED event will be received.
* @param gain - valid range: [0,15]
*/
void hsp_hs_set_speaker_gain(uint8_t gain);
void hsp_hs_support_custom_indications(int enable);
/**
* @brief Send button press action.
*/
void hsp_hs_send_button_press(void);
void hsp_hs_press_button(void);
/**
* @brief Enable custom indications
*
* Custom indications are disable by default.
* When enabled, custom indications are received via the HSP_SUBEVENT_AG_INDICATION.
*/
void hsp_hs_enable_custom_indications(int enable);
// When support custom commands is enabled, AG will send HSP_SUBEVENT_AG_INDICATION.
// On occurance of this event, client's packet handler must send the result back
// by calling hsp_hs_send_result function.
int hsp_hs_send_result(char * indication);
/**
* @brief Send answer to custom command
*
* On HSP_SUBEVENT_AG_INDICATION, the client needs to respond
* with this function with the result to the custom indication
*/
int hsp_hs_send_result(const char * indication);
/* API_END */
#if defined __cplusplus
}

View File

@ -191,7 +191,7 @@ int btstack_main(int argc, const char * argv[]){
// init SDP, create record for SPP and register with SDP
sdp_init();
memset((uint8_t *)hsp_service_buffer, 0, sizeof(hsp_service_buffer));
hsp_ag_create_service((uint8_t *)hsp_service_buffer, 0x10003, rfcomm_channel_nr, hsp_ag_service_name);
hsp_ag_create_sdp_record((uint8_t *)hsp_service_buffer, 0x10003, rfcomm_channel_nr, hsp_ag_service_name);
sdp_register_service((uint8_t *)hsp_service_buffer);
// turn on!

View File

@ -238,7 +238,7 @@ static int stdin_process(struct btstack_data_source *ds){
break;
case 'b':
printf("Press user button\n");
hsp_hs_press_button();
hsp_hs_send_button_press();
break;
default:
show_usage();
@ -321,7 +321,7 @@ int btstack_main(int argc, const char * argv[]){
sdp_init();
memset((uint8_t *)hsp_service_buffer, 0, sizeof(hsp_service_buffer));
hsp_hs_create_service((uint8_t *)hsp_service_buffer, 0x10004, rfcomm_channel_nr, hsp_hs_service_name, 0);
hsp_hs_create_sdp_record((uint8_t *)hsp_service_buffer, 0x10004, rfcomm_channel_nr, hsp_hs_service_name, 0);
sdp_register_service((uint8_t *)hsp_service_buffer);
hci_discoverable_control(1);