From 9ac4039c01439561d3f5f3f090565befef57a3ac Mon Sep 17 00:00:00 2001 From: Bonne Eggleston Date: Fri, 24 Jul 2026 16:28:22 -0700 Subject: [PATCH] [modbus] Rename core enums to EntityType, FunctionCode and ExceptionCode (#17844) Co-authored-by: Claude Fable 5 --- esphome/components/modbus/helpers.py | 35 ++++---- esphome/components/modbus/modbus.cpp | 28 +++---- esphome/components/modbus/modbus.h | 22 ++--- .../components/modbus/modbus_definitions.h | 34 +++++--- esphome/components/modbus/modbus_helpers.cpp | 81 +++++++++---------- esphome/components/modbus/modbus_helpers.h | 68 ++++++++-------- .../components/modbus_controller/__init__.py | 18 ++--- .../binary_sensor/modbus_binarysensor.cpp | 4 +- .../binary_sensor/modbus_binarysensor.h | 4 +- .../modbus_controller/modbus_controller.cpp | 72 ++++++++--------- .../modbus_controller/modbus_controller.h | 52 ++++++------ .../number/modbus_number.cpp | 4 +- .../modbus_controller/number/modbus_number.h | 2 +- .../output/modbus_output.cpp | 2 +- .../modbus_controller/output/modbus_output.h | 4 +- .../modbus_controller/select/modbus_select.h | 2 +- .../modbus_controller/sensor/modbus_sensor.h | 2 +- .../switch/modbus_switch.cpp | 8 +- .../modbus_controller/switch/modbus_switch.h | 4 +- .../text_sensor/modbus_textsensor.h | 2 +- .../modbus_server/modbus_server.cpp | 16 ++-- .../components/modbus/modbus_helpers_test.cpp | 2 +- .../components/modbus_controller/common.yaml | 2 +- .../modbus_server/modbus_server_test.cpp | 18 ++--- 24 files changed, 250 insertions(+), 236 deletions(-) diff --git a/esphome/components/modbus/helpers.py b/esphome/components/modbus/helpers.py index 9d7dc71547..e3029b2648 100644 --- a/esphome/components/modbus/helpers.py +++ b/esphome/components/modbus/helpers.py @@ -3,33 +3,34 @@ import esphome.codegen as cg modbus_ns = cg.esphome_ns.namespace("modbus") modbus_helpers_ns = modbus_ns.namespace("helpers") -ModbusFunctionCode_ns = modbus_ns.namespace("ModbusFunctionCode") -ModbusFunctionCode = ModbusFunctionCode_ns.enum("ModbusFunctionCode") +FunctionCode_ns = modbus_ns.namespace("FunctionCode") +FunctionCode = FunctionCode_ns.enum("FunctionCode") MODBUS_FUNCTION_CODE = { - "read_coils": ModbusFunctionCode.READ_COILS, - "read_discrete_inputs": ModbusFunctionCode.READ_DISCRETE_INPUTS, - "read_holding_registers": ModbusFunctionCode.READ_HOLDING_REGISTERS, - "read_input_registers": ModbusFunctionCode.READ_INPUT_REGISTERS, - "write_single_coil": ModbusFunctionCode.WRITE_SINGLE_COIL, - "write_single_register": ModbusFunctionCode.WRITE_SINGLE_REGISTER, - "write_multiple_coils": ModbusFunctionCode.WRITE_MULTIPLE_COILS, - "write_multiple_registers": ModbusFunctionCode.WRITE_MULTIPLE_REGISTERS, + "read_coils": FunctionCode.READ_COILS, + "read_discrete_inputs": FunctionCode.READ_DISCRETE_INPUTS, + "read_holding_registers": FunctionCode.READ_HOLDING_REGISTERS, + "read_input_registers": FunctionCode.READ_INPUT_REGISTERS, + "write_single_coil": FunctionCode.WRITE_SINGLE_COIL, + "write_single_register": FunctionCode.WRITE_SINGLE_REGISTER, + "write_multiple_coils": FunctionCode.WRITE_MULTIPLE_COILS, + "write_multiple_registers": FunctionCode.WRITE_MULTIPLE_REGISTERS, } -ModbusRegisterType_ns = modbus_ns.namespace("ModbusRegisterType") -ModbusRegisterType = ModbusRegisterType_ns.enum("ModbusRegisterType") +EntityType_ns = modbus_ns.namespace("EntityType") +EntityType = EntityType_ns.enum("EntityType") MODBUS_WRITE_REGISTER_TYPE = { - "custom": ModbusRegisterType.CUSTOM, - "coil": ModbusRegisterType.COIL, - "holding": ModbusRegisterType.HOLDING, + "custom": EntityType.CUSTOM, + "coil": EntityType.COIL, + "holding": EntityType.HOLDING, } MODBUS_REGISTER_TYPE = { **MODBUS_WRITE_REGISTER_TYPE, - "discrete_input": ModbusRegisterType.DISCRETE_INPUT, - "read": ModbusRegisterType.INPUT_REGISTER, + "discrete_input": EntityType.DISCRETE_INPUT, + "read": EntityType.INPUT_REGISTER, + "input": EntityType.INPUT_REGISTER, } SensorValueType_ns = modbus_helpers_ns.namespace("SensorValueType") diff --git a/esphome/components/modbus/modbus.cpp b/esphome/components/modbus/modbus.cpp index 7f90dcd738..eaca168ed8 100644 --- a/esphome/components/modbus/modbus.cpp +++ b/esphome/components/modbus/modbus.cpp @@ -312,7 +312,7 @@ void ModbusClientHub::process_modbus_server_frame(uint8_t address, std::spanlast_modbus_byte_ - this->last_send_); if (device) - device->on_error(request_pdu, static_cast(exception)); + device->on_error(request_pdu, static_cast(exception)); } else if (device) { // Not an error response device->on_response(request_pdu, pdu); @@ -354,7 +354,7 @@ bool ModbusServerHub::check_register_range_(uint8_t address, uint8_t function_co if ((uint32_t) start_address + number_of_registers > 0x10000u) { ESP_LOGW(TAG, "Register address out of range - start: %" PRIu16 " num: %" PRIu16, start_address, number_of_registers); - this->send_exception_(address, function_code, ModbusExceptionCode::ILLEGAL_DATA_ADDRESS); + this->send_exception_(address, function_code, ExceptionCode::ILLEGAL_DATA_ADDRESS); return false; } return true; @@ -373,22 +373,22 @@ void ModbusServerHub::process_modbus_client_frame_(uint8_t address, uint8_t func const uint8_t *response_data = response_buffer; uint16_t response_len = 0; - switch (static_cast(function_code)) { - case ModbusFunctionCode::READ_HOLDING_REGISTERS: - case ModbusFunctionCode::READ_INPUT_REGISTERS: { + switch (static_cast(function_code)) { + case FunctionCode::READ_HOLDING_REGISTERS: + case FunctionCode::READ_INPUT_REGISTERS: { // PDU data: start address(2) + quantity(2). uint16_t start_address = helpers::get_data(data, 0); uint16_t number_of_registers = helpers::get_data(data, 2); if (number_of_registers == 0 || number_of_registers > MAX_NUM_OF_REGISTERS_TO_READ) { ESP_LOGW(TAG, "Invalid number of registers %" PRIu16, number_of_registers); - this->send_exception_(address, function_code, ModbusExceptionCode::ILLEGAL_DATA_VALUE); + this->send_exception_(address, function_code, ExceptionCode::ILLEGAL_DATA_VALUE); return; } if (!this->check_register_range_(address, function_code, start_address, number_of_registers)) { return; } RegisterValues registers; - if (static_cast(function_code) == ModbusFunctionCode::READ_HOLDING_REGISTERS) { + if (static_cast(function_code) == FunctionCode::READ_HOLDING_REGISTERS) { status = device->on_read_holding_registers(start_address, number_of_registers, registers); } else { status = device->on_read_input_registers(start_address, number_of_registers, registers); @@ -403,7 +403,7 @@ void ModbusServerHub::process_modbus_client_frame_(uint8_t address, uint8_t func if (registers.size() != number_of_registers) { ESP_LOGE(TAG, "Incorrect response %" PRIu16 " requested, %zu returned", number_of_registers, registers.size()); - this->send_exception_(address, function_code, ModbusExceptionCode::SERVICE_DEVICE_FAILURE); + this->send_exception_(address, function_code, ExceptionCode::SERVICE_DEVICE_FAILURE); return; } @@ -415,8 +415,8 @@ void ModbusServerHub::process_modbus_client_frame_(uint8_t address, uint8_t func } break; } - case ModbusFunctionCode::WRITE_SINGLE_REGISTER: - case ModbusFunctionCode::WRITE_MULTIPLE_REGISTERS: { + case FunctionCode::WRITE_SINGLE_REGISTER: + case FunctionCode::WRITE_MULTIPLE_REGISTERS: { // PDU data: start address(2) [+ quantity(2) + byte count(1)] + register values. // A single-register write always targets one register; for a multiple-register write the // quantity is in the frame and its byte count must equal quantity * 2. The register values are @@ -424,7 +424,7 @@ void ModbusServerHub::process_modbus_client_frame_(uint8_t address, uint8_t func uint16_t start_address = helpers::get_data(data, 0); uint16_t number_of_registers = 1; uint16_t values_offset = 2; // single write: values follow the 2-byte start address - if (static_cast(function_code) == ModbusFunctionCode::WRITE_MULTIPLE_REGISTERS) { + if (static_cast(function_code) == FunctionCode::WRITE_MULTIPLE_REGISTERS) { number_of_registers = helpers::get_data(data, 2); uint8_t number_of_bytes = helpers::get_data(data, 4); values_offset = 5; // multiple write: values follow start address(2) + quantity(2) + byte count(1) @@ -432,7 +432,7 @@ void ModbusServerHub::process_modbus_client_frame_(uint8_t address, uint8_t func number_of_registers * 2 != number_of_bytes) { ESP_LOGW(TAG, "Invalid number of registers %" PRIu16 " or bytes %" PRIu8, number_of_registers, number_of_bytes); - this->send_exception_(address, function_code, ModbusExceptionCode::ILLEGAL_DATA_VALUE); + this->send_exception_(address, function_code, ExceptionCode::ILLEGAL_DATA_VALUE); return; } if (!this->check_register_range_(address, function_code, start_address, number_of_registers)) { @@ -451,7 +451,7 @@ void ModbusServerHub::process_modbus_client_frame_(uint8_t address, uint8_t func } default: ESP_LOGW(TAG, "Unsupported function code %" PRIu8, function_code); - this->send_exception_(address, function_code, ModbusExceptionCode::ILLEGAL_FUNCTION); + this->send_exception_(address, function_code, ExceptionCode::ILLEGAL_FUNCTION); return; } if (status.has_value()) { @@ -563,7 +563,7 @@ void ModbusServerHub::send_response_(uint8_t address, uint8_t function_code, con this->send_raw_(raw_frame, payload_len + 2); } -void ModbusServerHub::send_exception_(uint8_t address, uint8_t function_code, ModbusExceptionCode exception_code) { +void ModbusServerHub::send_exception_(uint8_t address, uint8_t function_code, ExceptionCode exception_code) { uint8_t raw_frame[3]; raw_frame[0] = address; raw_frame[1] = function_code | FUNCTION_CODE_EXCEPTION_MASK; diff --git a/esphome/components/modbus/modbus.h b/esphome/components/modbus/modbus.h index ee448245a4..61d5f552c1 100644 --- a/esphome/components/modbus/modbus.h +++ b/esphome/components/modbus/modbus.h @@ -105,8 +105,8 @@ class ModbusClientHub : public Modbus { void send(uint8_t address, uint8_t function_code, uint16_t start_address, uint16_t number_of_entities, uint8_t payload_len = 0, const uint8_t *payload = nullptr, ModbusClientDevice *device = nullptr) { this->send_pdu(address, - helpers::create_client_pdu((ModbusFunctionCode) function_code, start_address, number_of_entities, - payload, payload_len), + helpers::create_client_pdu((FunctionCode) function_code, start_address, number_of_entities, payload, + payload_len), device); }; void send_pdu(uint8_t address, std::span pdu, ModbusClientDevice *device = nullptr) { @@ -154,7 +154,7 @@ class ModbusServerHub : public Modbus { bool check_register_range_(uint8_t address, uint8_t function_code, uint16_t start_address, uint16_t number_of_registers); void send_raw_(const uint8_t *payload, uint16_t len); - void send_exception_(uint8_t address, uint8_t function_code, ModbusExceptionCode exception_code); + void send_exception_(uint8_t address, uint8_t function_code, ExceptionCode exception_code); void send_response_(uint8_t address, uint8_t function_code, const uint8_t *payload, uint16_t payload_len); uint8_t expecting_peer_response_{0}; std::vector devices_; @@ -184,7 +184,7 @@ class ModbusClientDevice { /// if they must outlive it. Slice the payload out of the response with helpers::server_pdu_payload(). virtual void on_response(std::span request_pdu, std::span response_pdu) {} /// Called with the request PDU and the modbus exception code decoded from the error response. - virtual void on_error(std::span request_pdu, ModbusExceptionCode exception_code) {} + virtual void on_error(std::span request_pdu, ExceptionCode exception_code) {} // The on_modbus_* names are signature-identical renames, so the new defaults forward to the old // virtuals: external devices overriding the old names keep working through the deprecation window. // Remove the forwards together with the deprecated names. @@ -211,10 +211,10 @@ class ModbusClientDevice { virtual bool on_modbus_no_response() { return false; } void send(uint8_t function, uint16_t start_address, uint16_t number_of_entities, uint8_t payload_len = 0, const uint8_t *payload = nullptr) { - this->parent_->send_pdu(this->address_, - helpers::create_client_pdu((ModbusFunctionCode) function, start_address, number_of_entities, - payload, payload_len), - this); + this->parent_->send_pdu( + this->address_, + helpers::create_client_pdu((FunctionCode) function, start_address, number_of_entities, payload, payload_len), + this); } void send_pdu(std::span pdu) { this->parent_->send_pdu(this->address_, pdu, this); } void send_raw(const std::vector &payload) { this->parent_->send_raw(payload, this); } @@ -240,7 +240,7 @@ using ModbusDevice ESPDEPRECATED("Use ModbusClientDevice instead. Removed in 202 // Transaction status: std::nullopt on success, otherwise the Modbus exception code. Server handlers return it; // (future) client response callbacks receive it. Named without a side prefix so both directions share it. -using ResponseStatus = std::optional; +using ResponseStatus = std::optional; // Register values exchanged with server handlers, in host byte order. Sized at the larger of the two protocol // maxima (read = 125 / 0x7D, write = 123 / 0x7B); the per-direction count limit is enforced by the hub, not by // the capacity of this type. @@ -259,7 +259,7 @@ class ModbusServerDevice { uint8_t get_address() const { return this->address_; } virtual ResponseStatus on_read_registers(uint16_t start_address, uint16_t number_of_registers, RegisterValues ®isters) { - return ModbusExceptionCode::ILLEGAL_FUNCTION; + return ExceptionCode::ILLEGAL_FUNCTION; }; virtual ResponseStatus on_read_input_registers(uint16_t start_address, uint16_t number_of_registers, RegisterValues ®isters) { @@ -270,7 +270,7 @@ class ModbusServerDevice { return this->on_read_registers(start_address, number_of_registers, registers); }; virtual ResponseStatus on_write_registers(uint16_t start_address, const RegisterValues ®isters) { - return ModbusExceptionCode::ILLEGAL_FUNCTION; + return ExceptionCode::ILLEGAL_FUNCTION; }; protected: diff --git a/esphome/components/modbus/modbus_definitions.h b/esphome/components/modbus/modbus_definitions.h index d11748bcd9..841222ff6a 100644 --- a/esphome/components/modbus/modbus_definitions.h +++ b/esphome/components/modbus/modbus_definitions.h @@ -14,7 +14,7 @@ const uint8_t FUNCTION_CODE_USER_DEFINED_SPACE_1_END = 72; // 0x48 const uint8_t FUNCTION_CODE_USER_DEFINED_SPACE_2_INIT = 100; // 0x64 const uint8_t FUNCTION_CODE_USER_DEFINED_SPACE_2_END = 110; // 0x6E -enum class ModbusFunctionCode : uint8_t { +enum class FunctionCode : uint8_t { INVALID = 0x00, // 0x00 is not a valid function code (even for custom functions). CUSTOM = 0x00, // The CUSTOM alias should be removed in future. READ_COILS = 0x01, @@ -37,14 +37,20 @@ enum class ModbusFunctionCode : uint8_t { READ_FIFO_QUEUE = 0x18, // not implemented }; -/*Allow direct comparison operators between ModbusFunctionCode and uint8_t*/ -inline bool operator==(ModbusFunctionCode lhs, uint8_t rhs) { return static_cast(lhs) == rhs; } -inline bool operator==(uint8_t lhs, ModbusFunctionCode rhs) { return lhs == static_cast(rhs); } -inline bool operator!=(ModbusFunctionCode lhs, uint8_t rhs) { return !(static_cast(lhs) == rhs); } -inline bool operator!=(uint8_t lhs, ModbusFunctionCode rhs) { return !(lhs == static_cast(rhs)); } +// Remove before 2027.2.0 +using ModbusFunctionCode ESPDEPRECATED("Use modbus::FunctionCode instead. Removed in 2027.2.0", + "2026.8.0") = FunctionCode; -// 4.3 MODBUS Data model -enum class ModbusRegisterType : uint8_t { +/*Allow direct comparison operators between FunctionCode and uint8_t*/ +inline bool operator==(FunctionCode lhs, uint8_t rhs) { return static_cast(lhs) == rhs; } +inline bool operator==(uint8_t lhs, FunctionCode rhs) { return lhs == static_cast(rhs); } +inline bool operator!=(FunctionCode lhs, uint8_t rhs) { return !(static_cast(lhs) == rhs); } +inline bool operator!=(uint8_t lhs, FunctionCode rhs) { return !(lhs == static_cast(rhs)); } + +// 4.3 MODBUS Data model. "Entity" is the spec's umbrella for the four primary tables; only the +// 16-bit tables are registers (coils and discrete inputs are bits), so the enum is not named +// RegisterType. +enum class EntityType : uint8_t { CUSTOM = 0x00, COIL = 0x01, DISCRETE_INPUT = 0x02, @@ -52,15 +58,17 @@ enum class ModbusRegisterType : uint8_t { // Named INPUT_REGISTER (not INPUT) because Arduino cores define INPUT as a macro. INPUT_REGISTER = 0x04, // Remove before 2027.2.0 - READ ESPDEPRECATED("Use ModbusRegisterType::INPUT_REGISTER instead. Removed in 2027.2.0", "2026.7.0") = - INPUT_REGISTER, + READ ESPDEPRECATED("Use EntityType::INPUT_REGISTER instead. Removed in 2027.2.0", "2026.7.0") = INPUT_REGISTER, }; +// Remove before 2027.2.0 +using ModbusRegisterType ESPDEPRECATED("Use modbus::EntityType instead. Removed in 2027.2.0", "2026.8.0") = EntityType; + // 7 MODBUS Exception Responses: const uint8_t FUNCTION_CODE_MASK = 0x7F; const uint8_t FUNCTION_CODE_EXCEPTION_MASK = 0x80; -enum class ModbusExceptionCode : uint8_t { +enum class ExceptionCode : uint8_t { ILLEGAL_FUNCTION = 0x01, ILLEGAL_DATA_ADDRESS = 0x02, ILLEGAL_DATA_VALUE = 0x03, @@ -72,6 +80,10 @@ enum class ModbusExceptionCode : uint8_t { GATEWAY_TARGET_DEVICE_FAILED_TO_RESPOND = 0x0B, }; +// Remove before 2027.2.0 +using ModbusExceptionCode ESPDEPRECATED("Use modbus::ExceptionCode instead. Removed in 2027.2.0", + "2026.8.0") = ExceptionCode; + // 6.12 16 (0x10) Write Multiple registers: static constexpr uint16_t MAX_NUM_OF_REGISTERS_TO_WRITE = 123; // 0x7B diff --git a/esphome/components/modbus/modbus_helpers.cpp b/esphome/components/modbus/modbus_helpers.cpp index de109606cb..1ed7912b40 100644 --- a/esphome/components/modbus/modbus_helpers.cpp +++ b/esphome/components/modbus/modbus_helpers.cpp @@ -13,29 +13,29 @@ uint16_t server_frame_length(const uint8_t *frame, size_t size) { if (is_function_code_exception(frame[1])) { return 5; // address(1) + function(1) + exception(1) + CRC(2) } - switch (static_cast(frame[1])) { - case ModbusFunctionCode::READ_COILS: - case ModbusFunctionCode::READ_DISCRETE_INPUTS: - case ModbusFunctionCode::READ_HOLDING_REGISTERS: - case ModbusFunctionCode::READ_INPUT_REGISTERS: + switch (static_cast(frame[1])) { + case FunctionCode::READ_COILS: + case FunctionCode::READ_DISCRETE_INPUTS: + case FunctionCode::READ_HOLDING_REGISTERS: + case FunctionCode::READ_INPUT_REGISTERS: // address(1) + function(1) + byte count(1) + data + CRC(2) return 5 + (size > 2 ? std::min(frame[2], uint8_t(MAX_NUM_OF_REGISTERS_TO_READ * 2)) : 0); - case ModbusFunctionCode::WRITE_SINGLE_COIL: - case ModbusFunctionCode::WRITE_SINGLE_REGISTER: - case ModbusFunctionCode::WRITE_MULTIPLE_COILS: - case ModbusFunctionCode::WRITE_MULTIPLE_REGISTERS: + case FunctionCode::WRITE_SINGLE_COIL: + case FunctionCode::WRITE_SINGLE_REGISTER: + case FunctionCode::WRITE_MULTIPLE_COILS: + case FunctionCode::WRITE_MULTIPLE_REGISTERS: return 8; // address(1) + function(1) + output/register address(2) + value(2) + CRC(2) // Unsupported function codes. Included here to prevent parser failures. Excluding Serial Line specific functions. - case ModbusFunctionCode::READ_FILE_RECORD: - case ModbusFunctionCode::WRITE_FILE_RECORD: + case FunctionCode::READ_FILE_RECORD: + case FunctionCode::WRITE_FILE_RECORD: // address(1) + function(1) + byte count(1) + data + CRC(2) return 5 + (size > 2 ? std::min(frame[2], uint8_t(MAX_FRAME_SIZE - 5)) : 0); - case ModbusFunctionCode::MASK_WRITE_REGISTER: + case FunctionCode::MASK_WRITE_REGISTER: return 10; // address(1) + function(1) + reference address(2) + AND mask(2) + OR mask(2) + CRC(2) - case ModbusFunctionCode::READ_WRITE_MULTIPLE_REGISTERS: + case FunctionCode::READ_WRITE_MULTIPLE_REGISTERS: // address(1) + function(1) + byte count(1) + data + CRC(2) return 5 + (size > 2 ? std::min(frame[2], uint8_t(MAX_NUM_OF_REGISTERS_TO_READ * 2)) : 0); - case ModbusFunctionCode::READ_FIFO_QUEUE: + case FunctionCode::READ_FIFO_QUEUE: // address(1) + function(1) + fifo address(2) CRC(2) return 6; default: @@ -46,31 +46,31 @@ uint16_t server_frame_length(const uint8_t *frame, size_t size) { uint16_t client_frame_length(const uint8_t *frame, size_t size) { if (size < 2) return MIN_FRAME_SIZE; - switch (static_cast(frame[1])) { - case ModbusFunctionCode::READ_COILS: - case ModbusFunctionCode::READ_DISCRETE_INPUTS: - case ModbusFunctionCode::READ_HOLDING_REGISTERS: - case ModbusFunctionCode::READ_INPUT_REGISTERS: + switch (static_cast(frame[1])) { + case FunctionCode::READ_COILS: + case FunctionCode::READ_DISCRETE_INPUTS: + case FunctionCode::READ_HOLDING_REGISTERS: + case FunctionCode::READ_INPUT_REGISTERS: // address(1) + function(1) + start address(2) + quantity(2) + CRC(2) - case ModbusFunctionCode::WRITE_SINGLE_COIL: - case ModbusFunctionCode::WRITE_SINGLE_REGISTER: + case FunctionCode::WRITE_SINGLE_COIL: + case FunctionCode::WRITE_SINGLE_REGISTER: return 8; // address(1) + function(1) + output/register address(2) + value(2) + CRC(2) - case ModbusFunctionCode::WRITE_MULTIPLE_COILS: - case ModbusFunctionCode::WRITE_MULTIPLE_REGISTERS: + case FunctionCode::WRITE_MULTIPLE_COILS: + case FunctionCode::WRITE_MULTIPLE_REGISTERS: // address(1) + function(1) + start address(2) + quantity(2) + byte count(1) + data + CRC(2) return 9 + (size > 6 ? std::min(frame[6], uint8_t(MAX_NUM_OF_REGISTERS_TO_WRITE * 2)) : 0); // Unsupported function codes. Included here to prevent parser failures. Excluding Serial Line specific functions. - case ModbusFunctionCode::READ_FILE_RECORD: - case ModbusFunctionCode::WRITE_FILE_RECORD: + case FunctionCode::READ_FILE_RECORD: + case FunctionCode::WRITE_FILE_RECORD: // address(1) + function(1) + byte count(1) + data + CRC(2) return 5 + (size > 2 ? std::min(frame[2], uint8_t(MAX_FRAME_SIZE - 5)) : 0); - case ModbusFunctionCode::MASK_WRITE_REGISTER: + case FunctionCode::MASK_WRITE_REGISTER: return 10; // address(1) + function(1) + reference address(2) + AND mask(2) + OR mask(2) + CRC(2) - case ModbusFunctionCode::READ_WRITE_MULTIPLE_REGISTERS: + case FunctionCode::READ_WRITE_MULTIPLE_REGISTERS: // address(1) + function(1) + read start address(2) + read quantity(2) + write start address(2) + // write quantity(2) + byte count(1) + data + CRC(2) return 13 + (size > 10 ? std::min(frame[10], uint8_t(MAX_NUM_OF_REGISTERS_TO_WRITE * 2)) : 0); - case ModbusFunctionCode::READ_FIFO_QUEUE: + case FunctionCode::READ_FIFO_QUEUE: // address(1) + function(1) + fifo address(2) CRC(2) return 6; default: @@ -197,7 +197,7 @@ std::optional registers_to_number(const uint16_t *registers, size_t cou return payload_to_number(bytes, required_size, sensor_value_type, 0, 0xFFFFFFFF); } -StaticVector create_client_pdu(ModbusFunctionCode function_code, uint16_t start_address, +StaticVector create_client_pdu(FunctionCode function_code, uint16_t start_address, uint16_t number_of_entities, const uint8_t *values, size_t values_len) { if (is_function_code_read(static_cast(function_code))) { @@ -221,33 +221,33 @@ StaticVector create_client_pdu(ModbusFunctionCode functio } switch (function_code) { - case ModbusFunctionCode::READ_COILS: + case FunctionCode::READ_COILS: if (number_of_entities > MAX_NUM_OF_COILS_TO_READ) { ESP_LOGE(TAG, "number_of_entities %u exceeds maximum coils to read %u for function code %02X", number_of_entities, MAX_NUM_OF_COILS_TO_READ, static_cast(function_code)); return {}; } break; - case ModbusFunctionCode::READ_DISCRETE_INPUTS: + case FunctionCode::READ_DISCRETE_INPUTS: if (number_of_entities > MAX_NUM_OF_DISCRETE_INPUTS_TO_READ) { ESP_LOGE(TAG, "number_of_entities %u exceeds maximum discrete inputs to read %u for function code %02X", number_of_entities, MAX_NUM_OF_DISCRETE_INPUTS_TO_READ, static_cast(function_code)); return {}; } break; - case ModbusFunctionCode::READ_HOLDING_REGISTERS: - case ModbusFunctionCode::READ_INPUT_REGISTERS: + case FunctionCode::READ_HOLDING_REGISTERS: + case FunctionCode::READ_INPUT_REGISTERS: if (number_of_entities > MAX_NUM_OF_REGISTERS_TO_READ) { ESP_LOGE(TAG, "number_of_entities %u exceeds maximum registers to read %u for function code %02X", number_of_entities, MAX_NUM_OF_REGISTERS_TO_READ, static_cast(function_code)); return {}; } break; - case ModbusFunctionCode::WRITE_SINGLE_COIL: - case ModbusFunctionCode::WRITE_SINGLE_REGISTER: + case FunctionCode::WRITE_SINGLE_COIL: + case FunctionCode::WRITE_SINGLE_REGISTER: break; // number_of_entities is ignored for single write, so no need to validate - case ModbusFunctionCode::WRITE_MULTIPLE_COILS: - case ModbusFunctionCode::WRITE_MULTIPLE_REGISTERS: + case FunctionCode::WRITE_MULTIPLE_COILS: + case FunctionCode::WRITE_MULTIPLE_REGISTERS: if (number_of_entities > MAX_NUM_OF_REGISTERS_TO_WRITE) { ESP_LOGE(TAG, "number_of_entities %u exceeds maximum registers to write %u for function code %02X", number_of_entities, MAX_NUM_OF_REGISTERS_TO_WRITE, static_cast(function_code)); @@ -263,15 +263,14 @@ StaticVector create_client_pdu(ModbusFunctionCode functio pdu.push_back(static_cast(function_code)); pdu.push_back(start_address >> 8); pdu.push_back(start_address >> 0); - if (function_code != ModbusFunctionCode::WRITE_SINGLE_COIL && - function_code != ModbusFunctionCode::WRITE_SINGLE_REGISTER) { + if (function_code != FunctionCode::WRITE_SINGLE_COIL && function_code != FunctionCode::WRITE_SINGLE_REGISTER) { pdu.push_back(number_of_entities >> 8); pdu.push_back(number_of_entities >> 0); } if (is_function_code_write(static_cast(function_code))) { - if (function_code == ModbusFunctionCode::WRITE_MULTIPLE_COILS || - function_code == ModbusFunctionCode::WRITE_MULTIPLE_REGISTERS) { + if (function_code == FunctionCode::WRITE_MULTIPLE_COILS || + function_code == FunctionCode::WRITE_MULTIPLE_REGISTERS) { // 6 bytes of overhead (fc + start_addr×2 + qty×2 + byte_count) leave MAX_PDU_SIZE-6 bytes for values static constexpr size_t MAX_WRITE_MULTIPLE_VALUES_LEN = MAX_PDU_SIZE - 6; if (values_len > MAX_WRITE_MULTIPLE_VALUES_LEN) { diff --git a/esphome/components/modbus/modbus_helpers.h b/esphome/components/modbus/modbus_helpers.h index 587f6838ee..0fece3be5d 100644 --- a/esphome/components/modbus/modbus_helpers.h +++ b/esphome/components/modbus/modbus_helpers.h @@ -12,19 +12,19 @@ namespace esphome::modbus::helpers { inline bool is_function_code_read(uint8_t function_code) { - ModbusFunctionCode masked_function_code = static_cast(function_code & FUNCTION_CODE_MASK); - return masked_function_code == ModbusFunctionCode::READ_COILS || - masked_function_code == ModbusFunctionCode::READ_DISCRETE_INPUTS || - masked_function_code == ModbusFunctionCode::READ_HOLDING_REGISTERS || - masked_function_code == ModbusFunctionCode::READ_INPUT_REGISTERS; + FunctionCode masked_function_code = static_cast(function_code & FUNCTION_CODE_MASK); + return masked_function_code == FunctionCode::READ_COILS || + masked_function_code == FunctionCode::READ_DISCRETE_INPUTS || + masked_function_code == FunctionCode::READ_HOLDING_REGISTERS || + masked_function_code == FunctionCode::READ_INPUT_REGISTERS; } inline bool is_function_code_write(uint8_t function_code) { - ModbusFunctionCode masked_function_code = static_cast(function_code & FUNCTION_CODE_MASK); - return masked_function_code == ModbusFunctionCode::WRITE_SINGLE_COIL || - masked_function_code == ModbusFunctionCode::WRITE_SINGLE_REGISTER || - masked_function_code == ModbusFunctionCode::WRITE_MULTIPLE_COILS || - masked_function_code == ModbusFunctionCode::WRITE_MULTIPLE_REGISTERS; + FunctionCode masked_function_code = static_cast(function_code & FUNCTION_CODE_MASK); + return masked_function_code == FunctionCode::WRITE_SINGLE_COIL || + masked_function_code == FunctionCode::WRITE_SINGLE_REGISTER || + masked_function_code == FunctionCode::WRITE_MULTIPLE_COILS || + masked_function_code == FunctionCode::WRITE_MULTIPLE_REGISTERS; } inline bool is_function_code_exception(uint8_t function_code) { @@ -52,11 +52,11 @@ ESPDEPRECATED("Use server_pdu_payload() on the response PDU instead. Removed in inline uint8_t server_frame_data_offset(const uint8_t *frame, size_t size) { if (size < 2) return 0; - switch (static_cast(frame[1])) { - case ModbusFunctionCode::READ_COILS: - case ModbusFunctionCode::READ_DISCRETE_INPUTS: - case ModbusFunctionCode::READ_HOLDING_REGISTERS: - case ModbusFunctionCode::READ_INPUT_REGISTERS: + switch (static_cast(frame[1])) { + case FunctionCode::READ_COILS: + case FunctionCode::READ_DISCRETE_INPUTS: + case FunctionCode::READ_HOLDING_REGISTERS: + case FunctionCode::READ_INPUT_REGISTERS: return 3; // address(1) + function(1) + byte count(1) + data + CRC(2) default: return 2; @@ -100,32 +100,32 @@ inline bool value_type_is_float(SensorValueType v) { return v == SensorValueType::FP32 || v == SensorValueType::FP32_R; } -inline ModbusFunctionCode modbus_register_read_function(ModbusRegisterType reg_type) { +inline FunctionCode modbus_register_read_function(EntityType reg_type) { switch (reg_type) { - case ModbusRegisterType::COIL: - return ModbusFunctionCode::READ_COILS; - case ModbusRegisterType::DISCRETE_INPUT: - return ModbusFunctionCode::READ_DISCRETE_INPUTS; - case ModbusRegisterType::HOLDING: - return ModbusFunctionCode::READ_HOLDING_REGISTERS; - case ModbusRegisterType::INPUT_REGISTER: - return ModbusFunctionCode::READ_INPUT_REGISTERS; + case EntityType::COIL: + return FunctionCode::READ_COILS; + case EntityType::DISCRETE_INPUT: + return FunctionCode::READ_DISCRETE_INPUTS; + case EntityType::HOLDING: + return FunctionCode::READ_HOLDING_REGISTERS; + case EntityType::INPUT_REGISTER: + return FunctionCode::READ_INPUT_REGISTERS; default: - return ModbusFunctionCode::INVALID; + return FunctionCode::INVALID; } } -inline ModbusFunctionCode modbus_register_write_function(ModbusRegisterType reg_type, bool multiple = false) { +inline FunctionCode modbus_register_write_function(EntityType reg_type, bool multiple = false) { switch (reg_type) { - case ModbusRegisterType::COIL: - return multiple ? ModbusFunctionCode::WRITE_MULTIPLE_COILS : ModbusFunctionCode::WRITE_SINGLE_COIL; - case ModbusRegisterType::HOLDING: - return multiple ? ModbusFunctionCode::WRITE_MULTIPLE_REGISTERS : ModbusFunctionCode::WRITE_SINGLE_REGISTER; + case EntityType::COIL: + return multiple ? FunctionCode::WRITE_MULTIPLE_COILS : FunctionCode::WRITE_SINGLE_COIL; + case EntityType::HOLDING: + return multiple ? FunctionCode::WRITE_MULTIPLE_REGISTERS : FunctionCode::WRITE_SINGLE_REGISTER; // These register types can't be written (per spec) - case ModbusRegisterType::INPUT_REGISTER: - case ModbusRegisterType::DISCRETE_INPUT: + case EntityType::INPUT_REGISTER: + case EntityType::DISCRETE_INPUT: default: - return ModbusFunctionCode::INVALID; + return FunctionCode::INVALID; } } @@ -340,7 +340,7 @@ std::optional registers_to_number(const uint16_t *registers, size_t cou * @param values_len length of values array * @return PDU (function code + data, no address, no CRC) */ -StaticVector create_client_pdu(ModbusFunctionCode function_code, uint16_t start_address, +StaticVector create_client_pdu(FunctionCode function_code, uint16_t start_address, uint16_t number_of_entities, const uint8_t *values = nullptr, size_t values_len = 0); diff --git a/esphome/components/modbus_controller/__init__.py b/esphome/components/modbus_controller/__init__.py index 527e9b047f..35a5479ecb 100644 --- a/esphome/components/modbus_controller/__init__.py +++ b/esphome/components/modbus_controller/__init__.py @@ -6,7 +6,7 @@ from esphome.components import modbus from esphome.components.modbus.helpers import ( MODBUS_REGISTER_TYPE, TYPE_REGISTER_MAP, - ModbusRegisterType, + EntityType, ) import esphome.config_validation as cv from esphome.const import CONF_ADDRESS, CONF_ID, CONF_LAMBDA, CONF_NAME, CONF_OFFSET @@ -217,13 +217,13 @@ async def register_modbus_device(var, config): def function_code_to_register(function_code): FUNCTION_CODE_TYPE_MAP = { - "read_coils": ModbusRegisterType.COIL, - "read_discrete_inputs": ModbusRegisterType.DISCRETE_INPUT, - "read_holding_registers": ModbusRegisterType.HOLDING, - "read_input_registers": ModbusRegisterType.INPUT_REGISTER, - "write_single_coil": ModbusRegisterType.COIL, - "write_single_register": ModbusRegisterType.HOLDING, - "write_multiple_coils": ModbusRegisterType.COIL, - "write_multiple_registers": ModbusRegisterType.HOLDING, + "read_coils": EntityType.COIL, + "read_discrete_inputs": EntityType.DISCRETE_INPUT, + "read_holding_registers": EntityType.HOLDING, + "read_input_registers": EntityType.INPUT_REGISTER, + "write_single_coil": EntityType.COIL, + "write_single_register": EntityType.HOLDING, + "write_multiple_coils": EntityType.COIL, + "write_multiple_registers": EntityType.HOLDING, } return FUNCTION_CODE_TYPE_MAP[function_code] diff --git a/esphome/components/modbus_controller/binary_sensor/modbus_binarysensor.cpp b/esphome/components/modbus_controller/binary_sensor/modbus_binarysensor.cpp index 9656013a5f..4175e9e6e4 100644 --- a/esphome/components/modbus_controller/binary_sensor/modbus_binarysensor.cpp +++ b/esphome/components/modbus_controller/binary_sensor/modbus_binarysensor.cpp @@ -11,8 +11,8 @@ void ModbusBinarySensor::parse_and_publish(const std::vector &data) { bool value; switch (this->register_type) { - case ModbusRegisterType::DISCRETE_INPUT: - case ModbusRegisterType::COIL: + case EntityType::DISCRETE_INPUT: + case EntityType::COIL: // offset for coil is the actual number of the coil not the byte offset value = modbus::helpers::bit_from_packed(this->offset, data); break; diff --git a/esphome/components/modbus_controller/binary_sensor/modbus_binarysensor.h b/esphome/components/modbus_controller/binary_sensor/modbus_binarysensor.h index 3f7c6b4dd6..518b198eae 100644 --- a/esphome/components/modbus_controller/binary_sensor/modbus_binarysensor.h +++ b/esphome/components/modbus_controller/binary_sensor/modbus_binarysensor.h @@ -10,7 +10,7 @@ namespace esphome::modbus_controller { class ModbusBinarySensor final : public Component, public binary_sensor::BinarySensor, public SensorItem { public: - ModbusBinarySensor(ModbusRegisterType register_type, uint16_t start_address, uint8_t offset, uint32_t bitmask, + ModbusBinarySensor(EntityType register_type, uint16_t start_address, uint8_t offset, uint32_t bitmask, uint16_t skip_updates, bool force_new_range) { this->register_type = register_type; this->start_address = start_address; @@ -20,7 +20,7 @@ class ModbusBinarySensor final : public Component, public binary_sensor::BinaryS this->skip_updates = skip_updates; this->force_new_range = force_new_range; - if (register_type == ModbusRegisterType::COIL || register_type == ModbusRegisterType::DISCRETE_INPUT) { + if (register_type == EntityType::COIL || register_type == EntityType::DISCRETE_INPUT) { this->register_count = offset + 1; } else { this->register_count = 1; diff --git a/esphome/components/modbus_controller/modbus_controller.cpp b/esphome/components/modbus_controller/modbus_controller.cpp index 84f8fc16b8..f8b522b05b 100644 --- a/esphome/components/modbus_controller/modbus_controller.cpp +++ b/esphome/components/modbus_controller/modbus_controller.cpp @@ -95,7 +95,7 @@ void ModbusController::process_modbus_data_(const ModbusCommandItem *response) { response->on_data_func(response->register_type, response->register_address, response->payload); } -void ModbusController::on_error(std::span request_pdu, modbus::ModbusExceptionCode exception_code) { +void ModbusController::on_error(std::span request_pdu, modbus::ExceptionCode exception_code) { // The request function code (request_pdu[0]) already carries what the log needs; the exception bit only // ever appears on the response, so no masking is needed here. const uint8_t function_code = request_pdu.empty() ? 0 : request_pdu[0]; @@ -116,7 +116,7 @@ void ModbusController::on_error(std::span request_pdu, modbus::Mo } } -SensorSet ModbusController::find_sensors_(ModbusRegisterType register_type, uint16_t start_address) const { +SensorSet ModbusController::find_sensors_(EntityType register_type, uint16_t start_address) const { auto reg_it = std::find_if( std::begin(this->register_ranges_), std::end(this->register_ranges_), [=](RegisterRange const &r) { return (r.start_address == start_address && r.register_type == register_type); }); @@ -130,7 +130,7 @@ SensorSet ModbusController::find_sensors_(ModbusRegisterType register_type, uint // not found return {}; } -void ModbusController::on_register_data(ModbusRegisterType register_type, uint16_t start_address, +void ModbusController::on_register_data(EntityType register_type, uint16_t start_address, const std::vector &data) { ESP_LOGV(TAG, "data for register address : 0x%X : ", start_address); @@ -164,18 +164,18 @@ void ModbusController::update_range_(RegisterRange &r) { r.skip_updates_counter); if (r.skip_updates_counter == 0) { // if a custom command is used the user supplied custom_data is only available in the SensorItem. - if (r.register_type == ModbusRegisterType::CUSTOM) { + if (r.register_type == EntityType::CUSTOM) { auto sensors = this->find_sensors_(r.register_type, r.start_address); if (!sensors.empty()) { auto sensor = sensors.cbegin(); auto command_item = ModbusCommandItem::create_custom_command( this, (*sensor)->custom_data, - [this](ModbusRegisterType register_type, uint16_t start_address, const std::vector &data) { - this->on_register_data(ModbusRegisterType::CUSTOM, start_address, data); + [this](EntityType register_type, uint16_t start_address, const std::vector &data) { + this->on_register_data(EntityType::CUSTOM, start_address, data); }); command_item.register_address = (*sensor)->start_address; command_item.register_count = (*sensor)->register_count; - command_item.function_code = ModbusFunctionCode::CUSTOM; + command_item.function_code = FunctionCode::CUSTOM; queue_command(command_item); } } else { @@ -237,7 +237,7 @@ size_t ModbusController::create_register_ranges_() { // this is not the first register in range so it might be possible // to reuse the last register or extend the current range if (!curr->force_new_range && r.register_type == curr->register_type && - curr->register_type != ModbusRegisterType::CUSTOM) { + curr->register_type != EntityType::CUSTOM) { if (curr->start_address == (r.start_address + r.register_count - prev->register_count) && curr->register_count == prev->register_count && curr->get_register_size() == prev->get_register_size()) { // this register can re-use the data from the previous register @@ -347,7 +347,7 @@ void ModbusController::loop() { } } -void ModbusController::on_write_register_response(ModbusRegisterType register_type, uint16_t start_address, +void ModbusController::on_write_register_response(EntityType register_type, uint16_t start_address, const std::vector &data) { ESP_LOGV(TAG, "Command ACK 0x%X %d ", modbus::helpers::get_data(data, 0), modbus::helpers::get_data(data, 1)); @@ -362,9 +362,8 @@ void ModbusController::dump_sensors_() { } ModbusCommandItem ModbusCommandItem::create_read_command( - ModbusController *modbusdevice, ModbusRegisterType register_type, uint16_t start_address, uint16_t register_count, - std::function &data)> - &&handler) { + ModbusController *modbusdevice, EntityType register_type, uint16_t start_address, uint16_t register_count, + std::function &data)> &&handler) { ModbusCommandItem cmd; cmd.modbusdevice = modbusdevice; cmd.register_type = register_type; @@ -375,16 +374,15 @@ ModbusCommandItem ModbusCommandItem::create_read_command( return cmd; } -ModbusCommandItem ModbusCommandItem::create_read_command(ModbusController *modbusdevice, - ModbusRegisterType register_type, uint16_t start_address, - uint16_t register_count) { +ModbusCommandItem ModbusCommandItem::create_read_command(ModbusController *modbusdevice, EntityType register_type, + uint16_t start_address, uint16_t register_count) { ModbusCommandItem cmd; cmd.modbusdevice = modbusdevice; cmd.register_type = register_type; cmd.function_code = modbus::helpers::modbus_register_read_function(register_type); cmd.register_address = start_address; cmd.register_count = register_count; - cmd.on_data_func = [modbusdevice](ModbusRegisterType register_type, uint16_t start_address, + cmd.on_data_func = [modbusdevice](EntityType register_type, uint16_t start_address, const std::vector &data) { modbusdevice->on_register_data(register_type, start_address, data); }; @@ -396,11 +394,11 @@ ModbusCommandItem ModbusCommandItem::create_write_multiple_command(ModbusControl const std::vector &values) { ModbusCommandItem cmd; cmd.modbusdevice = modbusdevice; - cmd.register_type = ModbusRegisterType::HOLDING; - cmd.function_code = ModbusFunctionCode::WRITE_MULTIPLE_REGISTERS; + cmd.register_type = EntityType::HOLDING; + cmd.function_code = FunctionCode::WRITE_MULTIPLE_REGISTERS; cmd.register_address = start_address; cmd.register_count = register_count; - cmd.on_data_func = [modbusdevice, cmd](ModbusRegisterType register_type, uint16_t start_address, + cmd.on_data_func = [modbusdevice, cmd](EntityType register_type, uint16_t start_address, const std::vector &data) { modbusdevice->on_write_register_response(cmd.register_type, start_address, data); }; @@ -416,11 +414,11 @@ ModbusCommandItem ModbusCommandItem::create_write_single_coil(ModbusController * bool value) { ModbusCommandItem cmd; cmd.modbusdevice = modbusdevice; - cmd.register_type = ModbusRegisterType::COIL; - cmd.function_code = ModbusFunctionCode::WRITE_SINGLE_COIL; + cmd.register_type = EntityType::COIL; + cmd.function_code = FunctionCode::WRITE_SINGLE_COIL; cmd.register_address = address; cmd.register_count = 1; - cmd.on_data_func = [modbusdevice, cmd](ModbusRegisterType register_type, uint16_t start_address, + cmd.on_data_func = [modbusdevice, cmd](EntityType register_type, uint16_t start_address, const std::vector &data) { modbusdevice->on_write_register_response(cmd.register_type, start_address, data); }; @@ -433,11 +431,11 @@ ModbusCommandItem ModbusCommandItem::create_write_multiple_coils(ModbusControlle const std::vector &values) { ModbusCommandItem cmd; cmd.modbusdevice = modbusdevice; - cmd.register_type = ModbusRegisterType::COIL; - cmd.function_code = ModbusFunctionCode::WRITE_MULTIPLE_COILS; + cmd.register_type = EntityType::COIL; + cmd.function_code = FunctionCode::WRITE_MULTIPLE_COILS; cmd.register_address = start_address; cmd.register_count = values.size(); - cmd.on_data_func = [modbusdevice, cmd](ModbusRegisterType register_type, uint16_t start_address, + cmd.on_data_func = [modbusdevice, cmd](EntityType register_type, uint16_t start_address, const std::vector &data) { modbusdevice->on_write_register_response(cmd.register_type, start_address, data); }; @@ -465,11 +463,11 @@ ModbusCommandItem ModbusCommandItem::create_write_single_command(ModbusControlle uint16_t value) { ModbusCommandItem cmd; cmd.modbusdevice = modbusdevice; - cmd.register_type = ModbusRegisterType::HOLDING; - cmd.function_code = ModbusFunctionCode::WRITE_SINGLE_REGISTER; + cmd.register_type = EntityType::HOLDING; + cmd.function_code = FunctionCode::WRITE_SINGLE_REGISTER; cmd.register_address = start_address; cmd.register_count = 1; // not used here anyways - cmd.on_data_func = [modbusdevice, cmd](ModbusRegisterType register_type, uint16_t start_address, + cmd.on_data_func = [modbusdevice, cmd](EntityType register_type, uint16_t start_address, const std::vector &data) { modbusdevice->on_write_register_response(cmd.register_type, start_address, data); }; @@ -482,13 +480,12 @@ ModbusCommandItem ModbusCommandItem::create_write_single_command(ModbusControlle ModbusCommandItem ModbusCommandItem::create_custom_command( ModbusController *modbusdevice, const std::vector &values, - std::function &data)> - &&handler) { + std::function &data)> &&handler) { ModbusCommandItem cmd; cmd.modbusdevice = modbusdevice; - cmd.function_code = ModbusFunctionCode::CUSTOM; + cmd.function_code = FunctionCode::CUSTOM; if (handler == nullptr) { - cmd.on_data_func = [](ModbusRegisterType register_type, uint16_t start_address, const std::vector &data) { + cmd.on_data_func = [](EntityType register_type, uint16_t start_address, const std::vector &data) { ESP_LOGI(TAG, "Custom Command sent"); }; } else { @@ -501,13 +498,12 @@ ModbusCommandItem ModbusCommandItem::create_custom_command( ModbusCommandItem ModbusCommandItem::create_custom_command( ModbusController *modbusdevice, const std::vector &values, - std::function &data)> - &&handler) { + std::function &data)> &&handler) { ModbusCommandItem cmd = {}; cmd.modbusdevice = modbusdevice; - cmd.function_code = ModbusFunctionCode::CUSTOM; + cmd.function_code = FunctionCode::CUSTOM; if (handler == nullptr) { - cmd.on_data_func = [](ModbusRegisterType register_type, uint16_t start_address, const std::vector &data) { + cmd.on_data_func = [](EntityType register_type, uint16_t start_address, const std::vector &data) { ESP_LOGI(TAG, "Custom Command sent"); }; } else { @@ -522,7 +518,7 @@ ModbusCommandItem ModbusCommandItem::create_custom_command( } bool ModbusCommandItem::send() { - if (this->function_code != ModbusFunctionCode::CUSTOM) { + if (this->function_code != FunctionCode::CUSTOM) { modbusdevice->send(uint8_t(this->function_code), this->register_address, this->register_count, this->payload.size(), this->payload.empty() ? nullptr : &this->payload[0]); } else { @@ -537,7 +533,7 @@ bool ModbusCommandItem::send() { bool ModbusCommandItem::is_equal(const ModbusCommandItem &other) { // for custom commands we have to check for identical payloads, since // address/count/type fields will be set to zero - return this->function_code == ModbusFunctionCode::CUSTOM + return this->function_code == FunctionCode::CUSTOM ? this->payload == other.payload : other.register_address == this->register_address && other.register_count == this->register_count && other.register_type == this->register_type && other.function_code == this->function_code; diff --git a/esphome/components/modbus_controller/modbus_controller.h b/esphome/components/modbus_controller/modbus_controller.h index 23e93057b8..3a9b2f71a9 100644 --- a/esphome/components/modbus_controller/modbus_controller.h +++ b/esphome/components/modbus_controller/modbus_controller.h @@ -17,22 +17,30 @@ namespace esphome::modbus_controller { class ModbusController; +using modbus::EntityType; +using modbus::ExceptionCode; +using modbus::FunctionCode; +using modbus::helpers::SensorValueType; + +// Remove before 2027.2.0 - deprecated names re-exported so external components keep their warning window +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +using modbus::ModbusExceptionCode; using modbus::ModbusFunctionCode; using modbus::ModbusRegisterType; -using modbus::ModbusExceptionCode; -using modbus::helpers::SensorValueType; +#pragma GCC diagnostic pop // Remove before 2026.10.0 — these helpers have moved to modbus::helpers ESPDEPRECATED("Use modbus::helpers::value_type_is_float() instead. Removed in 2026.10.0", "2026.4.0") inline bool value_type_is_float(SensorValueType v) { return modbus::helpers::value_type_is_float(v); } ESPDEPRECATED("Use modbus::helpers::modbus_register_read_function() instead. Removed in 2026.10.0", "2026.4.0") -inline ModbusFunctionCode modbus_register_read_function(ModbusRegisterType reg_type) { +inline FunctionCode modbus_register_read_function(EntityType reg_type) { return modbus::helpers::modbus_register_read_function(reg_type); } ESPDEPRECATED("Use modbus::helpers::modbus_register_write_function() instead. Removed in 2026.10.0", "2026.4.0") -inline ModbusFunctionCode modbus_register_write_function(ModbusRegisterType reg_type) { +inline FunctionCode modbus_register_write_function(EntityType reg_type) { return modbus::helpers::modbus_register_write_function(reg_type); } @@ -102,7 +110,7 @@ class SensorItem { void set_custom_data(const std::vector &data) { custom_data = data; } size_t virtual get_register_size() const { - if (register_type == ModbusRegisterType::COIL || register_type == ModbusRegisterType::DISCRETE_INPUT) { + if (register_type == EntityType::COIL || register_type == EntityType::DISCRETE_INPUT) { return 1; } else { // if CONF_RESPONSE_BYTES is used override the default return response_bytes > 0 ? response_bytes : register_count * 2; @@ -110,7 +118,7 @@ class SensorItem { } // Override register size for modbus devices not using 1 register for one dword void set_register_size(uint8_t register_size) { response_bytes = register_size; } - ModbusRegisterType register_type{ModbusRegisterType::CUSTOM}; + EntityType register_type{EntityType::CUSTOM}; SensorValueType sensor_value_type{SensorValueType::RAW}; uint16_t start_address{0}; uint32_t bitmask{0}; @@ -157,7 +165,7 @@ using SensorSet = std::set; struct RegisterRange { uint16_t start_address; - ModbusRegisterType register_type; + EntityType register_type; uint8_t register_count; uint16_t skip_updates; // the config value SensorSet sensors; // all sensors of this range @@ -170,10 +178,9 @@ class ModbusCommandItem { ModbusController *modbusdevice{nullptr}; uint16_t register_address{0}; uint16_t register_count{0}; - ModbusFunctionCode function_code{ModbusFunctionCode::CUSTOM}; - ModbusRegisterType register_type{ModbusRegisterType::CUSTOM}; - std::function &data)> - on_data_func; + FunctionCode function_code{FunctionCode::CUSTOM}; + EntityType register_type{EntityType::CUSTOM}; + std::function &data)> on_data_func; std::vector payload = {}; bool send(); /// Check if the command should be retried based on the max_retries parameter @@ -189,10 +196,10 @@ class ModbusCommandItem { * @param handler function called when the response is received * @return ModbusCommandItem with the prepared command */ - static ModbusCommandItem create_read_command( - ModbusController *modbusdevice, ModbusRegisterType register_type, uint16_t start_address, uint16_t register_count, - std::function &data)> - &&handler); + static ModbusCommandItem create_read_command(ModbusController *modbusdevice, EntityType register_type, + uint16_t start_address, uint16_t register_count, + std::function &data)> &&handler); /** Create modbus read command * Function code 02-04 * @param modbusdevice pointer to the device to execute the command @@ -201,7 +208,7 @@ class ModbusCommandItem { * @param register_count number of registers to read * @return ModbusCommandItem with the prepared command */ - static ModbusCommandItem create_read_command(ModbusController *modbusdevice, ModbusRegisterType register_type, + static ModbusCommandItem create_read_command(ModbusController *modbusdevice, EntityType register_type, uint16_t start_address, uint16_t register_count); /** Create modbus read command * Function code 02-04 @@ -251,7 +258,7 @@ class ModbusCommandItem { */ static ModbusCommandItem create_custom_command( ModbusController *modbusdevice, const std::vector &values, - std::function &data)> + std::function &data)> &&handler = nullptr); /** Create custom modbus command @@ -263,7 +270,7 @@ class ModbusCommandItem { */ static ModbusCommandItem create_custom_command( ModbusController *modbusdevice, const std::vector &values, - std::function &data)> + std::function &data)> &&handler = nullptr); bool is_equal(const ModbusCommandItem &other); @@ -296,13 +303,12 @@ class ModbusController final : public PollingComponent, public modbus::ModbusCli /// called when a modbus response was parsed without errors void on_response(std::span request_pdu, std::span response_pdu) override; /// called when a modbus error response was received - void on_error(std::span request_pdu, modbus::ModbusExceptionCode exception_code) override; + void on_error(std::span request_pdu, modbus::ExceptionCode exception_code) override; /// default delegate called by process_modbus_data when a response has retrieved from the incoming queue - void on_register_data(ModbusRegisterType register_type, uint16_t start_address, const std::vector &data); + void on_register_data(EntityType register_type, uint16_t start_address, const std::vector &data); /// default delegate called by process_modbus_data when a response for a write response has retrieved from the /// incoming queue - void on_write_register_response(ModbusRegisterType register_type, uint16_t start_address, - const std::vector &data); + void on_write_register_response(EntityType register_type, uint16_t start_address, const std::vector &data); /// Allow a duplicate command to be sent void set_allow_duplicate_commands(bool allow_duplicate_commands) { this->allow_duplicate_commands_ = allow_duplicate_commands; @@ -338,7 +344,7 @@ class ModbusController final : public PollingComponent, public modbus::ModbusCli /// parse sensormap_ and create range of sequential addresses size_t create_register_ranges_(); // find register in sensormap. Returns iterator with all registers having the same start address - SensorSet find_sensors_(ModbusRegisterType register_type, uint16_t start_address) const; + SensorSet find_sensors_(EntityType register_type, uint16_t start_address) const; /// submit the read command for the address range to the send queue void update_range_(RegisterRange &r); /// parse incoming modbus data diff --git a/esphome/components/modbus_controller/number/modbus_number.cpp b/esphome/components/modbus_controller/number/modbus_number.cpp index 2c81dd6830..97b490146a 100644 --- a/esphome/components/modbus_controller/number/modbus_number.cpp +++ b/esphome/components/modbus_controller/number/modbus_number.cpp @@ -57,7 +57,7 @@ void ModbusNumber::control(float value) { format_hex_pretty_to(hex_buf, sizeof(hex_buf), data.data(), data.size())); write_cmd = ModbusCommandItem::create_custom_command( this->parent_, data, - [this, write_cmd](ModbusRegisterType register_type, uint16_t start_address, const std::vector &data) { + [this, write_cmd](EntityType register_type, uint16_t start_address, const std::vector &data) { this->parent_->on_write_register_response(write_cmd.register_type, this->start_address, data); }); } else { @@ -77,7 +77,7 @@ void ModbusNumber::control(float value) { this->parent_, this->start_address + this->offset / 2, this->register_count, data); } // publish new value - write_cmd.on_data_func = [this, write_cmd, value](ModbusRegisterType register_type, uint16_t start_address, + write_cmd.on_data_func = [this, write_cmd, value](EntityType register_type, uint16_t start_address, const std::vector &data) { // gets called when the write command is ack'd from the device this->parent_->on_write_register_response(write_cmd.register_type, start_address, data); diff --git a/esphome/components/modbus_controller/number/modbus_number.h b/esphome/components/modbus_controller/number/modbus_number.h index ce64099170..4bb07f3f39 100644 --- a/esphome/components/modbus_controller/number/modbus_number.h +++ b/esphome/components/modbus_controller/number/modbus_number.h @@ -12,7 +12,7 @@ using value_to_data_t = std::function(float); class ModbusNumber final : public number::Number, public Component, public SensorItem { public: - ModbusNumber(ModbusRegisterType register_type, uint16_t start_address, uint8_t offset, uint32_t bitmask, + ModbusNumber(EntityType register_type, uint16_t start_address, uint8_t offset, uint32_t bitmask, SensorValueType value_type, int register_count, uint16_t skip_updates, bool force_new_range) { this->register_type = register_type; this->start_address = start_address; diff --git a/esphome/components/modbus_controller/output/modbus_output.cpp b/esphome/components/modbus_controller/output/modbus_output.cpp index 504e09a093..a3216b3a12 100644 --- a/esphome/components/modbus_controller/output/modbus_output.cpp +++ b/esphome/components/modbus_controller/output/modbus_output.cpp @@ -89,7 +89,7 @@ void ModbusBinaryOutput::write_state(bool state) { format_hex_pretty_to(hex_buf, sizeof(hex_buf), data.data(), data.size())); cmd = ModbusCommandItem::create_custom_command( this->parent_, data, - [this, cmd](ModbusRegisterType register_type, uint16_t start_address, const std::vector &data) { + [this, cmd](EntityType register_type, uint16_t start_address, const std::vector &data) { this->parent_->on_write_register_response(cmd.register_type, this->start_address, data); }); } else { diff --git a/esphome/components/modbus_controller/output/modbus_output.h b/esphome/components/modbus_controller/output/modbus_output.h index d904e58bd7..f55121a104 100644 --- a/esphome/components/modbus_controller/output/modbus_output.h +++ b/esphome/components/modbus_controller/output/modbus_output.h @@ -11,7 +11,7 @@ namespace esphome::modbus_controller { class ModbusFloatOutput final : public output::FloatOutput, public Component, public SensorItem { public: ModbusFloatOutput(uint16_t start_address, uint8_t offset, SensorValueType value_type, int register_count) { - this->register_type = ModbusRegisterType::HOLDING; + this->register_type = EntityType::HOLDING; this->start_address = start_address; this->offset = offset; this->bitmask = 0xFFFFFFFF; @@ -44,7 +44,7 @@ class ModbusFloatOutput final : public output::FloatOutput, public Component, pu class ModbusBinaryOutput final : public output::BinaryOutput, public Component, public SensorItem { public: ModbusBinaryOutput(uint16_t start_address, uint8_t offset) { - this->register_type = ModbusRegisterType::COIL; + this->register_type = EntityType::COIL; this->start_address = start_address; this->bitmask = 0xFFFFFFFF; this->sensor_value_type = SensorValueType::BIT; diff --git a/esphome/components/modbus_controller/select/modbus_select.h b/esphome/components/modbus_controller/select/modbus_select.h index fb9283305c..9a6f71c64b 100644 --- a/esphome/components/modbus_controller/select/modbus_select.h +++ b/esphome/components/modbus_controller/select/modbus_select.h @@ -13,7 +13,7 @@ class ModbusSelect final : public Component, public select::Select, public Senso public: ModbusSelect(SensorValueType sensor_value_type, uint16_t start_address, uint8_t register_count, uint16_t skip_updates, bool force_new_range, std::vector mapping) { - this->register_type = ModbusRegisterType::HOLDING; // not configurable + this->register_type = EntityType::HOLDING; // not configurable this->sensor_value_type = sensor_value_type; this->start_address = start_address; this->offset = 0; // not configurable diff --git a/esphome/components/modbus_controller/sensor/modbus_sensor.h b/esphome/components/modbus_controller/sensor/modbus_sensor.h index ea4f560b9c..d43746e059 100644 --- a/esphome/components/modbus_controller/sensor/modbus_sensor.h +++ b/esphome/components/modbus_controller/sensor/modbus_sensor.h @@ -10,7 +10,7 @@ namespace esphome::modbus_controller { class ModbusSensor final : public Component, public sensor::Sensor, public SensorItem { public: - ModbusSensor(ModbusRegisterType register_type, uint16_t start_address, uint8_t offset, uint32_t bitmask, + ModbusSensor(EntityType register_type, uint16_t start_address, uint8_t offset, uint32_t bitmask, SensorValueType value_type, int register_count, uint16_t skip_updates, bool force_new_range) { this->register_type = register_type; this->start_address = start_address; diff --git a/esphome/components/modbus_controller/switch/modbus_switch.cpp b/esphome/components/modbus_controller/switch/modbus_switch.cpp index c8b3868bdc..2a3737889a 100644 --- a/esphome/components/modbus_controller/switch/modbus_switch.cpp +++ b/esphome/components/modbus_controller/switch/modbus_switch.cpp @@ -30,8 +30,8 @@ bool ModbusSwitch::assumed_state() { return this->assumed_state_; } void ModbusSwitch::parse_and_publish(const std::vector &data) { bool value = false; switch (this->register_type) { - case ModbusRegisterType::DISCRETE_INPUT: - case ModbusRegisterType::COIL: + case EntityType::DISCRETE_INPUT: + case EntityType::COIL: // offset for coil is the actual number of the coil not the byte offset value = modbus::helpers::bit_from_packed(this->offset, data); break; @@ -82,13 +82,13 @@ void ModbusSwitch::write_state(bool state) { format_hex_pretty_to(hex_buf, sizeof(hex_buf), data.data(), data.size())); cmd = ModbusCommandItem::create_custom_command( this->parent_, data, - [this, cmd](ModbusRegisterType register_type, uint16_t start_address, const std::vector &data) { + [this, cmd](EntityType register_type, uint16_t start_address, const std::vector &data) { this->parent_->on_write_register_response(cmd.register_type, this->start_address, data); }); } else { ESP_LOGV(TAG, "write_state '%s': new value = %s type = %d address = %X offset = %x", this->get_name().c_str(), ONOFF(state), (int) this->register_type, this->start_address, this->offset); - if (this->register_type == ModbusRegisterType::COIL) { + if (this->register_type == EntityType::COIL) { // offset for coil and discrete inputs is the coil/register number not bytes if (this->use_write_multiple_) { std::vector states{state}; diff --git a/esphome/components/modbus_controller/switch/modbus_switch.h b/esphome/components/modbus_controller/switch/modbus_switch.h index d6e991582d..82f8fa2a27 100644 --- a/esphome/components/modbus_controller/switch/modbus_switch.h +++ b/esphome/components/modbus_controller/switch/modbus_switch.h @@ -10,7 +10,7 @@ namespace esphome::modbus_controller { class ModbusSwitch final : public Component, public switch_::Switch, public SensorItem { public: - ModbusSwitch(ModbusRegisterType register_type, uint16_t start_address, uint8_t offset, uint32_t bitmask, + ModbusSwitch(EntityType register_type, uint16_t start_address, uint8_t offset, uint32_t bitmask, uint16_t skip_updates, bool force_new_range) { this->register_type = register_type; this->start_address = start_address; @@ -19,7 +19,7 @@ class ModbusSwitch final : public Component, public switch_::Switch, public Sens this->sensor_value_type = SensorValueType::BIT; this->skip_updates = skip_updates; this->register_count = 1; - if (register_type == ModbusRegisterType::HOLDING || register_type == ModbusRegisterType::COIL) { + if (register_type == EntityType::HOLDING || register_type == EntityType::COIL) { this->start_address += offset; this->offset = 0; } diff --git a/esphome/components/modbus_controller/text_sensor/modbus_textsensor.h b/esphome/components/modbus_controller/text_sensor/modbus_textsensor.h index e9130c98d4..05b905312a 100644 --- a/esphome/components/modbus_controller/text_sensor/modbus_textsensor.h +++ b/esphome/components/modbus_controller/text_sensor/modbus_textsensor.h @@ -12,7 +12,7 @@ enum class RawEncoding { NONE = 0, HEXBYTES = 1, COMMA = 2, ANSI = 3 }; class ModbusTextSensor final : public Component, public text_sensor::TextSensor, public SensorItem { public: - ModbusTextSensor(ModbusRegisterType register_type, uint16_t start_address, uint8_t offset, uint8_t register_count, + ModbusTextSensor(EntityType register_type, uint16_t start_address, uint8_t offset, uint8_t register_count, uint16_t response_bytes, RawEncoding encode, uint16_t skip_updates, bool force_new_range) { this->register_type = register_type; this->start_address = start_address; diff --git a/esphome/components/modbus_server/modbus_server.cpp b/esphome/components/modbus_server/modbus_server.cpp index 4c4e72a086..e649635848 100644 --- a/esphome/components/modbus_server/modbus_server.cpp +++ b/esphome/components/modbus_server/modbus_server.cpp @@ -3,7 +3,7 @@ #include "esphome/core/log.h" namespace esphome::modbus_server { -using modbus::ModbusExceptionCode; +using modbus::ExceptionCode; using modbus::helpers::registers_to_number; static const char *const TAG = "modbus_server"; @@ -50,13 +50,13 @@ modbus::ResponseStatus ModbusServer::on_read_registers(uint16_t start_address, u } ESP_LOGW(TAG, "No register at 0x%04X and courtesy default not allowed. Sending exception response.", static_cast(current_address)); - return ModbusExceptionCode::ILLEGAL_DATA_ADDRESS; + return ExceptionCode::ILLEGAL_DATA_ADDRESS; } if (!server_register->read_lambda) { // Registered but not readable (write-only); don't mask it with the courtesy default. ESP_LOGW(TAG, "Register at 0x%04X is not readable. Sending exception response.", server_register->address); - return ModbusExceptionCode::ILLEGAL_DATA_ADDRESS; + return ExceptionCode::ILLEGAL_DATA_ADDRESS; } // A multi-register value is normally atomic: the request must start at its first register and cover all of @@ -72,7 +72,7 @@ modbus::ResponseStatus ModbusServer::on_read_registers(uint16_t start_address, u "Read clips the multi-register value at 0x%04X, which does not allow partial reads. " "Sending exception response.", server_register->address); - return ModbusExceptionCode::ILLEGAL_DATA_ADDRESS; + return ExceptionCode::ILLEGAL_DATA_ADDRESS; } int64_t value = server_register->read_lambda(); @@ -89,7 +89,7 @@ modbus::ResponseStatus ModbusServer::on_read_registers(uint16_t start_address, u // The value encoded to fewer words than its register span (e.g. a RAW register); treat as a device fault. ESP_LOGE(TAG, "Register at 0x%04X did not encode to %u registers", server_register->address, server_register->register_count); - return ModbusExceptionCode::SERVICE_DEVICE_FAILURE; + return ExceptionCode::SERVICE_DEVICE_FAILURE; } for (uint16_t i = 0; i < take; i++) { registers.push_back(value_words[value_offset + i]); @@ -132,7 +132,7 @@ modbus::ResponseStatus ModbusServer::on_write_registers(uint16_t start_address, // so we never apply a partial write before discovering a problem. The commit pass below re-runs // registers_to_number rather than caching the decoded values: using the same function for the check and // the write keeps a single source of truth for the decode bound, independent of how register_count was set. - ModbusExceptionCode precheck = ModbusExceptionCode::ILLEGAL_DATA_ADDRESS; // unmatched or unwritable register + ExceptionCode precheck = ExceptionCode::ILLEGAL_DATA_ADDRESS; // unmatched or unwritable register if (!for_each_register([&precheck, ®isters](ServerRegister *server_register, uint16_t register_offset) -> bool { if (server_register->write_lambda == nullptr) { return false; // unwritable -> ILLEGAL_DATA_ADDRESS @@ -140,7 +140,7 @@ modbus::ResponseStatus ModbusServer::on_write_registers(uint16_t start_address, if (!registers_to_number(registers.data() + register_offset, registers.size() - register_offset, server_register->value_type) .has_value()) { - precheck = ModbusExceptionCode::ILLEGAL_DATA_VALUE; // request doesn't supply the full value + precheck = ExceptionCode::ILLEGAL_DATA_VALUE; // request doesn't supply the full value return false; } return true; @@ -158,7 +158,7 @@ modbus::ResponseStatus ModbusServer::on_write_registers(uint16_t start_address, return server_register->write_lambda(number); })) { ESP_LOGW(TAG, "A register write callback failed mid-sequence; earlier writes were already applied."); - return ModbusExceptionCode::SERVICE_DEVICE_FAILURE; + return ExceptionCode::SERVICE_DEVICE_FAILURE; } // Success: the caller builds the write response (an echo of the request header). diff --git a/tests/components/modbus/modbus_helpers_test.cpp b/tests/components/modbus/modbus_helpers_test.cpp index 30ba12b16b..0cd6ac6693 100644 --- a/tests/components/modbus/modbus_helpers_test.cpp +++ b/tests/components/modbus/modbus_helpers_test.cpp @@ -4,7 +4,7 @@ namespace esphome::modbus::helpers { -using FC = ModbusFunctionCode; +using FC = FunctionCode; // --- server_frame_length --------------------------------------------------- // Frame layout: address(1) + function(1) + ... + CRC(2). Fixtures borrowed from diff --git a/tests/components/modbus_controller/common.yaml b/tests/components/modbus_controller/common.yaml index 51951a4528..aa2855c2b0 100644 --- a/tests/components/modbus_controller/common.yaml +++ b/tests/components/modbus_controller/common.yaml @@ -18,7 +18,7 @@ binary_sensor: modbus_controller_id: modbus_controller1 id: modbus_binary_sensor2 name: Test Binary Sensor with Lambda - register_type: read + register_type: input address: 0x3201 lambda: |- return x; diff --git a/tests/components/modbus_server/modbus_server_test.cpp b/tests/components/modbus_server/modbus_server_test.cpp index d95bb473c9..8c2e1d16d9 100644 --- a/tests/components/modbus_server/modbus_server_test.cpp +++ b/tests/components/modbus_server/modbus_server_test.cpp @@ -4,7 +4,7 @@ namespace esphome::modbus_server { -using modbus::ModbusExceptionCode; +using modbus::ExceptionCode; using modbus::RegisterValues; namespace { @@ -73,7 +73,7 @@ TEST(ModbusServerWrite, UnderSuppliedValueAppliesNothing) { auto status = server.on_write_registers(0x0000, make_registers({0x1111, 0x2222})); ASSERT_TRUE(status.has_value()); if (status.has_value()) - EXPECT_EQ(status.value(), ModbusExceptionCode::ILLEGAL_DATA_VALUE); + EXPECT_EQ(status.value(), ExceptionCode::ILLEGAL_DATA_VALUE); EXPECT_FALSE(word_written); // the writable WORD must NOT have been applied EXPECT_FALSE(dword_written); } @@ -87,7 +87,7 @@ TEST(ModbusServerWrite, UnwritableRegisterRejected) { auto status = server.on_write_registers(0x0000, make_registers({0x1234})); ASSERT_TRUE(status.has_value()); if (status.has_value()) - EXPECT_EQ(status.value(), ModbusExceptionCode::ILLEGAL_DATA_ADDRESS); + EXPECT_EQ(status.value(), ExceptionCode::ILLEGAL_DATA_ADDRESS); } // An address with no registered register yields ILLEGAL_DATA_ADDRESS. @@ -96,7 +96,7 @@ TEST(ModbusServerWrite, UnmatchedAddressRejected) { auto status = server.on_write_registers(0x0005, make_registers({0x1234})); ASSERT_TRUE(status.has_value()); if (status.has_value()) - EXPECT_EQ(status.value(), ModbusExceptionCode::ILLEGAL_DATA_ADDRESS); + EXPECT_EQ(status.value(), ExceptionCode::ILLEGAL_DATA_ADDRESS); } // A write_lambda failing at runtime is the one non-atomic case: the earlier register is already @@ -117,7 +117,7 @@ TEST(ModbusServerWrite, CallbackFailureIsServiceDeviceFailure) { auto status = server.on_write_registers(0x0000, make_registers({0xAAAA, 0xBBBB})); ASSERT_TRUE(status.has_value()); if (status.has_value()) - EXPECT_EQ(status.value(), ModbusExceptionCode::SERVICE_DEVICE_FAILURE); + EXPECT_EQ(status.value(), ExceptionCode::SERVICE_DEVICE_FAILURE); EXPECT_TRUE(first_written); // pre-validation passed, so the first write applied before the failure } @@ -168,7 +168,7 @@ TEST(ModbusServerRead, StartInsideValueRejected) { auto status = server.on_read_registers(0x0011, 1, out); // the second cell of the DWORD ASSERT_TRUE(status.has_value()); if (status.has_value()) - EXPECT_EQ(status.value(), ModbusExceptionCode::ILLEGAL_DATA_ADDRESS); + EXPECT_EQ(status.value(), ExceptionCode::ILLEGAL_DATA_ADDRESS); EXPECT_FALSE(read_called); } @@ -187,7 +187,7 @@ TEST(ModbusServerRead, ClippedTailRejected) { auto status = server.on_read_registers(0x0000, 1, out); // only 1 of the DWORD's 2 registers ASSERT_TRUE(status.has_value()); if (status.has_value()) - EXPECT_EQ(status.value(), ModbusExceptionCode::ILLEGAL_DATA_ADDRESS); + EXPECT_EQ(status.value(), ExceptionCode::ILLEGAL_DATA_ADDRESS); EXPECT_FALSE(read_called); } @@ -203,7 +203,7 @@ TEST(ModbusServerRead, WriteOnlyRegisterRejected) { auto status = server.on_read_registers(0x0000, 1, out); ASSERT_TRUE(status.has_value()); if (status.has_value()) - EXPECT_EQ(status.value(), ModbusExceptionCode::ILLEGAL_DATA_ADDRESS); + EXPECT_EQ(status.value(), ExceptionCode::ILLEGAL_DATA_ADDRESS); } // An unregistered address with courtesy enabled returns the default value for each cell. @@ -227,7 +227,7 @@ TEST(ModbusServerRead, UnregisteredRejectedWithoutCourtesy) { auto status = server.on_read_registers(0x0005, 1, out); ASSERT_TRUE(status.has_value()); if (status.has_value()) - EXPECT_EQ(status.value(), ModbusExceptionCode::ILLEGAL_DATA_ADDRESS); + EXPECT_EQ(status.value(), ExceptionCode::ILLEGAL_DATA_ADDRESS); } // --- partial reads (opt-in) ----------------------------------------------------