Skip to main content

modbus_bridge/
client_builder.rs

1//! Typestate builder for [`Client`](crate::Client).
2
3use crate::{client::Client, NoDelay, NoPin};
4
5/// Builder for [`Client`]. Obtain via [`Client::builder()`](crate::Client::builder).
6///
7/// Uses the same typestate pattern as [`BridgeBuilder`](crate::BridgeBuilder).
8/// `S` and `TX` start as `()` until `.rtu()` is called. `D` starts as
9/// [`NoDelay`](crate::NoDelay) and can be upgraded with `.delay()`.
10pub struct ClientBuilder<S, TX, D = NoDelay> {
11    pub(crate) serial: S,
12    pub(crate) tx_en: TX,
13    pub(crate) rtu_timeout_ms: Option<u32>,
14    pub(crate) tcp_timeout_ms: Option<u32>,
15    pub(crate) delay: D,
16}
17
18impl ClientBuilder<(), (), NoDelay> {
19    /// Creates a new `ClientBuilder` with no serial port configured.
20    ///
21    /// Prefer [`Client::builder()`](crate::Client::builder) over calling this directly.
22    pub fn new() -> Self {
23        Self {
24            serial: (),
25            tx_en: (),
26            rtu_timeout_ms: None,
27            tcp_timeout_ms: None,
28            delay: NoDelay,
29        }
30    }
31}
32
33impl Default for ClientBuilder<(), (), NoDelay> {
34    fn default() -> Self {
35        Self::new()
36    }
37}
38
39impl<D> ClientBuilder<(), (), D> {
40    /// Supplies the serial port and RS-485 TX-enable pin.
41    ///
42    /// # Examples
43    ///
44    /// ```rust,ignore
45    /// let client = Client::builder()
46    ///     .rtu(uart, tx_en_pin)
47    ///     .build();
48    /// ```
49    pub fn rtu<S, TX>(self, serial: S, tx_en: TX) -> ClientBuilder<S, TX, D> {
50        ClientBuilder {
51            serial,
52            tx_en,
53            rtu_timeout_ms: self.rtu_timeout_ms,
54            tcp_timeout_ms: self.tcp_timeout_ms,
55            delay: self.delay,
56        }
57    }
58
59    /// Supplies the serial port without a TX-enable pin.
60    ///
61    /// Use this when the RS-485 transceiver handles direction control automatically.
62    ///
63    /// # Examples
64    ///
65    /// ```rust,ignore
66    /// let client = Client::builder()
67    ///     .rtu_no_pin(uart)
68    ///     .build();
69    /// ```
70    pub fn rtu_no_pin<S>(self, serial: S) -> ClientBuilder<S, NoPin, D> {
71        ClientBuilder {
72            serial,
73            tx_en: NoPin,
74            rtu_timeout_ms: self.rtu_timeout_ms,
75            tcp_timeout_ms: self.tcp_timeout_ms,
76            delay: self.delay,
77        }
78    }
79}
80
81impl<S, TX, D> ClientBuilder<S, TX, D> {
82    /// Sets the RTU I/O timeout in milliseconds.
83    ///
84    /// Applied while waiting for an incoming RTU request from the serial master.
85    /// Requires a delay provider — call `.delay()` as well.
86    pub fn rtu_timeout(mut self, ms: u32) -> Self {
87        self.rtu_timeout_ms = Some(ms);
88        self
89    }
90
91    /// Sets the TCP I/O timeout in milliseconds.
92    ///
93    /// Applied while waiting for the upstream TCP server response.
94    /// Requires a delay provider — call `.delay()` as well.
95    pub fn tcp_timeout(mut self, ms: u32) -> Self {
96        self.tcp_timeout_ms = Some(ms);
97        self
98    }
99
100    /// Builds and returns the configured [`Client`](crate::Client).
101    ///
102    /// # Examples
103    ///
104    /// ```rust,ignore
105    /// let mut client = Client::builder()
106    ///     .rtu(uart, tx_en)
107    ///     .build();
108    /// ```
109    pub fn build(self) -> Client<S, TX, D> {
110        Client::from_parts(
111            self.serial,
112            self.tx_en,
113            self.delay,
114            self.rtu_timeout_ms,
115            self.tcp_timeout_ms,
116        )
117    }
118}
119
120impl<S, TX> ClientBuilder<S, TX, NoDelay> {
121    /// Supplies a delay provider and upgrades `D` from `NoDelay`.
122    ///
123    /// Must be called before `.build()` when using `.rtu_timeout()` or `.tcp_timeout()`.
124    ///
125    /// # Examples
126    ///
127    /// ```rust,ignore
128    /// let client = Client::builder()
129    ///     .rtu(uart, pin)
130    ///     .rtu_timeout(500)
131    ///     .delay(my_timer)
132    ///     .build();
133    /// ```
134    pub fn delay<D2>(self, delay: D2) -> ClientBuilder<S, TX, D2> {
135        ClientBuilder {
136            serial: self.serial,
137            tx_en: self.tx_en,
138            rtu_timeout_ms: self.rtu_timeout_ms,
139            tcp_timeout_ms: self.tcp_timeout_ms,
140            delay,
141        }
142    }
143}