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}