diff options
Diffstat (limited to 'zephyr/test/drivers/src/lis2dw12.c')
-rw-r--r-- | zephyr/test/drivers/src/lis2dw12.c | 363 |
1 files changed, 358 insertions, 5 deletions
diff --git a/zephyr/test/drivers/src/lis2dw12.c b/zephyr/test/drivers/src/lis2dw12.c index 287430e65b..24218aea9f 100644 --- a/zephyr/test/drivers/src/lis2dw12.c +++ b/zephyr/test/drivers/src/lis2dw12.c @@ -14,9 +14,34 @@ #define EMUL_LABEL DT_LABEL(DT_NODELABEL(lis2dw12_emul)) #include <stdio.h> + +#define CHECK_XYZ_EQUALS(VEC1, VEC2) \ + do { \ + zassert_equal((VEC1)[X], (VEC2)[X], \ + "Got %d for X, expected %d", (VEC1)[X], \ + (VEC2)[X]); \ + zassert_equal((VEC1)[Y], (VEC2)[Y], \ + "Got %d for Y, expected %d", (VEC1)[Y], \ + (VEC2)[Y]); \ + zassert_equal((VEC1)[Z], (VEC2)[Z], \ + "Got %d for Z, expected %d", (VEC1)[Z], \ + (VEC2)[Z]); \ + } while (0) + +/** Used with the LIS2DW12 set rate function to control rounding behavior */ +enum lis2dw12_round_mode { + ROUND_DOWN, + ROUND_UP, +}; + static void lis2dw12_setup(void) { lis2dw12_emul_reset(emul_get_binding(EMUL_LABEL)); + + /* Reset certain sensor struct values */ + struct motion_sensor_t *ms = &motion_sensors[LIS2DW12_SENSOR_ID]; + + ms->current_range = 0; } static void test_lis2dw12_init__fail_read_who_am_i(void) @@ -97,23 +122,351 @@ static void test_lis2dw12_init__fail_set_bdu(void) "expected at least one soft reset"); } +static void test_lis2dw12_init__fail_set_lir(void) +{ + const struct emul *emul = emul_get_binding(EMUL_LABEL); + struct motion_sensor_t *ms = &motion_sensors[LIS2DW12_SENSOR_ID]; + int rv; + + i2c_common_emul_set_read_fail_reg(lis2dw12_emul_to_i2c_emul(emul), + LIS2DW12_LIR_ADDR); + + rv = ms->drv->init(ms); + zassert_equal(EC_ERROR_INVAL, rv, "init returned %d but expected %d", + rv, EC_ERROR_INVAL); + zassert_true(lis2dw12_emul_get_soft_reset_count(emul) > 0, + "expected at least one soft reset"); +} + +static int lis2dw12_test_mock_write_fail_set_power_mode(struct i2c_emul *emul, + int reg, uint8_t val, + int bytes, void *data) +{ + if (reg == LIS2DW12_ACC_LPMODE_ADDR && bytes == 1 && + (val & LIS2DW12_ACC_LPMODE_MASK) != 0) { + /* Cause an error when trying to set the LPMODE */ + return -EIO; + } + return 1; +} + +static void test_lis2dw12_init__fail_set_power_mode(void) +{ + const struct emul *emul = emul_get_binding(EMUL_LABEL); + struct motion_sensor_t *ms = &motion_sensors[LIS2DW12_SENSOR_ID]; + int rv; + + i2c_common_emul_set_write_func( + lis2dw12_emul_to_i2c_emul(emul), + lis2dw12_test_mock_write_fail_set_power_mode, NULL); + + rv = ms->drv->init(ms); + zassert_equal(EC_ERROR_INVAL, rv, "init returned %d but expected %d", + rv, EC_ERROR_INVAL); + zassert_true(lis2dw12_emul_get_soft_reset_count(emul) > 0, + "expected at least one soft reset"); +} + +static void test_lis2dw12_init__success(void) +{ + const struct emul *emul = emul_get_binding(EMUL_LABEL); + struct motion_sensor_t *ms = &motion_sensors[LIS2DW12_SENSOR_ID]; + struct stprivate_data *drvdata = ms->drv_data; + + int rv; + + rv = ms->drv->init(ms); + zassert_equal(EC_SUCCESS, rv, "init returned %d but expected %d", rv, + EC_SUCCESS); + zassert_true(lis2dw12_emul_get_soft_reset_count(emul) > 0, + "expected at least one soft reset"); + zassert_equal(LIS2DW12_RESOLUTION, drvdata->resol, + "Expected resolution of %d but got %d", + LIS2DW12_RESOLUTION, drvdata->resol); +} + +static void test_lis2dw12_set_power_mode(void) +{ + const struct emul *emul = emul_get_binding(EMUL_LABEL); + struct motion_sensor_t *ms = &motion_sensors[LIS2DW12_SENSOR_ID]; + int rv; + + /* Part 1: happy path */ + rv = lis2dw12_set_power_mode(ms, LIS2DW12_LOW_POWER, + LIS2DW12_LOW_POWER_MODE_2); + zassert_equal(rv, EC_SUCCESS, "Expected %d but got %d", EC_SUCCESS, rv); + + /* Part 2: unimplemented modes */ + rv = lis2dw12_set_power_mode(ms, LIS2DW12_LOW_POWER, + LIS2DW12_LOW_POWER_MODE_1); + zassert_equal(rv, EC_ERROR_UNIMPLEMENTED, "Expected %d but got %d", + EC_ERROR_UNIMPLEMENTED, rv); + + /* Part 3: attempt to set mode but cannot modify reg. */ + i2c_common_emul_set_read_fail_reg(lis2dw12_emul_to_i2c_emul(emul), + LIS2DW12_ACC_MODE_ADDR); + rv = lis2dw12_set_power_mode(ms, LIS2DW12_LOW_POWER, + LIS2DW12_LOW_POWER_MODE_2); + zassert_equal(rv, EC_ERROR_INVAL, "Expected %d but got %d", + EC_ERROR_INVAL, rv); +} + +static void test_lis2dw12_set_range(void) +{ + const struct emul *emul = emul_get_binding(EMUL_LABEL); + struct motion_sensor_t *ms = &motion_sensors[LIS2DW12_SENSOR_ID]; + int rv; + + /* Part 1: Happy path. Go above the max range; it will be automatically + * clamped. + */ + + rv = ms->drv->set_range(ms, LIS2DW12_ACCEL_FS_MAX_VAL + 1, 0); + zassert_equal(rv, EC_SUCCESS, "Expected %d but got %d", EC_SUCCESS, rv); + zassert_equal(ms->current_range, LIS2DW12_ACCEL_FS_MAX_VAL, + "Expected %d but got %d", LIS2DW12_ACCEL_FS_MAX_VAL, + ms->current_range); + + /* Part 2: Error accessing register */ + i2c_common_emul_set_read_fail_reg(lis2dw12_emul_to_i2c_emul(emul), + LIS2DW12_FS_ADDR); + rv = ms->drv->set_range(ms, LIS2DW12_ACCEL_FS_MAX_VAL, 0); + zassert_equal(rv, EC_ERROR_INVAL, "Expected %d but got %d", + EC_ERROR_INVAL, rv); +} + +static void test_lis2dw12_set_rate(void) +{ + const struct emul *emul = emul_get_binding(EMUL_LABEL); + struct i2c_emul *i2c_emul = lis2dw12_emul_to_i2c_emul(emul); + struct motion_sensor_t *ms = &motion_sensors[LIS2DW12_SENSOR_ID]; + struct stprivate_data *drv_data = ms->drv_data; + int rv; + + /* Part 1: Turn off sensor with rate=0 */ + rv = ms->drv->set_data_rate(ms, 0, 0); + + zassert_equal(lis2dw12_emul_peek_odr(i2c_emul), + LIS2DW12_ODR_POWER_OFF_VAL, + "Output data rate should be %d but got %d", + LIS2DW12_ODR_POWER_OFF_VAL, + lis2dw12_emul_peek_odr(i2c_emul)); + zassert_equal(drv_data->base.odr, LIS2DW12_ODR_POWER_OFF_VAL, + "Output data rate should be %d but got %d", + LIS2DW12_ODR_POWER_OFF_VAL, drv_data->base.odr); + zassert_equal(rv, EC_SUCCESS, "Returned %d but expected %d", rv, + EC_SUCCESS); + + /* Part 2: Set some output data rates. We will request a certain rate + * and make sure the closest supported rate is used. + */ + + static const struct { + int requested_rate; /* millihertz */ + enum lis2dw12_round_mode round; + int expected_norm_rate; /* millihertz */ + uint8_t expected_reg_val; + } test_params[] = { + { 1000, ROUND_DOWN, LIS2DW12_ODR_MIN_VAL, + LIS2DW12_ODR_12HZ_VAL }, + { 12501, ROUND_DOWN, 12500, LIS2DW12_ODR_12HZ_VAL }, + { 25001, ROUND_DOWN, 25000, LIS2DW12_ODR_25HZ_VAL }, + { 50001, ROUND_DOWN, 50000, LIS2DW12_ODR_50HZ_VAL }, + { 100001, ROUND_DOWN, 100000, LIS2DW12_ODR_100HZ_VAL }, + { 200001, ROUND_DOWN, 200000, LIS2DW12_ODR_200HZ_VAL }, + { 400001, ROUND_DOWN, 400000, LIS2DW12_ODR_400HZ_VAL }, + { 800001, ROUND_DOWN, 800000, LIS2DW12_ODR_800HZ_VAL }, + { 1600001, ROUND_DOWN, 1600000, LIS2DW12_ODR_1_6kHZ_VAL }, + { 3200001, ROUND_DOWN, LIS2DW12_ODR_MAX_VAL, + LIS2DW12_ODR_1_6kHZ_VAL }, + + { 1000, ROUND_UP, LIS2DW12_ODR_MIN_VAL, LIS2DW12_ODR_12HZ_VAL }, + { 12501, ROUND_UP, 25000, LIS2DW12_ODR_25HZ_VAL }, + { 25001, ROUND_UP, 50000, LIS2DW12_ODR_50HZ_VAL }, + { 50001, ROUND_UP, 100000, LIS2DW12_ODR_100HZ_VAL }, + { 100001, ROUND_UP, 200000, LIS2DW12_ODR_200HZ_VAL }, + { 200001, ROUND_UP, 400000, LIS2DW12_ODR_400HZ_VAL }, + { 400001, ROUND_UP, 800000, LIS2DW12_ODR_800HZ_VAL }, + { 800001, ROUND_UP, 1600000, LIS2DW12_ODR_1_6kHZ_VAL }, + { 1600001, ROUND_UP, LIS2DW12_ODR_MAX_VAL, + LIS2DW12_ODR_1_6kHZ_VAL }, + }; + + for (size_t i = 0; i < ARRAY_SIZE(test_params); i++) { + /* For each test vector in the above array */ + drv_data->base.odr = -1; + rv = ms->drv->set_data_rate(ms, test_params[i].requested_rate, + test_params[i].round); + + /* Check the normalized rate the driver chose */ + zassert_equal( + drv_data->base.odr, test_params[i].expected_norm_rate, + "For requested rate %d, output data rate should be %d but got %d", + test_params[i].requested_rate, + test_params[i].expected_norm_rate, drv_data->base.odr); + + /* Read ODR and mode bits back from CTRL1 register */ + uint8_t odr_bits = lis2dw12_emul_peek_odr(i2c_emul); + + zassert_equal( + odr_bits, test_params[i].expected_reg_val, + "For requested rate %d, ODR bits should be 0x%x but got 0x%x - %d", + test_params[i].requested_rate, + test_params[i].expected_reg_val, odr_bits, + LIS2DW12_ODR_MAX_VAL); + + /* Check if high performance mode was enabled if rate > + * 200,000mHz + */ + + uint8_t mode_bits = lis2dw12_emul_peek_mode(i2c_emul); + uint8_t lpmode_bits = lis2dw12_emul_peek_lpmode(i2c_emul); + + if (odr_bits > LIS2DW12_ODR_200HZ_VAL) { + /* High performance mode, LP mode immaterial */ + zassert_equal(mode_bits, LIS2DW12_HIGH_PERF, + "MODE[1:0] should be 0x%x, but got 0x%x", + LIS2DW12_HIGH_PERF, mode_bits); + + } else { + /* Low power mode, LP mode 2 */ + zassert_equal(mode_bits, LIS2DW12_LOW_POWER, + "MODE[1:0] should be 0x%x, but got 0x%x", + LIS2DW12_LOW_POWER, mode_bits); + + zassert_equal( + lpmode_bits, LIS2DW12_LOW_POWER_MODE_2, + "LPMODE[1:0] should be 0x%x, but got 0x%x", + LIS2DW12_LOW_POWER_MODE_2, lpmode_bits); + } + } +} + +static void test_lis2dw12_read(void) +{ + const struct emul *emul = emul_get_binding(EMUL_LABEL); + struct i2c_emul *i2c_emul = lis2dw12_emul_to_i2c_emul(emul); + struct motion_sensor_t *ms = &motion_sensors[LIS2DW12_SENSOR_ID]; + struct stprivate_data *drvdata = ms->drv_data; + intv3_t sample = { 0, 0, 0 }; + int rv; + + /* Reading requires a range to be set. Use 1 so it has no effect + * when scaling samples. Also need to set the sensor resolution + * manually. + */ + + ms->drv->set_range(ms, 1, 0); + drvdata->resol = LIS2DW12_RESOLUTION; + + /* Part 1: Try to read from sensor, but cannot check status register for + * ready bit + */ + + i2c_common_emul_set_read_fail_reg(i2c_emul, LIS2DW12_STATUS_REG); + + rv = ms->drv->read(ms, sample); + + zassert_equal(rv, EC_ERROR_INVAL, + "Expected return val of %d but got %d", EC_ERROR_INVAL, + rv); + + /* Part 2: Try to read sensor, but no new data is available. In this + * case, the driver should return the reading in from `ms->raw_xyz` + */ + + i2c_common_emul_set_read_fail_reg(i2c_emul, + I2C_COMMON_EMUL_NO_FAIL_REG); + lis2dw12_emul_clear_accel_reading(emul); + ms->raw_xyz[X] = 123; + ms->raw_xyz[Y] = 456; + ms->raw_xyz[Z] = 789; + + rv = ms->drv->read(ms, sample); + + zassert_equal(rv, EC_SUCCESS, "Expected return val of %d but got %d", + EC_SUCCESS, rv); + CHECK_XYZ_EQUALS(sample, ms->raw_xyz); + + /* Part 3: Read from sensor w/ data ready, but an error occurs during + * read. + */ + intv3_t fake_sample = { 100, 200, 300 }; + + i2c_common_emul_set_read_fail_reg(i2c_emul, LIS2DW12_OUT_X_L_ADDR); + lis2dw12_emul_set_accel_reading(emul, fake_sample); + + rv = ms->drv->read(ms, sample); + + zassert_equal(rv, EC_ERROR_INVAL, + "Expected return val of %d but got %d", EC_ERROR_INVAL, + rv); + + /* Part 4: Success */ + + intv3_t expected_sample; + + for (int i = 0; i < ARRAY_SIZE(expected_sample); i++) { + /* The read routine will normalize `fake_sample` to use the full + * range of INT16, so we need to compensate in our expected + * output + */ + + expected_sample[i] = fake_sample[i] * + (1 << (16 - LIS2DW12_RESOLUTION)); + } + + i2c_common_emul_set_read_fail_reg(i2c_emul, + I2C_COMMON_EMUL_NO_FAIL_REG); + + lis2dw12_emul_set_accel_reading(emul, fake_sample); + + rv = ms->drv->read(ms, sample); + + zassert_equal(rv, EC_SUCCESS, "Expected return val of %d but got %d", + EC_SUCCESS, rv); + CHECK_XYZ_EQUALS(sample, expected_sample); +} + void test_suite_lis2dw12(void) { ztest_test_suite(lis2dw12, ztest_unit_test_setup_teardown( test_lis2dw12_init__fail_read_who_am_i, - lis2dw12_setup, unit_test_noop), + lis2dw12_setup, lis2dw12_setup), ztest_unit_test_setup_teardown( test_lis2dw12_init__fail_who_am_i, - lis2dw12_setup, unit_test_noop), + lis2dw12_setup, lis2dw12_setup), ztest_unit_test_setup_teardown( test_lis2dw12_init__fail_write_soft_reset, - lis2dw12_setup, unit_test_noop), + lis2dw12_setup, lis2dw12_setup), ztest_unit_test_setup_teardown( test_lis2dw12_init__timeout_read_soft_reset, - lis2dw12_setup, unit_test_noop), + lis2dw12_setup, lis2dw12_setup), ztest_unit_test_setup_teardown( test_lis2dw12_init__fail_set_bdu, - lis2dw12_setup, unit_test_noop)); + lis2dw12_setup, lis2dw12_setup), + ztest_unit_test_setup_teardown( + test_lis2dw12_init__fail_set_lir, + lis2dw12_setup, lis2dw12_setup), + ztest_unit_test_setup_teardown( + test_lis2dw12_init__fail_set_power_mode, + lis2dw12_setup, lis2dw12_setup), + ztest_unit_test_setup_teardown( + test_lis2dw12_init__success, + lis2dw12_setup, lis2dw12_setup), + ztest_unit_test_setup_teardown( + test_lis2dw12_set_power_mode, + lis2dw12_setup, lis2dw12_setup), + ztest_unit_test_setup_teardown( + test_lis2dw12_set_range, + lis2dw12_setup, lis2dw12_setup), + ztest_unit_test_setup_teardown( + test_lis2dw12_set_rate, + lis2dw12_setup, lis2dw12_setup), + ztest_unit_test_setup_teardown( + test_lis2dw12_read, + lis2dw12_setup, lis2dw12_setup) + ); ztest_run_test_suite(lis2dw12); } |