diff --git a/firmware/rust1/src/bin/heizung.rs b/firmware/rust1/src/bin/heizung.rs
index 688b033ddc553b01bc6616d5889a681e627692c2..d03b9575936da9c45941c4e243d5389b9171bec3 100644
--- a/firmware/rust1/src/bin/heizung.rs
+++ b/firmware/rust1/src/bin/heizung.rs
@@ -24,7 +24,7 @@ use {defmt_rtt as _, panic_probe as _};
 use heapless::String;
 
 use heizung::i2c_scan::{self, ScanResultForBus};
-use heizung::modbus_server::{ModbusServer, ModbusRegisters, ModbusErrorCode, ModbusAdressMatch};
+use heizung::modbus_server::{ModbusServer, ModbusRegisters, ModbusErrorCode, ModbusAdressMatch, U16Pusher};
 use heizung::rs485::RS485;
 
 #[embassy_executor::task]
@@ -428,6 +428,27 @@ impl<'a> ModbusRegisters for ModBusRegs<'a> {
     fn write_register(self: &mut Self, _device_addr: u8, addr: u16, value: u16) -> Result<u16, ModbusErrorCode> {
         Err(ModbusErrorCode::IllegalDataAddress)
     }
+
+    fn read_file_records(self: &mut Self, _device_addr: u8,
+            ref_type: u8, file_number: u16, record_number: u16, record_length: u16, mut pusher: U16Pusher<'_, 256>)
+            -> Result<(), ModbusErrorCode> {
+        match (ref_type, file_number) {
+            (6, 0) => {
+                let value = "Hello, World!!".as_bytes();
+                if record_number as usize >= value.len()/2 {
+                    return Ok(())  // or should that be an error?
+                }
+                let start = 2 * record_number as usize;
+                let end = start + 2 * record_length as usize;
+                let end = core::cmp::min(end, value.len());  // or should too large length be an error?
+                pusher.push_bytes(&value[start .. end])?;
+                Ok(())
+            },
+            _ => {
+                Err(ModbusErrorCode::IllegalDataAddress)
+            }
+        }
+    }
 }
 
 //#[embassy_executor::main]
diff --git a/firmware/rust1/src/modbus_server.rs b/firmware/rust1/src/modbus_server.rs
index 9d8500b15b6eee5fd6f88f8a19ad22a5a6bc1af2..94d7f72a6441e56a230f7abf166d110e7e2530bb 100644
--- a/firmware/rust1/src/modbus_server.rs
+++ b/firmware/rust1/src/modbus_server.rs
@@ -19,6 +19,10 @@ impl<'a, E: Clone> Cursor<'a, E> {
         self.0
     }
 
+    fn has_more_data(self: &Self) -> bool {
+        self.1 < self.0.len()
+    }
+
     fn read_u8(self: &mut Self) -> Result<u8, E> {
         if self.1 < self.0.len() {
             let x = self.0[self.1];
@@ -43,6 +47,23 @@ impl<'a, E: Clone> Cursor<'a, E> {
     }
 }
 
+pub struct U16Pusher<'a, const N: usize> {
+    buf: &'a mut Vec<u8, N>
+}
+
+impl<'a, const N: usize> U16Pusher<'a, N> {
+    pub fn push_bytes(self: &mut Self, xs: &[u8]) -> Result<(), ModbusErrorCode> {
+        for x in xs {
+            self.buf.push(*x).or(Err(ModbusErrorCode::ServerDeviceFailure))?;
+        }
+        Ok(())
+    }
+
+    pub fn push(self: &mut Self, x: u16) -> Result<(), ModbusErrorCode> {
+        self.push_bytes(&x.to_be_bytes())
+    }
+}
+
 
 #[repr(u8)]
 #[derive(PartialEq, Eq, Format, Clone)]
@@ -71,6 +92,9 @@ pub trait ModbusRegisters {
     fn read_input_register(self: &mut Self, device_addr: u8, addr: u16) -> Result<u16, ModbusErrorCode>;
     fn write_coil(self: &mut Self, device_addr: u8, addr: u16, value: bool) -> Result<(), ModbusErrorCode>;
     fn write_register(self: &mut Self, device_addr: u8, addr: u16, value: u16) -> Result<u16, ModbusErrorCode>;
+    fn read_file_records(self: &mut Self, device_addr: u8,
+        ref_type: u8, file_number: u16, record_number: u16, record_length: u16, pusher: U16Pusher<'_, 256>)
+        -> Result<(), ModbusErrorCode>;
 }
 
 #[derive(PartialEq, Eq, Format)]
@@ -91,6 +115,7 @@ fn get_modbus_frame_length(rxbuf: &[u8]) -> ModbusFrameLength {
     match rxbuf[1] {
         0x01..=0x06 => Length(8),
         0x0f | 0x10 => if rxbuf.len() == 7 { Length(9 + rxbuf[6] as u16) } else { NeedMoreData(7) },
+        0x14 => if rxbuf.len() == 3 { Length(5 + rxbuf[2] as u16) } else { NeedMoreData(3) },
         _ => Unknown,
     }
 }
@@ -131,7 +156,7 @@ impl<REGS: ModbusRegisters> ModbusServer<REGS> {
         use ModbusErrorCode::*;
 
         let rxbuf = &self.rxbuf;
-        let mut rx = Cursor::new(&rxbuf, ModbusErrorCode::IllegalDataValue);
+        let mut rx = Cursor::new(&rxbuf[0..rxbuf.len()-2], ModbusErrorCode::IllegalDataValue);
         let txbuf = &mut self.txbuf;
         info!("Modbus frame: {:?}", rxbuf.as_slice());
 
@@ -154,7 +179,7 @@ impl<REGS: ModbusRegisters> ModbusServer<REGS> {
             push_many(txbuf, &x.to_be_bytes())
         }
 
-        let _device_addr = rx.read_u8()?;
+        let device_addr = rx.read_u8()?;
 
         // see https://modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf
         let function = rx.read_u8()?;
@@ -173,7 +198,7 @@ impl<REGS: ModbusRegisters> ModbusServer<REGS> {
                     let mut x = 0;
                     for j in 0..7 {
                         if i*8+j < quantity {
-                            x |= (if self.regs.read_discrete_input(rxbuf[0], start + i*8 + j)? {1} else {0}) << j;
+                            x |= (if self.regs.read_discrete_input(device_addr, start + i*8 + j)? {1} else {0}) << j;
                         }
                     }
                     push(txbuf, x)?;
@@ -195,7 +220,7 @@ impl<REGS: ModbusRegisters> ModbusServer<REGS> {
                 push_many(txbuf, &rxbuf[0..2])?;
                 push(txbuf, byte_count as u8)?;
                 for i in 0..quantity {
-                    let value = self.regs.read_holding_register(rxbuf[0], start + i)?;
+                    let value = self.regs.read_holding_register(device_addr, start + i)?;
                     push_u16be(txbuf, value)?;
                 }
                 Ok(())
@@ -214,7 +239,7 @@ impl<REGS: ModbusRegisters> ModbusServer<REGS> {
                 push_many(txbuf, &rxbuf[0..2])?;
                 push(txbuf, (quantity*2) as u8)?;
                 for i in 0..quantity {
-                    let value = self.regs.read_input_register(rxbuf[0], start + i)?;
+                    let value = self.regs.read_input_register(device_addr, start + i)?;
                     push_u16be(txbuf, value)?;
                 }
                 Ok(())
@@ -234,7 +259,7 @@ impl<REGS: ModbusRegisters> ModbusServer<REGS> {
                 } else {
                     return Err(IllegalDataValue);
                 };
-                self.regs.write_coil(rxbuf[0], start, value)?;
+                self.regs.write_coil(device_addr, start, value)?;
                 if should_reply {
                     push_many(txbuf, &rxbuf[0..6])?;
                 }
@@ -248,7 +273,7 @@ impl<REGS: ModbusRegisters> ModbusServer<REGS> {
                 }
                 let start = rx.read_u16be()?;
                 let value = rx.read_u16be()?;
-                let actual_new_value = self.regs.write_register(rxbuf[0], start, value)?;
+                let actual_new_value = self.regs.write_register(device_addr, start, value)?;
                 if should_reply {
                     push_many(txbuf, &rxbuf[0..4])?;
                     push_u16be(txbuf, actual_new_value)?;
@@ -276,7 +301,7 @@ impl<REGS: ModbusRegisters> ModbusServer<REGS> {
                     let x = rxbuf[7 + i as usize];
                     for j in 0..7 {
                         if i*8+j < quantity {
-                            self.regs.write_coil(rxbuf[0], start + i*8 + j, (x >> j) != 0)?;
+                            self.regs.write_coil(device_addr, start + i*8 + j, (x >> j) != 0)?;
                         }
                     }
                 }
@@ -304,13 +329,52 @@ impl<REGS: ModbusRegisters> ModbusServer<REGS> {
                 }
                 for i in 0..quantity {
                     let value = rx.read_u16be()?;
-                    self.regs.write_register(rxbuf[0], start + i, value)?;
+                    self.regs.write_register(device_addr, start + i, value)?;
                 }
                 if should_reply {
                     push_many(txbuf, &rxbuf[0..6])?;
                 }
                 Ok(())
             },
+            0x14 => {
+                push_many(txbuf, &rxbuf[0..2])?;
+                push(txbuf, 0)?;
+                let byte_count = rx.read_u8()?;
+                if byte_count < 7 || byte_count > 0xf5 {
+                    return Err(IllegalDataValue)
+                }
+                while rx.has_more_data() {
+                    let ref_type = rx.read_u8()?;
+                    let file_number = rx.read_u16be()?;
+                    let record_number = rx.read_u16be()?;
+                    let record_length = rx.read_u16be()?;
+                    let pos_of_length = txbuf.len();
+                    push(txbuf, 1 + 2 * record_length as u8)?;
+                    push(txbuf, ref_type)?;
+                    if record_length > 127 || record_length as usize * 2 > capacity - txbuf.len() {
+                        return Err(IllegalDataValue)
+                    }
+                    let len_before = txbuf.len();
+                    let pusher = U16Pusher { buf: txbuf };
+                    self.regs.read_file_records(device_addr, ref_type, file_number, record_number, record_length, pusher)?;
+                    let len_after = txbuf.len();
+                    let len_added = len_after - len_before;
+                    if len_added % 2 != 0 {
+                        error!("Number of bytes added by read_file_records is not a multiple of 2 (u16)");
+                        return Err(ServerDeviceFailure)
+                    } else if len_added/2 > record_length as usize {
+                        error!("Too many record added by read_file_records: expected {} but got {}", record_length, len_added/2);
+                        return Err(ServerDeviceFailure)
+                    } else if len_added >= 255 {
+                        error!("Too many records added");
+                        return Err(ServerDeviceFailure)
+                    }
+                    txbuf[pos_of_length] = 1 + len_added as u8;
+                }
+                // update byte_count
+                txbuf[2] = txbuf.len() as u8 - 3;
+                Ok(())
+            },
             _ => {
                 Err(IllegalFunction)
             },