Lely core libraries 1.9.2
msg.c
Go to the documentation of this file.
1
24#include "can.h"
25#include <lely/can/msg.h>
26#include <lely/util/bits.h>
27#include <lely/util/errnum.h>
28#include <lely/util/util.h>
29
30#include <assert.h>
31#include <stdio.h>
32// Include inttypes.h after stdio.h to enforce declarations of format specifiers
33// in Newlib.
34#include <inttypes.h>
35#include <stdlib.h>
36
50static uint_least16_t can_crc(
51 uint_least16_t crc, const void *ptr, int off, size_t bits);
52
54static uint_least16_t can_crc_bits(
55 uint_least16_t crc, uint_least8_t byte, int off, int bits);
56
58static uint_least16_t can_crc_bytes(
59 uint_least16_t crc, const unsigned char *bp, size_t n);
60
61int
62can_msg_bits(const struct can_msg *msg, enum can_msg_bits_mode mode)
63{
64 assert(msg);
65
66#if !LELY_NO_CANFD
67 if (msg->flags & CAN_FLAG_EDL) {
69 return -1;
70 }
71#endif
72
73 if (msg->len > CAN_MAX_LEN) {
75 return -1;
76 }
77
78 switch (mode) {
80 int bits = msg->flags & CAN_FLAG_IDE ? 67 : 47;
81 if (!(msg->flags & CAN_FLAG_RTR))
82 bits += msg->len * 8;
83 return bits;
84 }
86 int bits = msg->flags & CAN_FLAG_IDE ? 80 : 55;
87 if (!(msg->flags & CAN_FLAG_RTR))
88 bits += msg->len * 10;
89 return bits;
90 }
91 case CAN_MSG_BITS_MODE_EXACT: break;
92 default: set_errnum(ERRNUM_INVAL); return -1;
93 }
94
95 uint_least8_t data[16] = { 0 };
96 uint_least8_t *bp = data;
97 int off = 0;
98 int bits = 0;
99
100 if (msg->flags & CAN_FLAG_IDE) {
101 // s = SOF, B = (base) Identifier, S = SRR, I = IDE,
102 // E = Identifier (extension), R = RTR = 1 = R1, 0 = R0,
103 // DLC4 = DLC, 0-7 = Data, C = CRC
104 // data[0-3] |.sBBBBBB BBBBBSIE EEEEEEEE EEEEEEEE|
105 // data[4-7] |ER10DLC4 00000000 11111111 22222222|
106 // data[8-11] |33333333 44444444 55555555 66666666|
107 // data[12-14] |77777777 CCCCCCCC CCCCCCC. ........|
108 uint_least32_t id = msg->id & CAN_MASK_EID;
109 off = 1;
110 *bp++ = (id >> 23) & 0x3f; // SOF = 0, base (Indentifier)
111 bits += 8 - off;
112
113 *bp++ = ((id >> 15) & 0xf8) // base (Indentifier)
114 | (0x03 << 1) // SRR, IDE
115 | ((id >> 17) & 0x01); // Identifier (extension)
116 bits += 8;
117
118 *bp++ = (id >> 9) & 0xff; // Identifier (extension)
119 bits += 8;
120
121 *bp++ = (id >> 1) & 0xff; // Identifier (extension)
122 bits += 8;
123
124 *bp++ = ((id << 7) & 0x80) // Identifier (extension)
125 | (!!(msg->flags & CAN_FLAG_RTR) << 6) // RTR
126 | (msg->len & 0x0f); // R1 = 0, R0 = 0, DLC
127 bits += 8;
128 } else {
129 // s = SOF, B = (base) Identifier, R = RTR, I = IDE, 0 = R0,
130 // DLC4 = DLC, 0-7 = Data, C = CRC
131 // data[0-3] |.....sBB BBBBBBBB BRI0DLC4 00000000|
132 // data[4-7] |11111111 22222222 33333333 44444444|
133 // data[8-11] |55555555 66666666 77777777 CCCCCCCC|
134 // data[12-14] |CCCCCCC. ........ ........ ........|
135 uint_least32_t id = msg->id & CAN_MASK_BID;
136 off = 5;
137 *bp++ = (id >> 9) & 0x03; // SOF = 0, base (Indentifier)
138 bits += 8 - off;
139
140 *bp++ = (id >> 1) & 0xff; // base (Indentifier)
141 bits += 8;
142
143 *bp++ = ((id << 7) & 0x80) // base (Indentifier)
144 | (!!(msg->flags & CAN_FLAG_RTR) << 6) // RTR
145 | (msg->len & 0x0f); // IDE = 0, R0 = 0, DLC
146 bits += 8;
147 }
148
149 if (!(msg->flags & CAN_FLAG_RTR) && msg->len) {
150 for (uint_least8_t i = 0; i < msg->len; i++, bits += 8)
151 *bp++ = msg->data[i] & 0xff;
152 }
153
154 uint_least16_t crc = can_crc(0, data, off, bits);
155 assert(!((off + bits) % 8));
156 *bp++ = (crc >> 7) & 0xff;
157 *bp++ = (crc << 1) & 0xff;
158 bits += 15;
159
160 // Count the stuffed bits.
161 int stuff = 0;
162 uint_least8_t mask = 0x1f;
163 uint_least8_t same = mask;
164 for (int i = off; i < off + bits;) {
165 // Alternate between looking for a series of zeros and ones.
166 same = same ? 0 : mask;
167 // Extract 5 bits at i at look for a bit flip.
168 // clang-format off
169 uint_least8_t five = (((uint_least16_t)data[i / 8] << 8)
170 | data[i / 8 + 1]) >> (16 - 5 - i % 8);
171 // clang-format on
172 int n = clz8((five & mask) ^ same) - 3;
173 i += n;
174 if (n < 5) {
175 // No bit stuffing needed. Check the next 5 bits.
176 mask = 0x1f;
177 } else {
178 // Insert a stuffed bit and look for the next 4 bits
179 // (the 5th bit is the stuffed one).
180 if (mask == 0x1e)
181 i--;
182 else
183 mask = 0x1e;
184 if (i <= off + bits)
185 stuff++;
186 }
187 }
188 bits += stuff;
189
190 bits += 3; // CRC delimiter, ACK slot, ACK delimiter
191 bits += 7; // EOF sequence
192 bits += 3; // intermission
193
194 return bits;
195}
196
197int
198snprintf_can_msg(char *s, size_t n, const struct can_msg *msg)
199{
200 if (!s)
201 n = 0;
202
203 if (!msg)
204 return 0;
205
206 uint_least8_t len = msg->len;
207#if !LELY_NO_CANFD
208 if (msg->flags & CAN_FLAG_EDL)
209 len = MIN(len, CANFD_MAX_LEN);
210 else
211#endif
212 len = MIN(len, CAN_MAX_LEN);
213
214 int r, t = 0;
215
216 if (msg->flags & CAN_FLAG_IDE)
217 r = snprintf(s, n, "%08" PRIX32, msg->id & CAN_MASK_EID);
218 else
219 r = snprintf(s, n, "%03" PRIX32, msg->id & CAN_MASK_BID);
220 if (r < 0)
221 return r;
222 t += r;
223 r = MIN((size_t)r, n);
224 s += r;
225 n -= r;
226
227#if !LELY_NO_CANFD
228 if (msg->flags & CAN_FLAG_EDL)
229 r = snprintf(s, n, " [%02d] ", len);
230 else
231#endif
232 r = snprintf(s, n, " [%d] ", len);
233 if (r < 0)
234 return r;
235 t += r;
236 r = MIN((size_t)r, n);
237 s += r;
238 n -= r;
239
240 if (msg->flags & CAN_FLAG_RTR) {
241 r = snprintf(s, n, " remote request");
242 if (r < 0)
243 return r;
244 t += r;
245 } else {
246 for (uint_least8_t i = 0; i < len; i++) {
247 int r = snprintf(s, n, " %02X", msg->data[i]);
248 if (r < 0)
249 return r;
250 t += r;
251 r = MIN((size_t)r, n);
252 s += r;
253 n -= r;
254 }
255 }
256
257 return t;
258}
259
260int
261asprintf_can_msg(char **ps, const struct can_msg *msg)
262{
263 int n = snprintf_can_msg(NULL, 0, msg);
264 if (n < 0)
265 return n;
266
267 char *s = malloc(n + 1);
268 if (!s)
269 return -1;
270
271 n = snprintf_can_msg(s, n + 1, msg);
272 if (n < 0) {
273 int errsv = errno;
274 free(s);
275 errno = errsv;
276 return n;
277 }
278
279 *ps = s;
280 return n;
281}
282
283static uint_least16_t
284can_crc(uint_least16_t crc, const void *ptr, int off, size_t bits)
285{
286 assert(ptr || !bits);
287
288 const uint_least8_t *bp = ptr;
289 bp += off / 8;
290 off %= 8;
291 if (off < 0) {
292 bp--;
293 off += 8;
294 }
295
296 if (off) {
297 int n = MIN((size_t)(8 - off), bits);
298 crc = can_crc_bits(crc, *bp++, off, n);
299 bits -= n;
300 }
301
302 size_t n = bits / 8;
303 crc = can_crc_bytes(crc, bp, n);
304 bp += n;
305 bits -= n * 8;
306
307 if (bits)
308 crc = can_crc_bits(crc, *bp, 0, bits);
309
310 return crc;
311}
312
313static uint_least16_t
314can_crc_bits(uint_least16_t crc, uint_least8_t byte, int off, int bits)
315{
316 assert(off >= 0);
317 assert(bits >= 0);
318 assert(off + bits <= 8);
319
320 for (byte <<= off; bits--; byte <<= 1) {
321 if ((byte ^ (crc >> 7)) & 0x80)
322 crc = (crc << 1) ^ 0x4599;
323 else
324 crc <<= 1;
325 }
326 return crc & 0x7fff;
327}
328
329static uint_least16_t
330can_crc_bytes(uint_least16_t crc, const unsigned char *bp, size_t n)
331{
332 assert(bp || !n);
333
334 // This table contains precomputed CRC-15-CAN checksums for each of the
335 // 256 bytes. The table was computed with the following code:
336 /*
337 uint_least16_t tab[256];
338 for (int n = 0; n < 256; n++) {
339 uint_least16_t crc = n << 7;
340 for (int k = 0; k < 8; k++) {
341 if (crc & 0x4000)
342 crc = (crc << 1) ^ 0x4599;
343 else
344 crc <<= 1;
345 }
346 tab[n] = crc & 0x7fff;
347 }
348 */
349 // clang-format off
350 static const uint_least16_t tab[] = {
351 0x0000, 0x4599, 0x4eab, 0x0b32, 0x58cf, 0x1d56, 0x1664, 0x53fd,
352 0x7407, 0x319e, 0x3aac, 0x7f35, 0x2cc8, 0x6951, 0x6263, 0x27fa,
353 0x2d97, 0x680e, 0x633c, 0x26a5, 0x7558, 0x30c1, 0x3bf3, 0x7e6a,
354 0x5990, 0x1c09, 0x173b, 0x52a2, 0x015f, 0x44c6, 0x4ff4, 0x0a6d,
355 0x5b2e, 0x1eb7, 0x1585, 0x501c, 0x03e1, 0x4678, 0x4d4a, 0x08d3,
356 0x2f29, 0x6ab0, 0x6182, 0x241b, 0x77e6, 0x327f, 0x394d, 0x7cd4,
357 0x76b9, 0x3320, 0x3812, 0x7d8b, 0x2e76, 0x6bef, 0x60dd, 0x2544,
358 0x02be, 0x4727, 0x4c15, 0x098c, 0x5a71, 0x1fe8, 0x14da, 0x5143,
359 0x73c5, 0x365c, 0x3d6e, 0x78f7, 0x2b0a, 0x6e93, 0x65a1, 0x2038,
360 0x07c2, 0x425b, 0x4969, 0x0cf0, 0x5f0d, 0x1a94, 0x11a6, 0x543f,
361 0x5e52, 0x1bcb, 0x10f9, 0x5560, 0x069d, 0x4304, 0x4836, 0x0daf,
362 0x2a55, 0x6fcc, 0x64fe, 0x2167, 0x729a, 0x3703, 0x3c31, 0x79a8,
363 0x28eb, 0x6d72, 0x6640, 0x23d9, 0x7024, 0x35bd, 0x3e8f, 0x7b16,
364 0x5cec, 0x1975, 0x1247, 0x57de, 0x0423, 0x41ba, 0x4a88, 0x0f11,
365 0x057c, 0x40e5, 0x4bd7, 0x0e4e, 0x5db3, 0x182a, 0x1318, 0x5681,
366 0x717b, 0x34e2, 0x3fd0, 0x7a49, 0x29b4, 0x6c2d, 0x671f, 0x2286,
367 0x2213, 0x678a, 0x6cb8, 0x2921, 0x7adc, 0x3f45, 0x3477, 0x71ee,
368 0x5614, 0x138d, 0x18bf, 0x5d26, 0x0edb, 0x4b42, 0x4070, 0x05e9,
369 0x0f84, 0x4a1d, 0x412f, 0x04b6, 0x574b, 0x12d2, 0x19e0, 0x5c79,
370 0x7b83, 0x3e1a, 0x3528, 0x70b1, 0x234c, 0x66d5, 0x6de7, 0x287e,
371 0x793d, 0x3ca4, 0x3796, 0x720f, 0x21f2, 0x646b, 0x6f59, 0x2ac0,
372 0x0d3a, 0x48a3, 0x4391, 0x0608, 0x55f5, 0x106c, 0x1b5e, 0x5ec7,
373 0x54aa, 0x1133, 0x1a01, 0x5f98, 0x0c65, 0x49fc, 0x42ce, 0x0757,
374 0x20ad, 0x6534, 0x6e06, 0x2b9f, 0x7862, 0x3dfb, 0x36c9, 0x7350,
375 0x51d6, 0x144f, 0x1f7d, 0x5ae4, 0x0919, 0x4c80, 0x47b2, 0x022b,
376 0x25d1, 0x6048, 0x6b7a, 0x2ee3, 0x7d1e, 0x3887, 0x33b5, 0x762c,
377 0x7c41, 0x39d8, 0x32ea, 0x7773, 0x248e, 0x6117, 0x6a25, 0x2fbc,
378 0x0846, 0x4ddf, 0x46ed, 0x0374, 0x5089, 0x1510, 0x1e22, 0x5bbb,
379 0x0af8, 0x4f61, 0x4453, 0x01ca, 0x5237, 0x17ae, 0x1c9c, 0x5905,
380 0x7eff, 0x3b66, 0x3054, 0x75cd, 0x2630, 0x63a9, 0x689b, 0x2d02,
381 0x276f, 0x62f6, 0x69c4, 0x2c5d, 0x7fa0, 0x3a39, 0x310b, 0x7492,
382 0x5368, 0x16f1, 0x1dc3, 0x585a, 0x0ba7, 0x4e3e, 0x450c, 0x0095
383 };
384 // clang-format on
385
386 while (n--)
387 crc = (tab[(*bp++ ^ (crc >> 7)) & 0xff] ^ (crc << 8)) & 0x7fff;
388 return crc;
389}
This header file is part of the utilities library; it contains the bit function definitions.
int clz8(uint_least8_t x)
Counts the number of leading zero bits in the unsigned 8-bit integer x.
Definition: bits.h:329
This header file is part of the utilities library; it contains the native and platform-independent er...
@ ERRNUM_INVAL
Invalid argument.
Definition: errnum.h:129
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
Definition: errnum.h:375
This is the public header file of the utilities library.
#define MIN(a, b)
Returns the minimum of a and b.
Definition: util.h:57
int snprintf_can_msg(char *s, size_t n, const struct can_msg *msg)
Prints the contents of a CAN or CAN FD format frame to a string buffer.
Definition: msg.c:198
static uint_least16_t can_crc_bytes(uint_least16_t crc, const unsigned char *bp, size_t n)
Computes a CRC-15-CAN checksum.
Definition: msg.c:330
static uint_least16_t can_crc(uint_least16_t crc, const void *ptr, int off, size_t bits)
Computes a bitwise CRC-15-CAN checksum, based on the 0x4599 generator polynomial.
Definition: msg.c:284
int asprintf_can_msg(char **ps, const struct can_msg *msg)
Equivalent to snprintf_can_msg(), except that it allocates a string large enough to hold the output,...
Definition: msg.c:261
int can_msg_bits(const struct can_msg *msg, enum can_msg_bits_mode mode)
Computes the size (in bits) of the specified CAN format frame on the CAN bus.
Definition: msg.c:62
static uint_least16_t can_crc_bits(uint_least16_t crc, uint_least8_t byte, int off, int bits)
Computes a bitwise CRC-15-CAN checksum of a single byte.
Definition: msg.c:314
This header file is part of the CAN library; it contains the CAN frame declarations.
#define CAN_MASK_EID
The mask used to extract the 29-bit Extended Identifier from a CAN frame.
Definition: msg.h:34
#define CAN_FLAG_RTR
The Remote Transmission Request (RTR) flag (unavailable in CAN FD format frames).
Definition: msg.h:47
#define CAN_MAX_LEN
The maximum number of bytes in the payload of a CAN format frame.
Definition: msg.h:73
#define CAN_FLAG_IDE
The Identifier Extension (IDE) flag.
Definition: msg.h:41
#define CANFD_MAX_LEN
The maximum number of bytes in the payload of a CAN FD format frame.
Definition: msg.h:77
#define CAN_MASK_BID
The mask used to extract the 11-bit Base Identifier from a CAN frame.
Definition: msg.h:31
can_msg_bits_mode
The method used to compute te size (in bits) of a CAN frame.
Definition: msg.h:128
@ CAN_MSG_BITS_MODE_WORST
Simple worst case estimate.
Definition: msg.h:132
@ CAN_MSG_BITS_MODE_EXACT
Exact calculation based of frame content and CRC.
Definition: msg.h:134
@ CAN_MSG_BITS_MODE_NO_STUFF
Simple calculation assuming no bit stuffing.
Definition: msg.h:130
#define CAN_FLAG_EDL
The Extended Data Length (EDL) flag.
Definition: msg.h:55
This is the internal header file of the CAN library.
This header file is part of the C11 and POSIX compatibility library; it includes <stdio....
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib....
A CAN or CAN FD format frame.
Definition: msg.h:88
uint_least8_t data[CAN_MSG_MAX_LEN]
The frame payload (in case of a data frame).
Definition: msg.h:103
uint_least32_t id
The identifier (11 or 29 bits, depending on the CAN_FLAG_IDE flag).
Definition: msg.h:90
uint_least8_t flags
The flags (any combination of CAN_FLAG_IDE, CAN_FLAG_RTR, CAN_FLAG_EDL, CAN_FLAG_BRS and CAN_FLAG_ESI...
Definition: msg.h:95
uint_least8_t len
The number of bytes in data (or the requested number of bytes in case of a remote frame).
Definition: msg.h:101