xref: /btstack/test/hfp/hfp_at_parser_test.cpp (revision d2621a777e3ea08a4ddf6f62253312d7306e7df7)
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 #include <stdint.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 
44 #include "CppUTest/TestHarness.h"
45 #include "CppUTest/CommandLineTestRunner.h"
46 
47 #include "btstack_event.h"
48 #include "classic/hfp.h"
49 #include "classic/hfp_hf.h"
50 #include "classic/hfp_ag.h"
51 
52 void hfp_parse(hfp_connection_t * context, uint8_t byte, int isHandsFree);
53 
54 static  hfp_connection_t context;
55 static int hfp_ag_indicators_nr = 7;
56 static hfp_ag_indicator_t hfp_ag_indicators[] = {
57     // index, name, min range, max range, status, mandatory, enabled, status changed
58     {1, "service",   0, 1, 1, 0, 0, 0},
59     {2, "call",      0, 1, 0, 1, 1, 0},
60     {3, "callsetup", 0, 3, 0, 1, 1, 0},
61     {4, "battchg",   0, 5, 3, 0, 0, 0},
62     {5, "signal",    0, 5, 5, 0, 0, 0},
63     {6, "roam",      0, 1, 0, 0, 0, 0},
64     {7, "callheld",  0, 2, 0, 1, 1, 0}
65 };
66 static uint8_t call_status_index = 2;
67 static uint8_t callsetup_status_index = 3;
68 static uint8_t callheld_status_index = 7;
69 
70 
71 static void parse_ag(const char * packet){
72     for (uint16_t pos = 0; pos < strlen(packet); pos++){
73         hfp_parse(&context, packet[pos], 0);
74     }
75 }
76 
77 static void parse_hf(const char * packet){
78     for (uint16_t pos = 0; pos < strlen(packet); pos++){
79         hfp_parse(&context, packet[pos], 1);
80     }
81 }
82 
83 TEST_GROUP(HFPParser){
84     char packet[200];
85     int pos;
86     int offset;
87 
88     void setup(void){
89         hfp_init();
90         memset(&context, 0, sizeof(hfp_connection_t));
91         context.parser_state = HFP_PARSER_CMD_HEADER;
92         context.parser_item_index = 0;
93         context.line_size = 0;
94         context.ag_indicators_nr = 0;
95         context.remote_codecs_nr = 0;
96         context.bnip_number[0] = 0;
97         context.bnip_type = 0;
98         memset(packet,0, sizeof(packet));
99     }
100 
101     void teardown(void){
102         hfp_deinit();
103     }
104 };
105 
106 TEST(HFPParser, HFP_HF_OK){
107     snprintf(packet, sizeof(packet), "\r\n%s\r\n", HFP_OK);
108     parse_hf(packet);
109     CHECK_EQUAL(HFP_CMD_OK, context.command);
110 }
111 
112 TEST(HFPParser, HFP_HF_SUPPORTED_FEATURES){
113     snprintf(packet, sizeof(packet), "\r\n%s:1007\r\n\r\nOK\r\n", HFP_SUPPORTED_FEATURES);
114     parse_hf(packet);
115     CHECK_EQUAL(HFP_CMD_OK, context.command);
116     CHECK_EQUAL(1007, context.remote_supported_features);
117 }
118 
119 TEST(HFPParser, HFP_CMD_INDICATORS_QUERY){
120     snprintf(packet, sizeof(packet), "\r\nAT%s?\r\n", HFP_INDICATOR);
121     parse_ag(packet);
122     CHECK_EQUAL(HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS, context.command);
123 }
124 
125 TEST(HFPParser, HFP_CMD_INDICATORS_RETRIEVE){
126     snprintf(packet, sizeof(packet), "\r\nAT%s=?\r\n", HFP_INDICATOR);
127     parse_ag(packet);
128     CHECK_EQUAL(HFP_CMD_RETRIEVE_AG_INDICATORS, context.command);
129 }
130 
131 TEST(HFPParser, HFP_HF_INDICATORS){
132     offset = 0;
133     offset += snprintf(packet, sizeof(packet), "%s:", HFP_INDICATOR);
134     for (pos = 0; pos < hfp_ag_indicators_nr; pos++){
135     	if (pos != 0) {
136 			packet[offset++] = ',';
137 		}
138     	offset += snprintf(packet+offset, sizeof(packet)-offset, "(\"%s\", (%d, %d)),", hfp_ag_indicators[pos].name, hfp_ag_indicators[pos].min_range, hfp_ag_indicators[pos].max_range);
139     }
140     offset += snprintf(packet+offset, sizeof(packet)-offset, "\r\n\r\nOK\r\n");
141     context.state = HFP_W4_RETRIEVE_INDICATORS;
142 
143     parse_hf(packet);
144     CHECK_EQUAL(HFP_CMD_OK, context.command);
145     CHECK_EQUAL(hfp_ag_indicators_nr, context.ag_indicators_nr);
146     for (pos = 0; pos < hfp_ag_indicators_nr; pos++){
147         CHECK_EQUAL(hfp_ag_indicators[pos].index, context.ag_indicators[pos].index);
148         STRCMP_EQUAL(hfp_ag_indicators[pos].name, context.ag_indicators[pos].name);
149         CHECK_EQUAL(hfp_ag_indicators[pos].min_range, context.ag_indicators[pos].min_range);
150         CHECK_EQUAL(hfp_ag_indicators[pos].max_range, context.ag_indicators[pos].max_range);
151     }
152 }
153 
154 TEST(HFPParser, HFP_HF_INDICATORS_RANGE){
155 	offset = 0;
156 	offset += snprintf(packet, sizeof(packet), "%s:", HFP_INDICATOR);
157 	for (pos = 0; pos < hfp_ag_indicators_nr; pos++){
158 		if (pos != 0) {
159 			packet[offset++] = ',';
160 		}
161 		offset += snprintf(packet+offset, sizeof(packet)-offset, "(\"%s\", (%d-%d)),", hfp_ag_indicators[pos].name, hfp_ag_indicators[pos].min_range, hfp_ag_indicators[pos].max_range);
162 	}
163 	offset += snprintf(packet+offset, sizeof(packet)-offset, "\r\n\r\nOK\r\n");
164 	context.state = HFP_W4_RETRIEVE_INDICATORS;
165 
166 	parse_hf(packet);
167 	CHECK_EQUAL(HFP_CMD_OK, context.command);
168 	CHECK_EQUAL(hfp_ag_indicators_nr, context.ag_indicators_nr);
169 	for (pos = 0; pos < hfp_ag_indicators_nr; pos++){
170 		CHECK_EQUAL(hfp_ag_indicators[pos].index, context.ag_indicators[pos].index);
171 		STRCMP_EQUAL(hfp_ag_indicators[pos].name, context.ag_indicators[pos].name);
172 		CHECK_EQUAL(hfp_ag_indicators[pos].min_range, context.ag_indicators[pos].min_range);
173 		CHECK_EQUAL(hfp_ag_indicators[pos].max_range, context.ag_indicators[pos].max_range);
174 	}
175 }
176 
177 TEST(HFPParser, HFP_HF_INDICATOR_STATUS){
178     // send status
179     offset = 0;
180     offset += snprintf(packet, sizeof(packet), "%s:", HFP_INDICATOR);
181     for (pos = 0; pos < hfp_ag_indicators_nr - 1; pos++){
182         offset += snprintf(packet+offset, sizeof(packet)-offset, "%d,", hfp_ag_indicators[pos].status);
183     }
184     offset += snprintf(packet+offset, sizeof(packet)-offset, "%d\r\n\r\nOK\r\n", hfp_ag_indicators[pos].status);
185 
186     //context.command = HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS;
187     context.state = HFP_W4_RETRIEVE_INDICATORS_STATUS;
188 
189     parse_hf(packet);
190     CHECK_EQUAL(HFP_CMD_OK, context.command);
191     for (pos = 0; pos < hfp_ag_indicators_nr; pos++){
192         CHECK_EQUAL(hfp_ag_indicators[pos].status, context.ag_indicators[pos].status);
193     }
194 }
195 
196 TEST(HFPParser, HFP_HF_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES_TEST){
197     snprintf(packet, sizeof(packet), "\r\nAT%s=?\r\n", HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES);
198     parse_ag(packet);
199     CHECK_EQUAL(HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES, context.command);
200 }
201 
202 TEST(HFPParser, HFP_HF_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES_SET){
203     int action = 1;
204     int call_index = 2;
205     snprintf(packet, sizeof(packet), "\r\nAT%s=%u%u\r\n", HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES, action, call_index);
206     parse_ag(packet);
207     CHECK_EQUAL(HFP_CMD_CALL_HOLD, context.command);
208     CHECK_EQUAL(action, context.ag_call_hold_action);
209     CHECK_EQUAL(call_index, context.call_index);
210 }
211 
212 TEST(HFPParser, HFP_HF_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES){
213     snprintf(packet, sizeof(packet), "\r\n%s:(1,1x,2,2x,3)\r\n\r\nOK\r\n", HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES);
214     parse_hf(packet);
215     CHECK_EQUAL(HFP_CMD_OK, context.command);
216     CHECK_EQUAL(5, context.remote_call_services_index);
217 
218     STRCMP_EQUAL("1", (char*)context.remote_call_services[0].name);
219     STRCMP_EQUAL("1x", (char*)context.remote_call_services[1].name);
220     STRCMP_EQUAL("2", (char*)context.remote_call_services[2].name);
221     STRCMP_EQUAL("2x", (char*)context.remote_call_services[3].name);
222     STRCMP_EQUAL("3", (char*)context.remote_call_services[4].name);
223 }
224 
225 TEST(HFPParser, HFP_GENERIC_STATUS_INDICATOR_TEST){
226     snprintf(packet, sizeof(packet), "\r\nAT%s=?\r\n", HFP_GENERIC_STATUS_INDICATOR);
227     parse_ag(packet);
228     CHECK_EQUAL(HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS, context.command);
229 }
230 
231 TEST(HFPParser, HFP_GENERIC_STATUS_INDICATOR_SET){
232     int param = 1;
233     snprintf(packet, sizeof(packet), "\r\nAT%s=%u\r\n", HFP_GENERIC_STATUS_INDICATOR, param);
234     parse_ag(packet);
235     CHECK_EQUAL(HFP_CMD_LIST_GENERIC_STATUS_INDICATORS, context.command);
236 }
237 
238 TEST(HFPParser, HFP_GENERIC_STATUS_INDICATOR_READ){
239     snprintf(packet, sizeof(packet), "\r\nAT%s?\r\n", HFP_GENERIC_STATUS_INDICATOR);
240     parse_ag(packet);
241     CHECK_EQUAL(HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS_STATE, context.command);
242 }
243 
244 TEST(HFPParser, HFP_HF_GENERIC_STATUS_INDICATOR_STATE){
245     snprintf(packet, sizeof(packet), "\r\n%s:0,1\r\n\r\nOK\r\n", HFP_GENERIC_STATUS_INDICATOR);
246     // context.command = HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS_STATE;
247     context.state = HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS;
248 
249     parse_hf(packet);
250     CHECK_EQUAL(HFP_CMD_OK, context.command);
251     CHECK_EQUAL(1, context.generic_status_indicators[0].state);
252 }
253 
254 TEST(HFPParser, HFP_HF_AG_INDICATOR_STATUS_UPDATE){
255     context.ag_indicators_nr = hfp_ag_indicators_nr;
256     memcpy(context.ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t));
257 
258     uint8_t index = 4;
259     uint8_t status = 5;
260 
261     snprintf(packet, sizeof(packet), "\r\n%s:%d,%d\r\n\r\nOK\r\n", HFP_TRANSFER_AG_INDICATOR_STATUS, index, status);
262 
263     parse_hf(packet);
264     CHECK_EQUAL(HFP_CMD_OK, context.command);
265     CHECK_EQUAL(status, context.ag_indicators[index - 1].status);
266 }
267 
268 TEST(HFPParser, HFP_HF_AG_QUERY_OPERATOR_SELECTION){
269     snprintf(packet, sizeof(packet), "\r\n%s:1,0,\"sunrise\"\r\n\r\nOK\r\n", HFP_QUERY_OPERATOR_SELECTION);
270 
271     context.command = HFP_CMD_QUERY_OPERATOR_SELECTION_NAME;
272 
273     parse_hf(packet);
274     CHECK_EQUAL(HFP_CMD_OK, context.command);
275     CHECK_EQUAL(0, context.operator_name_changed);
276     STRCMP_EQUAL( "sunrise", context.network_operator.name);
277 }
278 
279 TEST(HFPParser, HFP_HF_ERROR){
280     snprintf(packet, sizeof(packet), "\r\n%s\r\n", HFP_ERROR);
281 
282     parse_hf(packet);
283     CHECK_EQUAL(HFP_CMD_ERROR, context.command);
284 }
285 
286 TEST(HFPParser, HFP_HF_EXTENDED_AUDIO_GATEWAY_ERROR){
287     snprintf(packet, sizeof(packet), "\r\n%s:%d\r\n", HFP_EXTENDED_AUDIO_GATEWAY_ERROR, HFP_CME_ERROR_NO_NETWORK_SERVICE);
288 
289     parse_hf(packet);
290     CHECK_EQUAL(HFP_CMD_EXTENDED_AUDIO_GATEWAY_ERROR, context.command);
291     CHECK_EQUAL(HFP_CME_ERROR_NO_NETWORK_SERVICE, context.extended_audio_gateway_error_value);
292 }
293 
294 TEST(HFPParser, HFP_HF_AG_INDICATOR_CALLS_STATUS_UPDATE){
295     context.ag_indicators_nr = hfp_ag_indicators_nr;
296     memcpy(context.ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t));
297     uint8_t status = 1;
298 
299     // call status
300     uint8_t index = call_status_index;
301     snprintf(packet, sizeof(packet), "\r\n%s:%d,%d\r\n\r\nOK\r\n", HFP_TRANSFER_AG_INDICATOR_STATUS, index, status);
302     parse_hf(packet);
303     CHECK_EQUAL(HFP_CMD_OK, context.command);
304     CHECK_EQUAL(status, context.ag_indicators[index - 1].status);
305 
306     // callsetup status
307     index = callsetup_status_index;
308     snprintf(packet, sizeof(packet), "\r\n%s:%d,%d\r\n\r\nOK\r\n", HFP_TRANSFER_AG_INDICATOR_STATUS, index, status);
309     parse_hf(packet);
310     CHECK_EQUAL(HFP_CMD_OK, context.command);
311     CHECK_EQUAL(status, context.ag_indicators[index - 1].status);
312 
313     // callheld status
314     index = callheld_status_index;
315     snprintf(packet, sizeof(packet), "\r\n%s:%d,%d\r\n\r\nOK\r\n", HFP_TRANSFER_AG_INDICATOR_STATUS, index, status);
316     parse_hf(packet);
317     CHECK_EQUAL(HFP_CMD_OK, context.command);
318     CHECK_EQUAL(status, context.ag_indicators[index - 1].status);
319 }
320 
321 TEST(HFPParser, HFP_LIST_CURRENT_CALLS_1){
322     strcpy(packet, "\r\n+CLCC: 1,2,3,4,5,,129\r\n");
323     parse_hf(packet);
324     CHECK_EQUAL(HFP_CMD_LIST_CURRENT_CALLS, context.command);
325     CHECK_EQUAL(1, context.clcc_idx);
326     CHECK_EQUAL(2, context.clcc_dir);
327     CHECK_EQUAL(3, context.clcc_status);
328     CHECK_EQUAL(4, context.clcc_mode);
329     CHECK_EQUAL(5, context.clcc_mpty);
330     STRCMP_EQUAL("", context.bnip_number);
331     CHECK_EQUAL(129, context.bnip_type);
332 }
333 
334 TEST(HFPParser, HFP_LIST_CURRENT_CALLS_2){
335     strcpy(packet, "\r\n+CLCC: 1,2,3,4,5,"",129\r\n");
336     parse_hf(packet);
337     CHECK_EQUAL(HFP_CMD_LIST_CURRENT_CALLS, context.command);
338     CHECK_EQUAL(1, context.clcc_idx);
339     CHECK_EQUAL(2, context.clcc_dir);
340     CHECK_EQUAL(3, context.clcc_status);
341     CHECK_EQUAL(4, context.clcc_mode);
342     CHECK_EQUAL(5, context.clcc_mpty);
343     STRCMP_EQUAL("", context.bnip_number);
344     CHECK_EQUAL(129, context.bnip_type);
345 }
346 
347 TEST(HFPParser, HFP_AG_SUPPORTED_FEATURES){
348     snprintf(packet, sizeof(packet), "\r\nAT%s=159\r\n", HFP_SUPPORTED_FEATURES);
349     //context.keep_separator = 0;
350     parse_ag(packet);
351     CHECK_EQUAL(HFP_CMD_SUPPORTED_FEATURES, context.command);
352     CHECK_EQUAL(159, context.remote_supported_features);
353 }
354 
355 TEST(HFPParser, HFP_AG_AVAILABLE_CODECS){
356     snprintf(packet, sizeof(packet), "\r\nAT%s=0,1,2\r\n", HFP_AVAILABLE_CODECS);
357     parse_ag(packet);
358     CHECK_EQUAL(HFP_CMD_AVAILABLE_CODECS, context.command);
359     CHECK_EQUAL(3, context.remote_codecs_nr);
360     for (pos = 0; pos < 3; pos++){
361         CHECK_EQUAL(pos, context.remote_codecs[pos]);
362     }
363 }
364 
365 TEST(HFPParser, HFP_AG_GENERIC_STATUS_INDICATOR){
366     snprintf(packet, sizeof(packet), "\r\nAT%s=0,1,2,3,4\r\n", HFP_GENERIC_STATUS_INDICATOR);
367     parse_ag(packet);
368     CHECK_EQUAL(context.command, HFP_CMD_LIST_GENERIC_STATUS_INDICATORS);
369     CHECK_EQUAL(5, context.generic_status_indicators_nr);
370 
371     for (pos = 0; pos < context.generic_status_indicators_nr; pos++){
372         CHECK_EQUAL(pos, context.generic_status_indicators[pos].uuid);
373     }
374 }
375 
376 TEST(HFPParser, HFP_AG_ENABLE_INDICATOR_STATUS_UPDATE){
377     snprintf(packet, sizeof(packet), "\r\nAT%s=3,0,0,1\r\n", HFP_ENABLE_STATUS_UPDATE_FOR_AG_INDICATORS);
378     parse_ag(packet);
379     CHECK_EQUAL(HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE, context.command);
380     CHECK_EQUAL(1, context.enable_status_update_for_ag_indicators);
381 }
382 
383 TEST(HFPParser, HFP_AG_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE){
384     hfp_ag_init_ag_indicators(hfp_ag_indicators_nr, (hfp_ag_indicator_t *)&hfp_ag_indicators);
385     context.ag_indicators_nr = hfp_ag_indicators_nr;
386     memcpy(context.ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t));
387 
388     for (pos = 0; pos < hfp_ag_indicators_nr; pos++){
389         CHECK_EQUAL(hfp_ag_indicators[pos].index,   hfp_ag_get_ag_indicators(&context)[pos].index );
390         CHECK_EQUAL(hfp_ag_indicators[pos].enabled, hfp_ag_get_ag_indicators(&context)[pos].enabled);
391         CHECK_EQUAL(hfp_ag_indicators[pos].index,   context.ag_indicators[pos].index);
392         CHECK_EQUAL(hfp_ag_indicators[pos].enabled, context.ag_indicators[pos].enabled);
393     }
394     snprintf(packet, sizeof(packet), "\r\nAT%s=0,0,0,0,0,0,0\r\n",
395         HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS);
396     parse_ag(packet);
397     CHECK_EQUAL(HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE, context.command);
398 
399     for (pos = 0; pos < hfp_ag_indicators_nr; pos++){
400         if (hfp_ag_get_ag_indicators(&context)[pos].mandatory){
401             CHECK_EQUAL(1, hfp_ag_get_ag_indicators(&context)[pos].enabled);
402             CHECK_EQUAL(1, context.ag_indicators[pos].enabled);
403         } else {
404             CHECK_EQUAL(0, hfp_ag_get_ag_indicators(&context)[pos].enabled);
405             CHECK_EQUAL(0, context.ag_indicators[pos].enabled);
406         }
407     }
408 }
409 
410 TEST(HFPParser, HFP_AG_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE_OPT_VALUES3){
411     hfp_ag_init_ag_indicators(hfp_ag_indicators_nr, (hfp_ag_indicator_t *)&hfp_ag_indicators);
412     context.ag_indicators_nr = hfp_ag_indicators_nr;
413     memcpy(context.ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t));
414 
415     snprintf(packet, sizeof(packet), "\r\nAT%s=,1,,,,,1\r\n",
416         HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS);
417     parse_ag(packet);
418 
419     CHECK_EQUAL(HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE, context.command);
420 
421     for (pos = 0; pos < hfp_ag_indicators_nr; pos++){
422         CHECK_EQUAL(hfp_ag_indicators[pos].index, hfp_ag_get_ag_indicators(&context)[pos].index );
423         CHECK_EQUAL(hfp_ag_indicators[pos].enabled, hfp_ag_get_ag_indicators(&context)[pos].enabled);
424         CHECK_EQUAL(hfp_ag_indicators[pos].index, context.ag_indicators[pos].index );
425         CHECK_EQUAL(hfp_ag_indicators[pos].enabled, context.ag_indicators[pos].enabled);
426     }
427 }
428 
429 TEST(HFPParser, HFP_AG_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE_OPT_VALUES2){
430     hfp_ag_init_ag_indicators(hfp_ag_indicators_nr, (hfp_ag_indicator_t *)&hfp_ag_indicators);
431     context.ag_indicators_nr = hfp_ag_indicators_nr;
432     memcpy(context.ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t));
433 
434     snprintf(packet, sizeof(packet), "\r\nAT%s=1,,,1,1,1,\r\n",
435         HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS);
436     parse_ag(packet);
437 
438     CHECK_EQUAL(HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE, context.command);
439 
440     for (pos = 0; pos < hfp_ag_indicators_nr; pos++){
441         CHECK_EQUAL(1,hfp_ag_get_ag_indicators(&context)[pos].enabled);
442         CHECK_EQUAL(1, context.ag_indicators[pos].enabled);
443     }
444 }
445 
446 TEST(HFPParser, HFP_AG_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE_OPT_VALUES1){
447     hfp_ag_init_ag_indicators(hfp_ag_indicators_nr, (hfp_ag_indicator_t *)&hfp_ag_indicators);
448     context.ag_indicators_nr = hfp_ag_indicators_nr;
449     memcpy(context.ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t));
450 
451     snprintf(packet, sizeof(packet), "\r\nAT%s=1,,,1,1,1,\r\n",
452         HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS);
453     parse_ag(packet);
454 
455     CHECK_EQUAL(HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE, context.command);
456 
457     for (pos = 0; pos < hfp_ag_indicators_nr; pos++){
458         CHECK_EQUAL(1, hfp_ag_get_ag_indicators(&context)[pos].enabled);
459         CHECK_EQUAL(1, context.ag_indicators[pos].enabled);
460     }
461 }
462 
463 TEST(HFPParser, HFP_AG_HF_QUERY_OPERATOR_SELECTION){
464     context.network_operator.format = 0xff;
465     snprintf(packet, sizeof(packet), "\r\nAT%s=3,0\r\n", HFP_QUERY_OPERATOR_SELECTION);
466 
467     parse_ag(packet);
468     CHECK_EQUAL(0, context.operator_name_changed);
469     CHECK_EQUAL(HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT, context.command);
470 
471     snprintf(packet, sizeof(packet), "\r\nAT%s?\r\n", HFP_QUERY_OPERATOR_SELECTION);
472 
473     parse_ag(packet);
474     CHECK_EQUAL(HFP_CMD_QUERY_OPERATOR_SELECTION_NAME, context.command);
475     CHECK_EQUAL(0, context.operator_name_changed);
476 }
477 
478 TEST(HFPParser, HFP_AG_EXTENDED_AUDIO_GATEWAY_ERROR){
479     snprintf(packet, sizeof(packet), "\r\nAT%s=1\r\n", HFP_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR);
480 
481     parse_ag(packet);
482     CHECK_EQUAL(HFP_CMD_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR, context.command );
483     CHECK_EQUAL(1, context.enable_extended_audio_gateway_error_report);
484 }
485 
486 TEST(HFPParser, HFP_AG_TRIGGER_CODEC_CONNECTION_SETUP){
487     snprintf(packet, sizeof(packet), "\r\nAT%s\r\n", HFP_TRIGGER_CODEC_CONNECTION_SETUP);
488     parse_ag(packet);
489     CHECK_EQUAL(HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP, context.command);
490 }
491 
492 TEST(HFPParser, HFP_AG_CONFIRM_COMMON_CODEC){
493     int codec = 2;
494     snprintf(packet, sizeof(packet), "\r\nAT%s=%d\r\n", HFP_CONFIRM_COMMON_CODEC, codec);
495 
496     parse_ag(packet);
497     CHECK_EQUAL(HFP_CMD_HF_CONFIRMED_CODEC, context.command );
498     CHECK_EQUAL(codec, context.codec_confirmed);
499 }
500 
501 TEST(HFPParser, HFP_AG_DIAL){
502     strcpy(packet, "\r\nATD00123456789;\r\n");
503 
504     parse_ag(packet);
505     CHECK_EQUAL(HFP_CMD_CALL_PHONE_NUMBER, context.command);
506     STRCMP_EQUAL("00123456789", (const char *) &context.line_buffer[3]);
507 }
508 
509 TEST(HFPParser, HFP_ANSWER_CALL){
510     snprintf(packet, sizeof(packet), "\r\n%s\r\n", HFP_ANSWER_CALL);
511     parse_ag(packet);
512     CHECK_EQUAL(HFP_CMD_CALL_ANSWERED, context.command);
513 }
514 
515 TEST(HFPParser, HFP_CMD_RESPONSE_AND_HOLD_QUERY){
516     snprintf(packet, sizeof(packet), "\r\nAT%s?\r\n", HFP_RESPONSE_AND_HOLD);
517     parse_ag(packet);
518     CHECK_EQUAL(HFP_CMD_RESPONSE_AND_HOLD_QUERY, context.command);
519 }
520 
521 TEST(HFPParser, HFP_CMD_RESPONSE_AND_HOLD_COMMAND){
522     int param = 1;
523     snprintf(packet, sizeof(packet), "\r\nAT%s=%u\r\n", HFP_RESPONSE_AND_HOLD, param);
524     parse_ag(packet);
525     CHECK_EQUAL(HFP_CMD_RESPONSE_AND_HOLD_COMMAND, context.command);
526     CHECK_EQUAL(param, context.ag_response_and_hold_action);
527 }
528 
529 TEST(HFPParser, HFP_CMD_RESPONSE_AND_HOLD_STATUS){
530     int status = 1;
531     snprintf(packet, sizeof(packet), "\r\n%s:%u\r\n", HFP_RESPONSE_AND_HOLD, status);
532     parse_hf(packet);
533     CHECK_EQUAL(HFP_CMD_RESPONSE_AND_HOLD_STATUS, context.command);
534 }
535 
536 TEST(HFPParser, HFP_CMD_ENABLE_CLIP){
537     int param = 1;
538     snprintf(packet, sizeof(packet), "\r\nAT%s=%u\r\n", HFP_ENABLE_CLIP, param);
539     parse_ag(packet);
540     CHECK_EQUAL(HFP_CMD_ENABLE_CLIP, context.command);
541     CHECK_EQUAL(param, context.clip_enabled);
542 }
543 
544 TEST(HFPParser, HFP_CMD_AG_SENT_CLIP_INFORMATION_a){
545     // default/minimal
546     parse_hf("\r\n+CLIP: \"+123456789\",145\r\n");
547     CHECK_EQUAL(HFP_CMD_AG_SENT_CLIP_INFORMATION, context.command);
548     STRCMP_EQUAL("+123456789", context.bnip_number);
549     CHECK_EQUAL(145, context.bnip_type);
550     CHECK_EQUAL(false, context.clip_have_alpha);
551 }
552 
553 TEST(HFPParser, HFP_CMD_AG_SENT_CLIP_INFORMATION_b){
554     // iOS
555     parse_hf("\r\n+CLIP: \"+123456789\",145,,,\"BlueKitchen GmbH\"\r\n");
556     CHECK_EQUAL(HFP_CMD_AG_SENT_CLIP_INFORMATION, context.command);
557     STRCMP_EQUAL("+123456789", context.bnip_number);
558     CHECK_EQUAL(145, context.bnip_type);
559     CHECK_EQUAL(true, context.clip_have_alpha);
560     STRCMP_EQUAL("BlueKitchen GmbH", (const char *)context.line_buffer);
561 }
562 
563 TEST(HFPParser, HFP_CMD_AG_SENT_CLIP_INFORMATION_c){
564     // older iOS with additional ','
565     parse_hf("\r\n+CLIP: \"+123456789\",145,,,,\"BlueKitchen GmbH\"\r\n");
566     CHECK_EQUAL(HFP_CMD_AG_SENT_CLIP_INFORMATION, context.command);
567     STRCMP_EQUAL("+123456789", context.bnip_number);
568     CHECK_EQUAL(145, context.bnip_type);
569     CHECK_EQUAL(true, context.clip_have_alpha);
570     STRCMP_EQUAL("BlueKitchen GmbH", (const char *)context.line_buffer);
571 }
572 
573 TEST(HFPParser, HFP_CMD_AG_SENT_CLIP_INFORMATION_d){
574     // BlackBerry, additional quotes
575     parse_hf("\r\n+CLIP: \"+123456789\",145,\"\",,\"BlueKitchen GmbH\"\r\n");
576     CHECK_EQUAL(HFP_CMD_AG_SENT_CLIP_INFORMATION, context.command);
577     STRCMP_EQUAL("+123456789", context.bnip_number);
578     CHECK_EQUAL(145, context.bnip_type);
579     CHECK_EQUAL(true, context.clip_have_alpha);
580     STRCMP_EQUAL("BlueKitchen GmbH", (const char *)context.line_buffer);
581 }
582 
583 TEST(HFPParser, HFP_CMD_AG_SENT_CALL_WAITING_INFORMATION){
584     parse_hf("\r\n+CCWA: \"+123456789\",145,\"\",1,\"BlueKitchen GmbH\"\r\n");
585     CHECK_EQUAL(HFP_CMD_AG_SENT_CALL_WAITING_NOTIFICATION_UPDATE, context.command);
586     STRCMP_EQUAL("+123456789", context.bnip_number);
587     CHECK_EQUAL(145, context.bnip_type);
588     CHECK_EQUAL(true, context.clip_have_alpha);
589     STRCMP_EQUAL("BlueKitchen GmbH", (const char *)context.line_buffer);
590 }
591 
592 // #define LOG_LINE_BUFFER
593 static void hfp_at_parser_test_dump_line_buffer(void){
594 #ifdef LOG_LINE_BUFFER
595     uint16_t line_len = strlen(reinterpret_cast<const char *>(context.line_buffer));
596     printf("\nLine buffer: %s\n", context.line_buffer);
597     printf_hexdump(context.line_buffer, line_len);
598 #endif
599 }
600 
601 TEST(HFPParser, custom_command_hf){
602     hfp_custom_at_command_t custom_hf_command = {
603             .command = "+FOO:",
604             .command_id = 1
605     };
606     const char * custom_hf_command_string = "\r\n+FOO:1,2,3\r\n";
607     hfp_register_custom_hf_command(&custom_hf_command);
608     parse_hf(custom_hf_command_string);
609     CHECK_EQUAL(1, context.custom_at_command_id);
610     hfp_at_parser_test_dump_line_buffer();
611 }
612 
613 TEST(HFPParser, custom_command_ag_with_colon){
614     hfp_custom_at_command_t custom_ag_command = {
615             .command = "AT+FOO:",
616             .command_id = 2
617     };
618     const char * custom_hf_command_string = "\r\nAT+FOO:1,2,3\r\n";
619     hfp_register_custom_ag_command(&custom_ag_command);
620     parse_ag(custom_hf_command_string);
621     CHECK_EQUAL(2, context.custom_at_command_id);
622     hfp_at_parser_test_dump_line_buffer();
623 }
624 
625 TEST(HFPParser, custom_command_ag_with_question){
626     hfp_custom_at_command_t custom_ag_command = {
627             .command = "AT+FOO?",
628             .command_id = 3
629     };
630     const char * custom_hf_command_string = "\r\nAT+FOO?\r\n";
631     hfp_register_custom_ag_command(&custom_ag_command);
632     parse_ag(custom_hf_command_string);
633     CHECK_EQUAL(3, context.custom_at_command_id);
634     hfp_at_parser_test_dump_line_buffer();
635 }
636 
637 int main (int argc, const char * argv[]){
638     return CommandLineTestRunner::RunAllTests(argc, argv);
639 }
640