Skip to content

Commit

Permalink
nuttx/can: in trunk support to Send message cancel mechanism.
Browse files Browse the repository at this point in the history
add Send message cancel mechanism_1 based priority list.
  • Loading branch information
OceanfromXiaomi authored and xiaoxiang781216 committed Jan 17, 2025
1 parent 7d3ec5d commit 07f2600
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 4 deletions.
9 changes: 9 additions & 0 deletions drivers/can/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,15 @@ config CAN_TXPRIORITY
---help---
Prioritize sending based on canid.

config CAN_TXCANCEL
bool "Implement tx cancel ability"
default n
depends on CAN_TXPRIORITY
---help---
Enabling this feature adds support for the can cancel ability.
this ability can cancel the msg with the largest msgID in the
mailbox and return true if success.

choice
prompt "TX Ready Work Queue"
default CAN_TXREADY_HIPRI
Expand Down
34 changes: 31 additions & 3 deletions drivers/can/can.c
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,25 @@ static int can_xmit(FAR struct can_dev_s *dev)
}
}

#ifdef CONFIG_CAN_TXCANCEL
if (TX_PENDING(&dev->cd_sender) && can_txneed_cancel(&dev->cd_sender))
{
if (can_cancel_mbmsg(dev))
{
msg = can_get_msg(&dev->cd_sender);

/* Send the next message at the sender */

ret = dev_send(dev, msg);
if (ret < 0)
{
canerr("dev_send failed: %d\n", ret);
can_revert_msg(&dev->cd_sender, msg);
}
}
}
#endif

/* Make sure that TX interrupts are enabled */

dev_txint(dev, true);
Expand Down Expand Up @@ -594,13 +613,18 @@ static ssize_t can_write(FAR struct file *filep, FAR const char *buffer,

flags = enter_critical_section();

/* Check if the H/W TX is inactive when we started. In certain race
/* if CONFIG_CAN_TXCANCEL is enable, inactive will be always true, else
* Check if the H/W TX is inactive when we started. In certain race
* conditions, there may be a pending interrupt to kick things back off,
* but we will be sure here that there is not. That the hardware is IDLE
* and will need to be kick-started.
*/

inactive = dev_txempty(dev);
#ifdef CONFIG_CAN_TXCANCEL
inactive = true;
#else
inactive = dev_txready(dev);
#endif

/* Add the messages to the sender. Ignore any trailing messages that are
* shorter than the minimum.
Expand Down Expand Up @@ -653,7 +677,11 @@ static ssize_t can_write(FAR struct file *filep, FAR const char *buffer,

/* Re-check the H/W sender state */

inactive = dev_txempty(dev);
#ifdef CONFIG_CAN_TXCANCEL
inactive = true;
#else
inactive = dev_txready(dev);
#endif
}

/* We get here if there is space in sender. Add the new
Expand Down
83 changes: 83 additions & 0 deletions drivers/can/can_sender.c
Original file line number Diff line number Diff line change
Expand Up @@ -256,3 +256,86 @@ void can_send_done(FAR struct can_txcache_s *cd_sender)
}
#endif
}

/****************************************************************************
* Name: can_txneed_cancel
*
* Description:
* Compare the msgID between tx_sending and tx_pending's head when
* dev_txready return false and tx_pending is not empty, preserve the node
* with largest msgID in tx_sending into *callbackmsg_node. return true if
* the msgID in tx_pending's head < the smallest msgID in tx_sending.
*
****************************************************************************/

#ifdef CONFIG_CAN_TXCANCEL
bool can_txneed_cancel(FAR struct can_txcache_s *cd_sender)
{
FAR struct can_msg_node_s *msg_node;
FAR struct can_msg_node_s *tmp_node;

/* acquire min msgID from tx_sending and compare it with masgID
* in tx_pending list's head.
*/

if (SENDING_COUNT(cd_sender) == 0)
{
return false;
}

msg_node = list_first_entry(&cd_sender->tx_pending,
struct can_msg_node_s, list);
tmp_node = list_first_entry(&cd_sender->tx_sending,
struct can_msg_node_s, list);
if (msg_node->msg.cm_hdr.ch_id < tmp_node->msg.cm_hdr.ch_id)
{
return true;
}

return false;
}
#endif

/****************************************************************************
* Name: can_cancel_mbmsg
*
* Description:
* cancel the msg with the largest msgID in the mailbox and
* return true if success.
*
****************************************************************************/

#ifdef CONFIG_CAN_TXCANCEL
bool can_cancel_mbmsg(FAR struct can_dev_s *dev)
{
FAR struct can_msg_node_s *tmp_node;
FAR struct can_msg_node_s *callbackmsg_node;
FAR struct can_txcache_s *cd_sender = &dev->cd_sender;

callbackmsg_node = list_last_entry(&cd_sender->tx_sending,
struct can_msg_node_s, list);
if (dev->cd_ops->co_cancel != NULL &&
dev_cancel(dev, &callbackmsg_node->msg))
{
/* take tx_sending's specfic msg back into tx_pending. */

list_delete(&callbackmsg_node->list);

list_for_every_entry(&cd_sender->tx_pending, tmp_node,
struct can_msg_node_s, list)
{
if (tmp_node->msg.cm_hdr.ch_id >=
callbackmsg_node->msg.cm_hdr.ch_id)
{
break;
}
}

list_add_before(&tmp_node->list, &callbackmsg_node->list);

return true;
}

return false;
}
#endif
4 changes: 4 additions & 0 deletions include/nuttx/can/can.h
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@
#define dev_send(dev,m) (dev)->cd_ops->co_send(dev,m)
#define dev_txready(dev) (dev)->cd_ops->co_txready(dev)
#define dev_txempty(dev) (dev)->cd_ops->co_txempty(dev)
#define dev_cancel(dev,m) (dev)->cd_ops->co_cancel(dev,m)

/* CAN message support ******************************************************/

Expand Down Expand Up @@ -786,6 +787,9 @@ struct can_ops_s
*/

CODE bool (*co_txempty)(FAR struct can_dev_s *dev);

CODE bool (*co_cancel)(FAR struct can_dev_s *dev,
FAR struct can_msg_s *msg);
};

/* This is the device structure used by the driver. The caller of
Expand Down
30 changes: 29 additions & 1 deletion include/nuttx/can/can_sender.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,5 +235,33 @@ void can_revert_msg(FAR struct can_txcache_s *cd_sender,

void can_send_done(FAR struct can_txcache_s *cd_sender);

/****************************************************************************
* Name: can_txneed_cancel
*
* Description:
* Compare the msgID between tx_sending and tx_pending's head when
* dev_txready return false and tx_pending is not empty, preserve the node
* with largest msgID in tx_sending into *callbackmsg_node. return true if
* the msgID in tx_pending's head < the smallest msgID in tx_sending.
*
****************************************************************************/

#ifdef CONFIG_CAN_TXCANCEL
bool can_txneed_cancel(FAR struct can_txcache_s *cd_sender);
#endif

/****************************************************************************
* Name: can_cancel_mbmsg
*
* Description:
* cancel the msg with the largest msgID in the mailbox and
* return true if success.
*
****************************************************************************/

#ifdef CONFIG_CAN_TXCANCEL
bool can_cancel_mbmsg(FAR struct can_dev_s *dev);
#endif

#endif /* CONFIG_CAN */
#endif /* __INCLUDE_NUTTX_CAN_SENDER_H */
#endif /* __INCLUDE_NUTTX_CAN_SENDER_H */

0 comments on commit 07f2600

Please sign in to comment.