You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by pr...@apache.org on 2020/10/22 13:17:46 UTC
[incubator-nuttx] 01/03: driver/sensor: add unified management for
sensor
This is an automated email from the ASF dual-hosted git repository.
protobits pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
commit fa09c6a8bc98be155611a4e3047c46a88e56a79f
Author: dongjiuzhu <do...@xiaomi.com>
AuthorDate: Mon Oct 19 21:24:13 2020 +0800
driver/sensor: add unified management for sensor
Signed-off-by: dongjiuzhu <do...@xiaomi.com>
---
drivers/sensors/Make.defs | 2 +
drivers/sensors/sensor.c | 756 +++++++++++++++++++++++++++++++++++++++++
include/nuttx/sensors/ioctl.h | 46 +++
include/nuttx/sensors/sensor.h | 615 +++++++++++++++++++++++++++++++++
4 files changed, 1419 insertions(+)
diff --git a/drivers/sensors/Make.defs b/drivers/sensors/Make.defs
index 53d2132..bf87397 100644
--- a/drivers/sensors/Make.defs
+++ b/drivers/sensors/Make.defs
@@ -37,6 +37,8 @@
ifeq ($(CONFIG_SENSORS),y)
+CSRCS += sensor.c
+
ifeq ($(CONFIG_SENSORS_HCSR04),y)
CSRCS += hc_sr04.c
endif
diff --git a/drivers/sensors/sensor.c b/drivers/sensors/sensor.c
new file mode 100644
index 0000000..99ab9e7
--- /dev/null
+++ b/drivers/sensors/sensor.c
@@ -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);
+}
diff --git a/include/nuttx/sensors/ioctl.h b/include/nuttx/sensors/ioctl.h
index 889b2e2..39f09fc 100644
--- a/include/nuttx/sensors/ioctl.h
+++ b/include/nuttx/sensors/ioctl.h
@@ -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 */
diff --git a/include/nuttx/sensors/sensor.h b/include/nuttx/sensors/sensor.h
new file mode 100644
index 0000000..6d108b4
--- /dev/null
+++ b/include/nuttx/sensors/sensor.h
@@ -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 */