net/can: deliver data into multiple CAN conn bound to same dev
Because CAN is a broadcast protocol, each conn needs to be given independent data to avoid mutual interference. Signed-off-by: zhanghongyu <zhanghongyu@xiaomi.com>
This commit is contained in:
parent
589bb56bcb
commit
a9bff735e7
@ -184,6 +184,25 @@ void can_free(FAR struct can_conn_s *conn);
|
||||
|
||||
FAR struct can_conn_s *can_nextconn(FAR struct can_conn_s *conn);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: can_active()
|
||||
*
|
||||
* Description:
|
||||
* Traverse the list of NetLink connections that match dev
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - The device to search for.
|
||||
* conn - The current connection; may be NULL to start the search at the
|
||||
* beginning
|
||||
*
|
||||
* Assumptions:
|
||||
* This function is called from NetLink device logic.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct can_conn_s *can_active(FAR struct net_driver_s *dev,
|
||||
FAR struct can_conn_s *conn);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: can_callback
|
||||
*
|
||||
|
@ -225,4 +225,34 @@ FAR struct can_conn_s *can_nextconn(FAR struct can_conn_s *conn)
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: can_active()
|
||||
*
|
||||
* Description:
|
||||
* Traverse the list of NetLink connections that match dev
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - The device to search for.
|
||||
* conn - The current connection; may be NULL to start the search at the
|
||||
* beginning
|
||||
*
|
||||
* Assumptions:
|
||||
* This function is called from NetLink device logic.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct can_conn_s *can_active(FAR struct net_driver_s *dev,
|
||||
FAR struct can_conn_s *conn)
|
||||
{
|
||||
while ((conn = can_nextconn(conn)) != NULL)
|
||||
{
|
||||
if (conn->dev == NULL || conn->dev == dev)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NET_CAN */
|
||||
|
@ -127,6 +127,67 @@ const uint8_t len_to_can_dlc[65] =
|
||||
15,
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: can_input_conn
|
||||
*
|
||||
* Description:
|
||||
* Handle incoming packet input
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - The device driver structure containing the received packet
|
||||
* conn - A pointer to the CAN connection structure
|
||||
*
|
||||
* Returned Value:
|
||||
* OK The packet has been processed and can be deleted
|
||||
* -EAGAIN There is a matching connection, but could not dispatch the packet
|
||||
* yet. Useful when a packet arrives before a recv call is in
|
||||
* place.
|
||||
*
|
||||
* Assumptions:
|
||||
* This function can be called from an interrupt.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int can_input_conn(FAR struct net_driver_s *dev,
|
||||
FAR struct can_conn_s *conn)
|
||||
{
|
||||
uint16_t flags;
|
||||
uint16_t buflen = dev->d_len;
|
||||
int ret = OK;
|
||||
|
||||
/* Setup for the application callback */
|
||||
|
||||
dev->d_appdata = dev->d_buf;
|
||||
dev->d_sndlen = 0;
|
||||
dev->d_len = buflen;
|
||||
|
||||
/* Perform the application callback */
|
||||
|
||||
flags = can_callback(dev, conn, CAN_NEWDATA);
|
||||
|
||||
/* If the operation was successful, the CAN_NEWDATA flag is removed
|
||||
* and thus the packet can be deleted (OK will be returned).
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
@ -151,50 +212,36 @@ const uint8_t len_to_can_dlc[65] =
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int can_in(struct net_driver_s *dev)
|
||||
static int can_in(FAR struct net_driver_s *dev)
|
||||
{
|
||||
FAR struct can_conn_s *conn = NULL;
|
||||
int ret = OK;
|
||||
uint16_t buflen = dev->d_len;
|
||||
FAR struct can_conn_s *conn = can_active(dev, NULL);
|
||||
FAR struct can_conn_s *nextconn;
|
||||
|
||||
do
|
||||
/* Do we have second connection that can hold this packet? */
|
||||
|
||||
while ((nextconn = can_active(dev, conn)) != NULL)
|
||||
{
|
||||
conn = can_nextconn(conn);
|
||||
/* Yes... There are multiple listeners on the same dev.
|
||||
* We need to clone the packet and deliver it to each listener.
|
||||
*/
|
||||
|
||||
if (conn && (conn->dev == NULL || dev == conn->dev))
|
||||
FAR struct iob_s *iob = netdev_iob_clone(dev, false);
|
||||
|
||||
if (iob == NULL)
|
||||
{
|
||||
uint16_t flags;
|
||||
|
||||
/* Setup for the application callback */
|
||||
|
||||
dev->d_appdata = dev->d_buf;
|
||||
dev->d_sndlen = 0;
|
||||
dev->d_len = buflen;
|
||||
|
||||
/* Perform the application callback */
|
||||
|
||||
flags = can_callback(dev, conn, CAN_NEWDATA);
|
||||
|
||||
/* If the operation was successful, the CAN_NEWDATA flag is removed
|
||||
* and thus the packet can be deleted (OK will be returned).
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
nerr("ERROR: IOB clone failed.\n");
|
||||
break; /* We can still process one time without clone. */
|
||||
}
|
||||
}
|
||||
while (conn);
|
||||
|
||||
return ret;
|
||||
can_input_conn(dev, conn);
|
||||
|
||||
netdev_iob_replace(dev, iob);
|
||||
conn = nextconn;
|
||||
}
|
||||
|
||||
/* We can deliver the packet directly to the last listener. */
|
||||
|
||||
return can_input_conn(dev, conn);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
Loading…
x
Reference in New Issue
Block a user