mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-04-18 05:42:49 +00:00
hfp: supported features, codecs negotiation
This commit is contained in:
parent
fdba85bc1b
commit
2519d0dbc7
@ -617,6 +617,8 @@ extern "C" {
|
|||||||
#define HCI_EVENT_HFP_META 0xE9
|
#define HCI_EVENT_HFP_META 0xE9
|
||||||
|
|
||||||
#define HFP_SUBEVENT_AUDIO_CONNECTION_COMPLETE 0x01
|
#define HFP_SUBEVENT_AUDIO_CONNECTION_COMPLETE 0x01
|
||||||
|
#define HFP_SUBEVENT_SUPPORTED_FEATURES_EXCHANGE 0x02
|
||||||
|
|
||||||
|
|
||||||
// ANCS Client
|
// ANCS Client
|
||||||
#define ANCS_CLIENT_CONNECTED 0xF0
|
#define ANCS_CLIENT_CONNECTED 0xF0
|
||||||
|
91
src/hfp.c
91
src/hfp.c
@ -63,10 +63,57 @@
|
|||||||
static hfp_callback_t hfp_callback;
|
static hfp_callback_t hfp_callback;
|
||||||
static linked_list_t hfp_connections = NULL;
|
static linked_list_t hfp_connections = NULL;
|
||||||
|
|
||||||
|
int send_str_over_rfcomm(uint16_t cid, char * command){
|
||||||
|
if (!rfcomm_can_send_packet_now(cid)) return 1;
|
||||||
|
int err = rfcomm_send_internal(cid, (uint8_t*) command, strlen(command));
|
||||||
|
if (err){
|
||||||
|
printf("rfcomm_send_internal -> error 0X%02x", err);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
void join(char * buffer, int buffer_size, int buffer_offset, uint8_t * values, int values_nr){
|
||||||
|
int req_size = values_nr * 2;
|
||||||
|
if (buffer_size - buffer_offset < req_size ) {
|
||||||
|
log_error("join: buffer too small (size: %u. req: %u)", buffer_size, req_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int pos = buffer_offset;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < values_nr-1; i++){
|
||||||
|
buffer[pos++] = values[i];
|
||||||
|
buffer[pos++] = ',';
|
||||||
|
}
|
||||||
|
buffer[pos++] = values[i];
|
||||||
|
buffer[pos] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void emit_event(hfp_callback_t callback, uint8_t event_subtype, uint8_t value){
|
||||||
|
if (!callback) return;
|
||||||
|
uint8_t event[4];
|
||||||
|
event[0] = HCI_EVENT_HFP_META;
|
||||||
|
event[1] = sizeof(event) - 2;
|
||||||
|
event[2] = event_subtype;
|
||||||
|
event[3] = value; // status 0 == OK
|
||||||
|
(*callback)(event, sizeof(event));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static linked_item_t * get_hfp_connections(){
|
static linked_item_t * get_hfp_connections(){
|
||||||
return (linked_item_t *) &hfp_connections;
|
return (linked_item_t *) &hfp_connections;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hfp_connection_t * get_hfp_connection_context_for_rfcomm_cid(uint16_t cid){
|
||||||
|
linked_item_t *it;
|
||||||
|
for (it = get_hfp_connections(); it ; it = it->next){
|
||||||
|
hfp_connection_t * connection = (hfp_connection_t *) it;
|
||||||
|
if (connection->rfcomm_cid == cid){
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static hfp_connection_t * get_hfp_connection_context_for_handle(uint16_t handle){
|
static hfp_connection_t * get_hfp_connection_context_for_handle(uint16_t handle){
|
||||||
linked_item_t *it;
|
linked_item_t *it;
|
||||||
for (it = get_hfp_connections(); it ; it = it->next){
|
for (it = get_hfp_connections(); it ; it = it->next){
|
||||||
@ -123,6 +170,24 @@ void hfp_register_packet_handler(hfp_callback_t callback){
|
|||||||
hfp_callback = callback;
|
hfp_callback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* @param suported_features
|
||||||
|
* HF bit 0: EC and/or NR function (yes/no, 1 = yes, 0 = no)
|
||||||
|
* HF bit 1: Call waiting or three-way calling(yes/no, 1 = yes, 0 = no)
|
||||||
|
* HF bit 2: CLI presentation capability (yes/no, 1 = yes, 0 = no)
|
||||||
|
* HF bit 3: Voice recognition activation (yes/no, 1= yes, 0 = no)
|
||||||
|
* HF bit 4: Remote volume control (yes/no, 1 = yes, 0 = no)
|
||||||
|
* HF bit 5: Wide band speech (yes/no, 1 = yes, 0 = no)
|
||||||
|
*/
|
||||||
|
/* Bit position:
|
||||||
|
* AG bit 0: Three-way calling (yes/no, 1 = yes, 0 = no)
|
||||||
|
* AG bit 1: EC and/or NR function (yes/no, 1 = yes, 0 = no)
|
||||||
|
* AG bit 2: Voice recognition function (yes/no, 1 = yes, 0 = no)
|
||||||
|
* AG bit 3: In-band ring tone capability (yes/no, 1 = yes, 0 = no)
|
||||||
|
* AG bit 4: Attach a phone number to a voice tag (yes/no, 1 = yes, 0 = no)
|
||||||
|
* AG bit 5: Wide band speech (yes/no, 1 = yes, 0 = no)
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
void hfp_create_service(uint8_t * service, uint16_t service_uuid, int rfcomm_channel_nr, const char * name, uint16_t supported_features){
|
void hfp_create_service(uint8_t * service, uint16_t service_uuid, int rfcomm_channel_nr, const char * name, uint16_t supported_features){
|
||||||
uint8_t* attribute;
|
uint8_t* attribute;
|
||||||
de_create_sequence(service);
|
de_create_sequence(service);
|
||||||
@ -187,14 +252,6 @@ void hfp_create_service(uint8_t * service, uint16_t service_uuid, int rfcomm_cha
|
|||||||
de_add_data(service, DE_STRING, strlen(name), (uint8_t *) name);
|
de_add_data(service, DE_STRING, strlen(name), (uint8_t *) name);
|
||||||
|
|
||||||
de_add_number(service, DE_UINT, DE_SIZE_16, supported_features);
|
de_add_number(service, DE_UINT, DE_SIZE_16, supported_features);
|
||||||
/* Bit position:
|
|
||||||
* 0: EC and/or NR function (yes/no, 1 = yes, 0 = no)
|
|
||||||
* 1: Call waiting or three-way calling(yes/no, 1 = yes, 0 = no)
|
|
||||||
* 2: CLI presentation capability (yes/no, 1 = yes, 0 = no)
|
|
||||||
* 3: Voice recognition activation (yes/no, 1= yes, 0 = no)
|
|
||||||
* 4: Remote volume control (yes/no, 1 = yes, 0 = no)
|
|
||||||
* 5: Wide band speech (yes/no, 1 = yes, 0 = no)
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static hfp_connection_t * connection_doing_sdp_query = NULL;
|
static hfp_connection_t * connection_doing_sdp_query = NULL;
|
||||||
@ -235,19 +292,8 @@ static void hfp_reset_state(hfp_connection_t * connection){
|
|||||||
connection->state = HFP_IDLE;
|
connection->state = HFP_IDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void emit_event(hfp_callback_t callback, uint8_t event_subtype, uint8_t value){
|
|
||||||
if (!callback) return;
|
|
||||||
uint8_t event[4];
|
|
||||||
event[0] = HCI_EVENT_HFP_META;
|
|
||||||
event[1] = sizeof(event) - 2;
|
|
||||||
event[2] = event_subtype;
|
|
||||||
event[3] = value; // status 0 == OK
|
|
||||||
(*callback)(event, sizeof(event));
|
|
||||||
}
|
|
||||||
|
|
||||||
hfp_connection_t * handle_hci_event(uint8_t packet_type, uint8_t *packet, uint16_t size){
|
|
||||||
if (packet_type != HCI_EVENT_PACKET) return NULL;
|
|
||||||
|
|
||||||
|
hfp_connection_t * hfp_handle_hci_event(uint8_t packet_type, uint8_t *packet, uint16_t size){
|
||||||
bd_addr_t event_addr;
|
bd_addr_t event_addr;
|
||||||
hfp_connection_t * context = NULL;
|
hfp_connection_t * context = NULL;
|
||||||
|
|
||||||
@ -293,7 +339,7 @@ hfp_connection_t * handle_hci_event(uint8_t packet_type, uint8_t *packet, uint16
|
|||||||
context->con_handle = READ_BT_16(packet, 9);
|
context->con_handle = READ_BT_16(packet, 9);
|
||||||
context->rfcomm_cid = READ_BT_16(packet, 12);
|
context->rfcomm_cid = READ_BT_16(packet, 12);
|
||||||
uint16_t mtu = READ_BT_16(packet, 14);
|
uint16_t mtu = READ_BT_16(packet, 14);
|
||||||
|
context->state = HFP_W4_SUPPORTED_FEATURES_EXCHANGE;
|
||||||
printf("RFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u\n", context->rfcomm_cid, mtu);
|
printf("RFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u\n", context->rfcomm_cid, mtu);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -322,8 +368,9 @@ void hfp_connect(bd_addr_t bd_addr, uint16_t service_uuid){
|
|||||||
}
|
}
|
||||||
if (connection->state != HFP_IDLE) return;
|
if (connection->state != HFP_IDLE) return;
|
||||||
|
|
||||||
connection->state = HFP_W4_SDP_QUERY_COMPLETE;
|
|
||||||
memcpy(connection->remote_addr, bd_addr, 6);
|
memcpy(connection->remote_addr, bd_addr, 6);
|
||||||
|
connection->state = HFP_W4_SDP_QUERY_COMPLETE;
|
||||||
|
|
||||||
connection_doing_sdp_query = connection;
|
connection_doing_sdp_query = connection;
|
||||||
sdp_query_rfcomm_channel_and_name_for_uuid(connection->remote_addr, service_uuid);
|
sdp_query_rfcomm_channel_and_name_for_uuid(connection->remote_addr, service_uuid);
|
||||||
}
|
}
|
||||||
|
67
src/hfp.h
67
src/hfp.h
@ -52,11 +52,65 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define HFP_Default_HF_Supported_Features 0x0000
|
||||||
|
#define HFP_Default_AG_Supported_Features 0x0009
|
||||||
|
#define HFP_MAX_NUM_CODECS 20
|
||||||
|
|
||||||
|
/* AT+BRSF Result:
|
||||||
|
0: EC and/or NR function
|
||||||
|
1: Three-way calling
|
||||||
|
2: CLI presentation capability
|
||||||
|
3: Voice recognition activation
|
||||||
|
4: Remote volume control
|
||||||
|
5: Enhanced call status
|
||||||
|
6: Enhanced call control
|
||||||
|
7: Codec negotiation
|
||||||
|
8: HF Indicators
|
||||||
|
9: eSCO S4 (and T2) Settings Supported
|
||||||
|
10-31: Reserved for future definition
|
||||||
|
*/
|
||||||
|
/* +BRSF Result:
|
||||||
|
0: Three-way calling
|
||||||
|
1: EC and/or NR function
|
||||||
|
2: Voice recognition function
|
||||||
|
3: In-band ring tone capability
|
||||||
|
4: Attach a number to a voice tag
|
||||||
|
5: Ability to reject a call
|
||||||
|
6: Enhanced call status
|
||||||
|
7: Enhanced call control
|
||||||
|
8: Extended Error Result Codes
|
||||||
|
9: Codec negotiation
|
||||||
|
10: HF Indicators
|
||||||
|
11: eSCO S4 (and T2) Settings Supported
|
||||||
|
12-31: Reserved for future definition
|
||||||
|
*/
|
||||||
|
#define HFP_Supported_Features "+BRSF"
|
||||||
|
#define HFP_Available_Codecs "+BAC"
|
||||||
|
#define HFP_Codec_Indicator "+CIND"
|
||||||
|
#define HFP_Enable_Indicator_Status_Update "+CMER"
|
||||||
|
#define HFP_Support_Call_Hold_And_Multiparty_Services "+CHLD"
|
||||||
|
#define HFP_Generic_Status_Indicator "+BIND"
|
||||||
|
#define HFP_OK "OK"
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
HFP_IDLE,
|
HFP_IDLE,
|
||||||
HFP_SDP_QUERY_RFCOMM_CHANNEL,
|
HFP_SDP_QUERY_RFCOMM_CHANNEL,
|
||||||
HFP_W4_SDP_QUERY_COMPLETE,
|
HFP_W4_SDP_QUERY_COMPLETE,
|
||||||
HFP_W4_RFCOMM_CONNECTED,
|
HFP_W4_RFCOMM_CONNECTED,
|
||||||
|
HFP_W4_SUPPORTED_FEATURES_EXCHANGE,
|
||||||
|
HFP_W4_CODEC_NEGOTIATION,
|
||||||
|
HFP_W4_INDICATORS,
|
||||||
|
HFP_W4_INDICATORS_STATUS,
|
||||||
|
HFP_W4_INDICATORS_STATUS_UPDATE,
|
||||||
|
HFP_W4_CAN_HOLD_CALL,
|
||||||
|
HFP_W4_GENERIC_STATUS_INDICATORS,
|
||||||
|
HFP_W4_HF_GENERIC_STATUS_INDICATORS,
|
||||||
|
HFP_W4_AG_GENERIC_STATUS_INDICATORS,
|
||||||
|
HFP_W4_INITITAL_STATE_GENERIC_STATUS_INDICATORS,
|
||||||
|
|
||||||
|
HFP_CMD_SENT,
|
||||||
|
|
||||||
HFP_ACTIVE,
|
HFP_ACTIVE,
|
||||||
HFP_W2_DISCONNECT_RFCOMM,
|
HFP_W2_DISCONNECT_RFCOMM,
|
||||||
HFP_W4_RFCOMM_DISCONNECTED,
|
HFP_W4_RFCOMM_DISCONNECTED,
|
||||||
@ -74,16 +128,25 @@ typedef struct hfp_connection {
|
|||||||
uint16_t rfcomm_channel_nr;
|
uint16_t rfcomm_channel_nr;
|
||||||
uint16_t rfcomm_cid;
|
uint16_t rfcomm_cid;
|
||||||
|
|
||||||
uint16_t query_service_uuid;
|
uint8_t wait_ok;
|
||||||
|
uint8_t * codecs;
|
||||||
|
|
||||||
hfp_callback_t callback;
|
hfp_callback_t callback;
|
||||||
} hfp_connection_t;
|
} hfp_connection_t;
|
||||||
|
|
||||||
void hfp_create_service(uint8_t * service, uint16_t service_uuid, int rfcomm_channel_nr, const char * name, uint16_t supported_features);
|
void hfp_create_service(uint8_t * service, uint16_t service_uuid, int rfcomm_channel_nr, const char * name, uint16_t supported_features);
|
||||||
void hfp_register_packet_handler(hfp_callback_t callback);
|
void hfp_register_packet_handler(hfp_callback_t callback);
|
||||||
hfp_connection_t * handle_hci_event(uint8_t packet_type, uint8_t *packet, uint16_t size);
|
hfp_connection_t * hfp_handle_hci_event(uint8_t packet_type, uint8_t *packet, uint16_t size);
|
||||||
void hfp_init(uint16_t rfcomm_channel_nr);
|
void hfp_init(uint16_t rfcomm_channel_nr);
|
||||||
void hfp_connect(bd_addr_t bd_addr, uint16_t service_uuid);
|
void hfp_connect(bd_addr_t bd_addr, uint16_t service_uuid);
|
||||||
|
|
||||||
|
hfp_connection_t * get_hfp_connection_context_for_rfcomm_cid(uint16_t cid);
|
||||||
|
|
||||||
|
// TODO: move to utils
|
||||||
|
int send_str_over_rfcomm(uint16_t cid, char * command);
|
||||||
|
void join(char * buffer, int buffer_size, int buffer_offset, uint8_t * values, int values_nr);
|
||||||
|
void emit_event(hfp_callback_t callback, uint8_t event_subtype, uint8_t value);
|
||||||
|
|
||||||
#if defined __cplusplus
|
#if defined __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
47
src/hfp_ag.c
47
src/hfp_ag.c
@ -62,6 +62,9 @@
|
|||||||
#include "hfp_ag.h"
|
#include "hfp_ag.h"
|
||||||
|
|
||||||
static const char default_hfp_ag_service_name[] = "Voice gateway";
|
static const char default_hfp_ag_service_name[] = "Voice gateway";
|
||||||
|
static uint16_t hfp_supported_features = HFP_Default_HF_Supported_Features;
|
||||||
|
static uint8_t hfp_codecs_nr = 0;
|
||||||
|
static uint8_t hfp_codecs[HFP_MAX_NUM_CODECS];
|
||||||
|
|
||||||
static void packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
|
static void packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
|
||||||
|
|
||||||
@ -79,31 +82,61 @@ void hfp_ag_create_service(uint8_t * service, int rfcomm_channel_nr, const char
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void hfp_run(hfp_connection_t * connection){
|
static void hfp_run(hfp_connection_t * connection){
|
||||||
if (!connection) return;
|
if (!connection) return;
|
||||||
|
|
||||||
switch (connection->state){
|
switch (connection->state){
|
||||||
|
case HFP_W4_SUPPORTED_FEATURES_EXCHANGE:
|
||||||
|
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hfp_connection_t * hfp_handle_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
||||||
|
hfp_connection_t * context = get_hfp_connection_context_for_rfcomm_cid(channel);
|
||||||
|
if (!context) return NULL;
|
||||||
|
while (size > 0 && (packet[0] == '\n' || packet[0] == '\r')){
|
||||||
|
size--;
|
||||||
|
packet++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
static void packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
static void packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
||||||
// printf("packet_handler type %u, packet[0] %x\n", packet_type, packet[0]);
|
// printf("packet_handler type %u, packet[0] %x\n", packet_type, packet[0]);
|
||||||
hfp_connection_t * context = NULL;
|
hfp_connection_t * context = NULL;
|
||||||
|
|
||||||
if (packet_type == RFCOMM_DATA_PACKET){
|
switch (packet_type){
|
||||||
hfp_run(context);
|
case RFCOMM_DATA_PACKET:
|
||||||
return;
|
context = hfp_handle_rfcomm_event(packet_type, channel, packet, size);
|
||||||
}
|
break;
|
||||||
context = handle_hci_event(packet_type, packet, size);
|
case HCI_EVENT_PACKET:
|
||||||
|
context = hfp_handle_hci_event(packet_type, packet, size);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
hfp_run(context);
|
hfp_run(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hfp_ag_init(uint16_t rfcomm_channel_nr){
|
void hfp_ag_init(uint16_t rfcomm_channel_nr, uint16_t supported_features, uint8_t * codecs, int codecs_nr){
|
||||||
|
if (codecs_nr > HFP_MAX_NUM_CODECS){
|
||||||
|
log_error("hfp_init: codecs_nr (%d) > HFP_MAX_NUM_CODECS (%d)", codecs_nr, HFP_MAX_NUM_CODECS);
|
||||||
|
return;
|
||||||
|
}
|
||||||
hfp_init(rfcomm_channel_nr);
|
hfp_init(rfcomm_channel_nr);
|
||||||
rfcomm_register_packet_handler(packet_handler);
|
rfcomm_register_packet_handler(packet_handler);
|
||||||
|
// connection->codecs = codecs;
|
||||||
|
hfp_supported_features = supported_features;
|
||||||
|
hfp_codecs_nr = codecs_nr;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i=0; i<codecs_nr; i++){
|
||||||
|
hfp_codecs[i] = codecs[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void hfp_ag_connect(bd_addr_t bd_addr){
|
void hfp_ag_connect(bd_addr_t bd_addr){
|
||||||
|
@ -54,10 +54,12 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void hfp_ag_create_service(uint8_t * service, int rfcomm_channel_nr, const char * name, uint8_t ability_to_reject_call, uint16_t supported_features);
|
void hfp_ag_create_service(uint8_t * service, int rfcomm_channel_nr, const char * name, uint8_t ability_to_reject_call, uint16_t supported_features);
|
||||||
void hfp_ag_init(uint16_t rfcomm_channel_nr);
|
void hfp_ag_init(uint16_t rfcomm_channel_nr, uint16_t supported_features, uint8_t * codecs, int num_codecs);
|
||||||
void hfp_ag_connect(bd_addr_t bd_addr);
|
void hfp_ag_connect(bd_addr_t bd_addr);
|
||||||
void hfp_ag_disconnect(bd_addr_t bd_addr);
|
void hfp_ag_disconnect(bd_addr_t bd_addr);
|
||||||
|
|
||||||
|
void hfp_ag_supported_features_exchange(uint16_t supported_features);
|
||||||
|
|
||||||
#if defined __cplusplus
|
#if defined __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
114
src/hfp_hf.c
114
src/hfp_hf.c
@ -61,7 +61,12 @@
|
|||||||
#include "hfp.h"
|
#include "hfp.h"
|
||||||
#include "hfp_hf.h"
|
#include "hfp_hf.h"
|
||||||
|
|
||||||
|
|
||||||
static const char default_hfp_hf_service_name[] = "Hands-Free unit";
|
static const char default_hfp_hf_service_name[] = "Hands-Free unit";
|
||||||
|
static uint16_t hfp_supported_features = HFP_Default_HF_Supported_Features;
|
||||||
|
static uint8_t hfp_codecs_nr = 0;
|
||||||
|
static uint8_t hfp_codecs[HFP_MAX_NUM_CODECS];
|
||||||
|
|
||||||
|
|
||||||
static void packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
|
static void packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
|
||||||
|
|
||||||
@ -72,31 +77,126 @@ void hfp_hf_create_service(uint8_t * service, int rfcomm_channel_nr, const char
|
|||||||
hfp_create_service(service, SDP_Handsfree, rfcomm_channel_nr, name, supported_features);
|
hfp_create_service(service, SDP_Handsfree, rfcomm_channel_nr, name, supported_features);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hfp_hf_init(uint16_t rfcomm_channel_nr){
|
|
||||||
hfp_init(rfcomm_channel_nr);
|
static int bit(uint16_t bitmap, int position){
|
||||||
rfcomm_register_packet_handler(packet_handler);
|
return (bitmap >> position) & 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int hfp_hs_supported_features_exchange_cmd(uint16_t cid){
|
||||||
|
char buffer[20];
|
||||||
|
sprintf(buffer, "AT%s=%d\r\n", HFP_Supported_Features, hfp_supported_features);
|
||||||
|
return send_str_over_rfcomm(cid, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
int hfp_hs_codec_negotiation_cmd(uint16_t cid){
|
||||||
|
char buffer[30];
|
||||||
|
int buffer_offset = sprintf(buffer, "AT%s=", HFP_Available_Codecs);
|
||||||
|
join(buffer, sizeof(buffer), buffer_offset, hfp_codecs, hfp_codecs_nr);
|
||||||
|
return send_str_over_rfcomm(cid, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hfp_hs_retrieve_indicators_information();
|
||||||
|
void hfp_hs_request_indicators_status();
|
||||||
|
void hfp_hs_request_indicator_status_update();
|
||||||
|
void hfp_hs_list_generic_status_indicators();
|
||||||
|
|
||||||
static void hfp_run(hfp_connection_t * connection){
|
static void hfp_run(hfp_connection_t * connection){
|
||||||
if (!connection) return;
|
if (!connection) return;
|
||||||
|
|
||||||
|
int err = 0;
|
||||||
switch (connection->state){
|
switch (connection->state){
|
||||||
|
case HFP_W4_SUPPORTED_FEATURES_EXCHANGE:
|
||||||
|
err = hfp_hs_supported_features_exchange_cmd(connection->rfcomm_cid);
|
||||||
|
break;
|
||||||
|
case HFP_W4_CODEC_NEGOTIATION:
|
||||||
|
err = hfp_hs_codec_negotiation_cmd(connection->rfcomm_cid);
|
||||||
|
break;
|
||||||
|
case HFP_W4_INDICATORS:
|
||||||
|
break;
|
||||||
|
case HFP_W4_INDICATORS_STATUS:
|
||||||
|
break;
|
||||||
|
case HFP_W4_INDICATORS_STATUS_UPDATE:
|
||||||
|
break;
|
||||||
|
case HFP_W4_CAN_HOLD_CALL:
|
||||||
|
break;
|
||||||
|
case HFP_W4_GENERIC_STATUS_INDICATORS:
|
||||||
|
break;
|
||||||
|
case HFP_W4_HF_GENERIC_STATUS_INDICATORS:
|
||||||
|
break;
|
||||||
|
case HFP_W4_AG_GENERIC_STATUS_INDICATORS:
|
||||||
|
break;
|
||||||
|
case HFP_W4_INITITAL_STATE_GENERIC_STATUS_INDICATORS:
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (!err) connection->state = HFP_CMD_SENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
hfp_connection_t * hfp_handle_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
||||||
|
hfp_connection_t * context = get_hfp_connection_context_for_rfcomm_cid(channel);
|
||||||
|
if (!context) return NULL;
|
||||||
|
while (size > 0 && (packet[0] == '\n' || packet[0] == '\r')){
|
||||||
|
size--;
|
||||||
|
packet++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context->wait_ok){
|
||||||
|
if (strncmp((char *)packet, HFP_OK, strlen(HFP_OK)) == 0){
|
||||||
|
context->wait_ok = 0;
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp((char *)packet, HFP_Supported_Features, strlen(HFP_Supported_Features)) == 0){
|
||||||
|
uint16_t supported_features = (uint16_t)atoi((char*)&packet[strlen(HFP_Supported_Features+1)]);
|
||||||
|
if (bit(supported_features, 7) && bit(hfp_supported_features,9)){
|
||||||
|
context->state = HFP_W4_CODEC_NEGOTIATION;
|
||||||
|
} else {
|
||||||
|
context->state = HFP_W4_INDICATORS;
|
||||||
|
}
|
||||||
|
context->wait_ok = 1;
|
||||||
|
}
|
||||||
|
if (strncmp((char *)packet, HFP_Available_Codecs, strlen(HFP_Available_Codecs)) == 0){
|
||||||
|
// parse available codecs
|
||||||
|
}
|
||||||
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
static void packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
||||||
// printf("packet_handler type %u, packet[0] %x\n", packet_type, packet[0]);
|
// printf("packet_handler type %u, packet[0] %x\n", packet_type, packet[0]);
|
||||||
hfp_connection_t * context = NULL;
|
hfp_connection_t * context = NULL;
|
||||||
|
|
||||||
if (packet_type == RFCOMM_DATA_PACKET){
|
switch (packet_type){
|
||||||
hfp_run(context);
|
case RFCOMM_DATA_PACKET:
|
||||||
|
context = hfp_handle_rfcomm_event(packet_type, channel, packet, size);
|
||||||
|
break;
|
||||||
|
case HCI_EVENT_PACKET:
|
||||||
|
context = hfp_handle_hci_event(packet_type, packet, size);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
hfp_run(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hfp_hf_init(uint16_t rfcomm_channel_nr, uint16_t supported_features, uint8_t * codecs, int codecs_nr){
|
||||||
|
if (codecs_nr > HFP_MAX_NUM_CODECS){
|
||||||
|
log_error("hfp_init: codecs_nr (%d) > HFP_MAX_NUM_CODECS (%d)", codecs_nr, HFP_MAX_NUM_CODECS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
context = handle_hci_event(packet_type, packet, size);
|
hfp_init(rfcomm_channel_nr);
|
||||||
hfp_run(context);
|
rfcomm_register_packet_handler(packet_handler);
|
||||||
|
|
||||||
|
// connection->codecs = codecs;
|
||||||
|
hfp_supported_features = supported_features;
|
||||||
|
hfp_codecs_nr = codecs_nr;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i=0; i<codecs_nr; i++){
|
||||||
|
hfp_codecs[i] = codecs[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void hfp_hf_connect(bd_addr_t bd_addr){
|
void hfp_hf_connect(bd_addr_t bd_addr){
|
||||||
|
@ -55,7 +55,7 @@ extern "C" {
|
|||||||
|
|
||||||
|
|
||||||
void hfp_hf_create_service(uint8_t * service, int rfcomm_channel_nr, const char * name, uint16_t supported_features);
|
void hfp_hf_create_service(uint8_t * service, int rfcomm_channel_nr, const char * name, uint16_t supported_features);
|
||||||
void hfp_hf_init(uint16_t rfcomm_channel_nr);
|
void hfp_hf_init(uint16_t rfcomm_channel_nr, uint16_t supported_features, uint8_t * codecs, int num_codecs);
|
||||||
void hfp_hf_connect(bd_addr_t bd_addr);
|
void hfp_hf_connect(bd_addr_t bd_addr);
|
||||||
void hfp_hf_disconnect(bd_addr_t bd_addr);
|
void hfp_hf_disconnect(bd_addr_t bd_addr);
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ int btstack_main(int argc, const char * argv[]){
|
|||||||
l2cap_init();
|
l2cap_init();
|
||||||
rfcomm_init();
|
rfcomm_init();
|
||||||
|
|
||||||
hfp_ag_init(rfcomm_channel_nr);
|
// TODO: hfp_ag_init(rfcomm_channel_nr);
|
||||||
hfp_register_packet_handler(packet_handler);
|
hfp_register_packet_handler(packet_handler);
|
||||||
|
|
||||||
sdp_init();
|
sdp_init();
|
||||||
|
@ -129,7 +129,7 @@ int btstack_main(int argc, const char * argv[]){
|
|||||||
l2cap_init();
|
l2cap_init();
|
||||||
rfcomm_init();
|
rfcomm_init();
|
||||||
|
|
||||||
hfp_hf_init(rfcomm_channel_nr);
|
// TODO: hfp_hf_init(rfcomm_channel_nr);
|
||||||
hfp_register_packet_handler(packet_handler);
|
hfp_register_packet_handler(packet_handler);
|
||||||
|
|
||||||
sdp_init();
|
sdp_init();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user