1 /*
2 * Copyright (c) 2022 Trackunit Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /*************************************************************************************************/
8 /* Dependencies */
9 /*************************************************************************************************/
10 #include <zephyr/ztest.h>
11 #include <zephyr/kernel.h>
12 #include <zephyr/sys/atomic.h>
13 #include <string.h>
14
15 #include <zephyr/modem/chat.h>
16 #include <modem_backend_mock.h>
17
18 /*************************************************************************************************/
19 /* Instances */
20 /*************************************************************************************************/
21 static struct modem_chat cmd;
22 static uint8_t cmd_delimiter[] = {'\r', '\n'};
23 static uint8_t cmd_receive_buf[128];
24 static uint8_t *cmd_argv[32];
25 static uint32_t cmd_user_data = 0x145212;
26
27 static struct modem_backend_mock mock;
28 static uint8_t mock_rx_buf[128];
29 static uint8_t mock_tx_buf[128];
30 static struct modem_pipe *mock_pipe;
31
32 /*************************************************************************************************/
33 /* Track callbacks */
34 /*************************************************************************************************/
35 #define MODEM_CHAT_UTEST_ON_IMEI_CALLED_BIT (0)
36 #define MODEM_CHAT_UTEST_ON_CREG_CALLED_BIT (1)
37 #define MODEM_CHAT_UTEST_ON_CGREG_CALLED_BIT (2)
38 #define MODEM_CHAT_UTEST_ON_QENG_SERVINGCELL_CALLED_BIT (3)
39 #define MODEM_CHAT_UTEST_ON_NO_CARRIER_CALLED_BIT (4)
40 #define MODEM_CHAT_UTEST_ON_ERROR_CALLED_BIT (5)
41 #define MODEM_CHAT_UTEST_ON_RDY_CALLED_BIT (6)
42 #define MODEM_CHAT_UTEST_ON_APP_RDY_CALLED_BIT (7)
43 #define MODEM_CHAT_UTEST_ON_NORMAL_POWER_DOWN_CALLED_BIT (8)
44 #define MODEM_CHAT_UTEST_ON_SCRIPT_CALLBACK_BIT (9)
45 #define MODEM_CHAT_UTEST_ON_CMGL_PARTIAL_CALLED_BIT (10)
46 #define MODEM_CHAT_UTEST_ON_CMGL_PARTIAL_ANY_CALLED_BIT (11)
47
48 static atomic_t callback_called;
49
50 /*************************************************************************************************/
51 /* Script callbacks args copy */
52 /*************************************************************************************************/
53 static uint8_t argv_buffers[32][128];
54 static uint16_t argc_buffers;
55
clone_args(char ** argv,uint16_t argc)56 static void clone_args(char **argv, uint16_t argc)
57 {
58 argc_buffers = argc;
59
60 for (uint16_t i = 0; i < argc; i++) {
61 memcpy(argv_buffers[i], argv[i], strlen(argv[i]) + 1);
62 }
63 }
64
65 /*************************************************************************************************/
66 /* Script match callbacks */
67 /*************************************************************************************************/
on_imei(struct modem_chat * cmd,char ** argv,uint16_t argc,void * user_data)68 static void on_imei(struct modem_chat *cmd, char **argv, uint16_t argc, void *user_data)
69 {
70 atomic_set_bit(&callback_called, MODEM_CHAT_UTEST_ON_IMEI_CALLED_BIT);
71 clone_args(argv, argc);
72 }
73
on_creg(struct modem_chat * cmd,char ** argv,uint16_t argc,void * user_data)74 static void on_creg(struct modem_chat *cmd, char **argv, uint16_t argc, void *user_data)
75 {
76 atomic_set_bit(&callback_called, MODEM_CHAT_UTEST_ON_CREG_CALLED_BIT);
77 clone_args(argv, argc);
78 }
79
on_cgreg(struct modem_chat * cmd,char ** argv,uint16_t argc,void * user_data)80 static void on_cgreg(struct modem_chat *cmd, char **argv, uint16_t argc, void *user_data)
81 {
82 atomic_set_bit(&callback_called, MODEM_CHAT_UTEST_ON_CGREG_CALLED_BIT);
83 clone_args(argv, argc);
84 }
85
on_qeng_serving_cell(struct modem_chat * cmd,char ** argv,uint16_t argc,void * user_data)86 static void on_qeng_serving_cell(struct modem_chat *cmd, char **argv, uint16_t argc,
87 void *user_data)
88 {
89 atomic_set_bit(&callback_called, MODEM_CHAT_UTEST_ON_QENG_SERVINGCELL_CALLED_BIT);
90 clone_args(argv, argc);
91 }
92
on_no_carrier(struct modem_chat * cmd,char ** argv,uint16_t argc,void * user_data)93 static void on_no_carrier(struct modem_chat *cmd, char **argv, uint16_t argc, void *user_data)
94 {
95 atomic_set_bit(&callback_called, MODEM_CHAT_UTEST_ON_NO_CARRIER_CALLED_BIT);
96 clone_args(argv, argc);
97 }
98
on_error(struct modem_chat * cmd,char ** argv,uint16_t argc,void * user_data)99 static void on_error(struct modem_chat *cmd, char **argv, uint16_t argc, void *user_data)
100 {
101 atomic_set_bit(&callback_called, MODEM_CHAT_UTEST_ON_ERROR_CALLED_BIT);
102 clone_args(argv, argc);
103 }
104
on_rdy(struct modem_chat * cmd,char ** argv,uint16_t argc,void * user_data)105 static void on_rdy(struct modem_chat *cmd, char **argv, uint16_t argc, void *user_data)
106 {
107 atomic_set_bit(&callback_called, MODEM_CHAT_UTEST_ON_RDY_CALLED_BIT);
108 clone_args(argv, argc);
109 }
110
on_app_rdy(struct modem_chat * cmd,char ** argv,uint16_t argc,void * user_data)111 static void on_app_rdy(struct modem_chat *cmd, char **argv, uint16_t argc, void *user_data)
112 {
113 atomic_set_bit(&callback_called, MODEM_CHAT_UTEST_ON_APP_RDY_CALLED_BIT);
114 clone_args(argv, argc);
115 }
116
on_normal_power_down(struct modem_chat * cmd,char ** argv,uint16_t argc,void * user_data)117 static void on_normal_power_down(struct modem_chat *cmd, char **argv, uint16_t argc,
118 void *user_data)
119 {
120 atomic_set_bit(&callback_called, MODEM_CHAT_UTEST_ON_NORMAL_POWER_DOWN_CALLED_BIT);
121 clone_args(argv, argc);
122 }
123
on_cmgl_partial(struct modem_chat * cmd,char ** argv,uint16_t argc,void * user_data)124 static void on_cmgl_partial(struct modem_chat *cmd, char **argv, uint16_t argc, void *user_data)
125 {
126 atomic_set_bit(&callback_called, MODEM_CHAT_UTEST_ON_CMGL_PARTIAL_CALLED_BIT);
127 clone_args(argv, argc);
128 }
129
on_cmgl_any_partial(struct modem_chat * cmd,char ** argv,uint16_t argc,void * user_data)130 static void on_cmgl_any_partial(struct modem_chat *cmd, char **argv, uint16_t argc,
131 void *user_data)
132 {
133 atomic_set_bit(&callback_called, MODEM_CHAT_UTEST_ON_CMGL_PARTIAL_ANY_CALLED_BIT);
134 clone_args(argv, argc);
135 }
136
137 /*************************************************************************************************/
138 /* Script callback */
139 /*************************************************************************************************/
140 static enum modem_chat_script_result script_result;
141 static void *script_result_user_data;
142
on_script_result(struct modem_chat * cmd,enum modem_chat_script_result result,void * user_data)143 static void on_script_result(struct modem_chat *cmd, enum modem_chat_script_result result,
144 void *user_data)
145 {
146 atomic_set_bit(&callback_called, MODEM_CHAT_UTEST_ON_SCRIPT_CALLBACK_BIT);
147 script_result = result;
148 script_result_user_data = user_data;
149 }
150
151 /*************************************************************************************************/
152 /* Script */
153 /*************************************************************************************************/
154 MODEM_CHAT_MATCH_DEFINE(ok_match, "OK", "", NULL);
155 MODEM_CHAT_MATCH_DEFINE(imei_match, "", "", on_imei);
156 MODEM_CHAT_MATCH_DEFINE(creg_match, "CREG: ", ",", on_creg);
157 MODEM_CHAT_MATCH_DEFINE(cgreg_match, "CGREG: ", ",", on_cgreg);
158 MODEM_CHAT_MATCH_DEFINE(qeng_servinc_cell_match, "+QENG: \"servingcell\",", ",",
159 on_qeng_serving_cell);
160
161 MODEM_CHAT_MATCHES_DEFINE(unsol_matches, MODEM_CHAT_MATCH("RDY", "", on_rdy),
162 MODEM_CHAT_MATCH("APP RDY", "", on_app_rdy),
163 MODEM_CHAT_MATCH("NORMAL POWER DOWN", "", on_normal_power_down));
164
165 MODEM_CHAT_SCRIPT_CMDS_DEFINE(
166 script_cmds, MODEM_CHAT_SCRIPT_CMD_RESP("AT", ok_match),
167 MODEM_CHAT_SCRIPT_CMD_RESP("ATE0", ok_match),
168 MODEM_CHAT_SCRIPT_CMD_RESP("IMEI?", imei_match), MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match),
169 MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG?;+CGREG?", creg_match),
170 MODEM_CHAT_SCRIPT_CMD_RESP("", cgreg_match), MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match),
171 MODEM_CHAT_SCRIPT_CMD_RESP("AT+QENG=\"servingcell\"", qeng_servinc_cell_match),
172 MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match));
173
174 MODEM_CHAT_MATCHES_DEFINE(abort_matches, MODEM_CHAT_MATCH("NO CARRIER", "", on_no_carrier),
175 MODEM_CHAT_MATCH("ERROR ", ",:", on_error));
176
177 MODEM_CHAT_SCRIPT_DEFINE(script, script_cmds, abort_matches, on_script_result, 4);
178
179 /*************************************************************************************************/
180 /* Script implementing partial matches */
181 /*************************************************************************************************/
182 MODEM_CHAT_MATCHES_DEFINE(
183 cmgl_matches,
184 MODEM_CHAT_MATCH_INITIALIZER("+CMGL: ", ",", on_cmgl_partial, false, true),
185 MODEM_CHAT_MATCH_INITIALIZER("", "", on_cmgl_any_partial, false, true),
186 MODEM_CHAT_MATCH_INITIALIZER("OK", "", NULL, false, false)
187 );
188
189 MODEM_CHAT_SCRIPT_CMDS_DEFINE(
190 script_partial_cmds,
191 MODEM_CHAT_SCRIPT_CMD_RESP_MULT("AT+CMGL=4", cmgl_matches),
192 );
193
194 MODEM_CHAT_SCRIPT_DEFINE(script_partial, script_partial_cmds, abort_matches, on_script_result, 4);
195
196 /*************************************************************************************************/
197 /* Script containing timeout script chat command */
198 /*************************************************************************************************/
199 MODEM_CHAT_SCRIPT_CMDS_DEFINE(
200 script_timeout_cmd_cmds,
201 MODEM_CHAT_SCRIPT_CMD_RESP("AT", ok_match),
202 MODEM_CHAT_SCRIPT_CMD_RESP_NONE("", 4000),
203 MODEM_CHAT_SCRIPT_CMD_RESP("AT", ok_match),
204 );
205
206 MODEM_CHAT_SCRIPT_DEFINE(script_timeout_cmd, script_timeout_cmd_cmds, abort_matches,
207 on_script_result, 10);
208
209 /*************************************************************************************************/
210 /* Small echo script and mock transactions */
211 /*************************************************************************************************/
212 static const uint8_t at_echo_data[] = {'A', 'T', '\r', '\n'};
213 static const struct modem_backend_mock_transaction at_echo_transaction = {
214 .get = at_echo_data,
215 .get_size = sizeof(at_echo_data),
216 .put = at_echo_data,
217 .put_size = sizeof(at_echo_data),
218 };
219
220 static const uint8_t at_echo_error_data[] = {'E', 'R', 'R', 'O', 'R', ' ', '1', '\r', '\n'};
221 static const struct modem_backend_mock_transaction at_echo_error_transaction = {
222 .get = at_echo_data,
223 .get_size = sizeof(at_echo_data),
224 .put = at_echo_error_data,
225 .put_size = sizeof(at_echo_error_data),
226 };
227
228 MODEM_CHAT_MATCH_DEFINE(at_match, "AT", "", NULL);
229
230 MODEM_CHAT_SCRIPT_CMDS_DEFINE(
231 script_echo_cmds,
232 MODEM_CHAT_SCRIPT_CMD_RESP("AT", at_match),
233 );
234
235 MODEM_CHAT_SCRIPT_DEFINE(script_echo, script_echo_cmds, abort_matches, on_script_result, 4);
236
237 /*************************************************************************************************/
238 /* Script responses */
239 /*************************************************************************************************/
240 static const char at_response[] = "AT\r\n";
241 static const char ok_response[] = "OK\r\n";
242 static const char imei_response[] = "23412354123123\r\n";
243 static const char creg_response[] = "CREG: 1,2\r\n";
244 static const char cgreg_response[] = "CGREG: 10,43\r\n";
245
246 static const char qeng_servinc_cell_response[] = "+QENG: \"servingcell\",\"NOCONN\",\"GSM\",260"
247 ",03,E182,AEAD,52,32,2,-68,255,255,0,38,38,1,,"
248 ",,,,,,,,\r\n";
249
250 static const char cmgl_response_0[] = "+CMGL: 1,1,,50\r\n";
251 static const char cmgl_response_1[] = "07911326060032F064A9542954\r\n";
252
253 /*************************************************************************************************/
254 /* Test setup */
255 /*************************************************************************************************/
test_modem_chat_setup(void)256 static void *test_modem_chat_setup(void)
257 {
258 const struct modem_chat_config cmd_config = {
259 .user_data = &cmd_user_data,
260 .receive_buf = cmd_receive_buf,
261 .receive_buf_size = ARRAY_SIZE(cmd_receive_buf),
262 .delimiter = cmd_delimiter,
263 .delimiter_size = ARRAY_SIZE(cmd_delimiter),
264 .filter = NULL,
265 .filter_size = 0,
266 .argv = cmd_argv,
267 .argv_size = ARRAY_SIZE(cmd_argv),
268 .unsol_matches = unsol_matches,
269 .unsol_matches_size = ARRAY_SIZE(unsol_matches),
270 };
271
272 zassert(modem_chat_init(&cmd, &cmd_config) == 0, "Failed to init modem CMD");
273
274 const struct modem_backend_mock_config mock_config = {
275 .rx_buf = mock_rx_buf,
276 .rx_buf_size = ARRAY_SIZE(mock_rx_buf),
277 .tx_buf = mock_tx_buf,
278 .tx_buf_size = ARRAY_SIZE(mock_tx_buf),
279 .limit = 8,
280 };
281
282 mock_pipe = modem_backend_mock_init(&mock, &mock_config);
283 zassert(modem_pipe_open(mock_pipe, K_SECONDS(10)) == 0, "Failed to open mock pipe");
284 zassert(modem_chat_attach(&cmd, mock_pipe) == 0, "Failed to attach pipe mock to modem CMD");
285 return NULL;
286 }
287
test_modem_chat_before(void * f)288 static void test_modem_chat_before(void *f)
289 {
290 /* Reset callback called */
291 atomic_set(&callback_called, 0);
292
293 /* Reset mock pipe */
294 modem_backend_mock_reset(&mock);
295 }
296
test_modem_chat_after(void * f)297 static void test_modem_chat_after(void *f)
298 {
299 /* Abort script */
300 modem_chat_script_abort(&cmd);
301
302 k_msleep(100);
303 }
304
305 /*************************************************************************************************/
306 /* Buffers */
307 /*************************************************************************************************/
308 static uint8_t buffer[4096];
309
310 /*************************************************************************************************/
311 /* Tests */
312 /*************************************************************************************************/
ZTEST(modem_chat,test_script_no_error)313 ZTEST(modem_chat, test_script_no_error)
314 {
315 bool called;
316
317 zassert_true(modem_chat_script_run(&cmd, &script) == 0, "Failed to start script");
318 k_msleep(100);
319
320 /*
321 * Script sends "AT\r\n"
322 * Modem responds "AT\r\n"
323 * Modem responds "OK\r\n"
324 */
325
326 modem_backend_mock_get(&mock, buffer, ARRAY_SIZE(buffer));
327 zassert_true(memcmp(buffer, "AT\r", sizeof("AT\r") - 1) == 0,
328 "Request not sent as expected");
329
330 modem_backend_mock_put(&mock, at_response, sizeof(at_response) - 1);
331 modem_backend_mock_put(&mock, ok_response, sizeof(ok_response) - 1);
332
333 k_msleep(100);
334
335 /*
336 * Script sends "ATE0\r\n"
337 * Modem responds "OK\r\n"
338 */
339
340 modem_backend_mock_get(&mock, buffer, ARRAY_SIZE(buffer));
341 zassert_true(memcmp(buffer, "ATE0\r\n", sizeof("ATE0\r\n") - 1) == 0,
342 "Request not sent as expected");
343
344 modem_backend_mock_put(&mock, ok_response, sizeof(ok_response) - 1);
345
346 k_msleep(100);
347
348 /*
349 * Script sends "IMEI?\r\n"
350 * Modem responds "23412354123123\r\n"
351 * Modem responds "OK\r\n"
352 */
353
354 modem_backend_mock_get(&mock, buffer, ARRAY_SIZE(buffer));
355 zassert_true(memcmp(buffer, "IMEI?\r\n", sizeof("IMEI?\r\n") - 1) == 0,
356 "Request not sent as expected");
357
358 modem_backend_mock_put(&mock, imei_response, sizeof(imei_response) - 1);
359 modem_backend_mock_put(&mock, ok_response, sizeof(ok_response) - 1);
360
361 k_msleep(100);
362
363 zassert_true(atomic_test_bit(&callback_called, MODEM_CHAT_UTEST_ON_IMEI_CALLED_BIT) == true,
364 "Expected IMEI callback called");
365
366 zassert_true(argv_buffers[0][0] == '\0', "Unexpected argv");
367 zassert_true(memcmp(argv_buffers[1], "23412354123123", sizeof("23412354123123")) == 0,
368 "Unexpected argv");
369
370 zassert_true(argc_buffers == 2, "Unexpected argc");
371
372 /*
373 * Script sends "AT+CREG?;+CGREG?\r\n"
374 * Modem responds "CREG: 1,2\r\n"
375 * Modem responds "CGREG: 1,2\r\n"
376 * Modem responds "OK\r\n"
377 */
378
379 modem_backend_mock_get(&mock, buffer, ARRAY_SIZE(buffer));
380 zassert_true(memcmp(buffer, "AT+CREG?;+CGREG?\r\n", sizeof("AT+CREG?;+CGREG?\r\n") - 1) ==
381 0,
382 "Request not sent as expected");
383
384 modem_backend_mock_put(&mock, creg_response, sizeof(creg_response) - 1);
385
386 k_msleep(100);
387
388 zassert_true(memcmp(argv_buffers[0], "CREG: ", sizeof("CREG: ")) == 0, "Unexpected argv");
389 zassert_true(memcmp(argv_buffers[1], "1", sizeof("1")) == 0, "Unexpected argv");
390 zassert_true(memcmp(argv_buffers[2], "2", sizeof("2")) == 0, "Unexpected argv");
391 zassert_true(argc_buffers == 3, "Unexpected argc");
392 modem_backend_mock_put(&mock, cgreg_response, sizeof(cgreg_response) - 1);
393
394 k_msleep(100);
395
396 zassert_true(memcmp(argv_buffers[0], "CGREG: ", sizeof("CGREG: ")) == 0, "Unexpected argv");
397 zassert_true(memcmp(argv_buffers[1], "10", sizeof("10")) == 0, "Unexpected argv");
398 zassert_true(memcmp(argv_buffers[2], "43", sizeof("43")) == 0, "Unexpected argv");
399 zassert_true(argc_buffers == 3, "Unexpected argc");
400 modem_backend_mock_put(&mock, ok_response, sizeof(ok_response) - 1);
401
402 k_msleep(100);
403
404 /*
405 * Script sends "AT+QENG=\"servingcell\"\r\n"
406 * Modem responds qeng_servinc_cell_response (long string)
407 * Modem responds "OK\r\n"
408 */
409
410 modem_backend_mock_get(&mock, buffer, ARRAY_SIZE(buffer));
411 zassert_true(memcmp(buffer, "AT+QENG=\"servingcell\"\r\n",
412 sizeof("AT+QENG=\"servingcell\"\r\n") - 1) == 0,
413 "Request not sent as expected");
414
415 modem_backend_mock_put(&mock, qeng_servinc_cell_response,
416 sizeof(qeng_servinc_cell_response) - 1);
417
418 k_msleep(100);
419
420 zassert_true(memcmp(argv_buffers[0], "+QENG: \"servingcell\",",
421 sizeof("+QENG: \"servingcell\",")) == 0,
422 "Unexpected argv");
423
424 zassert_true(memcmp(argv_buffers[1], "\"NOCONN\"", sizeof("\"NOCONN\"")) == 0,
425 "Unexpected argv");
426
427 zassert_true(memcmp(argv_buffers[10], "-68", sizeof("-68")) == 0, "Unexpected argv");
428 zassert_true(argv_buffers[25][0] == '\0', "Unexpected argv");
429 zassert_true(argc_buffers == 26, "Unexpected argc");
430
431 /*
432 * Script ends after modem responds OK
433 */
434
435 called = atomic_test_bit(&callback_called, MODEM_CHAT_UTEST_ON_SCRIPT_CALLBACK_BIT);
436 zassert_true(called == false, "Script callback should not have been called yet");
437 modem_backend_mock_put(&mock, ok_response, sizeof(ok_response) - 1);
438
439 k_msleep(100);
440
441 called = atomic_test_bit(&callback_called, MODEM_CHAT_UTEST_ON_SCRIPT_CALLBACK_BIT);
442 zassert_true(called == true, "Script callback should have been called");
443 zassert_true(script_result == MODEM_CHAT_SCRIPT_RESULT_SUCCESS,
444 "Script result should be SUCCESS");
445 zassert_true(script_result_user_data == &cmd_user_data,
446 "Script result callback user data is incorrect");
447 }
448
ZTEST(modem_chat,test_start_script_twice_then_abort)449 ZTEST(modem_chat, test_start_script_twice_then_abort)
450 {
451 bool called;
452
453 zassert_true(modem_chat_script_run(&cmd, &script) == 0, "Failed to start script");
454
455 k_msleep(100);
456
457 zassert_true(modem_chat_script_run(&cmd, &script) == -EBUSY,
458 "Started new script while script is running");
459
460 called = atomic_test_bit(&callback_called, MODEM_CHAT_UTEST_ON_SCRIPT_CALLBACK_BIT);
461 zassert_true(called == false, "Script callback should not have been called yet");
462 modem_chat_script_abort(&cmd);
463
464 k_msleep(100);
465
466 called = atomic_test_bit(&callback_called, MODEM_CHAT_UTEST_ON_SCRIPT_CALLBACK_BIT);
467 zassert_true(called == true, "Script callback should have been called");
468 zassert_true(script_result == MODEM_CHAT_SCRIPT_RESULT_ABORT,
469 "Script result should be ABORT");
470 zassert_true(script_result_user_data == &cmd_user_data,
471 "Script result callback user data is incorrect");
472 }
473
ZTEST(modem_chat,test_start_script_then_time_out)474 ZTEST(modem_chat, test_start_script_then_time_out)
475 {
476 bool called;
477
478 zassert_true(modem_chat_script_run(&cmd, &script) == 0, "Failed to start script");
479 k_msleep(100);
480
481 called = atomic_test_bit(&callback_called, MODEM_CHAT_UTEST_ON_SCRIPT_CALLBACK_BIT);
482 zassert_true(called == false, "Script callback should not have been called yet");
483
484 k_msleep(5900);
485
486 called = atomic_test_bit(&callback_called, MODEM_CHAT_UTEST_ON_SCRIPT_CALLBACK_BIT);
487 zassert_true(called == true, "Script callback should have been called");
488 zassert_true(script_result == MODEM_CHAT_SCRIPT_RESULT_TIMEOUT,
489 "Script result should be TIMEOUT");
490 zassert_true(script_result_user_data == &cmd_user_data,
491 "Script result callback user data is incorrect");
492 }
493
ZTEST(modem_chat,test_script_with_partial_matches)494 ZTEST(modem_chat, test_script_with_partial_matches)
495 {
496 bool called;
497
498 zassert_true(modem_chat_script_run(&cmd, &script_partial) == 0, "Failed to start script");
499 k_msleep(100);
500
501 /*
502 * Script sends "AT+CMGL=4\r";
503 */
504
505 modem_backend_mock_get(&mock, buffer, ARRAY_SIZE(buffer));
506 zassert_true(memcmp(buffer, "AT+CMGL=4\r", sizeof("AT+CMGL=4\r") - 1) == 0,
507 "Request not sent as expected");
508
509 /*
510 * Modem will return the following sequence 3 times
511 * "+CMGL: 1,1,,50\r";
512 * "07911326060032F064A9542954\r"
513 */
514
515 for (uint8_t i = 0; i < 3; i++) {
516 atomic_set(&callback_called, 0);
517 modem_backend_mock_put(&mock, cmgl_response_0, sizeof(cmgl_response_0) - 1);
518 k_msleep(100);
519
520 called = atomic_test_bit(&callback_called,
521 MODEM_CHAT_UTEST_ON_CMGL_PARTIAL_CALLED_BIT);
522 zassert_equal(called, true, "Match callback not called");
523 zassert_equal(argc_buffers, 5, "Incorrect number of args");
524 zassert_str_equal(argv_buffers[0], "+CMGL: ",
525 "Incorrect argv received");
526 zassert_str_equal(argv_buffers[1], "1",
527 "Incorrect argv received");
528 zassert_str_equal(argv_buffers[2], "1",
529 "Incorrect argv received");
530 zassert_str_equal(argv_buffers[3], "",
531 "Incorrect argv received");
532 zassert_str_equal(argv_buffers[4], "50",
533 "Incorrect argv received");
534
535 atomic_set(&callback_called, 0);
536 modem_backend_mock_put(&mock, cmgl_response_1, sizeof(cmgl_response_1) - 1);
537 k_msleep(100);
538
539 called = atomic_test_bit(&callback_called,
540 MODEM_CHAT_UTEST_ON_CMGL_PARTIAL_ANY_CALLED_BIT);
541 zassert_equal(called, true, "Match callback not called");
542 zassert_equal(argc_buffers, 2, "Incorrect number of args");
543 zassert_str_equal(argv_buffers[0], "",
544 "Incorrect argv received");
545 zassert_str_equal(argv_buffers[1],
546 "07911326060032F064A9542954",
547 "Incorrect argv received");
548 }
549
550 atomic_set(&callback_called, 0);
551 modem_backend_mock_put(&mock, ok_response, sizeof(ok_response) - 1);
552 k_msleep(100);
553
554 /*
555 * Modem returns "OK\r"
556 * Script terminates
557 */
558
559 called = atomic_test_bit(&callback_called, MODEM_CHAT_UTEST_ON_SCRIPT_CALLBACK_BIT);
560 zassert_true(called == true, "Script callback should have been called");
561 zassert_equal(script_result, MODEM_CHAT_SCRIPT_RESULT_SUCCESS,
562 "Script should have stopped with success");
563
564 /* Assert no data was sent except the request */
565 zassert_equal(modem_backend_mock_get(&mock, buffer, ARRAY_SIZE(buffer)), 0,
566 "Script sent too many requests");
567 }
568
ZTEST(modem_chat,test_script_run_sync_complete)569 ZTEST(modem_chat, test_script_run_sync_complete)
570 {
571 modem_backend_mock_prime(&mock, &at_echo_transaction);
572 zassert_ok(modem_chat_run_script(&cmd, &script_echo), "Failed to run echo script");
573 }
574
ZTEST(modem_chat,test_script_run_sync_timeout)575 ZTEST(modem_chat, test_script_run_sync_timeout)
576 {
577 zassert_equal(modem_chat_run_script(&cmd, &script_echo), -EAGAIN,
578 "Failed to run echo script");
579 }
580
ZTEST(modem_chat,test_script_run_sync_abort)581 ZTEST(modem_chat, test_script_run_sync_abort)
582 {
583 modem_backend_mock_prime(&mock, &at_echo_error_transaction);
584 zassert_equal(modem_chat_run_script(&cmd, &script_echo), -EAGAIN,
585 "Echo script should time out and return -EAGAIN");
586 }
587
ZTEST(modem_chat,test_script_run_dynamic_script_sync)588 ZTEST(modem_chat, test_script_run_dynamic_script_sync)
589 {
590 char match[] = "AT";
591 char separators[] = ",";
592 char request[] = "AT";
593 char name[] = "Dynamic";
594
595 struct modem_chat_match stack_response_match = {
596 .match = NULL,
597 .match_size = 0,
598 .separators = NULL,
599 .separators_size = 0,
600 .wildcards = false,
601 .partial = false,
602 .callback = NULL,
603 };
604
605 struct modem_chat_script_chat stack_script_chat = {
606 .request = NULL,
607 .response_matches = &stack_response_match,
608 .response_matches_size = 1,
609 .timeout = 0,
610 };
611
612 struct modem_chat_script stack_script = {
613 .name = name,
614 .script_chats = &stack_script_chat,
615 .script_chats_size = 1,
616 .abort_matches = NULL,
617 .abort_matches_size = 0,
618 .callback = NULL,
619 .timeout = 1,
620 };
621
622 stack_response_match.match = match;
623 stack_response_match.match_size = strlen(match);
624 stack_response_match.separators = separators;
625 stack_response_match.separators_size = strlen(match);
626 stack_script_chat.request = request;
627 stack_script_chat.request_size = strlen(request);
628
629 modem_backend_mock_prime(&mock, &at_echo_transaction);
630 zassert_ok(modem_chat_run_script(&cmd, &stack_script), "Failed to run script");
631 }
632
ZTEST(modem_chat,test_script_chat_timeout_cmd)633 ZTEST(modem_chat, test_script_chat_timeout_cmd)
634 {
635 int ret;
636 bool called;
637
638 zassert_ok(modem_chat_run_script_async(&cmd, &script_timeout_cmd),
639 "Failed to start script");
640 k_msleep(100);
641
642 /*
643 * Script sends "AT\r\n";
644 */
645 ret = modem_backend_mock_get(&mock, buffer, ARRAY_SIZE(buffer));
646 zassert_equal(ret, sizeof("AT\r\n") - 1);
647 zassert_true(memcmp(buffer, "AT\r\n", sizeof("AT\r\n") - 1) == 0,
648 "Request not sent as expected");
649
650 /*
651 * Modem responds OK
652 */
653 modem_backend_mock_put(&mock, ok_response, sizeof(ok_response) - 1);
654
655 /*
656 * Script waits 4 seconds
657 */
658 k_msleep(3000);
659 zassert_equal(modem_backend_mock_get(&mock, buffer, ARRAY_SIZE(buffer)), 0);
660 k_msleep(2000);
661
662 /*
663 * Script sends "AT\r\n";
664 */
665 ret = modem_backend_mock_get(&mock, buffer, ARRAY_SIZE(buffer));
666 zassert_equal(ret, sizeof("AT\r\n") - 1);
667 zassert_true(memcmp(buffer, "AT\r\n", sizeof("AT\r\n") - 1) == 0,
668 "Request not sent as expected");
669
670 /*
671 * Modem responds OK
672 */
673 modem_backend_mock_put(&mock, ok_response, sizeof(ok_response) - 1);
674 k_msleep(100);
675
676 called = atomic_test_bit(&callback_called, MODEM_CHAT_UTEST_ON_SCRIPT_CALLBACK_BIT);
677 zassert_true(called == true, "Script callback should have been called");
678 zassert_equal(script_result, MODEM_CHAT_SCRIPT_RESULT_SUCCESS,
679 "Script should have stopped with success");
680
681 /* Assert no data was sent except the request */
682 zassert_equal(modem_backend_mock_get(&mock, buffer, ARRAY_SIZE(buffer)), 0,
683 "Script sent too many requests");
684 }
685
ZTEST(modem_chat,test_runtime_match)686 ZTEST(modem_chat, test_runtime_match)
687 {
688 int ret;
689 struct modem_chat_match test_match;
690
691 modem_chat_match_init(&test_match);
692
693 ret = modem_chat_match_set_match(&test_match, "AT345");
694 zassert_ok(ret, "Failed to set match");
695 zassert_ok(strcmp(test_match.match, "AT345"), "Failed to set match");
696 zassert_equal(test_match.match_size, 5, "Failed to set size of match");
697
698 ret = modem_chat_match_set_separators(&test_match, ",*");
699 zassert_ok(ret, "Failed to set match");
700 zassert_ok(strcmp(test_match.separators, ",*"), "Failed to set separators");
701 zassert_equal(test_match.separators_size, 2, "Failed to set size of separators");
702
703 modem_chat_match_set_partial(&test_match, true);
704 zassert_equal(test_match.partial, true);
705 modem_chat_match_set_partial(&test_match, false);
706 zassert_equal(test_match.partial, false);
707
708 modem_chat_match_enable_wildcards(&test_match, true);
709 zassert_equal(test_match.wildcards, true);
710 modem_chat_match_enable_wildcards(&test_match, false);
711 zassert_equal(test_match.wildcards, false);
712 }
713
ZTEST(modem_chat,test_runtime_script_chat)714 ZTEST(modem_chat, test_runtime_script_chat)
715 {
716 int ret;
717 struct modem_chat_script_chat test_script_chat;
718 struct modem_chat_match test_response_matches[2];
719
720 modem_chat_script_chat_init(&test_script_chat);
721
722 ret = modem_chat_script_chat_set_request(&test_script_chat, "AT345");
723 zassert_ok(ret, "Failed to set request");
724 zassert_ok(strcmp(test_script_chat.request, "AT345"), "Failed to set script_chat");
725 zassert_equal(test_script_chat.request_size, 5, "Failed to set size of script_chat");
726
727 ret = modem_chat_script_chat_set_response_matches(&test_script_chat,
728 test_response_matches,
729 ARRAY_SIZE(test_response_matches));
730 zassert_ok(ret, "Failed to set response matches");
731 zassert_equal(test_script_chat.response_matches, test_response_matches,
732 "Failed to set response_matches");
733 zassert_equal(test_script_chat.response_matches_size, ARRAY_SIZE(test_response_matches),
734 "Failed to set response_matches");
735
736 ret = modem_chat_script_chat_set_response_matches(&test_script_chat,
737 test_response_matches, 0);
738 zassert_equal(ret, -EINVAL, "Should have failed to set response matches");
739
740 ret = modem_chat_script_chat_set_response_matches(&test_script_chat, NULL, 1);
741 zassert_equal(ret, -EINVAL, "Should have failed to set response matches");
742 }
743
ZTEST(modem_chat,test_runtime_script)744 ZTEST(modem_chat, test_runtime_script)
745 {
746 int ret;
747 struct modem_chat_script test_script;
748 struct modem_chat_script_chat test_script_chats[2];
749 struct modem_chat_match test_abort_matches[2];
750
751 modem_chat_script_init(&test_script);
752 zassert_equal(strlen(test_script.name), 0, "Failed to set default name");
753
754 ret = modem_chat_script_set_script_chats(&test_script, test_script_chats,
755 ARRAY_SIZE(test_script_chats));
756 zassert_ok(ret, "Failed to set script chats");
757 zassert_equal(test_script.script_chats, test_script_chats,
758 "Failed to set script_chats");
759 zassert_equal(test_script.script_chats_size, ARRAY_SIZE(test_script_chats),
760 "Failed to set script_chats_size");
761
762 ret = modem_chat_script_set_script_chats(&test_script, test_script_chats, 0);
763 zassert_equal(ret, -EINVAL, "Should have failed to set script chats");
764
765 ret = modem_chat_script_set_script_chats(&test_script, NULL, 1);
766 zassert_equal(ret, -EINVAL, "Should have failed to set script chats");
767
768 ret = modem_chat_script_set_abort_matches(&test_script, test_abort_matches,
769 ARRAY_SIZE(test_abort_matches));
770 zassert_ok(ret, "Failed to set abort matches");
771 zassert_equal(test_script.abort_matches, test_abort_matches,
772 "Failed to set script_chats");
773 zassert_equal(test_script.abort_matches_size, ARRAY_SIZE(test_abort_matches),
774 "Failed to set script_chats_size");
775
776 ret = modem_chat_script_set_abort_matches(&test_script, test_abort_matches, 0);
777 zassert_equal(ret, -EINVAL, "Should have failed to set abort matches");
778
779 ret = modem_chat_script_set_abort_matches(&test_script, NULL, 1);
780 zassert_equal(ret, -EINVAL, "Should have failed to set abort matches");
781 }
782
783 /*************************************************************************************************/
784 /* Test suite */
785 /*************************************************************************************************/
786 ZTEST_SUITE(modem_chat, NULL, test_modem_chat_setup, test_modem_chat_before, test_modem_chat_after,
787 NULL);
788