drivers/sensors/apds9960.c: Use work_queue to read/process data when receive an IRQ
This commit is contained in:
parent
b87739d174
commit
0be36a6ac1
@ -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 */
|
||||
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user