2020-06-15 10:23:25 +02:00
|
|
|
/****************************************************************************
|
2021-03-08 18:39:04 -03:00
|
|
|
* net/can/can_callback.c
|
2020-06-15 10:23:25 +02:00
|
|
|
*
|
2024-09-11 14:39:39 +02:00
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
*
|
2020-06-15 10:23:25 +02:00
|
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
|
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
|
|
|
* this work for additional information regarding copyright ownership. The
|
|
|
|
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
|
|
|
|
* "License"); you may not use this file except in compliance with the
|
|
|
|
|
* License. You may obtain a copy of the License at
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
|
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
|
|
|
* License for the specific language governing permissions and limitations
|
|
|
|
|
* under the License.
|
|
|
|
|
*
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
|
* Included Files
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
|
#if defined(CONFIG_NET) && defined(CONFIG_NET_CAN)
|
|
|
|
|
|
|
|
|
|
#include <stdint.h>
|
2026-04-01 05:11:15 +05:30
|
|
|
#include <nuttx/debug.h>
|
2020-06-15 10:23:25 +02:00
|
|
|
|
|
|
|
|
#include <nuttx/net/netconfig.h>
|
|
|
|
|
#include <nuttx/net/netdev.h>
|
|
|
|
|
#include <nuttx/mm/iob.h>
|
2025-01-29 14:30:11 +01:00
|
|
|
#include <nuttx/net/netstats.h>
|
2025-04-15 22:36:17 +08:00
|
|
|
#include <nuttx/net/can.h>
|
2020-06-15 10:23:25 +02:00
|
|
|
|
|
|
|
|
#include "devif/devif.h"
|
2025-06-19 14:03:24 +08:00
|
|
|
#include "utils/utils.h"
|
2020-06-15 10:23:25 +02:00
|
|
|
#include "can/can.h"
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_NET_TIMESTAMP
|
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
|
* Private Functions
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
|
* Name: can_data_event
|
|
|
|
|
*
|
|
|
|
|
* Description:
|
|
|
|
|
* Handle data that is not accepted by the application because there is no
|
|
|
|
|
* listener in place ready to receive the data.
|
|
|
|
|
*
|
|
|
|
|
* Assumptions:
|
|
|
|
|
* - The caller has checked that CAN_NEWDATA is set in flags and that is no
|
|
|
|
|
* other handler available to process the incoming data.
|
|
|
|
|
* - This function must be called with the network locked.
|
|
|
|
|
*
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
2025-11-12 11:34:06 +08:00
|
|
|
static inline uint32_t
|
2020-06-15 10:23:25 +02:00
|
|
|
can_data_event(FAR struct net_driver_s *dev, FAR struct can_conn_s *conn,
|
2025-11-12 11:34:06 +08:00
|
|
|
uint32_t flags)
|
2020-06-15 10:23:25 +02:00
|
|
|
{
|
|
|
|
|
int buflen = dev->d_len;
|
2025-08-25 11:15:49 +08:00
|
|
|
int recvlen;
|
2025-11-12 11:34:06 +08:00
|
|
|
uint32_t ret;
|
2020-06-15 10:23:25 +02:00
|
|
|
|
2024-03-12 11:13:19 +02:00
|
|
|
#ifdef CONFIG_NET_TIMESTAMP
|
|
|
|
|
buflen -= sizeof(struct timeval);
|
|
|
|
|
#endif
|
|
|
|
|
|
2020-06-15 10:23:25 +02:00
|
|
|
ret = (flags & ~CAN_NEWDATA);
|
|
|
|
|
|
|
|
|
|
/* Save as the packet data as in the read-ahead buffer. NOTE that
|
|
|
|
|
* partial packets will not be buffered.
|
|
|
|
|
*/
|
|
|
|
|
|
2022-11-23 19:39:40 +08:00
|
|
|
recvlen = can_datahandler(dev, conn);
|
2020-06-15 10:23:25 +02:00
|
|
|
if (recvlen < buflen)
|
|
|
|
|
{
|
|
|
|
|
/* There is no handler to receive new data and there are no free
|
|
|
|
|
* read-ahead buffers to retain the data -- drop the packet.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
ninfo("Dropped %d bytes\n", dev->d_len);
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_NET_STATISTICS
|
2025-01-29 14:30:11 +01:00
|
|
|
g_netstats.can.drop++;
|
2020-06-15 10:23:25 +02:00
|
|
|
#endif
|
arch/arm/src/imxrt: Unify FlexCAN TX work and add SIOCGCANERRORS.
TX-complete and the deadline watchdog each queued their own callback on
the same work_s, and work_queue() cancels whatever is pending when a
work_s is reused, so whichever ran second was dropped: deadlines were
left set, the TX interrupt mask stayed off, or expired frames were never
aborted. Both now queue imxrt_tx_work(), which retires completions
before it aborts expired mailboxes.
Add SIOCGCANERRORS so a socket can read fault confinement, TEC/REC, a
monotonic bus error count and the RX mailbox overrun count. SIOCGCANSTATE
reports sleep/operational, not fault confinement, hence a new command.
The error count is sampled from the clear-on-read ESR1 error flags at
every driver entry rather than from ERRINT, which fires per error frame
and storms at bus rate once the bus is dead. Frames the CAN socket layer
drops for want of an IOB now count as rx_dropped in the netdev
statistics as well as in the global CAN statistics.
Tested on an i.MX RT1176 (ARK FMU-v6XRT) running PX4 with two DroneCAN
nodes: unplugging one node the ioctl reports error-passive, TEC 128,
REC 0 and a monotonic error count, matching ECR/ESR1 read over SWD at
20 Hz, while the other interface stays error-active with zero errors.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
2026-08-30 14:38:34 -06:00
|
|
|
NETDEV_RXDROPPED(dev);
|
2020-06-15 10:23:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* In any event, the new data has now been handled */
|
|
|
|
|
|
|
|
|
|
dev->d_len = 0;
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
|
* Public Functions
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
|
* Name: can_callback
|
|
|
|
|
*
|
|
|
|
|
* Description:
|
|
|
|
|
* Inform the application holding the packet socket of a change in state.
|
|
|
|
|
*
|
|
|
|
|
* Returned Value:
|
|
|
|
|
* OK if packet has been processed, otherwise ERROR.
|
|
|
|
|
*
|
|
|
|
|
* Assumptions:
|
|
|
|
|
* This function can be called from an interrupt.
|
|
|
|
|
*
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
2025-11-12 11:34:06 +08:00
|
|
|
uint32_t can_callback(FAR struct net_driver_s *dev,
|
|
|
|
|
FAR struct can_conn_s *conn, uint32_t flags)
|
2020-06-15 10:23:25 +02:00
|
|
|
{
|
|
|
|
|
/* Some sanity checking */
|
|
|
|
|
|
|
|
|
|
if (conn)
|
|
|
|
|
{
|
2022-11-23 19:39:40 +08:00
|
|
|
#ifdef CONFIG_NET_TIMESTAMP
|
2026-08-30 14:38:42 -06:00
|
|
|
/* TIMESTAMP sockopt is activated,
|
|
|
|
|
* create timestamp and copy to iob
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMP) &&
|
|
|
|
|
(dev->d_iob != NULL))
|
|
|
|
|
{
|
|
|
|
|
struct timeval tv;
|
|
|
|
|
FAR struct timespec *ts = (FAR struct timespec *)&tv;
|
|
|
|
|
int len;
|
2022-11-23 19:39:40 +08:00
|
|
|
|
2026-08-30 14:38:42 -06:00
|
|
|
clock_systime_timespec(ts);
|
|
|
|
|
tv.tv_usec = ts->tv_nsec / 1000;
|
|
|
|
|
|
|
|
|
|
len = iob_trycopyin(dev->d_iob, (FAR uint8_t *)&tv,
|
|
|
|
|
sizeof(struct timeval),
|
|
|
|
|
-CONFIG_NET_LL_GUARDSIZE, false);
|
|
|
|
|
if (len == sizeof(struct timeval))
|
2022-11-23 19:39:40 +08:00
|
|
|
{
|
2026-08-30 14:38:42 -06:00
|
|
|
dev->d_len += len;
|
2022-11-23 19:39:40 +08:00
|
|
|
}
|
2026-08-30 14:38:42 -06:00
|
|
|
}
|
2022-11-23 19:39:40 +08:00
|
|
|
#endif
|
2025-03-07 09:40:59 +01:00
|
|
|
|
2025-06-19 14:03:24 +08:00
|
|
|
conn_lock(&conn->sconn);
|
|
|
|
|
flags = devif_conn_event(dev, flags, conn->sconn.list);
|
2025-03-07 09:40:59 +01:00
|
|
|
|
|
|
|
|
/* Either we did not get the lock or there is no application listening
|
|
|
|
|
* If we did not get a lock we store the frame in the read-ahead buffer
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if ((flags & CAN_NEWDATA) != 0)
|
|
|
|
|
{
|
2020-06-15 10:23:25 +02:00
|
|
|
/* Data was not handled.. dispose of it appropriately */
|
|
|
|
|
|
|
|
|
|
flags = can_data_event(dev, conn, flags);
|
|
|
|
|
}
|
2026-04-02 16:48:32 +08:00
|
|
|
|
|
|
|
|
conn_unlock(&conn->sconn);
|
2020-06-15 10:23:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return flags;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
|
* Name: can_datahandler
|
|
|
|
|
*
|
|
|
|
|
* Description:
|
|
|
|
|
* Handle data that is not accepted by the application. This may be called
|
|
|
|
|
* either (1) from the data receive logic if it cannot buffer the data, or
|
|
|
|
|
* (2) from the CAN event logic is there is no listener in place ready to
|
|
|
|
|
* receive the data.
|
|
|
|
|
*
|
|
|
|
|
* Input Parameters:
|
2022-11-23 19:39:40 +08:00
|
|
|
* dev - The device which as active when the event was detected.
|
2020-06-15 10:23:25 +02:00
|
|
|
* conn - A pointer to the CAN connection structure
|
|
|
|
|
*
|
|
|
|
|
* Returned Value:
|
|
|
|
|
* The number of bytes actually buffered is returned. This will be either
|
|
|
|
|
* zero or equal to buflen; partial packets are not buffered.
|
|
|
|
|
*
|
|
|
|
|
* Assumptions:
|
|
|
|
|
* - The caller has checked that CAN_NEWDATA is set in flags and that is no
|
|
|
|
|
* other handler available to process the incoming data.
|
|
|
|
|
* - This function must be called with the network locked.
|
|
|
|
|
*
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
2025-08-25 11:15:49 +08:00
|
|
|
int can_datahandler(FAR struct net_driver_s *dev,
|
|
|
|
|
FAR struct can_conn_s *conn)
|
2020-06-15 10:23:25 +02:00
|
|
|
{
|
2022-11-23 19:39:40 +08:00
|
|
|
FAR struct iob_s *iob = dev->d_iob;
|
2024-06-06 19:54:54 +08:00
|
|
|
int ret = 0;
|
|
|
|
|
|
2025-06-19 14:03:24 +08:00
|
|
|
conn_lock(&conn->sconn);
|
2024-06-06 19:54:54 +08:00
|
|
|
#if CONFIG_NET_RECV_BUFSIZE > 0
|
2025-04-15 22:36:17 +08:00
|
|
|
# if CONFIG_NET_CAN_NBUFFERS > 0
|
|
|
|
|
int bufnum = div_const_roundup(conn->rcvbufs, NET_CAN_PKTSIZE);
|
|
|
|
|
# else
|
|
|
|
|
int bufnum = div_const_roundup(conn->rcvbufs, CONFIG_IOB_BUFSIZE);
|
|
|
|
|
# endif
|
2024-06-06 19:54:54 +08:00
|
|
|
/* Check the frame count pending on conn->readahead */
|
|
|
|
|
|
2025-04-15 22:36:17 +08:00
|
|
|
if (iob_get_queue_entry_count(&conn->readahead) >= bufnum)
|
2024-06-06 19:54:54 +08:00
|
|
|
{
|
2025-05-03 06:16:30 +02:00
|
|
|
nwarn("WARNING: There are no free receive buffer to retain the data. "
|
|
|
|
|
"Receive buffer number:%"PRId32", received frames:%"PRIuPTR" \n",
|
2025-04-15 22:36:17 +08:00
|
|
|
bufnum, iob_get_queue_entry_count(&conn->readahead));
|
2024-06-06 19:54:54 +08:00
|
|
|
goto errout;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2020-06-15 10:23:25 +02:00
|
|
|
|
2022-11-23 19:39:40 +08:00
|
|
|
/* Concat the iob to readahead */
|
2020-06-15 10:23:25 +02:00
|
|
|
|
|
|
|
|
ret = iob_tryadd_queue(iob, &conn->readahead);
|
2022-11-23 19:39:40 +08:00
|
|
|
if (ret >= 0)
|
2020-06-15 10:23:25 +02:00
|
|
|
{
|
|
|
|
|
#ifdef CONFIG_NET_CAN_NOTIFIER
|
2022-11-23 19:39:40 +08:00
|
|
|
/* Provide notification(s) that additional CAN read-ahead data is
|
|
|
|
|
* available.
|
|
|
|
|
*/
|
2020-06-15 10:23:25 +02:00
|
|
|
|
2022-11-23 19:39:40 +08:00
|
|
|
can_readahead_signal(conn);
|
2020-06-15 10:23:25 +02:00
|
|
|
#endif
|
2022-11-23 19:39:40 +08:00
|
|
|
ret = iob->io_pktlen;
|
|
|
|
|
|
2023-12-27 10:43:11 +08:00
|
|
|
/* Device buffer has been enqueued, clear the handle */
|
2022-12-07 23:08:53 +08:00
|
|
|
|
2023-12-27 10:43:11 +08:00
|
|
|
netdev_iob_clear(dev);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
nerr("ERROR: Failed to queue the I/O buffer chain: %d\n", ret);
|
2025-01-30 10:14:40 +01:00
|
|
|
ret = 0;
|
2024-06-06 19:54:54 +08:00
|
|
|
goto errout;
|
2023-12-27 10:43:11 +08:00
|
|
|
}
|
2022-12-07 23:08:53 +08:00
|
|
|
|
2025-06-19 14:03:24 +08:00
|
|
|
conn_unlock(&conn->sconn);
|
2022-11-23 19:39:40 +08:00
|
|
|
return ret;
|
2024-06-06 19:54:54 +08:00
|
|
|
|
|
|
|
|
errout:
|
|
|
|
|
netdev_iob_release(dev);
|
2025-06-19 14:03:24 +08:00
|
|
|
conn_unlock(&conn->sconn);
|
2024-06-06 19:54:54 +08:00
|
|
|
return ret;
|
2020-06-15 10:23:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif /* CONFIG_NET && CONFIG_NET_CAN */
|