Skip to content

Add S7CommPlus protocol scaffolding for S7-1200/1500#603

Open
gijzelaerr wants to merge 12 commits intomasterfrom
s7commplus-scaffolding
Open

Add S7CommPlus protocol scaffolding for S7-1200/1500#603
gijzelaerr wants to merge 12 commits intomasterfrom
s7commplus-scaffolding

Conversation

@gijzelaerr
Copy link
Owner

@gijzelaerr gijzelaerr commented Feb 28, 2026

Summary

Adds the snap7.s7commplus package for S7CommPlus protocol support, targeting S7-1200/1500 PLCs across all protocol versions (V1/V2/V3/TLS). Includes a functional server emulator, sync client, async client, and 111 passing tests.

Architecture

Module Description Status
protocol.py Protocol constants: opcodes, function codes, data types, element IDs, soft data types Complete
vlq.py Variable-Length Quantity encoding/decoding (32/64-bit, signed/unsigned) Complete
codec.py Frame headers, request/response headers, typed value serialization Complete
server.py PLC emulator with data blocks, named variables, session management, multi-client Complete (V1)
client.py Sync client: db_read, db_write, db_read_multi, explore Complete (V1)
async_client.py Async client with asyncio.Lock for concurrent safety Complete (V1)
connection.py Multi-version connection with COTP/TPKT transport Complete (V1)

Server emulator

The server emulates an S7-1200/1500 PLC with:

  • Data blocks with named variables and type metadata (register_db())
  • Thread-safe memory model with per-block locking
  • S7CommPlus protocol handling: CreateObject, DeleteObject, Explore, GetMultiVariables, SetMultiVariables
  • Multi-client support (threaded, each client gets a unique session ID)
  • CPU state management (Run/Stop)
server = S7CommPlusServer()
server.register_db(1, {
    "temperature": ("Real", 0),
    "pressure": ("Real", 4),
    "running": ("Bool", 8),
})
server.start(port=11020)

Protocol version support

Version Target PLCs Authentication Status
V1 S7-1200 FW V4.0+ Trivial anti-replay Working
V2 S7-1200/1500 older FW Proprietary HMAC-SHA256/AES Planned
V3 S7-1200/1500 pre-V17 ECC key exchange Planned
V3+TLS TIA Portal V17+ Standard TLS 1.3 Planned

The wire protocol (VLQ, data types, object model) is identical across all versions -- only the session authentication layer differs.

Tests (111 total)

  • 62 VLQ tests: Boundary values, roundtrips, signed/unsigned, 32/64-bit
  • 24 codec tests: Frame headers, request headers, fixed-width, typed values, strings
  • 7 server unit tests: Data blocks, named variables, CPU state, edge cases
  • 11 sync client integration tests: Connect, read, write, multi-read, explore, persistence, concurrent clients
  • 7 async client integration tests: Connect, read, write, concurrent reads with Lock

Test plan

  • 111 passing tests (VLQ, codec, server unit, sync integration, async integration)
  • Ruff lint passes
  • Existing test suite unaffected
  • Server handles multiple concurrent clients with unique sessions
  • Data persists across client sessions
  • Async Lock serializes concurrent reads correctly

🤖 Generated with Claude Code

gijzelaerr and others added 2 commits February 28, 2026 13:16
Adds the snap7.s7commplus package as a foundation for future S7CommPlus
protocol support, targeting all S7-1200/1500 PLCs (V1/V2/V3/TLS).

Includes:
- Protocol constants (opcodes, function codes, data types, element IDs)
- VLQ encoding/decoding (Variable-Length Quantity, the S7CommPlus wire format)
- Codec for frame headers, request/response headers, and typed values
- Connection skeleton with multi-version support (V1/V2/V3/TLS)
- Client stub with symbolic variable access API
- 86 passing tests for VLQ and codec modules

The wire protocol (VLQ, data types, object model) is the same across all
protocol versions -- only the session authentication layer differs. The
protocol version is auto-detected from the PLC's CreateObject response.

Reference: thomas-v2/S7CommPlusDriver (C#, LGPL-3.0)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server emulator (snap7/s7commplus/server.py):
- Full PLC memory model with thread-safe data blocks
- Named variable registration with type metadata
- Handles CreateObject/DeleteObject session management
- Handles Explore (browse registered DBs and variables)
- Handles GetMultiVariables/SetMultiVariables (read/write)
- Multi-client support (threaded)
- CPU state management

Async client (snap7/s7commplus/async_client.py):
- asyncio-based S7CommPlus client with Lock for concurrent safety
- Same API as sync client: db_read, db_write, db_read_multi, explore
- Native COTP/TPKT transport using asyncio streams

Updated sync client and connection to be functional for V1:
- CreateObject/DeleteObject session lifecycle
- Send/receive with S7CommPlus framing over COTP/TPKT
- db_read, db_write, db_read_multi operations

Integration tests (25 new tests):
- Server unit tests (data blocks, variables, CPU state)
- Sync client <-> server: connect, read, write, multi-read, explore
- Async client <-> server: connect, read, write, concurrent reads
- Data persistence across client sessions
- Multiple concurrent clients with unique sessions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
gijzelaerr and others added 10 commits February 28, 2026 13:35
Reframe protocol version descriptions around interoperability rather
than security vulnerabilities. Remove CVE references and replace
implementation-specific language with neutral terminology.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rewrite async tests to use asyncio.run() instead of @pytest.mark.asyncio
since pytest-asyncio is not a project dependency. Also apply ruff
formatting fixes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add pytest-asyncio to test dependencies and set asyncio_mode=auto.
Restore async test methods with @pytest.mark.asyncio instead of
asyncio.run() wrappers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix ruff formatting violations and mypy type errors in S7CommPlus code
that caused pre-commit CI to fail. Add end-to-end test suite for
validating S7CommPlus against a real S7-1200/1500 PLC.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…sync client improvements

Support bytes-type remote TSAP (e.g. "SIMATIC-ROOT-HMI") in ISOTCPConnection,
extend S7CommPlus protocol handling, and improve async client and server emulator.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… diagnostics

Adds hex dumps and detailed parsing at every protocol layer (ISO-TCP,
S7CommPlus connection, client) plus 6 new diagnostic e2e tests that
probe different payload formats and function codes against real hardware.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rewrite client payload encoding/decoding to use the correct S7CommPlus
protocol format with ItemAddress structures (SymbolCrc, AccessArea,
AccessSubArea, LIDs), ObjectQualifier, and proper PValue response
parsing. Previously the client used a simplified custom format that
only worked with the emulated server, causing ERROR2 responses from
real S7-1200/1500 PLCs.

- client.py: Correct GetMultiVariables/SetMultiVariables request format
- async_client.py: Reuse corrected payload builders from client.py
- codec.py: Add ItemAddress, ObjectQualifier, PValue encode/decode
- protocol.py: Add Ids constants (DB_ACCESS_AREA_BASE, etc.)
- server.py: Update to parse/generate the corrected wire format

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
S7CommPlus protocol uses 1-based LID byte offsets, but the client was
sending 0-based offsets. This caused real PLCs to reject all db_read
and db_write requests. Also fixes lint issues in e2e test file.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement the missing SetMultiVariables session handshake step that echoes
ServerSessionVersion (attr 306) back to the PLC after CreateObject. Without
this, PLCs reject data operations with ERROR2 (0x05A9).

For PLCs that don't provide ServerSessionVersion or don't support S7CommPlus
data operations, the client transparently falls back to the legacy S7 protocol.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…network interfaces

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant