Esempio n. 1
0
static void ajoy_enable(FAR const struct ajoy_lowerhalf_s *lower,
                         ajoy_buttonset_t press, ajoy_buttonset_t release,
                         ajoy_handler_t handler, FAR void *arg)
{
  irqstate_t flags;
  ajoy_buttonset_t either = press | release;
  ajoy_buttonset_t bit;
  bool rising;
  bool falling;
  int i;

  /* Start with all interrupts disabled */

  flags = enter_critical_section();
  ajoy_disable();

  iinfo("press: %02x release: %02x handler: %p arg: %p\n",
        press, release, handler, arg);

  /* If no events are indicated or if no handler is provided, then this
   * must really be a request to disable interrupts.
   */

  if (either && handler)
    {
      /* Save the new the handler and argument */

      g_ajoyhandler = handler;
      g_ajoyarg     = arg;

      /* Check each GPIO. */

      for (i = 0; i < AJOY_NGPIOS; i++)
        {
           /* Enable interrupts on each pin that has either a press or
            * release event associated with it.
            */

           bit = (1 << i);
           if ((either & bit) != 0)
             {
               /* Active low so a press corresponds to a falling edge and
                * a release corresponds to a rising edge.
                */

               falling = ((press & bit) != 0);
               rising  = ((release & bit) != 0);

               iinfo("GPIO %d: rising: %d falling: %d\n",
                      i, rising, falling);

               (void)stm32_gpiosetevent(g_joygpio[i], rising, falling,
                                        true, ajoy_interrupt, NULL);
             }
        }
    }

  leave_critical_section(flags);
}
Esempio n. 2
0
static int max11802_open(FAR struct file *filep)
{
#ifdef CONFIG_MAX11802_REFCNT
  FAR struct inode         *inode;
  FAR struct max11802_dev_s *priv;
  uint8_t                   tmp;
  int                       ret;

  iinfo("Opening\n");

  DEBUGASSERT(filep);
  inode = filep->f_inode;

  DEBUGASSERT(inode && inode->i_private);
  priv  = (FAR struct max11802_dev_s *)inode->i_private;

  /* Get exclusive access to the driver data structure */

  ret = sem_wait(&priv->devsem);
  if (ret < 0)
    {
      /* This should only happen if the wait was canceled by an signal */

      DEBUGASSERT(errno == EINTR);
      return -EINTR;
    }

  /* Increment the reference count */

  tmp = priv->crefs + 1;
  if (tmp == 0)
    {
      /* More than 255 opens; uint8_t overflows to zero */

      ret = -EMFILE;
      goto errout_with_sem;
    }

  /* When the reference increments to 1, this is the first open event
   * on the driver.. and an opportunity to do any one-time initialization.
   */

  /* Save the new open count on success */

  priv->crefs = tmp;

errout_with_sem:
  sem_post(&priv->devsem);
  return ret;
#else
  iinfo("Opening\n");
  return OK;
#endif
}
Esempio n. 3
0
static int tsc_attach(FAR struct ads7843e_config_s *state, xcpt_t isr)
{
  /* Attach the ADS7843E interrupt */

  iinfo("Attaching %p to IRQ %d\n", isr, SAM_TCS_IRQ);
  return irq_attach(SAM_TCS_IRQ, isr, NULL);
}
Esempio n. 4
0
static uint16_t ads7843e_sendcmd(FAR struct ads7843e_dev_s *priv, uint8_t cmd)
{
  uint8_t  buffer[2];
  uint16_t result;

  /* Select the ADS7843E */

  SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN(0), true);

  /* Send the command */

  (void)SPI_SEND(priv->spi, cmd);

  /* Wait a tiny amount to make sure that the acquisition time is complete */

   up_udelay(3); /* 3 microseconds */

  /* Read the 12-bit data (LS 4 bits will be padded with zero) */

  SPI_RECVBLOCK(priv->spi, buffer, 2);
  SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN(0), false);

  result = ((uint16_t)buffer[0] << 8) | (uint16_t)buffer[1];
  result = result >> 4;

  iinfo("cmd:%02x response:%04x\n", cmd, result);
  return result;
}
Esempio n. 5
0
static uint16_t max11802_sendcmd(FAR struct max11802_dev_s *priv,
                                 uint8_t cmd, int *tags)
{
  uint8_t  buffer[2];
  uint16_t result;

  /* Select the MAX11802 */

  SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true);

  /* Send the command */

  (void)SPI_SEND(priv->spi, cmd);

  /* Read the data */

  SPI_RECVBLOCK(priv->spi, buffer, 2);
  SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false);

  result = ((uint16_t)buffer[0] << 8) | (uint16_t)buffer[1];
  *tags = result & 0xF;
  result >>= 4; /* Get rid of tags */

  iinfo("cmd:%02x response:%04x\n", cmd, result);
  return result;
}
Esempio n. 6
0
static uint16_t tc_adc_read_sample(void)
{
  uint16_t retval;
  uint32_t adcsr;
  uint16_t count = 0;

  /* Validate the conversion is complete */

  adcsr = tc_adc_getreg(STM32_ADC_SR_OFFSET);
  while ((adcsr & ADC_SR_EOC) == 0)
    {
      adcsr = tc_adc_getreg(STM32_ADC_SR_OFFSET);
      count++;
    }

  /* Read the sample */

  retval = tc_adc_getreg(STM32_ADC_DR_OFFSET);
  retval &= ADC_DR_DATA_MASK;

  if (count > 0)
    {
      iinfo("Count = %d\n", count);
    }

  return retval;
}
Esempio n. 7
0
static bool tsc_pendown(FAR struct ads7843e_config_s *state)
{
  /* The /PENIRQ value is active low */

  bool pendown = !sam_gpioread(GPIO_TCS_IRQ);
  iinfo("pendown:%d\n", pendown);
  return pendown;
}
Esempio n. 8
0
static int tc_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
{
#if 1
  iinfo("cmd: %d arg: %ld\n", cmd, arg);
  return -ENOTTY; /* None yet supported */
#else
  FAR struct inode *inode;
  FAR struct tc_dev_s *priv;
  int ret;

  iinfo("cmd: %d arg: %ld\n", cmd, arg);
  DEBUGASSERT(filep);
  inode = filep->f_inode;

  DEBUGASSERT(inode && inode->i_private);
  priv  = (FAR struct tc_dev_s *)inode->i_private;

  /* Get exclusive access to the driver data structure */

  ret = nxsem_wait(&priv->devsem);
  if (ret < 0)
    {
      /* This should only happen if the wait was canceled by an signal */

      DEBUGASSERT(ret == -EINTR || ret == -ECANCELED);
      return ret;
    }

  /* Process the IOCTL by command */

  switch (cmd)
    {
      /* ADD IOCTL COMMAND CASES HERE */

      default:
        ret = -ENOTTY;
        break;
    }

  nxsem_post(&priv->devsem);
  return ret;
#endif
}
Esempio n. 9
0
static int max11802_close(FAR struct file *filep)
{
#ifdef CONFIG_MAX11802_REFCNT
  FAR struct inode         *inode;
  FAR struct max11802_dev_s *priv;
  int                       ret;

  iinfo("Closing\n");
  DEBUGASSERT(filep);
  inode = filep->f_inode;

  DEBUGASSERT(inode && inode->i_private);
  priv  = (FAR struct max11802_dev_s *)inode->i_private;

  /* Get exclusive access to the driver data structure */

  ret = sem_wait(&priv->devsem);
  if (ret < 0)
    {
      /* This should only happen if the wait was canceled by an signal */

      DEBUGASSERT(errno == EINTR);
      return -EINTR;
    }

  /* Decrement the reference count unless it would decrement a negative
   * value.  When the count decrements to zero, there are no further
   * open references to the driver.
   */

  if (priv->crefs >= 1)
    {
      priv->crefs--;
    }

  sem_post(&priv->devsem);
#endif
  iinfo("Closing\n");
  return OK;
}
Esempio n. 10
0
static int max11802_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
{
  FAR struct inode         *inode;
  FAR struct max11802_dev_s *priv;
  int                       ret;

  iinfo("cmd: %d arg: %ld\n", cmd, arg);
  DEBUGASSERT(filep);
  inode = filep->f_inode;

  DEBUGASSERT(inode && inode->i_private);
  priv  = (FAR struct max11802_dev_s *)inode->i_private;

  /* Get exclusive access to the driver data structure */

  ret = sem_wait(&priv->devsem);
  if (ret < 0)
    {
      /* This should only happen if the wait was canceled by an signal */

      DEBUGASSERT(errno == EINTR);
      return -EINTR;
    }

  /* Process the IOCTL by command */

  switch (cmd)
    {
      case TSIOC_SETFREQUENCY:  /* arg: Pointer to uint32_t frequency value */
        {
          FAR uint32_t *ptr = (FAR uint32_t *)((uintptr_t)arg);
          DEBUGASSERT(priv->config != NULL && ptr != NULL);
          priv->config->frequency = SPI_SETFREQUENCY(priv->spi, *ptr);
        }
        break;

      case TSIOC_GETFREQUENCY:  /* arg: Pointer to uint32_t frequency value */
        {
          FAR uint32_t *ptr = (FAR uint32_t *)((uintptr_t)arg);
          DEBUGASSERT(priv->config != NULL && ptr != NULL);
          *ptr = priv->config->frequency;
        }
        break;

      default:
        ret = -ENOTTY;
        break;
    }

  sem_post(&priv->devsem);
  return ret;
}
Esempio n. 11
0
static void ajoy_enable(FAR const struct ajoy_lowerhalf_s *lower,
                         ajoy_buttonset_t press, ajoy_buttonset_t release,
                         ajoy_handler_t handler, FAR void *arg)
{
  irqstate_t flags;
  ajoy_buttonset_t either = press | release;
  ajoy_buttonset_t bit;
  int i;

  /* Start with all interrupts disabled */

  flags = enter_critical_section();
  ajoy_disable();

  iinfo("press: %02x release: %02x handler: %p arg: %p\n",
        press, release, handler, arg);

  /* If no events are indicated or if no handler is provided, then this
   * must really be a request to disable interrupts.
   */

  if (either && handler)
    {
      /* Save the new the handler and argument */

      g_ajoyhandler = handler;
      g_ajoyarg     = arg;

      /* Check each GPIO. */

      for (i = 0; i < AJOY_NGPIOS; i++)
        {
           /* Enable interrupts on each pin that has either a press or
            * release event associated with it.
            */

           bit = (1 << i);
           if ((either & bit) != 0)
             {
               /* REVISIT:  It would be better if we reconfigured for
                * the edges of interest so that we do not get spurious
                * interrupts.
                */

               sam_pioirqenable(g_joyirq[i]);
             }
        }
    }

  leave_critical_section(flags);
}
Esempio n. 12
0
static void tsc_enable(FAR struct ads7843e_config_s *state, bool enable)
{
  /* Attach and enable, or detach and disable */

  iinfo("IRQ:%d enable:%d\n", SAM_TCS_IRQ, enable);
  if (enable)
    {
      sam_gpioirqenable(SAM_TCS_IRQ);
    }
  else
    {
      sam_gpioirqdisable(SAM_TCS_IRQ);
    }
}
Esempio n. 13
0
static void tc_notify(FAR struct tc_dev_s *priv)
{
#ifndef CONFIG_DISABLE_POLL
  int i;
#endif

  /* If no threads have the driver open, then just dump the state */

#ifdef CONFIG_TOUCHSCREEN_REFCNT
  if ((priv->crefs == 0) && priv->sample.contact == CONTACT_UP)
    {
      priv->sample.contact = CONTACT_NONE;
      priv->sample.valid   = false;
      priv->id++;
      return;
    }
#endif

  /* If there are threads waiting for read data, then signal one of them
   * that the read data is available.
   */

  if (priv->nwaiters > 0)
    {
      /* After posting this semaphore, we need to exit because the touchscreen
       * is no longer available.
       */

      nxsem_post(&priv->waitsem);
    }

  /* If there are threads waiting on poll() for touchscreen data to become available,
   * then wake them up now.  NOTE: we wake up all waiting threads because we
   * do not know that they are going to do.  If they all try to read the data,
   * then some make end up blocking after all.
   */

#ifndef CONFIG_DISABLE_POLL
  for (i = 0; i < CONFIG_TOUCHSCREEN_NPOLLWAITERS; i++)
    {
      struct pollfd *fds = priv->fds[i];
      if (fds)
        {
          fds->revents |= POLLIN;
          iinfo("Report events: %02x\n", fds->revents);
          nxsem_post(fds->sem);
        }
    }
#endif
}
Esempio n. 14
0
static bool tsc_busy(FAR struct ads7843e_config_s *state)
{
#if defined(CONFIG_DEBUG_INPUT) && defined(CONFIG_DEBUG_INFO)
  static bool last = (bool)-1;
#endif

  /* BUSY is high impedance when CS is high (not selected).  When CS is
   * is low, BUSY is active high.
   */

  bool busy = sam_gpioread(GPIO_TCS_BUSY);
#if defined(CONFIG_DEBUG_INPUT) && defined(CONFIG_DEBUG_INFO)
  if (busy != last)
    {
      iinfo("busy:%d\n", busy);
      last = busy;
    }
#endif

  return busy;
}
Esempio n. 15
0
	/*****************************************************************************************************************************
		open

		Prepares the database for use. An existing database is opened or otherwise an empty database is created.

		If the database is openend a table _META with meta info is loaded into a dictionary _META. The dictionary key is the 
		code of the data element. A data element is either a tabel (dimension/event) or a field (characteristic/property). 
		The value of the dictionary is the MET_INFO structure. This structure contains meta data about the data element.

		If the database is created an empty table _META is created.

		The function calls virtual functions, db_,  which must be overriden by a derived class for a specific database implementation.  

	******************************************************************************************************************************/
	void ARAS::open(DBInfo dbInfo) {
		if (isopen)
			return;

		// store db information
		this->dbInfo = dbInfo;
		
		// open or create database
		// performs the database specific initialization code, the specific information to be used is stored in the struct DBInfo.
		db_init_database();
		// performs the database specific code to check whether a database alreay exists and open it. 
		if (db_open_database()) {
			// read _META table from database into dictionary _META
			TABLE values;
			db_select_table("_META", {"CODE","INFO"}, values);
			for (auto i : values)
				_META.insert(std::pair<std::string, META_INFO>(i[0], META_INFO(i[1])));
		}
		else {
			// performs the database specific code to create a new database based on DBInfo. 
			db_create_database();

			// create table _META: define the columns
			META_INFO imeta(data_type::DIM, 0, "_META", "", "", "_META", "CODE", 0, 0, 0, 0);
			META_INFO icode(data_type::STR, SIZE_META_CODE_MAX, "_META", "", "","_META", "", 0, 0, 1, 0);
			META_INFO idescs(data_type::STR, SIZE_DESCS_MAX, "_META", "", "", "_META", "", 0, 0, 0, 0);
			META_INFO idescl(data_type::STR, SIZE_DESCL_MAX, "_META", "", "", "_META", "", 0, 0, 0, 0);
			META_INFO iinfo(data_type::STR, 0, "_META", "", "", "_META", "",0, 0, 0, 0);

			// define the table
			META_TABLE meta = { { "_META", "Meta data", "Meta data", imeta }, { "CODE", "CODE", "CODE", icode }, { "DESCS", "Short Description", "Short Description", idescs }, { "DESCL", "Long Description", "Long Description", idescl }, { "INFO", "INFO", "INFO", iinfo } };

			// performs the database specific code to create a new table
			db_create_table(meta);

			// load the meta data into the dictionary and the database table _META
			for (auto i : meta)
				insert_meta(i);
		}
	}
