1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
use failure::Error;
use libmodbus_sys as ffi;
use modbus_mapping::ModbusMapping;
use modbus::Modbus;


/// The server is waiting for request from clients and must answer when it is concerned by the request. The libmodbus
/// offers the following functions to handle requests:
///
/// * Receive
///     - [`receive()`](struct.Modbus.html#method.receive)
/// * Reply
///     - [`reply()`](struct.Modbus.html#method.reply), [`reply_exception()`](struct.Modbus.html#method.reply_exception)
///
pub trait ModbusServer {
    fn receive(&self, request: &mut [u8]) -> Result<i32, Error>;
    fn reply(&self, request: &[u8], request_len: i32, modbus_mapping: &ModbusMapping) -> Result<i32, Error>;
}

impl ModbusServer for Modbus {
    /// `receive` - receive an indication request
    ///
    /// The [`receive()`](#method.receive) function shall receive an indication request from the socket of the context
    /// ctx.
    /// This function is used by Modbus slave/server to receive and analyze indication request sent by the
    /// masters/clients.
    ///
    /// If you need to use another socket or file descriptor than the one defined in the context ctx, see the function
    /// [`set_socket()`](struct.Modbus.html#method.set_socket).
    ///
    /// # Examples
    ///
    /// ```rust,no_run
    /// use libmodbus_rs::{Modbus, ModbusServer, ModbusTCP};
    /// let modbus = Modbus::new_tcp("127.0.0.1", 1502).unwrap();
    /// let mut query = vec![0; Modbus::MAX_ADU_LENGTH as usize];
    ///
    /// assert!(modbus.receive(&mut query).is_ok());
    /// ```
    fn receive(&self, request: &mut [u8]) -> Result<i32, Error> {
        assert!(request.len() <= Modbus::MAX_ADU_LENGTH as usize);

        unsafe {
            let len = ffi::modbus_receive(self.ctx, request.as_mut_ptr());
            match len {
                -1 => bail!(::std::io::Error::last_os_error()),
                len => Ok(len),
            }
        }
    }

    /// `modbus_reply` - send a reponse to the received request
    ///
    /// The [`reply()`](#method.reply) function shall send a response to received request. The request req given in
    /// argument is analyzed, a response is then built and sent by using the information of the modbus context ctx.
    /// If the request indicates to read or write a value the operation will done in the modbus mapping mb_mapping
    /// according to the type of the manipulated data.
    /// If an error occurs, an exception response will be sent.
    ///
    /// This function is designed for Modbus server.
    ///
    /// # Examples
    ///
    /// ```rust,no_run
    /// use libmodbus_rs::{Modbus, ModbusServer, ModbusTCP};
    ///
    /// let modbus = Modbus::new_tcp("127.0.0.1", 1502).unwrap();
    /// let mut query = vec![0; Modbus::MAX_ADU_LENGTH as usize];
    ///
    /// assert!(modbus.receive(&mut query).is_ok());
    /// ```
    fn reply(&self, request: &[u8], request_len: i32, modbus_mapping: &ModbusMapping) -> Result<i32, Error> {
        unsafe {
            let len =
                ffi::modbus_reply(self.ctx, request.as_ptr(), request_len, modbus_mapping.modbus_mapping);
            match len {
                -1 => bail!(::std::io::Error::last_os_error()),
                len => Ok(len),
            }
        }
    }
}