Skip to main content

lego_powered_up/iodevice/
visionsensor.rs

1//! Support for
2//! https://rebrickable.com/parts/26912/sensor-color-and-distance-powered-up-2-x-4-x-2/
3
4use async_trait::async_trait;
5use core::fmt::Debug;
6use tokio::sync::broadcast;
7use tokio::task::JoinHandle;
8
9use super::modes;
10use super::Basic;
11use crate::device_trait;
12use crate::error::Result;
13use crate::notifications::{
14    CompletionInfo, PortOutputSubcommand, StartupInfo,
15    WriteDirectModeDataPayload,
16};
17
18#[derive(Debug, Copy, Clone)]
19pub enum DetectedColor {
20    NoObject = -1,
21    Black = 0,
22    Color1 = 1,
23    Color2 = 2,
24    Blue = 3,
25    Color4 = 4,
26    Green = 5,
27    Color6 = 6,
28    Yellow = 7,
29    Color8 = 8,
30    Red = 9,
31    White = 10,
32}
33#[derive(Debug, Copy, Clone)]
34pub enum OutputColor {
35    Off = 0,
36    Blue = 3,
37    Green = 5,
38    Red = 9,
39    White = 10,
40}
41
42device_trait!(VisionSensor, [
43    async fn visionsensor_color(
44        &self,
45    ) -> Result<(broadcast::Receiver<DetectedColor>, JoinHandle<()>)> {
46        self.device_mode(modes::VisionSensor::COLOR, 1, true).await?;
47        let port_id = self.port();
48
49        // Set up channel
50        let (tx, rx) = broadcast::channel::<DetectedColor>(8);
51        let mut rx_from_main = self
52            .get_rx()
53            .expect("Single value sender not in device cache");
54        let task = tokio::spawn(async move {
55            while let Ok(msg) = rx_from_main.recv().await {
56                if msg.port_id == port_id {
57                    match msg.data[0] {
58                        -1 => {
59                            let _ = tx.send(DetectedColor::NoObject);
60                        }
61                        0 => {
62                            let _ = tx.send(DetectedColor::Black);
63                        }
64                        1 => {
65                            let _ = tx.send(DetectedColor::Color1);
66                        }
67                        2 => {
68                            let _ = tx.send(DetectedColor::Color2);
69                        }
70                        3 => {
71                            let _ = tx.send(DetectedColor::Blue);
72                        }
73                        4 => {
74                            let _ = tx.send(DetectedColor::Color4);
75                        }
76                        5 => {
77                            let _ = tx.send(DetectedColor::Green);
78                        }
79                        6 => {
80                            let _ = tx.send(DetectedColor::Color6);
81                        }
82                        7 => {
83                            let _ = tx.send(DetectedColor::Yellow);
84                        }
85                        8 => {
86                            let _ = tx.send(DetectedColor::Color8);
87                        }
88                        9 => {
89                            let _ = tx.send(DetectedColor::Red);
90                        }
91                        10 => {
92                            let _ = tx.send(DetectedColor::White);
93                        }
94                        _ => (),
95                    }
96                }
97            }
98        });
99
100        Ok((rx, task))
101    },
102
103    // Just setting output mode turns the light off, which may be useful
104    async fn visionsensor_light_output_mode(&self) -> Result<()> {
105        self.check()?;
106        self.device_mode(modes::VisionSensor::COL_O, 1, true).await
107    },
108
109    // Output colors are limited to R, G, B and W (all three)
110    async fn visionsensor_set_color(&self, color: OutputColor) -> Result<()> {
111        self.check()?;
112        let subcommand = PortOutputSubcommand::WriteDirectModeData(
113            WriteDirectModeDataPayload::SetVisionSensorColor(color as i8),
114        );
115        self.device_command(subcommand, StartupInfo::ExecuteImmediately, CompletionInfo::NoAction).await
116    }
117]);