modbus_rtu/common/
baudrate.rs

1/// Represents supported baudrates for Modbus communication.
2///
3/// Each variant maps to an internal ID used within the protocol.
4/// The actual baudrate values (e.g., 9600, 115200) can be obtained via conversion.
5/// 
6/// ---
7/// # Supports
8/// - [`u32`] -> [`Baudrate`]
9/// - [`u64`] -> [`Baudrate`]
10/// - [`Baudrate`] -> [`u32`]
11/// - [`Baudrate`] -> [`u64`]
12/// 
13#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
14#[repr(u16)]
15pub enum Baudrate {
16    BR1200 = 0,
17    BR2400 = 1,
18    BR4800 = 2,
19    BR9600 = 3,
20    BR19200 = 4,
21    BR38400 = 5,
22    BR57600 = 6,
23    BR115200 = 7,
24}
25
26
27impl Baudrate {
28    /// Attempts to create a [`Baudrate`] from its internal ID.
29    ///
30    /// This is used when a baudrate needs to be reconstructed from a stored or transmitted ID.
31    ///
32    /// ---
33    /// # Args
34    /// - `id`: The internal identifier corresponding to a [`Baudrate`].
35    ///
36    /// ---
37    /// # Returns
38    /// `Some(..)` if the ID matches a known baudrate, otherwise `None`.
39    ///
40    /// ---
41    /// # Examples
42    /// ```
43    /// use modbus_rtu::common::Baudrate;
44    ///
45    /// # assert_eq!(Baudrate::from_id(0), Some(Baudrate::BR1200));
46    /// # assert_eq!(Baudrate::from_id(1), Some(Baudrate::BR2400));
47    /// # assert_eq!(Baudrate::from_id(2), Some(Baudrate::BR4800));
48    /// assert_eq!(Baudrate::from_id(3), Some(Baudrate::BR9600));
49    /// # assert_eq!(Baudrate::from_id(4), Some(Baudrate::BR19200));
50    /// # assert_eq!(Baudrate::from_id(5), Some(Baudrate::BR38400));
51    /// # assert_eq!(Baudrate::from_id(6), Some(Baudrate::BR57600));
52    /// # assert_eq!(Baudrate::from_id(7), Some(Baudrate::BR115200));
53    /// assert_eq!(Baudrate::from_id(99), None);
54    /// ```
55    /// 
56    pub fn from_id(id: u16) -> Option<Baudrate> {
57        use Baudrate::*;
58        match id {
59            val if val == BR1200 as u16 => Some(BR1200),
60            val if val == BR2400 as u16 => Some(BR2400),
61            val if val == BR4800 as u16 => Some(BR4800),
62            val if val == BR9600 as u16 => Some(BR9600),
63            val if val == BR19200 as u16 => Some(BR19200),
64            val if val == BR38400 as u16 => Some(BR38400),
65            val if val == BR57600 as u16 => Some(BR57600),
66            val if val == BR115200 as u16 => Some(BR115200),
67            _ => None,
68        }
69    }
70
71    /// Converts the [`Baudrate`] variant into its internal ID representation.
72    ///
73    /// This ID can be stored or transmitted and later converted back using [`Baudrate::from_id`].
74    ///
75    /// ---
76    /// # Returns
77    /// The internal [`u16`] ID associated with the baudrate.
78    ///
79    /// ---
80    /// # Examples
81    /// ```
82    /// use modbus_rtu::common::Baudrate;
83    ///
84    /// # assert_eq!(Baudrate::BR1200.to_id(), 0);
85    /// # assert_eq!(Baudrate::BR2400.to_id(), 1);
86    /// # assert_eq!(Baudrate::BR4800.to_id(), 2);
87    /// assert_eq!(Baudrate::BR9600.to_id(), 3);
88    /// # assert_eq!(Baudrate::BR19200.to_id(), 4);
89    /// # assert_eq!(Baudrate::BR38400.to_id(), 5);
90    /// # assert_eq!(Baudrate::BR57600.to_id(), 6);
91    /// # assert_eq!(Baudrate::BR115200.to_id(), 7);
92    /// ```
93    /// 
94    pub fn to_id(&self) -> u16 {
95        *self as u16
96    }
97
98    /// Calculates the packet end timeout in microseconds based on the baudrate.
99    ///
100    /// In Modbus RTU communication, this value defines the idle time required to consider a packet as ended. (3.5 char time)
101    ///
102    /// ---
103    /// # Returns
104    /// The idle time (in microseconds) required to delimit the end of a Modbus RTU packet at this baudrate.
105    ///
106    /// ---
107    /// # Examples
108    /// ```
109    /// use modbus_rtu::common::Baudrate;
110    ///
111    /// let baud = Baudrate::BR9600;
112    /// let packet_end_us: u64 = baud.packet_end_us();
113    /// ```
114    /// 
115    pub fn packet_end_us(&self) -> u64 {
116        let bps: u64 = self.into();
117        (35_000_000 + bps - 1) / bps
118    }
119}
120
121
122// u32 -> Baudrate
123impl TryFrom<u32> for Baudrate {
124    type Error = ();
125
126    fn try_from(value: u32) -> Result<Self, Self::Error> {
127        use Baudrate::*;
128        match value {
129              1_200 => Ok(BR1200),
130              2_400 => Ok(BR2400),
131              4_800 => Ok(BR4800),
132              9_600 => Ok(BR9600),
133             19_200 => Ok(BR19200),
134             38_400 => Ok(BR38400),
135             57_600 => Ok(BR57600),
136            115_200 => Ok(BR115200),
137            _ => Err(())
138        }
139    }
140}
141
142
143// u64 -> Baudrate
144impl TryFrom<u64> for Baudrate {
145    type Error = ();
146
147    fn try_from(value: u64) -> Result<Self, Self::Error> {
148        use Baudrate::*;
149        match value {
150              1_200 => Ok(BR1200),
151              2_400 => Ok(BR2400),
152              4_800 => Ok(BR4800),
153              9_600 => Ok(BR9600),
154             19_200 => Ok(BR19200),
155             38_400 => Ok(BR38400),
156             57_600 => Ok(BR57600),
157            115_200 => Ok(BR115200),
158            _ => Err(())
159        }
160    }
161}
162
163
164// Baudrate -> u32
165impl From<Baudrate> for u32 {
166    fn from(value: Baudrate) -> Self {
167        match value {
168            Baudrate::BR1200   =>   1_200,
169            Baudrate::BR2400   =>   2_400,
170            Baudrate::BR4800   =>   4_800,
171            Baudrate::BR9600   =>   9_600,
172            Baudrate::BR19200  =>  19_200,
173            Baudrate::BR38400  =>  38_400,
174            Baudrate::BR57600  =>  57_600,
175            Baudrate::BR115200 => 115_200,
176        }
177    }
178}
179
180
181// &Baudrate -> u32
182impl From<&Baudrate> for u32 {
183    fn from(value: &Baudrate) -> Self {
184        match value {
185            Baudrate::BR1200   =>   1_200,
186            Baudrate::BR2400   =>   2_400,
187            Baudrate::BR4800   =>   4_800,
188            Baudrate::BR9600   =>   9_600,
189            Baudrate::BR19200  =>  19_200,
190            Baudrate::BR38400  =>  38_400,
191            Baudrate::BR57600  =>  57_600,
192            Baudrate::BR115200 => 115_200,
193        }
194    }
195}
196
197
198// Baudrate -> u64
199impl From<Baudrate> for u64 {
200    fn from(value: Baudrate) -> Self {
201        match value {
202            Baudrate::BR1200   =>   1_200,
203            Baudrate::BR2400   =>   2_400,
204            Baudrate::BR4800   =>   4_800,
205            Baudrate::BR9600   =>   9_600,
206            Baudrate::BR19200  =>  19_200,
207            Baudrate::BR38400  =>  38_400,
208            Baudrate::BR57600  =>  57_600,
209            Baudrate::BR115200 => 115_200,
210        }
211    }
212}
213
214
215// &Baudrate -> u64
216impl From<&Baudrate> for u64 {
217    fn from(value: &Baudrate) -> Self {
218        match value {
219            Baudrate::BR1200   =>   1_200,
220            Baudrate::BR2400   =>   2_400,
221            Baudrate::BR4800   =>   4_800,
222            Baudrate::BR9600   =>   9_600,
223            Baudrate::BR19200  =>  19_200,
224            Baudrate::BR38400  =>  38_400,
225            Baudrate::BR57600  =>  57_600,
226            Baudrate::BR115200 => 115_200,
227        }
228    }
229}
230
231
232// Display
233#[cfg(not(feature = "no_std"))]
234impl std::fmt::Display for Baudrate {
235    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
236        let num: u32 = self.into();
237        write!(f, "Baudrate({})", num)
238    }
239}