Skip to content

Commit 025687a

Browse files
Yuval Peressyperess
authored andcommitted
sensors: fetch/get API alternative
Proof of concept for how to deprecate the fetch/get APIs by creating a single function that would handle converting a legacy request to an RTIO request and block while the request is processing. Signed-off-by: Yuval Peress <[email protected]>
1 parent 76b510c commit 025687a

File tree

5 files changed

+349
-150
lines changed

5 files changed

+349
-150
lines changed

drivers/sensor/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ config SENSOR_ASYNC_API
2727
select RTIO_SYS_MEM_BLOCKS
2828
select RTIO_CONSUME_SEM
2929
select RTIO_WORKQ
30+
default y
3031
help
3132
Enables the asynchronous sensor API by leveraging the RTIO subsystem.
3233

drivers/sensor/default_rtio_sensor.c

Lines changed: 212 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,178 @@
1010
#include <zephyr/drivers/sensor.h>
1111
#include <zephyr/drivers/sensor_clock.h>
1212
#include <zephyr/dsp/types.h>
13+
#include <zephyr/kernel.h>
1314
#include <zephyr/logging/log.h>
1415
#include <zephyr/rtio/work.h>
1516

1617
LOG_MODULE_REGISTER(sensor_compat, CONFIG_SENSOR_LOG_LEVEL);
1718

19+
static struct sensor_chan_spec default_channels[16];
20+
static struct sensor_read_config default_blocking_read_config = {
21+
.channels = default_channels,
22+
.max = ARRAY_SIZE(default_channels),
23+
};
24+
RTIO_IODEV_DEFINE(default_blocking_read_rtio_dev, &__sensor_iodev_api,
25+
&default_blocking_read_config);
26+
RTIO_DEFINE(default_blocking_rtio, 4, 4);
27+
K_MUTEX_DEFINE(blocking_rtio_mutex);
28+
1829
/*
1930
* Ensure that the size of the generic header aligns with the sensor channel specifier . If it
2031
* doesn't, then cores that require aligned memory access will fail to read channel[0].
2132
*/
2233
BUILD_ASSERT((sizeof(struct sensor_data_generic_header) % sizeof(struct sensor_chan_spec)) == 0);
2334

