use crate::prelude::*;
use libc::{c_char, c_int};
use libmodbus_sys as ffi;
use std::ffi::CString;
use std::str;
#[derive(Debug, PartialEq)]
#[allow(non_camel_case_types)]
pub enum SerialMode {
RtuRS232 = ffi::MODBUS_RTU_RS232 as isize,
RtuRS485 = ffi::MODBUS_RTU_RS485 as isize,
}
#[derive(Debug, PartialEq)]
pub enum RequestToSendMode {
RtuRtsNone = ffi::MODBUS_RTU_RTS_NONE as isize,
RtuRtsUp = ffi::MODBUS_RTU_RTS_UP as isize,
RtuRtsDown = ffi::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, Error>;
fn rtu_get_serial_mode(&self) -> Result<SerialMode, Error>;
fn rtu_set_serial_mode(&mut self, mode: SerialMode) -> Result<(), Error>;
fn rtu_get_rts(&self) -> Result<RequestToSendMode, Error>;
fn rtu_set_rts(&mut self, mode: RequestToSendMode) -> Result<(), Error>;
fn rtu_set_custom_rts(&mut self, _mode: RequestToSendMode) -> Result<i32, Error>;
fn rtu_get_rts_delay(&self) -> Result<i32, Error>;
fn rtu_set_rts_delay(&mut self, us: i32) -> Result<(), Error>;
}
impl ModbusRTU for Modbus {
fn new_rtu(
device: &str,
baud: i32,
parity: char,
data_bit: i32,
stop_bit: i32,
) -> Result<Modbus, Error> {
unsafe {
let device = CString::new(device).unwrap();
let ctx = ffi::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() {
Err(Error::Rtu {
msg: "new_rtu".to_owned(),
source: ::std::io::Error::last_os_error(),
})
} else {
Ok(Modbus { ctx: ctx })
}
}
}
fn rtu_get_serial_mode(&self) -> Result<SerialMode, Error> {
unsafe {
let mode = ffi::modbus_rtu_get_serial_mode(self.ctx);
match mode {
mode if mode == SerialMode::RtuRS232 as i32 => Ok(SerialMode::RtuRS232),
mode if mode == SerialMode::RtuRS485 as i32 => Ok(SerialMode::RtuRS485),
_ => Err(Error::Rtu {
msg: "rtu_get_serial_mode".to_owned(),
source: ::std::io::Error::last_os_error(),
}),
}
}
}
fn rtu_set_serial_mode(&mut self, mode: SerialMode) -> Result<(), Error> {
unsafe {
let mode = ffi::modbus_rtu_set_serial_mode(self.ctx, mode as c_int) as i32;
match mode {
-1 => Err(Error::Rtu {
msg: "rtu_set_serial_mode".to_owned(),
source: ::std::io::Error::last_os_error(),
}),
0 => Ok(()),
_ => panic!("libmodbus API incompatible response"),
}
}
}
fn rtu_set_rts(&mut self, mode: RequestToSendMode) -> Result<(), Error> {
unsafe {
match ffi::modbus_rtu_set_rts(self.ctx, mode as c_int) {
-1 => Err(Error::Rtu {
msg: "rtu_set_rts".to_owned(),
source: ::std::io::Error::last_os_error(),
}),
0 => Ok(()),
_ => panic!("libmodbus API incompatible response"),
}
}
}
fn rtu_get_rts(&self) -> Result<RequestToSendMode, Error> {
unsafe {
let mode = ffi::modbus_rtu_get_rts(self.ctx) as u32;
match mode {
ffi::MODBUS_RTU_RTS_NONE => Ok(RequestToSendMode::RtuRtsNone),
ffi::MODBUS_RTU_RTS_UP => Ok(RequestToSendMode::RtuRtsUp),
ffi::MODBUS_RTU_RTS_DOWN => Ok(RequestToSendMode::RtuRtsDown),
_ => Err(Error::Rtu {
msg: "rtu_get_rts".to_owned(),
source: ::std::io::Error::last_os_error(),
}),
}
}
}
fn rtu_set_custom_rts(&mut self, _mode: RequestToSendMode) -> Result<i32, Error> {
unimplemented!()
}
fn rtu_get_rts_delay(&self) -> Result<i32, Error> {
unsafe {
match ffi::modbus_rtu_get_rts_delay(self.ctx) {
-1 => Err(Error::Rtu {
msg: "rtu_get_rts_delay".to_owned(),
source: ::std::io::Error::last_os_error(),
}),
delay => Ok(delay),
}
}
}
fn rtu_set_rts_delay(&mut self, us: i32) -> Result<(), Error> {
unsafe {
match ffi::modbus_rtu_set_rts_delay(self.ctx, us as c_int) {
-1 => Err(Error::Rtu {
msg: "rtu_set_rts_delay".to_owned(),
source: ::std::io::Error::last_os_error(),
}),
0 => Ok(()),
_ => panic!("libmodbus API incompatible response"),
}
}
}
}