driver/sensors: support sensor flush operation

Supports the flush operation of the sensor.

The application can initiate a flush action through ioctl SNIOC_FLUSH
to trigger flush, and the call will be returned immediately.
Using SNIOC_GET_EVENTS to clear flush event,

However, the flush implementation is asynchronous, when all the flush
data is push to upper circbuffer, the POLLPRI event(FLUSH_COMPLETED)
will be reported.

Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
This commit is contained in:
dongjiuzhu1 2024-04-29 23:41:47 +08:00 committed by Xiang Xiao
parent 703bb7e7b3
commit 403469336f
5 changed files with 163 additions and 12 deletions

View file

@ -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 */

View file

@ -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;

View file

@ -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 */

View file

@ -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
*

View file

@ -321,6 +321,10 @@
#define SENSOR_INFO_NAME_SIZE 32
/* Sensor event flags */
#define SENSOR_EVENT_FLUSH_COMPLETE 0x01
/****************************************************************************
* Public Types
****************************************************************************/