Skip to content

Commit 6da536e

Browse files
committed
bmp581: Add One-shot Read-Decode support
Decoding one-shot reads through submit API. Signed-off-by: Luis Ubieda <luisf@croxel.com>
1 parent 6e5a7df commit 6da536e

File tree

4 files changed

+332
-0
lines changed

4 files changed

+332
-0
lines changed

drivers/sensor/bosch/bmp581/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,6 @@ zephyr_library_sources(
1010
bmp581.c
1111
bmp581_bus.c
1212
)
13+
zephyr_library_sources_ifdef(CONFIG_SENSOR_ASYNC_API
14+
bmp581_decoder.c
15+
)

drivers/sensor/bosch/bmp581/bmp581.c

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include "bmp581.h"
99
#include "bmp581_bus.h"
10+
#include "bmp581_decoder.h"
1011

1112
#include <math.h>
1213

@@ -586,10 +587,106 @@ static int bmp581_init(const struct device *dev)
586587
return ret;
587588
}
588589

590+
#ifdef CONFIG_SENSOR_ASYNC_API
591+
592+
static void bmp581_complete_result(struct rtio *ctx, const struct rtio_sqe *sqe, void *arg)
593+
{
594+
struct rtio_iodev_sqe *iodev_sqe = (struct rtio_iodev_sqe *)arg;
595+
struct rtio_cqe *cqe;
596+
int err = 0;
597+
598+
do {
599+
cqe = rtio_cqe_consume(ctx);
600+
if (cqe != NULL) {
601+
err = cqe->result;
602+
rtio_cqe_release(ctx, cqe);
603+
}
604+
} while (cqe != NULL);
605+
606+
if (err != 0) {
607+
rtio_iodev_sqe_err(iodev_sqe, err);
608+
} else {
609+
rtio_iodev_sqe_ok(iodev_sqe, 0);
610+
}
611+
}
612+
613+
static void bmp581_submit_one_shot(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe)
614+
{
615+
const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data;
616+
uint32_t min_buf_len = sizeof(struct bmp581_encoded_data);
617+
int err;
618+
uint8_t *buf;
619+
uint32_t buf_len;
620+
struct bmp581_encoded_data *edata;
621+
const struct bmp581_config *conf = dev->config;
622+
623+
err = rtio_sqe_rx_buf(iodev_sqe, min_buf_len, min_buf_len, &buf, &buf_len);
624+
CHECKIF((err < 0) || (buf_len < min_buf_len) || !buf) {
625+
LOG_ERR("Failed to get a read buffer of size %u bytes", min_buf_len);
626+
rtio_iodev_sqe_err(iodev_sqe, err);
627+
return;
628+
}
629+
630+
edata = (struct bmp581_encoded_data *)buf;
631+
632+
err = bmp581_encode(dev, cfg, 0, buf);
633+
if (err != 0) {
634+
LOG_ERR("Failed to encode sensor data");
635+
rtio_iodev_sqe_err(iodev_sqe, err);
636+
return;
637+
}
638+
639+
struct rtio_sqe *read_sqe;
640+
641+
err = bmp581_prep_reg_read_rtio_async(&conf->bus, BMP5_REG_TEMP_DATA_XLSB,
642+
edata->payload, sizeof(edata->payload),
643+
&read_sqe);
644+
if (err < 0) {
645+
LOG_ERR("Failed to prepare async read operation");
646+
rtio_iodev_sqe_err(iodev_sqe, err);
647+
return;
648+
}
649+
read_sqe->flags |= RTIO_SQE_CHAINED;
650+
651+
struct rtio_sqe *complete_sqe = rtio_sqe_acquire(conf->bus.rtio.ctx);
652+
653+
if (!complete_sqe) {
654+
LOG_ERR("Failed to acquire completion SQE");
655+
rtio_iodev_sqe_err(iodev_sqe, -ENOMEM);
656+
rtio_sqe_drop_all(conf->bus.rtio.ctx);
657+
return;
658+
}
659+
660+
rtio_sqe_prep_callback_no_cqe(complete_sqe,
661+
bmp581_complete_result,
662+
iodev_sqe,
663+
(void *)dev);
664+
665+
rtio_submit(conf->bus.rtio.ctx, 0);
666+
}
667+
668+
static void bmp581_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe)
669+
{
670+
const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data;
671+
672+
if (!cfg->is_streaming) {
673+
bmp581_submit_one_shot(dev, iodev_sqe);
674+
} else {
675+
LOG_ERR("Streaming not supported");
676+
rtio_iodev_sqe_err(iodev_sqe, -ENOTSUP);
677+
}
678+
}
679+
680+
#endif /* #ifdef CONFIG_SENSOR_ASYNC_API */
681+
589682
static DEVICE_API(sensor, bmp581_driver_api) = {
590683
.sample_fetch = bmp581_sample_fetch,
591684
.channel_get = bmp581_channel_get,
592685
.attr_set = bmp581_attr_set,
686+
#ifdef CONFIG_SENSOR_ASYNC_API
687+
.submit = bmp581_submit,
688+
.get_decoder = bmp581_get_decoder,
689+
#endif
593690
};
594691

