lib: make parse_canframe CAN XL aware

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
pull/504/head
Oliver Hartkopp 2024-02-27 22:22:24 +01:00
parent 3644a54d5b
commit 34a1cfad29
7 changed files with 164 additions and 71 deletions

View File

@ -306,6 +306,11 @@ int main(int argc, char **argv)
struct sockaddr_can addr = {
.can_family = AF_CAN,
};
struct can_raw_vcid_options vcid_opts = {
.flags = CAN_RAW_XL_VCID_RX_FILTER,
.rx_vcid = 0,
.rx_vcid_mask = 0,
};
char ctrlmsg[CMSG_SPACE(sizeof(struct timeval)) +
CMSG_SPACE(3 * sizeof(struct timespec)) +
CMSG_SPACE(sizeof(__u32))];
@ -601,6 +606,9 @@ int main(int argc, char **argv)
/* try to switch the socket into CAN XL mode */
setsockopt(obj->s, SOL_CAN_RAW, CAN_RAW_XL_FRAMES, &canfx_on, sizeof(canfx_on));
/* try to enable the CAN XL VCID pass through mode */
setsockopt(obj->s, SOL_CAN_RAW, CAN_RAW_XL_VCID_OPTS, &vcid_opts, sizeof(vcid_opts));
if (rcvbuf_size) {
int curr_rcvbuf_size;
socklen_t curr_rcvbuf_size_len = sizeof(curr_rcvbuf_size);

View File

@ -71,7 +71,7 @@ struct assignment {
char rxif[IFNAMSIZ];
};
static struct assignment asgn[CHANNELS];
const int canfd_on = 1;
const int canfx_on = 1;
extern int optind, opterr, optopt;
@ -239,9 +239,12 @@ int add_assignment(char *mode, int socket, char *txname, char *rxname, int verbo
int main(int argc, char **argv)
{
static char buf[BUFSZ], device[BUFSZ], ascframe[BUFSZ];
static char buf[BUFSZ], device[BUFSZ], ascframe[10000];
struct sockaddr_can addr;
static struct canfd_frame frame;
struct can_raw_vcid_options vcid_opts = {
.flags = CAN_RAW_XL_VCID_TX_PASS,
};
static cu_t cu;
static struct timeval today_tv, log_tv, last_log_tv, diff_tv;
struct timespec sleep_ts;
int s; /* CAN_RAW socket */
@ -360,7 +363,13 @@ int main(int argc, char **argv)
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
/* try to switch the socket into CAN FD mode */
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on));
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfx_on, sizeof(canfx_on));
/* try to switch the socket into CAN XL mode */
setsockopt(s, SOL_CAN_RAW, CAN_RAW_XL_FRAMES, &canfx_on, sizeof(canfx_on));
/* try to enable the CAN XL VCID pass through mode */
setsockopt(s, SOL_CAN_RAW, CAN_RAW_XL_VCID_OPTS, &vcid_opts, sizeof(vcid_opts));
if (loopback_disable) {
int loopback = 0;
@ -470,26 +479,28 @@ int main(int argc, char **argv)
} else if (txidx > 0) { /* only send to valid CAN devices */
txmtu = parse_canframe(ascframe, &frame); /* dual-use frame */
txmtu = parse_canframe(ascframe, &cu); /* dual-use frame */
if (!txmtu) {
fprintf(stderr, "wrong CAN frame format: '%s'!", ascframe);
return 1;
}
/* CAN XL frames need real frame length for sending */
if (txmtu == CANXL_MTU)
txmtu = CANXL_HDR_SIZE + cu.xl.len;
addr.can_family = AF_CAN;
addr.can_ifindex = txidx; /* send via this interface */
if (sendto(s, &frame, txmtu, 0, (struct sockaddr *)&addr, sizeof(addr)) != txmtu) {
if (sendto(s, &cu, txmtu, 0, (struct sockaddr *)&addr, sizeof(addr)) != txmtu) {
perror("sendto");
return 1;
}
if (verbose) {
static char abuf[10000]; /* ASCII buf FIXME - use calculated value */
printf("%s (%s) ", get_txname(device), device);
sprint_long_canframe(abuf, (cu_t *)&frame, CANLIB_VIEW_INDENT_SFF);
printf("%s\n", abuf);
sprint_long_canframe(ascframe, &cu, CANLIB_VIEW_INDENT_SFF);
printf("%s\n", ascframe);
}
if (count && (--count == 0))

View File

@ -92,9 +92,12 @@ int main(int argc, char **argv)
int s; /* can raw socket */
int required_mtu;
int mtu;
int enable_canfd = 1;
int enable_canfx = 1;
struct sockaddr_can addr;
struct canfd_frame frame;
struct can_raw_vcid_options vcid_opts = {
.flags = CAN_RAW_XL_VCID_TX_PASS,
};
static cu_t cu;
struct ifreq ifr;
/* check command line options */
@ -104,7 +107,7 @@ int main(int argc, char **argv)
}
/* parse CAN frame */
required_mtu = parse_canframe(argv[2], &frame);
required_mtu = parse_canframe(argv[2], &cu);
if (!required_mtu) {
fprintf(stderr, "\nWrong CAN-frame format!\n\n");
print_usage(argv[0]);
@ -137,22 +140,39 @@ int main(int argc, char **argv)
}
mtu = ifr.ifr_mtu;
if (mtu != CANFD_MTU && mtu != CANXL_MTU) {
printf("CAN interface is only Classical CAN capable - sorry.\n");
return 1;
if (mtu == CANFD_MTU) {
/* interface is ok - try to switch the socket into CAN FD mode */
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES,
&enable_canfx, sizeof(enable_canfx))){
printf("error when enabling CAN FD support\n");
return 1;
}
}
/* interface is ok - try to switch the socket into CAN FD mode */
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES,
&enable_canfd, sizeof(enable_canfd))){
printf("error when enabling CAN FD support\n");
return 1;
if (mtu >= CANXL_MIN_MTU) {
/* interface is ok - try to switch the socket into CAN XL mode */
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_XL_FRAMES,
&enable_canfx, sizeof(enable_canfx))){
printf("error when enabling CAN XL support\n");
return 1;
}
/* try to enable the CAN XL VCID pass through mode */
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_XL_VCID_OPTS,
&vcid_opts, sizeof(vcid_opts))) {
printf("error when enabling CAN XL VCID pass through\n");
return 1;
}
}
/* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 */
frame.len = can_fd_dlc2len(can_fd_len2dlc(frame.len));
}
/* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 */
if (required_mtu == CANFD_MTU)
cu.fd.len = can_fd_dlc2len(can_fd_len2dlc(cu.fd.len));
/* CAN XL frames need real frame length for sending */
if (required_mtu == CANXL_MTU)
required_mtu = CANXL_HDR_SIZE + cu.xl.len;
/*
* disable default receive filter on this RAW socket This is
* obsolete as we do not read from the socket at all, but for
@ -167,7 +187,7 @@ int main(int argc, char **argv)
}
/* send frame */
if (write(s, &frame, required_mtu) != required_mtu) {
if (write(s, &cu, required_mtu) != required_mtu) {
perror("write");
return 1;
}

110
lib.c
View File

@ -55,6 +55,7 @@
#define CANID_DELIM '#'
#define CC_DLC_DELIM '_'
#define XL_HDR_DELIM ':'
#define DATA_SEPERATOR '.'
const char hex_asc_upper[] = "0123456789ABCDEF";
@ -153,78 +154,128 @@ int hexstring2data(char *arg, unsigned char *data, int maxdlen)
return 0;
}
int parse_canframe(char *cs, struct canfd_frame *cf)
int parse_canframe(char *cs, cu_t *cu)
{
/* documentation see lib.h */
int i, idx, dlen, len;
int maxdlen = CAN_MAX_DLEN;
int ret = CAN_MTU;
int mtu = CAN_MTU;
__u8 *data = cu->fd.data; /* fill CAN CC/FD data by default */
canid_t tmp;
len = strlen(cs);
//printf("'%s' len %d\n", cs, len);
memset(cf, 0, sizeof(*cf)); /* init CAN FD frame, e.g. LEN = 0 */
memset(cu, 0, sizeof(*cu)); /* init CAN CC/FD/XL frame, e.g. LEN = 0 */
if (len < 4)
return 0;
if (cs[3] == CANID_DELIM) { /* 3 digits */
if (cs[3] == CANID_DELIM) { /* 3 digits SFF */
idx = 4;
for (i = 0; i < 3; i++) {
if ((tmp = asc2nibble(cs[i])) > 0x0F)
return 0;
cf->can_id |= (tmp << (2 - i) * 4);
cu->cc.can_id |= (tmp << (2 - i) * 4);
}
} else if (cs[8] == CANID_DELIM) { /* 8 digits */
} else if (cs[5] == CANID_DELIM) { /* 5 digits CAN XL VCID/PRIO*/
idx = 6;
for (i = 0; i < 5; i++) {
if ((tmp = asc2nibble(cs[i])) > 0x0F)
return 0;
cu->xl.prio |= (tmp << (4 - i) * 4);
}
/* the VCID starts at bit position 16 */
tmp = (cu->xl.prio << 4) & CANXL_VCID_MASK;
cu->xl.prio &= CANXL_PRIO_MASK;
cu->xl.prio |= tmp;
} else if (cs[8] == CANID_DELIM) { /* 8 digits EFF */
idx = 9;
for (i = 0; i < 8; i++) {
if ((tmp = asc2nibble(cs[i])) > 0x0F)
return 0;
cf->can_id |= (tmp << (7 - i) * 4);
cu->cc.can_id |= (tmp << (7 - i) * 4);
}
if (!(cf->can_id & CAN_ERR_FLAG)) /* 8 digits but no errorframe? */
cf->can_id |= CAN_EFF_FLAG; /* then it is an extended frame */
if (!(cu->cc.can_id & CAN_ERR_FLAG)) /* 8 digits but no errorframe? */
cu->cc.can_id |= CAN_EFF_FLAG; /* then it is an extended frame */
} else
return 0;
if ((cs[idx] == 'R') || (cs[idx] == 'r')) { /* RTR frame */
cf->can_id |= CAN_RTR_FLAG;
cu->cc.can_id |= CAN_RTR_FLAG;
/* check for optional DLC value for CAN 2.0B frames */
if (cs[++idx] && (tmp = asc2nibble(cs[idx++])) <= CAN_MAX_DLEN) {
cf->len = tmp;
cu->cc.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;
}
if ((tmp > CAN_MAX_DLEN) && (tmp <= CAN_MAX_RAW_DLC))
cu->cc.len8_dlc = tmp;
}
}
return ret;
return mtu;
}
if (cs[idx] == CANID_DELIM) { /* CAN FD frame escape char '##' */
maxdlen = CANFD_MAX_DLEN;
ret = CANFD_MTU;
mtu = CANFD_MTU;
/* CAN FD frame <canid>##<flags><data>* */
if ((tmp = asc2nibble(cs[idx + 1])) > 0x0F)
return 0;
cf->flags = tmp;
cf->flags |= CANFD_FDF; /* dual-use */
cu->fd.flags = tmp;
cu->fd.flags |= CANFD_FDF; /* dual-use */
idx += 2;
} else if (cs[idx + 14] == CANID_DELIM) { /* CAN XL frame '#80:00:11223344#' */
maxdlen = CANXL_MAX_DLEN;
mtu = CANXL_MTU;
data = cu->xl.data; /* fill CAN XL data */
if ((cs[idx + 2] != XL_HDR_DELIM) || (cs[idx + 5] != XL_HDR_DELIM))
return 0;
if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
return 0;
cu->xl.flags = (tmp << 4);
if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
return 0;
cu->xl.flags |= tmp;
/* force CAN XL flag if it was missing in the ASCII string */
cu->xl.flags |= CANXL_XLF;
idx++; /* skip XL_HDR_DELIM */
if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
return 0;
cu->xl.sdt = (tmp << 4);
if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
return 0;
cu->xl.sdt |= tmp;
idx++; /* skip XL_HDR_DELIM */
for (i = 0; i < 8; i++) {
if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
return 0;
cu->xl.af |= (tmp << (7 - i) * 4);
}
idx++; /* skip CANID_DELIM */
}
for (i = 0, dlen = 0; i < maxdlen; i++) {
@ -236,26 +287,27 @@ int parse_canframe(char *cs, struct canfd_frame *cf)
if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
return 0;
cf->data[i] = (tmp << 4);
data[i] = (tmp << 4);
if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
return 0;
cf->data[i] |= tmp;
data[i] |= tmp;
dlen++;
}
cf->len = dlen;
if (mtu == CANXL_MTU)
cu->xl.len = dlen;
else
cu->fd.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;
}
if ((dlc > CAN_MAX_DLEN) && (dlc <= CAN_MAX_RAW_DLC))
cu->cc.len8_dlc = dlc;
}
return ret;
return mtu;
}
int sprint_canframe(char *buf, cu_t *cu, int sep)

