This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 6cdd3eaf46e drivers/can: Use 8 data bytes for classic messages with 
DLC 9..15.
6cdd3eaf46e is described below

commit 6cdd3eaf46e79484770fe30bb3c181fed1943968
Author: raiden00pl <[email protected]>
AuthorDate: Fri Oct 23 09:18:18 2026 +0200

    drivers/can: Use 8 data bytes for classic messages with DLC 9..15.
    
    The character driver took the data length of every message from
    can_dlc2bytes(), which with CONFIG_CAN_FD gives 12..64 bytes for DLC
    9..15, also for classic frames.  write() of such a classic message with
    its 8 data bytes then returned 0 without sending it, and can_receive()
    copied up to 64 bytes from the 8-byte data of a classic lower half.
    Use the CAN FD length only when ch_edl is set and 8 bytes otherwise;
    the DLC itself is kept.  ctucanfd_pci, kvaser_pci and sim_canchar copy
    8 bytes for these frames too.
    
    Assisted-by: Claude:claude-opus-5-5
    Signed-off-by: raiden00pl <[email protected]>
---
 arch/sim/src/sim/sim_canchar.c |  5 ++++-
 drivers/can/can.c              | 41 ++++++++++++++++++++++++++++-------------
 drivers/can/ctucanfd_pci.c     | 15 ++++++++++++++-
 drivers/can/kvaser_pci.c       | 22 ++++++++++++++--------
 4 files changed, 60 insertions(+), 23 deletions(-)

diff --git a/arch/sim/src/sim/sim_canchar.c b/arch/sim/src/sim/sim_canchar.c
index 49c574c7ecd..a3c50552750 100644
--- a/arch/sim/src/sim/sim_canchar.c
+++ b/arch/sim/src/sim/sim_canchar.c
@@ -26,6 +26,7 @@
 
 #include <nuttx/debug.h>
 #include <stdio.h>
+#include <sys/param.h>
 #include <time.h>
 
 #include <nuttx/clock.h>
