Paparazzi UAS v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
slcan.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2025 Fabien-B <fabien-b@github.com>
3 *
4 * This file is part of paparazzi
5 *
6 * paparazzi is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * paparazzi is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with paparazzi; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 */
20
27#include "modules/core/slcan.h"
28#include "generated/airframe.h"
29#include "mcu_periph/uart.h"
30#include "mcu_periph/can.h"
32#include "pprzlink/pprzlink_device.h"
33#include "stdio.h"
34#include "string.h"
35
36
37
39
40static void slcan_handle_cmd(slcan_t* slcan);
41static void slcan_rsp_ok(slcan_t* slcan);
42static void slcan_rsp_error(slcan_t* slcan);
43
45
46static uint8_t hex2nibble(char a);
47static uint8_t nibble2hex(uint8_t x);
48
49
50void slcan_can_rx_cb(struct pprzcan_frame* rxframe, struct pprzaddr_can* src_addr, void* user_data);
51
52
53void slcan_init(void) {
54 slcan.dev = &SLCAN_PORT.device;
57 slcan.timestamp = true;
58 pprz_mtx_init(&slcan.mtx); // needed if support for a seconf interface is added
60
61}
62
63void slcan_event(void) {
64 while(slcan.dev->char_available(slcan.dev->periph) > 0) {
65 uint8_t b = slcan.dev->get_byte(slcan.dev->periph);
68
69 if(b == '\r' && slcan.cmd_buf_idx > 1) {
71 }
72
73 }
74}
75
77 uint8_t* args = &slcan->cmd_buf[1]; // where arguments begins
78
79
80 switch (slcan->cmd_buf[0])
81 {
82 // CAN frames
83 case 't':
84 case 'T':
85 case 'd':
86 case 'D':
87 case 'r':
88 case 'R':
91 } else {
93 }
94 break;
95
96 // a bunch of unimplemented commands. Just returns OK.
97 case 'S':
98 case 's':
99 case 'O':
100 case 'L':
101 case 'C':
102 case 'X':
103 case 'W':
104 case 'M':
105 case 'm':
106 case 'U':
107 case 'Q':
109 break;
110
111 // unimplemented commands, return ERROR.
112 case 'A':
113 case 'P':
115 break;
116
117 // Set timestamp ON/OFF
118 case 'Z':
119 slcan->timestamp = args[0] == '1';
120 break;
121
122 // get status
123 case 'F':
124 {
125 char rsp_buf[5];
126 const uint8_t status = 0; // TODO get status
127 int len = snprintf(rsp_buf, 5, "F%02X\r", status); // OK included
128 slcan->dev->put_buffer(slcan->dev->periph, 0, (uint8_t*)rsp_buf, (uint16_t)len);
129 break;
130 }
131
132 // get version
133 case 'V':
134 {
135 char rsp_buf[7];
136 int len = snprintf(rsp_buf, 7, "V%x%x%x%x\r", 1, 0, 1, 0); // OK included
137 slcan->dev->put_buffer(slcan->dev->periph, 0, (uint8_t*)rsp_buf, (uint16_t)len);
138 break;
139 }
140
141 // get serial number
142 case 'N':
143 {
144 char rsp_buf[7] = "NPPRZ\r"; // OK included
145 slcan->dev->put_buffer(slcan->dev->periph, 0, (uint8_t*)rsp_buf, 6);
146 break;
147 }
148
149 default:
151 break;
152 }
153
154 slcan->cmd_buf_idx = 0;
155
156}
157
158
160 const uint8_t n = slcan->cmd_buf_idx-2; // number of chars after the command char
161 const uint8_t cmd = slcan->cmd_buf[0];
162 uint8_t* args = &slcan->cmd_buf[1]; // where arguments begins
163 uint8_t* data;
164
165 //slcan_frame_t tx_frame;
166 struct pprzcan_frame tx_frame;
167
168 if(cmd == 't' || cmd == 'd' || cmd == 'r') {
169 // SID
170 if(n < 4) {return -1;} // error: not enough cmd chars
171 tx_frame.can_id = (hex2nibble(args[0]) << 8) |
172 (hex2nibble(args[1]) << 4) |
173 (hex2nibble(args[2]) << 0);
175 data = &args[4];
176 } else {
177 // EID
178 if(n < 9) {return -1;} // error: not enough cmd chars
179 tx_frame.can_id = (hex2nibble(args[0]) << 28) |
180 (hex2nibble(args[1]) << 24) |
181 (hex2nibble(args[2]) << 20) |
182 (hex2nibble(args[3]) << 16) |
183 (hex2nibble(args[4]) << 12) |
184 (hex2nibble(args[5]) << 8) |
185 (hex2nibble(args[6]) << 4) |
186 (hex2nibble(args[7]) << 0);
187 tx_frame.can_id |= CAN_FRAME_EFF;
189 data = &args[9];
190 }
191
192 if(cmd == 'r' || cmd == 'R') {
193 tx_frame.can_id |= CAN_FRAME_RTR;
194 } else {
195 if(n < tx_frame.len + (tx_frame.can_id & CAN_FRAME_EFF ? 9: 4)) {return -1;} // error: not enough cmd chars
196
197 for(int i=0; i < tx_frame.len; i++) {
198 tx_frame.data[i] = (hex2nibble(data[2*i]) << 4) | (hex2nibble(data[2*i+1]) << 0);
199 }
200 }
201
203 return 0;
204
205}
206
207
208
210 if(can_id & CAN_FRAME_EFF) {
211 if(flags & CANFD_FDF) {
212 return 'D';
213 } else {
214 if(can_id & CAN_FRAME_RTR) {
215 return 'R';
216 } else {
217 return 'T';
218 }
219 }
220 } else {
221 if(flags & CANFD_FDF) {
222 return 'd';
223 } else {
224 if(can_id & CAN_FRAME_RTR) {
225 return 'r';
226 } else {
227 return 't';
228 }
229 }
230 }
231}
232
233void slcan_can_rx_cb(struct pprzcan_frame* rxframe, struct pprzaddr_can* src_addr, void* user_data) {
234 slcan_t* slcan = (slcan_t*) user_data;
235 (void)src_addr;
237 uint16_t idx = 0;
238 slcan->tx_buf[idx++] = slcan_cmd_from_id(rxframe->can_id, rxframe->flags);
239 if(rxframe->can_id & CAN_FRAME_EFF) {
240 slcan->tx_buf[idx++] = nibble2hex((rxframe->can_id >> 28) & 0x01);
241 slcan->tx_buf[idx++] = nibble2hex((rxframe->can_id >> 24));
242 slcan->tx_buf[idx++] = nibble2hex((rxframe->can_id >> 20));
243 slcan->tx_buf[idx++] = nibble2hex((rxframe->can_id >> 16));
244 slcan->tx_buf[idx++] = nibble2hex((rxframe->can_id >> 12));
245 slcan->tx_buf[idx++] = nibble2hex((rxframe->can_id >> 8) );
246 slcan->tx_buf[idx++] = nibble2hex((rxframe->can_id >> 4) );
247 slcan->tx_buf[idx++] = nibble2hex((rxframe->can_id >> 0) );
248 } else {
249 slcan->tx_buf[idx++] = nibble2hex((rxframe->can_id >> 8) & 0x07);
250 slcan->tx_buf[idx++] = nibble2hex((rxframe->can_id >> 4));
251 slcan->tx_buf[idx++] = nibble2hex((rxframe->can_id >> 0));
252 }
253
254 slcan->tx_buf[idx++] = nibble2hex(can_len_to_dlc(rxframe->len));
255 for(int i=0; i<rxframe->len; i++) {
256 slcan->tx_buf[idx++] = nibble2hex(rxframe->data[i] >> 4);
257 slcan->tx_buf[idx++] = nibble2hex(rxframe->data[i]);
258 }
259
260 if(slcan->timestamp) {
261 slcan->tx_buf[idx++] = nibble2hex((rxframe->timestamp >> 12));
262 slcan->tx_buf[idx++] = nibble2hex((rxframe->timestamp >> 8));
263 slcan->tx_buf[idx++] = nibble2hex((rxframe->timestamp >> 4));
264 slcan->tx_buf[idx++] = nibble2hex((rxframe->timestamp >> 0));
265 }
266
267 slcan->tx_buf[idx++] = '\r';
268
269 slcan->dev->put_buffer(slcan->dev->periph, 0, slcan->tx_buf, idx);
270 slcan->dev->send_message(slcan->dev->periph, 0);
271
273}
274
276 slcan->dev->put_byte(slcan->dev->periph, 0, '\r');
277 slcan->dev->send_message(slcan->dev->periph, 0);
278}
279
281 slcan->dev->put_byte(slcan->dev->periph, 0, 0x07);
282 slcan->dev->send_message(slcan->dev->periph, 0);
283}
284
289 static uint8_t ConversionTable[] = {
290 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
291 };
292 return ConversionTable[x & 0x0F];
293}
294
298static uint8_t hex2nibble(char a) {
299 if (a >= 'A' && a <= 'F') {
300 return a - 'A' + 10;
301 } else if (a >= 'a' && a <= 'f') {
302 return a - 'a' + 10;
303 } else if (a >= '0' && a <= '9') {
304 return a - '0';
305 }
306 return 255;
307}
static uint8_t status
uint8_t can_dlc_to_len(uint8_t dlc)
Definition can.c:39
int can_register_callback(can_rx_frame_callback_t callback, struct pprzaddr_can *src_addr, void *user_data)
Add a callback on received frames from an interface.
Definition can.c:78
uint8_t can_len_to_dlc(uint8_t len)
Definition can.c:46
uint32_t timestamp
Definition can.h:76
uint8_t len
Definition can.h:74
int can_ifindex
Definition can.h:83
uint8_t data[SOCKETCAN_MAX_DLEN]
Definition can.h:77
#define CANFD_FDF
Definition can.h:70
uint8_t flags
Definition can.h:75
socketcan_id_t can_id
Definition can.h:73
#define CAN_FRAME_EFF
Definition can.h:62
#define CAN_FRAME_RTR
Definition can.h:60
int can_transmit_frame(struct pprzcan_frame *txframe, struct pprzaddr_can *addr)
Definition can_arch.c:137
int pprz_mtx_unlock(pprz_mutex_t *mtx)
int pprz_mtx_init(pprz_mutex_t *mtx)
int pprz_mtx_lock(pprz_mutex_t *mtx)
uint16_t foo
Definition main_demo5.c:58
static uint32_t idx
slcan_t slcan
Definition slcan.c:38
static uint8_t hex2nibble(char a)
hex2nibble('B') = 0x0B
Definition slcan.c:298
static void slcan_rsp_ok(slcan_t *slcan)
Definition slcan.c:275
void slcan_can_rx_cb(struct pprzcan_frame *rxframe, struct pprzaddr_can *src_addr, void *user_data)
Definition slcan.c:233
void slcan_event(void)
Definition slcan.c:63
static int slcan_handle_frame(slcan_t *slcan)
Definition slcan.c:159
static uint8_t slcan_cmd_from_id(uint32_t can_id, uint8_t flags)
Definition slcan.c:209
static void slcan_rsp_error(slcan_t *slcan)
Definition slcan.c:280
void slcan_init(void)
Definition slcan.c:53
static uint8_t nibble2hex(uint8_t x)
nibble2hex(2) == '2'
Definition slcan.c:288
static void slcan_handle_cmd(slcan_t *slcan)
Definition slcan.c:76
uint8_t cmd_buf_idx
Definition slcan.h:40
struct link_device * dev
Definition slcan.h:38
#define SLCAN_CMD_BUF_LEN
Definition slcan.h:34
bool timestamp
Definition slcan.h:42
uint8_t cmd_buf[SLCAN_CMD_BUF_LEN]
Definition slcan.h:39
uint8_t tx_buf[SLCAN_CMD_BUF_LEN]
Definition slcan.h:41
pprz_mutex_t mtx
Definition slcan.h:47
struct pprzaddr_can can_if
Definition slcan.h:44
arch independent UART (Universal Asynchronous Receiver/Transmitter) API
arch independent USB API
unsigned short uint16_t
Typedef defining 16 bit unsigned short type.
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.
float b
Definition wedgebug.c:202