libmodbus-rs 0.8.3

libmodbus bindings for Rust
extern crate libmodbus_rs;

use libmodbus_rs::{Modbus, ModbusClient, ModbusServer, ModbusMapping, FunctionCode, ModbusTCP};
use std::thread;
use std::time::Duration;

fn start_server(port: i32) -> thread::JoinHandle<()> {
    thread::spawn(move || {
        let mut modbus = Modbus::new_tcp("127.0.0.1", port).expect("Could not create TCP Server context");
        let mut socket = modbus.tcp_listen(1).expect("Could not listen to TCP socket");
        modbus.tcp_accept(&mut socket).expect("Could not accept connection");

        let mb_mapping = ModbusMapping::new(Modbus::MAX_READ_BITS, 
                                            Modbus::MAX_READ_BITS,
                                            Modbus::MAX_READ_REGISTERS, 
                                            Modbus::MAX_READ_REGISTERS).expect("Failed to allocate the mapping");

            loop {
                let mut query = vec![0u8; Modbus::TCP_MAX_ADU_LENGTH];

                match modbus.receive(&mut query) {
                    Ok(rc) => modbus.reply(&query, rc, &mb_mapping),
                    Err(_err) => break,
                }.expect("Could not receive");
            }
    })
}


#[test]
fn read_bits() {
    let port = 1502;
    // Start modbus server
    let server_thread = start_server(port);
    thread::sleep(Duration::from_millis(200));

    // connect client
    match Modbus::new_tcp("127.0.0.1", port) {
        Ok(client) => {
            let mut dest = vec![0u8; 100];
            client.connect().expect("could not connect");
            assert!(client.read_bits(0, 1, &mut dest).is_ok());
        },
        _ => panic!("could not connect"),
    }

    let _ = server_thread.join();
}

#[test]
fn read_input_bits() {
    let port = 1503;
    // Start modbus server
    let server_thread = start_server(port);
    thread::sleep(Duration::from_millis(200));

    // connect client
    match Modbus::new_tcp("127.0.0.1", port) {
        Ok(client) => {
            let mut dest = vec![0u8; 100];
            client.connect().expect("could not connect");
            assert!(client.read_input_bits(0, 1, &mut dest).is_ok());
        },
        _ => panic!("could not connect"),
    }

    let _ = server_thread.join();
}

#[test]
fn read_registers() {
    let port = 1504;
    // Start modbus server
    let server_thread = start_server(port);
    thread::sleep(Duration::from_millis(200));

    // connect client
    match Modbus::new_tcp("127.0.0.1", port) {
        Ok(client) => {
            let mut dest = vec![0u16; 100];
            client.connect().expect("could not connect");
            assert!(client.read_registers(0, 1, &mut dest).is_ok());
        },
        _ => panic!("could not connect"),
    }

    let _ = server_thread.join();
}

#[test]
fn read_input_registers() {
    let port = 1505;
    // Start modbus server
    let server_thread = start_server(port);
    thread::sleep(Duration::from_millis(200));

    // connect client
    match Modbus::new_tcp("127.0.0.1", port) {
        Ok(client) => {
            let mut dest = vec![0u16; 100];
            client.connect().expect("could not connect");
            assert!(client.read_input_registers(0, 1, &mut dest).is_ok());
        },
        _ => panic!("could not connect"),
    }

    let _ = server_thread.join();
}

#[test]
fn report_slave_id() {
    let port = 1506;
    // Start modbus server
    let server_thread = start_server(port);
    thread::sleep(Duration::from_millis(200));

    // connect client
    match Modbus::new_tcp("127.0.0.1", port) {
        Ok(client) => {
            let mut bytes = vec![0u8; Modbus::MAX_PDU_LENGTH];
            client.connect().expect("could not connect");
            // println!("{:?}", str::from_utf8(&client.report_slave_id[2..])) # => Ok("LMB3.1.4")
            assert!(client.report_slave_id(Modbus::MAX_PDU_LENGTH, &mut bytes).is_ok());
            // assert_eq!(client.report_slave_id().unwrap(), vec![180, 255, 76, 77, 66, 51, 46, 49, 46, 52]);
        },
        _ => panic!("could not connect"),
    }

    let _ = server_thread.join();
}

