From b521b5e1cafb075e361d8e57f2445d6388bb832f Mon Sep 17 00:00:00 2001 From: Marek Pilch <47844572+marpi82@users.noreply.github.com> Date: Wed, 5 Aug 2026 20:47:48 +0200 Subject: [PATCH] [modbus_server] Add tests for U_WORD_S and S_WORD_S (#17832) Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com> --- .../modbus_server/test_modbus_server.py | 2 + tests/components/modbus_server/common.yaml | 8 ++++ .../modbus_server/modbus_server_test.cpp | 28 +++++++++++++ .../uart_mock_modbus_server_controller.yaml | 24 +++++++++++ ...t_mock_modbus_server_controller_write.yaml | 42 +++++++++++++++++++ tests/integration/test_uart_mock_modbus.py | 7 +++- 6 files changed, 110 insertions(+), 1 deletion(-) diff --git a/tests/component_tests/modbus_server/test_modbus_server.py b/tests/component_tests/modbus_server/test_modbus_server.py index 7c978a5cd5..3e041c6d4a 100644 --- a/tests/component_tests/modbus_server/test_modbus_server.py +++ b/tests/component_tests/modbus_server/test_modbus_server.py @@ -82,3 +82,5 @@ def test_raw_value_type_rejected() -> None: with pytest.raises(cv.Invalid): validator("RAW") assert validator("U_WORD") == "U_WORD" + assert validator("U_WORD_S") == "U_WORD_S" + assert validator("S_WORD_S") == "S_WORD_S" diff --git a/tests/components/modbus_server/common.yaml b/tests/components/modbus_server/common.yaml index 8b2316b6e3..1f3a8f551b 100644 --- a/tests/components/modbus_server/common.yaml +++ b/tests/components/modbus_server/common.yaml @@ -40,3 +40,11 @@ modbus_server: value_type: U_WORD read_lambda: |- return (random_uint32() % 100); + # Covers CPP_TYPE_REGISTER_MAP / signed byte-swapped codegen + - address: 0x6 + value_type: S_WORD_S + read_lambda: |- + return -2; + write_lambda: |- + printf("address=%d, value=%d\n", (int) address, (int) x); + return true; diff --git a/tests/components/modbus_server/modbus_server_test.cpp b/tests/components/modbus_server/modbus_server_test.cpp index 8c2e1d16d9..2137a77f3d 100644 --- a/tests/components/modbus_server/modbus_server_test.cpp +++ b/tests/components/modbus_server/modbus_server_test.cpp @@ -34,6 +34,21 @@ TEST(ModbusServerWrite, SingleWordSucceeds) { EXPECT_EQ(written, 0x1234); } +TEST(ModbusServerWrite, SwappedWordSucceeds) { + ModbusServer server; + int64_t written = -1; + ServerRegister reg(0x0000, SensorValueType::U_WORD_S, 1); + reg.write_lambda = [&written](int64_t value) { + written = value; + return true; + }; + server.add_server_register(®); + + auto status = server.on_write_registers(0x0000, make_registers({0x3412})); + EXPECT_FALSE(status.has_value()); + EXPECT_EQ(written, 0x1234); +} + // A multi-register value is decoded high word first and applied as a single number. TEST(ModbusServerWrite, DwordSucceeds) { ModbusServer server; @@ -136,6 +151,19 @@ TEST(ModbusServerRead, SingleWordSucceeds) { EXPECT_EQ(out[0], 0x1234); } +TEST(ModbusServerRead, SwappedWordReturnsByteSwappedRegister) { + ModbusServer server; + ServerRegister reg(0x0000, SensorValueType::U_WORD_S, 1); + reg.read_lambda = []() -> int64_t { return 0x1234; }; + server.add_server_register(®); + + RegisterValues out; + auto status = server.on_read_registers(0x0000, 1, out); + EXPECT_FALSE(status.has_value()); + ASSERT_EQ(out.size(), 1u); + EXPECT_EQ(out[0], 0x3412); +} + TEST(ModbusServerRead, DwordReturnsTwoWordsHighFirst) { ModbusServer server; ServerRegister reg(0x0000, SensorValueType::U_DWORD, 2); diff --git a/tests/integration/fixtures/uart_mock_modbus_server_controller.yaml b/tests/integration/fixtures/uart_mock_modbus_server_controller.yaml index 20306bd73a..4a5d280a2f 100644 --- a/tests/integration/fixtures/uart_mock_modbus_server_controller.yaml +++ b/tests/integration/fixtures/uart_mock_modbus_server_controller.yaml @@ -64,9 +64,15 @@ modbus_server: - address: 0x01 value_type: U_WORD read_lambda: return 99; + - address: 0x02 + value_type: U_WORD_S + read_lambda: return 4660; - address: 0x03 value_type: S_WORD read_lambda: return -99; + - address: 0x04 + value_type: S_WORD_S + read_lambda: return -2; - address: 0x05 value_type: U_DWORD read_lambda: return 16909060; @@ -105,12 +111,30 @@ sensor: address: 0x01 register_type: holding value_type: U_WORD + - platform: modbus_controller + modbus_controller_id: modbus_controller_1 + name: "reg_u_word_s" + address: 0x02 + register_type: holding + value_type: U_WORD_S + - platform: modbus_controller + modbus_controller_id: modbus_controller_1 + name: "reg_u_word_s_raw" + address: 0x02 + register_type: holding + value_type: U_WORD - platform: modbus_controller modbus_controller_id: modbus_controller_1 name: "reg_s_word" address: 0x03 register_type: holding value_type: S_WORD + - platform: modbus_controller + modbus_controller_id: modbus_controller_1 + name: "reg_s_word_s" + address: 0x04 + register_type: holding + value_type: S_WORD_S - platform: modbus_controller modbus_controller_id: modbus_controller_1 name: "reg_u_dword" diff --git a/tests/integration/fixtures/uart_mock_modbus_server_controller_write.yaml b/tests/integration/fixtures/uart_mock_modbus_server_controller_write.yaml index b3b5e76e31..5ade49bd48 100644 --- a/tests/integration/fixtures/uart_mock_modbus_server_controller_write.yaml +++ b/tests/integration/fixtures/uart_mock_modbus_server_controller_write.yaml @@ -45,9 +45,15 @@ globals: - id: stored_u_word type: uint16_t initial_value: "11" + - id: stored_u_word_s + type: uint16_t + initial_value: "4660" - id: stored_s_word type: int16_t initial_value: "-11" + - id: stored_s_word_s + type: int16_t + initial_value: "-2" - id: stored_u_dword type: uint32_t initial_value: "1001" @@ -103,10 +109,18 @@ modbus_server: value_type: U_WORD read_lambda: return id(stored_u_word); write_lambda: id(stored_u_word) = x; return true; + - address: 0x02 + value_type: U_WORD_S + read_lambda: return id(stored_u_word_s); + write_lambda: id(stored_u_word_s) = x; return true; - address: 0x03 value_type: S_WORD read_lambda: return id(stored_s_word); write_lambda: id(stored_s_word) = x; return true; + - address: 0x04 + value_type: S_WORD_S + read_lambda: return id(stored_s_word_s); + write_lambda: id(stored_s_word_s) = x; return true; - address: 0x05 value_type: U_DWORD read_lambda: return id(stored_u_dword); @@ -155,12 +169,24 @@ sensor: address: 0x01 register_type: holding value_type: U_WORD + - platform: modbus_controller + modbus_controller_id: modbus_controller_1 + name: "reg_u_word_s" + address: 0x02 + register_type: holding + value_type: U_WORD_S - platform: modbus_controller modbus_controller_id: modbus_controller_1 name: "reg_s_word" address: 0x03 register_type: holding value_type: S_WORD + - platform: modbus_controller + modbus_controller_id: modbus_controller_1 + name: "reg_s_word_s" + address: 0x04 + register_type: holding + value_type: S_WORD_S - platform: modbus_controller modbus_controller_id: modbus_controller_1 name: "reg_u_dword" @@ -231,6 +257,14 @@ number: value_type: U_WORD min_value: 0 max_value: 65535 + - platform: modbus_controller + modbus_controller_id: modbus_controller_1 + name: "write_u_word_s" + address: 0x02 + register_type: holding + value_type: U_WORD_S + min_value: 0 + max_value: 65535 - platform: modbus_controller modbus_controller_id: modbus_controller_1 name: "write_s_word" @@ -239,6 +273,14 @@ number: value_type: S_WORD min_value: -16777215 max_value: 16777215 + - platform: modbus_controller + modbus_controller_id: modbus_controller_1 + name: "write_s_word_s" + address: 0x04 + register_type: holding + value_type: S_WORD_S + min_value: -16777215 + max_value: 16777215 - platform: modbus_controller modbus_controller_id: modbus_controller_1 name: "write_u_dword" diff --git a/tests/integration/test_uart_mock_modbus.py b/tests/integration/test_uart_mock_modbus.py index f1106f1c77..202fbe3f9c 100644 --- a/tests/integration/test_uart_mock_modbus.py +++ b/tests/integration/test_uart_mock_modbus.py @@ -215,7 +215,10 @@ async def test_uart_mock_modbus_server_controller( expected_values = { "reg_u_word": 99, + "reg_u_word_s": 4660, + "reg_u_word_s_raw": 13330, "reg_s_word": -99, + "reg_s_word_s": -2, "reg_u_dword": 16909060, "reg_s_dword": -16909060, "reg_u_dword_r": pytest.approx(67305985), @@ -249,14 +252,16 @@ async def test_uart_mock_modbus_server_controller_write( Verifies that writing to modbus server registers via the controller updates the server's stored values, which are then read back correctly on the next poll. - All 12 value types are tested: U/S_WORD, U/S_DWORD(_R), U/S_QWORD(_R), FP32(_R). + All 14 value types are tested: U/S_WORD, U/S_WORD_S, U/S_DWORD(_R), U/S_QWORD(_R), FP32(_R). """ line_callback, error_log_lines, warning_log_lines = _make_modbus_line_callback() register_test_cases: dict[str, RegisterTestCase] = { "reg_u_word": RegisterTestCase(11, "write_u_word", 42, 42), + "reg_u_word_s": RegisterTestCase(4660, "write_u_word_s", 17185, 17185), "reg_s_word": RegisterTestCase(-11, "write_s_word", -42, -42), + "reg_s_word_s": RegisterTestCase(-2, "write_s_word_s", -257, -257), "reg_u_dword": RegisterTestCase(1001, "write_u_dword", 2002, 2002), "reg_s_dword": RegisterTestCase(-1001, "write_s_dword", -2002, -2002), "reg_u_dword_r": RegisterTestCase(3003, "write_u_dword_r", 4004, 4004),