input_pipeline/light_sensor/
light_sensor_binding.rs1use super::types::Rgbc;
6use crate::input_device::{
7 self, Handled, InputDeviceBinding, InputDeviceDescriptor, InputDeviceStatus, InputEvent,
8};
9use crate::metrics;
10use anyhow::{Error, format_err};
11use async_trait::async_trait;
12use derivative::Derivative;
13use fidl_next_fuchsia_input_report::{InputReport, SensorType};
14use fuchsia_inspect::health::Reporter;
15use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
16use metrics_registry::*;
17
18#[derive(Derivative, Clone)]
19#[derivative(Debug)]
20pub struct LightSensorEvent {
21 #[derivative(Debug = "ignore")]
22 pub(crate) device_proxy:
23 fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, crate::Transport>,
24 pub(crate) rgbc: Rgbc<u16>,
25}
26
27impl PartialEq for LightSensorEvent {
28 fn eq(&self, other: &Self) -> bool {
29 self.rgbc == other.rgbc
30 }
31}
32
33impl Eq for LightSensorEvent {}
34
35impl LightSensorEvent {
36 pub fn record_inspect(&self, node: &fuchsia_inspect::Node) {
37 node.record_uint("red", u64::from(self.rgbc.red));
38 node.record_uint("green", u64::from(self.rgbc.green));
39 node.record_uint("blue", u64::from(self.rgbc.blue));
40 node.record_uint("clear", u64::from(self.rgbc.clear));
41 }
42}
43
44pub(crate) struct LightSensorBinding {
48 event_sender: UnboundedSender<Vec<InputEvent>>,
50
51 device_descriptor: LightSensorDeviceDescriptor,
53}
54
55#[derive(Copy, Clone, Debug, Eq, PartialEq)]
56pub struct LightSensorDeviceDescriptor {
57 pub(crate) vendor_id: u32,
59
60 pub(crate) product_id: u32,
62
63 pub(crate) device_id: u32,
65
66 pub(crate) sensor_layout: Rgbc<usize>,
68}
69
70#[async_trait]
71impl InputDeviceBinding for LightSensorBinding {
72 fn input_event_sender(&self) -> UnboundedSender<Vec<InputEvent>> {
73 self.event_sender.clone()
74 }
75
76 fn get_device_descriptor(&self) -> InputDeviceDescriptor {
77 InputDeviceDescriptor::LightSensor(self.device_descriptor.clone())
78 }
79}
80
81impl LightSensorBinding {
82 pub(crate) async fn new(
97 device_proxy: fidl_next::Client<
98 fidl_next_fuchsia_input_report::InputDevice,
99 crate::Transport,
100 >,
101 device_id: u32,
102 input_event_sender: UnboundedSender<Vec<InputEvent>>,
103 device_node: fuchsia_inspect::Node,
104 feature_flags: input_device::InputPipelineFeatureFlags,
105 metrics_logger: metrics::MetricsLogger,
106 ) -> Result<Self, Error> {
107 let (device_binding, mut inspect_status) = Self::bind_device(
108 &device_proxy,
109 device_id,
110 input_event_sender,
111 device_node,
112 metrics_logger.clone(),
113 )
114 .await?;
115 inspect_status.health_node.set_ok();
116 input_device::initialize_report_stream(
117 device_proxy.clone(),
118 device_binding.get_device_descriptor(),
119 device_binding.input_event_sender(),
120 inspect_status,
121 metrics_logger,
122 feature_flags,
123 move |report,
124 previous_report,
125 device_descriptor,
126 input_event_sender,
127 inspect_status,
128 metrics_logger,
129 _feature_flags| {
130 Self::process_reports(
131 report,
132 previous_report,
133 device_descriptor,
134 input_event_sender,
135 device_proxy.clone(),
136 inspect_status,
137 metrics_logger,
138 )
139 },
140 );
141
142 Ok(device_binding)
143 }
144
145 async fn bind_device(
157 device: &fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, crate::Transport>,
158 device_id: u32,
159 input_event_sender: UnboundedSender<Vec<InputEvent>>,
160 device_node: fuchsia_inspect::Node,
161 metrics_logger: metrics::MetricsLogger,
162 ) -> Result<(Self, InputDeviceStatus), Error> {
163 let mut input_device_status = InputDeviceStatus::new(device_node);
164 let descriptor = match device.get_descriptor().await {
165 Ok(descriptor) => descriptor.descriptor,
166 Err(_) => {
167 input_device_status.health_node.set_unhealthy("Could not get device descriptor.");
168 return Err(format_err!("Could not get descriptor for device_id: {}", device_id));
169 }
170 };
171 let device_info = descriptor.device_information.ok_or_else(|| {
172 input_device_status.health_node.set_unhealthy("Empty device_info in descriptor.");
173 metrics_logger.log_error(
176 InputPipelineErrorMetricDimensionEvent::LightEmptyDeviceInfo,
177 std::format!("DRIVER BUG: empty device_info for device_id: {}", device_id),
178 );
179 format_err!("empty device info for device_id: {}", device_id)
180 })?;
181 match descriptor.sensor {
182 Some(fidl_next_fuchsia_input_report::SensorDescriptor {
183 input: Some(input_descriptors),
184 ..
185 }) => {
186 let sensor_layout = input_descriptors
187 .into_iter()
188 .filter_map(|input_descriptor| {
189 input_descriptor.values.and_then(|values| {
190 let mut red_value = None;
191 let mut green_value = None;
192 let mut blue_value = None;
193 let mut clear_value = None;
194 for (i, value) in values.iter().enumerate() {
195 let old = match value.type_ {
196 SensorType::LightRed => {
197 std::mem::replace(&mut red_value, Some(i))
198 }
199 SensorType::LightGreen => {
200 std::mem::replace(&mut green_value, Some(i))
201 }
202 SensorType::LightBlue => {
203 std::mem::replace(&mut blue_value, Some(i))
204 }
205 SensorType::LightIlluminance => {
206 std::mem::replace(&mut clear_value, Some(i))
207 }
208 type_ => {
209 log::warn!(
210 "unexpected sensor type {type_:?} found on light \
211 sensor device"
212 );
213 None
214 }
215 };
216 if old.is_some() {
217 log::warn!(
218 "existing index for light sensor {:?} replaced",
219 value.type_
220 );
221 }
222 }
223
224 red_value.and_then(|red| {
225 green_value.and_then(|green| {
226 blue_value.and_then(|blue| {
227 clear_value.map(|clear| Rgbc { red, green, blue, clear })
228 })
229 })
230 })
231 })
232 })
233 .next()
234 .ok_or_else(|| {
235 input_device_status.health_node.set_unhealthy("Missing light sensor data.");
236 format_err!("missing sensor data in device")
237 })?;
238 Ok((
239 LightSensorBinding {
240 event_sender: input_event_sender,
241 device_descriptor: LightSensorDeviceDescriptor {
242 vendor_id: device_info.vendor_id.unwrap_or_default(),
243 product_id: device_info.product_id.unwrap_or_default(),
244 device_id,
245 sensor_layout,
246 },
247 },
248 input_device_status,
249 ))
250 }
251 device_descriptor => {
252 input_device_status
253 .health_node
254 .set_unhealthy("Light Sensor Device Descriptor failed to parse.");
255 Err(format_err!(
256 "Light Sensor Device Descriptor failed to parse: \n {:?}",
257 device_descriptor
258 ))
259 }
260 }
261 }
262
263 fn process_reports(
282 reports: Vec<InputReport>,
283 mut previous_report: Option<InputReport>,
284 device_descriptor: &input_device::InputDeviceDescriptor,
285 input_event_sender: &mut UnboundedSender<Vec<InputEvent>>,
286 device_proxy: fidl_next::Client<
287 fidl_next_fuchsia_input_report::InputDevice,
288 crate::Transport,
289 >,
290 inspect_status: &InputDeviceStatus,
291 metrics_logger: &metrics::MetricsLogger,
292 ) -> (Option<InputReport>, Option<UnboundedReceiver<InputEvent>>) {
293 fuchsia_trace::duration!("input", "light-sensor-binding-process-reports", "num_reports" => reports.len());
294 for report in reports {
295 previous_report = Self::process_report(
296 report,
297 previous_report,
298 device_descriptor,
299 input_event_sender,
300 device_proxy.clone(),
301 inspect_status,
302 metrics_logger,
303 );
304 }
305 (previous_report, None)
306 }
307
308 fn process_report(
309 report: InputReport,
310 previous_report: Option<InputReport>,
311 device_descriptor: &input_device::InputDeviceDescriptor,
312 input_event_sender: &mut UnboundedSender<Vec<InputEvent>>,
313 device_proxy: fidl_next::Client<
314 fidl_next_fuchsia_input_report::InputDevice,
315 crate::Transport,
316 >,
317 inspect_status: &InputDeviceStatus,
318 metrics_logger: &metrics::MetricsLogger,
319 ) -> Option<InputReport> {
320 if let Some(trace_id) = report.trace_id {
321 fuchsia_trace::flow_end!("input", "input_report", trace_id.into());
322 }
323
324 inspect_status.count_received_report(&report);
325 let light_sensor_descriptor =
326 if let input_device::InputDeviceDescriptor::LightSensor(light_sensor_descriptor) =
327 device_descriptor
328 {
329 light_sensor_descriptor
330 } else {
331 unreachable!()
332 };
333
334 let sensor = match &report.sensor {
336 None => {
337 inspect_status.count_filtered_report();
338 return previous_report;
339 }
340 Some(sensor) => sensor,
341 };
342
343 let values = match &sensor.values {
344 None => {
345 inspect_status.count_filtered_report();
346 return None;
347 }
348 Some(values) => values,
349 };
350
351 let event = input_device::InputEvent {
352 device_event: input_device::InputDeviceEvent::LightSensor(LightSensorEvent {
353 device_proxy,
354 rgbc: Rgbc {
355 red: values[light_sensor_descriptor.sensor_layout.red] as u16,
356 green: values[light_sensor_descriptor.sensor_layout.green] as u16,
357 blue: values[light_sensor_descriptor.sensor_layout.blue] as u16,
358 clear: values[light_sensor_descriptor.sensor_layout.clear] as u16,
359 },
360 }),
361 device_descriptor: device_descriptor.clone(),
362 event_time: zx::MonotonicInstant::get(),
363 handled: Handled::No,
364 trace_id: None,
365 };
366
367 if let Err(e) = input_event_sender.unbounded_send(vec![event.clone()]) {
368 metrics_logger.log_error(
369 InputPipelineErrorMetricDimensionEvent::LightFailedToSendEvent,
370 std::format!("Failed to send LightSensorEvent with error: {e:?}"),
371 );
372 } else {
373 inspect_status.count_generated_event(event);
374 }
375
376 Some(report)
377 }
378}