1 /*
2  * Copyright (c) 2022 Trackunit Corporation
3  * Copyright (c) 2025 Croxel Inc.
4  * Copyright (c) 2025 CogniPilot Foundation
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 #include <zephyr/ztest.h>
10 #include <zephyr/kernel.h>
11 
12 #include <zephyr/modem/ubx.h>
13 #include <zephyr/modem/ubx/protocol.h>
14 #include <modem_backend_mock.h>
15 
16 static struct modem_ubx cmd;
17 
18 static uint32_t cmd_user_data = 0x145212;
19 static uint8_t cmd_receive_buf[128];
20 
21 static uint8_t cmd_response[128];
22 
23 static struct modem_backend_mock mock;
24 static uint8_t mock_rx_buf[128];
25 static uint8_t mock_tx_buf[128];
26 static struct modem_pipe *mock_pipe;
27 
28 #define MODEM_UBX_UTEST_ON_NAK_RECEIVED_BIT	(0)
29 #define MODEM_UBX_UTEST_ON_ACK_RECEIVED_BIT	(1)
30 
31 static atomic_t callback_called;
32 
on_nak_received(struct modem_ubx * ubx,const struct ubx_frame * frame,size_t len,void * user_data)33 static void on_nak_received(struct modem_ubx *ubx, const struct ubx_frame *frame, size_t len,
34 			    void *user_data)
35 {
36 	atomic_set_bit(&callback_called, MODEM_UBX_UTEST_ON_NAK_RECEIVED_BIT);
37 }
38 
on_ack_received(struct modem_ubx * ubx,const struct ubx_frame * frame,size_t len,void * user_data)39 static void on_ack_received(struct modem_ubx *ubx, const struct ubx_frame *frame, size_t len,
40 			    void *user_data)
41 {
42 	atomic_set_bit(&callback_called, MODEM_UBX_UTEST_ON_ACK_RECEIVED_BIT);
43 }
44 
45 MODEM_UBX_MATCH_ARRAY_DEFINE(unsol_matches,
46 	MODEM_UBX_MATCH_DEFINE(UBX_CLASS_ID_ACK, UBX_MSG_ID_ACK, on_ack_received),
47 	MODEM_UBX_MATCH_DEFINE(UBX_CLASS_ID_ACK, UBX_MSG_ID_NAK, on_nak_received)
48 );
49 
50 static struct ubx_frame test_req = UBX_FRAME_ACK_INITIALIZER(0x01, 0x02);
51 
52 struct script_runner {
53 	struct modem_ubx_script script;
54 	struct {
55 		bool done;
56 		int ret;
57 	} result;
58 };
59 
60 static struct script_runner test_script_runner;
61 
test_setup(void)62 static void *test_setup(void)
63 {
64 	const struct modem_ubx_config cmd_config = {
65 		.user_data = &cmd_user_data,
66 		.receive_buf = cmd_receive_buf,
67 		.receive_buf_size = ARRAY_SIZE(cmd_receive_buf),
68 		.unsol_matches = {
69 			.array = unsol_matches,
70 			.size = ARRAY_SIZE(unsol_matches),
71 		},
72 	};
73 
74 	zassert(modem_ubx_init(&cmd, &cmd_config) == 0, "Failed to init modem CMD");
75 
76 	const struct modem_backend_mock_config mock_config = {
77 		.rx_buf = mock_rx_buf,
78 		.rx_buf_size = ARRAY_SIZE(mock_rx_buf),
79 		.tx_buf = mock_tx_buf,
80 		.tx_buf_size = ARRAY_SIZE(mock_tx_buf),
81 		.limit = 128,
82 	};
83 
84 	mock_pipe = modem_backend_mock_init(&mock, &mock_config);
85 	zassert(modem_pipe_open(mock_pipe, K_SECONDS(10)) == 0, "Failed to open mock pipe");
86 	zassert(modem_ubx_attach(&cmd, mock_pipe) == 0, "Failed to attach pipe mock to modem CMD");
87 
88 	return NULL;
89 }
90 
restore_ubx_script(void)91 static inline void restore_ubx_script(void)
92 {
93 	static const struct ubx_frame frame_restored = UBX_FRAME_ACK_INITIALIZER(0x01, 0x02);
94 	const struct script_runner script_runner_restored = {
95 		.script = {
96 			.request = {
97 				.buf = &test_req,
98 				.len = UBX_FRAME_SZ(frame_restored.payload_size),
99 			},
100 			.match = MODEM_UBX_MATCH_DEFINE(UBX_CLASS_ID_ACK, UBX_MSG_ID_ACK, NULL),
101 			.response = {
102 				.buf = cmd_response,
103 				.buf_len = sizeof(cmd_response),
104 			},
105 			.timeout = K_SECONDS(1),
106 		},
107 	};
108 
109 	test_script_runner = script_runner_restored;
110 	test_req = frame_restored;
111 }
112 
test_before(void * f)113 static void test_before(void *f)
114 {
115 	atomic_set(&callback_called, 0);
116 	modem_backend_mock_reset(&mock);
117 	restore_ubx_script();
118 }
119 
120 ZTEST_SUITE(modem_ubx, NULL, test_setup, test_before, NULL, NULL);
121 
122 static K_THREAD_STACK_ARRAY_DEFINE(stacks, 3, 2048);
123 static struct k_thread threads[3];
124 
script_runner_handler(void * val,void * unused1,void * unused2)125 static void script_runner_handler(void *val, void *unused1, void *unused2)
126 {
127 	struct script_runner *runner = (struct script_runner *)val;
128 
129 	int ret = modem_ubx_run_script(&cmd, &runner->script);
130 
131 	runner->result.done = true;
132 	runner->result.ret = ret;
133 }
134 
script_runner_start(struct script_runner * runner,uint8_t idx)135 static inline void script_runner_start(struct script_runner *runner, uint8_t idx)
136 {
137 	k_thread_create(&threads[idx],
138 			stacks[idx],
139 			K_THREAD_STACK_SIZEOF(stacks[idx]),
140 			script_runner_handler,
141 			runner, NULL, NULL,
142 			K_PRIO_COOP(CONFIG_NUM_COOP_PRIORITIES - 1),
143 			0,
144 			K_NO_WAIT);
145 
146 	k_thread_start(&threads[idx]);
147 }
148 
test_thread_yield(void)149 static inline void test_thread_yield(void)
150 {
151 	/** Used instead of k_yield() since internals of modem pipe may rely on
152 	 * multiple thread interactions which may not be served by simply
153 	 * yielding.
154 	 */
155 	k_sleep(K_MSEC(1));
156 }
157 
ZTEST(modem_ubx,test_cmd_no_rsp_is_non_blocking)158 ZTEST(modem_ubx, test_cmd_no_rsp_is_non_blocking)
159 {
160 	/** Keep in mind this only happens if there isn't an on-going transfer
161 	 * already. If that happens, it will wait until the other script
162 	 * finishes or this request times out. Check test-case:
163 	 * test_script_is_thread_safe for details.
164 	 */
165 	uint8_t buf[256];
166 	int len;
167 
168 	/* Setting filter class to 0 means no response is to be awaited */
169 	test_script_runner.script.match.filter.class = 0;
170 
171 	script_runner_start(&test_script_runner, 0);
172 	test_thread_yield();
173 
174 	len = modem_backend_mock_get(&mock, buf, sizeof(buf));
175 
176 	zassert_true(test_script_runner.result.done, "Script should be done");
177 	zassert_ok(test_script_runner.result.ret, "%d", test_script_runner.result.ret);
178 	zassert_equal(UBX_FRAME_SZ(test_req.payload_size), len, "expected: %d, got: %d",
179 		      UBX_FRAME_SZ(test_req.payload_size), len);
180 }
181 
ZTEST(modem_ubx,test_cmd_rsp_retries_and_times_out)182 ZTEST(modem_ubx, test_cmd_rsp_retries_and_times_out)
183 {
184 	uint8_t buf[512];
185 
186 	test_script_runner.script.timeout = K_SECONDS(3);
187 	test_script_runner.script.retry_count = 2; /* 2 Retries -> 3 Tries */
188 
189 	script_runner_start(&test_script_runner, 0);
190 	test_thread_yield();
191 
192 	zassert_false(test_script_runner.result.done, "Script should not be done");
193 
194 	for (size_t i = 0 ; i < (test_script_runner.script.retry_count + 1) ; i++) {
195 
196 		int len = modem_backend_mock_get(&mock, buf, sizeof(buf));
197 
198 		zassert_false(test_script_runner.result.done, "Script should not be done. "
199 							 "Iteration: %d", i);
200 		zassert_equal(UBX_FRAME_SZ(test_req.payload_size), len,
201 			      "Payload Sent does not match. "
202 			      "Expected: %d, Received: %d, Iteration: %d",
203 			      UBX_FRAME_SZ(test_req.payload_size), len, i);
204 
205 		k_sleep(K_SECONDS(1));
206 	}
207 
208 	zassert_true(test_script_runner.result.done, "Script should be done");
209 	zassert_equal(test_script_runner.result.ret, -EAGAIN, "Script should time out");
210 }
211 
ZTEST(modem_ubx,test_cmd_rsp_blocks_and_receives_rsp)212 ZTEST(modem_ubx, test_cmd_rsp_blocks_and_receives_rsp)
213 {
214 	static struct ubx_frame test_rsp = UBX_FRAME_ACK_INITIALIZER(0x02, 0x03);
215 
216 	script_runner_start(&test_script_runner, 0);
217 	test_thread_yield();
218 
219 	zassert_false(test_script_runner.result.done, "Script should not be done");
220 
221 	modem_backend_mock_put(&mock, (uint8_t *)&test_rsp, UBX_FRAME_SZ(test_rsp.payload_size));
222 	test_thread_yield();
223 
224 	zassert_true(test_script_runner.result.done, "Script should be done");
225 	zassert_ok(test_script_runner.result.ret);
226 	zassert_equal(UBX_FRAME_SZ(test_rsp.payload_size),
227 		      test_script_runner.script.response.received_len,
228 		      "expected: %d, got: %d",
229 		      UBX_FRAME_SZ(test_rsp.payload_size),
230 		      test_script_runner.script.response.received_len);
231 }
232 
ZTEST(modem_ubx,test_script_is_thread_safe)233 ZTEST(modem_ubx, test_script_is_thread_safe)
234 {
235 	static struct ubx_frame test_rsp = UBX_FRAME_ACK_INITIALIZER(0x02, 0x03);
236 	struct script_runner script_runner_1 = {
237 		.script = {
238 			.request = {
239 				.buf = &test_req,
240 				.len = UBX_FRAME_SZ(test_req.payload_size),
241 			},
242 			.match = MODEM_UBX_MATCH_DEFINE(UBX_CLASS_ID_ACK, UBX_MSG_ID_ACK, NULL),
243 			.response = {
244 				.buf = cmd_response,
245 				.buf_len = sizeof(cmd_response),
246 			},
247 			.timeout = K_SECONDS(1),
248 		},
249 	};
250 	struct script_runner script_runner_2 = {
251 		.script = {
252 			.request = {
253 				.buf = &test_req,
254 				.len = UBX_FRAME_SZ(test_req.payload_size),
255 			},
256 			.match = MODEM_UBX_MATCH_DEFINE(UBX_CLASS_ID_ACK, UBX_MSG_ID_ACK, NULL),
257 			.response = {
258 				.buf = cmd_response,
259 				.buf_len = sizeof(cmd_response),
260 			},
261 			.timeout = K_SECONDS(1),
262 		},
263 	};
264 
265 	script_runner_start(&script_runner_1, 0);
266 	script_runner_start(&script_runner_2, 1);
267 	test_thread_yield();
268 
269 	zassert_false(script_runner_1.result.done);
270 	zassert_false(script_runner_2.result.done);
271 
272 	modem_backend_mock_put(&mock, (uint8_t *)&test_rsp, UBX_FRAME_SZ(test_rsp.payload_size));
273 	test_thread_yield();
274 
275 	zassert_true(script_runner_1.result.done);
276 	zassert_ok(script_runner_1.result.ret);
277 	zassert_false(script_runner_2.result.done);
278 
279 	modem_backend_mock_put(&mock, (uint8_t *)&test_rsp, UBX_FRAME_SZ(test_rsp.payload_size));
280 	test_thread_yield();
281 
282 	zassert_true(script_runner_2.result.done);
283 	zassert_ok(script_runner_2.result.ret);
284 }
285 
ZTEST(modem_ubx,test_rsp_filters_out_bytes_before_payload)286 ZTEST(modem_ubx, test_rsp_filters_out_bytes_before_payload)
287 {
288 	static struct ubx_frame test_rsp = UBX_FRAME_ACK_INITIALIZER(0x02, 0x03);
289 
290 	/** Create a buf that contains an "AT command" followed by the UBX frame
291 	 * we're expecting. This should be handled by the modem_ubx.
292 	 */
293 	char atcmd[] = "Here's an AT command: AT\r\nOK.";
294 	uint8_t buf[256];
295 	size_t buf_len = 0;
296 
297 	memcpy(buf, atcmd, sizeof(atcmd));
298 	buf_len += sizeof(atcmd);
299 	memcpy(buf + buf_len, &test_rsp, UBX_FRAME_SZ(test_rsp.payload_size));
300 	buf_len += UBX_FRAME_SZ(test_rsp.payload_size);
301 
302 	script_runner_start(&test_script_runner, 0);
303 	test_thread_yield();
304 
305 	zassert_false(test_script_runner.result.done, "Script should not be done");
306 
307 	modem_backend_mock_put(&mock, (uint8_t *)buf, buf_len);
308 	test_thread_yield();
309 
310 	zassert_true(test_script_runner.result.done, "Script should be done");
311 	zassert_ok(test_script_runner.result.ret);
312 	zassert_equal(UBX_FRAME_SZ(test_rsp.payload_size),
313 		      test_script_runner.script.response.received_len,
314 		      "expected: %d, got: %d",
315 		      UBX_FRAME_SZ(test_rsp.payload_size),
316 		      test_script_runner.script.response.received_len);
317 	zassert_mem_equal(&test_rsp,
318 			  test_script_runner.script.response.buf,
319 			  UBX_FRAME_SZ(test_rsp.payload_size));
320 }
321 
ZTEST(modem_ubx,test_rsp_incomplete_packet_discarded)322 ZTEST(modem_ubx, test_rsp_incomplete_packet_discarded)
323 {
324 	static struct ubx_frame test_rsp = UBX_FRAME_ACK_INITIALIZER(0x02, 0x03);
325 
326 	uint8_t buf[256];
327 	size_t buf_len = 0;
328 
329 	memcpy(buf, &test_rsp, UBX_FRAME_SZ(test_rsp.payload_size) - 5);
330 	buf_len += UBX_FRAME_SZ(test_rsp.payload_size) - 5;
331 
332 	script_runner_start(&test_script_runner, 0);
333 	test_thread_yield();
334 
335 	zassert_false(test_script_runner.result.done, "Script should not be done");
336 
337 	modem_backend_mock_put(&mock, (uint8_t *)buf, buf_len);
338 	test_thread_yield();
339 
340 	zassert_false(test_script_runner.result.done, "Script should not be done");
341 
342 	k_sleep(K_SECONDS(1));
343 
344 	zassert_true(test_script_runner.result.done, "Script should be done");
345 	zassert_equal(-EAGAIN, test_script_runner.result.ret);
346 }
347 
ZTEST(modem_ubx,test_rsp_discards_invalid_len)348 ZTEST(modem_ubx, test_rsp_discards_invalid_len)
349 {
350 	static struct ubx_frame test_rsp = UBX_FRAME_ACK_INITIALIZER(0x02, 0x03);
351 
352 	/** Invalidate checksum */
353 	size_t frame_size = UBX_FRAME_SZ(test_rsp.payload_size);
354 
355 	test_rsp.payload_size = 0xFFFF;
356 
357 	script_runner_start(&test_script_runner, 0);
358 	test_thread_yield();
359 
360 	zassert_false(test_script_runner.result.done, "Script should not be done");
361 
362 	modem_backend_mock_put(&mock, (uint8_t *)&test_rsp, frame_size);
363 	test_thread_yield();
364 
365 	zassert_false(test_script_runner.result.done, "Script should not be done");
366 
367 	k_sleep(K_SECONDS(1));
368 
369 	zassert_true(test_script_runner.result.done, "Script should be done");
370 	zassert_equal(-EAGAIN, test_script_runner.result.ret);
371 }
372 
ZTEST(modem_ubx,test_rsp_discards_invalid_checksum)373 ZTEST(modem_ubx, test_rsp_discards_invalid_checksum)
374 {
375 	static struct ubx_frame test_rsp = UBX_FRAME_ACK_INITIALIZER(0x02, 0x03);
376 
377 	/** Invalidate checksum */
378 	test_rsp.payload_and_checksum[test_rsp.payload_size] = 0xDE;
379 	test_rsp.payload_and_checksum[test_rsp.payload_size + 1] = 0xAD;
380 
381 	script_runner_start(&test_script_runner, 0);
382 	test_thread_yield();
383 
384 	zassert_false(test_script_runner.result.done, "Script should not be done");
385 
386 	modem_backend_mock_put(&mock, (uint8_t *)&test_rsp, UBX_FRAME_SZ(test_rsp.payload_size));
387 	test_thread_yield();
388 
389 	zassert_false(test_script_runner.result.done, "Script should not be done");
390 
391 	k_sleep(K_SECONDS(1));
392 
393 	zassert_true(test_script_runner.result.done, "Script should be done");
394 	zassert_equal(-EAGAIN, test_script_runner.result.ret);
395 }
396 
ZTEST(modem_ubx,test_rsp_split_in_two_events)397 ZTEST(modem_ubx, test_rsp_split_in_two_events)
398 {
399 	static struct ubx_frame test_rsp = UBX_FRAME_ACK_INITIALIZER(0x02, 0x03);
400 	uint8_t *data_ptr = (uint8_t *)&test_rsp;
401 
402 	script_runner_start(&test_script_runner, 0);
403 	test_thread_yield();
404 
405 	zassert_false(test_script_runner.result.done, "Script should not be done");
406 
407 	/** The first portion of the packet. At this point the data should not be discarded,
408 	 * understanding there's more data to come.
409 	 */
410 	modem_backend_mock_put(&mock, data_ptr, UBX_FRAME_SZ(test_rsp.payload_size) - 5);
411 	test_thread_yield();
412 
413 	zassert_false(test_script_runner.result.done, "Script should not be done");
414 
415 	/** The other portion of the packet. This should complete the packet reception */
416 	modem_backend_mock_put(&mock, &data_ptr[UBX_FRAME_SZ(test_rsp.payload_size) - 5], 5);
417 	test_thread_yield();
418 
419 	zassert_true(test_script_runner.result.done, "Script should be done");
420 	zassert_ok(test_script_runner.result.ret);
421 	zassert_equal(UBX_FRAME_SZ(test_rsp.payload_size),
422 		      test_script_runner.script.response.received_len,
423 		      "expected: %d, got: %d",
424 		      UBX_FRAME_SZ(test_rsp.payload_size),
425 		      test_script_runner.script.response.received_len);
426 }
427 
ZTEST(modem_ubx,test_rsp_filters_out_non_matches)428 ZTEST(modem_ubx, test_rsp_filters_out_non_matches)
429 {
430 	static struct ubx_frame test_rsp_non_match = UBX_FRAME_NAK_INITIALIZER(0x02, 0x03);
431 	static struct ubx_frame test_rsp_match = UBX_FRAME_ACK_INITIALIZER(0x02, 0x03);
432 
433 	uint8_t buf[256];
434 	size_t buf_len = 0;
435 
436 	/** We're passing a valid packet, but not what we're expecing. We
437 	 * should not get an event out of this one.
438 	 */
439 	memcpy(buf, &test_rsp_non_match, UBX_FRAME_SZ(test_rsp_non_match.payload_size));
440 	buf_len += UBX_FRAME_SZ(test_rsp_non_match.payload_size);
441 
442 	script_runner_start(&test_script_runner, 0);
443 	test_thread_yield();
444 
445 	zassert_false(test_script_runner.result.done, "Script should not be done");
446 
447 	modem_backend_mock_put(&mock, (uint8_t *)buf, buf_len);
448 	test_thread_yield();
449 
450 	zassert_false(test_script_runner.result.done, "Script should not be done");
451 
452 	/** Now we're passing two valid packets, on the same event: one which
453 	 * does not match, one which matches. We should get the latter.
454 	 */
455 	memcpy(buf, &test_rsp_match, UBX_FRAME_SZ(test_rsp_match.payload_size));
456 	buf_len += UBX_FRAME_SZ(test_rsp_match.payload_size);
457 
458 	modem_backend_mock_put(&mock, (uint8_t *)buf, buf_len);
459 	test_thread_yield();
460 
461 	zassert_true(test_script_runner.result.done, "Script should be done");
462 	zassert_ok(test_script_runner.result.ret);
463 	zassert_equal(UBX_FRAME_SZ(test_rsp_match.payload_size),
464 		      test_script_runner.script.response.received_len,
465 		      "expected: %d, got: %d",
466 		      UBX_FRAME_SZ(test_rsp_match.payload_size),
467 		      test_script_runner.script.response.received_len);
468 	zassert_mem_equal(&test_rsp_match,
469 			  test_script_runner.script.response.buf,
470 			  UBX_FRAME_SZ(test_rsp_match.payload_size));
471 }
472 
ZTEST(modem_ubx,test_rsp_match_with_payload)473 ZTEST(modem_ubx, test_rsp_match_with_payload)
474 {
475 	static struct ubx_frame test_rsp_non_match = UBX_FRAME_ACK_INITIALIZER(0x02, 0x03);
476 	static struct ubx_frame test_rsp_match = UBX_FRAME_ACK_INITIALIZER(0x03, 0x04);
477 
478 	test_script_runner.script.match.filter.payload.buf = test_rsp_match.payload_and_checksum;
479 	test_script_runner.script.match.filter.payload.len = test_rsp_match.payload_size;
480 
481 	uint8_t buf[256];
482 	size_t buf_len = 0;
483 
484 	/** We're passing a valid packet, but not what we're expecing. We
485 	 * should not get an event out of this one.
486 	 */
487 	memcpy(buf, &test_rsp_non_match, UBX_FRAME_SZ(test_rsp_non_match.payload_size));
488 	buf_len += UBX_FRAME_SZ(test_rsp_non_match.payload_size);
489 
490 	script_runner_start(&test_script_runner, 0);
491 	test_thread_yield();
492 
493 	zassert_false(test_script_runner.result.done, "Script should not be done");
494 
495 	modem_backend_mock_put(&mock, (uint8_t *)buf, buf_len);
496 	test_thread_yield();
497 
498 	zassert_false(test_script_runner.result.done, "Script should not be done");
499 
500 	/** Now we're passing two valid packets, on the same event: one which
501 	 * does not match, one which matches. We should get the latter.
502 	 */
503 	memcpy(buf, &test_rsp_match, UBX_FRAME_SZ(test_rsp_match.payload_size));
504 	buf_len += UBX_FRAME_SZ(test_rsp_match.payload_size);
505 
506 	modem_backend_mock_put(&mock, (uint8_t *)buf, buf_len);
507 	test_thread_yield();
508 
509 	zassert_true(test_script_runner.result.done, "Script should be done");
510 	zassert_ok(test_script_runner.result.ret);
511 	zassert_equal(UBX_FRAME_SZ(test_rsp_match.payload_size),
512 		      test_script_runner.script.response.received_len,
513 		      "expected: %d, got: %d",
514 		      UBX_FRAME_SZ(test_rsp_match.payload_size),
515 		      test_script_runner.script.response.received_len);
516 	zassert_mem_equal(&test_rsp_match,
517 			  test_script_runner.script.response.buf,
518 			  UBX_FRAME_SZ(test_rsp_match.payload_size));
519 }
520 
ZTEST(modem_ubx,test_unsol_matches_trigger_cb)521 ZTEST(modem_ubx, test_unsol_matches_trigger_cb)
522 {
523 	static struct ubx_frame ack_frame = UBX_FRAME_ACK_INITIALIZER(0x01, 0x02);
524 	static struct ubx_frame nak_frame = UBX_FRAME_NAK_INITIALIZER(0x01, 0x02);
525 
526 	zassert_false(atomic_test_bit(&callback_called, MODEM_UBX_UTEST_ON_ACK_RECEIVED_BIT));
527 	zassert_false(atomic_test_bit(&callback_called, MODEM_UBX_UTEST_ON_NAK_RECEIVED_BIT));
528 
529 	modem_backend_mock_put(&mock,
530 			       (const uint8_t *)&ack_frame,
531 			       UBX_FRAME_SZ(ack_frame.payload_size));
532 	test_thread_yield();
533 
534 	zassert_true(atomic_test_bit(&callback_called, MODEM_UBX_UTEST_ON_ACK_RECEIVED_BIT));
535 	zassert_false(atomic_test_bit(&callback_called, MODEM_UBX_UTEST_ON_NAK_RECEIVED_BIT));
536 
537 	modem_backend_mock_put(&mock,
538 			       (const uint8_t *)&nak_frame,
539 			       UBX_FRAME_SZ(nak_frame.payload_size));
540 	test_thread_yield();
541 
542 	zassert_true(atomic_test_bit(&callback_called, MODEM_UBX_UTEST_ON_NAK_RECEIVED_BIT));
543 }
544 
ZTEST(modem_ubx,test_ubx_frame_encode_matches_compile_time_macro)545 ZTEST(modem_ubx, test_ubx_frame_encode_matches_compile_time_macro)
546 {
547 	static struct ubx_frame ack_frame = UBX_FRAME_ACK_INITIALIZER(0x01, 0x02);
548 
549 	uint8_t buf[256];
550 	struct ubx_ack ack = {
551 		.class = 0x01,
552 		.id = 0x02,
553 	};
554 
555 	int len = ubx_frame_encode(UBX_CLASS_ID_ACK, UBX_MSG_ID_ACK,
556 				   (const uint8_t *)&ack, sizeof(ack),
557 				   buf, sizeof(buf));
558 	zassert_equal(len, UBX_FRAME_SZ(sizeof(ack)), "Expected: %d, got: %d",
559 		      UBX_FRAME_SZ(sizeof(ack)), len);
560 	zassert_mem_equal(buf, &ack_frame, UBX_FRAME_SZ(sizeof(ack)));
561 }
562