mirror of
https://github.com/esphome/esphome.git
synced 2026-10-01 17:00:21 +00:00
[modbus] Hub and helpers cleanup; tighten queue_pdu validation (#18847)
This commit is contained in:
@@ -30,9 +30,11 @@ uint16_t server_pdu_length(const uint8_t *frame, size_t size) {
|
||||
switch (static_cast<FunctionCode>(frame[0])) {
|
||||
case FunctionCode::READ_COILS:
|
||||
case FunctionCode::READ_DISCRETE_INPUTS:
|
||||
// function(1) + byte count(1) + packed coil bytes
|
||||
return 2 + (size > 1 ? std::min(frame[1], uint8_t(packed_bit_bytes(MAX_NUM_OF_COILS_TO_READ))) : 0);
|
||||
case FunctionCode::READ_HOLDING_REGISTERS:
|
||||
case FunctionCode::READ_INPUT_REGISTERS:
|
||||
// function(1) + byte count(1) + data
|
||||
// function(1) + byte count(1) + register data
|
||||
return 2 + (size > 1 ? std::min(frame[1], uint8_t(MAX_NUM_OF_REGISTERS_TO_READ * 2)) : 0);
|
||||
case FunctionCode::WRITE_SINGLE_COIL:
|
||||
case FunctionCode::WRITE_SINGLE_REGISTER:
|
||||
@@ -60,6 +62,9 @@ uint16_t server_pdu_length(const uint8_t *frame, size_t size) {
|
||||
uint16_t client_pdu_length(const uint8_t *frame, size_t size) {
|
||||
if (size < MIN_PDU_SIZE)
|
||||
return MIN_PDU_SIZE;
|
||||
if (is_function_code_exception(frame[0])) {
|
||||
return 2; // never a valid request; sized like the exception reply so the CRC fails at once
|
||||
}
|
||||
switch (static_cast<FunctionCode>(frame[0])) {
|
||||
case FunctionCode::READ_COILS:
|
||||
case FunctionCode::READ_DISCRETE_INPUTS:
|
||||
@@ -381,8 +386,6 @@ ReadPdu create_read_pdu(FunctionCode function_code, uint16_t start_address, uint
|
||||
PduBuffer create_client_pdu(FunctionCode function_code, uint16_t start_address, uint16_t number_of_entities,
|
||||
const uint8_t *values, size_t values_len) {
|
||||
PduBuffer pdu; // declared before every return so NRVO fires (all paths return the same object)
|
||||
// Generic entry point; prefer the direction- and type-specific builders (create_read_pdu(),
|
||||
// create_write_registers_pdu(), etc.) which bound their inputs per spec.
|
||||
if (is_function_code_read_only(static_cast<uint8_t>(function_code))) {
|
||||
if (values != nullptr || values_len > 0) {
|
||||
ESP_LOGW(TAG, "Values provided for read function code %02X, but will be ignored",
|
||||
@@ -445,9 +448,7 @@ PduBuffer create_client_pdu(FunctionCode function_code, uint16_t start_address,
|
||||
return pdu;
|
||||
}
|
||||
// The quantity is spec-bounded above, so the data length just has to agree with it exactly
|
||||
// (registers are 2 bytes each, coils pack 8 per byte). This is the same consistency the response
|
||||
// dispatch enforces via is_client_pdu_standard(), so a frame built here can never be classified
|
||||
// non-standard on reply, and the spec bound keeps the PDU within capacity by construction.
|
||||
// (registers are 2 bytes each, coils pack 8 per byte).
|
||||
// Checked before the header append: a failed check must return an empty PDU, not a 5-byte partial one.
|
||||
const bool bits = function_code == FunctionCode::WRITE_MULTIPLE_COILS;
|
||||
const size_t expected_len = bits ? packed_bit_bytes(number_of_entities) : static_cast<size_t>(number_of_entities) * 2;
|
||||
|
||||
Reference in New Issue
Block a user