S7-1500 XML Over TCP: TCON/TSEND Configuration for HTTP Exchange

David Krause18 min read
SiemensTIA PortalTutorial / How-to
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

Overview: S7-1500 XML over TCP to a Third-Party HTTP Server

When an S7-1500 must hand structured data to a third-party application in XML form, the PLC becomes an HTTP client sending application/xml payloads over a TCP connection. The application layer is HTTP, the transport layer is TCP. The S7-1500 has no native HTTP client instruction, so the engineer must build the HTTP request bytes manually inside a data block and push them to the partner using the Open User Communication instructions TCON, TSEND, and TRCV. The TIA Portal V20 reference for these instructions is the Basics of Open User Communication (S7-1200, S7-1500, S7-1500T) guide.

The scenario covered here: a fixed-size XML document (no element growth, no schema changes) generated on the PLC, posted to a partner HTTP server on a documented TCP port, with a synchronous response. The partner reads the XML, processes the values, and replies. The PLC then disassembles the response. Three implementation paths exist:

  1. Raw TCP+HTTP with TCON/TSEND/TRCV — full control, no extra hardware, no library required.
  2. Siemens Open User Communication library (Entry ID 108740380) — pre-built FBs for S7-1500 to third-party control systems that also serve as templates for any TCP partner.
  3. FTP-based file drop with CP 1543-1 (Entry ID 103550797) — when the partner can pull the XML as a file, or when the XML is large or archived.

The first path is the most common when the XML fits in a single TSEND frame (≤ 8192 bytes per send call on a standard TCON). The library at Siemens Entry ID 108740380 accelerates the second.

Architecture Decision Matrix

Criterion Raw TCP+HTTP Open User Comm Library (108740380) FTP via CP 1543-1 (103550797)
Extra hardware None (use CPU PN port) None CP 1543-1 required
XML size ≤ ~8 KB per frame, multiple sends allowed Same Unlimited (file-based)
Trigger from PLC Push on event / cyclic Push / cyclic Push or pull (partner initiates)
Authentication None in HTTP layer Configurable FTP user/password on CP
Engineering effort High (manual HTTP framing) Medium (FB import) Medium (FTP config on CP)
Firmware floor Firmware V2.0+ on CPU 15xx CPU 1500 V2.5+ recommended CP 1543-1 V2.0+

If the partner exposes an HTTP endpoint and the XML is small, raw TCP+HTTP wins on simplicity. If the partner prefers to pull files on its own schedule, FTP with the CP 1543-1 is cleaner.

Prerequisites: Hardware, Firmware, and Software

Item Requirement
CPU S7-1500 (any PN-capable variant), firmware ≥ V2.0 for Open User Communication. V2.5+ recommended for full TSEND_C / TRCV_C feature set.
Engineering software TIA Portal V18 (or V19 / V20). V20 documentation live at docs.tia.siemens.cloud — Basics of Open User Communication.
CPU PROFINET interface IP address, subnet mask, gateway; physical connection to partner network.
Partner application HTTP server listening on a documented TCP port, expecting POST with Content-Type: application/xml (or text/xml).
Optional hardware CP 1543-1 (6GK7-543-1AX00-0XE0) for FTP path. See Siemens Entry ID 103550797.
Library (optional) Open User Communication library for S7-1500 to 3rd-party control systems: Siemens Entry ID 108740380.
Network firewall: Open the partner's TCP port bidirectionally. S7-1500 CPUs do not implement connection tracking that survives NAT rebind; if a stateful firewall sits between the PLC and partner, configure a pinhole for the partner's source port and the PLC's connection ID, or use a fixed partner port.

XML Payload Strategy: Fixed vs. Variable Size

The Open User Communication instructions move bytes — they do not parse XML. Whatever the application layer expects must be pre-built in a data block before TSEND fires.

If the XML document is fixed in length and content, the cleanest engineering is to store the entire HTTP request (headers + body) as a constant ARRAY of BYTE in a DB and only patch the variable values in place. This avoids runtime string concatenation and is deterministic — required for SIMATIC safety systems and for any project that needs reproducible cycle-time analysis.

If the XML document grows (new elements added by the partner, dynamic data, attribute count varies), the document is no longer fixed-size. You then need:

  • A scratch DB of ARRAY [0..N] of BYTE with N sized for the worst case.
  • Runtime string/byte construction (e.g. CONCAT, FILL_BLK, INSERT) to assemble the document.
  • A LEN tag passed to TSEND via its LEN input.

The remainder of this article assumes the fixed-size case, which is the most common when the partner has documented a stable XML schema and the PLC is the only writer.

