pamoja_core/device.rs
1//! Device-model traits implemented by capability crates.
2//!
3//! These traits describe the roles a piece of hardware can play in an
4//! application: a connectable [`Device`], a [`Sensor`] that produces readings, an
5//! [`Actuator`] that accepts commands, and a [`Telemetry`] source that streams
6//! frames. A single type may implement more than one of them.
7
8use crate::error::Result;
9
10/// A connectable physical or virtual device.
11///
12/// Implementors manage the lifecycle of an underlying resource such as a serial
13/// port, a network socket, or a vehicle link.
14pub trait Device {
15 /// Returns the stable identifier for this device.
16 ///
17 /// The identifier is expected to remain constant for the lifetime of the
18 /// device, for example a serial number, MAC address, or vehicle URI.
19 ///
20 /// # Returns
21 ///
22 /// A string slice borrowing the device's identifier.
23 fn id(&self) -> &str;
24
25 /// Opens the device and prepares it for use.
26 ///
27 /// # Returns
28 ///
29 /// `Ok(())` once the device is connected and ready.
30 ///
31 /// # Errors
32 ///
33 /// Returns [`Error::Io`](crate::Error::Io) if the underlying resource cannot
34 /// be opened, or [`Error::Transport`](crate::Error::Transport) if a link to
35 /// the device cannot be established.
36 async fn connect(&mut self) -> Result<()>;
37
38 /// Releases the device and any resources it holds.
39 ///
40 /// # Returns
41 ///
42 /// `Ok(())` once the device has been disconnected and its resources freed.
43 ///
44 /// # Errors
45 ///
46 /// Returns [`Error::Io`](crate::Error::Io) if the underlying resource cannot
47 /// be released cleanly.
48 async fn disconnect(&mut self) -> Result<()>;
49}
50
51/// A source of typed readings, such as a thermometer, GPS receiver, or lidar.
52pub trait Sensor {
53 /// The value produced by a single read, for example a temperature or a fix.
54 type Reading;
55
56 /// Takes a single reading from the sensor.
57 ///
58 /// # Returns
59 ///
60 /// The next [`Reading`](Self::Reading) sampled from the sensor.
61 ///
62 /// # Errors
63 ///
64 /// Returns [`Error::Io`](crate::Error::Io) if the sensor cannot be read, or
65 /// [`Error::Closed`](crate::Error::Closed) if the sensor has been
66 /// disconnected.
67 async fn read(&mut self) -> Result<Self::Reading>;
68}
69
70/// A sink that accepts typed commands, such as a motor or a valve.
71pub trait Actuator {
72 /// The command accepted by a single application, for example a setpoint.
73 type Command;
74
75 /// Applies a command to the actuator.
76 ///
77 /// # Arguments
78 ///
79 /// * `command` - the command to apply, consumed by the call.
80 ///
81 /// # Returns
82 ///
83 /// `Ok(())` once the command has been accepted by the actuator.
84 ///
85 /// # Errors
86 ///
87 /// Returns [`Error::Io`](crate::Error::Io) if the command cannot be
88 /// delivered, or [`Error::Closed`](crate::Error::Closed) if the actuator has
89 /// been disconnected.
90 async fn apply(&mut self, command: Self::Command) -> Result<()>;
91}
92
93/// A device that emits a continuous stream of telemetry frames.
94pub trait Telemetry {
95 /// A single telemetry frame, for example a status or position report.
96 type Frame;
97
98 /// Awaits the next telemetry frame.
99 ///
100 /// # Returns
101 ///
102 /// `Some(frame)` when a frame is available, or `None` once the telemetry
103 /// stream has ended.
104 ///
105 /// # Errors
106 ///
107 /// Returns [`Error::Transport`](crate::Error::Transport) if the telemetry
108 /// link fails while waiting.
109 async fn next_frame(&mut self) -> Result<Option<Self::Frame>>;
110}