libmodbus/modbus_tcp.rs
1use crate::prelude::*;
2use libmodbus_sys as ffi;
3use std::ffi::CString;
4
5/// The TCP backend implements a Modbus variant used for communications over TCP/IPv4 networks.
6/// It does not require a checksum calculation as lower layer takes care of the same.
7///
8/// * Create a Modbus TCP context
9///     - [`new_tcp()`](struct.Modbus.html#method.new_tcp)
10///
11pub trait ModbusTCP {
12    fn new_tcp(ip: &str, port: i32) -> Result<Modbus, Error>;
13    fn tcp_accept(&mut self, socket: &mut i32) -> Result<i32, Error>;
14    fn tcp_listen(&mut self, num_connection: i32) -> Result<i32, Error>;
15}
16
17impl ModbusTCP for Modbus {
18    /// `new_tcp` - create a libmodbus context for TCP/IPv4
19    ///
20    /// The [`new_tcp()`](#method.new_tcp) function shall allocate and initialize a modbus_t structure
21    /// to communicate with a Modbus TCP IPv4 server.
22    /// The **ip** argument specifies the IP address of the server to which the client wants to
23    /// establish a connection. A empty string `""` value can be used to listen any addresses in server mode.
24    /// The **port** argument is the TCP port to use. Set the port to `MODBUS_TCP_DEFAULT_PORT`
25    /// to use the default one (502). It’s convenient to use a port number greater than or
26    /// equal to 1024 because it’s not necessary to have administrator privileges.
27    ///
28    /// # Examples
29    ///
30    /// ```
31    /// use libmodbus::{Modbus, ModbusTCP};
32    ///
33    /// let modbus = Modbus::new_tcp("127.0.0.1", 1502).unwrap();
34    /// let modbus = Modbus::new_tcp("127.0.0.1", Modbus::TCP_DEFAULT_PORT as i32).unwrap();
35    ///
36    /// match modbus.connect() {
37    ///     Ok(_) => {  }
38    ///     Err(e) => println!("Error: {}", e),
39    /// }
40    /// ```
41    fn new_tcp(ip: &str, port: i32) -> Result<Modbus, Error> {
42        unsafe {
43            let ip = CString::new(ip).unwrap();
44            let ctx = ffi::modbus_new_tcp(ip.as_ptr(), port);
45
46            if ctx.is_null() {
47                Err(Error::Tcp {
48                    msg: "new_tcp".to_owned(),
49                    source: ::std::io::Error::last_os_error(),
50                })
51            } else {
52                Ok(Modbus { ctx: ctx })
53            }
54        }
55    }
56
57    /// `tcp_accept` - accept a new connection on a TCP Modbus socket (IPv4)
58    ///
59    /// The [`tcp_accept()`](#method.tcp_accept) function shall extract the first connection on the
60    /// queue of pending connections and create a new socket given as argument.
61    ///
62    /// # Parameters
63    ///
64    /// * `socket`  - Socket
65    ///
66    /// # Examples
67    ///
68    /// ```rust,no_run
69    /// use libmodbus::{Modbus, ModbusTCP};
70    ///
71    /// let mut modbus = Modbus::new_tcp("127.0.0.1", 1502).unwrap();
72    /// let mut socket = modbus.tcp_listen(1).unwrap();
73    ///
74    /// modbus.tcp_accept(&mut socket);
75    /// ```
76    fn tcp_accept(&mut self, socket: &mut i32) -> Result<i32, Error> {
77        unsafe {
78            match ffi::modbus_tcp_accept(self.ctx, socket) {
79                -1 => Err(Error::Tcp {
80                    msg: "tcp_accept".to_owned(),
81                    source: ::std::io::Error::last_os_error(),
82                }),
83                socket => Ok(socket),
84            }
85        }
86    }
87
88    /// `tcp_listen` - create and listen a TCP Modbus socket (IPv4)
89    ///
90    /// The [`tcp_listen()`](#method.tcp_listen) function shall create a socket and listen to maximum
91    /// `num_connection` incoming connections on the specified IP address.
92    /// If IP address is set to NULL or '0.0.0.0', any addresses will be listen.
93    ///
94    /// # Parameters
95    ///
96    /// * `num_connection`  - maximum number of incoming connections on the specified IP address
97    ///
98    /// # Examples
99    ///
100    /// ```rust,no_run
101    /// use libmodbus::{Modbus, ModbusTCP};
102    ///
103    /// let mut modbus = Modbus::new_tcp("127.0.0.1", 1502).unwrap();
104    ///
105    /// let socket = modbus.tcp_listen(1);
106    /// ```
107    fn tcp_listen(&mut self, num_connection: i32) -> Result<i32, Error> {
108        unsafe {
109            match ffi::modbus_tcp_listen(self.ctx, num_connection) {
110                -1 => Err(Error::Tcp {
111                    msg: "tcp_listen".to_owned(),
112                    source: ::std::io::Error::last_os_error(),
113                }),
114                socket => Ok(socket),
115            }
116        }
117    }
118}