Resolving Siemens LCOM TCP/IP Send Buffer Mismatch on S7-1500

David Krause17 min read
Industrial NetworkingSiemensTroubleshooting
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

Symptom: Unintended Payload Bytes on the PC Client

A common field report with the Siemens LCOM TCP/IP library on a SIMATIC S7-1500 server presents as follows: the S7-1500 CPU is configured as a TCP server, the PC application is the client, and the controller is wired to the network correctly. The PC receives data on the configured local port, the receive direction works, and the TCP socket itself is healthy. However, the payload bytes the PC reads off the socket are not the bytes that the user wrote into the LCOM send buffer on the PLC side. The end of the payload contains values that were never assigned in the project — random-looking or repeating patterns pulled from adjacent memory.

This is not a wire problem, a routing problem, or a firewall problem. The socket is open, the bytes are flowing, and the PC receives exactly the number of bytes the PLC says it is sending. The defect is in the way the LCOM send block is parameterised, specifically in the relationship between the declared array size in the instance data block and the length of the data actually being transmitted. When the two values disagree, the LCOM send block reads past the end of the user buffer and frames whatever happens to be in the next memory region as if it were legitimate payload.

Field signature: The PC receives a payload that is longer than the user buffer or whose last N bytes are clearly not from the application. The receive side returns no error code. The TCP socket does not disconnect. Only the payload contents are wrong.

LCOM Library Architecture Overview

The LCOM library is a Siemens-supplied function-block family for Ethernet-based TCP and UDP communication on SIMATIC S7-300, S7-400, S7-1200, and S7-1500 controllers. It is distributed as a global library that can be opened in TIA Portal or in the legacy STEP 7 environments, depending on the revision. The library is provided as an application example to demonstrate native TCP/UDP socket usage on top of the SIMATIC communication firmware and is documented alongside the SIMATIC S7-1500 Communication Function Manual.

The library typically ships the following building blocks (block names and exact catalog are revision-specific, but the functional split is stable across versions):

  • Connection management blocks: open, close, and supervise a TCP or UDP socket bound to a configured local port on the CPU.
  • Send block: copies the user payload from a referenced data area into the TCP send queue and triggers the lower-layer TSEND.
  • Receive block: processes incoming bytes from the lower-layer TRCV and stores them into a referenced data area.
  • Status / diagnostic block: surfaces connection state, error codes, and handshake progress to the user program.
  • Template block: a thin wrapper that exposes the underlying TCON/TSEND/TRCV system blocks with minimal additional framing — useful when the user wants a pure socket without the LCOM header.

Two characteristics of the LCOM blocks drive most of the buffer-related defects seen in the field:

  1. A header is prepended to every send frame. The header carries length, connection, and protocol-state information that the matching LCOM receive block on the peer side uses to reconstruct the stream. The PC client does not use the LCOM receive block, so it must strip the header itself, or it must use the template variant which does not add a header.
  2. The send block reads exactly the number of bytes that the user tells it to send, starting at the start address of the referenced data area. If the referenced area is smaller than the number of bytes requested, the firmware reads beyond the array boundary.

Root Cause: Array Size vs. Requested Length

The defect in the source incident traces directly to a buffer-sizing error. The user's data block contained an array whose element count was 18 bytes maximum — that is, a static ARRAY[0..17] OF BYTE or similar short buffer — but the LCOM send block was parameterised with a length of 100 bytes. The send block, instructed to transmit 100 bytes from the buffer's start address, dutifully read 100 bytes. The first 18 bytes were the user's application data; the remaining 82 bytes were whatever sat in the next 82 byte positions of the load memory, which on a freshly written data block is typically zeros or the previous-cycle remnants of an unrelated tag.

From the PC's perspective, the socket behaved correctly, the PLC reported a successful send, and the PC received exactly 100 bytes. The user only noticed the defect because the last 82 bytes did not match the application. The fix was to set the array length to match the data length — to resize the array to 100 elements and let the application populate all 100 of them — or alternatively, to lower the LEN parameter of the send block to match the actual useful payload.

Key invariant: For every LCOM send call, the byte length passed to the send block's LEN input must be less than or equal to the byte width of the referenced buffer. The PC will receive exactly LEN + LCOM header size bytes, regardless of what the buffer actually contains.

How the LCOM Header Changes the Calculation

