use errors::*;
use libc::{c_char, c_int};
use libmodbus_sys;
use modbus::Modbus;
use std::ffi::CString;
use std::io::Error;
use std::str;
#[derive(Debug, PartialEq)]
pub enum SerialMode {
MODBUS_RTU_RS232 = libmodbus_sys::MODBUS_RTU_RS232 as isize,
MODBUS_RTU_RS485 = libmodbus_sys::MODBUS_RTU_RS485 as isize,
}
#[derive(Debug, PartialEq)]
pub enum RequestToSendMode {
MODBUS_RTU_RTS_NONE = libmodbus_sys::MODBUS_RTU_RTS_NONE as isize,
MODBUS_RTU_RTS_UP = libmodbus_sys::MODBUS_RTU_RTS_UP as isize,
MODBUS_RTU_RTS_DOWN = libmodbus_sys::MODBUS_RTU_RTS_DOWN as isize,
}
pub trait ModbusRTU {
fn new_rtu(device: &str, baud: i32, parity: char, data_bit: i32, stop_bit: i32) -> Result<Modbus>;
fn rtu_get_serial_mode(&self) -> Result<SerialMode>;
fn rtu_set_serial_mode(&mut self, mode: SerialMode) -> Result<SerialMode>;
fn rtu_get_rts(&self) -> Result<RequestToSendMode>;
fn rtu_set_rts(&mut self, mode: RequestToSendMode) -> Result<RequestToSendMode>;
fn rtu_set_custom_rts(&mut self, _mode: RequestToSendMode) -> Result<i32>;
fn rtu_get_rts_delay(&self) -> Result<i32>;
fn rtu_set_rts_delay(&mut self, us: i32) -> Result<i32>;
}
impl ModbusRTU for Modbus {
fn new_rtu(device: &str, baud: i32, parity: char, data_bit: i32, stop_bit: i32) -> Result<Modbus> {
unsafe {
let device = CString::new(device).unwrap();
let ctx = libmodbus_sys::modbus_new_rtu(device.as_ptr(),
baud as c_int,
parity as c_char,
data_bit as c_int,
stop_bit as c_int);
if ctx.is_null() {
bail!(Error::last_os_error())
} else {
Ok(Modbus { ctx: ctx })
}
}
}
fn rtu_get_serial_mode(&self) -> Result<SerialMode> {
unsafe {
let mode = libmodbus_sys::modbus_rtu_get_serial_mode(self.ctx);
match mode {
mode if mode == SerialMode::MODBUS_RTU_RS232 as i32 => Ok(SerialMode::MODBUS_RTU_RS232),
mode if mode == SerialMode::MODBUS_RTU_RS485 as i32 => Ok(SerialMode::MODBUS_RTU_RS485),
_ => bail!(Error::last_os_error()),
}
}
}
fn rtu_set_serial_mode(&mut self, mode: SerialMode) -> Result<SerialMode> {
unsafe {
let mode = libmodbus_sys::modbus_rtu_set_serial_mode(self.ctx, mode as c_int) as u32;
match mode {
libmodbus_sys::MODBUS_RTU_RS232 => Ok(SerialMode::MODBUS_RTU_RS232),
libmodbus_sys::MODBUS_RTU_RS485 => Ok(SerialMode::MODBUS_RTU_RS485),
_ => bail!(Error::last_os_error()),
}
}
}
fn rtu_set_rts(&mut self, mode: RequestToSendMode) -> Result<RequestToSendMode> {
unsafe {
let mode = libmodbus_sys::modbus_rtu_set_rts(self.ctx, mode as c_int) as u32;
match mode {
libmodbus_sys::MODBUS_RTU_RTS_NONE => Ok(RequestToSendMode::MODBUS_RTU_RTS_NONE),
libmodbus_sys::MODBUS_RTU_RTS_UP => Ok(RequestToSendMode::MODBUS_RTU_RTS_UP),
libmodbus_sys::MODBUS_RTU_RTS_DOWN => Ok(RequestToSendMode::MODBUS_RTU_RTS_DOWN),
_ => bail!(Error::last_os_error()),
}
}
}
fn rtu_get_rts(&self) -> Result<RequestToSendMode> {
unsafe {
let mode = libmodbus_sys::modbus_rtu_get_rts(self.ctx) as u32;
match mode {
libmodbus_sys::MODBUS_RTU_RTS_NONE => Ok(RequestToSendMode::MODBUS_RTU_RTS_NONE),
libmodbus_sys::MODBUS_RTU_RTS_UP => Ok(RequestToSendMode::MODBUS_RTU_RTS_UP),
libmodbus_sys::MODBUS_RTU_RTS_DOWN => Ok(RequestToSendMode::MODBUS_RTU_RTS_DOWN),
_ => bail!(Error::last_os_error()),
}
}
}
fn rtu_set_custom_rts(&mut self, _mode: RequestToSendMode) -> Result<i32> {
unimplemented!()
}
fn rtu_get_rts_delay(&self) -> Result<i32> {
unsafe {
match libmodbus_sys::modbus_rtu_get_rts_delay(self.ctx) {
-1 => bail!(Error::last_os_error()),
delay => Ok(delay),
}
}
}
fn rtu_set_rts_delay(&mut self, us: i32) -> Result<i32> {
unsafe {
match libmodbus_sys::modbus_rtu_set_rts_delay(self.ctx, us as c_int) {
-1 => bail!(Error::last_os_error()),
_ => Ok(0),
}
}
}
}