2020-10-19 21:24:13 +08:00
|
|
|
/****************************************************************************
|
|
|
|
|
* drivers/sensors/sensor.c
|
|
|
|
|
*
|
2024-11-05 13:02:24 +01:00
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
*
|
2020-10-19 21:24:13 +08:00
|
|
|
* 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>
|
2021-05-18 14:59:14 +08:00
|
|
|
#include <assert.h>
|
2020-10-19 21:24:13 +08:00
|
|
|
#include <errno.h>
|
2026-04-01 05:11:15 +05:30
|
|
|
#include <nuttx/debug.h>
|
2025-04-24 16:11:19 +08:00
|
|
|
#include <libgen.h>
|
2020-10-19 21:24:13 +08:00
|
|
|
|
|
|
|
|
#include <poll.h>
|
|
|
|
|
#include <fcntl.h>
|
2022-03-22 15:46:02 +08:00
|
|
|
#include <nuttx/list.h>
|
2020-10-19 21:24:13 +08:00
|
|
|
#include <nuttx/kmalloc.h>
|
2024-03-04 18:14:35 +08:00
|
|
|
#include <nuttx/circbuf.h>
|
2022-06-14 11:33:13 +08:00
|
|
|
#include <nuttx/mutex.h>
|
2020-10-19 21:24:13 +08:00
|
|
|
#include <nuttx/sensors/sensor.h>
|
2024-10-09 12:14:18 +08:00
|
|
|
#include <nuttx/lib/lib.h>
|
drivers/sensors/sensor: pace POLLIN at the requested interval
A fetch() only lower half is always ready, so a subscriber that asked for
a rate with SNIOC_SET_INTERVAL got no pacing from poll(): the descriptor
reported POLLIN on every pass and the application had to sleep out the
period itself. That does not compose. An application polling several
topics reads them sequentially from one thread, so per read sleeps
serialize: three topics at 10 Hz sleeping 100 ms each yield 3.3 Hz per
topic rather than 10.
Pace it where poll() can act on it instead. A subscriber that never
requested a rate stays always ready, and one that did becomes ready once
per its own interval, driven by a watchdog armed in sensor_poll(). This
is the fetch() side of what sensor_is_updated() already does for a
pushing lower half, so both models now honor a requested rate the same
way.
The wdog_s lives in sensor_user_s rather than in the device, so each
subscriber is paced at its own interval instead of at the minimum across
all of them, and the timer only runs while somebody is polling. The
expiry runs in timer context and takes no lock: poll_notify() is safe
from an interrupt handler, and a teardown that raced it has already
cleared fds, which makes both the notify and the re-arm no-ops. Teardown
therefore just cancels the watchdog where it clears fds, and a watchdog
keeps this off the work queue entirely, which a fetch() only sensor
exists to avoid.
sensor_close() needs nothing of its own: poll_setup() holds a reference
on the file for the duration of the poll, so file_close() cannot run
until poll_teardown() has called sensor_poll() with setup false, and that
already cancelled the watchdog.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Felipe Moura <moura.fmo@gmail.com>
2026-08-01 13:00:29 -03:00
|
|
|
#include <nuttx/wdog.h>
|
2020-10-19 21:24:13 +08:00
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
|
* Pre-processor Definitions
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
/* Device naming ************************************************************/
|
|
|
|
|
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
#define ROUND_DOWN(x, y) (((x) / (y)) * (y))
|
2025-01-20 15:04:15 +08:00
|
|
|
#define DEVNAME_FMT "/dev/uorb/sensor_%s%d"
|
2024-06-28 23:35:55 +08:00
|
|
|
#define TIMING_BUF_ESIZE (sizeof(uint32_t))
|
2020-10-19 21:24:13 +08:00
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
|
* Private Types
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
drivers/sensors/: Add coordinate conversion function
convert from body coordinate system to right-hand
coordinate system.
Example:
Compared to the standard coordinate system,
the x-axis and y-axis are interchanged and have opposite directions,
the z-axis remains normal.
body coordinate ----> right-hand coordinate
+x +y
| |
| |
| |
| |
-y<-------. .------>+x
/ /
/ /
/ /
/ /
+z +z
So for the above conversion, using "P3" to represent transformation relationships
The front is 1 0 2, which represents the y x z axis.
The standard order is 0 1 2, so y and x are interchanged.
The following -1 1 1 indicates the direction of the axis.
The standard is 1 1 1. Because the current y-axis is opposite to
the standard x-axis, it is -1.
static const struct sensor_axis_map_s g_remap_tbl[] =
{
{ 0, 1, 2, 1, 1, 1 }, /* P0 */
{ 1, 0, 2, 1, -1, 1 }, /* P1 */
{ 0, 1, 2, -1, -1, 1 }, /* P2 */
{ 1, 0, 2, -1, 1, 1 }, /* P3 */
{ 0, 1, 2, -1, 1, -1 }, /* P4 */
{ 1, 0, 2, -1, -1, -1 }, /* P5 */
{ 0, 1, 2, 1, -1, -1 }, /* P6 */
{ 1, 0, 2, 1, 1, -1 }, /* P7 */
};
you can call the function sensor_remap_vector_raw16 and pass P3 parameters
to perform the conversion.
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2021-12-31 11:15:28 +08:00
|
|
|
struct sensor_axis_map_s
|
|
|
|
|
{
|
|
|
|
|
int8_t src_x;
|
|
|
|
|
int8_t src_y;
|
|
|
|
|
int8_t src_z;
|
|
|
|
|
|
|
|
|
|
int8_t sign_x;
|
|
|
|
|
int8_t sign_y;
|
|
|
|
|
int8_t sign_z;
|
|
|
|
|
};
|
|
|
|
|
|
2024-03-11 18:31:30 +08:00
|
|
|
/* This structure describes sensor meta */
|
2020-10-19 21:24:13 +08:00
|
|
|
|
2024-03-11 18:31:30 +08:00
|
|
|
struct sensor_meta_s
|
2020-10-19 21:24:13 +08:00
|
|
|
{
|
2024-06-28 23:35:55 +08:00
|
|
|
size_t esize;
|
2020-11-02 18:02:04 +08:00
|
|
|
FAR char *name;
|
2020-10-19 21:24:13 +08:00
|
|
|
};
|
|
|
|
|
|
2024-05-09 21:37:21 +08:00
|
|
|
typedef enum sensor_role_e
|
|
|
|
|
{
|
|
|
|
|
SENSOR_ROLE_NONE,
|
|
|
|
|
SENSOR_ROLE_WR,
|
|
|
|
|
SENSOR_ROLE_RD,
|
|
|
|
|
SENSOR_ROLE_RDWR,
|
|
|
|
|
} sensor_role_t;
|
|
|
|
|
|
2022-03-22 15:46:02 +08:00
|
|
|
/* This structure describes user info of sensor, the user may be
|
|
|
|
|
* advertiser or subscriber
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
struct sensor_user_s
|
|
|
|
|
{
|
|
|
|
|
/* The common info */
|
|
|
|
|
|
|
|
|
|
struct list_node node; /* Node of users list */
|
|
|
|
|
struct pollfd *fds; /* The poll structure of thread waiting events */
|
2024-05-09 21:37:21 +08:00
|
|
|
sensor_role_t role; /* The is used to indicate user's role based on open flags */
|
drivers/sensors/sensor: pace POLLIN at the requested interval
A fetch() only lower half is always ready, so a subscriber that asked for
a rate with SNIOC_SET_INTERVAL got no pacing from poll(): the descriptor
reported POLLIN on every pass and the application had to sleep out the
period itself. That does not compose. An application polling several
topics reads them sequentially from one thread, so per read sleeps
serialize: three topics at 10 Hz sleeping 100 ms each yield 3.3 Hz per
topic rather than 10.
Pace it where poll() can act on it instead. A subscriber that never
requested a rate stays always ready, and one that did becomes ready once
per its own interval, driven by a watchdog armed in sensor_poll(). This
is the fetch() side of what sensor_is_updated() already does for a
pushing lower half, so both models now honor a requested rate the same
way.
The wdog_s lives in sensor_user_s rather than in the device, so each
subscriber is paced at its own interval instead of at the minimum across
all of them, and the timer only runs while somebody is polling. The
expiry runs in timer context and takes no lock: poll_notify() is safe
from an interrupt handler, and a teardown that raced it has already
cleared fds, which makes both the notify and the re-arm no-ops. Teardown
therefore just cancels the watchdog where it clears fds, and a watchdog
keeps this off the work queue entirely, which a fetch() only sensor
exists to avoid.
sensor_close() needs nothing of its own: poll_setup() holds a reference
on the file for the duration of the poll, so file_close() cannot run
until poll_teardown() has called sensor_poll() with setup false, and that
already cancelled the watchdog.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Felipe Moura <moura.fmo@gmail.com>
2026-08-01 13:00:29 -03:00
|
|
|
struct wdog_s wdog; /* Paces POLLIN at the requested interval */
|
|
|
|
|
uint64_t fetched; /* When POLLIN was last reported, in usec */
|
2022-03-22 15:46:02 +08:00
|
|
|
bool changed; /* This is used to indicate event happens and need to
|
|
|
|
|
* asynchronous notify other users
|
|
|
|
|
*/
|
2024-04-29 23:41:47 +08:00
|
|
|
unsigned int event; /* The event of this sensor, eg: SENSOR_EVENT_FLUSH_COMPLETE. */
|
|
|
|
|
bool flushing; /* The is used to indicate user is flushing */
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
size_t bufferpos; /* The index of user generation in buffer */
|
2022-03-22 15:46:02 +08:00
|
|
|
|
|
|
|
|
/* The subscriber info
|
|
|
|
|
* Support multi advertisers to subscribe their own data when they
|
|
|
|
|
* appear in dual role
|
|
|
|
|
*/
|
|
|
|
|
|
2022-06-29 17:34:55 +08:00
|
|
|
struct sensor_ustate_s state;
|
2022-03-22 15:46:02 +08:00
|
|
|
};
|
|
|
|
|
|
2020-10-19 21:24:13 +08:00
|
|
|
/* This structure describes the state of the upper half driver */
|
|
|
|
|
|
|
|
|
|
struct sensor_upperhalf_s
|
|
|
|
|
{
|
2022-03-22 15:46:02 +08:00
|
|
|
FAR struct sensor_lowerhalf_s *lower; /* The handle of lower half driver */
|
|
|
|
|
struct sensor_state_s state; /* The state of sensor device */
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
struct circbuf_s timing; /* The circular buffer of generation */
|
|
|
|
|
struct circbuf_s buffer; /* The circular buffer of data */
|
2022-06-14 11:33:13 +08:00
|
|
|
rmutex_t lock; /* Manages exclusive access to file operations */
|
2022-03-22 15:46:02 +08:00
|
|
|
struct list_node userlist; /* List of users */
|
2025-04-24 16:11:19 +08:00
|
|
|
char name[NAME_MAX]; /* Upper topic name */
|
2020-10-19 21:24:13 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
|
* Private Function Prototypes
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void sensor_pollnotify(FAR struct sensor_upperhalf_s *upper,
|
2024-05-09 21:37:21 +08:00
|
|
|
pollevent_t eventset, sensor_role_t role);
|
2020-10-19 21:24:13 +08:00
|
|
|
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);
|
2022-03-11 17:05:47 +08:00
|
|
|
static ssize_t sensor_write(FAR struct file *filep, FAR const char *buffer,
|
|
|
|
|
size_t buflen);
|
2020-10-19 21:24:13 +08:00
|
|
|
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);
|
2022-03-11 17:05:47 +08:00
|
|
|
static ssize_t sensor_push_event(FAR void *priv, FAR const void *data,
|
|
|
|
|
size_t bytes);
|
drivers/sensors/sensor: pace POLLIN at the requested interval
A fetch() only lower half is always ready, so a subscriber that asked for
a rate with SNIOC_SET_INTERVAL got no pacing from poll(): the descriptor
reported POLLIN on every pass and the application had to sleep out the
period itself. That does not compose. An application polling several
topics reads them sequentially from one thread, so per read sleeps
serialize: three topics at 10 Hz sleeping 100 ms each yield 3.3 Hz per
topic rather than 10.
Pace it where poll() can act on it instead. A subscriber that never
requested a rate stays always ready, and one that did becomes ready once
per its own interval, driven by a watchdog armed in sensor_poll(). This
is the fetch() side of what sensor_is_updated() already does for a
pushing lower half, so both models now honor a requested rate the same
way.
The wdog_s lives in sensor_user_s rather than in the device, so each
subscriber is paced at its own interval instead of at the minimum across
all of them, and the timer only runs while somebody is polling. The
expiry runs in timer context and takes no lock: poll_notify() is safe
from an interrupt handler, and a teardown that raced it has already
cleared fds, which makes both the notify and the re-arm no-ops. Teardown
therefore just cancels the watchdog where it clears fds, and a watchdog
keeps this off the work queue entirely, which a fetch() only sensor
exists to avoid.
sensor_close() needs nothing of its own: poll_setup() holds a reference
on the file for the duration of the poll, so file_close() cannot run
until poll_teardown() has called sensor_poll() with setup false, and that
already cancelled the watchdog.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Felipe Moura <moura.fmo@gmail.com>
2026-08-01 13:00:29 -03:00
|
|
|
static void sensor_fetch_expired(wdparm_t arg);
|
2020-10-19 21:24:13 +08:00
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
|
* Private Data
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
drivers/sensors/: Add coordinate conversion function
convert from body coordinate system to right-hand
coordinate system.
Example:
Compared to the standard coordinate system,
the x-axis and y-axis are interchanged and have opposite directions,
the z-axis remains normal.
body coordinate ----> right-hand coordinate
+x +y
| |
| |
| |
| |
-y<-------. .------>+x
/ /
/ /
/ /
/ /
+z +z
So for the above conversion, using "P3" to represent transformation relationships
The front is 1 0 2, which represents the y x z axis.
The standard order is 0 1 2, so y and x are interchanged.
The following -1 1 1 indicates the direction of the axis.
The standard is 1 1 1. Because the current y-axis is opposite to
the standard x-axis, it is -1.
static const struct sensor_axis_map_s g_remap_tbl[] =
{
{ 0, 1, 2, 1, 1, 1 }, /* P0 */
{ 1, 0, 2, 1, -1, 1 }, /* P1 */
{ 0, 1, 2, -1, -1, 1 }, /* P2 */
{ 1, 0, 2, -1, 1, 1 }, /* P3 */
{ 0, 1, 2, -1, 1, -1 }, /* P4 */
{ 1, 0, 2, -1, -1, -1 }, /* P5 */
{ 0, 1, 2, 1, -1, -1 }, /* P6 */
{ 1, 0, 2, 1, 1, -1 }, /* P7 */
};
you can call the function sensor_remap_vector_raw16 and pass P3 parameters
to perform the conversion.
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2021-12-31 11:15:28 +08:00
|
|
|
static const struct sensor_axis_map_s g_remap_tbl[] =
|
|
|
|
|
{
|
|
|
|
|
{ 0, 1, 2, 1, 1, 1 }, /* P0 */
|
|
|
|
|
{ 1, 0, 2, 1, -1, 1 }, /* P1 */
|
|
|
|
|
{ 0, 1, 2, -1, -1, 1 }, /* P2 */
|
|
|
|
|
{ 1, 0, 2, -1, 1, 1 }, /* P3 */
|
|
|
|
|
{ 0, 1, 2, -1, 1, -1 }, /* P4 */
|
|
|
|
|
{ 1, 0, 2, -1, -1, -1 }, /* P5 */
|
|
|
|
|
{ 0, 1, 2, 1, -1, -1 }, /* P6 */
|
|
|
|
|
{ 1, 0, 2, 1, 1, -1 }, /* P7 */
|
|
|
|
|
};
|
|
|
|
|
|
2024-03-11 18:31:30 +08:00
|
|
|
static const struct sensor_meta_s g_sensor_meta[] =
|
2020-10-19 21:24:13 +08:00
|
|
|
{
|
2024-06-20 23:44:12 +08:00
|
|
|
{0, NULL},
|
|
|
|
|
{sizeof(struct sensor_accel), "accel"},
|
|
|
|
|
{sizeof(struct sensor_mag), "mag"},
|
2024-08-05 20:56:32 +08:00
|
|
|
{sizeof(struct sensor_orientation), "orientation"},
|
2024-06-20 23:44:12 +08:00
|
|
|
{sizeof(struct sensor_gyro), "gyro"},
|
|
|
|
|
{sizeof(struct sensor_light), "light"},
|
|
|
|
|
{sizeof(struct sensor_baro), "baro"},
|
2025-01-20 15:04:15 +08:00
|
|
|
{sizeof(struct sensor_temp), "temp"},
|
2024-06-20 23:44:12 +08:00
|
|
|
{sizeof(struct sensor_prox), "prox"},
|
|
|
|
|
{sizeof(struct sensor_rgb), "rgb"},
|
2024-08-05 20:56:32 +08:00
|
|
|
{sizeof(struct sensor_accel), "linear_accel"},
|
|
|
|
|
{sizeof(struct sensor_rotation), "rotation"},
|
2024-07-09 21:27:56 +08:00
|
|
|
{sizeof(struct sensor_humi), "humi"},
|
2025-01-20 15:04:15 +08:00
|
|
|
{sizeof(struct sensor_temp), "ambient_temp"},
|
2025-02-12 16:09:35 +08:00
|
|
|
{sizeof(struct sensor_mag_uncal), "mag_uncal"},
|
2024-06-20 23:44:12 +08:00
|
|
|
{sizeof(struct sensor_pm1p0), "pm1p0"},
|
2025-02-12 16:09:35 +08:00
|
|
|
{sizeof(struct sensor_gyro_uncal), "gyro_uncal"},
|
2024-08-05 20:56:32 +08:00
|
|
|
{sizeof(struct sensor_event), "motion_detect"},
|
|
|
|
|
{sizeof(struct sensor_event), "step_detector"},
|
|
|
|
|
{sizeof(struct sensor_step_counter), "step_counter"},
|
2024-06-20 23:44:12 +08:00
|
|
|
{sizeof(struct sensor_ph), "ph"},
|
|
|
|
|
{sizeof(struct sensor_hrate), "hrate"},
|
2024-08-05 20:56:32 +08:00
|
|
|
{sizeof(struct sensor_event), "tilt_detector"},
|
|
|
|
|
{sizeof(struct sensor_event), "wake_gesture"},
|
|
|
|
|
{sizeof(struct sensor_event), "glance_gesture"},
|
|
|
|
|
{sizeof(struct sensor_event), "pickup_gesture"},
|
|
|
|
|
{sizeof(struct sensor_event), "wrist_tilt"},
|
|
|
|
|
{sizeof(struct sensor_orientation), "device_orientation"},
|
|
|
|
|
{sizeof(struct sensor_pose_6dof), "pose_6dof"},
|
|
|
|
|
{sizeof(struct sensor_gas), "gas"},
|
|
|
|
|
{sizeof(struct sensor_event), "significant_motion"},
|
|
|
|
|
{sizeof(struct sensor_hbeat), "hbeat"},
|
|
|
|
|
{sizeof(struct sensor_force), "force"},
|
|
|
|
|
{sizeof(struct sensor_hall), "hall"},
|
|
|
|
|
{sizeof(struct sensor_event), "offbody_detector"},
|
2025-02-12 16:09:35 +08:00
|
|
|
{sizeof(struct sensor_accel_uncal), "accel_uncal"},
|
2024-08-05 20:56:32 +08:00
|
|
|
{sizeof(struct sensor_angle), "hinge_angle"},
|
|
|
|
|
{sizeof(struct sensor_ir), "ir"},
|
|
|
|
|
{sizeof(struct sensor_hcho), "hcho"},
|
|
|
|
|
{sizeof(struct sensor_tvoc), "tvoc"},
|
2024-07-09 21:27:56 +08:00
|
|
|
{sizeof(struct sensor_dust), "dust"},
|
2024-06-20 23:44:12 +08:00
|
|
|
{sizeof(struct sensor_ecg), "ecg"},
|
|
|
|
|
{sizeof(struct sensor_ppgd), "ppgd"},
|
|
|
|
|
{sizeof(struct sensor_ppgq), "ppgq"},
|
|
|
|
|
{sizeof(struct sensor_impd), "impd"},
|
|
|
|
|
{sizeof(struct sensor_ots), "ots"},
|
2024-08-05 20:56:32 +08:00
|
|
|
{sizeof(struct sensor_co2), "co2"},
|
2024-07-09 21:27:56 +08:00
|
|
|
{sizeof(struct sensor_cap), "cap"},
|
2024-06-20 23:44:12 +08:00
|
|
|
{sizeof(struct sensor_gnss), "gnss"},
|
|
|
|
|
{sizeof(struct sensor_gnss_satellite), "gnss_satellite"},
|
|
|
|
|
{sizeof(struct sensor_gnss_measurement), "gnss_measurement"},
|
|
|
|
|
{sizeof(struct sensor_gnss_clock), "gnss_clock"},
|
2024-07-22 16:24:56 +08:00
|
|
|
{sizeof(struct sensor_gnss_geofence_event), "gnss_geofence_event"},
|
2024-12-19 13:11:52 -03:00
|
|
|
{sizeof(struct sensor_velocity), "velocity"},
|
2025-01-20 15:04:15 +08:00
|
|
|
{sizeof(struct sensor_noise), "noise"},
|
|
|
|
|
{sizeof(struct sensor_pm25), "pm25"},
|
|
|
|
|
{sizeof(struct sensor_pm10), "pm10"},
|
|
|
|
|
{sizeof(struct sensor_uv), "uv"},
|
2024-11-04 17:24:44 +08:00
|
|
|
{sizeof(struct sensor_eng), "eng"},
|
2026-09-09 20:12:19 +08:00
|
|
|
{sizeof(struct sensor_voltage), "voltage"},
|
|
|
|
|
{sizeof(struct sensor_current), "current"},
|
|
|
|
|
{sizeof(struct sensor_power), "power"},
|
2026-09-09 20:15:48 +08:00
|
|
|
{sizeof(struct sensor_resistance), "resistance"},
|
|
|
|
|
{sizeof(struct sensor_conductivity), "conductivity"},
|
|
|
|
|
{sizeof(struct sensor_energy), "energy"},
|
|
|
|
|
{sizeof(struct sensor_charge), "charge"},
|
2020-10-19 21:24:13 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct file_operations g_sensor_fops =
|
|
|
|
|
{
|
|
|
|
|
sensor_open, /* open */
|
|
|
|
|
sensor_close, /* close */
|
|
|
|
|
sensor_read, /* read */
|
2022-03-11 17:05:47 +08:00
|
|
|
sensor_write, /* write */
|
2020-10-19 21:24:13 +08:00
|
|
|
NULL, /* seek */
|
|
|
|
|
sensor_ioctl, /* ioctl */
|
2023-01-02 17:02:51 +04:00
|
|
|
NULL, /* mmap */
|
2023-01-03 01:06:12 +08:00
|
|
|
NULL, /* truncate */
|
2020-10-19 21:24:13 +08:00
|
|
|
sensor_poll /* poll */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
|
* Private Functions
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
2022-06-23 12:13:56 +08:00
|
|
|
static void sensor_lock(FAR void *priv)
|
|
|
|
|
{
|
|
|
|
|
FAR struct sensor_upperhalf_s *upper = priv;
|
2026-09-11 19:25:56 +08:00
|
|
|
|
2022-06-23 12:13:56 +08:00
|
|
|
nxrmutex_lock(&upper->lock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void sensor_unlock(FAR void *priv)
|
|
|
|
|
{
|
|
|
|
|
FAR struct sensor_upperhalf_s *upper = priv;
|
2026-09-11 19:25:56 +08:00
|
|
|
|
2022-06-23 12:13:56 +08:00
|
|
|
nxrmutex_unlock(&upper->lock);
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-13 14:00:08 +08:00
|
|
|
static int sensor_update_interval(FAR struct file *filep,
|
|
|
|
|
FAR struct sensor_upperhalf_s *upper,
|
2022-03-22 15:46:02 +08:00
|
|
|
FAR struct sensor_user_s *user,
|
2024-06-28 23:35:55 +08:00
|
|
|
uint32_t interval)
|
2022-03-22 15:46:02 +08:00
|
|
|
{
|
|
|
|
|
FAR struct sensor_lowerhalf_s *lower = upper->lower;
|
|
|
|
|
FAR struct sensor_user_s *tmp;
|
2024-06-28 23:35:55 +08:00
|
|
|
uint32_t min_interval = interval;
|
|
|
|
|
uint32_t min_latency = interval != UINT32_MAX ?
|
|
|
|
|
user->state.latency : UINT32_MAX;
|
2024-12-02 11:14:15 +08:00
|
|
|
uint32_t orig_min_interval;
|
|
|
|
|
uint32_t orig_min_latency;
|
2022-03-22 15:46:02 +08:00
|
|
|
int ret = 0;
|
|
|
|
|
|
2022-06-29 17:34:55 +08:00
|
|
|
if (interval == user->state.interval)
|
2022-03-22 15:46:02 +08:00
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-02 11:14:15 +08:00
|
|
|
nxrmutex_lock(&upper->lock);
|
|
|
|
|
again:
|
2022-03-22 15:46:02 +08:00
|
|
|
list_for_every_entry(&upper->userlist, tmp, struct sensor_user_s, node)
|
2020-10-19 21:24:13 +08:00
|
|
|
{
|
2024-06-28 23:35:55 +08:00
|
|
|
if (tmp == user || tmp->state.interval == UINT32_MAX)
|
2020-10-19 21:24:13 +08:00
|
|
|
{
|
2022-03-22 15:46:02 +08:00
|
|
|
continue;
|
|
|
|
|
}
|
2020-10-19 21:24:13 +08:00
|
|
|
|
2022-06-29 17:34:55 +08:00
|
|
|
if (min_interval > tmp->state.interval)
|
2022-03-22 15:46:02 +08:00
|
|
|
{
|
2022-06-29 17:34:55 +08:00
|
|
|
min_interval = tmp->state.interval;
|
2022-03-22 15:46:02 +08:00
|
|
|
}
|
2020-11-04 21:31:30 +08:00
|
|
|
|
2022-06-29 17:34:55 +08:00
|
|
|
if (min_latency > tmp->state.latency)
|
2022-06-15 12:17:51 +08:00
|
|
|
{
|
2022-06-29 17:34:55 +08:00
|
|
|
min_latency = tmp->state.latency;
|
2022-06-15 12:17:51 +08:00
|
|
|
}
|
2022-03-22 15:46:02 +08:00
|
|
|
}
|
|
|
|
|
|
2022-06-15 12:17:51 +08:00
|
|
|
if (lower->ops->set_interval)
|
2022-03-22 15:46:02 +08:00
|
|
|
{
|
2024-06-28 23:35:55 +08:00
|
|
|
if (min_interval != UINT32_MAX &&
|
2022-06-15 12:17:51 +08:00
|
|
|
min_interval != upper->state.min_interval)
|
2022-03-22 15:46:02 +08:00
|
|
|
{
|
2024-06-28 23:35:55 +08:00
|
|
|
uint32_t expected_interval = min_interval;
|
2026-09-11 19:25:56 +08:00
|
|
|
|
2024-12-02 11:14:15 +08:00
|
|
|
orig_min_interval = upper->state.min_interval;
|
|
|
|
|
nxrmutex_unlock(&upper->lock);
|
2022-06-15 12:17:51 +08:00
|
|
|
ret = lower->ops->set_interval(lower, filep, &min_interval);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
{
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
2022-06-25 17:12:39 +08:00
|
|
|
else if (min_interval > expected_interval)
|
|
|
|
|
{
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
2024-12-02 11:14:15 +08:00
|
|
|
|
|
|
|
|
nxrmutex_lock(&upper->lock);
|
2025-04-24 16:11:19 +08:00
|
|
|
sminfo(upper->name, "update interval %" PRIu32, min_interval);
|
2024-12-02 11:14:15 +08:00
|
|
|
|
|
|
|
|
/* The upper min_interval is updated by other threads, set to
|
|
|
|
|
* driver again to avoid race condition.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (orig_min_interval != upper->state.min_interval)
|
|
|
|
|
{
|
|
|
|
|
goto again;
|
|
|
|
|
}
|
2022-06-15 12:17:51 +08:00
|
|
|
}
|
|
|
|
|
|
2024-06-28 23:35:55 +08:00
|
|
|
if (min_latency == UINT32_MAX)
|
2022-06-15 12:17:51 +08:00
|
|
|
{
|
|
|
|
|
min_latency = 0;
|
2020-10-19 21:24:13 +08:00
|
|
|
}
|
2022-06-16 14:26:42 +08:00
|
|
|
|
2022-06-15 12:17:51 +08:00
|
|
|
if (lower->ops->batch &&
|
|
|
|
|
(min_latency != upper->state.min_latency ||
|
|
|
|
|
(min_interval != upper->state.min_interval && min_latency)))
|
2022-06-16 14:26:42 +08:00
|
|
|
{
|
2024-12-02 11:14:15 +08:00
|
|
|
orig_min_latency = upper->state.min_latency;
|
|
|
|
|
nxrmutex_unlock(&upper->lock);
|
2022-06-15 12:17:51 +08:00
|
|
|
ret = lower->ops->batch(lower, filep, &min_latency);
|
2024-12-02 11:14:15 +08:00
|
|
|
nxrmutex_lock(&upper->lock);
|
|
|
|
|
|
|
|
|
|
/* The upper min_latency is updated by other threads, set to
|
|
|
|
|
* driver again to avoid race condition.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (orig_min_latency != upper->state.min_latency)
|
|
|
|
|
{
|
|
|
|
|
goto again;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-15 12:17:51 +08:00
|
|
|
if (ret >= 0)
|
|
|
|
|
{
|
2025-04-24 16:11:19 +08:00
|
|
|
sminfo(upper->name, "update batch %" PRIu32, min_latency);
|
2022-06-15 12:17:51 +08:00
|
|
|
upper->state.min_latency = min_latency;
|
|
|
|
|
}
|
2022-06-16 14:26:42 +08:00
|
|
|
}
|
2020-10-19 21:24:13 +08:00
|
|
|
}
|
2022-03-22 15:46:02 +08:00
|
|
|
|
|
|
|
|
upper->state.min_interval = min_interval;
|
2022-06-29 17:34:55 +08:00
|
|
|
user->state.interval = interval;
|
2024-05-09 21:37:21 +08:00
|
|
|
sensor_pollnotify(upper, POLLPRI, SENSOR_ROLE_WR);
|
2024-12-02 11:14:15 +08:00
|
|
|
nxrmutex_unlock(&upper->lock);
|
2022-03-22 15:46:02 +08:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-13 14:00:08 +08:00
|
|
|
static int sensor_update_latency(FAR struct file *filep,
|
|
|
|
|
FAR struct sensor_upperhalf_s *upper,
|
2022-03-22 15:46:02 +08:00
|
|
|
FAR struct sensor_user_s *user,
|
2024-06-28 23:35:55 +08:00
|
|
|
uint32_t latency)
|
2022-03-22 15:46:02 +08:00
|
|
|
{
|
|
|
|
|
FAR struct sensor_lowerhalf_s *lower = upper->lower;
|
|
|
|
|
FAR struct sensor_user_s *tmp;
|
2024-06-28 23:35:55 +08:00
|
|
|
uint32_t min_latency = latency;
|
2024-12-02 11:14:15 +08:00
|
|
|
uint32_t orig_min_latency;
|
2022-03-22 15:46:02 +08:00
|
|
|
int ret = 0;
|
|
|
|
|
|
2022-06-29 17:34:55 +08:00
|
|
|
if (latency == user->state.latency)
|
2022-03-22 15:46:02 +08:00
|
|
|
{
|
2022-06-15 12:17:51 +08:00
|
|
|
return 0;
|
2022-03-22 15:46:02 +08:00
|
|
|
}
|
|
|
|
|
|
2024-06-28 23:35:55 +08:00
|
|
|
if (user->state.interval == UINT32_MAX)
|
2022-03-22 15:46:02 +08:00
|
|
|
{
|
2022-06-29 17:34:55 +08:00
|
|
|
user->state.latency = latency;
|
2022-03-22 15:46:02 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-02 11:14:15 +08:00
|
|
|
nxrmutex_lock(&upper->lock);
|
|
|
|
|
again:
|
2022-03-22 15:46:02 +08:00
|
|
|
if (latency <= upper->state.min_latency)
|
|
|
|
|
{
|
|
|
|
|
goto update;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
list_for_every_entry(&upper->userlist, tmp, struct sensor_user_s, node)
|
|
|
|
|
{
|
2024-06-28 23:35:55 +08:00
|
|
|
if (tmp == user || tmp->state.interval == UINT32_MAX)
|
2022-03-22 15:46:02 +08:00
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-29 17:34:55 +08:00
|
|
|
if (min_latency > tmp->state.latency)
|
2022-03-22 15:46:02 +08:00
|
|
|
{
|
2022-06-29 17:34:55 +08:00
|
|
|
min_latency = tmp->state.latency;
|
2022-03-22 15:46:02 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
update:
|
2024-06-28 23:35:55 +08:00
|
|
|
if (min_latency == UINT32_MAX)
|
2022-06-15 12:17:51 +08:00
|
|
|
{
|
|
|
|
|
min_latency = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-22 15:46:02 +08:00
|
|
|
if (min_latency == upper->state.min_latency)
|
|
|
|
|
{
|
2022-06-29 17:34:55 +08:00
|
|
|
user->state.latency = latency;
|
2024-12-02 11:14:15 +08:00
|
|
|
nxrmutex_unlock(&upper->lock);
|
2022-03-22 15:46:02 +08:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-15 12:17:51 +08:00
|
|
|
if (lower->ops->batch)
|
2022-03-22 15:46:02 +08:00
|
|
|
{
|
2024-12-02 11:14:15 +08:00
|
|
|
orig_min_latency = upper->state.min_latency;
|
|
|
|
|
nxrmutex_unlock(&upper->lock);
|
2022-04-13 14:00:08 +08:00
|
|
|
ret = lower->ops->batch(lower, filep, &min_latency);
|
2022-03-22 15:46:02 +08:00
|
|
|
if (ret < 0)
|
|
|
|
|
{
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
2024-12-02 11:14:15 +08:00
|
|
|
|
2025-04-24 16:11:19 +08:00
|
|
|
sminfo(upper->name, "update batch %" PRIu32, min_latency);
|
2024-12-02 11:14:15 +08:00
|
|
|
nxrmutex_lock(&upper->lock);
|
|
|
|
|
|
|
|
|
|
/* The upper min_latency is updated by other threads, set to
|
|
|
|
|
* driver again to avoid race condition.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (orig_min_latency != upper->state.min_latency)
|
|
|
|
|
{
|
|
|
|
|
goto again;
|
|
|
|
|
}
|
2022-03-22 15:46:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
upper->state.min_latency = min_latency;
|
2022-06-29 17:34:55 +08:00
|
|
|
user->state.latency = latency;
|
2024-05-09 21:37:21 +08:00
|
|
|
sensor_pollnotify(upper, POLLPRI, SENSOR_ROLE_WR);
|
2024-12-02 11:14:15 +08:00
|
|
|
nxrmutex_unlock(&upper->lock);
|
2022-03-22 15:46:02 +08:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-13 23:25:08 +08:00
|
|
|
static void sensor_update_nonwakeup(FAR struct file *filep,
|
|
|
|
|
FAR struct sensor_upperhalf_s *upper,
|
|
|
|
|
FAR struct sensor_user_s *user,
|
|
|
|
|
bool nonwakeup)
|
|
|
|
|
{
|
|
|
|
|
FAR struct sensor_lowerhalf_s *lower = upper->lower;
|
|
|
|
|
|
|
|
|
|
if (nonwakeup == user->state.nonwakeup)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
user->state.nonwakeup = nonwakeup;
|
|
|
|
|
nxrmutex_lock(&upper->lock);
|
|
|
|
|
list_for_every_entry(&upper->userlist, user, struct sensor_user_s,
|
|
|
|
|
node)
|
|
|
|
|
{
|
|
|
|
|
if (!user->state.nonwakeup)
|
|
|
|
|
{
|
|
|
|
|
nonwakeup = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (nonwakeup != upper->state.nonwakeup)
|
|
|
|
|
{
|
|
|
|
|
upper->state.nonwakeup = nonwakeup;
|
2025-04-24 16:11:19 +08:00
|
|
|
sminfo(upper->name, "update nonwakeup %d", nonwakeup);
|
2025-02-11 20:25:41 +08:00
|
|
|
nxrmutex_unlock(&upper->lock);
|
2025-01-13 23:25:08 +08:00
|
|
|
if (lower->ops->set_nonwakeup)
|
|
|
|
|
{
|
|
|
|
|
lower->ops->set_nonwakeup(lower, filep, nonwakeup);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-02-11 20:25:41 +08:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
nxrmutex_unlock(&upper->lock);
|
|
|
|
|
}
|
2025-01-13 23:25:08 +08:00
|
|
|
}
|
|
|
|
|
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
static void sensor_generate_timing(FAR struct sensor_upperhalf_s *upper,
|
|
|
|
|
unsigned long nums)
|
|
|
|
|
{
|
2024-06-28 23:35:55 +08:00
|
|
|
uint32_t interval = upper->state.min_interval != UINT32_MAX ?
|
|
|
|
|
upper->state.min_interval : 1;
|
2026-09-11 19:25:56 +08:00
|
|
|
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
while (nums-- > 0)
|
|
|
|
|
{
|
|
|
|
|
upper->state.generation += interval;
|
|
|
|
|
circbuf_overwrite(&upper->timing, &upper->state.generation,
|
|
|
|
|
TIMING_BUF_ESIZE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool sensor_is_updated(FAR struct sensor_upperhalf_s *upper,
|
|
|
|
|
FAR struct sensor_user_s *user)
|
|
|
|
|
{
|
2024-07-22 12:59:40 +08:00
|
|
|
long delta = (long long)upper->state.generation - user->state.generation;
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
|
|
|
|
|
if (delta <= 0)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2024-06-28 23:35:55 +08:00
|
|
|
else if (user->state.interval == UINT32_MAX)
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Check whether next generation user want in buffer.
|
|
|
|
|
* generation next generation(not published yet)
|
|
|
|
|
* ____v_____________v
|
|
|
|
|
* ////|//////^ |
|
|
|
|
|
* ^ middle point
|
|
|
|
|
* next generation user want
|
|
|
|
|
*/
|
|
|
|
|
|
2022-06-29 17:34:55 +08:00
|
|
|
return delta >= user->state.interval -
|
|
|
|
|
(upper->state.min_interval >> 1);
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void sensor_catch_up(FAR struct sensor_upperhalf_s *upper,
|
|
|
|
|
FAR struct sensor_user_s *user)
|
|
|
|
|
{
|
2024-06-28 23:35:55 +08:00
|
|
|
uint32_t generation;
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
long delta;
|
|
|
|
|
|
|
|
|
|
circbuf_peek(&upper->timing, &generation, TIMING_BUF_ESIZE);
|
2024-07-22 12:59:40 +08:00
|
|
|
delta = (long long)generation - user->state.generation;
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
if (delta > 0)
|
|
|
|
|
{
|
|
|
|
|
user->bufferpos = upper->timing.tail / TIMING_BUF_ESIZE;
|
2024-06-28 23:35:55 +08:00
|
|
|
if (user->state.interval == UINT32_MAX)
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
{
|
2022-06-29 17:34:55 +08:00
|
|
|
user->state.generation = generation - 1;
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
delta -= upper->state.min_interval >> 1;
|
2022-06-29 17:34:55 +08:00
|
|
|
user->state.generation += ROUND_DOWN(delta,
|
|
|
|
|
user->state.interval);
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static ssize_t sensor_do_samples(FAR struct sensor_upperhalf_s *upper,
|
|
|
|
|
FAR struct sensor_user_s *user,
|
|
|
|
|
FAR char *buffer, size_t len)
|
|
|
|
|
{
|
2024-06-28 23:35:55 +08:00
|
|
|
uint32_t generation;
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
ssize_t ret = 0;
|
|
|
|
|
size_t nums;
|
|
|
|
|
size_t pos;
|
|
|
|
|
size_t end;
|
|
|
|
|
|
|
|
|
|
sensor_catch_up(upper, user);
|
|
|
|
|
nums = upper->timing.head / TIMING_BUF_ESIZE - user->bufferpos;
|
|
|
|
|
if (len < nums * upper->state.esize)
|
|
|
|
|
{
|
|
|
|
|
nums = len / upper->state.esize;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
len = nums * upper->state.esize;
|
|
|
|
|
|
|
|
|
|
/* Take samples continuously */
|
|
|
|
|
|
2024-06-28 23:35:55 +08:00
|
|
|
if (user->state.interval == UINT32_MAX)
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
{
|
2024-01-11 18:29:32 +08:00
|
|
|
if (buffer != NULL)
|
|
|
|
|
{
|
|
|
|
|
ret = circbuf_peekat(&upper->buffer,
|
|
|
|
|
user->bufferpos * upper->state.esize,
|
|
|
|
|
buffer, len);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ret = len;
|
|
|
|
|
}
|
|
|
|
|
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
user->bufferpos += nums;
|
|
|
|
|
circbuf_peekat(&upper->timing,
|
|
|
|
|
(user->bufferpos - 1) * TIMING_BUF_ESIZE,
|
2022-06-29 17:34:55 +08:00
|
|
|
&user->state.generation, TIMING_BUF_ESIZE);
|
2025-04-24 16:11:19 +08:00
|
|
|
smdebug(upper->name, "do sample interval:%" PRIu32 ", "
|
|
|
|
|
"user.generation:%" PRIu32 ", ret:%zd",
|
|
|
|
|
upper->state.generation, user->state.generation, ret);
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Take samples one-bye-one, to determine whether a sample needed:
|
|
|
|
|
*
|
|
|
|
|
* If user's next generation is on the left side of middle point,
|
|
|
|
|
* we should copy this sample for user.
|
|
|
|
|
* next_generation(or end)
|
|
|
|
|
* ________________v____
|
|
|
|
|
* timing buffer: //|//////. |
|
|
|
|
|
* ^ middle
|
|
|
|
|
* generation
|
|
|
|
|
* next sample(or end)
|
|
|
|
|
* ________________v____
|
|
|
|
|
* data buffer: | |
|
|
|
|
|
* ^
|
|
|
|
|
* sample
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
pos = user->bufferpos;
|
|
|
|
|
end = upper->timing.head / TIMING_BUF_ESIZE;
|
|
|
|
|
circbuf_peekat(&upper->timing, pos * TIMING_BUF_ESIZE,
|
|
|
|
|
&generation, TIMING_BUF_ESIZE);
|
|
|
|
|
while (pos++ != end)
|
|
|
|
|
{
|
2024-06-28 23:35:55 +08:00
|
|
|
uint32_t next_generation;
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
long delta;
|
|
|
|
|
|
|
|
|
|
if (pos * TIMING_BUF_ESIZE == upper->timing.head)
|
|
|
|
|
{
|
|
|
|
|
next_generation = upper->state.generation +
|
|
|
|
|
upper->state.min_interval;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
circbuf_peekat(&upper->timing, pos * TIMING_BUF_ESIZE,
|
|
|
|
|
&next_generation, TIMING_BUF_ESIZE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delta = next_generation + generation -
|
2022-06-29 17:34:55 +08:00
|
|
|
((user->state.generation + user->state.interval) << 1);
|
2025-04-24 16:11:19 +08:00
|
|
|
smdebug(upper->name, "do sample interval:%" PRIu32 ", "
|
|
|
|
|
"generation:%" PRIu32 ", user generation:% "PRIu32 ", "
|
|
|
|
|
"next generation:%" PRIu32, user->state.interval,
|
|
|
|
|
generation, user->state.generation, next_generation);
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
if (delta >= 0)
|
|
|
|
|
{
|
2024-01-11 18:29:32 +08:00
|
|
|
if (buffer != NULL)
|
|
|
|
|
{
|
|
|
|
|
ret += circbuf_peekat(&upper->buffer,
|
|
|
|
|
(pos - 1) * upper->state.esize,
|
|
|
|
|
buffer + ret, upper->state.esize);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ret += upper->state.esize;
|
|
|
|
|
}
|
|
|
|
|
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
user->bufferpos = pos;
|
2022-06-29 17:34:55 +08:00
|
|
|
user->state.generation += user->state.interval;
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
if (ret >= len)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
generation = next_generation;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-15 21:21:37 +08:00
|
|
|
if (pos - 1 == end && sensor_is_updated(upper, user))
|
|
|
|
|
{
|
|
|
|
|
generation = upper->state.generation - user->state.generation +
|
|
|
|
|
(upper->state.min_interval >> 1);
|
|
|
|
|
user->state.generation += ROUND_DOWN(generation,
|
|
|
|
|
user->state.interval);
|
|
|
|
|
}
|
|
|
|
|
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-22 15:46:02 +08:00
|
|
|
static void sensor_pollnotify_one(FAR struct sensor_user_s *user,
|
2024-05-09 21:37:21 +08:00
|
|
|
pollevent_t eventset,
|
|
|
|
|
sensor_role_t role)
|
2022-03-22 15:46:02 +08:00
|
|
|
{
|
2024-05-09 21:37:21 +08:00
|
|
|
if (!(user->role & role))
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-22 15:46:02 +08:00
|
|
|
if (eventset == POLLPRI)
|
|
|
|
|
{
|
|
|
|
|
user->changed = true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-19 11:08:57 +08:00
|
|
|
poll_notify(&user->fds, 1, eventset);
|
2022-03-22 15:46:02 +08:00
|
|
|
}
|
|
|
|
|
|
drivers/sensors/sensor: pace POLLIN at the requested interval
A fetch() only lower half is always ready, so a subscriber that asked for
a rate with SNIOC_SET_INTERVAL got no pacing from poll(): the descriptor
reported POLLIN on every pass and the application had to sleep out the
period itself. That does not compose. An application polling several
topics reads them sequentially from one thread, so per read sleeps
serialize: three topics at 10 Hz sleeping 100 ms each yield 3.3 Hz per
topic rather than 10.
Pace it where poll() can act on it instead. A subscriber that never
requested a rate stays always ready, and one that did becomes ready once
per its own interval, driven by a watchdog armed in sensor_poll(). This
is the fetch() side of what sensor_is_updated() already does for a
pushing lower half, so both models now honor a requested rate the same
way.
The wdog_s lives in sensor_user_s rather than in the device, so each
subscriber is paced at its own interval instead of at the minimum across
all of them, and the timer only runs while somebody is polling. The
expiry runs in timer context and takes no lock: poll_notify() is safe
from an interrupt handler, and a teardown that raced it has already
cleared fds, which makes both the notify and the re-arm no-ops. Teardown
therefore just cancels the watchdog where it clears fds, and a watchdog
keeps this off the work queue entirely, which a fetch() only sensor
exists to avoid.
sensor_close() needs nothing of its own: poll_setup() holds a reference
on the file for the duration of the poll, so file_close() cannot run
until poll_teardown() has called sensor_poll() with setup false, and that
already cancelled the watchdog.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Felipe Moura <moura.fmo@gmail.com>
2026-08-01 13:00:29 -03:00
|
|
|
static void sensor_fetch_expired(wdparm_t arg)
|
|
|
|
|
{
|
|
|
|
|
FAR struct sensor_user_s *user = (FAR struct sensor_user_s *)arg;
|
|
|
|
|
|
|
|
|
|
/* Timer context, so no lock: a teardown that raced us cleared fds, which
|
|
|
|
|
* makes both the notify and the re-arm below no-ops.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (user->fds != NULL)
|
|
|
|
|
{
|
|
|
|
|
user->fetched = sensor_get_timestamp();
|
|
|
|
|
sensor_pollnotify_one(user, POLLIN, SENSOR_ROLE_RD);
|
|
|
|
|
wd_start(&user->wdog, USEC2TICK(user->state.interval),
|
|
|
|
|
sensor_fetch_expired, arg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-22 15:46:02 +08:00
|
|
|
static void sensor_pollnotify(FAR struct sensor_upperhalf_s *upper,
|
2024-05-09 21:37:21 +08:00
|
|
|
pollevent_t eventset, sensor_role_t role)
|
2022-03-22 15:46:02 +08:00
|
|
|
{
|
|
|
|
|
FAR struct sensor_user_s *user;
|
|
|
|
|
|
|
|
|
|
list_for_every_entry(&upper->userlist, user, struct sensor_user_s, node)
|
|
|
|
|
{
|
2024-05-09 21:37:21 +08:00
|
|
|
sensor_pollnotify_one(user, eventset, role);
|
2022-03-22 15:46:02 +08:00
|
|
|
}
|
2020-10-19 21:24:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int sensor_open(FAR struct file *filep)
|
|
|
|
|
{
|
|
|
|
|
FAR struct inode *inode = filep->f_inode;
|
|
|
|
|
FAR struct sensor_upperhalf_s *upper = inode->i_private;
|
2020-11-12 18:40:37 +08:00
|
|
|
FAR struct sensor_lowerhalf_s *lower = upper->lower;
|
2022-03-22 15:46:02 +08:00
|
|
|
FAR struct sensor_user_s *user;
|
2022-04-29 23:08:59 +08:00
|
|
|
int ret = 0;
|
2020-10-19 21:24:13 +08:00
|
|
|
|
2022-06-14 11:33:13 +08:00
|
|
|
nxrmutex_lock(&upper->lock);
|
2022-03-22 15:46:02 +08:00
|
|
|
user = kmm_zalloc(sizeof(struct sensor_user_s));
|
|
|
|
|
if (user == NULL)
|
2020-10-19 21:24:13 +08:00
|
|
|
{
|
2022-03-22 15:46:02 +08:00
|
|
|
ret = -ENOMEM;
|
2022-09-06 14:18:45 +08:00
|
|
|
goto errout_with_lock;
|
2022-03-22 15:46:02 +08:00
|
|
|
}
|
2020-11-04 21:31:30 +08:00
|
|
|
|
2024-12-03 14:42:28 +08:00
|
|
|
if ((filep->f_oflags & O_DIRECT) == 0 && lower->ops->open)
|
2022-04-13 14:00:08 +08:00
|
|
|
{
|
|
|
|
|
ret = lower->ops->open(lower, filep);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
{
|
|
|
|
|
goto errout_with_user;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-03 14:42:28 +08:00
|
|
|
/* Using the O_DIRECT flag will prevent cross-core operations,
|
|
|
|
|
* allowing for direct I/O operations.
|
|
|
|
|
*/
|
|
|
|
|
|
2026-06-24 17:53:33 +08:00
|
|
|
if ((filep->f_oflags & O_ACCMODE) != O_WRONLY)
|
2022-03-22 15:46:02 +08:00
|
|
|
{
|
2024-12-03 14:42:28 +08:00
|
|
|
if (upper->state.nsubscribers == 0 && lower->ops->activate)
|
2022-03-22 15:46:02 +08:00
|
|
|
{
|
2024-12-03 14:42:28 +08:00
|
|
|
ret = lower->ops->activate(lower, filep, true);
|
|
|
|
|
if (ret < 0)
|
2022-03-22 15:46:02 +08:00
|
|
|
{
|
2024-12-03 14:42:28 +08:00
|
|
|
goto errout_with_open;
|
2022-03-22 15:46:02 +08:00
|
|
|
}
|
2024-07-04 11:21:44 +08:00
|
|
|
}
|
2022-03-22 15:46:02 +08:00
|
|
|
|
2024-12-03 14:42:28 +08:00
|
|
|
user->role |= SENSOR_ROLE_RD;
|
|
|
|
|
upper->state.nsubscribers++;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-24 17:53:33 +08:00
|
|
|
if ((filep->f_oflags & O_ACCMODE) != O_RDONLY)
|
2024-12-03 14:42:28 +08:00
|
|
|
{
|
|
|
|
|
user->role |= SENSOR_ROLE_WR;
|
|
|
|
|
upper->state.nadvertisers++;
|
|
|
|
|
if (filep->f_oflags & SENSOR_PERSIST)
|
2022-05-21 17:50:29 +08:00
|
|
|
{
|
2024-12-03 14:42:28 +08:00
|
|
|
lower->persist = true;
|
2022-05-21 17:50:29 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (upper->state.generation && lower->persist)
|
|
|
|
|
{
|
2022-06-29 17:34:55 +08:00
|
|
|
user->state.generation = upper->state.generation - 1;
|
2024-05-09 21:37:21 +08:00
|
|
|
user->bufferpos = upper->timing.head / TIMING_BUF_ESIZE - 1;
|
2022-05-21 17:50:29 +08:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-06-29 17:34:55 +08:00
|
|
|
user->state.generation = upper->state.generation;
|
2024-05-09 21:37:21 +08:00
|
|
|
user->bufferpos = upper->timing.head / TIMING_BUF_ESIZE;
|
2020-10-19 21:24:13 +08:00
|
|
|
}
|
|
|
|
|
|
2025-04-24 16:11:19 +08:00
|
|
|
sminfo(upper->name, "user address: %p, role type: %d, "
|
|
|
|
|
"user generation: %" PRIu32 ", upper generation: %" PRIu32 ", "
|
|
|
|
|
"nsubscribers: %" PRIu32 ", nadvertisers: %" PRIu32 ", persist: %d",
|
|
|
|
|
user, user->role, user->state.generation,
|
|
|
|
|
upper->state.generation, upper->state.nsubscribers,
|
|
|
|
|
upper->state.nadvertisers, lower->persist);
|
|
|
|
|
|
2024-06-28 23:35:55 +08:00
|
|
|
user->state.interval = UINT32_MAX;
|
2022-06-29 17:34:55 +08:00
|
|
|
user->state.esize = upper->state.esize;
|
2025-05-15 12:30:49 +08:00
|
|
|
user->state.nonwakeup = true;
|
2022-03-22 15:46:02 +08:00
|
|
|
list_add_tail(&upper->userlist, &user->node);
|
|
|
|
|
|
|
|
|
|
/* The new user generation, notify to other users */
|
|
|
|
|
|
2024-05-09 21:37:21 +08:00
|
|
|
sensor_pollnotify(upper, POLLPRI, SENSOR_ROLE_WR);
|
2022-03-22 15:46:02 +08:00
|
|
|
|
|
|
|
|
filep->f_priv = user;
|
2022-09-06 14:18:45 +08:00
|
|
|
goto errout_with_lock;
|
2022-03-22 15:46:02 +08:00
|
|
|
|
2022-04-13 14:00:08 +08:00
|
|
|
errout_with_open:
|
|
|
|
|
if (lower->ops->close)
|
|
|
|
|
{
|
|
|
|
|
lower->ops->close(lower, filep);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-22 15:46:02 +08:00
|
|
|
errout_with_user:
|
|
|
|
|
kmm_free(user);
|
2022-09-06 14:18:45 +08:00
|
|
|
errout_with_lock:
|
2022-06-14 11:33:13 +08:00
|
|
|
nxrmutex_unlock(&upper->lock);
|
2020-10-19 21:24:13 +08:00
|
|
|
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;
|
2022-03-22 15:46:02 +08:00
|
|
|
FAR struct sensor_user_s *user = filep->f_priv;
|
2022-04-29 23:08:59 +08:00
|
|
|
int ret = 0;
|
2020-10-19 21:24:13 +08:00
|
|
|
|
2025-01-13 23:25:08 +08:00
|
|
|
sensor_update_interval(filep, upper, user, UINT32_MAX);
|
|
|
|
|
sensor_update_latency(filep, upper, user, UINT32_MAX);
|
2025-05-09 12:25:24 +08:00
|
|
|
sensor_update_nonwakeup(filep, upper, user, true);
|
2025-01-13 23:25:08 +08:00
|
|
|
|
2022-06-14 11:33:13 +08:00
|
|
|
nxrmutex_lock(&upper->lock);
|
2025-01-13 23:25:08 +08:00
|
|
|
|
2024-12-03 14:42:28 +08:00
|
|
|
if ((filep->f_oflags & O_DIRECT) == 0 && lower->ops->close)
|
2022-04-13 14:00:08 +08:00
|
|
|
{
|
2025-01-13 23:25:08 +08:00
|
|
|
lower->ops->close(lower, filep);
|
2022-04-13 14:00:08 +08:00
|
|
|
}
|
|
|
|
|
|
2024-12-03 14:42:28 +08:00
|
|
|
/* Using the O_DIRECT flag will prevent cross-core operations,
|
|
|
|
|
* allowing for direct I/O operations.
|
|
|
|
|
*/
|
|
|
|
|
|
2026-06-24 17:53:33 +08:00
|
|
|
if ((filep->f_oflags & O_ACCMODE) != O_WRONLY)
|
2020-10-19 21:24:13 +08:00
|
|
|
{
|
2024-12-03 14:42:28 +08:00
|
|
|
upper->state.nsubscribers--;
|
|
|
|
|
if (upper->state.nsubscribers == 0 && lower->ops->activate)
|
2020-10-19 21:24:13 +08:00
|
|
|
{
|
2024-12-03 14:42:28 +08:00
|
|
|
lower->ops->activate(lower, filep, false);
|
2020-10-19 21:24:13 +08:00
|
|
|
}
|
2024-12-03 14:42:28 +08:00
|
|
|
}
|
2020-10-19 21:24:13 +08:00
|
|
|
|
2026-06-24 17:53:33 +08:00
|
|
|
if ((filep->f_oflags & O_ACCMODE) != O_RDONLY)
|
2024-12-03 14:42:28 +08:00
|
|
|
{
|
|
|
|
|
upper->state.nadvertisers--;
|
2022-03-22 15:46:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
list_delete(&user->node);
|
|
|
|
|
|
|
|
|
|
/* The user is closed, notify to other users */
|
|
|
|
|
|
2025-04-24 16:11:19 +08:00
|
|
|
sminfo(upper->name, "user address: %p, "
|
|
|
|
|
"close subscriber: %" PRIu32 ", close advertiser:%" PRIu32,
|
|
|
|
|
user, upper->state.nsubscribers, upper->state.nadvertisers);
|
2024-05-09 21:37:21 +08:00
|
|
|
sensor_pollnotify(upper, POLLPRI, SENSOR_ROLE_WR);
|
2022-06-14 11:33:13 +08:00
|
|
|
nxrmutex_unlock(&upper->lock);
|
2022-03-22 15:46:02 +08:00
|
|
|
|
|
|
|
|
kmm_free(user);
|
2020-10-19 21:24:13 +08:00
|
|
|
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;
|
2022-03-22 15:46:02 +08:00
|
|
|
FAR struct sensor_user_s *user = filep->f_priv;
|
2020-10-19 21:24:13 +08:00
|
|
|
ssize_t ret;
|
|
|
|
|
|
2024-01-11 18:29:32 +08:00
|
|
|
if (!len)
|
2020-10-19 21:24:13 +08:00
|
|
|
{
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-14 11:33:13 +08:00
|
|
|
nxrmutex_lock(&upper->lock);
|
2020-11-04 11:23:39 +08:00
|
|
|
if (lower->ops->fetch)
|
2020-10-19 21:24:13 +08:00
|
|
|
{
|
2024-01-11 18:29:32 +08:00
|
|
|
if (buffer == NULL)
|
|
|
|
|
{
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
drivers/sensors/sensor: pace POLLIN at the requested interval
A fetch() only lower half is always ready, so a subscriber that asked for
a rate with SNIOC_SET_INTERVAL got no pacing from poll(): the descriptor
reported POLLIN on every pass and the application had to sleep out the
period itself. That does not compose. An application polling several
topics reads them sequentially from one thread, so per read sleeps
serialize: three topics at 10 Hz sleeping 100 ms each yield 3.3 Hz per
topic rather than 10.
Pace it where poll() can act on it instead. A subscriber that never
requested a rate stays always ready, and one that did becomes ready once
per its own interval, driven by a watchdog armed in sensor_poll(). This
is the fetch() side of what sensor_is_updated() already does for a
pushing lower half, so both models now honor a requested rate the same
way.
The wdog_s lives in sensor_user_s rather than in the device, so each
subscriber is paced at its own interval instead of at the minimum across
all of them, and the timer only runs while somebody is polling. The
expiry runs in timer context and takes no lock: poll_notify() is safe
from an interrupt handler, and a teardown that raced it has already
cleared fds, which makes both the notify and the re-arm no-ops. Teardown
therefore just cancels the watchdog where it clears fds, and a watchdog
keeps this off the work queue entirely, which a fetch() only sensor
exists to avoid.
sensor_close() needs nothing of its own: poll_setup() holds a reference
on the file for the duration of the poll, so file_close() cannot run
until poll_teardown() has called sensor_poll() with setup false, and that
already cancelled the watchdog.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Felipe Moura <moura.fmo@gmail.com>
2026-08-01 13:00:29 -03:00
|
|
|
/* Read the device directly, there is nothing to wait for */
|
2020-10-19 21:24:13 +08:00
|
|
|
|
drivers/sensors/sensor: always report POLLIN for fetch only sensor
A fetch() only lower half reads the device on demand, so its data is
always available and there is never anything to wait for. The upper half
did not reflect that: poll() only reported POLLIN when the descriptor was
opened O_NONBLOCK, and a blocking read() waited on buffersem, which is
only posted when the lower half drives notify_event from an interrupt of
its own.
A fetch() only sensor with no interrupt therefore never satisfied
poll()/read() at all. This is not hypothetical: in the in tree
nucleo-h563zi:dts configuration CONFIG_STM32_DTS_TRIGGER defaults to 0,
which selects stm32_dts_fetch(), and no CONFIG_STM32_DTS_ITEN_* option is
enabled, so the DTS interrupt never fires. A blocking read() on that
sensor waits forever, even though stm32_dts_fetch() performs a complete
software triggered measurement on its own and needs no interrupt at all.
Applications had to work around this by forcing O_NONBLOCK on the
descriptor themselves, see apache/nuttx-apps#3686.
Drop the O_NONBLOCK special case in both paths: sensor_poll() now always
reports POLLIN for a fetch only sensor and sensor_read() calls fetch()
directly instead of waiting. Update the sensor_ops_s::fetch
documentation, which described the old contract.
With the wait gone, buffersem has no waiters left. Its only two readers
were the ones removed here, both in the fetch path: the wait in
sensor_read() and the nxsem_get_value() in sensor_poll(). The remaining
nxsem_post() calls in sensor_push_event() and sensor_notify_event() had
nothing left to wake, so drop the semaphore and those posts as well.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Felipe Moura <moura.fmo@gmail.com>
2026-08-01 12:37:00 -03:00
|
|
|
if (!upper->state.nsubscribers)
|
2021-02-07 17:13:31 +08:00
|
|
|
{
|
|
|
|
|
ret = -EAGAIN;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
2020-11-04 11:23:39 +08:00
|
|
|
|
drivers/sensors/sensor: always report POLLIN for fetch only sensor
A fetch() only lower half reads the device on demand, so its data is
always available and there is never anything to wait for. The upper half
did not reflect that: poll() only reported POLLIN when the descriptor was
opened O_NONBLOCK, and a blocking read() waited on buffersem, which is
only posted when the lower half drives notify_event from an interrupt of
its own.
A fetch() only sensor with no interrupt therefore never satisfied
poll()/read() at all. This is not hypothetical: in the in tree
nucleo-h563zi:dts configuration CONFIG_STM32_DTS_TRIGGER defaults to 0,
which selects stm32_dts_fetch(), and no CONFIG_STM32_DTS_ITEN_* option is
enabled, so the DTS interrupt never fires. A blocking read() on that
sensor waits forever, even though stm32_dts_fetch() performs a complete
software triggered measurement on its own and needs no interrupt at all.
Applications had to work around this by forcing O_NONBLOCK on the
descriptor themselves, see apache/nuttx-apps#3686.
Drop the O_NONBLOCK special case in both paths: sensor_poll() now always
reports POLLIN for a fetch only sensor and sensor_read() calls fetch()
directly instead of waiting. Update the sensor_ops_s::fetch
documentation, which described the old contract.
With the wait gone, buffersem has no waiters left. Its only two readers
were the ones removed here, both in the fetch path: the wait in
sensor_read() and the nxsem_get_value() in sensor_poll(). The remaining
nxsem_post() calls in sensor_push_event() and sensor_notify_event() had
nothing left to wake, so drop the semaphore and those posts as well.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Felipe Moura <moura.fmo@gmail.com>
2026-08-01 12:37:00 -03:00
|
|
|
ret = lower->ops->fetch(lower, filep, buffer, len);
|
2020-10-19 21:24:13 +08:00
|
|
|
}
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
else if (circbuf_is_empty(&upper->buffer))
|
2020-11-04 11:23:39 +08:00
|
|
|
{
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
ret = -ENODATA;
|
|
|
|
|
}
|
|
|
|
|
else if (sensor_is_updated(upper, user))
|
|
|
|
|
{
|
|
|
|
|
ret = sensor_do_samples(upper, user, buffer, len);
|
|
|
|
|
}
|
|
|
|
|
else if (lower->persist)
|
|
|
|
|
{
|
2024-01-11 18:29:32 +08:00
|
|
|
if (buffer == NULL)
|
|
|
|
|
{
|
|
|
|
|
ret = upper->state.esize;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Persistent device can get latest old data if not updated. */
|
2022-03-22 15:46:02 +08:00
|
|
|
|
2024-01-11 18:29:32 +08:00
|
|
|
ret = circbuf_peekat(&upper->buffer,
|
|
|
|
|
(user->bufferpos - 1) * upper->state.esize,
|
|
|
|
|
buffer, upper->state.esize);
|
|
|
|
|
}
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ret = -ENODATA;
|
2020-10-19 21:24:13 +08:00
|
|
|
}
|
|
|
|
|
|
2025-04-24 16:11:19 +08:00
|
|
|
if (ret > 0)
|
|
|
|
|
{
|
|
|
|
|
smdebug(upper->name, "the number of read event is:%zd",
|
|
|
|
|
ret / upper->state.esize);
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-07 17:13:31 +08:00
|
|
|
out:
|
2022-06-14 11:33:13 +08:00
|
|
|
nxrmutex_unlock(&upper->lock);
|
2020-10-19 21:24:13 +08:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-11 17:05:47 +08:00
|
|
|
static ssize_t sensor_write(FAR struct file *filep, FAR const char *buffer,
|
|
|
|
|
size_t buflen)
|
|
|
|
|
{
|
|
|
|
|
FAR struct inode *inode = filep->f_inode;
|
|
|
|
|
FAR struct sensor_upperhalf_s *upper = inode->i_private;
|
2022-04-08 22:46:29 +08:00
|
|
|
FAR struct sensor_lowerhalf_s *lower = upper->lower;
|
2022-03-11 17:05:47 +08:00
|
|
|
|
2022-04-08 22:46:29 +08:00
|
|
|
return lower->push_event(lower->priv, buffer, buflen);
|
2022-03-11 17:05:47 +08:00
|
|
|
}
|
|
|
|
|
|
2020-10-19 21:24:13 +08:00
|
|
|
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;
|
2022-03-22 15:46:02 +08:00
|
|
|
FAR struct sensor_user_s *user = filep->f_priv;
|
2024-06-28 23:35:55 +08:00
|
|
|
uint32_t arg1 = (uint32_t)arg;
|
2022-04-29 23:08:59 +08:00
|
|
|
int ret = 0;
|
2020-10-19 21:24:13 +08:00
|
|
|
|
2025-04-24 16:11:19 +08:00
|
|
|
smdebug(upper->name, "sensor ioctl start, cmd:%d", cmd);
|
2020-10-19 21:24:13 +08:00
|
|
|
switch (cmd)
|
|
|
|
|
{
|
2022-03-22 15:46:02 +08:00
|
|
|
case SNIOC_GET_STATE:
|
2020-10-19 21:24:13 +08:00
|
|
|
{
|
2022-06-14 11:33:13 +08:00
|
|
|
nxrmutex_lock(&upper->lock);
|
2022-03-22 15:46:02 +08:00
|
|
|
memcpy((FAR void *)(uintptr_t)arg,
|
|
|
|
|
&upper->state, sizeof(upper->state));
|
|
|
|
|
user->changed = false;
|
2022-06-14 11:33:13 +08:00
|
|
|
nxrmutex_unlock(&upper->lock);
|
2020-10-19 21:24:13 +08:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2022-06-29 17:34:55 +08:00
|
|
|
case SNIOC_GET_USTATE:
|
|
|
|
|
{
|
|
|
|
|
nxrmutex_lock(&upper->lock);
|
|
|
|
|
memcpy((FAR void *)(uintptr_t)arg,
|
|
|
|
|
&user->state, sizeof(user->state));
|
|
|
|
|
nxrmutex_unlock(&upper->lock);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2020-10-19 21:24:13 +08:00
|
|
|
case SNIOC_SET_INTERVAL:
|
|
|
|
|
{
|
2022-06-15 21:26:09 +08:00
|
|
|
ret = sensor_update_interval(filep, upper, user,
|
2024-06-28 23:35:55 +08:00
|
|
|
arg1 ? arg1 : UINT32_MAX);
|
2020-10-19 21:24:13 +08:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SNIOC_BATCH:
|
|
|
|
|
{
|
2024-06-28 23:35:55 +08:00
|
|
|
ret = sensor_update_latency(filep, upper, user, arg1);
|
2020-10-19 21:24:13 +08:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2021-09-27 20:16:15 +08:00
|
|
|
case SNIOC_SELFTEST:
|
|
|
|
|
{
|
|
|
|
|
if (lower->ops->selftest == NULL)
|
|
|
|
|
{
|
|
|
|
|
ret = -ENOTSUP;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-13 14:00:08 +08:00
|
|
|
ret = lower->ops->selftest(lower, filep, arg);
|
2021-09-27 20:16:15 +08:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2021-11-09 20:37:27 +08:00
|
|
|
case SNIOC_SET_CALIBVALUE:
|
|
|
|
|
{
|
|
|
|
|
if (lower->ops->set_calibvalue == NULL)
|
|
|
|
|
{
|
|
|
|
|
ret = -ENOTSUP;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-13 14:00:08 +08:00
|
|
|
ret = lower->ops->set_calibvalue(lower, filep, arg);
|
2021-11-09 20:37:27 +08:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2022-07-21 02:47:12 +00:00
|
|
|
case SNIOC_CALIBRATE:
|
|
|
|
|
{
|
|
|
|
|
if (lower->ops->calibrate == NULL)
|
|
|
|
|
{
|
|
|
|
|
ret = -ENOTSUP;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-13 14:00:08 +08:00
|
|
|
ret = lower->ops->calibrate(lower, filep, arg);
|
2022-07-21 02:47:12 +00:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2022-03-23 17:09:46 +08:00
|
|
|
case SNIOC_SET_USERPRIV:
|
2020-10-19 21:24:13 +08:00
|
|
|
{
|
2022-06-14 11:33:13 +08:00
|
|
|
nxrmutex_lock(&upper->lock);
|
2024-06-28 23:35:55 +08:00
|
|
|
upper->state.priv = (uint64_t)arg;
|
2022-06-14 11:33:13 +08:00
|
|
|
nxrmutex_unlock(&upper->lock);
|
2020-11-04 21:31:30 +08:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2025-01-13 23:25:08 +08:00
|
|
|
case SNIOC_SET_NONWAKEUP:
|
|
|
|
|
{
|
|
|
|
|
sensor_update_nonwakeup(filep, upper, user, (bool)arg);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2021-02-08 16:26:25 +08:00
|
|
|
case SNIOC_SET_BUFFER_NUMBER:
|
2020-11-04 21:31:30 +08:00
|
|
|
{
|
2022-06-14 11:33:13 +08:00
|
|
|
nxrmutex_lock(&upper->lock);
|
2022-07-21 02:32:29 +00:00
|
|
|
if (!circbuf_is_init(&upper->buffer))
|
2020-11-04 21:31:30 +08:00
|
|
|
{
|
2024-06-28 23:35:55 +08:00
|
|
|
if (arg1 >= lower->nbuffer)
|
2022-03-22 15:46:02 +08:00
|
|
|
{
|
2024-06-28 23:35:55 +08:00
|
|
|
lower->nbuffer = arg1;
|
|
|
|
|
upper->state.nbuffer = arg1;
|
2022-03-22 15:46:02 +08:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ret = -ERANGE;
|
|
|
|
|
}
|
2022-07-21 02:32:29 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ret = -EBUSY;
|
2020-11-04 21:31:30 +08:00
|
|
|
}
|
2022-04-29 23:08:59 +08:00
|
|
|
|
2022-06-14 11:33:13 +08:00
|
|
|
nxrmutex_unlock(&upper->lock);
|
2020-10-19 21:24:13 +08:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2022-06-28 15:50:37 +08:00
|
|
|
case SNIOC_UPDATED:
|
2022-04-26 14:01:11 +08:00
|
|
|
{
|
2022-06-14 11:33:13 +08:00
|
|
|
nxrmutex_lock(&upper->lock);
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
*(FAR bool *)(uintptr_t)arg = sensor_is_updated(upper, user);
|
2022-06-14 11:33:13 +08:00
|
|
|
nxrmutex_unlock(&upper->lock);
|
2022-04-26 14:01:11 +08:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2024-03-11 18:31:30 +08:00
|
|
|
case SNIOC_GET_INFO:
|
|
|
|
|
{
|
|
|
|
|
if (lower->ops->get_info == NULL)
|
|
|
|
|
{
|
|
|
|
|
ret = -ENOTSUP;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = lower->ops->get_info(lower, filep,
|
|
|
|
|
(FAR struct sensor_device_info_s *)(uintptr_t)arg);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2026-09-11 19:25:56 +08:00
|
|
|
case SNIOC_GET_EVENTS:
|
2024-04-29 23:41:47 +08:00
|
|
|
{
|
|
|
|
|
nxrmutex_lock(&upper->lock);
|
|
|
|
|
*(FAR unsigned int *)(uintptr_t)arg = user->event;
|
|
|
|
|
user->event = 0;
|
2024-07-10 17:52:19 +08:00
|
|
|
user->changed = false;
|
2024-04-29 23:41:47 +08:00
|
|
|
nxrmutex_unlock(&upper->lock);
|
|
|
|
|
}
|
2024-05-10 12:38:07 +08:00
|
|
|
break;
|
2024-04-29 23:41:47 +08:00
|
|
|
|
2026-09-11 19:25:56 +08:00
|
|
|
case SNIOC_FLUSH:
|
2024-04-29 23:41:47 +08:00
|
|
|
{
|
|
|
|
|
/* If the sensor is not activated, return -EINVAL. */
|
|
|
|
|
|
|
|
|
|
if (upper->state.nsubscribers == 0)
|
|
|
|
|
{
|
2025-05-09 16:49:54 +08:00
|
|
|
sminfo(upper->name, "sensor not activated");
|
2024-04-29 23:41:47 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-03 23:08:06 +08:00
|
|
|
ret = -ENOTSUP;
|
2024-04-29 23:41:47 +08:00
|
|
|
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)
|
|
|
|
|
{
|
2025-05-09 16:49:54 +08:00
|
|
|
sminfo(upper->name, "flushing start");
|
2024-04-29 23:41:47 +08:00
|
|
|
user->flushing = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-12-03 23:08:06 +08:00
|
|
|
|
|
|
|
|
if (ret == -ENOTSUP)
|
2024-04-29 23:41:47 +08:00
|
|
|
{
|
|
|
|
|
/* If flush is not supported, complete immediately */
|
|
|
|
|
|
2024-12-03 23:08:06 +08:00
|
|
|
user->flushing = false;
|
2024-04-29 23:41:47 +08:00
|
|
|
user->event |= SENSOR_EVENT_FLUSH_COMPLETE;
|
2024-05-09 21:37:21 +08:00
|
|
|
sensor_pollnotify_one(user, POLLPRI, user->role);
|
2024-12-03 23:08:06 +08:00
|
|
|
|
|
|
|
|
/* If caller isn't from remote core, convert ENOTSUP
|
|
|
|
|
* to zero return, indicating the flush is completed.
|
|
|
|
|
* If it's from remote core, need to inform the remote
|
|
|
|
|
* core the flush is not supported for driver.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if ((filep->f_oflags & SENSOR_REMOTE) == 0)
|
|
|
|
|
{
|
|
|
|
|
ret = 0;
|
|
|
|
|
}
|
2025-05-09 16:49:54 +08:00
|
|
|
|
|
|
|
|
sminfo(upper->name, "flush complete with result:%d", ret);
|
2024-04-29 23:41:47 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2020-10-19 21:24:13 +08:00
|
|
|
default:
|
2020-11-04 21:31:30 +08:00
|
|
|
|
|
|
|
|
/* Lowerhalf driver process other cmd. */
|
|
|
|
|
|
|
|
|
|
if (lower->ops->control)
|
|
|
|
|
{
|
2022-04-13 14:00:08 +08:00
|
|
|
ret = lower->ops->control(lower, filep, cmd, arg);
|
2020-11-04 21:31:30 +08:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ret = -ENOTTY;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-19 21:24:13 +08:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-24 16:11:19 +08:00
|
|
|
smdebug(upper->name, "sensor ioctl end, ret:%d", ret);
|
2020-10-19 21:24:13 +08:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int sensor_poll(FAR struct file *filep,
|
2022-03-22 15:46:02 +08:00
|
|
|
FAR struct pollfd *fds, bool setup)
|
2020-10-19 21:24:13 +08:00
|
|
|
{
|
|
|
|
|
FAR struct inode *inode = filep->f_inode;
|
|
|
|
|
FAR struct sensor_upperhalf_s *upper = inode->i_private;
|
2020-11-04 11:23:39 +08:00
|
|
|
FAR struct sensor_lowerhalf_s *lower = upper->lower;
|
2022-03-22 15:46:02 +08:00
|
|
|
FAR struct sensor_user_s *user = filep->f_priv;
|
2020-10-19 21:24:13 +08:00
|
|
|
pollevent_t eventset = 0;
|
2022-04-29 23:08:59 +08:00
|
|
|
int ret = 0;
|
2020-10-19 21:24:13 +08:00
|
|
|
|
2022-06-14 11:33:13 +08:00
|
|
|
nxrmutex_lock(&upper->lock);
|
2020-10-19 21:24:13 +08:00
|
|
|
if (setup)
|
|
|
|
|
{
|
2020-11-04 21:31:30 +08:00
|
|
|
/* Don't have enough space to store fds */
|
|
|
|
|
|
2022-03-22 15:46:02 +08:00
|
|
|
if (user->fds)
|
2020-11-04 21:31:30 +08:00
|
|
|
{
|
|
|
|
|
ret = -ENOSPC;
|
|
|
|
|
goto errout;
|
|
|
|
|
}
|
2020-10-19 21:24:13 +08:00
|
|
|
|
2022-03-22 15:46:02 +08:00
|
|
|
user->fds = fds;
|
|
|
|
|
fds->priv = filep;
|
2020-11-04 11:23:39 +08:00
|
|
|
if (lower->ops->fetch)
|
|
|
|
|
{
|
drivers/sensors/sensor: pace POLLIN at the requested interval
A fetch() only lower half is always ready, so a subscriber that asked for
a rate with SNIOC_SET_INTERVAL got no pacing from poll(): the descriptor
reported POLLIN on every pass and the application had to sleep out the
period itself. That does not compose. An application polling several
topics reads them sequentially from one thread, so per read sleeps
serialize: three topics at 10 Hz sleeping 100 ms each yield 3.3 Hz per
topic rather than 10.
Pace it where poll() can act on it instead. A subscriber that never
requested a rate stays always ready, and one that did becomes ready once
per its own interval, driven by a watchdog armed in sensor_poll(). This
is the fetch() side of what sensor_is_updated() already does for a
pushing lower half, so both models now honor a requested rate the same
way.
The wdog_s lives in sensor_user_s rather than in the device, so each
subscriber is paced at its own interval instead of at the minimum across
all of them, and the timer only runs while somebody is polling. The
expiry runs in timer context and takes no lock: poll_notify() is safe
from an interrupt handler, and a teardown that raced it has already
cleared fds, which makes both the notify and the re-arm no-ops. Teardown
therefore just cancels the watchdog where it clears fds, and a watchdog
keeps this off the work queue entirely, which a fetch() only sensor
exists to avoid.
sensor_close() needs nothing of its own: poll_setup() holds a reference
on the file for the duration of the poll, so file_close() cannot run
until poll_teardown() has called sensor_poll() with setup false, and that
already cancelled the watchdog.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Felipe Moura <moura.fmo@gmail.com>
2026-08-01 13:00:29 -03:00
|
|
|
/* Always ready, unless a rate was requested: then once per
|
|
|
|
|
* interval, woken by sensor_fetch_expired().
|
drivers/sensors/sensor: always report POLLIN for fetch only sensor
A fetch() only lower half reads the device on demand, so its data is
always available and there is never anything to wait for. The upper half
did not reflect that: poll() only reported POLLIN when the descriptor was
opened O_NONBLOCK, and a blocking read() waited on buffersem, which is
only posted when the lower half drives notify_event from an interrupt of
its own.
A fetch() only sensor with no interrupt therefore never satisfied
poll()/read() at all. This is not hypothetical: in the in tree
nucleo-h563zi:dts configuration CONFIG_STM32_DTS_TRIGGER defaults to 0,
which selects stm32_dts_fetch(), and no CONFIG_STM32_DTS_ITEN_* option is
enabled, so the DTS interrupt never fires. A blocking read() on that
sensor waits forever, even though stm32_dts_fetch() performs a complete
software triggered measurement on its own and needs no interrupt at all.
Applications had to work around this by forcing O_NONBLOCK on the
descriptor themselves, see apache/nuttx-apps#3686.
Drop the O_NONBLOCK special case in both paths: sensor_poll() now always
reports POLLIN for a fetch only sensor and sensor_read() calls fetch()
directly instead of waiting. Update the sensor_ops_s::fetch
documentation, which described the old contract.
With the wait gone, buffersem has no waiters left. Its only two readers
were the ones removed here, both in the fetch path: the wait in
sensor_read() and the nxsem_get_value() in sensor_poll(). The remaining
nxsem_post() calls in sensor_push_event() and sensor_notify_event() had
nothing left to wake, so drop the semaphore and those posts as well.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Felipe Moura <moura.fmo@gmail.com>
2026-08-01 12:37:00 -03:00
|
|
|
*/
|
2020-11-04 11:23:39 +08:00
|
|
|
|
drivers/sensors/sensor: pace POLLIN at the requested interval
A fetch() only lower half is always ready, so a subscriber that asked for
a rate with SNIOC_SET_INTERVAL got no pacing from poll(): the descriptor
reported POLLIN on every pass and the application had to sleep out the
period itself. That does not compose. An application polling several
topics reads them sequentially from one thread, so per read sleeps
serialize: three topics at 10 Hz sleeping 100 ms each yield 3.3 Hz per
topic rather than 10.
Pace it where poll() can act on it instead. A subscriber that never
requested a rate stays always ready, and one that did becomes ready once
per its own interval, driven by a watchdog armed in sensor_poll(). This
is the fetch() side of what sensor_is_updated() already does for a
pushing lower half, so both models now honor a requested rate the same
way.
The wdog_s lives in sensor_user_s rather than in the device, so each
subscriber is paced at its own interval instead of at the minimum across
all of them, and the timer only runs while somebody is polling. The
expiry runs in timer context and takes no lock: poll_notify() is safe
from an interrupt handler, and a teardown that raced it has already
cleared fds, which makes both the notify and the re-arm no-ops. Teardown
therefore just cancels the watchdog where it clears fds, and a watchdog
keeps this off the work queue entirely, which a fetch() only sensor
exists to avoid.
sensor_close() needs nothing of its own: poll_setup() holds a reference
on the file for the duration of the poll, so file_close() cannot run
until poll_teardown() has called sensor_poll() with setup false, and that
already cancelled the watchdog.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Felipe Moura <moura.fmo@gmail.com>
2026-08-01 13:00:29 -03:00
|
|
|
if (user->state.interval == UINT32_MAX)
|
|
|
|
|
{
|
|
|
|
|
eventset |= POLLIN;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
uint64_t now = sensor_get_timestamp();
|
|
|
|
|
uint64_t elapsed = now - user->fetched;
|
|
|
|
|
|
|
|
|
|
if (elapsed >= user->state.interval)
|
|
|
|
|
{
|
|
|
|
|
user->fetched = now;
|
|
|
|
|
eventset |= POLLIN;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
wd_start(&user->wdog,
|
|
|
|
|
USEC2TICK(user->state.interval - elapsed),
|
|
|
|
|
sensor_fetch_expired, (wdparm_t)user);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-11-04 11:23:39 +08:00
|
|
|
}
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
else if (sensor_is_updated(upper, user))
|
2020-10-19 21:24:13 +08:00
|
|
|
{
|
2022-09-19 11:08:57 +08:00
|
|
|
eventset |= POLLIN;
|
2020-10-19 21:24:13 +08:00
|
|
|
}
|
|
|
|
|
|
2022-03-22 15:46:02 +08:00
|
|
|
if (user->changed)
|
|
|
|
|
{
|
2022-09-19 11:08:57 +08:00
|
|
|
eventset |= POLLPRI;
|
2022-03-22 15:46:02 +08:00
|
|
|
}
|
|
|
|
|
|
2026-09-11 19:25:56 +08:00
|
|
|
poll_notify(&fds, 1, eventset);
|
2020-10-19 21:24:13 +08:00
|
|
|
}
|
2022-03-22 15:46:02 +08:00
|
|
|
else
|
2020-10-19 21:24:13 +08:00
|
|
|
{
|
2022-03-22 15:46:02 +08:00
|
|
|
user->fds = NULL;
|
|
|
|
|
fds->priv = NULL;
|
drivers/sensors/sensor: pace POLLIN at the requested interval
A fetch() only lower half is always ready, so a subscriber that asked for
a rate with SNIOC_SET_INTERVAL got no pacing from poll(): the descriptor
reported POLLIN on every pass and the application had to sleep out the
period itself. That does not compose. An application polling several
topics reads them sequentially from one thread, so per read sleeps
serialize: three topics at 10 Hz sleeping 100 ms each yield 3.3 Hz per
topic rather than 10.
Pace it where poll() can act on it instead. A subscriber that never
requested a rate stays always ready, and one that did becomes ready once
per its own interval, driven by a watchdog armed in sensor_poll(). This
is the fetch() side of what sensor_is_updated() already does for a
pushing lower half, so both models now honor a requested rate the same
way.
The wdog_s lives in sensor_user_s rather than in the device, so each
subscriber is paced at its own interval instead of at the minimum across
all of them, and the timer only runs while somebody is polling. The
expiry runs in timer context and takes no lock: poll_notify() is safe
from an interrupt handler, and a teardown that raced it has already
cleared fds, which makes both the notify and the re-arm no-ops. Teardown
therefore just cancels the watchdog where it clears fds, and a watchdog
keeps this off the work queue entirely, which a fetch() only sensor
exists to avoid.
sensor_close() needs nothing of its own: poll_setup() holds a reference
on the file for the duration of the poll, so file_close() cannot run
until poll_teardown() has called sensor_poll() with setup false, and that
already cancelled the watchdog.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Felipe Moura <moura.fmo@gmail.com>
2026-08-01 13:00:29 -03:00
|
|
|
wd_cancel(&user->wdog);
|
2020-10-19 21:24:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
errout:
|
2022-06-14 11:33:13 +08:00
|
|
|
nxrmutex_unlock(&upper->lock);
|
2020-10-19 21:24:13 +08:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-11 17:05:47 +08:00
|
|
|
static ssize_t sensor_push_event(FAR void *priv, FAR const void *data,
|
|
|
|
|
size_t bytes)
|
2020-10-19 21:24:13 +08:00
|
|
|
{
|
|
|
|
|
FAR struct sensor_upperhalf_s *upper = priv;
|
2022-07-21 02:32:29 +00:00
|
|
|
FAR struct sensor_lowerhalf_s *lower = upper->lower;
|
2022-03-22 15:46:02 +08:00
|
|
|
FAR struct sensor_user_s *user;
|
2022-03-23 17:09:46 +08:00
|
|
|
unsigned long envcount;
|
2022-03-11 17:05:47 +08:00
|
|
|
int ret;
|
2020-10-19 21:24:13 +08:00
|
|
|
|
2024-04-29 23:41:47 +08:00
|
|
|
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;
|
2024-05-09 21:37:21 +08:00
|
|
|
sensor_pollnotify_one(user, POLLPRI, user->role);
|
2025-05-09 16:49:54 +08:00
|
|
|
sminfo(upper->name, "flush complete, poll notify");
|
2024-04-29 23:41:47 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nxrmutex_unlock(&upper->lock);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-23 17:09:46 +08:00
|
|
|
envcount = bytes / upper->state.esize;
|
2024-04-29 23:41:47 +08:00
|
|
|
if (bytes != envcount * upper->state.esize)
|
2020-10-19 21:24:13 +08:00
|
|
|
{
|
2024-04-29 23:41:47 +08:00
|
|
|
nxrmutex_unlock(&upper->lock);
|
2022-03-11 17:05:47 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-21 02:32:29 +00:00
|
|
|
if (!circbuf_is_init(&upper->buffer))
|
|
|
|
|
{
|
|
|
|
|
/* Initialize sensor buffer when data is first generated */
|
|
|
|
|
|
2022-03-23 17:09:46 +08:00
|
|
|
ret = circbuf_init(&upper->buffer, NULL, lower->nbuffer *
|
|
|
|
|
upper->state.esize);
|
2022-07-21 02:32:29 +00:00
|
|
|
if (ret < 0)
|
|
|
|
|
{
|
2022-06-14 11:33:13 +08:00
|
|
|
nxrmutex_unlock(&upper->lock);
|
2022-07-21 02:32:29 +00:00
|
|
|
return ret;
|
|
|
|
|
}
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
|
|
|
|
|
ret = circbuf_init(&upper->timing, NULL, lower->nbuffer *
|
|
|
|
|
TIMING_BUF_ESIZE);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
{
|
|
|
|
|
circbuf_uninit(&upper->buffer);
|
|
|
|
|
nxrmutex_unlock(&upper->lock);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
2022-07-21 02:32:29 +00:00
|
|
|
}
|
|
|
|
|
|
2025-04-24 16:11:19 +08:00
|
|
|
smdebug(upper->name, "the number of write event is:%lu", envcount);
|
2020-11-12 18:40:37 +08:00
|
|
|
circbuf_overwrite(&upper->buffer, data, bytes);
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
sensor_generate_timing(upper, envcount);
|
2022-03-22 15:46:02 +08:00
|
|
|
list_for_every_entry(&upper->userlist, user, struct sensor_user_s, node)
|
2020-10-19 21:24:13 +08:00
|
|
|
{
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
if (sensor_is_updated(upper, user))
|
2022-03-22 15:46:02 +08:00
|
|
|
{
|
2024-05-09 21:37:21 +08:00
|
|
|
sensor_pollnotify_one(user, POLLIN, SENSOR_ROLE_RD);
|
2022-03-22 15:46:02 +08:00
|
|
|
}
|
2020-10-19 21:24:13 +08:00
|
|
|
}
|
|
|
|
|
|
2022-06-14 11:33:13 +08:00
|
|
|
nxrmutex_unlock(&upper->lock);
|
2022-03-11 17:05:47 +08:00
|
|
|
return bytes;
|
2020-10-19 21:24:13 +08:00
|
|
|
}
|
|
|
|
|
|
2020-11-04 11:23:39 +08:00
|
|
|
static void sensor_notify_event(FAR void *priv)
|
|
|
|
|
{
|
|
|
|
|
FAR struct sensor_upperhalf_s *upper = priv;
|
2022-03-22 15:46:02 +08:00
|
|
|
FAR struct sensor_user_s *user;
|
2020-11-04 11:23:39 +08:00
|
|
|
|
2022-06-14 11:33:13 +08:00
|
|
|
nxrmutex_lock(&upper->lock);
|
2022-03-22 15:46:02 +08:00
|
|
|
list_for_every_entry(&upper->userlist, user, struct sensor_user_s, node)
|
2020-11-04 11:23:39 +08:00
|
|
|
{
|
2024-05-09 21:37:21 +08:00
|
|
|
sensor_pollnotify_one(user, POLLIN, SENSOR_ROLE_RD);
|
2020-11-04 11:23:39 +08:00
|
|
|
}
|
|
|
|
|
|
2022-06-14 11:33:13 +08:00
|
|
|
nxrmutex_unlock(&upper->lock);
|
2020-11-04 11:23:39 +08:00
|
|
|
}
|
|
|
|
|
|
2020-10-19 21:24:13 +08:00
|
|
|
/****************************************************************************
|
|
|
|
|
* Public Functions
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
drivers/sensors/: Add coordinate conversion function
convert from body coordinate system to right-hand
coordinate system.
Example:
Compared to the standard coordinate system,
the x-axis and y-axis are interchanged and have opposite directions,
the z-axis remains normal.
body coordinate ----> right-hand coordinate
+x +y
| |
| |
| |
| |
-y<-------. .------>+x
/ /
/ /
/ /
/ /
+z +z
So for the above conversion, using "P3" to represent transformation relationships
The front is 1 0 2, which represents the y x z axis.
The standard order is 0 1 2, so y and x are interchanged.
The following -1 1 1 indicates the direction of the axis.
The standard is 1 1 1. Because the current y-axis is opposite to
the standard x-axis, it is -1.
static const struct sensor_axis_map_s g_remap_tbl[] =
{
{ 0, 1, 2, 1, 1, 1 }, /* P0 */
{ 1, 0, 2, 1, -1, 1 }, /* P1 */
{ 0, 1, 2, -1, -1, 1 }, /* P2 */
{ 1, 0, 2, -1, 1, 1 }, /* P3 */
{ 0, 1, 2, -1, 1, -1 }, /* P4 */
{ 1, 0, 2, -1, -1, -1 }, /* P5 */
{ 0, 1, 2, 1, -1, -1 }, /* P6 */
{ 1, 0, 2, 1, 1, -1 }, /* P7 */
};
you can call the function sensor_remap_vector_raw16 and pass P3 parameters
to perform the conversion.
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2021-12-31 11:15:28 +08:00
|
|
|
/****************************************************************************
|
|
|
|
|
* Name: sensor_remap_vector_raw16
|
|
|
|
|
*
|
|
|
|
|
* Description:
|
|
|
|
|
* This function remap the sensor data according to the place position on
|
|
|
|
|
* board. The value of place is determined base on g_remap_tbl.
|
|
|
|
|
*
|
|
|
|
|
* Input Parameters:
|
|
|
|
|
* in - A pointer to input data need remap.
|
|
|
|
|
* out - A pointer to output data.
|
|
|
|
|
* place - The place position of sensor on board,
|
|
|
|
|
* ex:SENSOR_BODY_COORDINATE_PX
|
|
|
|
|
*
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
void sensor_remap_vector_raw16(FAR const int16_t *in, FAR int16_t *out,
|
|
|
|
|
int place)
|
|
|
|
|
{
|
|
|
|
|
FAR const struct sensor_axis_map_s *remap;
|
|
|
|
|
int16_t tmp[3];
|
|
|
|
|
|
|
|
|
|
DEBUGASSERT(place < (sizeof(g_remap_tbl) / sizeof(g_remap_tbl[0])));
|
|
|
|
|
|
|
|
|
|
remap = &g_remap_tbl[place];
|
|
|
|
|
tmp[0] = in[remap->src_x] * remap->sign_x;
|
|
|
|
|
tmp[1] = in[remap->src_y] * remap->sign_y;
|
|
|
|
|
tmp[2] = in[remap->src_z] * remap->sign_z;
|
|
|
|
|
memcpy(out, tmp, sizeof(tmp));
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-19 21:24:13 +08:00
|
|
|
/****************************************************************************
|
|
|
|
|
* 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:
|
2020-11-02 18:02:04 +08:00
|
|
|
* 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.
|
|
|
|
|
* devno - The user specifies which device of this type, from 0. If the
|
2025-05-03 06:16:30 +02:00
|
|
|
* devno already exists, -EEXIST will be returned.
|
2020-10-19 21:24:13 +08:00
|
|
|
*
|
|
|
|
|
* Returned Value:
|
2026-05-28 15:57:27 +08:00
|
|
|
* OK if the driver was successfully registered; A negated errno value is
|
2020-10-19 21:24:13 +08:00
|
|
|
* returned on any failure.
|
|
|
|
|
*
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
2020-11-02 18:02:04 +08:00
|
|
|
int sensor_register(FAR struct sensor_lowerhalf_s *lower, int devno)
|
2020-10-19 21:24:13 +08:00
|
|
|
{
|
2024-10-09 12:14:18 +08:00
|
|
|
FAR char *path;
|
|
|
|
|
int ret;
|
2020-11-22 16:04:37 +08:00
|
|
|
|
|
|
|
|
DEBUGASSERT(lower != NULL);
|
|
|
|
|
|
2024-10-09 12:14:18 +08:00
|
|
|
path = lib_get_pathbuffer();
|
|
|
|
|
if (path == NULL)
|
|
|
|
|
{
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-29 11:39:44 +08:00
|
|
|
snprintf(path, PATH_MAX, DEVNAME_FMT,
|
2024-03-11 18:31:30 +08:00
|
|
|
g_sensor_meta[lower->type].name,
|
2020-11-22 16:04:37 +08:00
|
|
|
devno);
|
2024-10-09 12:14:18 +08:00
|
|
|
ret = sensor_custom_register(lower, path,
|
|
|
|
|
g_sensor_meta[lower->type].esize);
|
|
|
|
|
lib_put_pathbuffer(path);
|
|
|
|
|
return ret;
|
2020-11-22 16:04:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
|
* Name: sensor_custom_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.
|
|
|
|
|
*
|
|
|
|
|
* You can register the character device type by specific path and esize.
|
|
|
|
|
* This API corresponds to the sensor_custom_unregister.
|
|
|
|
|
*
|
|
|
|
|
* 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.
|
2022-08-08 13:42:03 +08:00
|
|
|
* path - The user specifies path of device. ex: /dev/uorb/xxx.
|
2020-11-22 16:04:37 +08:00
|
|
|
* esize - The element size of intermediate circular buffer.
|
|
|
|
|
*
|
|
|
|
|
* Returned Value:
|
2026-05-28 15:57:27 +08:00
|
|
|
* OK if the driver was successfully registered; A negated errno value is
|
2020-11-22 16:04:37 +08:00
|
|
|
* returned on any failure.
|
|
|
|
|
*
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
int sensor_custom_register(FAR struct sensor_lowerhalf_s *lower,
|
2024-06-28 23:35:55 +08:00
|
|
|
FAR const char *path, size_t esize)
|
2020-11-22 16:04:37 +08:00
|
|
|
{
|
|
|
|
|
FAR struct sensor_upperhalf_s *upper;
|
2020-10-19 21:24:13 +08:00
|
|
|
int ret = -EINVAL;
|
|
|
|
|
|
|
|
|
|
DEBUGASSERT(lower != NULL);
|
|
|
|
|
|
2020-11-22 16:04:37 +08:00
|
|
|
if (lower->type >= SENSOR_TYPE_COUNT || !esize)
|
2020-10-19 21:24:13 +08:00
|
|
|
{
|
2020-11-22 16:04:37 +08:00
|
|
|
snerr("ERROR: type is invalid\n");
|
2020-10-19 21:24:13 +08:00
|
|
|
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 */
|
|
|
|
|
|
2022-03-22 15:46:02 +08:00
|
|
|
list_initialize(&upper->userlist);
|
2022-03-23 17:09:46 +08:00
|
|
|
upper->state.esize = esize;
|
2024-06-28 23:35:55 +08:00
|
|
|
upper->state.min_interval = UINT32_MAX;
|
2025-05-15 12:30:49 +08:00
|
|
|
upper->state.nonwakeup = true;
|
2022-03-22 15:46:02 +08:00
|
|
|
if (lower->ops->activate)
|
|
|
|
|
{
|
|
|
|
|
upper->state.nadvertisers = 1;
|
|
|
|
|
}
|
2020-10-19 21:24:13 +08:00
|
|
|
|
2022-06-14 11:33:13 +08:00
|
|
|
nxrmutex_init(&upper->lock);
|
2020-10-19 21:24:13 +08:00
|
|
|
|
|
|
|
|
/* Bind the lower half data structure member */
|
|
|
|
|
|
2022-06-23 12:13:56 +08:00
|
|
|
lower->priv = upper;
|
|
|
|
|
lower->sensor_lock = sensor_lock;
|
|
|
|
|
lower->sensor_unlock = sensor_unlock;
|
2020-10-19 21:24:13 +08:00
|
|
|
|
2020-11-04 11:23:39 +08:00
|
|
|
if (!lower->ops->fetch)
|
|
|
|
|
{
|
2022-03-23 17:09:46 +08:00
|
|
|
if (!lower->nbuffer)
|
2020-11-22 16:04:37 +08:00
|
|
|
{
|
2022-03-23 17:09:46 +08:00
|
|
|
lower->nbuffer = 1;
|
2020-11-04 11:23:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lower->push_event = sensor_push_event;
|
|
|
|
|
}
|
|
|
|
|
else
|
2020-10-19 21:24:13 +08:00
|
|
|
{
|
2020-11-04 11:23:39 +08:00
|
|
|
lower->notify_event = sensor_notify_event;
|
2022-03-23 17:09:46 +08:00
|
|
|
lower->nbuffer = 0;
|
2020-10-19 21:24:13 +08:00
|
|
|
}
|
|
|
|
|
|
2022-04-08 22:46:29 +08:00
|
|
|
#ifdef CONFIG_SENSORS_RPMSG
|
|
|
|
|
lower = sensor_rpmsg_register(lower, path);
|
|
|
|
|
if (lower == NULL)
|
|
|
|
|
{
|
|
|
|
|
ret = -EIO;
|
2024-04-30 10:01:30 +08:00
|
|
|
goto rpmsg_err;
|
2022-04-08 22:46:29 +08:00
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2025-04-24 16:11:19 +08:00
|
|
|
strlcpy(upper->name, basename((char *)path), sizeof(upper->name));
|
2022-06-14 11:44:24 +08:00
|
|
|
upper->state.nbuffer = lower->nbuffer;
|
2022-04-08 22:46:29 +08:00
|
|
|
upper->lower = lower;
|
2025-04-24 16:11:19 +08:00
|
|
|
sminfo(upper->name, "Registering %s", path);
|
2026-07-14 20:40:10 -04:00
|
|
|
ret = register_driver(path, &g_sensor_fops, 0600, upper);
|
2022-06-14 11:44:24 +08:00
|
|
|
if (ret)
|
|
|
|
|
{
|
|
|
|
|
goto drv_err;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-19 21:24:13 +08:00
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
drv_err:
|
2024-04-30 10:01:30 +08:00
|
|
|
#ifdef CONFIG_SENSORS_RPMSG
|
|
|
|
|
sensor_rpmsg_unregister(lower);
|
|
|
|
|
rpmsg_err:
|
|
|
|
|
#endif
|
|
|
|
|
|
2022-06-14 11:33:13 +08:00
|
|
|
nxrmutex_destroy(&upper->lock);
|
2020-10-19 21:24:13 +08:00
|
|
|
|
|
|
|
|
kmm_free(upper);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
|
* Name: sensor_unregister
|
|
|
|
|
*
|
|
|
|
|
* Description:
|
|
|
|
|
* This function unregister character node and release all resource about
|
|
|
|
|
* upper half driver.
|
|
|
|
|
*
|
|
|
|
|
* Input Parameters:
|
2020-11-02 18:02:04 +08:00
|
|
|
* 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.
|
|
|
|
|
* devno - The user specifies which device of this type, from 0.
|
2024-11-14 15:08:08 +01:00
|
|
|
*
|
2020-10-19 21:24:13 +08:00
|
|
|
****************************************************************************/
|
|
|
|
|
|
2020-11-02 18:02:04 +08:00
|
|
|
void sensor_unregister(FAR struct sensor_lowerhalf_s *lower, int devno)
|
2020-10-19 21:24:13 +08:00
|
|
|
{
|
2024-10-09 12:14:18 +08:00
|
|
|
FAR char *path;
|
|
|
|
|
|
|
|
|
|
path = lib_get_pathbuffer();
|
|
|
|
|
if (path == NULL)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-10-19 21:24:13 +08:00
|
|
|
|
2022-03-29 11:39:44 +08:00
|
|
|
snprintf(path, PATH_MAX, DEVNAME_FMT,
|
2024-03-11 18:31:30 +08:00
|
|
|
g_sensor_meta[lower->type].name,
|
2020-11-22 16:04:37 +08:00
|
|
|
devno);
|
|
|
|
|
sensor_custom_unregister(lower, path);
|
2024-10-09 12:14:18 +08:00
|
|
|
lib_put_pathbuffer(path);
|
2020-11-22 16:04:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
|
* Name: sensor_custom_unregister
|
|
|
|
|
*
|
|
|
|
|
* Description:
|
|
|
|
|
* This function unregister character node and release all resource about
|
|
|
|
|
* upper half driver. This API corresponds to the sensor_custom_register.
|
|
|
|
|
*
|
|
|
|
|
* 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.
|
2022-08-08 13:42:03 +08:00
|
|
|
* path - The user specifies path of device, ex: /dev/uorb/xxx
|
2024-11-14 15:08:08 +01:00
|
|
|
*
|
2020-11-22 16:04:37 +08:00
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
void sensor_custom_unregister(FAR struct sensor_lowerhalf_s *lower,
|
|
|
|
|
FAR const char *path)
|
|
|
|
|
{
|
|
|
|
|
FAR struct sensor_upperhalf_s *upper;
|
|
|
|
|
|
2020-10-19 21:24:13 +08:00
|
|
|
DEBUGASSERT(lower != NULL);
|
|
|
|
|
DEBUGASSERT(lower->priv != NULL);
|
|
|
|
|
|
|
|
|
|
upper = lower->priv;
|
|
|
|
|
|
2025-04-24 16:11:19 +08:00
|
|
|
sminfo(upper->name, "UnRegistering");
|
2020-10-19 21:24:13 +08:00
|
|
|
unregister_driver(path);
|
|
|
|
|
|
2022-04-08 22:46:29 +08:00
|
|
|
#ifdef CONFIG_SENSORS_RPMSG
|
|
|
|
|
sensor_rpmsg_unregister(lower);
|
|
|
|
|
#endif
|
|
|
|
|
|
2022-06-14 11:33:13 +08:00
|
|
|
nxrmutex_destroy(&upper->lock);
|
2022-03-22 15:46:02 +08:00
|
|
|
if (circbuf_is_init(&upper->buffer))
|
|
|
|
|
{
|
|
|
|
|
circbuf_uninit(&upper->buffer);
|
nuttx/dirvers/sensor: down-sampling 2.0
1. about interval:
If interval is not set, generation is increased by 1 along with
publish and copy, multi-copy is continuous.
If interval is set, pick proper samples from buffer based on
mainline/user generation, multi-copy is one-by-one.
2. about bufferpos:
user->bufferpos always point to next position to check.
data user last read
----------v--------------------------
| | | |
-------------------^-----------------
bufferpos
If buffer is full, bufferpos point to buffer.head
Examples:
If a buffer contains 4 samples, newest generatoin is 40.
-------------------------------------
|10 |20 |30 |40
------------------------------^------
|
if user's next generation is 42, notify user to copy No.40 sample,
because 42 is closer to 40 than 50.
-------------------------------------
|10 |20 |30 |40
----------------------------------^--
|
if user's next generation is 48, do not notify user,
because 48 is closer to 50, which is next mainline sample.
Signed-off-by: jihandong <jihandong@xiaomi.com>
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2022-05-11 13:49:39 +08:00
|
|
|
circbuf_uninit(&upper->timing);
|
2022-03-22 15:46:02 +08:00
|
|
|
}
|
2020-10-19 21:24:13 +08:00
|
|
|
|
|
|
|
|
kmm_free(upper);
|
|
|
|
|
}
|