35+
static void append_q31_value(size_t idx, int8_t *shift, q31_t *values, size_t num_values,
36+
q31_t new_value, int8_t new_shift)
37+
{
38+
if (idx == 0 || *shift == new_shift) {
39+
*shift = new_shift;
40+
values[idx] = new_value;
41+
return;
42+
}
43+
if (new_shift < *shift) {
44+
/* Need to shift new_value */
45+
new_value >>= (*shift - new_shift);
46+
values[idx] = new_value;
47+
return;
48+
}
49+
/* Need to shift all the old values */
50+
for (size_t i = 0; i < idx; ++i) {
51+
values[i] >>= (new_shift - *shift);
52+
}
53+
values[idx] = new_value;
54+
*shift = new_shift;
55+
}
56+
57+
int sensor_read_and_decode(const struct device *dev, struct sensor_chan_spec *channels,
58+
size_t num_channels, int8_t *shift, q31_t *values, size_t num_values)
59+
{
60+
static uint8_t read_buffer[128];
61+
static uint8_t decode_buffer[128 + sizeof(uintptr_t) - 1];
62+
const struct sensor_decoder_api *decoder;
63+
int rc;
64+
65+
k_mutex_lock(&blocking_rtio_mutex, K_FOREVER);
66+
67+
rc = sensor_reconfigure_read_iodev(&default_blocking_read_rtio_dev, dev, channels,
68+
num_channels);
69+
70+
if (rc != 0) {
71+
LOG_ERR("Failed to reconfigure RTIO device");
72+
k_mutex_unlock(&blocking_rtio_mutex);
73+
return rc;
74+
}
75+
76+
rc = sensor_read(&default_blocking_read_rtio_dev, &default_blocking_rtio, read_buffer,
77+
sizeof(read_buffer));
78+
if (rc != 0) {
79+
LOG_ERR("Failed to read RTIO device");
80+
k_mutex_unlock(&blocking_rtio_mutex);
81+
return rc;
82+
}
83+
84+
rc = sensor_get_decoder(dev, &decoder);
85+
if (rc != 0) {
86+
LOG_ERR("Failed to get decoder");
87+
k_mutex_unlock(&blocking_rtio_mutex);
88+
return rc;
89+
}
90+
91+
size_t value_idx = 0;
92+
93+
for (size_t channel_idx = 0; channel_idx < num_channels && value_idx < num_values;
94+
++channel_idx) {
95+
size_t base_size;
96+
size_t frame_size;
97+
uint16_t frame_count;
98+
uint32_t fit = 0;
99+
100+
rc = decoder->get_frame_count(read_buffer, channels[channel_idx], &frame_count);
101+
if (rc != 0) {
102+
LOG_ERR("Failed to get frame count");
103+
k_mutex_unlock(&blocking_rtio_mutex);
104+
return rc;
105+
}
106+
107+
if (frame_count == 0) {
108+
LOG_ERR("Data missing for channel %d", channels[channel_idx].chan_type);
109+
k_mutex_unlock(&blocking_rtio_mutex);
110+
return -ENODATA;
111+
}
112+
113+
if (frame_count > 1) {
114+
LOG_WRN("Too much data for a one shot read, some frames will be skipped");
115+
}
116+
117+
rc = decoder->get_size_info(channels[channel_idx], &base_size, &frame_size);
118+
if (rc != 0) {
119+
LOG_ERR("Failed to get decode size requirements");
120+
k_mutex_unlock(&blocking_rtio_mutex);
121+
return rc;
122+
}
123+
124+
if (base_size + frame_size > sizeof(decode_buffer)) {
125+
LOG_ERR("Decoded size is too big");
126+
k_mutex_unlock(&blocking_rtio_mutex);
127+
return -ENOMEM;
128+
}
129+
130+
size_t alignment;
131+
void *aligned_decode_buffer;
132+
133+
if (SENSOR_CHANNEL_3_AXIS(channels[channel_idx].chan_type)) {
134+
alignment = _Alignof(struct sensor_three_axis_data);
135+
} else {
136+
alignment = _Alignof(struct sensor_q31_data);
137+
}
138+
139+
aligned_decode_buffer = (void *)ROUND_UP((uintptr_t)decode_buffer, alignment);
140+
141+
rc = decoder->decode(read_buffer, channels[channel_idx], &fit, 1,
142+
aligned_decode_buffer);
143+
if (rc <= 0) {
144+
LOG_ERR("Failed to decode frame");
145+
k_mutex_unlock(&blocking_rtio_mutex);
146+
return rc;
147+
}
148+
149+
switch (channels[channel_idx].chan_type) {
150+
case SENSOR_CHAN_ACCEL_XYZ:
151+
case SENSOR_CHAN_GYRO_XYZ:
152+
case SENSOR_CHAN_MAGN_XYZ: {
153+
struct sensor_three_axis_data *data =
154+
(struct sensor_three_axis_data *)aligned_decode_buffer;
155+
156+
LOG_DBG("Adding 3 entries for channel %d", channels[channel_idx].chan_type);
157+
append_q31_value(value_idx++, shift, values, num_values,
158+
data->readings[0].values[0], data->shift);
159+
append_q31_value(value_idx++, shift, values, num_values,
160+
data->readings[0].values[1], data->shift);
161+
append_q31_value(value_idx++, shift, values, num_values,
162+
data->readings[0].values[2], data->shift);
163+
break;
164+
}
165+
default: {
166+
struct sensor_q31_data *data =
167+
(struct sensor_q31_data *)aligned_decode_buffer;
168+
169+
LOG_DBG("Adding 1 entry for channel %d", channels[channel_idx].chan_type);
170+
append_q31_value(value_idx++, shift, values, num_values,
171+
data->readings[0].value, data->shift);
172+
break;
173+
}
174+
}
175+
}
176+
if (value_idx > num_values) {
177+
LOG_ERR("Wrote too many values, %zu / %zu", value_idx, num_values);
178+
k_mutex_unlock(&blocking_rtio_mutex);
179+
return -ENOMEM;
180+
}
181+
k_mutex_unlock(&blocking_rtio_mutex);
182+
return 0;
183+
}
184+
24185
static void sensor_submit_fallback(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe);
25186

