From f325aa186d97621bc6e88e14e5c0175f86a3e6f0 Mon Sep 17 00:00:00 2001 From: zhaohaiyang1 Date: Mon, 14 Oct 2024 13:47:07 +0800 Subject: [PATCH] nuttx/can: in trunk support to Send message cancel mechanism. add Send message cancel mechanism_1 based priority list. --- drivers/can/Kconfig | 9 ++++ drivers/can/can.c | 34 ++++++++++++-- drivers/can/can_sender.c | 83 ++++++++++++++++++++++++++++++++++ include/nuttx/can/can.h | 4 ++ include/nuttx/can/can_sender.h | 30 +++++++++++- 5 files changed, 156 insertions(+), 4 deletions(-) diff --git a/drivers/can/Kconfig b/drivers/can/Kconfig index 9e321b8218c..4f3bce5dc00 100644 --- a/drivers/can/Kconfig +++ b/drivers/can/Kconfig @@ -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 diff --git a/drivers/can/can.c b/drivers/can/can.c index b319b2aec6a..76b7aa35603 100644 --- a/drivers/can/can.c +++ b/drivers/can/can.c @@ -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); @@ -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. @@ -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 diff --git a/drivers/can/can_sender.c b/drivers/can/can_sender.c index 062461a9668..fe6cdbd3cd1 100644 --- a/drivers/can/can_sender.c +++ b/drivers/can/can_sender.c @@ -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 \ No newline at end of file diff --git a/include/nuttx/can/can.h b/include/nuttx/can/can.h index dc544c32998..cbba371d5ee 100644 --- a/include/nuttx/can/can.h +++ b/include/nuttx/can/can.h @@ -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 ******************************************************/ @@ -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 diff --git a/include/nuttx/can/can_sender.h b/include/nuttx/can/can_sender.h index 706aa666edb..40beea01d15 100644 --- a/include/nuttx/can/can_sender.h +++ b/include/nuttx/can/can_sender.h @@ -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 */ \ No newline at end of file