libmodbus/modbus_tcp_pi.rs
1use crate::prelude::*;
2use libmodbus_sys as ffi;
3use std::ffi::CString;
4
5/// The TCP PI (Protocol Independent) backend implements a Modbus variant used for communications over TCP IPv4 and
6/// IPv6 networks.
7/// It does not require a checksum calculation as lower layer takes care of the same.
8///
9/// Contrary to the TCP IPv4 only backend, the TCP PI backend offers hostname resolution but it consumes about 1Kb of
10/// additional memory.
11///
12/// * Create a Modbus TCP context
13/// - [`new_tcp_pi()`](struct.Modbus.html#method.new_tcp_pi)
14///
15pub trait ModbusTCPPI {
16 fn new_tcp_pi(node: &str, service: &str) -> Result<Modbus, Error>;
17 fn tcp_pi_accept(&mut self, socket: &mut i32) -> Result<i32, Error>;
18 fn tcp_pi_listen(&mut self, num_connection: i32) -> Result<i32, Error>;
19}
20
21impl ModbusTCPPI for Modbus {
22 /// `new_tcp_pi` - create a libmodbus context for TCP Protocol Independent
23 ///
24 /// The [`new_tcp_pi()`](#method.new_tcp_pi) function shall allocate and initialize a modbus_t structure to
25 /// communicate with a Modbus TCP IPv4 or IPv6 server.
26 ///
27 /// The **node** argument specifies the host name or IP address of the host to connect to, eg. "192.168.0.5" ,
28 /// "::1" or "server.com".
29 /// A NULL value can be used to listen any addresses in server mode.
30 ///
31 /// The **service** argument is the service name/port number to connect to. To use the default Modbus port use the
32 /// string "502".
33 /// On many Unix systems, it’s convenient to use a port number greater than or equal to 1024 because it’s not
34 /// necessary to have administrator privileges.
35 ///
36 /// # Examples
37 ///
38 /// ```
39 /// use libmodbus::{Modbus, ModbusTCPPI};
40 ///
41 /// let modbus = Modbus::new_tcp_pi("::1", "1502").unwrap();
42 ///
43 /// match modbus.connect() {
44 /// Ok(_) => {}
45 /// Err(e) => println!("Error: {}", e),
46 /// }
47 /// ```
48 fn new_tcp_pi(node: &str, service: &str) -> Result<Modbus, Error> {
49 unsafe {
50 let node = CString::new(node).unwrap();
51 let service = CString::new(service).unwrap();
52 let ctx = ffi::modbus_new_tcp_pi(node.as_ptr(), service.as_ptr());
53
54 if ctx.is_null() {
55 Err(Error::TcpPi {
56 msg: "new_tcp_pi".to_owned(),
57 source: ::std::io::Error::last_os_error(),
58 })
59 } else {
60 Ok(Modbus { ctx: ctx })
61 }
62 }
63 }
64
65 /// `tcp_pi_accept` - accept a new connection on a TCP PI Modbus socket (IPv6)
66 ///
67 /// The [`tcp_pi_accept()`](#method.tcp_pi_accept) function shall extract the first connection on the
68 /// queue of pending connections and create a new socket given as argument.
69 ///
70 /// # Parameters
71 ///
72 /// * `socket` - Socket
73 ///
74 /// # Examples
75 ///
76 /// ```rust,no_run
77 /// use libmodbus::{Modbus, ModbusMapping, ModbusServer, ModbusTCPPI};
78 ///
79 /// let mut modbus = Modbus::new_tcp_pi("::0", "1502").unwrap();
80 /// let mut socket = modbus.tcp_pi_listen(1).unwrap();
81 /// modbus.tcp_pi_accept(&mut socket).unwrap();
82 /// ```
83 fn tcp_pi_accept(&mut self, socket: &mut i32) -> Result<i32, Error> {
84 unsafe {
85 match ffi::modbus_tcp_pi_accept(self.ctx, socket) {
86 -1 => Err(Error::TcpPi {
87 msg: "tcp_pi_accept".to_owned(),
88 source: ::std::io::Error::last_os_error(),
89 }),
90 socket => Ok(socket),
91 }
92 }
93 }
94
95 /// `tcp_pi_listen` - create and listen a TCP PI Modbus socket (IPv6)
96 ///
97 /// The [`tcp_pi_listen()`](#method.tcp_pi_listen) function shall create a socket and listen to maximum
98 /// `num_connection` incoming connections on the specifieded node.
99 ///
100 /// # Parameters
101 ///
102 /// * `num_connection` - maximum number of incoming connections on the specified IP address
103 ///
104 /// If node is set to `""` or `0.0.0.0`, any addresses will be listen.
105 ///
106 /// # Examples
107 ///
108 /// For detailed examples, look at the examples directory of this crate.
109 ///
110 /// * unit-test-server.rs - simple but handle only one connection
111 /// * bandwidth-server-many-up.rs - handles several connection at once
112 ///
113 /// ```rust,no_run
114 /// use libmodbus::{Modbus, ModbusMapping, ModbusServer, ModbusTCPPI};
115 ///
116 /// let mut modbus = Modbus::new_tcp_pi("::0", "1502").unwrap();
117 /// let mut socket = modbus.tcp_pi_listen(1).unwrap();
118 ///
119 /// modbus.tcp_pi_accept(&mut socket);
120 ///
121 /// let modbus_mapping = ModbusMapping::new(500, 500, 500, 500).unwrap();
122 /// let mut query = vec![0u8; Modbus::MAX_ADU_LENGTH as usize];
123 ///
124 /// loop {
125 /// let request_len = modbus.receive(&mut query).unwrap();
126 /// modbus.reply(&query, request_len, &modbus_mapping);
127 /// }
128 /// ```
129 fn tcp_pi_listen(&mut self, num_connection: i32) -> Result<i32, Error> {
130 unsafe {
131 match ffi::modbus_tcp_pi_listen(self.ctx, num_connection) {
132 -1 => Err(Error::TcpPi {
133 msg: "tcp_pi_listen".to_owned(),
134 source: ::std::io::Error::last_os_error(),
135 }),
136 socket => Ok(socket),
137 }
138 }
139 }
140}