static int can_xmit(FAR struct can_dev_s *dev) { int tmpndx; int ret = -EBUSY; canllvdbg("xmit head: %d queue: %d tail: %d\n", dev->cd_xmit.tx_head, dev->cd_xmit.tx_queue, dev->cd_xmit.tx_tail); /* 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. */ while (dev->cd_xmit.tx_queue != dev->cd_xmit.tx_tail && dev_txready(dev)) { /* No.. The FIFO should not be empty in this case */ DEBUGASSERT(dev->cd_xmit.tx_head != dev->cd_xmit.tx_tail); /* Increment the FIFO queue index before sending (because dev_send() * might call can_txdone(). */ 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; } } /* Make sure that TX interrupts are enabled */ dev_txint(dev, true); return ret; }
int can_txdone(FAR struct can_dev_s *dev) { int ret = -ENOENT; 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.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.tx_head >= CONFIG_CAN_FIFOSIZE) { dev->cd_xmit.tx_head = 0; } /* Send the next message in the FIFO */ ret = can_xmit(dev); /* Are there any threads waiting for space in the TX FIFO? */ if (ret == OK && dev->cd_ntxwaiters > 0) { /* Yes.. Inform them that new xmit space is available */ ret = sem_post(&dev->cd_xmit.tx_sem); } } return ret; }
int can_receive(FAR struct can_dev_s *dev, FAR struct can_hdr_s *hdr, FAR uint8_t *data) { 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", hdr->ch_id, hdr->ch_dlc); /* Check if adding this new message would over-run the drivers ability to * enqueue read data. */ nexttail = fifo->rx_tail + 1; if (nexttail >= CONFIG_CAN_FIFOSIZE) { nexttail = 0; } /* First, check if this response matches any RTR response that we may be * waiting for. */ if (dev->cd_npendrtr > 0) { /* There are pending RTR requests -- search the lists of requests * and see any any matches this new message. */ for (i = 0; i < CONFIG_CAN_NPENDINGRTR; i++) { FAR struct can_rtrwait_s *rtr = &dev->cd_rtr[i]; FAR struct can_msg_s *msg = rtr->cr_msg; /* Check if the entry is valid and if the ID matches. A valid * entry has a non-NULL receiving address */ if (msg && hdr->ch_id == rtr->cr_id) { /* We have the response... copy the data to the user's buffer */ memcpy(&msg->cm_hdr, hdr, sizeof(struct can_hdr_s)); for (i = 0, dest = msg->cm_data; i < hdr->ch_dlc; i++) { *dest++ = *data++; } /* Mark the entry unused */ rtr->cr_msg = NULL; dev->cd_npendrtr--; /* And restart the waiting thread */ sem_post(&rtr->cr_sem); } } } /* Refuse the new data if the FIFO is full */ if (nexttail != fifo->rx_head) { /* Add the new, decoded CAN message at the tail of the FIFO */ memcpy(&fifo->rx_buffer[fifo->rx_tail].cm_hdr, hdr, sizeof(struct can_hdr_s)); for (i = 0, dest = fifo->rx_buffer[fifo->rx_tail].cm_data; i < hdr->ch_dlc; i++) { *dest++ = *data++; } /* Increment the tail of the circular buffer */ 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. */ if (dev->cd_nrxwaiters > 0) { sem_post(&fifo->rx_sem); } err = OK; } return err; }