person_sensor/lib.rs
1//! # Useful Things Person Sensor
2//!
3//! A small driver for the Useful Things Person Sensor.
4//!
5//! Original [developer guide](https://usfl.ink/ps_dev)
6//!
7//! This driver has been tested with v1.1 of the sensor, but should also work with v1 and v2.
8//! If you're able to validate the other board revisions, please open a PR to update this message :)
9//!
10//! ## Usage
11//!
12//! The sensor offers two modes: continuous and single shot.
13//! It can be converted between the two modes, and the compiler will prevent you from misusing
14//! functionality that is only available in a specific mode, or when an interrupt pin is provided.
15//!
16//! ```ignore
17//! use person_sensor::PersonSensorBuilder;
18//!
19//! let i2c = /* ... */;
20//! let interrupt_pin = /* ... */;
21//!
22//! // The driver can be initialized with or without the interrupt pin using the builder
23//! let mut person_sensor = PersonSensorBuilder::new_standby(i2c, true)
24//! .with_interrupt(interrupt_pin) // optional
25//! .build()
26//! .await
27//! .unwrap();
28//!
29//! let detections = person_sensor.capture_once().await.unwrap();
30//!
31//! // ERROR: an interrupt pin was provided, but person_sensor is in standby mode
32//! // person_sensor.wait_for_person().await.unwrap();
33//!
34//! // To use the functionality in continuous mode, convert the sensor like below,
35//! // or use the builder with new_continuous(...)
36//! let mut person_sensor = sensor.into_continuous_mode();
37//!
38//! // Now we meet all the requirements to wait for the next detection using the interrupt
39//! _ = person_sensor.wait_for_person().await.unwrap();
40//! // Read the latest detections.
41//! // Note wait_for_person() does not automatically read the detections
42//! let detections = person_sensor.get_detections().await.unwrap();
43//! ```
44//!
45//! ## Examples
46//!
47//! To run the examples on a pi pico, it should be sufficient to enter bootloader mode and run:
48//!
49//! ```bash
50//! cd examples
51//! cargo run --bin <example_name> --release
52//! ```
53
54#![no_std]
55
56mod person_sensor;
57mod person_sensor_builder;
58
59pub use person_sensor::IDMode;
60pub use person_sensor::PersonSensor;
61pub use person_sensor::ReadError;
62pub use person_sensor_builder::PersonSensorBuilder;
63
64/// The number of detections returned by the sensor.
65const MAX_DETECTIONS: usize = 4;
66
67#[repr(C, packed)]
68#[derive(Debug, Clone, PartialEq)]
69pub struct Face {
70 /// Confidence of the box prediction, ranges from 1 to 100.
71 pub box_confidence: u8,
72 pub box_left: u8,
73 pub box_top: u8,
74 pub box_right: u8,
75 pub box_bottom: u8,
76 /// The confidence of "calibrated" identities ranges from 1 to 100, and will be 0 or less if
77 /// this face is not recognized as any of the calibrated identities or is not the largest face
78 /// in the frame.
79 pub id_confidence: i8,
80 /// The ID number of the face, if it is recognized as any of the
81 /// calibrated identities *and* is the largest face in the frame.
82 /// By default, the sensor will not run any recognition until calibration has been performed.
83 /// After at least one person has been calibrated, the sensor will always run recognition on
84 /// the largest face present, and assign an ID number if it’s recognized as one that it has been calibrated on.
85 pub id: Option<PersonID>,
86 /// Indicates if somebody is looking directly at the device
87 /// > Note: ID works most reliably when the face is straight on to the sensor
88 pub is_facing: bool,
89}
90
91#[derive(Debug, Clone, Copy, PartialEq)]
92pub enum PersonIDError {
93 /// IDs can only range from 0 to 7.
94 InvalidId,
95}
96
97#[repr(transparent)]
98#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
99pub struct PersonID(u8);
100
101impl PersonID {
102 pub fn new(id: u8) -> Result<Self, PersonIDError> {
103 if id < 8 {
104 Ok(PersonID(id))
105 } else {
106 Err(PersonIDError::InvalidId)
107 }
108 }
109
110 /// Create a new person ID without checking the value
111 #[must_use]
112 pub fn new_unchecked(id: u8) -> Self {
113 PersonID(id)
114 }
115}
116
117impl TryFrom<u8> for PersonID {
118 type Error = PersonIDError;
119 fn try_from(value: u8) -> Result<Self, Self::Error> {
120 Self::new(value)
121 }
122}
123
124impl From<PersonID> for u8 {
125 fn from(id: PersonID) -> u8 {
126 id.0
127 }
128}