use crate::codec::SerialConfig; use tokio_serial::{SerialPortBuilderExt, SerialStream}; use tokio_modbus::{ client::rtu, client::Context, slave::Slave, prelude::*, }; pub (crate) struct ModbusClient { stream: SerialStream } impl ModbusClient { pub fn new(serial_config: SerialConfig) -> Self { let port_name = String::from_utf8(serial_config.port).unwrap(); let parity = match serial_config.parity { 0x00 => tokio_serial::Parity::None, 0x01 => tokio_serial::Parity::Odd, 0x02 => tokio_serial::Parity::Even, _ => tokio_serial::Parity::None }; let stopbits = match serial_config.stopbits { 0x01 => tokio_serial::StopBits::One, 0x02 => tokio_serial::StopBits::Two, _ => tokio_serial::StopBits::One }; let builder = tokio_serial::new(port_name, serial_config.baudrate) .data_bits(tokio_serial::DataBits::Eight) .stop_bits(stopbits) .parity(parity) .timeout(std::time::Duration::from_millis(serial_config.timeout as u64)); // 2. 建立串口连接 let stream = builder.open_native_async().unwrap(); Self { stream } } pub async fn request(&mut self, slave_id: u8, address: u16, cnt: u16) -> Result, Box> { let slave = Slave(slave_id); let mut ctx = rtu::attach_slave(&mut self.stream, slave); // 根据 address 范围执行不同操作 match address { // 保持寄存器(Holding Registers): 40000-49999 40000..=49999 => { let modbus_addr = address - 40000; // 转换为 Modbus 协议地址(0-9999) let response = ctx.read_holding_registers(modbus_addr, cnt).await?; println!("Holding Register {}: {:?}", modbus_addr, response); match response { Ok(bytes) => { Ok(bytes) } Err(e) => { Err(e.into()) } } } // 输入寄存器(Input Registers): 30000-39999 30000..=39999 => { let modbus_addr = address - 30000; let response = ctx.read_input_registers(modbus_addr, cnt).await?; println!("Input Register {}: {:?}", modbus_addr, response); match response { Ok(bytes) => { Ok(bytes) } Err(e) => { Err(e.into()) } } } // 离散输入(Discrete Inputs): 10000-19999 10000..=19999 => { let modbus_addr = address - 10000; let response = ctx.read_discrete_inputs(modbus_addr, 1).await?; println!("Discrete Input {}: {:?}", modbus_addr, response); match response { Ok(bytes) => { Ok(Self::bool_to_u16(bytes[0])) } Err(e) => { Err(e.into()) } } } // 线圈(Coils): 0-9999 0..=9999 => { let response = ctx.read_coils(address, 1).await?; println!("Coil {}: {:?}", address, response); match response { Ok(bytes) => { Ok(Self::bool_to_u16(bytes[0])) } Err(e) => { Err(e.into()) } } } _ => { return Err("Invalid Modbus address".into()); } } } pub fn bool_to_u16(val: bool) -> Vec { if val { vec![1] } else { vec![0] } } }