1 /*
2 * Copyright (c) 2019 Peter Bigot Consulting, LLC
3 * Copyright (c) 2020 Nordic Semiconductor ASA
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <zephyr/ztest.h>
9 #include <zephyr/sys/onoff.h>
10
11 static struct onoff_client onoff_cli;
12 struct onoff_transitions transitions;
13 static struct onoff_manager onoff_srv;
14 static struct onoff_monitor onoff_mon;
15
16 struct transition_record {
17 uint32_t state;
18 int res;
19 };
20 static struct transition_record trans[32];
21 static size_t ntrans;
22
trans_callback(struct onoff_manager * mgr,struct onoff_monitor * mon,uint32_t state,int res)23 static void trans_callback(struct onoff_manager *mgr,
24 struct onoff_monitor *mon,
25 uint32_t state,
26 int res)
27 {
28 if (ntrans < ARRAY_SIZE(trans)) {
29 trans[ntrans++] = (struct transition_record){
30 .state = state,
31 .res = res,
32 };
33 }
34 }
35
check_trans(uint32_t idx,uint32_t state,int res,const char * tag)36 static void check_trans(uint32_t idx,
37 uint32_t state,
38 int res,
39 const char *tag)
40 {
41 zassert_true(idx < ntrans,
42 "trans idx %u high: %s", idx, tag);
43
44 const struct transition_record *xp = trans + idx;
45
46 zassert_equal(xp->state, state,
47 "trans[%u] state %x != %x: %s",
48 idx, xp->state, state, tag);
49 zassert_equal(xp->res, res,
50 "trans[%u] res %d != %d: %s",
51 idx, xp->res, res, tag);
52 }
53
54 static struct onoff_manager *callback_srv;
55 static struct onoff_client *callback_cli;
56 static uint32_t callback_state;
57 static int callback_res;
58 static onoff_client_callback callback_fn;
59
callback(struct onoff_manager * srv,struct onoff_client * cli,uint32_t state,int res)60 static void callback(struct onoff_manager *srv,
61 struct onoff_client *cli,
62 uint32_t state,
63 int res)
64 {
65 onoff_client_callback cb = callback_fn;
66
67 callback_srv = srv;
68 callback_cli = cli;
69 callback_state = state;
70 callback_res = res;
71 callback_fn = NULL;
72
73 if (cb != NULL) {
74 cb(srv, cli, state, res);
75 }
76 }
77
check_callback(uint32_t state,int res,const char * tag)78 static void check_callback(uint32_t state,
79 int res,
80 const char *tag)
81 {
82 zassert_equal(callback_state, state,
83 "callback state %x != %x: %s",
84 callback_state, state, tag);
85 zassert_equal(callback_res, res,
86 "callback res %d != %d: %s",
87 callback_res, res, tag);
88 }
89
cli_result(const struct onoff_client * cp)90 static inline int cli_result(const struct onoff_client *cp)
91 {
92 int result;
93 int rc = sys_notify_fetch_result(&cp->notify, &result);
94
95 if (rc == 0) {
96 rc = result;
97 }
98 return rc;
99 }
100
check_result(int res,const char * tag)101 static void check_result(int res,
102 const char *tag)
103 {
104 zassert_equal(cli_result(&onoff_cli), res,
105 "cli res %d != %d: %s",
106 cli_result(&onoff_cli), res, tag);
107 }
108
109 struct transit_state {
110 const char *tag;
111 bool async;
112 int retval;
113 onoff_notify_fn notify;
114 struct onoff_manager *srv;
115 };
116
reset_transit_state(struct transit_state * tsp)117 static void reset_transit_state(struct transit_state *tsp)
118 {
119 tsp->async = false;
120 tsp->retval = 0;
121 tsp->notify = NULL;
122 tsp->srv = NULL;
123 }
124
run_transit(struct onoff_manager * srv,onoff_notify_fn notify,struct transit_state * tsp)125 static void run_transit(struct onoff_manager *srv,
126 onoff_notify_fn notify,
127 struct transit_state *tsp)
128 {
129 if (tsp->async) {
130 TC_PRINT("%s async\n", tsp->tag);
131 tsp->notify = notify;
132 tsp->srv = srv;
133 } else {
134 TC_PRINT("%s notify %d\n", tsp->tag, tsp->retval);
135 notify(srv, tsp->retval);
136 }
137 }
138
notify(struct transit_state * tsp)139 static void notify(struct transit_state *tsp)
140 {
141 TC_PRINT("%s settle %d %p\n", tsp->tag, tsp->retval, tsp->notify);
142 tsp->notify(tsp->srv, tsp->retval);
143 tsp->notify = NULL;
144 tsp->srv = NULL;
145 }
146
147 static struct transit_state start_state = {
148 .tag = "start",
149 };
start(struct onoff_manager * srv,onoff_notify_fn notify_fn)150 static void start(struct onoff_manager *srv,
151 onoff_notify_fn notify_fn)
152 {
153 run_transit(srv, notify_fn, &start_state);
154 }
155
156 static struct transit_state stop_state = {
157 .tag = "stop",
158 };
stop(struct onoff_manager * srv,onoff_notify_fn notify_fn)159 static void stop(struct onoff_manager *srv,
160 onoff_notify_fn notify_fn)
161 {
162 run_transit(srv, notify_fn, &stop_state);
163 }
164
165 static struct transit_state reset_state = {
166 .tag = "reset",
167 };
reset(struct onoff_manager * srv,onoff_notify_fn notify_fn)168 static void reset(struct onoff_manager *srv,
169 onoff_notify_fn notify_fn)
170 {
171 run_transit(srv, notify_fn, &reset_state);
172 }
173
174 static struct k_sem isr_sync;
175 static struct k_timer isr_timer;
176
isr_notify(struct k_timer * timer)177 static void isr_notify(struct k_timer *timer)
178 {
179 struct transit_state *tsp = k_timer_user_data_get(timer);
180
181 TC_PRINT("ISR NOTIFY %s %d\n", tsp->tag, k_is_in_isr());
182 notify(tsp);
183 k_sem_give(&isr_sync);
184 }
185
186 struct isr_call_state {
187 struct onoff_manager *srv;
188 struct onoff_client *cli;
189 int result;
190 };
191
isr_request(struct k_timer * timer)192 static void isr_request(struct k_timer *timer)
193 {
194 struct isr_call_state *rsp = k_timer_user_data_get(timer);
195
196 rsp->result = onoff_request(rsp->srv, rsp->cli);
197 k_sem_give(&isr_sync);
198 }
199
isr_release(struct k_timer * timer)200 static void isr_release(struct k_timer *timer)
201 {
202 struct isr_call_state *rsp = k_timer_user_data_get(timer);
203
204 rsp->result = onoff_release(rsp->srv);
205 k_sem_give(&isr_sync);
206 }
207
isr_reset(struct k_timer * timer)208 static void isr_reset(struct k_timer *timer)
209 {
210 struct isr_call_state *rsp = k_timer_user_data_get(timer);
211
212 rsp->result = onoff_reset(rsp->srv, rsp->cli);
213 k_sem_give(&isr_sync);
214 }
215
reset_cli(void)216 static void reset_cli(void)
217 {
218 onoff_cli = (struct onoff_client){};
219 sys_notify_init_callback(&onoff_cli.notify, callback);
220 }
221
reset_callback(void)222 static void reset_callback(void)
223 {
224 callback_state = -1;
225 callback_res = 0;
226 callback_fn = NULL;
227 }
228
setup_test(void)229 static void setup_test(void)
230 {
231 int rc;
232
233 reset_callback();
234 reset_transit_state(&start_state);
235 reset_transit_state(&stop_state);
236 reset_transit_state(&reset_state);
237 ntrans = 0;
238
239 transitions = (struct onoff_transitions)
240 ONOFF_TRANSITIONS_INITIALIZER(start, stop, reset);
241 rc = onoff_manager_init(&onoff_srv, &transitions);
242 zassert_equal(rc, 0,
243 "service init");
244
245 onoff_mon = (struct onoff_monitor){
246 .callback = trans_callback,
247 };
248 rc = onoff_monitor_register(&onoff_srv, &onoff_mon);
249 zassert_equal(rc, 0,
250 "mon reg");
251
252 reset_cli();
253 }
254
setup_error(void)255 static void setup_error(void)
256 {
257 int rc;
258
259 setup_test();
260 start_state.retval = -1;
261
262 rc = onoff_request(&onoff_srv, &onoff_cli);
263 zassert_equal(rc, ONOFF_STATE_OFF,
264 "req 0 0");
265 check_result(start_state.retval,
266 "err req");
267 zassert_true(onoff_has_error(&onoff_srv),
268 "has_err");
269
270 reset_cli();
271 }
272
ZTEST(onoff_api,test_manager_init)273 ZTEST(onoff_api, test_manager_init)
274 {
275 int rc;
276 struct onoff_transitions xit = {};
277
278 setup_test();
279
280 rc = onoff_manager_init(NULL, NULL);
281 zassert_equal(rc, -EINVAL,
282 "init 0 0");
283 rc = onoff_manager_init(&onoff_srv, NULL);
284 zassert_equal(rc, -EINVAL,
285 "init srv 0");
286 rc = onoff_manager_init(NULL, &transitions);
287 zassert_equal(rc, -EINVAL,
288 "init 0 xit");
289 rc = onoff_manager_init(&onoff_srv, &xit);
290 zassert_equal(rc, -EINVAL,
291 "init 0 xit-start");
292
293 xit.start = start;
294 rc = onoff_manager_init(&onoff_srv, &xit);
295 zassert_equal(rc, -EINVAL,
296 "init srv xit-stop");
297
298 xit.stop = stop;
299 rc = onoff_manager_init(&onoff_srv, &xit);
300 zassert_equal(rc, 0,
301 "init srv xit ok");
302 }
303
ZTEST(onoff_api,test_mon_reg)304 ZTEST(onoff_api, test_mon_reg)
305 {
306 static struct onoff_monitor mon = {};
307
308 setup_test();
309
310 /* Verify parameter validation */
311
312 zassert_equal(onoff_monitor_register(NULL, NULL), -EINVAL,
313 "mon reg 0 0");
314 zassert_equal(onoff_monitor_register(&onoff_srv, NULL), -EINVAL,
315 "mon reg srv 0");
316 zassert_equal(onoff_monitor_register(NULL, &mon), -EINVAL,
317 "mon reg 0 mon");
318 zassert_equal(onoff_monitor_register(&onoff_srv, &mon), -EINVAL,
319 "mon reg srv mon(!cb)");
320 }
321
ZTEST(onoff_api,test_mon_unreg)322 ZTEST(onoff_api, test_mon_unreg)
323 {
324 setup_test();
325
326 /* Verify parameter validation */
327
328 zassert_equal(onoff_monitor_unregister(NULL, NULL), -EINVAL,
329 "mon unreg 0 0");
330 zassert_equal(onoff_monitor_unregister(&onoff_srv, NULL), -EINVAL,
331 "mon unreg srv 0");
332 zassert_equal(onoff_monitor_unregister(NULL, &onoff_mon), -EINVAL,
333 "mon unreg 0 mon");
334 zassert_equal(onoff_monitor_unregister(&onoff_srv, &onoff_mon), 0,
335 "mon unreg 0 mon");
336 zassert_equal(onoff_monitor_unregister(&onoff_srv, &onoff_mon), -EINVAL,
337 "mon unreg 0 mon");
338 }
339
ZTEST(onoff_api,test_request)340 ZTEST(onoff_api, test_request)
341 {
342 struct onoff_client cli2 = {};
343 int rc;
344
345 setup_test();
346
347 rc = onoff_request(NULL, NULL);
348 zassert_equal(rc, -EINVAL,
349 "req 0 0");
350 rc = onoff_request(&onoff_srv, NULL);
351 zassert_equal(rc, -EINVAL,
352 "req srv 0");
353 rc = onoff_request(NULL, &onoff_cli);
354 zassert_equal(rc, -EINVAL,
355 "req 0 cli");
356
357 rc = onoff_request(&onoff_srv, &cli2);
358 zassert_equal(rc, -EINVAL,
359 "req srv cli-uninit");
360
361 onoff_cli.notify.flags |= BIT(ONOFF_CLIENT_EXTENSION_POS);
362 rc = onoff_request(&onoff_srv, &onoff_cli);
363 zassert_equal(rc, -EINVAL,
364 "req srv cli-flags");
365
366 onoff_cli.notify.flags &= ~BIT(ONOFF_CLIENT_EXTENSION_POS);
367 rc = onoff_request(&onoff_srv, &onoff_cli);
368 zassert_equal(rc, 0,
369 "req srv cli ok");
370
371 reset_cli();
372 onoff_srv.refs = -1;
373 rc = onoff_request(&onoff_srv, &onoff_cli);
374 zassert_equal(rc, -EAGAIN,
375 "req srv cli ofl");
376
377 }
378
ZTEST(onoff_api,test_basic_sync)379 ZTEST(onoff_api, test_basic_sync)
380 {
381 int rc;
382
383 /* Verify synchronous request and release behavior. */
384
385 setup_test();
386 start_state.retval = 16;
387 stop_state.retval = 23;
388
389 rc = onoff_request(&onoff_srv, &onoff_cli);
390 zassert_equal(rc, ONOFF_STATE_OFF,
391 "req: %d", rc);
392 zassert_equal(onoff_srv.refs, 1U,
393 "req refs: %u", onoff_srv.refs);
394 check_result(start_state.retval, "req");
395 zassert_equal(callback_srv, &onoff_srv,
396 "callback wrong srv");
397 zassert_equal(callback_cli, &onoff_cli,
398 "callback wrong cli");
399 check_callback(ONOFF_STATE_ON, start_state.retval,
400 "req");
401 zassert_equal(ntrans, 2U,
402 "req trans");
403 check_trans(0, ONOFF_STATE_TO_ON, 0,
404 "trans to-on");
405 check_trans(1, ONOFF_STATE_ON, start_state.retval,
406 "trans on");
407
408 rc = onoff_release(&onoff_srv);
409 zassert_equal(rc, ONOFF_STATE_ON,
410 "rel: %d", rc);
411 zassert_equal(onoff_srv.refs, 0U,
412 "rel refs: %u", onoff_srv.refs);
413 zassert_equal(ntrans, 4U,
414 "rel trans");
415 check_trans(2, ONOFF_STATE_TO_OFF, 0,
416 "trans to-off");
417 check_trans(3, ONOFF_STATE_OFF, stop_state.retval,
418 "trans off");
419
420 rc = onoff_release(&onoff_srv);
421 zassert_equal(rc, -ENOTSUP,
422 "re-rel: %d", rc);
423 }
424
ZTEST(onoff_api,test_basic_async)425 ZTEST(onoff_api, test_basic_async)
426 {
427 int rc;
428
429 /* Verify asynchronous request and release behavior. */
430
431 setup_test();
432 start_state.async = true;
433 start_state.retval = 51;
434 stop_state.async = true;
435 stop_state.retval = 17;
436
437 rc = onoff_request(&onoff_srv, &onoff_cli);
438 zassert_equal(rc, ONOFF_STATE_OFF,
439 "async req: %d", rc);
440 zassert_equal(onoff_srv.refs, 0U,
441 "to-on refs: %u", onoff_srv.refs);
442 check_result(-EAGAIN, "async req");
443 zassert_equal(ntrans, 1U,
444 "async req trans");
445 check_trans(0, ONOFF_STATE_TO_ON, 0,
446 "trans to-on");
447
448 notify(&start_state);
449 zassert_equal(onoff_srv.refs, 1U,
450 "on refs: %u", onoff_srv.refs);
451 check_result(start_state.retval, "async req");
452 zassert_equal(ntrans, 2U,
453 "async req trans");
454 check_trans(1, ONOFF_STATE_ON, start_state.retval,
455 "trans on");
456
457 rc = onoff_release(&onoff_srv);
458 zassert_true(rc >= 0,
459 "rel: %d", rc);
460 zassert_equal(onoff_srv.refs, 0U,
461 "on refs: %u", onoff_srv.refs);
462 zassert_equal(ntrans, 3U,
463 "async rel trans");
464 check_trans(2, ONOFF_STATE_TO_OFF, 0,
465 "trans to-off");
466
467 notify(&stop_state);
468 zassert_equal(onoff_srv.refs, 0U,
469 "rel refs: %u", onoff_srv.refs);
470 zassert_equal(ntrans, 4U,
471 "rel trans");
472 check_trans(3, ONOFF_STATE_OFF, stop_state.retval,
473 "trans off");
474 }
475
ZTEST(onoff_api,test_reset)476 ZTEST(onoff_api, test_reset)
477 {
478 struct onoff_client cli2 = {};
479 int rc;
480
481 setup_error();
482
483 reset_cli();
484 rc = onoff_reset(NULL, NULL);
485 zassert_equal(rc, -EINVAL,
486 "rst 0 0");
487 rc = onoff_reset(&onoff_srv, NULL);
488 zassert_equal(rc, -EINVAL,
489 "rst srv 0");
490 rc = onoff_reset(NULL, &onoff_cli);
491 zassert_equal(rc, -EINVAL,
492 "rst 0 cli");
493 rc = onoff_reset(&onoff_srv, &cli2);
494 zassert_equal(rc, -EINVAL,
495 "rst srv cli-cfg");
496
497 transitions.reset = NULL;
498 rc = onoff_reset(&onoff_srv, &onoff_cli);
499 zassert_equal(rc, -ENOTSUP,
500 "rst srv cli-cfg");
501
502 transitions.reset = reset;
503 rc = onoff_reset(&onoff_srv, &onoff_cli);
504 zassert_equal(rc, ONOFF_STATE_ERROR,
505 "rst srv cli");
506
507 reset_cli();
508 rc = onoff_reset(&onoff_srv, &onoff_cli);
509 zassert_equal(rc, -EALREADY,
510 "re-rst srv cli");
511 }
512
ZTEST(onoff_api,test_basic_reset)513 ZTEST(onoff_api, test_basic_reset)
514 {
515 int rc;
516
517 /* Verify that reset works. */
518
519 setup_error();
520
521 zassert_equal(ntrans, 2U,
522 "err trans");
523 check_trans(0, ONOFF_STATE_TO_ON, 0,
524 "trans to-on");
525 check_trans(1, ONOFF_STATE_ERROR, start_state.retval,
526 "trans on");
527
528 reset_cli();
529 reset_state.retval = 12;
530
531 rc = onoff_reset(&onoff_srv, &onoff_cli);
532 zassert_equal(rc, ONOFF_STATE_ERROR,
533 "rst");
534 check_result(reset_state.retval,
535 "rst");
536 zassert_equal(ntrans, 4U,
537 "err trans");
538 check_trans(2, ONOFF_STATE_RESETTING, 0,
539 "trans resetting");
540 check_trans(3, ONOFF_STATE_OFF, reset_state.retval,
541 "trans off");
542 }
543
ZTEST(onoff_api,test_multi_start)544 ZTEST(onoff_api, test_multi_start)
545 {
546 int rc;
547 struct onoff_client cli2 = {};
548
549 /* Verify multiple requests are satisfied when start
550 * transition completes.
551 */
552
553 setup_test();
554
555 start_state.async = true;
556 start_state.retval = 16;
557
558 rc = onoff_request(&onoff_srv, &onoff_cli);
559 zassert_equal(rc, ONOFF_STATE_OFF,
560 "req: %d", rc);
561 zassert_equal(onoff_srv.refs, 0U,
562 "req refs: %u", onoff_srv.refs);
563 check_result(-EAGAIN, "req");
564 zassert_equal(ntrans, 1U,
565 "req trans");
566 check_trans(0, ONOFF_STATE_TO_ON, 0,
567 "trans to-on");
568
569 sys_notify_init_spinwait(&cli2.notify);
570
571 rc = onoff_request(&onoff_srv, &cli2);
572 zassert_equal(rc, ONOFF_STATE_TO_ON,
573 "req2: %d", rc);
574 zassert_equal(cli_result(&cli2), -EAGAIN,
575 "req2 result");
576
577 notify(&start_state);
578
579 zassert_equal(ntrans, 2U,
580 "async req trans");
581 check_trans(1, ONOFF_STATE_ON, start_state.retval,
582 "trans on");
583 check_result(start_state.retval, "req");
584 zassert_equal(cli_result(&cli2), start_state.retval,
585 "req2");
586 }
587
ZTEST(onoff_api,test_indep_req)588 ZTEST(onoff_api, test_indep_req)
589 {
590 int rc;
591 struct onoff_client cli0 = {};
592
593 /* Verify that requests and releases while on behave as
594 * expected.
595 */
596
597 setup_test();
598 sys_notify_init_spinwait(&cli0.notify);
599 start_state.retval = 62;
600
601 rc = onoff_request(&onoff_srv, &cli0);
602 zassert_equal(rc, ONOFF_STATE_OFF,
603 "req0: %d", rc);
604 zassert_equal(onoff_srv.refs, 1U,
605 "req0 refs: %u", onoff_srv.refs);
606 zassert_equal(cli_result(&cli0), start_state.retval,
607 "req0 result");
608 zassert_equal(ntrans, 2U,
609 "req trans");
610 check_trans(0, ONOFF_STATE_TO_ON, 0,
611 "trans to-on");
612 check_trans(1, ONOFF_STATE_ON, start_state.retval,
613 "trans on");
614
615 ++start_state.retval;
616
617 rc = onoff_request(&onoff_srv, &onoff_cli);
618 zassert_equal(rc, ONOFF_STATE_ON,
619 "req: %d", rc);
620 check_result(0,
621 "req");
622
623 zassert_equal(ntrans, 2U,
624 "async req trans");
625 zassert_equal(onoff_srv.refs, 2U,
626 "srv refs: %u", onoff_srv.refs);
627
628 rc = onoff_release(&onoff_srv); /* pair with cli0 */
629 zassert_equal(rc, ONOFF_STATE_ON,
630 "rel: %d", rc);
631 zassert_equal(onoff_srv.refs, 1U,
632 "srv refs");
633 zassert_equal(ntrans, 2U,
634 "async req trans");
635
636 rc = onoff_release(&onoff_srv); /* pair with cli */
637 zassert_equal(rc, ONOFF_STATE_ON,
638 "rel: %d", rc);
639 zassert_equal(onoff_srv.refs, 0U,
640 "srv refs");
641 zassert_equal(ntrans, 4U,
642 "async req trans");
643 }
644
ZTEST(onoff_api,test_delayed_req)645 ZTEST(onoff_api, test_delayed_req)
646 {
647 int rc;
648
649 setup_test();
650 start_state.retval = 16;
651
652 /* Verify that a request received while turning off is
653 * processed on completion of the transition to off.
654 */
655
656 rc = onoff_request(&onoff_srv, &onoff_cli);
657 zassert_equal(rc, ONOFF_STATE_OFF,
658 "req: %d", rc);
659 check_result(start_state.retval, "req");
660 zassert_equal(ntrans, 2U,
661 "req trans");
662 check_trans(0, ONOFF_STATE_TO_ON, 0,
663 "trans to-on");
664 check_trans(1, ONOFF_STATE_ON, start_state.retval,
665 "trans on");
666
667 start_state.retval += 1;
668 stop_state.async = true;
669 stop_state.retval = 14;
670
671 rc = onoff_release(&onoff_srv);
672 zassert_true(rc >= 0,
673 "rel: %d", rc);
674 zassert_equal(onoff_srv.refs, 0U,
675 "on refs: %u", onoff_srv.refs);
676 zassert_equal(ntrans, 3U,
677 "async rel trans");
678 check_trans(2, ONOFF_STATE_TO_OFF, 0,
679 "trans to-off");
680
681 reset_cli();
682
683 rc = onoff_request(&onoff_srv, &onoff_cli);
684 zassert_equal(rc, ONOFF_STATE_TO_OFF,
685 "del req: %d", rc);
686 zassert_equal(ntrans, 3U,
687 "async rel trans");
688 check_result(-EAGAIN, "del req");
689
690 notify(&stop_state);
691
692 check_result(start_state.retval, "del req");
693 zassert_equal(ntrans, 6U,
694 "req trans");
695 check_trans(2, ONOFF_STATE_TO_OFF, 0,
696 "trans to-off");
697 check_trans(3, ONOFF_STATE_OFF, stop_state.retval,
698 "trans off");
699 check_trans(4, ONOFF_STATE_TO_ON, 0,
700 "trans to-on");
701 check_trans(5, ONOFF_STATE_ON, start_state.retval,
702 "trans on");
703 }
704
705
ZTEST(onoff_api,test_recheck_start)706 ZTEST(onoff_api, test_recheck_start)
707 {
708 int rc;
709
710 /* Verify fast-path recheck when entering ON with no clients.
711 *
712 * This removes the monitor which bypasses the unlock region
713 * in process_events() when there is no client and no
714 * transition.
715 */
716
717 setup_test();
718 rc = onoff_monitor_unregister(&onoff_srv, &onoff_mon);
719 zassert_equal(rc, 0,
720 "mon unreg");
721
722 start_state.async = true;
723
724 rc = onoff_request(&onoff_srv, &onoff_cli);
725 zassert_equal(rc, ONOFF_STATE_OFF,
726 "req");
727 rc = onoff_cancel(&onoff_srv, &onoff_cli);
728 zassert_equal(rc, ONOFF_STATE_TO_ON,
729 "cancel");
730
731 notify(&start_state);
732 zassert_equal(onoff_srv.flags, ONOFF_STATE_OFF,
733 "completed");
734 }
735
ZTEST(onoff_api,test_recheck_stop)736 ZTEST(onoff_api, test_recheck_stop)
737 {
738 int rc;
739
740 /* Verify fast-path recheck when entering OFF with clients.
741 *
742 * This removes the monitor which bypasses the unlock region
743 * in process_events() when there is no client and no
744 * transition.
745 */
746
747 setup_test();
748 rc = onoff_monitor_unregister(&onoff_srv, &onoff_mon);
749 zassert_equal(rc, 0,
750 "mon unreg");
751
752 rc = onoff_request(&onoff_srv, &onoff_cli);
753 zassert_equal(rc, ONOFF_STATE_OFF,
754 "req");
755 check_result(start_state.retval,
756 "req");
757
758 stop_state.async = true;
759 rc = onoff_release(&onoff_srv);
760 zassert_equal(rc, ONOFF_STATE_ON,
761 "rel");
762
763 reset_cli();
764 rc = onoff_request(&onoff_srv, &onoff_cli);
765 zassert_equal(rc, ONOFF_STATE_TO_OFF,
766 "delayed req");
767 check_result(-EAGAIN,
768 "delayed req");
769
770 notify(&stop_state);
771 zassert_equal(onoff_srv.flags, ONOFF_STATE_ON,
772 "completed");
773 }
774
rel_in_req_cb(struct onoff_manager * srv,struct onoff_client * cli,uint32_t state,int res)775 static void rel_in_req_cb(struct onoff_manager *srv,
776 struct onoff_client *cli,
777 uint32_t state,
778 int res)
779 {
780 int rc = onoff_release(srv);
781
782 zassert_equal(rc, ONOFF_STATE_ON,
783 "rel-in-req");
784 }
785
ZTEST(onoff_api,test_rel_in_req_cb)786 ZTEST(onoff_api, test_rel_in_req_cb)
787 {
788 int rc;
789
790 /* Verify that a release invoked during the request completion
791 * callback is processed to final state.
792 */
793
794 setup_test();
795 callback_fn = rel_in_req_cb;
796
797 rc = onoff_request(&onoff_srv, &onoff_cli);
798 zassert_equal(rc, ONOFF_STATE_OFF,
799 "req");
800
801 zassert_equal(callback_fn, NULL,
802 "invoke");
803
804 zassert_equal(ntrans, 4U,
805 "req trans");
806 check_trans(0, ONOFF_STATE_TO_ON, 0,
807 "trans to-on");
808 check_trans(1, ONOFF_STATE_ON, start_state.retval,
809 "trans on");
810 check_trans(2, ONOFF_STATE_TO_OFF, 0,
811 "trans to-off");
812 check_trans(3, ONOFF_STATE_OFF, stop_state.retval,
813 "trans off");
814 }
815
ZTEST(onoff_api,test_multi_reset)816 ZTEST(onoff_api, test_multi_reset)
817 {
818 int rc;
819 struct onoff_client cli2 = {};
820
821 /* Verify multiple reset requests are satisfied when reset
822 * transition completes.
823 */
824 setup_test();
825 start_state.retval = -23;
826
827 rc = onoff_request(&onoff_srv, &onoff_cli);
828 zassert_equal(rc, ONOFF_STATE_OFF,
829 "req err");
830 check_result(start_state.retval,
831 "req err");
832 zassert_true(onoff_has_error(&onoff_srv),
833 "has_error");
834 zassert_equal(ntrans, 2U,
835 "err trans");
836 check_trans(0, ONOFF_STATE_TO_ON, 0,
837 "trans to-on");
838 check_trans(1, ONOFF_STATE_ERROR, start_state.retval,
839 "trans on");
840
841 reset_state.async = true;
842 reset_state.retval = 21;
843
844 sys_notify_init_spinwait(&cli2.notify);
845 rc = onoff_reset(&onoff_srv, &cli2);
846 zassert_equal(rc, ONOFF_STATE_ERROR,
847 "rst2");
848 zassert_equal(cli_result(&cli2), -EAGAIN,
849 "rst2 result");
850 zassert_equal(ntrans, 3U,
851 "rst trans");
852 check_trans(2, ONOFF_STATE_RESETTING, 0,
853 "trans resetting");
854
855 reset_cli();
856 rc = onoff_reset(&onoff_srv, &onoff_cli);
857 zassert_equal(rc, ONOFF_STATE_RESETTING,
858 "rst");
859 zassert_equal(ntrans, 3U,
860 "rst trans");
861
862 notify(&reset_state);
863
864 zassert_equal(cli_result(&cli2), reset_state.retval,
865 "rst2 result");
866 check_result(reset_state.retval,
867 "rst");
868 zassert_equal(ntrans, 4U,
869 "rst trans");
870 check_trans(3, ONOFF_STATE_OFF, reset_state.retval,
871 "trans off");
872 }
873
ZTEST(onoff_api,test_error)874 ZTEST(onoff_api, test_error)
875 {
876 struct onoff_client cli2 = {};
877 int rc;
878
879 /* Verify rejected operations when error present. */
880
881 setup_error();
882
883 rc = onoff_request(&onoff_srv, &onoff_cli);
884 zassert_equal(rc, -EIO,
885 "req in err");
886
887 rc = onoff_release(&onoff_srv);
888 zassert_equal(rc, -EIO,
889 "rel in err");
890
891 reset_state.async = true;
892 sys_notify_init_spinwait(&cli2.notify);
893
894 rc = onoff_reset(&onoff_srv, &cli2);
895 zassert_equal(rc, ONOFF_STATE_ERROR,
896 "rst");
897
898 rc = onoff_request(&onoff_srv, &onoff_cli);
899 zassert_equal(rc, -ENOTSUP,
900 "req in err");
901
902 rc = onoff_release(&onoff_srv);
903 zassert_equal(rc, -ENOTSUP,
904 "rel in err");
905 }
906
ZTEST(onoff_api,test_cancel_req)907 ZTEST(onoff_api, test_cancel_req)
908 {
909 int rc;
910
911 setup_test();
912 start_state.async = true;
913 start_state.retval = 14;
914
915 rc = onoff_cancel(NULL, NULL);
916 zassert_equal(rc, -EINVAL,
917 "can 0 0");
918 rc = onoff_cancel(&onoff_srv, NULL);
919 zassert_equal(rc, -EINVAL,
920 "can srv 0");
921 rc = onoff_cancel(NULL, &onoff_cli);
922 zassert_equal(rc, -EINVAL,
923 "can 0 cli");
924
925 rc = onoff_request(&onoff_srv, &onoff_cli);
926 zassert_equal(rc, ONOFF_STATE_OFF,
927 "async req: %d", rc);
928 check_result(-EAGAIN, "async req");
929 zassert_equal(ntrans, 1U,
930 "req trans");
931 check_trans(0, ONOFF_STATE_TO_ON, 0,
932 "trans to-on");
933
934 rc = onoff_cancel(&onoff_srv, &onoff_cli);
935 zassert_equal(rc, ONOFF_STATE_TO_ON,
936 "cancel req: %d", rc);
937
938 rc = onoff_cancel(&onoff_srv, &onoff_cli);
939 zassert_equal(rc, -EALREADY,
940 "re-cancel req: %d", rc);
941
942 zassert_equal(ntrans, 1U,
943 "req trans");
944 notify(&start_state);
945
946 zassert_equal(ntrans, 4U,
947 "req trans");
948 check_trans(1, ONOFF_STATE_ON, start_state.retval,
949 "trans on");
950 check_trans(2, ONOFF_STATE_TO_OFF, 0,
951 "trans to-off");
952 check_trans(3, ONOFF_STATE_OFF, stop_state.retval,
953 "trans off");
954 }
955
ZTEST(onoff_api,test_cancel_delayed_req)956 ZTEST(onoff_api, test_cancel_delayed_req)
957 {
958 int rc;
959
960 setup_test();
961
962 rc = onoff_request(&onoff_srv, &onoff_cli);
963 zassert_equal(rc, ONOFF_STATE_OFF,
964 "req: %d", rc);
965 check_result(start_state.retval, "req");
966 zassert_equal(ntrans, 2U,
967 "req trans");
968 check_trans(0, ONOFF_STATE_TO_ON, 0,
969 "trans to-on");
970 check_trans(1, ONOFF_STATE_ON, start_state.retval,
971 "trans on");
972
973 stop_state.async = true;
974 stop_state.retval = 14;
975
976 rc = onoff_release(&onoff_srv);
977 zassert_true(rc >= 0,
978 "rel: %d", rc);
979 zassert_equal(onoff_srv.refs, 0U,
980 "on refs: %u", onoff_srv.refs);
981 zassert_equal(ntrans, 3U,
982 "async rel trans");
983 check_trans(2, ONOFF_STATE_TO_OFF, 0,
984 "trans to-off");
985
986 reset_cli();
987
988 rc = onoff_request(&onoff_srv, &onoff_cli);
989 zassert_equal(rc, ONOFF_STATE_TO_OFF,
990 "del req: %d", rc);
991 zassert_equal(ntrans, 3U,
992 "async rel trans");
993 check_result(-EAGAIN, "del req");
994
995 rc = onoff_cancel(&onoff_srv, &onoff_cli);
996 zassert_equal(rc, ONOFF_STATE_TO_OFF,
997 "can del req: %d", rc);
998
999 notify(&stop_state);
1000
1001 zassert_equal(ntrans, 4U,
1002 "req trans");
1003 check_trans(2, ONOFF_STATE_TO_OFF, 0,
1004 "trans to-off");
1005 check_trans(3, ONOFF_STATE_OFF, stop_state.retval,
1006 "trans off");
1007 }
1008
ZTEST(onoff_api,test_cancel_or_release)1009 ZTEST(onoff_api, test_cancel_or_release)
1010 {
1011 int rc;
1012
1013 /* First, verify that the cancel-or-release idiom works when
1014 * invoked in state TO-ON.
1015 */
1016
1017 setup_test();
1018 start_state.async = true;
1019
1020 rc = onoff_request(&onoff_srv, &onoff_cli);
1021 zassert_equal(rc, ONOFF_STATE_OFF,
1022 "req");
1023 rc = onoff_cancel_or_release(&onoff_srv, &onoff_cli);
1024 zassert_equal(rc, ONOFF_STATE_TO_ON,
1025 "c|r to-on");
1026 notify(&start_state);
1027
1028 zassert_equal(ntrans, 4U,
1029 "req trans");
1030 check_trans(3, ONOFF_STATE_OFF, stop_state.retval,
1031 "trans off");
1032
1033 /* Now verify that the cancel-or-release idiom works when
1034 * invoked in state ON.
1035 */
1036
1037 setup_test();
1038 start_state.async = false;
1039
1040 rc = onoff_request(&onoff_srv, &onoff_cli);
1041 zassert_equal(rc, ONOFF_STATE_OFF,
1042 "req");
1043 zassert_equal(ntrans, 2U,
1044 "req trans");
1045
1046 rc = onoff_cancel_or_release(&onoff_srv, &onoff_cli);
1047 zassert_equal(rc, ONOFF_STATE_ON,
1048 "c|r to-on");
1049 zassert_equal(ntrans, 4U,
1050 "req trans");
1051 check_trans(3, ONOFF_STATE_OFF, stop_state.retval,
1052 "trans off");
1053 }
1054
ZTEST(onoff_api,test_sync_basic)1055 ZTEST(onoff_api, test_sync_basic)
1056 {
1057 static struct onoff_sync_service srv = {};
1058 k_spinlock_key_t key;
1059 int res = 5;
1060 int rc;
1061
1062 reset_cli();
1063
1064 rc = onoff_sync_lock(&srv, &key);
1065 zassert_equal(rc, 0,
1066 "init req");
1067
1068 rc = onoff_sync_finalize(&srv, key, &onoff_cli, res, true);
1069 zassert_equal(rc, 1,
1070 "req count");
1071 zassert_equal(callback_srv, NULL,
1072 "sync cb srv");
1073 zassert_equal(callback_cli, &onoff_cli,
1074 "sync cb cli");
1075 check_callback(ONOFF_STATE_ON, res, "sync req");
1076
1077 reset_cli();
1078 reset_callback();
1079
1080 rc = onoff_sync_lock(&srv, &key);
1081 zassert_equal(rc, 1,
1082 "init rel");
1083
1084 ++res;
1085 rc = onoff_sync_finalize(&srv, key, &onoff_cli, res, true);
1086 zassert_equal(rc, 2,
1087 "req2 count");
1088 check_callback(ONOFF_STATE_ON, res, "sync req2");
1089
1090 reset_cli();
1091
1092 rc = onoff_sync_lock(&srv, &key);
1093 zassert_equal(rc, 2,
1094 "init rel");
1095
1096 rc = onoff_sync_finalize(&srv, key, NULL, res, false);
1097 zassert_equal(rc, 1,
1098 "rel count");
1099
1100 reset_cli();
1101
1102 rc = onoff_sync_lock(&srv, &key);
1103 zassert_equal(rc, 1,
1104 "init rel2");
1105
1106 rc = onoff_sync_finalize(&srv, key, NULL, res, false);
1107 zassert_equal(rc, 0,
1108 "rel2 count");
1109
1110 /* Extra release is caught and diagnosed. May not happen with
1111 * onoff manager, but we can/should do it for sync.
1112 */
1113 reset_cli();
1114
1115 rc = onoff_sync_lock(&srv, &key);
1116 zassert_equal(rc, 0,
1117 "init rel2");
1118
1119 rc = onoff_sync_finalize(&srv, key, NULL, res, false);
1120 zassert_equal(rc, -1,
1121 "rel-1 count");
1122
1123 /* Error state is visible to next lock. */
1124 reset_cli();
1125 reset_callback();
1126
1127 rc = onoff_sync_lock(&srv, &key);
1128 zassert_equal(rc, -1,
1129 "init req");
1130 }
1131
ZTEST(onoff_api,test_sync_error)1132 ZTEST(onoff_api, test_sync_error)
1133 {
1134 static struct onoff_sync_service srv = {};
1135 k_spinlock_key_t key;
1136 int res = -EPERM;
1137 int rc;
1138
1139 reset_cli();
1140 reset_callback();
1141
1142 rc = onoff_sync_lock(&srv, &key);
1143 zassert_equal(rc, 0,
1144 "init req");
1145
1146 rc = onoff_sync_finalize(&srv, key, &onoff_cli, res, true);
1147
1148 zassert_equal(rc, res,
1149 "err final");
1150 zassert_equal(srv.count, res,
1151 "srv err count");
1152 zassert_equal(callback_srv, NULL,
1153 "sync cb srv");
1154 zassert_equal(callback_cli, &onoff_cli,
1155 "sync cb cli");
1156 check_callback(ONOFF_STATE_ERROR, res, "err final");
1157
1158 /* Error is visible to next operation (the value is the
1159 * negative count)
1160 */
1161
1162 reset_cli();
1163 reset_callback();
1164
1165 rc = onoff_sync_lock(&srv, &key);
1166 zassert_equal(rc, -1,
1167 "init req");
1168
1169 /* Error is cleared by non-negative finalize result */
1170 res = 3;
1171 rc = onoff_sync_finalize(&srv, key, &onoff_cli, res, true);
1172
1173 zassert_equal(rc, 1,
1174 "req count %d", rc);
1175 check_callback(ONOFF_STATE_ON, res, "sync req");
1176
1177 rc = onoff_sync_lock(&srv, &key);
1178 zassert_equal(rc, 1,
1179 "init rel");
1180 }
1181
1182
test_init(void)1183 void *test_init(void)
1184 {
1185 k_sem_init(&isr_sync, 0, 1);
1186 k_timer_init(&isr_timer, isr_notify, NULL);
1187
1188 (void)isr_reset;
1189 (void)isr_release;
1190 (void)isr_request;
1191 return NULL;
1192 }
1193 ZTEST_SUITE(onoff_api, NULL, test_init, NULL, NULL, NULL);
1194