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