1use async_trait::async_trait;
5
6pub use crate::error::ModbusError;
7use crate::frame::{Request, Response};
8
9#[inline]
13fn unexpected_response(rsp: Response) -> ModbusError {
14 match rsp {
15 Response::Exception(fc, ex) => ModbusError::exception(fc, u8::from(ex)),
16 other => ModbusError::protocol(format!("unexpected response: {other:?}")),
17 }
18}
19
20#[async_trait]
55pub trait ModbusClient: Send + Sync {
56 async fn call(&self, slave: u8, request: Request<'_>) -> Result<Response, ModbusError>;
59
60 async fn read_coils(
64 &self,
65 slave: u8,
66 addr: u16,
67 quantity: u16,
68 ) -> Result<Vec<bool>, ModbusError> {
69 match self.call(slave, Request::ReadCoils(addr, quantity)).await? {
70 Response::ReadCoils(bits) => Ok(bits),
71 other => Err(unexpected_response(other)),
72 }
73 }
74 async fn read_discrete_inputs(
76 &self,
77 slave: u8,
78 addr: u16,
79 quantity: u16,
80 ) -> Result<Vec<bool>, ModbusError> {
81 match self
82 .call(slave, Request::ReadDiscreteInputs(addr, quantity))
83 .await?
84 {
85 Response::ReadDiscreteInputs(bits) => Ok(bits),
86 other => Err(unexpected_response(other)),
87 }
88 }
89 async fn read_holding_registers(
91 &self,
92 slave: u8,
93 addr: u16,
94 quantity: u16,
95 ) -> Result<Vec<u16>, ModbusError> {
96 match self
97 .call(slave, Request::ReadHoldingRegisters(addr, quantity))
98 .await?
99 {
100 Response::ReadHoldingRegisters(regs) => Ok(regs),
101 other => Err(unexpected_response(other)),
102 }
103 }
104 async fn read_input_registers(
106 &self,
107 slave: u8,
108 addr: u16,
109 quantity: u16,
110 ) -> Result<Vec<u16>, ModbusError> {
111 match self
112 .call(slave, Request::ReadInputRegisters(addr, quantity))
113 .await?
114 {
115 Response::ReadInputRegisters(regs) => Ok(regs),
116 other => Err(unexpected_response(other)),
117 }
118 }
119 async fn write_single_coil(
121 &self,
122 slave: u8,
123 addr: u16,
124 value: bool,
125 ) -> Result<(), ModbusError> {
126 match self
127 .call(slave, Request::WriteSingleCoil(addr, value))
128 .await?
129 {
130 Response::WriteSingleCoil(a, v) if a == addr && v == value => Ok(()),
131 other => Err(unexpected_response(other)),
132 }
133 }
134 async fn write_single_register(
136 &self,
137 slave: u8,
138 addr: u16,
139 value: u16,
140 ) -> Result<(), ModbusError> {
141 match self
142 .call(slave, Request::WriteSingleRegister(addr, value))
143 .await?
144 {
145 Response::WriteSingleRegister(a, v) if a == addr && v == value => Ok(()),
146 other => Err(unexpected_response(other)),
147 }
148 }
149 async fn write_multiple_coils(
151 &self,
152 slave: u8,
153 addr: u16,
154 values: &[bool],
155 ) -> Result<(), ModbusError> {
156 let req = Request::WriteMultipleCoils(addr, std::borrow::Cow::Borrowed(values));
157 match self.call(slave, req).await? {
158 Response::WriteMultipleCoils(a, n) if a == addr && n as usize == values.len() => Ok(()),
159 other => Err(unexpected_response(other)),
160 }
161 }
162 async fn write_multiple_registers(
164 &self,
165 slave: u8,
166 addr: u16,
167 values: &[u16],
168 ) -> Result<(), ModbusError> {
169 let req = Request::WriteMultipleRegisters(addr, std::borrow::Cow::Borrowed(values));
170 match self.call(slave, req).await? {
171 Response::WriteMultipleRegisters(a, n) if a == addr && n as usize == values.len() => {
172 Ok(())
173 }
174 other => Err(unexpected_response(other)),
175 }
176 }
177
178 async fn mask_write_register(
180 &self,
181 slave: u8,
182 addr: u16,
183 and_mask: u16,
184 or_mask: u16,
185 ) -> Result<(), ModbusError> {
186 match self
187 .call(slave, Request::MaskWriteRegister(addr, and_mask, or_mask))
188 .await?
189 {
190 Response::MaskWriteRegister(a, and, or)
191 if a == addr && and == and_mask && or == or_mask =>
192 {
193 Ok(())
194 }
195 other => Err(unexpected_response(other)),
196 }
197 }
198
199 async fn diagnostic(
201 &self,
202 slave: u8,
203 sub_function: u16,
204 data: u16,
205 ) -> Result<(u16, u16), ModbusError> {
206 match self
207 .call(slave, Request::Diagnostic(sub_function, data))
208 .await?
209 {
210 Response::Diagnostic(sf, d) => Ok((sf, d)),
211 other => Err(unexpected_response(other)),
212 }
213 }
214
215 async fn read_write_multiple_registers(
217 &self,
218 slave: u8,
219 read_addr: u16,
220 read_qty: u16,
221 write_addr: u16,
222 values: &[u16],
223 ) -> Result<Vec<u16>, ModbusError> {
224 let req = Request::ReadWriteMultipleRegisters(
225 read_addr,
226 read_qty,
227 write_addr,
228 std::borrow::Cow::Borrowed(values),
229 );
230 match self.call(slave, req).await? {
231 Response::ReadWriteMultipleRegisters(regs) => Ok(regs),
232 other => Err(unexpected_response(other)),
233 }
234 }
235}