Renames shadow variables found by -Wshadow. Signed-off-by: Daniel Leung <daniel.leung@intel.com>
1194 lines
27 KiB
C
1194 lines
27 KiB
C
/*
|
|
* Copyright (c) 2019 Peter Bigot Consulting, LLC
|
|
* Copyright (c) 2020 Nordic Semiconductor ASA
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/ztest.h>
|
|
#include <zephyr/sys/onoff.h>
|
|
|
|
static struct onoff_client onoff_cli;
|
|
struct onoff_transitions transitions;
|
|
static struct onoff_manager onoff_srv;
|
|
static struct onoff_monitor onoff_mon;
|
|
|
|
struct transition_record {
|
|
uint32_t state;
|
|
int res;
|
|
};
|
|
static struct transition_record trans[32];
|
|
static size_t ntrans;
|
|
|
|
static void trans_callback(struct onoff_manager *mgr,
|
|
struct onoff_monitor *mon,
|
|
uint32_t state,
|
|
int res)
|
|
{
|
|
if (ntrans < ARRAY_SIZE(trans)) {
|
|
trans[ntrans++] = (struct transition_record){
|
|
.state = state,
|
|
.res = res,
|
|
};
|
|
}
|
|
}
|
|
|
|
static void check_trans(uint32_t idx,
|
|
uint32_t state,
|
|
int res,
|
|
const char *tag)
|
|
{
|
|
zassert_true(idx < ntrans,
|
|
"trans idx %u high: %s", idx, tag);
|
|
|
|
const struct transition_record *xp = trans + idx;
|
|
|
|
zassert_equal(xp->state, state,
|
|
"trans[%u] state %x != %x: %s",
|
|
idx, xp->state, state, tag);
|
|
zassert_equal(xp->res, res,
|
|
"trans[%u] res %d != %d: %s",
|
|
idx, xp->res, res, tag);
|
|
}
|
|
|
|
static struct onoff_manager *callback_srv;
|
|
static struct onoff_client *callback_cli;
|
|
static uint32_t callback_state;
|
|
static int callback_res;
|
|
static onoff_client_callback callback_fn;
|
|
|
|
static void callback(struct onoff_manager *srv,
|
|
struct onoff_client *cli,
|
|
uint32_t state,
|
|
int res)
|
|
{
|
|
onoff_client_callback cb = callback_fn;
|
|
|
|
callback_srv = srv;
|
|
callback_cli = cli;
|
|
callback_state = state;
|
|
callback_res = res;
|
|
callback_fn = NULL;
|
|
|
|
if (cb != NULL) {
|
|
cb(srv, cli, state, res);
|
|
}
|
|
}
|
|
|
|
static void check_callback(uint32_t state,
|
|
int res,
|
|
const char *tag)
|
|
{
|
|
zassert_equal(callback_state, state,
|
|
"callback state %x != %x: %s",
|
|
callback_state, state, tag);
|
|
zassert_equal(callback_res, res,
|
|
"callback res %d != %d: %s",
|
|
callback_res, res, tag);
|
|
}
|
|
|
|
static inline int cli_result(const struct onoff_client *cp)
|
|
{
|
|
int result;
|
|
int rc = sys_notify_fetch_result(&cp->notify, &result);
|
|
|
|
if (rc == 0) {
|
|
rc = result;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
static void check_result(int res,
|
|
const char *tag)
|
|
{
|
|
zassert_equal(cli_result(&onoff_cli), res,
|
|
"cli res %d != %d: %s",
|
|
cli_result(&onoff_cli), res, tag);
|
|
}
|
|
|
|
struct transit_state {
|
|
const char *tag;
|
|
bool async;
|
|
int retval;
|
|
onoff_notify_fn notify;
|
|
struct onoff_manager *srv;
|
|
};
|
|
|
|
static void reset_transit_state(struct transit_state *tsp)
|
|
{
|
|
tsp->async = false;
|
|
tsp->retval = 0;
|
|
tsp->notify = NULL;
|
|
tsp->srv = NULL;
|
|
}
|
|
|
|
static void run_transit(struct onoff_manager *srv,
|
|
onoff_notify_fn notify,
|
|
struct transit_state *tsp)
|
|
{
|
|
if (tsp->async) {
|
|
TC_PRINT("%s async\n", tsp->tag);
|
|
tsp->notify = notify;
|
|
tsp->srv = srv;
|
|
} else {
|
|
TC_PRINT("%s notify %d\n", tsp->tag, tsp->retval);
|
|
notify(srv, tsp->retval);
|
|
}
|
|
}
|
|
|
|
static void notify(struct transit_state *tsp)
|
|
{
|
|
TC_PRINT("%s settle %d %p\n", tsp->tag, tsp->retval, tsp->notify);
|
|
tsp->notify(tsp->srv, tsp->retval);
|
|
tsp->notify = NULL;
|
|
tsp->srv = NULL;
|
|
}
|
|
|
|
static struct transit_state start_state = {
|
|
.tag = "start",
|
|
};
|
|
static void start(struct onoff_manager *srv,
|
|
onoff_notify_fn notify_fn)
|
|
{
|
|
run_transit(srv, notify_fn, &start_state);
|
|
}
|
|
|
|
static struct transit_state stop_state = {
|
|
.tag = "stop",
|
|
};
|
|
static void stop(struct onoff_manager *srv,
|
|
onoff_notify_fn notify_fn)
|
|
{
|
|
run_transit(srv, notify_fn, &stop_state);
|
|
}
|
|
|
|
static struct transit_state reset_state = {
|
|
.tag = "reset",
|
|
};
|
|
static void reset(struct onoff_manager *srv,
|
|
onoff_notify_fn notify_fn)
|
|
{
|
|
run_transit(srv, notify_fn, &reset_state);
|
|
}
|
|
|
|
static struct k_sem isr_sync;
|
|
static struct k_timer isr_timer;
|
|
|
|
static void isr_notify(struct k_timer *timer)
|
|
{
|
|
struct transit_state *tsp = k_timer_user_data_get(timer);
|
|
|
|
TC_PRINT("ISR NOTIFY %s %d\n", tsp->tag, k_is_in_isr());
|
|
notify(tsp);
|
|
k_sem_give(&isr_sync);
|
|
}
|
|
|
|
struct isr_call_state {
|
|
struct onoff_manager *srv;
|
|
struct onoff_client *cli;
|
|
int result;
|
|
};
|
|
|
|
static void isr_request(struct k_timer *timer)
|
|
{
|
|
struct isr_call_state *rsp = k_timer_user_data_get(timer);
|
|
|
|
rsp->result = onoff_request(rsp->srv, rsp->cli);
|
|
k_sem_give(&isr_sync);
|
|
}
|
|
|
|
static void isr_release(struct k_timer *timer)
|
|
{
|
|
struct isr_call_state *rsp = k_timer_user_data_get(timer);
|
|
|
|
rsp->result = onoff_release(rsp->srv);
|
|
k_sem_give(&isr_sync);
|
|
}
|
|
|
|
static void isr_reset(struct k_timer *timer)
|
|
{
|
|
struct isr_call_state *rsp = k_timer_user_data_get(timer);
|
|
|
|
rsp->result = onoff_reset(rsp->srv, rsp->cli);
|
|
k_sem_give(&isr_sync);
|
|
}
|
|
|
|
static void reset_cli(void)
|
|
{
|
|
onoff_cli = (struct onoff_client){};
|
|
sys_notify_init_callback(&onoff_cli.notify, callback);
|
|
}
|
|
|
|
static void reset_callback(void)
|
|
{
|
|
callback_state = -1;
|
|
callback_res = 0;
|
|
callback_fn = NULL;
|
|
}
|
|
|
|
static void setup_test(void)
|
|
{
|
|
int rc;
|
|
|
|
reset_callback();
|
|
reset_transit_state(&start_state);
|
|
reset_transit_state(&stop_state);
|
|
reset_transit_state(&reset_state);
|
|
ntrans = 0;
|
|
|
|
transitions = (struct onoff_transitions)
|
|
ONOFF_TRANSITIONS_INITIALIZER(start, stop, reset);
|
|
rc = onoff_manager_init(&onoff_srv, &transitions);
|
|
zassert_equal(rc, 0,
|
|
"service init");
|
|
|
|
onoff_mon = (struct onoff_monitor){
|
|
.callback = trans_callback,
|
|
};
|
|
rc = onoff_monitor_register(&onoff_srv, &onoff_mon);
|
|
zassert_equal(rc, 0,
|
|
"mon reg");
|
|
|
|
reset_cli();
|
|
}
|
|
|
|
static void setup_error(void)
|
|
{
|
|
int rc;
|
|
|
|
setup_test();
|
|
start_state.retval = -1;
|
|
|
|
rc = onoff_request(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, ONOFF_STATE_OFF,
|
|
"req 0 0");
|
|
check_result(start_state.retval,
|
|
"err req");
|
|
zassert_true(onoff_has_error(&onoff_srv),
|
|
"has_err");
|
|
|
|
reset_cli();
|
|
}
|
|
|
|
ZTEST(onoff_api, test_manager_init)
|
|
{
|
|
int rc;
|
|
struct onoff_transitions xit = {};
|
|
|
|
setup_test();
|
|
|
|
rc = onoff_manager_init(NULL, NULL);
|
|
zassert_equal(rc, -EINVAL,
|
|
"init 0 0");
|
|
rc = onoff_manager_init(&onoff_srv, NULL);
|
|
zassert_equal(rc, -EINVAL,
|
|
"init srv 0");
|
|
rc = onoff_manager_init(NULL, &transitions);
|
|
zassert_equal(rc, -EINVAL,
|
|
"init 0 xit");
|
|
rc = onoff_manager_init(&onoff_srv, &xit);
|
|
zassert_equal(rc, -EINVAL,
|
|
"init 0 xit-start");
|
|
|
|
xit.start = start;
|
|
rc = onoff_manager_init(&onoff_srv, &xit);
|
|
zassert_equal(rc, -EINVAL,
|
|
"init srv xit-stop");
|
|
|
|
xit.stop = stop;
|
|
rc = onoff_manager_init(&onoff_srv, &xit);
|
|
zassert_equal(rc, 0,
|
|
"init srv xit ok");
|
|
}
|
|
|
|
ZTEST(onoff_api, test_mon_reg)
|
|
{
|
|
static struct onoff_monitor mon = {};
|
|
|
|
setup_test();
|
|
|
|
/* Verify parameter validation */
|
|
|
|
zassert_equal(onoff_monitor_register(NULL, NULL), -EINVAL,
|
|
"mon reg 0 0");
|
|
zassert_equal(onoff_monitor_register(&onoff_srv, NULL), -EINVAL,
|
|
"mon reg srv 0");
|
|
zassert_equal(onoff_monitor_register(NULL, &mon), -EINVAL,
|
|
"mon reg 0 mon");
|
|
zassert_equal(onoff_monitor_register(&onoff_srv, &mon), -EINVAL,
|
|
"mon reg srv mon(!cb)");
|
|
}
|
|
|
|
ZTEST(onoff_api, test_mon_unreg)
|
|
{
|
|
setup_test();
|
|
|
|
/* Verify parameter validation */
|
|
|
|
zassert_equal(onoff_monitor_unregister(NULL, NULL), -EINVAL,
|
|
"mon unreg 0 0");
|
|
zassert_equal(onoff_monitor_unregister(&onoff_srv, NULL), -EINVAL,
|
|
"mon unreg srv 0");
|
|
zassert_equal(onoff_monitor_unregister(NULL, &onoff_mon), -EINVAL,
|
|
"mon unreg 0 mon");
|
|
zassert_equal(onoff_monitor_unregister(&onoff_srv, &onoff_mon), 0,
|
|
"mon unreg 0 mon");
|
|
zassert_equal(onoff_monitor_unregister(&onoff_srv, &onoff_mon), -EINVAL,
|
|
"mon unreg 0 mon");
|
|
}
|
|
|
|
ZTEST(onoff_api, test_request)
|
|
{
|
|
struct onoff_client cli2 = {};
|
|
int rc;
|
|
|
|
setup_test();
|
|
|
|
rc = onoff_request(NULL, NULL);
|
|
zassert_equal(rc, -EINVAL,
|
|
"req 0 0");
|
|
rc = onoff_request(&onoff_srv, NULL);
|
|
zassert_equal(rc, -EINVAL,
|
|
"req srv 0");
|
|
rc = onoff_request(NULL, &onoff_cli);
|
|
zassert_equal(rc, -EINVAL,
|
|
"req 0 cli");
|
|
|
|
rc = onoff_request(&onoff_srv, &cli2);
|
|
zassert_equal(rc, -EINVAL,
|
|
"req srv cli-uninit");
|
|
|
|
onoff_cli.notify.flags |= BIT(ONOFF_CLIENT_EXTENSION_POS);
|
|
rc = onoff_request(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, -EINVAL,
|
|
"req srv cli-flags");
|
|
|
|
onoff_cli.notify.flags &= ~BIT(ONOFF_CLIENT_EXTENSION_POS);
|
|
rc = onoff_request(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, 0,
|
|
"req srv cli ok");
|
|
|
|
reset_cli();
|
|
onoff_srv.refs = -1;
|
|
rc = onoff_request(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, -EAGAIN,
|
|
"req srv cli ofl");
|
|
|
|
}
|
|
|
|
ZTEST(onoff_api, test_basic_sync)
|
|
{
|
|
int rc;
|
|
|
|
/* Verify synchronous request and release behavior. */
|
|
|
|
setup_test();
|
|
start_state.retval = 16;
|
|
stop_state.retval = 23;
|
|
|
|
rc = onoff_request(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, ONOFF_STATE_OFF,
|
|
"req: %d", rc);
|
|
zassert_equal(onoff_srv.refs, 1U,
|
|
"req refs: %u", onoff_srv.refs);
|
|
check_result(start_state.retval, "req");
|
|
zassert_equal(callback_srv, &onoff_srv,
|
|
"callback wrong srv");
|
|
zassert_equal(callback_cli, &onoff_cli,
|
|
"callback wrong cli");
|
|
check_callback(ONOFF_STATE_ON, start_state.retval,
|
|
"req");
|
|
zassert_equal(ntrans, 2U,
|
|
"req trans");
|
|
check_trans(0, ONOFF_STATE_TO_ON, 0,
|
|
"trans to-on");
|
|
check_trans(1, ONOFF_STATE_ON, start_state.retval,
|
|
"trans on");
|
|
|
|
rc = onoff_release(&onoff_srv);
|
|
zassert_equal(rc, ONOFF_STATE_ON,
|
|
"rel: %d", rc);
|
|
zassert_equal(onoff_srv.refs, 0U,
|
|
"rel refs: %u", onoff_srv.refs);
|
|
zassert_equal(ntrans, 4U,
|
|
"rel trans");
|
|
check_trans(2, ONOFF_STATE_TO_OFF, 0,
|
|
"trans to-off");
|
|
check_trans(3, ONOFF_STATE_OFF, stop_state.retval,
|
|
"trans off");
|
|
|
|
rc = onoff_release(&onoff_srv);
|
|
zassert_equal(rc, -ENOTSUP,
|
|
"re-rel: %d", rc);
|
|
}
|
|
|
|
ZTEST(onoff_api, test_basic_async)
|
|
{
|
|
int rc;
|
|
|
|
/* Verify asynchronous request and release behavior. */
|
|
|
|
setup_test();
|
|
start_state.async = true;
|
|
start_state.retval = 51;
|
|
stop_state.async = true;
|
|
stop_state.retval = 17;
|
|
|
|
rc = onoff_request(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, ONOFF_STATE_OFF,
|
|
"async req: %d", rc);
|
|
zassert_equal(onoff_srv.refs, 0U,
|
|
"to-on refs: %u", onoff_srv.refs);
|
|
check_result(-EAGAIN, "async req");
|
|
zassert_equal(ntrans, 1U,
|
|
"async req trans");
|
|
check_trans(0, ONOFF_STATE_TO_ON, 0,
|
|
"trans to-on");
|
|
|
|
notify(&start_state);
|
|
zassert_equal(onoff_srv.refs, 1U,
|
|
"on refs: %u", onoff_srv.refs);
|
|
check_result(start_state.retval, "async req");
|
|
zassert_equal(ntrans, 2U,
|
|
"async req trans");
|
|
check_trans(1, ONOFF_STATE_ON, start_state.retval,
|
|
"trans on");
|
|
|
|
rc = onoff_release(&onoff_srv);
|
|
zassert_true(rc >= 0,
|
|
"rel: %d", rc);
|
|
zassert_equal(onoff_srv.refs, 0U,
|
|
"on refs: %u", onoff_srv.refs);
|
|
zassert_equal(ntrans, 3U,
|
|
"async rel trans");
|
|
check_trans(2, ONOFF_STATE_TO_OFF, 0,
|
|
"trans to-off");
|
|
|
|
notify(&stop_state);
|
|
zassert_equal(onoff_srv.refs, 0U,
|
|
"rel refs: %u", onoff_srv.refs);
|
|
zassert_equal(ntrans, 4U,
|
|
"rel trans");
|
|
check_trans(3, ONOFF_STATE_OFF, stop_state.retval,
|
|
"trans off");
|
|
}
|
|
|
|
ZTEST(onoff_api, test_reset)
|
|
{
|
|
struct onoff_client cli2 = {};
|
|
int rc;
|
|
|
|
setup_error();
|
|
|
|
reset_cli();
|
|
rc = onoff_reset(NULL, NULL);
|
|
zassert_equal(rc, -EINVAL,
|
|
"rst 0 0");
|
|
rc = onoff_reset(&onoff_srv, NULL);
|
|
zassert_equal(rc, -EINVAL,
|
|
"rst srv 0");
|
|
rc = onoff_reset(NULL, &onoff_cli);
|
|
zassert_equal(rc, -EINVAL,
|
|
"rst 0 cli");
|
|
rc = onoff_reset(&onoff_srv, &cli2);
|
|
zassert_equal(rc, -EINVAL,
|
|
"rst srv cli-cfg");
|
|
|
|
transitions.reset = NULL;
|
|
rc = onoff_reset(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, -ENOTSUP,
|
|
"rst srv cli-cfg");
|
|
|
|
transitions.reset = reset;
|
|
rc = onoff_reset(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, ONOFF_STATE_ERROR,
|
|
"rst srv cli");
|
|
|
|
reset_cli();
|
|
rc = onoff_reset(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, -EALREADY,
|
|
"re-rst srv cli");
|
|
}
|
|
|
|
ZTEST(onoff_api, test_basic_reset)
|
|
{
|
|
int rc;
|
|
|
|
/* Verify that reset works. */
|
|
|
|
setup_error();
|
|
|
|
zassert_equal(ntrans, 2U,
|
|
"err trans");
|
|
check_trans(0, ONOFF_STATE_TO_ON, 0,
|
|
"trans to-on");
|
|
check_trans(1, ONOFF_STATE_ERROR, start_state.retval,
|
|
"trans on");
|
|
|
|
reset_cli();
|
|
reset_state.retval = 12;
|
|
|
|
rc = onoff_reset(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, ONOFF_STATE_ERROR,
|
|
"rst");
|
|
check_result(reset_state.retval,
|
|
"rst");
|
|
zassert_equal(ntrans, 4U,
|
|
"err trans");
|
|
check_trans(2, ONOFF_STATE_RESETTING, 0,
|
|
"trans resetting");
|
|
check_trans(3, ONOFF_STATE_OFF, reset_state.retval,
|
|
"trans off");
|
|
}
|
|
|
|
ZTEST(onoff_api, test_multi_start)
|
|
{
|
|
int rc;
|
|
struct onoff_client cli2 = {};
|
|
|
|
/* Verify multiple requests are satisfied when start
|
|
* transition completes.
|
|
*/
|
|
|
|
setup_test();
|
|
|
|
start_state.async = true;
|
|
start_state.retval = 16;
|
|
|
|
rc = onoff_request(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, ONOFF_STATE_OFF,
|
|
"req: %d", rc);
|
|
zassert_equal(onoff_srv.refs, 0U,
|
|
"req refs: %u", onoff_srv.refs);
|
|
check_result(-EAGAIN, "req");
|
|
zassert_equal(ntrans, 1U,
|
|
"req trans");
|
|
check_trans(0, ONOFF_STATE_TO_ON, 0,
|
|
"trans to-on");
|
|
|
|
sys_notify_init_spinwait(&cli2.notify);
|
|
|
|
rc = onoff_request(&onoff_srv, &cli2);
|
|
zassert_equal(rc, ONOFF_STATE_TO_ON,
|
|
"req2: %d", rc);
|
|
zassert_equal(cli_result(&cli2), -EAGAIN,
|
|
"req2 result");
|
|
|
|
notify(&start_state);
|
|
|
|
zassert_equal(ntrans, 2U,
|
|
"async req trans");
|
|
check_trans(1, ONOFF_STATE_ON, start_state.retval,
|
|
"trans on");
|
|
check_result(start_state.retval, "req");
|
|
zassert_equal(cli_result(&cli2), start_state.retval,
|
|
"req2");
|
|
}
|
|
|
|
ZTEST(onoff_api, test_indep_req)
|
|
{
|
|
int rc;
|
|
struct onoff_client cli0 = {};
|
|
|
|
/* Verify that requests and releases while on behave as
|
|
* expected.
|
|
*/
|
|
|
|
setup_test();
|
|
sys_notify_init_spinwait(&cli0.notify);
|
|
start_state.retval = 62;
|
|
|
|
rc = onoff_request(&onoff_srv, &cli0);
|
|
zassert_equal(rc, ONOFF_STATE_OFF,
|
|
"req0: %d", rc);
|
|
zassert_equal(onoff_srv.refs, 1U,
|
|
"req0 refs: %u", onoff_srv.refs);
|
|
zassert_equal(cli_result(&cli0), start_state.retval,
|
|
"req0 result");
|
|
zassert_equal(ntrans, 2U,
|
|
"req trans");
|
|
check_trans(0, ONOFF_STATE_TO_ON, 0,
|
|
"trans to-on");
|
|
check_trans(1, ONOFF_STATE_ON, start_state.retval,
|
|
"trans on");
|
|
|
|
++start_state.retval;
|
|
|
|
rc = onoff_request(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, ONOFF_STATE_ON,
|
|
"req: %d", rc);
|
|
check_result(0,
|
|
"req");
|
|
|
|
zassert_equal(ntrans, 2U,
|
|
"async req trans");
|
|
zassert_equal(onoff_srv.refs, 2U,
|
|
"srv refs: %u", onoff_srv.refs);
|
|
|
|
rc = onoff_release(&onoff_srv); /* pair with cli0 */
|
|
zassert_equal(rc, ONOFF_STATE_ON,
|
|
"rel: %d", rc);
|
|
zassert_equal(onoff_srv.refs, 1U,
|
|
"srv refs");
|
|
zassert_equal(ntrans, 2U,
|
|
"async req trans");
|
|
|
|
rc = onoff_release(&onoff_srv); /* pair with cli */
|
|
zassert_equal(rc, ONOFF_STATE_ON,
|
|
"rel: %d", rc);
|
|
zassert_equal(onoff_srv.refs, 0U,
|
|
"srv refs");
|
|
zassert_equal(ntrans, 4U,
|
|
"async req trans");
|
|
}
|
|
|
|
ZTEST(onoff_api, test_delayed_req)
|
|
{
|
|
int rc;
|
|
|
|
setup_test();
|
|
start_state.retval = 16;
|
|
|
|
/* Verify that a request received while turning off is
|
|
* processed on completion of the transition to off.
|
|
*/
|
|
|
|
rc = onoff_request(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, ONOFF_STATE_OFF,
|
|
"req: %d", rc);
|
|
check_result(start_state.retval, "req");
|
|
zassert_equal(ntrans, 2U,
|
|
"req trans");
|
|
check_trans(0, ONOFF_STATE_TO_ON, 0,
|
|
"trans to-on");
|
|
check_trans(1, ONOFF_STATE_ON, start_state.retval,
|
|
"trans on");
|
|
|
|
start_state.retval += 1;
|
|
stop_state.async = true;
|
|
stop_state.retval = 14;
|
|
|
|
rc = onoff_release(&onoff_srv);
|
|
zassert_true(rc >= 0,
|
|
"rel: %d", rc);
|
|
zassert_equal(onoff_srv.refs, 0U,
|
|
"on refs: %u", onoff_srv.refs);
|
|
zassert_equal(ntrans, 3U,
|
|
"async rel trans");
|
|
check_trans(2, ONOFF_STATE_TO_OFF, 0,
|
|
"trans to-off");
|
|
|
|
reset_cli();
|
|
|
|
rc = onoff_request(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, ONOFF_STATE_TO_OFF,
|
|
"del req: %d", rc);
|
|
zassert_equal(ntrans, 3U,
|
|
"async rel trans");
|
|
check_result(-EAGAIN, "del req");
|
|
|
|
notify(&stop_state);
|
|
|
|
check_result(start_state.retval, "del req");
|
|
zassert_equal(ntrans, 6U,
|
|
"req trans");
|
|
check_trans(2, ONOFF_STATE_TO_OFF, 0,
|
|
"trans to-off");
|
|
check_trans(3, ONOFF_STATE_OFF, stop_state.retval,
|
|
"trans off");
|
|
check_trans(4, ONOFF_STATE_TO_ON, 0,
|
|
"trans to-on");
|
|
check_trans(5, ONOFF_STATE_ON, start_state.retval,
|
|
"trans on");
|
|
}
|
|
|
|
|
|
ZTEST(onoff_api, test_recheck_start)
|
|
{
|
|
int rc;
|
|
|
|
/* Verify fast-path recheck when entering ON with no clients.
|
|
*
|
|
* This removes the monitor which bypasses the unlock region
|
|
* in process_events() when there is no client and no
|
|
* transition.
|
|
*/
|
|
|
|
setup_test();
|
|
rc = onoff_monitor_unregister(&onoff_srv, &onoff_mon);
|
|
zassert_equal(rc, 0,
|
|
"mon unreg");
|
|
|
|
start_state.async = true;
|
|
|
|
rc = onoff_request(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, ONOFF_STATE_OFF,
|
|
"req");
|
|
rc = onoff_cancel(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, ONOFF_STATE_TO_ON,
|
|
"cancel");
|
|
|
|
notify(&start_state);
|
|
zassert_equal(onoff_srv.flags, ONOFF_STATE_OFF,
|
|
"completed");
|
|
}
|
|
|
|
ZTEST(onoff_api, test_recheck_stop)
|
|
{
|
|
int rc;
|
|
|
|
/* Verify fast-path recheck when entering OFF with clients.
|
|
*
|
|
* This removes the monitor which bypasses the unlock region
|
|
* in process_events() when there is no client and no
|
|
* transition.
|
|
*/
|
|
|
|
setup_test();
|
|
rc = onoff_monitor_unregister(&onoff_srv, &onoff_mon);
|
|
zassert_equal(rc, 0,
|
|
"mon unreg");
|
|
|
|
rc = onoff_request(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, ONOFF_STATE_OFF,
|
|
"req");
|
|
check_result(start_state.retval,
|
|
"req");
|
|
|
|
stop_state.async = true;
|
|
rc = onoff_release(&onoff_srv);
|
|
zassert_equal(rc, ONOFF_STATE_ON,
|
|
"rel");
|
|
|
|
reset_cli();
|
|
rc = onoff_request(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, ONOFF_STATE_TO_OFF,
|
|
"delayed req");
|
|
check_result(-EAGAIN,
|
|
"delayed req");
|
|
|
|
notify(&stop_state);
|
|
zassert_equal(onoff_srv.flags, ONOFF_STATE_ON,
|
|
"completed");
|
|
}
|
|
|
|
static void rel_in_req_cb(struct onoff_manager *srv,
|
|
struct onoff_client *cli,
|
|
uint32_t state,
|
|
int res)
|
|
{
|
|
int rc = onoff_release(srv);
|
|
|
|
zassert_equal(rc, ONOFF_STATE_ON,
|
|
"rel-in-req");
|
|
}
|
|
|
|
ZTEST(onoff_api, test_rel_in_req_cb)
|
|
{
|
|
int rc;
|
|
|
|
/* Verify that a release invoked during the request completion
|
|
* callback is processed to final state.
|
|
*/
|
|
|
|
setup_test();
|
|
callback_fn = rel_in_req_cb;
|
|
|
|
rc = onoff_request(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, ONOFF_STATE_OFF,
|
|
"req");
|
|
|
|
zassert_equal(callback_fn, NULL,
|
|
"invoke");
|
|
|
|
zassert_equal(ntrans, 4U,
|
|
"req trans");
|
|
check_trans(0, ONOFF_STATE_TO_ON, 0,
|
|
"trans to-on");
|
|
check_trans(1, ONOFF_STATE_ON, start_state.retval,
|
|
"trans on");
|
|
check_trans(2, ONOFF_STATE_TO_OFF, 0,
|
|
"trans to-off");
|
|
check_trans(3, ONOFF_STATE_OFF, stop_state.retval,
|
|
"trans off");
|
|
}
|
|
|
|
ZTEST(onoff_api, test_multi_reset)
|
|
{
|
|
int rc;
|
|
struct onoff_client cli2 = {};
|
|
|
|
/* Verify multiple reset requests are satisfied when reset
|
|
* transition completes.
|
|
*/
|
|
setup_test();
|
|
start_state.retval = -23;
|
|
|
|
rc = onoff_request(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, ONOFF_STATE_OFF,
|
|
"req err");
|
|
check_result(start_state.retval,
|
|
"req err");
|
|
zassert_true(onoff_has_error(&onoff_srv),
|
|
"has_error");
|
|
zassert_equal(ntrans, 2U,
|
|
"err trans");
|
|
check_trans(0, ONOFF_STATE_TO_ON, 0,
|
|
"trans to-on");
|
|
check_trans(1, ONOFF_STATE_ERROR, start_state.retval,
|
|
"trans on");
|
|
|
|
reset_state.async = true;
|
|
reset_state.retval = 21;
|
|
|
|
sys_notify_init_spinwait(&cli2.notify);
|
|
rc = onoff_reset(&onoff_srv, &cli2);
|
|
zassert_equal(rc, ONOFF_STATE_ERROR,
|
|
"rst2");
|
|
zassert_equal(cli_result(&cli2), -EAGAIN,
|
|
"rst2 result");
|
|
zassert_equal(ntrans, 3U,
|
|
"rst trans");
|
|
check_trans(2, ONOFF_STATE_RESETTING, 0,
|
|
"trans resetting");
|
|
|
|
reset_cli();
|
|
rc = onoff_reset(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, ONOFF_STATE_RESETTING,
|
|
"rst");
|
|
zassert_equal(ntrans, 3U,
|
|
"rst trans");
|
|
|
|
notify(&reset_state);
|
|
|
|
zassert_equal(cli_result(&cli2), reset_state.retval,
|
|
"rst2 result");
|
|
check_result(reset_state.retval,
|
|
"rst");
|
|
zassert_equal(ntrans, 4U,
|
|
"rst trans");
|
|
check_trans(3, ONOFF_STATE_OFF, reset_state.retval,
|
|
"trans off");
|
|
}
|
|
|
|
ZTEST(onoff_api, test_error)
|
|
{
|
|
struct onoff_client cli2 = {};
|
|
int rc;
|
|
|
|
/* Verify rejected operations when error present. */
|
|
|
|
setup_error();
|
|
|
|
rc = onoff_request(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, -EIO,
|
|
"req in err");
|
|
|
|
rc = onoff_release(&onoff_srv);
|
|
zassert_equal(rc, -EIO,
|
|
"rel in err");
|
|
|
|
reset_state.async = true;
|
|
sys_notify_init_spinwait(&cli2.notify);
|
|
|
|
rc = onoff_reset(&onoff_srv, &cli2);
|
|
zassert_equal(rc, ONOFF_STATE_ERROR,
|
|
"rst");
|
|
|
|
rc = onoff_request(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, -ENOTSUP,
|
|
"req in err");
|
|
|
|
rc = onoff_release(&onoff_srv);
|
|
zassert_equal(rc, -ENOTSUP,
|
|
"rel in err");
|
|
}
|
|
|
|
ZTEST(onoff_api, test_cancel_req)
|
|
{
|
|
int rc;
|
|
|
|
setup_test();
|
|
start_state.async = true;
|
|
start_state.retval = 14;
|
|
|
|
rc = onoff_cancel(NULL, NULL);
|
|
zassert_equal(rc, -EINVAL,
|
|
"can 0 0");
|
|
rc = onoff_cancel(&onoff_srv, NULL);
|
|
zassert_equal(rc, -EINVAL,
|
|
"can srv 0");
|
|
rc = onoff_cancel(NULL, &onoff_cli);
|
|
zassert_equal(rc, -EINVAL,
|
|
"can 0 cli");
|
|
|
|
rc = onoff_request(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, ONOFF_STATE_OFF,
|
|
"async req: %d", rc);
|
|
check_result(-EAGAIN, "async req");
|
|
zassert_equal(ntrans, 1U,
|
|
"req trans");
|
|
check_trans(0, ONOFF_STATE_TO_ON, 0,
|
|
"trans to-on");
|
|
|
|
rc = onoff_cancel(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, ONOFF_STATE_TO_ON,
|
|
"cancel req: %d", rc);
|
|
|
|
rc = onoff_cancel(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, -EALREADY,
|
|
"re-cancel req: %d", rc);
|
|
|
|
zassert_equal(ntrans, 1U,
|
|
"req trans");
|
|
notify(&start_state);
|
|
|
|
zassert_equal(ntrans, 4U,
|
|
"req trans");
|
|
check_trans(1, ONOFF_STATE_ON, start_state.retval,
|
|
"trans on");
|
|
check_trans(2, ONOFF_STATE_TO_OFF, 0,
|
|
"trans to-off");
|
|
check_trans(3, ONOFF_STATE_OFF, stop_state.retval,
|
|
"trans off");
|
|
}
|
|
|
|
ZTEST(onoff_api, test_cancel_delayed_req)
|
|
{
|
|
int rc;
|
|
|
|
setup_test();
|
|
|
|
rc = onoff_request(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, ONOFF_STATE_OFF,
|
|
"req: %d", rc);
|
|
check_result(start_state.retval, "req");
|
|
zassert_equal(ntrans, 2U,
|
|
"req trans");
|
|
check_trans(0, ONOFF_STATE_TO_ON, 0,
|
|
"trans to-on");
|
|
check_trans(1, ONOFF_STATE_ON, start_state.retval,
|
|
"trans on");
|
|
|
|
stop_state.async = true;
|
|
stop_state.retval = 14;
|
|
|
|
rc = onoff_release(&onoff_srv);
|
|
zassert_true(rc >= 0,
|
|
"rel: %d", rc);
|
|
zassert_equal(onoff_srv.refs, 0U,
|
|
"on refs: %u", onoff_srv.refs);
|
|
zassert_equal(ntrans, 3U,
|
|
"async rel trans");
|
|
check_trans(2, ONOFF_STATE_TO_OFF, 0,
|
|
"trans to-off");
|
|
|
|
reset_cli();
|
|
|
|
rc = onoff_request(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, ONOFF_STATE_TO_OFF,
|
|
"del req: %d", rc);
|
|
zassert_equal(ntrans, 3U,
|
|
"async rel trans");
|
|
check_result(-EAGAIN, "del req");
|
|
|
|
rc = onoff_cancel(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, ONOFF_STATE_TO_OFF,
|
|
"can del req: %d", rc);
|
|
|
|
notify(&stop_state);
|
|
|
|
zassert_equal(ntrans, 4U,
|
|
"req trans");
|
|
check_trans(2, ONOFF_STATE_TO_OFF, 0,
|
|
"trans to-off");
|
|
check_trans(3, ONOFF_STATE_OFF, stop_state.retval,
|
|
"trans off");
|
|
}
|
|
|
|
ZTEST(onoff_api, test_cancel_or_release)
|
|
{
|
|
int rc;
|
|
|
|
/* First, verify that the cancel-or-release idiom works when
|
|
* invoked in state TO-ON.
|
|
*/
|
|
|
|
setup_test();
|
|
start_state.async = true;
|
|
|
|
rc = onoff_request(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, ONOFF_STATE_OFF,
|
|
"req");
|
|
rc = onoff_cancel_or_release(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, ONOFF_STATE_TO_ON,
|
|
"c|r to-on");
|
|
notify(&start_state);
|
|
|
|
zassert_equal(ntrans, 4U,
|
|
"req trans");
|
|
check_trans(3, ONOFF_STATE_OFF, stop_state.retval,
|
|
"trans off");
|
|
|
|
/* Now verify that the cancel-or-release idiom works when
|
|
* invoked in state ON.
|
|
*/
|
|
|
|
setup_test();
|
|
start_state.async = false;
|
|
|
|
rc = onoff_request(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, ONOFF_STATE_OFF,
|
|
"req");
|
|
zassert_equal(ntrans, 2U,
|
|
"req trans");
|
|
|
|
rc = onoff_cancel_or_release(&onoff_srv, &onoff_cli);
|
|
zassert_equal(rc, ONOFF_STATE_ON,
|
|
"c|r to-on");
|
|
zassert_equal(ntrans, 4U,
|
|
"req trans");
|
|
check_trans(3, ONOFF_STATE_OFF, stop_state.retval,
|
|
"trans off");
|
|
}
|
|
|
|
ZTEST(onoff_api, test_sync_basic)
|
|
{
|
|
static struct onoff_sync_service srv = {};
|
|
k_spinlock_key_t key;
|
|
int res = 5;
|
|
int rc;
|
|
|
|
reset_cli();
|
|
|
|
rc = onoff_sync_lock(&srv, &key);
|
|
zassert_equal(rc, 0,
|
|
"init req");
|
|
|
|
rc = onoff_sync_finalize(&srv, key, &onoff_cli, res, true);
|
|
zassert_equal(rc, 1,
|
|
"req count");
|
|
zassert_equal(callback_srv, NULL,
|
|
"sync cb srv");
|
|
zassert_equal(callback_cli, &onoff_cli,
|
|
"sync cb cli");
|
|
check_callback(ONOFF_STATE_ON, res, "sync req");
|
|
|
|
reset_cli();
|
|
reset_callback();
|
|
|
|
rc = onoff_sync_lock(&srv, &key);
|
|
zassert_equal(rc, 1,
|
|
"init rel");
|
|
|
|
++res;
|
|
rc = onoff_sync_finalize(&srv, key, &onoff_cli, res, true);
|
|
zassert_equal(rc, 2,
|
|
"req2 count");
|
|
check_callback(ONOFF_STATE_ON, res, "sync req2");
|
|
|
|
reset_cli();
|
|
|
|
rc = onoff_sync_lock(&srv, &key);
|
|
zassert_equal(rc, 2,
|
|
"init rel");
|
|
|
|
rc = onoff_sync_finalize(&srv, key, NULL, res, false);
|
|
zassert_equal(rc, 1,
|
|
"rel count");
|
|
|
|
reset_cli();
|
|
|
|
rc = onoff_sync_lock(&srv, &key);
|
|
zassert_equal(rc, 1,
|
|
"init rel2");
|
|
|
|
rc = onoff_sync_finalize(&srv, key, NULL, res, false);
|
|
zassert_equal(rc, 0,
|
|
"rel2 count");
|
|
|
|
/* Extra release is caught and diagnosed. May not happen with
|
|
* onoff manager, but we can/should do it for sync.
|
|
*/
|
|
reset_cli();
|
|
|
|
rc = onoff_sync_lock(&srv, &key);
|
|
zassert_equal(rc, 0,
|
|
"init rel2");
|
|
|
|
rc = onoff_sync_finalize(&srv, key, NULL, res, false);
|
|
zassert_equal(rc, -1,
|
|
"rel-1 count");
|
|
|
|
/* Error state is visible to next lock. */
|
|
reset_cli();
|
|
reset_callback();
|
|
|
|
rc = onoff_sync_lock(&srv, &key);
|
|
zassert_equal(rc, -1,
|
|
"init req");
|
|
}
|
|
|
|
ZTEST(onoff_api, test_sync_error)
|
|
{
|
|
static struct onoff_sync_service srv = {};
|
|
k_spinlock_key_t key;
|
|
int res = -EPERM;
|
|
int rc;
|
|
|
|
reset_cli();
|
|
reset_callback();
|
|
|
|
rc = onoff_sync_lock(&srv, &key);
|
|
zassert_equal(rc, 0,
|
|
"init req");
|
|
|
|
rc = onoff_sync_finalize(&srv, key, &onoff_cli, res, true);
|
|
|
|
zassert_equal(rc, res,
|
|
"err final");
|
|
zassert_equal(srv.count, res,
|
|
"srv err count");
|
|
zassert_equal(callback_srv, NULL,
|
|
"sync cb srv");
|
|
zassert_equal(callback_cli, &onoff_cli,
|
|
"sync cb cli");
|
|
check_callback(ONOFF_STATE_ERROR, res, "err final");
|
|
|
|
/* Error is visible to next operation (the value is the
|
|
* negative count)
|
|
*/
|
|
|
|
reset_cli();
|
|
reset_callback();
|
|
|
|
rc = onoff_sync_lock(&srv, &key);
|
|
zassert_equal(rc, -1,
|
|
"init req");
|
|
|
|
/* Error is cleared by non-negative finalize result */
|
|
res = 3;
|
|
rc = onoff_sync_finalize(&srv, key, &onoff_cli, res, true);
|
|
|
|
zassert_equal(rc, 1,
|
|
"req count %d", rc);
|
|
check_callback(ONOFF_STATE_ON, res, "sync req");
|
|
|
|
rc = onoff_sync_lock(&srv, &key);
|
|
zassert_equal(rc, 1,
|
|
"init rel");
|
|
}
|
|
|
|
|
|
void *test_init(void)
|
|
{
|
|
k_sem_init(&isr_sync, 0, 1);
|
|
k_timer_init(&isr_timer, isr_notify, NULL);
|
|
|
|
(void)isr_reset;
|
|
(void)isr_release;
|
|
(void)isr_request;
|
|
return NULL;
|
|
}
|
|
ZTEST_SUITE(onoff_api, NULL, test_init, NULL, NULL, NULL);
|