mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-24 13:43:38 +00:00
Merge branch 'master' into ble-api-cleanup
This commit is contained in:
commit
66a048ab90
@ -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
|
||||
|
@ -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!
|
||||
|
@ -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];
|
||||
|
@ -37,7 +37,7 @@
|
||||
|
||||
// *****************************************************************************
|
||||
//
|
||||
// Minimal setup for HFP Audio Gateway (AG) unit (!! UNDER DEVELOPMENT !!)
|
||||
// HFP Audio Gateway (AG) unit
|
||||
//
|
||||
// *****************************************************************************
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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!
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user