Esempio n. 16
0
static ajoy_buttonset_t ajoy_buttons(FAR const struct ajoy_lowerhalf_s *lower)
{
  ajoy_buttonset_t ret = 0;
  int i;

  /* Read each joystick GPIO value */

  for (i = 0; i < AJOY_NGPIOS; i++)
    {
      /* Button outputs are pulled high. So a sensed low level means that the
       * button is pressed.
       */

      if (!stm32_gpioread(g_joygpio[i]))
        {
          ret |= (1 << i);
        }
    }

  iinfo("Returning: %02x\n", ret);
  return ret;
}
Esempio n. 17
0
static void max11802_notify(FAR struct max11802_dev_s *priv)
{
#ifndef CONFIG_DISABLE_POLL
  int i;
#endif

  /* If there are threads waiting for read data, then signal one of them
   * that the read data is available.
   */

  if (priv->nwaiters > 0)
    {
      /* After posting this semaphore, we need to exit because the sample
       * is no longer available.
       */

      sem_post(&priv->waitsem);
    }

  /* If there are threads waiting on poll() for MAX11802 data to become
   * available, then wake them up now.  NOTE: we wake up all waiting
   * threads because we do not know that they are going to do.  If they
   * all try to read the data, then some make end up blocking after all.
   */

#ifndef CONFIG_DISABLE_POLL
  for (i = 0; i < CONFIG_MAX11802_NPOLLWAITERS; i++)
    {
      struct pollfd *fds = priv->fds[i];
      if (fds)
        {
          fds->revents |= POLLIN;
          iinfo("Report events: %02x\n", fds->revents);
          sem_post(fds->sem);
        }
    }
#endif
}
Esempio n. 18
0
int sam_tsc_setup(int minor)
{
  FAR struct spi_dev_s *dev;
  int ret;

  iinfo("minor %d\n", minor);
  DEBUGASSERT(minor == 0);

  /* Configure and enable the ADS7843E interrupt pin as an input */

  (void)sam_configgpio(GPIO_TCS_BUSY);
  (void)sam_configgpio(GPIO_TCS_IRQ);

  /* Configure the PIO interrupt */

  sam_gpioirq(GPIO_TCS_IRQ);

  /* Get an instance of the SPI interface for the touchscreen chip select */

  dev = sam_spibus_initialize(TSC_CSNUM);
  if (!dev)
    {
      ierr("ERROR: Failed to initialize SPI chip select %d\n", TSC_CSNUM);
      return -ENODEV;
    }

  /* Initialize and register the SPI touschscreen device */

  ret = ads7843e_register(dev, &g_tscinfo, CONFIG_ADS7843E_DEVMINOR);
  if (ret < 0)
    {
      ierr("ERROR: Failed to initialize SPI chip select %d\n", TSC_CSNUM);
      /* sam_spibus_uninitialize(dev); */
      return -ENODEV;
    }

  return OK;
}
Esempio n. 19
0
static int max11802_poll(FAR struct file *filep, FAR struct pollfd *fds,
                        bool setup)
{
  FAR struct inode *inode;
  FAR struct max11802_dev_s *priv;
  int ret;
  int i;

  iinfo("setup: %d\n", (int)setup);
  DEBUGASSERT(filep && fds);
  inode = filep->f_inode;

  DEBUGASSERT(inode && inode->i_private);
  priv  = (FAR struct max11802_dev_s *)inode->i_private;

  /* Are we setting up the poll?  Or tearing it down? */

  ret = sem_wait(&priv->devsem);
  if (ret < 0)
    {
      /* This should only happen if the wait was canceled by an signal */

      DEBUGASSERT(errno == EINTR);
      return -EINTR;
    }

  if (setup)
    {
      /* Ignore waits that do not include POLLIN */

      if ((fds->events & POLLIN) == 0)
        {
          ret = -EDEADLK;
          goto errout;
        }

      /* This is a request to set up the poll.  Find an available
       * slot for the poll structure reference
       */

      for (i = 0; i < CONFIG_MAX11802_NPOLLWAITERS; i++)
        {
          /* Find an available slot */

          if (!priv->fds[i])
            {
              /* Bind the poll structure and this slot */

              priv->fds[i] = fds;
              fds->priv    = &priv->fds[i];
              break;
            }
        }

      if (i >= CONFIG_MAX11802_NPOLLWAITERS)
        {
          fds->priv    = NULL;
          ret          = -EBUSY;
          goto errout;
        }

      /* Should we immediately notify on any of the requested events? */

      if (priv->penchange)
        {
          max11802_notify(priv);
        }
    }
  else if (fds->priv)
    {
      /* This is a request to tear down the poll. */

      struct pollfd **slot = (struct pollfd **)fds->priv;
      DEBUGASSERT(slot != NULL);

      /* Remove all memory of the poll setup */

      *slot                = NULL;
      fds->priv            = NULL;
    }

errout:
  sem_post(&priv->devsem);
  return ret;
}
Esempio n. 20
0
static ssize_t max11802_read(FAR struct file *filep, FAR char *buffer,
                             size_t len)
{
  FAR struct inode          *inode;
  FAR struct max11802_dev_s *priv;
  FAR struct touch_sample_s *report;
  struct max11802_sample_s   sample;
  int                        ret;

  iinfo("buffer:%p len:%d\n", buffer, len);
  DEBUGASSERT(filep);
  inode = filep->f_inode;

  DEBUGASSERT(inode && inode->i_private);
  priv  = (FAR struct max11802_dev_s *)inode->i_private;

  /* Verify that the caller has provided a buffer large enough to receive
   * the touch data.
   */

  if (len < SIZEOF_TOUCH_SAMPLE_S(1))
    {
      /* We could provide logic to break up a touch report into segments and
       * handle smaller reads... but why?
       */

      ierr("ERROR: Unsupported read size: %d\n", len);
      return -ENOSYS;
    }

  /* Get exclusive access to the driver data structure */

  ret = sem_wait(&priv->devsem);
  if (ret < 0)
    {
      /* This should only happen if the wait was cancelled by an signal */

      ierr("ERROR: sem_wait: %d\n", errno);
      DEBUGASSERT(errno == EINTR);
      return -EINTR;
    }

  /* Try to read sample data. */

  ret = max11802_sample(priv, &sample);
  if (ret < 0)
    {
      /* Sample data is not available now.  We would ave to wait to get
       * receive sample data.  If the user has specified the O_NONBLOCK
       * option, then just return an error.
       */

      iinfo("Sample data is not available\n");
      if (filep->f_oflags & O_NONBLOCK)
        {
          ret = -EAGAIN;
          goto errout;
       }

      /* Wait for sample data */

      ret = max11802_waitsample(priv, &sample);
      if (ret < 0)
        {
          /* We might have been awakened by a signal */

          ierr("ERROR: max11802_waitsample: %d\n", ret);
          goto errout;
        }
    }

  /* In any event, we now have sampled MAX11802 data that we can report
   * to the caller.
   */

  report = (FAR struct touch_sample_s *)buffer;
  memset(report, 0, SIZEOF_TOUCH_SAMPLE_S(1));
  report->npoints            = 1;
  report->point[0].id        = sample.id;
  report->point[0].x         = sample.x;
  report->point[0].y         = sample.y;

  /* Report the appropriate flags */

  if (sample.contact == CONTACT_UP)
    {
      /* Pen is now up.  Is the positional data valid?  This is important to
       * know because the release will be sent to the window based on its
       * last positional data.
       */

      if (sample.valid)
        {
          report->point[0].flags  = TOUCH_UP | TOUCH_ID_VALID | TOUCH_POS_VALID;
        }
      else
        {
          report->point[0].flags  = TOUCH_UP | TOUCH_ID_VALID;
        }
    }
  else if (sample.contact == CONTACT_DOWN)
    {
      /* First contact */

      report->point[0].flags  = TOUCH_DOWN | TOUCH_ID_VALID | TOUCH_POS_VALID;
    }
  else /* if (sample->contact == CONTACT_MOVE) */
    {
      /* Movement of the same contact */

      report->point[0].flags  = TOUCH_MOVE | TOUCH_ID_VALID | TOUCH_POS_VALID;
    }

  iinfo("  id:      %d\n", report->point[0].id);
  iinfo("  flags:   %02x\n", report->point[0].flags);
  iinfo("  x:       %d\n", report->point[0].x);
  iinfo("  y:       %d\n", report->point[0].y);

  ret = SIZEOF_TOUCH_SAMPLE_S(1);

errout:
  sem_post(&priv->devsem);
  iinfo("Returning: %d\n", ret);
  return ret;
}
Esempio n. 21
0
static ajoy_buttonset_t ajoy_supported(FAR const struct ajoy_lowerhalf_s *lower)
{
  iinfo("Supported: %02x\n", AJOY_SUPPORTED);
  return (ajoy_buttonset_t)AJOY_SUPPORTED;
}
Esempio n. 22
0
static int ajoy_sample(FAR const struct ajoy_lowerhalf_s *lower,
                       FAR struct ajoy_sample_s *sample)
{
#ifndef NO_JOYSTICK_ADC
  struct adc_msg_s adcmsg[MAX_ADC_CHANNELS];
  FAR struct adc_msg_s *ptr;
  ssize_t nread;
  ssize_t offset;
  int have;
  int i;

  /* Read all of the available samples (handling the case where additional
   * channels are enabled).
   */

  nread = file_read(&g_adcfile, adcmsg,
                    MAX_ADC_CHANNELS * sizeof(struct adc_msg_s));
  if (nread < 0)
    {
      if (nread != -EINTR)
        {
          ierr("ERROR: read failed: %d\n", (int)nread);
        }

      return nread;
    }
  else if (nread < NJOYSTICK_CHANNELS * sizeof(struct adc_msg_s))
    {
      ierr("ERROR: read too small: %ld\n", (long)nread);
      return -EIO;
    }

  /* Sample and the raw analog inputs */

#ifdef CONFIG_ADC_DMA
  have = 0;

#else
  /* If DMA is not supported, then we will have only a single ADC channel */

  have = 2;
  sample->as_y = 0;
#endif

  for (i = 0, offset = 0;
       i < MAX_ADC_CHANNELS && offset < nread && have != 3;
       i++, offset += sizeof(struct adc_msg_s))
    {
      ptr = &adcmsg[i];

      /* Is this one of the channels that we need? */

      if ((have & 1) == 0 && ptr->am_channel == 0)
        {
          int32_t tmp = ptr->am_data;
          sample->as_x = (int16_t)tmp;
          have |= 1;

          iinfo("X sample: %ld -> %d\n", (long)tmp, (int)sample->as_x);
        }

#ifdef CONFIG_ADC_DMA
      if ((have & 2) == 0 && ptr->am_channel == 1)
        {
          int32_t tmp = ptr->am_data;
          sample->as_y = (int16_t)tmp;
          have |= 2;

          iinfo("Y sample: %ld -> %d\n", (long)tmp, (int)sample->as_y);
        }
#endif
    }

  if (have != 3)
    {
      ierr("ERROR: Could not find joystick channels\n");
      return -EIO;
    }

#else
  /* ADC support is disabled */

  sample->as_x = 0;
  sample->as_y = 0;
#endif

  /* Sample the discrete button inputs */

  sample->as_buttons = ajoy_buttons(lower);
  iinfo("Returning: %02x\n", sample->as_buttons);
  return OK;
}
Esempio n. 23
0
static void max11802_worker(FAR void *arg)
{
  FAR struct max11802_dev_s    *priv = (FAR struct max11802_dev_s *)arg;
  FAR struct max11802_config_s *config;
  uint16_t                      x;
  uint16_t                      y;
  uint16_t                      xdiff;
  uint16_t                      ydiff;
  bool                          pendown;
  int                           ret;
  int                           tags, tags2;

  ASSERT(priv != NULL);

  /* Get a pointer the callbacks for convenience (and so the code is not so
   * ugly).
   */

  config = priv->config;
  DEBUGASSERT(config != NULL);

  /* Disable the watchdog timer.  This is safe because it is started only
   * by this function and this function is serialized on the worker thread.
   */

  wd_cancel(priv->wdog);

  /* Lock the SPI bus so that we have exclusive access */

  max11802_lock(priv->spi);

  /* Start coordinate measurement */

  (void)max11802_sendcmd(priv, MAX11802_CMD_MEASUREXY, &tags);

  /* Get exclusive access to the driver data structure */

  do
    {
      ret = sem_wait(&priv->devsem);

      /* This should only fail if the wait was cancelled by an signal
       * (and the worker thread will receive a lot of signals).
       */

      DEBUGASSERT(ret == OK || errno == EINTR);
    }
  while (ret < 0);

  /* Check for pen up or down by reading the PENIRQ GPIO. */

  pendown = config->pendown(config);

  /* Handle the change from pen down to pen up */

  if (pendown)
    {
      iinfo("\nPD\n");
    }
  else
    {
      iinfo("\nPU\n");
    }

  if (!pendown)
    {
      /* The pen is up.. reset thresholding variables. */

      priv->threshx = INVALID_THRESHOLD;
      priv->threshy = INVALID_THRESHOLD;

      /* Ignore the interrupt if the pen was already up (CONTACT_NONE ==
       * pen up and already reported; CONTACT_UP == pen up, but not
       * reported).
       */

      iinfo("\nPC%d\n", priv->sample.contact);

      if (priv->sample.contact == CONTACT_NONE ||
          priv->sample.contact == CONTACT_UP)

        {
          goto ignored;
        }

      /* The pen is up.  NOTE: We know from a previous test, that this is a
       * loss of contact condition.  This will be changed to CONTACT_NONE
       * after the loss of contact is sampled.
       */

       priv->sample.contact = CONTACT_UP;
    }

  /* It is a pen down event.  If the last loss-of-contact event has not been
   * processed yet, then we have to ignore the pen down event (or else it
   * will look like a drag event)
   */

  else if (priv->sample.contact == CONTACT_UP)
    {
      /* If we have not yet processed the last pen up event, then we
       * cannot handle this pen down event. We will have to discard it.
       * That should be okay because we will set the timer to to sample
       * again later.
       */

       iinfo("Previous pen up event still in buffer\n");
       max11802_notify(priv);
       wd_start(priv->wdog, MAX11802_WDOG_DELAY, max11802_wdog, 1,
                (uint32_t)priv);
       goto ignored;
    }
  else
    {
      /* Wait for data ready
       *
       * Note: MAX11802 signals the readiness of the results using
       * the lowest 4 bits of the result. However these are the
       * last bits to be read out of the device. It appears that
       * the hardware value can change in the middle of the readout,
       * causing the upper bits to be still invalid even though lower
       * bits indicate valid result.
       *
       * We work around this by reading the registers once more after
       * the tags indicate they are ready.
       */

      int readycount = 0;
      do
        {
#ifdef CONFIG_MAX11802_SWAPXY
          x = max11802_sendcmd(priv, MAX11802_CMD_YPOSITION, &tags);
          y = max11802_sendcmd(priv, MAX11802_CMD_XPOSITION, &tags2);
#else
          x = max11802_sendcmd(priv, MAX11802_CMD_XPOSITION, &tags);
          y = max11802_sendcmd(priv, MAX11802_CMD_YPOSITION, &tags2);
#endif
          if (tags != 0xF && tags2 != 0xF)
            {
              readycount++;
            }
        }
      while (readycount < 2);

      /* Continue to sample the position while the pen is down */

      wd_start(priv->wdog, MAX11802_WDOG_DELAY, max11802_wdog, 1,
               (uint32_t)priv);

      /* Check if data is valid */

      if ((tags & 0x03) != 0)
        {
          iinfo("Touch ended before measurement\n");
          goto ignored;
        }

      /* Perform a thresholding operation so that the results will be more
       * stable.  If the difference from the last sample is small, then
       * ignore the event.
       *
       * REVISIT:  Should a large change in pressure also generate a event?
       */

      xdiff = x > priv->threshx ? (x - priv->threshx) : (priv->threshx - x);
      ydiff = y > priv->threshy ? (y - priv->threshy) : (priv->threshy - y);

      /* Check the thresholds.  Bail if there is no significant difference */

      if (xdiff < CONFIG_MAX11802_THRESHX && ydiff < CONFIG_MAX11802_THRESHY)
        {
          /* Little or no change in either direction ... don't report anything. */

          goto ignored;
        }

      /* When we see a big difference, snap to the new x/y thresholds */

      priv->threshx       = x;
      priv->threshy       = y;

      /* Update the x/y position in the sample data */

      priv->sample.x      = priv->threshx;
      priv->sample.y      = priv->threshy;

      /* The X/Y positional data is now valid */

      priv->sample.valid = true;

      /* If this is the first (acknowledged) pen down report, then report
       * this as the first contact.  If contact == CONTACT_DOWN, it will be
       * set to set to CONTACT_MOVE after the contact is first sampled.
       */

      if (priv->sample.contact != CONTACT_MOVE)
        {
          /* First contact */

          priv->sample.contact = CONTACT_DOWN;
        }
    }

  /* Indicate the availability of new sample data for this ID */

  priv->sample.id = priv->id;
  priv->penchange = true;

  /* Notify any waiters that new MAX11802 data is available */

  max11802_notify(priv);

ignored:
  config->enable(config, true);

  /* Release our lock on the state structure and unlock the SPI bus */

  sem_post(&priv->devsem);
  max11802_unlock(priv->spi);
}
Esempio n. 24
0
static int max11802_waitsample(FAR struct max11802_dev_s *priv,
                               FAR struct max11802_sample_s *sample)
{
  irqstate_t flags;
  int ret;

  /* Interrupts must be disabled when this is called to (1) prevent posting
   * of semaphores from interrupt handlers, and (2) to prevent sampled data
   * from changing until it has been reported.
   *
   * In addition, we will also disable pre-emption to prevent other threads
   * from getting control while we muck with the semaphores.
   */

  sched_lock();
  flags = enter_critical_section();

  /* Now release the semaphore that manages mutually exclusive access to
   * the device structure.  This may cause other tasks to become ready to
   * run, but they cannot run yet because pre-emption is disabled.
   */

  sem_post(&priv->devsem);

  /* Try to get the a sample... if we cannot, then wait on the semaphore
   * that is posted when new sample data is available.
   */

  while (max11802_sample(priv, sample) < 0)
    {
      /* Wait for a change in the MAX11802 state */

      iinfo("Waiting..\n");
      priv->nwaiters++;
      ret = sem_wait(&priv->waitsem);
      priv->nwaiters--;

      if (ret < 0)
        {
          /* If we are awakened by a signal, then we need to return
           * the failure now.
           */

          ierr("ERROR: sem_wait: %d\n", errno);
          DEBUGASSERT(errno == EINTR);
          ret = -EINTR;
          goto errout;
        }
    }

  iinfo("Sampled\n");

  /* Re-acquire the semaphore that manages mutually exclusive access to
   * the device structure.  We may have to wait here.  But we have our
   * sample.  Interrupts and pre-emption will be re-enabled while we wait.
   */

  ret = sem_wait(&priv->devsem);

errout:
  /* Then re-enable interrupts.  We might get interrupt here and there
   * could be a new sample.  But no new threads will run because we still
   * have pre-emption disabled.
   */

  leave_critical_section(flags);

  /* Restore pre-emption.  We might get suspended here but that is okay
   * because we already have our sample.  Note:  this means that if there
   * were two threads reading from the MAX11802 for some reason, the data
   * might be read out of order.
   */

  sched_unlock();
  return ret;
}
Esempio n. 25
0
int max11802_register(FAR struct spi_dev_s *spi,
                      FAR struct max11802_config_s *config, int minor)
{
  FAR struct max11802_dev_s *priv;
  char devname[DEV_NAMELEN];
#ifdef CONFIG_MAX11802_MULTIPLE
  irqstate_t flags;
#endif
  int ret;

  iinfo("spi: %p minor: %d\n", spi, minor);

  /* Debug-only sanity checks */

  DEBUGASSERT(spi != NULL && config != NULL && minor >= 0 && minor < 100);

  /* Create and initialize a MAX11802 device driver instance */

#ifndef CONFIG_MAX11802_MULTIPLE
  priv = &g_max11802;
#else
  priv = (FAR struct max11802_dev_s *)kmm_malloc(sizeof(struct max11802_dev_s));
  if (!priv)
    {
      ierr("ERROR: kmm_malloc(%d) failed\n", sizeof(struct max11802_dev_s));
      return -ENOMEM;
    }
#endif

  /* Initialize the MAX11802 device driver instance */

  memset(priv, 0, sizeof(struct max11802_dev_s));
  priv->spi     = spi;               /* Save the SPI device handle */
  priv->config  = config;            /* Save the board configuration */
  priv->wdog    = wd_create();       /* Create a watchdog timer */
  priv->threshx = INVALID_THRESHOLD; /* Initialize thresholding logic */
  priv->threshy = INVALID_THRESHOLD; /* Initialize thresholding logic */

  /* Initialize semaphores */

  sem_init(&priv->devsem,  0, 1);    /* Initialize device structure semaphore */
  sem_init(&priv->waitsem, 0, 0);    /* Initialize pen event wait semaphore */

  /* The pen event semaphore is used for signaling and, hence, should not
   * have priority inheritance enabled.
   */

  sem_setprotocol(&priv->waitsem, SEM_PRIO_NONE);

  /* Make sure that interrupts are disabled */

  config->clear(config);
  config->enable(config, false);

  /* Attach the interrupt handler */

  ret = config->attach(config, max11802_interrupt);
  if (ret < 0)
    {
      ierr("ERROR: Failed to attach interrupt\n");
      goto errout_with_priv;
    }

  iinfo("Mode: %d Bits: 8 Frequency: %d\n",
        CONFIG_MAX11802_SPIMODE, CONFIG_MAX11802_FREQUENCY);

  /* Lock the SPI bus so that we have exclusive access */

  max11802_lock(spi);

  /* Configure MAX11802 registers */

  SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true);
  (void)SPI_SEND(priv->spi, MAX11802_CMD_MODE_WR);
  (void)SPI_SEND(priv->spi, MAX11802_MODE);
  SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false);

  SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true);
  (void)SPI_SEND(priv->spi, MAX11802_CMD_AVG_WR);
  (void)SPI_SEND(priv->spi, MAX11802_AVG);
  SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false);

  SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true);
  (void)SPI_SEND(priv->spi, MAX11802_CMD_TIMING_WR);
  (void)SPI_SEND(priv->spi, MAX11802_TIMING);
  SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false);

  SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true);
  (void)SPI_SEND(priv->spi, MAX11802_CMD_DELAY_WR);
  (void)SPI_SEND(priv->spi, MAX11802_DELAY);
  SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false);

  /* Test that the device access was successful. */

  SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true);
  (void)SPI_SEND(priv->spi, MAX11802_CMD_MODE_RD);
  ret = SPI_SEND(priv->spi, 0);
  SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false);

  /* Unlock the bus */

  max11802_unlock(spi);

  if (ret != MAX11802_MODE)
  {
    ierr("ERROR: max11802 mode readback failed: %02x\n", ret);
    goto errout_with_priv;
  }

  /* Register the device as an input device */

  (void)snprintf(devname, DEV_NAMELEN, DEV_FORMAT, minor);
  iinfo("Registering %s\n", devname);

  ret = register_driver(devname, &max11802_fops, 0666, priv);
  if (ret < 0)
    {
      ierr("ERROR: register_driver() failed: %d\n", ret);
      goto errout_with_priv;
    }

  /* If multiple MAX11802 devices are supported, then we will need to add
   * this new instance to a list of device instances so that it can be
   * found by the interrupt handler based on the recieved IRQ number.
   */

