From 089b1c17f6cab31dc8cb0d6ef94975b2063835c5 Mon Sep 17 00:00:00 2001 From: dongjiuzhu Date: Wed, 4 Nov 2020 11:23:39 +0800 Subject: [PATCH] driver/sensor: add fetch api to read sensor data directly 1.use userspace buffer rather than intermediate buffer of upperhalf driver 2.support block and non-block ways. Change-Id: I1d0cecfaa20ce54961c58713d8f2f8857e349791 Signed-off-by: dongjiuzhu --- drivers/sensors/sensor.c | 135 +++++++++++++++++++++++++-------- include/nuttx/sensors/sensor.h | 78 +++++++++++++++---- 2 files changed, 166 insertions(+), 47 deletions(-) diff --git a/drivers/sensors/sensor.c b/drivers/sensors/sensor.c index e41115c93f..1f6ae10249 100644 --- a/drivers/sensors/sensor.c +++ b/drivers/sensors/sensor.c @@ -73,7 +73,6 @@ struct sensor_buffer_s struct sensor_upperhalf_s { - /* poll structures of threads waiting for driver events. */ FAR struct pollfd *fds[CONFIG_SENSORS_NPOLLWAITERS]; @@ -403,24 +402,13 @@ static ssize_t sensor_read(FAR struct file *filep, FAR char *buffer, 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 (lower->ops->fetch) { - if (filep->f_oflags & O_NONBLOCK) - { - ret = -EAGAIN; - goto again; - } - else + if (!(filep->f_oflags & O_NONBLOCK)) { nxsem_post(&upper->exclsem); ret = nxsem_wait_uninterruptible(&upper->buffersem); - if (ret) + if (ret < 0) { return ret; } @@ -431,21 +419,55 @@ static ssize_t sensor_read(FAR struct file *filep, FAR char *buffer, return ret; } } + + ret = lower->ops->fetch(lower, buffer, len); } - - 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_size && - sensor_buffer_len(upper->buffer) <= lower->buffer_size) + else { - sensor_buffer_resize(&upper->buffer, lower->type, - lower->buffer_size); + /* 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 < 0) + { + 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_size && + sensor_buffer_len(upper->buffer) <= lower->buffer_size) + { + sensor_buffer_resize(&upper->buffer, lower->type, + lower->buffer_size); + } } again: @@ -579,7 +601,9 @@ static int sensor_poll(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; pollevent_t eventset = 0; + int semcount; int ret; int i; @@ -609,7 +633,24 @@ static int sensor_poll(FAR struct file *filep, goto errout; } - if (!sensor_buffer_is_empty(upper->buffer)) + if (lower->ops->fetch) + { + /* Always return POLLIN for fetch data directly(non-block) */ + + if (filep->f_oflags & O_NONBLOCK) + { + eventset |= (fds->events & POLLIN); + } + else + { + nxsem_get_value(&upper->buffersem, &semcount); + if (semcount > 0) + { + eventset |= (fds->events & POLLIN); + } + } + } + else if (!sensor_buffer_is_empty(upper->buffer)) { eventset |= (fds->events & POLLIN); } @@ -638,7 +679,7 @@ errout: } static void sensor_push_event(FAR void *priv, FAR const void *data, - uint32_t bytes) + size_t bytes) { FAR struct sensor_upperhalf_s *upper = priv; int semcount; @@ -659,6 +700,26 @@ static void sensor_push_event(FAR void *priv, FAR const void *data, nxsem_post(&upper->exclsem); } +static void sensor_notify_event(FAR void *priv) +{ + FAR struct sensor_upperhalf_s *upper = priv; + int semcount; + + if (nxsem_wait(&upper->exclsem) < 0) + { + return; + } + + sensor_pollnotify(upper, POLLIN); + nxsem_get_value(&upper->buffersem, &semcount); + if (semcount < 1) + { + nxsem_post(&upper->buffersem); + } + + nxsem_post(&upper->exclsem); +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -723,11 +784,19 @@ int sensor_register(FAR struct sensor_lowerhalf_s *lower, int devno) /* Bind the lower half data structure member */ lower->priv = upper; - lower->push_event = sensor_push_event; - if (!lower->buffer_size) + if (!lower->ops->fetch) { - lower->buffer_size = g_sensor_info[lower->type].esize; + if (!lower->buffer_size) + { + lower->buffer_size = g_sensor_info[lower->type].esize; + } + + lower->push_event = sensor_push_event; + } + else + { + lower->notify_event = sensor_notify_event; } /* Initialize sensor buffer */ diff --git a/include/nuttx/sensors/sensor.h b/include/nuttx/sensors/sensor.h index f7c3aac08b..14bc9e0735 100644 --- a/include/nuttx/sensors/sensor.h +++ b/include/nuttx/sensors/sensor.h @@ -497,6 +497,38 @@ struct sensor_ops_s CODE int (*batch)(FAR struct sensor_lowerhalf_s *lower, FAR unsigned int *latency_us); + /************************************************************************** + * Name: fetch + * + * Fetch sensor register data by this function. It will use buffer of + * userspace provided and disables intermediate buffer of upper half. It's + * recommend that the lowerhalf driver writer to use this function for + * slower sensor ODR (output data rate) of sensor because this way saves + * space and it's simple. + * + * If fetch isn't NULL, upper half driver will disable intermediate + * buffer and userspace can't set buffer size by ioctl. + * + * You can call this function to read sensor register data by I2C/SPI bus + * when open mode is non-block, and poll are always successful. + * When you call this function and open mode is block, you will wait + * until sensor data ready, then read sensor data. + * + * Input Parameters: + * lower - The instance of lower half sensor driver. + * buffer - The buffer of receive sensor event, it's provided by + * file_operation::sensor_read. + * buflen - The size of buffer. + * + * Returned Value: + * The size of read buffer returned on success; a negated errno value + * on failure. + * + **************************************************************************/ + + CODE int (*fetch)(FAR struct sensor_lowerhalf_s *lower, + FAR char *buffer, size_t buflen); + /************************************************************************** * Name: control * @@ -552,21 +584,39 @@ struct sensor_lowerhalf_s 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 - **************************************************************************/ + union + { + /********************************************************************** + * 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); + CODE void (*push_event)(FAR void *priv, FAR const void *data, + size_t bytes); + + /********************************************************************** + * Name: notify_event + * + * Description: + * Lower half driver notify sensor data ready and can read by fetch. + * It is provided by upper half driver to lower half driver. + * + * This api is used when sensor_ops_s::fetch isn't NULL. + * + * Input Parameters: + * priv - Upper half driver handle + **********************************************************************/ + + CODE void (*notify_event)(FAR void *priv); + }; /* The private opaque pointer to be passed to upper-layer during callback */