1003 lines
24 KiB
C
1003 lines
24 KiB
C
/* 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();
|
|
}
|