xref: /btstack/src/classic/hsp_hs.c (revision 24b3c62931f131de8243230463f3536778ba1e63)
1 /*
2  * Copyright (C) 2014 BlueKitchen GmbH
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holders nor the names of
14  *    contributors may be used to endorse or promote products derived
15  *    from this software without specific prior written permission.
16  * 4. Any redistribution, use, or modification is done solely for
17  *    personal benefit and not for any commercial purpose or for
18  *    monetary gain.
19  *
20  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * Please inquire about commercial licensing options at
34  * [email protected]
35  *
36  */
37 
38 // *****************************************************************************
39 //
40 // Minimal setup for HSP Headset (!! UNDER DEVELOPMENT !!)
41 //
42 // *****************************************************************************
43 
44 #include "btstack_config.h"
45 
46 #include <stdint.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 
51 #include "hci_cmd.h"
52 #include "btstack_run_loop.h"
53 
54 #include "hci.h"
55 #include "btstack_memory.h"
56 #include "hci_dump.h"
57 #include "l2cap.h"
58 #include "classic/sdp_query_rfcomm.h"
59 #include "classic/sdp.h"
60 #include "btstack_debug.h"
61 #include "hsp_hs.h"
62 
63 
64 #define HSP_AG_OK "OK"
65 #define HSP_AG_ERROR "ERROR"
66 #define HSP_AG_RING "RING"
67 #define HSP_MICROPHONE_GAIN "+VGM="
68 #define HSP_SPEAKER_GAIN "+VGS="
69 
70 #define HSP_HS_AT_CKPD "AT+CKPD=200\r\n"
71 #define HSP_HS_MICROPHONE_GAIN "AT+VGM"
72 #define HSP_HS_SPEAKER_GAIN "AT+VGS"
73 
74 static const char default_hsp_hs_service_name[] = "Headset";
75 
76 static bd_addr_t remote = {0x04, 0x0C, 0xCE, 0xE4, 0x85, 0xD3};
77 static uint8_t channel_nr = 0;
78 
79 static uint16_t mtu;
80 static uint16_t rfcomm_cid = 0;
81 static uint16_t sco_handle = 0;
82 static uint16_t rfcomm_handle = 0;
83 
84 // static uint8_t connection_state = 0;
85 
86 static int hs_microphone_gain = -1;
87 static int hs_speaker_gain = -1;
88 
89 static uint8_t hs_send_button_press = 0;
90 static uint8_t hs_support_custom_indications = 0;
91 static uint8_t hs_outgoing_connection = 0;
92 
93 typedef enum {
94     HSP_IDLE,
95     HSP_SDP_QUERY_RFCOMM_CHANNEL,
96     HSP_W4_SDP_QUERY_COMPLETE,
97     HSP_W4_RFCOMM_CONNECTED,
98     HSP_W4_USER_ACTION,
99     HSP_W2_CONNECT_SCO,
100     HSP_W4_SCO_CONNECTED,
101     HSP_ACTIVE,
102     HSP_W2_DISCONNECT_SCO,
103     HSP_W4_SCO_DISCONNECTED,
104     HSP_W2_DISCONNECT_RFCOMM,
105     HSP_W4_RFCOMM_DISCONNECTED,
106     HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN
107 } hsp_state_t;
108 
109 static hsp_state_t hsp_state = HSP_IDLE;
110 
111 static void hsp_run(void);
112 static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
113 static void handle_query_rfcomm_event(sdp_query_event_t * event, void * context);
114 
115 static hsp_hs_callback_t hsp_hs_callback;
116 static void dummy_notify(uint8_t * event, uint16_t size){}
117 
118 void hsp_hs_register_packet_handler(hsp_hs_callback_t callback){
119     if (callback == NULL){
120         callback = &dummy_notify;
121     }
122     hsp_hs_callback = callback;
123 }
124 
125 static void emit_event(uint8_t event_subtype, uint8_t value){
126     if (!hsp_hs_callback) return;
127     uint8_t event[4];
128     event[0] = HCI_EVENT_HSP_META;
129     event[1] = sizeof(event) - 2;
130     event[2] = event_subtype;
131     event[3] = value; // status 0 == OK
132     (*hsp_hs_callback)(event, sizeof(event));
133 }
134 
135 static void emit_event_audio_connected(uint8_t status, uint16_t handle){
136     if (!hsp_hs_callback) return;
137     uint8_t event[6];
138     event[0] = HCI_EVENT_HSP_META;
139     event[1] = sizeof(event) - 2;
140     event[2] = HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE;
141     event[3] = status;
142     bt_store_16(event, 4, handle);
143     (*hsp_hs_callback)(event, sizeof(event));
144 }
145 
146 // remote audio volume control
147 // AG +VGM=13 [0..15] ; HS AT+VGM=6 | AG OK
148 
149 static int hsp_hs_send_str_over_rfcomm(uint16_t cid, const char * command){
150     if (!rfcomm_can_send_packet_now(rfcomm_cid)) return 1;
151     int err = rfcomm_send(cid, (uint8_t*) command, strlen(command));
152     if (err){
153         printf("rfcomm_send -> error 0X%02x", err);
154     }
155     return err;
156 }
157 
158 void hsp_hs_support_custom_indications(int enable){
159     hs_support_custom_indications = enable;
160 }
161 
162 // When support custom commands is enabled, AG will send HSP_SUBEVENT_HS_COMMAND.
163 // On occurance of this event, client's packet handler must send the result back
164 // by calling hsp_hs_send_result function.
165 int hsp_hs_send_result(char * result){
166     if (!hs_support_custom_indications) return 1;
167     return hsp_hs_send_str_over_rfcomm(rfcomm_cid, result);
168 }
169 
170 
171 void hsp_hs_create_service(uint8_t * service, uint32_t service_record_handle, int rfcomm_channel_nr, const char * name, uint8_t have_remote_audio_control){
172     uint8_t* attribute;
173     de_create_sequence(service);
174 
175     // 0x0000 "Service Record Handle"
176     de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ServiceRecordHandle);
177     de_add_number(service, DE_UINT, DE_SIZE_32, service_record_handle);
178 
179     // 0x0001 "Service Class ID List"
180     de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_ServiceClassIDList);
181     attribute = de_push_sequence(service);
182     {
183         //  see Bluetooth Erratum #3507
184         de_add_number(attribute, DE_UUID, DE_SIZE_16, SDP_HSP);          // 0x1108
185         de_add_number(attribute, DE_UUID, DE_SIZE_16, SDP_Headset_HS);   // 0x1131
186         de_add_number(attribute, DE_UUID, DE_SIZE_16, SDP_GenericAudio); // 0x1203
187     }
188     de_pop_sequence(service, attribute);
189 
190     // 0x0004 "Protocol Descriptor List"
191     de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_ProtocolDescriptorList);
192     attribute = de_push_sequence(service);
193     {
194         uint8_t* l2cpProtocol = de_push_sequence(attribute);
195         {
196             de_add_number(l2cpProtocol,  DE_UUID, DE_SIZE_16, SDP_L2CAPProtocol);
197         }
198         de_pop_sequence(attribute, l2cpProtocol);
199 
200         uint8_t* rfcomm = de_push_sequence(attribute);
201         {
202             de_add_number(rfcomm,  DE_UUID, DE_SIZE_16, SDP_RFCOMMProtocol);  // rfcomm_service
203             de_add_number(rfcomm,  DE_UINT, DE_SIZE_8,  rfcomm_channel_nr);  // rfcomm channel
204         }
205         de_pop_sequence(attribute, rfcomm);
206     }
207     de_pop_sequence(service, attribute);
208 
209     // 0x0005 "Public Browse Group"
210     de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_BrowseGroupList); // public browse group
211     attribute = de_push_sequence(service);
212     {
213         de_add_number(attribute,  DE_UUID, DE_SIZE_16, SDP_PublicBrowseGroup);
214     }
215     de_pop_sequence(service, attribute);
216 
217     // 0x0009 "Bluetooth Profile Descriptor List"
218     de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_BluetoothProfileDescriptorList);
219     attribute = de_push_sequence(service);
220     {
221         uint8_t *hsp_profile = de_push_sequence(attribute);
222         {
223             de_add_number(hsp_profile,  DE_UUID, DE_SIZE_16, SDP_HSP);
224             de_add_number(hsp_profile,  DE_UINT, DE_SIZE_16, 0x0102); // Verision 1.2
225         }
226         de_pop_sequence(attribute, hsp_profile);
227     }
228     de_pop_sequence(service, attribute);
229 
230     // 0x0100 "Service Name"
231     de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0100);
232     if (name){
233         de_add_data(service,  DE_STRING, strlen(name), (uint8_t *) name);
234     } else {
235         de_add_data(service,  DE_STRING, strlen(default_hsp_hs_service_name), (uint8_t *) default_hsp_hs_service_name);
236     }
237 
238     // Remote audio volume control
239     de_add_number(service, DE_UINT, DE_SIZE_16, 0x030C);
240     de_add_number(service, DE_BOOL, DE_SIZE_8, have_remote_audio_control);
241 }
242 
243 static void hsp_hs_reset_state(void){
244     hsp_state = HSP_IDLE;
245 
246     rfcomm_cid = 0;
247     rfcomm_handle = 0;
248     sco_handle = 0;
249 
250     hs_microphone_gain = -1;
251     hs_speaker_gain = -1;
252 
253     hs_send_button_press = 0;
254     hs_support_custom_indications = 0;
255 }
256 
257 void hsp_hs_init(uint8_t rfcomm_channel_nr){
258     // init L2CAP
259     l2cap_init();
260     l2cap_register_packet_handler(packet_handler);
261 
262     rfcomm_init();
263     rfcomm_register_packet_handler(packet_handler);
264     rfcomm_register_service(rfcomm_channel_nr, 0xffff);  // reserved channel, mtu limited by l2cap
265 
266     sdp_query_rfcomm_register_callback(handle_query_rfcomm_event, NULL);
267 
268     hsp_hs_reset_state();
269 }
270 
271 
272 void hsp_hs_connect(bd_addr_t bd_addr){
273     if (hsp_state != HSP_IDLE) return;
274     hs_outgoing_connection = 1;
275     hsp_state = HSP_SDP_QUERY_RFCOMM_CHANNEL;
276     memcpy(remote, bd_addr, 6);
277     hsp_run();
278 }
279 
280 void hsp_hs_disconnect(bd_addr_t bd_addr){
281     switch (hsp_state){
282         case HSP_ACTIVE:
283             printf("HSP_W4_USER_ACTION\n");
284             hsp_state = HSP_W4_USER_ACTION;
285             hs_send_button_press = 1;
286             break;
287         case HSP_W4_RFCOMM_CONNECTED:
288             printf("HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN \n");
289             hsp_state = HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN;
290             break;
291         default:
292             return;
293     }
294     hsp_run();
295 }
296 
297 
298 void hsp_hs_set_microphone_gain(uint8_t gain){
299     if (gain < 0 || gain >15) {
300         printf("Gain must be in interval [0..15], it is given %d\n", gain);
301         return;
302     }
303     hs_microphone_gain = gain;
304     hsp_run();
305 }
306 
307 // AG +VGS=5  [0..15] ; HS AT+VGM=6 | AG OK
308 void hsp_hs_set_speaker_gain(uint8_t gain){
309     if (gain < 0 || gain >15) {
310         printf("Gain must be in interval [0..15], it is given %d\n", gain);
311         return;
312     }
313     hs_speaker_gain = gain;
314     hsp_run();
315 }
316 
317 
318 static void hsp_run(void){
319     int err;
320 
321     if (hs_send_button_press){
322         hs_send_button_press = 0;
323         err = hsp_hs_send_str_over_rfcomm(rfcomm_cid, HSP_HS_AT_CKPD);
324         if (err) {
325             hs_send_button_press = 1;
326         }
327         return;
328     }
329 
330     switch (hsp_state){
331         case HSP_SDP_QUERY_RFCOMM_CHANNEL:
332             hsp_state = HSP_W4_SDP_QUERY_COMPLETE;
333             sdp_query_rfcomm_channel_and_name_for_uuid(remote, SDP_Headset_AG);
334             break;
335 
336         case HSP_W2_CONNECT_SCO:
337             hsp_state = HSP_W4_SCO_CONNECTED;
338             break;
339 
340         case HSP_W2_DISCONNECT_SCO:
341             hsp_state = HSP_W4_SCO_DISCONNECTED;
342             break;
343 
344         case HSP_ACTIVE:
345 
346              if (hs_microphone_gain >= 0){
347                 int gain = hs_microphone_gain;
348                 hs_microphone_gain = -1;
349                 char buffer[20];
350                 sprintf(buffer, "%s=%d\r\n", HSP_HS_MICROPHONE_GAIN, gain);
351                 err = hsp_hs_send_str_over_rfcomm(rfcomm_cid, buffer);
352                 if (err) {
353                     hs_microphone_gain = gain;
354                 }
355                 break;
356             }
357 
358             if (hs_speaker_gain >= 0){
359                 int gain = hs_speaker_gain;
360                 hs_speaker_gain = -1;
361                 char buffer[20];
362                 sprintf(buffer, "%s=%d\r\n", HSP_HS_SPEAKER_GAIN, gain);
363                 err = hsp_hs_send_str_over_rfcomm(rfcomm_cid, buffer);
364                 if (err) {
365                     hs_speaker_gain = gain;
366                 }
367                 break;
368             }
369 
370             break;
371         default:
372             break;
373     }
374 }
375 
376 
377 static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
378     // printf("packet_handler type %u, packet[0] %x\n", packet_type, packet[0]);
379     if (packet_type == RFCOMM_DATA_PACKET){
380         // skip over leading newline
381         while (size > 0 && (packet[0] == '\n' || packet[0] == '\r')){
382             size--;
383             packet++;
384         }
385         if (strncmp((char *)packet, HSP_AG_RING, strlen(HSP_AG_RING)) == 0){
386             emit_event(HSP_SUBEVENT_RING, 0);
387         } else if (strncmp((char *)packet, HSP_AG_OK, strlen(HSP_AG_OK)) == 0){
388             printf("OK RECEIVED\n");
389             switch (hsp_state){
390                 case HSP_W4_RFCOMM_CONNECTED:
391                     hsp_state = HSP_W2_CONNECT_SCO;
392                     break;
393                 case HSP_W4_USER_ACTION:
394                     hsp_state = HSP_W2_DISCONNECT_SCO;
395                     break;
396                 default:
397                     break;
398             }
399         } else if (strncmp((char *)packet, HSP_MICROPHONE_GAIN, strlen(HSP_MICROPHONE_GAIN)) == 0){
400             uint8_t gain = (uint8_t)atoi((char*)&packet[strlen(HSP_MICROPHONE_GAIN)]);
401             emit_event(HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED, gain);
402 
403         } else if (strncmp((char *)packet, HSP_SPEAKER_GAIN, strlen(HSP_SPEAKER_GAIN)) == 0){
404             uint8_t gain = (uint8_t)atoi((char*)&packet[strlen(HSP_SPEAKER_GAIN)]);
405             emit_event(HSP_SUBEVENT_SPEAKER_GAIN_CHANGED, gain);
406         } else {
407             if (!hsp_hs_callback) return;
408             // strip trailing newline
409             while (size > 0 && (packet[size-1] == '\n' || packet[size-1] == '\r')){
410                 size--;
411             }
412             // add trailing \0
413             packet[size] = 0;
414             // re-use incoming buffer to avoid reserving large buffers - ugly but efficient
415             uint8_t * event = packet - 3;
416             event[0] = HCI_EVENT_HSP_META;
417             event[1] = size + 1;
418             event[2] = HSP_SUBEVENT_AG_INDICATION;
419             (*hsp_hs_callback)(event, size+3);
420         }
421         hsp_run();
422         return;
423     }
424 
425     if (packet_type != HCI_EVENT_PACKET) return;
426     uint8_t event = packet[0];
427     bd_addr_t event_addr;
428     uint16_t handle;
429 
430     switch (event) {
431         case BTSTACK_EVENT_STATE:
432             // bt stack activated, get started
433             if (packet[2] == HCI_STATE_WORKING){
434                 printf("BTstack activated, get started .\n");
435             }
436             hsp_hs_callback(packet, size);
437             break;
438 
439         case HCI_EVENT_PIN_CODE_REQUEST:
440             // inform about pin code request
441             printf("Pin code request - using '0000'\n\r");
442             bt_flip_addr(event_addr, &packet[2]);
443             hci_send_cmd(&hci_pin_code_request_reply, &event_addr, 4, "0000");
444             break;
445         case HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE:{
446             int index = 2;
447             uint8_t status = packet[index++];
448             sco_handle = READ_BT_16(packet, index);
449             index+=2;
450             bd_addr_t address;
451             memcpy(address, &packet[index], 6);
452             index+=6;
453             uint8_t link_type = packet[index++];
454             uint8_t transmission_interval = packet[index++];  // measured in slots
455             uint8_t retransmission_interval = packet[index++];// measured in slots
456             uint16_t rx_packet_length = READ_BT_16(packet, index); // measured in bytes
457             index+=2;
458             uint16_t tx_packet_length = READ_BT_16(packet, index); // measured in bytes
459             index+=2;
460             uint8_t air_mode = packet[index];
461 
462             if (status != 0){
463                 log_error("(e)SCO Connection failed, status %u", status);
464                 emit_event_audio_connected(status, sco_handle);
465                 break;
466             }
467             switch (link_type){
468                 case 0x00:
469                     printf("SCO Connection established. \n");
470                     if (transmission_interval != 0) log_error("SCO Connection: transmission_interval not zero: %d.", transmission_interval);
471                     if (retransmission_interval != 0) log_error("SCO Connection: retransmission_interval not zero: %d.", retransmission_interval);
472                     if (rx_packet_length != 0) log_error("SCO Connection: rx_packet_length not zero: %d.", rx_packet_length);
473                     if (tx_packet_length != 0) log_error("SCO Connection: tx_packet_length not zero: %d.", tx_packet_length);
474                     break;
475                 case 0x02:
476                     printf("eSCO Connection established. \n");
477                     break;
478                 default:
479                     log_error("(e)SCO reserved link_type 0x%2x", link_type);
480                     break;
481             }
482             log_info("sco_handle 0x%2x, address %s, transmission_interval %u slots, retransmission_interval %u slots, "
483                  " rx_packet_length %u bytes, tx_packet_length %u bytes, air_mode 0x%2x (0x02 == CVSD)", sco_handle,
484                  bd_addr_to_str(address), transmission_interval, retransmission_interval, rx_packet_length, tx_packet_length, air_mode);
485 
486             if (hsp_state == HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN){
487                 hsp_state = HSP_W2_DISCONNECT_SCO;
488                 break;
489             }
490 
491             // forward event to app
492             hsp_hs_callback(packet, size);
493 
494             hsp_state = HSP_ACTIVE;
495             emit_event_audio_connected(0, sco_handle);
496             break;
497         }
498 
499         case RFCOMM_EVENT_INCOMING_CONNECTION:
500             // data: event (8), len(8), address(48), channel (8), rfcomm_cid (16)
501             if (hsp_state != HSP_IDLE) return;
502 
503             bt_flip_addr(event_addr, &packet[2]);
504             rfcomm_cid = READ_BT_16(packet, 9);
505             printf("RFCOMM channel %u requested for %s\n", packet[8], bd_addr_to_str(event_addr));
506             rfcomm_accept_connection(rfcomm_cid);
507 
508             hsp_state = HSP_W4_RFCOMM_CONNECTED;
509             break;
510 
511         case RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE:
512             printf("RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE packet_handler type %u, packet[0] %x\n", packet_type, packet[0]);
513             // data: event(8), len(8), status (8), address (48), handle(16), server channel(8), rfcomm_cid(16), max frame size(16)
514             if (packet[2]) {
515                 printf("RFCOMM channel open failed, status %u\n", packet[2]);
516                 hsp_hs_reset_state();
517                 emit_event(HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE, packet[2]);
518                 hs_outgoing_connection = 0;
519             } else {
520                 // data: event(8) , len(8), status (8), address (48), handle (16), server channel(8), rfcomm_cid(16), max frame size(16)
521                 rfcomm_handle = READ_BT_16(packet, 9);
522                 rfcomm_cid = READ_BT_16(packet, 12);
523                 mtu = READ_BT_16(packet, 14);
524                 printf("RFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u\n", rfcomm_cid, mtu);
525 
526                 if (hs_outgoing_connection){
527                     hs_outgoing_connection = 0;
528                     hs_send_button_press = 1;
529                 }
530 
531                 switch (hsp_state){
532                     case HSP_W4_RFCOMM_CONNECTED:
533                         hsp_state = HSP_W2_CONNECT_SCO;
534                         break;
535                     case HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN:
536                         hsp_state = HSP_W2_DISCONNECT_RFCOMM;
537                         break;
538                     default:
539                         break;
540                 }
541             }
542             break;
543         case DAEMON_EVENT_HCI_PACKET_SENT:
544         case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS:
545         case RFCOMM_EVENT_CREDITS:
546             hsp_hs_callback(packet, size);
547             break;
548 
549         case HCI_EVENT_DISCONNECTION_COMPLETE:
550             printf("HCI_EVENT_DISCONNECTION_COMPLETE \n");
551             // if (hsp_state != HSP_W4_SCO_DISCONNECTED){
552             //     printf("received gap disconnect in wrong hsp state\n");
553             // }
554             handle = READ_BT_16(packet,3);
555             if (handle == sco_handle){
556                 sco_handle = 0;
557                 hsp_state = HSP_W2_DISCONNECT_RFCOMM;
558                 printf(" HSP_W2_DISCONNECT_RFCOMM\n");
559                 break;
560             }
561             break;
562         case RFCOMM_EVENT_CHANNEL_CLOSED:
563             printf("RFCOMM_EVENT_CHANNEL_CLOSED\n");
564             // if (hsp_state != HSP_W4_RFCOMM_DISCONNECTED){
565             //     printf("received RFCOMM disconnect in wrong hsp state\n");
566             // }
567             printf("RFCOMM channel closed\n");
568             hsp_hs_reset_state();
569             emit_event(HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE,0);
570             break;
571         default:
572             break;
573     }
574     hsp_run();
575 }
576 
577 static void handle_query_rfcomm_event(sdp_query_event_t * event, void * context){
578     sdp_query_rfcomm_service_event_t * ve;
579     sdp_query_complete_event_t * ce;
580 
581     switch (event->type){
582         case SDP_QUERY_RFCOMM_SERVICE:
583             ve = (sdp_query_rfcomm_service_event_t*) event;
584             channel_nr = ve->channel_nr;
585             printf("** Service name: '%s', RFCOMM port %u\n", ve->service_name, channel_nr);
586             break;
587         case SDP_QUERY_COMPLETE:
588             ce = (sdp_query_complete_event_t*) event;
589 
590             if (channel_nr > 0){
591                 hsp_state = HSP_W4_RFCOMM_CONNECTED;
592                 printf("RFCOMM create channel.\n");
593                 rfcomm_create_channel(remote, channel_nr, NULL);
594                 break;
595             }
596             hsp_hs_reset_state();
597             printf("Service not found, status %u.\n", ce->status);
598             exit(0);
599             break;
600     }
601 }
602 
603 void hsp_hs_press_button(void){
604     hs_send_button_press = 1;
605     hsp_run();
606 }
607 
608 
609 
610 
611