nuttx/Documentation/guides/reading_can_msgs.rst
Karel Kočí c61d7c7e8d nuttx/can: add message alignment
This adds ability for read and write operations to work with messages
aligned to configured number of bytes. This has few different use
cases.

The alignment is specified as unsigned integer and can be changed with
ioctl command CANIOC_SET_MSGALIGN. The current value can be queried by
CANIOC_GET_MSGALIGN command.

The default value for the message alignment is 1. This will provide
behavior consistent with current one. Thus messages are placed to the
buffer right after data of the previous one. The same applies for
writes.

The special alignment value 0 disables read and write of multiple frames. Thus
read will always return at most one message and write will always write
only one message even if larger buffer size is provided.

Another use case is if message alignment is set to exactly message
representation size (`sizeof(struct can_msg_s)`). This allows writing
and reading arrays of messages.

Other values provide even more advanced and specialized use cases, such
as optimizations if architecture has to emulate some non-aligned
accesses, there alignment of for example 4 bytes could provide
performance boost.

The original motivation behind this is was compatibility with socket
CAN. It is easier to port applications to NuttX's CAN driver if only one
frame is provided at the time. This solution was suggested by Pavel Pisa
<pisa@fel.cvut.cz> as a more versatile variant of plain boolean
disabling the multiple frame retrieval.

Signed-off-by: Karel Kočí <kkoci@elektroline.cz>
2025-11-24 14:11:41 +08:00

90 lines
2.7 KiB
ReStructuredText

====================
Reading CAN Messages
====================
NuttX's CAN driver's default behavior is to return multiple messages for single
``read`` operation, if they fit. If your code (especially if migrated from
SocketCAN) doesn't count with it, then you will most likely encounter seemingly
lost frames. You have two options: Either implement your code to support this
behavior or you can switch this behavior off.
The following example shows how you can handle multiple messages:
.. code-block:: c
#define BUFLEN 128 /* Some arbitrary size for the CAN RX buffer */
FAR struct can_msg_s *msg;
char rxbuffer[BUFLEN];
ssize_t nread;
int nbytes;
int msglen
int i;
/* Read messages into the RX buffer */
nread = read(fd, rxbuffer, BUFLEN);
/* Check for read errors */
...
/* Process each message in the RX buffer */
for (i = 0; i <= nread - CAN_MSGLEN(0); i += msglen)
{
/* Get the next message from the RX buffer */
msg = (FAR struct can_msg_s *)&rxbuffer[i];
nbytes = can_dlc2bytes(msg->cm_hdr.ch_dlc);
msglen = CAN_MSGLEN(nbytes);
DEBUGASSERT(i + msglen < BUFLEN);
/* Process the next CAN message */
...
}
By looping over the read buffer and parsing out each CAN message, it is
possible to avoid losing messages that are stored contiguously in the input
buffer.
The alternative is to use message alignment functionality. By setting the
message alignment to zero the driver will always return only a single message
for a single ``read`` operation:
.. code-block:: c
unsigned msgalign = 0;
ioctl(fd, CANIOC_SET_MSGALIGN, &msgalign);
The message alignment functionality can be used to tweak the behavior event
further. It in general controls alignment of messages in the buffers passed to
both ``read`` and ``write`` operations. While the default behavior of packing as
many messages to the buffer as possible provides the most efficient exchange,
you might also want and easier usage where you pass array of messages. This can
be ensured with setting message align size to exactly size of the message:
.. code-block:: c
unsigned msgsiz = sizeof(struct can_msg_s);
struct can_msg_s msgs[5];
ssize_t nread;
int i;
/* Set message alignment to message size. */
ioctl(fd, CANIOC_SET_MSGALIGN, &msgsiz);
/* Read messages to the array. */
nread = read(fd, msgs, sizeof(msgs));
/* Iterate over read messages */
for (i = 0; i < nread / msgsiz; i--)
{
/* Process CAN message msgs[i] */
}
The same alignment rule applies to the ``write`` as well, so with alignment like
it is in the example you write array of message and not message packed right
after each other.