You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by gn...@apache.org on 2020/06/02 14:09:29 UTC

[incubator-nuttx] 11/31: Added CAN_RAW_FD_FRAMES sockopt support

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

gnutt pushed a commit to branch SocketCAN
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit 1fa53edb62ae731af44ef7677f7b422fad547d95
Author: Peter van der Perk <pe...@nxp.com>
AuthorDate: Wed Feb 26 13:36:24 2020 +0100

    Added CAN_RAW_FD_FRAMES sockopt support
    
    Also CAN FD is disabled on startup, which is default behaviour for SocketCAN
---
 net/can/can.h            | 10 ++++++++++
 net/can/can_conn.c       |  3 +++
 net/can/can_getsockopt.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++
 net/can/can_recvfrom.c   | 28 +++++++++++++++++++++++----
 net/can/can_send.c       | 50 ++++++++++++++++++++++++++++++------------------
 net/can/can_setsockopt.c | 21 +++++++++++++++++---
 net/socket/getsockopt.c  |  4 ++--
 net/socket/setsockopt.c  |  6 ++++++
 8 files changed, 142 insertions(+), 28 deletions(-)

diff --git a/net/can/can.h b/net/can/can.h
index 67c8d6f..5992deb 100644
--- a/net/can/can.h
+++ b/net/can/can.h
@@ -104,6 +104,16 @@ struct can_conn_s
    */
 
   struct can_poll_s pollinfo[4]; /* FIXME make dynamic */
+  
+#ifdef CONFIG_NET_CANPROTO_OPTIONS
+  int32_t loopback;
+  int32_t recv_own_msgs;
+  int32_t fd_frames;
+  
+  /* TODO add filter support */
+#endif
+  
+  
 };
 
 /****************************************************************************
diff --git a/net/can/can_conn.c b/net/can/can_conn.c
index 4969f6d..21622b5 100644
--- a/net/can/can_conn.c
+++ b/net/can/can_conn.c
@@ -138,6 +138,9 @@ FAR struct can_conn_s *can_alloc(void)
       /* Make sure that the connection is marked as uninitialized */
 
       memset(conn, 0, sizeof(*conn));
+      
+      /* FIXME SocketCAN default behavior enables loopback */
+      
 
       /* Enqueue the connection into the active list */
 
diff --git a/net/can/can_getsockopt.c b/net/can/can_getsockopt.c
index 1fe8218..91720ad 100644
--- a/net/can/can_getsockopt.c
+++ b/net/can/can_getsockopt.c
@@ -114,12 +114,60 @@ int can_getsockopt(FAR struct socket *psock, int option,
         break;
 
       case CAN_RAW_LOOPBACK:
+        if (*value_len < sizeof(conn->loopback))
+          {
+            /* REVISIT: POSIX says that we should truncate the value if it
+             * is larger than value_len.   That just doesn't make sense
+             * to me in this case.
+             */
+
+            ret              = -EINVAL;
+          }
+        else
+          {
+            FAR int *loopback  = (FAR int32_t *)value;
+            *loopback          = conn->loopback;
+            *value_len         = sizeof(conn->loopback);
+            ret                = OK;
+          }
         break;
 
       case CAN_RAW_RECV_OWN_MSGS:
+        if (*value_len < sizeof(conn->recv_own_msgs))
+          {
+            /* REVISIT: POSIX says that we should truncate the value if it
+             * is larger than value_len.   That just doesn't make sense
+             * to me in this case.
+             */
+
+            ret              = -EINVAL;
+          }
+        else
+          {
+            FAR int *recv_own_msgs = (FAR int32_t *)value;
+            *recv_own_msgs         = conn->recv_own_msgs;
+            *value_len             = sizeof(conn->recv_own_msgs);
+            ret                    = OK;
+          }
         break;
 
       case CAN_RAW_FD_FRAMES:
+        if (*value_len < sizeof(conn->fd_frames))
+          {
+            /* REVISIT: POSIX says that we should truncate the value if it
+             * is larger than value_len.   That just doesn't make sense
+             * to me in this case.
+             */
+
+            ret              = -EINVAL;
+          }
+        else
+          {
+            FAR int *fd_frames = (FAR int32_t *)value;
+            *fd_frames         = conn->fd_frames;
+            *value_len         = sizeof(conn->fd_frames);
+            ret                = OK;
+          }
         break;
 
       case CAN_RAW_JOIN_FILTERS:
diff --git a/net/can/can_recvfrom.c b/net/can/can_recvfrom.c
index d2f71a6..f83d07c 100644
--- a/net/can/can_recvfrom.c
+++ b/net/can/can_recvfrom.c
@@ -276,6 +276,16 @@ static inline int can_readahead(struct can_recvfrom_s *pstate)
                              IOBUSER_NET_CAN_READAHEAD);
         }
 
