/* Copyright 2019 The Chromium OS Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * * Test USB Type-C VPD and CTVPD module. */ #include "common.h" #include "task.h" #include "test_util.h" #include "timer.h" #include "usb_pd.h" #include "usb_sm.h" #include "usb_tc_sm.h" #include "util.h" #include "usb_pd_test_util.h" #include "vpd_api.h" /* * Test State Hierarchy * SM_TEST_A4 transitions to SM_TEST_B4 * SM_TEST_B4 transitions to SM_TEST_B5 * SM_TEST_B5 transitions to SM_TEST_B6 * SM_TEST_B6 transitions to SM_TEST_C * SM_TEST_C transitions to SM_TEST_A7 * SM_TEST_A7 transitions to SM_TEST_A6 * SM_TEST_A6 transitions to SM_TEST_A5 * SM_TEST_A5 transitions to SM_TEST_A4 * * --------------------------- --------------------------- * | SM_TEST_SUPER_A1 | | SM_TEST_SUPER_B1 | * | ----------------------- | | ----------------------- | * | | SM_TEST_SUPER_A2 | | | | SM_TEST_SUPER_B2 | | * | | ------------------- | | | | ------------------- | | * | | |SM_TEST_SUPER_A3 | | | | | |SM_TEST_SUPER_B3 | | | * | | | | | | | | | | | | * | | | ------------- | | | | | | ------------- | | | * | | | | SM_TEST_A4|------------------>| SM_TEST_B4| | | | * | | | ------------- | | | | | | ------------- | | | * | | | ^ | | | | | |--------|--------| | | * | | | | | | | | | | | | * | | | -------------- | | | | | \/ | | * | | | | SM_TEST_A5 | | | | | | -------------- | | * | | | -------------- | | | | | | SM_TEST_B5 | | | * | | |--------^--------| | | | | -------------- | | * | | | | | | | | | | * | | -------------- | | | -----------|----------- | * | | | SM_TEST_A6 | | | | \/ | * | | -------------- | | | -------------- | * | |----------^----------| | | | SM_TEST_B6 | | * | | | | -------------- | * | -------------- | |--------/----------------| * | | SM_TEST_A7 | | / * | -------------- | / * |------------------^------| / * \ / * \ \/ * ------------- * | SM_TEST_C | * ------------- * * test_hierarchy_0: Tests a flat state machine without super states * test_hierarchy_1: Tests a hierarchical state machine with 1 super state * test_hierarchy_2: Tests a hierarchical state machine with 2 super states * test_hierarchy_3: Tests a hierarchical state machine with 3 super states * */ #define SEQUENCE_SIZE 55 enum state_id { ENTER_A1 = 1, RUN_A1, EXIT_A1, ENTER_A2, RUN_A2, EXIT_A2, ENTER_A3, RUN_A3, EXIT_A3, ENTER_A4, RUN_A4, EXIT_A4, ENTER_A5, RUN_A5, EXIT_A5, ENTER_A6, RUN_A6, EXIT_A6, ENTER_A7, RUN_A7, EXIT_A7, ENTER_B1, RUN_B1, EXIT_B1, ENTER_B2, RUN_B2, EXIT_B2, ENTER_B3, RUN_B3, EXIT_B3, ENTER_B4, RUN_B4, EXIT_B4, ENTER_B5, RUN_B5, EXIT_B5, ENTER_B6, RUN_B6, EXIT_B6, ENTER_C, RUN_C, EXIT_C, }; #define PORT0 0 struct sm_ { /* struct sm_obj must be first */ struct sm_ctx ctx; int sv_tmp; int idx; int seq[SEQUENCE_SIZE]; } sm[1]; enum state { SM_TEST_SUPER_A1, SM_TEST_SUPER_A2, SM_TEST_SUPER_A3, SM_TEST_SUPER_B1, SM_TEST_SUPER_B2, SM_TEST_SUPER_B3, SM_TEST_A4, SM_TEST_A5, SM_TEST_A6, SM_TEST_A7, SM_TEST_B4, SM_TEST_B5, SM_TEST_B6, SM_TEST_C, }; static const struct usb_state states[]; static struct control { usb_state_ptr a3_entry_to; usb_state_ptr b3_run_to; usb_state_ptr b6_entry_to; usb_state_ptr c_entry_to; usb_state_ptr c_exit_to; } test_control; static void set_state_sm(const int port, const enum state new_state) { set_state(port, &sm[port].ctx, &states[new_state]); } static void sm_test_super_A1_entry(const int port) { sm[port].seq[sm[port].idx++] = ENTER_A1; } static void sm_test_super_A1_run(const int port) { sm[port].seq[sm[port].idx++] = RUN_A1; } static void sm_test_super_A1_exit(const int port) { sm[port].seq[sm[port].idx++] = EXIT_A1; } static void sm_test_super_B1_entry(const int port) { sm[port].seq[sm[port].idx++] = ENTER_B1; } static void sm_test_super_B1_run(const int port) { sm[port].seq[sm[port].idx++] = RUN_B1; } static void sm_test_super_B1_exit(const int port) { sm[port].seq[sm[port].idx++] = EXIT_B1; } static void sm_test_super_A2_entry(const int port) { sm[port].seq[sm[port].idx++] = ENTER_A2; } static void sm_test_super_A2_run(const int port) { sm[port].seq[sm[port].idx++] = RUN_A2; } static void sm_test_super_A2_exit(const int port) { sm[port].seq[sm[port].idx++] = EXIT_A2; } static void sm_test_super_B2_entry(const int port) { sm[port].seq[sm[port].idx++] = ENTER_B2; } static void sm_test_super_B2_run(const int port) { sm[port].seq[sm[port].idx++] = RUN_B2; } static void sm_test_super_B2_exit(const int port) { sm[port].seq[sm[port].idx++] = EXIT_B2; } static void sm_test_super_A3_entry(const int port) { sm[port].seq[sm[port].idx++] = ENTER_A3; if (test_control.a3_entry_to) set_state(port, &sm[port].ctx, test_control.a3_entry_to); } static void sm_test_super_A3_run(const int port) { sm[port].seq[sm[port].idx++] = RUN_A3; } static void sm_test_super_A3_exit(const int port) { sm[port].seq[sm[port].idx++] = EXIT_A3; } static void sm_test_super_B3_entry(const int port) { sm[port].seq[sm[port].idx++] = ENTER_B3; } static void sm_test_super_B3_run(const int port) { sm[port].seq[sm[port].idx++] = RUN_B3; if (test_control.b3_run_to) set_state(port, &sm[port].ctx, test_control.b3_run_to); } static void sm_test_super_B3_exit(const int port) { sm[port].seq[sm[port].idx++] = EXIT_B3; } static void sm_test_A4_entry(const int port) { sm[port].sv_tmp = 0; sm[port].seq[sm[port].idx++] = ENTER_A4; } static void sm_test_A4_run(const int port) { if (sm[port].sv_tmp == 0) { sm[port].sv_tmp = 1; sm[port].seq[sm[port].idx++] = RUN_A4; } else { set_state_sm(port, SM_TEST_B4); } } static void sm_test_A4_exit(const int port) { sm[port].seq[sm[port].idx++] = EXIT_A4; } static void sm_test_A5_entry(const int port) { sm[port].sv_tmp = 0; sm[port].seq[sm[port].idx++] = ENTER_A5; } static void sm_test_A5_run(const int port) { if (sm[port].sv_tmp == 0) { sm[port].sv_tmp = 1; sm[port].seq[sm[port].idx++] = RUN_A5; } else { set_state_sm(port, SM_TEST_A4); } } static void sm_test_A5_exit(const int port) { sm[port].seq[sm[port].idx++] = EXIT_A5; } static void sm_test_A6_entry(const int port) { sm[port].sv_tmp = 0; sm[port].seq[sm[port].idx++] = ENTER_A6; } static void sm_test_A6_run(const int port) { if (sm[port].sv_tmp == 0) { sm[port].sv_tmp = 1; sm[port].seq[sm[port].idx++] = RUN_A6; } else { set_state_sm(port, SM_TEST_A5); } } static void sm_test_A6_exit(const int port) { sm[port].seq[sm[port].idx++] = EXIT_A6; } static void sm_test_A7_entry(const int port) { sm[port].sv_tmp = 0; sm[port].seq[sm[port].idx++] = ENTER_A7; } static void sm_test_A7_run(const int port) { if (sm[port].sv_tmp == 0) { sm[port].sv_tmp = 1; sm[port].seq[sm[port].idx++] = RUN_A7; } else { set_state_sm(port, SM_TEST_A6); } } static void sm_test_A7_exit(const int port) { sm[port].seq[sm[port].idx++] = EXIT_A7; } static void sm_test_B4_entry(const int port) { sm[port].sv_tmp = 0; sm[port].seq[sm[port].idx++] = ENTER_B4; } static void sm_test_B4_run(const int port) { if (sm[port].sv_tmp == 0) { sm[port].seq[sm[port].idx++] = RUN_B4; sm[port].sv_tmp = 1; } else { set_state_sm(port, SM_TEST_B5); } } static void sm_test_B4_exit(const int port) { sm[port].seq[sm[port].idx++] = EXIT_B4; } static void sm_test_B5_entry(const int port) { sm[port].sv_tmp = 0; sm[port].seq[sm[port].idx++] = ENTER_B5; } static void sm_test_B5_run(const int port) { if (sm[port].sv_tmp == 0) { sm[port].sv_tmp = 1; sm[port].seq[sm[port].idx++] = RUN_B5; } else { set_state_sm(port, SM_TEST_B6); } } static void sm_test_B5_exit(const int port) { sm[port].seq[sm[port].idx++] = EXIT_B5; } static void sm_test_B6_entry(const int port) { sm[port].sv_tmp = 0; sm[port].seq[sm[port].idx++] = ENTER_B6; if (test_control.b6_entry_to) set_state(port, &sm[port].ctx, test_control.b6_entry_to); } static void sm_test_B6_run(const int port) { if (sm[port].sv_tmp == 0) { sm[port].sv_tmp = 1; sm[port].seq[sm[port].idx++] = RUN_B6; } else { set_state_sm(port, SM_TEST_C); } } static void sm_test_B6_exit(const int port) { sm[port].seq[sm[port].idx++] = EXIT_B6; } static void sm_test_C_entry(const int port) { sm[port].sv_tmp = 0; sm[port].seq[sm[port].idx++] = ENTER_C; if (test_control.c_entry_to) set_state(port, &sm[port].ctx, test_control.c_entry_to); } static void sm_test_C_run(const int port) { if (sm[port].sv_tmp == 0) { sm[port].seq[sm[port].idx++] = RUN_C; sm[port].sv_tmp = 1; } else { set_state_sm(port, SM_TEST_A7); } } static void sm_test_C_exit(const int port) { sm[port].seq[sm[port].idx++] = EXIT_C; if (test_control.c_exit_to) set_state(port, &sm[port].ctx, test_control.c_exit_to); } static void run_sm(void) { task_wake(TASK_ID_TEST); task_wait_event(5 * MSEC); } test_static int test_hierarchy_0(void) { int port = PORT0; int i = 0; set_state_sm(port, SM_TEST_A4); run_sm(); TEST_EQ(sm[port].seq[i], ENTER_A4, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_A4, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_A4, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_B4, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_B4, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_B4, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_B5, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_B5, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_B5, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_B6, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_B6, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_B6, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_C, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_C, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_C, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A7, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_A7, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_A7, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A6, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_A6, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_A6, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A5, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_A5, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_A5, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A4, "%d"); ++i; for (; i < SEQUENCE_SIZE; i++) TEST_EQ(sm[port].seq[i], 0, "%d"); return EC_SUCCESS; } test_static int test_hierarchy_1(void) { int port = PORT0; int i = 0; set_state_sm(port, SM_TEST_A4); run_sm(); TEST_EQ(sm[port].seq[i], ENTER_A3, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A4, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_A4, "%d"); ++i; TEST_EQ(sm[port].seq[i], RUN_A3, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_A4, "%d"); ++i; TEST_EQ(sm[port].seq[i], EXIT_A3, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_B3, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_B4, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_B4, "%d"); ++i; TEST_EQ(sm[port].seq[i], RUN_B3, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_B4, "%d"); ++i; TEST_EQ(sm[port].seq[i], EXIT_B3, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_B5, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_B5, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_B5, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_B6, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_B6, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_B6, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_C, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_C, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_C, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A7, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_A7, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_A7, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A6, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_A6, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_A6, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A3, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A5, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_A5, "%d"); ++i; TEST_EQ(sm[port].seq[i], RUN_A3, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_A5, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A4, "%d"); ++i; for (i = 33; i < SEQUENCE_SIZE; i++) TEST_EQ(sm[port].seq[i], 0, "%d"); return EC_SUCCESS; } test_static int test_hierarchy_2(void) { int port = PORT0; int i = 0; set_state_sm(port, SM_TEST_A4); run_sm(); TEST_EQ(sm[port].seq[i], ENTER_A2, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A3, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A4, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_A4, "%d"); ++i; TEST_EQ(sm[port].seq[i], RUN_A3, "%d"); ++i; TEST_EQ(sm[port].seq[i], RUN_A2, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_A4, "%d"); ++i; TEST_EQ(sm[port].seq[i], EXIT_A3, "%d"); ++i; TEST_EQ(sm[port].seq[i], EXIT_A2, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_B2, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_B3, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_B4, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_B4, "%d"); ++i; TEST_EQ(sm[port].seq[i], RUN_B3, "%d"); ++i; TEST_EQ(sm[port].seq[i], RUN_B2, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_B4, "%d"); ++i; TEST_EQ(sm[port].seq[i], EXIT_B3, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_B5, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_B5, "%d"); ++i; TEST_EQ(sm[port].seq[i], RUN_B2, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_B5, "%d"); ++i; TEST_EQ(sm[port].seq[i], EXIT_B2, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_B6, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_B6, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_B6, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_C, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_C, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_C, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A7, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_A7, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_A7, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A2, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A6, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_A6, "%d"); ++i; TEST_EQ(sm[port].seq[i], RUN_A2, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_A6, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A3, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A5, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_A5, "%d"); ++i; TEST_EQ(sm[port].seq[i], RUN_A3, "%d"); ++i; TEST_EQ(sm[port].seq[i], RUN_A2, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_A5, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A4, "%d"); ++i; for (; i < SEQUENCE_SIZE; i++) TEST_EQ(sm[port].seq[i], 0, "%d"); return EC_SUCCESS; } test_static int test_hierarchy_3(void) { int port = PORT0; int i = 0; set_state_sm(port, SM_TEST_A4); run_sm(); TEST_EQ(sm[port].seq[i], ENTER_A1, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A2, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A3, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A4, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_A4, "%d"); ++i; TEST_EQ(sm[port].seq[i], RUN_A3, "%d"); ++i; TEST_EQ(sm[port].seq[i], RUN_A2, "%d"); ++i; TEST_EQ(sm[port].seq[i], RUN_A1, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_A4, "%d"); ++i; TEST_EQ(sm[port].seq[i], EXIT_A3, "%d"); ++i; TEST_EQ(sm[port].seq[i], EXIT_A2, "%d"); ++i; TEST_EQ(sm[port].seq[i], EXIT_A1, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_B1, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_B2, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_B3, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_B4, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_B4, "%d"); ++i; TEST_EQ(sm[port].seq[i], RUN_B3, "%d"); ++i; TEST_EQ(sm[port].seq[i], RUN_B2, "%d"); ++i; TEST_EQ(sm[port].seq[i], RUN_B1, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_B4, "%d"); ++i; TEST_EQ(sm[port].seq[i], EXIT_B3, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_B5, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_B5, "%d"); ++i; TEST_EQ(sm[port].seq[i], RUN_B2, "%d"); ++i; TEST_EQ(sm[port].seq[i], RUN_B1, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_B5, "%d"); ++i; TEST_EQ(sm[port].seq[i], EXIT_B2, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_B6, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_B6, "%d"); ++i; TEST_EQ(sm[port].seq[i], RUN_B1, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_B6, "%d"); ++i; TEST_EQ(sm[port].seq[i], EXIT_B1, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_C, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_C, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_C, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A1, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A7, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_A7, "%d"); ++i; TEST_EQ(sm[port].seq[i], RUN_A1, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_A7, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A2, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A6, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_A6, "%d"); ++i; TEST_EQ(sm[port].seq[i], RUN_A2, "%d"); ++i; TEST_EQ(sm[port].seq[i], RUN_A1, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_A6, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A3, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A5, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], RUN_A5, "%d"); ++i; TEST_EQ(sm[port].seq[i], RUN_A3, "%d"); ++i; TEST_EQ(sm[port].seq[i], RUN_A2, "%d"); ++i; TEST_EQ(sm[port].seq[i], RUN_A1, "%d"); ++i; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_A5, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A4, "%d"); ++i; for (; i < SEQUENCE_SIZE; i++) TEST_EQ(sm[port].seq[i], 0, "%d"); return EC_SUCCESS; } test_static int test_set_state_from_parents(void) { int port = PORT0; int i = 0; /* Start state machine */ test_control.a3_entry_to = &states[SM_TEST_B4]; run_sm(); set_state_sm(port, SM_TEST_A4); TEST_EQ(sm[port].seq[i], ENTER_A1, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A2, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A3, "%d"); ++i; /* Does not enter or exit A4 */ TEST_EQ(sm[port].seq[i], EXIT_A3, "%d"); ++i; TEST_EQ(sm[port].seq[i], EXIT_A2, "%d"); ++i; TEST_EQ(sm[port].seq[i], EXIT_A1, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_B1, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_B2, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_B3, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_B4, "%d"); ++i; /* Ensure we didn't go further than above statements */ TEST_EQ(sm[port].seq[i], 0, "%d"); test_control.b3_run_to = &states[SM_TEST_B5]; run_sm(); TEST_EQ(sm[port].seq[i], RUN_B4, "%d"); ++i; TEST_EQ(sm[port].seq[i], RUN_B3, "%d"); ++i; /* Does not run b2 or b1 */ TEST_EQ(sm[port].seq[i], EXIT_B4, "%d"); ++i; TEST_EQ(sm[port].seq[i], EXIT_B3, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_B5, "%d"); ++i; /* Ensure we didn't go further than above statements */ TEST_EQ(sm[port].seq[i], 0, "%d"); run_sm(); TEST_EQ(sm[port].seq[i], RUN_B5, "%d"); ++i; TEST_EQ(sm[port].seq[i], RUN_B2, "%d"); ++i; TEST_EQ(sm[port].seq[i], RUN_B1, "%d"); ++i; /* Ensure we didn't go further than above statements */ TEST_EQ(sm[port].seq[i], 0, "%d"); /* * Ensure that multiple chains of parent entry works. Also ensure * that set states in exit are ignored. */ test_control.b6_entry_to = &states[SM_TEST_C]; test_control.c_entry_to = &states[SM_TEST_A7]; test_control.c_exit_to = &states[SM_TEST_A4]; run_sm(); TEST_EQ(sm[port].seq[i], EXIT_B5, "%d"); ++i; TEST_EQ(sm[port].seq[i], EXIT_B2, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_B6, "%d"); ++i; TEST_EQ(sm[port].seq[i], EXIT_B6, "%d"); ++i; TEST_EQ(sm[port].seq[i], EXIT_B1, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_C, "%d"); ++i; TEST_EQ(sm[port].seq[i], EXIT_C, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A1, "%d"); ++i; TEST_EQ(sm[port].seq[i], ENTER_A7, "%d"); ++i; /* Ensure we didn't go further than above statements */ TEST_EQ(sm[port].seq[i], 0, "%d"); for (; i < SEQUENCE_SIZE; i++) TEST_EQ(sm[port].seq[i], 0, "%d"); return EC_SUCCESS; } #ifdef TEST_USB_SM_FRAMEWORK_H3 #define TEST_AT_LEAST_3 #endif #if defined(TEST_AT_LEAST_3) || defined(TEST_USB_SM_FRAMEWORK_H2) #define TEST_AT_LEAST_2 #endif #if defined(TEST_AT_LEAST_2) || defined(TEST_USB_SM_FRAMEWORK_H1) #define TEST_AT_LEAST_1 #endif static const struct usb_state states[] = { [SM_TEST_SUPER_A1] = { .entry = sm_test_super_A1_entry, .run = sm_test_super_A1_run, .exit = sm_test_super_A1_exit, }, [SM_TEST_SUPER_A2] = { .entry = sm_test_super_A2_entry, .run = sm_test_super_A2_run, .exit = sm_test_super_A2_exit, #ifdef TEST_AT_LEAST_3 .parent = &states[SM_TEST_SUPER_A1], #endif }, [SM_TEST_SUPER_A3] = { .entry = sm_test_super_A3_entry, .run = sm_test_super_A3_run, .exit = sm_test_super_A3_exit, #ifdef TEST_AT_LEAST_2 .parent = &states[SM_TEST_SUPER_A2], #endif }, [SM_TEST_SUPER_B1] = { .entry = sm_test_super_B1_entry, .run = sm_test_super_B1_run, .exit = sm_test_super_B1_exit, }, [SM_TEST_SUPER_B2] = { .entry = sm_test_super_B2_entry, .run = sm_test_super_B2_run, .exit = sm_test_super_B2_exit, #ifdef TEST_AT_LEAST_3 .parent = &states[SM_TEST_SUPER_B1], #endif }, [SM_TEST_SUPER_B3] = { .entry = sm_test_super_B3_entry, .run = sm_test_super_B3_run, .exit = sm_test_super_B3_exit, #ifdef TEST_AT_LEAST_2 .parent = &states[SM_TEST_SUPER_B2], #endif }, [SM_TEST_A4] = { .entry = sm_test_A4_entry, .run = sm_test_A4_run, .exit = sm_test_A4_exit, #ifdef TEST_AT_LEAST_1 .parent = &states[SM_TEST_SUPER_A3], #endif }, [SM_TEST_A5] = { .entry = sm_test_A5_entry, .run = sm_test_A5_run, .exit = sm_test_A5_exit, #ifdef TEST_AT_LEAST_1 .parent = &states[SM_TEST_SUPER_A3], #endif }, [SM_TEST_A6] = { .entry = sm_test_A6_entry, .run = sm_test_A6_run, .exit = sm_test_A6_exit, #ifdef TEST_AT_LEAST_2 .parent = &states[SM_TEST_SUPER_A2], #endif }, [SM_TEST_A7] = { .entry = sm_test_A7_entry, .run = sm_test_A7_run, .exit = sm_test_A7_exit, #ifdef TEST_AT_LEAST_3 .parent = &states[SM_TEST_SUPER_A1], #endif }, [SM_TEST_B4] = { .entry = sm_test_B4_entry, .run = sm_test_B4_run, .exit = sm_test_B4_exit, #ifdef TEST_AT_LEAST_1 .parent = &states[SM_TEST_SUPER_B3], #endif }, [SM_TEST_B5] = { .entry = sm_test_B5_entry, .run = sm_test_B5_run, .exit = sm_test_B5_exit, #ifdef TEST_AT_LEAST_2 .parent = &states[SM_TEST_SUPER_B2], #endif }, [SM_TEST_B6] = { .entry = sm_test_B6_entry, .run = sm_test_B6_run, .exit = sm_test_B6_exit, #ifdef TEST_AT_LEAST_3 .parent = &states[SM_TEST_SUPER_B1], #endif }, [SM_TEST_C] = { .entry = sm_test_C_entry, .run = sm_test_C_run, .exit = sm_test_C_exit, }, }; /* Run before each RUN_TEST line */ void before_test(void) { /* Rest test variables */ memset(&sm[PORT0], 0, sizeof(struct sm_)); memset(&test_control, 0, sizeof(struct control)); } int test_task(void *u) { int port = PORT0; while (1) { /* wait for next event/packet or timeout expiration */ task_wait_event(-1); /* run state machine */ run_state(port, &sm[port].ctx); } return EC_SUCCESS; } void run_test(int argc, char **argv) { test_reset(); #if defined(TEST_USB_SM_FRAMEWORK_H3) RUN_TEST(test_hierarchy_3); RUN_TEST(test_set_state_from_parents); #elif defined(TEST_USB_SM_FRAMEWORK_H2) RUN_TEST(test_hierarchy_2); #elif defined(TEST_USB_SM_FRAMEWORK_H1) RUN_TEST(test_hierarchy_1); #else RUN_TEST(test_hierarchy_0); #endif test_print_result(); }