lego_powered_up/iodevice/
definition.rs1use std::collections::BTreeMap;
6use std::fmt;
7
8use crate::notifications::*;
9use crate::IoTypeId;
10
11type ModeId = u8;
12
13#[derive(Debug, Default, Clone)]
14pub struct Definition {
15 kind: IoTypeId,
16 port: u8,
17 capabilities: Vec<Capability>,
18 mode_count: u8,
19 modes: std::collections::BTreeMap<ModeId, PortMode>,
20 valid_combos: Vec<Vec<u8>>,
21}
22impl fmt::Display for Definition {
23 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
24 write!(
25 f,
26 "{:#?} on port {} ({:#x}) with {} modes: {:#?}",
27 self.kind,
28 self.port,
29 self.port,
30 self.mode_count,
31 self.modes
32 .values()
33 .map(|mode| &mode.name[..])
34 .collect::<Vec<_>>()
35 )
36 }
37}
38
39impl Definition {
40 pub fn kind(&self) -> &IoTypeId {
41 &self.kind
42 }
43 pub fn port(&self) -> u8 {
44 self.port
45 }
46 pub fn capabilities(&self) -> &Vec<Capability> {
47 &self.capabilities
48 }
49 pub fn mode_count(&self) -> &u8 {
50 &self.mode_count
51 }
52 pub fn modes(&self) -> &BTreeMap<ModeId, PortMode> {
53 &self.modes
54 }
55 pub fn valid_combos(&self) -> &Vec<Vec<u8>> {
56 &self.valid_combos
57 }
58
59 pub fn new(kind: IoTypeId, port: u8) -> Self {
60 Self {
61 kind,
62 port,
63 mode_count: Default::default(),
64 capabilities: Default::default(),
65 valid_combos: Default::default(),
66 modes: Default::default(),
67 }
68 }
69 pub fn set_mode_count(&mut self, mode_count: u8) {
70 self.mode_count = mode_count;
71 }
72 pub fn set_modes(&mut self, input_modes: u16, output_modes: u16) {
73 let mut r: BTreeMap<ModeId, PortMode> = BTreeMap::new();
74 for mode in 0..15 {
75 if (input_modes >> mode as u16) & 1 == 1 {
76 r.insert(mode as u8, PortMode::new(ModeKind::Sensor));
77 }
78 }
79 for mode in 0..15 {
80 if (output_modes >> mode as u16) & 1 == 1 {
81 r.insert(mode as u8, PortMode::new(ModeKind::Output));
82 }
83 }
84
85 while r.len() < self.mode_count as usize {
87 let mut empty_key = 0;
88 while r.contains_key(&empty_key) {
89 empty_key += 1
90 }
91 r.insert(empty_key, PortMode::new(ModeKind::Hidden));
92 }
93 self.modes = r;
94 }
95 pub fn set_capabilities(&mut self, capabilities: u8) {
100 let mut r: Vec<Capability> = Vec::new();
101 if (capabilities >> 3) & 1 == 1 {
102 r.push(Capability::LogicalSynchronizable)
103 }
104 if (capabilities >> 2) & 1 == 1 {
105 r.push(Capability::LogicalCombinable)
106 }
107 if (capabilities >> 1) & 1 == 1 {
108 r.push(Capability::ProvideData)
109 }
110 if capabilities & 1 == 1 {
111 r.push(Capability::AcceptData)
112 }
113 self.capabilities = r;
114 }
115
116 pub fn set_valid_combos(&mut self, valid: Vec<u8>) {
117 for combo in valid {
118 let mut v: Vec<u8> = Vec::new();
119 for mode in 0..7 {
120 if (combo >> mode as u8) & 1 == 1 {
121 v.push(mode as u8);
122 }
123 }
124 self.valid_combos.push(v);
125 }
126 self.valid_combos.pop(); }
128
129 pub fn set_mode_name(&mut self, mode_id: u8, chars_as_bytes: Vec<u8>) {
130 let mut truncated: Vec<u8> = Vec::new();
132 for c in chars_as_bytes {
133 if c == 0 {
134 break;
135 } else {
136 truncated.push(c)
137 }
138 }
139
140 let name = String::from_utf8(truncated).expect("Found invalid UTF-8");
141 let mode = self.modes.get_mut(&mode_id);
142 match mode {
143 Some(m) => m.name = name,
144 None => {
145 error!(
146 "Found name without matching mode. Port:{} Mode:{} Name:{}",
147 self.port, &mode_id, &name
148 );
149 println!(
150 "Found name without matching mode. Port:{} Mode:{} Name:{}",
151 self.port, &mode_id, &name
152 );
153
154 }
159 }
160 }
161 pub fn set_mode_raw(&mut self, mode_id: u8, min: f32, max: f32) {
162 self.modes.get_mut(&mode_id).unwrap().raw = (min, max);
164 }
165 pub fn set_mode_pct(&mut self, mode_id: u8, min: f32, max: f32) {
166 self.modes.get_mut(&mode_id).unwrap().pct = (min, max);
168 }
169 pub fn set_mode_si(&mut self, mode_id: u8, min: f32, max: f32) {
170 self.modes.get_mut(&mode_id).unwrap().si = (min, max);
172 }
173 pub fn set_mode_symbol(&mut self, mode_id: u8, chars_as_bytes: Vec<u8>) {
174 let mut truncated: Vec<u8> = Vec::new();
175 for c in chars_as_bytes {
176 if c == 0 {
177 break;
178 } else {
179 truncated.push(c)
180 }
181 }
182 let symbol = String::from_utf8(truncated).expect("Found invalid UTF-8");
183 let mode = self.modes.get_mut(&mode_id);
184 match mode {
185 Some(m) => m.symbol = symbol,
186 None => {
187 error!("Found symbol without matching mode. Port:{} Mode:{} Symbol:{}", self.port, &mode_id, &symbol);
188 println!("Found symbol without matching mode. Port:{} Mode:{} Symbol:{}", self.port, &mode_id, &symbol);
189 }
190 }
191 }
192
193 pub fn set_mode_mapping(
198 &mut self,
199 mode_id: u8,
200 input: MappingValue,
201 output: MappingValue,
202 ) {
203 let mode = self.modes.get_mut(&mode_id).unwrap();
204 let mut r: Vec<Mapping> = Vec::new();
205 if (input.0 >> 7) & 1 == 1 {
206 r.push(Mapping::SupportsNull)
207 }
208 if (input.0 >> 6) & 1 == 1 {
209 r.push(Mapping::SupportsFunctional)
210 }
211 if (input.0 >> 4) & 1 == 1 {
213 r.push(Mapping::Absolute)
214 }
215 if (input.0 >> 3) & 1 == 1 {
216 r.push(Mapping::Relative)
217 }
218 if (input.0 >> 2) & 1 == 1 {
219 r.push(Mapping::Discrete)
220 }
221 mode.input_mapping = r;
224
225 let mut r: Vec<Mapping> = Vec::new();
226 if (output.0 >> 7) & 1 == 1 {
227 r.push(Mapping::SupportsNull)
228 }
229 if (output.0 >> 6) & 1 == 1 {
230 r.push(Mapping::SupportsFunctional)
231 }
232 if (output.0 >> 4) & 1 == 1 {
234 r.push(Mapping::Absolute)
235 }
236 if (output.0 >> 3) & 1 == 1 {
237 r.push(Mapping::Relative)
238 }
239 if (output.0 >> 2) & 1 == 1 {
240 r.push(Mapping::Discrete)
241 }
242 mode.output_mapping = r;
245 }
246 pub fn set_mode_valueformat(
247 &mut self,
248 mode_id: u8,
249 format: ValueFormatType,
250 ) {
251 self.modes.get_mut(&mode_id).unwrap().value_format = format;
252 }
253
254 pub fn set_mode_motor_bias(&mut self, mode_id: u8, bias: u8) {
255 self.modes.get_mut(&mode_id).unwrap().motor_bias = bias;
257 }
258}
259
260#[derive(Debug, Default, Clone)]
261pub struct PortMode {
262 pub kind: ModeKind,
263 pub name: String, pub raw: (f32, f32), pub pct: (f32, f32), pub si: (f32, f32), pub symbol: String, pub input_mapping: Vec<Mapping>, pub output_mapping: Vec<Mapping>,
270 pub motor_bias: u8, pub value_format: ValueFormatType,
273}
274impl fmt::Display for PortMode {
275 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
276 write!(
277 f,
278 "{:<10?} {:<10} {:<10} {:}",
279 self.kind, self.name, self.symbol, self.value_format
280 )
281 }
282}
283
284impl PortMode {
285 pub fn new(mode_kind: ModeKind) -> Self {
286 Self {
287 kind: mode_kind,
288 name: Default::default(),
289 raw: Default::default(),
290 pct: Default::default(),
291 si: Default::default(),
292 symbol: Default::default(),
293 input_mapping: Default::default(),
294 output_mapping: Default::default(),
295 motor_bias: Default::default(),
296 value_format: Default::default(),
298 }
299 }
300 pub fn name(&self) -> &str {
301 &self.name
302 }
303}
304
305#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
306pub enum ModeKind {
307 #[default]
308 Unknown,
309 Sensor,
310 Output,
311 Hidden,
312}
313
314#[derive(Debug, Default, Copy, Clone)]
315pub enum Capability {
316 #[default]
318 None,
319 LogicalSynchronizable = 0b1000,
320 LogicalCombinable = 0b0100,
321 ProvideData = 0b0010, AcceptData = 0b0001, }
324
325#[derive(Debug, Default, Copy, Clone)]
326pub enum Mapping {
327 #[default]
328 Unknown,
329 SupportsNull = 0b1000_0000,
330 SupportsFunctional = 0b0100_0000,
331 Absolute = 0b0001_0000, Relative = 0b0000_1000, Discrete = 0b0000_0100, }