#[test]
fn write_bit() {
    let port = 1507;
    // Start modbus server
    let server_thread = start_server(port);
    thread::sleep(Duration::from_millis(200));

    // connect client
    match Modbus::new_tcp("127.0.0.1", port) {
        Ok(client) => {
            client.connect().expect("could not connect");
            assert!(client.write_bit(0, true).is_ok());
        },
        _ => panic!("could not connect"),
    }

    let _ = server_thread.join();
}

#[test]
fn write_bits() {
    let port = 1508;
    // Start modbus server
    let server_thread = start_server(port);
    thread::sleep(Duration::from_millis(200));

    // connect client
    match Modbus::new_tcp("127.0.0.1", port) {
        Ok(client) => {
            client.connect().expect("could not connect");
            let src = vec![1u8];
            assert_eq!(client.write_bits(0, 1, &src).unwrap(), 1);
        },
        _ => panic!("could not connect"),
    }

    let _ = server_thread.join();
}

#[test]
fn write_register() {
    let port = 1509;
    // Start modbus server
    let server_thread = start_server(port);
    thread::sleep(Duration::from_millis(200));

    // connect client
    match Modbus::new_tcp("127.0.0.1", port) {
        Ok(client) => {
            client.connect().expect("could not connect");
            let address: u16 = 1;
            let value = u16::max_value();
            assert!(client.write_register(address, value).is_ok());
        },
        _ => panic!("could not connect"),
    }

    let _ = server_thread.join();
}

#[test]
fn write_registers() {
    let port = 1510;
    // Start modbus server
    let server_thread = start_server(port);
    thread::sleep(Duration::from_millis(200));

    // connect client
    match Modbus::new_tcp("127.0.0.1", port) {
        Ok(client) => {
            client.connect().expect("could not connect");
            let address = 1;
            let tab_bytes = vec![0u16];
            assert_eq!(client.write_registers(address, 1, &tab_bytes).unwrap(), 1);
        },
        _ => panic!("could not connect"),
    }

    let _ = server_thread.join();
}

#[test]
fn write_and_read_registers() {
    let port = 1511;
    // Start modbus server
    let server_thread = start_server(port);
    thread::sleep(Duration::from_millis(200));

    // connect client
    match Modbus::new_tcp("127.0.0.1", port) {
        Ok(client) => {
            client.connect().expect("could not connect");
        },
        _ => panic!("could not connect"),
    }

    let _ = server_thread.join();
}

#[test]
fn send_raw_request() {
    let port = 1512;
    // Start modbus server
    let server_thread = start_server(port);
    thread::sleep(Duration::from_millis(200));

    // connect client
    match Modbus::new_tcp("127.0.0.1", port) {
        Ok(client) => {
            client.connect().expect("could not connect");
            let mut raw_request: Vec<u8> = vec![0xFF, FunctionCode::ReadHoldingRegisters as u8, 0x00, 0x01, 0x0, 0x05];
            let mut response = vec![0u8; Modbus::MAX_ADU_LENGTH];
            assert_eq!(client.send_raw_request(&mut raw_request, 12).unwrap(), 18);
            assert!(client.receive_confirmation(&mut response).is_ok());
        },
        _ => panic!("could not connect"),
    }

    let _ = server_thread.join();
}

#[test]
fn receive_confirmation() {
    let port = 1513;
    // Start modbus server
    let server_thread = start_server(port);
    thread::sleep(Duration::from_millis(200));

    // connect client
    match Modbus::new_tcp("127.0.0.1", port) {
        Ok(client) => {
            client.connect().expect("could not connect");
            let mut raw_request: Vec<u8> = vec![0xFF, FunctionCode::ReadHoldingRegisters as u8, 0x00, 0x01, 0x0, 0x05];
            let mut response = vec![0u8; Modbus::MAX_ADU_LENGTH];
            assert_eq!(client.send_raw_request(&mut raw_request, 12).unwrap(), 18);
            assert!(client.receive_confirmation(&mut response).is_ok());
        },
        _ => panic!("could not connect"),
    }

    let _ = server_thread.join();
}