Skip to main content

lego_powered_up/iodevice/
remote.rs

1//! Support for the button devices in
2//! https://rebrickable.com/parts/28739/control-unit-powered-up/
3//! The unit as a whole functions as a hub that connects the
4//! two button devices, hubled and voltage and rssi sensors.
5
6use crate::Result;
7
8use async_trait::async_trait;
9use core::fmt::Debug;
10use tokio::sync::broadcast;
11use tokio::task::JoinHandle;
12
13use super::Basic;
14use crate::device_trait;
15use crate::notifications::{
16    ButtonState, InputSetupSingle,
17    NetworkCommand::{self},
18    NotificationMessage, PortValueSingleFormat,
19};
20
21#[derive(Debug, Copy, Clone)]
22pub enum RcButtonState {
23    Aup,
24    Aplus,
25    Ared,
26    Aminus,
27    Bup,
28    Bplus,
29    Bred,
30    Bminus,
31    Green,
32    GreenUp,
33}
34
35device_trait!(RcDevice, [
36    fn get_rx_pvs(&self) -> Result<broadcast::Receiver<PortValueSingleFormat>>;,
37    fn get_rx_nwc(&self) -> Result<broadcast::Receiver<NetworkCommand>>;,
38
39    async fn remote_buttons_enable_by_port(&self, port_id: u8) -> Result<()> {
40        self.check()?;
41        let msg =
42            NotificationMessage::PortInputFormatSetupSingle(InputSetupSingle {
43                port_id,
44                mode: 0,
45                delta: 1,
46                notification_enabled: true,
47            });
48        self.commit(msg).await
49    },
50
51    async fn remote_connect(
52        &self,
53    ) -> Result<(broadcast::Receiver<RcButtonState>, JoinHandle<()>)> {
54        self.remote_buttons_enable_by_port(0x0).await?;
55        self.remote_buttons_enable_by_port(0x1).await?;
56
57        // Set up channel
58        let (tx, rx) = broadcast::channel::<RcButtonState>(64);
59        let mut pvs_from_main = self
60            .get_rx_pvs()
61            .expect("Single value sender not in device cache");
62        let task = tokio::spawn(async move {
63            while let Ok(msg) = pvs_from_main.recv().await {
64                match msg.port_id {
65                    0x0 => match msg.data[0] {
66                        0 => {
67                            let _ = tx.send(RcButtonState::Aup);
68                        }
69                        1 => {
70                            let _ = tx.send(RcButtonState::Aplus);
71                        }
72                        127 => {
73                            let _ = tx.send(RcButtonState::Ared);
74                        }
75                        -1 => {
76                            let _ = tx.send(RcButtonState::Aminus);
77                        }
78                        _ => (),
79                    },
80                    0x1 => match msg.data[0] {
81                        0 => {
82                            let _ = tx.send(RcButtonState::Bup);
83                        }
84                        1 => {
85                            let _ = tx.send(RcButtonState::Bplus);
86                        }
87                        127 => {
88                            let _ = tx.send(RcButtonState::Bred);
89                        }
90                        -1 => {
91                            let _ = tx.send(RcButtonState::Bminus);
92                        }
93                        _ => (),
94                    },
95                    _ => (),
96                }
97            }
98        });
99
100        Ok((rx, task))
101    },
102
103    async fn remote_connect_with_green(
104        &self,
105    ) -> Result<(broadcast::Receiver<RcButtonState>, JoinHandle<()>)> {
106        self.remote_buttons_enable_by_port(0x0).await?;
107        self.remote_buttons_enable_by_port(0x1).await?;
108
109        // Set up channel
110        let (tx, rx) = broadcast::channel::<RcButtonState>(8);
111        let mut pvs_from_main = self
112            .get_rx_pvs()
113            .expect("Single value sender not in device cache");
114        let mut nwc_from_main = self
115            .get_rx_nwc()
116            .expect("Network command sender not in device cache");
117        let task = tokio::spawn(async move {
118            loop {
119                tokio::select! {
120                    Ok(msg) = pvs_from_main.recv() => {
121                        match msg.port_id {
122                            0x0 => {
123                                match msg.data[0] {
124                                    0 => { let _ = tx.send(RcButtonState::Aup); }
125                                    1 => { let _ = tx.send(RcButtonState::Aplus); }
126                                    127 => { let _ = tx.send(RcButtonState::Ared); }
127                                    -1 => { let _ = tx.send(RcButtonState::Aminus); }
128                                    _  => ()
129                                }
130                            }
131                            0x1 => {
132                                match msg.data[0] {
133                                    0 => { let _ = tx.send(RcButtonState::Bup); }
134                                    1 => { let _ = tx.send(RcButtonState::Bplus); }
135                                    127 => { let _ = tx.send(RcButtonState::Bred); }
136                                    -1 => { let _ = tx.send(RcButtonState::Bminus); }
137                                    _  => ()
138                                }
139                            }
140                            _ => ()
141                        }
142                    },
143                    Ok(msg) = nwc_from_main.recv() => {
144                        match msg {
145                            NetworkCommand::ConnectionRequest(ButtonState::Up) => { let _ = tx.send(RcButtonState::Green); },
146                            NetworkCommand::ConnectionRequest(ButtonState::Released) => { let _ = tx.send(RcButtonState::GreenUp); },
147                            _ => ()
148                        }
149                    },
150                    else => { break }
151                };
152            }
153        });
154
155        Ok((rx, task))
156    }
157]);