Skip to main content

rustmod_client/
sync.rs

1use crate::{
2    ClientConfig, ClientError, ModbusClient, ReadDeviceIdentificationResponse,
3    ReportServerIdResponse,
4};
5use rustmod_datalink::{DataLinkError, ModbusTcpTransport};
6use thiserror::Error;
7use tokio::runtime::Runtime;
8
9#[derive(Debug, Error)]
10pub enum SyncClientError {
11    #[error("runtime init error: {0}")]
12    RuntimeInit(std::io::Error),
13    #[error("datalink error: {0}")]
14    DataLink(#[from] DataLinkError),
15    #[error("client error: {0}")]
16    Client(#[from] ClientError),
17}
18
19pub struct SyncModbusTcpClient {
20    runtime: Runtime,
21    client: ModbusClient<ModbusTcpTransport>,
22}
23
24impl SyncModbusTcpClient {
25    pub fn connect(addr: &str) -> Result<Self, SyncClientError> {
26        Self::connect_with_config(addr, ClientConfig::default())
27    }
28
29    pub fn connect_with_config(addr: &str, config: ClientConfig) -> Result<Self, SyncClientError> {
30        let runtime = tokio::runtime::Builder::new_multi_thread()
31            .enable_all()
32            .build()
33            .map_err(SyncClientError::RuntimeInit)?;
34        let link = runtime.block_on(ModbusTcpTransport::connect(addr))?;
35        let client = ModbusClient::with_config(link, config);
36        Ok(Self { runtime, client })
37    }
38
39    pub fn config(&self) -> ClientConfig {
40        self.client.config()
41    }
42
43    pub fn read_coils(
44        &self,
45        unit_id: u8,
46        start: u16,
47        quantity: u16,
48    ) -> Result<Vec<bool>, SyncClientError> {
49        self.runtime
50            .block_on(self.client.read_coils(unit_id, start, quantity))
51            .map_err(SyncClientError::Client)
52    }
53
54    pub fn read_discrete_inputs(
55        &self,
56        unit_id: u8,
57        start: u16,
58        quantity: u16,
59    ) -> Result<Vec<bool>, SyncClientError> {
60        self.runtime
61            .block_on(self.client.read_discrete_inputs(unit_id, start, quantity))
62            .map_err(SyncClientError::Client)
63    }
64
65    pub fn read_holding_registers(
66        &self,
67        unit_id: u8,
68        start: u16,
69        quantity: u16,
70    ) -> Result<Vec<u16>, SyncClientError> {
71        self.runtime
72            .block_on(self.client.read_holding_registers(unit_id, start, quantity))
73            .map_err(SyncClientError::Client)
74    }
75
76    pub fn read_input_registers(
77        &self,
78        unit_id: u8,
79        start: u16,
80        quantity: u16,
81    ) -> Result<Vec<u16>, SyncClientError> {
82        self.runtime
83            .block_on(self.client.read_input_registers(unit_id, start, quantity))
84            .map_err(SyncClientError::Client)
85    }
86
87    pub fn write_single_coil(
88        &self,
89        unit_id: u8,
90        address: u16,
91        value: bool,
92    ) -> Result<(), SyncClientError> {
93        self.runtime
94            .block_on(self.client.write_single_coil(unit_id, address, value))
95            .map_err(SyncClientError::Client)
96    }
97
98    pub fn write_single_register(
99        &self,
100        unit_id: u8,
101        address: u16,
102        value: u16,
103    ) -> Result<(), SyncClientError> {
104        self.runtime
105            .block_on(self.client.write_single_register(unit_id, address, value))
106            .map_err(SyncClientError::Client)
107    }
108
109    pub fn mask_write_register(
110        &self,
111        unit_id: u8,
112        address: u16,
113        and_mask: u16,
114        or_mask: u16,
115    ) -> Result<(), SyncClientError> {
116        self.runtime
117            .block_on(
118                self.client
119                    .mask_write_register(unit_id, address, and_mask, or_mask),
120            )
121            .map_err(SyncClientError::Client)
122    }
123
124    pub fn write_multiple_coils(
125        &self,
126        unit_id: u8,
127        start: u16,
128        values: &[bool],
129    ) -> Result<(), SyncClientError> {
130        self.runtime
131            .block_on(self.client.write_multiple_coils(unit_id, start, values))
132            .map_err(SyncClientError::Client)
133    }
134
135    pub fn write_multiple_registers(
136        &self,
137        unit_id: u8,
138        start: u16,
139        values: &[u16],
140    ) -> Result<(), SyncClientError> {
141        self.runtime
142            .block_on(self.client.write_multiple_registers(unit_id, start, values))
143            .map_err(SyncClientError::Client)
144    }
145
146    pub fn read_write_multiple_registers(
147        &self,
148        unit_id: u8,
149        read_start: u16,
150        read_quantity: u16,
151        write_start: u16,
152        write_values: &[u16],
153    ) -> Result<Vec<u16>, SyncClientError> {
154        self.runtime
155            .block_on(self.client.read_write_multiple_registers(
156                unit_id,
157                read_start,
158                read_quantity,
159                write_start,
160                write_values,
161            ))
162            .map_err(SyncClientError::Client)
163    }
164
165    pub fn custom_request(
166        &self,
167        unit_id: u8,
168        function_code: u8,
169        payload: &[u8],
170    ) -> Result<Vec<u8>, SyncClientError> {
171        self.runtime
172            .block_on(self.client.custom_request(unit_id, function_code, payload))
173            .map_err(SyncClientError::Client)
174    }
175
176    pub fn report_server_id(&self, unit_id: u8) -> Result<ReportServerIdResponse, SyncClientError> {
177        self.runtime
178            .block_on(self.client.report_server_id(unit_id))
179            .map_err(SyncClientError::Client)
180    }
181
182    pub fn read_device_identification(
183        &self,
184        unit_id: u8,
185        read_device_id_code: u8,
186        object_id: u8,
187    ) -> Result<ReadDeviceIdentificationResponse, SyncClientError> {
188        self.runtime
189            .block_on(self.client.read_device_identification(
190                unit_id,
191                read_device_id_code,
192                object_id,
193            ))
194            .map_err(SyncClientError::Client)
195    }
196}