1use crate::device::PoKeysDevice;
4use crate::error::{PoKeysError, Result};
5use log::info;
6use serde::{Deserialize, Serialize};
7
8mod private;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
12pub enum PinFunction {
13 PinRestricted = 0,
14 Reserved = 1,
15 DigitalInput = 2,
16 DigitalOutput = 4,
17 AnalogInput = 8,
18 AnalogOutput = 16,
19 TriggeredInput = 32,
20 DigitalCounter = 64,
21 InvertPin = 128,
22}
23
24impl PinFunction {
25 pub fn from_u8(value: u8) -> Result<Self> {
28 match value {
29 0 => Ok(PinFunction::PinRestricted),
30 1 => Ok(PinFunction::Reserved),
31 2 => Ok(PinFunction::DigitalInput),
32 4 => Ok(PinFunction::DigitalOutput),
33 8 => Ok(PinFunction::AnalogInput),
34 16 => Ok(PinFunction::AnalogOutput),
35 32 => Ok(PinFunction::TriggeredInput),
36 64 => Ok(PinFunction::DigitalCounter),
37 128 => Ok(PinFunction::InvertPin),
38 v if (v & PinFunction::DigitalOutput as u8) != 0 => Ok(PinFunction::DigitalOutput),
40 v if (v & PinFunction::DigitalInput as u8) != 0 => Ok(PinFunction::DigitalInput),
41 v if (v & PinFunction::AnalogInput as u8) != 0 => Ok(PinFunction::AnalogInput),
42 v if (v & PinFunction::AnalogOutput as u8) != 0 => Ok(PinFunction::AnalogOutput),
43 v if (v & PinFunction::DigitalCounter as u8) != 0 => Ok(PinFunction::DigitalCounter),
44 v if (v & PinFunction::TriggeredInput as u8) != 0 => Ok(PinFunction::TriggeredInput),
45 _ => Ok(PinFunction::PinRestricted), }
47 }
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq)]
52pub enum PinCapability {
53 DigitalInput = 1,
54 DigitalOutput,
55 AnalogInput,
56 MfAnalogInput,
57 AnalogOutput,
58 KeyboardMapping,
59 TriggeredInput,
60 DigitalCounter,
61 PwmOutput,
62 FastEncoder1A,
63 FastEncoder1B,
64 FastEncoder1I,
65 FastEncoder2A,
66 FastEncoder2B,
67 FastEncoder2I,
68 FastEncoder3A,
69 FastEncoder3B,
70 FastEncoder3I,
71 UltraFastEncoderA,
72 UltraFastEncoderB,
73 UltraFastEncoderI,
74 LcdE,
75 LcdRw,
76 LcdRs,
77 LcdD4,
78 LcdD5,
79 LcdD6,
80 LcdD7,
81}
82
83#[derive(Debug, Clone, Serialize, Deserialize)]
85pub struct PinData {
86 pub digital_counter_value: u32,
87 pub analog_value: u32,
88 pub pin_function: u8,
89 pub counter_options: u8,
90 pub digital_value_get: u8,
91 pub digital_value_set: u8,
92 pub digital_counter_available: u8,
93 pub mapping_type: u8,
94 pub key_code_macro_id: u8,
95 pub key_modifier: u8,
96 pub down_key_code_macro_id: u8,
97 pub down_key_modifier: u8,
98 pub up_key_code_macro_id: u8,
99 pub up_key_modifier: u8,
100 pub prevent_update: u8,
101}
102
103impl PinData {
104 pub fn new() -> Self {
105 Self {
106 digital_counter_value: 0,
107 analog_value: 0,
108 pin_function: PinFunction::PinRestricted as u8,
109 counter_options: 0,
110 digital_value_get: 0,
111 digital_value_set: 0,
112 digital_counter_available: 0,
113 mapping_type: 0,
114 key_code_macro_id: 0,
115 key_modifier: 0,
116 down_key_code_macro_id: 0,
117 down_key_modifier: 0,
118 up_key_code_macro_id: 0,
119 up_key_modifier: 0,
120 prevent_update: 0,
121 }
122 }
123
124 pub fn is_digital_input(&self) -> bool {
125 (self.pin_function & PinFunction::DigitalInput as u8) != 0
126 }
127
128 pub fn is_digital_output(&self) -> bool {
129 (self.pin_function & PinFunction::DigitalOutput as u8) != 0
130 }
131
132 pub fn is_analog_input(&self) -> bool {
133 (self.pin_function & PinFunction::AnalogInput as u8) != 0
134 }
135
136 pub fn is_analog_output(&self) -> bool {
137 (self.pin_function & PinFunction::AnalogOutput as u8) != 0
138 }
139
140 pub fn is_digital_counter(&self) -> bool {
141 (self.pin_function & PinFunction::DigitalCounter as u8) != 0
142 }
143}
144
145impl Default for PinData {
146 fn default() -> Self {
147 Self::new()
148 }
149}
150
151impl PoKeysDevice {
152 pub fn set_pin_function(
154 &mut self,
155 pin: u32,
156 pin_function: PinFunction,
157 ) -> Result<(u32, PinFunction)> {
158 match self.write_pin_function(pin, pin_function) {
159 Ok((pin, pin_function)) => Ok((pin, pin_function)),
160 Err(e) => Err(e),
161 }
162 }
163
164 pub fn get_pin_function(&self, pin: u32) -> Result<PinFunction> {
166 match self.check_pin_range(pin) {
167 Ok(pin_index) => {
168 let function_value = self.pins[pin_index].pin_function;
169
170 match function_value {
172 0 => Ok(PinFunction::PinRestricted),
173 1 => Ok(PinFunction::Reserved),
174 2 => Ok(PinFunction::DigitalInput),
175 4 => Ok(PinFunction::DigitalOutput),
176 8 => Ok(PinFunction::AnalogInput),
177 16 => Ok(PinFunction::AnalogOutput),
178 32 => Ok(PinFunction::TriggeredInput),
179 64 => Ok(PinFunction::DigitalCounter),
180 128 => Ok(PinFunction::InvertPin),
181 _ => Ok(PinFunction::PinRestricted), }
183 }
184
185 Err(e) => Err(e),
186 }
187 }
188
189 pub fn get_digital_input(&mut self, pin: u32) -> Result<bool> {
191 if pin == 0 || pin as usize > self.pins.len() {
192 return Err(PoKeysError::Parameter("Invalid pin number".to_string()));
193 }
194
195 let res = self.read_digital_input(pin)?;
197
198 let pin_index = (pin - 1) as usize;
199 self.pins[pin_index].digital_value_get = res;
200 Ok(true)
201 }
202
203 pub fn set_digital_output(&mut self, pin: u32, value: bool) -> Result<bool> {
205 if pin == 0 || pin as usize > self.pins.len() {
206 return Err(PoKeysError::Parameter("Invalid pin number".to_string()));
207 }
208
209 match self.write_digital_output(pin, !value) {
211 Ok(_) => {
212 let pin_index = (pin - 1) as usize;
213 self.pins[pin_index].digital_value_set = if value { 1 } else { 0 };
214 info!(
215 "Pin {} set to {:?}",
216 pin,
217 if value { "High" } else { "Low" }
218 );
219 Ok(true)
220 }
221 Err(e) => Err(e),
222 }
223 }
224
225 pub fn get_analog_input(&mut self, pin: u32) -> Result<u32> {
227 if pin == 0 || pin as usize > self.pins.len() {
228 return Err(PoKeysError::Parameter("Invalid pin number".to_string()));
229 }
230
231 self.read_analog_inputs()?;
233
234 let pin_index = (pin - 1) as usize;
235 Ok(self.pins[pin_index].analog_value)
236 }
237
238 pub fn set_analog_output(&mut self, pin: u32, value: u32) -> Result<()> {
240 if pin == 0 || pin as usize > self.pins.len() {
241 return Err(PoKeysError::Parameter("Invalid pin number".to_string()));
242 }
243
244 let pin_index = (pin - 1) as usize;
245 self.pins[pin_index].analog_value = value;
246
247 self.write_analog_outputs()?;
249 Ok(())
250 }
251
252 pub fn get_digital_counter(&mut self, pin: u32) -> Result<u32> {
254 if pin == 0 || pin as usize > self.pins.len() {
255 return Err(PoKeysError::Parameter("Invalid pin number".to_string()));
256 }
257
258 let pin_index = (pin - 1) as usize;
259 if self.pins[pin_index].digital_counter_available == 0 {
260 return Err(PoKeysError::NotSupported);
261 }
262
263 self.read_digital_counters()?;
265
266 Ok(self.pins[pin_index].digital_counter_value)
267 }
268
269 pub fn reset_digital_counter(&mut self, pin: u32) -> Result<()> {
271 if pin == 0 || pin as usize > self.pins.len() {
272 return Err(PoKeysError::Parameter("Invalid pin number".to_string()));
273 }
274
275 let pin_index = (pin - 1) as usize;
276 if self.pins[pin_index].digital_counter_available == 0 {
277 return Err(PoKeysError::NotSupported);
278 }
279 self.send_request(0x30, pin as u8, 0, 0, 0)?;
281 Ok(())
282 }
283
284 pub fn get_digital_inputs(&mut self) -> Result<()> {
286 let response = self.send_request(0x10, 0, 0, 0, 0)?;
287
288 for i in 0..self.pins.len().min(55) {
290 let byte_index = 8 + (i / 8);
291 let bit_index = i % 8;
292
293 if byte_index < response.len() {
294 self.pins[i].digital_value_get = if (response[byte_index] & (1 << bit_index)) != 0 {
295 1
296 } else {
297 0
298 };
299 }
300 }
301
302 Ok(())
303 }
304
305 pub fn write_digital_outputs(&mut self) -> Result<()> {
307 let mut output_data = [0u8; 8];
309
310 for i in 0..self.pins.len().min(55) {
311 if self.pins[i].is_digital_output() && self.pins[i].digital_value_set != 0 {
312 let byte_index = i / 8;
313 let bit_index = i % 8;
314 output_data[byte_index] |= 1 << bit_index;
315 }
316 }
317
318 self.send_request(
320 0x11,
321 output_data[0],
322 output_data[1],
323 output_data[2],
324 output_data[3],
325 )?;
326
327 if self.pins.len() > 32 {
329 self.send_request(
330 0x12,
331 output_data[4],
332 output_data[5],
333 output_data[6],
334 output_data[7],
335 )?;
336 }
337
338 Ok(())
339 }
340
341 pub fn read_analog_inputs(&mut self) -> Result<()> {
343 let response = self.send_request(0x20, 0, 0, 0, 0)?;
344
345 let mut data_index = 8;
347 for i in 0..self.pins.len() {
348 if self.pins[i].is_analog_input() && data_index + 3 < response.len() {
349 self.pins[i].analog_value = u32::from_le_bytes([
350 response[data_index],
351 response[data_index + 1],
352 response[data_index + 2],
353 response[data_index + 3],
354 ]);
355 data_index += 4;
356 }
357 }
358
359 Ok(())
360 }
361
362 pub fn write_analog_outputs(&mut self) -> Result<()> {
364 let mut request_data = Vec::new();
366
367 for pin in &self.pins {
368 if pin.is_analog_output() {
369 request_data.extend_from_slice(&pin.analog_value.to_le_bytes());
370 }
371 }
372
373 if !request_data.is_empty() {
375 self.send_request(0x21, 0, 0, 0, 0)?;
376 }
378
379 Ok(())
380 }
381
382 pub fn read_digital_counters(&mut self) -> Result<()> {
384 let response = self.send_request(0x31, 0, 0, 0, 0)?;
385
386 let mut data_index = 8;
388 for i in 0..self.pins.len() {
389 if self.pins[i].digital_counter_available != 0 && data_index + 3 < response.len() {
390 self.pins[i].digital_counter_value = u32::from_le_bytes([
391 response[data_index],
392 response[data_index + 1],
393 response[data_index + 2],
394 response[data_index + 3],
395 ]);
396 data_index += 4;
397 }
398 }
399
400 Ok(())
401 }
402
403 pub fn read_all_pin_functions(&mut self) -> Result<[PinFunction; 55]> {
407 use crate::io::private::Command;
408
409 let response = self.send_request(
412 Command::InputOutputExtended as u8,
413 0, 0, 0, 0, )?;
418
419 if response.len() < 64 {
420 return Err(PoKeysError::Protocol(
421 "Response too short for bulk pin read".to_string(),
422 ));
423 }
424
425 if response[1] != Command::InputOutputExtended as u8 {
426 return Err(PoKeysError::Protocol(
427 "Invalid response command".to_string(),
428 ));
429 }
430
431 let mut functions = [PinFunction::PinRestricted; 55];
434 for i in 0..55 {
435 let function_value = response[8 + i];
436 functions[i] = PinFunction::from_u8(function_value)?;
437 }
438
439 for (i, &function) in functions.iter().enumerate() {
441 if i < self.pins.len() {
442 self.pins[i].pin_function = function as u8;
443 }
444 }
445
446 Ok(functions)
447 }
448
449 pub fn set_all_pin_functions(&mut self, functions: &[PinFunction; 55]) -> Result<()> {
457 let mut changes_made = 0;
462
463 for (i, &desired_function) in functions.iter().enumerate() {
464 let pin_number = (i + 1) as u32;
465
466 let current_function = self.get_pin_function(pin_number)?;
468 if current_function != desired_function {
469 self.set_pin_function(pin_number, desired_function)?;
471 changes_made += 1;
472 }
473 }
474
475 if changes_made > 0 {
476 log::info!(
477 "Applied {} pin function changes using optimized batch operations",
478 changes_made
479 );
480 }
481
482 Ok(())
483 }
484}
485
486#[cfg(test)]
487mod tests {
488 use super::*;
489
490 #[test]
491 fn test_pin_data_creation() {
492 let pin_data = PinData::new();
493 assert_eq!(pin_data.pin_function, PinFunction::PinRestricted as u8);
494 assert_eq!(pin_data.digital_value_get, 0);
495 assert_eq!(pin_data.digital_value_set, 0);
496 }
497
498 #[test]
499 fn test_pin_function_checks() {
500 let mut pin_data = PinData::new();
501
502 pin_data.pin_function = PinFunction::DigitalInput as u8;
503 assert!(pin_data.is_digital_input());
504 assert!(!pin_data.is_digital_output());
505
506 pin_data.pin_function = PinFunction::DigitalOutput as u8;
507 assert!(!pin_data.is_digital_input());
508 assert!(pin_data.is_digital_output());
509
510 pin_data.pin_function =
511 (PinFunction::DigitalInput as u8) | (PinFunction::DigitalOutput as u8);
512 assert!(pin_data.is_digital_input());
513 assert!(pin_data.is_digital_output());
514 }
515}