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}