driver/sensor: add unified management for sensor

Signed-off-by: dongjiuzhu <dongjiuzhu1@xiaomi.com>
This commit is contained in:
dongjiuzhu 2020-10-19 21:24:13 +08:00 committed by Matias N
parent d1f82ced26
commit fa09c6a8bc
4 changed files with 1419 additions and 0 deletions

View File

@ -37,6 +37,8 @@
ifeq ($(CONFIG_SENSORS),y)
CSRCS += sensor.c
ifeq ($(CONFIG_SENSORS_HCSR04),y)
CSRCS += hc_sr04.c
endif

756
drivers/sensors/sensor.c Normal file
View File

@ -0,0 +1,756 @@
/****************************************************************************
* drivers/sensors/sensor.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <debug.h>
#include <poll.h>
#include <fcntl.h>
#include <nuttx/kmalloc.h>
#include <nuttx/sensors/sensor.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Device naming ************************************************************/
#define ROUNDUP(x, esize) ((x + (esize - 1)) / (esize)) * (esize)
#define DEVNAME_FMT "/dev/sensor/%s%s%d"
#define DEVNAME_MAX 64
#define DEVNAME_UNCAL "_uncal"
/****************************************************************************
* Private Types
****************************************************************************/
/* This structure describes sensor info */
struct sensor_info
{
uint8_t idx;
const uint8_t esize;
FAR const char *name;
};
/* This structure describes sensor circular buffer */
struct sensor_buffer_s
{
uint32_t head;
uint32_t tail;
uint32_t size;
FAR void *data;
};
/* This structure describes the state of the upper half driver */
struct sensor_upperhalf_s
{
FAR struct sensor_lowerhalf_s *lower; /* the handle of lower half driver */
FAR struct sensor_buffer_s *buffer; /* The circualr buffer of sensor device */
FAR struct pollfd *fds; /* poll structures of threads waiting for driver events. */
uint8_t idx; /* The index number of node path */
uint8_t crefs; /* Number of times the device has been opened */
sem_t exclsem; /* Manages exclusive access to file operations */
sem_t buffersem; /* Wakeup user waiting for data in circular buffer */
bool enabled; /* The status of sensor enable or disable */
unsigned int interval; /* The sample interval for sensor, in us */
unsigned int latency; /* The batch latency for sensor, in us */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static void sensor_pollnotify(FAR struct sensor_upperhalf_s *upper,
pollevent_t eventset);
static int sensor_open(FAR struct file *filep);
static int sensor_close(FAR struct file *filep);
static ssize_t sensor_read(FAR struct file *filep, FAR char *buffer,
size_t buflen);
static int sensor_ioctl(FAR struct file *filep, int cmd,
unsigned long arg);
static int sensor_poll(FAR struct file *filep, FAR struct pollfd *fds,
bool setup);
/****************************************************************************
* Private Data
****************************************************************************/
static struct sensor_info g_sensor_info[] =
{
{0, sizeof(struct sensor_event_accel), "accel"},
{0, sizeof(struct sensor_event_mag), "mag"},
{0, sizeof(struct sensor_event_gyro), "gyro"},
{0, sizeof(struct sensor_event_light), "light"},
{0, sizeof(struct sensor_event_baro), "baro"},
{0, sizeof(struct sensor_event_prox), "prox"},
{0, sizeof(struct sensor_event_humi), "humi"},
{0, sizeof(struct sensor_event_temp), "temp"},
{0, sizeof(struct sensor_event_rgb), "rgb"},
{0, sizeof(struct sensor_event_hall), "hall"},
{0, sizeof(struct sensor_event_ir), "ir"},
{0, sizeof(struct sensor_event_gps), "gps"},
{0, sizeof(struct sensor_event_uv), "uv"},
{0, sizeof(struct sensor_event_noise), "noise"},
{0, sizeof(struct sensor_event_pm25), "pm25"},
{0, sizeof(struct sensor_event_pm1p0), "pm1p0"},
{0, sizeof(struct sensor_event_pm10), "pm10"},
{0, sizeof(struct sensor_event_co2), "co2"},
{0, sizeof(struct sensor_event_hcho), "hcho"},
{0, sizeof(struct sensor_event_tvoc), "tvoc"},
{0, sizeof(struct sensor_event_ph), "ph"},
{0, sizeof(struct sensor_event_dust), "dust"},
{0, sizeof(struct sensor_event_hrate), "hrate"},
{0, sizeof(struct sensor_event_hbeat), "hbeat"},
};
static const struct file_operations g_sensor_fops =
{
sensor_open, /* open */
sensor_close, /* close */
sensor_read, /* read */
NULL, /* write */
NULL, /* seek */
sensor_ioctl, /* ioctl */
sensor_poll /* poll */
};
/****************************************************************************
* Private Functions
****************************************************************************/
static bool sensor_buffer_is_empty(FAR struct sensor_buffer_s *buffer)
{
return buffer->head == buffer->tail;
}
static uint32_t sensor_buffer_len(FAR struct sensor_buffer_s *buffer)
{
return buffer->head - buffer->tail;
}
static uint32_t sensor_buffer_unused(FAR struct sensor_buffer_s *buffer)
{
return buffer->size - sensor_buffer_len(buffer);
}
static void sensor_buffer_reset(FAR struct sensor_buffer_s *buffer)
{
buffer->head = buffer->tail = 0;
}
static void sensor_buffer_push(FAR struct sensor_buffer_s *buffer,
FAR const void *data, uint32_t bytes)
{
uint32_t space = sensor_buffer_unused(buffer);
uint32_t off = buffer->head % buffer->size;
uint32_t overwrite = 0;
/* If buffer is full or there is not enough space, overwriting of old
* data will occur, we should move tail point after pushing data
* completely.
*/
if (bytes > buffer->size)
{
data += bytes - buffer->size;
bytes = buffer->size;
}
if (bytes > space)
{
overwrite = bytes - space;
}
space = buffer->size - off;
if (bytes < space)
{
space = bytes;
}
memcpy(buffer->data + off, data, space);
memcpy(buffer->data, data + space, bytes - space);
buffer->head += bytes;
buffer->tail += overwrite;
}
static uint32_t sensor_buffer_pop(FAR struct sensor_buffer_s *buffer,
FAR void *data, uint32_t bytes)
{
uint32_t len = sensor_buffer_len(buffer);
uint32_t off;
if (bytes > len)
{
bytes = len;
}
if (!data)
{
goto skip;
}
off = buffer->tail % buffer->size;
len = buffer->size - off;
if (bytes < len)
{
len = bytes;
}
memcpy(data, buffer->data + off, len);
memcpy(data + len, buffer->data, bytes - len);
skip:
buffer->tail += bytes;
return bytes;
}
static int sensor_buffer_resize(FAR struct sensor_buffer_s **buffer,
int type, uint32_t bytes)
{
FAR struct sensor_buffer_s *tmp;
int len = sensor_buffer_len(*buffer);
int skipped;
bytes = ROUNDUP(bytes, g_sensor_info[type].esize);
tmp = kmm_malloc(sizeof(*tmp) + bytes);
if (!tmp)
{
snerr("Faild to alloc memory for circular buffer\n");
return -ENOMEM;
}
tmp->data = tmp + 1;
skipped = (bytes > len) ? 0 : len - bytes;
len -= skipped;
sensor_buffer_pop(*buffer, NULL, skipped);
sensor_buffer_pop(*buffer, tmp->data, len);
tmp->size = bytes;
tmp->head = len;
tmp->tail = 0;
kmm_free(*buffer);
*buffer = tmp;
return 0;
}
static int sensor_buffer_create(FAR struct sensor_buffer_s **buffer,
int type, uint32_t bytes)
{
FAR struct sensor_buffer_s *tmp;
bytes = ROUNDUP(bytes, g_sensor_info[type].esize);
tmp = kmm_malloc(sizeof(*tmp) + bytes);
if (!tmp)
{
snerr("Faild to malloc memory for circular buffer\n");
return -ENOMEM;
}
tmp->size = bytes;
tmp->data = tmp + 1;
tmp->head = 0;
tmp->tail = 0;
*buffer = tmp;
return 0;
}
static void sensor_buffer_release(FAR struct sensor_buffer_s *buffer)
{
kmm_free(buffer);
}
static void sensor_pollnotify(FAR struct sensor_upperhalf_s *upper,
pollevent_t eventset)
{
int semcount;
if (upper->fds)
{
upper->fds->revents |= (upper->fds->events & eventset);
if (upper->fds->revents != 0)
{
sninfo("Report events: %02x\n", upper->fds->revents);
nxsem_get_value(upper->fds->sem, &semcount);
if (semcount < 1)
{
nxsem_post(upper->fds->sem);
}
}
}
}
static int sensor_open(FAR struct file *filep)
{
FAR struct inode *inode = filep->f_inode;
FAR struct sensor_upperhalf_s *upper = inode->i_private;
int ret;
ret = nxsem_wait(&upper->exclsem);
if (ret < 0)
{
return ret;
}
if (upper->crefs)
{
ret = -EBUSY;
}
else
{
upper->crefs++;
upper->fds = NULL;
sensor_buffer_reset(upper->buffer);
}
nxsem_post(&upper->exclsem);
return ret;
}
static int sensor_close(FAR struct file *filep)
{
FAR struct inode *inode = filep->f_inode;
FAR struct sensor_upperhalf_s *upper = inode->i_private;
FAR struct sensor_lowerhalf_s *lower = upper->lower;
int ret;
ret = nxsem_wait(&upper->exclsem);
if (ret < 0)
{
return ret;
}
if (--upper->crefs <= 0 && upper->enabled)
{
ret = lower->ops->activate ?
lower->ops->activate(lower, false) : -ENOTSUP;
if (ret >= 0)
{
upper->enabled = false;
}
}
nxsem_post(&upper->exclsem);
return ret;
}
static ssize_t sensor_read(FAR struct file *filep, FAR char *buffer,
size_t len)
{
FAR struct inode *inode = filep->f_inode;
FAR struct sensor_upperhalf_s *upper = inode->i_private;
FAR struct sensor_lowerhalf_s *lower = upper->lower;
ssize_t ret;
if (!buffer || !len)
{
return -EINVAL;
}
ret = nxsem_wait(&upper->exclsem);
if (ret < 0)
{
return ret;
}
/* We must make sure that when the semaphore is equal to 1, there must
* be events avaliable in the buffer, so we use a while statement to
* synchronize this case that other read operations consume events
* that have just entered the buffer.
*/
while (sensor_buffer_is_empty(upper->buffer))
{
if (filep->f_oflags & O_NONBLOCK)
{
ret = -EAGAIN;
goto again;
}
else
{
nxsem_post(&upper->exclsem);
ret = nxsem_wait_uninterruptible(&upper->buffersem);
if (ret)
{
return ret;
}
ret = nxsem_wait(&upper->exclsem);
if (ret < 0)
{
return ret;
}
}
}
ret = sensor_buffer_pop(upper->buffer, buffer, len);
/* Release some buffer space when current mode isn't batch mode and last
* mode is batch mode, and the number of bytes avaliable in buffer is
* less than the number of bytes origin.
*/
if (upper->latency == 0 &&
upper->buffer->size > lower->buffer_bytes &&
sensor_buffer_len(upper->buffer) <= lower->buffer_bytes)
{
sensor_buffer_resize(&upper->buffer, lower->type, lower->buffer_bytes);
}
again:
nxsem_post(&upper->exclsem);
return ret;
}
static int sensor_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
{
FAR struct inode *inode = filep->f_inode;
FAR struct sensor_upperhalf_s *upper = inode->i_private;
FAR struct sensor_lowerhalf_s *lower = upper->lower;
FAR unsigned int *val = (unsigned int *)(uintptr_t)arg;
int ret;
sninfo("cmd=%x arg=%08x\n", cmd, arg);
ret = nxsem_wait(&upper->exclsem);
if (ret < 0)
{
return ret;
}
switch (cmd)
{
case SNIOC_ACTIVATE:
{
if (upper->enabled == !!arg)
{
break;
}
ret = lower->ops->activate ?
lower->ops->activate(lower, !!arg) : -ENOTSUP;
if (ret >= 0)
{
upper->enabled = !!arg;
}
}
break;
case SNIOC_SET_INTERVAL:
{
if (upper->interval == *val)
{
break;
}
ret = lower->ops->set_interval ?
lower->ops->set_interval(lower, val) : -ENOTSUP;
if (ret >= 0)
{
upper->interval = *val;
}
}
break;
case SNIOC_BATCH:
{
if (upper->interval == 0)
{
ret = -EINVAL;
break;
}
if (upper->latency == *val)
{
break;
}
ret = lower->ops->batch ?
lower->ops->batch(lower, val) : -ENOTSUP;
if (ret >= 0)
{
upper->latency = *val;
if (*val != 0)
{
/* Adjust length of buffer in batch mode */
sensor_buffer_resize(&upper->buffer, lower->type,
lower->buffer_bytes +
ROUNDUP(*val, upper->interval) /
upper->interval *
g_sensor_info[lower->type].esize);
}
}
}
break;
case SNIOC_GET_NEVENTBUF:
{
*val = lower->buffer_bytes / g_sensor_info[lower->type].esize;
}
break;
default:
ret = -ENOTTY;
break;
}
nxsem_post(&upper->exclsem);
return ret;
}
static int sensor_poll(FAR struct file *filep,
struct pollfd *fds, bool setup)
{
FAR struct inode *inode = filep->f_inode;
FAR struct sensor_upperhalf_s *upper = inode->i_private;
pollevent_t eventset = 0;
int ret;
ret = nxsem_wait(&upper->exclsem);
if (ret < 0)
{
return ret;
}
if (setup)
{
if (upper->fds)
{
ret = -EBUSY;
goto errout;
}
upper->fds = fds;
fds->priv = &upper->fds;
if (!sensor_buffer_is_empty(upper->buffer))
{
eventset |= (fds->events & POLLIN);
}
if (eventset)
{
sensor_pollnotify(upper, eventset);
}
}
else if (fds->priv != NULL)
{
FAR struct pollfd **slot = (FAR struct pollfd **)fds->priv;
if (!slot)
{
ret = -EIO;
goto errout;
}
*slot = NULL;
fds->priv = NULL;
}
errout:
nxsem_post(&upper->exclsem);
return ret;
}
static void sensor_push_event(FAR void *priv, FAR const void *data,
uint32_t bytes)
{
FAR struct sensor_upperhalf_s *upper = priv;
int semcount;
if (!bytes || nxsem_wait(&upper->exclsem) < 0)
{
return;
}
sensor_buffer_push(upper->buffer, data, bytes);
sensor_pollnotify(upper, POLLIN);
nxsem_get_value(&upper->buffersem, &semcount);
if (semcount < 1)
{
nxsem_post(&upper->buffersem);
}
nxsem_post(&upper->exclsem);
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: sensor_register
*
* Description:
* This function binds an instance of a "lower half" Sensor driver with the
* "upper half" Sensor device and registers that device so that can be used
* by application code.
*
* We will register the chararter device by node name format based on the
* type of sensor. Multiple types of the same type are distinguished by
* numbers. eg: accel0, accel1
*
* Input Parameters:
* dev - A pointer to an instance of lower half sensor driver. This
* instance is bound to the sensor driver and must persists as long
* as the driver persists.
*
* Returned Value:
* OK if the driver was successfully register; A negated errno value is
* returned on any failure.
*
****************************************************************************/
int sensor_register(FAR struct sensor_lowerhalf_s *lower)
{
FAR struct sensor_upperhalf_s *upper;
char path[DEVNAME_MAX];
int ret = -EINVAL;
DEBUGASSERT(lower != NULL);
if (lower->type >= SENSOR_TYPE_COUNT)
{
snerr("ERROR: Type is invalid\n");
return ret;
}
/* Allocate the upper-half data structure */
upper = kmm_zalloc(sizeof(struct sensor_upperhalf_s));
if (!upper)
{
snerr("ERROR: Allocation failed\n");
return -ENOMEM;
}
/* Initialize the upper-half data structure */
upper->lower = lower;
nxsem_init(&upper->exclsem, 0, 1);
nxsem_init(&upper->buffersem, 0, 0);
nxsem_set_protocol(&upper->buffersem, SEM_PRIO_NONE);
/* Bind the lower half data structure member */
lower->priv = upper;
lower->push_event = sensor_push_event;
if (!lower->buffer_bytes)
{
lower->buffer_bytes = g_sensor_info[lower->type].esize;
}
/* Initialize sensor buffer */
ret = sensor_buffer_create(&upper->buffer,
lower->type, lower->buffer_bytes);
if (ret)
{
goto buf_err;
}
upper->idx = g_sensor_info[lower->type].idx++;
snprintf(path, DEVNAME_MAX, DEVNAME_FMT,
g_sensor_info[lower->type].name,
lower->uncalibrated ? DEVNAME_UNCAL : "",
upper->idx);
sninfo("Registering %s\n", path);
ret = register_driver(path, &g_sensor_fops, 0666, upper);
if (ret)
{
goto drv_err;
}
return ret;
drv_err:
sensor_buffer_release(upper->buffer);
g_sensor_info[lower->type].idx--;
buf_err:
nxsem_destroy(&upper->exclsem);
nxsem_destroy(&upper->buffersem);
kmm_free(upper);
return ret;
}
/****************************************************************************
* Name: sensor_unregister
*
* Description:
* This function unregister character node and release all resource about
* upper half driver.
*
* Input Parameters:
* dev - A pointer to an instance of lower half sensor driver. This
* instance is bound to the sensor driver and must persists as long
* as the driver persists.
****************************************************************************/
void sensor_unregister(FAR struct sensor_lowerhalf_s *lower)
{
FAR struct sensor_upperhalf_s *upper;
char path[DEVNAME_MAX];
DEBUGASSERT(lower != NULL);
DEBUGASSERT(lower->priv != NULL);
upper = lower->priv;
snprintf(path, DEVNAME_MAX, DEVNAME_FMT,
g_sensor_info[lower->type].name,
lower->uncalibrated ? DEVNAME_UNCAL : "",
upper->idx);
sninfo("UnRegistering %s\n", path);
unregister_driver(path);
nxsem_destroy(&upper->exclsem);
nxsem_destroy(&upper->buffersem);
sensor_buffer_release(upper->buffer);
kmm_free(upper);
}

View File

@ -181,8 +181,11 @@
/* IOCTL commands unique to the SCD30 */
/* SNIOC_RESET */ /* Arg: None */
/* SNIOC_START */ /* Arg: None */
/* SNIOC_STOP */ /* Arg: None */
/* SNIOC_READ_CONVERT_DATA */ /* Arg: struct scd30_conv_data_s* */
#define SNIOC_SET_INTERVAL _SNIOC(0x0054) /* Arg: uint16_t value (seconds) */
#define SNIOC_SET_TEMP_OFFSET _SNIOC(0x0055) /* Arg: uint16_t value (0.01 Kelvin) */
@ -194,9 +197,13 @@
/* IOCTL commands unique to the SGP30 */
/* SNIOC_RESET */ /* Arg: None */
/* SNIOC_START_SELFTEST */ /* Arg: None */
/* SNIOC_READ_CONVERT_DATA */ /* Arg: struct sgp30_conv_data_s* */
/* SNIOC_READ_RAW_DATA */ /* Arg: struct sgp30_raw_data_s* */
#define SNIOC_GET_BASELINE _SNIOC(0x005a) /* Arg: struct sgp30_baseline_s* */
#define SNIOC_SET_BASELINE _SNIOC(0x005b) /* Arg: const struct sgp30_baseline_s* */
#define SNIOC_SET_HUMIDITY _SNIOC(0x005c) /* Arg: uint32_t value (mg/m³) */
@ -204,9 +211,13 @@
/* IOCTL commands unique to the SPS30 */
/* SNIOC_RESET */ /* Arg: None */
/* SNIOC_START */ /* Arg: None */
/* SNIOC_STOP */ /* Arg: None */
/* SNIOC_READ_CONVERT_DATA */ /* Arg: struct sps30_conv_data_s* */
#define SNIOC_SET_CLEAN_INTERVAL _SNIOC(0x005d) /* Arg: uint32_t value (seconds) */
#define SNIOC_START_FAN_CLEANING _SNIOC(0x005e) /* Arg: None */
@ -227,4 +238,39 @@
#define SNIOC_SET_RESOLUTION _SNIOC(0x0065) /* Arg: uint8_t value */
#define SNIOC_SET_RANGE _SNIOC(0x0066) /* Arg: uint8_t value */
/* Command: SNIOC_ACTIVATE
* Description: Enable or disable sensor
* Argument: true or false.
*/
#define SNIOC_ACTIVATE _SNIOC(0x0067)
/* Command: SNIOC_SET_INTERVAL
* Description: Set interval between samples
* Argument: This is the interval pointer, in microseconds
*/
#define SNIOC_SET_INTERVAL _SNIOC(0x0068)
/* Command: SNIOC_BATCH
* Description: Set batch latency between batch data.
* Argument: This is the latency pointer, in microseconds
*/
#define SNIOC_BATCH _SNIOC(0x0069)
/* Command: SNIOC_GET_NEVENTBUF
* Description: the number of sensor events that sensor buffer of upper half holds.
* Argument: This is the number of events pointer, is output parameter.
* Note: We need to tell the application layer number of sensor events in
* sensor buffer. This buffer is used to solve the problem that the
* application layer can't read the sensor event in time. We recommend
* the number of sensor events in application layer's buffer is same as
* result by call this function.
* This is number of sensor events rather than the length of buffer.
* See sensor.h(struct sensor_lower_half_s buffer_bytes).
*/
#define SNIOC_GET_NEVENTBUF _SNIOC(0x0070)
#endif /* __INCLUDE_NUTTX_SENSORS_IOCTL_H */

View File

@ -0,0 +1,615 @@
/****************************************************************************
* include/nuttx/sensors/sensors.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __INCLUDE_NUTTX_SENSORS_SENSOR_H
#define __INCLUDE_NUTTX_SENSORS_SENSOR_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <time.h>
#include <nuttx/sensors/ioctl.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* sensor type definition */
/* Accelerometer
* All values are in SI units (m/s^2), and measure the acceleration of the
* device minus the acceleration dut to gravity.
*/
#define SENSOR_TYPE_ACCELEROMETER 0
/* Magneric Field
* All values are in micro-Tesla (uT) and measure the geomagnetic field
* in X, Y and Z axis.
*/
#define SENSOR_TYPE_MAGNETIC_FIELD 1
/* Gyroscope
* All values are in radians/second and measure the rate of rotation around
* the X, Y and Z axis.
*/
#define SENSOR_TYPE_GYROSCOPE 2
/* Ambient Light
* The ambient light sensor value is returned in SI units lux.
*/
#define SENSOR_TYPE_LIGHT 3
/* Barometer
* All values are in hectopascal (hPa) and measure the athmospheric pressure
* we can calculate altitude by perssure.
*/
#define SENSOR_TYPE_BAROMETER 4
/* Proximity
* The values correspond to the distance to the nearest
* object in centimeters.
*/
#define SENSOR_TYPE_PROXIMITY 5
/* Relative Humidity
* A relative humidity sensor measure relative ambient air humidity and
* return a value in percent.
*/
#define SENSOR_TYPE_RELATIVE_HUMIDITY 6
/* Ambient Temperature
* The ambient (room) temperature in degree Celsius
*/
#define SENSOR_TYPE_AMBIENT_TEMPERATURE 7
/* RGB
* We use these values of RGB to weighted to obtain the color of LED.
* These values is in unit percent.
*/
#define SENSOR_TYPE_RGB 8
/* Hall
* All values are in bool type (0 or 1) and it often is used to as switch.
* A values of 1 indicates that switch on.
*/
#define SENSOR_TYPE_HALL 9
/* IR (Infrared Ray)
* This sensor can detect a human approach and outputs a signal from
* interrupt pins. This sensor value is in lux.
*/
#define SENSOR_TYPE_IR 10
/* GPS
* A sensor of this type returns gps data. Include year, month, day,
* hour, minutes, seconds, altitude, longitude, latitude.
*/
#define SENSOR_TYPE_GPS 11
/* Ultraviolet light sensor
* This sensor can identify the UV index in ambient light help people
* to effectively protect themselves from sunburns, cancer or eye damage.
* This value range is 0 - 15.
*/
#define SENSOR_TYPE_ULTRAVIOLET 12
/* Noise Loudness
* A sensor of this type returns the loudness of noise in SI units (db)
*/
#define SENSOR_TYPE_NOISE 13
/* PM25
* A sensor of this type returns the content of pm2.5 in the air
* This value is in SI units (ug/m^3)
*/
#define SENSOR_TYPE_PM25 14
/* PM1P0
* A sensor of this type returns the content of pm1.0 in the air
* This value is in SI units (ug/m^3)
*/
#define SENSOR_TYPE_PM1P0 15
/* PM10
* A sensor of this type returns the content of pm10 in the air
* This value is in SI units (ug/m^3)
*/
#define SENSOR_TYPE_PM10 16
/* CO2
* A sensor of this type returns the content of CO2 in the air
* This vaule is in units (ppm-part per million).
*/
#define SENSOR_TYPE_CO2 17
/* HCHO
* The HCHO pollution is an important indicator of household air
* pollution. This value is in units (ppm-part per million).
*/
#define SENSOR_TYPE_HCHO 18
/* TVOC (total volatile organic compounds)
* The indoor TVOC is cause indoor air pollution is one of the
* main reasons why. This value is in units (ppb-part per billion).
*/
#define SENSOR_TYPE_TVOC 19
/* PH
* The acid-base degree describes the strength of the aqueous
* solution, expressed by pH. In the thermodynamic standard
* condition, the aqueous solution with pH=7 is neutral,
* pH<7 is acidic, and pH>7 is alkaline.
*/
#define SENSOR_TYPE_PH 20
/* Dust
* A sensor of this type returns the content of dust in the air
* values is in ug/m^3.
*/
#define SENSOR_TYPE_DUST 21
/* Heart Rate
* A sensor of this type returns the current heart rate.
* Current heart rate is in beats per minute (BPM).
*/
#define SENSOR_TYPE_HEART_RATE 22
/* Heart Beat
* A sensor of this type returns an event evetytime
* a hear beat peek is detected. Peak here ideally corresponds
* to the positive peak in the QRS complex of and ECG signal.
*/
#define SENSOR_TYPE_HEART_BEAT 23
/* The total number of sensor */
#define SENSOR_TYPE_COUNT 24
/****************************************************************************
* Inline Functions
****************************************************************************/
static inline uint64_t sensor_get_timestamp(void)
{
struct timespec ts;
#ifdef CONFIG_CLOCK_MONOTONIC
clock_gettime(CLOCK_MONOTONIC, &ts);
#else
clock_gettime(CLOCK_REALTIME, &ts);
#endif
return 1000000ull * ts.tv_sec + ts.tv_nsec / 1000;
}
/****************************************************************************
* Public Types
****************************************************************************/
/* These structures prefixed with sensor_event are sensor data, and member
* that are not used must be written as NAN or INT_MIN/INT_MAX, than
* reported.
*/
struct sensor_event_accel /* Type: Accerometer */
{
uint64_t timestamp; /* Units is microseconds */
float x; /* Axis X in m/s^2 */
float y; /* Axis Y in m/s^2 */
float z; /* Axis Z in m/s^2 */
float temperature; /* Temperature in degrees celsius */
};
struct sensor_event_gyro /* Type: Gyroscope */
{
uint64_t timestamp; /* Units is microseconds */
float x; /* Axis X in rad/s */
float y; /* Axis Y in rad/s */
float z; /* Axis Z in rad/s */
float temperature; /* Temperature in degrees celsius */
};
struct sensor_event_mag /* Type: Magnetic Field */
{
uint64_t timestamp; /* Units is microseconds */
float x; /* Axis X in Gauss or micro Tesla (uT) */
float y; /* Axis Y in Gauss or micro Tesla (uT) */
float z; /* Axis Z in Gauss or micro Tesla (uT) */
float temperature; /* Temperature in degrees celsius */
};
struct sensor_event_baro /* Type: Barometer */
{
uint64_t timestamp; /* Units is microseconds */
float pressure; /* pressure measurement in millibar or hpa */
float temperature; /* Temperature in degrees celsius */
};
struct sensor_event_prox /* Type: proximity */
{
uint64_t timestamp; /* Units is microseconds */
float proximity; /* distance to the nearest object in centimeters */
};
struct sensor_event_light /* Type: Light */
{
uint64_t timestamp; /* Units is microseconds */
float light; /* in SI lux units */
};
struct sensor_event_humi /* Type: Relative Humidity */
{
uint64_t timestamp; /* Units is microseconds */
float humidity; /* in percent */
};
struct sensor_event_temp /* Type: Ambient Temperature */
{
uint64_t timestamp; /* Units is microseconds */
float temperature; /* Temperature in degrees celsius */
};
struct sensor_event_rgb /* Type: RGB */
{
uint64_t timestamp; /* Units is microseconds */
float r; /* Units is percent */
float g; /* Units is percent */
float b; /* Units is percent */
};
struct sensor_event_hall /* Type: HALL */
{
uint64_t timestamp; /* Units is microseconds */
bool hall; /* Boolean type */
};
struct sensor_event_ir /* Type: Infrared Ray */
{
uint64_t timestamp; /* Units is microseconds */
float ir; /* in SI units lux */
};
struct sensor_event_gps /* Type: Gps */
{
int year; /* Time */
int month;
int day;
int hour;
int min;
int sec;
int msec;
float yaw; /* Unit is Si degrees */
float height; /* Unit is SI m */
float speed; /* Unit is m/s */
float latitude; /* Unit is degrees */
float longitude; /* Unit is degrees */
};
struct sensor_event_uv /* Type: Ultraviolet Light */
{
uint64_t timestamp; /* Units is microseconds */
float uvi; /* the vaule range is 0 - 15 */
};
struct sensor_event_noise /* Type: Noise Loudness */
{
uint64_t timestamp; /* Units is microseconds */
float db; /* in SI units db */
};
struct sensor_event_pm25 /* Type: PM25 */
{
uint64_t timestamp; /* Units is microseconds */
float pm25; /* in SI units ug/m^3 */
};
struct sensor_event_pm10 /* Type: PM10 */
{
uint64_t timestamp; /* Units is microseconds */
float pm10; /* in SI units ug/m^3 */
};
struct sensor_event_pm1p0 /* Type: PM1P0 */
{
uint64_t timestamp; /* Units is microseconds */
float pm1p0; /* in SI units ug/m^3 */
};
struct sensor_event_co2 /* Type: CO2 */
{
uint64_t timestamp; /* Units is microseconds */
float co2; /* in SI units ppm */
};
struct sensor_event_hcho /* Type: HCHO */
{
uint64_t timestamp; /* Units is microseconds */
float hcho; /* in SI units ppm */
};
struct sensor_event_tvoc /* Type: TVOC */
{
uint64_t timestamp; /* Units is microseconds */
float tvoc; /* in SI units ppm */
};
struct sensor_event_ph /* Type: PH */
{
uint64_t timestamp; /* Units is microseconds */
float ph; /* PH = 7.0 neutral, PH < 7.0 acidic, PH > 7.0 alkaline */
};
struct sensor_event_dust /* Type: DUST */
{
uint64_t timestamp; /* Units is microseconds */
float dust; /* is SI units ug/m^3 */
};
struct sensor_event_hrate /* Type: Heart Rate */
{
uint64_t timestamp; /* Units is microseconds */
float bpm; /* is SI units BPM */
};
struct sensor_event_hbeat /* Type: Heart Beat */
{
uint64_t timestamp; /* Units is microseconds */
float beat; /* Units is times/minutes */
};
/* The sensor lower half driver interface */
struct sensor_lowerhalf_s;
struct sensor_ops_s
{
/**************************************************************************
* Name: activate
*
* Description:
* Enable or disable sensor device. when enable sensor, sensor will
* work in current mode(if not set, use default mode). when disable
* sensor, it will disable sense path and stop convert.
*
* Input Parameters:
* lower - The instance of lower half sensor driver
* enable - true(enable) and false(disable)
*
* Returned Value:
* Zero (OK) or positive on success; a negated errno value on failure.
*
**************************************************************************/
CODE int (*activate)(FAR struct sensor_lowerhalf_s *lower, bool enable);
/**************************************************************************
* Name: set_interval
*
* Description:
* Set the sensor output data period in microseconds for a given sensor.
* If *period_us > max_delay it will be truncated to max_dealy and if
* *period_us < min_delay it will be replaced by min_delay.
*
* Before changing the interval, we need to push the prepared data to
* ensure that they are not lost.
*
* Input Parameters:
* lower - The instance of lower half sensor driver.
* period_us - the time between samples, in us, it may be overwrite by
* lower half driver.
*
* Returned Value:
* Zero (OK) or positive on success; a negated errno value on failure.
*
**************************************************************************/
CODE int (*set_interval)(FAR struct sensor_lowerhalf_s *lower,
FAR unsigned int *period_us);
/**************************************************************************
* Name: batch
*
* Description:
* Set sensor's maximum report latency in microseconds.
*
* This function can be called while the sensor is activated,
* in which case it must not cause any sensor measurements to be lost.
* So, it is necessary to flush fifo or read ready data from data
* register to prevent data lost before we using batch mode.
*
* This sensor default mode isn't batch mode, so we need call this
* function and *latency_us != 0.
* If *latency_us > max_report_latency it will be truncated to
* max_report_latency and return *latency_us to user
* And we must flush fifo data to prevent data lost, then adjust latency.
*
* We can exit batch mode by call this function with *latency_us = 0.
* And we must flush fifo data to prevent data lost, then stop batch.
*
* If sensor doesn't support batching (FIFO size zero), set batch to
* NULL.
*
* We must set interval by calling set_interval before calling batch(),
* othrewise, -EINVAL is returned.
*
* The reason why we don't have flush operation is that we need to push
* the prepared data out before adjusting the latency to ensure that the
* data will not be lost.
*
* Input Parameters:
* lower - The instance of lower half sensor driver.
* latency_us - the time between batch data, in us. It may by overwrite
* by lower half driver.
*
* Returned Value:
* Zero (OK) or positive on success; a negated errno value on failure.
*
**************************************************************************/
CODE int (*batch)(FAR struct sensor_lowerhalf_s *lower,
FAR unsigned int *latency_us);
};
/* This structure is the generic form of state structure used by lower half
* Sensor driver.
*/
struct sensor_lowerhalf_s
{
/* The type of sensor device */
int type;
/* The bytes length of the circular buffer used.
* This sensor circular buffer is used to slove issue that application
* can't read sensor event in time. If this length of buffer is too large,
* the latency of sensor event will be too larage. If the length of buffer
* is too small, the event will be overwrite before application read them.
* So, it's recommended to set according to sensor odr. If odr is low, you
* can set to a length of sensor event. If odr is high, you can set to two
* or three length of sensor event.
*/
uint32_t buffer_bytes;
/* The uncalibrated use to describe whether the sensor event is
* uncalibrated. True is uncalibrated data, false is calibrated data,
* default false.
*/
bool uncalibrated;
/* The lower half sensor driver operations */
FAR const struct sensor_ops_s *ops;
/**************************************************************************
* Name: push_event
*
* Description:
* Lower half driver push sensor event by calling this function.
* It is provided by upper half driver to lower half driver.
*
* Input Parameters:
* priv - Upper half driver handle
* data - The buffer of event, it can be all type of sensor events.
* bytes - The number of bytes of sensor event
**************************************************************************/
CODE void (*push_event)(FAR void *priv, FAR const void *data,
uint32_t bytes);
/* The private opaque pointer to be passed to upper-layer during callback */
FAR void *priv;
};
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* "Upper Half" Sensor Driver Interfaces
****************************************************************************/
/****************************************************************************
* Name: sensor_register
*
* Description:
* This function binds an instance of a "lower half" Sensor driver with the
* "upper half" Sensor device and registers that device so that can be used
* by application code.
*
* We will register the chararter device by node name format based on the
* type of sensor. Multiple types of the same type are distinguished by
* numbers. eg: accel0, accel1
*
* Input Parameters:
* dev - A pointer to an instance of lower half sensor driver. This
* instance is bound to the sensor driver and must persists as long
* as the driver persists.
*
* Returned Value:
* OK if the driver was successfully register; A negated errno value is
* returned on any failure.
*
****************************************************************************/
int sensor_register(FAR struct sensor_lowerhalf_s *dev);
/****************************************************************************
* Name: sensor_unregister
*
* Description:
* This function unregister character node and release all resource about
* upper half driver.
*
* Input Parameters:
* dev - A pointer to an instance of lower half sensor driver. This
* instance is bound to the sensor driver and must persists as long
* as the driver persists.
****************************************************************************/
void sensor_unregister(FAR struct sensor_lowerhalf_s *dev);
#undef EXTERN
#if defined(__cplusplus)
}
#endif
#endif /* __INCLUDE_NUTTX_SENSORS_SENSOR_H */