diff --git a/include/btstack/hci_cmds.h b/include/btstack/hci_cmds.h index dbca7f6e8..fb93baf41 100644 --- a/include/btstack/hci_cmds.h +++ b/include/btstack/hci_cmds.h @@ -616,8 +616,8 @@ extern "C" { #define HCI_EVENT_HFP_META 0xE9 -#define HFP_SUBEVENT_AUDIO_CONNECTION_COMPLETE 0x01 -#define HFP_SUBEVENT_SUPPORTED_FEATURES_EXCHANGE 0x02 +#define HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED 0x01 +#define HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED 0x02 // ANCS Client diff --git a/src/hfp.c b/src/hfp.c index 6b4304911..261cfd39a 100644 --- a/src/hfp.c +++ b/src/hfp.c @@ -93,7 +93,7 @@ static const char * hfp_ag_features[] = { "Reserved for future definition" }; -static hfp_callback_t hfp_callback; + static linked_list_t hfp_connections = NULL; const char * hfp_hf_feature(int index){ @@ -135,7 +135,7 @@ int join(char * buffer, int buffer_size, uint8_t * values, int values_nr){ } -static void hfp_emit_event(hfp_callback_t callback, uint8_t event_subtype, uint8_t value){ +void hfp_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; @@ -178,6 +178,8 @@ static hfp_connection_t * create_hfp_connection_context(){ hfp_connection_t * context = btstack_memory_hfp_connection_get(); if (!context) return NULL; // init state + memset(context,0, sizeof(hfp_connection_t)); + context->state = HFP_IDLE; context->line_size = 0; context->parser_state = HFP_PARSER_CMD_HEADER; @@ -193,6 +195,9 @@ static hfp_connection_t * create_hfp_connection_context(){ return context; } +static void remove_hfp_connection_context(hfp_connection_t * context){ + linked_list_remove(&hfp_connections, (linked_item_t*)context); +} hfp_connection_t * provide_hfp_connection_context_for_bd_addr(bd_addr_t bd_addr){ hfp_connection_t * context = get_hfp_connection_context_for_bd_addr(bd_addr); @@ -202,23 +207,6 @@ hfp_connection_t * provide_hfp_connection_context_for_bd_addr(bd_addr_t bd_addr) return context; } -hfp_connection_t * provide_hfp_connection_context_for_rfcomm_cid(uint16_t rfcomm_cid){ - hfp_connection_t * context = get_hfp_connection_context_for_rfcomm_cid(rfcomm_cid); - if (context) return context; - context = create_hfp_connection_context(); - printf("Set RFCOMM cid %p %u\n", context, context->rfcomm_cid); - context->rfcomm_cid = rfcomm_cid; - return context; -} - - -void hfp_register_packet_handler(hfp_callback_t callback){ - if (callback == NULL){ - log_error("hfp_register_packet_handler called with NULL callback"); - return; - } - hfp_callback = callback; -} /* @param suported_features * HF bit 0: EC and/or NR function (yes/no, 1 = yes, 0 = no) @@ -338,15 +326,9 @@ static void handle_query_rfcomm_event(sdp_query_event_t * event, void * context) } } -static void hfp_reset_state(hfp_connection_t * connection){ - if (!connection) return; - connection->state = HFP_IDLE; -} - - -hfp_connection_t * hfp_handle_hci_event(uint8_t packet_type, uint8_t *packet, uint16_t size){ - +void hfp_handle_hci_event(uint8_t packet_type, uint8_t *packet, uint16_t size){ bd_addr_t event_addr; + uint16_t rfcomm_cid = 0; hfp_connection_t * context = NULL; switch (packet[0]) { @@ -367,9 +349,9 @@ hfp_connection_t * hfp_handle_hci_event(uint8_t packet_type, uint8_t *packet, ui case RFCOMM_EVENT_INCOMING_CONNECTION: // data: event (8), len(8), address(48), channel (8), rfcomm_cid (16) bt_flip_addr(event_addr, &packet[2]); - context = provide_hfp_connection_context_for_bd_addr(event_addr); + context = get_hfp_connection_context_for_bd_addr(event_addr); - if (!context || context->state != HFP_IDLE) return context; + if (!context || context->state != HFP_IDLE) return; context->rfcomm_cid = READ_BT_16(packet, 9); context->state = HFP_W4_RFCOMM_CONNECTED; @@ -381,34 +363,41 @@ hfp_connection_t * hfp_handle_hci_event(uint8_t packet_type, uint8_t *packet, ui // data: event(8), len(8), status (8), address (48), handle(16), server channel(8), rfcomm_cid(16), max frame size(16) printf("RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE packet_handler type %u, packet[0] %x\n", packet_type, packet[0]); bt_flip_addr(event_addr, &packet[3]); - context = provide_hfp_connection_context_for_bd_addr(event_addr); - if (!context || context->state != HFP_W4_RFCOMM_CONNECTED) return context; + context = get_hfp_connection_context_for_bd_addr(event_addr); + if (!context || context->state != HFP_W4_RFCOMM_CONNECTED) return; if (packet[2]) { - hfp_reset_state(context); - // hfp_emit_event(context->callback, HFP_SUBEVENT_CONNECTION_COMPLETE, packet[2]); + remove_hfp_connection_context(context); } else { context->con_handle = READ_BT_16(packet, 9); context->rfcomm_cid = READ_BT_16(packet, 12); uint16_t mtu = READ_BT_16(packet, 14); - context->state = HFP_EXCHANGE_SUPPORTED_FEATURES; printf("RFCOMM channel open succeeded. Context %p, RFCOMM Channel ID 0x%02x, max frame size %u\n", context, context->rfcomm_cid, mtu); + + switch (context->state){ + case HFP_W4_RFCOMM_CONNECTED: + context->state = HFP_EXCHANGE_SUPPORTED_FEATURES; + break; + case HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN: + context->state = HFP_W2_DISCONNECT_RFCOMM; + printf("Shutting down RFCOMM.\n"); + break; + default: + break; + } } break; - case HCI_EVENT_DISCONNECTION_COMPLETE: - printf("HCI_EVENT_DISCONNECTION_COMPLETE \n"); - break; + case RFCOMM_EVENT_CHANNEL_CLOSED: - printf(" RFCOMM_EVENT_CHANNEL_CLOSED\n"); - // hfp_emit_event(context->callback, HFP_SUBEVENT_DISCONNECTION_COMPLETE,0); - break; - case RFCOMM_EVENT_CREDITS: - context = provide_hfp_connection_context_for_rfcomm_cid(READ_BT_16(packet, 2)); + rfcomm_cid = READ_BT_16(packet,2); + context = get_hfp_connection_context_for_rfcomm_cid(rfcomm_cid); + if (!context) break; + remove_hfp_connection_context(context); break; + default: break; } - return context; } void update_command(hfp_connection_t * context); @@ -548,20 +537,40 @@ void hfp_init(uint16_t rfcomm_channel_nr){ } void hfp_connect(bd_addr_t bd_addr, uint16_t service_uuid){ - hfp_connection_t * connection = provide_hfp_connection_context_for_bd_addr(bd_addr); - log_info("hfp_connect %s, context %p", bd_addr_to_str(bd_addr), connection); + hfp_connection_t * context = provide_hfp_connection_context_for_bd_addr(bd_addr); + log_info("hfp_connect %s, context %p", bd_addr_to_str(bd_addr), context); - if (!connection) { - log_error("hfp_hf_connect for addr %s failed", bd_addr_to_str(bd_addr)); + if (!context) { + log_error("hfp_connect for addr %s failed", bd_addr_to_str(bd_addr)); return; } - if (connection->state != HFP_IDLE) return; + if (context->state != HFP_IDLE) return; - memcpy(connection->remote_addr, bd_addr, 6); - connection->state = HFP_W4_SDP_QUERY_COMPLETE; + memcpy(context->remote_addr, bd_addr, 6); + context->state = HFP_W4_SDP_QUERY_COMPLETE; - connection_doing_sdp_query = connection; - sdp_query_rfcomm_channel_and_name_for_uuid(connection->remote_addr, service_uuid); + connection_doing_sdp_query = context; + sdp_query_rfcomm_channel_and_name_for_uuid(context->remote_addr, service_uuid); +} + +hfp_connection_t * hfp_disconnect(bd_addr_t bd_addr){ + hfp_connection_t * context = get_hfp_connection_context_for_bd_addr(bd_addr); + if (!context) { + log_error("hfp_disconnect for addr %s failed", bd_addr_to_str(bd_addr)); + return NULL; + } + + switch (context->state){ + case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED: + context->state = HFP_W2_DISCONNECT_RFCOMM; + break; + case HFP_W4_RFCOMM_CONNECTED: + context->state = HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN; + break; + default: + break; + } + return context; } void hfp_set_codec(hfp_connection_t * context, uint8_t *packet, uint16_t size){ diff --git a/src/hfp.h b/src/hfp.h index 9b063f094..0b8ee3393 100644 --- a/src/hfp.h +++ b/src/hfp.h @@ -167,13 +167,13 @@ typedef enum { HFP_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS, // 20 HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS, - HFP_ACTIVE, // 22 + HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED, // 22 + HFP_W2_DISCONNECT_RFCOMM, HFP_W4_RFCOMM_DISCONNECTED, HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN } hfp_state_t; - typedef void (*hfp_callback_t)(uint8_t * event, uint16_t event_size); typedef struct{ @@ -193,7 +193,7 @@ typedef struct{ typedef struct hfp_connection { linked_item_t item; hfp_state_t state; - + hfp_command_t command; hfp_parser_state_t parser_state; @@ -215,17 +215,19 @@ typedef struct hfp_connection { uint32_t remote_indicators_status; - hfp_callback_t callback; } 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_register_packet_handler(hfp_callback_t callback); -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_connect(bd_addr_t bd_addr, uint16_t service_uuid); +void hfp_handle_hci_event(uint8_t packet_type, uint8_t *packet, uint16_t size); +void hfp_emit_event(hfp_callback_t callback, uint8_t event_subtype, uint8_t value); -hfp_connection_t * provide_hfp_connection_context_for_rfcomm_cid(uint16_t cid); +void hfp_init(uint16_t rfcomm_channel_nr); + +void hfp_connect(bd_addr_t bd_addr, uint16_t service_uuid); +hfp_connection_t * hfp_disconnect(bd_addr_t bd_addr); + +hfp_connection_t * get_hfp_connection_context_for_rfcomm_cid(uint16_t cid); linked_list_t * hfp_get_connections(); void hfp_parse(hfp_connection_t * context, uint8_t byte); diff --git a/src/hfp_ag.c b/src/hfp_ag.c index f966da1a0..16ba6b4bb 100644 --- a/src/hfp_ag.c +++ b/src/hfp_ag.c @@ -74,9 +74,18 @@ static hfp_ag_indicator_t hfp_ag_indicators[HFP_MAX_NUM_AG_INDICATORS]; static int hfp_ag_call_hold_services_nr = 0; static char *hfp_ag_call_hold_services[6]; +static hfp_callback_t hfp_callback; static void packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); +void hfp_ag_register_packet_handler(hfp_callback_t callback){ + if (callback == NULL){ + log_error("hfp_ag_register_packet_handler called with NULL callback"); + return; + } + hfp_callback = callback; +} + static int has_codec_negotiation_feature(hfp_connection_t * connection){ int hf = get_bit(connection->remote_supported_features, HFP_HFSF_CODEC_NEGOTIATION); @@ -291,7 +300,7 @@ void update_command(hfp_connection_t * context){ void hfp_run_for_context(hfp_connection_t *context){ if (!context) return; if (!rfcomm_can_send_packet_now(context->rfcomm_cid)) return; - printf("hfp_run_for_context: command %d, state %d\n", context->command, context->state); + switch(context->command){ case HFP_CMD_SUPPORTED_FEATURES: switch(context->state){ @@ -337,7 +346,8 @@ void hfp_run_for_context(hfp_connection_t *context){ context->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS; break; } - context->state = HFP_ACTIVE; + context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; + hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0); break; default: break; @@ -355,7 +365,8 @@ void hfp_run_for_context(hfp_connection_t *context){ context->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS; break; } - context->state = HFP_ACTIVE; + context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; + hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0); break; default: break; @@ -369,7 +380,8 @@ void hfp_run_for_context(hfp_connection_t *context){ context->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS; break; } - context->state = HFP_ACTIVE; + context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; + hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0); break; default: break; @@ -387,7 +399,20 @@ void hfp_run_for_context(hfp_connection_t *context){ break; case HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS: hfp_ag_retrieve_initital_supported_generic_status_indicators_cmd(context->rfcomm_cid); - context->state = HFP_ACTIVE; + + context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; + hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0); + break; + default: + break; + } + break; + case HFP_CMD_NONE: + switch(context->state){ + case HFP_W2_DISCONNECT_RFCOMM: + // printf("rfcomm_disconnect_internal cid 0x%02x\n", context->rfcomm_cid); + context->state = HFP_W4_RFCOMM_DISCONNECTED; + rfcomm_disconnect_internal(context->rfcomm_cid); break; default: break; @@ -401,7 +426,7 @@ void hfp_run_for_context(hfp_connection_t *context){ } static void hfp_handle_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ - hfp_connection_t * context = provide_hfp_connection_context_for_rfcomm_cid(channel); + hfp_connection_t * context = get_hfp_connection_context_for_rfcomm_cid(channel); if (!context) return; if (context->state == HFP_EXCHANGE_SUPPORTED_FEATURES){ context->state = HFP_W4_EXCHANGE_SUPPORTED_FEATURES; @@ -434,6 +459,18 @@ static void packet_handler(void * connection, uint8_t packet_type, uint16_t chan break; case HCI_EVENT_PACKET: hfp_handle_hci_event(packet_type, packet, size); + switch(packet[0]){ + case RFCOMM_EVENT_CHANNEL_CLOSED: + hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED, 0); + break; + case RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE: + if (packet[2]){ + hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, packet[2]); + } + break; + default: + break; + } break; default: break; @@ -476,6 +513,7 @@ void hfp_ag_connect(bd_addr_t bd_addr){ } void hfp_ag_disconnect(bd_addr_t bd_addr){ - + hfp_connection_t * connection = hfp_disconnect(bd_addr); + hfp_run_for_context(connection); } diff --git a/src/hfp_ag.h b/src/hfp_ag.h index 8ed8f4aa7..58ab58af6 100644 --- a/src/hfp_ag.h +++ b/src/hfp_ag.h @@ -59,6 +59,7 @@ void hfp_ag_init(uint16_t rfcomm_channel_nr, uint32_t supported_features, hfp_ag_indicator_t * ag_indicators, int ag_indicators_nr, hfp_hf_indicator_t * hf_indicators, int hf_indicators_nr, char *call_hold_services[], int call_hold_services_nr); +void hfp_ag_register_packet_handler(hfp_callback_t callback); void hfp_ag_connect(bd_addr_t bd_addr); void hfp_ag_disconnect(bd_addr_t bd_addr); diff --git a/src/hfp_hf.c b/src/hfp_hf.c index 883b33c9b..d93f30d2b 100644 --- a/src/hfp_hf.c +++ b/src/hfp_hf.c @@ -71,6 +71,17 @@ static uint8_t hfp_indicators_nr = 0; static uint8_t hfp_indicators[HFP_MAX_NUM_HF_INDICATORS]; static uint8_t hfp_indicators_status; +static hfp_callback_t hfp_callback; + +void hfp_hf_register_packet_handler(hfp_callback_t callback){ + hfp_callback = callback; + if (callback == NULL){ + log_error("hfp_hf_register_packet_handler called with NULL callback"); + return; + } + hfp_callback = callback; +} + static int has_codec_negotiation_feature(hfp_connection_t * connection){ int hf = get_bit(hfp_supported_features, HFP_HFSF_CODEC_NEGOTIATION); @@ -169,50 +180,54 @@ int hfp_hs_list_initital_supported_generic_status_indicators_cmd(uint16_t cid){ return send_str_over_rfcomm(cid, buffer); } -static void hfp_run_for_context(hfp_connection_t * connection){ - if (!connection) return; - // printf("hfp send cmd: context %p, RFCOMM cid %u \n", connection, connection->rfcomm_cid ); - if (!rfcomm_can_send_packet_now(connection->rfcomm_cid)) return; +static void hfp_run_for_context(hfp_connection_t * context){ + if (!context) return; + // printf("hfp send cmd: context %p, RFCOMM cid %u \n", context, context->rfcomm_cid ); + if (!rfcomm_can_send_packet_now(context->rfcomm_cid)) return; - switch (connection->state){ + switch (context->state){ case HFP_EXCHANGE_SUPPORTED_FEATURES: - hfp_hs_exchange_supported_features_cmd(connection->rfcomm_cid); - connection->state = HFP_W4_EXCHANGE_SUPPORTED_FEATURES; + hfp_hs_exchange_supported_features_cmd(context->rfcomm_cid); + context->state = HFP_W4_EXCHANGE_SUPPORTED_FEATURES; break; case HFP_NOTIFY_ON_CODECS: - hfp_hs_retrieve_codec_cmd(connection->rfcomm_cid); - connection->state = HFP_W4_NOTIFY_ON_CODECS; + hfp_hs_retrieve_codec_cmd(context->rfcomm_cid); + context->state = HFP_W4_NOTIFY_ON_CODECS; break; case HFP_RETRIEVE_INDICATORS: - hfp_hs_retrieve_indicators_cmd(connection->rfcomm_cid); - connection->state = HFP_W4_RETRIEVE_INDICATORS; + hfp_hs_retrieve_indicators_cmd(context->rfcomm_cid); + context->state = HFP_W4_RETRIEVE_INDICATORS; break; case HFP_RETRIEVE_INDICATORS_STATUS: - hfp_hs_retrieve_indicators_status_cmd(connection->rfcomm_cid); - connection->state = HFP_W4_RETRIEVE_INDICATORS_STATUS; + hfp_hs_retrieve_indicators_status_cmd(context->rfcomm_cid); + context->state = HFP_W4_RETRIEVE_INDICATORS_STATUS; break; case HFP_ENABLE_INDICATORS_STATUS_UPDATE: - hfp_hs_toggle_indicator_status_update_cmd(connection->rfcomm_cid, 1); - connection->state = HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE; + hfp_hs_toggle_indicator_status_update_cmd(context->rfcomm_cid, 1); + context->state = HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE; break; case HFP_RETRIEVE_CAN_HOLD_CALL: - hfp_hs_retrieve_can_hold_call_cmd(connection->rfcomm_cid); - connection->state = HFP_W4_RETRIEVE_CAN_HOLD_CALL; + hfp_hs_retrieve_can_hold_call_cmd(context->rfcomm_cid); + context->state = HFP_W4_RETRIEVE_CAN_HOLD_CALL; break; case HFP_LIST_GENERIC_STATUS_INDICATORS: - hfp_hs_list_supported_generic_status_indicators_cmd(connection->rfcomm_cid); - connection->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS; + hfp_hs_list_supported_generic_status_indicators_cmd(context->rfcomm_cid); + context->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS; break; case HFP_RETRIEVE_GENERIC_STATUS_INDICATORS: - hfp_hs_retrieve_supported_generic_status_indicators_cmd(connection->rfcomm_cid); - connection->state = HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS; + hfp_hs_retrieve_supported_generic_status_indicators_cmd(context->rfcomm_cid); + context->state = HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS; break; case HFP_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS: - hfp_hs_list_initital_supported_generic_status_indicators_cmd(connection->rfcomm_cid); - connection->state = HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS; + hfp_hs_list_initital_supported_generic_status_indicators_cmd(context->rfcomm_cid); + context->state = HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS; break; - case HFP_ACTIVE: - printf("HFP_ACTIVE\n"); + case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED: + hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0); + break; + case HFP_W2_DISCONNECT_RFCOMM: + context->state = HFP_W4_RFCOMM_DISCONNECTED; + rfcomm_disconnect_internal(context->rfcomm_cid); break; default: break; @@ -297,7 +312,7 @@ void handle_switch_on_ok(hfp_connection_t *context){ context->state = HFP_LIST_GENERIC_STATUS_INDICATORS; break; } - context->state = HFP_ACTIVE; + context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; break; case HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE: @@ -309,7 +324,7 @@ void handle_switch_on_ok(hfp_connection_t *context){ context->state = HFP_LIST_GENERIC_STATUS_INDICATORS; break; } - context->state = HFP_ACTIVE; + context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; break; case HFP_W4_RETRIEVE_CAN_HOLD_CALL: @@ -317,7 +332,7 @@ void handle_switch_on_ok(hfp_connection_t *context){ context->state = HFP_LIST_GENERIC_STATUS_INDICATORS; break; } - context->state = HFP_ACTIVE; + context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; break; case HFP_W4_LIST_GENERIC_STATUS_INDICATORS: @@ -330,7 +345,7 @@ void handle_switch_on_ok(hfp_connection_t *context){ case HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS: printf("Supported initial state generic status indicators \n"); - context->state = HFP_ACTIVE; + context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; break; default: @@ -342,7 +357,7 @@ void handle_switch_on_ok(hfp_connection_t *context){ } static void hfp_handle_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ - hfp_connection_t * context = provide_hfp_connection_context_for_rfcomm_cid(channel); + hfp_connection_t * context = get_hfp_connection_context_for_rfcomm_cid(channel); if (!context) return; packet[size] = 0; @@ -372,8 +387,21 @@ static void packet_handler(void * connection, uint8_t packet_type, uint16_t chan break; case HCI_EVENT_PACKET: hfp_handle_hci_event(packet_type, packet, size); + switch(packet[0]){ + case RFCOMM_EVENT_CHANNEL_CLOSED: + hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED, 0); + break; + case RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE: + if (packet[2]){ + hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, packet[2]); + } + break; + default: + break; + } break; default: + printf(" hf packet handler\n"); break; } hfp_run(); @@ -407,5 +435,6 @@ void hfp_hf_connect(bd_addr_t bd_addr){ } void hfp_hf_disconnect(bd_addr_t bd_addr){ - + hfp_connection_t * connection = hfp_disconnect(bd_addr); + hfp_run_for_context(connection); } \ No newline at end of file diff --git a/src/hfp_hf.h b/src/hfp_hf.h index 9f342df69..7ecdd5805 100644 --- a/src/hfp_hf.h +++ b/src/hfp_hf.h @@ -53,9 +53,9 @@ extern "C" { #endif - 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, uint32_t supported_features, uint8_t * codecs, int codecs_nr, uint16_t * indicators, int indicators_nr, uint32_t indicators_status); +void hfp_hf_register_packet_handler(hfp_callback_t callback); void hfp_hf_connect(bd_addr_t bd_addr); void hfp_hf_disconnect(bd_addr_t bd_addr); diff --git a/test/pts/hfp_ag_test.c b/test/pts/hfp_ag_test.c index ca50b4936..de7889f69 100644 --- a/test/pts/hfp_ag_test.c +++ b/test/pts/hfp_ag_test.c @@ -125,7 +125,7 @@ static int stdin_process(struct data_source *ds){ break; case 'd': printf("Releasing HFP connection.\n"); - hfp_ag_disconnect(pts_addr); + hfp_ag_disconnect(speaker); break; default: show_usage(); @@ -136,7 +136,23 @@ static int stdin_process(struct data_source *ds){ } void packet_handler(uint8_t * event, uint16_t event_size){ + if (event[0] != HCI_EVENT_HFP_META) return; + switch (event[2]) { + case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED: + if (event[3] == 0){ + printf("Service level connection established.\n\n"); + } else { + printf("Service level connection establishment failed with status %u\n", event[3]); + } + break; + case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED: + if (event[3] == 0){ + printf("Service level connection released.\n\n"); + } else { + printf("Service level connection releasing failed with status %u\n", event[3]); + } + break; default: printf("event not handled %u\n", event[2]); break; @@ -154,7 +170,7 @@ int btstack_main(int argc, const char * argv[]){ hf_indicators, hf_indicators_nr, call_hold_services, call_hold_services_nr); - hfp_register_packet_handler(packet_handler); + hfp_ag_register_packet_handler(packet_handler); sdp_init(); // init SDP, create record for SPP and register with SDP diff --git a/test/pts/hfp_hf_test.c b/test/pts/hfp_hf_test.c index 16c9df2d4..5762c11cc 100644 --- a/test/pts/hfp_hf_test.c +++ b/test/pts/hfp_hf_test.c @@ -108,7 +108,7 @@ static int stdin_process(struct data_source *ds){ break; case 'd': printf("Releasing HFP connection.\n"); - hfp_hf_disconnect(pts_addr); + hfp_hf_disconnect(phone); break; default: show_usage(); @@ -118,14 +118,32 @@ static int stdin_process(struct data_source *ds){ return 0; } + void packet_handler(uint8_t * event, uint16_t event_size){ + if (event[0] != HCI_EVENT_HFP_META) return; + switch (event[2]) { + case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED: + if (event[3] == 0){ + printf("Service level connection established.\n\n"); + } else { + printf("Service level connection establishment failed with status %u\n", event[3]); + } + break; + case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED: + if (event[3] == 0){ + printf("Service level connection released.\n\n"); + } else { + printf("Service level connection releasing failed with status %u\n", event[3]); + } + break; default: printf("event not handled %u\n", event[2]); break; } } + int btstack_main(int argc, const char * argv[]){ // init L2CAP l2cap_init(); @@ -134,7 +152,7 @@ int btstack_main(int argc, const char * argv[]){ // hfp_hf_init(rfcomm_channel_nr, HFP_DEFAULT_HF_SUPPORTED_FEATURES, codecs, sizeof(codecs), indicators, sizeof(indicators)/sizeof(uint16_t), 1); hfp_hf_init(rfcomm_channel_nr, 438, codecs, sizeof(codecs), indicators, sizeof(indicators)/sizeof(uint16_t), 1); - hfp_register_packet_handler(packet_handler); + hfp_hf_register_packet_handler(packet_handler); sdp_init(); // init SDP, create record for SPP and register with SDP