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
bmp581_encode_channel(enum sensor_channel chan)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
bmp581_encode(const struct device * dev,const struct sensor_read_config * read_config,uint8_t trigger_status,uint8_t * buf)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 edata->header.fifo_count = data->stream.fifo_thres;
53 } else {
54 const struct sensor_chan_spec *const channels = read_config->channels;
55 size_t num_channels = read_config->count;
56
57 for (size_t i = 0; i < num_channels; i++) {
58 edata->header.channels |= bmp581_encode_channel(channels[i].chan_type);
59 }
60 }
61
62 err = sensor_clock_get_cycles(&cycles);
63 if (err != 0) {
64 return err;
65 }
66
67 edata->header.events = trigger_status;
68 edata->header.timestamp = sensor_clock_cycles_to_ns(cycles);
69
70 return 0;
71 }
72
bmp581_decoder_get_frame_count(const uint8_t * buffer,struct sensor_chan_spec chan_spec,uint16_t * frame_count)73 static int bmp581_decoder_get_frame_count(const uint8_t *buffer,
74 struct sensor_chan_spec chan_spec,
75 uint16_t *frame_count)
76 {
77 const struct bmp581_encoded_data *edata = (const struct bmp581_encoded_data *)buffer;
78
79 if (chan_spec.chan_idx != 0) {
80 return -ENOTSUP;
81 }
82
83 uint8_t channel_request = bmp581_encode_channel(chan_spec.chan_type);
84
85 /* Filter unknown channels and having no data */
86 if ((edata->header.channels & channel_request) != channel_request) {
87 return -ENODATA;
88 }
89
90 if (edata->header.events & BMP581_EVENT_FIFO_WM) {
91 *frame_count = edata->header.fifo_count;
92 } else {
93 *frame_count = 1;
94 }
95 return 0;
96 }
97
bmp581_decoder_get_size_info(struct sensor_chan_spec chan_spec,size_t * base_size,size_t * frame_size)98 static int bmp581_decoder_get_size_info(struct sensor_chan_spec chan_spec,
99 size_t *base_size,
100 size_t *frame_size)
101 {
102 switch (chan_spec.chan_type) {
103 case SENSOR_CHAN_AMBIENT_TEMP:
104 case SENSOR_CHAN_PRESS:
105 *base_size = sizeof(struct sensor_q31_data);
106 *frame_size = sizeof(struct sensor_q31_sample_data);
107 return 0;
108 default:
109 return -ENOTSUP;
110 }
111 }
112
bmp581_convert_raw_to_q31_value(const struct bmp581_encoded_header * header,struct sensor_chan_spec * chan_spec,const struct bmp581_frame * frame,uint32_t * fit,struct sensor_q31_data * out)113 static int bmp581_convert_raw_to_q31_value(const struct bmp581_encoded_header *header,
114 struct sensor_chan_spec *chan_spec,
115 const struct bmp581_frame *frame,
116 uint32_t *fit,
117 struct sensor_q31_data *out)
118 {
119 if (((header->events & BMP581_EVENT_FIFO_WM) != 0 && *fit >= header->fifo_count) ||
120 ((header->events & BMP581_EVENT_FIFO_WM) == 0 && *fit != 0)) {
121 return -ENODATA;
122 }
123
124 switch (chan_spec->chan_type) {
125 case SENSOR_CHAN_AMBIENT_TEMP: {
126 /* Temperature is in data[2:0], data[2] is integer part */
127 uint32_t raw_temp = ((uint32_t)frame[*fit].payload[2] << 16) |
128 ((uint16_t)frame[*fit].payload[1] << 8) |
129 frame[*fit].payload[0];
130 int32_t raw_temp_signed = sign_extend(raw_temp, 23);
131
132 out->shift = (31 - 16); /* 16 left shifts gives us the value in celsius */
133 out->readings[*fit].value = raw_temp_signed;
134 break;
135 }
136 case SENSOR_CHAN_PRESS: {
137 if (!header->press_en) {
138 return -ENODATA;
139 }
140 /* Shift by 10 bits because we'll divide by 1000 to make it kPa */
141 uint64_t raw_press = (((uint32_t)frame[*fit].payload[5] << 16) |
142 ((uint16_t)frame[*fit].payload[4] << 8) |
143 frame[*fit].payload[3]);
144
145 int64_t raw_press_signed = sign_extend_64(raw_press, 23);
146
147 raw_press_signed *= 1024;
148 raw_press_signed /= 1000;
149
150 /* Original value was in Pa by left-shifting 6 spaces, but
151 * we've multiplied by 2^10 to not lose precision when
152 * converting to kPa. Hence, left-shift 16 spaces.
153 */
154 out->shift = (31 - 6 - 10);
155 out->readings[*fit].value = (int32_t)raw_press_signed;
156 break;
157 }
158 default:
159 return -EINVAL;
160 }
161
162 *fit = (*fit) + 1;
163 return 0;
164 }
165
bmp581_decoder_decode(const uint8_t * buffer,struct sensor_chan_spec chan_spec,uint32_t * fit,uint16_t max_count,void * data_out)166 static int bmp581_decoder_decode(const uint8_t *buffer,
167 struct sensor_chan_spec chan_spec,
168 uint32_t *fit,
169 uint16_t max_count,
170 void *data_out)
171 {
172 const struct bmp581_encoded_data *edata = (const struct bmp581_encoded_data *)buffer;
173 uint8_t channel_request;
174
175 if (max_count == 0 || chan_spec.chan_idx != 0) {
176 return -EINVAL;
177 }
178
179 channel_request = bmp581_encode_channel(chan_spec.chan_type);
180 if ((channel_request & edata->header.channels) != channel_request) {
181 return -ENODATA;
182 }
183
184 struct sensor_q31_data *out = data_out;
185
186 out->header.base_timestamp_ns = edata->header.timestamp;
187
188 int err;
189 uint32_t fit_0 = *fit;
190
191 do {
192 err = bmp581_convert_raw_to_q31_value(&edata->header, &chan_spec,
193 edata->frame, fit, out);
194 } while (err == 0 && *fit < max_count);
195
196 if (*fit == fit_0 || err != 0) {
197 return err;
198 }
199
200 out->header.reading_count = *fit;
201 return *fit - fit_0;
202 }
203
bmp581_decoder_has_trigger(const uint8_t * buffer,enum sensor_trigger_type trigger)204 static bool bmp581_decoder_has_trigger(const uint8_t *buffer, enum sensor_trigger_type trigger)
205 {
206 const struct bmp581_encoded_data *edata = (const struct bmp581_encoded_data *)buffer;
207
208 if ((trigger == SENSOR_TRIG_DATA_READY &&
209 edata->header.events & BMP581_EVENT_DRDY) ||
210 (trigger == SENSOR_TRIG_FIFO_WATERMARK &&
211 edata->header.events & BMP581_EVENT_FIFO_WM)) {
212 return true;
213 }
214
215 return false;
216 }
217
218 SENSOR_DECODER_API_DT_DEFINE() = {
219 .get_frame_count = bmp581_decoder_get_frame_count,
220 .get_size_info = bmp581_decoder_get_size_info,
221 .decode = bmp581_decoder_decode,
222 .has_trigger = bmp581_decoder_has_trigger,
223 };
224
bmp581_get_decoder(const struct device * dev,const struct sensor_decoder_api ** decoder)225 int bmp581_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder)
226 {
227 ARG_UNUSED(dev);
228 *decoder = &SENSOR_DECODER_NAME();
229 return 0;
230 }
231