1use crate::consts::*;
8use crate::error::{Error, OptionContext, Result};
9use log::{debug, trace};
10use lpu_macros::Parse;
11use num_derive::FromPrimitive;
12use num_traits::FromPrimitive;
13use std::collections::HashMap;
14use std::fmt::{self, Debug, Display};
15
16pub use self::message::NotificationMessage;
17pub mod message;
18
19#[macro_use]
20pub mod macros;
21
22pub const MAX_NAME_SIZE: usize = 14;
23
24#[repr(u8)]
26#[derive(Copy, Clone, Debug, PartialEq, Eq)]
27pub enum HubLedMode {
28 Colour = 0x0,
30 Rgb = 0x01,
32}
33
34#[derive(Clone, Debug, PartialEq, Eq)]
35pub struct HubProperty {
36 pub property: HubPropertyValue,
37 pub operation: HubPropertyOperation,
38 pub reference: HubPropertyRef,
39}
40
41impl HubProperty {
42 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
43 let property_int = next!(msg);
44 let operation = ok!(HubPropertyOperation::from_u8(next!(msg)));
45 let property = HubPropertyValue::parse(property_int, &mut msg)?;
46 let reference = match property {
47 HubPropertyValue::AdvertisingName(_) => {
48 HubPropertyRef::AdvertisingName
49 }
50 HubPropertyValue::Button(_) => HubPropertyRef::Button,
51 HubPropertyValue::FwVersion(_) => HubPropertyRef::FwVersion,
52 HubPropertyValue::HwVersion(_) => HubPropertyRef::HwVersion,
53 HubPropertyValue::Rssi(_) => HubPropertyRef::Rssi,
54 HubPropertyValue::BatteryVoltage(_) => {
55 HubPropertyRef::BatteryVoltage
56 }
57 HubPropertyValue::BatteryType(_) => HubPropertyRef::BatteryType,
58 HubPropertyValue::ManufacturerName(_) => {
59 HubPropertyRef::ManufacturerName
60 }
61 HubPropertyValue::RadioFirmwareVersion(_) => {
62 HubPropertyRef::RadioFirmwareVersion
63 }
64 HubPropertyValue::LegoWirelessProtocolVersion(_) => {
65 HubPropertyRef::LegoWirelessProtocolVersion
66 }
67 HubPropertyValue::SystemTypeId(_) => HubPropertyRef::SystemTypeId,
68 HubPropertyValue::HwNetworkId(_) => HubPropertyRef::HwNetworkId,
69 HubPropertyValue::PrimaryMacAddress(_) => {
70 HubPropertyRef::PrimaryMacAddress
71 }
72 HubPropertyValue::SecondaryMacAddress => {
73 HubPropertyRef::SecondaryMacAddress
74 }
75 HubPropertyValue::HardwareNetworkFamily(_) => {
76 HubPropertyRef::HardwareNetworkFamily
77 }
78 };
79
80 Ok(Self {
81 reference,
82 operation,
83 property,
84 })
85 }
86 pub fn serialise(&self) -> Vec<u8> {
87 let mut msg = Vec::with_capacity(10);
88 msg.extend_from_slice(&[
89 0,
90 0,
91 MessageType::HubProperties as u8,
92 self.reference as u8,
94 self.operation as u8,
95 ]);
96
97 msg
98 }
99}
100
101#[derive(Clone, Debug, PartialEq, Eq)]
102pub enum HubPropertyValue {
103 AdvertisingName(Vec<u8>),
104 Button(u8),
105 FwVersion(i32),
106 HwVersion(i32),
107 Rssi(i8),
108 BatteryVoltage(u8),
109 BatteryType(HubBatteryType),
110 ManufacturerName(Vec<u8>),
111 RadioFirmwareVersion(Vec<u8>),
112 LegoWirelessProtocolVersion(u16),
113 SystemTypeId(u8),
114 HwNetworkId(u8),
115 PrimaryMacAddress([u8; 6]),
116 SecondaryMacAddress,
117 HardwareNetworkFamily(u8),
118}
119
120impl HubPropertyValue {
121 pub fn parse<'a>(
122 prop_type: u8,
123 mut msg: impl Iterator<Item = &'a u8>,
124 ) -> Result<Self> {
125 use HubPropertyValue::*;
126 let prop_type = ok!(HubPropertyRef::from_u8(prop_type));
127
128 Ok(match prop_type {
129 HubPropertyRef::AdvertisingName => {
130 let name = msg.copied().collect();
132
133 AdvertisingName(name)
134 }
135 HubPropertyRef::Button => Button(next!(msg)),
136 HubPropertyRef::FwVersion => {
137 let vers = next_i32!(msg);
138
139 FwVersion(vers)
140 }
141 HubPropertyRef::HwVersion => {
142 let vers = next_i32!(msg);
143
144 HwVersion(vers)
145 }
146 HubPropertyRef::Rssi => {
147 let bytes = [next!(msg)];
148 let rssi = i8::from_le_bytes(bytes);
149
150 Rssi(rssi)
151 }
152 HubPropertyRef::BatteryVoltage => BatteryVoltage(next!(msg)),
153 HubPropertyRef::BatteryType => {
154 BatteryType(ok!(HubBatteryType::parse(&mut msg)))
155 }
156 HubPropertyRef::ManufacturerName => {
157 let name = msg.copied().collect();
158
159 ManufacturerName(name)
160 }
161 HubPropertyRef::RadioFirmwareVersion => {
162 let vers = msg.copied().collect();
163
164 RadioFirmwareVersion(vers)
165 }
166 HubPropertyRef::LegoWirelessProtocolVersion => {
167 let vers = next_u16!(msg);
168
169 LegoWirelessProtocolVersion(vers)
170 }
171 HubPropertyRef::SystemTypeId => SystemTypeId(next!(msg)),
172 HubPropertyRef::HwNetworkId => HwNetworkId(next!(msg)),
173 HubPropertyRef::PrimaryMacAddress => {
174 let mac = [
175 next!(msg),
176 next!(msg),
177 next!(msg),
178 next!(msg),
179 next!(msg),
180 next!(msg),
181 ];
182 PrimaryMacAddress(mac)
183 }
184 HubPropertyRef::SecondaryMacAddress => SecondaryMacAddress,
185 HubPropertyRef::HardwareNetworkFamily => {
186 HardwareNetworkFamily(next!(msg))
187 }
188 })
189 }
190}
191
192#[repr(u8)]
193#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, Parse)]
194pub enum HubBatteryType {
195 Normal = 0x00,
196 Rechargeable = 0x01,
197}
198
199#[repr(u8)]
200#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, Parse)]
201pub enum HubAction {
202 SwitchOffHub = 0x01,
203 Disconnect = 0x02,
204 VccPortControlOn = 0x03,
205 VccPortControlOff = 0x04,
206 ActivateBusyIndication = 0x05,
207 ResetBusyIndication = 0x06,
208 Shutdown = 0x2F,
209 HubWillSwitchOff = 0x30,
210 HubWillDisconnect = 0x31,
211 HubWillGoIntoBootMode = 0x32,
212}
213
214#[derive(Copy, Clone, Debug, PartialEq, Eq)]
215pub struct HubActionRequest {
216 pub(crate) action_type: HubAction,
217}
218
219impl HubActionRequest {
220 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
221 let action_type = HubAction::parse(&mut msg)?;
222 Ok(HubActionRequest { action_type })
223 }
224 pub fn serialise(&self) -> Vec<u8> {
225 let mut msg = Vec::with_capacity(10);
226 msg.extend_from_slice(&[
227 0,
228 0,
229 MessageType::HubActions as u8,
230 self.action_type as u8,
231 ]);
232 msg
233 }
234}
235
236#[repr(u8)]
237#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, Parse)]
238pub enum AlertType {
239 LowVoltage = 0x01,
240 HighCurrent = 0x02,
241 LowSignalStrength = 0x03,
242 OverPowerCondition = 0x04,
243}
244impl Display for AlertType {
245 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
246 match self {
247 AlertType::HighCurrent => write!(f, "High current"),
248 AlertType::LowSignalStrength => write!(f, "Low signal strength"),
249 AlertType::LowVoltage => write!(f, "Low voltage"),
250 AlertType::OverPowerCondition => write!(f, "Over power condition"),
251 }
252 }
253}
254
255#[repr(u8)]
256#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, Parse)]
257pub enum AlertOperation {
258 EnableUpdates = 0x01,
259 DisableUpdates = 0x02,
260 RequestUpdate = 0x03,
261 Update = 0x04,
262}
263
264#[repr(u8)]
265#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, Parse)]
266pub enum AlertPayload {
267 StatusOk = 0x00,
268 Alert = 0xFF,
269}
270
271#[derive(Copy, Clone, Debug, PartialEq, Eq)]
272pub struct HubAlert {
273 pub alert_type: AlertType,
274 pub operation: AlertOperation,
275 pub payload: AlertPayload,
276}
277
278impl HubAlert {
279 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
280 let alert_type = AlertType::parse(&mut msg)?;
281 let operation = AlertOperation::parse(&mut msg)?;
282 let payload = AlertPayload::parse(&mut msg)?;
283 Ok(HubAlert {
284 alert_type,
285 operation,
286 payload,
287 })
288 }
289 pub fn serialise(&self) -> Vec<u8> {
290 let mut msg = Vec::with_capacity(10);
291 msg.extend_from_slice(&[
292 0,
293 0,
294 MessageType::HubAlerts as u8,
295 self.alert_type as u8,
296 self.operation as u8,
297 ]);
298 msg
299 }
300}
301
302#[derive(Copy, Clone, Debug, PartialEq, Eq)]
303pub struct AttachedIo {
304 pub port: u8,
305 pub event: IoAttachEvent,
306}
307
308impl AttachedIo {
309 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
310 let port = next!(msg);
311 let event = IoAttachEvent::parse(&mut msg)?;
312 Ok(Self { port, event })
313 }
314}
315
316#[repr(u8)]
317#[derive(Copy, Clone, Debug, PartialEq, Eq)]
318pub enum IoAttachEvent {
319 DetachedIo {
320 },
322 AttachedIo {
323 io_type_id: IoTypeId,
324 hw_rev: VersionNumber,
325 fw_rev: VersionNumber,
326 },
327 AttachedVirtualIo {
328 io_type_id: IoTypeId,
329 port_a: u8,
330 port_b: u8,
331 },
332}
333
334impl IoAttachEvent {
335 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
338 let event_type = ok!(Event::from_u8(next!(msg)));
339
340 Ok(match event_type {
341 Event::DetachedIo => {
342 IoAttachEvent::DetachedIo {}
344 }
345
346 Event::AttachedIo => {
347 let io_type_id = ok!(IoTypeId::from_u16(next_u16!(msg)));
348 let hw_rev = VersionNumber::parse(&mut msg)?;
349 let fw_rev = VersionNumber::parse(&mut msg)?;
350 IoAttachEvent::AttachedIo {
351 io_type_id,
352 hw_rev,
353 fw_rev,
354 }
355 }
356 Event::AttachedVirtualIo => {
357 let io_type_id = ok!(IoTypeId::from_u16(next_u16!(msg)));
358 let port_a = next!(msg);
359 let port_b = next!(msg);
360 IoAttachEvent::AttachedVirtualIo {
361 io_type_id,
362 port_a,
363 port_b,
364 }
365 }
366 })
367 }
368}
369
370#[derive(Copy, Clone, PartialEq, Eq)]
376pub struct VersionNumber {
377 pub major: u8,
378 pub minor: u8,
379 pub bugfix: u8,
380 pub build: u16,
381}
382
383impl VersionNumber {
384 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
385 let build = next_u16!(msg);
389 let byte2 = next!(msg);
390 let byte3 = next!(msg);
391 let major = (byte3 & 0x70) >> 4;
394 let minor = byte3 & 0x0f;
395 let bugfix = (byte2 >> 4) * 10 + (byte2 & 0x0f);
397 Ok(Self {
405 major,
406 minor,
407 bugfix,
408 build,
409 })
410 }
411
412 pub fn serialise(&self) -> Vec<u8> {
413 let byte3 = (self.major << 4) | self.minor;
414 let byte2 = ((self.bugfix / 10) << 4) | (self.bugfix % 10);
415 let byte1 = (self.build >> 8) as u8;
428 let byte0 = self.build as u8;
429
430 vec![byte0, byte1, byte2, byte3]
431 }
432}
433
434impl Display for VersionNumber {
435 fn fmt(
436 &self,
437 fmt: &mut fmt::Formatter,
438 ) -> std::result::Result<(), fmt::Error> {
439 write!(
440 fmt,
441 "{}.{}.{}.{:x}",
442 self.major, self.minor, self.bugfix, self.build
443 )
444 }
445}
446
447impl Debug for VersionNumber {
448 fn fmt(
449 &self,
450 fmt: &mut fmt::Formatter,
451 ) -> std::result::Result<(), fmt::Error> {
452 write!(fmt, "{}", self)
453 }
454}
455
456#[derive(Copy, Clone, Debug, PartialEq, Eq)]
457pub struct ErrorMessageFormat {
458 command_type: u8,
459 error_code: ErrorCode,
460}
461
462impl ErrorMessageFormat {
463 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
464 trace!("ErrorMessageFormat");
465 let command_type = next!(msg);
466 let error_code = ErrorCode::parse(&mut msg)?;
467 Ok(Self {
468 command_type,
469 error_code,
470 })
471 }
472}
473
474#[repr(u8)]
475#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, Parse)]
476pub enum ErrorCode {
477 Ack = 0x01,
478 Mack = 0x02,
479 BufferOverflow = 0x03,
480 Timeout = 0x04,
481 CommandNotRecognized = 0x05,
482 InvalidUse = 0x06,
483 Overcurrent = 0x07,
484 InternalError = 0x08,
485}
486
487#[repr(u8)]
503#[derive(Copy, Clone, Debug, PartialEq, Eq)]
504pub enum NetworkCommand {
505 ConnectionRequest(ButtonState),
506 FamilyRequest,
507 FamilySet(NetworkFamily),
508 JoinDenied(),
509 GetFamily(),
510 Family(NetworkFamily),
511 GetSubfamily(),
512 Subfamily(NetworkSubFamily),
513 SubfamilySet(NetworkSubFamily),
514 GetExtendedFamily(),
515 ExtendedFamily {
516 family: NetworkFamily,
517 subfamily: NetworkSubFamily,
518 },
519 ExtendedFamilySet {
520 family: NetworkFamily,
521 subfamily: NetworkSubFamily,
522 },
523 ResetLongPressTiming(),
524}
525
526impl NetworkCommand {
527 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
528 use NetworkCommand::*;
529 let command_type = ok!(HwNetworkCommandType::from_u8(next!(msg)));
530
531 Ok(match command_type {
532 HwNetworkCommandType::ConnectionRequest => {
533 let button = ButtonState::parse(&mut msg)?;
534 ConnectionRequest(button)
535 }
536 HwNetworkCommandType::FamilyRequest => FamilyRequest,
537 HwNetworkCommandType::FamilySet => {
538 let fam = NetworkFamily::parse(&mut msg)?;
539 FamilySet(fam)
540 }
541 HwNetworkCommandType::JoinDenied => {
542 todo!()
543 }
544 HwNetworkCommandType::GetFamily => {
545 todo!()
546 }
547 HwNetworkCommandType::Family => {
548 let fam = NetworkFamily::parse(&mut msg)?;
549 Family(fam)
550 }
551 HwNetworkCommandType::GetSubfamily => {
552 todo!()
553 }
554 HwNetworkCommandType::Subfamily => {
555 let fam = NetworkSubFamily::parse(&mut msg)?;
556 Subfamily(fam)
557 }
558 HwNetworkCommandType::SubfamilySet => {
559 let fam = NetworkSubFamily::parse(&mut msg)?;
560 SubfamilySet(fam)
561 }
562 HwNetworkCommandType::GetExtendedFamily => {
563 todo!()
564 }
565 HwNetworkCommandType::ExtendedFamily => {
566 let byte = next!(msg);
568 let fam_byte = byte & 0x0f;
569 let sub_bytes = (byte >> 4) & 0x7;
570 let family = ok!(NetworkFamily::from_u8(fam_byte));
571 let subfamily = ok!(NetworkSubFamily::from_u8(sub_bytes));
572 ExtendedFamily { family, subfamily }
573 }
574 HwNetworkCommandType::ExtendedFamilySet => {
575 let byte = next!(msg);
577 let fam_byte = byte & 0x0f;
578 let sub_bytes = (byte >> 4) & 0x7;
579 let family = ok!(NetworkFamily::from_u8(fam_byte));
580 let subfamily = ok!(NetworkSubFamily::from_u8(sub_bytes));
581 ExtendedFamilySet { family, subfamily }
582 }
583 HwNetworkCommandType::ResetLongPressTiming => {
584 todo!()
585 }
586 })
587 }
588}
589
590#[repr(u8)]
591#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, Parse)]
592pub enum ButtonState {
593 Pressed = 2,
594 Released = 0,
595 Up = 1,
596 Down = 255,
597 Stop = 127,
598}
599
600#[repr(u8)]
601#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, Parse)]
602pub enum NetworkFamily {
603 Green = 0x01,
604 Yellow = 0x02,
605 Red = 0x03,
606 Blue = 0x04,
607 Purple = 0x05,
608 LightBlue = 0x06,
609 Teal = 0x07,
610 Pink = 0x08,
611 White = 0x00,
612}
613
614#[repr(u8)]
615#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, Parse)]
616pub enum NetworkSubFamily {
617 OneFlash = 0x01,
618 TwoFlashes = 0x02,
619 ThreeFlashes = 0x03,
620 FourFlashes = 0x04,
621 FiveFlashes = 0x05,
622 SixFlashes = 0x06,
623 SevenFlashes = 0x07,
624}
625
626#[repr(u8)]
627#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, Parse)]
628pub enum LockStatus {
629 Ok = 0x00,
630 NotLocked = 0xff,
631}
632
633#[derive(Copy, Clone, Debug, PartialEq, Eq)]
634pub struct InformationRequest {
635 pub(crate) port_id: u8,
636 pub(crate) information_type: InformationType,
637}
638
639impl InformationRequest {
640 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
641 let port_id = next!(msg);
642 let information_type = InformationType::parse(&mut msg)?;
643 Ok(InformationRequest {
644 port_id,
645 information_type,
646 })
647 }
648 pub fn serialise(&self) -> Vec<u8> {
649 let mut msg = Vec::with_capacity(10);
650 msg.extend_from_slice(&[
651 0,
652 0,
653 MessageType::PortInformationRequest as u8,
654 self.port_id,
655 self.information_type as u8,
656 ]);
657 msg
658 }
659}
660
661#[repr(u8)]
662#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, Parse)]
663pub enum InformationType {
664 PortValue = 0x00,
665 ModeInfo = 0x01,
666 PossibleModeCombinations = 0x02,
667}
668
669#[derive(Copy, Clone, Debug, PartialEq, Eq)]
670pub struct ModeInformationRequest {
671 pub(crate) port_id: u8,
672 pub(crate) mode: u8,
673 pub(crate) information_type: ModeInformationType,
674}
675
676impl ModeInformationRequest {
677 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
678 let port_id = next!(msg);
679 let mode = next!(msg);
680 let information_type = ModeInformationType::parse(&mut msg)?;
681 Ok(Self {
682 port_id,
683 mode,
684 information_type,
685 })
686 }
687 pub fn serialise(&self) -> Vec<u8> {
688 let mut msg = Vec::with_capacity(10);
689 msg.extend_from_slice(&[
690 0,
691 0,
692 MessageType::PortModeInformationRequest as u8,
693 self.port_id,
694 self.mode,
695 self.information_type as u8,
696 ]);
697 msg
698 }
699}
700
701#[repr(u8)]
702#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, Parse)]
703pub enum ModeInformationType {
704 Name = 0x00,
705 Raw = 0x01,
706 Pct = 0x02,
707 Si = 0x03,
708 Symbol = 0x04,
709 Mapping = 0x05,
710 UsedInternally = 0x06,
711 MotorBias = 0x07,
712 CapabilityBits = 0x08,
713 ValueFormat = 0x80,
714}
715
716#[derive(Copy, Clone, Debug, PartialEq, Eq)]
717pub struct InputSetupSingle {
718 pub(crate) port_id: u8,
719 pub(crate) mode: u8,
720 pub(crate) delta: u32,
721 pub(crate) notification_enabled: bool,
722}
723
724impl InputSetupSingle {
725 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
726 let port_id = next!(msg);
727 let mode = next!(msg);
728 let delta = next_u32!(msg);
729 let notif_byte = next!(msg);
730 let notification_enabled = match notif_byte {
731 0x00 => false,
732 0x01 => true,
733 b => {
734 return Err(Error::ParseError(format!(
735 "Invalid notification enabled state {:x}",
736 b
737 )))
738 }
739 };
740 Ok(Self {
741 port_id,
742 mode,
743 delta,
744 notification_enabled,
745 })
746 }
747
748 pub fn serialise(&self) -> Vec<u8> {
749 let mut msg = Vec::with_capacity(10);
750 msg.extend_from_slice(&[
751 0,
752 0,
753 MessageType::PortInputFormatSetupSingle as u8,
754 self.port_id,
755 self.mode,
756 ]);
757 msg.extend_from_slice(&self.delta.to_le_bytes());
758 msg.push(self.notification_enabled as u8);
759 msg
760 }
761}
762
763#[derive(Copy, Clone, Debug, PartialEq, Eq)]
764pub struct InputSetupCombined {
765 pub(crate) port_id: u8,
766 pub(crate) subcommand: InputSetupCombinedSubcommand,
767}
768
769impl InputSetupCombined {
770 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
771 let port_id = next!(msg);
772 let subcommand = InputSetupCombinedSubcommand::parse(&mut msg)?;
773 Ok(InputSetupCombined {
774 port_id,
775 subcommand,
776 })
777 }
778 pub fn serialise(&self) -> Vec<u8> {
779 use InputSetupCombinedSubcommand::*;
780 match &self.subcommand {
781 SetModeanddatasetCombinations {
782 combination_index,
783 mode_dataset,
784 } => {
785 let mut bytes = vec![
786 0, 0, MessageType::PortInputFormatSetupCombined as u8,
790 self.port_id,
792 InputSetupCombinedSubcommandValue::SetModeanddatasetCombinations as u8,
793 *combination_index,
795 ];
796 let md = mode_dataset.as_slice();
800 for val in md.iter() {
801 if *val == 255 {
802 break;
803 } else {
804 bytes.push(*val);
805 }
806 }
807 bytes
809 }
810 LockLpf2DeviceForSetup {} => {
811 vec![
812 0, 0, MessageType::PortInputFormatSetupCombined as u8,
816 self.port_id,
818 InputSetupCombinedSubcommandValue::LockLpf2DeviceForSetup
819 as u8,
820 ]
821 }
822 UnlockAndStartMultiEnabled {} => {
823 vec![
824 0, 0, MessageType::PortInputFormatSetupCombined as u8,
828 self.port_id,
830 InputSetupCombinedSubcommandValue::UnlockAndStartMultiEnabled as u8,
831 ]
832 }
833 UnlockAndStartMultiDisabled {} => {
834 vec![
835 0, 0, MessageType::PortInputFormatSetupCombined as u8,
839 self.port_id,
841 InputSetupCombinedSubcommandValue::UnlockAndStartMultiDisabled as u8,
842 ]
843 }
844 NotUsed {} => {
845 vec![
846 0, 0, MessageType::PortInputFormatSetupCombined as u8,
850 self.port_id,
852 InputSetupCombinedSubcommandValue::NotUsed as u8,
853 ]
854 }
855 ResetSensor {} => {
856 vec![
857 0, 0, MessageType::PortInputFormatSetupCombined as u8,
861 self.port_id,
863 InputSetupCombinedSubcommandValue::ResetSensor as u8,
864 ]
865 }
866 }
867 }
868}
869
870#[derive(Copy, Clone, Debug, PartialEq, Eq)]
871pub enum InputSetupCombinedSubcommand {
872 SetModeanddatasetCombinations {
873 combination_index: u8,
874 mode_dataset: [u8; 8],
875 },
876 LockLpf2DeviceForSetup,
877 UnlockAndStartMultiEnabled,
878 UnlockAndStartMultiDisabled,
879 NotUsed,
880 ResetSensor,
881}
882
883impl InputSetupCombinedSubcommand {
884 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
885 use InputSetupCombinedSubcommand::*;
886
887 let comm = ok!(PortInputFormatSetupSubCommand::from_u8(next!(msg)));
888 Ok(match comm {
889 PortInputFormatSetupSubCommand::SetModeanddatasetCombinations => {
890 let combination_index = next!(msg);
891 let mut mode_dataset = [0_u8; 8];
892 for ele in mode_dataset.iter_mut() {
893 *ele = next!(msg);
894 }
895 SetModeanddatasetCombinations {
896 combination_index,
897 mode_dataset,
898 }
899 }
900 PortInputFormatSetupSubCommand::LockLpf2DeviceForSetup => {
901 LockLpf2DeviceForSetup
902 }
903 PortInputFormatSetupSubCommand::UnlockAndStartMultiEnabled => {
904 UnlockAndStartMultiEnabled
905 }
906
907 PortInputFormatSetupSubCommand::UnlockAndStartMultiDisabled => {
908 UnlockAndStartMultiDisabled
909 }
910 PortInputFormatSetupSubCommand::NotUsed => NotUsed,
911 PortInputFormatSetupSubCommand::ResetSensor => ResetSensor,
912 })
913 }
914}
915
916#[derive(Clone, Debug, PartialEq, Eq)]
917pub struct PortInformationValue {
918 pub port_id: u8,
919 pub information_type: PortInformationType,
920}
921
922impl PortInformationValue {
923 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
924 let port_id = next!(msg);
925 let information_type = PortInformationType::parse(&mut msg)?;
926 Ok(Self {
927 port_id,
928 information_type,
929 })
930 }
931}
932
933#[derive(Clone, Debug, PartialEq, Eq)]
934pub enum PortInformationType {
935 ModeInfo {
936 capabilities: PortCapabilities,
937 mode_count: u8,
938 input_modes: u16,
939 output_modes: u16,
940 },
941 PossibleModeCombinations(Vec<u8>),
942}
943
944impl PortInformationType {
945 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
946 use PortInformationType::*;
947
948 let mode = next!(msg);
949 match mode {
950 1 => {
951 let capabilities = PortCapabilities(next!(msg));
953 let mode_count = next!(msg);
954 let input_modes = next_u16!(msg);
955 let output_modes = next_u16!(msg);
956 Ok(ModeInfo {
957 capabilities,
958 mode_count,
959 input_modes,
960 output_modes,
961 })
962 }
963 2 => {
964 let combinations = msg.cloned().collect();
966 Ok(PossibleModeCombinations(combinations))
967 }
968 m => Err(Error::ParseError(format!(
969 "Invalid port information type {}",
970 m
971 ))),
972 }
973 }
974}
975
976#[derive(Clone, Debug, PartialEq, Eq)]
977pub struct PortCapabilities(pub u8);
978impl PortCapabilities {
979 pub const LOGICAL_SYNCHRONIZABLE: u8 = 0b1000;
980 pub const LOGICAL_COMBINABLE: u8 = 0b0100;
981 pub const INPUT: u8 = 0b0010;
982 pub const OUTPUT: u8 = 0b0001;
983}
984
985#[derive(Clone, Debug, PartialEq)]
986pub struct PortModeInformationValue {
987 pub port_id: u8,
988 pub mode: u8,
989 pub information_type: PortModeInformationType,
990}
991
992impl PortModeInformationValue {
993 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
994 let port_id = next!(msg);
995 let mode = next!(msg);
996 let information_type = PortModeInformationType::parse(&mut msg)?;
997 Ok(Self {
998 port_id,
999 mode,
1000 information_type,
1001 })
1002 }
1003}
1004
1005#[repr(u8)]
1006#[derive(Clone, Debug, PartialEq)]
1007pub enum PortModeInformationType {
1008 Name(Vec<u8>),
1009 RawRange {
1010 min: f32,
1011 max: f32,
1012 },
1013 PctRange {
1014 min: f32,
1015 max: f32,
1016 },
1017 SiRange {
1018 min: f32,
1019 max: f32,
1020 },
1021 Symbol(Vec<u8>),
1022 Mapping {
1023 input: MappingValue,
1024 output: MappingValue,
1025 },
1026 MotorBias(u8),
1027 CapabilityBits([u8; 6]),
1028 ValueFormat(ValueFormatType),
1029}
1030
1031impl PortModeInformationType {
1032 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
1033 use PortModeInformationType::*;
1034
1035 let info_type = next!(msg);
1036 Ok(match info_type {
1037 0 => {
1038 let name = msg.cloned().collect();
1040 Name(name)
1041 }
1042 1 => {
1043 let min = next_f32!(msg);
1045 let max = next_f32!(msg);
1046 RawRange { min, max }
1047 }
1048 2 => {
1049 let min = next_f32!(msg);
1051 let max = next_f32!(msg);
1052 PctRange { min, max }
1053 }
1054 3 => {
1055 let min = next_f32!(msg);
1057 let max = next_f32!(msg);
1058 SiRange { min, max }
1059 }
1060 4 => {
1061 let sym = msg.cloned().collect();
1063 Symbol(sym)
1064 }
1065 5 => {
1066 let input = MappingValue(next!(msg));
1070 let output = MappingValue(next!(msg));
1071 Mapping { input, output }
1072 }
1073 7 => {
1074 MotorBias(next!(msg))
1076 }
1077 8 => {
1078 let mut bits = [0_u8; 6];
1081 for ele in bits.iter_mut() {
1082 *ele = next!(msg);
1083 }
1084 CapabilityBits(bits)
1085 }
1086 128 => {
1087 let number_of_datasets = next!(msg);
1089 let dataset_type = DatasetType::parse(&mut msg)?;
1090 let total_figures = next!(msg);
1091 let decimals = next!(msg);
1092 ValueFormat(ValueFormatType {
1093 number_of_datasets,
1094 dataset_type,
1095 total_figures,
1096 decimals,
1097 })
1098 }
1099 t => {
1100 return Err(Error::ParseError(format!(
1101 "Invalid information type {}",
1102 t
1103 )))
1104 }
1105 })
1106 }
1107}
1108
1109#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
1110pub struct ValueFormatType {
1111 pub number_of_datasets: u8,
1112 pub dataset_type: DatasetType,
1113 pub total_figures: u8,
1114 pub decimals: u8,
1115}
1116impl fmt::Display for ValueFormatType {
1117 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1118 write!(
1119 f,
1120 "{:>4} value(s) of {:<8} Figures: {:<3} Decimals: {:<3}",
1121 self.number_of_datasets,
1122 self.dataset_type,
1123 self.total_figures,
1124 self.decimals
1125 )
1126 }
1127}
1128
1129#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1130pub struct MappingValue(pub u8);
1131impl MappingValue {
1132 pub const SUPPORTS_NULL: u8 = 0b1000_0000;
1133 pub const SUPPORTS_FUNCTIONAL2: u8 = 0b0100_0000;
1134 pub const ABS: u8 = 0b0001_0000;
1135 pub const REL: u8 = 0b0000_1000;
1136 pub const DIS: u8 = 0b0000_0100;
1137}
1138
1139#[repr(u8)]
1140#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, Parse, Default)]
1141pub enum DatasetType {
1142 #[default]
1143 Bits8 = 0b00,
1144 Bits16 = 0b01,
1145 Bits32 = 0b10,
1146 Float = 0b11,
1147}
1148impl fmt::Display for DatasetType {
1149 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1150 match *self {
1151 DatasetType::Bits8 => {
1152 write!(f, " 8 bit")
1153 }
1154 DatasetType::Bits16 => {
1155 write!(f, "16 bit")
1156 }
1157 DatasetType::Bits32 => {
1158 write!(f, "32 bit")
1159 }
1160 DatasetType::Float => {
1161 write!(f, "float ")
1162 }
1163 }
1164 }
1165}
1166
1167#[derive(Copy, Clone, Debug, PartialEq)]
1168pub enum TypedValue {
1169 Bits8(u8),
1170 Bits16(u16),
1171 Bits32(u32),
1172 Float(f32),
1173}
1174
1175#[derive(Clone, Debug, PartialEq, Eq)]
1199pub struct PortValueSingleFormat {
1200 pub port_id: u8,
1201 pub data: Vec<i8>,
1202}
1203impl PortValueSingleFormat {
1204 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
1205 let port_id = next!(msg);
1206 let data = msg.cloned().map(|x| x as i8).collect();
1207 Ok(Self { port_id, data })
1208 }
1209
1210 pub fn process(&self, _type_mapping: ()) -> HashMap<u8, TypedValue> {
1211 unimplemented!()
1212 }
1213}
1214
1215#[derive(Clone, Debug, PartialEq, Eq)]
1219pub struct PortValueCombinedFormat {
1220 pub port_id: u8,
1221 pub data: Vec<u8>,
1222}
1223
1224impl PortValueCombinedFormat {
1225 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
1226 let port_id = next!(msg);
1227 let data = msg.cloned().collect();
1228 Ok(Self { port_id, data })
1229 }
1230}
1231
1232#[derive(Clone, Debug, PartialEq, Eq)]
1233pub struct PortInputFormatSingleFormat {
1234 pub port_id: u8,
1235 pub mode: u8,
1236 pub delta: u32,
1237 pub notification_enabled: bool,
1238}
1239
1240impl PortInputFormatSingleFormat {
1241 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
1242 let port_id = next!(msg);
1243 let mode = next!(msg);
1244 let delta = next_u32!(msg);
1245 let notification_enabled = match next!(msg) {
1246 0 => Ok(false),
1247 1 => Ok(true),
1248 v => Err(Error::ParseError(format!(
1249 "Invalid notification enabled status {}",
1250 v
1251 ))),
1252 }?;
1253 Ok(Self {
1254 port_id,
1255 mode,
1256 delta,
1257 notification_enabled,
1258 })
1259 }
1260}
1261
1262#[derive(Clone, Debug, PartialEq, Eq)]
1263pub struct PortInputFormatCombinedFormat {
1264 port_id: u8,
1265 control: u8,
1266 combination_index: u8,
1267 multi_update: bool,
1268 mode_dataset_combination_pointer: u16,
1269}
1270
1271impl PortInputFormatCombinedFormat {
1272 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
1273 let port_id = next!(msg);
1274 let control = next!(msg);
1275
1276 let combination_index: u8 = 0; let multi_update = (control >> 7) != 0;
1281 let mode_dataset_combination_pointer = next_u16!(msg);
1282
1283 Ok(Self {
1284 port_id,
1285 control,
1286 combination_index,
1287 multi_update,
1288 mode_dataset_combination_pointer,
1289 })
1290 }
1291}
1292
1293#[derive(Clone, Debug, PartialEq, Eq)]
1294pub enum VirtualPortSetupFormat {
1295 Disconnect { port_id: u8 },
1296 Connect { port_a: u8, port_b: u8 },
1297}
1298
1299impl VirtualPortSetupFormat {
1300 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
1301 use VirtualPortSetupFormat::*;
1302 match next!(msg) {
1303 0 => {
1304 let port_id = next!(msg);
1306 Ok(Disconnect { port_id })
1307 }
1308 1 => {
1309 let port_a = next!(msg);
1311 let port_b = next!(msg);
1312 Ok(Connect { port_a, port_b })
1313 }
1314 c => Err(Error::ParseError(format!(
1315 "Invalid virtual port subcommand {}",
1316 c
1317 ))),
1318 }
1319 }
1320}
1321
1322#[derive(Clone, Debug, PartialEq, Eq)]
1323pub struct PortOutputCommandFormat {
1324 pub port_id: u8,
1325 pub startup_info: StartupInfo,
1326 pub completion_info: CompletionInfo,
1327 pub subcommand: PortOutputSubcommand,
1328}
1329
1330impl PortOutputCommandFormat {
1331 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
1332 let port_id = next!(msg);
1333 let startup_and_completion_byte = next!(msg);
1334 let startup_info = ok!(StartupInfo::from_u8(
1335 (startup_and_completion_byte & 0xf0) >> 4
1336 ));
1337 let completion_info =
1338 ok!(CompletionInfo::from_u8(startup_and_completion_byte & 0x0f));
1339 let subcommand = PortOutputSubcommand::parse(&mut msg)?;
1340
1341 Ok(Self {
1342 port_id,
1343 startup_info,
1344 completion_info,
1345 subcommand,
1346 })
1347 }
1348
1349 pub fn serialise(&self) -> Vec<u8> {
1350 use PortOutputSubcommand::*;
1351 let startup_and_completion_byte =
1352 ((self.startup_info as u8) << 4) + self.completion_info as u8;
1353 match &self.subcommand {
1354 WriteDirectModeData(data) => data.serialise(self),
1355 StartSpeed {
1356 speed,
1357 max_power,
1358 use_acc_profile,
1359 use_dec_profile,
1360 } => {
1361 let profile =
1362 ((*use_acc_profile as u8) << 1) | (*use_dec_profile as u8);
1363 let speed = speed.to_le_bytes()[0];
1364 let max_power = max_power.to_le_bytes()[0];
1365 vec![
1366 0, 0, MessageType::PortOutputCommand as u8,
1370 self.port_id,
1372 startup_and_completion_byte,
1374 PortOutputSubCommandValue::StartSpeed as u8,
1375 speed,
1377 max_power,
1378 profile,
1379 ]
1380 }
1381 StartSpeedForDegrees {
1382 degrees,
1383 speed,
1384 max_power,
1385 end_state,
1386 use_acc_profile,
1387 use_dec_profile,
1388 } => {
1389 let profile =
1390 ((*use_acc_profile as u8) << 1) | (*use_dec_profile as u8);
1391 let speed = speed.to_le_bytes()[0];
1392 let max_power = max_power.to_le_bytes()[0];
1393 let degrees = degrees.to_le_bytes();
1394 let mut bytes = vec![
1395 0, 0, MessageType::PortOutputCommand as u8,
1399 self.port_id,
1401 startup_and_completion_byte,
1402 PortOutputSubCommandValue::StartSpeedForDegrees as u8,
1403 ];
1404 bytes.extend_from_slice(°rees);
1406 bytes.push(speed);
1407 bytes.push(max_power);
1408 bytes.push(end_state.to_u8());
1409 bytes.push(profile);
1410
1411 bytes
1412 }
1413 GotoAbsolutePosition {
1414 abs_pos,
1415 speed,
1416 max_power,
1417 end_state,
1418 use_acc_profile,
1419 use_dec_profile,
1420 } => {
1421 let profile =
1422 ((*use_acc_profile as u8) << 1) | (*use_dec_profile as u8);
1423 let speed = speed.to_le_bytes()[0];
1424 let max_power = max_power.to_le_bytes()[0];
1425 let abs_pos = abs_pos.to_le_bytes();
1426 let mut bytes = vec![
1427 0, 0, MessageType::PortOutputCommand as u8,
1431 self.port_id,
1433 startup_and_completion_byte,
1434 PortOutputSubCommandValue::GotoAbsolutePosition as u8,
1435 ];
1436 bytes.extend_from_slice(&abs_pos);
1438 bytes.push(speed);
1439 bytes.push(max_power);
1440 bytes.push(end_state.to_u8());
1441 bytes.push(profile);
1442
1443 bytes
1444 }
1445 StartSpeedForTime {
1446 time,
1447 speed,
1448 max_power,
1449 end_state,
1450 use_acc_profile,
1451 use_dec_profile,
1452 } => {
1453 let profile =
1454 ((*use_acc_profile as u8) << 1) | (*use_dec_profile as u8);
1455 let speed = speed.to_le_bytes()[0];
1456 let max_power = max_power.to_le_bytes()[0];
1457 dbg!(time);
1458 let time = time.to_le_bytes();
1459 dbg!(time);
1460 let mut bytes = vec![
1461 0, 0, MessageType::PortOutputCommand as u8,
1465 self.port_id,
1467 startup_and_completion_byte,
1468 PortOutputSubCommandValue::StartSpeedForTime as u8,
1469 ];
1470 bytes.extend_from_slice(&time);
1472 bytes.push(speed);
1473 bytes.push(max_power);
1474 bytes.push(end_state.to_u8());
1475 bytes.push(profile);
1476
1477 bytes
1478 }
1479 SetAccTime {
1480 time,
1481 profile_number,
1482 } => {
1483 let time = time.to_le_bytes();
1484 let profile_number = profile_number.to_le_bytes();
1485 let mut bytes = vec![
1486 0, 0, MessageType::PortOutputCommand as u8,
1490 self.port_id,
1492 startup_and_completion_byte,
1493 PortOutputSubCommandValue::SetAccTime as u8,
1494 ];
1495 bytes.extend_from_slice(&time);
1497 bytes.extend_from_slice(&profile_number);
1498
1499 bytes
1500 }
1501 SetDecTime {
1502 time,
1503 profile_number,
1504 } => {
1505 let time = time.to_le_bytes();
1506 let profile_number = profile_number.to_le_bytes();
1507 let mut bytes = vec![
1508 0, 0, MessageType::PortOutputCommand as u8,
1512 self.port_id,
1514 startup_and_completion_byte,
1515 PortOutputSubCommandValue::SetDecTime as u8,
1516 ];
1517 bytes.extend_from_slice(&time);
1519 bytes.extend_from_slice(&profile_number);
1520
1521 bytes
1522 }
1523 _ => todo!(),
1524 }
1525 }
1526}
1527
1528#[repr(u8)]
1529#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive)]
1530pub enum StartupInfo {
1531 BufferIfNecessary = 0b0000,
1532 ExecuteImmediately = 0b0001,
1533}
1534
1535#[repr(u8)]
1536#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive)]
1537pub enum CompletionInfo {
1538 NoAction = 0b0000,
1539 CommandFeedback = 0b0001,
1540}
1541
1542impl StartupInfo {
1543 pub fn serialise(&self, completion: &CompletionInfo) -> u8 {
1544 ((*self as u8) << 4) | (*completion as u8)
1545 }
1546}
1547
1548#[derive(Clone, Debug, PartialEq, Eq)]
1549pub enum PortOutputSubcommand {
1550 StartPower2 {
1556 power1: Power,
1557 power2: Power,
1558 },
1559 SetAccTime {
1560 time: i16,
1561 profile_number: i8,
1562 },
1563 SetDecTime {
1564 time: i16,
1565 profile_number: i8,
1566 },
1567 StartSpeed {
1568 speed: i8,
1569 max_power: u8,
1570 use_acc_profile: bool,
1571 use_dec_profile: bool,
1572 },
1573 StartSpeedNoPower {
1574 speed: i8,
1575 max_power: u8,
1576 use_acc_profile: bool,
1577 use_dec_profile: bool,
1578 },
1579 StartSpeed2 {
1580 speed1: i8,
1581 speed2: i8,
1582 max_power: u8,
1583 use_acc_profile: bool,
1584 use_dec_profile: bool,
1585 },
1586 StartSpeedForTime {
1587 time: i16,
1588 speed: i8,
1589 max_power: u8,
1590 end_state: EndState,
1591 use_acc_profile: bool,
1592 use_dec_profile: bool,
1593 },
1594 StartSpeedForTime2 {
1595 time: i16,
1596 speed_l: i8,
1597 speed_r: i8,
1598 max_power: u8,
1599 end_state: EndState,
1600 use_acc_profile: bool,
1601 use_dec_profile: bool,
1602 },
1603 StartSpeedForDegrees {
1604 degrees: i32,
1605 speed: i8,
1606 max_power: u8,
1607 end_state: EndState,
1608 use_acc_profile: bool,
1609 use_dec_profile: bool,
1610 },
1611 StartSpeedForDegrees2 {
1612 degrees: i32,
1613 speed_l: i8,
1614 speed_r: i8,
1615 max_power: u8,
1616 end_state: EndState,
1617 use_acc_profile: bool,
1618 use_dec_profile: bool,
1619 },
1620 GotoAbsolutePosition {
1621 abs_pos: i32,
1622 speed: i8,
1623 max_power: u8,
1624 end_state: EndState,
1625 use_acc_profile: bool,
1626 use_dec_profile: bool,
1627 },
1628 GotoAbsolutePosition2 {
1629 abs_pos1: i32,
1630 abs_pos2: i32,
1631 speed: i8,
1632 max_power: u8,
1633 end_state: EndState,
1634 use_acc_profile: bool,
1635 use_dec_profile: bool,
1636 },
1637 PresetEncoder2 {
1638 left_position: i32,
1639 right_position: i32,
1640 },
1641 WriteDirect(WriteDirectPayload),
1642 WriteDirectModeData(WriteDirectModeDataPayload),
1643}
1644
1645impl PortOutputSubcommand {
1646 pub const POWER_FLOAT: i8 = 0;
1647 pub const POWER_BRAKE: i8 = 127;
1648
1649 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
1650 use PortOutputSubcommand::*;
1651
1652 let subcomm = next!(msg);
1653 trace!("Port output subcommand: {:x}", subcomm);
1654 Ok(match subcomm {
1655 0x02 => {
1656 let power1 = Power::parse(&mut msg)?;
1658 let power2 = Power::parse(&mut msg)?;
1659 StartPower2 { power1, power2 }
1660 }
1661 0x05 => {
1662 let time = next_i16!(msg);
1664 let profile_number = next_i8!(msg);
1665 SetAccTime {
1666 time,
1667 profile_number,
1668 }
1669 }
1670 0x06 => {
1671 let time = next_i16!(msg);
1673 let profile_number = next_i8!(msg);
1674 SetDecTime {
1675 time,
1676 profile_number,
1677 }
1678 }
1679 0x07 => {
1680 let speed = next_i8!(msg);
1682 let max_power = next!(msg);
1683 let use_prof = next!(msg);
1684 let use_acc_profile = (use_prof & 0x01) != 0;
1685 let use_dec_profile = (use_prof & 0x02) != 0;
1686 StartSpeed {
1687 speed,
1688 max_power,
1689 use_acc_profile,
1690 use_dec_profile,
1691 }
1692 }
1693 0x08 => {
1694 let speed1 = next_i8!(msg);
1696 let speed2 = next_i8!(msg);
1697 let max_power = next!(msg);
1698 let use_prof = next!(msg);
1699 let use_acc_profile = (use_prof & 0x01) != 0;
1700 let use_dec_profile = (use_prof & 0x02) != 0;
1701 StartSpeed2 {
1702 speed1,
1703 speed2,
1704 max_power,
1705 use_acc_profile,
1706 use_dec_profile,
1707 }
1708 }
1709 0x09 => {
1710 let time = next_i16!(msg);
1712 let speed = next_i8!(msg);
1713 let max_power = next!(msg);
1714 let end_state = EndState::parse(&mut msg)?;
1715 let use_prof = next!(msg);
1716 let use_acc_profile = (use_prof & 0x01) != 0;
1717 let use_dec_profile = (use_prof & 0x02) != 0;
1718 StartSpeedForTime {
1719 time,
1720 speed,
1721 max_power,
1722 end_state,
1723 use_acc_profile,
1724 use_dec_profile,
1725 }
1726 }
1727 0x0a => {
1728 let time = next_i16!(msg);
1731 let speed_l = next_i8!(msg);
1732 let speed_r = next_i8!(msg);
1733 let max_power = next!(msg);
1734 let end_state = EndState::parse(&mut msg)?;
1735 let use_prof = next!(msg);
1736 let use_acc_profile = (use_prof & 0x01) != 0;
1737 let use_dec_profile = (use_prof & 0x02) != 0;
1738 StartSpeedForTime2 {
1739 time,
1740 speed_l,
1741 speed_r,
1742 max_power,
1743 end_state,
1744 use_acc_profile,
1745 use_dec_profile,
1746 }
1747 }
1748 0x0b => {
1749 let degrees = next_i32!(msg);
1752 let speed = next_i8!(msg);
1753 let max_power = next!(msg);
1754 let end_state = EndState::parse(&mut msg)?;
1755 let use_prof = next!(msg);
1756 let use_acc_profile = (use_prof & 0x01) != 0;
1757 let use_dec_profile = (use_prof & 0x02) != 0;
1758 StartSpeedForDegrees {
1759 degrees,
1760 speed,
1761 max_power,
1762 end_state,
1763 use_acc_profile,
1764 use_dec_profile,
1765 }
1766 }
1767 0x0c => {
1768 let degrees = next_i32!(msg);
1771 let speed_l = next_i8!(msg);
1772 let speed_r = next_i8!(msg);
1773 let max_power = next!(msg);
1774 let end_state = EndState::parse(&mut msg)?;
1775 let use_prof = next!(msg);
1776 let use_acc_profile = (use_prof & 0x01) != 0;
1777 let use_dec_profile = (use_prof & 0x02) != 0;
1778 StartSpeedForDegrees2 {
1779 degrees,
1780 speed_l,
1781 speed_r,
1782 max_power,
1783 end_state,
1784 use_acc_profile,
1785 use_dec_profile,
1786 }
1787 }
1788 0x0d => {
1789 let abs_pos = next_i32!(msg);
1792 let speed = next_i8!(msg);
1793 let max_power = next!(msg);
1794 let end_state = EndState::parse(&mut msg)?;
1795 let use_prof = next!(msg);
1796 let use_acc_profile = (use_prof & 0x01) != 0;
1797 let use_dec_profile = (use_prof & 0x02) != 0;
1798 GotoAbsolutePosition {
1799 abs_pos,
1800 speed,
1801 max_power,
1802 end_state,
1803 use_acc_profile,
1804 use_dec_profile,
1805 }
1806 }
1807 0x0e => {
1808 let abs_pos1 = next_i32!(msg);
1811 let abs_pos2 = next_i32!(msg);
1812 let speed = next_i8!(msg);
1813 let max_power = next!(msg);
1814 let end_state = EndState::parse(&mut msg)?;
1815 let use_prof = next!(msg);
1816 let use_acc_profile = (use_prof & 0x01) != 0;
1817 let use_dec_profile = (use_prof & 0x02) != 0;
1818 GotoAbsolutePosition2 {
1819 abs_pos1,
1820 abs_pos2,
1821 speed,
1822 max_power,
1823 end_state,
1824 use_acc_profile,
1825 use_dec_profile,
1826 }
1827 }
1828 0x14 => {
1829 let left_position = next_i32!(msg);
1831 let right_position = next_i32!(msg);
1832 PresetEncoder2 {
1833 left_position,
1834 right_position,
1835 }
1836 }
1837 0x50 => {
1838 let data = WriteDirectPayload::parse(&mut msg)?;
1840 WriteDirect(data)
1841 }
1842 0x51 => {
1843 let data = WriteDirectModeDataPayload::parse(&mut msg)?;
1845 WriteDirectModeData(data)
1846 }
1847 c => {
1848 return Err(Error::ParseError(format!(
1849 "Invalid port output subcommand {}",
1850 c
1851 )))
1852 }
1853 })
1854 }
1855}
1856
1857#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1858pub enum Speed {
1859 Cw(u8),
1860 Ccw(u8),
1861 Hold,
1862}
1863
1864impl Speed {
1865 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
1866 let val = next_i8!(msg);
1867 Speed::from_i8(val)
1868 }
1869
1870 pub fn to_u8(&self) -> u8 {
1871 use Speed::*;
1872 let integer: i8 = match self {
1873 Hold => 0,
1874 Cw(p) => *p as i8,
1875 Ccw(p) => -(*p as i8),
1876 };
1877 integer.to_le_bytes()[0]
1878 }
1879
1880 pub fn from_i8(val: i8) -> Result<Self> {
1881 use Speed::*;
1882 match val {
1883 0 => Ok(Hold),
1884 p if (1..=100).contains(&p) => Ok(Cw(p as u8)),
1885 p if (-100..=-1).contains(&p) => Ok(Ccw((-p) as u8)),
1886 p => Err(Error::ParseError(format!(
1887 "Invalid value for Speed: {}",
1888 p
1889 ))),
1890 }
1891 }
1892}
1893
1894#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1895pub enum Power {
1896 Cw(u8),
1897 Ccw(u8),
1898 Float,
1899 Brake,
1900}
1901
1902impl Power {
1903 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
1904 let val = next_i8!(msg);
1905 Power::from_i8(val)
1906 }
1907
1908 pub fn to_u8(&self) -> u8 {
1909 use Power::*;
1910 let integer: i8 = match self {
1911 Float => 0,
1912 Brake => 127,
1913 Cw(p) => *p as i8,
1914 Ccw(p) => -(*p as i8),
1915 };
1916 integer.to_le_bytes()[0]
1917 }
1918
1919 pub fn from_i8(val: i8) -> Result<Self> {
1920 use Power::*;
1921 match val {
1922 0 => Ok(Float),
1923 127 => Ok(Brake),
1924 p if (1..=100).contains(&p) => Ok(Cw(p as u8)),
1925 p if (-100..=-1).contains(&p) => Ok(Ccw((-p) as u8)),
1926 p => Err(Error::ParseError(format!(
1927 "Invalid value for power: {}",
1928 p
1929 ))),
1930 }
1931 }
1932}
1933
1934#[derive(Clone, Debug, PartialEq, Eq)]
1935pub enum WriteDirectPayload {
1936 TiltFactoryCalibration {
1937 orientation: CalibrationOrientation,
1938 pass_code: String,
1939 },
1940 HardwareReset,
1941}
1942
1943impl WriteDirectPayload {
1944 pub fn parse<'a>(_msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
1945 todo!()
1946 }
1947}
1948
1949#[repr(i8)]
1950#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive)]
1951pub enum CalibrationOrientation {
1952 LayingFlat = 1,
1953 Standing = 2,
1954}
1955
1956impl CalibrationOrientation {
1957 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
1958 Ok(ok!(Self::from_i8(next_i8!(msg))))
1959 }
1960}
1961
1962#[repr(u8)]
1963#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, Parse)]
1964pub enum EndState {
1965 Float = 0,
1966 Hold = 126,
1967 Brake = 127,
1968}
1969impl EndState {
1970 pub fn to_u8(&self) -> u8 {
1971 use EndState::*;
1972 let integer: u8 = match self {
1973 Float => 0,
1974 Hold => 126,
1975 Brake => 127,
1976 };
1977 integer.to_le_bytes()[0]
1978 }
1979}
1980
1981#[derive(Clone, Debug, PartialEq, Eq)]
1982pub enum WriteDirectModeDataPayload {
1983 StartPower(Power),
1984 PresetEncoder(i32),
1992 TiltImpactPreset(i32),
1993 TiltConfigOrientation(Orientation),
1994 TiltConfigImpact {
1995 impact_threshold: i8,
1996 bump_holdoff: i8,
1997 },
1998 TiltFactoryCalibration(i8),
1999 SetHubColor(i8),
2000 SetHubRgb {
2001 red: u8,
2002 green: u8,
2003 blue: u8,
2004 },
2005 SetVisionSensorColor(i8),
2006}
2007
2008impl WriteDirectModeDataPayload {
2009 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
2010 use WriteDirectModeDataPayload::*;
2011
2012 let mode = next!(msg);
2013 Ok(match mode {
2014 0x01 => {
2015 let power = Power::parse(&mut msg)?;
2018 StartPower(power)
2019 }
2020 0x02 => {
2021 let position = next_i32!(msg);
2023 PresetEncoder(position)
2024 }
2025 0x03 => {
2026 let preset_value = next_i32!(msg);
2029 TiltImpactPreset(preset_value)
2030 }
2031 0x05 => {
2032 let orientation = Orientation::parse(&mut msg)?;
2035 TiltConfigOrientation(orientation)
2036 }
2037 0x06 => {
2038 let impact_threshold = next_i8!(msg);
2041 let bump_holdoff = next_i8!(msg);
2042 TiltConfigImpact {
2043 impact_threshold,
2044 bump_holdoff,
2045 }
2046 }
2047 0x07 => {
2048 let orientation = next_i8!(msg);
2051 TiltFactoryCalibration(orientation)
2053 }
2054 0x08 => {
2055 let col = next_i8!(msg);
2057 SetHubColor(col)
2058 }
2059 0x09 => {
2060 let red = next!(msg);
2062 let green = next!(msg);
2063 let blue = next!(msg);
2064 SetHubRgb { red, green, blue }
2065 }
2066 m => {
2067 return Err(Error::ParseError(format!(
2068 "Invalid write direct mode {}",
2069 m
2070 )))
2071 }
2072 })
2073 }
2074
2075 pub fn serialise(&self, meta: &PortOutputCommandFormat) -> Vec<u8> {
2076 use WriteDirectModeDataPayload::*;
2077 match self {
2078 SetHubRgb { red, green, blue } => {
2079 let startup_and_completion =
2080 meta.startup_info.serialise(&meta.completion_info);
2081 vec![
2082 0,
2083 0, MessageType::PortOutputCommand as u8,
2085 meta.port_id,
2086 startup_and_completion,
2087 0x51, crate::iodevice::modes::HubLed::RGB_O,
2090 *red,
2091 *green,
2092 *blue,
2093 ]
2094 }
2095 SetHubColor(c) => {
2096 let startup_and_completion =
2097 meta.startup_info.serialise(&meta.completion_info);
2098 vec![
2099 0,
2100 0, MessageType::PortOutputCommand as u8,
2102 meta.port_id,
2103 startup_and_completion,
2104 0x51, crate::iodevice::modes::HubLed::COL_O,
2106 *c as u8,
2107 ]
2108 }
2109 StartPower(p) => {
2110 let startup_and_completion =
2111 meta.startup_info.serialise(&meta.completion_info);
2112 let power = p.to_u8();
2113 vec![
2114 0,
2115 0, MessageType::PortOutputCommand as u8,
2117 meta.port_id,
2118 startup_and_completion,
2119 0x51, crate::iodevice::modes::InternalMotorTacho::POWER,
2121 power,
2122 ]
2123 }
2124 PresetEncoder(position) => {
2125 let startup_and_completion =
2126 meta.startup_info.serialise(&meta.completion_info);
2127 let pos_bytes: [u8; 4] = position.to_le_bytes(); vec![
2129 0,
2130 0, MessageType::PortOutputCommand as u8,
2132 meta.port_id,
2133 startup_and_completion,
2134 0x51, crate::iodevice::modes::InternalMotorTacho::POS,
2136 pos_bytes[0],
2137 pos_bytes[1],
2138 pos_bytes[2],
2139 pos_bytes[3],
2140 ]
2141 }
2142 TiltImpactPreset(preset_value) => {
2144 let startup_and_completion =
2145 meta.startup_info.serialise(&meta.completion_info);
2146 let val_bytes: [u8; 4] = preset_value.to_le_bytes(); vec![
2148 0,
2149 0, MessageType::PortOutputCommand as u8,
2151 meta.port_id,
2152 startup_and_completion,
2153 0x51, crate::iodevice::modes::InternalTilt::IMPCT,
2155 val_bytes[0],
2156 val_bytes[1],
2157 val_bytes[2],
2158 val_bytes[3],
2159 ]
2160 }
2161 TiltConfigOrientation(orientation) => {
2163 let startup_and_completion =
2164 meta.startup_info.serialise(&meta.completion_info);
2165 vec![
2166 0,
2167 0, MessageType::PortOutputCommand as u8,
2169 meta.port_id,
2170 startup_and_completion,
2171 0x51, crate::iodevice::modes::InternalTilt::OR_CF,
2173 *orientation as u8,
2174 ]
2175 }
2176 TiltConfigImpact {
2178 impact_threshold,
2179 bump_holdoff,
2180 } => {
2181 let startup_and_completion =
2182 meta.startup_info.serialise(&meta.completion_info);
2183 vec![
2184 0,
2185 0, MessageType::PortOutputCommand as u8,
2187 meta.port_id,
2188 startup_and_completion,
2189 0x51, crate::iodevice::modes::InternalTilt::IM_CF,
2191 *impact_threshold as u8,
2192 *bump_holdoff as u8,
2193 ]
2194 }
2195 TiltFactoryCalibration(orientation) => {
2197 let startup_and_completion =
2198 meta.startup_info.serialise(&meta.completion_info);
2199 vec![
2200 0,
2201 0, MessageType::PortOutputCommand as u8,
2203 meta.port_id,
2204 startup_and_completion,
2205 0x51, crate::iodevice::modes::InternalTilt::CALIB,
2207 *orientation as u8,
2208 b'C',
2209 b'a',
2210 b'l',
2211 b'i',
2212 b'b',
2213 b'-',
2214 b'S',
2215 b'e',
2216 b'n',
2217 b's',
2218 b'o',
2219 b'r',
2220 ]
2221 }
2222 SetVisionSensorColor(c) => {
2223 let startup_and_completion =
2224 meta.startup_info.serialise(&meta.completion_info);
2225 vec![
2226 0,
2227 0, MessageType::PortOutputCommand as u8,
2229 meta.port_id,
2230 startup_and_completion,
2231 0x51, crate::iodevice::modes::VisionSensor::COL_O,
2233 *c as u8,
2234 ]
2235 }
2236 }
2237 }
2238}
2239
2240#[repr(i8)]
2241#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive)]
2242pub enum Orientation {
2243 Bottom = 0,
2244 Front = 1,
2245 Back = 2,
2246 Left = 3,
2247 Right = 4,
2248 Top = 5,
2249 UseActualAsBottomReference = 6,
2250}
2251
2252impl Orientation {
2253 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
2254 Ok(ok!(Self::from_i8(next_i8!(msg))))
2255 }
2256}
2257
2258#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2259pub struct PortOutputCommandFeedbackFormat {
2260 pub msg1: FeedbackMessage,
2261 pub msg2: Option<FeedbackMessage>,
2262 pub msg3: Option<FeedbackMessage>,
2263}
2264
2265impl PortOutputCommandFeedbackFormat {
2266 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
2267 let msg1 = FeedbackMessage::parse(&mut msg)?;
2268 let msg2 = FeedbackMessage::parse(&mut msg).ok();
2269 let msg3 = FeedbackMessage::parse(&mut msg).ok();
2270 Ok(PortOutputCommandFeedbackFormat { msg1, msg2, msg3 })
2271 }
2272}
2273
2274#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2275pub struct FeedbackMessage {
2276 pub port_id: u8,
2277 pub empty_cmd_in_progress: bool, pub empty_cmd_completed: bool, pub discarded: bool, pub idle: bool, pub busy_full: bool, }
2283
2284impl FeedbackMessage {
2285 pub fn parse<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<Self> {
2286 let port_id = next!(msg);
2287 let bitfields = next!(msg);
2288 let empty_cmd_in_progress = (bitfields & 0x01) != 0;
2289 let empty_cmd_completed = (bitfields & 0x02) != 0;
2290 let discarded = (bitfields & 0x04) != 0;
2291 let idle = (bitfields & 0x08) != 0;
2292 let busy_full = (bitfields & 0x10) != 0;
2293 Ok(FeedbackMessage {
2294 port_id,
2295 empty_cmd_in_progress,
2296 empty_cmd_completed,
2297 discarded,
2298 idle,
2299 busy_full,
2300 })
2301 }
2302}