sensor: add SNIOC_READLAST

If enable SNIOC_READLAST, sensor_read will return 0
when there is no new data until last read.

Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
This commit is contained in:
Jiuzhu Dong 2022-04-26 14:01:11 +08:00 committed by Xiang Xiao
parent 2f5727b102
commit 6f3873dfa2
2 changed files with 56 additions and 30 deletions

View File

@ -95,6 +95,7 @@ struct sensor_upperhalf_s
struct circbuf_s buffer; /* The circular buffer of sensor device */ struct circbuf_s buffer; /* The circular buffer of sensor device */
sem_t exclsem; /* Manages exclusive access to file operations */ sem_t exclsem; /* Manages exclusive access to file operations */
struct list_node userlist; /* List of users */ struct list_node userlist; /* List of users */
bool readlast; /* The flag of readlast */
}; };
/**************************************************************************** /****************************************************************************
@ -525,13 +526,35 @@ static ssize_t sensor_read(FAR struct file *filep, FAR char *buffer,
} }
else else
{ {
/* We must make sure that when the semaphore is equal to 1, there must /* If readlast is true, you can always read the last data
* be events available in the buffer, so we use a while statement to * in the circbuffer as initial value for new users when the
* synchronize this case that other read operations consume events * sensor device has not yet generated new data, otherwise,
* that have just entered the buffer. * it will return 0 when there isn't new data.
*/ */
while (circbuf_is_empty(&upper->buffer)) if (upper->readlast)
{
if (circbuf_is_empty(&upper->buffer))
{
ret = -ENODATA;
goto out;
}
if (user->generation == upper->state.generation)
{
user->generation--;
}
}
else
{
/* We must make sure that when the semaphore is equal to 1,
* there must be events available 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 (circbuf_is_empty(&upper->buffer) ||
user->generation == upper->state.generation)
{ {
if (filep->f_oflags & O_NONBLOCK) if (filep->f_oflags & O_NONBLOCK)
{ {
@ -540,36 +563,23 @@ static ssize_t sensor_read(FAR struct file *filep, FAR char *buffer,
} }
else else
{ {
nxsem_post(&upper->exclsem); nxmutex_unlock(&upper->lock);
ret = nxsem_wait_uninterruptible(&user->buffersem); ret = nxsem_wait_uninterruptible(&user->buffersem);
if (ret < 0) if (ret < 0)
{ {
return ret; return ret;
} }
ret = nxsem_wait(&upper->exclsem); nxmutex_lock(&upper->lock);
if (ret < 0)
{
return ret;
} }
} }
} }
/* Always read the last data in the circbuffer as initial value
* for new users when the sensor device has not yet generated
* new data.
*/
if (user->generation == upper->state.generation)
{
user->generation--;
}
/* If user's generation isn't within circbuffer range, the /* If user's generation isn't within circbuffer range, the
* oldest data in circbuffer are returned to the users. * oldest data in circbuffer are returned to the users.
*/ */
else if (!sensor_in_range(upper->state.generation - lower->nbuffer, if (!sensor_in_range(upper->state.generation - lower->nbuffer,
user->generation, upper->state.generation)) user->generation, upper->state.generation))
{ {
@ -704,6 +714,12 @@ static int sensor_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
} }
break; break;
case SNIOC_READLAST:
{
upper->readlast = !!arg;
}
break;
default: default:
/* Lowerhalf driver process other cmd. */ /* Lowerhalf driver process other cmd. */
@ -969,6 +985,7 @@ int sensor_custom_register(FAR struct sensor_lowerhalf_s *lower,
/* Initialize the upper-half data structure */ /* Initialize the upper-half data structure */
list_initialize(&upper->userlist); list_initialize(&upper->userlist);
upper->readlast = true;
upper->state.esize = esize; upper->state.esize = esize;
upper->state.min_interval = ULONG_MAX; upper->state.min_interval = ULONG_MAX;
upper->state.min_latency = ULONG_MAX; upper->state.min_latency = ULONG_MAX;

View File

@ -326,4 +326,13 @@
#define SNIOC_UNREGISTER _SNIOC(0x0090) #define SNIOC_UNREGISTER _SNIOC(0x0090)
#endif #endif
/* Command: SNIOC_READLAST
* Description: If enable readlast, there is no data update in time,
* the latest data can always be returned.
* Disable readlast, if there is no data update, return 0.
* Argument: True or false
*/
#define SNIOC_READLAST _SNIOC(0x0091)
#endif /* __INCLUDE_NUTTX_SENSORS_IOCTL_H */ #endif /* __INCLUDE_NUTTX_SENSORS_IOCTL_H */