On the wire, the LCOM send block emits a small protocol header before the user payload. The header typically includes connection identifier bytes, a length field, and protocol-state flags. The exact format is documented in the LCOM library reference that ships with the blocks; it is not an open standard, and it is not the same as a standard TCP framing such as RFC 1006 (ISO-on-TCP) or Modbus TCP's MBAP header.

This has two practical consequences for the PC client programmer:

  1. The PC must know the header size and strip it before handing the remaining bytes to the application. A common mistake is to assume that the first byte of the LCOM stream is application data, which causes the first few bytes of every message to be lost and the message alignment to drift by the header size on every receive.
  2. The header contains a length field that tells the peer how many payload bytes follow. If the PC does not parse this length field, it cannot tell where one LCOM frame ends and the next begins, and it will read across frame boundaries, mixing two messages into one.

If the user does not want to deal with the LCOM header at all, the template block family is the recommended alternative. The template block exposes a near-raw TCP socket with diagnostics; the user reads and writes bytes without the LCOM framing layer. The trade-off is that the diagnostics surface and the connection-state supervision in the template block are less polished than in the full LCOM blocks, which is why most production deployments use the full LCOM library and write a small header-stripping parser on the PC side.

Pre-Diagnostic Checklist

Before touching the block parameters, run the following sanity checks. They are quick, they rule out the easy non-LCOM causes, and they make the rest of the diagnostic flow much shorter.

  1. Confirm the socket is open. On the S7-1500, the connection-management block of the LCOM library exposes a connection-state output (commonly a BOOL or an enum). Verify that it transitions to "connected" or equivalent before the send block is called.
  2. Confirm the local port is correct. The CPU's local port, the client port on the PC, and the firewall rules on the PC must all match. Use a packet capture to verify the three-way handshake completes — SYN, SYN-ACK, ACK — between the PC and the CPU IP.
  3. Confirm the receive direction is healthy. If the receive path returns errors, the LCOM handshake is not complete and the send path is not in a defined state. Fix receive first.
  4. Confirm the S7-1500 firmware supports the LCOM version in use. Older LCOM revisions were written against S7-300/S7-400 firmwares. While the blocks can be installed on S7-1500, some versions are not optimised for it and may exhibit diagnostic gaps.

Step-by-Step Resolution Procedure

Follow this procedure in order. The first three steps resolve the specific defect in the source incident; the remaining steps harden the deployment against the same class of error in the future.

Step 1: Inspect the Declared Array in the Instance Data Block

Open the LCOM instance data block in TIA Portal. Locate the array that backs the send buffer. Note its declared element count and its element type. For a ARRAY[0..N] OF BYTE, the maximum payload is N+1 bytes. For arrays of larger types, multiply: an ARRAY[0..9] OF WORD holds 20 bytes, an ARRAY[0..4] OF DWORD holds 20 bytes, and so on.

Step 2: Inspect the LEN Input of the LCOM Send Block

Open the LCOM send block's instance and read the LEN input. This is the number of payload bytes the block will request from TSEND. It must be less than or equal to the byte width of the array from Step 1. If the LEN input is a variable, scan the user program for the statement that writes to it; a constant or a tag-typed length parameter that does not match the array is the typical root cause.

Step 3: Resize the Array or Adjust the Length

Choose one of the two paths below, and apply the change consistently across every call site that writes into the buffer or reads from the LEN tag.

  • Path A — Resize the array up: declare a new ARRAY[0..99] OF BYTE (matching a 100-byte LEN) and update every user assignment to populate bytes 0 through 99. This is the correct path when the application genuinely needs to transmit 100 bytes.
  • Path B — Reduce the LEN input: keep the original 18-element array and lower the LEN parameter of the send block to 18. This is the correct path when the application only ever has 18 bytes of meaningful data and the higher LEN was a copy-paste error.

Do not change both at once. Pick one direction, rebuild, download, and verify on the PC before optimising further.

Step 4: Recompile, Download, and Restart the PLC

After changing the array bounds or the LEN tag, perform a full download of the program blocks and the data blocks to the S7-1500. Re-initialise the data block if the array bounds changed, because leftover data in the now-larger region will otherwise be transmitted on the first send. Restart the LCOM connection-management block to re-establish the socket.

Step 5: Capture the Wire

On the PC, attach a packet capture utility and filter to the TCP stream between the PC IP and the CPU IP. Verify that the first few bytes of every PC-bound segment are the LCOM header, that the header length field matches the number of payload bytes that follow, and that the payload contents match the application's view of the array.

Step 6: Validate End-to-End

