1 /*
2  * Copyright (c) 2021 Titouan Christophe
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/device.h>
9 #include <zephyr/drivers/sensor.h>
10 #include <zephyr/drivers/gpio.h>
11 
12 #include "display_7seg.h"
13 
14 /*
15  * Get button configuration from the devicetree sw0 alias. This is mandatory.
16  */
17 #define SW0_NODE        DT_ALIAS(sw0)
18 #if !DT_NODE_HAS_STATUS(SW0_NODE, okay)
19 #error "Unsupported board: sw0 devicetree alias is not defined"
20 #endif
21 
22 #define N_MODES ARRAY_SIZE(modes)
23 #define N_SENSORS ARRAY_SIZE(sensors)
24 #define LEFT   sensors[0]
25 #define CENTER sensors[1]
26 #define RIGHT  sensors[2]
27 
28 typedef void (*fsm_state)(void);
29 
30 static int64_t last_mode_change;
31 
32 static const struct device *const sensors[] = {
33 	DEVICE_DT_GET(DT_NODELABEL(vl53l0x_l_x_nucleo_53l0a1)),
34 	DEVICE_DT_GET(DT_NODELABEL(vl53l0x_c_x_nucleo_53l0a1)),
35 	DEVICE_DT_GET(DT_NODELABEL(vl53l0x_r_x_nucleo_53l0a1)),
36 };
37 
mode_show_distance(void)38 static void mode_show_distance(void)
39 {
40 	int ret;
41 	double distance;
42 	struct sensor_value value;
43 
44 	ret = sensor_sample_fetch(CENTER);
45 	if (ret) {
46 		printk("sensor_sample_fetch(%s) failed -> %d\n", CENTER->name, ret);
47 		display_chars(TEXT_Err);
48 		return;
49 	}
50 
51 	ret = sensor_channel_get(CENTER, SENSOR_CHAN_DISTANCE, &value);
52 	if (ret) {
53 		printk("sensor_channel_get(%s) failed -> %d\n", CENTER->name, ret);
54 		display_chars(TEXT_Err);
55 		return;
56 	}
57 	distance = sensor_value_to_double(&value);
58 	if (distance < 1.25) {
59 		display_number(100 * distance, 10);
60 	} else {
61 		display_chars(DISPLAY_OFF);
62 	}
63 }
64 
mode_show_presence(void)65 static void mode_show_presence(void)
66 {
67 	int i, ret;
68 	struct sensor_value value;
69 	uint8_t text[4] = { CHAR_OFF, CHAR_OFF, CHAR_OFF, CHAR_OFF };
70 
71 	for (i = 0; i < N_SENSORS; i++) {
72 		ret = sensor_sample_fetch(sensors[i]);
73 		if (ret) {
74 			printk("sensor_sample_fetch(%s) failed -> %d\n",
75 			       sensors[i]->name, ret);
76 			display_chars(TEXT_Err);
77 			return;
78 		}
79 		ret = sensor_channel_get(sensors[i],
80 					 SENSOR_CHAN_PROX,
81 					 &value);
82 		if (ret) {
83 			printk("sensor_channel_get(%s) failed -> %d\n",
84 			       sensors[i]->name, ret);
85 			display_chars(TEXT_Err);
86 			return;
87 		}
88 
89 		if (value.val1) {
90 			text[i] = CHAR_UNDERSCORE | CHAR_DASH | CHAR_OVERLINE;
91 		}
92 	}
93 	display_chars(text);
94 }
95 
96 static size_t current_mode;
97 static fsm_state modes[] = {
98 	mode_show_distance,
99 	mode_show_presence,
100 };
101 
change_mode(const struct device * dev,struct gpio_callback * cb,uint32_t pins)102 static void change_mode(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
103 {
104 	(void) dev;
105 	(void) cb;
106 	(void) pins;
107 
108 	int64_t now = k_uptime_get();
109 
110 	if (now - last_mode_change > 300) {
111 		current_mode = (current_mode + 1) % N_MODES;
112 		last_mode_change = now;
113 	}
114 }
115 
116 
main(void)117 int main(void)
118 {
119 	struct gpio_callback button_cb_data;
120 	const uint8_t Hello[4] = { CHAR_H, CHAR_E, CHAR_PIPE | CHAR_1, CHAR_0 };
121 	const struct gpio_dt_spec button = GPIO_DT_SPEC_GET(SW0_NODE, gpios);
122 
123 	display_chars(Hello);
124 	k_sleep(K_MSEC(1000));
125 
126 	if (!gpio_is_ready_dt(&button)) {
127 		printk("Error: button device %s is not ready\n",
128 		       button.port->name);
129 		return 0;
130 	}
131 
132 	gpio_pin_configure_dt(&button, GPIO_INPUT);
133 	gpio_pin_interrupt_configure_dt(&button, GPIO_INT_EDGE_RISING);
134 	gpio_init_callback(&button_cb_data, change_mode, BIT(button.pin));
135 	gpio_add_callback(button.port, &button_cb_data);
136 
137 	while (1) {
138 		modes[current_mode]();
139 	}
140 	return 0;
141 }
142