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/byteorder.h>
10 
11 #include "paa3905.h"
12 #include "paa3905_reg.h"
13 #include "paa3905_decoder.h"
14 
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_REGISTER(PAA3905_DECODER, CONFIG_SENSOR_LOG_LEVEL);
17 
18 #define DT_DRV_COMPAT pixart_paa3905
19 
paa3905_encode_channel(enum sensor_channel chan)20 uint8_t paa3905_encode_channel(enum sensor_channel chan)
21 {
22 	switch (chan) {
23 	case SENSOR_CHAN_POS_DX:
24 		return BIT(0);
25 	case SENSOR_CHAN_POS_DY:
26 		return BIT(1);
27 	case SENSOR_CHAN_POS_DXYZ:
28 		return BIT(2);
29 	default:
30 		return 0;
31 	}
32 }
33 
is_data_valid(const struct paa3905_encoded_data * edata)34 static bool is_data_valid(const struct paa3905_encoded_data *edata)
35 {
36 	uint8_t squal_min;
37 	uint32_t shutter_max;
38 	uint32_t shutter;
39 
40 	if (!REG_MOTION_DETECTED(edata->motion)) {
41 		LOG_WRN("Invalid data - No motion detected");
42 		return false;
43 	}
44 
45 	if (REG_MOTION_CHALLENGING_COND(edata->motion)) {
46 		LOG_WRN("Invalid data - Challenging conditions");
47 		return false;
48 	}
49 
50 	switch (REG_OBSERVATION_MODE(edata->observation)) {
51 	case OBSERVATION_MODE_BRIGHT:
52 		squal_min = SQUAL_MIN_BRIGHT;
53 		shutter_max = SHUTTER_MAX_BRIGHT;
54 		break;
55 	case OBSERVATION_MODE_LOW_LIGHT:
56 		squal_min = SQUAL_MIN_LOW_LIGHT;
57 		shutter_max = SHUTTER_MAX_LOW_LIGHT;
58 		break;
59 	case OBSERVATION_MODE_SUPER_LOW_LIGHT:
60 		squal_min = SQUAL_MIN_SUPER_LOW_LIGHT;
61 		shutter_max = SHUTTER_MAX_SUPER_LOW_LIGHT;
62 		break;
63 	default:
64 		LOG_ERR("Invalid op mode");
65 		return false;
66 	}
67 
68 	shutter = sys_be24_to_cpu(edata->shutter);
69 
70 	if (edata->squal < squal_min || shutter >= shutter_max) {
71 		LOG_WRN("Invalid data - mode: %d squal: 0x%02X shutter: 0x%06X",
72 			(uint8_t)REG_OBSERVATION_MODE(edata->observation), edata->squal, shutter);
73 
74 		return false;
75 	}
76 
77 	return true;
78 }
79 
paa3905_decoder_get_frame_count(const uint8_t * buffer,struct sensor_chan_spec chan_spec,uint16_t * frame_count)80 static int paa3905_decoder_get_frame_count(const uint8_t *buffer,
81 					   struct sensor_chan_spec chan_spec,
82 					   uint16_t *frame_count)
83 {
84 	struct paa3905_encoded_data *edata = (struct paa3905_encoded_data *)buffer;
85 
86 	if (chan_spec.chan_idx != 0) {
87 		return -ENOTSUP;
88 	}
89 
90 	uint8_t channel_request = paa3905_encode_channel(chan_spec.chan_type);
91 
92 	if (((edata->header.channels & channel_request) != channel_request) ||
93 	    !is_data_valid(edata)) {
94 		return -ENODATA;
95 	}
96 
97 	switch (chan_spec.chan_type) {
98 	case SENSOR_CHAN_POS_DX:
99 	case SENSOR_CHAN_POS_DY:
100 	case SENSOR_CHAN_POS_DXYZ:
101 		*frame_count = 1;
102 		return 0;
103 	default:
104 		return -ENOTSUP;
105 	}
106 
107 	return -1;
108 }
109 
paa3905_decoder_get_size_info(struct sensor_chan_spec chan_spec,size_t * base_size,size_t * frame_size)110 static int paa3905_decoder_get_size_info(struct sensor_chan_spec chan_spec,
111 					 size_t *base_size,
112 					 size_t *frame_size)
113 {
114 	switch (chan_spec.chan_type) {
115 	case SENSOR_CHAN_POS_DX:
116 	case SENSOR_CHAN_POS_DY:
117 		*base_size = sizeof(struct sensor_q31_data);
118 		*frame_size = sizeof(struct sensor_q31_sample_data);
119 		return 0;
120 	case SENSOR_CHAN_POS_DXYZ:
121 		*base_size = sizeof(struct sensor_three_axis_data);
122 		*frame_size = sizeof(struct sensor_three_axis_data);
123 		return 0;
124 	default:
125 		return -ENOTSUP;
126 	}
127 }
128 
paa3905_decoder_decode(const uint8_t * buffer,struct sensor_chan_spec chan_spec,uint32_t * fit,uint16_t max_count,void * data_out)129 static int paa3905_decoder_decode(const uint8_t *buffer,
130 				  struct sensor_chan_spec chan_spec,
131 				  uint32_t *fit,
132 				  uint16_t max_count,
133 				  void *data_out)
134 {
135 	struct paa3905_encoded_data *edata = (struct paa3905_encoded_data *)buffer;
136 	uint8_t channel_request;
137 
138 	if (*fit != 0) {
139 		return 0;
140 	}
141 
142 	if (max_count == 0 || chan_spec.chan_idx != 0) {
143 		return -EINVAL;
144 	}
145 
146 	switch (chan_spec.chan_type) {
147 	case SENSOR_CHAN_POS_DX:
148 	case SENSOR_CHAN_POS_DY: {
149 		channel_request = paa3905_encode_channel(chan_spec.chan_type);
150 		if (((edata->header.channels & channel_request) != channel_request) ||
151 		    !is_data_valid(edata)) {
152 			LOG_ERR("No data available");
153 			return -ENODATA;
154 		}
155 
156 		struct sensor_q31_data *out = (struct sensor_q31_data *)data_out;
157 
158 		out->header.base_timestamp_ns = edata->header.timestamp;
159 		out->header.reading_count = 1;
160 		out->shift = 31;
161 
162 		out->readings->value = (chan_spec.chan_type == SENSOR_CHAN_POS_DX) ?
163 				       edata->delta.x :
164 				       edata->delta.y;
165 
166 		*fit = 1;
167 		return 1;
168 	}
169 	case SENSOR_CHAN_POS_DXYZ: {
170 		channel_request = paa3905_encode_channel(chan_spec.chan_type);
171 		if (((edata->header.channels & channel_request) != channel_request) ||
172 		    !is_data_valid(edata)) {
173 			LOG_ERR("No data available");
174 			return -ENODATA;
175 		}
176 
177 		struct sensor_three_axis_data *out = (struct sensor_three_axis_data *)data_out;
178 
179 		out->header.base_timestamp_ns = edata->header.timestamp;
180 		out->header.reading_count = 1;
181 		out->shift = 31;
182 
183 		out->readings[0].x = edata->delta.x;
184 		out->readings[0].y = edata->delta.y;
185 		out->readings[0].z = 0;
186 
187 		*fit = 1;
188 		return 1;
189 	}
190 	default:
191 		return -EINVAL;
192 	}
193 
194 	return -1;
195 }
196 
paa3905_decoder_has_trigger(const uint8_t * buffer,enum sensor_trigger_type trigger)197 static bool paa3905_decoder_has_trigger(const uint8_t *buffer, enum sensor_trigger_type trigger)
198 {
199 	struct paa3905_encoded_data *edata = (struct paa3905_encoded_data *)buffer;
200 
201 	switch (trigger) {
202 	case SENSOR_TRIG_DATA_READY:
203 		return edata->header.events.drdy;
204 	case SENSOR_TRIG_MOTION:
205 		return edata->header.events.motion;
206 	default:
207 		return false;
208 	}
209 }
210 
211 SENSOR_DECODER_API_DT_DEFINE() = {
212 	.get_frame_count = paa3905_decoder_get_frame_count,
213 	.get_size_info = paa3905_decoder_get_size_info,
214 	.decode = paa3905_decoder_decode,
215 	.has_trigger = paa3905_decoder_has_trigger,
216 };
217 
paa3905_get_decoder(const struct device * dev,const struct sensor_decoder_api ** decoder)218 int paa3905_get_decoder(const struct device *dev,
219 	const struct sensor_decoder_api **decoder)
220 {
221 	ARG_UNUSED(dev);
222 	*decoder = &SENSOR_DECODER_NAME();
223 
224 	return 0;
225 }
226 
paa3905_encode(const struct device * dev,const struct sensor_chan_spec * const channels,size_t num_channels,uint8_t * buf)227 int paa3905_encode(const struct device *dev,
228 		   const struct sensor_chan_spec *const channels,
229 		   size_t num_channels,
230 		   uint8_t *buf)
231 {
232 	struct paa3905_encoded_data *edata = (struct paa3905_encoded_data *)buf;
233 	uint64_t cycles;
234 	int err;
235 
236 	edata->header.channels = 0;
237 	edata->header.events.drdy = false;
238 	edata->header.events.motion = false;
239 
240 	for (size_t i = 0 ; i < num_channels; i++) {
241 		edata->header.channels |= paa3905_encode_channel(channels[i].chan_type);
242 	}
243 
244 	err = sensor_clock_get_cycles(&cycles);
245 	if (err != 0) {
246 		return err;
247 	}
248 
249 	edata->header.timestamp = sensor_clock_cycles_to_ns(cycles);
250 
251 	return 0;
252 }
253