Send a known sentinel pattern from the PLC — for example, write 0x01..0x64 into the array and trigger a single send. On the PC, read the receive buffer, strip the LCOM header, and verify that the remaining bytes are exactly 0x01..0x64. This is the only test that proves the full path is correct.

Buffer Sizing Reference Table

Use this table to translate between common S7-1500 array declarations and the maximum payload that can be safely sent through LCOM. The LCOM header is on top of the array byte width and is not included in these numbers.

Declaration Element count Byte width Max payload (bytes) LEN input value
ARRAY[0..17] OF BYTE 18 18 18 18
ARRAY[0..99] OF BYTE 100 100 100 100
ARRAY[0..9] OF WORD 10 20 20 20
ARRAY[0..4] OF DWORD 5 20 20 20
ARRAY[0..1] OF LREAL 2 16 16 16
ARRAY[0..0..511] OF BYTE 512 512 512 512

General formula:

max_payload_bytes = SUM over i of (element_count_i × sizeof(element_type_i))

For a homogeneous array of N elements of type T:

max_payload_bytes = N × sizeof(T)

Verifying the Receive Path on the PC

Once the PLC side is corrected, the PC client must be audited as well. Three classes of PC-side defect are common companions to the LCOM buffer-sizing error:

  1. Receiving into a buffer that is too small. The PC application allocates a receive buffer of 18 bytes but the LCOM frame is 100 + header bytes. The PC's TCP stack truncates or splits the message, and the application misinterprets subsequent messages. The fix is to size the PC receive buffer to LEN_payload + LCOM_header + slack.
  2. Reading before the full message has arrived. TCP is a stream protocol. A single LCOM message may arrive in multiple recv() calls, or two messages may arrive in a single call. The PC must use the LCOM header's length field to buffer bytes until a complete message has been assembled, then process the whole message atomically.
  3. Ignoring the LCOM header. If the PC application feeds the first byte of the LCOM stream directly into the application parser, message corruption will look like PLC-side garbage, but the PLC is actually correct. The header must be parsed and discarded before application processing.

For TCP-level diagnosis on the PC, attach a network capture utility and filter to the conversation between the PC and the CPU. This is the only way to see exactly what the PLC transmitted and to distinguish a PLC-side buffer defect from a PC-side framing defect. Microsoft's TCP/IP troubleshooting guidance provides a useful methodology for distinguishing network-layer from application-layer issues when the socket itself is healthy.

Choosing Between LCOM, LCOM Template, and Native TCON/TSEND/TRCV

LCOM is one of three common ways to expose a TCP server on an S7-1500. The other two are the LCOM template block family and the native Open User Communication blocks (TCON, TSEND, TRCV, TDISCON) that ship with the S7-1500 firmware. The choice depends on what the PC client expects and how much LCOM-specific framing the application is willing to absorb.

Aspect LCOM (full library) LCOM template Native TCON/TSEND/TRCV
Header on the wire Yes (LCOM-specific) No No (raw TCP) or RFC 1006 (ISO-on-TCP)
PC client complexity High — must parse LCOM header Low — pure byte stream Lowest — standard TCP
PLC-side diagnostics Rich (state, error, supervision) Moderate Moderate (status word per FB)
Buffer-sizing risk High (buffer vs. LEN mismatch common) High (same root cause applies) High (LEN to TSEND must match buffer)
Suitable for heterogeneous clients No — LCOM is a Siemens protocol Yes Yes
Library version dependency Yes — LCOM rev must match CPU firmware Yes No — built into firmware

Recommendation: If the PC client is a third-party application with no Siemens libraries, prefer the LCOM template or native TCON/TSEND/TRCV. If the PC client is part of a Siemens ecosystem or is custom-written in C# or Python, the full LCOM library's diagnostics are valuable, but plan to invest time in the PC-side header parser. In all cases, allocate the PLC-side array with a fixed, known, application-wide size and pass the same value to the LEN input; never let the array dimension and the LEN parameter be set independently.

Troubleshooting Matrix

