Resolving S7-400 AG_LRCV TCP Message Jumbling with CP Cards

David Krause14 min read
S7-400SiemensTroubleshooting
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

Problem Description: Interleaved TCP Frames on S7-400 with AG_LRCV

When an S7-400 CPU (e.g., CPU 414-3 PN/DP, CPU 416-3, CPU 417-4) exchanges data with an external partner (X-COM SYSTEM, third-party SCADA, or vendor instrumentation) over TCP/IP through a CP 443-1 communications processor using the AG_LRCV function block, multiple incoming TCP frames are frequently concatenated into a single receive buffer. The PLC application then cannot determine where one logical message ends and the next one begins, producing what field engineers commonly describe as "jumbled" or interleaved data.

A representative failure case uses the following message stream from the X-COM device:

Message Type Message ID (bytes 0..5) Payload Length (bytes) Cadence
Process 1 6 bytes (unique) 300 Event-driven
Process 2 6 bytes (unique) 10 Event-driven
Process 3 6 bytes (unique) 27 Event-driven
Process 4 6 bytes (unique) 27 Event-driven
Live (heartbeat) 6 bytes (unique) 30 Every 30 s

The engineer provisioned RECV = P#DB2001.DBX0.0 BYTE 444 to cover the worst-case payload (300 + 10 + 27 + 27 + 6-byte IDs + a 30-byte Live frame + TCP framing slack). Even with this oversized buffer, the four process frames and the periodic Live frame are interleaved inside DB2001 in the order the partner sent them rather than in the order the PLC expects.

Field Symptom: NDR (New Data Received) on AG_LRCV toggles TRUE, but parsing logic reading offset 6 onward produces garbage because the 6-byte Message-ID header no longer matches the assumed payload length at that offset.

Root Cause: S7-400 CP TCP Has No True ADHOC Mode

The most common root cause is assuming that AG_LRCV on S7-400 supports the same ADHOC behavior (LEN = 0, "return whatever arrived in one TCP segment") that the open user-communication blocks provide on S7-1200 and S7-1500. On S7-300/400 systems using the CP 443-1, the receive model is fundamentally different.

How AG_LRCV actually behaves on CP 443-1

The AG_LRCV block (FB 12 within the SIMATIC_NET_CP library, STEP 7 V5.6) requests a fixed number of bytes equal to the LEN input from the CP firmware. The CP fills its internal receive mailbox with up to LEN bytes; only after the requested length has been satisfied does the CP raise NDR = TRUE on the PLC side. Multiple TCP segments from the partner are concatenated by the CP up to LEN bytes before the application block sees them.

Consequences:

  • Setting LEN = 0 on a CP 443-1 typically does not deliver an ADHOC frame. CP firmware for S7-400 generally requires LEN > 0. The CP returns ERROR = TRUE, STATUS = W#16#8085 (LEN = 0 not permitted) or simply leaves the job pending indefinitely.
  • If LEN is set to 444 and the partner delivers, say, 300 bytes for Process 1, the CP waits for the remaining 144 bytes before signalling NDR. During that wait, a Live frame (30 bytes) may arrive and be appended to the 300 bytes still pending, producing a 330-byte frame with two concatenated headers.
  • The CP cannot, by itself, demultiplex variable-length messages; it presents a byte stream, not a message stream.

Status codes frequently observed during this fault

STATUS (WORD) Meaning Typical Cause
W#16#0000 Job completed without error Normal NDR completion
W#16#8085 LEN = 0 not allowed on this CP ADHOC mode attempted on CP 443-1
W#16#80A1 Receive buffer too small RECV length < LEN
W#16#80C0 Connection not established TCP partner not connected
W#16#80C3 Connection aborted by partner Partner closed the socket
W#16#80D0 Resource problem on CP Too many parallel AG_LRCV jobs
W#16#8186 Pointer error in RECV Bad P#DB syntax (missing BYTE length)

For the authoritative list, refer to the SIMATIC NET function block online help installed with STEP 7 V5.6 and the Siemens Support entry 79993470 on "How do you program the AG_LSEND/AG_LRCV blocks for data exchange via TCP/IP between S7-300/S7-400 and an external partner?"

