ipmi_rs/connection/
mod.rs

1mod completion_code;
2use std::num::NonZeroU8;
3
4pub use completion_code::CompletionCode;
5
6mod impls;
7
8#[cfg(feature = "unix-file")]
9pub use impls::File;
10
11pub use impls::rmcp;
12
13mod netfn;
14pub use netfn::NetFn;
15
16mod request;
17pub use request::{Request, RequestTargetAddress};
18
19mod response;
20pub use response::Response;
21
22#[derive(Copy, Clone, Debug, PartialEq)]
23pub struct Address(pub u8);
24
25#[derive(Copy, Clone, Debug, PartialEq)]
26pub struct ChannelNumber(NonZeroU8);
27
28impl ChannelNumber {
29    /// Create a new `ChannelNumber`.
30    ///
31    /// This function returns `None` if `value > 0xB`
32    pub fn new(value: NonZeroU8) -> Option<Self> {
33        if value.get() <= 0xB {
34            Some(Self(value))
35        } else {
36            None
37        }
38    }
39
40    /// Get the value of this `ChannelNumber`.
41    ///
42    /// It is guaranteed that values returned by
43    /// this function are less than or equal to `0xB`
44    pub fn value(&self) -> NonZeroU8 {
45        self.0
46    }
47}
48
49#[derive(Copy, Clone, Debug, PartialEq)]
50pub enum Channel {
51    Primary,
52    Numbered(ChannelNumber),
53    System,
54    Current,
55}
56
57impl Channel {
58    /// Create a new `Channel`.
59    ///
60    /// This function returns `None` if `value == 0xC` || value == 0xD || value > 0xF`
61    pub fn new(value: u8) -> Option<Self> {
62        match value {
63            0 => Some(Self::Primary),
64            0xE => Some(Self::Current),
65            0xF => Some(Self::System),
66            v => Some(Self::Numbered(ChannelNumber::new(NonZeroU8::new(v)?)?)),
67        }
68    }
69
70    /// The number of this channel.
71    ///
72    /// This value is guaranteed to be less than or
73    /// equal to 0xF, and will be 0xE if `self` is
74    /// [`Channel::Current`].
75    pub fn value(&self) -> u8 {
76        match self {
77            Channel::Primary => 0x0,
78            Channel::Numbered(v) => v.value().get(),
79            Channel::Current => 0xE,
80            Channel::System => 0xF,
81        }
82    }
83}
84
85impl core::fmt::Display for Channel {
86    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87        match self {
88            Channel::Primary => write!(f, "Primary channel"),
89            Channel::Numbered(number) => write!(f, "Channel 0x{:01X}", number.value()),
90            Channel::Current => write!(f, "Current channel"),
91            Channel::System => write!(f, "System channel"),
92        }
93    }
94}
95
96#[derive(Clone, Copy, Debug, PartialEq)]
97pub enum LogicalUnit {
98    Zero,
99    One,
100    Two,
101    Three,
102}
103
104impl LogicalUnit {
105    /// Construct a `LogicalUnit` from the two lowest bits of `value`,
106    /// ignoring all other bits.
107    pub fn from_low_bits(value: u8) -> Self {
108        let value = value & 0b11;
109
110        match value {
111            0b00 => Self::Zero,
112            0b01 => Self::One,
113            0b10 => Self::Two,
114            0b11 => Self::Three,
115            _ => unreachable!("Value bitmasked with 0b11 has value greater than 3"),
116        }
117    }
118}
119
120impl TryFrom<u8> for LogicalUnit {
121    type Error = ();
122
123    fn try_from(value: u8) -> Result<Self, Self::Error> {
124        if value <= 0b11 {
125            Ok(Self::from_low_bits(value))
126        } else {
127            Err(())
128        }
129    }
130}
131
132impl LogicalUnit {
133    pub fn value(&self) -> u8 {
134        match self {
135            LogicalUnit::Zero => 0,
136            LogicalUnit::One => 1,
137            LogicalUnit::Two => 2,
138            LogicalUnit::Three => 3,
139        }
140    }
141}
142
143pub trait IpmiConnection {
144    type SendError: core::fmt::Debug;
145    type RecvError: core::fmt::Debug;
146    type Error: core::fmt::Debug + From<Self::SendError> + From<Self::RecvError>;
147
148    fn send(&mut self, request: &mut Request) -> Result<(), Self::SendError>;
149    fn recv(&mut self) -> Result<Response, Self::RecvError>;
150    fn send_recv(&mut self, request: &mut Request) -> Result<Response, Self::Error>;
151}
152
153#[derive(Clone, Debug, PartialEq)]
154pub struct Message {
155    netfn: u8,
156    cmd: u8,
157    data: Vec<u8>,
158}
159
160impl Message {
161    pub fn new_request(netfn: NetFn, cmd: u8, data: Vec<u8>) -> Self {
162        Self {
163            netfn: netfn.request_value(),
164            cmd,
165            data,
166        }
167    }
168
169    pub fn new_response(netfn: NetFn, cmd: u8, data: Vec<u8>) -> Self {
170        Self {
171            netfn: netfn.response_value(),
172            cmd,
173            data,
174        }
175    }
176
177    pub fn new_raw(netfn: u8, cmd: u8, data: Vec<u8>) -> Self {
178        Self { netfn, cmd, data }
179    }
180
181    pub fn netfn(&self) -> NetFn {
182        NetFn::from(self.netfn)
183    }
184
185    pub fn netfn_raw(&self) -> u8 {
186        self.netfn
187    }
188
189    pub fn cmd(&self) -> u8 {
190        self.cmd
191    }
192
193    pub fn data(&self) -> &[u8] {
194        &self.data
195    }
196
197    pub fn data_mut(&mut self) -> &mut [u8] {
198        &mut self.data
199    }
200}
201
202#[derive(Clone, Copy, Debug, PartialEq)]
203pub enum ParseResponseError<T> {
204    Failed(CompletionCode),
205    NotEnoughData,
206    Parse(T),
207}
208
209impl<T> From<T> for ParseResponseError<T> {
210    fn from(value: T) -> Self {
211        Self::Parse(value)
212    }
213}
214
215pub trait IpmiCommand: Into<Message> {
216    type Output;
217    type Error;
218
219    fn parse_response(
220        completion_code: CompletionCode,
221        data: &[u8],
222    ) -> Result<Self::Output, ParseResponseError<Self::Error>>;
223
224    fn check_cc_success(cc: CompletionCode) -> Result<(), ParseResponseError<Self::Error>> {
225        if cc.is_success() {
226            Ok(())
227        } else {
228            Err(ParseResponseError::Failed(cc))
229        }
230    }
231
232    fn target(&self) -> Option<(Address, Channel)> {
233        None
234    }
235}