diff --git a/tests/boards/nrf/qdec/boards/bl54l15_dvk_nrf54l15_common.dtsi b/tests/boards/nrf/qdec/boards/bl54l15_dvk_nrf54l15_common.dtsi index 4db67a49a5e..19ca5e83647 100644 --- a/tests/boards/nrf/qdec/boards/bl54l15_dvk_nrf54l15_common.dtsi +++ b/tests/boards/nrf/qdec/boards/bl54l15_dvk_nrf54l15_common.dtsi @@ -5,12 +5,6 @@ */ / { - aliases { - qdec0 = &qdec20; - qenca = &phase_a; - qencb = &phase_b; - }; - encoder-emulate { compatible = "gpio-leds"; @@ -22,6 +16,14 @@ gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>; }; }; + + qdec_loopbacks: loopbacks { + compatible = "test-qdec-loopbacks"; + loopback0 { + qdec = <&qdec20>; + qenc-emul-gpios = <&phase_a &phase_b>; + }; + }; }; &pinctrl { diff --git a/tests/boards/nrf/qdec/boards/bl54l15u_dvk_nrf54l15_common.dtsi b/tests/boards/nrf/qdec/boards/bl54l15u_dvk_nrf54l15_common.dtsi index 4db67a49a5e..19ca5e83647 100644 --- a/tests/boards/nrf/qdec/boards/bl54l15u_dvk_nrf54l15_common.dtsi +++ b/tests/boards/nrf/qdec/boards/bl54l15u_dvk_nrf54l15_common.dtsi @@ -5,12 +5,6 @@ */ / { - aliases { - qdec0 = &qdec20; - qenca = &phase_a; - qencb = &phase_b; - }; - encoder-emulate { compatible = "gpio-leds"; @@ -22,6 +16,14 @@ gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>; }; }; + + qdec_loopbacks: loopbacks { + compatible = "test-qdec-loopbacks"; + loopback0 { + qdec = <&qdec20>; + qenc-emul-gpios = <&phase_a &phase_b>; + }; + }; }; &pinctrl { diff --git a/tests/boards/nrf/qdec/boards/nrf52840dk_nrf52840.overlay b/tests/boards/nrf/qdec/boards/nrf52840dk_nrf52840.overlay index f227fb95c38..a495df07f7c 100644 --- a/tests/boards/nrf/qdec/boards/nrf52840dk_nrf52840.overlay +++ b/tests/boards/nrf/qdec/boards/nrf52840dk_nrf52840.overlay @@ -22,6 +22,13 @@ }; }; + qdec_loopbacks: loopbacks { + compatible = "test-qdec-loopbacks"; + loopback0 { + qdec = <&qdec0>; + qenc-emul-gpios = <&phase_a &phase_b>; + }; + }; }; &pinctrl { diff --git a/tests/boards/nrf/qdec/boards/nrf5340dk_nrf5340_cpuapp.overlay b/tests/boards/nrf/qdec/boards/nrf5340dk_nrf5340_cpuapp.overlay index ed6a5587f5b..d1f008c8193 100644 --- a/tests/boards/nrf/qdec/boards/nrf5340dk_nrf5340_cpuapp.overlay +++ b/tests/boards/nrf/qdec/boards/nrf5340dk_nrf5340_cpuapp.overlay @@ -4,12 +4,6 @@ */ / { - aliases { - qdec0 = &qdec1; - qenca = &phase_a; - qencb = &phase_b; - }; - encoder-emulate { compatible = "gpio-leds"; phase_a: phase_a { @@ -21,6 +15,14 @@ gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>; }; }; + + qdec_loopbacks: loopbacks { + compatible = "test-qdec-loopbacks"; + loopback0 { + qdec = <&qdec1>; + qenc-emul-gpios = <&phase_a &phase_b>; + }; + }; }; &pinctrl { diff --git a/tests/boards/nrf/qdec/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/tests/boards/nrf/qdec/boards/nrf54h20dk_nrf54h20_cpuapp.overlay index 7e6da5a3458..7e43c70dac0 100644 --- a/tests/boards/nrf/qdec/boards/nrf54h20dk_nrf54h20_cpuapp.overlay +++ b/tests/boards/nrf/qdec/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -3,49 +3,101 @@ * SPDX-License-Identifier: Apache-2.0 */ -/ { - aliases { - qdec0 = &qdec130; - qenca = &phase_a; - qencb = &phase_b; - }; +/* Required loopbacks + * P2.08 <-> P2.09 + * P2.10 <-> P2.11 + * P1.02 <-> P1.03 + * P7.01 <-> P1.05 + */ +/ { encoder-emulate { compatible = "gpio-leds"; - phase_a: phase_a { + phase_a0: phase_a0 { gpios = <&gpio2 9 GPIO_ACTIVE_HIGH>; }; - phase_b: phase_b { + phase_b0: phase_b0 { gpios = <&gpio2 11 GPIO_ACTIVE_HIGH>; }; + phase_a1: phase_a1 { + gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>; + }; + phase_b1: phase_b1 { + gpios = <&gpio7 1 GPIO_ACTIVE_HIGH>; + }; + }; + + qdec_loopbacks: loopbacks { + compatible = "test-qdec-loopbacks"; + loopback0 { + qdec = <&qdec130>; + qenc-emul-gpios = <&phase_a0 &phase_b0>; + }; + loopback1 { + qdec = <&qdec131>; + qenc-emul-gpios = <&phase_a1 &phase_b1>; + }; }; }; &pinctrl { - qdec_pinctrl: qdec_pinctrl { + qdec_130_pinctrl: qdec_130_pinctrl { group1 { psels = , ; }; }; - qdec_sleep_pinctrl: qdec_sleep_pinctrl { + qdec_130_sleep_pinctrl: qdec_130_sleep_pinctrl { group1 { psels = , ; low-power-enable; }; }; + + qdec_131_pinctrl: qdec_131_pinctrl { + group1 { + psels = , + ; + }; + }; + + qdec_131_sleep_pinctrl: qdec_131_sleep_pinctrl { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; + +&gpio1 { + status = "okay"; }; &gpio2 { status = "okay"; }; +&gpio7 { + status = "okay"; +}; + &qdec130 { status = "okay"; - pinctrl-0 = <&qdec_pinctrl>; - pinctrl-1 = <&qdec_sleep_pinctrl>; + pinctrl-0 = <&qdec_130_pinctrl>; + pinctrl-1 = <&qdec_130_sleep_pinctrl>; + pinctrl-names = "default", "sleep"; + steps = <127>; + led-pre = <500>; + zephyr,pm-device-runtime-auto; +}; + +&qdec131 { + status = "okay"; + pinctrl-0 = <&qdec_131_pinctrl>; + pinctrl-1 = <&qdec_131_sleep_pinctrl>; pinctrl-names = "default", "sleep"; steps = <127>; led-pre = <500>; diff --git a/tests/boards/nrf/qdec/boards/nrf54l15dk_nrf54l15_common.dtsi b/tests/boards/nrf/qdec/boards/nrf54l15dk_nrf54l15_common.dtsi index 3fa426569b8..f2729414652 100644 --- a/tests/boards/nrf/qdec/boards/nrf54l15dk_nrf54l15_common.dtsi +++ b/tests/boards/nrf/qdec/boards/nrf54l15dk_nrf54l15_common.dtsi @@ -3,49 +3,97 @@ * SPDX-License-Identifier: Apache-2.0 */ -/ { - aliases { - qdec0 = &qdec20; - qenca = &phase_a; - qencb = &phase_b; - }; +/* Required loopbacks + * P1.8 <-> P1.9 + * P1.10 <-> P1.11 + * P1.12 <-> P1.13 + * P1.14 <-> P2.10 + */ +/ { encoder-emulate { compatible = "gpio-leds"; - phase_a: phase_a { + phase_a0: phase_a0 { gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>; }; - phase_b: phase_b { + phase_b0: phase_b0 { gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>; }; + phase_a1: phase_a1 { + gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>; + }; + phase_b1: phase_b1 { + gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>; + }; + }; + + qdec_loopbacks: loopbacks { + compatible = "test-qdec-loopbacks"; + loopback0 { + qdec = <&qdec20>; + qenc-emul-gpios = <&phase_a0 &phase_b0>; + }; + loopback1 { + qdec = <&qdec21>; + qenc-emul-gpios = <&phase_a1 &phase_b1>; + }; }; }; &pinctrl { - qdec_pinctrl: qdec_pinctrl { + qdec_20_pinctrl: qdec_20_pinctrl { group1 { psels = , ; }; }; - qdec_sleep_pinctrl: qdec_sleep_pinctrl { + qdec_20_sleep_pinctrl: qdec_20_sleep_pinctrl { group1 { psels = , ; low-power-enable; }; }; + + qdec_21_pinctrl: qdec_21_pinctrl { + group1 { + psels = , + ; + }; + }; + + qdec_21_sleep_pinctrl: qdec_21_sleep_pinctrl { + group1 { + psels = , + ; + low-power-enable; + }; + }; }; &gpio1 { status = "okay"; }; +&gpio2 { + status = "okay"; +}; + &qdec20 { status = "okay"; - pinctrl-0 = <&qdec_pinctrl>; - pinctrl-1 = <&qdec_sleep_pinctrl>; + pinctrl-0 = <&qdec_20_pinctrl>; + pinctrl-1 = <&qdec_20_sleep_pinctrl>; + pinctrl-names = "default", "sleep"; + steps = <127>; + led-pre = <500>; + zephyr,pm-device-runtime-auto; +}; + +&qdec21 { + status = "okay"; + pinctrl-0 = <&qdec_21_pinctrl>; + pinctrl-1 = <&qdec_21_sleep_pinctrl>; pinctrl-names = "default", "sleep"; steps = <127>; led-pre = <500>; diff --git a/tests/boards/nrf/qdec/boards/nrf54lm20dk_nrf54lm20_common.dtsi b/tests/boards/nrf/qdec/boards/nrf54lm20dk_nrf54lm20_common.dtsi index 84e7b1dbc30..6f8f3a18431 100644 --- a/tests/boards/nrf/qdec/boards/nrf54lm20dk_nrf54lm20_common.dtsi +++ b/tests/boards/nrf/qdec/boards/nrf54lm20dk_nrf54lm20_common.dtsi @@ -11,12 +11,6 @@ */ / { - aliases { - qdec0 = &qdec20; - qenca = &phase_a; - qencb = &phase_b; - }; - encoder-emulate { compatible = "gpio-leds"; phase_a: phase_a { @@ -26,6 +20,14 @@ gpios = <&gpio1 23 GPIO_ACTIVE_HIGH>; }; }; + + qdec_loopbacks: loopbacks { + compatible = "test-qdec-loopbacks"; + loopback0 { + qdec = <&qdec20>; + qenc-emul-gpios = <&phase_a &phase_b>; + }; + }; }; &pinctrl { diff --git a/tests/boards/nrf/qdec/dts/bindings/test-qdec-loopback.yaml b/tests/boards/nrf/qdec/dts/bindings/test-qdec-loopback.yaml new file mode 100644 index 00000000000..e03b2ff3bc3 --- /dev/null +++ b/tests/boards/nrf/qdec/dts/bindings/test-qdec-loopback.yaml @@ -0,0 +1,20 @@ +description: | + Binding describing loopbacks required to run tests/boards/nrf/qdec test in Zephyr. + +compatible: "test-qdec-loopbacks" + +child-binding: + description: | + Binding describing a single loopback pair consisting of a QDEC device and two "gpio-leds" pins + working as a quadrature encoder for the test. + properties: + qdec: + type: phandle + required: true + description: Node of the QDEC device used to capture quadrature signal in the loopback. + qenc-emul-gpios: + type: phandles + required: true + description: | + Children nodes of "gpio-leds" compatible used to generate quadrature signal. The first + phandles outputs phase A signal, the second one outputs phase B signal. diff --git a/tests/boards/nrf/qdec/src/main.c b/tests/boards/nrf/qdec/src/main.c index d87feb22f42..9d138d325fb 100644 --- a/tests/boards/nrf/qdec/src/main.c +++ b/tests/boards/nrf/qdec/src/main.c @@ -11,20 +11,45 @@ #include #include +/** + * Structure grouping gpio pins used for QENC emulation connected with a QDEC device + * with a loopback. + */ +struct qdec_qenc_loopback { + struct gpio_dt_spec qenc_phase_a; + struct gpio_dt_spec qenc_phase_b; + + const struct device *qdec; + uint32_t qdec_config_step; +}; + static K_SEM_DEFINE(sem, 0, 1); -static const struct gpio_dt_spec phase_a = GPIO_DT_SPEC_GET(DT_ALIAS(qenca), gpios); -static const struct gpio_dt_spec phase_b = GPIO_DT_SPEC_GET(DT_ALIAS(qencb), gpios); -static const struct device *const qdec_dev = DEVICE_DT_GET(DT_ALIAS(qdec0)); -static const uint32_t qdec_config_step = DT_PROP(DT_ALIAS(qdec0), steps); + +#define GET_QDEC_QENC_LOOPBACK(x) \ + { \ + .qenc_phase_a = GPIO_DT_SPEC_GET(DT_PHANDLE_BY_IDX(x, qenc_emul_gpios, 0), gpios), \ + .qenc_phase_b = GPIO_DT_SPEC_GET(DT_PHANDLE_BY_IDX(x, qenc_emul_gpios, 1), gpios), \ + .qdec = DEVICE_DT_GET(DT_PHANDLE(x, qdec)), \ + .qdec_config_step = DT_PROP_BY_PHANDLE(x, qdec, steps) \ + } + + +struct qdec_qenc_loopback loopbacks[] = { + DT_FOREACH_CHILD_SEP(DT_NODELABEL(qdec_loopbacks), GET_QDEC_QENC_LOOPBACK, (,)) +}; + +#define TESTED_QDEC_COUNT ARRAY_SIZE(loopbacks) + static struct sensor_trigger qdec_trigger = {.type = SENSOR_TRIG_DATA_READY, .chan = SENSOR_CHAN_ROTATION}; + static bool toggle_a = true; +static struct qdec_qenc_loopback *loopback_currently_under_test; static void qdec_trigger_handler(const struct device *dev, const struct sensor_trigger *trigger) { zassert_not_null(dev); zassert_not_null(trigger); - zassert_equal_ptr(dev, qdec_dev); /* trigger should be stored as a pointer in a driver * thus this address should match */ @@ -36,9 +61,9 @@ static void qdec_trigger_handler(const struct device *dev, const struct sensor_t static void qenc_emulate_work_handler(struct k_work *work) { if (toggle_a) { - gpio_pin_toggle_dt(&phase_a); + gpio_pin_toggle_dt(&loopback_currently_under_test->qenc_phase_a); } else { - gpio_pin_toggle_dt(&phase_b); + gpio_pin_toggle_dt(&loopback_currently_under_test->qenc_phase_b); } toggle_a = !toggle_a; } @@ -71,43 +96,46 @@ static void qenc_emulate_setup_pin(const struct gpio_dt_spec *gpio_dt) zassert_true(rc == 0, "%s: pin configure failed: %d", gpio_dt->port->name, rc); } -static void qenc_emulate_start(k_timeout_t period, bool forward) +static void qenc_emulate_start(struct qdec_qenc_loopback *loopback, k_timeout_t period, + bool forward) { - qenc_emulate_reset_pin(&phase_a); - qenc_emulate_reset_pin(&phase_b); + qenc_emulate_reset_pin(&loopback->qenc_phase_a); + qenc_emulate_reset_pin(&loopback->qenc_phase_b); toggle_a = !forward; - + loopback_currently_under_test = loopback; k_timer_start(&qenc_emulate_timer, period, period); } static void qenc_emulate_stop(void) { - k_timer_stop(&qenc_emulate_timer); - - qenc_emulate_reset_pin(&phase_a); - qenc_emulate_reset_pin(&phase_b); + if (loopback_currently_under_test) { + k_timer_stop(&qenc_emulate_timer); + qenc_emulate_reset_pin(&loopback_currently_under_test->qenc_phase_a); + qenc_emulate_reset_pin(&loopback_currently_under_test->qenc_phase_b); + } } -static void qenc_emulate_verify_reading(int emulator_period_ms, int emulation_duration_ms, - bool forward, bool overflow_expected) +static void qenc_emulate_verify_reading(struct qdec_qenc_loopback *loopback, + int emulator_period_ms, int emulation_duration_ms, bool forward, + bool overflow_expected) { int rc; struct sensor_value val = {0}; int32_t expected_steps = emulation_duration_ms / emulator_period_ms; - int32_t expected_reading = 360 * expected_steps / qdec_config_step; - int32_t delta = expected_reading / 5; + int32_t expected_reading = 360 * expected_steps / loopback->qdec_config_step; + int32_t delta = expected_reading / 4; if (!forward) { expected_reading *= -1; } - qenc_emulate_start(K_MSEC(emulator_period_ms), forward); + qenc_emulate_start(loopback, K_MSEC(emulator_period_ms), forward); - /* wait for some readings*/ + /* wait for some readings */ k_msleep(emulation_duration_ms); - rc = sensor_sample_fetch(qdec_dev); + rc = sensor_sample_fetch(loopback->qdec); if (!overflow_expected) { zassert_true(rc == 0, "Failed to fetch sample (%d)", rc); @@ -115,9 +143,11 @@ static void qenc_emulate_verify_reading(int emulator_period_ms, int emulation_du zassert_true(rc == -EOVERFLOW, "Failed to detect overflow"); } - rc = sensor_channel_get(qdec_dev, SENSOR_CHAN_ROTATION, &val); + rc = sensor_channel_get(loopback->qdec, SENSOR_CHAN_ROTATION, &val); zassert_true(rc == 0, "Failed to get sample (%d)", rc); + TC_PRINT("Expected reading: %d, actual value: %d, delta: %d\n", + expected_reading, val.val1, delta); if (!overflow_expected) { zassert_within(val.val1, expected_reading, delta, "Expected reading: %d, but got: %d", expected_reading, val.val1); @@ -128,35 +158,31 @@ static void qenc_emulate_verify_reading(int emulator_period_ms, int emulation_du /* wait and get readings to clear state */ k_msleep(100); - rc = sensor_sample_fetch(qdec_dev); + rc = sensor_sample_fetch(loopback->qdec); zassert_true(rc == 0, "Failed to fetch sample (%d)", rc); - rc = sensor_channel_get(qdec_dev, SENSOR_CHAN_ROTATION, &val); + rc = sensor_channel_get(loopback->qdec, SENSOR_CHAN_ROTATION, &val); zassert_true(rc == 0, "Failed to get sample (%d)", rc); } -/** - * @brief sensor_trigger_set test disable trigger - * - * Confirm trigger happens after set and stops after being disabled - * - */ -ZTEST(qdec_sensor, test_sensor_trigger_set_and_disable) +static void sensor_trigger_set_and_disable(struct qdec_qenc_loopback *loopback) { int rc; if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { - pm_device_runtime_get(qdec_dev); + pm_device_runtime_get(loopback->qdec); } + k_sem_give(&sem); + qdec_trigger.type = SENSOR_TRIG_DATA_READY; qdec_trigger.chan = SENSOR_CHAN_ALL; - rc = sensor_trigger_set(qdec_dev, &qdec_trigger, qdec_trigger_handler); + rc = sensor_trigger_set(loopback->qdec, &qdec_trigger, qdec_trigger_handler); zassume_true(rc != -ENOSYS, "sensor_trigger_set not supported"); zassert_true(rc == 0, "sensor_trigger_set failed: %d", rc); - qenc_emulate_start(K_MSEC(10), true); + qenc_emulate_start(loopback, K_MSEC(10), true); /* emulation working, handler should be called */ rc = k_sem_take(&sem, K_MSEC(200)); @@ -168,7 +194,7 @@ ZTEST(qdec_sensor, test_sensor_trigger_set_and_disable) rc = k_sem_take(&sem, K_MSEC(200)); if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { - pm_device_runtime_put(qdec_dev); + pm_device_runtime_put(loopback->qdec); } /* there should be no triggers now*/ @@ -176,199 +202,238 @@ ZTEST(qdec_sensor, test_sensor_trigger_set_and_disable) zassert_true(rc == -EAGAIN, "qdec handler should not be triggered (%d)", rc); if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { - pm_device_runtime_get(qdec_dev); + pm_device_runtime_get(loopback->qdec); } /* register empty trigger - disable trigger */ - rc = sensor_trigger_set(qdec_dev, &qdec_trigger, NULL); + rc = sensor_trigger_set(loopback->qdec, &qdec_trigger, NULL); zassert_true(rc == 0, "sensor_trigger_set failed: %d", rc); - qenc_emulate_start(K_MSEC(10), true); + qenc_emulate_start(loopback, K_MSEC(10), true); /* emulation working, but handler not set, thus should not be called */ rc = k_sem_take(&sem, K_MSEC(200)); zassert_true(rc == -EAGAIN, "qdec handler should not be triggered (%d)", rc); if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { - pm_device_runtime_put(qdec_dev); + pm_device_runtime_put(loopback->qdec); } } /** - * @brief sensor_trigger_set test + * @brief sensor_trigger_set test disable trigger * - * Confirm trigger happens after set + * Confirm trigger happens after set and stops after being disabled * */ -ZTEST(qdec_sensor, test_sensor_trigger_set) +ZTEST(qdec_sensor, test_sensor_trigger_set_and_disable) +{ + for (size_t i = 0; i < TESTED_QDEC_COUNT; i++) { + TC_PRINT("Testing QDEC index %d, address: %p\n", i, loopbacks[i].qdec); + sensor_trigger_set_and_disable(&loopbacks[i]); + } +} + +static void sensor_trigger_set_test(struct qdec_qenc_loopback *loopback) { int rc; struct sensor_value val = {0}; if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { - pm_device_runtime_get(qdec_dev); + pm_device_runtime_get(loopback->qdec); } qdec_trigger.type = SENSOR_TRIG_DATA_READY; qdec_trigger.chan = SENSOR_CHAN_ROTATION; - rc = sensor_trigger_set(qdec_dev, &qdec_trigger, qdec_trigger_handler); + rc = sensor_trigger_set(loopback->qdec, &qdec_trigger, qdec_trigger_handler); zassume_true(rc != -ENOSYS, "sensor_trigger_set not supported"); zassert_true(rc == 0, "sensor_trigger_set failed: %d", rc); - qenc_emulate_start(K_MSEC(10), true); + qenc_emulate_start(loopback, K_MSEC(10), true); /* emulation working now */ rc = k_sem_take(&sem, K_MSEC(200)); zassert_true(rc == 0, "qdec handler should be triggered (%d)", rc); - rc = sensor_sample_fetch(qdec_dev); + rc = sensor_sample_fetch(loopback->qdec); zassert_true(rc == 0, "Failed to fetch sample (%d)", rc); - rc = sensor_channel_get(qdec_dev, SENSOR_CHAN_ROTATION, &val); + rc = sensor_channel_get(loopback->qdec, SENSOR_CHAN_ROTATION, &val); zassert_true(rc == 0, "Failed to fetch sample (%d)", rc); TC_PRINT("QDEC reading: %d\n", val.val1); zassert_true(val.val1 != 0, "No readings from QDEC"); if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { - pm_device_runtime_put(qdec_dev); + pm_device_runtime_put(loopback->qdec); } + + qenc_emulate_stop(); + /* emulation not working, but there may be old trigger which needs to be cleaned up */ + rc = k_sem_take(&sem, K_MSEC(200)); } /** - * @brief sensor_trigger_set test negative + * @brief sensor_trigger_set test * - * Confirm setting trigger with invalid data does not work + * Confirm trigger happens after set * */ -ZTEST(qdec_sensor, test_sensor_trigger_set_negative) +ZTEST(qdec_sensor, test_sensor_trigger_set) +{ + for (size_t i = 0; i < TESTED_QDEC_COUNT; i++) { + TC_PRINT("Testing QDEC index %d, address: %p\n", i, loopbacks[i].qdec); + sensor_trigger_set_test(&loopbacks[i]); + } +} + +static void sensor_trigger_set_negative(struct qdec_qenc_loopback *loopback) { int rc; if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { - pm_device_runtime_get(qdec_dev); + pm_device_runtime_get(loopback->qdec); } - rc = sensor_trigger_set(qdec_dev, &qdec_trigger, qdec_trigger_handler); + rc = sensor_trigger_set(loopback->qdec, &qdec_trigger, qdec_trigger_handler); zassume_true(rc != -ENOSYS, "sensor_trigger_set not supported"); qdec_trigger.type = SENSOR_TRIG_MAX; qdec_trigger.chan = SENSOR_CHAN_ROTATION; - rc = sensor_trigger_set(qdec_dev, &qdec_trigger, qdec_trigger_handler); + rc = sensor_trigger_set(loopback->qdec, &qdec_trigger, qdec_trigger_handler); zassume_true(rc < 0, "sensor_trigger_set should fail due to invalid trigger type"); qdec_trigger.type = SENSOR_TRIG_DATA_READY; qdec_trigger.chan = SENSOR_CHAN_MAX; - rc = sensor_trigger_set(qdec_dev, &qdec_trigger, qdec_trigger_handler); + rc = sensor_trigger_set(loopback->qdec, &qdec_trigger, qdec_trigger_handler); zassume_true(rc < 0, "sensor_trigger_set should fail due to invalid channel"); if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { - pm_device_runtime_put(qdec_dev); + pm_device_runtime_put(loopback->qdec); } } /** - * @brief QDEC readings tests + * @brief sensor_trigger_set test negative * - * Valid reading from QDEC base on simulated signal + * Confirm setting trigger with invalid data does not work * */ -ZTEST(qdec_sensor, test_qdec_readings) +ZTEST(qdec_sensor, test_sensor_trigger_set_negative) { - if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { - pm_device_runtime_get(qdec_dev); - } - - qenc_emulate_verify_reading(10, 100, true, false); - qenc_emulate_verify_reading(2, 500, true, false); - qenc_emulate_verify_reading(10, 200, false, false); - qenc_emulate_verify_reading(1, 1000, false, true); - qenc_emulate_verify_reading(1, 1000, true, true); - - if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { - pm_device_runtime_put(qdec_dev); + for (size_t i = 0; i < TESTED_QDEC_COUNT; i++) { + TC_PRINT("Testing QDEC index %d, address: %p\n", i, loopbacks[i].qdec); + sensor_trigger_set_negative(&loopbacks[i]); } } /** - * @brief sensor_channel_get test with no emulation + * @brief QDEC readings tests * - * Confirm getting empty reading from QDEC + * Valid reading from QDEC base on simulated signal * */ -ZTEST(qdec_sensor, test_sensor_channel_get_empty) +ZTEST(qdec_sensor, test_qdec_readings) +{ + for (size_t i = 0; i < TESTED_QDEC_COUNT; i++) { + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + pm_device_runtime_get(loopbacks[i].qdec); + } + + TC_PRINT("Testing QDEC index %d, address: %p\n", i, loopbacks[i].qdec); + qenc_emulate_verify_reading(&loopbacks[i], 10, 100, true, false); + qenc_emulate_verify_reading(&loopbacks[i], 2, 500, true, false); + qenc_emulate_verify_reading(&loopbacks[i], 10, 200, false, false); + qenc_emulate_verify_reading(&loopbacks[i], 1, 1000, false, true); + qenc_emulate_verify_reading(&loopbacks[i], 1, 1000, true, true); + + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + pm_device_runtime_put(loopbacks[i].qdec); + } + } +} + +static void sensor_channel_get_empty(const struct device *const dev) { int rc; struct sensor_value val = {0}; if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { - pm_device_runtime_get(qdec_dev); + pm_device_runtime_get(dev); } /* wait for potential new readings */ k_msleep(100); - rc = sensor_sample_fetch(qdec_dev); + rc = sensor_sample_fetch(dev); zassert_true(rc == 0, "Failed to fetch sample (%d)", rc); /* get readings but ignore them, as they may include reading from time * when emulation was still working (i.e. during previous test) */ - rc = sensor_channel_get(qdec_dev, SENSOR_CHAN_ROTATION, &val); + rc = sensor_channel_get(dev, SENSOR_CHAN_ROTATION, &val); zassert_true(rc == 0, "Failed to get sample (%d)", rc); /* wait for potential new readings */ k_msleep(100); - rc = sensor_sample_fetch(qdec_dev); + rc = sensor_sample_fetch(dev); zassert_true(rc == 0, "Failed to fetch sample (%d)", rc); /* emulation was not working, expect no readings */ - rc = sensor_channel_get(qdec_dev, SENSOR_CHAN_ROTATION, &val); + rc = sensor_channel_get(dev, SENSOR_CHAN_ROTATION, &val); zassert_true(rc == 0, "Failed to get sample (%d)", rc); zassert_true(val.val1 == 0, "Expected no readings but got: %d", val.val1); zassert_true(val.val2 == 0, "Expected no readings but got: %d", val.val2); if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { - pm_device_runtime_put(qdec_dev); + pm_device_runtime_put(dev); } } /** - * @brief sensor_channel_get test with emulation + * @brief sensor_channel_get test with no emulation * - * Confirm getting readings from QDEC + * Confirm getting empty reading from QDEC * */ -ZTEST(qdec_sensor, test_sensor_channel_get) +ZTEST(qdec_sensor, test_sensor_channel_get_empty) +{ + for (size_t i = 0; i < TESTED_QDEC_COUNT; i++) { + TC_PRINT("Testing QDEC index %d, address: %p\n", i, loopbacks[i].qdec); + sensor_channel_get_empty(loopbacks[i].qdec); + } +} + +static void sensor_channel_get_test(struct qdec_qenc_loopback *loopback) { int rc; struct sensor_value val_first = {0}; struct sensor_value val_second = {0}; if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { - pm_device_runtime_get(qdec_dev); + pm_device_runtime_get(loopback->qdec); } - qenc_emulate_start(K_MSEC(10), true); + qenc_emulate_start(loopback, K_MSEC(10), true); /* wait for some readings*/ k_msleep(100); - rc = sensor_sample_fetch(qdec_dev); + rc = sensor_sample_fetch(loopback->qdec); zassert_true(rc == 0, "Failed to fetch sample (%d)", rc); - rc = sensor_channel_get(qdec_dev, SENSOR_CHAN_ROTATION, &val_first); + rc = sensor_channel_get(loopback->qdec, SENSOR_CHAN_ROTATION, &val_first); zassert_true(rc == 0, "Failed to get sample (%d)", rc); zassert_true(val_first.val1 != 0, "No readings from QDEC"); /* wait for more readings*/ k_msleep(200); - rc = sensor_channel_get(qdec_dev, SENSOR_CHAN_ROTATION, &val_second); + rc = sensor_channel_get(loopback->qdec, SENSOR_CHAN_ROTATION, &val_second); zassert_true(rc == 0, "Failed to fetch sample (%d)", rc); zassert_true(val_second.val1 != 0, "No readings from QDEC"); @@ -386,81 +451,111 @@ ZTEST(qdec_sensor, test_sensor_channel_get) val_second.val2); if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { - pm_device_runtime_put(qdec_dev); + pm_device_runtime_put(loopback->qdec); } } /** - * @brief sensor_channel_get test negative + * @brief sensor_channel_get test with emulation * - * Confirm getting readings from QDEC with invalid channel + * Confirm getting readings from QDEC * */ -ZTEST(qdec_sensor, test_sensor_channel_get_negative) +ZTEST(qdec_sensor, test_sensor_channel_get) +{ + for (size_t i = 0; i < TESTED_QDEC_COUNT; i++) { + TC_PRINT("Testing QDEC index %d, address: %p\n", i, loopbacks[i].qdec); + sensor_channel_get_test(&loopbacks[i]); + } +} + +static void sensor_channel_get_negative(struct qdec_qenc_loopback *loopback) { int rc; struct sensor_value val = {0}; if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { - pm_device_runtime_get(qdec_dev); + pm_device_runtime_get(loopback->qdec); } - qenc_emulate_start(K_MSEC(10), true); + qenc_emulate_start(loopback, K_MSEC(10), true); /* wait for some readings*/ k_msleep(100); - rc = sensor_sample_fetch(qdec_dev); + rc = sensor_sample_fetch(loopback->qdec); zassert_true(rc == 0, "Failed to fetch sample (%d)", rc); - rc = sensor_channel_get(qdec_dev, SENSOR_CHAN_MAX, &val); + rc = sensor_channel_get(loopback->qdec, SENSOR_CHAN_MAX, &val); zassert_true(rc < 0, "Should failed to get sample (%d)", rc); zassert_true(val.val1 == 0, "Some readings from QDEC: %d", val.val1); zassert_true(val.val2 == 0, "Some readings from QDEC: %d", val.val2); if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { - pm_device_runtime_put(qdec_dev); + pm_device_runtime_put(loopback->qdec); } } /** - * @brief sensor_sample_fetch(_chan) test + * @brief sensor_channel_get test negative * - * Confirm fetching work with QDEC specific channel - rotation + * Confirm getting readings from QDEC with invalid channel * */ -ZTEST(qdec_sensor, test_sensor_sample_fetch) +ZTEST(qdec_sensor, test_sensor_channel_get_negative) +{ + for (size_t i = 0; i < TESTED_QDEC_COUNT; i++) { + TC_PRINT("Testing QDEC index %d, address: %p\n", i, loopbacks[i].qdec); + sensor_channel_get_negative(&loopbacks[i]); + } +} + +static void sensor_sample_fetch_test(const struct device *const dev) { int rc; if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { - pm_device_runtime_get(qdec_dev); + pm_device_runtime_get(dev); } - rc = sensor_sample_fetch(qdec_dev); + rc = sensor_sample_fetch(dev); zassert_true(rc == 0, "Failed to fetch sample (%d)", rc); - rc = sensor_sample_fetch_chan(qdec_dev, SENSOR_CHAN_ROTATION); + rc = sensor_sample_fetch_chan(dev, SENSOR_CHAN_ROTATION); zassert_true(rc == 0, "Failed to fetch sample (%d)", rc); - rc = sensor_sample_fetch_chan(qdec_dev, SENSOR_CHAN_MAX); + rc = sensor_sample_fetch_chan(dev, SENSOR_CHAN_MAX); zassert_true(rc < 0, "Should fail to fetch sample from invalid channel (%d)", rc); if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { - pm_device_runtime_put(qdec_dev); + pm_device_runtime_put(dev); } } -static void *setup(void) +/** + * @brief sensor_sample_fetch(_chan) test + * + * Confirm fetching work with QDEC specific channel - rotation + * + */ +ZTEST(qdec_sensor, test_sensor_sample_fetch) { - int rc; + for (size_t i = 0; i < TESTED_QDEC_COUNT; i++) { + TC_PRINT("Testing QDEC index %d, address: %p\n", i, loopbacks[i].qdec); + sensor_sample_fetch_test(loopbacks[i].qdec); + } +} - rc = device_is_ready(qdec_dev); - zassert_true(rc, "QDEC device not ready: %d", rc); +static void *setup(void) +{ + for (size_t i = 0; i < TESTED_QDEC_COUNT; i++) { + int rc = device_is_ready(loopbacks[i].qdec); - qenc_emulate_setup_pin(&phase_a); - qenc_emulate_setup_pin(&phase_b); + zassert_true(rc, "QDEC index %d not ready: %d", i, rc); + qenc_emulate_setup_pin(&loopbacks[i].qenc_phase_a); + qenc_emulate_setup_pin(&loopbacks[i].qenc_phase_b); + } return NULL; }