| /* Copyright (c) 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 "test_util.h" | |
| #include "timer.h" | |
| #include "keyboard_protocol.h" | |
| #define INDEX_VOL_DOWN 0 | |
| #define INDEX_VOL_UP 1 | |
| #define UNCHANGED -1 | |
| static const struct button_config *button_vol_down = &buttons[INDEX_VOL_DOWN]; | |
| static const struct button_config *button_vol_up = &buttons[INDEX_VOL_UP]; | |
| static int button_state[CONFIG_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 < CONFIG_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[INDEX_VOL_DOWN] == 1); | |
| return EC_SUCCESS; | |
| } | |
| /* Test releasing a button */ | |
| static int test_button_release(void) | |
| { | |
| gpio_set_level(button_vol_up->gpio, 1); | |
| msleep(100); | |
| gpio_set_level(button_vol_up->gpio, 0); | |
| msleep(100); | |
| TEST_ASSERT(button_state[INDEX_VOL_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[INDEX_VOL_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[INDEX_VOL_DOWN] == UNCHANGED); | |
| gpio_set_level(button_vol_down->gpio, 1); | |
| msleep(10); | |
| TEST_ASSERT(button_state[INDEX_VOL_DOWN] == UNCHANGED); | |
| gpio_set_level(button_vol_down->gpio, 0); | |
| msleep(20); | |
| TEST_ASSERT(button_state[INDEX_VOL_DOWN] == UNCHANGED); | |
| msleep(20); | |
| TEST_ASSERT(button_state[INDEX_VOL_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[INDEX_VOL_DOWN] == UNCHANGED); | |
| gpio_set_level(button_vol_down->gpio, 1); | |
| msleep(20); | |
| TEST_ASSERT(button_state[INDEX_VOL_DOWN] == UNCHANGED); | |
| gpio_set_level(button_vol_down->gpio, 0); | |
| msleep(20); | |
| TEST_ASSERT(button_state[INDEX_VOL_DOWN] == UNCHANGED); | |
| msleep(20); | |
| TEST_ASSERT(button_state[INDEX_VOL_DOWN] == 1); | |
| msleep(60); | |
| TEST_ASSERT(button_state[INDEX_VOL_DOWN] == 1); | |
| gpio_set_level(button_vol_down->gpio, 1); | |
| msleep(20); | |
| TEST_ASSERT(button_state[INDEX_VOL_DOWN] == 1); | |
| msleep(20); | |
| TEST_ASSERT(button_state[INDEX_VOL_DOWN] == 0); | |
| msleep(60); | |
| TEST_ASSERT(button_state[INDEX_VOL_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, 1); | |
| TEST_ASSERT(button_state[INDEX_VOL_DOWN] == UNCHANGED); | |
| TEST_ASSERT(button_state[INDEX_VOL_UP] == UNCHANGED); | |
| msleep(30); | |
| TEST_ASSERT(button_state[INDEX_VOL_DOWN] == 1); | |
| TEST_ASSERT(button_state[INDEX_VOL_UP] == UNCHANGED); | |
| msleep(40); | |
| TEST_ASSERT(button_state[INDEX_VOL_DOWN] == 1); | |
| TEST_ASSERT(button_state[INDEX_VOL_UP] == 1); | |
| return EC_SUCCESS; | |
| } | |
| static void button_init(void) | |
| { | |
| int i; | |
| ccprintf("[%T Setting button GPIOs to inactive state.]\n"); | |
| for (i = 0; i < CONFIG_BUTTON_COUNT; i++) | |
| gpio_set_level(buttons[i].gpio, | |
| !(buttons[i].flags & BUTTON_FLAG_ACTIVE_HIGH)); | |
| msleep(100); | |
| for (i = 0; i < CONFIG_BUTTON_COUNT; i++) | |
| button_state[i] = UNCHANGED; | |
| } | |
| void run_test(void) | |
| { | |
| test_reset(); | |
| button_init(); | |
| RUN_TEST(test_button_press); | |
| button_init(); | |
| RUN_TEST(test_button_release); | |
| button_init(); | |
| RUN_TEST(test_button_debounce_short_press); | |
| button_init(); | |
| RUN_TEST(test_button_debounce_short_bounce); | |
| button_init(); | |
| RUN_TEST(test_button_debounce_stability); | |
| button_init(); | |
| RUN_TEST(test_button_press_both); | |
| test_print_result(); | |
| } |