Skip to content

Commit

Permalink
Merge pull request #38 from Okoyl/master
Browse files Browse the repository at this point in the history
Implemented Modbus Function code FC23 client function.
  • Loading branch information
hirschenberger authored Dec 20, 2023
2 parents cf3a4bf + ca2ca0a commit d259a8a
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 7 deletions.
9 changes: 9 additions & 0 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,14 @@ pub trait Client {

fn write_multiple_registers(&mut self, address: u16, values: &[u16]) -> Result<()>;

fn write_read_multiple_registers(
&mut self,
write_address: u16,
write_quantity: u16,
write_values: &[u16],
read_address: u16,
read_quantity: u16,
) -> Result<Vec<u16>>;

fn set_uid(&mut self, uid: u8);
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ enum Function<'a> {
WriteSingleRegister(Address, Value),
WriteMultipleCoils(Address, Quantity, &'a [u8]),
WriteMultipleRegisters(Address, Quantity, &'a [u8]),
WriteReadMultipleRegisters(Address, Quantity, &'a [u8], Address, Quantity),
}

impl<'a> Function<'a> {
Expand All @@ -65,6 +66,7 @@ impl<'a> Function<'a> {
Function::WriteSingleRegister(_, _) => 0x06,
Function::WriteMultipleCoils(_, _, _) => 0x0f,
Function::WriteMultipleRegisters(_, _, _) => 0x10,
Function::WriteReadMultipleRegisters(_, _, _, _, _) => 0x17,
}
// ReadExceptionStatus = 0x07,
// ReportSlaveId = 0x11,
Expand Down
51 changes: 51 additions & 0 deletions src/tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,43 @@ impl Transport {
self.write(&mut buff)
}

fn write_read_multiple(&mut self, fun: &Function) -> Result<Vec<u8>> {
if let Function::WriteReadMultipleRegisters(write_addr, write_quantity, write_values, read_addr, read_quantity) = *fun {
let expected_bytes = 2 * read_quantity as usize;

let header = Header::new(self, MODBUS_HEADER_SIZE as u16 + 10u16 + write_quantity * 2 + 1u16);
let mut buff = header.pack()?;

buff.write_u8(fun.code())?;
buff.write_u16::<BigEndian>(read_addr)?;
buff.write_u16::<BigEndian>(read_quantity)?;
buff.write_u16::<BigEndian>(write_addr)?;
buff.write_u16::<BigEndian>(write_quantity)?;
buff.write_u8((write_values.len()) as u8)?;
for v in write_values {
buff.write_u8(*v)?;
}

match self.stream.write_all(&buff) {
Ok(_s) => {
let mut reply = vec![0; MODBUS_HEADER_SIZE + expected_bytes + 2];
match self.stream.read(&mut reply) {
Ok(_s) => {
let resp_hd = Header::unpack(&reply[..MODBUS_HEADER_SIZE])?;
Transport::validate_response_header(&header, &resp_hd)?;
Transport::validate_response_code(&buff, &reply)?;
Transport::get_reply_data(&reply, expected_bytes)
}
Err(e) => Err(Error::Io(e)),
}
}
Err(e) => Err(Error::Io(e)),
}
} else {
Err(Error::InvalidFunction)
}
}

fn write_multiple(&mut self, fun: &Function) -> Result<()> {
let (addr, quantity, values) = match *fun {
Function::WriteMultipleCoils(a, q, v) | Function::WriteMultipleRegisters(a, q, v) => {
Expand Down Expand Up @@ -397,6 +434,20 @@ impl Client for Transport {
))
}

/// Write a multiple 16bit registers starting at address `write_addr` and read starting at address `read_addr`.
fn write_read_multiple_registers(
&mut self,
write_address: u16,
write_quantity: u16,
write_values: &[u16],
read_address: u16,
read_quantity: u16,
) -> Result<Vec<u16>> {
let write_bytes = binary::unpack_bytes(write_values);
let read_bytes = self.write_read_multiple(&Function::WriteReadMultipleRegisters(write_address, write_quantity, &write_bytes, read_address, read_quantity))?;
binary::pack_bytes(&read_bytes[..])
}

/// Set the unit identifier.
fn set_uid(&mut self, uid: u8) {
self.uid = uid;
Expand Down
10 changes: 3 additions & 7 deletions tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,14 +179,10 @@ mod modbus_server_tests {
fn test_write_read_multiple_registers() {
let (_s, cfg) = start_dummy_server_with_cfg();
let mut trans = Transport::new_with_cfg("127.0.0.1", cfg).unwrap();
// assert!(write_multiple_registers(&mut trans, 0, &[]).is_err());
assert!(trans.write_multiple_registers(0, &[23]).is_ok());
assert_eq!(trans.read_holding_registers(0, 1).unwrap(), &[23]);
assert!(trans.write_multiple_registers(0, &[1, 2, 3]).is_ok());
assert_eq!(trans.read_holding_registers(0, 1).unwrap(), &[1]);
assert_eq!(trans.read_holding_registers(1, 1).unwrap(), &[2]);
assert_eq!(trans.read_holding_registers(2, 1).unwrap(), &[3]);
assert!(trans.write_read_multiple_registers(0, 3, &[1, 2, 3], 0, 3).is_ok());
assert_eq!(trans.read_holding_registers(0, 3).unwrap(), &[1, 2, 3]);
assert_eq!(trans.write_read_multiple_registers(3, 2, &[4, 5], 1, 4).unwrap(), &[2, 3, 4, 5]);
assert_eq!(trans.read_holding_registers(0, 5).unwrap(), &[1, 2, 3, 4, 5]);
}

#[test]
Expand Down

0 comments on commit d259a8a

Please sign in to comment.