Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 34 additions & 68 deletions drivers/can/can.c
Original file line number Diff line number Diff line change
Expand Up @@ -365,10 +365,6 @@ static ssize_t can_read(FAR struct file *filep, FAR char *buffer,
FAR struct can_rxfifo_s *fifo;
irqstate_t flags;
int ret = 0;
#ifdef CONFIG_CAN_ERRORS
FAR struct inode *inode = filep->f_inode;
FAR struct can_dev_s *dev = inode->i_private;
#endif

caninfo("buflen: %zu\n", buflen);

Expand All @@ -388,18 +384,9 @@ static ssize_t can_read(FAR struct file *filep, FAR char *buffer,
flags = enter_critical_section();

#ifdef CONFIG_CAN_ERRORS

/* Check for reader fifo overflow */

if (fifo->rx_overflow)
{
dev->cd_error |= CAN_ERROR5_RXOVERFLOW;
fifo->rx_overflow = false;
}

/* Check for internal errors */

if (dev->cd_error != 0)
if (fifo->rx_error != 0)
{
FAR struct can_msg_s *msg;

Expand All @@ -422,11 +409,11 @@ static ssize_t can_read(FAR struct file *filep, FAR char *buffer,
#endif
msg->cm_hdr.ch_unused = 0;
memset(&(msg->cm_data), 0, CAN_ERROR_DLC);
msg->cm_data[5] = dev->cd_error;
msg->cm_data[5] = fifo->rx_error;

/* Reset the error flag */

dev->cd_error = 0;
fifo->rx_error = 0;

ret = CAN_MSGLEN(CAN_ERROR_DLC);
goto return_with_irqdisabled;
Expand Down Expand Up @@ -572,6 +559,7 @@ static int can_xmit(FAR struct can_dev_s *dev)
if (ret < 0)
{
canerr("dev_send failed: %d\n", ret);
dev->cd_xmit.tx_queue = tmpndx;
break;
}
}
Expand Down Expand Up @@ -893,19 +881,24 @@ static int can_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
}
break;

/* FIONWRITE: Return the number of CAN messages in the send queue */
/* FIONWRITE: Return the number of CAN messages in the send queue */

case FIONWRITE:
{
*(FAR uint8_t *)arg = dev->cd_xmit.tx_tail;
*(FAR uint8_t *)arg = CONFIG_CAN_FIFOSIZE - 1 -
(dev->cd_xmit.tx_tail - dev->cd_xmit.tx_head);
}
break;

/* FIONREAD: Return the number of CAN messages in the receive FIFO */
/* FIONREAD: Return the number of CAN messages in the receive FIFO */

case FIONREAD:
{
*(FAR uint8_t *)arg = reader->fifo.rx_tail;
*(FAR uint8_t *)arg =
#ifdef CONFIG_CAN_ERRORS
(reader->fifo.rx_error != 0) +
#endif
reader->fifo.rx_tail - reader->fifo.rx_head;
}
break;

Expand Down Expand Up @@ -934,9 +927,8 @@ static int can_poll(FAR struct file *filep, FAR struct pollfd *fds,
FAR struct can_dev_s *dev = inode->i_private;
FAR struct can_reader_s *reader = NULL;
pollevent_t eventset = 0;
int ndx;
int sval;
irqstate_t flags;
int ndx;
int ret;
int i;

Expand Down Expand Up @@ -1001,21 +993,8 @@ static int can_poll(FAR struct file *filep, FAR struct pollfd *fds,

/* Should we immediately notify on any of the requested events?
* First, check if the xmit buffer is full.
*
* Get exclusive access to the cd_xmit buffer indices. NOTE: that
* we do not let this wait be interrupted by a signal (we probably
* should, but that would be a little awkward).
*/

DEBUGASSERT(dev->cd_ntxwaiters < 255);
dev->cd_ntxwaiters++;
do
{
ret = nxsem_wait(&dev->cd_xmit.tx_sem);
}
while (ret < 0);
dev->cd_ntxwaiters--;

ndx = dev->cd_xmit.tx_tail + 1;
if (ndx >= CONFIG_CAN_FIFOSIZE)
{
Expand All @@ -1027,29 +1006,17 @@ static int can_poll(FAR struct file *filep, FAR struct pollfd *fds,
eventset |= POLLOUT;
}

nxsem_post(&dev->cd_xmit.tx_sem);

/* Check whether there are messages in the RX FIFO. */

ret = nxsem_get_value(&reader->fifo.rx_sem, &sval);

if (ret < 0)
{
DEBUGPANIC();
goto return_with_irqdisabled;
}
else if (sval > 0)
if (reader->fifo.rx_head != reader->fifo.rx_tail
#ifdef CONFIG_CAN_ERRORS
|| reader->fifo.rx_error != 0
#endif
)
{
if (reader->fifo.rx_head != reader->fifo.rx_tail)
{
/* No need to wait, just notify the application immediately */
/* No need to wait, just notify the application immediately */

eventset |= POLLIN;
}
else
{
canerr("RX FIFO sem not locked but FIFO is empty.\n");
}
eventset |= POLLIN;
}

poll_notify(&fds, 1, eventset);
Expand Down Expand Up @@ -1102,14 +1069,11 @@ int can_register(FAR const char *path, FAR struct can_dev_s *dev)
dev->cd_crefs = 0;
dev->cd_npendrtr = 0;
dev->cd_ntxwaiters = 0;
#ifdef CONFIG_CAN_ERRORS
dev->cd_error = 0;
#endif
list_initialize(&dev->cd_readers);

/* Initialize semaphores */

nxsem_init(&dev->cd_xmit.tx_sem, 0, 1);
nxsem_init(&dev->cd_xmit.tx_sem, 0, 0);
nxmutex_init(&dev->cd_closelock);
nxmutex_init(&dev->cd_polllock);

Expand Down Expand Up @@ -1251,21 +1215,14 @@ int can_receive(FAR struct can_dev_s *dev, FAR struct can_hdr_s *hdr,

fifo->rx_tail = nexttail;

/* Notify all poll/select waiters that they can read from the
* cd_recv buffer
*/

poll_notify(dev->cd_fds, CONFIG_CAN_NPOLLWAITERS, POLLIN);

if (nxsem_get_value(&fifo->rx_sem, &sval) < 0)
{
DEBUGPANIC();
#ifdef CONFIG_CAN_ERRORS
/* Report unspecified error */

dev->cd_error |= CAN_ERROR5_UNSPEC;
fifo->rx_error |= CAN_ERROR5_UNSPEC;
#endif
return -EINVAL;
continue;
}

/* Unlock the binary semaphore, waking up can_read if it is
Expand All @@ -1285,11 +1242,20 @@ int can_receive(FAR struct can_dev_s *dev, FAR struct can_hdr_s *hdr,
{
/* Report rx overflow error */

fifo->rx_overflow = true;
fifo->rx_error |= CAN_ERROR5_RXOVERFLOW;
}
#endif
}

/* Notify all poll/select waiters that they can read from the
* cd_recv buffer
*/

if (ret == OK)
{
poll_notify(dev->cd_fds, CONFIG_CAN_NPOLLWAITERS, POLLIN);
}

return ret;
}

Expand Down
5 changes: 1 addition & 4 deletions include/nuttx/can/can.h
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,7 @@ struct can_rxfifo_s
sem_t rx_sem;

#ifdef CONFIG_CAN_ERRORS
bool rx_overflow; /* Indicates the RX FIFO overflow event */
uint8_t rx_error; /* Flags to indicate internal device errors */
#endif
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 */
Expand Down Expand Up @@ -666,9 +666,6 @@ struct can_dev_s
uint8_t cd_crefs; /* References counts on number of opens */
uint8_t cd_npendrtr; /* Number of pending RTR messages */
volatile uint8_t cd_ntxwaiters; /* Number of threads waiting to enqueue a message */
#ifdef CONFIG_CAN_ERRORS
uint8_t cd_error; /* Flags to indicate internal device errors */
#endif
struct list_node cd_readers; /* List of readers */
mutex_t cd_closelock; /* Locks out new opens while close is in progress */
mutex_t cd_polllock; /* Manages exclusive access to cd_fds[] */
Expand Down