sys: onoff: Move transition functions out of service struct

Extracted transition functions from onoff structure to external one
which allows to keep them in flash.

Signed-off-by: Krzysztof Chruscinski <krzysztof.chruscinski@nordicsemi.no>
This commit is contained in:
Krzysztof Chruscinski 2020-02-04 09:41:52 +01:00 committed by Carles Cufí
commit e2ca46c329
3 changed files with 120 additions and 90 deletions

View file

@ -25,7 +25,7 @@ extern "C" {
*/ */
enum onoff_service_flags { enum onoff_service_flags {
/** /**
* @brief Flag passed to onoff_service_init(). * @brief Flag used in struct onoff_service_transitions.
* *
* When provided this indicates the start transition function * When provided this indicates the start transition function
* may cause the calling thread to wait. This blocks attempts * may cause the calling thread to wait. This blocks attempts
@ -34,7 +34,7 @@ enum onoff_service_flags {
ONOFF_SERVICE_START_SLEEPS = BIT(0), ONOFF_SERVICE_START_SLEEPS = BIT(0),
/** /**
* @brief Flag passed to onoff_service_init(). * @brief Flag used in struct onoff_service_transitions.
* *
* As with @ref ONOFF_SERVICE_START_SLEEPS but describing the * As with @ref ONOFF_SERVICE_START_SLEEPS but describing the
* stop transition function. * stop transition function.
@ -42,7 +42,7 @@ enum onoff_service_flags {
ONOFF_SERVICE_STOP_SLEEPS = BIT(1), ONOFF_SERVICE_STOP_SLEEPS = BIT(1),
/** /**
* @brief Flag passed to onoff_service_init(). * @brief Flag used in struct onoff_service_transitions.
* *
* As with @ref ONOFF_SERVICE_START_SLEEPS but describing the * As with @ref ONOFF_SERVICE_START_SLEEPS but describing the
* reset transition function. * reset transition function.
@ -102,6 +102,21 @@ typedef void (*onoff_service_notify_fn)(struct onoff_service *srv,
typedef void (*onoff_service_transition_fn)(struct onoff_service *srv, typedef void (*onoff_service_transition_fn)(struct onoff_service *srv,
onoff_service_notify_fn notify); onoff_service_notify_fn notify);
/** @brief On-off service transition functions. */
struct onoff_service_transitions {
/* Function to invoke to transition the service to on. */
onoff_service_transition_fn start;
/* Function to invoke to transition the service to off. */
onoff_service_transition_fn stop;
/* Function to force the service state to reset, where supported. */
onoff_service_transition_fn reset;
/* Flags identifying transition function capabilities. */
u8_t flags;
};
/** /**
* @brief State associated with an on-off service. * @brief State associated with an on-off service.
* *
@ -117,16 +132,8 @@ struct onoff_service {
*/ */
sys_slist_t clients; sys_slist_t clients;
/* Function to invoke to transition the service to on. */ /* Transition functions. */
onoff_service_transition_fn start; const struct onoff_service_transitions *transitions;
/* Function to invoke to transition the service to off. */
onoff_service_transition_fn stop;
/* Function to force the service state to reset, where
* supported.
*/
onoff_service_transition_fn reset;
/* Mutex protection for flags, clients, releaser, and refs. */ /* Mutex protection for flags, clients, releaser, and refs. */
struct k_spinlock lock; struct k_spinlock lock;
@ -141,14 +148,30 @@ struct onoff_service {
u16_t refs; u16_t refs;
}; };
/** @internal */ /** @brief Initializer of transitions structure.
#define ONOFF_SERVICE_INITIALIZER(_start, _stop, _reset, _flags) { \ *
* @param _start a function used to transition from off to on state.
*
* @param _stop a function used to transition from on to off state.
*
* @param _reset a function used to clear errors and force the service to an off
* state. Can be null.
*
* @param _flags any or all of the flags from enum onoff_service_flags.
*/
#define ONOFF_SERVICE_TRANSITIONS_INITIALIZER(_start, _stop, _reset, _flags) { \
.start = _start, \ .start = _start, \
.stop = _stop, \ .stop = _stop, \
.reset = _reset, \ .reset = _reset, \
.flags = _flags, \ .flags = _flags, \
} }
/** @internal */
#define ONOFF_SERVICE_INITIALIZER(_transitions) { \
.transitions = _transitions, \
.flags = (_transitions)->flags, \
}
/** /**
* @brief Initialize an on-off service to off state. * @brief Initialize an on-off service to off state.
* *
@ -160,32 +183,14 @@ struct onoff_service {
* *
* @param srv the service definition object to be initialized. * @param srv the service definition object to be initialized.
* *
* @param start the function used to (initiate a) transition from off * @param transitions A structure with transition functions. Structure must be
* to on. This must not be null. Include @ref ONOFF_SERVICE_START_SLEEPS as * persistent as it is used by the service.
* appropriate in flags.
*
* @param stop the function used to (initiate a) transition from on to
* off. This must not be null. Include @ref ONOFF_SERVICE_STOP_SLEEPS
* as appropriate in flags.
*
* @param reset the function used to clear errors and force the
* service to an off state. Pass null if the service cannot or need
* not be reset. (Services where a transition operation can complete
* with an error notification should support the reset operation.)
* Include @ref ONOFF_SERVICE_RESET_SLEEPS as appropriate in flags.
*
* @param flags any or all of the flags mentioned above,
* e.g. @ref ONOFF_SERVICE_START_SLEEPS. Use of other flags produces an
* error.
* *
* @retval 0 on success * @retval 0 on success
* @retval -EINVAL if start, stop, or flags are invalid * @retval -EINVAL if start, stop, or flags are invalid
*/ */
int onoff_service_init(struct onoff_service *srv, int onoff_service_init(struct onoff_service *srv,
onoff_service_transition_fn start, const struct onoff_service_transitions *transitions);
onoff_service_transition_fn stop,
onoff_service_transition_fn reset,
u32_t flags);
/** @internal /** @internal
* *

View file

@ -11,6 +11,7 @@
#define CLIENT_NOTIFY_METHOD_MASK 0x03 #define CLIENT_NOTIFY_METHOD_MASK 0x03
#define CLIENT_VALID_FLAGS_MASK 0x07 #define CLIENT_VALID_FLAGS_MASK 0x07
#define SERVICE_CONFIG_FLAGS \ #define SERVICE_CONFIG_FLAGS \
(ONOFF_SERVICE_START_SLEEPS \ (ONOFF_SERVICE_START_SLEEPS \
| ONOFF_SERVICE_STOP_SLEEPS \ | ONOFF_SERVICE_STOP_SLEEPS \
@ -76,21 +77,17 @@ static int validate_args(const struct onoff_service *srv,
} }
int onoff_service_init(struct onoff_service *srv, int onoff_service_init(struct onoff_service *srv,
onoff_service_transition_fn start, const struct onoff_service_transitions *transitions)
onoff_service_transition_fn stop,
onoff_service_transition_fn reset,
u32_t flags)
{ {
if ((flags & SERVICE_CONFIG_FLAGS) != flags) { if (transitions->flags & ~SERVICE_CONFIG_FLAGS) {
return -EINVAL; return -EINVAL;
} }
if ((start == NULL) || (stop == NULL)) { if ((transitions->start == NULL) || (transitions->stop == NULL)) {
return -EINVAL; return -EINVAL;
} }
*srv = (struct onoff_service)ONOFF_SERVICE_INITIALIZER(start, stop, *srv = (struct onoff_service)ONOFF_SERVICE_INITIALIZER(transitions);
reset, flags);
return 0; return 0;
} }
@ -261,8 +258,8 @@ out:
k_spin_unlock(&srv->lock, key); k_spin_unlock(&srv->lock, key);
if (start) { if (start) {
__ASSERT_NO_MSG(srv->start != NULL); __ASSERT_NO_MSG(srv->transitions->start != NULL);
srv->start(srv, onoff_start_notify); srv->transitions->start(srv, onoff_start_notify);
} else if (notify) { } else if (notify) {
notify_one(srv, cli, 0); notify_one(srv, cli, 0);
} }
@ -328,7 +325,7 @@ static void onoff_stop_notify(struct onoff_service *srv,
if (notify_clients) { if (notify_clients) {
notify_all(srv, &clients, client_res); notify_all(srv, &clients, client_res);
} else if (start) { } else if (start) {
srv->start(srv, onoff_start_notify); srv->transitions->start(srv, onoff_start_notify);
} }
} }
@ -396,8 +393,8 @@ out:
k_spin_unlock(&srv->lock, key); k_spin_unlock(&srv->lock, key);
if (stop) { if (stop) {
__ASSERT_NO_MSG(srv->stop != NULL); __ASSERT_NO_MSG(srv->transitions->stop != NULL);
srv->stop(srv, onoff_stop_notify); srv->transitions->stop(srv, onoff_stop_notify);
} else if (notify) { } else if (notify) {
notify_one(srv, cli, 0); notify_one(srv, cli, 0);
} }
@ -435,7 +432,7 @@ static void onoff_reset_notify(struct onoff_service *srv,
int onoff_service_reset(struct onoff_service *srv, int onoff_service_reset(struct onoff_service *srv,
struct onoff_client *cli) struct onoff_client *cli)
{ {
if (srv->reset == NULL) { if (srv->transitions->reset == NULL) {
return -ENOTSUP; return -ENOTSUP;
} }
@ -472,7 +469,7 @@ out:
k_spin_unlock(&srv->lock, key); k_spin_unlock(&srv->lock, key);
if (reset) { if (reset) {
srv->reset(srv, onoff_reset_notify); srv->transitions->reset(srv, onoff_reset_notify);
} }
return rv; return rv;

View file

@ -167,44 +167,53 @@ static void test_service_init_validation(void)
{ {
int rc; int rc;
struct onoff_service srv; struct onoff_service srv;
const struct onoff_service_transitions null_transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(NULL, NULL, NULL, 0);
const struct onoff_service_transitions start_transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, NULL, NULL, 0);
const struct onoff_service_transitions stop_transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(NULL, stop, NULL, 0);
struct onoff_service_transitions start_stop_transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, NULL, 0);
const struct onoff_service_transitions all_transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, reset,
ONOFF_SERVICE_START_SLEEPS);
clear_transit(); clear_transit();
rc = onoff_service_init(NULL, NULL, NULL, NULL, 0); rc = onoff_service_init(NULL, &null_transitions);
zassert_equal(rc, -EINVAL, zassert_equal(rc, -EINVAL,
"init null srv %d", rc); "init null srv %d", rc);
rc = onoff_service_init(&srv, NULL, NULL, NULL, 0); rc = onoff_service_init(&srv, &null_transitions);
zassert_equal(rc, -EINVAL, zassert_equal(rc, -EINVAL,
"init null transit %d", rc); "init null transit %d", rc);
rc = onoff_service_init(&srv, start, NULL, NULL, 0); rc = onoff_service_init(&srv, &start_transitions);
zassert_equal(rc, -EINVAL, zassert_equal(rc, -EINVAL,
"init null stop %d", rc); "init null stop %d", rc);
rc = onoff_service_init(&srv, NULL, stop, NULL, 0); rc = onoff_service_init(&srv, &stop_transitions);
zassert_equal(rc, -EINVAL, zassert_equal(rc, -EINVAL,
"init null start %d", rc); "init null start %d", rc);
rc = onoff_service_init(&srv, start, stop, NULL, start_stop_transitions.flags |= ONOFF_SERVICE_INTERNAL_BASE;
ONOFF_SERVICE_INTERNAL_BASE); rc = onoff_service_init(&srv, &start_stop_transitions);
zassert_equal(rc, -EINVAL, zassert_equal(rc, -EINVAL,
"init bad flags %d", rc); "init bad flags %d", rc);
u32_t flags = ONOFF_SERVICE_START_SLEEPS;
memset(&srv, 0xA5, sizeof(srv)); memset(&srv, 0xA5, sizeof(srv));
zassert_false(sys_slist_is_empty(&srv.clients), zassert_false(sys_slist_is_empty(&srv.clients),
"slist empty"); "slist empty");
rc = onoff_service_init(&srv, start, stop, reset, flags); rc = onoff_service_init(&srv, &all_transitions);
zassert_equal(rc, 0, zassert_equal(rc, 0,
"init good %d", rc); "init good %d", rc);
zassert_equal(srv.start, start, zassert_equal(srv.transitions->start, start,
"init start mismatch"); "init start mismatch");
zassert_equal(srv.stop, stop, zassert_equal(srv.transitions->stop, stop,
"init stop mismatch"); "init stop mismatch");
zassert_equal(srv.reset, reset, zassert_equal(srv.transitions->reset, reset,
"init reset mismatch"); "init reset mismatch");
zassert_equal(srv.flags, ONOFF_SERVICE_START_SLEEPS, zassert_equal(srv.flags, ONOFF_SERVICE_START_SLEEPS,
"init flags mismatch"); "init flags mismatch");
@ -256,6 +265,8 @@ static void test_validate_args(void)
struct onoff_service srv; struct onoff_service srv;
struct k_poll_signal sig; struct k_poll_signal sig;
struct onoff_client cli; struct onoff_client cli;
const struct onoff_service_transitions transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, NULL, 0);
clear_transit(); clear_transit();
@ -263,7 +274,7 @@ static void test_validate_args(void)
* release, and reset; test it through the request API. * release, and reset; test it through the request API.
*/ */
rc = onoff_service_init(&srv, start, stop, NULL, 0); rc = onoff_service_init(&srv, &transitions);
zassert_equal(rc, 0, zassert_equal(rc, 0,
"service init"); "service init");
@ -334,17 +345,21 @@ static void test_reset(void)
struct onoff_client cli; struct onoff_client cli;
unsigned int signalled = 0; unsigned int signalled = 0;
int result = 0; int result = 0;
const struct onoff_service_transitions transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, NULL, 0);
struct onoff_service_transitions transitions_with_reset =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, reset, 0);
clear_transit(); clear_transit();
rc = onoff_service_init(&srv, start, stop, NULL, 0); rc = onoff_service_init(&srv, &transitions);
zassert_equal(rc, 0, zassert_equal(rc, 0,
"service init"); "service init");
rc = onoff_service_reset(&srv, &cli); rc = onoff_service_reset(&srv, &cli);
zassert_equal(rc, -ENOTSUP, zassert_equal(rc, -ENOTSUP,
"reset: %d", rc); "reset: %d", rc);
rc = onoff_service_init(&srv, start, stop, reset, 0); rc = onoff_service_init(&srv, &transitions_with_reset);
zassert_equal(rc, 0, zassert_equal(rc, 0,
"service init"); "service init");
@ -423,8 +438,8 @@ static void test_reset(void)
zassert_false(onoff_service_has_error(&srv), zassert_false(onoff_service_has_error(&srv),
"has error"); "has error");
rc = onoff_service_init(&srv, start, stop, reset, transitions_with_reset.flags |= ONOFF_SERVICE_RESET_SLEEPS;
ONOFF_SERVICE_RESET_SLEEPS); rc = onoff_service_init(&srv, &transitions_with_reset);
zassert_equal(rc, 0, zassert_equal(rc, 0,
"service init"); "service init");
start_state.retval = -23; start_state.retval = -23;
@ -460,10 +475,12 @@ static void test_request(void)
{ {
int rc; int rc;
struct onoff_service srv; struct onoff_service srv;
struct onoff_service_transitions transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, reset, 0);
clear_transit(); clear_transit();
rc = onoff_service_init(&srv, start, stop, reset, 0); rc = onoff_service_init(&srv, &transitions);
zassert_equal(rc, 0, zassert_equal(rc, 0,
"service init"); "service init");
@ -546,8 +563,8 @@ static void test_request(void)
"has error"); "has error");
/* Diagnose a no-wait delayed start */ /* Diagnose a no-wait delayed start */
rc = onoff_service_init(&srv, start, stop, reset, transitions.flags |= ONOFF_SERVICE_START_SLEEPS;
ONOFF_SERVICE_START_SLEEPS); rc = onoff_service_init(&srv, &transitions);
zassert_equal(rc, 0, zassert_equal(rc, 0,
"service init"); "service init");
start_state.async = true; start_state.async = true;
@ -578,10 +595,12 @@ static void test_sync(void)
{ {
int rc; int rc;
struct onoff_service srv; struct onoff_service srv;
const struct onoff_service_transitions transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, reset, 0);
clear_transit(); clear_transit();
rc = onoff_service_init(&srv, start, stop, reset, 0); rc = onoff_service_init(&srv, &transitions);
zassert_equal(rc, 0, zassert_equal(rc, 0,
"service init"); "service init");
@ -628,6 +647,9 @@ static void test_async(void)
struct onoff_client cli[2]; struct onoff_client cli[2];
unsigned int signalled = 0; unsigned int signalled = 0;
int result = 0; int result = 0;
const struct onoff_service_transitions transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, reset,
ONOFF_SERVICE_START_SLEEPS | ONOFF_SERVICE_STOP_SLEEPS);
clear_transit(); clear_transit();
start_state.async = true; start_state.async = true;
@ -635,9 +657,7 @@ static void test_async(void)
stop_state.async = true; stop_state.async = true;
stop_state.retval = 17; stop_state.retval = 17;
rc = onoff_service_init(&srv, start, stop, reset, rc = onoff_service_init(&srv, &transitions);
ONOFF_SERVICE_START_SLEEPS
| ONOFF_SERVICE_STOP_SLEEPS);
zassert_equal(rc, 0, zassert_equal(rc, 0,
"service init"); "service init");
@ -820,14 +840,16 @@ static void test_half_sync(void)
struct onoff_service srv; struct onoff_service srv;
struct k_poll_signal sig; struct k_poll_signal sig;
struct onoff_client cli; struct onoff_client cli;
const struct onoff_service_transitions transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, NULL,
ONOFF_SERVICE_STOP_SLEEPS);
clear_transit(); clear_transit();
start_state.retval = 23; start_state.retval = 23;
stop_state.async = true; stop_state.async = true;
stop_state.retval = 17; stop_state.retval = 17;
rc = onoff_service_init(&srv, start, stop, NULL, rc = onoff_service_init(&srv, &transitions);
ONOFF_SERVICE_STOP_SLEEPS);
zassert_equal(rc, 0, zassert_equal(rc, 0,
"service init"); "service init");
@ -876,6 +898,9 @@ static void test_cancel_request_waits(void)
struct onoff_service srv; struct onoff_service srv;
struct k_poll_signal sig; struct k_poll_signal sig;
struct onoff_client cli; struct onoff_client cli;
const struct onoff_service_transitions transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, NULL,
ONOFF_SERVICE_START_SLEEPS | ONOFF_SERVICE_STOP_SLEEPS);
clear_transit(); clear_transit();
start_state.async = true; start_state.async = true;
@ -883,9 +908,7 @@ static void test_cancel_request_waits(void)
stop_state.async = true; stop_state.async = true;
stop_state.retval = 31; stop_state.retval = 31;
rc = onoff_service_init(&srv, start, stop, NULL, rc = onoff_service_init(&srv, &transitions);
ONOFF_SERVICE_START_SLEEPS
| ONOFF_SERVICE_STOP_SLEEPS);
zassert_equal(rc, 0, zassert_equal(rc, 0,
"service init"); "service init");
@ -972,14 +995,16 @@ static void test_cancel_request_ok(void)
struct onoff_service srv; struct onoff_service srv;
struct k_poll_signal sig; struct k_poll_signal sig;
struct onoff_client cli; struct onoff_client cli;
const struct onoff_service_transitions transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, NULL,
ONOFF_SERVICE_START_SLEEPS);
clear_transit(); clear_transit();
start_state.async = true; start_state.async = true;
start_state.retval = 14; start_state.retval = 14;
stop_state.retval = 31; stop_state.retval = 31;
rc = onoff_service_init(&srv, start, stop, NULL, rc = onoff_service_init(&srv, &transitions);
ONOFF_SERVICE_START_SLEEPS);
zassert_equal(rc, 0, zassert_equal(rc, 0,
"service init"); "service init");
@ -1027,6 +1052,9 @@ static void test_blocked_restart(void)
int result; int result;
struct k_poll_signal sig[2]; struct k_poll_signal sig[2];
struct onoff_client cli[2]; struct onoff_client cli[2];
const struct onoff_service_transitions transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, NULL,
ONOFF_SERVICE_START_SLEEPS | ONOFF_SERVICE_STOP_SLEEPS);
clear_transit(); clear_transit();
start_state.async = true; start_state.async = true;
@ -1034,9 +1062,7 @@ static void test_blocked_restart(void)
stop_state.async = true; stop_state.async = true;
stop_state.retval = 31; stop_state.retval = 31;
rc = onoff_service_init(&srv, start, stop, NULL, rc = onoff_service_init(&srv, &transitions);
ONOFF_SERVICE_START_SLEEPS
| ONOFF_SERVICE_STOP_SLEEPS);
zassert_equal(rc, 0, zassert_equal(rc, 0,
"service init"); "service init");
@ -1103,14 +1129,16 @@ static void test_cancel_release(void)
{ {
int rc; int rc;
struct onoff_service srv; struct onoff_service srv;
const struct onoff_service_transitions transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, NULL,
ONOFF_SERVICE_STOP_SLEEPS);
clear_transit(); clear_transit();
start_state.retval = 16; start_state.retval = 16;
stop_state.async = true; stop_state.async = true;
stop_state.retval = 94; stop_state.retval = 94;
rc = onoff_service_init(&srv, start, stop, NULL, rc = onoff_service_init(&srv, &transitions);
ONOFF_SERVICE_STOP_SLEEPS);
zassert_equal(rc, 0, zassert_equal(rc, 0,
"service init"); "service init");