Skip to content

Commit f241c35

Browse files
committed
fix: use correct sub_area (3736) for I/Q/M controller-area symbolic access
CONTROLLER_AREA_VALUE_ACTUAL was 2551, which is actually DB_InitialChanged, not a controller-area sub-area. As a result the PLC rejected every symbolic read/write to I/Q/M areas (read -> item ReturnValue error; write -> 0x4D0013). ControllerArea_ValueActual is 3736 (0xE98). Correcting the constant fixes both _build_symbolic_read_payload and _build_symbolic_write_payload, which select it for access_area < 0x8A0E0000. Verified on a real S7-1500 (CPU 1507S F soft-controller, FW V2.x) over TLS: I/Q/M symbolic reads now succeed; values match an independent C# S7CommPlusDriver dump. Same root cause as upstream #736. Adds regression tests pinning the constant and the sub_area chosen by the read/write payload builders for controller vs DB areas. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent f943844 commit f241c35

2 files changed

Lines changed: 35 additions & 1 deletion

File tree

s7/protocol.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,11 @@ class Ids(IntEnum):
152152

153153
# Data block access sub-areas
154154
DB_VALUE_ACTUAL = 2550
155-
CONTROLLER_AREA_VALUE_ACTUAL = 2551
155+
# Symbolic (LID-based) access to controller areas (I/Q/M). The previous value
156+
# 2551 was wrong: 2551 is DB_InitialChanged, not a controller-area sub-area, so
157+
# the PLC rejected every I/Q/M symbolic read/write. ControllerArea_ValueActual
158+
# is 3736 (0xE98). Ref: thomas-v2/S7CommPlusDriver/Core/Ids.cs.
159+
CONTROLLER_AREA_VALUE_ACTUAL = 3736
156160

157161
# ObjectQualifier structure IDs
158162
OBJECT_QUALIFIER = 1256

tests/test_s7_codec.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
)
3838
from s7.protocol import PROTOCOL_ID, DataType, Opcode, FunctionCode, Ids
3939
from s7.vlq import encode_uint32_vlq, encode_int32_vlq, encode_uint64_vlq, encode_int64_vlq
40+
from s7._s7commplus_client import _build_symbolic_read_payload, _build_symbolic_write_payload
4041

4142

4243
class TestFrameHeader:
@@ -357,6 +358,35 @@ def test_custom_symbol_crc(self) -> None:
357358
assert field_count == 4
358359

359360

361+
class TestControllerAreaSubArea:
362+
"""Regression: I/Q/M symbolic access must use ControllerArea_ValueActual (3736).
363+
364+
The earlier value 2551 was DB_InitialChanged, not a controller-area sub-area,
365+
so the PLC rejected every I/Q/M symbolic read/write.
366+
"""
367+
368+
# IArea/QArea/MArea native-object RIDs (all < 0x8A0E0000 → controller-area path)
369+
IAREA_RID = 0x50
370+
371+
def test_constant_value(self) -> None:
372+
assert Ids.CONTROLLER_AREA_VALUE_ACTUAL == 3736
373+
assert Ids.CONTROLLER_AREA_VALUE_ACTUAL != Ids.DB_VALUE_ACTUAL
374+
375+
def test_read_payload_uses_controller_sub_area(self) -> None:
376+
payload = _build_symbolic_read_payload(self.IAREA_RID, lids=[0x124])
377+
assert encode_uint32_vlq(3736) in payload
378+
assert encode_uint32_vlq(2551) not in payload
379+
380+
def test_write_payload_uses_controller_sub_area(self) -> None:
381+
payload = _build_symbolic_write_payload(self.IAREA_RID, lids=[0x124], data=b"\x01")
382+
assert encode_uint32_vlq(3736) in payload
383+
assert encode_uint32_vlq(2551) not in payload
384+
385+
def test_db_area_still_uses_db_sub_area(self) -> None:
386+
payload = _build_symbolic_read_payload(0x8A0E012C, lids=[0x4E, 0x69])
387+
assert encode_uint32_vlq(Ids.DB_VALUE_ACTUAL) in payload
388+
389+
360390
class TestPValueBlob:
361391
def test_basic_blob(self) -> None:
362392
data = bytes([1, 2, 3, 4])

0 commit comments

Comments
 (0)