9
0
Fork 0

Fix last change; the change was good but will prevent queuing multiple outgoing CAN packets

git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@4293 7fd9a85b-ad96-42d3-883c-3090e2eb8679
This commit is contained in:
patacongo 2012-01-11 05:03:51 +00:00
parent f350f95af0
commit 3d8cf0f510
2 changed files with 112 additions and 62 deletions

View File

@ -169,10 +169,11 @@ static int can_open(FAR struct file *filep)
{
/* Mark the FIFOs empty */
dev->cd_xmit.cf_head = 0;
dev->cd_xmit.cf_tail = 0;
dev->cd_recv.cf_head = 0;
dev->cd_recv.cf_tail = 0;
dev->cd_xmit.tx_head = 0;
dev->cd_xmit.tx_queue = 0;
dev->cd_xmit.tx_tail = 0;
dev->cd_recv.rx_head = 0;
dev->cd_recv.rx_tail = 0;
/* Finally, Enable the CAN RX interrupt */
@ -235,7 +236,7 @@ static int can_close(FAR struct file *filep)
/* Now we wait for the transmit FIFO to clear */
while (dev->cd_xmit.cf_head != dev->cd_xmit.cf_tail)
while (dev->cd_xmit.tx_head != dev->cd_xmit.tx_tail)
{
#ifndef CONFIG_DISABLE_SIGNALS
usleep(HALF_SECOND_USEC);
@ -294,7 +295,7 @@ static ssize_t can_read(FAR struct file *filep, FAR char *buffer, size_t buflen)
/* Interrupts must be disabled while accessing the cd_recv FIFO */
flags = irqsave();
while (dev->cd_recv.cf_head == dev->cd_recv.cf_tail)
while (dev->cd_recv.rx_head == dev->cd_recv.rx_tail)
{
/* The receive FIFO is empty -- was non-blocking mode selected? */
@ -306,7 +307,7 @@ static ssize_t can_read(FAR struct file *filep, FAR char *buffer, size_t buflen)
/* Wait for a message to be received */
ret = sem_wait(&dev->cd_recv.cf_sem);
ret = sem_wait(&dev->cd_recv.rx_sem);
if (ret < 0)
{
ret = -errno;
@ -323,7 +324,7 @@ static ssize_t can_read(FAR struct file *filep, FAR char *buffer, size_t buflen)
{
/* Will the next message in the FIFO fit into the user buffer? */
FAR struct can_msg_s *msg = &dev->cd_recv.cf_buffer[dev->cd_recv.cf_head];
FAR struct can_msg_s *msg = &dev->cd_recv.rx_buffer[dev->cd_recv.rx_head];
int msglen = CAN_MSGLEN(msg->cm_hdr);
if (nread + msglen > buflen)
@ -338,12 +339,12 @@ static ssize_t can_read(FAR struct file *filep, FAR char *buffer, size_t buflen)
/* Increment the head of the circular message buffer */
if (++dev->cd_recv.cf_head >= CONFIG_CAN_FIFOSIZE)
if (++dev->cd_recv.rx_head >= CONFIG_CAN_FIFOSIZE)
{
dev->cd_recv.cf_head = 0;
dev->cd_recv.rx_head = 0;
}
}
while (dev->cd_recv.cf_head != dev->cd_recv.cf_tail);
while (dev->cd_recv.rx_head != dev->cd_recv.rx_tail);
/* All on the messages have bee transferred. Return the number of bytes
* that were read.
@ -370,26 +371,62 @@ return_with_irqdisabled:
static int can_xmit(FAR struct can_dev_s *dev)
{
bool enable = false;
int ret = OK;
int tmpndx;
int ret = -EBUSY;
canllvdbg("xmit head: %d tail: %d\n", dev->cd_xmit.cf_head, dev->cd_xmit.cf_tail);
canllvdbg("xmit head: %d queue: %d tail: %d\n",
dev->cd_xmit.tx_head, dev->cd_xmit.tx_queue, dev->cd_xmit.tx_tail);
/* Check if the xmit FIFO is not empty and the CAN hardware is ready to accept
* more data.
/* If there is nothing to send, then just disable interrupts and return */
if (dev->cd_xmit.tx_head == dev->cd_xmit.tx_tail)
{
DEBUGASSERT(dev->cd_xmit.tx_queue == dev->cd_xmit.tx_head);
dev_txint(dev, false);
return -EIO;
}
/* Check if we have already queued all of the data in the TX fifo.
*
* tx_tail: Incremented in can_write each time a message is queued in the FIFO
* tx_head: Incremented in can_txdone each time a message completes
* tx_queue: Incremented each time that a message is sent to the hardware.
*
* Logically (ignoring buffer wrap-around): tx_head <= tx_queue <= tx_tail
* tx_head == tx_queue == tx_tail means that the FIFO is empty
* tx_head < tx_queue == tx_tail means that all data has been queued, but
* we are still waiting for transmissions to complete.
*/
if (dev->cd_xmit.cf_head != dev->cd_xmit.cf_tail && dev_txready(dev))
while (dev->cd_xmit.tx_queue != dev->cd_xmit.tx_tail && dev_txready(dev))
{
/* Send the next message at the head of the FIFO */
/* No.. The fifo should not be empty in this case */
ret = dev_send(dev, &dev->cd_xmit.cf_buffer[dev->cd_xmit.cf_head]);
DEBUGASSERT(dev->cd_xmit.tx_head != dev->cd_xmit.tx_tail);
/* Make sure the TX done interrupts are enabled */
/* Increment the FIFO queue index before sending (because dev_send()
* might call can_txdone().
*/
enable = (ret == OK ? true : false);
tmpndx = dev->cd_xmit.tx_queue;
if (++dev->cd_xmit.tx_queue >= CONFIG_CAN_FIFOSIZE)
{
dev->cd_xmit.tx_queue = 0;
}
/* Send the next message at the FIFO queue index */
ret = dev_send(dev, &dev->cd_xmit.tx_buffer[tmpndx]);
if (ret != OK)
{
candbg("dev_send failed: %d\n", ret);
break;
}
}
dev_txint(dev, enable);
/* Make sure that TX interrupts are enabled */
dev_txint(dev, true);
return ret;
}
@ -399,16 +436,16 @@ static int can_xmit(FAR struct can_dev_s *dev)
static ssize_t can_write(FAR struct file *filep, FAR const char *buffer, size_t buflen)
{
FAR struct inode *inode = filep->f_inode;
FAR struct can_dev_s *dev = inode->i_private;
FAR struct can_fifo_s *fifo = &dev->cd_xmit;
FAR struct can_msg_s *msg;
bool inactive;
ssize_t nsent = 0;
irqstate_t flags;
int nexttail;
int msglen;
int ret = 0;
FAR struct inode *inode = filep->f_inode;
FAR struct can_dev_s *dev = inode->i_private;
FAR struct can_txfifo_s *fifo = &dev->cd_xmit;
FAR struct can_msg_s *msg;
bool inactive;
ssize_t nsent = 0;
irqstate_t flags;
int nexttail;
int msglen;
int ret = 0;
canvdbg("buflen: %d\n", buflen);
@ -433,7 +470,7 @@ static ssize_t can_write(FAR struct file *filep, FAR const char *buffer, size_t
* xmit data.
*/
nexttail = fifo->cf_tail + 1;
nexttail = fifo->tx_tail + 1;
if (nexttail >= CONFIG_CAN_FIFOSIZE)
{
nexttail = 0;
@ -441,7 +478,7 @@ static ssize_t can_write(FAR struct file *filep, FAR const char *buffer, size_t
/* If the XMIT fifo becomes full, then wait for space to become available */
while (nexttail == fifo->cf_head)
while (nexttail == fifo->tx_head)
{
/* The transmit FIFO is full -- was non-blocking mode selected? */
@ -474,7 +511,7 @@ static ssize_t can_write(FAR struct file *filep, FAR const char *buffer, size_t
{
DEBUGASSERT(dev->cd_ntxwaiters < 255);
dev->cd_ntxwaiters++;
ret = sem_wait(&fifo->cf_sem);
ret = sem_wait(&fifo->tx_sem);
dev->cd_ntxwaiters--;
if (ret < 0 && errno != EINTR)
@ -496,11 +533,11 @@ static ssize_t can_write(FAR struct file *filep, FAR const char *buffer, size_t
msg = (FAR struct can_msg_s *)&buffer[nsent];
msglen = CAN_MSGLEN(msg->cm_hdr);
memcpy(&fifo->cf_buffer[fifo->cf_tail], msg, msglen);
memcpy(&fifo->tx_buffer[fifo->tx_tail], msg, msglen);
/* Increment the tail of the circular buffer */
fifo->cf_tail = nexttail;
fifo->tx_tail = nexttail;
/* Increment the number of bytes that were sent */
@ -632,8 +669,8 @@ int can_register(FAR const char *path, FAR struct can_dev_s *dev)
dev->cd_ocount = 0;
sem_init(&dev->cd_xmit.cf_sem, 0, 0);
sem_init(&dev->cd_recv.cf_sem, 0, 0);
sem_init(&dev->cd_xmit.tx_sem, 0, 0);
sem_init(&dev->cd_recv.rx_sem, 0, 0);
sem_init(&dev->cd_closesem, 0, 1);
for (i = 0; i < CONFIG_CAN_NPENDINGRTR; i++)
@ -671,11 +708,11 @@ int can_register(FAR const char *path, FAR struct can_dev_s *dev)
int can_receive(FAR struct can_dev_s *dev, uint16_t hdr, FAR uint8_t *data)
{
FAR struct can_fifo_s *fifo = &dev->cd_recv;
FAR uint8_t *dest;
int nexttail;
int err = -ENOMEM;
int i;
FAR struct can_rxfifo_s *fifo = &dev->cd_recv;
FAR uint8_t *dest;
int nexttail;
int err = -ENOMEM;
int i;
canllvdbg("ID: %d DLC: %d\n", CAN_ID(hdr), CAN_DLC(hdr));
@ -683,7 +720,7 @@ int can_receive(FAR struct can_dev_s *dev, uint16_t hdr, FAR uint8_t *data)
* read data.
*/
nexttail = fifo->cf_tail + 1;
nexttail = fifo->rx_tail + 1;
if (nexttail >= CONFIG_CAN_FIFOSIZE)
{
nexttail = 0;
@ -729,25 +766,25 @@ int can_receive(FAR struct can_dev_s *dev, uint16_t hdr, FAR uint8_t *data)
/* Refuse the new data if the FIFO is full */
if (nexttail != fifo->cf_head)
if (nexttail != fifo->rx_head)
{
/* Add the new, decoded CAN message at the tail of the FIFO */
fifo->cf_buffer[fifo->cf_tail].cm_hdr = hdr;
for (i = 0, dest = fifo->cf_buffer[fifo->cf_tail].cm_data; i < CAN_DLC(hdr); i++)
fifo->rx_buffer[fifo->rx_tail].cm_hdr = hdr;
for (i = 0, dest = fifo->rx_buffer[fifo->rx_tail].cm_data; i < CAN_DLC(hdr); i++)
{
*dest++ = *data++;
}
/* Increment the tail of the circular buffer */
fifo->cf_tail = nexttail;
fifo->rx_tail = nexttail;
/* The increment the counting semaphore. The maximum value should be
* CONFIG_CAN_FIFOSIZE -- one possible count for each allocated message buffer.
*/
sem_post(&fifo->cf_sem);
sem_post(&fifo->rx_sem);
err = OK;
}
return err;
@ -773,17 +810,20 @@ int can_txdone(FAR struct can_dev_s *dev)
{
int ret = -ENOENT;
canllvdbg("xmit head: %d tail: %d\n", dev->cd_xmit.cf_head, dev->cd_xmit.cf_tail);
canllvdbg("xmit head: %d queue: %d tail: %d\n",
dev->cd_xmit.tx_head, dev->cd_xmit.tx_queue, dev->cd_xmit.tx_tail);
/* Verify that the xmit FIFO is not empty */
if (dev->cd_xmit.cf_head != dev->cd_xmit.cf_tail)
if (dev->cd_xmit.tx_head != dev->cd_xmit.tx_tail)
{
DEBUGASSERT(dev->cd_xmit.tx_head != dev->cd_xmit.tx_queue);
/* Remove the message at the head of the xmit FIFO */
if (++dev->cd_xmit.cf_head >= CONFIG_CAN_FIFOSIZE)
if (++dev->cd_xmit.tx_head >= CONFIG_CAN_FIFOSIZE)
{
dev->cd_xmit.cf_head = 0;
dev->cd_xmit.tx_head = 0;
}
/* Send the next message in the FIFO */
@ -796,7 +836,7 @@ int can_txdone(FAR struct can_dev_s *dev)
{
/* Yes.. Inform them that new xmit space is available */
ret = sem_post(&dev->cd_xmit.cf_sem);
ret = sem_post(&dev->cd_xmit.tx_sem);
}
}
return ret;

View File

@ -140,13 +140,23 @@ struct can_msg_s
/* This structure defines a CAN message FIFO. */
struct can_fifo_s
struct can_rxfifo_s
{
sem_t cf_sem; /* Counting semaphore */
uint8_t cf_head; /* Index to the head [IN] index in the circular buffer */
uint8_t cf_tail; /* Index to the tail [OUT] index in the circular buffer */
sem_t rx_sem; /* Counting semaphore */
uint8_t rx_head; /* Index to the head [IN] in the circular buffer */
uint8_t rx_tail; /* Index to the tail [OUT] in the circular buffer */
/* Circular buffer of CAN messages */
struct can_msg_s cf_buffer[CONFIG_CAN_FIFOSIZE];
struct can_msg_s rx_buffer[CONFIG_CAN_FIFOSIZE];
};
struct can_txfifo_s
{
sem_t tx_sem; /* Counting semaphore */
uint8_t tx_head; /* Index to the head [IN] in the circular buffer */
uint8_t tx_queue; /* Index to next message to send */
uint8_t tx_tail; /* Index to the tail [OUT] in the circular buffer */
/* Circular buffer of CAN messages */
struct can_msg_s tx_buffer[CONFIG_CAN_FIFOSIZE];
};
/* The following structure define the logic to handle one RTR message transaction */
@ -235,8 +245,8 @@ struct can_dev_s
uint8_t cd_ntxwaiters; /* Number of threads waiting to enqueue a message */
sem_t cd_closesem; /* Locks out new opens while close is in progress */
sem_t cd_recvsem; /* Used to wakeup user waiting for space in cd_recv.buffer */
struct can_fifo_s cd_xmit; /* Describes transmit FIFO */
struct can_fifo_s cd_recv; /* Describes receive FIFO */
struct can_txfifo_s cd_xmit; /* Describes transmit FIFO */
struct can_rxfifo_s cd_recv; /* Describes receive FIFO */
/* List of pending RTR requests */
struct can_rtrwait_s cd_rtr[CONFIG_CAN_NPENDINGRTR];
FAR const struct can_ops_s *cd_ops; /* Arch-specific operations */