Exemplo n.º 1
0
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;
}
Exemplo n.º 2
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;
}
Exemplo n.º 3
0
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;
}