[modbus] Build single-value register writes on a right-sized stack buffer (#18844)

Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
Bonne Eggleston
2026-08-28 18:36:24 +00:00
committed by GitHub
co-authored by J. Nick Koston
parent 768ab5b672
commit 59397b4e28
6 changed files with 61 additions and 3 deletions
+19 -3
View File
@@ -485,9 +485,12 @@ static bool register_block_in_range(const LogString *role, uint16_t start_addres
return true;
}
PduBuffer create_write_registers_pdu(uint16_t start_address, std::span<const uint16_t> values) {
PduBuffer pdu; // declared before every return so NRVO fires (all paths return the same object)
if (!register_block_in_range(LOG_STR("Write"), start_address, values.size(), MAX_NUM_OF_REGISTERS_TO_WRITE)) {
// The ceiling comes from the buffer itself: push_back() drops silently, so a bound wider than the buffer
// would put a truncated frame on the wire.
template<typename Pdu> static Pdu build_write_registers_pdu(uint16_t start_address, std::span<const uint16_t> values) {
constexpr auto max_registers = static_cast<uint16_t>((Pdu::capacity() - WRITE_MULTIPLE_HEADER_SIZE) / 2);
Pdu pdu; // declared before every return so NRVO fires (all paths return the same object)
if (!register_block_in_range(LOG_STR("Write"), start_address, values.size(), max_registers)) {
return pdu;
}
append_pdu_header(pdu, FunctionCode::WRITE_MULTIPLE_REGISTERS, start_address, values.size());
@@ -498,6 +501,19 @@ PduBuffer create_write_registers_pdu(uint16_t start_address, std::span<const uin
return pdu;
}
static_assert((PduBuffer::capacity() - WRITE_MULTIPLE_HEADER_SIZE) / 2 == MAX_NUM_OF_REGISTERS_TO_WRITE,
"a full-frame PDU must hold exactly MAX_NUM_OF_REGISTERS_TO_WRITE registers");
static_assert((WriteFewRegistersPdu::capacity() - WRITE_MULTIPLE_HEADER_SIZE) / 2 == MAX_FEW_REGISTERS,
"the small write buffer must hold exactly MAX_FEW_REGISTERS registers");
PduBuffer create_write_registers_pdu(uint16_t start_address, std::span<const uint16_t> values) {
return build_write_registers_pdu<PduBuffer>(start_address, values);
}
WriteFewRegistersPdu create_write_few_registers_pdu(uint16_t start_address, std::span<const uint16_t> values) {
return build_write_registers_pdu<WriteFewRegistersPdu>(start_address, values);
}
PduBuffer create_read_write_multiple_registers_pdu(uint16_t read_start_address, uint16_t read_count,
uint16_t write_start_address,
std::span<const uint16_t> write_values) {