drivers/sensors/apds9960.c: Use work_queue to read/process data when receive an IRQ

This commit is contained in:
Alan Carvalho de Assis 2017-10-20 08:54:44 -06:00 committed by Gregory Nutt
parent b87739d174
commit 0be36a6ac1
2 changed files with 99 additions and 42 deletions

View File

@ -51,6 +51,7 @@
#include <nuttx/kmalloc.h>
#include <nuttx/signal.h>
#include <nuttx/random.h>
#include <nuttx/wqueue.h>
#include <nuttx/fs/fs.h>
#include <nuttx/i2c/i2c_master.h>
#include <nuttx/sensors/apds9960.h>
@ -71,16 +72,18 @@
struct apds9960_dev_s
{
FAR struct apds9960_config_s *config; /* Hardware Configuration */
struct gesture_data_s gesture_data; /* Gesture data container */
int gesture_ud_delta; /* UP/DOWN delta */
int gesture_lr_delta; /* LEFT/RIGHT delta */
int gesture_ud_count; /* UP/DOWN counter */
int gesture_lr_count; /* LEFT/RIGHT counter */
int gesture_near_count; /* Near distance counter */
int gesture_far_count; /* Far distance counter */
int gesture_state; /* Gesture machine state */
int gesture_motion; /* Gesture motion direction */
FAR struct apds9960_config_s *config; /* Hardware Configuration */
struct work_s work; /* Supports ISR "bottom half" */
struct gesture_data_s gesture_data; /* Gesture data container */
int gesture_ud_delta; /* UP/DOWN delta */
int gesture_lr_delta; /* LEFT/RIGHT delta */
int gesture_ud_count; /* UP/DOWN counter */
int gesture_lr_count; /* LEFT/RIGHT counter */
int gesture_near_count; /* Near distance counter */
int gesture_far_count; /* Far distance counter */
int gesture_state; /* Gesture machine state */
int gesture_motion; /* Gesture motion direction */
sem_t sample_sem; /* Semaphore for sample data */
};
/****************************************************************************
@ -99,6 +102,17 @@ static int apds9960_setdefault(FAR struct apds9960_dev_s *priv);
static int apds9960_probe(FAR struct apds9960_dev_s *priv);
/* Work queue */
static void apds9960_worker(FAR void *arg);
/* Gesture processing/decoding functions */
static int apds9960_readgesture(FAR struct apds9960_dev_s *priv);
static bool apds9960_decodegesture(FAR struct apds9960_dev_s *priv);
static bool apds9960_processgesture(FAR struct apds9960_dev_s *priv);
static bool apds9960_isgestureavailable(FAR struct apds9960_dev_s *priv);
/* I2C Helpers */
static int apds9960_i2c_read(FAR struct apds9960_dev_s *priv,
@ -143,6 +157,24 @@ static const struct file_operations g_apds9960_fops =
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: apds9960_worker
****************************************************************************/
static void apds9960_worker(FAR void *arg)
{
FAR struct apds9960_dev_s *priv = (FAR struct apds9960_dev_s *)arg;
int ret;
DEBUGASSERT(priv != NULL);
ret = apds9960_readgesture(priv);
if (ret != DIR_NONE)
{
sninfo("Got a valid gesture!\n");
}
}
/****************************************************************************
* Name: apds9960_int_handler
*
@ -153,11 +185,23 @@ static const struct file_operations g_apds9960_fops =
static int apds9960_int_handler(int irq, FAR void *context, FAR void *arg)
{
int ret;
FAR struct apds9960_dev_s *priv = (FAR struct apds9960_dev_s *)arg;
DEBUGASSERT(priv != NULL);
snwarn("Interrupt on I2C add %d!\n", priv->config->i2c_addr);
/* Transfer processing to the worker thread. Since APDS-9960 interrupts
* are disabled while the work is pending, no special action should be
* required to protect the work queue.
*/
DEBUGASSERT(priv->work.worker == NULL);
ret = work_queue(HPWORK, &priv->work, apds9960_worker, priv, 0);
if (ret != 0)
{
snerr("ERROR: Failed to queue work: %d\n", ret);
}
return OK;
}
@ -185,7 +229,6 @@ static void apds9960_resetgesture(FAR struct apds9960_dev_s *priv)
priv->gesture_far_count = 0;
priv->gesture_state = 0;
priv->gesture_motion = DIR_NONE;
}
/****************************************************************************
@ -587,7 +630,7 @@ static bool apds9960_isgestureavailable(FAR struct apds9960_dev_s *priv)
*
****************************************************************************/
bool apds9960_processgesture(FAR struct apds9960_dev_s *priv)
static bool apds9960_processgesture(FAR struct apds9960_dev_s *priv)
{
uint8_t u_first = 0;
uint8_t d_first = 0;
@ -811,14 +854,14 @@ bool apds9960_processgesture(FAR struct apds9960_dev_s *priv)
}
/****************************************************************************
* Name: apds9960_readgesture
* Name: apds9960_decodegesture
*
* Description:
* Read the photodiode data, process/decode it and return the guess
* Decode the sensor data and return true if there is some valid data
*
****************************************************************************/
bool apds9960_decodegesture(FAR struct apds9960_dev_s *priv)
static bool apds9960_decodegesture(FAR struct apds9960_dev_s *priv)
{
/* Return if near or far event is detected */
@ -944,7 +987,7 @@ bool apds9960_decodegesture(FAR struct apds9960_dev_s *priv)
*
****************************************************************************/
int apds9960_readgesture(FAR struct apds9960_dev_s *priv)
static int apds9960_readgesture(FAR struct apds9960_dev_s *priv)
{
uint8_t fifo_level = 0;
uint8_t bytes_read = 0;
@ -1086,6 +1129,10 @@ int apds9960_readgesture(FAR struct apds9960_dev_s *priv)
snwarn("RESULT = DOWN\n");
}
/* Increase semaphore to indicate new data */
nxsem_post(&priv->sample_sem);
apds9960_resetgesture(priv);
return motion;
}
@ -1127,6 +1174,7 @@ static ssize_t apds9960_read(FAR struct file *filep, FAR char *buffer,
{
FAR struct inode *inode;
FAR struct apds9960_dev_s *priv;
int ret;
DEBUGASSERT(filep);
inode = filep->f_inode;
@ -1136,21 +1184,28 @@ static ssize_t apds9960_read(FAR struct file *filep, FAR char *buffer,
/* Check if the user is reading the right size */
if (buflen != 4)
if (buflen < 1)
{
snerr("ERROR: You need to read 4 bytes from this sensor!\n");
snerr("ERROR: You need to read at least 1 byte from this sensor!\n");
return -EINVAL;
}
/* Read Gesture */
/* Wait for data available */
apds9960_readgesture(priv);
do
{
ret = nxsem_wait(&priv->sample_sem);
/* Just return something, when done this driver will return keyboard arrows */
/* The only case that an error should occur here is if the wait was
* awakened by a signal.
*/
buffer = (FAR char *) priv->gesture_data.u_data;
DEBUGASSERT(ret == OK || ret == -EINTR);
}
while (ret == -EINTR);
nxsig_usleep(1000);
buffer[0] = (char) priv->gesture_motion;
buflen = 1;
return buflen;
}
@ -1206,6 +1261,8 @@ int apds9960_register(FAR const char *devpath,
}
priv->config = config;
nxsem_init(&priv->sample_sem, 0, 0);
priv->gesture_motion = DIR_NONE;
/* Probe APDS9960 device */

View File

@ -122,9 +122,9 @@
/* PERS Register */
#define APERS_SHIFT 0 /* Bits 0-3: ALS Int. Persistence */
#define APERS_SHIFT 0 /* Bits 0-3: ALS Int. Persistence */
#define APERS_MASK (0xf << PERS_APERS_SHIFT)
#define PPERS_SHIFT 4 /* Bits 4-7: Prox. Int. Persistence */
#define PPERS_SHIFT 4 /* Bits 4-7: Prox. Int. Persistence */
#define PPERS_MASK (0xf << PERS_APERS_SHIFT)
/* CONFIG1 Register */
@ -134,10 +134,10 @@
/* PPULSE Register */
#define PPULSE_SHIFT 0 /* Bits 0-5: Prox. Pulse Count (1 up to 64 pulses) */
#define PPULSE_SHIFT 0 /* Bits 0-5: Prox. Pulse Count (1 up to 64 pulses) */
#define PPULSE_MASK (0x3f << PPULSE_SHIFT)
# define PPULSE_NUM(n) ((n-1) << PPULSE_SHIFT)
#define PPLEN_SHIFT 6 /* Bits 6-7: Prox. Pulse Lenght */
#define PPLEN_SHIFT 6 /* Bits 6-7: Prox. Pulse Lenght */
#define PPLEN_MASK (3 << PPLEN_SHIFT)
# define PPLEN_4US (0 << PPLEN_SHIFT)
# define PPLEN_8US (1 << PPLEN_SHIFT)
@ -146,19 +146,19 @@
/* CONTROL Register */
#define AGAIN_SHIFT 0 /* Bits 0-1: ALS Gain Control */
#define AGAIN_SHIFT 0 /* Bits 0-1: ALS Gain Control */
#define AGAIN_MASK (3 << AGAIN_SHIFT)
# define AGAIN_1X (0 << AGAIN_SHIFT)
# define AGAIN_2X (1 << AGAIN_SHIFT)
# define AGAIN_4X (2 << AGAIN_SHIFT)
# define AGAIN_8X (3 << AGAIN_SHIFT)
#define PGAIN_SHIFT 2 /* Bits 2-3: Proximity Gain Control */
#define PGAIN_SHIFT 2 /* Bits 2-3: Proximity Gain Control */
#define PGAIN_MASK (3 << PGAIN_SHIFT)
# define PGAIN_1X (0 << PGAIN_SHIFT)
# define PGAIN_2X (1 << PGAIN_SHIFT)
# define PGAIN_4X (2 << PGAIN_SHIFT)
# define PGAIN_8X (3 << PGAIN_SHIFT)
#define LDRIVE_SHIFT 6 /* Bits 6-7: LED Drive Strength */
#define LDRIVE_SHIFT 6 /* Bits 6-7: LED Drive Strength */
#define LDRIVE_MASK (3 << LDRIVE_SHIFT)
# define LDRIVE_100MA (0 << LDRIVE_SHIFT)
# define LDRIVE_50MA (1 << LDRIVE_SHIFT)
@ -167,7 +167,7 @@
/* CONFIG2 Register */
#define LEDBOOST_SHIFT 4 /* Bits 4-5: Proximity/Gesture LED Boost */
#define LEDBOOST_SHIFT 4 /* Bits 4-5: Proximity/Gesture LED Boost */
#define LEDBOOST_MASK (3 << LEDBOOST_SHIFT)
# define LEDBOOST_100 (0 << LEDBOOST_SHIFT) /* Boost LED 100% */
# define LEDBOOST_150 (1 << LEDBOOST_SHIFT) /* Boost LED 150% */
@ -195,15 +195,15 @@
/* GCONFIG1 Register */
#define GEXPERS_SHIFT 0 /* Bits 0-1: Gesture Exit Persistence */
#define GEXPERS_SHIFT 0 /* Bits 0-1: Gesture Exit Persistence */
#define GEXPERS_MASK (3 << GEXPERS_SHIFT)
# define GEXPERS_1ST (0 << GEXPERS_SHIFT) /* 1st 'gesture end' exits */
# define GEXPERS_2ND (1 << GEXPERS_SHIFT) /* 2nd 'gesture end' exits */
# define GEXPERS_4TH (2 << GEXPERS_SHIFT) /* 4th 'gesture end' exits */
# define GEXPERS_7TH (3 << GEXPERS_SHIFT) /* 7th 'gesture end' exits */
#define GEXMSK_SHIFT 2 /* Bits 2-5: Gesture Exit Mask */
#define GEXMSK_SHIFT 2 /* Bits 2-5: Gesture Exit Mask */
#define GEXMSK_MASK (0xf << GEXMSK_SHIFT)
#define GFIFOTH_SHIFT 6 /* Bits 6-7: Gesture FIFO Threshold */
#define GFIFOTH_SHIFT 6 /* Bits 6-7: Gesture FIFO Threshold */
#define GFIFOTH_MASK (3 << GFIFOTH_SHIFT)
# define GFIFOTH_1DS (0 << GFIFOTH_SHIFT) /* Interrupt after 1 dataset */
# define GFIFOTH_4DS (1 << GFIFOTH_SHIFT) /* Interrupt after 4 datasets */
@ -212,7 +212,7 @@
/* GCONFIG2 Register */
#define GWTIME_SHIFT 0 /* Bits 0-2: Gesture Wait Time */
#define GWTIME_SHIFT 0 /* Bits 0-2: Gesture Wait Time */
#define GWTIME_MASK (7 << GWTIME_SHIFT)
# define GWTIME_0MS (0 << GWTIME_SHIFT)
# define GWTIME_2p8MS (1 << GWTIME_SHIFT)
@ -222,13 +222,13 @@
# define GWTIME_22p4MS (5 << GWTIME_SHIFT)
# define GWTIME_30p8MS (6 << GWTIME_SHIFT)
# define GWTIME_39p2MS (7 << GWTIME_SHIFT)
#define GLDRIVE_SHIFT 3 /* Bits 3-4: Gesture LED Drive Strength */
#define GLDRIVE_SHIFT 3 /* Bits 3-4: Gesture LED Drive Strength */
#define GLDRIVE_MASK (3 << GLDRIVE_SHIFT)
# define GLDRIVE_100MA (0 << GLDRIVE_SHIFT)
# define GLDRIVE_50MA (1 << GLDRIVE_SHIFT)
# define GLDRIVE_25MA (2 << GLDRIVE_SHIFT)
# define GLDRIVE_12p5MA (3 << GLDRIVE_SHIFT)
#define GGAIN_SHIFT 5 /* Bits 5-6: Gesture Gain Control */
#define GGAIN_SHIFT 5 /* Bits 5-6: Gesture Gain Control */
#define GGAIN_MASK (3 << GGAIN_SHIFT)
# define GGAIN_1X (0 << GGAIN_SHIFT)
# define GGAIN_2X (1 << GGAIN_SHIFT)
@ -237,10 +237,10 @@
/* GPULSE Register */
#define GPULSE_SHIFT 0 /* Bits 0-5: Pulse Count */
#define GPULSE_SHIFT 0 /* Bits 0-5: Pulse Count */
#define GPULSE_MASK (0x3f << GPULSE_SHIFT)
# define GPULSE_NUM(n) ((n-1) << GPULSE_SHIFT)
#define GPLEN_SHIFT 6 /* Bit 6-7: Gesture Pulse Length */
#define GPLEN_SHIFT 6 /* Bit 6-7: Gesture Pulse Length */
#define GPLEN_MASK (3 << GPLEN_SHIFT)
# define GPLEN_4US (0 << GPLEN_SHIFT)
# define GPLEN_8US (1 << GPLEN_SHIFT)
@ -249,7 +249,7 @@
/* GCONFIG3 Register */
#define GDIMS_SHIFT 0 /* Bits 0-1: Gesture Dimension Select */
#define GDIMS_SHIFT 0 /* Bits 0-1: Gesture Dimension Select */
#define GDIMS_MASK (3 << GDIMS_SHIFT)
/* GCONFIG4 Register */
@ -278,7 +278,7 @@
#define DEFAULT_CONFIG3 0 /* Enable all photodiodes, no SAI */
#define DEFAULT_GPENTH 40 /* Threshold for entering gesture mode */
#define DEFAULT_GEXTH 30 /* Threshold for exiting gesture mode */
#define DEFAULT_GCONFIG1 GFIFOTH_4DS /* 4 gesture events for int., 1 for exit */
#define DEFAULT_GCONFIG1 GFIFOTH_8DS /* 8 gesture events for int., 1 for exit */
#define DEFAULT_GCONFIG2 (GGAIN_4X | GLDRIVE_100MA /*| GWTIME_2p8MS*/ )
#define DEFAULT_GOFFSET_U 0 /* No offset scaling for gesture mode */
#define DEFAULT_GOFFSET_D 0 /* No offset scaling for gesture mode */