From c9b44d2644993fa417c9a69fe51cf227c2abdabd Mon Sep 17 00:00:00 2001 From: Benjamin Koch <bbbsnowball@gmail.com> Date: Tue, 30 May 2023 01:49:18 +0200 Subject: [PATCH] implement readwrite_registers --- firmware/rust1/rtumaster_pymodbus.py | 5 +++++ firmware/rust1/src/bin/heizung.rs | 15 +++++++++++++-- firmware/rust1/src/modbus_server.rs | 26 ++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/firmware/rust1/rtumaster_pymodbus.py b/firmware/rust1/rtumaster_pymodbus.py index 27cc982..a5cb29d 100644 --- a/firmware/rust1/rtumaster_pymodbus.py +++ b/firmware/rust1/rtumaster_pymodbus.py @@ -6,6 +6,7 @@ import logging import time import sys +import struct import pymodbus from pymodbus.exceptions import ModbusException from pymodbus.client import ModbusSerialClient @@ -49,6 +50,10 @@ def main(): logger.info("read scratch reg: %s: %r", x, x.registers) assert x.registers == [0x17] + x = client.readwrite_registers(read_address=0, read_count=3, write_address=1, + write_registers=[struct.unpack(">H", b"PI")[0], 103], slave=DEVICE_ADDR) + logger.info("read/write regs: %s: %r", x, x.registers) + x = client.read_file_record([ # documentation says tuple of: Reference type, File number, Record Number, Record Length # but actually an object is expected: diff --git a/firmware/rust1/src/bin/heizung.rs b/firmware/rust1/src/bin/heizung.rs index 7008396..ef40a5a 100644 --- a/firmware/rust1/src/bin/heizung.rs +++ b/firmware/rust1/src/bin/heizung.rs @@ -461,8 +461,16 @@ impl<'a> ModbusRegisters for ModBusRegs<'a> { match addr { 0 => { self.device_state = value; Ok(self.device_state) }, 1 => { - const OK: u16 = 'O' as u16 | (('K' as u16) << 8); - const UP: u16 = 'U' as u16 | (('P' as u16) << 8); + const fn be(s: &str) -> u16 { + core::assert!(s.len() == 2); + core::assert!(s.as_bytes().len() == 2); + let x = s.as_bytes()[0]; + let y = s.as_bytes()[1]; + u16::from_be_bytes([x, y]) + } + const OK: u16 = be("OK"); // mark booted + const UP: u16 = be("UP"); // mark updated -> swap to DFU on next reset + const PI: u16 = be("PI"); // ping / no-op match value { OK => { self.uf2updater.mark_booted().map(|_| value) @@ -473,6 +481,9 @@ impl<'a> ModbusRegisters for ModBusRegs<'a> { UP => { Ok(0) }, + PI => { + Ok(value) + }, _ => Err(ModbusErrorCode::IllegalDataValue), } }, diff --git a/firmware/rust1/src/modbus_server.rs b/firmware/rust1/src/modbus_server.rs index 66d433c..fa1c6d2 100644 --- a/firmware/rust1/src/modbus_server.rs +++ b/firmware/rust1/src/modbus_server.rs @@ -138,6 +138,7 @@ fn get_modbus_frame_length(rxbuf: &[u8]) -> ModbusFrameLength { 0x0f | 0x10 => if rxbuf.len() == 7 { Length(9 + rxbuf[6] as u16) } else { NeedMoreData(7) }, 0x14 | 0x15 => if rxbuf.len() == 3 { Length(5 + rxbuf[2] as u16) } else { NeedMoreData(3) }, 0x16 => Length(10), + 0x17 => if rxbuf.len() == 11 { Length(13 + rxbuf[10] as u16) } else { NeedMoreData(11) }, _ => Unknown, } } @@ -428,6 +429,31 @@ impl<REGS: ModbusRegisters> ModbusServer<REGS> { push_many(txbuf, &rxbuf[0..rxbuf.len()-2])?; Ok(()) }, + 0x17 => { + let read_addr = rx.read_u16be()?; + let read_count = rx.read_u16be()?; + let write_addr = rx.read_u16be()?; + let write_count = rx.read_u16be()?; + let write_byte_count = rx.read_u8()?; + if read_count < 1 || read_count > 0x7d || write_count < 1 || write_count > 0x79 || write_byte_count as u16 != write_count * 2 { + return Err(IllegalDataValue) + } + + for i in 0..write_count { + info!("write {}", write_addr+i); + self.regs.write_register(device_addr, write_addr + i, rx.read_u16be()?)?; + } + + push_many(txbuf, &rxbuf[0..2])?; + push(txbuf, read_count as u8 * 2)?; + for i in 0..read_count { + info!("read {}", read_addr+i); + let value = self.regs.read_holding_register(device_addr, read_addr + i)?; + push_u16be(txbuf, value)?; + } + info!("done"); + Ok(()) + }, _ => { Err(IllegalFunction) }, -- GitLab