提交 fa5bca7d authored 作者: Serhij S's avatar Serhij S

Serial fixes, Modbus Serial->Rtu

上级 b544390a
...@@ -27,7 +27,7 @@ impl Client { ...@@ -27,7 +27,7 @@ impl Client {
pub enum Protocol { pub enum Protocol {
Tcp, Tcp,
Serial, Rtu,
} }
trait Communicator { trait Communicator {
......
use crate::Error; use crate::{Error, Result};
use super::Client; use super::Client;
use super::Communicator; use super::Communicator;
...@@ -6,37 +6,47 @@ use super::Protocol; ...@@ -6,37 +6,47 @@ use super::Protocol;
use parking_lot::{Mutex, MutexGuard}; use parking_lot::{Mutex, MutexGuard};
use serial::prelude::*; use serial::prelude::*;
use serial::SystemPort; use serial::SystemPort;
use std::io;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::str::FromStr;
use std::sync::Arc; use std::sync::Arc;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
pub fn connect(path: &str, timeout: Duration, frame_delay: Duration) -> Result<Client, Error> { pub fn connect(path: &str, timeout: Duration, frame_delay: Duration) -> Result<Client> {
Ok(Client(Serial::create(path, timeout, frame_delay)?)) Ok(Client(Serial::create(path, timeout, frame_delay)?))
} }
fn parse_path( #[derive(Debug, Clone, Eq, PartialEq)]
path: &str, pub struct Parameters {
) -> ( pub port_dev: String,
&str, pub baud_rate: serial::BaudRate,
serial::BaudRate, pub char_size: serial::CharSize,
serial::CharSize, pub parity: serial::Parity,
serial::Parity, pub stop_bits: serial::StopBits,
serial::StopBits, }
) {
impl FromStr for Parameters {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
parse_path(s)
}
}
fn parse_path(path: &str) -> Result<Parameters> {
let mut sp = path.split(':'); let mut sp = path.split(':');
let port_dev = sp.next().unwrap(); let port_dev = sp.next().unwrap();
let s_baud_rate = sp let s_baud_rate = sp
.next() .next()
.unwrap_or_else(|| panic!("serial baud rate not specified: {}", path)); .ok_or_else(|| Error::invalid_data(format!("serial baud rate not specified: {}", path)))?;
let s_char_size = sp let s_char_size = sp
.next() .next()
.unwrap_or_else(|| panic!("serial char size not specified: {}", path)); .ok_or_else(|| Error::invalid_data(format!("serial char size not specified: {}", path)))?;
let s_parity = sp let s_parity = sp
.next() .next()
.unwrap_or_else(|| panic!("serial parity not specified: {}", path)); .ok_or_else(|| Error::invalid_data(format!("serial parity not specified: {}", path)))?;
let s_stop_bits = sp let s_stop_bits = sp
.next() .next()
.unwrap_or_else(|| panic!("serial stopbits not specified: {}", path)); .ok_or_else(|| Error::invalid_data(format!("serial stopbits not specified: {}", path)))?;
let baud_rate = match s_baud_rate { let baud_rate = match s_baud_rate {
"110" => serial::Baud110, "110" => serial::Baud110,
"300" => serial::Baud300, "300" => serial::Baud300,
...@@ -49,61 +59,72 @@ fn parse_path( ...@@ -49,61 +59,72 @@ fn parse_path(
"38400" => serial::Baud38400, "38400" => serial::Baud38400,
"57600" => serial::Baud57600, "57600" => serial::Baud57600,
"115200" => serial::Baud115200, "115200" => serial::Baud115200,
v => panic!("specified serial baud rate not supported: {}", v), v => {
return Err(Error::invalid_data(format!(
"specified serial baud rate not supported: {}",
v
)))
}
}; };
let char_size = match s_char_size { let char_size = match s_char_size {
"5" => serial::Bits5, "5" => serial::Bits5,
"6" => serial::Bits6, "6" => serial::Bits6,
"7" => serial::Bits7, "7" => serial::Bits7,
"8" => serial::Bits8, "8" => serial::Bits8,
v => panic!("specified serial char size not supported: {}", v), v => {
return Err(Error::invalid_data(format!(
"specified serial char size not supported: {}",
v
)))
}
}; };
let parity = match s_parity { let parity = match s_parity {
"N" => serial::ParityNone, "N" => serial::ParityNone,
"E" => serial::ParityEven, "E" => serial::ParityEven,
"O" => serial::ParityOdd, "O" => serial::ParityOdd,
v => panic!("specified serial parity not supported: {}", v), v => {
return Err(Error::invalid_data(format!(
"specified serial parity not supported: {}",
v
)))
}
}; };
let stop_bits = match s_stop_bits { let stop_bits = match s_stop_bits {
"1" => serial::Stop1, "1" => serial::Stop1,
"2" => serial::Stop2, "2" => serial::Stop2,
v => unimplemented!("specified serial stop bits not supported: {}", v), v => unimplemented!("specified serial stop bits not supported: {}", v),
}; };
(port_dev, baud_rate, char_size, parity, stop_bits) Ok(Parameters {
} port_dev: port_dev.to_owned(),
baud_rate,
/// # Panics char_size,
/// parity,
/// Will panic on misconfigured listen string stop_bits,
pub fn check_path(path: &str) { })
let _ = parse_path(path);
} }
/// # Panics pub fn open(params: &Parameters, timeout: Duration) -> Result<SystemPort> {
/// let mut port = serial::open(&params.port_dev).map_err(Error::io)?;
/// Will panic on misconfigured listen string
pub fn open(listen: &str, timeout: Duration) -> Result<SystemPort, serial::Error> {
let (port_dev, baud_rate, char_size, parity, stop_bits) = parse_path(listen);
let mut port = serial::open(&port_dev)?;
port.reconfigure(&|settings| { port.reconfigure(&|settings| {
(settings.set_baud_rate(baud_rate).unwrap()); (settings.set_baud_rate(params.baud_rate).unwrap());
settings.set_char_size(char_size); settings.set_char_size(params.char_size);
settings.set_parity(parity); settings.set_parity(params.parity);
settings.set_stop_bits(stop_bits); settings.set_stop_bits(params.stop_bits);
settings.set_flow_control(serial::FlowNone); settings.set_flow_control(serial::FlowNone);
Ok(()) Ok(())
})?; })
port.set_timeout(timeout)?; .map_err(Error::io)?;
port.set_timeout(timeout).map_err(Error::io)?;
Ok(port) Ok(port)
} }
#[allow(clippy::module_name_repetitions)] #[allow(clippy::module_name_repetitions)]
pub struct Serial { pub struct Serial {
path: String,
port: Mutex<SPort>, port: Mutex<SPort>,
timeout: Duration, timeout: Duration,
frame_delay: Duration, frame_delay: Duration,
busy: Mutex<()>, busy: Mutex<()>,
params: Parameters,
} }
#[derive(Default)] #[derive(Default)]
...@@ -124,8 +145,10 @@ impl Communicator for Serial { ...@@ -124,8 +145,10 @@ impl Communicator for Serial {
port.system_port.take(); port.system_port.take();
port.last_frame.take(); port.last_frame.take();
} }
fn write(&self, buf: &[u8]) -> Result<(), std::io::Error> { fn write(&self, buf: &[u8]) -> std::result::Result<(), std::io::Error> {
let mut port = self.get_port()?; let mut port = self
.get_port()
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
if let Some(last_frame) = port.last_frame { if let Some(last_frame) = port.last_frame {
let el = last_frame.elapsed(); let el = last_frame.elapsed();
if el < self.frame_delay { if el < self.frame_delay {
...@@ -144,10 +167,12 @@ impl Communicator for Serial { ...@@ -144,10 +167,12 @@ impl Communicator for Serial {
if result.is_ok() { if result.is_ok() {
port.last_frame.replace(Instant::now()); port.last_frame.replace(Instant::now());
} }
result result.map_err(Into::into)
} }
fn read_exact(&self, buf: &mut [u8]) -> Result<(), std::io::Error> { fn read_exact(&self, buf: &mut [u8]) -> std::result::Result<(), std::io::Error> {
let mut port = self.get_port()?; let mut port = self
.get_port()
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
port.system_port port.system_port
.as_mut() .as_mut()
.unwrap() .unwrap()
...@@ -156,35 +181,29 @@ impl Communicator for Serial { ...@@ -156,35 +181,29 @@ impl Communicator for Serial {
self.reconnect(); self.reconnect();
e e
}) })
.map_err(Into::into)
} }
fn protocol(&self) -> Protocol { fn protocol(&self) -> Protocol {
Protocol::Serial Protocol::Rtu
} }
} }
impl Serial { impl Serial {
/// # Panics pub fn create(path: &str, timeout: Duration, frame_delay: Duration) -> Result<Arc<Self>> {
/// let params = parse_path(path)?;
/// Will panic on misconfigured path string
pub fn create(
path: &str,
timeout: Duration,
frame_delay: Duration,
) -> Result<Arc<Self>, Error> {
check_path(path);
Ok(Self { Ok(Self {
path: path.to_owned(),
port: <_>::default(), port: <_>::default(),
timeout, timeout,
frame_delay, frame_delay,
busy: <_>::default(), busy: <_>::default(),
params,
} }
.into()) .into())
} }
fn get_port(&self) -> Result<MutexGuard<SPort>, std::io::Error> { fn get_port(&self) -> Result<MutexGuard<SPort>> {
let mut lock = self.port.lock(); let mut lock = self.port.lock();
if lock.system_port.as_mut().is_none() { if lock.system_port.as_mut().is_none() {
let port = open(&self.path, self.timeout)?; let port = open(&self.params, self.timeout)?;
lock.system_port.replace(port); lock.system_port.replace(port);
lock.last_frame.take(); lock.last_frame.take();
} }
......
...@@ -38,7 +38,7 @@ impl From<Protocol> for ModbusProto { ...@@ -38,7 +38,7 @@ impl From<Protocol> for ModbusProto {
fn from(value: Protocol) -> Self { fn from(value: Protocol) -> Self {
match value { match value {
Protocol::Tcp => ModbusProto::TcpUdp, Protocol::Tcp => ModbusProto::TcpUdp,
Protocol::Serial => ModbusProto::Rtu, Protocol::Rtu => ModbusProto::Rtu,
} }
} }
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论