can-utils: add support for Classic CAN raw DLC values
ISO 11898-1 Chapter 8.4.2.3 defines a 4 bit data length code (DLC) table which
maps the DLC to the payload length of the CAN frame in bytes:
DLC -> payload length
0 .. 8 -> 0 .. 8
9 .. 15 -> 8
Although the DLC values 8 .. 15 in Classical CAN always result in a payload
length of 8 bytes these DLC values are transparently transmitted on the CAN
bus.
To access the raw DLC values 9 .. 15 the len8_dlc element is introduced, which
is only valid when the payload length 'len' is 8 and the DLC is greater than 8.
The extension for len8_dlc has been implemented for the Classic CAN frame
representation in the log file format and analogue for cansend.
cangen can now randomly generate Classic CAN DLC values from 0 .. 15.
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
pull/260/head
parent
1845141208
commit
5960c19e6c
8
cangen.c
8
cangen.c
|
|
@ -413,8 +413,14 @@ int main(int argc, char **argv)
|
|||
frame.len = can_dlc2len(random() & 0xF);
|
||||
else {
|
||||
frame.len = random() & 0xF;
|
||||
if (frame.len & 8)
|
||||
|
||||
/* generate Classic CAN len8 DLCs */
|
||||
if (frame.len > CAN_MAX_DLEN) {
|
||||
struct can_frame *ccf = (struct can_frame *)&frame;
|
||||
|
||||
ccf->len8_dlc = frame.len;
|
||||
frame.len = 8; /* for about 50% of the frames */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
10
cansend.c
10
cansend.c
|
|
@ -61,8 +61,10 @@ void print_usage(char *prg)
|
|||
fprintf(stderr, "%s - send CAN-frames via CAN_RAW sockets.\n", prg);
|
||||
fprintf(stderr, "\nUsage: %s <device> <can_frame>.\n", prg);
|
||||
fprintf(stderr, "\n<can_frame>:\n");
|
||||
fprintf(stderr, " <can_id>#{data} for 'classic' CAN 2.0 data frames\n");
|
||||
fprintf(stderr, " <can_id>#R{len} for 'classic' CAN 2.0 data frames\n");
|
||||
fprintf(stderr, " <can_id>#{data} for Classical CAN 2.0 data frames\n");
|
||||
fprintf(stderr, " <can_id>#R{len} for Classical CAN 2.0 data frames\n");
|
||||
fprintf(stderr, " <can_id>#{data}_{dlc} for Classical CAN 2.0 data frames\n");
|
||||
fprintf(stderr, " <can_id>#R{len}_{dlc} for Classical CAN 2.0 data frames\n");
|
||||
fprintf(stderr, " <can_id>##<flags>{data} for CAN FD frames\n\n");
|
||||
fprintf(stderr, "<can_id>:\n"
|
||||
" 3 (SFF) or 8 (EFF) hex chars\n");
|
||||
|
|
@ -70,11 +72,13 @@ void print_usage(char *prg)
|
|||
" 0..8 (0..64 CAN FD) ASCII hex-values (optionally separated by '.')\n");
|
||||
fprintf(stderr, "{len}:\n"
|
||||
" an optional 0..8 value as RTR frames can contain a valid dlc field\n");
|
||||
fprintf(stderr, "_{dlc}:\n"
|
||||
" an optional 9..F data length code value when payload length is 8\n");
|
||||
fprintf(stderr, "<flags>:\n"
|
||||
" a single ASCII Hex value (0 .. F) which defines canfd_frame.flags\n\n");
|
||||
fprintf(stderr, "Examples:\n");
|
||||
fprintf(stderr, " 5A1#11.2233.44556677.88 / 123#DEADBEEF / 5AA# / 123##1 / 213##311223344 /\n"
|
||||
" 1F334455#1122334455667788 / 123#R / 00000123#R3\n\n");
|
||||
" 1F334455#1122334455667788_B / 123#R / 00000123#R3 / 333#R8_E\n\n");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
48
lib.c
48
lib.c
|
|
@ -53,6 +53,7 @@
|
|||
#include "lib.h"
|
||||
|
||||
#define CANID_DELIM '#'
|
||||
#define CC_DLC_DELIM '_'
|
||||
#define DATA_SEPERATOR '.'
|
||||
|
||||
const char hex_asc_upper[] = "0123456789ABCDEF";
|
||||
|
|
@ -195,9 +196,19 @@ int parse_canframe(char *cs, struct canfd_frame *cf) {
|
|||
cf->can_id |= CAN_RTR_FLAG;
|
||||
|
||||
/* check for optional DLC value for CAN 2.0B frames */
|
||||
if(cs[++idx] && (tmp = asc2nibble(cs[idx])) <= CAN_MAX_DLC)
|
||||
if(cs[++idx] && (tmp = asc2nibble(cs[idx++])) <= CAN_MAX_DLEN) {
|
||||
cf->len = tmp;
|
||||
|
||||
/* check for optional raw DLC value for CAN 2.0B frames */
|
||||
if ((tmp == CAN_MAX_DLEN) && (cs[idx++] == CC_DLC_DELIM)) {
|
||||
tmp = asc2nibble(cs[idx]);
|
||||
if ((tmp > CAN_MAX_DLEN) && (tmp <= CAN_MAX_RAW_DLC)) {
|
||||
struct can_frame *ccf = (struct can_frame *)cf;
|
||||
|
||||
ccf->len8_dlc = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -232,6 +243,17 @@ int parse_canframe(char *cs, struct canfd_frame *cf) {
|
|||
}
|
||||
cf->len = dlen;
|
||||
|
||||
/* check for extra DLC when having a Classic CAN with 8 bytes payload */
|
||||
if ((maxdlen == CAN_MAX_DLEN) && (dlen == CAN_MAX_DLEN) && (cs[idx++] == CC_DLC_DELIM)) {
|
||||
unsigned char dlc = asc2nibble(cs[idx]);
|
||||
|
||||
if ((dlc > CAN_MAX_DLEN) && (dlc <= CAN_MAX_RAW_DLC)) {
|
||||
struct can_frame *ccf = (struct can_frame *)cf;
|
||||
|
||||
ccf->len8_dlc = dlc;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -270,9 +292,20 @@ void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen) {
|
|||
if (maxdlen == CAN_MAX_DLEN && cf->can_id & CAN_RTR_FLAG) {
|
||||
buf[offset++] = 'R';
|
||||
/* print a given CAN 2.0B DLC if it's not zero */
|
||||
if (cf->len && cf->len <= CAN_MAX_DLC)
|
||||
if (cf->len && cf->len <= CAN_MAX_DLEN) {
|
||||
buf[offset++] = hex_asc_upper_lo(cf->len);
|
||||
|
||||
/* check for optional raw DLC value for CAN 2.0B frames */
|
||||
if (cf->len == CAN_MAX_DLEN) {
|
||||
struct can_frame *ccf = (struct can_frame *)cf;
|
||||
|
||||
if ((ccf->len8_dlc > CAN_MAX_DLEN) && (ccf->len8_dlc <= CAN_MAX_RAW_DLC)) {
|
||||
buf[offset++] = CC_DLC_DELIM;
|
||||
buf[offset++] = hex_asc_upper_lo(ccf->len8_dlc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buf[offset] = 0;
|
||||
return;
|
||||
}
|
||||
|
|
@ -292,6 +325,17 @@ void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen) {
|
|||
buf[offset++] = '.';
|
||||
}
|
||||
|
||||
/* check for extra DLC when having a Classic CAN with 8 bytes payload */
|
||||
if ((maxdlen == CAN_MAX_DLEN) && (len == CAN_MAX_DLEN)) {
|
||||
struct can_frame *ccf = (struct can_frame *)cf;
|
||||
unsigned char dlc = ccf->len8_dlc;
|
||||
|
||||
if ((dlc > CAN_MAX_DLEN) && (dlc <= CAN_MAX_RAW_DLC)) {
|
||||
buf[offset++] = CC_DLC_DELIM;
|
||||
buf[offset++] = hex_asc_upper_lo(dlc);
|
||||
}
|
||||
}
|
||||
|
||||
buf[offset] = 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
12
lib.h
12
lib.h
|
|
@ -99,10 +99,11 @@ int parse_canframe(char *cs, struct canfd_frame *cf);
|
|||
/*
|
||||
* Transfers a valid ASCII string describing a CAN frame into struct canfd_frame.
|
||||
*
|
||||
* CAN 2.0 frames
|
||||
* - string layout <can_id>#{R{len}|data}
|
||||
* CAN 2.0 frames (aka Classical CAN)
|
||||
* - string layout <can_id>#{R{len}|data}{_len8_dlc}
|
||||
* - {data} has 0 to 8 hex-values that can (optionally) be separated by '.'
|
||||
* - {len} can take values from 0 to 8 and can be omitted if zero
|
||||
* - {_len8_dlc} can take hex values from '_9' to '_F' when len is CAN_MAX_DLEN
|
||||
* - return value on successful parsing: CAN_MTU
|
||||
*
|
||||
* CAN FD frames
|
||||
|
|
@ -124,10 +125,12 @@ int parse_canframe(char *cs, struct canfd_frame *cf);
|
|||
* 123#R -> standard CAN-Id = 0x123, len = 0, RTR-frame
|
||||
* 123#R0 -> standard CAN-Id = 0x123, len = 0, RTR-frame
|
||||
* 123#R7 -> standard CAN-Id = 0x123, len = 7, RTR-frame
|
||||
* 123#R8_9 -> standard CAN-Id = 0x123, len = 8, dlc = 9, RTR-frame
|
||||
* 7A1#r -> standard CAN-Id = 0x7A1, len = 0, RTR-frame
|
||||
*
|
||||
* 123#00 -> standard CAN-Id = 0x123, len = 1, data[0] = 0x00
|
||||
* 123#1122334455667788 -> standard CAN-Id = 0x123, len = 8
|
||||
* 123#1122334455667788_E -> standard CAN-Id = 0x123, len = 8, dlc = 14
|
||||
* 123#11.22.33.44.55.66.77.88 -> standard CAN-Id = 0x123, len = 8
|
||||
* 123#11.2233.44556677.88 -> standard CAN-Id = 0x123, len = 8
|
||||
* 32345678#112233 -> error frame with CAN_ERR_FLAG (0x2000000) set
|
||||
|
|
@ -155,10 +158,11 @@ void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen);
|
|||
* The CAN data[] is separated by '.' when sep != 0.
|
||||
*
|
||||
* The type of the CAN frame (CAN 2.0 / CAN FD) is specified by maxdlen:
|
||||
* maxdlen = 8 -> CAN2.0 frame
|
||||
* maxdlen = 8 -> CAN2.0 frame (aka Classical CAN)
|
||||
* maxdlen = 64 -> CAN FD frame
|
||||
*
|
||||
* 12345678#112233 -> extended CAN-Id = 0x12345678, len = 3, data, sep = 0
|
||||
* 123#1122334455667788_E -> standard CAN-Id = 0x123, len = 8, dlc = 14, data, sep = 0
|
||||
* 12345678#R -> extended CAN-Id = 0x12345678, RTR, len = 0
|
||||
* 12345678#R5 -> extended CAN-Id = 0x12345678, RTR, len = 5
|
||||
* 123#11.22.33.44.55.66.77.88 -> standard CAN-Id = 0x123, dlc = 8, sep = 1
|
||||
|
|
@ -187,7 +191,7 @@ void sprint_long_canframe(char *buf , struct canfd_frame *cf, int view, int maxd
|
|||
* Creates a CAN frame hexadecimal output in user readable format.
|
||||
*
|
||||
* The type of the CAN frame (CAN 2.0 / CAN FD) is specified by maxdlen:
|
||||
* maxdlen = 8 -> CAN2.0 frame
|
||||
* maxdlen = 8 -> CAN2.0 frame (aka Classical CAN)
|
||||
* maxdlen = 64 -> CAN FD frame
|
||||
*
|
||||
* 12345678 [3] 11 22 33 -> extended CAN-Id = 0x12345678, dlc = 3, data
|
||||
|
|
|
|||
Loading…
Reference in New Issue