blob: ba544a749a99acadc282de6399c4feeb879f47ff [file] [log] [blame]
/* 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();
}