1 /*
2 * Copyright (c) 2024 Adrien Leravat
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6 #include <zephyr/devicetree.h>
7 #include <zephyr/drivers/gpio.h>
8 #include <zephyr/drivers/gpio/gpio_emul.h>
9 #include <zephyr/drivers/sensor.h>
10 #include <zephyr/ztest.h>
11
12 #if DT_NODE_HAS_STATUS(DT_INST(0, hc_sr04), okay)
13 #define HC_SR04 DT_NODELABEL(hc_sr04)
14 #define HC_SR04_GPIO_OUT DT_GPIO_CTLR(DT_INST(0, hc_sr04), trigger_gpios)
15 #define HC_SR04_PIN_OUT DT_GPIO_PIN(DT_INST(0, hc_sr04), trigger_gpios)
16 #define HC_SR04_GPIO_IN DT_GPIO_CTLR(DT_INST(0, hc_sr04), echo_gpios)
17 #define HC_SR04_PIN_IN DT_GPIO_PIN(DT_INST(0, hc_sr04), echo_gpios)
18 #else
19 #error "HC-SR04 not enabled"
20 #endif
21
22 #define TEST_MEASURED_VALUE(fixture, value, duration_us, value1, value2) \
23 fixture->emul.echo_duration_us = duration_us; \
24 zassert_false(sensor_sample_fetch(fixture->dev), "sensor_sample_fetch failed"); \
25 zassert_false(sensor_channel_get(fixture->dev, SENSOR_CHAN_DISTANCE, &value), \
26 "sensor_channel_get failed"); \
27 zassert_equal(value.val1, value1, "incorrect measurement for value.val1"); \
28 zassert_within(value.val2, value2, 10000, "incorrect measurement for value.val2"); \
29
30 struct hcsr04_emul {
31 bool fail_echo;
32 uint32_t echo_duration_us;
33 struct gpio_callback cb;
34 };
35
36 struct hcsr04_fixture {
37 const struct device *dev;
38 struct hcsr04_emul emul;
39 };
40
41 static void gpio_emul_callback_handler(const struct device *port,
42 struct gpio_callback *cb,
43 gpio_port_pins_t pins);
44
hcsr04_setup(void)45 static void *hcsr04_setup(void)
46 {
47 static struct hcsr04_fixture fixture = {
48 .dev = DEVICE_DT_GET(HC_SR04),
49 .emul = {
50 .fail_echo = false,
51 .echo_duration_us = 0
52 }
53 };
54 const struct device *gpio_dev = DEVICE_DT_GET(HC_SR04_GPIO_IN);
55
56 zassert_not_null(fixture.dev);
57 zassert_not_null(gpio_dev);
58 zassert_true(device_is_ready(fixture.dev));
59 zassert_equal(DEVICE_DT_GET(HC_SR04_GPIO_IN), DEVICE_DT_GET(HC_SR04_GPIO_OUT),
60 "Input and output GPIO devices must the same");
61
62 zassert_true(device_is_ready(gpio_dev), "GPIO dev is not ready");
63
64 gpio_init_callback(&fixture.emul.cb, &gpio_emul_callback_handler, BIT(HC_SR04_PIN_OUT));
65 zassert_false(gpio_add_callback(gpio_dev, &fixture.emul.cb),
66 "Failed to add emulation callback");
67
68 return &fixture;
69 }
70
hcsr04_before(void * f)71 static void hcsr04_before(void *f)
72 {
73 struct hcsr04_fixture *fixture = f;
74
75 fixture->emul.fail_echo = false;
76 }
77
gpio_emul_callback_handler(const struct device * port,struct gpio_callback * cb,gpio_port_pins_t pins)78 static void gpio_emul_callback_handler(const struct device *port,
79 struct gpio_callback *cb,
80 gpio_port_pins_t pins)
81 {
82 const struct hcsr04_emul *emul = CONTAINER_OF(cb, struct hcsr04_emul, cb);
83
84 if (emul->fail_echo) {
85 return;
86 }
87 if (gpio_emul_output_get(port, HC_SR04_PIN_OUT) == 1) {
88 /* Ignore rising edge */
89 return;
90 }
91
92 /* Output high-level on echo pin */
93 gpio_emul_input_set(port, HC_SR04_PIN_IN, 1);
94 k_busy_wait(emul->echo_duration_us);
95 gpio_emul_input_set(port, HC_SR04_PIN_IN, 0);
96 }
97
98 ZTEST_SUITE(hcsr04, NULL, hcsr04_setup, hcsr04_before, NULL, NULL);
99
ZTEST_USER_F(hcsr04,test_sample_fetch_fail_no_echo)100 ZTEST_USER_F(hcsr04, test_sample_fetch_fail_no_echo)
101 {
102 int ret;
103
104 fixture->emul.fail_echo = true;
105
106 ret = sensor_sample_fetch(fixture->dev);
107 zassert_equal(-EIO, ret, "sensor_sample_fetch unexpected return code %d", ret);
108 }
109
ZTEST_USER_F(hcsr04,test_sample_fetch)110 ZTEST_USER_F(hcsr04, test_sample_fetch)
111 {
112 int ret;
113
114 ret = sensor_sample_fetch(fixture->dev);
115 zassert_equal(0, ret, "sensor_sample_fetch unexpected return code %d", ret);
116 }
117
ZTEST_USER_F(hcsr04,test_channel_get_fails_with_wrong_channel)118 ZTEST_USER_F(hcsr04, test_channel_get_fails_with_wrong_channel)
119 {
120 int ret;
121 struct sensor_value value;
122
123 ret = sensor_channel_get(fixture->dev, SENSOR_CHAN_ACCEL_X, &value);
124 zassert_equal(-ENOTSUP, ret, "sensor_channel_get returned unexpected code with %d", ret);
125 }
126
ZTEST_USER_F(hcsr04,test_channel_get_at_10cm)127 ZTEST_USER_F(hcsr04, test_channel_get_at_10cm)
128 {
129 struct sensor_value value;
130
131 TEST_MEASURED_VALUE(fixture, value, 583, 0, 100000);
132 }
133
ZTEST_USER_F(hcsr04,test_channel_get_at_150cm)134 ZTEST_USER_F(hcsr04, test_channel_get_at_150cm)
135 {
136 struct sensor_value value;
137
138 TEST_MEASURED_VALUE(fixture, value, 8745, 1, 500000);
139 }
140