Beispiel #1
0
static ssize_t can_read(FAR struct file *filep, FAR char *buffer,
                        size_t buflen)
{
  FAR struct inode     *inode = filep->f_inode;
  FAR struct can_dev_s *dev   = inode->i_private;
  size_t                nread;
  irqstate_t            flags;
  int                   ret   = 0;

  canvdbg("buflen: %d\n", buflen);

  /* The caller must provide enough memory to catch the smallest possible
   * message.  This is not a system error condition, but we won't permit
   * it,  Hence we return 0.
   */

  if (buflen >= CAN_MSGLEN(0))
    {
      /* Interrupts must be disabled while accessing the cd_recv FIFO */

      flags = irqsave();
      while (dev->cd_recv.rx_head == dev->cd_recv.rx_tail)
        {
          /* The receive FIFO is empty -- was non-blocking mode selected? */

          if (filep->f_oflags & O_NONBLOCK)
            {
              ret = -EAGAIN;
              goto return_with_irqdisabled;
            }

          /* Wait for a message to be received */

          dev->cd_nrxwaiters++;
          do
            {
              ret = sem_wait(&dev->cd_recv.rx_sem);
            }
          while (ret >= 0 && dev->cd_recv.rx_head == dev->cd_recv.rx_tail);
          dev->cd_nrxwaiters--;

          if (ret < 0)
            {
              ret = -get_errno();
              goto return_with_irqdisabled;
            }
        }

      /* The cd_recv FIFO is not empty.  Copy all buffered data that will fit
       * in the user buffer.
       */

      nread = 0;
      do
        {
          /* Will the next message in the FIFO fit into the user buffer? */

          FAR struct can_msg_s *msg = &dev->cd_recv.rx_buffer[dev->cd_recv.rx_head];
          int msglen = CAN_MSGLEN(msg->cm_hdr.ch_dlc);

          if (nread + msglen > buflen)
            {
              break;
            }

          /* Copy the message to the user buffer */

          memcpy(&buffer[nread], msg, msglen);
          nread += msglen;

          /* Increment the head of the circular message buffer */

          if (++dev->cd_recv.rx_head >= CONFIG_CAN_FIFOSIZE)
            {
              dev->cd_recv.rx_head = 0;
            }
        }
      while (dev->cd_recv.rx_head != dev->cd_recv.rx_tail);

      /* All on the messages have bee transferred.  Return the number of bytes
       * that were read.
       */

      ret = nread;

return_with_irqdisabled:
      irqrestore(flags);
    }

  return ret;
}
Beispiel #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;
}
Beispiel #3
0
int can_main(int argc, FAR char *argv[])
#endif
{
  struct canioc_bittiming_s bt;

#ifdef CONFIG_EXAMPLES_CAN_WRITE
  struct can_msg_s txmsg;
#ifdef CONFIG_CAN_EXTID
  bool extended = true;
  uint32_t msgid;
#else
  uint16_t msgid;
#endif
  long minid    = 1;
  long maxid    = MAX_ID;
  int msgdlc;
  uint8_t msgdata;
  int i;
#endif

#ifdef CONFIG_EXAMPLES_CAN_READ
  struct can_msg_s rxmsg;
#endif

  size_t msgsize;
  ssize_t nbytes;
  bool badarg   = false;
  bool help     = false;
#ifdef CONFIG_NSH_BUILTIN_APPS
  long nmsgs    = CONFIG_EXAMPLES_CAN_NMSGS;
  long msgno;
#endif
  int option;
  int fd;
  int errval    = 0;
  int ret;

  /* Parse command line parameters */

  while ((option = getopt(argc, argv, OPT_STR)) != ERROR)
    {
      switch (option)
        {
#ifdef CONFIG_EXAMPLES_CAN_WRITE
#ifdef CONFIG_CAN_EXTID
          case 's':
            extended = false;
            break;
#endif

          case 'a':
            minid = strtol(optarg, NULL, 10);
            if (minid < 1 || minid > maxid)
              {
                fprintf(stderr, "<min-id> out of range\n");
                badarg = true;
              }
            break;

          case 'b':
            maxid = strtol(optarg, NULL, 10);
            if (maxid < minid || maxid > MAX_ID)
              {
                fprintf(stderr, "ERROR: <max-id> out of range\n");
                badarg = true;
              }
            break;
#endif

          case 'h':
            help = true;
            break;

#ifdef CONFIG_NSH_BUILTIN_APPS
          case 'n':
            nmsgs = strtol(optarg, NULL, 10);
            if (nmsgs < 1)
              {
                fprintf(stderr, "ERROR: <nmsgs> out of range\n");
                badarg = true;
              }
            break;
#endif

          case ':':
            fprintf(stderr, "ERROR: Bad option argument\n");
            badarg = true;
            break;

          case '?':
          default:
            fprintf(stderr, "ERROR: Unrecognized option\n");
            badarg = true;
            break;
        }
    }

  if (badarg)
    {
      show_usage(argv[0]);
      return EXIT_FAILURE;
    }

  if (help)
    {
      show_usage(argv[0]);
      return EXIT_SUCCESS;
    }

#if defined(CONFIG_EXAMPLES_CAN_WRITE) && defined(CONFIG_CAN_EXTID)
  if (!extended && maxid > CAN_MAX_STDMSGID)
    {
      maxid = CAN_MAX_STDMSGID;
      if (minid > maxid)
        {
          minid = maxid;
        }
    }
#endif

  if (optind != argc)
    {
      fprintf(stderr, "ERROR: Garbage on command line\n");
      show_usage(argv[0]);
      return EXIT_FAILURE;
    }

#ifdef CONFIG_NSH_BUILTIN_APPS
  printf("nmsgs: %d\n", nmsgs);
#endif
#ifdef CONFIG_EXAMPLES_CAN_WRITE
  printf("min ID: %ld max ID: %ld\n", minid, maxid);
#endif

  /* Initialization of the CAN hardware is performed by logic external to
   * this test.
   */

  ret = boardctl(BOARDIOC_CAN_INITIALIZE, 0);
  if (ret < 0)
    {
      printf("ERROR: BOARDIOC_CAN_INITIALIZE failed: %d\n", ret);
      errval = 1;
      goto errout;
    }

  /* Open the CAN device for reading */

  fd = open(CONFIG_EXAMPLES_CAN_DEVPATH, CAN_OFLAGS);
  if (fd < 0)
    {
      printf("ERROR: open %s failed: %d\n",
             CONFIG_EXAMPLES_CAN_DEVPATH, errno);
      errval = 2;
      goto errout_with_dev;
    }

  /* Show bit timing information if provided by the driver.  Not all CAN
   * drivers will support this IOCTL.
   */

  ret = ioctl(fd, CANIOC_GET_BITTIMING, (unsigned long)((uintptr_t)&bt));
  if (ret < 0)
    {
      printf("Bit timing not available: %d\n", errno);
    }
  else
    {
      printf("Bit timing:\n");
      printf("   Baud: %lu\n", (unsigned long)bt.bt_baud);
      printf("  TSEG1: %u\n", bt.bt_tseg1);
      printf("  TSEG2: %u\n", bt.bt_tseg2);
      printf("    SJW: %u\n", bt.bt_sjw);
    }

  /* Now loop the appropriate number of times, performing one loopback test
   * on each pass.
   */

#ifdef CONFIG_EXAMPLES_CAN_WRITE
  msgdlc  = 1;
  msgid   = minid;
  msgdata = 0;
#endif

#ifdef CONFIG_NSH_BUILTIN_APPS
  for (msgno = 0; msgno < nmsgs; msgno++)
#else
  for (; ; )
#endif
    {
      /* Flush any output before the loop entered or from the previous pass
       * through the loop.
       */

      fflush(stdout);

#ifdef CONFIG_EXAMPLES_CAN_WRITE

      /* Construct the next TX message */

      txmsg.cm_hdr.ch_id     = msgid;
      txmsg.cm_hdr.ch_rtr    = false;
      txmsg.cm_hdr.ch_dlc    = msgdlc;
#ifdef CONFIG_CAN_ERRORS
      txmsg.cm_hdr.ch_error  = 0;
#endif
#ifdef CONFIG_CAN_EXTID
      txmsg.cm_hdr.ch_extid  = extended;
#endif
      txmsg.cm_hdr.ch_unused = 0;

      for (i = 0; i < msgdlc; i++)
        {
          txmsg.cm_data[i] = msgdata + i;
        }

      /* Send the TX message */

      msgsize = CAN_MSGLEN(msgdlc);
      nbytes = write(fd, &txmsg, msgsize);
      if (nbytes != msgsize)
        {
          printf("ERROR: write(%ld) returned %ld\n",
                 (long)msgsize, (long)nbytes);
          errval = 3;
          goto errout_with_dev;
        }

      printf("  ID: %4u DLC: %d\n", msgid, msgdlc);

#endif

#ifdef CONFIG_EXAMPLES_CAN_READ

      /* Read the RX message */

      msgsize = sizeof(struct can_msg_s);
      nbytes = read(fd, &rxmsg, msgsize);
      if (nbytes < CAN_MSGLEN(0) || nbytes > msgsize)
        {
          printf("ERROR: read(%ld) returned %ld\n",
                 (long)msgsize, (long)nbytes);
          errval = 4;
          goto errout_with_dev;
        }

      printf("  ID: %4u DLC: %u\n",
             rxmsg.cm_hdr.ch_id, rxmsg.cm_hdr.ch_dlc);

#ifdef CONFIG_CAN_ERRORS
      /* Check for error reports */

      if (rxmsg.cm_hdr.ch_error != 0)
        {
          printf("ERROR: CAN error report: [0x%04x]\n", rxmsg.cm_hdr.ch_id);
          if ((rxmsg.cm_hdr.ch_id & CAN_ERROR_TXTIMEOUT) != 0)
            {
              printf("  TX timeout\n");
            }

          if ((rxmsg.cm_hdr.ch_id & CAN_ERROR_LOSTARB) != 0)
            {
              printf("  Lost arbitration: %02x\n", rxmsg.cm_data[0]);
            }

          if ((rxmsg.cm_hdr.ch_id & CAN_ERROR_CONTROLLER) != 0)
            {
              printf("  Controller error: %02x\n", rxmsg.cm_data[1]);
            }

          if ((rxmsg.cm_hdr.ch_id & CAN_ERROR_PROTOCOL) != 0)
            {
              printf("  Protocol error: %02x %02x\n", rxmsg.cm_data[2], rxmsg.cm_data[3]);
            }

          if ((rxmsg.cm_hdr.ch_id & CAN_ERROR_TRANSCEIVER) != 0)
            {
              printf("  Transceiver error: %02x\n", rxmsg.cm_data[4]);
            }

          if ((rxmsg.cm_hdr.ch_id & CAN_ERROR_NOACK) != 0)
            {
              printf("  No ACK received on transmission\n");
            }

          if ((rxmsg.cm_hdr.ch_id & CAN_ERROR_BUSOFF) != 0)
            {
              printf("  Bus off\n");
            }

          if ((rxmsg.cm_hdr.ch_id & CAN_ERROR_BUSERROR) != 0)
            {
              printf("  Bus error\n");
            }

          if ((rxmsg.cm_hdr.ch_id & CAN_ERROR_RESTARTED) != 0)
            {
              printf("  Controller restarted\n");
            }
        }
      else
#endif
        {
#if defined(CONFIG_EXAMPLES_CAN_WRITE) && defined(CONFIG_CAN_LOOPBACK)

          /* Verify that the received messages are the same */

          if (memcmp(&txmsg.cm_hdr, &rxmsg.cm_hdr, sizeof(struct can_hdr_s)) != 0)
            {
              printf("ERROR: Sent header does not match received header:\n");
              lib_dumpbuffer("Sent header",
                             (FAR const uint8_t *)&txmsg.cm_hdr,
                             sizeof(struct can_hdr_s));
              lib_dumpbuffer("Received header",
                             (FAR const uint8_t *)&rxmsg.cm_hdr,
                             sizeof(struct can_hdr_s));
              errval = 4;
              goto errout_with_dev;
            }

          if (memcmp(txmsg.cm_data, rxmsg.cm_data, msgdlc) != 0)
            {
              printf("ERROR: Data does not match. DLC=%d\n", msgdlc);
              for (i = 0; i < msgdlc; i++)
                {
                  printf("  %d: TX 0x%02x RX 0x%02x\n",
                         i, txmsg.cm_data[i], rxmsg.cm_data[i]);
                  errval = 5;
                  goto errout_with_dev;
                }
            }

          /* Report success */

          printf("  ID: %4u DLC: %d -- OK\n", msgid, msgdlc);

#else

          /* Print the data received */

          printf("Data received:\n");
          for (i = 0; i < msgdlc; i++)
            {
              printf("  %d: 0x%02x\n", i, rxmsg.cm_data[i]);
            }
#endif
        }
#endif

#ifdef CONFIG_EXAMPLES_CAN_WRITE

      /* Set up for the next pass */

      msgdata += msgdlc;

      if (++msgid > maxid)
        {
          msgid = minid;
        }

      if (++msgdlc > CAN_MAXDATALEN)
        {
          msgdlc = 1;
        }
#endif
    }

errout_with_dev:
  close(fd);

errout:
  printf("Terminating!\n");
  fflush(stdout);
  return errval;
}