Prerequisites Before Changing Code

  1. Confirm the CP type and firmware. Open HW Config in STEP 7 V5.6 and read the order number and firmware of the CP (typical: 6GK7443-1EX30-0XE0 or 6GK7443-1GX30-0XE0). CP firmware prior to V2.x has reduced buffer handling; upgrade to the latest firmware available on the Siemens Industry Online Support portal.
  2. Confirm the library path. The AG_LRCV / AG_LSEND blocks ship in SIMATIC_NET_CP (CP 300/400 family), not in the generic Standard Library > Communication Blocks. Install the SIMATIC NET PC software DVD or the SIMATIC NET library package if the FB does not appear in your program.
  3. Verify the TCP connection configuration in NetPro. Open NetPro, select the CP443-1, add an unspecified TCP connection (or ISO-on-TCP configured as TCP), and confirm the partner IP, partner port, local port, and connection ID. Note the Connection ID value — it is the ID input on AG_LRCV, not the LADDR (hardware ID).
  4. Reserve an exclusive DB for the receive buffer. Use DB2001 with a length ≥ 444 bytes (the recommended minimum is the sum of the longest single message + the longest partner-side TCP segment the OS can deliver, typically 1460 bytes for Ethernet).

Solution A: Byte-by-Byte Streaming Parser (Recommended)

The most robust pattern on S7-400 is to stop trying to align AG_LRCV with logical messages and instead treat the CP as a byte source. Use a small LEN so NDR toggles frequently, then reassemble messages in a dedicated DB by walking the 6-byte ID header.

Step 1 — Configure AG_LRCV for short, frequent reads

Set LEN = 1 on every call (or use LEN = 16 if latency is acceptable and the partner batches small messages). The CP returns every TCP-received byte in roughly real time. Drive EN permanently TRUE and toggle EN_R = TRUE continuously — never gate EN with application conditions; use REQ/EN_R for handshake.

Sample call in STL:

      CALL  FB 12, DB 50      // AG_LRCV instance
       ID    := W#16#0001     // Connection ID from NetPro
       LADDR := W#16#03FF     // HW ID (diagnostics address of CP)
       RECV  := P#DB2100.DBX 0.0 BYTE 16
       NDR   := M 100.0       // New data received
       ERROR := M 100.1       // Error flag
       STATUS:= MW 102        // Status word
       LEN   := 16            // Read up to 16 bytes per job
       EN_R  := TRUE          // Receive enabled
Pointer syntax trap: the Any-pointer RECV must end with the BYTE count. Writing P#DB2001.DBX0.0 without the trailing BYTE n yields STATUS = W#16#8186 (pointer error). Always confirm with ENTER in the LAD/FBD editor that the pointer shows a byte count.

Step 2 — Maintain a streaming buffer in DB2100

Allocate a ring or shift buffer in DB2100 with at least 1024 bytes. On each NDR, copy the freshly received bytes (count returned in LEN) to the next free position. Then run a parser that:

  1. Reads the next 6 bytes as a candidate Message ID.
  2. Looks up the expected payload length for that ID in a lookup table (constant block: 300, 10, 27, 27, or 30 bytes).
  3. If the candidate plus its expected payload is fully present in the buffer, copies the full message (6 + payload) into a per-message output DB (e.g., DB2201..DB2205) and shifts the streaming buffer left by the consumed byte count.
  4. If not yet complete, leaves the bytes in place and waits for the next NDR.

This state machine runs in OB1 (or OB35 at 100 ms for predictable load) and decouples the CP's TCP behavior from the application's logical message view.

Step 3 — Verify with a Hercules TCP test client

Before reconnecting the X-COM SYSTEM, point NetPro at a PC running the free Hercules SETUP utility (or any TCP client) on the partner IP/port. Use it to send:

  • One 300-byte frame with a known ID;
  • One 30-byte frame immediately afterward.

Confirm that the parser populates the correct output DB and that the buffer pointer advances. This isolates PLC code from the partner's behavior while you iterate.

Solution B: Fixed-Length Sizing Per Message Class

If the partner can be reconfigured, the simplest long-term fix is to negotiate a fixed TCP frame size per logical message class. Each logical message becomes either:

  • a 306-byte frame (6-byte ID + 300-byte payload) for Process 1, or
  • separate connections per message type (one TCP connection per ID), or
  • explicit length-prefixed framing with a 4-byte big-endian length header in addition to the 6-byte ID.

With fixed 306-byte frames, LEN = 306 on AG_LRCV produces exactly one logical message per NDR. The Live frame becomes its own 36-byte frame, handled by a second instance of AG_LRCV with LEN = 36 running on a separate unspecified TCP connection defined in NetPro.

