Problem Description: TRCV Hangs After Soft CPU Reboot
An S7-1200 CPU configured as an Open User Communication (OUC) TCP client using the legacy TCON + TSEND + TRCV instruction triplet can establish a session to a remote PC server (Java, C#, Python, or LabVIEW socket listener) on first power-up, but fails to recover when the PLC performs a soft reboot — an initialization cycle triggered by an HMI button, a recipe change, or a user logic reset, not a STOP/RUN transition. The CPU does not toggle the RUN/STOP LED, no diagnostic buffer entry is generated, yet the TRCV instruction remains in BUSY = 1 and never returns a frame even though the PC server reports that the socket remains open and is still transmitting.
Symptom summary observed in the field:
- First connection after power-on: OK (data is received,
RCVD_LENincrements, noERRORbit). - Soft reboot is executed (e.g.
RESTARTOB call, RUN-to-RUN transition triggered by SFC, or a self-initiated re-initialization routine). - PC server logs: connection from PLC IP, then periodic
send()calls succeed at socket level. - PLC side:
TRCVstays inBUSY = 1,DONE = 0,ERROR = 0indefinitely. No data ever appears in the receive area. -
TCONreportsSTATUS = 0000_0000(idle, not connected) or stuck inSTATUS = 7000_0000(no job pending) depending on the watchdog timing.
Attempting a manual reconnection sequence — energizing TDISCON, waiting for DONE or ERROR, then re-energizing TCON.REQ — does not clear the fault. The connection is marked established on the PC side, but no TCP traffic is observed on Wireshark captures from the PLC switch port for the receive direction.
Root Cause Analysis
The failure is rooted in how the legacy TCON / TRCV pair manages the internal connection table on firmware versions prior to the TSEND_C auto-state machine, combined with the one-cycle visibility of the STATUS output of the Open User Communication blocks. Two distinct issues overlap in this scenario:
Issue 1: TCON Does Not Re-Arm After Soft Reboot
The S7-1200 maintains the OUC connection descriptor in a non-retentive work memory area that is re-initialized only on STOP→RUN or power-cycle. A soft reboot — for example, calling RESTART in OB100 or a logic-driven initialization that re-runs OB1 from the top without STOP→RUN — does not invalidate the connection ID entry the way a hard reset does. The TCON block returns STATUS = 0000_0000 because it considers the connection slot empty, but the underlying CP socket layer still owns the TCP handle. When the user code then re-triggers TCON.REQ, the CP layer rejects the bind request with an internal W#16#80E2-class error that is immediately overwritten on the next scan because the STATUS output is only valid for one cycle (see Issue 2). The visible result is a silent hang.
Reference: Siemens KB 109744220 — Open User Communication: STATUS of TCON/TRCV/TDISCON only valid in one cycle.
Issue 2: STATUS/ERROR Are One-Cycle Diagnostics
For all blocks in the OUC family (TCON, TDISCON, TSEND, TRCV, TUSEND, TURCV), the STATUS and ERROR outputs are non-retentive and overwritten every scan. Reading them with an HMI tag without a mirroring tag in a global DB or M-area means the engineer is reading 16#0000_0000 99% of the time, even when a real error was raised the cycle before. This is the single most common cause of “TRCV hangs with no error” reports.
Reference: Siemens KB 109751826 — Why does the TRCV block show STATUS = 0 even though the connection is broken?
Issue 3: Asymmetric T-Block Pairing
When the engineer wrote the original code, TCON was used to open the connection, then TSEND and TRCV were used independently for send/receive. This pattern is documented but fragile: TCON must complete (DONE = 1) before TRCV is enabled, otherwise TRCV enters W#16#80C8 (“Connection not established”) which is then lost to the one-cycle STATUS issue. A single FB (TSEND_C) bundles the connection state machine with the send and receive calls, eliminating the hand-off race.
Diagnostic Procedure
Before changing the code, capture the actual error class. The following procedure is what the original poster did not do and is the recommended first step in any OUC hang.
- Create a global DB named
DB_OUC_Diagwith twoDWORDtags:lastTrcvStatusandlastTconStatus. - In OB1, after each OUC block call, copy the
STATUSoutput to the corresponding DB tag using a simple MOVE. Do not read theSTATUStag from the HMI without this mirror. - Add the mirror tags to an HMI watch table or a Web Server user-defined page for live observation.
- Trigger the soft reboot and observe the captured
STATUScodes in the cycle following the failure. Typical signatures for this scenario include:-
W#16#80E2— Connection ID already in use / resource busy. -
W#16#80C3— Connection terminated by remote (server closed). -
W#16#80B0— No free connection resource. -
W#16#80A1— Connection or channel error.
-
- Cross-check with Wireshark (port mirror on the switch): look for SYN without SYN-ACK, FIN without close, or RST from the PLC after the soft reboot.
Solution: Replace TCON/TRCV With TSEND_C
The verified workaround — confirmed by the original poster and consistent with Siemens’ recommended migration path — is to abandon the manual TCON+TRCV pattern and use the consolidated TSEND_C FB. The TSEND_C instruction internally manages the connection state, handles the TCON bind, the TRCV polling, and the TDISCON teardown in a single state machine that is re-entrant across soft reboots.
Why TSEND_C Survives the Soft Reboot
The TSEND_C FB stores its state in the instance DB, which is retained across a RUN-to-RUN cycle as long as the DB is configured as non-optimized (or accessible via “Set in IDB”). On a soft reboot, the instance is re-initialized to the idle state and the connection is reopened by the internal state machine, producing a fresh SYN that the PC server accepts. The CP-layer stale-handle problem that affects the legacy triplet does not occur because the new bind goes through the same descriptor TSEND_C owns.
Implementation in TIA Portal V15.1 to V18
The following step-by-step migration keeps the existing connection description in the Connection properties DB and replaces only the FBs in OB1. It is valid for CPU firmware V4.2 and later (S7-1200, part numbers 6ES721x-1xxxxx-0XB0 with FW V4.2 to V4.6).
-
Open the project in TIA Portal, expand Program blocks, and locate the existing
TCON,TSEND,TRCVinstances. -
Right-click the program block folder → Add new block → Standard → Communications → TSEND_C. Place it as
FB_OUCin OB1 with instance DBDB_OUC_IDB(auto-numbered). - Open the Properties of the new TSEND_C instance and configure:
-
REQ— a pulse from your initialization logic; rising edge triggers a send. Tie to a “send on change” trigger or a periodic pulse (e.g. clock bit from_1sin the system clock). -
CONT—TRUEto keep the connection open after each send. -
LEN— fixed length matching the PC server protocol (typical: 32, 64, 128 bytes). For variable-length frames, useLEN = 0and rely on theNDR(New Data Received) output. -
DATA— point to a standard access DB or P# pointer to a data block. If using optimized access, ensure the DB has the “Accessible from HMI” attribute. -
CONNECT— reuse theTCON_ParamUDT or build a new one. Active connection = TRUE for the PLC as client.RemoteAddress = '192.168.0.50',RemotePort = 2000,LocalPort = 0(any).
-
-
Delete the legacy
TCON,TSEND,TRCV, andTDISCONinstances to avoid descriptor collisions. -
Add a STATUS mirror:
// OB1, network 10 L "FB_OUC".STATUS T "DB_OUC_Diag".lastStatus // DWORD - Compile and download with “Download to device → All” (do not do a software reset on download; that will mask the fix).
- Trigger the soft reboot and watch the PC server log: the connection is dropped and a new TCP session is established within 2–5 s.
Example: TSEND_C Interface in Structured Text (SCL)
The SCL source for the call, suitable for an S7-1200 with firmware V4.4 and TIA Portal V17 or later, is shown below. This is the exact pattern that resolved the field case.
// FB_OUC wrapper, SCL
DATA_BLOCK "DB_OUC_IDB"
{ S7_Optimized_Access := 'TRUE' }
BEGIN
END_DATA_BLOCK
FUNCTION_BLOCK "FB_OUC"
VAR
bInitDone : BOOL;
bSendTrig : BOOL;
diRxLen : DINT;
tRstTimer : TON_TIME;
END_VAR
BEGIN
// State 0: Wait for first init
IF NOT bInitDone THEN
"FB_TSEND_C".REQ := FALSE;
"FB_TSEND_C".CONT := TRUE;
"FB_TSEND_C".LEN := 32;
"FB_TSEND_C".DATA := P#DB_OUC.TxBuffer DBW 0 BYTE 32;
// CONNECT is configured in the instance properties
bInitDone := TRUE;
END_IF;
// Periodic send pulse (1 Hz) for heartbeat
bSendTrig := "Clock_1Hz" AND NOT "bPrev1Hz";
"bPrev1Hz" := "Clock_1Hz";
"FB_TSEND_C".REQ := bSendTrig;
// Mirror status for diagnostics
"DB_OUC_Diag".lastStatus := "FB_TSEND_C".STATUS;
"DB_OUC_Diag".busy := "FB_TSEND_C".BUSY;
"DB_OUC_Diag".error := "FB_TSEND_C".ERROR;
"DB_OUC_Diag".done := "FB_TSEND_C".DONE;
"DB_OUC_Diag".ndr := "FB_TSEND_C".NDR;
// Capture received length
IF "FB_TSEND_C".NDR THEN
diRxLen := DWORD_TO_DINT("FB_TSEND_C".RCVD_LEN);
"DB_OUC_Diag".lastRxLen := diRxLen;
END_IF;
END_FUNCTION_BLOCK
Ladder Logic Alternative (TIA Portal V15.1)
For engineers on the classic LAD editor without SCL, the equivalent call is a single network with the TSEND_C instance:
Network 5: TSEND_C call
"Tag_SendTrig" ---|"| |----+----( "FB_TSEND_C".REQ )
|
TRUE ---------|" |----( "FB_TSEND_C".CONT )
|
32 ---------|-/P-+----( "FB_TSEND_C".LEN )
Receive data is automatically written to the configured DATA range; no separate TRCV call is needed.
Status Code Reference for OUC Blocks
The following table covers the status codes most commonly encountered during a soft-reboot reconnection failure on the S7-1200 platform. All values are 16-bit in the lower word of the STATUS DWORD; the upper word is reserved.
| STATUS (hex) | Block | Meaning | Field Action |
|---|---|---|---|
| 0000_0000 | All | No error / no job active | Normal idle state. |
| 7000_0000 | TRCV / TCON | No job pending (initial state) | Ensure REQ is pulsed. |
| 7001_0000 | TRCV | Receive started, waiting for data | Normal; do not re-trigger. |
| 7002_0000 | TRCV | Receive in progress, data incoming | Wait for NDR or ERROR. |
| 7003_0000 | TCON | Connection establishment in progress | Wait for DONE. |
| 80A1_0000 | All | Connection or channel error (e.g. partner closed) | Issue TDISCON, then TCON or rely on TSEND_C auto-reconnect. |
| 80A7_0000 | TRCV / TSEND | Partner initiated disconnect (FIN received) | Same as above; TSEND_C handles it automatically. |
| 80B0_0000 | TCON | No free connection resource | Reduce simultaneous connections; max 8 per CPU on V4.x. |
| 80C3_0000 | TCON | Connection terminated by remote | Re-arm with TDISCON + TCON, or migrate to TSEND_C. |
| 80C8_0000 | TRCV | Connection not established | Check TCON status; check CONNECT UDT fields. |
| 80E2_0000 | TCON | Connection ID already in use / internal resource busy | Re-arm after TDISCON, or migrate to TSEND_C (root cause of this article). |
| 80E3_0000 | TDISCON | Disconnect in progress | Wait for DONE. |
| 80FF_0000 | All | Internal CP error / firmware fault | Power-cycle CPU; check firmware version. |
Verification Procedure
- With the new
TSEND_Ccode loaded, place the CPU in RUN. - Confirm a TCP session to the PC server is established (Wireshark or netstat on the server).
- Trigger the soft reboot via your HMI button or
RESTARTcall. - Within 2–5 s, observe in Wireshark: a
FIN, ACKfrom the PLC, followed by a freshSYNfrom the PLC and aSYN, ACKfrom the server. - On the server, confirm the new client port and the heartbeat payload is being received.
- Check
DB_OUC_Diag.lastStatus— it should be7001_0000(receive started) or0000_0000(idle between sends), not80A1or80E2. - Run a 24-hour soak test with a soft-reboot triggered every 30 minutes; log the
lastStatusandlastRxLento confirm no degradation.
Edge Cases and Additional Caveats
Firmware-Specific Behavior
S7-1200 CPUs with firmware V4.0 to V4.1 do not support TSEND_C in the same consolidated form; on those platforms, the recommended pattern is a periodic TDISCON-then-TCON cycle driven by a watchdog timer. Reference: Siemens FAQ 67364622 — Open User Communication with S7-1200.
Keep-Alive vs Soft Reboot
The PLC does not emit TCP keep-alives by default. If the PC server has an idle-timeout of 60 s and the PLC only sends every 5 minutes, the server will close the socket while the PLC is still in 7001_0000 state. Add a 10-s heartbeat in the application layer, or enable the “Keep alive” parameter in the TCON_Param UDT (field “ActiveEstablishment” plus the keep-alive interval, supported on FW V4.3+).
Multiple Soft Reboots in Quick Succession
If your user logic re-initializes more than once per second, the CP layer will reject the second bind with W#16#80B0 (no free resource). Insert a 2-s TON timer between initialization cycles; this is the minimum recovery time for the internal TCP close-handshake on the S7-1200.
Replacing TCON With TSEND_C on a Live System
The migration requires a STOP→RUN transition once, because the connection descriptor must be cleared from the work memory. Plan a 30-s outage. After the first RUN, no further restarts are required for reconnection logic.
Troubleshooting Matrix
| Symptom | First-Cycle STATUS (mirrored) | Wireshark Signature | Likely Root Cause | Fix |
|---|---|---|---|---|
| TRCV hangs after soft reboot, no error visible | 80E2_0000 then 0000 | No SYN after FIN | Stale CP handle; legacy TCON+TRCV pattern | Migrate to TSEND_C (this article’s scenario) |
| Connection establishes, then server logs “client closed” after 60 s | 80A7_0000 | FIN from PLC, no further SYN | Server idle timeout, no app-layer heartbeat | Add 10-s heartbeat; enable keep-alive in CONNECT UDT |
| TRCV reports “data” but buffer is zeroed | 7002_0000 | Normal traffic | DATA pointer overlap or DB optimized-access mismatch | Use standard-access DB for DATA pointer |
| Status always 0000 even on fault | 0000_0000 (read late) | Any | STATUS one-cycle visibility | Mirror STATUS to a global DB tag |
| TSEND_C “DONE” never sets | 7003_0000 | SYN without SYN-ACK | Firewall on PC or wrong IP/port | Disable Windows firewall rule for inbound 2000/TCP; verify IP |
| Multiple soft reboots, second one fails | 80B0_0000 | SYN retransmit | Re-arming too fast | Add 2-s TON between init cycles |
Why the STATUS-Mirror Pattern Is Non-Negotiable
Even after migrating to TSEND_C, the diagnostic mirror in DB_OUC_Diag must remain. The STATUS output of TSEND_C is subject to the same one-cycle visibility rule. A Siemens support entry states explicitly: “the parameter ERROR, STATUS etc shows the value only for its own cycle. You have to copy the DWORD of STATUS in another memory to analyze the error code.” Without the mirror, a future firmware update or a new error condition will produce the same “no error” mystery the original poster encountered.
Alternative Controller Platforms (Cross-Reference)
For engineers who may need to replicate this pattern on other Siemens families:
-
S7-1500: The same
TSEND_C/TRCV_Cpattern applies, but the consolidated block is namedTRCV_Cfor receive-dominant flows. State machine is identical. Reference: Siemens KB 109768639. - ET 200SP CPU: Identical to S7-1500, FW V2.5 and later. Uses the same instruction set.
-
S7-300/400: No
TSEND_C; useTCON+TRCVfrom the standard library. The hang behavior is similar and requires the periodic disconnect/connect pattern.
Field-Proven Commissioning Checklist
- Confirm CPU firmware ≥ V4.2 (use Online → Diagnostics → CPU Information).
- Configure the
CONNECTUDT in theTSEND_Cinstance withActiveEstablished = TRUE(PLC is client). - Set
LocalPort = 0to let the CPU assign an ephemeral port; the PC server identifies the PLC by IP only. - Set
RemotePortto a fixed value on the server (e.g. 2000) and disable the server-side idle timeout or extend it to >5 minutes. - Enable Web Server on the CPU (default port 80) to view the mirrored
DB_OUC_Diagfrom a browser — useful for remote troubleshooting without TIA Portal. - Add the
DB_OUC_Diagtags to a watch table in TIA Portal and pin them for permanent online monitoring. - Document the soft-reboot trigger path (HMI tag, OB100, or application) so the same sequence can be replayed in QA.
Why does my S7-1200 TRCV block show STATUS = 0 even though the TCP connection is broken?
The STATUS output of all Open User Communication blocks (TCON, TDISCON, TSEND, TRCV, TSEND_C) is valid for one scan cycle only. If you read it from an HMI or watch table after that cycle, you will see W#16#0000_0000. Mirror STATUS to a global DB tag immediately after the block call to capture transient errors.
How do I re-establish a TCP connection after a soft reboot on the S7-1200 without stopping the CPU?
Replace the legacy TCON + TSEND + TRCV + TDISCON instruction set with the consolidated TSEND_C block. TSEND_C contains an internal state machine that re-arms the connection on every RUN transition, including soft reboots, without requiring the user to manually pulse TDISCON and TCON.
What STATUS code indicates the connection ID is already in use after a soft reboot?
W#16#80E2_0000 on TCON indicates that the connection descriptor in the CP layer still holds a stale TCP handle from the previous session. This is the root cause of the “TRCV hangs after soft reboot” symptom and is the specific code the original poster missed because it was overwritten on the next scan.
Does TSEND_C work on S7-1200 firmware V4.0 or V4.1?
No. TSEND_C in its consolidated form requires S7-1200 firmware V4.2 or later (6ES721x-1xxxxx-0XB0 with FW V4.2+). On V4.0/V4.1 you must use the legacy TCON + TRCV pattern with a periodic TDISCON/TCON watchdog cycle.
How many simultaneous TCP connections does an S7-1200 support?
The S7-1200 CPU supports up to 8 Open User Communication connections (active, passive, or mixed) on firmware V4.x. Exceeding this limit returns W#16#80B0_0000 on TCON. For more connections, add a CP 1243-1 or CP 1242-7 communications processor.