#![allow(unused_variables)]
#![allow(unused_assignments)]
#![allow(dead_code)]
extern crate failure;
extern crate libmodbus_rs;
mod unit_test_config;
use failure::Error;
use libmodbus_rs::{Modbus, ModbusMapping, ModbusClient, ModbusServer, ModbusTCP, ModbusTCPPI, ModbusRTU};
use libmodbus_rs::Exception;
use libmodbus_rs::prelude::*;
use std::env;
use std::thread::sleep;
use std::time::Duration;
use unit_test_config::*;
fn run() -> Result<(), Error> {
let backend;
let args: Vec<_> = env::args().collect();
if args.len() > 1 {
match args[1].to_lowercase().as_ref() {
"tcp" => backend = Backend::TCP,
"tcppi" => backend = Backend::TCPPI,
"rtu" => backend = Backend::RTU,
_ => {
println!("Usage:\n {} [tcp|tcppi|rtu] - Modbus server for unit testing\n\n", args[0]);
std::process::exit(-1);
},
}
} else {
backend = Backend::TCP;
}
let (mut modbus, mut query) = match backend {
Backend::TCP => {
(Modbus::new_tcp("127.0.0.1", 1502).unwrap(),
vec![0u8; Modbus::TCP_MAX_ADU_LENGTH as usize])
},
Backend::TCPPI => {
(Modbus::new_tcp_pi("::0", "1502").unwrap(),
vec![0u8; Modbus::TCP_MAX_ADU_LENGTH as usize])
},
Backend::RTU => {
(Modbus::new_rtu("/dev/ttyUSB0", 115200, 'N', 8, 1).unwrap(),
vec![0u8; Modbus::RTU_MAX_ADU_LENGTH as usize])
},
};
if backend == Backend::RTU {
modbus.set_slave(SERVER_ID)?;
}
let header_length = modbus.get_header_length() as usize;
modbus.set_debug(true).expect("could not set modbus DEBUG mode");
let modbus_mapping =
ModbusMapping::new_start_address(UT_BITS_ADDRESS,
UT_BITS_NB,
UT_INPUT_BITS_ADDRESS,
UT_INPUT_BITS_NB,
UT_REGISTERS_ADDRESS,
UT_REGISTERS_NB,
UT_INPUT_REGISTERS_ADDRESS,
UT_INPUT_REGISTERS_NB)?;
set_bits_from_bytes(modbus_mapping.get_input_bits_mut(), 0, UT_INPUT_BITS_NB,
&UT_INPUT_BITS_TAB);
for i in 0..UT_INPUT_REGISTERS_NB {
modbus_mapping.get_input_registers_mut()[i as usize] = UT_INPUT_REGISTERS_TAB[i as usize];
}
match backend {
Backend::TCP => {
let mut socket = modbus.tcp_listen(1)?;
modbus.tcp_accept(&mut socket)?;
},
Backend::TCPPI => {
let mut socket = modbus.tcp_pi_listen(1)?;
modbus.tcp_pi_accept(&mut socket)?;
},
Backend::RTU => {
modbus.connect()?;
},
}
loop {
let mut rc: std::result::Result<i32, Error>;
loop {
rc = modbus.receive(&mut query);
match rc {
Ok(0) => {}
_ => break,
}
}
if rc.is_err() && rc.as_ref().unwrap_err().to_string() != "Invalid CRC" {
break;
}
if query[header_length] == 0x03 {
if query[header_length + 3] as u16 == UT_REGISTERS_NB_SPECIAL {
println!("Set an incorrect number of values");
query[header_length + 3] = (UT_REGISTERS_NB_SPECIAL - 1) as u8;
} else if query[header_length + 1] as u16 == UT_REGISTERS_ADDRESS_SPECIAL {
println!("Reply to this special register address by an exception");
modbus.reply_exception(&query, Exception::SlaveDeviceBusy).unwrap();
continue;
} else if query[header_length + 1] as u16 == UT_REGISTERS_ADDRESS_INVALID_TID_OR_SLAVE {
const RAW_REQ_LENGTH: usize = 5;
let mut raw_req = vec![
if backend == Backend::RTU { INVALID_SERVER_ID } else { 0xFF },
0x03,
0x02, 0x00, 0x00
];
println!("Reply with an invalid TID or slave");
modbus.send_raw_request(&mut raw_req, RAW_REQ_LENGTH).unwrap();
continue;
} else if query[header_length + 1] as u16 == UT_REGISTERS_ADDRESS_SLEEP_500_MS {
println!("Sleep 0.5 s before replying");
sleep(Duration::from_millis(500));
} else if query[header_length + 1] as u16 == UT_REGISTERS_ADDRESS_BYTE_SLEEP_5_MS {
let mut req = vec![0x00, 0x1C, 0x00, 0x00, 0x00, 0x05, 0xFF, 0x03, 0x02, 0x00, 0x00];
let req_length = 11;
let w_s = modbus.get_socket();
if w_s.is_err() {
println!("Unable to get a valid socket in special test");
continue;
}
req[1] = query[1];
for i in 0..req_length {
println!("({:2X})", req[i]);
sleep(Duration::from_millis(5));
}
continue;
}
}
let rc = modbus.reply(&query, rc.unwrap(), &modbus_mapping);
if rc.is_err() { break; }
}
println!("Quit the loop: ");
Ok(())
}
fn main() {
if let Err(ref err) = run() {
println!("Error: {}", err);
std::process::exit(1)
}
}