libmodbus/
modbus_client.rs

1use crate::prelude::*;
2use libc::c_int;
3use libmodbus_sys as ffi;
4
5/// The Modbus protocol defines different data types and functions to read and write them from/to remote devices.
6/// The following functions are used by the clients to send Modbus requests:
7///
8/// * Read data
9///     - [`read_bits()`](struct.Modbus.html#method.read_bits),
10/// [`read_input_bits()`](struct.Modbus.html#method.read_input_bits),
11/// [`read_registers()`](struct.Modbus.html#method.read_registers),
12/// [`read_input_registers()`](struct.Modbus.html#method.read_input_registers),
13/// [`report_slave_id()`](struct.Modbus.html#method.report_slave_id)
14/// * Write data
15///     - [`write_bit()`](struct.Modbus.html#method.write_bit),
16/// [`write_register()`](struct.Modbus.html#method.write_register),
17/// [`write_bits()`](struct.Modbus.html#method.write_bits),
18/// [`write_registers()`](struct.Modbus.html#method.write_registers)
19/// * Write and read data
20///     - [`write_and_read_registers()`](struct.Modbus.html#method.write_and_read_registers)
21/// * Raw requests
22///     - [`send_raw_request()`](struct.Modbus.html#method.send_raw_request),
23/// [`receive_confirmation()`](struct.Modbus.html#method.receive_confirmation)
24/// * Reply an exception
25///     - [`reply_exception()`](struct.Modbus.html#method.reply_exception)
26///
27pub trait ModbusClient {
28    fn read_bits(&self, address: u16, num: u16, dest: &mut [u8]) -> Result<u16, Error>;
29    fn read_input_bits(&self, address: u16, num: u16, dest: &mut [u8]) -> Result<u16, Error>;
30    fn read_registers(&self, address: u16, num: u16, dest: &mut [u16]) -> Result<u16, Error>;
31    fn read_input_registers(&self, address: u16, num: u16, dest: &mut [u16]) -> Result<u16, Error>;
32    fn report_slave_id(&self, max_dest: usize, dest: &mut [u8]) -> Result<u16, Error>;
33    fn write_bit(&self, address: u16, status: bool) -> Result<(), Error>;
34    fn write_bits(&self, address: u16, num: u16, src: &[u8]) -> Result<u16, Error>;
35    fn write_register(&self, address: u16, value: u16) -> Result<(), Error>;
36    fn write_registers(&self, address: u16, num: u16, src: &[u16]) -> Result<u16, Error>;
37    fn write_and_read_registers(
38        &self,
39        write_address: u16,
40        write_num: u16,
41        src: &[u16],
42        read_address: u16,
43        read_num: u16,
44        dest: &mut [u16],
45    ) -> Result<u16, Error>;
46    fn mask_write_register(&self, address: u16, and_mask: u16, or_mask: u16) -> Result<(), Error>;
47    fn send_raw_request(&self, raw_request: &mut [u8], lenght: usize) -> Result<u16, Error>;
48    fn receive_confirmation(&self, response: &mut [u8]) -> Result<u16, Error>;
49}
50
51// TODO: add real, working examples
52impl ModbusClient for Modbus {
53    /// `read_bits` - read many bits
54    ///
55    /// The [`read_bits()`](#method.read_bits) function shall read the status of the `num` bits (coils) to the
56    /// `address` of the remote device. The result of reading is stored in `dest` slice as unsigned bytes (8 bits) set
57    /// to TRUE or FALSE.
58    ///
59    /// The function uses the **Modbus function code 0x01** (read coil status).
60    ///
61    /// # Return value
62    ///
63    /// The function returns a `Result` containing the number of read bits if successful. Otherwise it returns an Error.
64    ///
65    /// # Parameters
66    ///
67    /// * `address` - address of the remote device
68    /// * `num`     - number of coils to read
69    /// * `dest`    - the result of the reading is stored here
70    ///
71    /// # Examples
72    ///
73    /// ```rust,no_run
74    /// use libmodbus::{Modbus, ModbusClient, ModbusTCP};
75    /// let modbus = Modbus::new_tcp("127.0.0.1", 1502).unwrap();
76    /// let mut dest = vec![0u8; 100];
77    ///
78    /// assert!(modbus.read_bits(0, 1, &mut dest).is_ok());
79    /// ```
80    fn read_bits(&self, address: u16, num: u16, dest: &mut [u8]) -> Result<u16, Error> {
81        unsafe {
82            match ffi::modbus_read_bits(self.ctx, address as c_int, num as c_int, dest.as_mut_ptr())
83            {
84                -1 => Err(Error::Client {
85                    msg: "read_bits failure".to_owned(),
86                    source: ::std::io::Error::last_os_error(),
87                }),
88                len => Ok(len as u16),
89            }
90        }
91    }
92
93    /// `read_input_bits` - read many input bits
94    ///
95    /// The [`read_input_bits()`](#method.read_input_bits) function shall read the content of the `num` input bits to
96    /// the `address` of the remote device. The result of reading is stored in `dest` slice as unsigned bytes (8 bits)
97    /// set to TRUE or FALSE.
98    ///
99    /// The function uses the **Modbus function code 0x02** (read input status).
100    ///
101    /// # Return value
102    ///
103    /// The function returns a `Result` containing the number of read bits if successful. Otherwise it returns an Error.
104    ///
105    /// # Parameters
106    ///
107    /// * `address` - address of the remote device
108    /// * `num`     - number of input bits to read
109    /// * `dest`    - the result of the reading is stored here
110    ///
111    /// # Examples
112    ///
113    /// ```rust,no_run
114    /// use libmodbus::{Modbus, ModbusClient, ModbusTCP};
115    /// let modbus = Modbus::new_tcp("127.0.0.1", 1502).unwrap();
116    /// let mut dest = vec![0u8; 100];
117    ///
118    /// assert!(modbus.read_input_bits(0, 1, &mut dest).is_ok());
119    /// ```
120    fn read_input_bits(&self, address: u16, num: u16, dest: &mut [u8]) -> Result<u16, Error> {
121        unsafe {
122            match ffi::modbus_read_input_bits(
123                self.ctx,
124                address as c_int,
125                num as c_int,
126                dest.as_mut_ptr(),
127            ) {
128                -1 => Err(Error::Client {
129                    msg: "read_input_bits".to_owned(),
130                    source: ::std::io::Error::last_os_error(),
131                }),
132                len => Ok(len as u16),
133            }
134        }
135    }
136
137    /// `read_registers` - read many registers
138    ///
139    /// The [`read_registers()`](#method.read_registers) function shall read the content of the `num` holding registers
140    /// to the `address` of the remote device. The result of reading is stored in `dest` slice as u16 word values.
141    ///
142    /// The function uses the **Modbus function code 0x03** (read holding registers).
143    ///
144    /// # Return value
145    ///
146    /// The function returns a `Result` containing the number of read bits if successful. Otherwise it returns an Error.
147    ///
148    /// # Parameters
149    ///
150    /// * `address` - address of the remote device
151    /// * `num`     - number of holding registers to read
152    /// * `dest`    - the result of the reading is stored here
153    ///
154    /// # Examples
155    ///
156    /// ```rust,no_run
157    /// use libmodbus::{Modbus, ModbusClient, ModbusTCP};
158    /// let modbus = Modbus::new_tcp("127.0.0.1", 1502).unwrap();
159    /// let mut dest = vec![0u16; 100];
160    ///
161    /// assert!(modbus.read_registers(0, 1, &mut dest).is_ok());
162    /// ```
163    fn read_registers(&self, address: u16, num: u16, dest: &mut [u16]) -> Result<u16, Error> {
164        unsafe {
165            match ffi::modbus_read_registers(
166                self.ctx,
167                address as c_int,
168                num as c_int,
169                dest.as_mut_ptr(),
170            ) {
171                -1 => Err(Error::Client {
172                    msg: "read_registers".to_owned(),
173                    source: ::std::io::Error::last_os_error(),
174                }),
175                len => Ok(len as u16),
176            }
177        }
178    }
179
180    /// `read_input_registers` -  read many input registers
181    ///
182    /// The [`read_input_registers()`](#method.read_input_registers) function shall read the content of the `num`
183    /// holding registers to the `address` of the remote device. The result of reading is stored in `dest` slice as u16
184    /// word values.
185    ///
186    /// The function uses the **Modbus function code 0x04** (read input registers). The holding registers and input
187    /// registers have different historical meaning, but nowadays it’s more common to use holding registers only.
188    ///
189    /// # Return value
190    ///
191    /// The function returns a `Result` containing the number of read bits if successful. Otherwise it returns an Error.
192    ///
193    /// # Parameters
194    ///
195    /// * `address` - address of the remote device
196    /// * `num`     - number of input registers to read
197    /// * `dest`    - the result of the reading is stored here
198    ///
199    /// # Examples
200    ///
201    /// ```rust,no_run
202    /// use libmodbus::{Modbus, ModbusClient, ModbusTCP};
203    /// let modbus = Modbus::new_tcp("127.0.0.1", 1502).unwrap();
204    /// let mut dest = vec![0u16; 100];
205    ///
206    /// assert!(modbus.read_input_registers(0, 1, &mut dest).is_ok());
207    /// ```
208    fn read_input_registers(&self, address: u16, num: u16, dest: &mut [u16]) -> Result<u16, Error> {
209        unsafe {
210            match ffi::modbus_read_input_registers(
211                self.ctx,
212                address as c_int,
213                num as c_int,
214                dest.as_mut_ptr(),
215            ) {
216                -1 => Err(Error::Client {
217                    msg: "read_input_registers".to_owned(),
218                    source: ::std::io::Error::last_os_error(),
219                }),
220                len => Ok(len as u16),
221            }
222        }
223    }
224
225    /// `report_slave_id` - returns a description of the controller
226    ///
227    /// The [`report_slave_id()`](#method.report_slave_id) function shall send a request to the controller to obtain a
228    /// description of the controller. The response stored in `dest` contains:
229    ///     * the slave ID, this unique ID is in reality not unique at all so it's not possible to depend on it to know
230    /// how the information are packed in the response.
231    ///     * the run indicator status (0x00 = OFF, 0xFF = ON)
232    ///     * additional data specific to each controller. For example, libmodbus returns the version of the library as
233    /// a string.
234    ///
235    /// # Return value
236    ///
237    /// The function returns a `Result` containing the number of read bits if successful. If the output was truncated
238    /// due the `max_dest` limit then the return value is the number of bytes which would have been written to `dest`.
239    /// Thus, a return value greater than the `max_dest` means that the resonse data was truncated.
240    /// Otherwise the Result contains an Error.
241    ///
242    /// # Parameters
243    ///
244    /// * `max_dest`    - limit, write `max_dest` bytes from the response to `dest`
245    /// * `dest`    - the result of the reading is stored here
246    ///
247    /// # Examples
248    ///
249    /// ```rust,no_run
250    /// use libmodbus::{Modbus, ModbusClient, ModbusTCP};
251    /// let modbus = Modbus::new_tcp("127.0.0.1", 1502).unwrap();
252    /// let mut bytes = vec![0u8; Modbus::MAX_PDU_LENGTH];
253    ///
254    /// assert!(modbus.report_slave_id(Modbus::MAX_PDU_LENGTH, &mut bytes).is_ok());
255    /// // assert_eq!(bytes, vec![180, 255, 76, 77, 66, 51, 46, 49, 46, 52]));
256    /// ```
257    fn report_slave_id(&self, max_dest: usize, dest: &mut [u8]) -> Result<u16, Error> {
258        unsafe {
259            match ffi::modbus_report_slave_id(self.ctx, max_dest as c_int, dest.as_mut_ptr()) {
260                -1 => Err(Error::Client {
261                    msg: "report_slave_id".to_owned(),
262                    source: ::std::io::Error::last_os_error(),
263                }),
264                len => Ok(len as u16),
265            }
266        }
267    }
268
269    /// `write_bit` - write a single bit
270    ///
271    /// The [`write_bit()`](#method.write_bit) function shall write the `status` at the `address` of the remote device.
272    /// The value must be set to `true` of `false`.
273    ///
274    /// The function uses the **Modbus function code 0x05** (force single coil).
275    ///
276    /// # Return value
277    ///
278    /// The function return an OK Result, containing a one, if successful. Otherwise it contains an Error.
279    ///
280    /// # Parameters
281    ///
282    /// * `address` - address of the remote device
283    /// * `status` - status that should write at the address `addr`
284    ///
285    /// # Examples
286    ///
287    /// ```rust,no_run
288    /// use libmodbus::{Modbus, ModbusClient, ModbusTCP};
289    /// let modbus = Modbus::new_tcp("127.0.0.1", 1502).unwrap();
290    /// let address = 1;
291    ///
292    /// assert!(modbus.write_bit(address, true).is_ok());
293    /// ```
294    fn write_bit(&self, address: u16, status: bool) -> Result<(), Error> {
295        unsafe {
296            match ffi::modbus_write_bit(self.ctx, address as c_int, status as c_int) {
297                -1 => Err(Error::Client {
298                    msg: "write_bit".to_owned(),
299                    source: ::std::io::Error::last_os_error(),
300                }),
301                1 => Ok(()),
302                _ => panic!("libmodbus API incompatible response"),
303            }
304        }
305    }
306
307    /// `write_register` - write a single register
308    ///
309    /// The [`write_register()`](#method.write_register) function shall write the value of value holding registers at
310    /// the address addr of the remote device.
311    ///
312    /// The function uses the **Modbus function code 0x06** (preset single register).
313    ///
314    /// # Return value
315    ///
316    /// The function return an OK Result, containing a one, if successful. Otherwise it contains an Error.
317    ///
318    /// # Parameters
319    ///
320    /// * `address` - address of the remote device
321    /// * `value` - vec with the value of the holding register which shall be written
322    ///
323    /// # Examples
324    ///
325    /// ```rust,no_run
326    /// use libmodbus::{Modbus, ModbusClient, ModbusTCP};
327    /// let modbus = Modbus::new_tcp("127.0.0.1", 1502).unwrap();
328    /// let address = 1;
329    /// let value = u16::max_value();
330    ///
331    /// assert!(modbus.write_register(address, value).is_ok());
332    /// ```
333    fn write_register(&self, address: u16, value: u16) -> Result<(), Error> {
334        unsafe {
335            match ffi::modbus_write_register(self.ctx, address as c_int, value) {
336                -1 => Err(Error::Client {
337                    msg: "write_register".to_owned(),
338                    source: ::std::io::Error::last_os_error(),
339                }),
340                1 => Ok(()),
341                _ => panic!("libmodbus API incompatible response"),
342            }
343        }
344    }
345
346    /// `write_bits` - write many bits
347    ///
348    /// The [`write_bits()`](#method.write_bits) function shall write the status of the bits (coils) from `src` at the
349    /// `address` of the remote device. The `src` array must contains bytes set to TRUE or FALSE.
350    ///
351    /// The function shall return the number of written bits if successful. Otherwise it contains an Error.
352    ///
353    /// # Return value
354    ///
355    /// The function returns a Ok Result containing the number of written bits. Otherwise it contains an Error.
356    ///
357    /// # Parameters
358    ///
359    /// * `address` - address of the remote device
360    /// * `num`     - number or bits that should be writen at the address `address`
361    /// * `src`     - vec of `0` and `1` (true and false) values
362    ///
363    /// # Examples
364    ///
365    /// ```rust,no_run
366    /// use libmodbus::{Modbus, ModbusClient, ModbusTCP};
367    /// let modbus = Modbus::new_tcp("127.0.0.1", 1502).unwrap();
368    /// let address = 1;
369    /// let tab_bytes = vec![0u8];
370    ///
371    /// assert_eq!(modbus.write_bits(address, 1, &tab_bytes).unwrap(), 1);
372    /// ```
373    fn write_bits(&self, address: u16, num: u16, src: &[u8]) -> Result<u16, Error> {
374        unsafe {
375            match ffi::modbus_write_bits(self.ctx, address as c_int, num as c_int, src.as_ptr()) {
376                -1 => Err(Error::Client {
377                    msg: "write_bits".to_owned(),
378                    source: ::std::io::Error::last_os_error(),
379                }),
380                num => Ok(num as u16),
381            }
382        }
383    }
384
385    /// `write_registers` - write many registers
386    ///
387    /// The [`write_registers()`](#method.write_registers) function shall write the content of the `num` holding
388    /// registers
389    /// from the array `src` at `address` of the remote device.
390    ///
391    /// The function uses the **Modbus function code 0x10** (preset multiple registers).
392    ///
393    /// # Return value
394    ///
395    /// The function returns a Ok Result containing the number of written bytes. Otherwise it contains an Error.
396    ///
397    /// # Parameters
398    ///
399    /// * `address` - address of the remote device
400    /// * `num`     - number of holding registers that should write at the address `address`
401    /// * `src`     - holding register
402    ///
403    /// # Examples
404    ///
405    /// ```rust,no_run
406    /// use libmodbus::{Modbus, ModbusClient, ModbusTCP};
407    /// let modbus = Modbus::new_tcp("127.0.0.1", 1502).unwrap();
408    /// let address = 1;
409    /// let tab_bytes = vec![0u16];
410    ///
411    /// assert_eq!(modbus.write_registers(address, 1, &tab_bytes).unwrap(), 1);
412    /// ```
413    fn write_registers(&self, address: u16, num: u16, src: &[u16]) -> Result<u16, Error> {
414        unsafe {
415            match ffi::modbus_write_registers(
416                self.ctx,
417                address as c_int,
418                num as c_int,
419                src.as_ptr(),
420            ) {
421                -1 => Err(Error::Client {
422                    msg: "write_registers".to_owned(),
423                    source: ::std::io::Error::last_os_error(),
424                }),
425                num => Ok(num as u16),
426            }
427        }
428    }
429
430    /// `write_and_read_registers` - write and read many registers in a single transaction
431    ///
432    /// The [`write_and_read_registers()`](#method.write_and_read_registers) function shall write the content of the
433    /// write_nb holding registers from the array src to the address write_addr of the remote device then shall read
434    /// the content of the read_nb holding registers to the address read_addr of the remote device. The result of
435    /// reading is stored in dest array as word values (16 bits).
436    ///
437    /// The function uses the **Modbus function code 0x17** (write/read registers).
438    ///
439    /// # Return value
440    ///
441    /// The function returns a Ok Result containing the number of read registers. Otherwise it contains an Error.
442    ///
443    /// # Parameters
444    ///
445    /// * `write_address`   - address of the remote device
446    /// * `write_num`       - number of holding registers
447    /// * `src`             - holding register
448    /// * `read_address`    - address of the remote device
449    /// * `read_num`        - number of holding registers
450    /// * `dest`            - holding register
451    ///
452    /// # Examples
453    ///
454    /// ```rust,no_run
455    /// use libmodbus::{Modbus, ModbusClient, ModbusTCP};
456    /// let modbus = Modbus::new_tcp("127.0.0.1", 1502).unwrap();
457    /// let address = 1;
458    /// let request_bytes = vec![1u16];
459    /// let mut response_bytes = vec![0u16];
460    ///
461    /// assert_eq!(modbus.write_and_read_registers(
462    ///                 address, 1, &request_bytes,
463    ///                 address, 1, &mut response_bytes).unwrap(), 1);
464    /// ```
465    fn write_and_read_registers(
466        &self,
467        write_address: u16,
468        write_num: u16,
469        src: &[u16],
470        read_address: u16,
471        read_num: u16,
472        dest: &mut [u16],
473    ) -> Result<u16, Error> {
474        unsafe {
475            match ffi::modbus_write_and_read_registers(
476                self.ctx,
477                write_address as c_int,
478                write_num as c_int,
479                src.as_ptr(),
480                read_address as c_int,
481                read_num as c_int,
482                dest.as_mut_ptr(),
483            ) {
484                -1 => Err(Error::Client {
485                    msg: "write_and_read_registers".to_owned(),
486                    source: ::std::io::Error::last_os_error(),
487                }),
488                num => Ok(num as u16),
489            }
490        }
491    }
492
493    /// `mask_write_register` - mask a single register
494    ///
495    /// The [`mask_write_register()`](#method.mask_write_register) function shall modify the value of the
496    /// holding register at the address `address` of the remote device using the algorithm:
497    ///
498    /// ```bash,no_run
499    /// new value = (current value AND 'and') OR ('or' AND (NOT 'and'))
500    /// ```
501    ///
502    /// The function uses the **Modbus function code 0x16** (mask single register).
503    ///
504    /// # Return value
505    ///
506    /// The function returns a Ok Result if succesful. Otherwise it contains an Error.
507    ///
508    /// # Parameters
509    ///
510    /// * `address`    - address of the remote device
511    /// * `and_mask`   - AND mask
512    /// * `or_mask`    - OR mask
513    ///
514    /// # Examples
515    ///
516    /// ```rust,no_run
517    /// use libmodbus::{Modbus, ModbusClient, ModbusTCP};
518    /// let modbus = Modbus::new_tcp("127.0.0.1", 1502).unwrap();
519    ///
520    /// assert!(modbus.mask_write_register(1, 0xF2, 0x25).is_ok());
521    /// ```
522    fn mask_write_register(&self, address: u16, and_mask: u16, or_mask: u16) -> Result<(), Error> {
523        unsafe {
524            match ffi::modbus_mask_write_register(self.ctx, address as c_int, and_mask, or_mask) {
525                -1 => Err(Error::Client {
526                    msg: "mask_write_register".to_owned(),
527                    source: ::std::io::Error::last_os_error(),
528                }),
529                1 => Ok(()),
530                _ => panic!("libmodbus API incompatible response"),
531            }
532        }
533    }
534
535    /// `send_raw_request` - send a raw request
536    ///
537    /// The [`send_raw_request()`](#method.send_raw_request) function shall send a request via the socket of the
538    /// current modbus contest.
539    ///
540    /// This function must be used for debugging purposes because you have to take care to make a valid request by hand.
541    /// The function only adds to the message, the header or CRC of the selected backend, so `raw_request` must start
542    /// and contain at least a slave/unit identifier and a function code.
543    /// This function can be used to send request not handled by the library.
544    ///
545    /// The enum [`FunctionCode`](enum.FunctionCode.html) provides a list of supported Modbus functions codes, to help
546    /// build of raw requests.
547    ///
548    /// # Parameters
549    ///
550    /// * `raw_request`     - raw request to send
551    /// * `length`          - raw request length
552    ///
553    /// # Return value
554    ///
555    /// The function returns a Result, containing the full message lenght,  counting the extra data relating to the
556    /// backend, if successful. Otherwise it contains an Error.
557    ///
558    /// # Examples
559    ///
560    /// ```rust,no_run
561    /// use libmodbus::{Modbus, ModbusClient, ModbusTCP, FunctionCode};
562    ///
563    /// let modbus = Modbus::new_tcp("127.0.0.1", 1502).unwrap();
564    /// let mut raw_request: Vec<u8> = vec![0xFF, FunctionCode::ReadHoldingRegisters as u8, 0x00, 0x01, 0x0, 0x05];
565    /// let mut response = vec![0u8; Modbus::TCP_MAX_ADU_LENGTH];
566    /// let request_len = raw_request.len();
567    ///
568    /// assert_eq!(modbus.send_raw_request(&mut raw_request, request_len).unwrap(), 6);
569    /// assert!(modbus.receive_confirmation(&mut response).is_ok());
570    /// ```
571    fn send_raw_request(&self, raw_request: &mut [u8], lenght: usize) -> Result<u16, Error> {
572        unsafe {
573            match ffi::modbus_send_raw_request(self.ctx, raw_request.as_mut_ptr(), lenght as c_int)
574            {
575                -1 => Err(Error::Client {
576                    msg: "send_raw_request".to_owned(),
577                    source: ::std::io::Error::last_os_error(),
578                }),
579                num => Ok(num as u16),
580            }
581        }
582    }
583
584    /// `receive_confirmation` - receive a confirmation request
585    ///
586    /// The [`receive_confirmation()`](#method.receive_confirmation) function shall receive a request via the socket of
587    /// the context `ctx` Member of the [Modbus struct](struct.Modbus.html).
588    /// This function must be used for debugging purposes because the received response isn’t checked against the
589    /// initial request.
590    /// This function can be used to receive request not handled by the library.
591    ///
592    /// The maximum size of the response depends on the used backend, in RTU the `response` array
593    /// must be `Modbus::RTU_MAX_ADU_LENGTH` bytes and in TCP it must be
594    /// `Modbus::TCP_MAX_ADU_LENGTH` bytes. If you want to write code compatible with both,
595    /// you can use the constant `Modbus::MAX_ADU_LENGTH` (maximum value of all libmodbus backends).
596    ///
597    /// # Return value
598    ///
599    /// The function returns a Result containing the response length if successful.
600    /// The returned request length can be zero if the indication request is ignored
601    /// (eg. a query for another slave in RTU mode). Otherwise it contains an Error.
602    ///
603    /// # Parameters
604    ///
605    /// * `response`   - store for the received response
606    ///
607    /// # Examples
608    ///
609    /// ```rust,no_run
610    /// use libmodbus::{Modbus, ModbusClient, ModbusTCP};
611    /// let modbus = Modbus::new_tcp("127.0.0.1", 1502).unwrap();
612    /// let mut response = vec![0u8; Modbus::MAX_ADU_LENGTH];
613    ///
614    /// assert!(modbus.receive_confirmation(&mut response).is_ok());
615    /// ```
616    fn receive_confirmation(&self, response: &mut [u8]) -> Result<u16, Error> {
617        unsafe {
618            match ffi::modbus_receive_confirmation(self.ctx, response.as_mut_ptr()) {
619                -1 => Err(Error::Client {
620                    msg: "receive_confirmation".to_owned(),
621                    source: ::std::io::Error::last_os_error(),
622                }),
623                len => Ok(len as u16),
624            }
625        }
626    }
627}