xref: /btstack/src/classic/hfp.c (revision 3deb3ec68039c68a16974dffc53343233662f909)
1*3deb3ec6SMatthias Ringwald /*
2*3deb3ec6SMatthias Ringwald  * Copyright (C) 2014 BlueKitchen GmbH
3*3deb3ec6SMatthias Ringwald  *
4*3deb3ec6SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5*3deb3ec6SMatthias Ringwald  * modification, are permitted provided that the following conditions
6*3deb3ec6SMatthias Ringwald  * are met:
7*3deb3ec6SMatthias Ringwald  *
8*3deb3ec6SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9*3deb3ec6SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10*3deb3ec6SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11*3deb3ec6SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12*3deb3ec6SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13*3deb3ec6SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14*3deb3ec6SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15*3deb3ec6SMatthias Ringwald  *    from this software without specific prior written permission.
16*3deb3ec6SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17*3deb3ec6SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18*3deb3ec6SMatthias Ringwald  *    monetary gain.
19*3deb3ec6SMatthias Ringwald  *
20*3deb3ec6SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21*3deb3ec6SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*3deb3ec6SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*3deb3ec6SMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24*3deb3ec6SMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25*3deb3ec6SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26*3deb3ec6SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27*3deb3ec6SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28*3deb3ec6SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29*3deb3ec6SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30*3deb3ec6SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*3deb3ec6SMatthias Ringwald  * SUCH DAMAGE.
32*3deb3ec6SMatthias Ringwald  *
33*3deb3ec6SMatthias Ringwald  * Please inquire about commercial licensing options at
34*3deb3ec6SMatthias Ringwald  * [email protected]
35*3deb3ec6SMatthias Ringwald  *
36*3deb3ec6SMatthias Ringwald  */
37*3deb3ec6SMatthias Ringwald 
38*3deb3ec6SMatthias Ringwald // *****************************************************************************
39*3deb3ec6SMatthias Ringwald //
40*3deb3ec6SMatthias Ringwald // Minimal setup for HFP Audio Gateway (AG) unit (!! UNDER DEVELOPMENT !!)
41*3deb3ec6SMatthias Ringwald //
42*3deb3ec6SMatthias Ringwald // *****************************************************************************
43*3deb3ec6SMatthias Ringwald 
44*3deb3ec6SMatthias Ringwald #include "btstack-config.h"
45*3deb3ec6SMatthias Ringwald 
46*3deb3ec6SMatthias Ringwald #include <stdint.h>
47*3deb3ec6SMatthias Ringwald #include <stdio.h>
48*3deb3ec6SMatthias Ringwald #include <stdlib.h>
49*3deb3ec6SMatthias Ringwald #include <string.h>
50*3deb3ec6SMatthias Ringwald #include <inttypes.h>
51*3deb3ec6SMatthias Ringwald 
52*3deb3ec6SMatthias Ringwald #include "hci_cmds.h"
53*3deb3ec6SMatthias Ringwald #include "run_loop.h"
54*3deb3ec6SMatthias Ringwald 
55*3deb3ec6SMatthias Ringwald #include "hci.h"
56*3deb3ec6SMatthias Ringwald #include "btstack_memory.h"
57*3deb3ec6SMatthias Ringwald #include "hci_dump.h"
58*3deb3ec6SMatthias Ringwald #include "l2cap.h"
59*3deb3ec6SMatthias Ringwald #include "sdp_query_rfcomm.h"
60*3deb3ec6SMatthias Ringwald #include "sdp.h"
61*3deb3ec6SMatthias Ringwald #include "debug.h"
62*3deb3ec6SMatthias Ringwald 
63*3deb3ec6SMatthias Ringwald #define HFP_HF_FEATURES_SIZE 10
64*3deb3ec6SMatthias Ringwald #define HFP_AG_FEATURES_SIZE 12
65*3deb3ec6SMatthias Ringwald 
66*3deb3ec6SMatthias Ringwald 
67*3deb3ec6SMatthias Ringwald static const char * hfp_hf_features[] = {
68*3deb3ec6SMatthias Ringwald     "EC and/or NR function",
69*3deb3ec6SMatthias Ringwald     "Three-way calling",
70*3deb3ec6SMatthias Ringwald     "CLI presentation capability",
71*3deb3ec6SMatthias Ringwald     "Voice recognition activation",
72*3deb3ec6SMatthias Ringwald     "Remote volume control",
73*3deb3ec6SMatthias Ringwald 
74*3deb3ec6SMatthias Ringwald     "Enhanced call status",
75*3deb3ec6SMatthias Ringwald     "Enhanced call control",
76*3deb3ec6SMatthias Ringwald 
77*3deb3ec6SMatthias Ringwald     "Codec negotiation",
78*3deb3ec6SMatthias Ringwald 
79*3deb3ec6SMatthias Ringwald     "HF Indicators",
80*3deb3ec6SMatthias Ringwald     "eSCO S4 (and T2) Settings Supported",
81*3deb3ec6SMatthias Ringwald     "Reserved for future definition"
82*3deb3ec6SMatthias Ringwald };
83*3deb3ec6SMatthias Ringwald 
84*3deb3ec6SMatthias Ringwald static const char * hfp_ag_features[] = {
85*3deb3ec6SMatthias Ringwald     "Three-way calling",
86*3deb3ec6SMatthias Ringwald     "EC and/or NR function",
87*3deb3ec6SMatthias Ringwald     "Voice recognition function",
88*3deb3ec6SMatthias Ringwald     "In-band ring tone capability",
89*3deb3ec6SMatthias Ringwald     "Attach a number to a voice tag",
90*3deb3ec6SMatthias Ringwald     "Ability to reject a call",
91*3deb3ec6SMatthias Ringwald     "Enhanced call status",
92*3deb3ec6SMatthias Ringwald     "Enhanced call control",
93*3deb3ec6SMatthias Ringwald     "Extended Error Result Codes",
94*3deb3ec6SMatthias Ringwald     "Codec negotiation",
95*3deb3ec6SMatthias Ringwald     "HF Indicators",
96*3deb3ec6SMatthias Ringwald     "eSCO S4 (and T2) Settings Supported",
97*3deb3ec6SMatthias Ringwald     "Reserved for future definition"
98*3deb3ec6SMatthias Ringwald };
99*3deb3ec6SMatthias Ringwald 
100*3deb3ec6SMatthias Ringwald static int hfp_generic_status_indicators_nr = 0;
101*3deb3ec6SMatthias Ringwald static hfp_generic_status_indicator_t hfp_generic_status_indicators[HFP_MAX_NUM_HF_INDICATORS];
102*3deb3ec6SMatthias Ringwald 
103*3deb3ec6SMatthias Ringwald static linked_list_t hfp_connections = NULL;
104*3deb3ec6SMatthias Ringwald 
105*3deb3ec6SMatthias Ringwald hfp_generic_status_indicator_t * get_hfp_generic_status_indicators(void){
106*3deb3ec6SMatthias Ringwald     return (hfp_generic_status_indicator_t *) &hfp_generic_status_indicators;
107*3deb3ec6SMatthias Ringwald }
108*3deb3ec6SMatthias Ringwald int get_hfp_generic_status_indicators_nr(void){
109*3deb3ec6SMatthias Ringwald     return hfp_generic_status_indicators_nr;
110*3deb3ec6SMatthias Ringwald }
111*3deb3ec6SMatthias Ringwald void set_hfp_generic_status_indicators(hfp_generic_status_indicator_t * indicators, int indicator_nr){
112*3deb3ec6SMatthias Ringwald     if (indicator_nr > HFP_MAX_NUM_HF_INDICATORS) return;
113*3deb3ec6SMatthias Ringwald     hfp_generic_status_indicators_nr = indicator_nr;
114*3deb3ec6SMatthias Ringwald     memcpy(hfp_generic_status_indicators, indicators, indicator_nr * sizeof(hfp_generic_status_indicator_t));
115*3deb3ec6SMatthias Ringwald }
116*3deb3ec6SMatthias Ringwald 
117*3deb3ec6SMatthias Ringwald const char * hfp_hf_feature(int index){
118*3deb3ec6SMatthias Ringwald     if (index > HFP_HF_FEATURES_SIZE){
119*3deb3ec6SMatthias Ringwald         return hfp_hf_features[HFP_HF_FEATURES_SIZE];
120*3deb3ec6SMatthias Ringwald     }
121*3deb3ec6SMatthias Ringwald     return hfp_hf_features[index];
122*3deb3ec6SMatthias Ringwald }
123*3deb3ec6SMatthias Ringwald 
124*3deb3ec6SMatthias Ringwald const char * hfp_ag_feature(int index){
125*3deb3ec6SMatthias Ringwald     if (index > HFP_AG_FEATURES_SIZE){
126*3deb3ec6SMatthias Ringwald         return hfp_ag_features[HFP_AG_FEATURES_SIZE];
127*3deb3ec6SMatthias Ringwald     }
128*3deb3ec6SMatthias Ringwald     return hfp_ag_features[index];
129*3deb3ec6SMatthias Ringwald }
130*3deb3ec6SMatthias Ringwald 
131*3deb3ec6SMatthias Ringwald int send_str_over_rfcomm(uint16_t cid, char * command){
132*3deb3ec6SMatthias Ringwald     if (!rfcomm_can_send_packet_now(cid)) return 1;
133*3deb3ec6SMatthias Ringwald     int err = rfcomm_send_internal(cid, (uint8_t*) command, strlen(command));
134*3deb3ec6SMatthias Ringwald     if (err){
135*3deb3ec6SMatthias Ringwald         log_error("rfcomm_send_internal -> error 0x%02x \n", err);
136*3deb3ec6SMatthias Ringwald     }
137*3deb3ec6SMatthias Ringwald     return 1;
138*3deb3ec6SMatthias Ringwald }
139*3deb3ec6SMatthias Ringwald 
140*3deb3ec6SMatthias Ringwald #if 0
141*3deb3ec6SMatthias Ringwald void hfp_set_codec(hfp_connection_t * context, uint8_t *packet, uint16_t size){
142*3deb3ec6SMatthias Ringwald     // parse available codecs
143*3deb3ec6SMatthias Ringwald     int pos = 0;
144*3deb3ec6SMatthias Ringwald     int i;
145*3deb3ec6SMatthias Ringwald     for (i=0; i<size; i++){
146*3deb3ec6SMatthias Ringwald         pos+=8;
147*3deb3ec6SMatthias Ringwald         if (packet[pos] > context->negotiated_codec){
148*3deb3ec6SMatthias Ringwald             context->negotiated_codec = packet[pos];
149*3deb3ec6SMatthias Ringwald         }
150*3deb3ec6SMatthias Ringwald     }
151*3deb3ec6SMatthias Ringwald     printf("Negotiated Codec 0x%02x\n", context->negotiated_codec);
152*3deb3ec6SMatthias Ringwald }
153*3deb3ec6SMatthias Ringwald #endif
154*3deb3ec6SMatthias Ringwald 
155*3deb3ec6SMatthias Ringwald // UTILS
156*3deb3ec6SMatthias Ringwald int get_bit(uint16_t bitmap, int position){
157*3deb3ec6SMatthias Ringwald     return (bitmap >> position) & 1;
158*3deb3ec6SMatthias Ringwald }
159*3deb3ec6SMatthias Ringwald 
160*3deb3ec6SMatthias Ringwald int store_bit(uint32_t bitmap, int position, uint8_t value){
161*3deb3ec6SMatthias Ringwald     if (value){
162*3deb3ec6SMatthias Ringwald         bitmap |= 1 << position;
163*3deb3ec6SMatthias Ringwald     } else {
164*3deb3ec6SMatthias Ringwald         bitmap &= ~ (1 << position);
165*3deb3ec6SMatthias Ringwald     }
166*3deb3ec6SMatthias Ringwald     return bitmap;
167*3deb3ec6SMatthias Ringwald }
168*3deb3ec6SMatthias Ringwald 
169*3deb3ec6SMatthias Ringwald int join(char * buffer, int buffer_size, uint8_t * values, int values_nr){
170*3deb3ec6SMatthias Ringwald     if (buffer_size < values_nr * 3) return 0;
171*3deb3ec6SMatthias Ringwald     int i;
172*3deb3ec6SMatthias Ringwald     int offset = 0;
173*3deb3ec6SMatthias Ringwald     for (i = 0; i < values_nr-1; i++) {
174*3deb3ec6SMatthias Ringwald       offset += snprintf(buffer+offset, buffer_size-offset, "%d,", values[i]); // puts string into buffer
175*3deb3ec6SMatthias Ringwald     }
176*3deb3ec6SMatthias Ringwald     if (i<values_nr){
177*3deb3ec6SMatthias Ringwald         offset += snprintf(buffer+offset, buffer_size-offset, "%d", values[i]);
178*3deb3ec6SMatthias Ringwald     }
179*3deb3ec6SMatthias Ringwald     return offset;
180*3deb3ec6SMatthias Ringwald }
181*3deb3ec6SMatthias Ringwald 
182*3deb3ec6SMatthias Ringwald int join_bitmap(char * buffer, int buffer_size, uint32_t values, int values_nr){
183*3deb3ec6SMatthias Ringwald     if (buffer_size < values_nr * 3) return 0;
184*3deb3ec6SMatthias Ringwald 
185*3deb3ec6SMatthias Ringwald     int i;
186*3deb3ec6SMatthias Ringwald     int offset = 0;
187*3deb3ec6SMatthias Ringwald     for (i = 0; i < values_nr-1; i++) {
188*3deb3ec6SMatthias Ringwald       offset += snprintf(buffer+offset, buffer_size-offset, "%d,", get_bit(values,i)); // puts string into buffer
189*3deb3ec6SMatthias Ringwald     }
190*3deb3ec6SMatthias Ringwald 
191*3deb3ec6SMatthias Ringwald     if (i<values_nr){
192*3deb3ec6SMatthias Ringwald         offset += snprintf(buffer+offset, buffer_size-offset, "%d", get_bit(values,i));
193*3deb3ec6SMatthias Ringwald     }
194*3deb3ec6SMatthias Ringwald     return offset;
195*3deb3ec6SMatthias Ringwald }
196*3deb3ec6SMatthias Ringwald 
197*3deb3ec6SMatthias Ringwald void hfp_emit_event(hfp_callback_t callback, uint8_t event_subtype, uint8_t value){
198*3deb3ec6SMatthias Ringwald     if (!callback) return;
199*3deb3ec6SMatthias Ringwald     uint8_t event[4];
200*3deb3ec6SMatthias Ringwald     event[0] = HCI_EVENT_HFP_META;
201*3deb3ec6SMatthias Ringwald     event[1] = sizeof(event) - 2;
202*3deb3ec6SMatthias Ringwald     event[2] = event_subtype;
203*3deb3ec6SMatthias Ringwald     event[3] = value; // status 0 == OK
204*3deb3ec6SMatthias Ringwald     (*callback)(event, sizeof(event));
205*3deb3ec6SMatthias Ringwald }
206*3deb3ec6SMatthias Ringwald 
207*3deb3ec6SMatthias Ringwald 
208*3deb3ec6SMatthias Ringwald linked_list_t * hfp_get_connections(){
209*3deb3ec6SMatthias Ringwald     return (linked_list_t *) &hfp_connections;
210*3deb3ec6SMatthias Ringwald }
211*3deb3ec6SMatthias Ringwald 
212*3deb3ec6SMatthias Ringwald hfp_connection_t * get_hfp_connection_context_for_rfcomm_cid(uint16_t cid){
213*3deb3ec6SMatthias Ringwald     linked_list_iterator_t it;
214*3deb3ec6SMatthias Ringwald     linked_list_iterator_init(&it, hfp_get_connections());
215*3deb3ec6SMatthias Ringwald     while (linked_list_iterator_has_next(&it)){
216*3deb3ec6SMatthias Ringwald         hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it);
217*3deb3ec6SMatthias Ringwald         if (connection->rfcomm_cid == cid){
218*3deb3ec6SMatthias Ringwald             return connection;
219*3deb3ec6SMatthias Ringwald         }
220*3deb3ec6SMatthias Ringwald     }
221*3deb3ec6SMatthias Ringwald     return NULL;
222*3deb3ec6SMatthias Ringwald }
223*3deb3ec6SMatthias Ringwald 
224*3deb3ec6SMatthias Ringwald hfp_connection_t * get_hfp_connection_context_for_bd_addr(bd_addr_t bd_addr){
225*3deb3ec6SMatthias Ringwald     linked_list_iterator_t it;
226*3deb3ec6SMatthias Ringwald     linked_list_iterator_init(&it, hfp_get_connections());
227*3deb3ec6SMatthias Ringwald     while (linked_list_iterator_has_next(&it)){
228*3deb3ec6SMatthias Ringwald         hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it);
229*3deb3ec6SMatthias Ringwald         if (memcmp(connection->remote_addr, bd_addr, 6) == 0) {
230*3deb3ec6SMatthias Ringwald             return connection;
231*3deb3ec6SMatthias Ringwald         }
232*3deb3ec6SMatthias Ringwald     }
233*3deb3ec6SMatthias Ringwald     return NULL;
234*3deb3ec6SMatthias Ringwald }
235*3deb3ec6SMatthias Ringwald 
236*3deb3ec6SMatthias Ringwald static hfp_connection_t * get_hfp_connection_context_for_handle(uint16_t handle){
237*3deb3ec6SMatthias Ringwald     linked_list_iterator_t it;
238*3deb3ec6SMatthias Ringwald     linked_list_iterator_init(&it, hfp_get_connections());
239*3deb3ec6SMatthias Ringwald     while (linked_list_iterator_has_next(&it)){
240*3deb3ec6SMatthias Ringwald         hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it);
241*3deb3ec6SMatthias Ringwald         if (connection->con_handle == handle){
242*3deb3ec6SMatthias Ringwald             return connection;
243*3deb3ec6SMatthias Ringwald         }
244*3deb3ec6SMatthias Ringwald     }
245*3deb3ec6SMatthias Ringwald     return NULL;
246*3deb3ec6SMatthias Ringwald }
247*3deb3ec6SMatthias Ringwald 
248*3deb3ec6SMatthias Ringwald void hfp_reset_context_flags(hfp_connection_t * context){
249*3deb3ec6SMatthias Ringwald     if (!context) return;
250*3deb3ec6SMatthias Ringwald     context->wait_ok = 0;
251*3deb3ec6SMatthias Ringwald     context->send_ok = 0;
252*3deb3ec6SMatthias Ringwald     context->send_error = 0;
253*3deb3ec6SMatthias Ringwald 
254*3deb3ec6SMatthias Ringwald     context->keep_separator = 0;
255*3deb3ec6SMatthias Ringwald 
256*3deb3ec6SMatthias Ringwald     context->retrieve_ag_indicators = 0;        // HFP_CMD_INDICATOR, check if needed
257*3deb3ec6SMatthias Ringwald     context->retrieve_ag_indicators_status = 0;
258*3deb3ec6SMatthias Ringwald 
259*3deb3ec6SMatthias Ringwald     context->list_generic_status_indicators = 0;           // HFP_CMD_LIST_GENERIC_STATUS_INDICATOR
260*3deb3ec6SMatthias Ringwald     context->retrieve_generic_status_indicators = 0;       // HFP_CMD_GENERIC_STATUS_INDICATOR
261*3deb3ec6SMatthias Ringwald     context->retrieve_generic_status_indicators_state = 0; // HFP_CMD_GENERIC_STATUS_INDICATOR_STATE
262*3deb3ec6SMatthias Ringwald 
263*3deb3ec6SMatthias Ringwald     context->change_status_update_for_individual_ag_indicators = 0;
264*3deb3ec6SMatthias Ringwald 
265*3deb3ec6SMatthias Ringwald     context->operator_name_format = 0;
266*3deb3ec6SMatthias Ringwald     context->operator_name = 0;
267*3deb3ec6SMatthias Ringwald     context->operator_name_changed = 0;
268*3deb3ec6SMatthias Ringwald 
269*3deb3ec6SMatthias Ringwald     context->enable_extended_audio_gateway_error_report = 0;
270*3deb3ec6SMatthias Ringwald     context->extended_audio_gateway_error = 0;
271*3deb3ec6SMatthias Ringwald 
272*3deb3ec6SMatthias Ringwald     // can come any time (here taken into account only after SLE),
273*3deb3ec6SMatthias Ringwald     // if codec negotiation feature is set
274*3deb3ec6SMatthias Ringwald     context->notify_ag_on_new_codecs = 0;
275*3deb3ec6SMatthias Ringwald 
276*3deb3ec6SMatthias Ringwald     // establish codecs connection
277*3deb3ec6SMatthias Ringwald     context->ag_trigger_codec_connection_setup = 0;
278*3deb3ec6SMatthias Ringwald     context->hf_trigger_codec_connection_setup = 0;
279*3deb3ec6SMatthias Ringwald     context->suggested_codec = 0;
280*3deb3ec6SMatthias Ringwald     context->negotiated_codec = 0;
281*3deb3ec6SMatthias Ringwald     context->codec_confirmed = 0;
282*3deb3ec6SMatthias Ringwald 
283*3deb3ec6SMatthias Ringwald     context->establish_audio_connection = 0;
284*3deb3ec6SMatthias Ringwald }
285*3deb3ec6SMatthias Ringwald 
286*3deb3ec6SMatthias Ringwald static hfp_connection_t * create_hfp_connection_context(){
287*3deb3ec6SMatthias Ringwald     hfp_connection_t * context = btstack_memory_hfp_connection_get();
288*3deb3ec6SMatthias Ringwald     if (!context) return NULL;
289*3deb3ec6SMatthias Ringwald     // init state
290*3deb3ec6SMatthias Ringwald     memset(context,0, sizeof(hfp_connection_t));
291*3deb3ec6SMatthias Ringwald 
292*3deb3ec6SMatthias Ringwald     context->state = HFP_IDLE;
293*3deb3ec6SMatthias Ringwald     context->parser_state = HFP_PARSER_CMD_HEADER;
294*3deb3ec6SMatthias Ringwald     context->command = HFP_CMD_NONE;
295*3deb3ec6SMatthias Ringwald     context->negotiated_codec = 0;
296*3deb3ec6SMatthias Ringwald 
297*3deb3ec6SMatthias Ringwald     context->enable_status_update_for_ag_indicators = 0xFF;
298*3deb3ec6SMatthias Ringwald 
299*3deb3ec6SMatthias Ringwald     context->generic_status_indicators_nr = hfp_generic_status_indicators_nr;
300*3deb3ec6SMatthias Ringwald     memcpy(context->generic_status_indicators, hfp_generic_status_indicators, hfp_generic_status_indicators_nr * sizeof(hfp_generic_status_indicator_t));
301*3deb3ec6SMatthias Ringwald 
302*3deb3ec6SMatthias Ringwald     linked_list_add(&hfp_connections, (linked_item_t*)context);
303*3deb3ec6SMatthias Ringwald     return context;
304*3deb3ec6SMatthias Ringwald }
305*3deb3ec6SMatthias Ringwald 
306*3deb3ec6SMatthias Ringwald static void remove_hfp_connection_context(hfp_connection_t * context){
307*3deb3ec6SMatthias Ringwald     linked_list_remove(&hfp_connections, (linked_item_t*)context);
308*3deb3ec6SMatthias Ringwald }
309*3deb3ec6SMatthias Ringwald 
310*3deb3ec6SMatthias Ringwald static hfp_connection_t * provide_hfp_connection_context_for_bd_addr(bd_addr_t bd_addr){
311*3deb3ec6SMatthias Ringwald     hfp_connection_t * context = get_hfp_connection_context_for_bd_addr(bd_addr);
312*3deb3ec6SMatthias Ringwald     if (context) return  context;
313*3deb3ec6SMatthias Ringwald     context = create_hfp_connection_context();
314*3deb3ec6SMatthias Ringwald     memcpy(context->remote_addr, bd_addr, 6);
315*3deb3ec6SMatthias Ringwald     return context;
316*3deb3ec6SMatthias Ringwald }
317*3deb3ec6SMatthias Ringwald 
318*3deb3ec6SMatthias Ringwald 
319*3deb3ec6SMatthias Ringwald /* @param suported_features
320*3deb3ec6SMatthias Ringwald  * HF bit 0: EC and/or NR function (yes/no, 1 = yes, 0 = no)
321*3deb3ec6SMatthias Ringwald  * HF bit 1: Call waiting or three-way calling(yes/no, 1 = yes, 0 = no)
322*3deb3ec6SMatthias Ringwald  * HF bit 2: CLI presentation capability (yes/no, 1 = yes, 0 = no)
323*3deb3ec6SMatthias Ringwald  * HF bit 3: Voice recognition activation (yes/no, 1= yes, 0 = no)
324*3deb3ec6SMatthias Ringwald  * HF bit 4: Remote volume control (yes/no, 1 = yes, 0 = no)
325*3deb3ec6SMatthias Ringwald  * HF bit 5: Wide band speech (yes/no, 1 = yes, 0 = no)
326*3deb3ec6SMatthias Ringwald  */
327*3deb3ec6SMatthias Ringwald  /* Bit position:
328*3deb3ec6SMatthias Ringwald  * AG bit 0: Three-way calling (yes/no, 1 = yes, 0 = no)
329*3deb3ec6SMatthias Ringwald  * AG bit 1: EC and/or NR function (yes/no, 1 = yes, 0 = no)
330*3deb3ec6SMatthias Ringwald  * AG bit 2: Voice recognition function (yes/no, 1 = yes, 0 = no)
331*3deb3ec6SMatthias Ringwald  * AG bit 3: In-band ring tone capability (yes/no, 1 = yes, 0 = no)
332*3deb3ec6SMatthias Ringwald  * AG bit 4: Attach a phone number to a voice tag (yes/no, 1 = yes, 0 = no)
333*3deb3ec6SMatthias Ringwald  * AG bit 5: Wide band speech (yes/no, 1 = yes, 0 = no)
334*3deb3ec6SMatthias Ringwald  */
335*3deb3ec6SMatthias Ringwald 
336*3deb3ec6SMatthias Ringwald 
337*3deb3ec6SMatthias Ringwald void hfp_create_sdp_record(uint8_t * service, uint16_t service_uuid, int rfcomm_channel_nr, const char * name, uint16_t supported_features){
338*3deb3ec6SMatthias Ringwald     uint8_t* attribute;
339*3deb3ec6SMatthias Ringwald     de_create_sequence(service);
340*3deb3ec6SMatthias Ringwald 
341*3deb3ec6SMatthias Ringwald     // 0x0000 "Service Record Handle"
342*3deb3ec6SMatthias Ringwald     de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ServiceRecordHandle);
343*3deb3ec6SMatthias Ringwald     de_add_number(service, DE_UINT, DE_SIZE_32, 0x10001);
344*3deb3ec6SMatthias Ringwald 
345*3deb3ec6SMatthias Ringwald     // 0x0001 "Service Class ID List"
346*3deb3ec6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_ServiceClassIDList);
347*3deb3ec6SMatthias Ringwald     attribute = de_push_sequence(service);
348*3deb3ec6SMatthias Ringwald     {
349*3deb3ec6SMatthias Ringwald         //  "UUID for Service"
350*3deb3ec6SMatthias Ringwald         de_add_number(attribute, DE_UUID, DE_SIZE_16, service_uuid);
351*3deb3ec6SMatthias Ringwald         de_add_number(attribute, DE_UUID, DE_SIZE_16, SDP_GenericAudio);
352*3deb3ec6SMatthias Ringwald     }
353*3deb3ec6SMatthias Ringwald     de_pop_sequence(service, attribute);
354*3deb3ec6SMatthias Ringwald 
355*3deb3ec6SMatthias Ringwald     // 0x0004 "Protocol Descriptor List"
356*3deb3ec6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_ProtocolDescriptorList);
357*3deb3ec6SMatthias Ringwald     attribute = de_push_sequence(service);
358*3deb3ec6SMatthias Ringwald     {
359*3deb3ec6SMatthias Ringwald         uint8_t* l2cpProtocol = de_push_sequence(attribute);
360*3deb3ec6SMatthias Ringwald         {
361*3deb3ec6SMatthias Ringwald             de_add_number(l2cpProtocol,  DE_UUID, DE_SIZE_16, SDP_L2CAPProtocol);
362*3deb3ec6SMatthias Ringwald         }
363*3deb3ec6SMatthias Ringwald         de_pop_sequence(attribute, l2cpProtocol);
364*3deb3ec6SMatthias Ringwald 
365*3deb3ec6SMatthias Ringwald         uint8_t* rfcomm = de_push_sequence(attribute);
366*3deb3ec6SMatthias Ringwald         {
367*3deb3ec6SMatthias Ringwald             de_add_number(rfcomm,  DE_UUID, DE_SIZE_16, SDP_RFCOMMProtocol);  // rfcomm_service
368*3deb3ec6SMatthias Ringwald             de_add_number(rfcomm,  DE_UINT, DE_SIZE_8,  rfcomm_channel_nr);  // rfcomm channel
369*3deb3ec6SMatthias Ringwald         }
370*3deb3ec6SMatthias Ringwald         de_pop_sequence(attribute, rfcomm);
371*3deb3ec6SMatthias Ringwald     }
372*3deb3ec6SMatthias Ringwald     de_pop_sequence(service, attribute);
373*3deb3ec6SMatthias Ringwald 
374*3deb3ec6SMatthias Ringwald 
375*3deb3ec6SMatthias Ringwald     // 0x0005 "Public Browse Group"
376*3deb3ec6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_BrowseGroupList); // public browse group
377*3deb3ec6SMatthias Ringwald     attribute = de_push_sequence(service);
378*3deb3ec6SMatthias Ringwald     {
379*3deb3ec6SMatthias Ringwald         de_add_number(attribute,  DE_UUID, DE_SIZE_16, SDP_PublicBrowseGroup);
380*3deb3ec6SMatthias Ringwald     }
381*3deb3ec6SMatthias Ringwald     de_pop_sequence(service, attribute);
382*3deb3ec6SMatthias Ringwald 
383*3deb3ec6SMatthias Ringwald     // 0x0009 "Bluetooth Profile Descriptor List"
384*3deb3ec6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_BluetoothProfileDescriptorList);
385*3deb3ec6SMatthias Ringwald     attribute = de_push_sequence(service);
386*3deb3ec6SMatthias Ringwald     {
387*3deb3ec6SMatthias Ringwald         uint8_t *sppProfile = de_push_sequence(attribute);
388*3deb3ec6SMatthias Ringwald         {
389*3deb3ec6SMatthias Ringwald             de_add_number(sppProfile,  DE_UUID, DE_SIZE_16, SDP_Handsfree);
390*3deb3ec6SMatthias Ringwald             de_add_number(sppProfile,  DE_UINT, DE_SIZE_16, 0x0107); // Verision 1.7
391*3deb3ec6SMatthias Ringwald         }
392*3deb3ec6SMatthias Ringwald         de_pop_sequence(attribute, sppProfile);
393*3deb3ec6SMatthias Ringwald     }
394*3deb3ec6SMatthias Ringwald     de_pop_sequence(service, attribute);
395*3deb3ec6SMatthias Ringwald 
396*3deb3ec6SMatthias Ringwald     // 0x0100 "Service Name"
397*3deb3ec6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0100);
398*3deb3ec6SMatthias Ringwald     de_add_data(service,  DE_STRING, strlen(name), (uint8_t *) name);
399*3deb3ec6SMatthias Ringwald 
400*3deb3ec6SMatthias Ringwald     de_add_number(service, DE_UINT, DE_SIZE_16, supported_features);
401*3deb3ec6SMatthias Ringwald }
402*3deb3ec6SMatthias Ringwald 
403*3deb3ec6SMatthias Ringwald static hfp_connection_t * connection_doing_sdp_query = NULL;
404*3deb3ec6SMatthias Ringwald static void handle_query_rfcomm_event(sdp_query_event_t * event, void * context){
405*3deb3ec6SMatthias Ringwald     sdp_query_rfcomm_service_event_t * ve;
406*3deb3ec6SMatthias Ringwald     sdp_query_complete_event_t * ce;
407*3deb3ec6SMatthias Ringwald     hfp_connection_t * connection = connection_doing_sdp_query;
408*3deb3ec6SMatthias Ringwald 
409*3deb3ec6SMatthias Ringwald     if ( connection->state != HFP_W4_SDP_QUERY_COMPLETE) return;
410*3deb3ec6SMatthias Ringwald 
411*3deb3ec6SMatthias Ringwald     switch (event->type){
412*3deb3ec6SMatthias Ringwald         case SDP_QUERY_RFCOMM_SERVICE:
413*3deb3ec6SMatthias Ringwald             ve = (sdp_query_rfcomm_service_event_t*) event;
414*3deb3ec6SMatthias Ringwald             if (!connection) {
415*3deb3ec6SMatthias Ringwald                 log_error("handle_query_rfcomm_event alloc connection for RFCOMM port %u failed", ve->channel_nr);
416*3deb3ec6SMatthias Ringwald                 return;
417*3deb3ec6SMatthias Ringwald             }
418*3deb3ec6SMatthias Ringwald             connection->rfcomm_channel_nr = ve->channel_nr;
419*3deb3ec6SMatthias Ringwald             break;
420*3deb3ec6SMatthias Ringwald         case SDP_QUERY_COMPLETE:
421*3deb3ec6SMatthias Ringwald             connection_doing_sdp_query = NULL;
422*3deb3ec6SMatthias Ringwald             ce = (sdp_query_complete_event_t*) event;
423*3deb3ec6SMatthias Ringwald 
424*3deb3ec6SMatthias Ringwald             if (connection->rfcomm_channel_nr > 0){
425*3deb3ec6SMatthias Ringwald                 connection->state = HFP_W4_RFCOMM_CONNECTED;
426*3deb3ec6SMatthias Ringwald                 log_info("HFP: SDP_QUERY_COMPLETE context %p, addr %s, state %d", connection, bd_addr_to_str( connection->remote_addr),  connection->state);
427*3deb3ec6SMatthias Ringwald                 rfcomm_create_channel_internal(NULL, connection->remote_addr, connection->rfcomm_channel_nr);
428*3deb3ec6SMatthias Ringwald                 break;
429*3deb3ec6SMatthias Ringwald             }
430*3deb3ec6SMatthias Ringwald             log_info("rfcomm service not found, status %u.", ce->status);
431*3deb3ec6SMatthias Ringwald             break;
432*3deb3ec6SMatthias Ringwald         default:
433*3deb3ec6SMatthias Ringwald             break;
434*3deb3ec6SMatthias Ringwald     }
435*3deb3ec6SMatthias Ringwald }
436*3deb3ec6SMatthias Ringwald 
437*3deb3ec6SMatthias Ringwald void hfp_handle_hci_event(hfp_callback_t callback, uint8_t packet_type, uint8_t *packet, uint16_t size){
438*3deb3ec6SMatthias Ringwald     bd_addr_t event_addr;
439*3deb3ec6SMatthias Ringwald     uint16_t rfcomm_cid, handle;
440*3deb3ec6SMatthias Ringwald     hfp_connection_t * context = NULL;
441*3deb3ec6SMatthias Ringwald 
442*3deb3ec6SMatthias Ringwald     switch (packet[0]) {
443*3deb3ec6SMatthias Ringwald         case BTSTACK_EVENT_STATE:
444*3deb3ec6SMatthias Ringwald             // bt stack activated, get started
445*3deb3ec6SMatthias Ringwald             if (packet[2] == HCI_STATE_WORKING){
446*3deb3ec6SMatthias Ringwald                 printf("BTstack activated, get started .\n");
447*3deb3ec6SMatthias Ringwald             }
448*3deb3ec6SMatthias Ringwald             break;
449*3deb3ec6SMatthias Ringwald 
450*3deb3ec6SMatthias Ringwald         case HCI_EVENT_PIN_CODE_REQUEST:
451*3deb3ec6SMatthias Ringwald             // inform about pin code request
452*3deb3ec6SMatthias Ringwald             printf("Pin code request - using '0000'\n\r");
453*3deb3ec6SMatthias Ringwald             bt_flip_addr(event_addr, &packet[2]);
454*3deb3ec6SMatthias Ringwald             hci_send_cmd(&hci_pin_code_request_reply, &event_addr, 4, "0000");
455*3deb3ec6SMatthias Ringwald             break;
456*3deb3ec6SMatthias Ringwald 
457*3deb3ec6SMatthias Ringwald         case RFCOMM_EVENT_INCOMING_CONNECTION:
458*3deb3ec6SMatthias Ringwald             // data: event (8), len(8), address(48), channel (8), rfcomm_cid (16)
459*3deb3ec6SMatthias Ringwald             bt_flip_addr(event_addr, &packet[2]);
460*3deb3ec6SMatthias Ringwald             context = get_hfp_connection_context_for_bd_addr(event_addr);
461*3deb3ec6SMatthias Ringwald 
462*3deb3ec6SMatthias Ringwald             if (!context || context->state != HFP_IDLE) return;
463*3deb3ec6SMatthias Ringwald 
464*3deb3ec6SMatthias Ringwald             context->rfcomm_cid = READ_BT_16(packet, 9);
465*3deb3ec6SMatthias Ringwald             context->state = HFP_W4_RFCOMM_CONNECTED;
466*3deb3ec6SMatthias Ringwald             printf("RFCOMM channel %u requested for %s\n", context->rfcomm_cid, bd_addr_to_str(context->remote_addr));
467*3deb3ec6SMatthias Ringwald             rfcomm_accept_connection_internal(context->rfcomm_cid);
468*3deb3ec6SMatthias Ringwald             break;
469*3deb3ec6SMatthias Ringwald 
470*3deb3ec6SMatthias Ringwald         case RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE:
471*3deb3ec6SMatthias Ringwald             // data: event(8), len(8), status (8), address (48), handle(16), server channel(8), rfcomm_cid(16), max frame size(16)
472*3deb3ec6SMatthias Ringwald             printf("RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE packet_handler type %u, packet[0] %x\n", packet_type, packet[0]);
473*3deb3ec6SMatthias Ringwald             bt_flip_addr(event_addr, &packet[3]);
474*3deb3ec6SMatthias Ringwald             context = get_hfp_connection_context_for_bd_addr(event_addr);
475*3deb3ec6SMatthias Ringwald             if (!context || context->state != HFP_W4_RFCOMM_CONNECTED) return;
476*3deb3ec6SMatthias Ringwald 
477*3deb3ec6SMatthias Ringwald             if (packet[2]) {
478*3deb3ec6SMatthias Ringwald                 hfp_emit_event(callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, packet[2]);
479*3deb3ec6SMatthias Ringwald                 remove_hfp_connection_context(context);
480*3deb3ec6SMatthias Ringwald             } else {
481*3deb3ec6SMatthias Ringwald                 context->con_handle = READ_BT_16(packet, 9);
482*3deb3ec6SMatthias Ringwald                 context->rfcomm_cid = READ_BT_16(packet, 12);
483*3deb3ec6SMatthias Ringwald                 uint16_t mtu = READ_BT_16(packet, 14);
484*3deb3ec6SMatthias Ringwald                 printf("RFCOMM channel open succeeded. Context %p, RFCOMM Channel ID 0x%02x, max frame size %u\n", context, context->rfcomm_cid, mtu);
485*3deb3ec6SMatthias Ringwald 
486*3deb3ec6SMatthias Ringwald                 switch (context->state){
487*3deb3ec6SMatthias Ringwald                     case HFP_W4_RFCOMM_CONNECTED:
488*3deb3ec6SMatthias Ringwald                         context->state = HFP_EXCHANGE_SUPPORTED_FEATURES;
489*3deb3ec6SMatthias Ringwald                         break;
490*3deb3ec6SMatthias Ringwald                     case HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN:
491*3deb3ec6SMatthias Ringwald                         context->state = HFP_W2_DISCONNECT_RFCOMM;
492*3deb3ec6SMatthias Ringwald                         printf("Shutting down RFCOMM.\n");
493*3deb3ec6SMatthias Ringwald                         break;
494*3deb3ec6SMatthias Ringwald                     default:
495*3deb3ec6SMatthias Ringwald                         break;
496*3deb3ec6SMatthias Ringwald                 }
497*3deb3ec6SMatthias Ringwald             }
498*3deb3ec6SMatthias Ringwald             break;
499*3deb3ec6SMatthias Ringwald 
500*3deb3ec6SMatthias Ringwald         case HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE:{
501*3deb3ec6SMatthias Ringwald             int index = 2;
502*3deb3ec6SMatthias Ringwald             uint8_t status = packet[index++];
503*3deb3ec6SMatthias Ringwald             uint16_t sco_handle = READ_BT_16(packet, index);
504*3deb3ec6SMatthias Ringwald             index+=2;
505*3deb3ec6SMatthias Ringwald             bd_addr_t address;
506*3deb3ec6SMatthias Ringwald             memcpy(address, &packet[index], 6);
507*3deb3ec6SMatthias Ringwald             index+=6;
508*3deb3ec6SMatthias Ringwald             uint8_t link_type = packet[index++];
509*3deb3ec6SMatthias Ringwald             uint8_t transmission_interval = packet[index++];  // measured in slots
510*3deb3ec6SMatthias Ringwald             uint8_t retransmission_interval = packet[index++];// measured in slots
511*3deb3ec6SMatthias Ringwald             uint16_t rx_packet_length = READ_BT_16(packet, index); // measured in bytes
512*3deb3ec6SMatthias Ringwald             index+=2;
513*3deb3ec6SMatthias Ringwald             uint16_t tx_packet_length = READ_BT_16(packet, index); // measured in bytes
514*3deb3ec6SMatthias Ringwald             index+=2;
515*3deb3ec6SMatthias Ringwald             uint8_t air_mode = packet[index];
516*3deb3ec6SMatthias Ringwald 
517*3deb3ec6SMatthias Ringwald             if (status != 0){
518*3deb3ec6SMatthias Ringwald                 log_error("(e)SCO Connection is not established, status %u", status);
519*3deb3ec6SMatthias Ringwald                 break;
520*3deb3ec6SMatthias Ringwald             }
521*3deb3ec6SMatthias Ringwald             switch (link_type){
522*3deb3ec6SMatthias Ringwald                 case 0x00:
523*3deb3ec6SMatthias Ringwald                     printf("SCO Connection established. \n");
524*3deb3ec6SMatthias Ringwald                     if (transmission_interval != 0) log_error("SCO Connection: transmission_interval not zero: %d.", transmission_interval);
525*3deb3ec6SMatthias Ringwald                     if (retransmission_interval != 0) log_error("SCO Connection: retransmission_interval not zero: %d.", retransmission_interval);
526*3deb3ec6SMatthias Ringwald                     if (rx_packet_length != 0) log_error("SCO Connection: rx_packet_length not zero: %d.", rx_packet_length);
527*3deb3ec6SMatthias Ringwald                     if (tx_packet_length != 0) log_error("SCO Connection: tx_packet_length not zero: %d.", tx_packet_length);
528*3deb3ec6SMatthias Ringwald                     break;
529*3deb3ec6SMatthias Ringwald                 case 0x02:
530*3deb3ec6SMatthias Ringwald                     printf("eSCO Connection established. \n");
531*3deb3ec6SMatthias Ringwald                     break;
532*3deb3ec6SMatthias Ringwald                 default:
533*3deb3ec6SMatthias Ringwald                     log_error("(e)SCO reserved link_type 0x%2x", link_type);
534*3deb3ec6SMatthias Ringwald                     break;
535*3deb3ec6SMatthias Ringwald             }
536*3deb3ec6SMatthias Ringwald             log_info("sco_handle 0x%2x, address %s, transmission_interval %u slots, retransmission_interval %u slots, "
537*3deb3ec6SMatthias Ringwald                  " rx_packet_length %u bytes, tx_packet_length %u bytes, air_mode 0x%2x (0x02 == CVSD)", sco_handle,
538*3deb3ec6SMatthias Ringwald                  bd_addr_to_str(address), transmission_interval, retransmission_interval, rx_packet_length, tx_packet_length, air_mode);
539*3deb3ec6SMatthias Ringwald 
540*3deb3ec6SMatthias Ringwald             context = get_hfp_connection_context_for_bd_addr(address);
541*3deb3ec6SMatthias Ringwald 
542*3deb3ec6SMatthias Ringwald             if (context->state == HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN){
543*3deb3ec6SMatthias Ringwald                 context->state = HFP_W2_DISCONNECT_SCO;
544*3deb3ec6SMatthias Ringwald                 break;
545*3deb3ec6SMatthias Ringwald             }
546*3deb3ec6SMatthias Ringwald 
547*3deb3ec6SMatthias Ringwald             context->sco_handle = sco_handle;
548*3deb3ec6SMatthias Ringwald             context->state = HFP_AUDIO_CONNECTION_ESTABLISHED;
549*3deb3ec6SMatthias Ringwald             hfp_emit_event(callback, HFP_SUBEVENT_AUDIO_CONNECTION_COMPLETE, packet[2]);
550*3deb3ec6SMatthias Ringwald             break;
551*3deb3ec6SMatthias Ringwald         }
552*3deb3ec6SMatthias Ringwald 
553*3deb3ec6SMatthias Ringwald         case RFCOMM_EVENT_CHANNEL_CLOSED:
554*3deb3ec6SMatthias Ringwald             rfcomm_cid = READ_BT_16(packet,2);
555*3deb3ec6SMatthias Ringwald             context = get_hfp_connection_context_for_rfcomm_cid(rfcomm_cid);
556*3deb3ec6SMatthias Ringwald             if (!context) break;
557*3deb3ec6SMatthias Ringwald             if (context->state == HFP_W4_RFCOMM_DISCONNECTED_AND_RESTART){
558*3deb3ec6SMatthias Ringwald                 context->state = HFP_IDLE;
559*3deb3ec6SMatthias Ringwald                 hfp_establish_service_level_connection(context->remote_addr, context->service_uuid);
560*3deb3ec6SMatthias Ringwald                 break;
561*3deb3ec6SMatthias Ringwald             }
562*3deb3ec6SMatthias Ringwald 
563*3deb3ec6SMatthias Ringwald             hfp_emit_event(callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED, 0);
564*3deb3ec6SMatthias Ringwald             remove_hfp_connection_context(context);
565*3deb3ec6SMatthias Ringwald             break;
566*3deb3ec6SMatthias Ringwald 
567*3deb3ec6SMatthias Ringwald         case HCI_EVENT_DISCONNECTION_COMPLETE:
568*3deb3ec6SMatthias Ringwald             handle = READ_BT_16(packet,3);
569*3deb3ec6SMatthias Ringwald             context = get_hfp_connection_context_for_handle(handle);
570*3deb3ec6SMatthias Ringwald             if (!context) break;
571*3deb3ec6SMatthias Ringwald             if (context->state == HFP_W4_RFCOMM_DISCONNECTED_AND_RESTART){
572*3deb3ec6SMatthias Ringwald                 context->state = HFP_IDLE;
573*3deb3ec6SMatthias Ringwald                 hfp_establish_service_level_connection(context->remote_addr, context->service_uuid);
574*3deb3ec6SMatthias Ringwald                 break;
575*3deb3ec6SMatthias Ringwald             }
576*3deb3ec6SMatthias Ringwald             hfp_emit_event(callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED, packet[2]);
577*3deb3ec6SMatthias Ringwald             remove_hfp_connection_context(context);
578*3deb3ec6SMatthias Ringwald             break;
579*3deb3ec6SMatthias Ringwald 
580*3deb3ec6SMatthias Ringwald         default:
581*3deb3ec6SMatthias Ringwald             break;
582*3deb3ec6SMatthias Ringwald     }
583*3deb3ec6SMatthias Ringwald }
584*3deb3ec6SMatthias Ringwald 
585*3deb3ec6SMatthias Ringwald // translates command string into hfp_command_t CMD and flags to distinguish between CMD=, CMD?, CMD=?
586*3deb3ec6SMatthias Ringwald static void process_command(hfp_connection_t * context){
587*3deb3ec6SMatthias Ringwald     if (context->line_size < 2) return;
588*3deb3ec6SMatthias Ringwald     // printf("process_command %s\n", context->line_buffer);
589*3deb3ec6SMatthias Ringwald     context->command = HFP_CMD_NONE;
590*3deb3ec6SMatthias Ringwald     int offset = 0;
591*3deb3ec6SMatthias Ringwald     int isHandsFree = 1;
592*3deb3ec6SMatthias Ringwald 
593*3deb3ec6SMatthias Ringwald     if (strncmp((char *)context->line_buffer, "AT", 2) == 0){
594*3deb3ec6SMatthias Ringwald         offset = 2;
595*3deb3ec6SMatthias Ringwald         isHandsFree = 0;
596*3deb3ec6SMatthias Ringwald     }
597*3deb3ec6SMatthias Ringwald 
598*3deb3ec6SMatthias Ringwald     if (strncmp((char *)context->line_buffer+offset, HFP_ERROR, strlen(HFP_ERROR)) == 0){
599*3deb3ec6SMatthias Ringwald         context->command = HFP_CMD_ERROR;
600*3deb3ec6SMatthias Ringwald         return;
601*3deb3ec6SMatthias Ringwald     }
602*3deb3ec6SMatthias Ringwald 
603*3deb3ec6SMatthias Ringwald     if (isHandsFree && strncmp((char *)context->line_buffer+offset, HFP_OK, strlen(HFP_OK)) == 0){
604*3deb3ec6SMatthias Ringwald         //printf("parsed HFP_CMD_OK \n");
605*3deb3ec6SMatthias Ringwald         context->command = HFP_CMD_OK;
606*3deb3ec6SMatthias Ringwald         return;
607*3deb3ec6SMatthias Ringwald     }
608*3deb3ec6SMatthias Ringwald 
609*3deb3ec6SMatthias Ringwald     if (strncmp((char *)context->line_buffer+offset, HFP_SUPPORTED_FEATURES, strlen(HFP_SUPPORTED_FEATURES)) == 0){
610*3deb3ec6SMatthias Ringwald         context->command = HFP_CMD_SUPPORTED_FEATURES;
611*3deb3ec6SMatthias Ringwald         return;
612*3deb3ec6SMatthias Ringwald     }
613*3deb3ec6SMatthias Ringwald 
614*3deb3ec6SMatthias Ringwald     if (strncmp((char *)context->line_buffer+offset, HFP_INDICATOR, strlen(HFP_INDICATOR)) == 0){
615*3deb3ec6SMatthias Ringwald         //printf("parsed HFP_INDICATOR \n");
616*3deb3ec6SMatthias Ringwald         context->command = HFP_CMD_INDICATOR;
617*3deb3ec6SMatthias Ringwald         if (isHandsFree) return;
618*3deb3ec6SMatthias Ringwald 
619*3deb3ec6SMatthias Ringwald         if (strncmp((char *)context->line_buffer+strlen(HFP_INDICATOR)+offset, "?", 1) == 0){
620*3deb3ec6SMatthias Ringwald             context->retrieve_ag_indicators_status = 1;
621*3deb3ec6SMatthias Ringwald             context->retrieve_ag_indicators = 0;
622*3deb3ec6SMatthias Ringwald         } else {
623*3deb3ec6SMatthias Ringwald             context->retrieve_ag_indicators = 1;
624*3deb3ec6SMatthias Ringwald             context->retrieve_ag_indicators_status = 0;
625*3deb3ec6SMatthias Ringwald         }
626*3deb3ec6SMatthias Ringwald         return;
627*3deb3ec6SMatthias Ringwald     }
628*3deb3ec6SMatthias Ringwald 
629*3deb3ec6SMatthias Ringwald     if (strncmp((char *)context->line_buffer+offset, HFP_AVAILABLE_CODECS, strlen(HFP_AVAILABLE_CODECS)) == 0){
630*3deb3ec6SMatthias Ringwald         context->command = HFP_CMD_AVAILABLE_CODECS;
631*3deb3ec6SMatthias Ringwald         context->notify_ag_on_new_codecs = 1;
632*3deb3ec6SMatthias Ringwald         return;
633*3deb3ec6SMatthias Ringwald     }
634*3deb3ec6SMatthias Ringwald 
635*3deb3ec6SMatthias Ringwald     if (strncmp((char *)context->line_buffer+offset, HFP_ENABLE_STATUS_UPDATE_FOR_AG_INDICATORS, strlen(HFP_ENABLE_STATUS_UPDATE_FOR_AG_INDICATORS)) == 0){
636*3deb3ec6SMatthias Ringwald         context->command = HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE;
637*3deb3ec6SMatthias Ringwald         return;
638*3deb3ec6SMatthias Ringwald     }
639*3deb3ec6SMatthias Ringwald 
640*3deb3ec6SMatthias Ringwald     if (strncmp((char *)context->line_buffer+offset, HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES, strlen(HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES)) == 0){
641*3deb3ec6SMatthias Ringwald         context->command = HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES;
642*3deb3ec6SMatthias Ringwald         return;
643*3deb3ec6SMatthias Ringwald     }
644*3deb3ec6SMatthias Ringwald 
645*3deb3ec6SMatthias Ringwald     if (strncmp((char *)context->line_buffer+offset, HFP_GENERIC_STATUS_INDICATOR, strlen(HFP_GENERIC_STATUS_INDICATOR)) == 0){
646*3deb3ec6SMatthias Ringwald         context->command = HFP_CMD_GENERIC_STATUS_INDICATOR;
647*3deb3ec6SMatthias Ringwald         if (isHandsFree) return;
648*3deb3ec6SMatthias Ringwald 
649*3deb3ec6SMatthias Ringwald         if (strncmp((char *)context->line_buffer+strlen(HFP_GENERIC_STATUS_INDICATOR)+offset, "=?", 2) == 0){
650*3deb3ec6SMatthias Ringwald             context->list_generic_status_indicators = 0;
651*3deb3ec6SMatthias Ringwald             context->retrieve_generic_status_indicators = 1;
652*3deb3ec6SMatthias Ringwald             context->retrieve_generic_status_indicators_state = 0;
653*3deb3ec6SMatthias Ringwald         } else if (strncmp((char *)context->line_buffer+strlen(HFP_GENERIC_STATUS_INDICATOR)+offset, "=", 1) == 0){
654*3deb3ec6SMatthias Ringwald             context->list_generic_status_indicators = 1;
655*3deb3ec6SMatthias Ringwald             context->retrieve_generic_status_indicators = 0;
656*3deb3ec6SMatthias Ringwald             context->retrieve_generic_status_indicators_state = 0;
657*3deb3ec6SMatthias Ringwald         } else {
658*3deb3ec6SMatthias Ringwald             context->list_generic_status_indicators = 0;
659*3deb3ec6SMatthias Ringwald             context->retrieve_generic_status_indicators = 0;
660*3deb3ec6SMatthias Ringwald             context->retrieve_generic_status_indicators_state = 1;
661*3deb3ec6SMatthias Ringwald         }
662*3deb3ec6SMatthias Ringwald         return;
663*3deb3ec6SMatthias Ringwald     }
664*3deb3ec6SMatthias Ringwald 
665*3deb3ec6SMatthias Ringwald     if (strncmp((char *)context->line_buffer+offset, HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS, strlen(HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS)) == 0){
666*3deb3ec6SMatthias Ringwald         context->command = HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE;
667*3deb3ec6SMatthias Ringwald         return;
668*3deb3ec6SMatthias Ringwald     }
669*3deb3ec6SMatthias Ringwald 
670*3deb3ec6SMatthias Ringwald 
671*3deb3ec6SMatthias Ringwald     if (strncmp((char *)context->line_buffer+offset, HFP_QUERY_OPERATOR_SELECTION, strlen(HFP_QUERY_OPERATOR_SELECTION)) == 0){
672*3deb3ec6SMatthias Ringwald         context->command = HFP_CMD_QUERY_OPERATOR_SELECTION;
673*3deb3ec6SMatthias Ringwald         context->operator_name = 1;
674*3deb3ec6SMatthias Ringwald         context->operator_name_format = 0;
675*3deb3ec6SMatthias Ringwald         if (isHandsFree) return;
676*3deb3ec6SMatthias Ringwald 
677*3deb3ec6SMatthias Ringwald         context->operator_name = 0;
678*3deb3ec6SMatthias Ringwald         if (strncmp((char *)context->line_buffer+strlen(HFP_QUERY_OPERATOR_SELECTION)+offset, "=", 1) == 0){
679*3deb3ec6SMatthias Ringwald             context->operator_name_format = 1;
680*3deb3ec6SMatthias Ringwald         }
681*3deb3ec6SMatthias Ringwald         return;
682*3deb3ec6SMatthias Ringwald     }
683*3deb3ec6SMatthias Ringwald 
684*3deb3ec6SMatthias Ringwald     if (strncmp((char *)context->line_buffer+offset, HFP_TRANSFER_AG_INDICATOR_STATUS, strlen(HFP_TRANSFER_AG_INDICATOR_STATUS)) == 0){
685*3deb3ec6SMatthias Ringwald         context->command = HFP_CMD_TRANSFER_AG_INDICATOR_STATUS;
686*3deb3ec6SMatthias Ringwald         return;
687*3deb3ec6SMatthias Ringwald     }
688*3deb3ec6SMatthias Ringwald 
689*3deb3ec6SMatthias Ringwald     if (isHandsFree && strncmp((char *)context->line_buffer+offset, HFP_EXTENDED_AUDIO_GATEWAY_ERROR, strlen(HFP_EXTENDED_AUDIO_GATEWAY_ERROR)) == 0){
690*3deb3ec6SMatthias Ringwald         context->command = HFP_CMD_EXTENDED_AUDIO_GATEWAY_ERROR;
691*3deb3ec6SMatthias Ringwald         return;
692*3deb3ec6SMatthias Ringwald     }
693*3deb3ec6SMatthias Ringwald 
694*3deb3ec6SMatthias Ringwald     if (!isHandsFree && strncmp((char *)context->line_buffer+offset, HFP_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR, strlen(HFP_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR)) == 0){
695*3deb3ec6SMatthias Ringwald         context->command = HFP_CMD_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR;
696*3deb3ec6SMatthias Ringwald         return;
697*3deb3ec6SMatthias Ringwald     }
698*3deb3ec6SMatthias Ringwald 
699*3deb3ec6SMatthias Ringwald     if (strncmp((char *)context->line_buffer+offset, HFP_TRIGGER_CODEC_CONNECTION_SETUP, strlen(HFP_TRIGGER_CODEC_CONNECTION_SETUP)) == 0){
700*3deb3ec6SMatthias Ringwald         context->command = HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP;
701*3deb3ec6SMatthias Ringwald         // printf("HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP update command\n");
702*3deb3ec6SMatthias Ringwald         if (isHandsFree){
703*3deb3ec6SMatthias Ringwald             context->hf_trigger_codec_connection_setup = 1;
704*3deb3ec6SMatthias Ringwald             printf("update command: hf_trigger_codec_connection_setup = 1\n");
705*3deb3ec6SMatthias Ringwald         } else {
706*3deb3ec6SMatthias Ringwald             context->hf_trigger_codec_connection_setup = 1;
707*3deb3ec6SMatthias Ringwald             printf("update command: hf_trigger_codec_connection_setup = 1\n");
708*3deb3ec6SMatthias Ringwald         }
709*3deb3ec6SMatthias Ringwald         return;
710*3deb3ec6SMatthias Ringwald     }
711*3deb3ec6SMatthias Ringwald 
712*3deb3ec6SMatthias Ringwald     if (strncmp((char *)context->line_buffer+offset, HFP_CONFIRM_COMMON_CODEC, strlen(HFP_CONFIRM_COMMON_CODEC)) == 0){
713*3deb3ec6SMatthias Ringwald         if (!isHandsFree){
714*3deb3ec6SMatthias Ringwald             context->command = HFP_CMD_HF_CONFIRMED_CODEC;
715*3deb3ec6SMatthias Ringwald         } else {
716*3deb3ec6SMatthias Ringwald             context->command = HFP_CMD_AG_SUGGESTED_CODEC;
717*3deb3ec6SMatthias Ringwald         }
718*3deb3ec6SMatthias Ringwald         return;
719*3deb3ec6SMatthias Ringwald     }
720*3deb3ec6SMatthias Ringwald 
721*3deb3ec6SMatthias Ringwald     if (strncmp((char *)context->line_buffer+offset, "NOP", 3) == 0) return;
722*3deb3ec6SMatthias Ringwald 
723*3deb3ec6SMatthias Ringwald     printf(" process unknown command 3 %s \n", context->line_buffer);
724*3deb3ec6SMatthias Ringwald }
725*3deb3ec6SMatthias Ringwald 
726*3deb3ec6SMatthias Ringwald #if 0
727*3deb3ec6SMatthias Ringwald uint32_t fromBinary(char *s) {
728*3deb3ec6SMatthias Ringwald     return (uint32_t) strtol(s, NULL, 2);
729*3deb3ec6SMatthias Ringwald }
730*3deb3ec6SMatthias Ringwald #endif
731*3deb3ec6SMatthias Ringwald 
732*3deb3ec6SMatthias Ringwald static void hfp_parser_store_byte(hfp_connection_t * context, uint8_t byte){
733*3deb3ec6SMatthias Ringwald     // TODO: add limit
734*3deb3ec6SMatthias Ringwald     context->line_buffer[context->line_size++] = byte;
735*3deb3ec6SMatthias Ringwald     context->line_buffer[context->line_size] = 0;
736*3deb3ec6SMatthias Ringwald }
737*3deb3ec6SMatthias Ringwald static int hfp_parser_is_buffer_empty(hfp_connection_t * context){
738*3deb3ec6SMatthias Ringwald     return context->line_size == 0;
739*3deb3ec6SMatthias Ringwald }
740*3deb3ec6SMatthias Ringwald 
741*3deb3ec6SMatthias Ringwald static int hfp_parser_is_end_of_line(uint8_t byte){
742*3deb3ec6SMatthias Ringwald     return byte == '\n' || byte == '\r';
743*3deb3ec6SMatthias Ringwald }
744*3deb3ec6SMatthias Ringwald 
745*3deb3ec6SMatthias Ringwald static int hfp_parser_is_end_of_header(uint8_t byte){
746*3deb3ec6SMatthias Ringwald     return hfp_parser_is_end_of_line(byte) || byte == ':' || byte == '?';
747*3deb3ec6SMatthias Ringwald }
748*3deb3ec6SMatthias Ringwald 
749*3deb3ec6SMatthias Ringwald static int hfp_parser_found_separator(hfp_connection_t * context, uint8_t byte){
750*3deb3ec6SMatthias Ringwald     if (context->keep_separator == 1) return 1;
751*3deb3ec6SMatthias Ringwald 
752*3deb3ec6SMatthias Ringwald     int found_separator =   byte == ',' || byte == '\n'|| byte == '\r'||
753*3deb3ec6SMatthias Ringwald                             byte == ')' || byte == '(' || byte == ':' ||
754*3deb3ec6SMatthias Ringwald                             byte == '-' || byte == '"' ||  byte == '?'|| byte == '=';
755*3deb3ec6SMatthias Ringwald     return found_separator;
756*3deb3ec6SMatthias Ringwald }
757*3deb3ec6SMatthias Ringwald 
758*3deb3ec6SMatthias Ringwald static void hfp_parser_next_state(hfp_connection_t * context, uint8_t byte){
759*3deb3ec6SMatthias Ringwald     context->line_size = 0;
760*3deb3ec6SMatthias Ringwald     if (hfp_parser_is_end_of_line(byte)){
761*3deb3ec6SMatthias Ringwald         context->parser_item_index = 0;
762*3deb3ec6SMatthias Ringwald         context->parser_state = HFP_PARSER_CMD_HEADER;
763*3deb3ec6SMatthias Ringwald         return;
764*3deb3ec6SMatthias Ringwald     }
765*3deb3ec6SMatthias Ringwald     switch (context->parser_state){
766*3deb3ec6SMatthias Ringwald         case HFP_PARSER_CMD_HEADER:
767*3deb3ec6SMatthias Ringwald             context->parser_state = HFP_PARSER_CMD_SEQUENCE;
768*3deb3ec6SMatthias Ringwald             if (context->keep_separator == 1){
769*3deb3ec6SMatthias Ringwald                 hfp_parser_store_byte(context, byte);
770*3deb3ec6SMatthias Ringwald                 context->keep_separator = 0;
771*3deb3ec6SMatthias Ringwald             }
772*3deb3ec6SMatthias Ringwald             break;
773*3deb3ec6SMatthias Ringwald         case HFP_PARSER_CMD_SEQUENCE:
774*3deb3ec6SMatthias Ringwald             switch (context->command){
775*3deb3ec6SMatthias Ringwald                 case HFP_CMD_TRANSFER_AG_INDICATOR_STATUS:
776*3deb3ec6SMatthias Ringwald                 case HFP_CMD_QUERY_OPERATOR_SELECTION:
777*3deb3ec6SMatthias Ringwald                     context->parser_state = HFP_PARSER_SECOND_ITEM;
778*3deb3ec6SMatthias Ringwald                     break;
779*3deb3ec6SMatthias Ringwald                 case HFP_CMD_INDICATOR:
780*3deb3ec6SMatthias Ringwald                     if (context->retrieve_ag_indicators == 1){
781*3deb3ec6SMatthias Ringwald                         context->parser_state = HFP_PARSER_SECOND_ITEM;
782*3deb3ec6SMatthias Ringwald                         break;
783*3deb3ec6SMatthias Ringwald                     }
784*3deb3ec6SMatthias Ringwald                     break;
785*3deb3ec6SMatthias Ringwald                 case HFP_CMD_GENERIC_STATUS_INDICATOR:
786*3deb3ec6SMatthias Ringwald                     if (context->retrieve_generic_status_indicators_state == 1){
787*3deb3ec6SMatthias Ringwald                         context->parser_state = HFP_PARSER_SECOND_ITEM;
788*3deb3ec6SMatthias Ringwald                         break;
789*3deb3ec6SMatthias Ringwald                     }
790*3deb3ec6SMatthias Ringwald                     break;
791*3deb3ec6SMatthias Ringwald                 default:
792*3deb3ec6SMatthias Ringwald                     break;
793*3deb3ec6SMatthias Ringwald             }
794*3deb3ec6SMatthias Ringwald             break;
795*3deb3ec6SMatthias Ringwald         case HFP_PARSER_SECOND_ITEM:
796*3deb3ec6SMatthias Ringwald             context->parser_state = HFP_PARSER_THIRD_ITEM;
797*3deb3ec6SMatthias Ringwald             break;
798*3deb3ec6SMatthias Ringwald         case HFP_PARSER_THIRD_ITEM:
799*3deb3ec6SMatthias Ringwald             if (context->command == HFP_CMD_INDICATOR && context->retrieve_ag_indicators){
800*3deb3ec6SMatthias Ringwald                 context->parser_state = HFP_PARSER_CMD_SEQUENCE;
801*3deb3ec6SMatthias Ringwald                 break;
802*3deb3ec6SMatthias Ringwald             }
803*3deb3ec6SMatthias Ringwald             context->parser_state = HFP_PARSER_CMD_HEADER;
804*3deb3ec6SMatthias Ringwald             break;
805*3deb3ec6SMatthias Ringwald     }
806*3deb3ec6SMatthias Ringwald }
807*3deb3ec6SMatthias Ringwald 
808*3deb3ec6SMatthias Ringwald void hfp_parse(hfp_connection_t * context, uint8_t byte){
809*3deb3ec6SMatthias Ringwald     int value;
810*3deb3ec6SMatthias Ringwald 
811*3deb3ec6SMatthias Ringwald     // TODO: handle space inside word
812*3deb3ec6SMatthias Ringwald     if (byte == ' ' && context->parser_state > HFP_PARSER_CMD_HEADER) return;
813*3deb3ec6SMatthias Ringwald 
814*3deb3ec6SMatthias Ringwald     if (!hfp_parser_found_separator(context, byte)){
815*3deb3ec6SMatthias Ringwald         hfp_parser_store_byte(context, byte);
816*3deb3ec6SMatthias Ringwald         return;
817*3deb3ec6SMatthias Ringwald     }
818*3deb3ec6SMatthias Ringwald     if (hfp_parser_is_end_of_line(byte)) {
819*3deb3ec6SMatthias Ringwald         if (hfp_parser_is_buffer_empty(context)){
820*3deb3ec6SMatthias Ringwald             context->parser_state = HFP_PARSER_CMD_HEADER;
821*3deb3ec6SMatthias Ringwald         }
822*3deb3ec6SMatthias Ringwald     }
823*3deb3ec6SMatthias Ringwald     if (hfp_parser_is_buffer_empty(context)) return;
824*3deb3ec6SMatthias Ringwald 
825*3deb3ec6SMatthias Ringwald 
826*3deb3ec6SMatthias Ringwald     switch (context->parser_state){
827*3deb3ec6SMatthias Ringwald         case HFP_PARSER_CMD_HEADER: // header
828*3deb3ec6SMatthias Ringwald             if (byte == '='){
829*3deb3ec6SMatthias Ringwald                 context->keep_separator = 1;
830*3deb3ec6SMatthias Ringwald                 hfp_parser_store_byte(context, byte);
831*3deb3ec6SMatthias Ringwald                 return;
832*3deb3ec6SMatthias Ringwald             }
833*3deb3ec6SMatthias Ringwald 
834*3deb3ec6SMatthias Ringwald             if (byte == '?'){
835*3deb3ec6SMatthias Ringwald                 context->keep_separator = 0;
836*3deb3ec6SMatthias Ringwald                 hfp_parser_store_byte(context, byte);
837*3deb3ec6SMatthias Ringwald                 return;
838*3deb3ec6SMatthias Ringwald             }
839*3deb3ec6SMatthias Ringwald             // printf(" parse header 2 %s, keep separator $ %d\n", context->line_buffer, context->keep_separator);
840*3deb3ec6SMatthias Ringwald             if (hfp_parser_is_end_of_header(byte) || context->keep_separator == 1){
841*3deb3ec6SMatthias Ringwald                 // printf(" parse header 3 %s, keep separator $ %d\n", context->line_buffer, context->keep_separator);
842*3deb3ec6SMatthias Ringwald                 process_command(context);
843*3deb3ec6SMatthias Ringwald             }
844*3deb3ec6SMatthias Ringwald             break;
845*3deb3ec6SMatthias Ringwald 
846*3deb3ec6SMatthias Ringwald         case HFP_PARSER_CMD_SEQUENCE: // parse comma separated sequence, ignore breacktes
847*3deb3ec6SMatthias Ringwald             switch (context->command){
848*3deb3ec6SMatthias Ringwald                 case HFP_CMD_HF_CONFIRMED_CODEC:
849*3deb3ec6SMatthias Ringwald                     context->codec_confirmed = atoi((char*)context->line_buffer);
850*3deb3ec6SMatthias Ringwald                     log_info("hfp parse HFP_CMD_HF_CONFIRMED_CODEC %d\n", context->codec_confirmed);
851*3deb3ec6SMatthias Ringwald                     break;
852*3deb3ec6SMatthias Ringwald                 case HFP_CMD_AG_SUGGESTED_CODEC:
853*3deb3ec6SMatthias Ringwald                     context->suggested_codec = atoi((char*)context->line_buffer);
854*3deb3ec6SMatthias Ringwald                     log_info("hfp parse HFP_CMD_AG_SUGGESTED_CODEC %d\n", context->suggested_codec);
855*3deb3ec6SMatthias Ringwald                     break;
856*3deb3ec6SMatthias Ringwald                 case HFP_CMD_SUPPORTED_FEATURES:
857*3deb3ec6SMatthias Ringwald                     context->remote_supported_features = atoi((char*)context->line_buffer);
858*3deb3ec6SMatthias Ringwald                     log_info("Parsed supported feature %d\n", context->remote_supported_features);
859*3deb3ec6SMatthias Ringwald                     break;
860*3deb3ec6SMatthias Ringwald                 case HFP_CMD_AVAILABLE_CODECS:
861*3deb3ec6SMatthias Ringwald                     log_info("Parsed codec %s\n", context->line_buffer);
862*3deb3ec6SMatthias Ringwald                     context->remote_codecs[context->parser_item_index] = (uint16_t)atoi((char*)context->line_buffer);
863*3deb3ec6SMatthias Ringwald                     context->parser_item_index++;
864*3deb3ec6SMatthias Ringwald                     context->remote_codecs_nr = context->parser_item_index;
865*3deb3ec6SMatthias Ringwald                     break;
866*3deb3ec6SMatthias Ringwald                 case HFP_CMD_INDICATOR:
867*3deb3ec6SMatthias Ringwald                     if (context->retrieve_ag_indicators == 1){
868*3deb3ec6SMatthias Ringwald                         strcpy((char *)context->ag_indicators[context->parser_item_index].name,  (char *)context->line_buffer);
869*3deb3ec6SMatthias Ringwald                         context->ag_indicators[context->parser_item_index].index = context->parser_item_index+1;
870*3deb3ec6SMatthias Ringwald                         log_info("Indicator %d: %s (", context->ag_indicators_nr+1, context->line_buffer);
871*3deb3ec6SMatthias Ringwald                     }
872*3deb3ec6SMatthias Ringwald 
873*3deb3ec6SMatthias Ringwald                     if (context->retrieve_ag_indicators_status == 1){
874*3deb3ec6SMatthias Ringwald                         log_info("Parsed Indicator %d with status: %s\n", context->parser_item_index+1, context->line_buffer);
875*3deb3ec6SMatthias Ringwald                         context->ag_indicators[context->parser_item_index].status = atoi((char *) context->line_buffer);
876*3deb3ec6SMatthias Ringwald                         context->parser_item_index++;
877*3deb3ec6SMatthias Ringwald                         break;
878*3deb3ec6SMatthias Ringwald                     }
879*3deb3ec6SMatthias Ringwald                     break;
880*3deb3ec6SMatthias Ringwald                 case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE:
881*3deb3ec6SMatthias Ringwald                     context->parser_item_index++;
882*3deb3ec6SMatthias Ringwald                     if (context->parser_item_index != 4) break;
883*3deb3ec6SMatthias Ringwald                     log_info("Parsed Enable indicators: %s\n", context->line_buffer);
884*3deb3ec6SMatthias Ringwald                     value = atoi((char *)&context->line_buffer[0]);
885*3deb3ec6SMatthias Ringwald                     context->enable_status_update_for_ag_indicators = (uint8_t) value;
886*3deb3ec6SMatthias Ringwald                     break;
887*3deb3ec6SMatthias Ringwald                 case HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES:
888*3deb3ec6SMatthias Ringwald                     log_info("Parsed Support call hold: %s\n", context->line_buffer);
889*3deb3ec6SMatthias Ringwald                     if (context->line_size > 2 ) break;
890*3deb3ec6SMatthias Ringwald                     strcpy((char *)context->remote_call_services[context->remote_call_services_nr].name,  (char *)context->line_buffer);
891*3deb3ec6SMatthias Ringwald                     context->remote_call_services_nr++;
892*3deb3ec6SMatthias Ringwald                     break;
893*3deb3ec6SMatthias Ringwald                 case HFP_CMD_GENERIC_STATUS_INDICATOR:
894*3deb3ec6SMatthias Ringwald                     log_info("parser HFP_CMD_GENERIC_STATUS_INDICATOR 1 (%d, %d, %d)\n",
895*3deb3ec6SMatthias Ringwald                             context->list_generic_status_indicators,
896*3deb3ec6SMatthias Ringwald                             context->retrieve_generic_status_indicators,
897*3deb3ec6SMatthias Ringwald                             context->retrieve_generic_status_indicators_state);
898*3deb3ec6SMatthias Ringwald                     if (context->retrieve_generic_status_indicators == 1 || context->list_generic_status_indicators == 1){
899*3deb3ec6SMatthias Ringwald                         log_info("Parsed Generic status indicator: %s\n", context->line_buffer);
900*3deb3ec6SMatthias Ringwald                         context->generic_status_indicators[context->parser_item_index].uuid = (uint16_t)atoi((char*)context->line_buffer);
901*3deb3ec6SMatthias Ringwald                         context->parser_item_index++;
902*3deb3ec6SMatthias Ringwald                         context->generic_status_indicators_nr = context->parser_item_index;
903*3deb3ec6SMatthias Ringwald                         break;
904*3deb3ec6SMatthias Ringwald                     }
905*3deb3ec6SMatthias Ringwald                     log_info("parser HFP_CMD_GENERIC_STATUS_INDICATOR 2\n");
906*3deb3ec6SMatthias Ringwald                     if (context->retrieve_generic_status_indicators_state == 1){
907*3deb3ec6SMatthias Ringwald                         // HF parses inital AG gen. ind. state
908*3deb3ec6SMatthias Ringwald                         log_info("Parsed List generic status indicator %s state: ", context->line_buffer);
909*3deb3ec6SMatthias Ringwald                         context->parser_item_index = (uint8_t)atoi((char*)context->line_buffer);
910*3deb3ec6SMatthias Ringwald                         break;
911*3deb3ec6SMatthias Ringwald                     }
912*3deb3ec6SMatthias Ringwald                     break;
913*3deb3ec6SMatthias Ringwald 
914*3deb3ec6SMatthias Ringwald                 case HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE:
915*3deb3ec6SMatthias Ringwald                     // AG parses new gen. ind. state
916*3deb3ec6SMatthias Ringwald                     log_info("Parsed Enable ag indicator state: %s\n", context->line_buffer);
917*3deb3ec6SMatthias Ringwald                     value = atoi((char *)&context->line_buffer[0]);
918*3deb3ec6SMatthias Ringwald                     if (!context->ag_indicators[context->parser_item_index].mandatory){
919*3deb3ec6SMatthias Ringwald                         context->ag_indicators[context->parser_item_index].enabled = value;
920*3deb3ec6SMatthias Ringwald                     }
921*3deb3ec6SMatthias Ringwald                     context->parser_item_index++;
922*3deb3ec6SMatthias Ringwald                     break;
923*3deb3ec6SMatthias Ringwald                 case HFP_CMD_TRANSFER_AG_INDICATOR_STATUS:
924*3deb3ec6SMatthias Ringwald                     // indicators are indexed starting with 1
925*3deb3ec6SMatthias Ringwald                     context->parser_item_index = atoi((char *)&context->line_buffer[0]) - 1;
926*3deb3ec6SMatthias Ringwald                     log_info("Parsed status of the AG indicator %d, status ", context->parser_item_index);
927*3deb3ec6SMatthias Ringwald                     break;
928*3deb3ec6SMatthias Ringwald                 case HFP_CMD_QUERY_OPERATOR_SELECTION:
929*3deb3ec6SMatthias Ringwald                     if (context->operator_name_format == 1){
930*3deb3ec6SMatthias Ringwald                         if (context->line_buffer[0] == '3'){
931*3deb3ec6SMatthias Ringwald                             log_info("Parsed Set network operator format : %s, ", context->line_buffer);
932*3deb3ec6SMatthias Ringwald                             break;
933*3deb3ec6SMatthias Ringwald                         }
934*3deb3ec6SMatthias Ringwald                         // TODO emit ERROR, wrong format
935*3deb3ec6SMatthias Ringwald                         log_info("ERROR Set network operator format: index %s not supported\n", context->line_buffer);
936*3deb3ec6SMatthias Ringwald                         break;
937*3deb3ec6SMatthias Ringwald                     }
938*3deb3ec6SMatthias Ringwald 
939*3deb3ec6SMatthias Ringwald                     if (context->operator_name == 1) {
940*3deb3ec6SMatthias Ringwald                         context->network_operator.mode = atoi((char *)&context->line_buffer[0]);
941*3deb3ec6SMatthias Ringwald                         log_info("Parsed network operator mode: %d, ", context->network_operator.mode);
942*3deb3ec6SMatthias Ringwald                         break;
943*3deb3ec6SMatthias Ringwald                     }
944*3deb3ec6SMatthias Ringwald                     break;
945*3deb3ec6SMatthias Ringwald                 case HFP_CMD_ERROR:
946*3deb3ec6SMatthias Ringwald                     break;
947*3deb3ec6SMatthias Ringwald                 case HFP_CMD_EXTENDED_AUDIO_GATEWAY_ERROR:
948*3deb3ec6SMatthias Ringwald                     context->extended_audio_gateway_error = (uint8_t)atoi((char*)context->line_buffer);
949*3deb3ec6SMatthias Ringwald                     break;
950*3deb3ec6SMatthias Ringwald                 case HFP_CMD_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR:
951*3deb3ec6SMatthias Ringwald                     context->enable_extended_audio_gateway_error_report = (uint8_t)atoi((char*)context->line_buffer);
952*3deb3ec6SMatthias Ringwald                     context->send_ok = 1;
953*3deb3ec6SMatthias Ringwald                     context->extended_audio_gateway_error = 0;
954*3deb3ec6SMatthias Ringwald                     break;
955*3deb3ec6SMatthias Ringwald                 default:
956*3deb3ec6SMatthias Ringwald                     break;
957*3deb3ec6SMatthias Ringwald             }
958*3deb3ec6SMatthias Ringwald             break;
959*3deb3ec6SMatthias Ringwald 
960*3deb3ec6SMatthias Ringwald         case HFP_PARSER_SECOND_ITEM:
961*3deb3ec6SMatthias Ringwald             switch (context->command){
962*3deb3ec6SMatthias Ringwald                 case HFP_CMD_QUERY_OPERATOR_SELECTION:
963*3deb3ec6SMatthias Ringwald                     if (context->operator_name_format == 1) {
964*3deb3ec6SMatthias Ringwald                         log_info("format %s \n", context->line_buffer);
965*3deb3ec6SMatthias Ringwald                         context->network_operator.format =  atoi((char *)&context->line_buffer[0]);
966*3deb3ec6SMatthias Ringwald                         break;
967*3deb3ec6SMatthias Ringwald                     }
968*3deb3ec6SMatthias Ringwald                     if (context->operator_name == 1){
969*3deb3ec6SMatthias Ringwald                         log_info("format %s, ", context->line_buffer);
970*3deb3ec6SMatthias Ringwald                         context->network_operator.format =  atoi((char *)&context->line_buffer[0]);
971*3deb3ec6SMatthias Ringwald                     }
972*3deb3ec6SMatthias Ringwald                     break;
973*3deb3ec6SMatthias Ringwald                 case HFP_CMD_GENERIC_STATUS_INDICATOR:
974*3deb3ec6SMatthias Ringwald                     context->generic_status_indicators[context->parser_item_index].state = (uint8_t)atoi((char*)context->line_buffer);
975*3deb3ec6SMatthias Ringwald                     break;
976*3deb3ec6SMatthias Ringwald                 case HFP_CMD_TRANSFER_AG_INDICATOR_STATUS:
977*3deb3ec6SMatthias Ringwald                     context->ag_indicators[context->parser_item_index].status = (uint8_t)atoi((char*)context->line_buffer);
978*3deb3ec6SMatthias Ringwald                     context->ag_indicators[context->parser_item_index].status_changed = 1;
979*3deb3ec6SMatthias Ringwald                     break;
980*3deb3ec6SMatthias Ringwald                 case HFP_CMD_INDICATOR:
981*3deb3ec6SMatthias Ringwald                     if (context->retrieve_ag_indicators == 1){
982*3deb3ec6SMatthias Ringwald                         context->ag_indicators[context->parser_item_index].min_range = atoi((char *)context->line_buffer);
983*3deb3ec6SMatthias Ringwald                         log_info("%s, ", context->line_buffer);
984*3deb3ec6SMatthias Ringwald                     }
985*3deb3ec6SMatthias Ringwald                     break;
986*3deb3ec6SMatthias Ringwald                 default:
987*3deb3ec6SMatthias Ringwald                     break;
988*3deb3ec6SMatthias Ringwald             }
989*3deb3ec6SMatthias Ringwald             break;
990*3deb3ec6SMatthias Ringwald 
991*3deb3ec6SMatthias Ringwald         case HFP_PARSER_THIRD_ITEM:
992*3deb3ec6SMatthias Ringwald              switch (context->command){
993*3deb3ec6SMatthias Ringwald                 case HFP_CMD_QUERY_OPERATOR_SELECTION:
994*3deb3ec6SMatthias Ringwald                     if (context->operator_name == 1){
995*3deb3ec6SMatthias Ringwald                         strcpy(context->network_operator.name, (char *)context->line_buffer);
996*3deb3ec6SMatthias Ringwald                         log_info("name %s\n", context->line_buffer);
997*3deb3ec6SMatthias Ringwald                     }
998*3deb3ec6SMatthias Ringwald                     break;
999*3deb3ec6SMatthias Ringwald                 case HFP_CMD_INDICATOR:
1000*3deb3ec6SMatthias Ringwald                     if (context->retrieve_ag_indicators == 1){
1001*3deb3ec6SMatthias Ringwald                         context->ag_indicators[context->parser_item_index].max_range = atoi((char *)context->line_buffer);
1002*3deb3ec6SMatthias Ringwald                         context->parser_item_index++;
1003*3deb3ec6SMatthias Ringwald                         context->ag_indicators_nr = context->parser_item_index;
1004*3deb3ec6SMatthias Ringwald                         log_info("%s)\n", context->line_buffer);
1005*3deb3ec6SMatthias Ringwald                     }
1006*3deb3ec6SMatthias Ringwald                     break;
1007*3deb3ec6SMatthias Ringwald                 default:
1008*3deb3ec6SMatthias Ringwald                     break;
1009*3deb3ec6SMatthias Ringwald             }
1010*3deb3ec6SMatthias Ringwald             break;
1011*3deb3ec6SMatthias Ringwald     }
1012*3deb3ec6SMatthias Ringwald     hfp_parser_next_state(context, byte);
1013*3deb3ec6SMatthias Ringwald }
1014*3deb3ec6SMatthias Ringwald 
1015*3deb3ec6SMatthias Ringwald void hfp_init(uint16_t rfcomm_channel_nr){
1016*3deb3ec6SMatthias Ringwald     rfcomm_register_service_internal(NULL, rfcomm_channel_nr, 0xffff);
1017*3deb3ec6SMatthias Ringwald     sdp_query_rfcomm_register_callback(handle_query_rfcomm_event, NULL);
1018*3deb3ec6SMatthias Ringwald }
1019*3deb3ec6SMatthias Ringwald 
1020*3deb3ec6SMatthias Ringwald void hfp_establish_service_level_connection(bd_addr_t bd_addr, uint16_t service_uuid){
1021*3deb3ec6SMatthias Ringwald     hfp_connection_t * context = provide_hfp_connection_context_for_bd_addr(bd_addr);
1022*3deb3ec6SMatthias Ringwald     log_info("hfp_connect %s, context %p", bd_addr_to_str(bd_addr), context);
1023*3deb3ec6SMatthias Ringwald 
1024*3deb3ec6SMatthias Ringwald     if (!context) {
1025*3deb3ec6SMatthias Ringwald         log_error("hfp_establish_service_level_connection for addr %s failed", bd_addr_to_str(bd_addr));
1026*3deb3ec6SMatthias Ringwald         return;
1027*3deb3ec6SMatthias Ringwald     }
1028*3deb3ec6SMatthias Ringwald     switch (context->state){
1029*3deb3ec6SMatthias Ringwald         case HFP_W2_DISCONNECT_RFCOMM:
1030*3deb3ec6SMatthias Ringwald             context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
1031*3deb3ec6SMatthias Ringwald             return;
1032*3deb3ec6SMatthias Ringwald         case HFP_W4_RFCOMM_DISCONNECTED:
1033*3deb3ec6SMatthias Ringwald             context->state = HFP_W4_RFCOMM_DISCONNECTED_AND_RESTART;
1034*3deb3ec6SMatthias Ringwald             return;
1035*3deb3ec6SMatthias Ringwald         case HFP_IDLE:
1036*3deb3ec6SMatthias Ringwald             memcpy(context->remote_addr, bd_addr, 6);
1037*3deb3ec6SMatthias Ringwald             context->state = HFP_W4_SDP_QUERY_COMPLETE;
1038*3deb3ec6SMatthias Ringwald             connection_doing_sdp_query = context;
1039*3deb3ec6SMatthias Ringwald             context->service_uuid = service_uuid;
1040*3deb3ec6SMatthias Ringwald             sdp_query_rfcomm_channel_and_name_for_uuid(context->remote_addr, service_uuid);
1041*3deb3ec6SMatthias Ringwald             break;
1042*3deb3ec6SMatthias Ringwald         default:
1043*3deb3ec6SMatthias Ringwald             break;
1044*3deb3ec6SMatthias Ringwald     }
1045*3deb3ec6SMatthias Ringwald }
1046*3deb3ec6SMatthias Ringwald 
1047*3deb3ec6SMatthias Ringwald void hfp_release_service_level_connection(hfp_connection_t * context){
1048*3deb3ec6SMatthias Ringwald     if (!context) return;
1049*3deb3ec6SMatthias Ringwald 
1050*3deb3ec6SMatthias Ringwald     if (context->state < HFP_W4_RFCOMM_CONNECTED){
1051*3deb3ec6SMatthias Ringwald         context->state = HFP_IDLE;
1052*3deb3ec6SMatthias Ringwald         return;
1053*3deb3ec6SMatthias Ringwald     }
1054*3deb3ec6SMatthias Ringwald 
1055*3deb3ec6SMatthias Ringwald     if (context->state == HFP_W4_RFCOMM_CONNECTED){
1056*3deb3ec6SMatthias Ringwald         context->state = HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN;
1057*3deb3ec6SMatthias Ringwald         return;
1058*3deb3ec6SMatthias Ringwald     }
1059*3deb3ec6SMatthias Ringwald 
1060*3deb3ec6SMatthias Ringwald     if (context->state < HFP_CCE_W4_SCO_CONNECTION_ESTABLISHED){
1061*3deb3ec6SMatthias Ringwald         context->state = HFP_W2_DISCONNECT_RFCOMM;
1062*3deb3ec6SMatthias Ringwald         return;
1063*3deb3ec6SMatthias Ringwald     }
1064*3deb3ec6SMatthias Ringwald 
1065*3deb3ec6SMatthias Ringwald     if (context->state < HFP_W4_SCO_DISCONNECTED){
1066*3deb3ec6SMatthias Ringwald         context->state = HFP_W2_DISCONNECT_SCO;
1067*3deb3ec6SMatthias Ringwald         return;
1068*3deb3ec6SMatthias Ringwald     }
1069*3deb3ec6SMatthias Ringwald 
1070*3deb3ec6SMatthias Ringwald     return;
1071*3deb3ec6SMatthias Ringwald }
1072*3deb3ec6SMatthias Ringwald 
1073*3deb3ec6SMatthias Ringwald void hfp_release_audio_connection(hfp_connection_t * connection){
1074*3deb3ec6SMatthias Ringwald     if (!connection) return;
1075*3deb3ec6SMatthias Ringwald     if (connection->state >= HFP_W2_DISCONNECT_SCO) return;
1076*3deb3ec6SMatthias Ringwald     connection->release_audio_connection = 1;
1077*3deb3ec6SMatthias Ringwald }
1078*3deb3ec6SMatthias Ringwald 
1079*3deb3ec6SMatthias Ringwald 
1080