This solution is the closest to "drop-in" on existing S7-400 hardware because no streaming parser is needed.

Solution C: Move TCP to the CPU's PN/PN Interface

If the S7-400 CPU is a CPU 41x-3 PN/DP variant (e.g., 6ES7414-3EM07-0AB0, 6ES7416-3ES07-0AB0), it exposes an integrated PROFINET interface. The PN port of the CPU supports the open-communication blocks (TCON, TSEND, TRCV) from the Standard Library > Communication Blocks > TCP. TRCV with LEN = 0 provides genuine ADHOC behavior on the PN port — it returns exactly one TCP segment per NDR regardless of length.

To migrate:

  1. Re-route the Ethernet cable from the CP 443-1 to the CPU PN port (or add a second Ethernet network).
  2. In NetPro, create a new TCP connection on the PN interface instead of the CP.
  3. Replace AG_LRCV with TRCV (FB 63, instance DB) and AG_LSEND with TSEND (FB 64).
  4. Set LEN = 0 on TRCV; the block now hands you one segment per NDR, and your existing 6-byte-ID parser works unchanged.
Note: The integrated PN interface on S7-400 CPUs is not identical to the PN interface on S7-1500. It supports TCP, ISO-on-TCP, and UDP open communication but is limited in the number of connections (typically 16). Confirm against the CPU's technical data in the Siemens S7-400 manual set for your specific order number before committing to this path.

Connection ID Versus Hardware ID — Common Wiring Error

The two ID parameters on AG_LRCV are frequently confused:

Input Meaning Where to find it
ID Connection ID from NetPro NetPro → right-click the connection → "Object Properties" → "General" tab → "Connection ID" field
LADDR Logical base address / diagnostics address of the CP HW Config → CP443-1 → Properties → "Diagnostics Address" (default e.g., 8181 dec = 1FF5 hex, but commonly set to 03FF hex / 1023 dec)

Swapping these is a common cause of STATUS = W#16#80C0 (connection not established) or pending jobs that never complete. Always verify both values in NetPro before commissioning.

Parameter Sanity Checklist