@@ -226,8 +227,10 @@ static int sim_can_send(struct can_dev_s *dev, struct 
can_msg_s *msg)
     {
       struct can_frame frame;
 
+      /* DLC 9..15 of a classic frame means 8 data bytes */
+
       frame.can_id  = msg->cm_hdr.ch_id;
-      frame.can_dlc = msg->cm_hdr.ch_dlc;
+      frame.can_dlc = MIN(msg->cm_hdr.ch_dlc, CAN_MAX_DLEN);
 
       if (msg->cm_hdr.ch_rtr)
         {
diff --git a/drivers/can/can.c b/drivers/can/can.c
index d01647dcac0..887318bd440 100644
--- a/drivers/can/can.c
+++ b/drivers/can/can.c
@@ -44,6 +44,7 @@
 #include <nuttx/clock.h>
 #include <nuttx/signal.h>
 #include <nuttx/fs/fs.h>
+#include <nuttx/can.h>
 #include <nuttx/can/can.h>
 #include <nuttx/can/can_sender.h>
 #include <nuttx/kmalloc.h>
@@ -120,6 +121,7 @@ static int            can_ioctl(FAR struct file *filep, int 
cmd,
 static int            can_poll(FAR struct file *filep,
                                FAR struct pollfd *fds,
                                bool setup);
+static int            can_datalen(FAR const struct can_hdr_s *hdr);
 
 /****************************************************************************
  * Private Data
@@ -142,6 +144,27 @@ static const struct file_operations g_canops =
  * Private Functions
  ****************************************************************************/
 
+/****************************************************************************
+ * Name: can_datalen
+ *
+ * Description:
+ *   Return the number of data bytes of a CAN message.  The DLC codes 9..15
+ *   mean 12..64 bytes in a CAN FD frame but 8 bytes in a classic frame.
+ *
+ ****************************************************************************/
+
+static int can_datalen(FAR const struct can_hdr_s *hdr)
+{
+#ifdef CONFIG_CAN_FD
+  if (hdr->ch_edl)
+    {
+      return can_dlc2bytes(hdr->ch_dlc);
+    }
+#endif
+
+  return MIN(hdr->ch_dlc, CAN_MAX_DLEN);
+}
+
 /****************************************************************************
  * Name: can_txready_work
  *
@@ -513,7 +536,7 @@ static ssize_t can_read(FAR struct file *filep, FAR char 
*buffer,
           /* Will the next message in the FIFO fit into the user buffer? */
 
           FAR struct can_msg_s *msg = &fifo->rx_buffer[fifo->rx_head];
-          int nbytes = can_dlc2bytes(msg->cm_hdr.ch_dlc);
+          int nbytes = can_datalen(&msg->cm_hdr);
           int msglen = CAN_MSGLEN(nbytes);
 
           if (ret + msglen > buflen)
@@ -806,7 +829,7 @@ static ssize_t can_write(FAR struct file *filep, FAR const 
char *buffer,
         }
       else
         {
-          nbytes = can_dlc2bytes(msg->cm_hdr.ch_dlc);
+          nbytes = can_datalen(&msg->cm_hdr);
         }
 
       msglen = CAN_MSGLEN(nbytes);
@@ -1379,7 +1402,7 @@ int can_receive(FAR struct can_dev_s *dev, FAR struct 
can_hdr_s *hdr,
 
               memcpy(&waitmsg->cm_hdr, hdr, sizeof(struct can_hdr_s));
 
-              nbytes = can_dlc2bytes(hdr->ch_dlc);
+              nbytes = can_datalen(hdr);
               if (nbytes)
                 {
                   memcpy(waitmsg->cm_data, data, nbytes);
@@ -1413,20 +1436,12 @@ int can_receive(FAR struct can_dev_s *dev, FAR struct 
can_hdr_s *hdr,
         {
           int nbytes;
 
-          /* Add the new, decoded CAN message at the tail of the FIFO.
-           *
-           * REVISIT:  In the CAN FD format, the coding of the DLC differs
-           * from the standard CAN format. The DLC codes 0 to 8 have the
-           * same coding as in standard CAN, the codes 9 to 15, which in
-           * standard CAN all code a data field of 8 bytes, are encoded:
-           *
-           *   9->12, 10->16, 11->20, 12->24, 13->32, 14->48, 15->64
-           */
+          /* Add the new, decoded CAN message at the tail of the FIFO */
 
           memcpy(&fifo->rx_buffer[fifo->rx_tail].cm_hdr, hdr,
                  sizeof(struct can_hdr_s));
 
-          nbytes = can_dlc2bytes(hdr->ch_dlc);
+          nbytes = can_datalen(hdr);
           if (nbytes)
             {
               memcpy(fifo->rx_buffer[fifo->rx_tail].cm_data, data, nbytes);
diff --git a/drivers/can/ctucanfd_pci.c b/drivers/can/ctucanfd_pci.c
index a8b92c8fe3d..af4ab1004f5 100644
--- a/drivers/can/ctucanfd_pci.c
+++ b/drivers/can/ctucanfd_pci.c
@@ -37,6 +37,7 @@
 #include <nuttx/pci/pci.h>
 
 #ifdef CONFIG_CAN_CTUCANFD_CHARDEV
+#  include <nuttx/can.h>
 #  include <nuttx/can/can.h>
 #endif
 
@@ -636,7 +637,19 @@ static int ctucanfd_chrdev_send(FAR struct can_dev_s *dev,
   ctucanfd_putreg(priv, offset + CTUCANFD_TXBUF_TSL, 0);
   ctucanfd_putreg(priv, offset + CTUCANFD_TXBUF_TSU, 0);
 
-  bytes = can_dlc2bytes(msg->cm_hdr.ch_dlc);
+  /* DLC 9..15 of a classic frame carry 8 data bytes */
+
+#ifdef CONFIG_CAN_FD
+  if (msg->cm_hdr.ch_edl)
+    {
+      bytes = can_dlc2bytes(msg->cm_hdr.ch_dlc);
+    }
+  else
+#endif
+    {
+      bytes = MIN(msg->cm_hdr.ch_dlc, CAN_MAX_DLEN);
+    }
+
   for (i = 0; i < bytes; i++)
     {
       ctucanfd_putreg(priv, offset + CTUCANFD_TXBUF_DATA + i,
diff --git a/drivers/can/kvaser_pci.c b/drivers/can/kvaser_pci.c
index 7e2760f54f8..1b7118ccf04 100644
--- a/drivers/can/kvaser_pci.c
+++ b/drivers/can/kvaser_pci.c
@@ -30,12 +30,14 @@
 #include <nuttx/debug.h>
 #include <errno.h>
 #include <stdio.h>
+#include <sys/param.h>
 
 #include <nuttx/arch.h>
 #include <nuttx/kmalloc.h>
 #include <nuttx/pci/pci.h>
 
 #ifdef CONFIG_CAN_KVASER_CHARDEV
+#  include <nuttx/can.h>
 #  include <nuttx/can/can.h>
 #endif
 
@@ -660,21 +662,20 @@ static int kvaser_chrdev_send(FAR struct can_dev_s *dev,
       return -EBUSY;
     }
 
-  /* Get data bytes for this frame */
-
-  bytes = can_dlc2bytes(msg->cm_hdr.ch_dlc);
-
 #ifdef CONFIG_CAN_FD
   /* Drop CAN FD frames */
 
-  if (bytes > 8 || msg->cm_hdr.ch_edl ||
-      msg->cm_hdr.ch_brs || msg->cm_hdr.ch_esi)
+  if (msg->cm_hdr.ch_edl || msg->cm_hdr.ch_brs || msg->cm_hdr.ch_esi)
     {
       canerr("ERROR: CAN FD frames not supported\n");
       return -ENOTSUP;
     }
 #endif
 
+  /* Get data bytes for this frame, DLC 9..15 means 8 bytes */
+
+  bytes = MIN(msg->cm_hdr.ch_dlc, CAN_MAX_DLEN);
+
   /* Set up the DLC */
 
   fi = msg->cm_hdr.ch_dlc;
@@ -852,12 +853,17 @@ static void kvaser_chardev_receive(FAR struct 
kvaser_sja_s *priv)
 
 #ifdef CONFIG_CAN_ERRORS
       hdr.ch_error = 0;
+#endif
+#ifdef CONFIG_CAN_FD
+      hdr.ch_edl   = 0;
+      hdr.ch_brs   = 0;
+      hdr.ch_esi   = 0;
 #endif
       hdr.ch_tcf   = 0;
 
-      /* Get data */
+      /* Get data, DLC 9..15 means 8 bytes */
 
-      for (i = 0; i < can_dlc2bytes(hdr.ch_dlc); i++)
+      for (i = 0; i < MIN(hdr.ch_dlc, CAN_MAX_DLEN); i++)
         {
           data[i] = kvaser_getreg_sja(priv, dreg + i);
         }

Reply via email to