1use super::command::Command;
43use crate::traits::{ParamValue, ParameterId, PortId};
44use std::fmt;
45use std::time::{SystemTime, UNIX_EPOCH};
46
47#[derive(Debug, Clone, PartialEq, Eq, Hash)]
56pub enum SignalOrigin {
57 Automaton(String),
59 Sensor(String),
61 Servo(String),
63 External(String),
65 Manual,
67 Script,
69}
70
71impl SignalOrigin {
72 pub fn name(&self) -> &str {
74 match self {
75 SignalOrigin::Automaton(name) => name,
76 SignalOrigin::Sensor(name) => name,
77 SignalOrigin::Servo(name) => name,
78 SignalOrigin::External(name) => name,
79 SignalOrigin::Manual => "manual",
80 SignalOrigin::Script => "script",
81 }
82 }
83
84 pub fn kind(&self) -> &'static str {
86 match self {
87 SignalOrigin::Automaton(_) => "automaton",
88 SignalOrigin::Sensor(_) => "sensor",
89 SignalOrigin::Servo(_) => "servo",
90 SignalOrigin::External(_) => "external",
91 SignalOrigin::Manual => "manual",
92 SignalOrigin::Script => "script",
93 }
94 }
95}
96
97impl fmt::Display for SignalOrigin {
98 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99 match self {
100 SignalOrigin::Automaton(name) => write!(f, "⚙️ {}", name),
101 SignalOrigin::Sensor(name) => write!(f, "👁️ {}", name),
102 SignalOrigin::Servo(name) => write!(f, "🦾 {}", name),
103 SignalOrigin::External(name) => write!(f, "🌍 {}", name),
104 SignalOrigin::Manual => write!(f, "👤 manual"),
105 SignalOrigin::Script => write!(f, "📜 script"),
106 }
107 }
108}
109
110#[derive(Debug, Clone)]
114pub struct SetParameter {
115 pub port: PortId,
117 pub parameter: ParameterId,
119 pub value: ParamValue,
121 pub source: SignalOrigin,
123 pub timestamp: u64,
125}
126
127impl SetParameter {
128 pub fn new(
130 port: PortId,
131 parameter: ParameterId,
132 value: ParamValue,
133 source: SignalOrigin,
134 ) -> Self {
135 Self {
136 port,
137 parameter,
138 value,
139 source,
140 timestamp: Self::now(),
141 }
142 }
143
144 pub fn with_timestamp(
146 port: PortId,
147 parameter: ParameterId,
148 value: ParamValue,
149 source: SignalOrigin,
150 timestamp: u64,
151 ) -> Self {
152 Self {
153 port,
154 parameter,
155 value,
156 source,
157 timestamp,
158 }
159 }
160
161 pub fn now() -> u64 {
163 SystemTime::now()
164 .duration_since(UNIX_EPOCH)
165 .unwrap_or_default()
166 .as_micros() as u64
167 }
168}
169
170impl PartialEq for SetParameter {
171 fn eq(&self, other: &Self) -> bool {
172 self.port == other.port
173 && self.parameter == other.parameter
174 && self.value == other.value
175 && self.source == other.source
176 }
177}
178
179impl fmt::Display for SetParameter {
180 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181 write!(
182 f,
183 "[{}] {} → {}::{} = {:?}",
184 self.timestamp, self.source, self.port, self.parameter, self.value
185 )
186 }
187}
188
189impl Command for SetParameter {}
191
192#[derive(Debug, Clone)]
196pub enum AutomatonCommand {
197 SetEnabled {
199 id: String,
201 enabled: bool,
203 },
204 SetParameter {
206 id: String,
208 name: String,
210 value: f32,
212 },
213 Reset {
215 id: String,
217 },
218 Connect {
220 from: String,
222 to: String,
224 gain: f32,
226 },
227 Disconnect {
229 from: String,
231 to: String,
233 },
234 Create {
236 kind: String,
238 id: String,
240 params: Vec<(String, f32)>,
242 },
243 Destroy {
245 id: String,
247 },
248}
249
250impl AutomatonCommand {
251 pub fn automaton_id(&self) -> Option<&str> {
253 match self {
254 AutomatonCommand::SetEnabled { id, .. } => Some(id),
255 AutomatonCommand::SetParameter { id, .. } => Some(id),
256 AutomatonCommand::Reset { id } => Some(id),
257 AutomatonCommand::Connect { from, to: _to, .. } => Some(from),
258 AutomatonCommand::Disconnect { from, to: _to } => Some(from),
259 AutomatonCommand::Create { id, .. } => Some(id),
260 AutomatonCommand::Destroy { id } => Some(id),
261 }
262 }
263}
264
265impl fmt::Display for AutomatonCommand {
266 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
267 match self {
268 AutomatonCommand::SetEnabled { id, enabled } => {
269 write!(f, "Automaton[{}] set_enabled({})", id, enabled)
270 }
271 AutomatonCommand::SetParameter { id, name, value } => {
272 write!(f, "Automaton[{}] set_param({}={:.2})", id, name, value)
273 }
274 AutomatonCommand::Reset { id } => {
275 write!(f, "Automaton[{}] reset()", id)
276 }
277 AutomatonCommand::Connect { from, to, gain } => {
278 write!(f, "Automaton connect {} → {} gain={:.2}", from, to, gain)
279 }
280 AutomatonCommand::Disconnect { from, to } => {
281 write!(f, "Automaton disconnect {} → {}", from, to)
282 }
283 AutomatonCommand::Create { kind, id, params } => {
284 write!(
285 f,
286 "Automaton create {} as {} with {} params",
287 kind,
288 id,
289 params.len()
290 )
291 }
292 AutomatonCommand::Destroy { id } => {
293 write!(f, "Automaton destroy {}", id)
294 }
295 }
296 }
297}
298
299impl Command for AutomatonCommand {}
300
301#[derive(Debug, Clone)]
305pub enum CalibrationKind {
306 Auto,
308 SetCurrentAsMin,
310 SetCurrentAsMax,
312 Reset,
314}
315
316impl fmt::Display for CalibrationKind {
317 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
318 match self {
319 CalibrationKind::Auto => write!(f, "auto"),
320 CalibrationKind::SetCurrentAsMin => write!(f, "set_min"),
321 CalibrationKind::SetCurrentAsMax => write!(f, "set_max"),
322 CalibrationKind::Reset => write!(f, "reset"),
323 }
324 }
325}
326
327#[derive(Debug, Clone)]
329pub enum SensorCommand {
330 StartListening {
332 id: String,
334 source: String,
336 },
337 StopListening {
339 id: String,
341 },
342 SetSensitivity {
344 id: String,
346 value: f32,
348 },
349 Calibrate {
351 id: String,
353 kind: CalibrationKind,
355 },
356 SetEnabled {
358 id: String,
360 enabled: bool,
362 },
363}
364
365impl SensorCommand {
366 pub fn sensor_id(&self) -> &str {
368 match self {
369 SensorCommand::StartListening { id, .. } => id,
370 SensorCommand::StopListening { id } => id,
371 SensorCommand::SetSensitivity { id, .. } => id,
372 SensorCommand::Calibrate { id, .. } => id,
373 SensorCommand::SetEnabled { id, .. } => id,
374 }
375 }
376}
377
378impl fmt::Display for SensorCommand {
379 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
380 match self {
381 SensorCommand::StartListening { id, source } => {
382 write!(f, "Sensor[{}] start listening to {}", id, source)
383 }
384 SensorCommand::StopListening { id } => {
385 write!(f, "Sensor[{}] stop listening", id)
386 }
387 SensorCommand::SetSensitivity { id, value } => {
388 write!(f, "Sensor[{}] set sensitivity to {:.2}", id, value)
389 }
390 SensorCommand::Calibrate { id, kind } => {
391 write!(f, "Sensor[{}] calibrate {}", id, kind)
392 }
393 SensorCommand::SetEnabled { id, enabled } => {
394 write!(f, "Sensor[{}] set enabled({})", id, enabled)
395 }
396 }
397 }
398}
399
400impl Command for SensorCommand {}
401
402#[derive(Debug, Clone)]
406pub enum MappingType {
407 Linear,
409 Exponential,
411 Logarithmic,
413 Inverted,
415 Custom(String),
417}
418
419impl fmt::Display for MappingType {
420 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
421 match self {
422 MappingType::Linear => write!(f, "linear"),
423 MappingType::Exponential => write!(f, "exponential"),
424 MappingType::Logarithmic => write!(f, "logarithmic"),
425 MappingType::Inverted => write!(f, "inverted"),
426 MappingType::Custom(s) => write!(f, "custom({})", s),
427 }
428 }
429}
430
431#[derive(Debug, Clone)]
433pub enum ServoCommand {
434 BindToAutomaton {
436 servo_id: String,
438 automaton_id: String,
440 },
441 BindToParameter {
443 servo_id: String,
445 port: PortId,
447 parameter: ParameterId,
449 },
450 Unbind {
452 servo_id: String,
454 },
455 SetRange {
457 servo_id: String,
459 min: f32,
461 max: f32,
463 },
464 SetMapping {
466 servo_id: String,
468 mapping: MappingType,
470 },
471 SetEnabled {
473 servo_id: String,
475 enabled: bool,
477 },
478}
479
480impl ServoCommand {
481 pub fn servo_id(&self) -> &str {
483 match self {
484 ServoCommand::BindToAutomaton { servo_id, .. } => servo_id,
485 ServoCommand::BindToParameter { servo_id, .. } => servo_id,
486 ServoCommand::Unbind { servo_id } => servo_id,
487 ServoCommand::SetRange { servo_id, .. } => servo_id,
488 ServoCommand::SetMapping { servo_id, .. } => servo_id,
489 ServoCommand::SetEnabled { servo_id, .. } => servo_id,
490 }
491 }
492}
493
494impl fmt::Display for ServoCommand {
495 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
496 match self {
497 ServoCommand::BindToAutomaton {
498 servo_id,
499 automaton_id,
500 } => {
501 write!(f, "Servo[{}] bind to automaton {}", servo_id, automaton_id)
502 }
503 ServoCommand::BindToParameter {
504 servo_id,
505 port,
506 parameter,
507 } => {
508 write!(f, "Servo[{}] bind to {}::{}", servo_id, port, parameter)
509 }
510 ServoCommand::Unbind { servo_id } => {
511 write!(f, "Servo[{}] unbind", servo_id)
512 }
513 ServoCommand::SetRange { servo_id, min, max } => {
514 write!(f, "Servo[{}] set range [{}, {}]", servo_id, min, max)
515 }
516 ServoCommand::SetMapping { servo_id, mapping } => {
517 write!(f, "Servo[{}] set mapping {}", servo_id, mapping)
518 }
519 ServoCommand::SetEnabled { servo_id, enabled } => {
520 write!(f, "Servo[{}] set enabled({})", servo_id, enabled)
521 }
522 }
523 }
524}
525
526impl Command for ServoCommand {}
527
528#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
532pub enum CommandType {
533 SetParameter,
535 Automaton,
537 Sensor,
539 Servo,
541 System,
543}
544
545impl fmt::Display for CommandType {
546 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
547 match self {
548 CommandType::SetParameter => write!(f, "SetParameter"),
549 CommandType::Automaton => write!(f, "Automaton"),
550 CommandType::Sensor => write!(f, "Sensor"),
551 CommandType::Servo => write!(f, "Servo"),
552 CommandType::System => write!(f, "System"),
553 }
554 }
555}
556
557#[derive(Debug, Clone)]
562pub enum CommandEnum {
563 SetParameter(SetParameter),
565 Automaton(AutomatonCommand),
567 Sensor(SensorCommand),
569 Servo(ServoCommand),
571 System {
573 kind: String,
575 data: Vec<u8>,
577 },
578}
579
580impl CommandEnum {
581 pub fn command_type(&self) -> CommandType {
583 match self {
584 CommandEnum::SetParameter(_) => CommandType::SetParameter,
585 CommandEnum::Automaton(_) => CommandType::Automaton,
586 CommandEnum::Sensor(_) => CommandType::Sensor,
587 CommandEnum::Servo(_) => CommandType::Servo,
588 CommandEnum::System { .. } => CommandType::System,
589 }
590 }
591
592 pub fn target_node_id(&self) -> Option<crate::traits::NodeId> {
594 match self {
595 CommandEnum::SetParameter(cmd) => Some(cmd.port.node_id()),
596 _ => None,
597 }
598 }
599
600 pub fn timestamp(&self) -> Option<u64> {
602 match self {
603 CommandEnum::SetParameter(cmd) => Some(cmd.timestamp),
604 _ => None,
605 }
606 }
607
608 pub fn as_set_parameter(&self) -> Option<&SetParameter> {
610 match self {
611 CommandEnum::SetParameter(cmd) => Some(cmd),
612 _ => None,
613 }
614 }
615
616 pub fn as_automaton(&self) -> Option<&AutomatonCommand> {
618 match self {
619 CommandEnum::Automaton(cmd) => Some(cmd),
620 _ => None,
621 }
622 }
623
624 pub fn as_sensor(&self) -> Option<&SensorCommand> {
626 match self {
627 CommandEnum::Sensor(cmd) => Some(cmd),
628 _ => None,
629 }
630 }
631
632 pub fn as_servo(&self) -> Option<&ServoCommand> {
634 match self {
635 CommandEnum::Servo(cmd) => Some(cmd),
636 _ => None,
637 }
638 }
639}
640
641impl fmt::Display for CommandEnum {
642 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
643 match self {
644 CommandEnum::SetParameter(cmd) => write!(f, "{}", cmd),
645 CommandEnum::Automaton(cmd) => write!(f, "{}", cmd),
646 CommandEnum::Sensor(cmd) => write!(f, "{}", cmd),
647 CommandEnum::Servo(cmd) => write!(f, "{}", cmd),
648 CommandEnum::System { kind, data } => {
649 write!(f, "System[{}] ({} bytes)", kind, data.len())
650 }
651 }
652 }
653}
654
655impl Command for CommandEnum {}
657
658pub trait ToCommand: Send + 'static {
662 type Command: Into<CommandEnum>;
664
665 fn to_command(self) -> Self::Command;
667}
668
669pub trait FromCommand: Sized {
671 type Command: TryInto<Self> + Clone;
673
674 fn from_command(cmd: Self::Command) -> Option<Self>;
676}
677
678impl From<SetParameter> for CommandEnum {
679 fn from(cmd: SetParameter) -> Self {
680 CommandEnum::SetParameter(cmd)
681 }
682}
683
684impl From<AutomatonCommand> for CommandEnum {
685 fn from(cmd: AutomatonCommand) -> Self {
686 CommandEnum::Automaton(cmd)
687 }
688}
689
690impl From<SensorCommand> for CommandEnum {
691 fn from(cmd: SensorCommand) -> Self {
692 CommandEnum::Sensor(cmd)
693 }
694}
695
696impl From<ServoCommand> for CommandEnum {
697 fn from(cmd: ServoCommand) -> Self {
698 CommandEnum::Servo(cmd)
699 }
700}
701
702impl TryFrom<CommandEnum> for SetParameter {
703 type Error = ();
704
705 fn try_from(cmd: CommandEnum) -> Result<Self, Self::Error> {
706 match cmd {
707 CommandEnum::SetParameter(cmd) => Ok(cmd),
708 _ => Err(()),
709 }
710 }
711}
712
713impl TryFrom<CommandEnum> for AutomatonCommand {
714 type Error = ();
715
716 fn try_from(cmd: CommandEnum) -> Result<Self, Self::Error> {
717 match cmd {
718 CommandEnum::Automaton(cmd) => Ok(cmd),
719 _ => Err(()),
720 }
721 }
722}
723
724impl TryFrom<CommandEnum> for SensorCommand {
725 type Error = ();
726
727 fn try_from(cmd: CommandEnum) -> Result<Self, Self::Error> {
728 match cmd {
729 CommandEnum::Sensor(cmd) => Ok(cmd),
730 _ => Err(()),
731 }
732 }
733}
734
735impl TryFrom<CommandEnum> for ServoCommand {
736 type Error = ();
737
738 fn try_from(cmd: CommandEnum) -> Result<Self, Self::Error> {
739 match cmd {
740 CommandEnum::Servo(cmd) => Ok(cmd),
741 _ => Err(()),
742 }
743 }
744}