mirror of
https://github.com/apache/nuttx.git
synced 2026-09-10 02:46:33 +00:00
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>
90 lines
2.7 KiB
ReStructuredText
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.
|