diff --git a/drivers/can/can.c b/drivers/can/can.c index dea1d0fa67..be8165f441 100644 --- a/drivers/can/can.c +++ b/drivers/can/can.c @@ -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); @@ -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; @@ -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; @@ -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; } } @@ -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; @@ -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; @@ -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) { @@ -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) + if (reader->fifo.rx_head != reader->fifo.rx_tail +#ifdef CONFIG_CAN_ERRORS + || reader->fifo.rx_error != 0 +#endif + ) { - DEBUGPANIC(); - goto return_with_irqdisabled; - } - else if (sval > 0) - { - 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); @@ -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); @@ -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 @@ -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; } diff --git a/include/nuttx/can/can.h b/include/nuttx/can/can.h index 054876418f..1d53e8442b 100644 --- a/include/nuttx/can/can.h +++ b/include/nuttx/can/can.h @@ -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 */ @@ -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[] */