Step 1: Build the XML Payload as a Byte Array DB

Create a global DB (e.g. DB_XML_Buffer) with the structure below. The httpRequest array holds the complete HTTP POST including the body; xmlBody is a separate view used when you need to update only the values.

  1. In TIA Portal, add a new DB. Uncheck "Optimized block access" if you need fixed offsets for diagnostic purposes, or keep it optimized and access symbolically.
  2. Add tag httpRequest : ARRAY[0..1023] of BYTE — sized for headers + a 1 KB XML body with margin.
  3. Add tag reqLen : DINT — actual byte count to transmit.
  4. Add tag connId : WORD — connection ID assigned to TCON (range 1..4095 on S7-1500; 0 is reserved for the diagnostic buffer).
  5. Pre-populate httpRequest with the literal bytes of the HTTP request. Use the constant string syntax in TIA Portal to declare a multi-line literal and convert it via STRING_TO_BLK or assign to the array at startup.

Sample HTTP request to be stored as the array (shown as text, must be sent as raw bytes):


POST /api/plcdata HTTP/1.1\r\n
Host: 10.20.30.40:8080\r\n
Content-Type: application/xml; charset=utf-8\r\n
Content-Length: 187\r\n
Connection: keep-alive\r\n
\r\n
<?xml version="1.0" encoding="UTF-8"?>\r\n
<plc><ts>2025-01-15T10:30:00</ts><val1>1234</val1><val2>5678</val2></plc>\r\n
CRLF handling: HTTP/1.1 mandates CRLF (0x0D 0x0A) between header lines and a blank CRLF separating headers from body. Most partner stacks will reject a request with bare LF (0x0A). Do not let TIA Portal's string editor silently normalize line endings.
Content-Length accuracy: The byte count in Content-Length must equal the exact body length, not a padded length. Mismatches cause the partner to either hang waiting for more bytes or close the connection prematurely. Recompute Content-Length after every value change.

For the value-update workflow, expose a sub-structure of xmlBody as STRING variables and use the Siemens string-handling instructions to overwrite the value segments in place. Avoid building the document from scratch per cycle.

Step 2: Configure the TCP Connection with TCON

The TCON instruction establishes and maintains a TCP connection. A single TCON instance is required per partner endpoint; it is typically called once at startup or in OB100.

  1. Drag TCON from the Instructions panel (Communications → Open User Communication) into OB1 or a startup OB.
  2. Create an instance DB (e.g. DB_TCON_Inst).
  3. Wire REQ to a one-shot (e.g. first-cycle flag from FirstScan in OB100 or a positive edge from a manual start tag).
  4. Set ID to a unique connection ID, e.g. W#16#0001.
  5. Create a TCON_Param tag (a UDT or struct of type TCON_Param) with the parameters in the table below.
  6. Wire DONE, BUSY, and ERROR to a status DB and evaluate STATUS on rising edge of ERROR.
TCON_Param field Value (example) Notes
InterfaceId 64 (built-in PN interface of CPU 1515-2 PN) Find under Devices & Networks → CPU properties → PROFINET interface → System constants. 64 = HW ID of the IE interface; on other CPUs the value differs.
ID W#16#0001 Must match ID input on TCON/TSEND/TRCV.
ConnectionType B#16#0B (TCP, ISO-on-TCP is B#16#0C, UDP is B#16#0D) Use B#16#0B for raw HTTP over TCP.
ActiveEstablished TRUE PLC opens the connection (acts as HTTP client). FALSE = partner opens.
RemoteAddress '10.20.30.40' Partner IP. STRING[15] in the UDT.
RemotePort 8080 Partner HTTP port.
LocalPort 0 0 = any free local port assigned by the CPU.
LocalAddress '192.168.0.10' Optional, leave 0.0.0.0 for any local IP.

TCON returns STATUS = 0x0000_0000 on success, STATUS = 0x0000_8180 while busy, and STATUS = 0x80A1_xxxx on partner-side rejections (Wireshark on the partner side helps distinguish partner RST from PLC-side errors). 0x80C8_0000 indicates the connection is already established — typically harmless on warm restart.

Step 3: Construct and Send the HTTP Request with TSEND

TSEND transmits a byte block over an established connection. Unlike TSEND_C, it does not manage the connection — that is TCON's job. Use TSEND_C if you want connection management bundled, but it is generally cleaner to keep TCON separate for HTTP scenarios where you want a persistent connection and a separate send/receive cycle.

