Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions s7/_s7commplus_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,7 @@ def _build_read_payload(items: list[tuple[int, int, int]]) -> bytes:
for addr in addresses:
payload += addr
payload += encode_object_qualifier()
payload += encode_uint32_vlq(1)
payload += struct.pack(">I", 0)

return bytes(payload)
Expand Down Expand Up @@ -580,6 +581,7 @@ def _build_write_payload(items: list[tuple[int, int, bytes]]) -> bytes:
payload += encode_pvalue_blob(data)
payload += bytes([0x00])
payload += encode_object_qualifier()
payload += encode_uint32_vlq(1)
payload += struct.pack(">I", 0)

return bytes(payload)
Expand Down Expand Up @@ -632,6 +634,7 @@ def _build_area_read_payload(area_rid: int, start: int, size: int) -> bytes:
payload += encode_uint32_vlq(field_count)
payload += addr_bytes
payload += encode_object_qualifier()
payload += encode_uint32_vlq(1)
payload += struct.pack(">I", 0)
return bytes(payload)

Expand All @@ -653,6 +656,7 @@ def _build_area_write_payload(area_rid: int, start: int, data: bytes) -> bytes:
payload += encode_pvalue_blob(data)
payload += bytes([0x00])
payload += encode_object_qualifier()
payload += encode_uint32_vlq(1)
payload += struct.pack(">I", 0)
return bytes(payload)

Expand Down Expand Up @@ -685,6 +689,7 @@ def _build_symbolic_read_payload(access_area: int, lids: list[int], symbol_crc:
payload += encode_uint32_vlq(field_count)
payload += addr_bytes
payload += encode_object_qualifier()
payload += encode_uint32_vlq(1)
payload += struct.pack(">I", 0)
return bytes(payload)

Expand Down Expand Up @@ -712,6 +717,7 @@ def _build_symbolic_write_payload(access_area: int, lids: list[int], data: bytes
payload += encode_pvalue_blob(data)
payload += bytes([0x00])
payload += encode_object_qualifier()
payload += encode_uint32_vlq(1)
payload += struct.pack(">I", 0)
return bytes(payload)

Expand Down
52 changes: 52 additions & 0 deletions tests/test_s7_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,29 @@
_parse_read_response,
_build_write_payload,
_parse_write_response,
<<<<<<< HEAD
_build_explore_request,
_parse_explore_datablocks,
||||||| parent of 22a5c08 (fix: add SequenceNumber to Get/SetMultiVariables payloads (#738))
=======
_build_area_read_payload,
_build_area_write_payload,
_build_symbolic_read_payload,
_build_symbolic_write_payload,
>>>>>>> 22a5c08 (fix: add SequenceNumber to Get/SetMultiVariables payloads (#738))
)
<<<<<<< HEAD
from s7.connection import S7CommPlusConnection
from s7.codec import encode_pvalue_blob
from s7.codec import _pvalue_element_size as _element_size
from s7.codec import skip_typed_value, parse_server_session_version
||||||| parent of 22a5c08 (fix: add SequenceNumber to Get/SetMultiVariables payloads (#738))
from s7.codec import encode_pvalue_blob
from s7.connection import S7CommPlusConnection, _element_size
=======
from s7.codec import encode_object_qualifier, encode_pvalue_blob
from s7.connection import S7CommPlusConnection, _element_size
>>>>>>> 22a5c08 (fix: add SequenceNumber to Get/SetMultiVariables payloads (#738))
from s7.protocol import DataType, ElementID, ObjectId
from s7.vlq import (
encode_uint32_vlq,
Expand Down Expand Up @@ -194,6 +210,42 @@ def test_write_read_consistency(self) -> None:
assert isinstance(write_payload, bytes)


class TestSequenceNumber:
"""Verify all payload builders include a SequenceNumber after ObjectQualifier."""

@staticmethod
def _has_sequence_number(payload: bytes) -> bool:
oq = encode_object_qualifier()
idx = bytes(payload).find(oq)
assert idx >= 0, "ObjectQualifier not found in payload"
seq_offset = idx + len(oq)
return payload[seq_offset : seq_offset + 1] == encode_uint32_vlq(1)

def test_read_payload_has_sequence_number(self) -> None:
payload = _build_read_payload([(1, 0, 4)])
assert self._has_sequence_number(payload)

def test_write_payload_has_sequence_number(self) -> None:
payload = _build_write_payload([(1, 0, bytes([1, 2, 3, 4]))])
assert self._has_sequence_number(payload)

def test_area_read_payload_has_sequence_number(self) -> None:
payload = _build_area_read_payload(82, 0, 4)
assert self._has_sequence_number(payload)

def test_area_write_payload_has_sequence_number(self) -> None:
payload = _build_area_write_payload(82, 0, b"\x00\x00\x00\x00")
assert self._has_sequence_number(payload)

def test_symbolic_read_payload_has_sequence_number(self) -> None:
payload = _build_symbolic_read_payload(0x8A0E0001, [1, 4])
assert self._has_sequence_number(payload)

def test_symbolic_write_payload_has_sequence_number(self) -> None:
payload = _build_symbolic_write_payload(0x8A0E0001, [1, 4], b"\x01")
assert self._has_sequence_number(payload)


# -- Connection unit tests --


Expand Down
Loading