/* Copyright 2023 The ChromiumOS Authors * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * * Test clamshell/tablet when the sensors are broken. */ #include "accelgyro.h" #include "common.h" #include "console.h" #include "gpio.h" #include "hooks.h" #include "host_command.h" #include "motion_common.h" #include "motion_sense.h" #include "tablet_mode.h" #include "test_util.h" #include "timer.h" #include "util.h" /*****************************************************************************/ /* Mock functions */ static int accel_init(struct motion_sensor_t *s) { return EC_ERROR_UNKNOWN; } /* Only populate _init(), sensor stack should not touch the sensors on failure. */ const struct accelgyro_drv test_motion_sense = { .init = accel_init, }; struct motion_sensor_t motion_sensors[] = { [BASE] = { .name = "base", .active_mask = SENSOR_ACTIVE_S0_S3_S5, .chip = MOTIONSENSE_CHIP_LSM6DS0, .type = MOTIONSENSE_TYPE_ACCEL, .location = MOTIONSENSE_LOC_BASE, .drv = &test_motion_sense, .rot_standard_ref = NULL, .default_range = 2, }, [LID] = { .name = "lid", .active_mask = SENSOR_ACTIVE_S0_S3_S5, .chip = MOTIONSENSE_CHIP_KXCJ9, .type = MOTIONSENSE_TYPE_ACCEL, .location = MOTIONSENSE_LOC_LID, .drv = &test_motion_sense, .rot_standard_ref = NULL, .default_range = 2, }, }; const unsigned int motion_sensor_count = ARRAY_SIZE(motion_sensors); static int tablet_hook_count; static void tablet_mode_change_hook(void) { tablet_hook_count++; } DECLARE_HOOK(HOOK_TABLET_MODE_CHANGE, tablet_mode_change_hook, HOOK_PRIO_DEFAULT); void before_test(void) { /* Make sure the device lid is in a consistent state (close). */ gpio_set_level(GPIO_TABLET_MODE_L, 1); msleep(50); gpio_set_level(GPIO_LID_OPEN, 0); msleep(50); tablet_hook_count = 1; } /* * The device is in clamshell mode from before_test(), * Go through GPIO transitions and observe the table mode state. */ test_static int test_start_lid_close(void) { TEST_ASSERT(!tablet_get_mode()); /* Opening, No change. */ gpio_set_level(GPIO_LID_OPEN, 1); msleep(50); TEST_ASSERT(tablet_hook_count == 1); TEST_ASSERT(!tablet_get_mode()); /* full 360, tablet mode. */ gpio_set_level(GPIO_TABLET_MODE_L, 0); msleep(50); TEST_ASSERT(tablet_hook_count == 2); TEST_ASSERT(tablet_get_mode()); /* Going out of 360 mode, no change. */ gpio_set_level(GPIO_TABLET_MODE_L, 1); msleep(50); TEST_ASSERT(tablet_hook_count == 2); TEST_ASSERT(tablet_get_mode()); /* Back to close. */ gpio_set_level(GPIO_LID_OPEN, 0); msleep(50); TEST_ASSERT(tablet_hook_count == 3); TEST_ASSERT(!tablet_get_mode()); return EC_SUCCESS; } /* * Put the device in tablet mode first. * Reset the EC, keep the existing GPIO level. * Verify the state is not forgotten when the EC starts in tablet mode after * reset. */ test_static int test_start_tablet_mode(void) { /* Go in tablet mode */ gpio_set_level(GPIO_LID_OPEN, 1); gpio_set_level(GPIO_TABLET_MODE_L, 0); msleep(50); TEST_ASSERT(tablet_hook_count == 2); /* Shutdown device */ hook_notify(HOOK_CHIPSET_SHUTDOWN); msleep(50); TEST_ASSERT(sensor_active == SENSOR_ACTIVE_S5); TEST_ASSERT(tablet_hook_count == 2); TEST_ASSERT(tablet_get_mode()); return EC_SUCCESS; } /* * Put the device in tablet mode first. * Do a fast transition from 0 degree to 360 degree: * Observe the transition happens. * then 360 degree to 0 degree. * Observe the transition happens. */ test_static int test_fast_transition(void) { TEST_ASSERT(!tablet_get_mode()); /* Go in tablet mode fast.*/ gpio_set_level(GPIO_LID_OPEN, 1); gpio_set_level(GPIO_TABLET_MODE_L, 0); msleep(50); TEST_ASSERT(tablet_get_mode()); TEST_ASSERT(tablet_hook_count == 2); /* Go in clamshell mode fast.*/ gpio_set_level(GPIO_LID_OPEN, 0); gpio_set_level(GPIO_TABLET_MODE_L, 1); msleep(50); TEST_ASSERT(!tablet_get_mode()); TEST_ASSERT(tablet_hook_count == 3); return EC_SUCCESS; } void run_test(int argc, const char **argv) { test_reset(); RUN_TEST(test_start_lid_close); RUN_TEST(test_start_tablet_mode); RUN_TEST(test_fast_transition); test_print_result(); }