HTTP frame construction before TSEND: The HTTP request is plain ASCII text. Build it once, parameterize the value fields, and ship the buffer to TSEND. Sample build flow:

  1. Copy a template byte array into httpRequest at startup (use a startup OB, or fill from constants).
  2. On each transmit cycle, write the new timestamp / values into the body at fixed offsets using BLKMOV / MOVE_BLK.
  3. Recompute the Content-Length header by converting the body length DINT to ASCII and BLKMOV into the header area at the documented offset.
  4. Set reqLen = headers length + 2 + body length (the 2 bytes account for the blank-line CRLF separator).

LEN_Header := 156;  // bytes from 'POST' to 'Connection: keep-alive\r\n' (computed once at design time)
LEN_Body   := ...;  // value from runtime

// Total transmitted length:
reqLen := LEN_Header + 2 + LEN_Body;
// (2 bytes for the blank line that separates headers from body: 0x0D 0x0A)

For ASCII clarity, the on-wire shape is:


[ HTTP Headers ........ (ASCII, CRLF terminated) ]
[ 0x0D 0x0A                                          ]  <-- blank line separator
[ XML body ........... (UTF-8, exact Content-Length)  ]

Wiring the TSEND call:

  1. Drag TSEND into OB1 (or a cyclic OB) with its own instance DB (e.g. DB_TSEND_Inst).
  2. Wire REQ to a positive edge each time the partner should receive a fresh XML (e.g. on a "send" pushbutton or cyclic trigger).
  3. Wire ID to W#16#0001 (the same connection ID used by TCON).
  4. Wire LEN to reqLen.
  5. Wire DATA to httpRequest (use P#DB_XML_Buffer.httpRequest for absolute access, or a VARIANT pointer for symbolic access).
  6. Evaluate DONE to fire the next TRCV cycle. ERROR + STATUS feed the diagnostic buffer.
TSEND STATUS (hex) Meaning Action
0x0000_0000 Send complete, DONE latched Proceed to TRCV if expecting a response
0x0000_8180 Busy, transmission in progress Wait, do not re-trigger
0x80A1_0100 Connection aborted by partner (RST received) Re-run TCON, then re-send
0x80C4_0100 Temporary resource shortage on CPU Retry with backoff
0x80B1_0000 LEN larger than the DATA source area Correct LEN or grow the buffer

Step 4: Receive the HTTP Response with TRCV

If the partner replies synchronously, call TRCV after TSEND.DONE rises. TRCV can operate in two modes:

  • Ad-hoc mode (LEN = 0): returns whatever data is in the receive buffer at call time.
  • Length-prefixed mode (LEN > 0): blocks until exactly LEN bytes arrive or the partner closes.

HTTP responses are CRLF-delimited and the body length comes from the partner's Content-Length header. The pragmatic approach:

  1. Allocate a large receive buffer, e.g. rcvBuf : ARRAY[0..4095] of BYTE.
  2. Call TRCV with LEN = 0 and a short cycle (e.g. 100 ms timer in OB1).
  3. When NDR rises, scan the buffer for the \r\n\r\n pattern to locate the body start.
  4. Parse the response status line, log it, and process the body (or discard it if the partner only echoes an HTTP 200 OK).

If the partner does not reply (one-way POST with no response), skip TRCV entirely. TCON keeps the socket open for the next send — this is the Connection: keep-alive advantage. To force a clean close, set TCON's REQ to FALSE for one cycle, or call the TDISCON instruction.

Siemens Open User Communication Library (Entry ID 108740380)

For projects where the third party is a Rockwell ControlLogix/GuardLogix controller, or where the team wants a pre-built FB library as a starting point, Siemens publishes the "Open User Communication to 3rd party control system (CLX/GLX controller)" library at Siemens Entry ID 108740380.

What the library provides:

  • A connection FB that wraps TCON with the parameter struct populated for CLX/GLX endpoints.
  • A send FB and receive FB with standardized error decoding.
  • An example project for TIA Portal V18 / V19 / V20 with both PLC and HMI components.

To adapt it for a generic HTTP server (not a CLX/GLX controller):

  • Replace the CLX MSG instruction pattern with your own XML payload buffer.
  • Keep the connection management, error decoding, and diagnostic tagging from the library.
  • The library's documented "send complete" path feeds straight into a TRCV call, which is the pattern shown in Step 4.

This path is faster to commission on multi-PLC projects (one library handles 5+ partners consistently) and is the recommended starting point when the third party is a Rockwell controller. The first link on the entry page lists the prerequisites, supported firmware, and example TIA Portal versions.

FTP Alternative via CP 1543-1 (Entry ID 103550797)

When the XML grows past a single TSEND frame, the partner wants a durable file, or you need authentication beyond HTTP basic, the FTP path is the right tool. The CP 1543-1 (6GK7-543-1AX00-0XE0) is a security module with an integrated FTP server. The S7-1500 writes the XML to a file on the CP's SD card or RAM disk; the partner FTP client logs in and pulls the file. Full configuration steps and a sample project are in Siemens Entry ID 103550797 — FTP communication with S7-1500 and CP 1543-1.

When FTP is the right call:

  • XML file > ~8 KB and you want to avoid manual fragmentation and reassembly in the application layer.
  • The partner's architecture is "poll the latest data" rather than "subscribe to a stream".
  • Audit trail: the CP can log every FTP transfer to syslog, which the raw HTTP path does not provide natively.
  • You already own a CP 1543-1 for firewall / VPN reasons — you get FTP for free.

When FTP is the wrong call:

  • The partner requires sub-second latency — FTP adds file I/O latency on the SD card.
  • You need push semantics (PLC → partner without partner polling). With the FTP server profile, the partner must pull; to push, you need a CP configuration that supports FTP client mode, which is a different profile.
CP 1543-1 firmware floor: V2.0 is the baseline for the documented example; V2.2+ is required for syslog to a remote server and for AES-256 on the FTP password. Check the firmware shipped on the module before commissioning — Siemens Service Pack downloads include release notes listing the FTP-related fixes.

Verification, Performance, and Security

Verification — run the following checks in order. Each must pass before moving to the next.

  1. TCON established: In the PLC's online diagnostics → Connections, verify the connection ID shows "Established" with the partner IP and port. TCON.STATUS = 0 on completion.
  2. Wire capture: Run Wireshark on a SPAN port of the switch between the PLC and partner. Filter ip.addr == <partner> && tcp.port == <8080>. Confirm the HTTP POST goes out, the request body matches the byte count in Content-Length, and the partner's ACK arrives.
  3. Partner log: Verify the partner's HTTP server logged a 200 OK response. If the partner returns 400, capture the response body and decode the partner's error message; it usually points at malformed XML or wrong Content-Type.
  4. PLC receive path: In the receive DB, confirm the response body is present at the expected offset and that TRCV.NDR pulsed.
  5. Cycle-time impact: In the CPU's online diagnostics → Cycle time, confirm the OB1 extension when TSEND fires is < 5 ms on a typical S7-1515. If it is higher, move the send to a lower-priority OB (e.g. OB30) to avoid jitter on the motion / PID cycle.
  6. Loss-of-partner test: Disconnect the partner's network cable. TSEND should report ERROR = TRUE with STATUS = 0x80A1_0100 within the TCP retransmission timeout (default ~3 s on S7-1500 PN interface). Reconnect and verify auto-recovery on the next REQ.
  7. Soak test: Run cyclic sends for at least 24 h. Watch for TCON entering a "stale" state (DONE TRUE but partner has closed). Symptom: TSEND returns 0x80A1 immediately. Fix: implement a watchdog that runs TDISCON + TCON if no successful send has occurred in N seconds.

Performance and cycle-time notes: TSEND is non-blocking from the application's perspective — the instruction returns immediately and the data is copied into the CPU's internal TCP send buffer. Actual transmission happens asynchronously in the firmware's communication task. A single TSEND call adds microseconds to OB1, not milliseconds. The real cost is the BLKMOV / string build that prepares the buffer. For a 1 KB XML, expect 50–200 µs of CPU time on a CPU 1515-2 PN. For multi-KB payloads, consider building the body in a lower-priority OB (e.g. OB35) and signalling OB1 when ready; avoid CONCAT in fast OBs (it re-allocates the string each call); use MOVE_BLK with explicit length for fixed-size value patches. For PLC-to-PLC where the partner is also a SIMATIC, use the PUT / GET instructions instead — they handle fragmentation and partner acknowledgement automatically. XML over raw TCP is for the case where the partner explicitly requires XML at the application layer.

Security considerations: Raw TCP+HTTP carries no encryption and no authentication. If the link crosses an untrusted network, use a CP 1543-1 (or CP 1545-1) as the gateway and enable the IPsec / OpenVPN tunnel between the CP and a counterpart firewall — the CP terminates the tunnel; the S7-1500 talks plain TCP to the CP's internal interface. Moving the partner to HTTPS requires a custom TCP-based TLS implementation on the S7-1500 side (not natively supported by the Open User Communication instructions) or a third-party TLS library. Restrict the partner IP at the network layer (firewall ACL on the switch or the CP) so only the documented partner IP can establish the TCP session. The library at Entry ID 108740380 includes a security checklist that applies to any third-party integration, not only the CLX/GLX case.

Troubleshooting Matrix

Symptom Likely root cause First diagnostic Fix
TCON.ERROR rises immediately with STATUS = 0x80A7_0000 Partner IP unreachable (ARP fails) or firewall blocks SYN Ping partner from a laptop on the same subnet; check switch port LED Fix routing, open firewall for the partner port, verify the CPU's PROFINET interface IP is set under Device configuration → Ethernet addresses
TSEND busy forever (STATUS = 0x0000_8180) REQ toggled faster than TSEND can complete; or LEN exceeds send buffer Check BUSY edge behavior; verify LEN ≤ actual DATA size Trigger REQ only on DONE or ERROR of the previous send; trim LEN or grow buffer
Partner returns HTTP 400 Bad Request Malformed HTTP request — most often Content-Length wrong, LF-only line endings, or Content-Type missing Capture full TCP stream in Wireshark; diff against RFC 7230 Fix HTTP framing; for LF-only, regenerate template with explicit 0x0D 0x0A bytes
Partner returns HTTP 413 / connection reset mid-body Body larger than partner's client_max_body_size (nginx) or equivalent Check partner log for size limit; check Content-Length vs. actual body Reduce XML, raise partner limit, or switch to chunked transfer encoding (advanced — requires manual HTTP/1.1 chunked encoding in the array)
TRCV never receives NDR Partner is one-way POST with no response; or partner's response is on a different socket Wireshark: did the partner send anything back? Did the partner close the socket? If partner is one-way, remove the TRCV call; if response is on a new connection, the partner is using HTTP/1.1 close semantics and you need a reconnect
Connection "stuck" after long idle Intermediate firewall idle-timeout closed the TCP session; PLC doesn't notice until next send Wireshark: see if a FIN came from the firewall before the next PLC send Send a keep-alive heartbeat (low-rate TSEND with a tiny payload) or implement periodic TDISCON/TCON cycle
XML values "shifted" by one position after a logic edit Optimized vs. non-optimized DB access mismatch; the byte offsets moved when the DB was regenerated Compare DB "Offset" column online vs. offline Pin to symbolic access; or use a UDT with named fields and never hand-edit offsets
CPU goes to STOP on the first TSEND LEN larger than the actual byte length of DATA; CPU raises a programming error OB121 Check the diagnostic buffer for OB121 Trim LEN to actual body+headers; add OB121 with a pass-through if you want a graceful recovery instead of STOP
Wireshark decode tip: Right-click an HTTP packet → "Decode As" → HTTP. This forces Wireshark to parse the TCP stream as HTTP even if the port is non-standard, which makes header inspection dramatically easier than reading raw bytes.

FAQ

Does the S7-1500 support HTTP POST natively, or must I build the request bytes manually?

The S7-1500 has no native HTTP client instruction. You must build the HTTP request (headers + body) as a byte array in a DB and transmit it with TSEND over a TCON connection. The TIA Portal help (F1 on the Open User Communication instructions) covers the instruction set; the request framing is on the engineer. The reference manual is the V20 Open User Communication guide at docs.tia.siemens.cloud.

What is the maximum XML payload size per TSEND call on S7-1500?

On firmware V2.0 and newer, TSEND accepts up to 65536 bytes per call, but the practical single-frame limit is the partner's TCP receive window. A 1 KB–4 KB XML fits comfortably in a single send. For larger documents, use the multi-segment TSEND pattern (send a marker segment, then TRCV acknowledge, then continue) or move to FTP via CP 1543-1 (see Entry ID 103550797).

Can I use TSEND_C instead of separate TCON and TSEND?

Yes. TSEND_C bundles connection establishment, send, and optional receive. It is convenient for one-shot requests. For a persistent HTTP connection with periodic sends, the explicit TCON + TSEND + TRCV pattern is easier to diagnose because each instruction's status is independent — TCON.STATUS shows connection health without conflating with the send result.

How do I send XML to a Rockwell ControlLogix / GuardLogix controller using the same approach?

Use the Siemens Open User Communication library for S7-1500 to 3rd-party control systems at Siemens Entry ID 108740380. The library wraps the connection and provides sample code adapted for CLX/GLX endpoints. The XML payload pattern above still applies for the application-layer data.

When should I switch from raw TCP+HTTP to FTP with CP 1543-1?

Switch to FTP when the XML exceeds ~8 KB, the partner prefers to pull files on its own schedule, you need an audit trail, or you already own a CP 1543-1 for security reasons. The reference configuration is at Siemens Entry ID 103550797.

Back to blog