26187
static void sensor_iodev_submit(struct rtio_iodev_sqe *iodev_sqe)
@@ -108,12 +269,7 @@ static inline int check_header_contains_channel(const struct sensor_data_generic
108269
return -1;
109270
}
110271

111-
/**
112-
* @brief Fallback function for retrofiting old drivers to rtio (sync)
113-
*
114-
* @param[in] iodev_sqe The read submission queue event
115-
*/
116-
static void sensor_submit_fallback_sync(struct rtio_iodev_sqe *iodev_sqe)
272+
void z_impl_sensor_submit_fallback_sync(struct rtio_iodev_sqe *iodev_sqe)
117273
{
118274
const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data;
119275
const struct device *dev = cfg->sensor;
@@ -134,15 +290,16 @@ static void sensor_submit_fallback_sync(struct rtio_iodev_sqe *iodev_sqe)
134290
uint8_t *buf;
135291
uint32_t buf_len;
136292

137-
rc = sensor_sample_fetch(dev);
293+
rc = z_impl_sensor_sample_fetch(dev);
138294
/* Check that the fetch succeeded */
139295
if (rc != 0) {
140296
LOG_WRN("Failed to fetch samples");
141297
rtio_iodev_sqe_err(iodev_sqe, rc);
142298
return;
143299
}
144300

145-
/* Get the buffer for the frame, it may be allocated dynamically by the rtio context */
301+
/* Get the buffer for the frame, it may be allocated dynamically by the rtio context
302+
*/
146303
rc = rtio_sqe_rx_buf(iodev_sqe, min_buf_len, min_buf_len, &buf, &buf_len);
147304
if (rc != 0) {
148305
LOG_WRN("Failed to get a read buffer of size %u bytes", min_buf_len);
@@ -165,26 +322,18 @@ static void sensor_submit_fallback_sync(struct rtio_iodev_sqe *iodev_sqe)
165322
const int num_samples = SENSOR_CHANNEL_3_AXIS(channels[i].chan_type) ? 3 : 1;
166323

167324
/* Get the current channel requested by the user */
168-
rc = sensor_channel_get(dev, channels[i].chan_type, value);
325+
rc = z_impl_sensor_channel_get(dev, channels[i].chan_type, value);
169326

170327
if (num_samples == 3) {
171-
header->channels[sample_idx++] = (struct sensor_chan_spec) {
172-
rc == 0 ? channels[i].chan_type - 3 : SENSOR_CHAN_MAX,
173-
0
174-
};
175-
header->channels[sample_idx++] = (struct sensor_chan_spec) {
176-
rc == 0 ? channels[i].chan_type - 2 : SENSOR_CHAN_MAX,
177-
0
178-
};
179-
header->channels[sample_idx++] = (struct sensor_chan_spec) {
180-
rc == 0 ? channels[i].chan_type - 1 : SENSOR_CHAN_MAX,
181-
0
182-
};
328+
header->channels[sample_idx++] = (struct sensor_chan_spec){
329+
rc == 0 ? channels[i].chan_type - 3 : SENSOR_CHAN_MAX, 0};
330+
header->channels[sample_idx++] = (struct sensor_chan_spec){
331+
rc == 0 ? channels[i].chan_type - 2 : SENSOR_CHAN_MAX, 0};
332+
header->channels[sample_idx++] = (struct sensor_chan_spec){
333+
rc == 0 ? channels[i].chan_type - 1 : SENSOR_CHAN_MAX, 0};
183334
} else {
184-
header->channels[sample_idx++] = (struct sensor_chan_spec) {
185-
rc == 0 ? channels[i].chan_type : SENSOR_CHAN_MAX,
186-
0
187-
};
335+
header->channels[sample_idx++] = (struct sensor_chan_spec){
336+
rc == 0 ? channels[i].chan_type : SENSOR_CHAN_MAX, 0};
188337
}
189338

190339
if (rc != 0) {
@@ -193,19 +342,20 @@ static void sensor_submit_fallback_sync(struct rtio_iodev_sqe *iodev_sqe)
193342
continue;
194343
}
195344

196-
/* Get the largest absolute value reading to set the scale for the channel */
345+
/* Get the largest absolute value reading to set the scale for the channel
346+
*/
197347
uint32_t header_scale = 0;
198348

199349
for (int sample = 0; sample < num_samples; ++sample) {
200350
/*
201351
* The scale is the ceil(abs(sample)).
202-
* Since we are using fractional values, it's easier to assume that .val2
203-
* is non 0 and convert this to abs(sample.val1) + 1 (removing a branch).
204-
* Since it's possible that val1 (int32_t) is saturated (INT32_MAX) we need
205-
* to upcast it to 64 bit int first, then take the abs() of that 64 bit
206-
* int before we '+ 1'. Once that's done, we can safely cast back down
207-
* to uint32_t because the min value is 0 and max is INT32_MAX + 1 which
208-
* is less than UINT32_MAX.
352+
* Since we are using fractional values, it's easier to assume that
353+
* .val2 is non 0 and convert this to abs(sample.val1) + 1 (removing
354+
* a branch). Since it's possible that val1 (int32_t) is saturated
355+
* (INT32_MAX) we need to upcast it to 64 bit int first, then take
356+
* the abs() of that 64 bit int before we '+ 1'. Once that's done,
357+
* we can safely cast back down to uint32_t because the min value is
358+
* 0 and max is INT32_MAX + 1 which is less than UINT32_MAX.
209359
*/
210360
uint32_t scale = (uint32_t)llabs((int64_t)value[sample].val1) + 1;
211361

@@ -218,9 +368,9 @@ static void sensor_submit_fallback_sync(struct rtio_iodev_sqe *iodev_sqe)
218368
sample_idx -= num_samples;
219369
if (header->shift < new_shift) {
220370
/*
221-
* Shift was updated, need to convert all the existing q values. This could
222-
* be optimized by calling zdsp_scale_q31() but that would force a
223-
* dependency between sensors and the zDSP subsystem.
371+
* Shift was updated, need to convert all the existing q values.
372+
* This could be optimized by calling zdsp_scale_q31() but that
373+
* would force a dependency between sensors and the zDSP subsystem.
224374
*/
225375
for (int q_idx = 0; q_idx < sample_idx; ++q_idx) {
226376
q[q_idx] = q[q_idx] >> (new_shift - header->shift);
@@ -230,8 +380,8 @@ static void sensor_submit_fallback_sync(struct rtio_iodev_sqe *iodev_sqe)
230380

231381
/*
232382
* Spread the q31 values. This is needed because some channels are 3D. If
233-
* the user specified one of those then num_samples will be 3; and we need to
234-
* produce 3 separate readings.
383+
* the user specified one of those then num_samples will be 3; and we need
384+
* to produce 3 separate readings.
235385
*/
236386
for (int sample = 0; sample < num_samples; ++sample) {
237387
/* Check if the channel is already in the buffer */
@@ -251,14 +401,15 @@ static void sensor_submit_fallback_sync(struct rtio_iodev_sqe *iodev_sqe)
251401
int64_t value_u = sensor_value_to_micro(&value[sample]);
252402

253403
/* Convert to q31 using the shift */
404+
254405
q[sample_idx + sample] =
255-
((value_u * ((INT64_C(1) << 31) - 1)) / 1000000) >> header->shift;
406+
((value_u * ((INT64_C(1) << (31 - header->shift)) - 1)) / 1000000);
256407

257-
LOG_DBG("value[%d]=%s%d.%06d, q[%d]@%p=%d, shift: %d",
258-
sample, value_u < 0 ? "-" : "",
259-
abs((int)value[sample].val1), abs((int)value[sample].val2),
260-
(int)(sample_idx + sample), (void *)&q[sample_idx + sample],
261-
q[sample_idx + sample], header->shift);
408+
LOG_DBG("value[%d]=%s%d.%06d, q[%d]@%p=%d, shift: %d", sample,
409+
value_u < 0 ? "-" : "", abs((int)value[sample].val1),
410+
abs((int)value[sample].val2), (int)(sample_idx + sample),
411+
(void *)&q[sample_idx + sample], q[sample_idx + sample],
412+
header->shift);
262413
}
263414
sample_idx += num_samples;
264415
}
@@ -332,8 +483,10 @@ static int get_frame_count(const uint8_t *buffer, struct sensor_chan_spec channe
332483
case SENSOR_CHAN_GYRO_XYZ:
333484
case SENSOR_CHAN_MAGN_XYZ:
334485
case SENSOR_CHAN_POS_DXYZ:
335-
for (size_t i = 0 ; i < header->num_channels; ++i) {
336-
/* For 3-axis channels, we need to verify we have each individual axis */
486+
for (size_t i = 0; i < header->num_channels; ++i) {
487+
/* For 3-axis channels, we need to verify we have each individual
488+
* axis
489+
*/
337490
struct sensor_chan_spec channel_x = {
338491
.chan_type = channel.chan_type - 3,
339492
.chan_idx = channel.chan_idx,
@@ -347,8 +500,8 @@ static int get_frame_count(const uint8_t *buffer, struct sensor_chan_spec channe
347500
.chan_idx = channel.chan_idx,
348501
};
349502

350-
/** The three axes don't need to be at the beginning of the header, but
351-
* they should be consecutive.
503+
/* The three axes don't need to be at the beginning of the header,
504+
* but they should be consecutive.
352505
*/
353506
if (((header->num_channels - i) >= 3) &&
354507
sensor_chan_spec_eq(header->channels[i], channel_x) &&
@@ -378,7 +531,7 @@ int sensor_natively_supported_channel_size_info(struct sensor_chan_spec channel,
378531
__ASSERT_NO_MSG(base_size != NULL);
379532
__ASSERT_NO_MSG(frame_size != NULL);
380533

381-
if (channel.chan_type >= SENSOR_CHAN_ALL) {
534+
if (channel.chan_type >= SENSOR_CHAN_MAX) {
382535
return -ENOTSUP;
383536
}
384537

@@ -480,19 +633,25 @@ static int decode_q31(const struct sensor_data_generic_header *header, const q31
480633
* @return >0 the number of decoded frames
481634
* @return <0 on error
482635
*/
483-
static int decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec,
484-
uint32_t *fit, uint16_t max_count, void *data_out)
636+
static int decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec, uint32_t *fit,
637+
uint16_t max_count, void *data_out)
485638
{
486639
const struct sensor_data_generic_header *header =
487640
(const struct sensor_data_generic_header *)buffer;
488641
const q31_t *q = (const q31_t *)(buffer + compute_header_size(header->num_channels));
489642
int count = 0;
490643

491-
if (*fit != 0 || max_count < 1) {
644+
if (*fit != 0) {
645+
LOG_ERR("Frame iterator MUST be 0");
646+
return -EINVAL;
647+
}
648+
if (max_count < 1) {
649+
LOG_ERR("max_count CANNOT be 0");
492650
return -EINVAL;
493651
}
494652

495-
if (chan_spec.chan_type >= SENSOR_CHAN_ALL) {
653+
if (chan_spec.chan_type >= SENSOR_CHAN_MAX) {
654+
LOG_WRN("Channe type too big");
496655
return 0;
497656
}
498657

0 commit comments

Comments
 (0)