On 21.07.22 05:13, Vincent Mailhol wrote:
On Thu. 21 juil. 2022 at 11:37, Vincent Mailhol
<vincent.mailhol@xxxxxxxxx> wrote:
On Wed. 21 Jul. 2022 at 01:43, Oliver Hartkopp <socketcan@xxxxxxxxxxxx> wrote:
And even the user space side to handle a mix of CAN frame types is
pretty simple IMO:
union {
struct can_frame cc;
struct canfd_frame fd;
struct canxl_frame xl;
} can;
Do you want to add this union in the kernel uapi or is it just a
userland example?
More brainstorming. If we want to introduce a generic can structure in
linux/can.h, we could do:
struct canxl_frame {
canid_t prio; /* 11 bit priority for arbitration (canid_t) */
__u8 xl_flags; /* additional flags for CAN XL */
__u8 fd_flags; /* CAN(-FD) flags */
__u16 len; /* frame payload length in byte */
__u32 af; /* acceptance field */
__u8 sdt; /* SDU (service data unit) type */
__u8 __res0; /* reserved / padding */
__u8 __res1; /* reserved / padding */
__u8 __res2; /* reserved / padding */
__u8 data[CANXL_MAX_DLEN] __attribute__((aligned(8)));
};
union can_generic_frame {
struct {
union {
canid_t can_id;
canid_t prio;
};
union {
__u16 type;
struct {
__u8 xl_flags;
__u8 fd_flags;
} __attribute__((packed));
} __attribute__((packed));
};
struct can_frame cc;
struct canfd_frame fd;
struct canxl_frame xl;
};
#define CANXL_XLF 0x80 /* apply to canxl_frame::xl_flags */
#define CAN_TYPE_CC 0
#ifdef __LITTLE_ENDIAN
#define CAN_TYPE_FD (CANFD_FDF << 8)
#define CAN_TYPE_XL (CANXL_XLF)
#else /* __BIG_ENDIAN */
#define CAN_TYPE_FD (CANFD_FDF)
#define CAN_TYPE_XL (CANXL_XLF << 8)
#endif
#define CAN_TYPE_MASK (CAN_TYPE_FD | CAN_TYPE_XL)
Because can_generic_frame::type overlaps with the can(fd)_frame::len,
it will contain garbage and thus it is necessary to mask it with
CAN_TYPE_MASK.
The CANFD_FDF is only set in the rx path. In the tx path it is simply
ignored. This done, we can use it as below when *receiving* can
frames:
No problem to set CANFD_FDF in raw_sendmsg() when we process a CAN FD
frame in the tx path ...
int foo()
{
union can_generic_frame can;
/* receive a frame */
switch (can.type & CAN_TYPE_MASK) {
case CAN_TYPE_CC:
printf("Received classical CAN Frame\n");
break;
case CAN_TYPE_FD:
printf("Received CAN FD Frame\n");
break;
case CAN_TYPE_XL:
printf("Received CAN XL Frame\n");
break;
default:
fprintf(stderr, "Unknown type: %x\n", can.type & CAN_TYPE_MASK);
}
return EXIT_SUCCESS;
}
If you just want to get rid of the nbytes checking and we make sure
CANFD_FDF is properly set in the future we are not far from such an easy
check - even without moving the sdt element or endian magic:
if (can.xl_flags & CANXL_XLF) {
printf("Received CAN XL Frame\n");
} else if (can.fd_flags & CANFD_FDF) {
printf("Received CAN FD Frame\n");
} else {
printf("Received classical CAN Frame\n");
}
Regards,
Oliver