| /* |
| * Copyright 2021 The Chromium OS Authors |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/ztest.h> |
| #include <zephyr/smf.h> |
| |
| /* |
| * Flat Test Transition: |
| * |
| * A_ENTRY --> A_RUN --> A_EXIT --> B_ENTRY --> B_RUN --| |
| * | |
| * |----------------------------------------------------| |
| * | |
| * |--> B_EXIT --> C_ENTRY --> C_RUN --> C_EXIT |
| * |
| */ |
| |
| |
| #define TEST_OBJECT(o) ((struct test_object *)o) |
| |
| #define SMF_RUN 3 |
| |
| #define STATE_A_ENTRY_BIT (1 << 0) |
| #define STATE_A_RUN_BIT (1 << 1) |
| #define STATE_A_EXIT_BIT (1 << 2) |
| |
| #define STATE_B_ENTRY_BIT (1 << 3) |
| #define STATE_B_RUN_BIT (1 << 4) |
| #define STATE_B_EXIT_BIT (1 << 5) |
| |
| #define STATE_C_ENTRY_BIT (1 << 6) |
| #define STATE_C_RUN_BIT (1 << 7) |
| #define STATE_C_EXIT_BIT (1 << 8) |
| |
| #define TEST_ENTRY_VALUE_NUM 0 |
| #define TEST_RUN_VALUE_NUM 4 |
| #define TEST_EXIT_VALUE_NUM 8 |
| #define TEST_VALUE_NUM 9 |
| |
| static uint32_t test_value[] = { |
| 0x00, /* STATE_A_ENTRY */ |
| 0x01, /* STATE_A_RUN */ |
| 0x03, /* STATE_A_EXIT */ |
| 0x07, /* STATE_B_ENTRY */ |
| 0x0f, /* STATE_B_RUN */ |
| 0x1f, /* STATE_B_EXIT */ |
| 0x3f, /* STATE_C_ENTRY */ |
| 0x7f, /* STATE_C_RUN */ |
| 0xff, /* STATE_C_EXIT */ |
| 0x1ff, /* FINAL VALUE */ |
| }; |
| |
| /* Forward declaration of test_states */ |
| static const struct smf_state test_states[]; |
| |
| /* List of all TypeC-level states */ |
| enum test_state { |
| STATE_A, |
| STATE_B, |
| STATE_C, |
| STATE_D |
| }; |
| |
| enum terminate_action { |
| NONE, |
| ENTRY, |
| RUN, |
| EXIT |
| }; |
| |
| static struct test_object { |
| struct smf_ctx ctx; |
| uint32_t transition_bits; |
| uint32_t tv_idx; |
| enum terminate_action terminate; |
| } test_obj; |
| |
| static void state_a_entry(void *obj) |
| { |
| struct test_object *o = TEST_OBJECT(obj); |
| |
| o->tv_idx = 0; |
| zassert_equal(o->transition_bits, test_value[o->tv_idx], |
| "Test State A entry failed"); |
| |
| if (o->terminate == ENTRY) { |
| smf_set_terminate(obj, -1); |
| return; |
| } |
| |
| o->transition_bits |= STATE_A_ENTRY_BIT; |
| } |
| |
| static void state_a_run(void *obj) |
| { |
| struct test_object *o = TEST_OBJECT(obj); |
| |
| o->tv_idx++; |
| zassert_equal(o->transition_bits, test_value[o->tv_idx], |
| "Test State A run failed"); |
| |
| o->transition_bits |= STATE_A_RUN_BIT; |
| |
| smf_set_state(SMF_CTX(obj), &test_states[STATE_B]); |
| } |
| |
| static void state_a_exit(void *obj) |
| { |
| struct test_object *o = TEST_OBJECT(obj); |
| |
| o->tv_idx++; |
| zassert_equal(o->transition_bits, test_value[o->tv_idx], |
| "Test State A exit failed"); |
| |
| o->transition_bits |= STATE_A_EXIT_BIT; |
| } |
| |
| static void state_b_entry(void *obj) |
| { |
| struct test_object *o = TEST_OBJECT(obj); |
| |
| o->tv_idx++; |
| zassert_equal(o->transition_bits, test_value[o->tv_idx], |
| "Test State B entry failed"); |
| |
| o->transition_bits |= STATE_B_ENTRY_BIT; |
| } |
| |
| static void state_b_run(void *obj) |
| { |
| struct test_object *o = TEST_OBJECT(obj); |
| |
| o->tv_idx++; |
| zassert_equal(o->transition_bits, test_value[o->tv_idx], |
| "Test State B run failed"); |
| |
| if (o->terminate == RUN) { |
| smf_set_terminate(obj, -1); |
| return; |
| } |
| |
| o->transition_bits |= STATE_B_RUN_BIT; |
| |
| smf_set_state(SMF_CTX(obj), &test_states[STATE_C]); |
| } |
| |
| static void state_b_exit(void *obj) |
| { |
| struct test_object *o = TEST_OBJECT(obj); |
| |
| o->tv_idx++; |
| zassert_equal(o->transition_bits, test_value[o->tv_idx], |
| "Test State B exit failed"); |
| o->transition_bits |= STATE_B_EXIT_BIT; |
| } |
| |
| static void state_c_entry(void *obj) |
| { |
| struct test_object *o = TEST_OBJECT(obj); |
| |
| o->tv_idx++; |
| zassert_equal(o->transition_bits, test_value[o->tv_idx], |
| "Test State C entry failed"); |
| o->transition_bits |= STATE_C_ENTRY_BIT; |
| } |
| |
| static void state_c_run(void *obj) |
| { |
| struct test_object *o = TEST_OBJECT(obj); |
| |
| o->tv_idx++; |
| zassert_equal(o->transition_bits, test_value[o->tv_idx], |
| "Test State C run failed"); |
| o->transition_bits |= STATE_C_RUN_BIT; |
| |
| smf_set_state(SMF_CTX(obj), &test_states[STATE_D]); |
| } |
| |
| static void state_c_exit(void *obj) |
| { |
| struct test_object *o = TEST_OBJECT(obj); |
| |
| o->tv_idx++; |
| zassert_equal(o->transition_bits, test_value[o->tv_idx], |
| "Test State C exit failed"); |
| |
| if (o->terminate == EXIT) { |
| smf_set_terminate(obj, -1); |
| return; |
| } |
| |
| o->transition_bits |= STATE_C_EXIT_BIT; |
| } |
| |
| static void state_d_entry(void *obj) |
| { |
| struct test_object *o = TEST_OBJECT(obj); |
| |
| o->tv_idx++; |
| } |
| |
| static void state_d_run(void *obj) |
| { |
| /* Do nothing */ |
| } |
| |
| static void state_d_exit(void *obj) |
| { |
| /* Do nothing */ |
| } |
| |
| static const struct smf_state test_states[] = { |
| [STATE_A] = SMF_CREATE_STATE(state_a_entry, state_a_run, state_a_exit), |
| [STATE_B] = SMF_CREATE_STATE(state_b_entry, state_b_run, state_b_exit), |
| [STATE_C] = SMF_CREATE_STATE(state_c_entry, state_c_run, state_c_exit), |
| [STATE_D] = SMF_CREATE_STATE(state_d_entry, state_d_run, state_d_exit), |
| }; |
| |
| ZTEST(smf_tests, test_smf_flat) |
| { |
| /* A) Test transitions */ |
| |
| test_obj.transition_bits = 0; |
| test_obj.terminate = NONE; |
| smf_set_initial((struct smf_ctx *)&test_obj, &test_states[STATE_A]); |
| |
| for (int i = 0; i < SMF_RUN; i++) { |
| if (smf_run_state((struct smf_ctx *)&test_obj)) { |
| break; |
| } |
| } |
| |
| zassert_equal(TEST_VALUE_NUM, test_obj.tv_idx, |
| "Incorrect test value index"); |
| zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx], |
| "Final state not reached"); |
| |
| /* B) Test termination in entry action */ |
| |
| test_obj.transition_bits = 0; |
| test_obj.terminate = ENTRY; |
| smf_set_initial((struct smf_ctx *)&test_obj, &test_states[STATE_A]); |
| |
| for (int i = 0; i < SMF_RUN; i++) { |
| if (smf_run_state((struct smf_ctx *)&test_obj)) { |
| break; |
| } |
| } |
| |
| zassert_equal(TEST_ENTRY_VALUE_NUM, test_obj.tv_idx, |
| "Incorrect test value index for entry termination"); |
| zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx], |
| "Final entry termination state not reached"); |
| |
| /* C) Test termination in run action */ |
| |
| test_obj.transition_bits = 0; |
| test_obj.terminate = RUN; |
| smf_set_initial((struct smf_ctx *)&test_obj, &test_states[STATE_A]); |
| |
| for (int i = 0; i < SMF_RUN; i++) { |
| if (smf_run_state((struct smf_ctx *)&test_obj)) { |
| break; |
| } |
| } |
| |
| zassert_equal(TEST_RUN_VALUE_NUM, test_obj.tv_idx, |
| "Incorrect test value index for run termination"); |
| zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx], |
| "Final run termination state not reached"); |
| |
| /* D) Test termination in exit action */ |
| |
| test_obj.transition_bits = 0; |
| test_obj.terminate = EXIT; |
| smf_set_initial((struct smf_ctx *)&test_obj, &test_states[STATE_A]); |
| |
| for (int i = 0; i < SMF_RUN; i++) { |
| if (smf_run_state((struct smf_ctx *)&test_obj)) { |
| break; |
| } |
| } |
| |
| zassert_equal(TEST_EXIT_VALUE_NUM, test_obj.tv_idx, |
| "Incorrect test value index for exit termination"); |
| zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx], |
| "Final exit termination state not reached"); |
| } |