From 51a845ce54e38ca6ecc13c2fd7029802cb07076f Mon Sep 17 00:00:00 2001 From: Jari van Ewijk Date: Fri, 22 Jul 2022 10:23:20 +0200 Subject: [PATCH] SocketCAN: add non-blocking write Co-authored-by: Peter van der Perk --- net/can/can.h | 26 ++++++++++++++++++++++ net/can/can_input.c | 52 ++++++++++++++++++++----------------------- net/can/can_sendmsg.c | 48 +++++++++++++++++++++++++++++++++++++-- net/can/can_sockif.c | 10 +++------ 4 files changed, 99 insertions(+), 37 deletions(-) diff --git a/net/can/can.h b/net/can/can.h index 48f9e1087d6d3..d317fea6f781b 100644 --- a/net/can/can.h +++ b/net/can/can.h @@ -267,6 +267,32 @@ ssize_t can_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg, void can_poll(FAR struct net_driver_s *dev, FAR struct can_conn_s *conn); +/**************************************************************************** + * Name: psock_can_cansend + * + * Description: + * psock_can_cansend() returns a value indicating if a write to the socket + * would block. It is still possible that the write may block if another + * write occurs first. + * + * Input Parameters: + * psock An instance of the internal socket structure. + * + * Returned Value: + * OK + * At least one byte of data could be successfully written. + * -EWOULDBLOCK + * There is no room in the output buffer. + * -EBADF + * An invalid descriptor was specified. + * + * Assumptions: + * None + * + ****************************************************************************/ + +int psock_can_cansend(FAR struct socket *psock); + /**************************************************************************** * Name: can_sendmsg * diff --git a/net/can/can_input.c b/net/can/can_input.c index 024bb9aad524a..7a073d566d7bc 100644 --- a/net/can/can_input.c +++ b/net/can/can_input.c @@ -155,48 +155,44 @@ int can_input(struct net_driver_s *dev) { FAR struct can_conn_s *conn = NULL; int ret = OK; + uint16_t buflen = dev->d_len; do { - /* FIXME Support for multiple sockets??? */ - conn = can_nextconn(conn); - } - while (conn && conn->dev != 0 && dev != conn->dev); - - if (conn) - { - uint16_t flags; - /* Setup for the application callback */ + if (conn && (conn->dev == 0x0 || dev == conn->dev)) + { + uint16_t flags; - dev->d_appdata = dev->d_buf; - dev->d_sndlen = 0; + /* Setup for the application callback */ - /* Perform the application callback */ + dev->d_appdata = dev->d_buf; + dev->d_sndlen = 0; + dev->d_len = buflen; - flags = can_callback(dev, conn, CAN_NEWDATA); + /* Perform the application callback */ - /* If the operation was successful, the CAN_NEWDATA flag is removed - * and thus the packet can be deleted (OK will be returned). - */ + flags = can_callback(dev, conn, CAN_NEWDATA); - if ((flags & CAN_NEWDATA) != 0) - { - /* No.. the packet was not processed now. Return -EAGAIN so - * that the driver may retry again later. We still need to - * set d_len to zero so that the driver is aware that there - * is nothing to be sent. + /* If the operation was successful, the CAN_NEWDATA flag is removed + * and thus the packet can be deleted (OK will be returned). */ - nwarn("WARNING: Packet not processed\n"); - ret = -EAGAIN; + if ((flags & CAN_NEWDATA) != 0) + { + /* No.. the packet was not processed now. Return -EAGAIN so + * that the driver may retry again later. We still need to + * set d_len to zero so that the driver is aware that there + * is nothing to be sent. + */ + + nwarn("WARNING: Packet not processed\n"); + ret = -EAGAIN; + } } } - else - { - ninfo("No CAN listener\n"); - } + while (conn); return ret; } diff --git a/net/can/can_sendmsg.c b/net/can/can_sendmsg.c index a7912d99d1d00..3ccea61826c4f 100644 --- a/net/can/can_sendmsg.c +++ b/net/can/can_sendmsg.c @@ -259,10 +259,17 @@ ssize_t can_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg, netdev_txnotify_dev(dev); /* Wait for the send to complete or an error to occur. - * net_lockedwait will also terminate if a signal is received. + * net_timedwait will also terminate if a signal is received. */ - ret = net_lockedwait(&state.snd_sem); + if (_SS_ISNONBLOCK(conn->sconn.s_flags) || (flags & MSG_DONTWAIT) != 0) + { + ret = net_timedwait(&state.snd_sem, 0); + } + else + { + ret = net_timedwait(&state.snd_sem, UINT_MAX); + } /* Make sure that no further events are processed */ @@ -296,4 +303,41 @@ ssize_t can_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg, return state.snd_sent; } +/**************************************************************************** + * Name: psock_can_cansend + * + * Description: + * psock_can_cansend() returns a value indicating if a write to the socket + * would block. No space in the buffer is actually reserved, so it is + * possible that the write may still block if the buffer is filled by + * another means. + * + * Input Parameters: + * psock An instance of the internal socket structure. + * + * Returned Value: + * OK + * At least one byte of data could be successfully written. + * -EWOULDBLOCK + * There is no room in the output buffer. + * -EBADF + * An invalid descriptor was specified. + * + ****************************************************************************/ + +int psock_can_cansend(FAR struct socket *psock) +{ + /* Verify that we received a valid socket */ + + if (psock == NULL || psock->s_conn == NULL) + { + nerr("ERROR: Invalid socket\n"); + return -EBADF; + } + + /* TODO Query CAN driver mailboxes to see if there's mailbox available */ + + return OK; +} + #endif /* CONFIG_NET && CONFIG_NET_CAN */ diff --git a/net/can/can_sockif.c b/net/can/can_sockif.c index 780641f9727ef..bddc3ef9b8b2f 100644 --- a/net/can/can_sockif.c +++ b/net/can/can_sockif.c @@ -139,15 +139,13 @@ static uint16_t can_poll_eventhandler(FAR struct net_driver_s *dev, eventset |= (POLLHUP | POLLERR); } -#if 0 /* A poll is a sign that we are free to send data. */ else if ((flags & CAN_POLL) != 0 && - psock_udp_cansend(info->psock) >= 0) + psock_can_cansend(info->psock) >= 0) { eventset |= (POLLOUT & info->fds->events); } -#endif /* Awaken the caller of poll() is requested event occurred. */ @@ -608,14 +606,12 @@ static int can_poll_local(FAR struct socket *psock, FAR struct pollfd *fds, fds->revents |= (POLLRDNORM & fds->events); } - #if 0 - if (psock_udp_cansend(psock) >= 0) + if (psock_can_cansend(psock) >= 0) { - /* Normal data may be sent without blocking (at least one byte). */ + /* A CAN frame may be sent without blocking. */ fds->revents |= (POLLWRNORM & fds->events); } - #endif /* Check if any requested events are already in effect */