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 // #define LOG_LINE_BUFFER
hfp_at_parser_test_dump_line_buffer(void)71 static void hfp_at_parser_test_dump_line_buffer(void){
72 #ifdef LOG_LINE_BUFFER
73 uint16_t line_len = strlen(reinterpret_cast<const char *>(context.line_buffer));
74 printf("\nLine buffer: %s\n", context.line_buffer);
75 printf_hexdump(context.line_buffer, line_len);
76 #endif
77 }
78
parse_ag(const char * packet)79 static void parse_ag(const char * packet){
80 for (uint16_t pos = 0; pos < strlen(packet); pos++){
81 hfp_parse(&context, packet[pos], 0);
82 }
83 }
84
parse_hf(const char * packet)85 static void parse_hf(const char * packet){
86 for (uint16_t pos = 0; pos < strlen(packet); pos++){
87 hfp_parse(&context, packet[pos], 1);
88 }
89 }
90
TEST_GROUP(HFPParser)91 TEST_GROUP(HFPParser){
92 char packet[200];
93 int pos;
94 int offset;
95
96 void setup(void){
97 hfp_init();
98 memset(&context, 0, sizeof(hfp_connection_t));
99 context.parser_state = HFP_PARSER_CMD_HEADER;
100 context.parser_item_index = 0;
101 context.line_size = 0;
102 context.ag_indicators_nr = 0;
103 context.remote_codecs_nr = 0;
104 context.bnip_number[0] = 0;
105 context.bnip_type = 0;
106 memset(packet,0, sizeof(packet));
107 }
108
109 void teardown(void){
110 hfp_deinit();
111 }
112 };
113
TEST(HFPParser,HFP_HF_OK)114 TEST(HFPParser, HFP_HF_OK){
115 snprintf(packet, sizeof(packet), "\r\n%s\r\n", HFP_OK);
116 parse_hf(packet);
117 CHECK_EQUAL(HFP_CMD_OK, context.command);
118 }
119
TEST(HFPParser,HFP_HF_SUPPORTED_FEATURES)120 TEST(HFPParser, HFP_HF_SUPPORTED_FEATURES){
121 snprintf(packet, sizeof(packet), "\r\n%s:1007\r\n\r\nOK\r\n", HFP_SUPPORTED_FEATURES);
122 parse_hf(packet);
123 CHECK_EQUAL(HFP_CMD_OK, context.command);
124 CHECK_EQUAL(1007, context.remote_supported_features);
125 }
126
TEST(HFPParser,HFP_CMD_INDICATORS_QUERY)127 TEST(HFPParser, HFP_CMD_INDICATORS_QUERY){
128 snprintf(packet, sizeof(packet), "\r\nAT%s?\r\n", HFP_INDICATOR);
129 parse_ag(packet);
130 CHECK_EQUAL(HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS, context.command);
131 }
132
TEST(HFPParser,HFP_CMD_INDICATORS_RETRIEVE)133 TEST(HFPParser, HFP_CMD_INDICATORS_RETRIEVE){
134 snprintf(packet, sizeof(packet), "\r\nAT%s=?\r\n", HFP_INDICATOR);
135 parse_ag(packet);
136 CHECK_EQUAL(HFP_CMD_RETRIEVE_AG_INDICATORS, context.command);
137 }
138
TEST(HFPParser,HFP_HF_INDICATORS)139 TEST(HFPParser, HFP_HF_INDICATORS){
140 offset = 0;
141 offset += snprintf(packet, sizeof(packet), "%s:", HFP_INDICATOR);
142 for (pos = 0; pos < hfp_ag_indicators_nr; pos++){
143 if (pos != 0) {
144 packet[offset++] = ',';
145 }
146 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);
147 }
148 offset += snprintf(packet+offset, sizeof(packet)-offset, "\r\n\r\nOK\r\n");
149 context.state = HFP_W4_RETRIEVE_INDICATORS;
150
151 parse_hf(packet);
152 CHECK_EQUAL(HFP_CMD_OK, context.command);
153 CHECK_EQUAL(hfp_ag_indicators_nr, context.ag_indicators_nr);
154 for (pos = 0; pos < hfp_ag_indicators_nr; pos++){
155 CHECK_EQUAL(hfp_ag_indicators[pos].index, context.ag_indicators[pos].index);
156 STRCMP_EQUAL(hfp_ag_indicators[pos].name, context.ag_indicators[pos].name);
157 CHECK_EQUAL(hfp_ag_indicators[pos].min_range, context.ag_indicators[pos].min_range);
158 CHECK_EQUAL(hfp_ag_indicators[pos].max_range, context.ag_indicators[pos].max_range);
159 }
160 }
161
TEST(HFPParser,HFP_HF_INDICATORS_RANGE)162 TEST(HFPParser, HFP_HF_INDICATORS_RANGE){
163 offset = 0;
164 offset += snprintf(packet, sizeof(packet), "%s:", HFP_INDICATOR);
165 for (pos = 0; pos < hfp_ag_indicators_nr; pos++){
166 if (pos != 0) {
167 packet[offset++] = ',';
168 }
169 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);
170 }
171 offset += snprintf(packet+offset, sizeof(packet)-offset, "\r\n\r\nOK\r\n");
172 context.state = HFP_W4_RETRIEVE_INDICATORS;
173
174 parse_hf(packet);
175 CHECK_EQUAL(HFP_CMD_OK, context.command);
176 CHECK_EQUAL(hfp_ag_indicators_nr, context.ag_indicators_nr);
177 for (pos = 0; pos < hfp_ag_indicators_nr; pos++){
178 CHECK_EQUAL(hfp_ag_indicators[pos].index, context.ag_indicators[pos].index);
179 STRCMP_EQUAL(hfp_ag_indicators[pos].name, context.ag_indicators[pos].name);
180 CHECK_EQUAL(hfp_ag_indicators[pos].min_range, context.ag_indicators[pos].min_range);
181 CHECK_EQUAL(hfp_ag_indicators[pos].max_range, context.ag_indicators[pos].max_range);
182 }
183 }
184
TEST(HFPParser,HFP_HF_INDICATOR_STATUS)185 TEST(HFPParser, HFP_HF_INDICATOR_STATUS){
186 // send status
187 offset = 0;
188 offset += snprintf(packet, sizeof(packet), "%s:", HFP_INDICATOR);
189 for (pos = 0; pos < hfp_ag_indicators_nr - 1; pos++){
190 offset += snprintf(packet+offset, sizeof(packet)-offset, "%d,", hfp_ag_indicators[pos].status);
191 }
192 offset += snprintf(packet+offset, sizeof(packet)-offset, "%d\r\n\r\nOK\r\n", hfp_ag_indicators[pos].status);
193
194 //context.command = HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS;
195 context.state = HFP_W4_RETRIEVE_INDICATORS_STATUS;
196
197 parse_hf(packet);
198 CHECK_EQUAL(HFP_CMD_OK, context.command);
199 for (pos = 0; pos < hfp_ag_indicators_nr; pos++){
200 CHECK_EQUAL(hfp_ag_indicators[pos].status, context.ag_indicators[pos].status);
201 }
202 }
203
TEST(HFPParser,HFP_HF_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES_TEST)204 TEST(HFPParser, HFP_HF_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES_TEST){
205 snprintf(packet, sizeof(packet), "\r\nAT%s=?\r\n", HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES);
206 parse_ag(packet);
207 CHECK_EQUAL(HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES, context.command);
208 }
209
TEST(HFPParser,HFP_HF_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES_SET)210 TEST(HFPParser, HFP_HF_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES_SET){
211 int action = 1;
212 int call_index = 2;
213 snprintf(packet, sizeof(packet), "\r\nAT%s=%u%u\r\n", HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES, action, call_index);
214 parse_ag(packet);
215 CHECK_EQUAL(HFP_CMD_CALL_HOLD, context.command);
216 CHECK_EQUAL(action, context.ag_call_hold_action);
217 CHECK_EQUAL(call_index, context.call_index);
218 }
219
TEST(HFPParser,HFP_HF_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES)220 TEST(HFPParser, HFP_HF_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES){
221 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);
222 parse_hf(packet);
223 CHECK_EQUAL(HFP_CMD_OK, context.command);
224 CHECK_EQUAL(5, context.remote_call_services_index);
225
226 STRCMP_EQUAL("1", (char*)context.remote_call_services[0].name);
227 STRCMP_EQUAL("1x", (char*)context.remote_call_services[1].name);
228 STRCMP_EQUAL("2", (char*)context.remote_call_services[2].name);
229 STRCMP_EQUAL("2x", (char*)context.remote_call_services[3].name);
230 STRCMP_EQUAL("3", (char*)context.remote_call_services[4].name);
231 }
232
TEST(HFPParser,HFP_GENERIC_STATUS_INDICATOR_TEST)233 TEST(HFPParser, HFP_GENERIC_STATUS_INDICATOR_TEST){
234 snprintf(packet, sizeof(packet), "\r\nAT%s=?\r\n", HFP_GENERIC_STATUS_INDICATOR);
235 parse_ag(packet);
236 CHECK_EQUAL(HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS, context.command);
237 }
238
TEST(HFPParser,HFP_GENERIC_STATUS_INDICATOR_SET)239 TEST(HFPParser, HFP_GENERIC_STATUS_INDICATOR_SET){
240 int param1 = 1;
241 int param2 = 2;
242 int param3 = 3;
243 snprintf(packet, sizeof(packet), "\r\nAT%s= %u,%u,%u\r\n", HFP_GENERIC_STATUS_INDICATOR, param1, param2, param3);
244 parse_ag(packet);
245 CHECK_EQUAL(HFP_CMD_LIST_GENERIC_STATUS_INDICATORS, context.command);
246 }
247
TEST(HFPParser,HFP_GENERIC_STATUS_INDICATOR_READ)248 TEST(HFPParser, HFP_GENERIC_STATUS_INDICATOR_READ){
249 snprintf(packet, sizeof(packet), "\r\nAT%s?\r\n", HFP_GENERIC_STATUS_INDICATOR);
250 parse_ag(packet);
251 CHECK_EQUAL(HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS_STATE, context.command);
252 }
253
TEST(HFPParser,HFP_HF_GENERIC_STATUS_INDICATOR_STATE)254 TEST(HFPParser, HFP_HF_GENERIC_STATUS_INDICATOR_STATE){
255 snprintf(packet, sizeof(packet), "\r\n%s:0,1\r\n\r\nOK\r\n", HFP_GENERIC_STATUS_INDICATOR);
256 // context.command = HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS_STATE;
257 context.state = HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS;
258
259 parse_hf(packet);
260 CHECK_EQUAL(HFP_CMD_OK, context.command);
261 CHECK_EQUAL(1, context.generic_status_indicators[0].state);
262 }
263
TEST(HFPParser,HFP_HF_AG_INDICATOR_STATUS_UPDATE)264 TEST(HFPParser, HFP_HF_AG_INDICATOR_STATUS_UPDATE){
265 context.ag_indicators_nr = hfp_ag_indicators_nr;
266 memcpy(context.ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t));
267
268 uint8_t index = 4;
269 uint8_t status = 5;
270
271 snprintf(packet, sizeof(packet), "\r\n%s:%d,%d\r\n\r\nOK\r\n", HFP_TRANSFER_AG_INDICATOR_STATUS, index, status);
272
273 parse_hf(packet);
274 CHECK_EQUAL(HFP_CMD_OK, context.command);
275 CHECK_EQUAL(status, context.ag_indicators[index - 1].status);
276 }
277
TEST(HFPParser,HFP_HF_AG_QUERY_OPERATOR_SELECTION)278 TEST(HFPParser, HFP_HF_AG_QUERY_OPERATOR_SELECTION){
279 snprintf(packet, sizeof(packet), "\r\n%s:1,0,\"sunrise\"\r\n\r\nOK\r\n", HFP_QUERY_OPERATOR_SELECTION);
280
281 context.command = HFP_CMD_QUERY_OPERATOR_SELECTION_NAME;
282
283 parse_hf(packet);
284 CHECK_EQUAL(HFP_CMD_OK, context.command);
285 CHECK_EQUAL(0, context.operator_name_changed);
286 STRCMP_EQUAL( "sunrise", context.network_operator.name);
287 }
288
TEST(HFPParser,HFP_HF_ERROR)289 TEST(HFPParser, HFP_HF_ERROR){
290 snprintf(packet, sizeof(packet), "\r\n%s\r\n", HFP_ERROR);
291
292 parse_hf(packet);
293 CHECK_EQUAL(HFP_CMD_ERROR, context.command);
294 }
295
TEST(HFPParser,HFP_HF_EXTENDED_AUDIO_GATEWAY_ERROR)296 TEST(HFPParser, HFP_HF_EXTENDED_AUDIO_GATEWAY_ERROR){
297 snprintf(packet, sizeof(packet), "\r\n%s:%d\r\n", HFP_EXTENDED_AUDIO_GATEWAY_ERROR, HFP_CME_ERROR_NO_NETWORK_SERVICE);
298
299 parse_hf(packet);
300 CHECK_EQUAL(HFP_CMD_EXTENDED_AUDIO_GATEWAY_ERROR, context.command);
301 CHECK_EQUAL(HFP_CME_ERROR_NO_NETWORK_SERVICE, context.extended_audio_gateway_error_value);
302 }
303
TEST(HFPParser,HFP_HF_AG_INDICATOR_CALLS_STATUS_UPDATE)304 TEST(HFPParser, HFP_HF_AG_INDICATOR_CALLS_STATUS_UPDATE){
305 context.ag_indicators_nr = hfp_ag_indicators_nr;
306 memcpy(context.ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t));
307 uint8_t status = 1;
308
309 // call status
310 uint8_t index = call_status_index;
311 snprintf(packet, sizeof(packet), "\r\n%s:%d,%d\r\n\r\nOK\r\n", HFP_TRANSFER_AG_INDICATOR_STATUS, index, status);
312 parse_hf(packet);
313 CHECK_EQUAL(HFP_CMD_OK, context.command);
314 CHECK_EQUAL(status, context.ag_indicators[index - 1].status);
315
316 // callsetup status
317 index = callsetup_status_index;
318 snprintf(packet, sizeof(packet), "\r\n%s:%d,%d\r\n\r\nOK\r\n", HFP_TRANSFER_AG_INDICATOR_STATUS, index, status);
319 parse_hf(packet);
320 CHECK_EQUAL(HFP_CMD_OK, context.command);
321 CHECK_EQUAL(status, context.ag_indicators[index - 1].status);
322
323 // callheld status
324 index = callheld_status_index;
325 snprintf(packet, sizeof(packet), "\r\n%s:%d,%d\r\n\r\nOK\r\n", HFP_TRANSFER_AG_INDICATOR_STATUS, index, status);
326 parse_hf(packet);
327 CHECK_EQUAL(HFP_CMD_OK, context.command);
328 CHECK_EQUAL(status, context.ag_indicators[index - 1].status);
329 }
330
TEST(HFPParser,HFP_LIST_CURRENT_CALLS_1)331 TEST(HFPParser, HFP_LIST_CURRENT_CALLS_1){
332 strcpy(packet, "\r\n+CLCC: 1,2,3,4,5,,129\r\n");
333 parse_hf(packet);
334 CHECK_EQUAL(HFP_CMD_LIST_CURRENT_CALLS, context.command);
335 CHECK_EQUAL(1, context.clcc_idx);
336 CHECK_EQUAL(2, context.clcc_dir);
337 CHECK_EQUAL(3, context.clcc_status);
338 CHECK_EQUAL(4, context.clcc_mode);
339 CHECK_EQUAL(5, context.clcc_mpty);
340 STRCMP_EQUAL("", context.bnip_number);
341 CHECK_EQUAL(129, context.bnip_type);
342 }
343
TEST(HFPParser,HFP_LIST_CURRENT_CALLS_2)344 TEST(HFPParser, HFP_LIST_CURRENT_CALLS_2){
345 strcpy(packet, "\r\n+CLCC: 1,2,3,4,5,"",129\r\n");
346 parse_hf(packet);
347 CHECK_EQUAL(HFP_CMD_LIST_CURRENT_CALLS, context.command);
348 CHECK_EQUAL(1, context.clcc_idx);
349 CHECK_EQUAL(2, context.clcc_dir);
350 CHECK_EQUAL(3, context.clcc_status);
351 CHECK_EQUAL(4, context.clcc_mode);
352 CHECK_EQUAL(5, context.clcc_mpty);
353 STRCMP_EQUAL("", context.bnip_number);
354 CHECK_EQUAL(129, context.bnip_type);
355 }
356
TEST(HFPParser,HFP_AG_SUPPORTED_FEATURES)357 TEST(HFPParser, HFP_AG_SUPPORTED_FEATURES){
358 snprintf(packet, sizeof(packet), "\r\nAT%s=159\r\n", HFP_SUPPORTED_FEATURES);
359 //context.keep_separator = 0;
360 parse_ag(packet);
361 CHECK_EQUAL(HFP_CMD_SUPPORTED_FEATURES, context.command);
362 CHECK_EQUAL(159, context.remote_supported_features);
363 }
364
TEST(HFPParser,HFP_AG_AVAILABLE_CODECS)365 TEST(HFPParser, HFP_AG_AVAILABLE_CODECS){
366 snprintf(packet, sizeof(packet), "\r\nAT%s=0,1,2\r\n", HFP_AVAILABLE_CODECS);
367 parse_ag(packet);
368 CHECK_EQUAL(HFP_CMD_AVAILABLE_CODECS, context.command);
369 CHECK_EQUAL(3, context.remote_codecs_nr);
370 for (pos = 0; pos < 3; pos++){
371 CHECK_EQUAL(pos, context.remote_codecs[pos]);
372 }
373 }
374
TEST(HFPParser,HFP_AG_GENERIC_STATUS_INDICATOR)375 TEST(HFPParser, HFP_AG_GENERIC_STATUS_INDICATOR){
376 snprintf(packet, sizeof(packet), "\r\nAT%s=0,1,2,3,4\r\n", HFP_GENERIC_STATUS_INDICATOR);
377 parse_ag(packet);
378 CHECK_EQUAL(context.command, HFP_CMD_LIST_GENERIC_STATUS_INDICATORS);
379 CHECK_EQUAL(5, context.generic_status_indicators_nr);
380
381 for (pos = 0; pos < context.generic_status_indicators_nr; pos++){
382 CHECK_EQUAL(pos, context.generic_status_indicators[pos].uuid);
383 }
384 }
385
TEST(HFPParser,HFP_AG_ENABLE_INDICATOR_STATUS_UPDATE)386 TEST(HFPParser, HFP_AG_ENABLE_INDICATOR_STATUS_UPDATE){
387 snprintf(packet, sizeof(packet), "\r\nAT%s=3,0,0,1\r\n", HFP_ENABLE_STATUS_UPDATE_FOR_AG_INDICATORS);
388 parse_ag(packet);
389 CHECK_EQUAL(HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE, context.command);
390 CHECK_EQUAL(1, context.enable_status_update_for_ag_indicators);
391 }
392
TEST(HFPParser,HFP_AG_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE)393 TEST(HFPParser, HFP_AG_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE){
394 hfp_ag_init_ag_indicators(hfp_ag_indicators_nr, (hfp_ag_indicator_t *)&hfp_ag_indicators);
395 context.ag_indicators_nr = hfp_ag_indicators_nr;
396 memcpy(context.ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t));
397
398 for (pos = 0; pos < hfp_ag_indicators_nr; pos++){
399 CHECK_EQUAL(hfp_ag_indicators[pos].index, hfp_ag_get_ag_indicators(&context)[pos].index );
400 CHECK_EQUAL(hfp_ag_indicators[pos].enabled, hfp_ag_get_ag_indicators(&context)[pos].enabled);
401 CHECK_EQUAL(hfp_ag_indicators[pos].index, context.ag_indicators[pos].index);
402 CHECK_EQUAL(hfp_ag_indicators[pos].enabled, context.ag_indicators[pos].enabled);
403 }
404 snprintf(packet, sizeof(packet), "\r\nAT%s=0,0,0,0,0,0,0\r\n",
405 HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS);
406 parse_ag(packet);
407 CHECK_EQUAL(HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE, context.command);
408
409 for (pos = 0; pos < hfp_ag_indicators_nr; pos++){
410 if (hfp_ag_get_ag_indicators(&context)[pos].mandatory){
411 CHECK_EQUAL(1, hfp_ag_get_ag_indicators(&context)[pos].enabled);
412 CHECK_EQUAL(1, context.ag_indicators[pos].enabled);
413 } else {
414 CHECK_EQUAL(0, hfp_ag_get_ag_indicators(&context)[pos].enabled);
415 CHECK_EQUAL(0, context.ag_indicators[pos].enabled);
416 }
417 }
418 }
419
TEST(HFPParser,HFP_AG_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE_OPT_VALUES3)420 TEST(HFPParser, HFP_AG_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE_OPT_VALUES3){
421 hfp_ag_init_ag_indicators(hfp_ag_indicators_nr, (hfp_ag_indicator_t *)&hfp_ag_indicators);
422 context.ag_indicators_nr = hfp_ag_indicators_nr;
423 memcpy(context.ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t));
424
425 snprintf(packet, sizeof(packet), "\r\nAT%s=,1,,,,,1\r\n",
426 HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS);
427 parse_ag(packet);
428
429 CHECK_EQUAL(HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE, context.command);
430
431 for (pos = 0; pos < hfp_ag_indicators_nr; pos++){
432 CHECK_EQUAL(hfp_ag_indicators[pos].index, hfp_ag_get_ag_indicators(&context)[pos].index );
433 CHECK_EQUAL(hfp_ag_indicators[pos].enabled, hfp_ag_get_ag_indicators(&context)[pos].enabled);
434 CHECK_EQUAL(hfp_ag_indicators[pos].index, context.ag_indicators[pos].index );
435 CHECK_EQUAL(hfp_ag_indicators[pos].enabled, context.ag_indicators[pos].enabled);
436 }
437 }
438
TEST(HFPParser,HFP_AG_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE_OPT_VALUES2)439 TEST(HFPParser, HFP_AG_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE_OPT_VALUES2){
440 hfp_ag_init_ag_indicators(hfp_ag_indicators_nr, (hfp_ag_indicator_t *)&hfp_ag_indicators);
441 context.ag_indicators_nr = hfp_ag_indicators_nr;
442 memcpy(context.ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t));
443
444 snprintf(packet, sizeof(packet), "\r\nAT%s=1,,,1,1,1,\r\n",
445 HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS);
446 parse_ag(packet);
447
448 CHECK_EQUAL(HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE, context.command);
449
450 for (pos = 0; pos < hfp_ag_indicators_nr; pos++){
451 CHECK_EQUAL(1,hfp_ag_get_ag_indicators(&context)[pos].enabled);
452 CHECK_EQUAL(1, context.ag_indicators[pos].enabled);
453 }
454 }
455
TEST(HFPParser,HFP_AG_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE_OPT_VALUES1)456 TEST(HFPParser, HFP_AG_ENABLE_INDIVIDUAL_INDICATOR_STATUS_UPDATE_OPT_VALUES1){
457 hfp_ag_init_ag_indicators(hfp_ag_indicators_nr, (hfp_ag_indicator_t *)&hfp_ag_indicators);
458 context.ag_indicators_nr = hfp_ag_indicators_nr;
459 memcpy(context.ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t));
460
461 snprintf(packet, sizeof(packet), "\r\nAT%s=1,,,1,1,1,\r\n",
462 HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS);
463 parse_ag(packet);
464
465 CHECK_EQUAL(HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE, context.command);
466
467 for (pos = 0; pos < hfp_ag_indicators_nr; pos++){
468 CHECK_EQUAL(1, hfp_ag_get_ag_indicators(&context)[pos].enabled);
469 CHECK_EQUAL(1, context.ag_indicators[pos].enabled);
470 }
471 }
472
TEST(HFPParser,HFP_AG_HF_QUERY_OPERATOR_SELECTION)473 TEST(HFPParser, HFP_AG_HF_QUERY_OPERATOR_SELECTION){
474 context.network_operator.format = 0xff;
475 snprintf(packet, sizeof(packet), "\r\nAT%s=3,0\r\n", HFP_QUERY_OPERATOR_SELECTION);
476
477 parse_ag(packet);
478 CHECK_EQUAL(0, context.operator_name_changed);
479 CHECK_EQUAL(HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT, context.command);
480
481 snprintf(packet, sizeof(packet), "\r\nAT%s?\r\n", HFP_QUERY_OPERATOR_SELECTION);
482
483 parse_ag(packet);
484 CHECK_EQUAL(HFP_CMD_QUERY_OPERATOR_SELECTION_NAME, context.command);
485 CHECK_EQUAL(0, context.operator_name_changed);
486 }
487
TEST(HFPParser,HFP_AG_EXTENDED_AUDIO_GATEWAY_ERROR)488 TEST(HFPParser, HFP_AG_EXTENDED_AUDIO_GATEWAY_ERROR){
489 snprintf(packet, sizeof(packet), "\r\nAT%s=1\r\n", HFP_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR);
490
491 parse_ag(packet);
492 CHECK_EQUAL(HFP_CMD_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR, context.command );
493 CHECK_EQUAL(1, context.enable_extended_audio_gateway_error_report);
494 }
495
TEST(HFPParser,HFP_AG_TRIGGER_CODEC_CONNECTION_SETUP)496 TEST(HFPParser, HFP_AG_TRIGGER_CODEC_CONNECTION_SETUP){
497 snprintf(packet, sizeof(packet), "\r\nAT%s\r\n", HFP_TRIGGER_CODEC_CONNECTION_SETUP);
498 parse_ag(packet);
499 CHECK_EQUAL(HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP, context.command);
500 }
501
TEST(HFPParser,HFP_AG_CONFIRM_COMMON_CODEC)502 TEST(HFPParser, HFP_AG_CONFIRM_COMMON_CODEC){
503 int codec = 2;
504 snprintf(packet, sizeof(packet), "\r\nAT%s=%d\r\n", HFP_CONFIRM_COMMON_CODEC, codec);
505
506 parse_ag(packet);
507 CHECK_EQUAL(HFP_CMD_HF_CONFIRMED_CODEC, context.command );
508 CHECK_EQUAL(codec, context.codec_confirmed);
509 }
510
TEST(HFPParser,HFP_AG_DIAL)511 TEST(HFPParser, HFP_AG_DIAL){
512 strcpy(packet, "\r\nATD00123456789;\r\n");
513
514 parse_ag(packet);
515 CHECK_EQUAL(HFP_CMD_CALL_PHONE_NUMBER, context.command);
516 STRCMP_EQUAL("00123456789", (const char *) &context.line_buffer[3]);
517 }
518
TEST(HFPParser,HFP_ANSWER_CALL)519 TEST(HFPParser, HFP_ANSWER_CALL){
520 snprintf(packet, sizeof(packet), "\r\n%s\r\n", HFP_ANSWER_CALL);
521 parse_ag(packet);
522 CHECK_EQUAL(HFP_CMD_CALL_ANSWERED, context.command);
523 }
524
TEST(HFPParser,HFP_CMD_RESPONSE_AND_HOLD_QUERY)525 TEST(HFPParser, HFP_CMD_RESPONSE_AND_HOLD_QUERY){
526 snprintf(packet, sizeof(packet), "\r\nAT%s?\r\n", HFP_RESPONSE_AND_HOLD);
527 parse_ag(packet);
528 CHECK_EQUAL(HFP_CMD_RESPONSE_AND_HOLD_QUERY, context.command);
529 }
530
TEST(HFPParser,HFP_CMD_RESPONSE_AND_HOLD_COMMAND)531 TEST(HFPParser, HFP_CMD_RESPONSE_AND_HOLD_COMMAND){
532 int param = 1;
533 snprintf(packet, sizeof(packet), "\r\nAT%s=%u\r\n", HFP_RESPONSE_AND_HOLD, param);
534 parse_ag(packet);
535 CHECK_EQUAL(HFP_CMD_RESPONSE_AND_HOLD_COMMAND, context.command);
536 CHECK_EQUAL(param, context.ag_response_and_hold_action);
537 }
538
TEST(HFPParser,HFP_CMD_RESPONSE_AND_HOLD_STATUS)539 TEST(HFPParser, HFP_CMD_RESPONSE_AND_HOLD_STATUS){
540 int status = 1;
541 snprintf(packet, sizeof(packet), "\r\n%s:%u\r\n", HFP_RESPONSE_AND_HOLD, status);
542 parse_hf(packet);
543 CHECK_EQUAL(HFP_CMD_RESPONSE_AND_HOLD_STATUS, context.command);
544 }
545
TEST(HFPParser,HFP_CMD_ENABLE_CLIP)546 TEST(HFPParser, HFP_CMD_ENABLE_CLIP){
547 int param = 1;
548 snprintf(packet, sizeof(packet), "\r\nAT%s=%u\r\n", HFP_ENABLE_CLIP, param);
549 parse_ag(packet);
550 CHECK_EQUAL(HFP_CMD_ENABLE_CLIP, context.command);
551 CHECK_EQUAL(param, context.clip_enabled);
552 }
553
TEST(HFPParser,HFP_CMD_AG_SENT_CLIP_INFORMATION_a)554 TEST(HFPParser, HFP_CMD_AG_SENT_CLIP_INFORMATION_a){
555 // default/minimal
556 parse_hf("\r\n+CLIP: \"+123456789\",145\r\n");
557 CHECK_EQUAL(HFP_CMD_AG_SENT_CLIP_INFORMATION, context.command);
558 STRCMP_EQUAL("+123456789", context.bnip_number);
559 CHECK_EQUAL(145, context.bnip_type);
560 CHECK_EQUAL(false, context.clip_have_alpha);
561 }
562
TEST(HFPParser,HFP_CMD_AG_SENT_CLIP_INFORMATION_b)563 TEST(HFPParser, HFP_CMD_AG_SENT_CLIP_INFORMATION_b){
564 // iOS
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
TEST(HFPParser,HFP_CMD_AG_SENT_CLIP_INFORMATION_c)573 TEST(HFPParser, HFP_CMD_AG_SENT_CLIP_INFORMATION_c){
574 // older iOS with additional ','
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
TEST(HFPParser,HFP_CMD_AG_SENT_CLIP_INFORMATION_d)583 TEST(HFPParser, HFP_CMD_AG_SENT_CLIP_INFORMATION_d){
584 // BlackBerry, additional quotes
585 parse_hf("\r\n+CLIP: \"+123456789\",145,\"\",,\"BlueKitchen GmbH\"\r\n");
586 CHECK_EQUAL(HFP_CMD_AG_SENT_CLIP_INFORMATION, context.command);
587 STRCMP_EQUAL("+123456789", context.bnip_number);
588 CHECK_EQUAL(145, context.bnip_type);
589 CHECK_EQUAL(true, context.clip_have_alpha);
590 STRCMP_EQUAL("BlueKitchen GmbH", (const char *)context.line_buffer);
591 }
592
TEST(HFPParser,HFP_CMD_AG_SENT_CALL_WAITING_INFORMATION)593 TEST(HFPParser, HFP_CMD_AG_SENT_CALL_WAITING_INFORMATION){
594 parse_hf("\r\n+CCWA: \"+123456789\",145,\"\",1,\"BlueKitchen GmbH\"\r\n");
595 CHECK_EQUAL(HFP_CMD_AG_SENT_CALL_WAITING_NOTIFICATION_UPDATE, context.command);
596 STRCMP_EQUAL("+123456789", context.bnip_number);
597 CHECK_EQUAL(145, context.bnip_type);
598 CHECK_EQUAL(true, context.clip_have_alpha);
599 STRCMP_EQUAL("BlueKitchen GmbH", (const char *)context.line_buffer);
600 }
601
TEST(HFPParser,custom_command_hf)602 TEST(HFPParser, custom_command_hf){
603 hfp_custom_at_command_t custom_hf_command = {
604 .command = "+FOO:",
605 .command_id = 1
606 };
607 const char * custom_hf_command_string = "\r\n+FOO:1,2,3\r\n";
608 hfp_register_custom_hf_command(&custom_hf_command);
609 parse_hf(custom_hf_command_string);
610 CHECK_EQUAL(1, context.custom_at_command_id);
611 STRCMP_EQUAL("+FOO:1,2,3", (const char *)context.line_buffer);
612 hfp_at_parser_test_dump_line_buffer();
613 }
614
TEST(HFPParser,custom_command_ag_with_colon)615 TEST(HFPParser, custom_command_ag_with_colon){
616 hfp_custom_at_command_t custom_ag_command = {
617 .command = "AT+FOO:",
618 .command_id = 2
619 };
620 const char * custom_hf_command_string = "\r\nAT+FOO:1,2,3\r\n";
621 hfp_register_custom_ag_command(&custom_ag_command);
622 parse_ag(custom_hf_command_string);
623 CHECK_EQUAL(2, context.custom_at_command_id);
624 STRCMP_EQUAL("AT+FOO:1,2,3", (const char *)context.line_buffer);
625 hfp_at_parser_test_dump_line_buffer();
626 }
627
TEST(HFPParser,custom_command_ag_with_question)628 TEST(HFPParser, custom_command_ag_with_question){
629 hfp_custom_at_command_t custom_ag_command = {
630 .command = "AT+FOO?",
631 .command_id = 3
632 };
633 const char * custom_hf_command_string = "\r\nAT+FOO?\r\n";
634 hfp_register_custom_ag_command(&custom_ag_command);
635 parse_ag(custom_hf_command_string);
636 CHECK_EQUAL(3, context.custom_at_command_id);
637 STRCMP_EQUAL("AT+FOO?", (const char *)context.line_buffer);
638 hfp_at_parser_test_dump_line_buffer();
639 }
640
TEST(HFPParser,custom_command_hf_with_assignment)641 TEST(HFPParser, custom_command_hf_with_assignment){
642 hfp_custom_at_command_t custom_ag_command = {
643 .command = "AT+TEST=",
644 .command_id = 3
645 };
646 const char * custom_hf_command_string = "\r\nAT+TEST=ABCDE\r\n";
647 hfp_register_custom_ag_command(&custom_ag_command);
648 parse_ag(custom_hf_command_string);
649 CHECK_EQUAL(3, context.custom_at_command_id);
650 STRCMP_EQUAL("AT+TEST=ABCDE", (const char *)context.line_buffer);
651 hfp_at_parser_test_dump_line_buffer();
652 }
653
TEST(HFPParser,HFP_GABRBAGE_AND_ANSWER_CALL)654 TEST(HFPParser, HFP_GABRBAGE_AND_ANSWER_CALL){
655 parse_ag("\r\nAT+ABCDEF\r\n");
656 CHECK_EQUAL(HFP_CMD_UNKNOWN, context.command);
657 snprintf(packet, sizeof(packet), "\r\n%s\r\n", HFP_ANSWER_CALL);
658 parse_ag(packet);
659 CHECK_EQUAL(HFP_CMD_CALL_ANSWERED, context.command);
660 }
661
TEST(HFPParser,AG_SENDS_RANDOM)662 TEST(HFPParser, AG_SENDS_RANDOM){
663 parse_hf("\r\n+$PATH:511\r\n");
664 CHECK_EQUAL(HFP_CMD_UNKNOWN, context.command);
665 }
666
TEST(HFPParser,long_command)667 TEST(HFPParser, long_command){
668 char command[300];
669 uint16_t offset = 0;
670 const char * header = "+CIEV";
671 uint16_t header_len = strlen(header);
672 memcpy(&command[offset], header, header_len);
673 offset += header_len;
674 command[offset++] = 0x02;
675 command[offset++] = 0x32;
676 uint16_t num_2c = 250;
677 memset(&command[offset], 0x2c, num_2c);
678 offset += num_2c;
679 command[offset++] = 0x31;
680 command[offset++] = '\r';
681 command[offset++] = '\n';
682 command[offset++] = 0x00;
683 parse_hf(command);
684 }
685
TEST(HFPParser,apple_accessory_information)686 TEST(HFPParser, apple_accessory_information){
687 parse_ag("\n\rAT+XAPL=ABCD-1234-0100,10\r\n");
688 CHECK_EQUAL(HFP_CMD_APPLE_ACCESSORY_INFORMATION, context.command);
689 CHECK_EQUAL(0xABCD, context.apple_accessory_vendor_id);
690 CHECK_EQUAL(0x1234, context.apple_accessory_product_id);
691 STRCMP_EQUAL("0100",context.apple_accessory_version);
692 CHECK_EQUAL(10, context.apple_accessory_features);
693 }
694
TEST(HFPParser,apple_accessory_state_battery)695 TEST(HFPParser, apple_accessory_state_battery){
696 context.apple_accessory_battery_level = -1;
697 context.apple_accessory_docked = -1;
698 parse_ag("\n\rAT+IPHONEACCEV=1,1,3\r\n");
699 CHECK_EQUAL(HFP_CMD_APPLE_ACCESSORY_STATE, context.command);
700 CHECK_EQUAL(3, context.apple_accessory_battery_level);
701 CHECK_EQUAL(-1, context.apple_accessory_docked);
702 }
703
TEST(HFPParser,apple_accessory_state_docked)704 TEST(HFPParser, apple_accessory_state_docked){
705 context.apple_accessory_battery_level = -1;
706 context.apple_accessory_docked = -1;
707 parse_ag("\n\rAT+IPHONEACCEV=1,2,1\r\n");
708 CHECK_EQUAL(HFP_CMD_APPLE_ACCESSORY_STATE, context.command);
709 CHECK_EQUAL(-1, context.apple_accessory_battery_level);
710 CHECK_EQUAL(1, context.apple_accessory_docked);
711 }
712
TEST(HFPParser,apple_accessory_state_both)713 TEST(HFPParser, apple_accessory_state_both){
714 context.apple_accessory_battery_level = -1;
715 context.apple_accessory_docked = -1;
716 parse_ag("\n\rAT+IPHONEACCEV=1,1,3,2,1\r\n");
717 CHECK_EQUAL(HFP_CMD_APPLE_ACCESSORY_STATE, context.command);
718 CHECK_EQUAL(3, context.apple_accessory_battery_level);
719 CHECK_EQUAL(1, context.apple_accessory_docked);
720 }
721
TEST(HFPParser,dummy)722 TEST(HFPParser,dummy){
723 unsigned char data[] = {
724 0x99, 0x08, 0x0a
725 };
726 unsigned int data_len = sizeof(data);
727 int is_handsfree = data[0] & 1;
728 hfp_connection_t hfp_connection;
729 memset(&hfp_connection, 0, sizeof(hfp_connection_t));
730 uint32_t i;
731 for (i = 1; i < data_len; i++){
732 hfp_parse(&hfp_connection, data[i], is_handsfree);
733 }
734
735 }
736
main(int argc,const char * argv[])737 int main (int argc, const char * argv[]){
738 return CommandLineTestRunner::RunAllTests(argc, argv);
739 }
740