/* Copyright 2014 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. */ #include "console.h" #include "ec_commands.h" #include "lightbar.h" #include "host_command.h" #include "test_util.h" #include "timer.h" #include "util.h" static int get_seq(void) { int rv; struct ec_params_lightbar params; struct ec_response_lightbar resp; /* Get the state */ memset(&resp, 0, sizeof(resp)); params.cmd = LIGHTBAR_CMD_GET_SEQ; rv = test_send_host_command(EC_CMD_LIGHTBAR_CMD, 0, ¶ms, sizeof(params), &resp, sizeof(resp)); if (rv != EC_RES_SUCCESS) { ccprintf("%s:%s(): rv = %d\n", __FILE__, __func__, rv); return -1; } return resp.get_seq.num; } static int set_seq(int s) { int rv; struct ec_params_lightbar params; struct ec_response_lightbar resp; /* Get the state */ memset(&resp, 0, sizeof(resp)); params.cmd = LIGHTBAR_CMD_SEQ; params.seq.num = s; rv = test_send_host_command(EC_CMD_LIGHTBAR_CMD, 0, ¶ms, sizeof(params), &resp, sizeof(resp)); if (rv != EC_RES_SUCCESS) { ccprintf("%s:%s(): rv = %d\n", __FILE__, __func__, rv); return -1; } return EC_RES_SUCCESS; } static int test_double_oneshots(void) { /* Start in S0 */ TEST_ASSERT(set_seq(LIGHTBAR_S0) == EC_RES_SUCCESS); usleep(SECOND); TEST_ASSERT(get_seq() == LIGHTBAR_S0); /* Invoke the oneshot */ TEST_ASSERT(set_seq(LIGHTBAR_TAP) == EC_RES_SUCCESS); usleep(SECOND); TEST_ASSERT(get_seq() == LIGHTBAR_TAP); /* Switch to a different oneshot while that one's running */ TEST_ASSERT(set_seq(LIGHTBAR_KONAMI) == EC_RES_SUCCESS); usleep(SECOND); TEST_ASSERT(get_seq() == LIGHTBAR_KONAMI); /* Afterwards, it should go back to the original normal state */ usleep(30 * SECOND); TEST_ASSERT(get_seq() == LIGHTBAR_S0); /* Same test, but with a bunch more oneshots. */ TEST_ASSERT(set_seq(LIGHTBAR_S0) == EC_RES_SUCCESS); usleep(SECOND); TEST_ASSERT(get_seq() == LIGHTBAR_S0); TEST_ASSERT(set_seq(LIGHTBAR_TAP) == EC_RES_SUCCESS); usleep(SECOND); TEST_ASSERT(get_seq() == LIGHTBAR_TAP); TEST_ASSERT(set_seq(LIGHTBAR_KONAMI) == EC_RES_SUCCESS); usleep(SECOND); TEST_ASSERT(get_seq() == LIGHTBAR_KONAMI); TEST_ASSERT(set_seq(LIGHTBAR_TAP) == EC_RES_SUCCESS); usleep(SECOND); TEST_ASSERT(get_seq() == LIGHTBAR_TAP); TEST_ASSERT(set_seq(LIGHTBAR_KONAMI) == EC_RES_SUCCESS); usleep(SECOND); TEST_ASSERT(get_seq() == LIGHTBAR_KONAMI); TEST_ASSERT(set_seq(LIGHTBAR_TAP) == EC_RES_SUCCESS); usleep(SECOND); TEST_ASSERT(get_seq() == LIGHTBAR_TAP); /* It should still go back to the original normal state */ usleep(30 * SECOND); TEST_ASSERT(get_seq() == LIGHTBAR_S0); /* But if the interruption is a normal state, that should stick. */ TEST_ASSERT(set_seq(LIGHTBAR_S0) == EC_RES_SUCCESS); usleep(SECOND); TEST_ASSERT(get_seq() == LIGHTBAR_S0); TEST_ASSERT(set_seq(LIGHTBAR_TAP) == EC_RES_SUCCESS); usleep(SECOND); TEST_ASSERT(get_seq() == LIGHTBAR_TAP); TEST_ASSERT(set_seq(LIGHTBAR_KONAMI) == EC_RES_SUCCESS); usleep(SECOND); TEST_ASSERT(get_seq() == LIGHTBAR_KONAMI); /* Here's a normal sequence */ TEST_ASSERT(set_seq(LIGHTBAR_S3) == EC_RES_SUCCESS); usleep(SECOND); TEST_ASSERT(get_seq() == LIGHTBAR_S3); /* And another one-shot */ TEST_ASSERT(set_seq(LIGHTBAR_TAP) == EC_RES_SUCCESS); usleep(SECOND); TEST_ASSERT(get_seq() == LIGHTBAR_TAP); TEST_ASSERT(set_seq(LIGHTBAR_KONAMI) == EC_RES_SUCCESS); usleep(SECOND); TEST_ASSERT(get_seq() == LIGHTBAR_KONAMI); TEST_ASSERT(set_seq(LIGHTBAR_TAP) == EC_RES_SUCCESS); usleep(SECOND); TEST_ASSERT(get_seq() == LIGHTBAR_TAP); /* It should go back to the new normal sequence */ usleep(30 * SECOND); TEST_ASSERT(get_seq() == LIGHTBAR_S3); return EC_SUCCESS; } static int test_oneshots_norm_msg(void) { /* Revert to the next state when interrupted with a normal message. */ enum lightbar_sequence seqs[] = { LIGHTBAR_KONAMI, LIGHTBAR_TAP, }; int i; for (i = 0; i < ARRAY_SIZE(seqs); i++) { /* Start in S0 */ TEST_ASSERT(set_seq(LIGHTBAR_S0) == EC_RES_SUCCESS); usleep(SECOND); /* Invoke the oneshot */ TEST_ASSERT(set_seq(seqs[i]) == EC_RES_SUCCESS); usleep(SECOND); /* Interrupt with S0S3 */ TEST_ASSERT(set_seq(LIGHTBAR_S0S3) == EC_RES_SUCCESS); usleep(SECOND); /* It should be back right away */ TEST_ASSERT(get_seq() == LIGHTBAR_S0S3); /* And transition on to the correct value */ usleep(30 * SECOND); TEST_ASSERT(get_seq() == LIGHTBAR_S3); } return EC_SUCCESS; } static int test_stop_timeout(void) { int i; for (i = 0; i < LIGHTBAR_NUM_SEQUENCES; i++) { /* Start in S0 */ TEST_ASSERT(set_seq(LIGHTBAR_S0) == EC_RES_SUCCESS); usleep(SECOND); /* Tell it to stop */ TEST_ASSERT(set_seq(LIGHTBAR_STOP) == EC_RES_SUCCESS); usleep(SECOND); TEST_ASSERT(get_seq() == LIGHTBAR_STOP); /* Try to interrupt it */ TEST_ASSERT(set_seq(i) == EC_RES_SUCCESS); usleep(SECOND); /* What happened? */ if (i == LIGHTBAR_RUN || i == LIGHTBAR_S0S3 || i == LIGHTBAR_S3 || i == LIGHTBAR_S3S5 || i == LIGHTBAR_S5) /* RUN or shutdown sequences should stop it */ TEST_ASSERT(get_seq() == LIGHTBAR_S0); else /* All other sequences should be ignored */ TEST_ASSERT(get_seq() == LIGHTBAR_STOP); /* Let it RUN again for the next iteration */ TEST_ASSERT(set_seq(LIGHTBAR_RUN) == EC_RES_SUCCESS); usleep(SECOND); } TEST_ASSERT(set_seq(LIGHTBAR_S0) == EC_RES_SUCCESS); return EC_SUCCESS; } static int test_oneshots_timeout(void) { /* These should revert to the previous state after running */ enum lightbar_sequence seqs[] = { LIGHTBAR_RUN, LIGHTBAR_KONAMI, LIGHTBAR_TAP, }; int i; for (i = 0; i < ARRAY_SIZE(seqs); i++) { TEST_ASSERT(set_seq(LIGHTBAR_S0) == EC_RES_SUCCESS); usleep(SECOND); TEST_ASSERT(set_seq(seqs[i]) == EC_RES_SUCCESS); /* Assume the oneshot sequence takes at least a second (except * for LIGHTBAR_RUN, which returns immediately) */ if (seqs[i] != LIGHTBAR_RUN) { usleep(SECOND); TEST_ASSERT(get_seq() == seqs[i]); } usleep(30 * SECOND); TEST_ASSERT(get_seq() == LIGHTBAR_S0); } return EC_SUCCESS; } static int test_transition_states(void) { /* S5S3 */ TEST_ASSERT(set_seq(LIGHTBAR_S5S3) == EC_RES_SUCCESS); usleep(10 * SECOND); TEST_ASSERT(get_seq() == LIGHTBAR_S3); /* S3S0 */ TEST_ASSERT(set_seq(LIGHTBAR_S3S0) == EC_RES_SUCCESS); usleep(10 * SECOND); TEST_ASSERT(get_seq() == LIGHTBAR_S0); /* S0S3 */ TEST_ASSERT(set_seq(LIGHTBAR_S0S3) == EC_RES_SUCCESS); usleep(10 * SECOND); TEST_ASSERT(get_seq() == LIGHTBAR_S3); /* S3S5 */ TEST_ASSERT(set_seq(LIGHTBAR_S3S5) == EC_RES_SUCCESS); usleep(10 * SECOND); TEST_ASSERT(get_seq() == LIGHTBAR_S5); return EC_SUCCESS; } static int test_stable_states(void) { int i; /* Wait for the lightbar task to initialize */ msleep(500); /* It should come up in S5 */ TEST_ASSERT(get_seq() == LIGHTBAR_S5); /* It should stay there */ for (i = 0; i < 30; i++) { usleep(SECOND); TEST_ASSERT(get_seq() == LIGHTBAR_S5); } /* S3 is sticky, too */ TEST_ASSERT(set_seq(LIGHTBAR_S3) == EC_RES_SUCCESS); for (i = 0; i < 30; i++) { usleep(SECOND); TEST_ASSERT(get_seq() == LIGHTBAR_S3); } /* And S0 */ TEST_ASSERT(set_seq(LIGHTBAR_S0) == EC_RES_SUCCESS); for (i = 0; i < 30; i++) { usleep(SECOND); TEST_ASSERT(get_seq() == LIGHTBAR_S0); } return EC_SUCCESS; } const struct lb_brightness_def lb_brightness_levels[] = { { /* regular brightness */ .lux_up = 60, .lux_down = 40, }, { /* 25 - 50% brightness */ .lux_up = 40, .lux_down = 20, }, { /* 0 .. 25% brightness */ .lux_up = 0, .lux_down = 0, }, }; const unsigned int lb_brightness_levels_count = ARRAY_SIZE(lb_brightness_levels); int lux_level_to_google_color(const int lux); extern int google_color_id; int lid_is_open(void) { return 1; } static int test_als_lightbar(void) { int lux_data[] = { 500, 100, 35, 15, 30, 35, 55, 70, 55, 100 }; int exp_gcid[] = { 0, 0, 1, 2, 2, 2, 1, 0, 0, 0 }; int exp_chg[] = { 0, 0, 1, 1, 0, 0, 1, 1, 0, 0 }; int i; BUILD_ASSERT(ARRAY_SIZE(lux_data) == ARRAY_SIZE(exp_gcid)); BUILD_ASSERT(ARRAY_SIZE(lux_data) == ARRAY_SIZE(exp_chg)); google_color_id = 0; for (i = 0; i < ARRAY_SIZE(lux_data); i++) { TEST_ASSERT(exp_chg[i] == lux_level_to_google_color(lux_data[i])); TEST_ASSERT(exp_gcid[i] == google_color_id); } return EC_SUCCESS; } void run_test(void) { RUN_TEST(test_stable_states); RUN_TEST(test_transition_states); RUN_TEST(test_oneshots_timeout); RUN_TEST(test_stop_timeout); RUN_TEST(test_oneshots_norm_msg); RUN_TEST(test_double_oneshots); RUN_TEST(test_als_lightbar); test_print_result(); }