3
lib.h
View File

@ -111,8 +111,7 @@ int hexstring2data(char *arg, unsigned char *data, int maxdlen);
*
*/
struct canfd_frame;
int parse_canframe(char *cs, struct canfd_frame *cf);
int parse_canframe(char *cs, cu_t *cu);
/*
* Transfers a valid ASCII string describing a CAN frame into struct canfd_frame.
*

View File

@ -183,9 +183,9 @@ void canfd_asc(struct canfd_frame *cf, int devno, int mtu, char *extra_info, FIL
int main(int argc, char **argv)
{
static char buf[BUFSZ], device[BUFSZ], ascframe[BUFSZ], extra_info[BUFSZ];
static char buf[BUFSZ], device[BUFSZ], ascframe[10000], extra_info[BUFSZ];
struct canfd_frame cf;
static cu_t cu;
static struct timeval tv, start_tv;
FILE *infile = stdin;
FILE *outfile = stdout;
@ -286,20 +286,23 @@ int main(int argc, char **argv)
(crlf)?"\r\n":"\n");
}
for (i=0, devno=0; i<maxdev; i++) {
for (i = 0, devno = 0; i < maxdev; i++) {
if (!strcmp(device, argv[optind+i])) {
devno = i+1; /* start with channel '1' */
devno = i + 1; /* start with channel '1' */
break;
}
}
if (devno) { /* only convert for selected CAN devices */
mtu = parse_canframe(ascframe, &cf);
mtu = parse_canframe(ascframe, &cu);
/* convert only CAN CC and CAN FD frames */
if ((mtu != CAN_MTU) && (mtu != CANFD_MTU))
return 1;
/* we don't support error message frames in CAN FD */
if ((mtu == CANFD_MTU) && (cf.can_id & CAN_ERR_FLAG))
if ((mtu == CANFD_MTU) && (cu.cc.can_id & CAN_ERR_FLAG))
continue;
tv.tv_sec = tv.tv_sec - start_tv.tv_sec;
@ -315,9 +318,9 @@ int main(int argc, char **argv)
fprintf(outfile, "%4llu.%06llu ", (unsigned long long)tv.tv_sec, (unsigned long long)tv.tv_usec);
if ((mtu == CAN_MTU) && (fdfmt == 0))
can_asc(&cf, devno, nortrdlc, extra_info, outfile);
can_asc(&cu.fd, devno, nortrdlc, extra_info, outfile);
else
canfd_asc(&cf, devno, mtu, extra_info, outfile);
canfd_asc(&cu.fd, devno, mtu, extra_info, outfile);
if (crlf)
fprintf(outfile, "\r");

View File

@ -55,27 +55,27 @@
int main(void)
{
char buf[BUFSZ], timestamp[BUFSZ], device[BUFSZ], ascframe[BUFSZ];
struct canfd_frame cf;
static cu_t cu;
int mtu;
while (fgets(buf, BUFSZ-1, stdin)) {
if (sscanf(buf, "%s %s %s", timestamp, device, ascframe) != 3)
return 1;
mtu = parse_canframe(ascframe, &cf);
mtu = parse_canframe(ascframe, &cu);
/* mark dual-use struct canfd_frame */
/* mark dual-use struct canfd_frame - no CAN_XL support */
if (mtu == CAN_MTU)
cf.flags = 0;
cu.fd.flags = 0;
else if (mtu == CANFD_MTU)
cf.flags |= CANFD_FDF;
cu.fd.flags |= CANFD_FDF;
else {
fprintf(stderr, "read: incomplete CAN frame\n");
fprintf(stderr, "read: no valid CAN CC/FD frame\n");
return 1;
}
/* with ASCII output */
sprint_long_canframe(ascframe, (cu_t *)&cf,
sprint_long_canframe(ascframe, &cu,
(CANLIB_VIEW_INDENT_SFF | CANLIB_VIEW_ASCII));
printf("%s %s %s\n", timestamp, device, ascframe);