diff --git a/drivers/sensors/sensor.c b/drivers/sensors/sensor.c index cdb02dd55d..1ca83c7172 100644 --- a/drivers/sensors/sensor.c +++ b/drivers/sensors/sensor.c @@ -87,6 +87,8 @@ struct sensor_user_s bool changed; /* This is used to indicate event happens and need to * asynchronous notify other users */ + unsigned int event; /* The event of this sensor, eg: SENSOR_EVENT_FLUSH_COMPLETE. */ + bool flushing; /* The is used to indicate user is flushing */ sem_t buffersem; /* Wakeup user waiting for data in circular buffer */ size_t bufferpos; /* The index of user generation in buffer */ @@ -879,6 +881,51 @@ static int sensor_ioctl(FAR struct file *filep, int cmd, unsigned long arg) } break; + case SNIOC_GET_EVENTS: + { + nxrmutex_lock(&upper->lock); + *(FAR unsigned int *)(uintptr_t)arg = user->event; + user->event = 0; + nxrmutex_unlock(&upper->lock); + } + + case SNIOC_FLUSH: + { + nxrmutex_lock(&upper->lock); + + /* If the sensor is not activated, return -EINVAL. */ + + if (upper->state.nsubscribers == 0) + { + nxrmutex_unlock(&upper->lock); + return -EINVAL; + } + + if (lower->ops->flush != NULL) + { + /* Lower half driver will do flush in asynchronous mode, + * flush will be completed until push event happened with + * bytes is zero. + */ + + ret = lower->ops->flush(lower, filep); + if (ret >= 0) + { + user->flushing = true; + } + } + else + { + /* If flush is not supported, complete immediately */ + + user->event |= SENSOR_EVENT_FLUSH_COMPLETE; + sensor_pollnotify_one(user, POLLPRI); + } + + nxrmutex_unlock(&upper->lock); + } + break; + default: /* Lowerhalf driver process other cmd. */ @@ -972,13 +1019,31 @@ static ssize_t sensor_push_event(FAR void *priv, FAR const void *data, int semcount; int ret; - envcount = bytes / upper->state.esize; - if (!envcount || bytes != envcount * upper->state.esize) + nxrmutex_lock(&upper->lock); + if (bytes == 0) { + list_for_every_entry(&upper->userlist, user, struct sensor_user_s, + node) + { + if (user->flushing) + { + user->flushing = false; + user->event |= SENSOR_EVENT_FLUSH_COMPLETE; + sensor_pollnotify_one(user, POLLPRI); + } + } + + nxrmutex_unlock(&upper->lock); + return 0; + } + + envcount = bytes / upper->state.esize; + if (bytes != envcount * upper->state.esize) + { + nxrmutex_unlock(&upper->lock); return -EINVAL; } - nxrmutex_lock(&upper->lock); if (!circbuf_is_init(&upper->buffer)) { /* Initialize sensor buffer when data is first generated */ diff --git a/drivers/sensors/sensor_rpmsg.c b/drivers/sensors/sensor_rpmsg.c index 2dc4715a4d..47ead41b8e 100644 --- a/drivers/sensors/sensor_rpmsg.c +++ b/drivers/sensors/sensor_rpmsg.c @@ -116,6 +116,7 @@ struct sensor_rpmsg_stub_s FAR struct rpmsg_endpoint *ept; uint64_t cookie; struct file file; + bool flushing; }; /* This structure describes the proxy info about remote advertisers. */ @@ -206,6 +207,8 @@ static int sensor_rpmsg_set_interval(FAR struct sensor_lowerhalf_s *lower, static int sensor_rpmsg_batch(FAR struct sensor_lowerhalf_s *lower, FAR struct file *filep, FAR unsigned long *latency_us); +static int sensor_rpmsg_flush(FAR struct sensor_lowerhalf_s *lower, + FAR struct file *filep); static int sensor_rpmsg_selftest(FAR struct sensor_lowerhalf_s *lower, FAR struct file *filep, unsigned long arg); @@ -249,7 +252,8 @@ static int sensor_rpmsg_ioctlack_handler(FAR struct rpmsg_endpoint *ept, FAR void *data, size_t len, uint32_t src, FAR void *priv); static void sensor_rpmsg_push_event_one(FAR struct sensor_rpmsg_dev_s *dev, - FAR struct sensor_rpmsg_stub_s *stub); + FAR struct sensor_rpmsg_stub_s *stub, + bool flushed); /**************************************************************************** * Private Data @@ -262,6 +266,7 @@ static const struct sensor_ops_s g_sensor_rpmsg_ops = .activate = sensor_rpmsg_activate, .set_interval = sensor_rpmsg_set_interval, .batch = sensor_rpmsg_batch, + .flush = sensor_rpmsg_flush, .selftest = sensor_rpmsg_selftest, .set_calibvalue = sensor_rpmsg_set_calibvalue, .calibrate = sensor_rpmsg_calibrate, @@ -554,7 +559,7 @@ sensor_rpmsg_alloc_stub(FAR struct sensor_rpmsg_dev_s *dev, if (dev->lower.persist) { - sensor_rpmsg_push_event_one(dev, stub); + sensor_rpmsg_push_event_one(dev, stub, false); } sensor_rpmsg_unlock(dev); @@ -696,6 +701,25 @@ SENSOR_RPMSG_FUNCTION(set_calibvalue, SNIOC_SET_CALIBVALUE, arg, arg, 256, true) SENSOR_RPMSG_FUNCTION(calibrate, SNIOC_CALIBRATE, arg, arg, 256, true) +static int sensor_rpmsg_flush(FAR struct sensor_lowerhalf_s *lower, + FAR struct file *filep) +{ + FAR struct sensor_rpmsg_dev_s *dev = lower->priv; + FAR struct sensor_lowerhalf_s *drv = dev->drv; + int ret = -ENOTTY; + + if (drv->ops->flush) + { + ret = drv->ops->flush(drv, filep); + } + else if (!(filep->f_oflags & SENSOR_REMOTE)) + { + ret = sensor_rpmsg_ioctl(dev, SNIOC_FLUSH, 0, 0, true); + } + + return ret; +} + static int sensor_rpmsg_get_info(FAR struct sensor_lowerhalf_s *lower, FAR struct file *filep, FAR struct sensor_device_info_s *info) @@ -754,7 +778,8 @@ static void sensor_rpmsg_data_worker(FAR void *arg) } static void sensor_rpmsg_push_event_one(FAR struct sensor_rpmsg_dev_s *dev, - FAR struct sensor_rpmsg_stub_s *stub) + FAR struct sensor_rpmsg_stub_s *stub, + bool flushed) { FAR struct sensor_rpmsg_cell_s *cell; FAR struct sensor_rpmsg_ept_s *sre; @@ -790,7 +815,7 @@ static void sensor_rpmsg_push_event_one(FAR struct sensor_rpmsg_dev_s *dev, for (; ; ) { ret = file_ioctl(&stub->file, SNIOC_UPDATED, &updated); - if (ret < 0 || !updated) + if (ret < 0 || (!updated && !flushed)) { break; } @@ -823,11 +848,19 @@ static void sensor_rpmsg_push_event_one(FAR struct sensor_rpmsg_dev_s *dev, } cell = sre->buffer + sre->written; - ret = file_read(&stub->file, cell->data, - sre->space - sre->written - sizeof(*cell)); - if (ret <= 0) + if (flushed) { - break; + flushed = false; + stub->flushing = false; + } + else + { + ret = file_read(&stub->file, cell->data, + sre->space - sre->written - sizeof(*cell)); + if (ret <= 0) + { + break; + } } cell->len = ret; @@ -891,7 +924,8 @@ static ssize_t sensor_rpmsg_push_event(FAR void *priv, FAR const void *data, list_for_every_entry_safe(&dev->stublist, stub, stmp, struct sensor_rpmsg_stub_s, node) { - sensor_rpmsg_push_event_one(dev, stub); + sensor_rpmsg_push_event_one(dev, stub, + stub->flushing && bytes == 0); } sensor_rpmsg_unlock(dev); @@ -1145,6 +1179,11 @@ static int sensor_rpmsg_ioctl_handler(FAR struct rpmsg_endpoint *ept, if (stub->ept == ept) { msg->result = file_ioctl(&stub->file, msg->request, arg); + if (msg->result >= 0 && msg->request == SNIOC_FLUSH) + { + stub->flushing = true; + } + if (msg->cookie) { msg->command = SENSOR_RPMSG_IOCTL_ACK; diff --git a/include/nuttx/sensors/ioctl.h b/include/nuttx/sensors/ioctl.h index 0dc98b5358..e9fd00170e 100644 --- a/include/nuttx/sensors/ioctl.h +++ b/include/nuttx/sensors/ioctl.h @@ -451,4 +451,17 @@ # define SNIOC_SET_INFO _SNIOC(0x009C) #endif +/* Command: SNIOC_FLUSH + * Description: Flush sensor harware fifo buffer. + */ + +#define SNIOC_FLUSH _SNIOC(0x009D) + +/* Command: SNIOC_GET_EVENTS + * Description: Get events of the sensor device. + * Argument: The events pointer, (unsigned int *) + */ + +#define SNIOC_GET_EVENTS _SNIOC(0x009E) + #endif /* __INCLUDE_NUTTX_SENSORS_IOCTL_H */ diff --git a/include/nuttx/sensors/sensor.h b/include/nuttx/sensors/sensor.h index 1075cd29eb..c64d09de13 100644 --- a/include/nuttx/sensors/sensor.h +++ b/include/nuttx/sensors/sensor.h @@ -352,6 +352,36 @@ struct sensor_ops_s FAR struct file *filep, FAR char *buffer, size_t buflen); + /************************************************************************** + * Name: flush + * + * When sensor data accumulates in the hardware buffer but does not + * reach the watermark, the upper-layer application can immediately push + * the fifo data to the upper layer circbuffer through the flush operation. + * + * The flush operation is an asynchronous operation. The lower half driver + * must call push event with data is NULL and len is zero when the flush + * action is completed, then upper half driver triggers the POLLPRI event, + * and update user state event to tell application the flush complete + * event. + * + * You can call the flush operation at any time. When the sensor is not + * activated, flsuh returns -EINVAL. When the sensor does not support fifo, + * it immediately returns the POLLPRI event, indicating that the flush + * is completed. + * + * Input Parameters: + * lower - The instance of lower half sensor driver. + * filep - The pointer of file, represents each user using sensor. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + **************************************************************************/ + + CODE int (*flush)(FAR struct sensor_lowerhalf_s *lower, + FAR struct file *filep); + /************************************************************************** * Name: selftest * diff --git a/include/nuttx/uorb.h b/include/nuttx/uorb.h index 71ed839731..e1764c0138 100644 --- a/include/nuttx/uorb.h +++ b/include/nuttx/uorb.h @@ -321,6 +321,10 @@ #define SENSOR_INFO_NAME_SIZE 32 +/* Sensor event flags */ + +#define SENSOR_EVENT_FLUSH_COMPLETE 0x01 + /**************************************************************************** * Public Types ****************************************************************************/