1use core::marker::PhantomData;
2
3use crc16::MCRF4XX;
4use embedded_hal_async::{digital::Wait, i2c::I2c};
5
6use crate::{Face, PersonID, MAX_DETECTIONS};
7
8const PERSON_SENSOR_I2C_ADDRESS: u8 = 0x62;
9
10#[repr(u8)]
11pub(crate) enum PersonSensorMode {
12 Standby = 0x00,
14 Continuous = 0x01,
16}
17
18#[derive(Debug, PartialEq, Eq, Clone, Copy)]
20#[repr(u8)]
21pub enum IDMode {
22 LabelAndLocation = 0x01,
27 LocationOnly = 0x00,
31}
32
33#[derive(Debug, PartialEq, Eq, Clone, Copy)]
34pub enum ReadError<E> {
35 ChecksumMismatch,
36 I2CError(E),
37}
38
39impl<E> From<E> for ReadError<E> {
40 fn from(error: E) -> Self {
41 Self::I2CError(error)
42 }
43}
44
45pub struct ContinuousCaptureMode;
46pub struct StandbyMode;
47
48#[derive(Debug)]
78pub struct PersonSensor<I2C, INT, MODE> {
79 pub(crate) i2c: I2C,
80 pub(crate) interrupt: INT,
81 pub(crate) mode: PhantomData<MODE>,
82 pub(crate) validate_checksum: bool,
83}
84
85impl<I2C, INT, MODE> PersonSensor<I2C, INT, MODE>
86where
87 I2C: I2c,
88{
89 async fn latest_results(
91 &mut self,
92 ) -> Result<heapless::Vec<Face, MAX_DETECTIONS>, ReadError<I2C::Error>> {
93 let mut buffer = [0u8; 39];
94 self.i2c
95 .read(PERSON_SENSOR_I2C_ADDRESS, &mut buffer)
96 .await?;
97
98 if self.validate_checksum {
99 let checksum = crc16::State::<MCRF4XX>::calculate(&buffer[..37]);
100 if u16::from_le_bytes([buffer[37], buffer[38]]) != checksum {
101 return Err(ReadError::<I2C::Error>::ChecksumMismatch);
102 }
103 }
104
105 let mut faces = heapless::Vec::<Face, MAX_DETECTIONS>::new();
106
107 let num_faces = buffer[4];
108
109 #[expect(clippy::cast_possible_wrap)]
110 for face_num in 0..num_faces {
111 let face_start_offset = 5 + face_num as usize * 8;
112
113 let id_confidence = buffer[face_start_offset + 5] as i8;
114 let person_id = match id_confidence {
115 0 => None,
116 _ => Some(PersonID::new_unchecked(buffer[face_start_offset + 6])),
117 };
118
119 let face = Face {
120 box_confidence: buffer[face_start_offset],
121 box_left: buffer[face_start_offset + 1],
122 box_top: buffer[face_start_offset + 2],
123 box_right: buffer[face_start_offset + 3],
124 box_bottom: buffer[face_start_offset + 4],
125 id_confidence,
126 id: person_id,
127 is_facing: buffer[face_start_offset + 7] > 0,
128 };
129
130 match faces.push(face) {
131 Ok(()) => {}
132 Err(_) => break,
133 };
134 }
135
136 Ok(faces)
137 }
138
139 pub(crate) async fn set_mode(&mut self, mode: PersonSensorMode) -> Result<(), I2C::Error> {
141 self.i2c
142 .write(PERSON_SENSOR_I2C_ADDRESS, &[0x01, mode as u8])
143 .await
144 }
145
146 pub async fn set_id_mode(&mut self, mode: IDMode) -> Result<(), I2C::Error> {
148 self.i2c
149 .write(PERSON_SENSOR_I2C_ADDRESS, &[0x02, mode as u8])
150 .await
151 }
152
153 #[deprecated(
157 since = "0.3.1",
158 note = "Please use `set_id_mode` instead. This method will be removed in a future release."
159 )]
160 pub async fn enable_id_model(&mut self, enable: bool) -> Result<(), I2C::Error> {
161 self.i2c
162 .write(PERSON_SENSOR_I2C_ADDRESS, &[0x02, u8::from(enable)])
163 .await
164 }
165
166 pub fn set_checksum_enabled(&mut self, enable: bool) {
171 self.validate_checksum = enable;
172 }
173
174 pub async fn label_next_id(&mut self, id: PersonID) -> Result<(), I2C::Error> {
181 self.i2c
182 .write(PERSON_SENSOR_I2C_ADDRESS, &[0x04, id.into()])
183 .await
184 }
185
186 pub async fn set_persist_ids(&mut self, persist: bool) -> Result<(), I2C::Error> {
190 self.i2c
191 .write(PERSON_SENSOR_I2C_ADDRESS, &[0x05, u8::from(persist)])
192 .await
193 }
194
195 pub async fn erase_ids(&mut self) -> Result<(), I2C::Error> {
197 self.i2c
198 .write(PERSON_SENSOR_I2C_ADDRESS, &[0x06, 0x00])
199 .await
200 }
201
202 pub async fn set_indicator(&mut self, enabled: bool) -> Result<(), I2C::Error> {
204 self.i2c
205 .write(PERSON_SENSOR_I2C_ADDRESS, &[0x07, u8::from(enabled)])
206 .await
207 }
208}
209
210impl<I2C, INT> PersonSensor<I2C, INT, StandbyMode>
211where
212 I2C: I2c,
213{
214 pub async fn capture_once(
216 &mut self,
217 ) -> Result<heapless::Vec<Face, MAX_DETECTIONS>, ReadError<I2C::Error>> {
218 self.i2c
219 .write(PERSON_SENSOR_I2C_ADDRESS, &[0x03, 0x00])
220 .await?;
221
222 self.latest_results().await
223 }
224
225 pub async fn into_continuous_mode(
227 self,
228 ) -> Result<PersonSensor<I2C, INT, ContinuousCaptureMode>, I2C::Error> {
229 let mut sensor = self;
230 sensor.set_mode(PersonSensorMode::Continuous).await?;
231 Ok(PersonSensor {
232 i2c: sensor.i2c,
233 interrupt: sensor.interrupt,
234 mode: PhantomData,
235 validate_checksum: sensor.validate_checksum,
236 })
237 }
238}
239
240impl<I2C, INT> PersonSensor<I2C, INT, ContinuousCaptureMode>
241where
242 I2C: I2c,
243{
244 pub async fn into_standby_mode(
247 self,
248 ) -> Result<PersonSensor<I2C, INT, StandbyMode>, I2C::Error> {
249 let mut sensor = self;
250 sensor.set_mode(PersonSensorMode::Standby).await?;
251 Ok(PersonSensor {
252 i2c: sensor.i2c,
253 interrupt: sensor.interrupt,
254 mode: PhantomData,
255 validate_checksum: sensor.validate_checksum,
256 })
257 }
258
259 pub async fn get_detections(
269 &mut self,
270 ) -> Result<heapless::Vec<Face, MAX_DETECTIONS>, ReadError<I2C::Error>> {
271 self.latest_results().await
272 }
273}
274
275impl<I2C, INT> PersonSensor<I2C, INT, ContinuousCaptureMode>
276where
277 INT: Wait,
278{
279 pub async fn wait_for_person(&mut self) -> Result<(), INT::Error> {
282 self.interrupt.wait_for_high().await
283 }
284}