Problem Overview
Engineers configuring Open UDP communication between a Siemens SIMATIC S7-400 CPU and a third-party sensor — most commonly a Leuze barcode reader, distance sensor, or RFID reader — using the standard Open Communication blocks (FB65 TCON, FB66 TDISCON, FB67 TUSEND, FB68 TURCV) frequently encounter a stuck-state condition that suggests the UDP "connection" has never been established. The TCON instance DB shows DONE=0, BUSY=1, ERROR=0, STATUS=7002H on every cycle, and the active_est bit inside the UDT65 TCON_Param structure never transitions to TRUE even when the initial value is preset. A subsequent attempt to repeat TCON or to send data via TUSEND then returns STATUS=80B5H. This article documents the root cause, the correct parameterization of UDT65 for UDP, the meaning of every status code encountered, and the verification procedure required for S7-400 Open UDP against a Leuze or equivalent UDP endpoint.
For the reference network the addressing is fixed as:
- S7-400 CPU IP/port: 192.168.1.1:2801
- Leuze sensor IP/port: 192.168.1.209:3601
- CPU: 414-3 PN/DP (6ES7 414-3EM07-0AB0, firmware V6.0.7)
- FB65 TCON → DONE=0, BUSY=1, ERROR=0, STATUS=7002H (repeating every cycle)
- UDT65
active_est= FALSE despite the initial value being TRUE - UDT65
local_tsap_idorrem_staddrfields appear unmodified - Second TCON call → DONE=0, BUSY=0, ERROR=1, STATUS=80B5H
- FB67 TUSEND never increments its DONE flag; no UDP datagram leaves the CPU
Hardware and Software Stack
The configuration described here applies to any SIMATIC S7-400 CPU with integrated PN interface or with an external CP443-1. The Open Communication blocks FB65 through FB68 are part of the standard STEP 7 V5.x library "SIMATIC_NET_CP" and have been delivered with every release since STEP 7 V5.0. There is no firmware-specific behavior change in the Open Communication blocks between CPU firmware V4.x and V6.x; differences appear only in the supported maximum number of simultaneous connections (currently 16 for the integrated PROFINET interface of CPU 414-3 PN/DP). Reference documentation is available in the Siemens Industry Online Support at support.industry.siemens.com.
| Component | Specification | Notes |
|---|---|---|
| CPU | SIMATIC S7-400 CPU 414-3 PN/DP | Order number 6ES7 414-3EM07-0AB0 (or -0AB10) |
| Firmware | V6.0.5 or later | Open UDP requires minimum firmware V5.1 on CPU 414-3 PN/DP |
| STEP 7 | STEP 7 V5.5 SP4 or later (TIA Portal V14+ also supported) | Library "SIMATIC_NET_CP" or "Communication Blocks" |
| Function blocks | FB65 TCON, FB66 TDISCON, FB67 TUSEND, FB68 TURCV | UDT65 (TCON_Param), UDT66 (TCON_Param_Ext) |
| Remote partner | Leuze sensor (e.g. DCR 200i, ODS 9 series, BPS 300i) | Configured for UDP unicast on port 3601 |
| Ethernet | PROFINET interface X1 of CPU 414-3 PN/DP | 10/100 Mbit/s, full duplex, no router between partners |
The reference OpenUDP example provided by Siemens is published as entry 32038773 in the Siemens support database and includes a working STEP 7 V5.5 project, the UDT65 layout, and the FB65/FB67/FB68 call skeletons. The example is the canonical starting point for any S7-400 Open UDP application: Siemens Support Entry 32038773 — OpenUDP Example.
Root Cause Analysis
The 7002H status with BUSY=1 is not an error — it is the standard "job in progress" indicator returned by TCON while it is performing the configuration. For TCP connections the busy phase lasts until the three-way handshake completes; for UDP there is no handshake, but TCON still validates the UDT65 structure, opens the local socket, and binds the local port. This processing takes between one and three OB1 cycles on a CPU 414-3 PN/DP.
The reason the active_est bit never becomes TRUE is fundamental to how UDP is implemented on the S7-400. UDP is a connectionless protocol. The S7-400 Open Communication stack does not maintain a state machine for a UDP "connection" — there is no SYN, no ACK, no FIN. TCON only registers the local UDP socket descriptor in the CP firmware and writes the remote IP and remote port into the routing table so that TUSEND/TURCV know where to send and from where to expect datagrams. Because there is no handshake, the parameter active_est is intentionally ignored when connection_type = 19 (UDP). The bit is always FALSE on a properly configured UDP endpoint, regardless of whether the user has preset it to TRUE.
active_est = TRUE has no effect. The CPU ignores the bit. The active endpoint is implicitly registered the first time a datagram is successfully transmitted via TUSEND, and the link is held in the routing table for the lifetime of the TCON instance.The 80B5H error code returned by the second TCON call confirms the first call did succeed. Per the Siemens Open Communication manual, STATUS=80B5H from TCON means "connection already established" — the connection ID is already bound in the CP firmware and cannot be reconfigured without first calling TDISCON. The user is therefore caught in a paradox: TCON appears to never complete (because BUSY stays 1 in the online monitor), yet the connection ID is already allocated. The discrepancy is explained by the online monitor behavior — TCON sets BUSY=1 for the single cycle in which it processes the request and clears it to 0 on the next cycle if the operation completed. If TCON is called more than once per cycle, or if the online monitor is refreshing on a slower cycle than the OB1 scan, the user observes BUSY=1 indefinitely.
UDT65 (TCON_Param) Parameter Reference for UDP
The UDT65 structure has a fixed length of 64 bytes and is the only configuration interface for TCON, TUSEND, and TURCV. The fields must be initialized with the desired values and the structure passed to TCON by reference in the CONNECT parameter. For UDP the following mapping applies:
| UDT65 field | Data type | Length (bytes) | UDP value | Description |
|---|---|---|---|---|
| block_length | WORD | 2 | W#16#0040 (= 64) | Total length of TCON_Param; always 64 for S7-400 |
| id | WORD | 2 | 1 to 16 | Local connection ID; must be unique within the CPU |
| connection_type | BYTE | 1 | B#16#13 (19) | 19 = UDP unicast; 20 = UDP broadcast |
| active_est | BOOL | 1 bit (byte 5 bit 0) | FALSE | Ignored for UDP; set FALSE to avoid diagnostic confusion |
| local_device_id | BYTE | 1 | B#16#00 | 0 = integrated PN interface; 1..16 = CP443-1 slot |
| local_tsap_id_len | BYTE | 1 | B#16#02 | Length of local port field; 2 bytes for UDP port |
| local_tsap_id | ARRAY[1..16] OF BYTE | 16 | Byte 0,1 = local port | For UDP, only the first two bytes are used: high-byte / low-byte of local port (e.g. 2801 → B#16#0A, B#16#F1) |
| rem_subnet_id_len | BYTE | 1 | B#16#00 | Not used for UDP, set to 0 |
| rem_subnet_id | ARRAY[1..6] OF BYTE | 6 | All zeros | Not used for UDP |
| rem_staddr_len | BYTE | 1 | B#16#04 | Length of remote IP address field; 4 for IPv4 |
| rem_staddr | ARRAY[1..16] OF BYTE | 16 | Bytes 0..3 = remote IP | Remote IPv4 address; for 192.168.1.209 use B#16#C0, B#16#A8, B#16#01, B#16#D1 |
| rem_tsap_id_len | BYTE | 1 | B#16#02 | Length of remote port field |
| rem_tsap_id | ARRAY[1..16] OF BYTE | 16 | Bytes 0,1 = remote port | Remote UDP port; for 3601 use B#16#0E, B#16#11 |
| next_staddr_len | BYTE | 1 | B#16#00 | Routing not used |
| next_staddr | ARRAY[1..6] OF BYTE | 6 | All zeros | Not used |
| spare | WORD | 2 | W#16#0000 | Reserved |
Important detail: although UDT65 lists rem_staddr as 16 bytes, the CPU only reads the first rem_staddr_len bytes. Setting rem_staddr_len = 4 and writing the four IP address octets in network byte order (big-endian) is sufficient. The same applies to local_tsap_id and rem_tsap_id: only the first len bytes are consumed.
rem_staddr_len = 0 or local_tsap_id_len = 0 causes TCON to immediately return STATUS=80B7H (parameter assignment error). For UDP both length fields must be set to 2 (port length) and rem_staddr_len must be 4.Step-by-Step Resolution
Follow this procedure to bring S7-400 Open UDP communication into operation. The procedure assumes STEP 7 V5.5 SP4 with the standard SIMATIC_NET_CP library. A working reference example is available as Siemens Support Entry 32038773.
- Insert the four Open Communication blocks from the library into your S7-400 project (FB65 TCON, FB66 TDISCON, FB67 TUSEND, FB68 TURCV). Each block automatically creates an instance DB when first opened. Accept the default instance DB numbers or assign your own range (e.g. DB500..DB503).
- Declare a data block of type UDT65 for the TCON_Param. Place it in a global DB (DB510 for example) and initialize every field according to the table above. The block must be 64 bytes long — verify the byte length in the DB declaration.
- Write the IP address and port values into the UDT65. For the Leuze sensor on 192.168.1.209:3601 and local 192.168.1.1:2801 the values are:
local_tsap_id[1] := B#16#0A; // high byte of 2801 = 0x0AF1 local_tsap_id[2] := B#16#F1; // low byte rem_staddr[1] := B#16#C0; // 192 rem_staddr[2] := B#16#A8; // 168 rem_staddr[3] := B#16#01; // 1 rem_staddr[4] := B#16#D1; // 209 rem_tsap_id[1] := B#16#0E; // high byte of 3601 = 0x0E11 rem_tsap_id[2] := B#16#11; // low byte - Set
connection_typeto B#16#13 (decimal 19) andactive_estto FALSE. Do not preset active_est to TRUE — the CPU ignores it for UDP and it confuses diagnostics. - Configure the network interface in HW Config: assign the IP 192.168.1.1 to the CPU PROFINET interface X1, subnet mask 255.255.255.0, no router. Compile and download the hardware configuration.
- Configure the Leuze sensor (or equivalent) for UDP unicast on port 3601, target IP 192.168.1.1, target port 2801. Confirm with the Leuze configuration tool (Sensor Studio / webConfig) that the sensor transmits datagrams on each trigger.
- In OB1, call FB65 TCON with REQ=TRUE on the first scan and FALSE thereafter. Pass the UDT65 by reference (e.g.
"DB510".TCON_UDP) as the CONNECT parameter. On CPU startup OB100 or the first OB1 cycle, set REQ=TRUE. The block then returns DONE=1, ERROR=0, STATUS=0000H after one or two OB1 cycles. Subsequent cycles with REQ=FALSE do not initiate a new connection — the connection ID remains bound. - Verify the connection by inspecting the instance DB. After successful TCON, the internal state area shows BUSY=0, DONE=1, STATUS=0000H, and the connection ID is locked. The active_est flag remains FALSE — this is correct behavior, not an error.
- Call FB67 TUSEND with REQ=TRUE on a send trigger. Pass the same connection ID and the data buffer. The block returns DONE=1 after the datagram leaves the PROFINET interface (typically 5 to 20 ms later). Use FB68 TURCV to receive the Leuze response.
- For shutdown or connection reconfiguration, call FB66 TDISCON with REQ=TRUE. After DONE=1 the connection ID is released and a new TCON call can re-bind it.
Status Code Reference
The status codes returned by FB65 to FB68 follow the SIMATIC Open Communication convention. DONE/BUSY/ERROR/STATUS combinations and their meaning:
| STATUS (hex) | DONE | BUSY | ERROR | Block | Meaning | Action |
|---|---|---|---|---|---|---|
| 0000 | 1 | 0 | 0 | All | Job completed without error | None |
| 7000 | 0 | 0 | 0 | All | No job active (REQ=FALSE) | None |
| 7001 | 0 | 1 | 0 | TCON/TDISCON | Job accepted, starting execution | Wait for next cycle |
| 7002 | 0 | 1 | 0 | All | Job in progress | Wait; do not re-trigger with REQ=TRUE |
| 80A0 | 0 | 0 | 1 | TCON/TUSEND/TURCV | Negative acknowledgment from PROFINET interface | Check wiring, IP, subnet mask |
| 80A1 | 0 | 0 | 1 | All | PROFINET interface busy | Retry on next cycle |
| 80A3 | 0 | 0 | 1 | TDISCON | Connection being terminated by remote partner | None, wait for DONE |
| 80A7 | 0 | 0 | 1 | All | PROFINET interface down or not configured | Check HW Config, download again |
| 80B4 | 0 | 0 | 1 | All | Resource exhausted (no free connection ID) | Free an existing connection with TDISCON |
| 80B5 | 0 | 0 | 1 | TCON | Connection ID already bound | Call TDISCON first, then retry TCON |
| 80B5 | 0 | 0 | 1 | TUSEND/TURCV | Connection not established | Call TCON first and verify STATUS=0000H |
| 80B7 | 0 | 0 | 1 | TCON | Parameter assignment error (length fields, ID range) | Validate UDT65 lengths against the table above |
| 80B8 | 0 | 0 | 1 | All | Parameter error in SDO / RD | Check the data buffer pointer and length |
| 80C3 | 0 | 0 | 1 | TCON | Maximum number of connections reached | Reduce active connections, terminate unused IDs |
| 80C4 | 0 | 0 | 1 | All | Temporary resource error | Retry on next OB1 cycle |
Sample FB65/FB67/FB68 Implementation
The following SCL (Structured Control Language) snippets show a clean cyclic implementation of Open UDP communication. The example uses connection ID 1 for the Leuze sensor and assumes the UDT65 instance is named TCON_UDP in DB510.
// OB100 - first scan initialization
// Trigger TCON on cold restart; bind the UDT65 instance
FB65_TCON_DB(
REQ := TRUE,
ID := 1,
CONNECT := "DB510".TCON_UDP);
// OB1 - cyclic operation
// Edge-trigger REQ on first OB1 scan only
IF "First_Scan" THEN
FB65_TCON_DB.REQ := TRUE;
ELSE
FB65_TCON_DB.REQ := FALSE;
END_IF;
// Capture DONE/ERROR for persistent diagnostics
IF FB65_TCON_DB.DONE = TRUE AND FB65_TCON_DB.ERROR = FALSE THEN
"UDP_Connected" := TRUE;
"UDP_Last_Status" := FB65_TCON_DB.STATUS;
END_IF;
IF FB65_TCON_DB.ERROR = TRUE THEN
"UDP_Last_Error" := FB65_TCON_DB.STATUS;
END_IF;
// Send trigger - rising edge from application
IF "Send_Trigger" AND "UDP_Connected" THEN
FB67_TUSEND_DB(
REQ := TRUE,
ID := 1,
LEN := "Send_Length",
DATA := "Send_Buffer");
ELSE
FB67_TUSEND_DB.REQ := FALSE;
END_IF;
// Continuous receive - call TURCV every cycle
FB68_TURCV_DB(
EN_R := TRUE,
ID := 1,
LEN := "Recv_Length",
DATA := "Recv_Buffer",
NDR => "Recv_New_Data",
RCVD_LEN => "Recv_Actual_Len");
For ladder logic implementation in STEP 7 the equivalent calls are made via the FB blocks directly on the network. The instance DBs generated by STEP 7 expose all inputs as static variables, so the REQ edge-triggering can be performed by an auxiliary marker (M_TCON_Req) initialized in OB100 and cleared after the first successful TCON completion.
Network Configuration and Firewall Considerations
UDP open communication uses the standard Ethernet II frame on UDP/IP. No special routing is required between the S7-400 and the sensor provided they share the same IP subnet. The following checklist applies:
- Confirm the Leuze sensor and the S7-400 PROFINET interface are on the same subnet (192.168.1.0/24). A mismatched subnet mask or router entry is the most common cause of 80A0H errors.
- Disable any managed switch features (IGMP snooping, broadcast storm control, DHCP snooping) on the port connected to the CPU. These features do not block unicast UDP but may delay or drop datagrams under load.
- If a Windows engineering station is on the same network and runs the Windows Firewall, add inbound rules for UDP port 2801 if the engineering PC is to act as a UDP listener for diagnostic capture.
- Configure the Leuze sensor for unicast UDP (not broadcast). Broadcast UDP (connection_type = 20) requires an additional subnet ID configuration and is supported only on CP443-1 with firmware V3.x or later; the integrated PN interface of CPU 414-3 PN/DP supports broadcast but with restrictions on the number of receivers.
- Use a network tap or Wireshark on a mirrored port to confirm the datagram is leaving the sensor and arriving at the CPU. A missing datagram is indistinguishable from a CPU configuration error if only the instance DB is monitored.
- Check the maximum UDP payload size. The S7-400 Open Communication stack limits a single TUSEND call to 2048 bytes per datagram. Leuze sensor responses typically fit within 64 to 512 bytes; if a custom configuration produces larger frames, segment the payload across multiple TUSEND calls.
Verification Procedure
After the TCON call returns STATUS=0000H, perform the following verification in order:
- Open the instance DB of FB65 TCON in STEP 7 online (Monitor/Modify). Confirm that the internal state block shows STATUS=0000H, ERROR=0, BUSY=0. The
active_estbit will still be FALSE — this is correct. - Trigger a TUSEND call with a known 4-byte payload (e.g.
16#01020000). Monitor the TUSEND instance DB until DONE=1, ERROR=0, STATUS=0000H. If DONE=1 with STATUS=0000H but no datagram appears at the sensor, the issue is on the sensor side or the network. - Use Wireshark on a mirrored port to capture the datagram. The source IP must be 192.168.1.1, source port 2801, destination IP 192.168.1.209, destination port 3601. The UDP checksum should be non-zero.
- On the Leuze sensor, check the transmission counter (most Leuze sensors expose a TCP/UDP frame counter). It must increment on every TUSEND call. If the counter is zero, the datagram did not reach the sensor.
- Trigger a sensor response and verify with TURCV that NDR toggles to TRUE and RCVD_LEN reflects the actual payload length. Cross-check against the expected response from the Leuze protocol documentation.
- Stress-test by sending 1000 TUSEND calls in rapid succession (OB35 cyclic interrupt at 100 ms is a good test rate). Monitor for any instance DB status that is not 0000H after the burst. Any non-zero STATUS indicates intermittent routing or buffer pressure issues.
- Power-cycle the CPU and confirm that the connection auto-reestablishes on the next OB1 scan. The instance DB values from the previous session are lost; the UDT65 initialization values must be correct in the DB load image.
Common Pitfalls and Field Notes
| Pitfall | Symptom | Fix |
|---|---|---|
| active_est preset to TRUE for UDP | Online monitor shows BUSY=1 with 7002H; user expects TRUE → FALSE transition | Set active_est=FALSE; the bit has no meaning for UDP |
| Wrong byte order in local_tsap_id | Socket binds to port 0; TUSEND fails with 80B4 | Use network byte order: high byte first, low byte second |
| Missing OB1 call to TCON | TCON instance DB never updates; status remains 0000H | Verify the FB65 call exists in OB1 and the instance DB number matches |
| Calling TCON every cycle with REQ=TRUE | Second call returns 80B5H; CPU floods the routing table | Edge-trigger REQ=TRUE only on startup or after TDISCON |
| Confusing TCP and UDP TCON_Param | TCON returns 80B7H (parameter error) | Use connection_type=19 for UDP, do not specify TSAP strings |
| Leuze sensor configured for TCP | Datagrams leave the CPU but the sensor does not respond | Switch the Leuze sensor to UDP mode in its webConfig |
| Multiple instance DBs sharing connection ID | TCON returns 80B5H on the second instance | Each connection ID 1..16 must be unique across all Open Communication instances |
| Subnet mismatch between CPU and sensor | TUSEND returns 80A0H or no datagram is transmitted | Verify both endpoints are in 192.168.1.0/24 with no router |
| Watchdog timeout during long OB1 scan | TURCV NDR never sets; receive buffer fills slowly | Reduce OB1 scan time or move TURCV to OB35 (cyclic interrupt) |
| CPU restart wipes UDT65 instance DB | First datagram after restart returns 80B5H from TUSEND | Edge-trigger TCON in OB100 on every cold/warm restart |
| Mixing FB65/FB67 instance DBs from different library versions | Interface mismatch, block does not compile | Use the same SIMATIC_NET_CP library version across the project |
Difference Between S7-400 and S7-1500 Open Communication
The TCON / TUSEND / TURCV family of blocks on S7-1500 has been renamed and extended. On S7-1500 with TIA Portal V14+ the blocks are TSEND_C, TRCV_C, TCON, TDISCON, TUSEND, and TURCV — and they are integrated in the instruction list, not in a separate library. The behavior of TCON for UDP is identical (active_est ignored, connection_type=19), but the UDT layout has changed and TCON_Param is now a PLC data type (UDT) with a different field order. Migration of an S7-400 Open UDP project to S7-1500 requires recreating the TCON_Param in TIA Portal; copying the S7-400 instance DB does not work because the byte offsets of the address fields differ.
For S7-300 the blocks are named differently (FC5 AG_SEND, FC6 AG_RECV) and the Open Communication blocks FB65 to FB68 are not available. The S7-300 path uses the AG_SEND / AG_RECV interface over an ISO transport connection or a UDP connection configured with the older "Open Communication Wizard" tool. If the same application must run on S7-300 and S7-400, the UDP endpoints must be re-implemented for the S7-300 with FC5/FC6 plus a configured UDP connection in NetPro.
For S7-1200 with firmware V4.0 or later, TUSEND and TURCV exist as TSEND_C and TRCV_C but only support TCP. UDP open communication on S7-1200 is not available through the standard instruction set — a third-party CP or a user-defined UDP implementation via the T-INDICATOR block family is required. This is a documented limitation of the S7-1200 PLC firmware; see the S7-1200 system manual on Siemens Industry Online Support for the protocol support matrix.
Frequently Asked Questions
Why does the active_est flag in UDT65 stay FALSE on a working UDP connection?
For UDP (connection_type = 19) the S7-400 Open Communication stack does not maintain a connection state machine. The active_est bit is part of the TCP state machine only. For UDP the CPU ignores the bit, registers the local socket, and binds the routing entry — there is no SYN/ACK exchange to make "active" true. The connection is considered established as soon as TCON returns STATUS=0000H.
What does STATUS 7002H from FB65 TCON actually mean?
STATUS=7002H with BUSY=1 means the connection setup job is in progress. For TCP this lasts until the handshake completes; for UDP it lasts only one to three OB1 cycles. The block does not re-trigger automatically — once DONE=1 the status reverts to 0000H (success) or to 7000H (no active job) on the next call. Inspect the instance DB for the persistent state rather than the live STATUS output, and capture the DONE/ERROR edges into a marker for diagnostics.
Why does the second TCON call return 80B5H?
STATUS=80B5H from TCON means "connection ID already bound". The first TCON call succeeded — the connection descriptor is now held by the CP firmware. Calling TCON again with the same ID without first calling TDISCON returns 80B5H. Edge-trigger the REQ input so that TCON runs only once on startup, or after TDISCON completes.
How do I distinguish a TCON error from a TUSEND error?
Inspect both instance DBs independently. If TCON returns STATUS=0000H but TUSEND returns 80B5H, the connection is not established from TUSEND's perspective — call TCON again and verify STATUS=0000H before triggering TUSEND. If both return 0000H and no datagram is observed, the issue is on the sensor side (wrong protocol, wrong port, firewall) or on the network (subnet mismatch, switch blocking).
Can I use the same TCON_Param for sending and receiving?
Yes. A single TCON instance registered with connection_type=19 supports bidirectional UDP traffic on the same local port and remote port. Both TUSEND (outgoing) and TURCV (incoming) reference the same connection ID. The CPU PROFINET interface handles the demultiplexing internally based on the UDP port.
Does the Leuze sensor need any specific configuration for S7-400 UDP?
Yes. Configure the Leuze sensor for "UDP unicast" (not TCP, not broadcast). Set the destination IP to the S7-400 IP (192.168.1.1) and the destination port to the local UDP port (2801). The sensor's source port (3601) and source IP (192.168.1.209) must match the values written into UDT65 rem_staddr and rem_tsap_id. The payload format depends on the Leuze protocol — typically a header byte followed by the data field. Refer to the Leuze protocol manual for the exact frame layout and any required acknowledgments.