| /* 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. |
| * |
| * Test non-keyboard buttons. |
| * |
| * Using GPIOS and buttons[] defined in board/host/board.c |
| * Volume down is active low with a debounce time of 30 mSec. |
| * Volume up is active high with a debounce time of 60 mSec. |
| * |
| */ |
| |
| #include "button.h" |
| #include "common.h" |
| #include "console.h" |
| #include "gpio.h" |
| #include "host_command.h" |
| #include "test_util.h" |
| #include "timer.h" |
| #include "keyboard_config.h" |
| #include "keyboard_protocol.h" |
| #include "util.h" |
| |
| #define UNCHANGED -1 |
| |
| uint8_t keyboard_cols = KEYBOARD_COLS_MAX; |
| |
| static const struct button_config *button_vol_down = |
| &buttons[BUTTON_VOLUME_DOWN]; |
| static const struct button_config *button_vol_up = &buttons[BUTTON_VOLUME_UP]; |
| |
| static int button_state[BUTTON_COUNT]; |
| |
| /* |
| * Callback from the button handling logic. |
| * This is normally implemented by a keyboard protocol handler. |
| */ |
| void keyboard_update_button(enum keyboard_button_type button, int is_pressed) |
| { |
| int i; |
| |
| for (i = 0; i < BUTTON_COUNT; i++) { |
| if (buttons[i].type == button) { |
| button_state[i] = is_pressed; |
| break; |
| } |
| } |
| } |
| |
| /* Test pressing a button */ |
| static int test_button_press(void) |
| { |
| gpio_set_level(button_vol_down->gpio, 0); |
| msleep(100); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == 1); |
| |
| return EC_SUCCESS; |
| } |
| |
| /* Test releasing a button */ |
| static int test_button_release(void) |
| { |
| gpio_set_level(button_vol_up->gpio, 0); |
| msleep(100); |
| gpio_set_level(button_vol_up->gpio, 1); |
| msleep(100); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_UP] == 0); |
| |
| return EC_SUCCESS; |
| } |
| |
| /* A press shorter than the debounce time should not trigger an update */ |
| static int test_button_debounce_short_press(void) |
| { |
| gpio_set_level(button_vol_down->gpio, 0); |
| msleep(10); |
| gpio_set_level(button_vol_down->gpio, 1); |
| msleep(100); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == UNCHANGED); |
| |
| return EC_SUCCESS; |
| } |
| |
| /* A short bounce while pressing should still result in a button press */ |
| static int test_button_debounce_short_bounce(void) |
| { |
| gpio_set_level(button_vol_down->gpio, 0); |
| msleep(10); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == UNCHANGED); |
| gpio_set_level(button_vol_down->gpio, 1); |
| msleep(10); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == UNCHANGED); |
| gpio_set_level(button_vol_down->gpio, 0); |
| msleep(20); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == UNCHANGED); |
| msleep(20); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == 1); |
| |
| return EC_SUCCESS; |
| } |
| |
| /* Button level must be stable for the entire debounce interval */ |
| static int test_button_debounce_stability(void) |
| { |
| gpio_set_level(button_vol_down->gpio, 0); |
| msleep(20); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == UNCHANGED); |
| gpio_set_level(button_vol_down->gpio, 1); |
| msleep(20); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == UNCHANGED); |
| gpio_set_level(button_vol_down->gpio, 0); |
| msleep(20); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == UNCHANGED); |
| msleep(20); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == 1); |
| msleep(60); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == 1); |
| gpio_set_level(button_vol_down->gpio, 1); |
| msleep(20); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == 1); |
| msleep(20); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == 0); |
| msleep(60); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == 0); |
| |
| return EC_SUCCESS; |
| } |
| |
| /* Test pressing both buttons at different times */ |
| static int test_button_press_both(void) |
| { |
| gpio_set_level(button_vol_down->gpio, 0); |
| msleep(10); |
| gpio_set_level(button_vol_up->gpio, 0); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == UNCHANGED); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_UP] == UNCHANGED); |
| msleep(30); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == 1); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_UP] == UNCHANGED); |
| msleep(40); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == 1); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_UP] == 1); |
| |
| return EC_SUCCESS; |
| } |
| |
| /* Button simulate test cases */ |
| static int send_button_hostcmd(uint32_t btn_mask, uint32_t press_ms) |
| { |
| struct ec_params_button p; |
| |
| p.press_ms = press_ms; |
| p.btn_mask = btn_mask; |
| |
| return test_send_host_command(EC_CMD_BUTTON, 0, &p, sizeof(p), NULL, 0); |
| } |
| |
| static void test_sim_button_util(uint32_t btn_mask, uint32_t press_ms) |
| { |
| send_button_hostcmd(btn_mask, press_ms); |
| msleep(100); |
| } |
| |
| /* Test simulate pressing a button */ |
| static int test_sim_button_press(void) |
| { |
| test_sim_button_util(1 << KEYBOARD_BUTTON_VOLUME_DOWN, 100); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == 1); |
| |
| return EC_SUCCESS; |
| } |
| |
| /* Test simulate releasing a button */ |
| static int test_sim_button_release(void) |
| { |
| test_sim_button_util(1 << KEYBOARD_BUTTON_VOLUME_UP, 50); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_UP] == 0); |
| |
| return EC_SUCCESS; |
| } |
| |
| /* A press shorter than the debounce time should not trigger an update */ |
| static int test_sim_button_debounce_short_press(void) |
| { |
| test_sim_button_util(1 << KEYBOARD_BUTTON_VOLUME_DOWN, 10); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == UNCHANGED); |
| |
| return EC_SUCCESS; |
| } |
| |
| /* A short bounce while pressing should still result in a button press */ |
| static int test_sim_button_debounce_short_bounce(void) |
| { |
| uint32_t btn_mask = 0; |
| |
| btn_mask |= (1 << KEYBOARD_BUTTON_VOLUME_DOWN); |
| send_button_hostcmd(btn_mask, 10); |
| msleep(50); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == UNCHANGED); |
| |
| send_button_hostcmd(btn_mask, 100); |
| msleep(20); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == UNCHANGED); |
| msleep(20); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == 1); |
| |
| return EC_SUCCESS; |
| } |
| |
| /* Button level must be stable for the entire debounce interval */ |
| static int test_sim_button_debounce_stability(void) |
| { |
| uint32_t btn_mask = 0; |
| |
| btn_mask |= (1 << KEYBOARD_BUTTON_VOLUME_DOWN); |
| send_button_hostcmd(btn_mask, 10); |
| msleep(20); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == UNCHANGED); |
| msleep(20); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == UNCHANGED); |
| |
| send_button_hostcmd(btn_mask, 100); |
| msleep(20); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == UNCHANGED); |
| msleep(20); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == 1); |
| msleep(60); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == 1); |
| |
| msleep(20); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == 1); |
| msleep(20); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == 0); |
| msleep(60); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == 0); |
| |
| return EC_SUCCESS; |
| } |
| |
| /* Test simulate pressing both buttons */ |
| static int test_sim_button_press_both(void) |
| { |
| uint32_t btn_mask = 0; |
| |
| btn_mask |= (1 << KEYBOARD_BUTTON_VOLUME_DOWN); |
| btn_mask |= (1 << KEYBOARD_BUTTON_VOLUME_UP); |
| send_button_hostcmd(btn_mask, 100); |
| msleep(10); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == UNCHANGED); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_UP] == UNCHANGED); |
| msleep(60); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == 1); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_UP] == 1); |
| msleep(100); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_DOWN] == 0); |
| TEST_ASSERT(button_state[BUTTON_VOLUME_UP] == 0); |
| |
| return EC_SUCCESS; |
| } |
| |
| static void button_test_init(void) |
| { |
| int i; |
| |
| ccprints("Setting button GPIOs to inactive state"); |
| for (i = 0; i < BUTTON_COUNT; i++) |
| gpio_set_level(buttons[i].gpio, |
| !(buttons[i].flags & BUTTON_FLAG_ACTIVE_HIGH)); |
| |
| msleep(100); |
| for (i = 0; i < BUTTON_COUNT; i++) |
| button_state[i] = UNCHANGED; |
| } |
| |
| void run_test(int argc, char **argv) |
| { |
| test_reset(); |
| |
| button_init(); |
| |
| button_test_init(); |
| RUN_TEST(test_button_press); |
| |
| button_test_init(); |
| RUN_TEST(test_button_release); |
| |
| button_test_init(); |
| RUN_TEST(test_button_debounce_short_press); |
| |
| button_test_init(); |
| RUN_TEST(test_button_debounce_short_bounce); |
| |
| button_test_init(); |
| RUN_TEST(test_button_debounce_stability); |
| |
| button_test_init(); |
| RUN_TEST(test_button_press_both); |
| |
| button_test_init(); |
| RUN_TEST(test_sim_button_press); |
| |
| button_test_init(); |
| RUN_TEST(test_sim_button_release); |
| |
| button_test_init(); |
| RUN_TEST(test_sim_button_debounce_short_press); |
| |
| button_test_init(); |
| RUN_TEST(test_sim_button_debounce_short_bounce); |
| |
| button_test_init(); |
| RUN_TEST(test_sim_button_debounce_stability); |
| |
| button_test_init(); |
| RUN_TEST(test_sim_button_press_both); |
| |
| test_print_result(); |
| } |