#ifdef CONFIG_MAX11802_MULTIPLE
  flags          = enter_critical_section();
  priv->flink    = g_max11802list;
  g_max11802list = priv;
  leave_critical_section(flags);
#endif

  /* Schedule work to perform the initial sampling and to set the data
   * availability conditions.
   */

  ret = work_queue(HPWORK, &priv->work, max11802_worker, priv, 0);
  if (ret != 0)
    {
      ierr("ERROR: Failed to queue work: %d\n", ret);
      goto errout_with_priv;
    }

  /* And return success (?) */

  return OK;

errout_with_priv:
  sem_destroy(&priv->devsem);
#ifdef CONFIG_MAX11802_MULTIPLE
  kmm_free(priv);
#endif
  return ret;
}
Esempio n. 26
0
static void tc_worker(FAR void *arg)
{
  FAR struct tc_dev_s *priv = (FAR struct tc_dev_s *)arg;
  uint32_t delay = TC_PENUP_POLL_TICKS;
  uint16_t value;
  uint16_t newx = 0;
  int16_t xdiff;
  int16_t ydiff;
  int ret;

  DEBUGASSERT(priv != NULL);

  /* Perform the next action based on the state of the conversions */

  switch (priv->state)
    {
    /* The touchscreen is IDLE and we are ready to begin the next sample */

    case TC_READY:
      {
        /* Select DRIVE for Y sampling */

        /* Configure XL, XR with drive voltages and disable YU drive.  Note that
         * this is configuring the DRIVEA and DRIVEB outputs to enable the on-board
         * transistor drive logic to energize the touch panel.
         */

        *((uint32_t *) LCD_TP_PORT_SETRESET) = LCD_SAMPY_BITS;

        /* Allow time for the Y DRIVE to settle */

        priv->resamplecount = 0;
        priv->sampcount = 0;
        priv->value = 0;
        priv->state = TC_READY_SETTLE;
        delay       = TC_SETTLE_TICKS;
      }
      break;

    case TC_READY_SETTLE:
      {
        /* Start Y sampling */

        tc_y_sample();

        /* Allow time for the Y pend down sampling */

        priv->state = TC_YPENDOWN;
        delay       = TC_SAMPLE_TICKS;
      }
      break;

    /* The Y sampling time has elapsed and the Y value should be ready
     * for conversion
     */

    case TC_YPENDOWN:
      {
        /* Convert the Y sample value */

        value = tc_adc_read_sample();

        /* A converted value at the minimum would mean that there is no touch
         * and that the sampling period is complete.
         */

        if (!tc_valid_sample(value))
          {
            priv->state = TC_PENUP;
          }
        else
          {
            /* Allow time for touch inputs to stabilize */

            priv->state = TC_DEBOUNCE;
            delay       = TC_DEBOUNCE_TICKS;
          }
      }
      break;

    /* The debounce time period has elapsed and we are ready to re-sample
     * the touchscreen.
     */

    case TC_RESAMPLE:
      {
        /* Select DRIVE for Y sampling */

        /* Configure XL, XR with drive voltages and disable YU drive.  Note that
         * this is configuring the DRIVEA and DRIVEB outputs to enable the on-board
         * transistor drive logic to energize the touch panel.
         */

        *((uint32_t *) LCD_TP_PORT_SETRESET) = LCD_SAMPY_BITS;

        /* Allow time for the Y DRIVE to settle */

        priv->state = TC_DEBOUNCE;
        delay       = TC_SETTLE_TICKS;
      }
      break;

    case TC_DEBOUNCE:
      {
        /* (Re-)start Y sampling */

        tc_y_sample();

        /* Allow time for the Y sampling */

        priv->state = TC_YSAMPLE;
        delay       = TC_SAMPLE_TICKS;
      }
      break;

    /* The Y sampling period has elapsed and we are ready to perform the
     * conversion.
     */

    case TC_YSAMPLE:                          /* Allowing time for the Y sampling */
      {
        /* Read the Y axis position */

        value = tc_adc_read_sample();

        /* A converted value at the minimum would mean that we lost the contact
         * before all of the conversions were completed.  At converted value at
         * the maximum value is probably bad too.
         */

        if (!tc_valid_sample(value))
          {
#ifdef CONFIG_TOUCHSCREEN_RESAMPLE
            priv->state = TC_RESAMPLE;
            delay       = TC_RESAMPLE_TICKS;
#else
            priv->state = TC_PENUP;
#endif
          }
        else
          {
            value       = MAX_ADC - value;
            priv->value += value;
            if (++priv->sampcount < CONFIG_TOUCHSCREEN_AVG_SAMPLES)
              {
                priv->state = TC_READY_SETTLE;
                delay = 1;
                break;
              }

            priv->newy  = value / CONFIG_TOUCHSCREEN_AVG_SAMPLES;
            priv->value = 0;
            priv->sampcount = 0;
            iinfo("Y=%d\n", priv->newy);

            /* Configure YU and YD with drive voltages and disable XR drive.  Note that
             * this is configuring the DRIVEA and DRIVEB outputs to enable the on-board
             * transistor drive logic to energize the touch panel.
             */

            *((uint32_t *) LCD_TP_PORT_SETRESET) = LCD_SAMPX_BITS;

            /* Allow time for the X sampling */

            priv->state = TC_XSETTLE;
            delay       = TC_SETTLE_TICKS;
          }
      }
      break;

    case TC_XRESAMPLE:                /* Perform X resampling */
      {
        if (priv->resamplecount-- == 0)
          {
            priv->state = TC_PENUP;
            break;
          }
      }

    case TC_XSETTLE:                  /* Allowing time X to settle after changing DRIVE */
      {
        /* The X Drive settling time has elaspsed and it's time to start
         * the conversion
         */

        /* Start X sampling */

        tc_x_sample();

        /* Allow time for the X sampling */

        priv->state = TC_XSAMPLE;
        delay       = TC_SAMPLE_TICKS;
      }
      break;

    case TC_XSAMPLE:                 /* Allowing time for the X sampling */
      {
        /* Read the converted X axis position */

        value = tc_adc_read_sample();

        /* A converted value at the minimum would mean that we lost the contact
         * before all of the conversions were completed.  At converted value at
         * the maximum value is probably bad too.
         */

        if (!tc_valid_sample(value))
          {
#ifdef CONFIG_TOUCHSCREEN_RESAMPLE
            priv->state = TC_XRESAMPLE;
            if (priv->resamplecount == 0)
                priv->resamplecount = 1;
            delay       = TC_RESAMPLE_TICKS;
#else
            priv->state = TC_PENUP;
#endif
          }
        else
          {
            /* Calculate the X axis position */

            //value = MAX_ADC - value;
            priv->value += value;
            if (++priv->sampcount < CONFIG_TOUCHSCREEN_AVG_SAMPLES)
              {
                priv->state = TC_XSETTLE;
                delay = 1;
                break;
              }

            newx  = value / CONFIG_TOUCHSCREEN_AVG_SAMPLES;
            iinfo("X=%d\n", newx);

            /* Samples are available */

            priv->state = TC_PENDOWN;
          }
      }
      break;
    }

  /* Check for terminal conditions.. */

  /* Check if the sampling resulted in a pen up decision.  If so, we need to
   * handle the change from pen down to pen up.
   */

  if (priv->state == TC_PENUP)
    {
      /* Ignore if the pen was already down (CONTACT_NONE == pen up and already
       * reported.  CONTACT_UP == pen up, but not reported)
       */

      if (priv->sample.contact != CONTACT_NONE &&
          priv->sample.contact != CONTACT_UP)
        {
          /* The pen is up.  We know from the above test, that this is a
           * loss of contact condition.  This will be changed to CONTACT_NONE
           * after the loss of contact is sampled.
           */

          priv->sample.contact = CONTACT_UP;

          /* Indicate the availability of new sample data for this ID */

          priv->sample.id = priv->id;
          priv->penchange = true;

          /* Notify any waiters that new touchscreen data is available */

          iinfo("1:X=%d, Y=%d\n", priv->sample.x, priv->sample.y);

          tc_notify(priv);
        }

      /* Set up for the next poll */

      priv->sample.valid = false;
      priv->state        = TC_READY;
      delay              = TC_PENUP_POLL_TICKS;
    }

  /* Check if the sampling resulted in a pen down decision. */

  else if (priv->state == TC_PENDOWN)
    {
      /* It is a pen down event.  If the last loss-of-contact event has not been
       * processed yet, then we have to ignore the pen down event (or else it will
       * look like a drag event)
       */

      if (priv->sample.contact != CONTACT_UP)
        {
          /* Perform a thresholding operation so that the results will be more stable.
           * If the difference from the last sample is small, then ignore the event.
           */

          xdiff = (int16_t)priv->sample.x - (int16_t)newx;
          if (xdiff < 0)
            {
              xdiff = -xdiff;
            }

          ydiff = (int16_t)priv->sample.y - (int16_t)priv->newy;
          if (ydiff < 0)
            {
              ydiff = -ydiff;
            }

          if (xdiff >= CONFIG_TOUCHSCREEN_THRESHX ||
              ydiff >= CONFIG_TOUCHSCREEN_THRESHY)
            {
              /* There is some change above the threshold... Report the change. */

#ifdef CONFIG_LCD_LANDSCAPE
              priv->sample.x     = MAX_ADC - priv->newy;
              priv->sample.y     = newx;
#else
              priv->sample.x     = newx;
              priv->sample.y     = priv->newy;
#endif
              priv->sample.valid = true;

              /* If this is the first (acknowledged) penddown report, then report
               * this as the first contact.  If contact == CONTACT_DOWN, it will be
               * set to set to CONTACT_MOVE after the contact is first sampled.
               */

              if (priv->sample.contact != CONTACT_MOVE)
                {
                  /* First contact */

                  priv->sample.contact = CONTACT_DOWN;
                }

              /* Indicate the availability of new sample data for this ID */

              priv->sample.id = priv->id;
              priv->penchange = true;

              /* Notify any waiters that nes touchscreen data is available */

              iinfo("2:X=%d, Y=%d\n", priv->sample.x, priv->sample.y);

              tc_notify(priv);
            }
        }

      /* Set up for the next poll */

      priv->state = TC_READY;
      delay       = TC_PENDOWN_POLL_TICKS;
    }

  /* Set up the next sample event */

  ret = work_queue(HPWORK, &priv->work, tc_worker, priv, delay);
  DEBUGASSERT(ret == 0);
}
Esempio n. 27
0
int stm32_tsc_setup(int minor)
{
  FAR struct tc_dev_s *priv;
  char devname[DEV_NAMELEN];
#ifdef CONFIG_TOUCHSCREEN_MULTIPLE
  irqstate_t flags;
#endif
  int ret;

  iinfo("minor: %d\n", minor);
  DEBUGASSERT(minor >= 0 && minor < 100);

  /* If we only have one touchscreen, check if we already did init */

#ifndef CONFIG_TOUCHSCREEN_MULTIPLE
  if (g_touchinitdone)
    {
      return OK;
    }
#endif

  /* Configure the touchscreen DRIVEA and DRIVEB pins for output */

  stm32_configgpio(GPIO_TP_DRIVEA);
  stm32_configgpio(GPIO_TP_DRIVEB);

  /* Configure Analog inputs for sampling X and Y coordinates */

  stm32_configgpio(GPIO_TP_XL);
  stm32_configgpio(GPIO_TP_YD);

  tc_adc_init();

  /* Create and initialize a touchscreen device driver instance */

#ifndef CONFIG_TOUCHSCREEN_MULTIPLE
  priv = &g_touchscreen;
#else
  priv = (FAR struct tc_dev_s *)kmm_malloc(sizeof(struct tc_dev_s));
  if (!priv)
    {
      ierr("ERROR: kmm_malloc(%d) failed\n", sizeof(struct tc_dev_s));
      return -ENOMEM;
    }
#endif

  /* Initialize the touchscreen device driver instance */

  memset(priv, 0, sizeof(struct tc_dev_s));
  nxsem_init(&priv->devsem,  0, 1); /* Initialize device structure semaphore */
  nxsem_init(&priv->waitsem, 0, 0); /* Initialize pen event wait semaphore */

  /* Register the device as an input device */

  (void)snprintf(devname, DEV_NAMELEN, DEV_FORMAT, minor);
  iinfo("Registering %s\n", devname);

  ret = register_driver(devname, &tc_fops, 0666, priv);
  if (ret < 0)
    {
      ierr("ERROR: register_driver() failed: %d\n", ret);
      goto errout_with_priv;
    }

  /* Schedule work to perform the initial sampling and to set the data
   * availability conditions.
   */

  priv->state = TC_READY;
  ret = work_queue(HPWORK, &priv->work, tc_worker, priv, 0);
  if (ret != 0)
    {
      ierr("ERROR: Failed to queue work: %d\n", ret);
      goto errout_with_priv;
    }

  /* And return success (?) */

#ifndef CONFIG_TOUCHSCREEN_MULTIPLE
  g_touchinitdone = true;
#endif

  return OK;

errout_with_priv:
  nxsem_destroy(&priv->devsem);
#ifdef CONFIG_TOUCHSCREEN_MULTIPLE
  kmm_free(priv);
#endif
  return ret;
}
Esempio n. 28
0
static void djoy_sample(FAR struct djoy_upperhalf_s *priv)
{
  FAR const struct djoy_lowerhalf_s *lower = priv->du_lower;
  FAR struct djoy_open_s *opriv;
  djoy_buttonset_t sample;
#if !defined(CONFIG_DISABLE_POLL) || !defined(CONFIG_DISABLE_SIGNALS)
  djoy_buttonset_t change;
  djoy_buttonset_t press;
  djoy_buttonset_t release;
#endif
  irqstate_t flags;
#ifndef CONFIG_DISABLE_POLL
  int i;
#endif

  DEBUGASSERT(priv && priv->du_lower);
  lower = priv->du_lower;

  /* This routine is called both task level and interrupt level, so
   * interrupts must be disabled.
   */

  flags = enter_critical_section();

  /* Sample the new button state */

  DEBUGASSERT(lower->dl_sample);
  sample = lower->dl_sample(lower);

#if !defined(CONFIG_DISABLE_POLL) || !defined(CONFIG_DISABLE_SIGNALS)
  /* Determine which buttons have been newly pressed and which have been
   * newly released.
   */

  change  = sample ^ priv->du_sample;
  press   = change & sample;

  DEBUGASSERT(lower->dl_supported);
  release = change & (lower->dl_supported(lower) & ~sample);

  /* Visit each opened reference to the device */

  for (opriv = priv->du_open; opriv; opriv = opriv->do_flink)
    {
#ifndef CONFIG_DISABLE_POLL
      /* Have any poll events occurred? */

      if ((press & opriv->do_pollevents.dp_press)     != 0 ||
          (release & opriv->do_pollevents.dp_release) != 0)
        {
          /* Yes.. Notify all waiters */

          for (i = 0; i < CONFIG_DJOYSTICK_NPOLLWAITERS; i++)
            {
              FAR struct pollfd *fds = opriv->do_fds[i];
              if (fds)
                {
                  fds->revents |= (fds->events & POLLIN);
                  if (fds->revents != 0)
                    {
                      iinfo("Report events: %02x\n", fds->revents);
                      sem_post(fds->sem);
                    }
                }
            }
        }
#endif

#ifndef CONFIG_DISABLE_SIGNALS
      /* Have any signal events occurred? */

      if ((press & opriv->do_notify.dn_press)     != 0 ||
          (release & opriv->do_notify.dn_release) != 0)
        {
          /* Yes.. Signal the waiter */

#ifdef CONFIG_CAN_PASS_STRUCTS
          union sigval value;
          value.sival_int = (int)sample;
          (void)sigqueue(opriv->do_pid, opriv->do_notify.dn_signo, value);
#else
          (void)sigqueue(opriv->do_pid, opriv->do_notify.dn.signo,
                         (FAR void *)sample);
#endif
        }
#endif
    }

  /* Enable/disable interrupt handling */

  djoy_enable(priv);
#endif

  priv->du_sample = sample;
  leave_critical_section(flags);
}
Esempio n. 29
0
int board_ajoy_initialize(void)
{
  int ret;
  int i;

#ifndef NO_JOYSTICK_ADC
  int fd;

  iinfo("Initialize ADC driver: /dev/adc0\n");

  /* NOTE: The ADC driver was initialized earlier in the bring-up sequence. */
  /* Open the ADC driver for reading. */

  fd = open("/dev/adc0", O_RDONLY);
  if (fd < 0)
    {
      int errcode = get_errno();
      ierr("ERROR: Failed to open /dev/adc0: %d\n", errcode);
      return -errcode;
    }

  /* Detach the file structure from the file descriptor so that it can be
   * used on any thread.
   */

  ret = file_detach(fd, &g_adcfile);
  if (ret < 0)
    {
      ierr("ERROR: Failed to detach from file descriptor: %d\n", ret);
      (void)close(fd);
      return ret;
    }
#endif

  /* Configure the GPIO pins as interrupting inputs.  NOTE: This is
   * unnecessary for interrupting pins since it will also be done by
   * stm32_gpiosetevent().
   */

  for (i = 0; i < AJOY_NGPIOS; i++)
    {
      /* Configure the PIO as an input */

      stm32_configgpio(g_joygpio[i]);
    }

  /* Register the joystick device as /dev/ajoy0 */

  iinfo("Initialize joystick driver: /dev/ajoy0\n");

  ret = ajoy_register("/dev/ajoy0", &g_ajoylower);
  if (ret < 0)
    {
      ierr("ERROR: ajoy_register failed: %d\n", ret);
#ifndef NO_JOYSTICK_ADC
      file_close_detached(&g_adcfile);
#endif
    }

  return ret;
}
Esempio n. 30
0
int stmpe811_register(STMPE811_HANDLE handle, int minor)
{
  FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)handle;
  char devname[DEV_NAMELEN];
  int ret;

  iinfo("handle=%p minor=%d\n", handle, minor);
  DEBUGASSERT(priv);

  /* Get exclusive access to the device structure */

  ret = sem_wait(&priv->exclsem);
  if (ret < 0)
    {
      int errval = errno;
      ierr("ERROR: sem_wait failed: %d\n", errval);
      return -errval;
    }

  /* Make sure that the pins (4-7) need by the TSC are not already in use */

  if ((priv->inuse & TSC_PIN_SET) != 0)
    {
      ierr("ERROR: TSC pins is already in-use: %02x\n", priv->inuse);
      sem_post(&priv->exclsem);
      return -EBUSY;
    }

  /* Initialize the TS structure fields to their default values */

  priv->minor     = minor;
  priv->penchange = false;
  priv->threshx   = 0;
  priv->threshy   = 0;

  /* Create a timer for catching missed pen up conditions */

  priv->wdog      = wd_create();
  if (!priv->wdog)
    {
      ierr("ERROR: Failed to create a watchdog\n", errno);
      sem_post(&priv->exclsem);
      return -ENOSPC;
    }

  /* Register the character driver */

  snprintf(devname, DEV_NAMELEN, DEV_FORMAT, minor);
  ret = register_driver(devname, &g_stmpe811fops, 0666, priv);
  if (ret < 0)
    {
      ierr("ERROR: Failed to register driver %s: %d\n", devname, ret);
      sem_post(&priv->exclsem);
      return ret;
    }

  /* Initialize the touchscreen controller */

  stmpe811_tscinitialize(priv);

  /* Inidicate that the touchscreen controller was successfully initialized */

  priv->inuse |= TSC_PIN_SET;                    /* Pins 4-7 are now in-use */
  priv->flags |= STMPE811_FLAGS_TSC_INITIALIZED;  /* TSC function is initialized */
  sem_post(&priv->exclsem);
  return ret;
}