595692
#define BMP581_INIT(i) \
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
/*
2+
* Copyright (c) 2025 Croxel, Inc.
3+
* Copyright (c) 2025 CogniPilot Foundation
4+
*
5+
* SPDX-License-Identifier: Apache-2.0
6+
*/
7+
8+
#include <zephyr/drivers/sensor_clock.h>
9+
#include <zephyr/sys/util.h>
10+
#include "bmp581.h"
11+
#include "bmp581_decoder.h"
12+
13+
#include <zephyr/logging/log.h>
14+
LOG_MODULE_REGISTER(BMP581_DECODER, CONFIG_SENSOR_LOG_LEVEL);
15+
16+
static uint8_t bmp581_encode_channel(enum sensor_channel chan)
17+
{
18+
uint8_t encode_bmask = 0;
19+
20+
switch (chan) {
21+
case SENSOR_CHAN_AMBIENT_TEMP:
22+
encode_bmask |= BIT(0);
23+
break;
24+
case SENSOR_CHAN_PRESS:
25+
encode_bmask |= BIT(1);
26+
break;
27+
case SENSOR_CHAN_ALL:
28+
encode_bmask |= BIT(0) | BIT(1);
29+
break;
30+
default:
31+
break;
32+
}
33+
34+
return encode_bmask;
35+
}
36+
37+
int bmp581_encode(const struct device *dev,
38+
const struct sensor_read_config *read_config,
39+
uint8_t trigger_status,
40+
uint8_t *buf)
41+
{
42+
struct bmp581_encoded_data *edata = (struct bmp581_encoded_data *)buf;
43+
struct bmp581_data *data = dev->data;
44+
uint64_t cycles;
45+
int err;
46+
47+
edata->header.channels = 0;
48+
edata->header.press_en = data->osr_odr_press_config.press_en;
49+
50+
if (trigger_status) {
51+
edata->header.channels |= bmp581_encode_channel(SENSOR_CHAN_ALL);
52+
} else {
53+
const struct sensor_chan_spec *const channels = read_config->channels;
54+
size_t num_channels = read_config->count;
55+
56+
for (size_t i = 0; i < num_channels; i++) {
57+
edata->header.channels |= bmp581_encode_channel(channels[i].chan_type);
58+
}
59+
}
60+
61+
err = sensor_clock_get_cycles(&cycles);
62+
if (err != 0) {
63+
return err;
64+
}
65+
66+
edata->header.events = trigger_status ? BIT(0) : 0;
67+
edata->header.timestamp = sensor_clock_cycles_to_ns(cycles);
68+
69+
return 0;
70+
}
71+
72+
static int bmp581_decoder_get_frame_count(const uint8_t *buffer,
73+
struct sensor_chan_spec chan_spec,
74+
uint16_t *frame_count)
75+
{
76+
const struct bmp581_encoded_data *edata = (const struct bmp581_encoded_data *)buffer;
77+
78+
if (chan_spec.chan_idx != 0) {
79+
return -ENOTSUP;
80+
}
81+
82+
uint8_t channel_request = bmp581_encode_channel(chan_spec.chan_type);
83+
84+
/* Filter unknown channels and having no data */
85+
if ((edata->header.channels & channel_request) != channel_request) {
86+
return -ENODATA;
87+
}
88+
89+
*frame_count = 1;
90+
return 0;
91+
}
92+
93+
static int bmp581_decoder_get_size_info(struct sensor_chan_spec chan_spec,
94+
size_t *base_size,
95+
size_t *frame_size)
96+
{
97+
switch (chan_spec.chan_type) {
98+
case SENSOR_CHAN_AMBIENT_TEMP:
99+
case SENSOR_CHAN_PRESS:
100+
*base_size = sizeof(struct sensor_q31_data);
101+
*frame_size = sizeof(struct sensor_q31_sample_data);
102+
return 0;
103+
default:
104+
return -ENOTSUP;
105+
}
106+
}
107+
108+
static int bmp581_decoder_decode(const uint8_t *buffer,
109+
struct sensor_chan_spec chan_spec,
110+
uint32_t *fit,
111+
uint16_t max_count,
112+
void *data_out)
113+
{
114+
const struct bmp581_encoded_data *edata = (const struct bmp581_encoded_data *)buffer;
115+
uint8_t channel_request;
116+
117+
if (*fit != 0) {
118+
return 0;
119+
}
120+
121+
if (max_count == 0 || chan_spec.chan_idx != 0) {
122+
return -EINVAL;
123+
}
124+
125+
channel_request = bmp581_encode_channel(chan_spec.chan_type);
126+
if ((channel_request & edata->header.channels) != channel_request) {
127+
return -ENODATA;
128+
}
129+
130+
struct sensor_q31_data *out = data_out;
131+
132+
out->header.base_timestamp_ns = edata->header.timestamp;
133+
out->header.reading_count = 1;
134+
135+
switch (chan_spec.chan_type) {
136+
case SENSOR_CHAN_AMBIENT_TEMP: {
137+
/* Temperature is in data[2:0], data[2] is integer part */
138+
uint32_t raw_temp = ((uint32_t)edata->payload[2] << 16) |
139+
((uint16_t)edata->payload[1] << 8) |
140+
edata->payload[0];
141+
int32_t raw_temp_signed = sign_extend(raw_temp, 23);
142+
143+
out->shift = (31 - 16); /* 16 left shifts gives us the value in celsius */
144+
out->readings[0].value = raw_temp_signed;
145+
break;
146+
}
147+
case SENSOR_CHAN_PRESS:
148+
if (!edata->header.press_en) {
149+
return -ENODATA;
150+
}
151+
/* Shift by 10 bits because we'll divide by 1000 to make it kPa */
152+
uint64_t raw_press = (((uint32_t)edata->payload[5] << 16) |
153+
((uint16_t)edata->payload[4] << 8) |
154+
edata->payload[3]);
155+
156+
int64_t raw_press_signed = sign_extend_64(raw_press, 23);
157+
158+
raw_press_signed *= 1024;
159+
raw_press_signed /= 1000;
160+
161+
/* Original value was in Pa by left-shifting 6 spaces, but
162+
* we've multiplied by 2^10 to not lose precision when
163+
* converting to kPa. Hence, left-shift 16 spaces.
164+
*/
165+
out->shift = (31 - 6 - 10);
166+
out->readings[0].value = (int32_t)raw_press_signed;
167+
break;
168+
default:
169+
return -EINVAL;
170+
}
171+
172+
*fit = 1;
173+
return 1;
174+
}
175+
176+
static bool bmp581_decoder_has_trigger(const uint8_t *buffer, enum sensor_trigger_type trigger)
177+
{
178+
const struct bmp581_encoded_data *edata = (const struct bmp581_encoded_data *)buffer;
179+
180+
if ((trigger == SENSOR_TRIG_DATA_READY) && (edata->header.events != 0)) {
181+
return true;
182+
}
183+
184+
return false;
185+
}
186+
187+
SENSOR_DECODER_API_DT_DEFINE() = {
188+
.get_frame_count = bmp581_decoder_get_frame_count,
189+
.get_size_info = bmp581_decoder_get_size_info,
190+
.decode = bmp581_decoder_decode,
191+
.has_trigger = bmp581_decoder_has_trigger,
192+
};
193+
194+
int bmp581_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder)
195+
{
196+
ARG_UNUSED(dev);
197+
*decoder = &SENSOR_DECODER_NAME();
198+
return 0;
199+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright (c) 2025 Croxel, Inc.
3+
* Copyright (c) 2025 CogniPilot Foundation
4+
*
5+
* SPDX-License-Identifier: Apache-2.0
6+
*/
7+
8+
#ifndef ZEPHYR_DRIVERS_SENSOR_BMP581_DECODER_H_
9+
#define ZEPHYR_DRIVERS_SENSOR_BMP581_DECODER_H_
10+
11+
#include <stdint.h>
12+
#include <zephyr/drivers/sensor.h>
13+
#include "bmp581.h"
14+
15+
struct bmp581_encoded_data {
16+
struct {
17+
uint8_t channels;
18+
uint8_t events;
19+
uint64_t timestamp;
20+
uint8_t press_en;
21+
} header;
22+
uint8_t payload[6]; /* 3 bytes temp + 3 bytes press */
23+
};
24+
25+
int bmp581_encode(const struct device *dev,
26+
const struct sensor_read_config *read_config,
27+
uint8_t trigger_status,
28+
uint8_t *buf);
29+
30+
int bmp581_get_decoder(const struct device *dev,
31+
const struct sensor_decoder_api **decoder);
32+
33+
#endif /* ZEPHYR_DRIVERS_SENSOR_BMP581_DECODER_H_ */

0 commit comments

Comments
 (0)