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