13deb3ec6SMatthias Ringwald /*
23deb3ec6SMatthias Ringwald * Copyright (C) 2014 BlueKitchen GmbH
33deb3ec6SMatthias Ringwald *
43deb3ec6SMatthias Ringwald * Redistribution and use in source and binary forms, with or without
53deb3ec6SMatthias Ringwald * modification, are permitted provided that the following conditions
63deb3ec6SMatthias Ringwald * are met:
73deb3ec6SMatthias Ringwald *
83deb3ec6SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright
93deb3ec6SMatthias Ringwald * notice, this list of conditions and the following disclaimer.
103deb3ec6SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright
113deb3ec6SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the
123deb3ec6SMatthias Ringwald * documentation and/or other materials provided with the distribution.
133deb3ec6SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of
143deb3ec6SMatthias Ringwald * contributors may be used to endorse or promote products derived
153deb3ec6SMatthias Ringwald * from this software without specific prior written permission.
163deb3ec6SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for
173deb3ec6SMatthias Ringwald * personal benefit and not for any commercial purpose or for
183deb3ec6SMatthias Ringwald * monetary gain.
193deb3ec6SMatthias Ringwald *
203deb3ec6SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
213deb3ec6SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
223deb3ec6SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
232fca4dadSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
242fca4dadSMilanka Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
253deb3ec6SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
263deb3ec6SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
273deb3ec6SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
283deb3ec6SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
293deb3ec6SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
303deb3ec6SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
313deb3ec6SMatthias Ringwald * SUCH DAMAGE.
323deb3ec6SMatthias Ringwald *
333deb3ec6SMatthias Ringwald * Please inquire about commercial licensing options at
343deb3ec6SMatthias Ringwald * [email protected]
353deb3ec6SMatthias Ringwald *
363deb3ec6SMatthias Ringwald */
37ab2c6ae4SMatthias Ringwald
38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "hsp_hs.c"
393deb3ec6SMatthias Ringwald
403deb3ec6SMatthias Ringwald // *****************************************************************************
413deb3ec6SMatthias Ringwald //
4266a048abSMatthias Ringwald // HSP Headset
433deb3ec6SMatthias Ringwald //
443deb3ec6SMatthias Ringwald // *****************************************************************************
453deb3ec6SMatthias Ringwald
467907f069SMatthias Ringwald #include "btstack_config.h"
473deb3ec6SMatthias Ringwald
483deb3ec6SMatthias Ringwald #include <stdint.h>
493cfa4086SMatthias Ringwald #include <stdio.h>
503deb3ec6SMatthias Ringwald #include <string.h>
513deb3ec6SMatthias Ringwald
52235946f1SMatthias Ringwald #include "bluetooth_sdp.h"
5316ece135SMatthias Ringwald #include "btstack_debug.h"
547bd8e93bSMatthias Ringwald #include "btstack_event.h"
557bd8e93bSMatthias Ringwald #include "btstack_memory.h"
567bd8e93bSMatthias Ringwald #include "btstack_run_loop.h"
5759c6af15SMatthias Ringwald #include "classic/core.h"
58746ccb7eSMatthias Ringwald #include "classic/sdp_server.h"
59efda0b48SMatthias Ringwald #include "classic/sdp_client_rfcomm.h"
60023f2764SMatthias Ringwald #include "classic/sdp_util.h"
61acb6281eSMilanka Ringwald #include "classic/sdp_client.h"
627bd8e93bSMatthias Ringwald #include "hci.h"
637bd8e93bSMatthias Ringwald #include "hci_cmd.h"
647bd8e93bSMatthias Ringwald #include "hci_dump.h"
653deb3ec6SMatthias Ringwald #include "hsp_hs.h"
667bd8e93bSMatthias Ringwald #include "l2cap.h"
673deb3ec6SMatthias Ringwald
683deb3ec6SMatthias Ringwald #define HSP_AG_OK "OK"
693deb3ec6SMatthias Ringwald #define HSP_AG_ERROR "ERROR"
703deb3ec6SMatthias Ringwald #define HSP_AG_RING "RING"
713deb3ec6SMatthias Ringwald #define HSP_MICROPHONE_GAIN "+VGM="
723deb3ec6SMatthias Ringwald #define HSP_SPEAKER_GAIN "+VGS="
733deb3ec6SMatthias Ringwald
743deb3ec6SMatthias Ringwald #define HSP_HS_AT_CKPD "AT+CKPD=200\r\n"
753deb3ec6SMatthias Ringwald #define HSP_HS_MICROPHONE_GAIN "AT+VGM"
763deb3ec6SMatthias Ringwald #define HSP_HS_SPEAKER_GAIN "AT+VGS"
773deb3ec6SMatthias Ringwald
78fb460ca0SMatthias Ringwald static const char hsp_hs_default_service_name[] = "Headset";
793962dc20SMatthias Ringwald
803deb3ec6SMatthias Ringwald typedef enum {
813deb3ec6SMatthias Ringwald HSP_IDLE,
82acb6281eSMilanka Ringwald HSP_W2_SEND_SDP_QUERY,
8399a10067SMatthias Ringwald HSP_W4_SDP_QUERY_COMPLETE,
843deb3ec6SMatthias Ringwald HSP_W4_RFCOMM_CONNECTED,
8599a10067SMatthias Ringwald
8699a10067SMatthias Ringwald HSP_RFCOMM_CONNECTION_ESTABLISHED,
8799a10067SMatthias Ringwald
883deb3ec6SMatthias Ringwald HSP_W2_CONNECT_SCO,
893deb3ec6SMatthias Ringwald HSP_W4_SCO_CONNECTED,
9099a10067SMatthias Ringwald
9199a10067SMatthias Ringwald HSP_AUDIO_CONNECTION_ESTABLISHED,
9299a10067SMatthias Ringwald
933deb3ec6SMatthias Ringwald HSP_W2_DISCONNECT_SCO,
943deb3ec6SMatthias Ringwald HSP_W4_SCO_DISCONNECTED,
9599a10067SMatthias Ringwald
963deb3ec6SMatthias Ringwald HSP_W2_DISCONNECT_RFCOMM,
973deb3ec6SMatthias Ringwald HSP_W4_RFCOMM_DISCONNECTED,
983deb3ec6SMatthias Ringwald HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN
993deb3ec6SMatthias Ringwald } hsp_state_t;
1003deb3ec6SMatthias Ringwald
101fb460ca0SMatthias Ringwald // higher-layer callbacks
102fb460ca0SMatthias Ringwald static btstack_packet_handler_t hsp_hs_callback;
103fb460ca0SMatthias Ringwald
104fb460ca0SMatthias Ringwald static bd_addr_t hsp_hs_remote;
105fb460ca0SMatthias Ringwald static uint8_t hsp_hs_rfcomm_channel_nr;
106fb460ca0SMatthias Ringwald static uint16_t hsp_hs_rfcomm_cid;
107fb460ca0SMatthias Ringwald static uint16_t hsp_hs_rfcomm_mtu;
108fb460ca0SMatthias Ringwald
109fb460ca0SMatthias Ringwald static hci_con_handle_t hsp_hs_sco_handle;
110fb460ca0SMatthias Ringwald static hci_con_handle_t hsp_hs_rfcomm_handle;
111acb6281eSMilanka Ringwald
112637244f1SMatthias Ringwald static hsp_state_t hsp_state;
1133deb3ec6SMatthias Ringwald
114fb460ca0SMatthias Ringwald static int hsp_hs_microphone_gain;
115fb460ca0SMatthias Ringwald static int hsp_hs_speaker_gain;
116fb460ca0SMatthias Ringwald
117fb460ca0SMatthias Ringwald static uint8_t hsp_hs_send_button_press_triggered;
118fb460ca0SMatthias Ringwald static uint8_t hsp_hs_wait_ok;
119fb460ca0SMatthias Ringwald static uint8_t hsp_hs_accept_sco_connection;
120fb460ca0SMatthias Ringwald
121fb460ca0SMatthias Ringwald static uint8_t hsp_hs_support_custom_indications;
122fb460ca0SMatthias Ringwald static uint8_t hsp_hs_establish_audio_connection_triggered;
123fb460ca0SMatthias Ringwald static uint8_t hsp_hs_release_audio_connection_triggered;
124fb460ca0SMatthias Ringwald
125fb460ca0SMatthias Ringwald static uint16_t hsp_hs_sco_packet_types;
126fb460ca0SMatthias Ringwald
127fb460ca0SMatthias Ringwald static btstack_packet_callback_registration_t hsp_hs_hci_event_callback_registration;
128fb460ca0SMatthias Ringwald static btstack_context_callback_registration_t hsp_hs_handle_sdp_client_query_request;
129fb460ca0SMatthias Ringwald
130401a115bSMatthias Ringwald #ifdef ENABLE_RTK_PCM_WBS
131401a115bSMatthias Ringwald static bool hsp_hs_rtk_send_sco_config;
132401a115bSMatthias Ringwald #endif
133fb460ca0SMatthias Ringwald
1343deb3ec6SMatthias Ringwald static void hsp_run(void);
135e53943d7SMatthias Ringwald static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
1366c927b22SMatthias Ringwald static void handle_query_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
1373deb3ec6SMatthias Ringwald
hsp_hs_register_packet_handler(btstack_packet_handler_t callback)13813839019SMatthias Ringwald void hsp_hs_register_packet_handler(btstack_packet_handler_t callback){
139a15a08d7SMatthias Ringwald btstack_assert(callback);
1403deb3ec6SMatthias Ringwald hsp_hs_callback = callback;
1413deb3ec6SMatthias Ringwald }
1423deb3ec6SMatthias Ringwald
emit_event(uint8_t event_subtype)143a15a08d7SMatthias Ringwald static void emit_event(uint8_t event_subtype){
1443deb3ec6SMatthias Ringwald if (!hsp_hs_callback) return;
145a15a08d7SMatthias Ringwald uint8_t event[5];
1463deb3ec6SMatthias Ringwald event[0] = HCI_EVENT_HSP_META;
1473deb3ec6SMatthias Ringwald event[1] = sizeof(event) - 2;
1483deb3ec6SMatthias Ringwald event[2] = event_subtype;
149a15a08d7SMatthias Ringwald little_endian_store_16(event, 3, hsp_hs_rfcomm_handle);
15013839019SMatthias Ringwald (*hsp_hs_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
1513deb3ec6SMatthias Ringwald }
1524af9a48dSMatthias Ringwald
emit_event_with_value(uint8_t event_subtype,uint8_t value)153a15a08d7SMatthias Ringwald static void emit_event_with_value(uint8_t event_subtype, uint8_t value){
1544af9a48dSMatthias Ringwald if (!hsp_hs_callback) return;
1554af9a48dSMatthias Ringwald uint8_t event[6];
1564af9a48dSMatthias Ringwald event[0] = HCI_EVENT_HSP_META;
1574af9a48dSMatthias Ringwald event[1] = sizeof(event) - 2;
158a15a08d7SMatthias Ringwald event[2] = event_subtype;
159a15a08d7SMatthias Ringwald little_endian_store_16(event, 3, hsp_hs_rfcomm_handle);
160a15a08d7SMatthias Ringwald event[5] = value;
16113839019SMatthias Ringwald (*hsp_hs_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
1624af9a48dSMatthias Ringwald }
1634af9a48dSMatthias Ringwald
emit_event_rfcomm_connected(uint8_t status)164a15a08d7SMatthias Ringwald static void emit_event_rfcomm_connected(uint8_t status){
165a15a08d7SMatthias Ringwald if (!hsp_hs_callback) return;
166a15a08d7SMatthias Ringwald uint8_t event[12];
167a15a08d7SMatthias Ringwald event[0] = HCI_EVENT_HSP_META;
168a15a08d7SMatthias Ringwald event[1] = sizeof(event) - 2;
169a15a08d7SMatthias Ringwald event[2] = HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE;
170a15a08d7SMatthias Ringwald little_endian_store_16(event, 3, hsp_hs_rfcomm_handle);
171a15a08d7SMatthias Ringwald event[5] = status;
172a15a08d7SMatthias Ringwald reverse_bd_addr(hsp_hs_remote, &event[6]);
173a15a08d7SMatthias Ringwald (*hsp_hs_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
174a15a08d7SMatthias Ringwald }
175a15a08d7SMatthias Ringwald
emit_event_audio_connected(uint8_t status,uint16_t sco_handle)176a15a08d7SMatthias Ringwald static void emit_event_audio_connected(uint8_t status, uint16_t sco_handle){
177a15a08d7SMatthias Ringwald if (!hsp_hs_callback) return;
178a15a08d7SMatthias Ringwald uint8_t event[8];
179a15a08d7SMatthias Ringwald event[0] = HCI_EVENT_HSP_META;
180a15a08d7SMatthias Ringwald event[1] = sizeof(event) - 2;
181a15a08d7SMatthias Ringwald event[2] = HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE;
182a15a08d7SMatthias Ringwald little_endian_store_16(event, 3, hsp_hs_rfcomm_handle);
183a15a08d7SMatthias Ringwald event[5] = status;
184a15a08d7SMatthias Ringwald little_endian_store_16(event, 6, sco_handle);
185a15a08d7SMatthias Ringwald (*hsp_hs_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
186a15a08d7SMatthias Ringwald }
187a15a08d7SMatthias Ringwald
emit_event_audio_disconnected(uint16_t sco_handle)188a15a08d7SMatthias Ringwald static void emit_event_audio_disconnected(uint16_t sco_handle){
189a15a08d7SMatthias Ringwald if (!hsp_hs_callback) return;
190a15a08d7SMatthias Ringwald uint8_t event[7];
191a15a08d7SMatthias Ringwald event[0] = HCI_EVENT_HSP_META;
192a15a08d7SMatthias Ringwald event[1] = sizeof(event) - 2;
193a15a08d7SMatthias Ringwald event[2] = HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE;
194a15a08d7SMatthias Ringwald little_endian_store_16(event, 3, hsp_hs_rfcomm_handle);
195a15a08d7SMatthias Ringwald little_endian_store_16(event, 5, sco_handle);
196a15a08d7SMatthias Ringwald (*hsp_hs_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
197a15a08d7SMatthias Ringwald }
198a15a08d7SMatthias Ringwald
199a15a08d7SMatthias Ringwald
200605d1b1dSMilanka Ringwald // remote audio volume control
2013deb3ec6SMatthias Ringwald // AG +VGM=13 [0..15] ; HS AT+VGM=6 | AG OK
2023deb3ec6SMatthias Ringwald
hsp_hs_send_str_over_rfcomm(uint16_t cid,const char * command)2033deb3ec6SMatthias Ringwald static int hsp_hs_send_str_over_rfcomm(uint16_t cid, const char * command){
204fb460ca0SMatthias Ringwald if (!rfcomm_can_send_packet_now(hsp_hs_rfcomm_cid)) return 1;
205ab2445a0SMatthias Ringwald int err = rfcomm_send(cid, (uint8_t*) command, (uint16_t) strlen(command));
2063deb3ec6SMatthias Ringwald if (err){
207a0ffb263SMatthias Ringwald log_info("rfcomm_send_internal -> error 0X%02x", err);
2083deb3ec6SMatthias Ringwald }
2093deb3ec6SMatthias Ringwald return err;
2103deb3ec6SMatthias Ringwald }
2113deb3ec6SMatthias Ringwald
hsp_hs_enable_custom_indications(int enable)21266a048abSMatthias Ringwald void hsp_hs_enable_custom_indications(int enable){
213fb460ca0SMatthias Ringwald hsp_hs_support_custom_indications = enable;
2143deb3ec6SMatthias Ringwald }
2153deb3ec6SMatthias Ringwald
hsp_hs_send_result(const char * result)21666a048abSMatthias Ringwald int hsp_hs_send_result(const char * result){
217fb460ca0SMatthias Ringwald if (!hsp_hs_support_custom_indications) return 1;
218fb460ca0SMatthias Ringwald return hsp_hs_send_str_over_rfcomm(hsp_hs_rfcomm_cid, result);
2193deb3ec6SMatthias Ringwald }
2203deb3ec6SMatthias Ringwald
2213deb3ec6SMatthias Ringwald
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)222605d1b1dSMilanka Ringwald 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){
2233deb3ec6SMatthias Ringwald uint8_t* attribute;
2243deb3ec6SMatthias Ringwald de_create_sequence(service);
2253deb3ec6SMatthias Ringwald
2263deb3ec6SMatthias Ringwald // 0x0000 "Service Record Handle"
227235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_RECORD_HANDLE);
2284bcb6098SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_32, service_record_handle);
2293deb3ec6SMatthias Ringwald
2303deb3ec6SMatthias Ringwald // 0x0001 "Service Class ID List"
231235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST);
2323deb3ec6SMatthias Ringwald attribute = de_push_sequence(service);
2333deb3ec6SMatthias Ringwald {
234d210d9c4SMatthias Ringwald // see Bluetooth Erratum #3507
235235946f1SMatthias Ringwald de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_HEADSET); // 0x1108
236235946f1SMatthias Ringwald de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_HEADSET_HS); // 0x1131
237235946f1SMatthias Ringwald de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_GENERIC_AUDIO); // 0x1203
2383deb3ec6SMatthias Ringwald }
2393deb3ec6SMatthias Ringwald de_pop_sequence(service, attribute);
2403deb3ec6SMatthias Ringwald
2413deb3ec6SMatthias Ringwald // 0x0004 "Protocol Descriptor List"
242235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST);
2433deb3ec6SMatthias Ringwald attribute = de_push_sequence(service);
2443deb3ec6SMatthias Ringwald {
2453deb3ec6SMatthias Ringwald uint8_t* l2cpProtocol = de_push_sequence(attribute);
2463deb3ec6SMatthias Ringwald {
247235946f1SMatthias Ringwald de_add_number(l2cpProtocol, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP);
2483deb3ec6SMatthias Ringwald }
2493deb3ec6SMatthias Ringwald de_pop_sequence(attribute, l2cpProtocol);
2503deb3ec6SMatthias Ringwald
2513deb3ec6SMatthias Ringwald uint8_t* rfcomm = de_push_sequence(attribute);
2523deb3ec6SMatthias Ringwald {
253235946f1SMatthias Ringwald de_add_number(rfcomm, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_RFCOMM); // rfcomm_service
2543deb3ec6SMatthias Ringwald de_add_number(rfcomm, DE_UINT, DE_SIZE_8, rfcomm_channel_nr); // rfcomm channel
2553deb3ec6SMatthias Ringwald }
2563deb3ec6SMatthias Ringwald de_pop_sequence(attribute, rfcomm);
2573deb3ec6SMatthias Ringwald }
2583deb3ec6SMatthias Ringwald de_pop_sequence(service, attribute);
2593deb3ec6SMatthias Ringwald
2603deb3ec6SMatthias Ringwald // 0x0005 "Public Browse Group"
261235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BROWSE_GROUP_LIST); // public browse group
2623deb3ec6SMatthias Ringwald attribute = de_push_sequence(service);
2633deb3ec6SMatthias Ringwald {
264235946f1SMatthias Ringwald de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PUBLIC_BROWSE_ROOT);
2653deb3ec6SMatthias Ringwald }
2663deb3ec6SMatthias Ringwald de_pop_sequence(service, attribute);
2673deb3ec6SMatthias Ringwald
2683deb3ec6SMatthias Ringwald // 0x0009 "Bluetooth Profile Descriptor List"
269235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
2703deb3ec6SMatthias Ringwald attribute = de_push_sequence(service);
2713deb3ec6SMatthias Ringwald {
272d210d9c4SMatthias Ringwald uint8_t *hsp_profile = de_push_sequence(attribute);
2733deb3ec6SMatthias Ringwald {
274235946f1SMatthias Ringwald de_add_number(hsp_profile, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_HEADSET);
275d210d9c4SMatthias Ringwald de_add_number(hsp_profile, DE_UINT, DE_SIZE_16, 0x0102); // Verision 1.2
2763deb3ec6SMatthias Ringwald }
277d210d9c4SMatthias Ringwald de_pop_sequence(attribute, hsp_profile);
2783deb3ec6SMatthias Ringwald }
2793deb3ec6SMatthias Ringwald de_pop_sequence(service, attribute);
2803deb3ec6SMatthias Ringwald
2813deb3ec6SMatthias Ringwald // 0x0100 "Service Name"
2823deb3ec6SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, 0x0100);
2833deb3ec6SMatthias Ringwald if (name){
284ab2445a0SMatthias Ringwald de_add_data(service, DE_STRING, (uint16_t) strlen(name), (uint8_t *) name);
2853deb3ec6SMatthias Ringwald } else {
286ab2445a0SMatthias Ringwald de_add_data(service, DE_STRING, (uint16_t) strlen(hsp_hs_default_service_name), (uint8_t *) hsp_hs_default_service_name);
2873deb3ec6SMatthias Ringwald }
2883deb3ec6SMatthias Ringwald
289605d1b1dSMilanka Ringwald // Remote audio volume control
2903deb3ec6SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, 0x030C);
291605d1b1dSMilanka Ringwald de_add_number(service, DE_BOOL, DE_SIZE_8, have_remote_audio_control);
2923deb3ec6SMatthias Ringwald }
2933deb3ec6SMatthias Ringwald
hsp_hs_reset_state(void)2943deb3ec6SMatthias Ringwald static void hsp_hs_reset_state(void){
2953deb3ec6SMatthias Ringwald hsp_state = HSP_IDLE;
296fb460ca0SMatthias Ringwald hsp_hs_microphone_gain = -1;
297fb460ca0SMatthias Ringwald hsp_hs_speaker_gain = -1;
298fb460ca0SMatthias Ringwald hsp_hs_rfcomm_cid = 0;
299fb460ca0SMatthias Ringwald hsp_hs_rfcomm_channel_nr = 0;
300fb460ca0SMatthias Ringwald hsp_hs_rfcomm_handle = HCI_CON_HANDLE_INVALID;
301fb460ca0SMatthias Ringwald hsp_hs_sco_handle = HCI_CON_HANDLE_INVALID;
3023deb3ec6SMatthias Ringwald
303fb460ca0SMatthias Ringwald hsp_hs_send_button_press_triggered = 0;
304fb460ca0SMatthias Ringwald hsp_hs_wait_ok = 0;
305fb460ca0SMatthias Ringwald hsp_hs_support_custom_indications = 0;
306fffdd288SMatthias Ringwald
307fb460ca0SMatthias Ringwald hsp_hs_accept_sco_connection = 0;
308fb460ca0SMatthias Ringwald hsp_hs_establish_audio_connection_triggered = 0;
309fb460ca0SMatthias Ringwald hsp_hs_release_audio_connection_triggered = 0;
3103deb3ec6SMatthias Ringwald }
3113deb3ec6SMatthias Ringwald
hsp_hs_init(uint8_t rfcomm_channel_nr)3123deb3ec6SMatthias Ringwald void hsp_hs_init(uint8_t rfcomm_channel_nr){
313c5b64319SMatthias Ringwald // register for HCI events
314fb460ca0SMatthias Ringwald hsp_hs_hci_event_callback_registration.callback = &packet_handler;
315fb460ca0SMatthias Ringwald hci_add_event_handler(&hsp_hs_hci_event_callback_registration);
316c5b64319SMatthias Ringwald
317ccb8ddfbSMatthias Ringwald rfcomm_register_service(packet_handler, rfcomm_channel_nr, 0xffff); // reserved channel, mtu limited by l2cap
3183deb3ec6SMatthias Ringwald
3193962dc20SMatthias Ringwald hsp_hs_sco_packet_types = SCO_PACKET_TYPES_ALL;
3203deb3ec6SMatthias Ringwald hsp_hs_reset_state();
3213deb3ec6SMatthias Ringwald }
3223deb3ec6SMatthias Ringwald
hsp_hs_deinit(void)323637244f1SMatthias Ringwald void hsp_hs_deinit(void){
324fb460ca0SMatthias Ringwald hsp_hs_reset_state();
325637244f1SMatthias Ringwald hsp_hs_callback = NULL;
326fb460ca0SMatthias Ringwald (void)memset(hsp_hs_remote, 0, 6);
327fb460ca0SMatthias Ringwald (void)memset(&hsp_hs_hci_event_callback_registration, 0, sizeof(btstack_packet_callback_registration_t));
328fb460ca0SMatthias Ringwald (void)memset(&hsp_hs_handle_sdp_client_query_request, 0, sizeof(btstack_context_callback_registration_t));
329637244f1SMatthias Ringwald }
330637244f1SMatthias Ringwald
hsp_hs_handle_start_sdp_client_query(void * context)331acb6281eSMilanka Ringwald static void hsp_hs_handle_start_sdp_client_query(void * context){
332acb6281eSMilanka Ringwald UNUSED(context);
333acb6281eSMilanka Ringwald if (hsp_state != HSP_W2_SEND_SDP_QUERY) return;
334acb6281eSMilanka Ringwald
335acb6281eSMilanka Ringwald hsp_state = HSP_W4_SDP_QUERY_COMPLETE;
336fb460ca0SMatthias Ringwald log_info("Start SDP query %s, 0x%02x", bd_addr_to_str(hsp_hs_remote), BLUETOOTH_SERVICE_CLASS_HEADSET_AUDIO_GATEWAY_AG);
337fb460ca0SMatthias Ringwald sdp_client_query_rfcomm_channel_and_name_for_service_class_uuid(&handle_query_rfcomm_event, hsp_hs_remote, BLUETOOTH_SERVICE_CLASS_HEADSET_AUDIO_GATEWAY_AG);
338acb6281eSMilanka Ringwald }
3393deb3ec6SMatthias Ringwald
hsp_hs_connect(bd_addr_t bd_addr)3403deb3ec6SMatthias Ringwald void hsp_hs_connect(bd_addr_t bd_addr){
3413deb3ec6SMatthias Ringwald if (hsp_state != HSP_IDLE) return;
342acb6281eSMilanka Ringwald
343fb460ca0SMatthias Ringwald (void)memcpy(hsp_hs_remote, bd_addr, 6);
344acb6281eSMilanka Ringwald hsp_state = HSP_W2_SEND_SDP_QUERY;
345acb6281eSMilanka Ringwald hsp_hs_handle_sdp_client_query_request.callback = &hsp_hs_handle_start_sdp_client_query;
346acb6281eSMilanka Ringwald // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback
347acb6281eSMilanka Ringwald (void) sdp_client_register_query_callback(&hsp_hs_handle_sdp_client_query_request);
3483deb3ec6SMatthias Ringwald }
3493deb3ec6SMatthias Ringwald
hsp_hs_disconnect(void)35099a10067SMatthias Ringwald void hsp_hs_disconnect(void){
35199a10067SMatthias Ringwald hsp_hs_release_audio_connection();
35299a10067SMatthias Ringwald
35399a10067SMatthias Ringwald if (hsp_state < HSP_W4_RFCOMM_CONNECTED){
35499a10067SMatthias Ringwald hsp_state = HSP_IDLE;
35599a10067SMatthias Ringwald return;
35699a10067SMatthias Ringwald }
35799a10067SMatthias Ringwald
35899a10067SMatthias Ringwald if (hsp_state == HSP_W4_RFCOMM_CONNECTED){
35999a10067SMatthias Ringwald hsp_state = HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN;
36099a10067SMatthias Ringwald return;
36199a10067SMatthias Ringwald }
36299a10067SMatthias Ringwald
363fb460ca0SMatthias Ringwald hsp_hs_establish_audio_connection_triggered = 0;
364fb460ca0SMatthias Ringwald rfcomm_disconnect(hsp_hs_rfcomm_cid);
36599a10067SMatthias Ringwald }
36699a10067SMatthias Ringwald
36799a10067SMatthias Ringwald
hsp_hs_establish_audio_connection(void)36899a10067SMatthias Ringwald void hsp_hs_establish_audio_connection(void){
3693deb3ec6SMatthias Ringwald switch (hsp_state){
37099a10067SMatthias Ringwald case HSP_RFCOMM_CONNECTION_ESTABLISHED:
371fb460ca0SMatthias Ringwald hsp_hs_establish_audio_connection_triggered = 1;
37299a10067SMatthias Ringwald hsp_state = HSP_W4_SCO_CONNECTED;
3733deb3ec6SMatthias Ringwald break;
3743deb3ec6SMatthias Ringwald case HSP_W4_RFCOMM_CONNECTED:
3753deb3ec6SMatthias Ringwald hsp_state = HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN;
3763deb3ec6SMatthias Ringwald break;
3773deb3ec6SMatthias Ringwald default:
37899a10067SMatthias Ringwald break;
3793deb3ec6SMatthias Ringwald }
3803deb3ec6SMatthias Ringwald hsp_run();
3813deb3ec6SMatthias Ringwald }
3823deb3ec6SMatthias Ringwald
hsp_hs_release_audio_connection(void)38399a10067SMatthias Ringwald void hsp_hs_release_audio_connection(void){
38499a10067SMatthias Ringwald if (hsp_state >= HSP_W2_DISCONNECT_SCO) return;
38599a10067SMatthias Ringwald if (hsp_state < HSP_AUDIO_CONNECTION_ESTABLISHED) return;
386fb460ca0SMatthias Ringwald hsp_hs_release_audio_connection_triggered = 1;
38799a10067SMatthias Ringwald hsp_run();
38899a10067SMatthias Ringwald }
3893deb3ec6SMatthias Ringwald
hsp_hs_set_microphone_gain(uint8_t gain)3903deb3ec6SMatthias Ringwald void hsp_hs_set_microphone_gain(uint8_t gain){
3913982eab9SMatthias Ringwald if (gain >15) {
392a0ffb263SMatthias Ringwald log_info("Gain must be in interval [0..15], it is given %d", gain);
3933deb3ec6SMatthias Ringwald return;
3943deb3ec6SMatthias Ringwald }
395fb460ca0SMatthias Ringwald hsp_hs_microphone_gain = gain;
3963deb3ec6SMatthias Ringwald hsp_run();
3973deb3ec6SMatthias Ringwald }
3983deb3ec6SMatthias Ringwald
3993deb3ec6SMatthias Ringwald // AG +VGS=5 [0..15] ; HS AT+VGM=6 | AG OK
hsp_hs_set_speaker_gain(uint8_t gain)4003deb3ec6SMatthias Ringwald void hsp_hs_set_speaker_gain(uint8_t gain){
4013982eab9SMatthias Ringwald if (gain >15) {
402a0ffb263SMatthias Ringwald log_info("Gain must be in interval [0..15], it is given %d", gain);
4033deb3ec6SMatthias Ringwald return;
4043deb3ec6SMatthias Ringwald }
405fb460ca0SMatthias Ringwald hsp_hs_speaker_gain = gain;
4063deb3ec6SMatthias Ringwald hsp_run();
4073deb3ec6SMatthias Ringwald }
4083deb3ec6SMatthias Ringwald
hsp_run_handle_state(void)409ed75eaecSMatthias Ringwald static void hsp_run_handle_state(void){
410ed75eaecSMatthias Ringwald switch (hsp_state){
411ed75eaecSMatthias Ringwald case HSP_AUDIO_CONNECTION_ESTABLISHED:
412ed75eaecSMatthias Ringwald case HSP_RFCOMM_CONNECTION_ESTABLISHED:
413ed75eaecSMatthias Ringwald
414fb460ca0SMatthias Ringwald if (hsp_hs_microphone_gain >= 0){
415fb460ca0SMatthias Ringwald if (!rfcomm_can_send_packet_now(hsp_hs_rfcomm_cid)) {
416fb460ca0SMatthias Ringwald rfcomm_request_can_send_now_event(hsp_hs_rfcomm_cid);
417ed75eaecSMatthias Ringwald return;
418ed75eaecSMatthias Ringwald }
419ed75eaecSMatthias Ringwald char buffer[20];
420*5753fca5SMatthias Ringwald btstack_snprintf_assert_complete(buffer, sizeof(buffer), "%s=%d\r",
421fb460ca0SMatthias Ringwald HSP_HS_MICROPHONE_GAIN, hsp_hs_microphone_gain);
422fb460ca0SMatthias Ringwald hsp_hs_send_str_over_rfcomm(hsp_hs_rfcomm_cid, buffer);
423fb460ca0SMatthias Ringwald hsp_hs_microphone_gain = -1;
424ed75eaecSMatthias Ringwald break;
425ed75eaecSMatthias Ringwald }
426ed75eaecSMatthias Ringwald
427fb460ca0SMatthias Ringwald if (hsp_hs_speaker_gain >= 0){
428fb460ca0SMatthias Ringwald if (!rfcomm_can_send_packet_now(hsp_hs_rfcomm_cid)) {
429fb460ca0SMatthias Ringwald rfcomm_request_can_send_now_event(hsp_hs_rfcomm_cid);
430ed75eaecSMatthias Ringwald return;
431ed75eaecSMatthias Ringwald }
432ed75eaecSMatthias Ringwald char buffer[20];
433*5753fca5SMatthias Ringwald btstack_snprintf_assert_complete(buffer, sizeof(buffer), "%s=%d\r",
434fb460ca0SMatthias Ringwald HSP_HS_SPEAKER_GAIN, hsp_hs_speaker_gain);
435fb460ca0SMatthias Ringwald hsp_hs_send_str_over_rfcomm(hsp_hs_rfcomm_cid, buffer);
436fb460ca0SMatthias Ringwald hsp_hs_speaker_gain = -1;
437ed75eaecSMatthias Ringwald break;
438ed75eaecSMatthias Ringwald }
439ed75eaecSMatthias Ringwald break;
440ed75eaecSMatthias Ringwald case HSP_W4_RFCOMM_DISCONNECTED:
441fb460ca0SMatthias Ringwald rfcomm_disconnect(hsp_hs_rfcomm_cid);
442ed75eaecSMatthias Ringwald break;
443ed75eaecSMatthias Ringwald default:
444ed75eaecSMatthias Ringwald break;
445ed75eaecSMatthias Ringwald }
446ed75eaecSMatthias Ringwald }
4473deb3ec6SMatthias Ringwald
hsp_run(void)4483deb3ec6SMatthias Ringwald static void hsp_run(void){
4495c17d699SMatthias Ringwald
450fb460ca0SMatthias Ringwald if (hsp_hs_wait_ok) return;
451093577faSMatthias Ringwald
452fb460ca0SMatthias Ringwald if (hsp_hs_accept_sco_connection && hci_can_send_command_packet_now()){
453c169df2fSMatthias Ringwald
454fb460ca0SMatthias Ringwald bool eSCO = hsp_hs_accept_sco_connection == 2;
455fb460ca0SMatthias Ringwald hsp_hs_accept_sco_connection = 0;
456b100348fSMilanka Ringwald
457b100348fSMilanka Ringwald log_info("HSP: sending hci_accept_connection_request.");
458b100348fSMilanka Ringwald
4593962dc20SMatthias Ringwald // pick packet types based on SCO link type (SCO vs. eSCO)
4603962dc20SMatthias Ringwald uint16_t packet_types;
461fb460ca0SMatthias Ringwald if (eSCO && hci_extended_sco_link_supported() && hci_remote_esco_supported(hsp_hs_rfcomm_handle)){
46226bb3782SMatthias Ringwald packet_types = SCO_PACKET_TYPES_EV3 | SCO_PACKET_TYPES_2EV3;
463b100348fSMilanka Ringwald } else {
46426bb3782SMatthias Ringwald packet_types = SCO_PACKET_TYPES_HV3 | SCO_PACKET_TYPES_HV2 | SCO_PACKET_TYPES_HV1;
465b100348fSMilanka Ringwald }
466b100348fSMilanka Ringwald
4673962dc20SMatthias Ringwald // packet type override
4683962dc20SMatthias Ringwald packet_types &= hsp_hs_sco_packet_types;
4693962dc20SMatthias Ringwald
4703962dc20SMatthias Ringwald // bits 6-9 are 'don't use'
4713962dc20SMatthias Ringwald packet_types ^= 0x03c0;
4723962dc20SMatthias Ringwald
473b100348fSMilanka Ringwald uint16_t sco_voice_setting = hci_get_sco_voice_setting();
474b100348fSMilanka Ringwald
475b100348fSMilanka Ringwald log_info("HFP: sending hci_accept_connection_request, sco_voice_setting %02x", sco_voice_setting);
476fb460ca0SMatthias Ringwald hci_send_cmd(&hci_accept_synchronous_connection, hsp_hs_remote, 8000, 8000, 0xffff, sco_voice_setting, 0xff, packet_types);
477b100348fSMilanka Ringwald return;
478b100348fSMilanka Ringwald }
479b100348fSMilanka Ringwald
480fb460ca0SMatthias Ringwald if (hsp_hs_release_audio_connection_triggered){
481fb460ca0SMatthias Ringwald if (!rfcomm_can_send_packet_now(hsp_hs_rfcomm_cid)) {
482fb460ca0SMatthias Ringwald rfcomm_request_can_send_now_event(hsp_hs_rfcomm_cid);
4835c17d699SMatthias Ringwald return;
4845c17d699SMatthias Ringwald }
485fb460ca0SMatthias Ringwald hsp_hs_release_audio_connection_triggered = 0;
486fb460ca0SMatthias Ringwald hsp_hs_wait_ok = 1;
487fb460ca0SMatthias Ringwald hsp_hs_send_str_over_rfcomm(hsp_hs_rfcomm_cid, HSP_HS_AT_CKPD);
48899a10067SMatthias Ringwald return;
48999a10067SMatthias Ringwald }
49099a10067SMatthias Ringwald
491fb460ca0SMatthias Ringwald if (hsp_hs_establish_audio_connection_triggered){
492fb460ca0SMatthias Ringwald if (!rfcomm_can_send_packet_now(hsp_hs_rfcomm_cid)) {
493fb460ca0SMatthias Ringwald rfcomm_request_can_send_now_event(hsp_hs_rfcomm_cid);
494093577faSMatthias Ringwald return;
495093577faSMatthias Ringwald }
496fb460ca0SMatthias Ringwald hsp_hs_establish_audio_connection_triggered = 0;
497fb460ca0SMatthias Ringwald hsp_hs_wait_ok = 1;
498fb460ca0SMatthias Ringwald hsp_hs_send_str_over_rfcomm(hsp_hs_rfcomm_cid, HSP_HS_AT_CKPD);
49999a10067SMatthias Ringwald return;
50099a10067SMatthias Ringwald }
5013deb3ec6SMatthias Ringwald
502fb460ca0SMatthias Ringwald if (hsp_hs_send_button_press_triggered){
503fb460ca0SMatthias Ringwald if (!rfcomm_can_send_packet_now(hsp_hs_rfcomm_cid)) {
504fb460ca0SMatthias Ringwald rfcomm_request_can_send_now_event(hsp_hs_rfcomm_cid);
505093577faSMatthias Ringwald return;
506093577faSMatthias Ringwald }
507fb460ca0SMatthias Ringwald hsp_hs_send_button_press_triggered = 0;
508fb460ca0SMatthias Ringwald hsp_hs_wait_ok = 1;
509fb460ca0SMatthias Ringwald hsp_hs_send_str_over_rfcomm(hsp_hs_rfcomm_cid, HSP_HS_AT_CKPD);
5103deb3ec6SMatthias Ringwald return;
5113deb3ec6SMatthias Ringwald }
5123deb3ec6SMatthias Ringwald
513401a115bSMatthias Ringwald #ifdef ENABLE_RTK_PCM_WBS
514401a115bSMatthias Ringwald if (hsp_hs_rtk_send_sco_config){
515401a115bSMatthias Ringwald hsp_hs_rtk_send_sco_config = false;
516401a115bSMatthias Ringwald log_info("RTK SCO: 16k + CVSD");
517401a115bSMatthias Ringwald hci_send_cmd(&hci_rtk_configure_sco_routing, 0x81, 0x90, 0x00, 0x00, 0x1a, 0x0c, 0x0c, 0x00, 0x01);
518401a115bSMatthias Ringwald return;
519401a115bSMatthias Ringwald }
520401a115bSMatthias Ringwald #endif
521401a115bSMatthias Ringwald
522ed75eaecSMatthias Ringwald hsp_run_handle_state();
5233deb3ec6SMatthias Ringwald }
5243deb3ec6SMatthias Ringwald
5253deb3ec6SMatthias Ringwald
packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)526e53943d7SMatthias Ringwald static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
527f08eeab9SMatthias Ringwald UNUSED(channel); // ok: no channel for HCI_EVENT_PACKET and only single active RFCOMM channel
5283deb3ec6SMatthias Ringwald if (packet_type == RFCOMM_DATA_PACKET){
529f5054c00SMatthias Ringwald // skip over leading newline
530c1ab6cc1SMatthias Ringwald while ((size > 0) && ((packet[0] == '\n') || (packet[0] == '\r'))){
5313deb3ec6SMatthias Ringwald size--;
5323deb3ec6SMatthias Ringwald packet++;
5333deb3ec6SMatthias Ringwald }
5343deb3ec6SMatthias Ringwald if (strncmp((char *)packet, HSP_AG_RING, strlen(HSP_AG_RING)) == 0){
535a15a08d7SMatthias Ringwald emit_event(HSP_SUBEVENT_RING);
536f5054c00SMatthias Ringwald } else if (strncmp((char *)packet, HSP_AG_OK, strlen(HSP_AG_OK)) == 0){
537fb460ca0SMatthias Ringwald hsp_hs_wait_ok = 0;
5383deb3ec6SMatthias Ringwald } else if (strncmp((char *)packet, HSP_MICROPHONE_GAIN, strlen(HSP_MICROPHONE_GAIN)) == 0){
5392308e108SMilanka Ringwald uint8_t gain = (uint8_t)btstack_atoi((char*)&packet[strlen(HSP_MICROPHONE_GAIN)]);
540a15a08d7SMatthias Ringwald emit_event_with_value(HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED, gain);
5413deb3ec6SMatthias Ringwald
5423deb3ec6SMatthias Ringwald } else if (strncmp((char *)packet, HSP_SPEAKER_GAIN, strlen(HSP_SPEAKER_GAIN)) == 0){
5432308e108SMilanka Ringwald uint8_t gain = (uint8_t)btstack_atoi((char*)&packet[strlen(HSP_SPEAKER_GAIN)]);
544a15a08d7SMatthias Ringwald emit_event_with_value(HSP_SUBEVENT_SPEAKER_GAIN_CHANGED, gain);
5453deb3ec6SMatthias Ringwald } else {
5463deb3ec6SMatthias Ringwald if (!hsp_hs_callback) return;
547f5054c00SMatthias Ringwald // strip trailing newline
548c1ab6cc1SMatthias Ringwald while ((size > 0) && ((packet[size-1] == '\n') || (packet[size-1] == '\r'))){
549f5054c00SMatthias Ringwald size--;
550f5054c00SMatthias Ringwald }
551ab2445a0SMatthias Ringwald if ((size + 4) > 255) return;
552f5054c00SMatthias Ringwald // add trailing \0
553f5054c00SMatthias Ringwald packet[size] = 0;
554a15a08d7SMatthias Ringwald // re-use incoming buffer to avoid reserving buffers/memcpy - ugly but efficient
555a15a08d7SMatthias Ringwald uint8_t * event = packet - 6;
5563deb3ec6SMatthias Ringwald event[0] = HCI_EVENT_HSP_META;
557ab2445a0SMatthias Ringwald event[1] = (uint8_t) (size + 4);
5583deb3ec6SMatthias Ringwald event[2] = HSP_SUBEVENT_AG_INDICATION;
559a15a08d7SMatthias Ringwald little_endian_store_16(event, 3, hsp_hs_rfcomm_handle);
560ab2445a0SMatthias Ringwald event[5] = (uint8_t) size;
561a15a08d7SMatthias Ringwald (*hsp_hs_callback)(HCI_EVENT_PACKET, 0, event, size+6);
5623deb3ec6SMatthias Ringwald }
5633deb3ec6SMatthias Ringwald hsp_run();
5643deb3ec6SMatthias Ringwald return;
5653deb3ec6SMatthias Ringwald }
5663deb3ec6SMatthias Ringwald
5673deb3ec6SMatthias Ringwald if (packet_type != HCI_EVENT_PACKET) return;
568ff0aba06SMatthias Ringwald
5690e2df43fSMatthias Ringwald uint8_t event = hci_event_packet_get_type(packet);
5703deb3ec6SMatthias Ringwald bd_addr_t event_addr;
5713deb3ec6SMatthias Ringwald uint16_t handle;
572a15a08d7SMatthias Ringwald uint8_t status;
573a15a08d7SMatthias Ringwald
5743deb3ec6SMatthias Ringwald switch (event) {
575b100348fSMilanka Ringwald case HCI_EVENT_CONNECTION_REQUEST:
576b100348fSMilanka Ringwald switch(hci_event_connection_request_get_link_type(packet)){
577b100348fSMilanka Ringwald case 0: // SCO
578b100348fSMilanka Ringwald case 2: // eSCO
579b100348fSMilanka Ringwald hci_event_connection_request_get_bd_addr(packet, event_addr);
580fb460ca0SMatthias Ringwald if (bd_addr_cmp(event_addr, hsp_hs_remote) == 0){
581c169df2fSMatthias Ringwald if (hci_event_connection_request_get_link_type(packet) == 2){
582fb460ca0SMatthias Ringwald hsp_hs_accept_sco_connection = 2;
583c169df2fSMatthias Ringwald } else {
584fb460ca0SMatthias Ringwald hsp_hs_accept_sco_connection = 1;
585b100348fSMilanka Ringwald }
586fb460ca0SMatthias Ringwald log_info("hs_accept_sco_connection %u", hsp_hs_accept_sco_connection);
587c169df2fSMatthias Ringwald }
588b100348fSMilanka Ringwald break;
589b100348fSMilanka Ringwald default:
590b100348fSMilanka Ringwald break;
591b100348fSMilanka Ringwald }
592b100348fSMilanka Ringwald break;
593b100348fSMilanka Ringwald
5943deb3ec6SMatthias Ringwald case HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE:{
59599a10067SMatthias Ringwald if (hsp_state < HSP_RFCOMM_CONNECTION_ESTABLISHED) return;
596ff0aba06SMatthias Ringwald hci_event_synchronous_connection_complete_get_bd_addr(packet, event_addr);
597f75a03a0SMatthias Ringwald status = hci_event_synchronous_connection_complete_get_status(packet);
598fb460ca0SMatthias Ringwald hsp_hs_sco_handle = hci_event_synchronous_connection_complete_get_handle(packet);
599ff0aba06SMatthias Ringwald uint8_t link_type = hci_event_synchronous_connection_complete_get_link_type(packet);
600ff0aba06SMatthias Ringwald uint8_t transmission_interval = hci_event_synchronous_connection_complete_get_transmission_interval(packet); // measured in slots
601ff0aba06SMatthias Ringwald uint8_t retransmission_interval = hci_event_synchronous_connection_complete_get_retransmission_interval(packet); // measured in slots
602ff0aba06SMatthias Ringwald uint16_t rx_packet_length = hci_event_synchronous_connection_complete_get_rx_packet_length(packet); // measured in bytes
603ff0aba06SMatthias Ringwald uint16_t tx_packet_length = hci_event_synchronous_connection_complete_get_tx_packet_length(packet); // measured in bytes
6043deb3ec6SMatthias Ringwald
6053deb3ec6SMatthias Ringwald if (status != 0){
6064af9a48dSMatthias Ringwald log_error("(e)SCO Connection failed, status %u", status);
607fb460ca0SMatthias Ringwald emit_event_audio_connected(status, hsp_hs_sco_handle);
60899a10067SMatthias Ringwald hsp_state = HSP_RFCOMM_CONNECTION_ESTABLISHED ;
6093deb3ec6SMatthias Ringwald break;
6103deb3ec6SMatthias Ringwald }
61199a10067SMatthias Ringwald
6123deb3ec6SMatthias Ringwald switch (link_type){
6133deb3ec6SMatthias Ringwald case 0x00:
614a0ffb263SMatthias Ringwald log_info("SCO Connection established.");
6153deb3ec6SMatthias Ringwald if (transmission_interval != 0) log_error("SCO Connection: transmission_interval not zero: %d.", transmission_interval);
6163deb3ec6SMatthias Ringwald if (retransmission_interval != 0) log_error("SCO Connection: retransmission_interval not zero: %d.", retransmission_interval);
6173deb3ec6SMatthias Ringwald if (rx_packet_length != 0) log_error("SCO Connection: rx_packet_length not zero: %d.", rx_packet_length);
6183deb3ec6SMatthias Ringwald if (tx_packet_length != 0) log_error("SCO Connection: tx_packet_length not zero: %d.", tx_packet_length);
6193deb3ec6SMatthias Ringwald break;
6203deb3ec6SMatthias Ringwald case 0x02:
621a0ffb263SMatthias Ringwald log_info("eSCO Connection established.");
6223deb3ec6SMatthias Ringwald break;
6233deb3ec6SMatthias Ringwald default:
6243deb3ec6SMatthias Ringwald log_error("(e)SCO reserved link_type 0x%2x", link_type);
6253deb3ec6SMatthias Ringwald break;
6263deb3ec6SMatthias Ringwald }
6273deb3ec6SMatthias Ringwald log_info("sco_handle 0x%2x, address %s, transmission_interval %u slots, retransmission_interval %u slots, "
628fb460ca0SMatthias Ringwald " rx_packet_length %u bytes, tx_packet_length %u bytes, air_mode 0x%2x (0x02 == CVSD)", hsp_hs_sco_handle,
629e0d13a19SMilanka Ringwald bd_addr_to_str(event_addr), transmission_interval, retransmission_interval, rx_packet_length, tx_packet_length,
630e0d13a19SMilanka Ringwald hci_event_synchronous_connection_complete_get_air_mode(packet));
6313deb3ec6SMatthias Ringwald
63299a10067SMatthias Ringwald hsp_state = HSP_AUDIO_CONNECTION_ESTABLISHED;
633fb460ca0SMatthias Ringwald emit_event_audio_connected(status, hsp_hs_sco_handle);
6343deb3ec6SMatthias Ringwald break;
6353deb3ec6SMatthias Ringwald }
6363deb3ec6SMatthias Ringwald
6373deb3ec6SMatthias Ringwald case RFCOMM_EVENT_INCOMING_CONNECTION:
6383deb3ec6SMatthias Ringwald if (hsp_state != HSP_IDLE) return;
639ff0aba06SMatthias Ringwald rfcomm_event_incoming_connection_get_bd_addr(packet, event_addr);
640fb460ca0SMatthias Ringwald hsp_hs_rfcomm_cid = rfcomm_event_incoming_connection_get_rfcomm_cid(packet);
641ff0aba06SMatthias Ringwald log_info("RFCOMM channel %u requested for %s", rfcomm_event_incoming_connection_get_server_channel(packet), bd_addr_to_str(event_addr));
6423deb3ec6SMatthias Ringwald hsp_state = HSP_W4_RFCOMM_CONNECTED;
643fb460ca0SMatthias Ringwald rfcomm_accept_connection(hsp_hs_rfcomm_cid);
6443deb3ec6SMatthias Ringwald break;
6453deb3ec6SMatthias Ringwald
646f8f6a918SMatthias Ringwald case RFCOMM_EVENT_CHANNEL_OPENED:
64799a10067SMatthias Ringwald if (hsp_state != HSP_W4_RFCOMM_CONNECTED) return;
648a15a08d7SMatthias Ringwald status = rfcomm_event_channel_opened_get_status(packet);
649a15a08d7SMatthias Ringwald if (status != ERROR_CODE_SUCCESS) {
650a15a08d7SMatthias Ringwald log_info("RFCOMM channel open failed, status %u", status);
65199a10067SMatthias Ringwald hsp_state = HSP_IDLE;
6523deb3ec6SMatthias Ringwald hsp_hs_reset_state();
6533deb3ec6SMatthias Ringwald } else {
654fb460ca0SMatthias Ringwald rfcomm_event_channel_opened_get_bd_addr(packet, hsp_hs_remote);
655fb460ca0SMatthias Ringwald hsp_hs_rfcomm_handle = rfcomm_event_channel_opened_get_con_handle(packet);
656fb460ca0SMatthias Ringwald hsp_hs_rfcomm_cid = rfcomm_event_channel_opened_get_rfcomm_cid(packet);
657a15a08d7SMatthias Ringwald rfcomm_event_channel_opened_get_bd_addr(packet, hsp_hs_remote);
658fb460ca0SMatthias Ringwald hsp_hs_rfcomm_mtu = rfcomm_event_channel_opened_get_max_frame_size(packet);
659fb460ca0SMatthias Ringwald log_info("RFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u, handle %02x", hsp_hs_rfcomm_cid, hsp_hs_rfcomm_mtu, hsp_hs_rfcomm_handle);
66099a10067SMatthias Ringwald hsp_state = HSP_RFCOMM_CONNECTION_ESTABLISHED;
661401a115bSMatthias Ringwald #ifdef ENABLE_RTK_PCM_WBS
662401a115bSMatthias Ringwald hsp_hs_rtk_send_sco_config = true;
663401a115bSMatthias Ringwald #endif
664f5054c00SMatthias Ringwald }
665faf3a639SMatthias Ringwald emit_event_rfcomm_connected(status);
6663deb3ec6SMatthias Ringwald break;
6671b89a84bSMatthias Ringwald
6681b89a84bSMatthias Ringwald case RFCOMM_EVENT_CAN_SEND_NOW:
6695c17d699SMatthias Ringwald hsp_run();
6703deb3ec6SMatthias Ringwald break;
6713deb3ec6SMatthias Ringwald
6723deb3ec6SMatthias Ringwald case HCI_EVENT_DISCONNECTION_COMPLETE:
673ff0aba06SMatthias Ringwald handle = hci_event_disconnection_complete_get_connection_handle(packet);
674fb460ca0SMatthias Ringwald if (handle == hsp_hs_sco_handle){
675a15a08d7SMatthias Ringwald hci_con_handle_t sco_handle = hsp_hs_sco_handle;
676a15a08d7SMatthias Ringwald hsp_hs_sco_handle = HCI_CON_HANDLE_INVALID;
67799a10067SMatthias Ringwald hsp_state = HSP_RFCOMM_CONNECTION_ESTABLISHED;
678a15a08d7SMatthias Ringwald emit_event_audio_disconnected(sco_handle);
6793deb3ec6SMatthias Ringwald break;
6803deb3ec6SMatthias Ringwald }
6813deb3ec6SMatthias Ringwald break;
6825c17d699SMatthias Ringwald
6833deb3ec6SMatthias Ringwald case RFCOMM_EVENT_CHANNEL_CLOSED:
684ff0aba06SMatthias Ringwald hsp_state = HSP_IDLE;
6853deb3ec6SMatthias Ringwald hsp_hs_reset_state();
686a15a08d7SMatthias Ringwald emit_event(HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE);
6873deb3ec6SMatthias Ringwald break;
6885c17d699SMatthias Ringwald
6893deb3ec6SMatthias Ringwald default:
6903deb3ec6SMatthias Ringwald break;
6913deb3ec6SMatthias Ringwald }
6925c17d699SMatthias Ringwald
6933deb3ec6SMatthias Ringwald hsp_run();
6943deb3ec6SMatthias Ringwald }
6953deb3ec6SMatthias Ringwald
handle_query_rfcomm_event(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)6966c927b22SMatthias Ringwald static void handle_query_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
697f08eeab9SMatthias Ringwald UNUSED(packet_type); // ok: handling own sdp events
698f08eeab9SMatthias Ringwald UNUSED(channel); // ok: no channel
699f08eeab9SMatthias Ringwald UNUSED(size); // ok: handling own sdp events
7009ec2630cSMatthias Ringwald
7010e2df43fSMatthias Ringwald switch (hci_event_packet_get_type(packet)){
7025611a760SMatthias Ringwald case SDP_EVENT_QUERY_RFCOMM_SERVICE:
703fb460ca0SMatthias Ringwald hsp_hs_rfcomm_channel_nr = sdp_event_query_rfcomm_service_get_rfcomm_channel(packet);
704fb460ca0SMatthias Ringwald log_info("** Service name: '%s', RFCOMM port %u", sdp_event_query_rfcomm_service_get_name(packet), hsp_hs_rfcomm_channel_nr);
7053deb3ec6SMatthias Ringwald break;
7065611a760SMatthias Ringwald case SDP_EVENT_QUERY_COMPLETE:
707fb460ca0SMatthias Ringwald if (hsp_hs_rfcomm_channel_nr > 0){
7083deb3ec6SMatthias Ringwald hsp_state = HSP_W4_RFCOMM_CONNECTED;
709fb460ca0SMatthias Ringwald log_info("HSP: SDP_QUERY_COMPLETE. RFCOMM create channel, addr %s, rfcomm channel nr %d", bd_addr_to_str(hsp_hs_remote), hsp_hs_rfcomm_channel_nr);
710fb460ca0SMatthias Ringwald rfcomm_create_channel(packet_handler, hsp_hs_remote, hsp_hs_rfcomm_channel_nr, NULL);
7113deb3ec6SMatthias Ringwald break;
7123deb3ec6SMatthias Ringwald }
7133deb3ec6SMatthias Ringwald hsp_hs_reset_state();
714a0ffb263SMatthias Ringwald log_info("Service not found, status %u.", sdp_event_query_complete_get_status(packet));
71519937103SMilanka Ringwald if (sdp_event_query_complete_get_status(packet)){
716a15a08d7SMatthias Ringwald emit_event_with_value(HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE,
717a15a08d7SMatthias Ringwald sdp_event_query_complete_get_status(packet));
71819937103SMilanka Ringwald } else {
719a15a08d7SMatthias Ringwald emit_event_with_value(HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE, SDP_SERVICE_NOT_FOUND);
72019937103SMilanka Ringwald }
7213deb3ec6SMatthias Ringwald break;
7227bbeb3adSMilanka Ringwald default:
7237bbeb3adSMilanka Ringwald break;
7243deb3ec6SMatthias Ringwald }
7253deb3ec6SMatthias Ringwald }
7263deb3ec6SMatthias Ringwald
hsp_hs_send_button_press(void)72766a048abSMatthias Ringwald void hsp_hs_send_button_press(void){
728505f1c30SMatthias Ringwald if ((hsp_state < HSP_RFCOMM_CONNECTION_ESTABLISHED) || (hsp_state >= HSP_W4_RFCOMM_DISCONNECTED)) return;
729fb460ca0SMatthias Ringwald hsp_hs_send_button_press_triggered = 1;
730f5054c00SMatthias Ringwald hsp_run();
731f5054c00SMatthias Ringwald }
7323962dc20SMatthias Ringwald
hsp_hs_set_sco_packet_types(uint16_t packet_types)7333962dc20SMatthias Ringwald void hsp_hs_set_sco_packet_types(uint16_t packet_types){
7343962dc20SMatthias Ringwald hsp_hs_sco_packet_types = packet_types;
7353962dc20SMatthias Ringwald }
736