+	  /* do not pass frames with DLC > 8 to a legacy socket */
+	  if (!conn->fd_frames)
+	    {
+		  struct canfd_frame *cfd = (struct canfd_frame *)pstate->pr_buffer;
+		  if (cfd->len > CAN_MAX_DLEN)
+		    {
+	  			return 0;
+		    }
+	    }
+
       return recvlen;
     }
 
@@ -287,6 +297,7 @@ static uint16_t can_recvfrom_eventhandler(FAR struct net_driver_s *dev,
                                           FAR void *pvpriv, uint16_t flags)
 {
   struct can_recvfrom_s *pstate = (struct can_recvfrom_s *)pvpriv;
+  struct can_conn_s *conn = (struct can_conn_s *)pstate->pr_sock->s_conn;
 
   /* 'priv' might be null in some race conditions (?) */
 
@@ -296,6 +307,18 @@ static uint16_t can_recvfrom_eventhandler(FAR struct net_driver_s *dev,
 
       if ((flags & CAN_NEWDATA) != 0)
         {
+    	  /* do not pass frames with DLC > 8 to a legacy socket */
+    	  if (!conn->fd_frames)
+    	    {
+    		  struct canfd_frame *cfd = (struct canfd_frame *)dev->d_appdata;
+    	      if (cfd->len > CAN_MAX_DLEN)
+    	      {
+    	    	/* DO WE NEED TO CLEAR FLAGS?? */
+    	        flags &= ~CAN_NEWDATA;
+  	  			return flags;
+    	      }
+    	    }
+
           /* Copy the packet */
 
           can_newdata(dev, pstate);
@@ -355,10 +378,7 @@ static ssize_t can_recvfrom_result(int result,
 
   if (pstate->pr_result < 0)
     {
-      /* This might return EAGAIN on a timeout or ENOTCONN on loss of
-       * connection (CAN only)
-       */
-
+      /* This might return EAGAIN on a timeout */
       return pstate->pr_result;
     }
 
diff --git a/net/can/can_send.c b/net/can/can_send.c
index 6b7a609..1d8677d 100644
--- a/net/can/can_send.c
+++ b/net/can/can_send.c
@@ -184,6 +184,21 @@ ssize_t psock_can_send(FAR struct socket *psock, FAR const void *buf,
     {
       return -ENODEV;
     }
+    
+  if(conn->fd_frames)
+    {
+        if(len != CANFD_MTU && len != CAN_MTU)
+          {
+              return -EINVAL;
+          } 
+    }
+    else 
+    {
+        if(len != CAN_MTU)
+          {
+              return -EINVAL;
+          }
+    }
 
   /* Perform the send operation */
 
@@ -205,33 +220,30 @@ ssize_t psock_can_send(FAR struct socket *psock, FAR const void *buf,
   state.snd_buflen    = len;            /* Number of bytes to send */
   state.snd_buffer    = buf;            /* Buffer to send from */
 
-  if (len > 0)
-    {
-      /* Allocate resource to receive a callback */
+  /* Allocate resource to receive a callback */
 
-      state.snd_cb = can_callback_alloc(dev, conn);
-      if (state.snd_cb)
-        {
-          /* Set up the callback in the connection */
+  state.snd_cb = can_callback_alloc(dev, conn);
+  if (state.snd_cb)
+    {
+      /* Set up the callback in the connection */
 
-          state.snd_cb->flags = CAN_POLL;
-          state.snd_cb->priv  = (FAR void *)&state;
-          state.snd_cb->event = psock_send_eventhandler;
+      state.snd_cb->flags = CAN_POLL;
+      state.snd_cb->priv  = (FAR void *)&state;
+      state.snd_cb->event = psock_send_eventhandler;
 
-          /* Notify the device driver that new TX data is available. */
+      /* Notify the device driver that new TX data is available. */
 
-          netdev_txnotify_dev(dev);
+      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.
-           */
+      /* Wait for the send to complete or an error to occur.
+      * net_lockedwait will also terminate if a signal is received.
+      */
 
-          ret = net_lockedwait(&state.snd_sem);
+      ret = net_lockedwait(&state.snd_sem);
 
-          /* Make sure that no further events are processed */
+      /* Make sure that no further events are processed */
 
-          can_callback_free(dev, conn, state.snd_cb);
-        }
+      can_callback_free(dev, conn, state.snd_cb);
     }
 
   nxsem_destroy(&state.snd_sem);
diff --git a/net/can/can_setsockopt.c b/net/can/can_setsockopt.c
index 2d117a8..3bad6e0 100644
--- a/net/can/can_setsockopt.c
+++ b/net/can/can_setsockopt.c
@@ -108,13 +108,28 @@ int can_setsockopt(FAR struct socket *psock, int option,
         break;
 
       case CAN_RAW_LOOPBACK:
-        break;
+		if (value_len != sizeof(conn->loopback))
+			return -EINVAL;
+
+		conn->loopback = *(FAR int32_t *)value;
+
+		break;
 
       case CAN_RAW_RECV_OWN_MSGS:
-        break;
+		if (value_len != sizeof(conn->recv_own_msgs))
+			return -EINVAL;
+
+		conn->recv_own_msgs = *(FAR int32_t *)value;
+
+		break;
 
       case CAN_RAW_FD_FRAMES:
-        break;
+		if (value_len != sizeof(conn->fd_frames))
+			return -EINVAL;
+
+		conn->fd_frames = *(FAR int32_t *)value;
+
+		break;
 
       case CAN_RAW_JOIN_FILTERS:
         break;
diff --git a/net/socket/getsockopt.c b/net/socket/getsockopt.c
index 6d71106..fa58e6d 100644
--- a/net/socket/getsockopt.c
+++ b/net/socket/getsockopt.c
@@ -371,8 +371,8 @@ int psock_getsockopt(FAR struct socket *psock, int level, int option,
        break;
 #endif
 
-      case SOL_CAN_RAW:
-#ifdef CONFIG_NET_TCPPROTO_OPTIONS
+      case SOL_CAN_RAW:/* CAN protocol socket options (see include/netpacket/can.h) */
+#ifdef CONFIG_NET_CANPROTO_OPTIONS
        ret = can_getsockopt(psock, option, value, value_len);
 #endif
        break;
diff --git a/net/socket/setsockopt.c b/net/socket/setsockopt.c
index 211a1df..46e1b6e 100644
--- a/net/socket/setsockopt.c
+++ b/net/socket/setsockopt.c
@@ -399,6 +399,12 @@ int psock_setsockopt(FAR struct socket *psock, int level, int option,
         break;
 #endif
 
+#ifdef CONFIG_NET_CAN
+      case SOL_CAN_RAW:   /* CAN protocol socket options (see include/netpacket/can.h) */
+        ret = can_setsockopt(psock, option, value, value_len);
+        break;
+#endif
+
       default:         /* The provided level is invalid */
         ret = -EINVAL;
         break;