Parameter Required value Common error
ID Hex value from NetPro (e.g., W#16#0001) Using the diagnostics address instead of the connection ID
LADDR Hex value of CP diagnostics address (e.g., W#16#03FF) Leaving at default 0
RECV P#DB2100.DBX0.0 BYTE N with N ≥ LEN Omitting the BYTE N suffix; RECV length < LEN
LEN > 0 for CP 443-1; ≤ length of RECV area Setting LEN = 0 (CP rejects with W#16#8085)
EN_R Continuously TRUE Pulsing EN instead of EN_R; missing retrigger
EN Continuously TRUE (ladder rung) Gating with conditions that lock out the block

Verification Procedure

  1. Open STEP 7 V5.6, go online with the S7-400 station, and place DB2001 (or your streaming buffer DB) in VAT/monitoring. Force LEN = 1 temporarily and trigger a few messages from the partner.
  2. Confirm that NDR toggles repeatedly, that LEN returns the correct number of bytes (typically 1 with LEN = 1), and that ERROR stays FALSE with STATUS = W#16#0000.
  3. Verify the parser output DBs. For each of the five message IDs (4 process + 1 live), confirm that the payload bytes match what the partner sent (compare against Hercules or Wireshark capture).
  4. Capture a parallel Wireshark trace on the partner side to confirm that no TCP retransmits or segment coalescing is occurring at the network layer. The PLC behavior should now match the wire-level behavior.
  5. Run a 24-hour soak test with the partner sending the full mix of messages at the normal cadence, including the 30-second Live frame. Monitor the buffer underflow/overflow counters and the parser's "messages rejected" counter (implement one for diagnostics).

Troubleshooting Matrix

Observed Symptom Likely Cause Fix
NDR never goes TRUE, ERROR = TRUE, STATUS = W#16#8085 LEN = 0 used on CP 443-1 Set LEN > 0 or move to Solution C (PN port with TRCV)
NDR TRUE but only after long delays, with concatenated frames LEN set to sum of all messages; CP waits for full fill Reduce LEN to expected single-frame size; implement streaming parser (Solution A)
ERROR = TRUE, STATUS = W#16#8186 RECV Any-pointer syntax error Use P#DB2100.DBX0.0 BYTE N with explicit N
ERROR = TRUE, STATUS = W#16#80C0 ID/LADDR swapped or wrong connection Re-verify Connection ID in NetPro vs ID input; set LADDR to diagnostics address
First frame correct, subsequent frames offset Parser not advancing buffer pointer Confirm consumed-bytes math matches ID + payload length
Live (30-byte) frames missing during high process traffic Process frames monopolizing the receive buffer Use separate TCP connection for Live frames (Solution B)
Works on bench, fails when CP443-1 hot-swapped CP firmware mismatch after replacement Match firmware version; re-download NetPro connection config

Safety and Operational Considerations

The X-COM SYSTEM messages in the original case include a 30-second Live frame that is presumably a keep-alive or watchdog. If the PLC stops parsing for any reason — buffer overrun, scan-time spike, CP firmware bug — the partner's watchdog will eventually flag a communication loss and may stop transmitting process data. Always implement:

  • A "Live frame received within 60 s" boolean that the parser maintains; expose it to the HMI as a comms-health indicator.
  • A buffer-overflow alarm that triggers when the streaming buffer exceeds 80% capacity.
  • A fallback path: if the parser fails to consume three consecutive Live frames, switch the partner connection to a secondary PLC or raise an operator alarm.

Notes on ADHOC Documentation

Siemens' open-communication documentation explicitly defines ADHOC mode only for S7-1200/1500 and for the PN interface of S7-400 CPUs. The CP 443-1 firmware does not implement LEN = 0. Any application that relies on ADHOC behavior on an S7-400 + CP 443-1 must be rewritten as a streaming parser or moved to a hardware path that supports ADHOC. The Siemens Support entry 79993470 cited in the field discussion is the canonical reference for the supported LEN values and pointer conventions.

Why does AG_LRCV concatenate two TCP frames on my S7-400 with CP 443-1?

Because the CP 443-1 firmware does not support ADHOC mode (LEN = 0). It waits until either LEN bytes have been received or its internal segment buffer is full, then signals NDR once. Any TCP segments that arrived in the meantime are concatenated. Reduce LEN to a small value (e.g., 1 or 16) and run a streaming parser in the PLC that reassembles messages from the 6-byte ID header.

Can I use LEN = 0 on AG_LRCV with CP 443-1 for true ADHOC?

No. CP 443-1 firmware rejects LEN = 0 with STATUS = W#16#8085. True ADHOC is supported only on the integrated PN interface of S7-1200/1500 CPUs and on the PN interface of CPU 41x-3 PN/DP variants, using the TRCV block (FB 63) from the Standard Library.

How do I distinguish the Connection ID from the Hardware ID on AG_LRCV?

The ID input (W#16#xxxx) is the connection identifier assigned by NetPro when you create the TCP connection. The LADDR input is the logical/diagnostics base address of the CP module, read from HW Config (commonly W#16#03FF / 1023 dec). The two are independent values; swapping them is a leading cause of STATUS = W#16#80C0 errors.

Why am I getting STATUS W#16#8186 on AG_LRCV?

STATUS 8186 means the RECV Any-pointer is malformed. In STEP 7 V5.6 the correct form is P#DB2100.DBX0.0 BYTE 100 — the BYTE n suffix is mandatory. If you omit it or specify a length smaller than LEN, the CP rejects the job.

Should I use EN or EN_R on AG_LRCV to start a receive?

Use EN_R. EN should remain permanently TRUE so the FB is always scheduled; the receive job is gated by EN_R (rising edge starts a new receive) or held continuously for streaming reception. Pulsing EN interrupts the FB instance and is a common reason jobs never complete.

Is it better to add a second AG_LRCV for the Live (30-byte) frame?

If the partner supports a second TCP connection, yes. Use one unspecified TCP connection per logical message class in NetPro, each with its own Connection ID, and bind a separate AG_LRCV instance with the matching LEN. This avoids interleaving entirely and keeps each receive deterministic.

What is the maximum buffer size I should set for AG_LRCV?

Match it to LEN, not to a guessed "worst case". A RECV area much larger than LEN is wasted DB space; a RECV area smaller than LEN produces STATUS = W#16#80A1. For a streaming parser, allocate a separate large DB (≥1024 bytes) for the rolling buffer and keep the AG_LRCV RECV area small.

Back to blog