1 /*
2 * Copyright (c) 2024 CogniPilot Foundation
3 * Copyright (c) 2024 NXP Semiconductors
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #define DT_DRV_COMPAT futaba_sbus
9
10 #include <zephyr/device.h>
11 #include <zephyr/input/input.h>
12 #include <zephyr/irq.h>
13 #include <zephyr/kernel.h>
14 #include <zephyr/logging/log.h>
15 #include <zephyr/sys/time_units.h>
16 #include <zephyr/sys_clock.h>
17 #include <zephyr/drivers/uart.h>
18
19 LOG_MODULE_REGISTER(futaba_sbus, CONFIG_INPUT_LOG_LEVEL);
20
21 /* Driver config */
22 struct sbus_input_channel {
23 uint32_t sbus_channel;
24 uint32_t type;
25 uint32_t zephyr_code;
26 };
27
28 const struct uart_config uart_cfg_sbus = {
29 .baudrate = 100000,
30 .parity = UART_CFG_PARITY_EVEN,
31 .stop_bits = UART_CFG_STOP_BITS_2,
32 .data_bits = UART_CFG_DATA_BITS_8,
33 .flow_ctrl = UART_CFG_FLOW_CTRL_NONE
34 };
35
36 struct input_sbus_config {
37 uint8_t num_channels;
38 const struct sbus_input_channel *channel_info;
39 const struct device *uart_dev;
40 uart_irq_callback_user_data_t cb;
41 };
42
43 #define SBUS_FRAME_LEN 25
44 #define SBUS_HEADER 0x0F
45 #define SBUS_FOOTER 0x00
46
47 #define SBUS_SERVO_LEN 22
48 #define SBUS_SERVO_CH_MASK 0x7FF
49
50 #define SBUS_BYTE24_IDX 23
51 #define SBUS_BYTE24_CH17 0x01
52 #define SBUS_BYTE24_CH18 0x02
53 #define SBUS_BYTE24_FRAME_LOST 0x04
54 #define SBUS_BYTE24_FAILSAFE 0x08
55
56 #define SBUS_TRANSMISSION_TIME_MS 4 /* Max transmission of a single SBUS frame */
57 #define SBUS_INTERFRAME_SPACING_MS 20 /* Max spacing between SBUS frames */
58 #define SBUS_CHANNEL_COUNT 16
59
60 #define REPORT_FILTER CONFIG_INPUT_SBUS_REPORT_FILTER
61 #define CHANNEL_VALUE_ZERO CONFIG_INPUT_SBUS_CHANNEL_VALUE_ZERO
62 #define CHANNEL_VALUE_ONE CONFIG_INPUT_SBUS_CHANNEL_VALUE_ONE
63
64 struct input_sbus_data {
65 struct k_thread thread;
66 struct k_sem report_lock;
67
68 uint16_t xfer_bytes;
69 uint8_t rd_data[SBUS_FRAME_LEN];
70 uint8_t sbus_frame[SBUS_FRAME_LEN];
71 bool partial_sync;
72 bool in_sync;
73 uint32_t last_rx_time;
74
75 uint16_t last_reported_value[SBUS_CHANNEL_COUNT];
76 int8_t channel_mapping[SBUS_CHANNEL_COUNT];
77
78 K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_INPUT_SBUS_THREAD_STACK_SIZE);
79 };
80
input_sbus_report(const struct device * dev,unsigned int sbus_channel,unsigned int value)81 static void input_sbus_report(const struct device *dev, unsigned int sbus_channel,
82 unsigned int value)
83 {
84 const struct input_sbus_config *const config = dev->config;
85 struct input_sbus_data *const data = dev->data;
86
87 int channel = data->channel_mapping[sbus_channel];
88
89 /* Not Mapped */
90 if (channel == -1) {
91 return;
92 }
93
94 if (value >= (data->last_reported_value[channel] + REPORT_FILTER) ||
95 value <= (data->last_reported_value[channel] - REPORT_FILTER)) {
96 switch (config->channel_info[channel].type) {
97 case INPUT_EV_ABS:
98 case INPUT_EV_MSC:
99 input_report(dev, config->channel_info[channel].type,
100 config->channel_info[channel].zephyr_code, value, false,
101 K_FOREVER);
102 break;
103
104 default:
105 if (value > CHANNEL_VALUE_ONE) {
106 input_report_key(dev, config->channel_info[channel].zephyr_code, 1,
107 false, K_FOREVER);
108 } else if (value < CHANNEL_VALUE_ZERO) {
109 input_report_key(dev, config->channel_info[channel].zephyr_code, 0,
110 false, K_FOREVER);
111 }
112 }
113 data->last_reported_value[channel] = value;
114 }
115 }
116
input_sbus_input_report_thread(const struct device * dev,void * dummy2,void * dummy3)117 static void input_sbus_input_report_thread(const struct device *dev, void *dummy2, void *dummy3)
118 {
119 struct input_sbus_data *const data = dev->data;
120
121 ARG_UNUSED(dummy2);
122 ARG_UNUSED(dummy3);
123
124 uint8_t i, channel;
125 uint8_t *sbus_channel_data = &data->sbus_frame[1]; /* Omit header */
126 uint16_t value;
127 int bits_read;
128 unsigned int key;
129 int ret;
130 bool connected_reported = false;
131
132 while (true) {
133 if (!data->in_sync) {
134 k_sem_take(&data->report_lock, K_FOREVER);
135 if (data->in_sync) {
136 LOG_DBG("SBUS receiver connected");
137 } else {
138 continue;
139 }
140 } else {
141 ret = k_sem_take(&data->report_lock, K_MSEC(SBUS_INTERFRAME_SPACING_MS));
142 if (ret == -EBUSY) {
143 continue;
144 } else if (ret < 0 || !data->in_sync) {
145 /* We've lost sync with the UART receiver */
146 key = irq_lock();
147
148 data->partial_sync = false;
149 data->in_sync = false;
150 data->xfer_bytes = 0;
151 irq_unlock(key);
152
153 connected_reported = false;
154 LOG_DBG("SBUS receiver connection lost");
155
156 /* Report connection lost */
157 continue;
158 }
159 }
160
161 if (connected_reported &&
162 data->sbus_frame[SBUS_BYTE24_IDX] & SBUS_BYTE24_FRAME_LOST) {
163 LOG_DBG("SBUS controller connection lost");
164 connected_reported = false;
165 } else if (!connected_reported &&
166 !(data->sbus_frame[SBUS_BYTE24_IDX] & SBUS_BYTE24_FRAME_LOST)) {
167 LOG_DBG("SBUS controller connected");
168 connected_reported = true;
169 }
170
171 /* Parse the data */
172 channel = 0;
173 value = 0;
174 bits_read = 0;
175
176 for (i = 0; i < SBUS_SERVO_LEN; i++) {
177 /* Read the next byte */
178 unsigned char byte = sbus_channel_data[i];
179
180 /* Extract bits and construct the 11-bit value */
181 value |= byte << bits_read;
182 bits_read += 8;
183
184 /* Check if we've read enough bits to form a full 11-bit value */
185 while (bits_read >= 11) {
186 input_sbus_report(dev, channel, value & SBUS_SERVO_CH_MASK);
187
188 /* Shift right to prepare for the next 11 bits */
189 value >>= 11;
190 bits_read -= 11;
191 channel++;
192 }
193 }
194
195 #ifdef CONFIG_INPUT_SBUS_SEND_SYNC
196 input_report(dev, 0, 0, 0, true, K_FOREVER);
197 #endif
198 }
199 }
200
sbus_resync(const struct device * uart_dev,struct input_sbus_data * const data)201 static void sbus_resync(const struct device *uart_dev, struct input_sbus_data *const data)
202 {
203 uint8_t *rd_data = data->rd_data;
204
205 if (data->partial_sync) {
206 data->xfer_bytes += uart_fifo_read(uart_dev, &rd_data[data->xfer_bytes],
207 SBUS_FRAME_LEN - data->xfer_bytes);
208 if (data->xfer_bytes == SBUS_FRAME_LEN) {
209 /* Transfer took longer then 4ms probably faulty */
210 if (k_uptime_get_32() - data->last_rx_time > SBUS_TRANSMISSION_TIME_MS) {
211 data->xfer_bytes = 0;
212 data->partial_sync = false;
213 } else if (rd_data[0] == SBUS_HEADER &&
214 rd_data[SBUS_FRAME_LEN - 1] == SBUS_FOOTER) {
215 data->in_sync = true;
216 } else {
217 /* Dummy read to clear fifo */
218 uart_fifo_read(uart_dev, &rd_data[0], 1);
219 data->xfer_bytes = 0;
220 data->partial_sync = false;
221 }
222 }
223 } else {
224 if (uart_fifo_read(uart_dev, &rd_data[0], 1) == 1) {
225 if (rd_data[0] == SBUS_HEADER) {
226 data->partial_sync = true;
227 data->xfer_bytes = 1;
228 data->last_rx_time = k_uptime_get_32();
229 }
230 }
231 }
232 }
233
sbus_uart_isr(const struct device * uart_dev,void * user_data)234 static void sbus_uart_isr(const struct device *uart_dev, void *user_data)
235 {
236 const struct device *dev = user_data;
237 struct input_sbus_data *const data = dev->data;
238 uint8_t *rd_data = data->rd_data;
239
240 if (uart_dev == NULL) {
241 LOG_DBG("UART device is NULL");
242 return;
243 }
244
245 if (!uart_irq_update(uart_dev)) {
246 LOG_DBG("Unable to start processing interrupts");
247 return;
248 }
249
250 while (uart_irq_rx_ready(uart_dev) && data->xfer_bytes <= SBUS_FRAME_LEN) {
251 if (data->in_sync) {
252 if (data->xfer_bytes == 0) {
253 data->last_rx_time = k_uptime_get_32();
254 }
255 data->xfer_bytes += uart_fifo_read(uart_dev, &rd_data[data->xfer_bytes],
256 SBUS_FRAME_LEN - data->xfer_bytes);
257 } else {
258 sbus_resync(uart_dev, data);
259 }
260 }
261
262 if (data->in_sync && (k_uptime_get_32() - data->last_rx_time >
263 SBUS_INTERFRAME_SPACING_MS)) {
264 data->partial_sync = false;
265 data->in_sync = false;
266 data->xfer_bytes = 0;
267 k_sem_give(&data->report_lock);
268 } else if (data->in_sync && data->xfer_bytes == SBUS_FRAME_LEN) {
269 data->xfer_bytes = 0;
270
271 if (rd_data[0] == SBUS_HEADER && rd_data[SBUS_FRAME_LEN - 1] == SBUS_FOOTER) {
272 memcpy(data->sbus_frame, rd_data, SBUS_FRAME_LEN);
273 k_sem_give(&data->report_lock);
274 } else {
275 data->partial_sync = false;
276 data->in_sync = false;
277 }
278 }
279 }
280
281 /*
282 * @brief Initialize sbus driver
283 */
input_sbus_init(const struct device * dev)284 static int input_sbus_init(const struct device *dev)
285 {
286 const struct input_sbus_config *const config = dev->config;
287 struct input_sbus_data *const data = dev->data;
288 int i, ret;
289
290 uart_irq_rx_disable(config->uart_dev);
291 uart_irq_tx_disable(config->uart_dev);
292
293 LOG_DBG("Initializing SBUS driver");
294
295 for (i = 0; i < SBUS_CHANNEL_COUNT; i++) {
296 data->last_reported_value[i] = 0;
297 data->channel_mapping[i] = -1;
298 }
299
300 data->xfer_bytes = 0;
301 data->in_sync = false;
302 data->partial_sync = false;
303 data->last_rx_time = 0;
304
305 for (i = 0; i < config->num_channels; i++) {
306 data->channel_mapping[config->channel_info[i].sbus_channel - 1] = i;
307 }
308
309 ret = uart_configure(config->uart_dev, &uart_cfg_sbus);
310 if (ret < 0) {
311 LOG_ERR("Unable to configure UART port: %d", ret);
312 return ret;
313 }
314
315 ret = uart_irq_callback_user_data_set(config->uart_dev, config->cb, (void *)dev);
316 if (ret < 0) {
317 if (ret == -ENOTSUP) {
318 LOG_ERR("Interrupt-driven UART API support not enabled");
319 } else if (ret == -ENOSYS) {
320 LOG_ERR("UART device does not support interrupt-driven API");
321 } else {
322 LOG_ERR("Error setting UART callback: %d", ret);
323 }
324 return ret;
325 }
326
327 uart_irq_rx_enable(config->uart_dev);
328
329 k_sem_init(&data->report_lock, 0, 1);
330
331 k_thread_create(&data->thread, data->thread_stack,
332 K_KERNEL_STACK_SIZEOF(data->thread_stack),
333 (k_thread_entry_t)input_sbus_input_report_thread, (void *)dev, NULL, NULL,
334 CONFIG_INPUT_SBUS_THREAD_PRIORITY, 0, K_NO_WAIT);
335
336 k_thread_name_set(&data->thread, dev->name);
337
338 return ret;
339 }
340
341 #define INPUT_CHANNEL_CHECK(input_channel_id) \
342 BUILD_ASSERT(IN_RANGE(DT_PROP(input_channel_id, channel), 1, 16), \
343 "invalid channel number"); \
344 BUILD_ASSERT(DT_PROP(input_channel_id, type) == INPUT_EV_ABS || \
345 DT_PROP(input_channel_id, type) == INPUT_EV_KEY || \
346 DT_PROP(input_channel_id, type) == INPUT_EV_MSC, \
347 "invalid channel type");
348
349 #define SBUS_INPUT_CHANNEL_INITIALIZER(input_channel_id) \
350 { \
351 .sbus_channel = DT_PROP(input_channel_id, channel), \
352 .type = DT_PROP(input_channel_id, type), \
353 .zephyr_code = DT_PROP(input_channel_id, zephyr_code), \
354 },
355
356 #define INPUT_SBUS_INIT(n) \
357 \
358 static const struct sbus_input_channel input_##n[] = { \
359 DT_INST_FOREACH_CHILD(n, SBUS_INPUT_CHANNEL_INITIALIZER) \
360 }; \
361 DT_INST_FOREACH_CHILD(n, INPUT_CHANNEL_CHECK) \
362 \
363 static struct input_sbus_data sbus_data_##n; \
364 \
365 static const struct input_sbus_config sbus_cfg_##n = { \
366 .channel_info = input_##n, \
367 .uart_dev = DEVICE_DT_GET(DT_INST_BUS(n)), \
368 .num_channels = ARRAY_SIZE(input_##n), \
369 .cb = sbus_uart_isr, \
370 }; \
371 \
372 DEVICE_DT_INST_DEFINE(n, input_sbus_init, NULL, &sbus_data_##n, &sbus_cfg_##n, \
373 POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL);
374
375 DT_INST_FOREACH_STATUS_OKAY(INPUT_SBUS_INIT)
376