Symptom Likely cause First check Fix
PC receives N + extra bytes, extras look like zeros Array smaller than LEN Compare DB array bounds to send LEN Resize array to LEN, or lower LEN to array width
PC receives N + extra bytes, extras are repeating pattern Array smaller than LEN, DB region uninitialised Inspect DB online Same as above, then re-initialise DB
PC receives N bytes but the first few are wrong LCOM header not stripped on PC Capture wire, look at first bytes Implement LCOM header parser on PC
PC receives bursts of bytes with no message boundaries PC not using LCOM length field Capture wire, look at header Buffer until LCOM length is satisfied
PLC reports send error 80C3 / similar Connection not established Check connection state on PLC Fix receive path, verify port, verify firewall
PC connects, receives nothing PLC side not transmitting Check trigger logic on PLC Trigger send on connection-established edge
Works on first send, fails on second Connection not re-established after disconnect Check connection state machine Implement reconnect logic in connection-management block

Best Practices for LCOM TCP Deployments

  1. Centralise the buffer length in one tag. Use a single constant or variable — never a magic number at the call site — to define the LEN passed to the send block. Reference the same tag when sizing the array in the DB. This eliminates the buffer-vs-length mismatch class of errors at compile time.
  2. Initialise the buffer on first use. When the array is resized up, populate the new region with a known pattern (typically zero) on cold restart, or use a FILL_BLK call in the startup OB. Otherwise, the first send after a download will transmit pre-download memory contents.
  3. Validate the receive path on the PC with a wire capture before commissioning the PLC code. A simple PC test client that sends known bytes over a loopback, plus a capture filter on the conversation, establishes a baseline of what the PC parser must do. Once the PC is correct, the PLC side is much easier to debug.
  4. Document the LCOM header format on the PC side. The LCOM header is not an open standard; the only authoritative description is the documentation that ships with the LCOM library revision in use. Keep a copy of that documentation with the PC source code so that future maintainers do not have to re-derive the framing.
  5. Add a length cross-check on the PC. The LCOM header's length field should equal the number of payload bytes that follow. If they disagree, log the anomaly and drop the message. This protects against silent corruption from future LCOM revisions or from PC-side buffer overruns.
  6. Use connection supervision on the PLC. The full LCOM library exposes a connection-state output. Subscribe to it in the user program and use its falling edge to re-initialise the send buffer and reset the LEN counter, so a stale buffer is not transmitted after a reconnect.

Verification Checklist

After applying the resolution, run through this checklist. Every item must be green before the deployment is considered stable.

  • DB array element count matches LEN input to the send block.
  • Wire capture shows LCOM header followed by exactly the application payload, with no trailing bytes.
  • PC parser strips the LCOM header and delivers payload bytes to the application unchanged.
  • PC parser uses the LCOM length field to assemble complete messages from TCP segments.
  • PC receive buffer is sized to at least (LEN_payload + LCOM_header + 32 bytes slack).
  • Reconnect path is tested: kill the socket from the PC, verify the PLC re-establishes, verify the buffer is re-initialised on the new connection.
  • Connection-state supervision is wired into the user program; the send block is not called when the connection is not in the established state.

FAQ

Why is the S7-1500 sending bytes that I never wrote into my DB?

Your LCOM send block is configured to send more bytes than the size of the array in the instance data block. The block reads that many bytes from the start of the array, including the memory immediately after the array. Match the array element count to the LEN input — for a 100-byte payload, declare an ARRAY[0..99] OF BYTE and populate bytes 0 through 99.

Does the LCOM library add a header to every TCP send?

Yes, the full LCOM block family prepends an LCOM-specific header that carries length, connection, and protocol-state information. The PC client must parse and discard this header before processing the payload. If you want a raw byte stream, use the LCOM template block or the native TCON/TSEND/TRCV system blocks instead.

How do I know what my LCOM header looks like on the wire?

Capture the TCP stream with a packet-capture utility filtered to the PC-to-CPU conversation. The header is the first few bytes of every PC-bound segment, immediately before the user payload. The LCOM library documentation that ships with your specific library revision is the authoritative description of the header format and is the only source to reference when implementing the PC parser.

Can I use LCOM on an S7-1500 with the PC as a TCP client?

Yes. Configure the S7-1500 as the TCP server by setting the active/passive connection establishment bit in the connection-management block so that the CPU listens on a configured local port. The PC opens the socket to the CPU IP and port, and once the connection is established, both directions carry data through the LCOM send and receive blocks.

What is the difference between the LCOM full library and the LCOM template block?

The full LCOM library adds a Siemens-specific header to every frame and provides a richer diagnostics surface. The template block exposes a near-raw TCP socket with minimal additional framing, which is easier to interoperate with third-party clients that do not want to parse the LCOM header. The trade-off is less detailed diagnostics on the PLC side.

Back to blog