diff --git a/include/sys/onoff.h b/include/sys/onoff.h index d8629d6a549..9f49e791835 100644 --- a/include/sys/onoff.h +++ b/include/sys/onoff.h @@ -25,7 +25,7 @@ extern "C" { */ 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 * may cause the calling thread to wait. This blocks attempts @@ -34,7 +34,7 @@ enum onoff_service_flags { 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 * stop transition function. @@ -42,7 +42,7 @@ enum onoff_service_flags { 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 * 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, 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. * @@ -117,16 +132,8 @@ struct onoff_service { */ sys_slist_t clients; - /* 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; + /* Transition functions. */ + const struct onoff_service_transitions *transitions; /* Mutex protection for flags, clients, releaser, and refs. */ struct k_spinlock lock; @@ -141,12 +148,28 @@ struct onoff_service { u16_t refs; }; +/** @brief Initializer of transitions structure. + * + * @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, \ + .stop = _stop, \ + .reset = _reset, \ + .flags = _flags, \ +} + /** @internal */ -#define ONOFF_SERVICE_INITIALIZER(_start, _stop, _reset, _flags) { \ - .start = _start, \ - .stop = _stop, \ - .reset = _reset, \ - .flags = _flags, \ +#define ONOFF_SERVICE_INITIALIZER(_transitions) { \ + .transitions = _transitions, \ + .flags = (_transitions)->flags, \ } /** @@ -160,32 +183,14 @@ struct onoff_service { * * @param srv the service definition object to be initialized. * - * @param start the function used to (initiate a) transition from off - * to on. This must not be null. Include @ref ONOFF_SERVICE_START_SLEEPS as - * 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. + * @param transitions A structure with transition functions. Structure must be + * persistent as it is used by the service. * * @retval 0 on success * @retval -EINVAL if start, stop, or flags are invalid */ int onoff_service_init(struct onoff_service *srv, - onoff_service_transition_fn start, - onoff_service_transition_fn stop, - onoff_service_transition_fn reset, - u32_t flags); + const struct onoff_service_transitions *transitions); /** @internal * diff --git a/lib/os/onoff.c b/lib/os/onoff.c index 2a999b6ef8b..140527fb7cd 100644 --- a/lib/os/onoff.c +++ b/lib/os/onoff.c @@ -11,6 +11,7 @@ #define CLIENT_NOTIFY_METHOD_MASK 0x03 #define CLIENT_VALID_FLAGS_MASK 0x07 + #define SERVICE_CONFIG_FLAGS \ (ONOFF_SERVICE_START_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, - onoff_service_transition_fn start, - onoff_service_transition_fn stop, - onoff_service_transition_fn reset, - u32_t flags) + const struct onoff_service_transitions *transitions) { - if ((flags & SERVICE_CONFIG_FLAGS) != flags) { + if (transitions->flags & ~SERVICE_CONFIG_FLAGS) { return -EINVAL; } - if ((start == NULL) || (stop == NULL)) { + if ((transitions->start == NULL) || (transitions->stop == NULL)) { return -EINVAL; } - *srv = (struct onoff_service)ONOFF_SERVICE_INITIALIZER(start, stop, - reset, flags); + *srv = (struct onoff_service)ONOFF_SERVICE_INITIALIZER(transitions); return 0; } @@ -261,8 +258,8 @@ out: k_spin_unlock(&srv->lock, key); if (start) { - __ASSERT_NO_MSG(srv->start != NULL); - srv->start(srv, onoff_start_notify); + __ASSERT_NO_MSG(srv->transitions->start != NULL); + srv->transitions->start(srv, onoff_start_notify); } else if (notify) { notify_one(srv, cli, 0); } @@ -328,7 +325,7 @@ static void onoff_stop_notify(struct onoff_service *srv, if (notify_clients) { notify_all(srv, &clients, client_res); } 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); if (stop) { - __ASSERT_NO_MSG(srv->stop != NULL); - srv->stop(srv, onoff_stop_notify); + __ASSERT_NO_MSG(srv->transitions->stop != NULL); + srv->transitions->stop(srv, onoff_stop_notify); } else if (notify) { 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, struct onoff_client *cli) { - if (srv->reset == NULL) { + if (srv->transitions->reset == NULL) { return -ENOTSUP; } @@ -472,7 +469,7 @@ out: k_spin_unlock(&srv->lock, key); if (reset) { - srv->reset(srv, onoff_reset_notify); + srv->transitions->reset(srv, onoff_reset_notify); } return rv; diff --git a/tests/lib/onoff/src/main.c b/tests/lib/onoff/src/main.c index 0cf2de278df..25c7e08c242 100644 --- a/tests/lib/onoff/src/main.c +++ b/tests/lib/onoff/src/main.c @@ -167,44 +167,53 @@ static void test_service_init_validation(void) { int rc; 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(); - rc = onoff_service_init(NULL, NULL, NULL, NULL, 0); + rc = onoff_service_init(NULL, &null_transitions); zassert_equal(rc, -EINVAL, "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, "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, "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, "init null start %d", rc); - rc = onoff_service_init(&srv, start, stop, NULL, - ONOFF_SERVICE_INTERNAL_BASE); + start_stop_transitions.flags |= ONOFF_SERVICE_INTERNAL_BASE; + rc = onoff_service_init(&srv, &start_stop_transitions); zassert_equal(rc, -EINVAL, "init bad flags %d", rc); - u32_t flags = ONOFF_SERVICE_START_SLEEPS; - memset(&srv, 0xA5, sizeof(srv)); zassert_false(sys_slist_is_empty(&srv.clients), "slist empty"); - rc = onoff_service_init(&srv, start, stop, reset, flags); + rc = onoff_service_init(&srv, &all_transitions); zassert_equal(rc, 0, "init good %d", rc); - zassert_equal(srv.start, start, + zassert_equal(srv.transitions->start, start, "init start mismatch"); - zassert_equal(srv.stop, stop, + zassert_equal(srv.transitions->stop, stop, "init stop mismatch"); - zassert_equal(srv.reset, reset, + zassert_equal(srv.transitions->reset, reset, "init reset mismatch"); zassert_equal(srv.flags, ONOFF_SERVICE_START_SLEEPS, "init flags mismatch"); @@ -256,6 +265,8 @@ static void test_validate_args(void) struct onoff_service srv; struct k_poll_signal sig; struct onoff_client cli; + const struct onoff_service_transitions transitions = + ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, NULL, 0); clear_transit(); @@ -263,7 +274,7 @@ static void test_validate_args(void) * 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, "service init"); @@ -334,17 +345,21 @@ static void test_reset(void) struct onoff_client cli; unsigned int signalled = 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(); - rc = onoff_service_init(&srv, start, stop, NULL, 0); + rc = onoff_service_init(&srv, &transitions); zassert_equal(rc, 0, "service init"); rc = onoff_service_reset(&srv, &cli); zassert_equal(rc, -ENOTSUP, "reset: %d", rc); - rc = onoff_service_init(&srv, start, stop, reset, 0); + rc = onoff_service_init(&srv, &transitions_with_reset); zassert_equal(rc, 0, "service init"); @@ -423,8 +438,8 @@ static void test_reset(void) zassert_false(onoff_service_has_error(&srv), "has error"); - rc = onoff_service_init(&srv, start, stop, reset, - ONOFF_SERVICE_RESET_SLEEPS); + transitions_with_reset.flags |= ONOFF_SERVICE_RESET_SLEEPS; + rc = onoff_service_init(&srv, &transitions_with_reset); zassert_equal(rc, 0, "service init"); start_state.retval = -23; @@ -460,10 +475,12 @@ static void test_request(void) { int rc; struct onoff_service srv; + struct onoff_service_transitions transitions = + ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, reset, 0); clear_transit(); - rc = onoff_service_init(&srv, start, stop, reset, 0); + rc = onoff_service_init(&srv, &transitions); zassert_equal(rc, 0, "service init"); @@ -546,8 +563,8 @@ static void test_request(void) "has error"); /* Diagnose a no-wait delayed start */ - rc = onoff_service_init(&srv, start, stop, reset, - ONOFF_SERVICE_START_SLEEPS); + transitions.flags |= ONOFF_SERVICE_START_SLEEPS; + rc = onoff_service_init(&srv, &transitions); zassert_equal(rc, 0, "service init"); start_state.async = true; @@ -578,10 +595,12 @@ static void test_sync(void) { int rc; struct onoff_service srv; + const struct onoff_service_transitions transitions = + ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, reset, 0); clear_transit(); - rc = onoff_service_init(&srv, start, stop, reset, 0); + rc = onoff_service_init(&srv, &transitions); zassert_equal(rc, 0, "service init"); @@ -628,6 +647,9 @@ static void test_async(void) struct onoff_client cli[2]; unsigned int signalled = 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(); start_state.async = true; @@ -635,9 +657,7 @@ static void test_async(void) stop_state.async = true; stop_state.retval = 17; - rc = onoff_service_init(&srv, start, stop, reset, - ONOFF_SERVICE_START_SLEEPS - | ONOFF_SERVICE_STOP_SLEEPS); + rc = onoff_service_init(&srv, &transitions); zassert_equal(rc, 0, "service init"); @@ -820,14 +840,16 @@ static void test_half_sync(void) struct onoff_service srv; struct k_poll_signal sig; struct onoff_client cli; + const struct onoff_service_transitions transitions = + ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, NULL, + ONOFF_SERVICE_STOP_SLEEPS); clear_transit(); start_state.retval = 23; stop_state.async = true; stop_state.retval = 17; - rc = onoff_service_init(&srv, start, stop, NULL, - ONOFF_SERVICE_STOP_SLEEPS); + rc = onoff_service_init(&srv, &transitions); zassert_equal(rc, 0, "service init"); @@ -876,6 +898,9 @@ static void test_cancel_request_waits(void) struct onoff_service srv; struct k_poll_signal sig; 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(); start_state.async = true; @@ -883,9 +908,7 @@ static void test_cancel_request_waits(void) stop_state.async = true; stop_state.retval = 31; - rc = onoff_service_init(&srv, start, stop, NULL, - ONOFF_SERVICE_START_SLEEPS - | ONOFF_SERVICE_STOP_SLEEPS); + rc = onoff_service_init(&srv, &transitions); zassert_equal(rc, 0, "service init"); @@ -972,14 +995,16 @@ static void test_cancel_request_ok(void) struct onoff_service srv; struct k_poll_signal sig; struct onoff_client cli; + const struct onoff_service_transitions transitions = + ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, NULL, + ONOFF_SERVICE_START_SLEEPS); clear_transit(); start_state.async = true; start_state.retval = 14; stop_state.retval = 31; - rc = onoff_service_init(&srv, start, stop, NULL, - ONOFF_SERVICE_START_SLEEPS); + rc = onoff_service_init(&srv, &transitions); zassert_equal(rc, 0, "service init"); @@ -1027,6 +1052,9 @@ static void test_blocked_restart(void) int result; struct k_poll_signal sig[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(); start_state.async = true; @@ -1034,9 +1062,7 @@ static void test_blocked_restart(void) stop_state.async = true; stop_state.retval = 31; - rc = onoff_service_init(&srv, start, stop, NULL, - ONOFF_SERVICE_START_SLEEPS - | ONOFF_SERVICE_STOP_SLEEPS); + rc = onoff_service_init(&srv, &transitions); zassert_equal(rc, 0, "service init"); @@ -1103,14 +1129,16 @@ static void test_cancel_release(void) { int rc; struct onoff_service srv; + const struct onoff_service_transitions transitions = + ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, NULL, + ONOFF_SERVICE_STOP_SLEEPS); clear_transit(); start_state.retval = 16; stop_state.async = true; stop_state.retval = 94; - rc = onoff_service_init(&srv, start, stop, NULL, - ONOFF_SERVICE_STOP_SLEEPS); + rc = onoff_service_init(&srv, &transitions); zassert_equal(rc, 0, "service init");