Пример #1
0
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;
}
Пример #2
0
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_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);

  /* Interrupts must disabled throughout the following */

  flags = irqsave();

  /* Check if the 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);

  /* Add the messages to the FIFO.  Ignore any trailing messages that are
   * shorter than the minimum.
   */

  while ((buflen - nsent) >= CAN_MSGLEN(0))
    {
      /* Check if adding this new message would over-run the drivers ability
       * to enqueue xmit data.
       */

      nexttail = fifo->tx_tail + 1;
      if (nexttail >= CONFIG_CAN_FIFOSIZE)
        {
          nexttail = 0;
        }

      /* If the XMIT FIFO becomes full, then wait for space to become available */

      while (nexttail == fifo->tx_head)
        {
          /* The transmit FIFO is full  -- was non-blocking mode selected? */

          if (filep->f_oflags & O_NONBLOCK)
            {
              if (nsent == 0)
                {
                  ret = -EAGAIN;
                }
              else
                {
                  ret = nsent;
                }

              goto return_with_irqdisabled;
            }

          /* If the TX hardware was inactive when we started, then we will have
           * start the XMIT sequence generate the TX done interrupts needed
           * to clear the FIFO.
           */

          if (inactive)
            {
              can_xmit(dev);
            }

          /* Wait for a message to be sent */

          do
            {
              DEBUGASSERT(dev->cd_ntxwaiters < 255);
              dev->cd_ntxwaiters++;
              ret = sem_wait(&fifo->tx_sem);
              dev->cd_ntxwaiters--;

              if (ret < 0 && get_errno() != EINTR)
                {
                  ret = -get_errno();
                  goto return_with_irqdisabled;
                }
            }
          while (ret < 0);

          /* Re-check the FIFO state */

          inactive = dev_txempty(dev);
        }

      /* We get here if there is space at the end of the FIFO.  Add the new
       * CAN message at the tail of the FIFO.
       */

      msg    = (FAR struct can_msg_s *)&buffer[nsent];
      msglen = CAN_MSGLEN(msg->cm_hdr.ch_dlc);
      memcpy(&fifo->tx_buffer[fifo->tx_tail], msg, msglen);

      /* Increment the tail of the circular buffer */

      fifo->tx_tail = nexttail;

      /* Increment the number of bytes that were sent */

      nsent += msglen;
    }

 /* We get here after all messages have been added to the FIFO.  Check if
  * we need to kick of the XMIT sequence.
  */

 if (inactive)
   {
     can_xmit(dev);
   }

  /* Return the number of bytes that were sent */

  ret = nsent;

return_with_irqdisabled:
  irqrestore(flags);
  return ret;
}