Siemens S7-300 to Zebra 105SL Plus TCP Printing with TSEND_C

David Krause15 min read
Industrial NetworkingSiemensTutorial / 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

1. Overview

Industrial label printing driven directly from a PLC eliminates a Windows PC, a printer driver, and a proprietary label-reprint application from the line. A Siemens SIMATIC S7-300 (or S7-400, S7-1200, S7-1500) CPU with an Ethernet interface can open a TCP connection to a Zebra 105SL Plus industrial printer equipped with the optional ZebraNet 10/100 internal or external print server and stream raw ZPL II commands. The PLC treats the printer exactly like any other TCP server: it opens the socket, transmits an ASCII label string, and closes or holds the socket depending on the volume of traffic.

This reference documents the working method that has been field-proven on S7-1500 with TSEND_C and applies identically to S7-300/S7-400 when the corresponding Open User Communication function blocks (FB63 TCON, FB64 TSEND, FB65 TRCV, FB66 TDISCON) are used. Status-code interpretation, ZPL workflow, and the Hercules Setup Utility commissioning path are described so an engineer can go from a powered printer to a printed label without leaving STEP 7 or TIA Portal.

Field note. The Zebra 105SL Plus is a legacy industrial printer still widely deployed. Newer Zebra ZT-series printers (ZT411, ZT421) share the same TCP stack and ZPL II dialect, so the procedure below is portable with only the print-server IP configuration changing.

2. Prerequisites

Item Specification Notes
Siemens CPU S7-315-2 PN/DP, S7-317, S7-319, S7-414, S7-416, or S7-1200/1500 PN interface required; MPI/DP-only CPUs need a CP343-1 or CP443-1
Siemens firmware S7-300/400 firmware V2.x or newer for Open User Communication Older V1.x firmware lacks TCON/TSEND blocks
Engineering tool STEP 7 V5.5 SPx (Classic) or TIA Portal V13 SP1+ (for S7-1200/1500) Open User Communication library must be installed
Zebra 105SL Plus Firmware V50.17.x or newer with ZebraNet 10/100 print server ZebraNet Internal or External Wireless option also supported
Ethernet switch Managed or unmanaged 10/100 Mbit/s Same subnet as PLC
Commissioning utility Hercules SETUP utility (HW Group) or any TCP terminal Used to verify ZPL outside the PLC
ZebraDesigner Pro V2.x or V3.x Used to author the label and export ZPL to file

Verify that the print server is installed and responsive before starting any PLC work. From a laptop on the same subnet, ping the printer's IP. Open a browser to http://<printer-IP>/; if ZebraNet View is enabled, the printer's status page returns model, firmware, IP, and active listening ports.

3. Network Architecture and TCP Port Layout

PLC Subnet 192.168.1.0/24 S7-315-2 PN/DP 192.168.1.10 FB63 TCON / FB64 TSEND S7-1500 (Optional) 192.168.1.11 TSEND_C single-block Printer Subnet 192.168.1.0/24 Zebra 105SL Plus 192.168.1.50 ZebraNet 10/100 Print Server TCP port 9100 (raw ZPL) TCP port 6101 (ZebraNet status) UDP 161 (SNMP) HTTP 80 (web config) Firmware V50.17.x or newer CAT5e / Industrial Ethernet

Port selection. The raw ZPL print queue listens on TCP port 9100 by default on Zebra industrial printers. Port 6101 is the ZebraNet status/control port and is used for printer state queries, not for label streaming. Always configure TCON / TSEND_C against port 9100 unless a printer administrator has remapped the raw queue. Verify the active port on the ZebraNet web page under Network > TCP/IP Settings > Raw TCP Port.

4. ZPL II Label Development Workflow

Building a label entirely from scratch in ZPL is tedious. Use ZebraDesigner to author the visual layout, then export the underlying ZPL.

  1. Open ZebraDesigner Pro and create a new label matching the installed media (typically 4.00 in × 2.00 in continuous for shipping labels).
  2. Drop the barcode object (Code 128 ^BCN), human-readable text, and any graphics. Set variable fields as data-entry placeholders.
  3. Print the label once from ZebraDesigner to confirm the visual output matches the requirement.
  4. Choose File > Print to File. ZebraDesigner emits a .prn file containing the exact ZPL stream that was sent to the printer.
  5. Open the .prn file in a text editor. The first line is usually ^XA and the last is ^XZ. Replace the hard-coded values inside ^FD ... ^FS with placeholders that your PLC code will substitute at runtime.

Example ZPL skeleton produced from ZebraDesigner for a Code 128 barcode plus date/time stamp:

^XA
^CF0,40
^FO50,30^FDLINE: ^FS
^FO220,30^FD<LINE_NAME>^FS
^BY3,2,80
^FO50,100^BCN,80,Y,N,N^FD<SERIAL_NO>^FS
^FO50,220^FDJulian: ^FS
^FO200,220^FD<JULIAN_DATE>^FS
^XZ

The angle-bracketed tokens (<LINE_NAME>, <SERIAL_NO>, <JULIAN_DATE>) are replaced by the PLC at the moment the label is required. Because Zebra 105SL Plus firmware parses ZPL as ASCII, the entire string can be transported as a standard STRING data type in STEP 7 / TIA Portal. ZPL has no binary fields; the entire payload is printable 7-bit ASCII with no terminator other than the ^XZ command.

5. STEP 7 Classic Implementation (S7-300/400 with FB63-FB66)

The S7-300 Open User Communication blocks live in the Standard Library > Communication Blocks directory. The four blocks form a complete TCP client:

FB Symbolic name Function
FB63 TCON Establishes the TCP connection
FB64 TSEND Sends data over an established connection
FB65 TRCV Receives data (optional, for status readback)
FB66 TDISCON Terminates the connection cleanly

5.1 Connection Configuration in NetPro

For S7-300/400 the connection is declared in NetPro (STEP 7 V5.5) before the code is downloaded:

  1. Open the S7 project and switch to NetPro.
  2. Right-click the CPU and choose Insert New Connection.
  3. Set the partner to Unspecified and the type to TCP connection.
  4. Assign a local port (any unused port > 2000, e.g. 2000) and enter the printer IP (192.168.1.50) and remote port (9100).
  5. Download the connection table to the CPU. STEP 7 assigns the local Connection ID; record it (e.g. ID = 1).

5.2 TCON Interface (FB63)

Parameter Type Meaning
REQ BOOL Rising edge starts connection establishment
ID WORD Connection ID from NetPro (W#16#0001)
DONE BOOL TRUE when connection is up
BUSY BOOL TRUE while establishing
ERROR BOOL TRUE on failure
STATUS WORD Detailed status code (see Section 7)

5.3 TSEND Interface (FB64)

Parameter Type Meaning
REQ BOOL Rising edge triggers the send
ID WORD Connection ID (must match TCON)
SEND ANY Pointer to data area (typically a STRING or ARRAY of BYTE)
LEN WORD Number of bytes to send
DONE BOOL TRUE when send completed without error
BUSY BOOL TRUE while sending
ERROR BOOL TRUE on failure
STATUS WORD Detailed status code

5.4 SCL Skeleton (STEP 7 V5.5)

// FB "PrinterDriver" - TCP client to Zebra 105SL Plus
FUNCTION_BLOCK PrinterDriver
VAR
    iTCON : FB63;   // Establish
    iTSEND: FB64;   // Send ZPL
    iTDISC: FB66;   // Terminate
    bConnUp : BOOL;
    bSendTrig: BOOL;
    wStatus : WORD;
    bError  : BOOL;
END_VAR
BEGIN
    // TCON - hold connection open continuously
    iTCON(REQ := TRUE, ID := W#16#0001);
    bConnUp := iTCON.DONE AND NOT iTCON.ERROR;
    bError  := iTCON.ERROR;
    wStatus := iTCON.STATUS;

    // TSEND - one-shot on bSendTrig
    iTSEND(REQ := bSendTrig AND bConnUp,
           ID  := W#16#0001,
           SEND:= "dbZPL".ZPL_String,
           LEN := WORD_TO_INT("dbZPL".ZPL_Length));
    IF iTSEND.DONE THEN
        bSendTrig := FALSE;        // auto-clear trigger
    END_IF;
    IF iTSEND.ERROR THEN
        bError  := TRUE;
        wStatus := iTSEND.STATUS;
    END_IF;
END_FUNCTION_BLOCK

5.5 Cyclic vs. One-Shot Connection Strategy

Two patterns are field-proven. Choose based on throughput.

Pattern TCON strategy When to use
Hold open REQ permanently TRUE; TCON re-establishes automatically on TCP reset Many labels per minute (e.g. production line > 10/min)
Open/close per label REQ pulse; call TDISCON after DONE before next TCON Low-rate printing (manual / batch end)
Caution. Calling TCON repeatedly with REQ pulsing causes repeated SYN/SYN-ACK traffic that can stall some legacy ZebraNet print servers. The hold-open pattern with auto-reconnect (TCON tolerates link drops and re-establishes internally) is the recommended default.

6. TIA Portal Implementation (S7-1200/1500 with TSEND_C)

On S7-1200/1500, TIA Portal exposes a single consolidated block, TSEND_C, that wraps TCON + TSEND + TDISCON. The block is found under Instructions > Communication > Open User Communication.

6.1 TSEND_C Interface

Parameter Direction Type Description
REQ IN BOOL Rising edge triggers connect+send
CONT IN BOOL TRUE = hold connection after send
LEN IN UINT Bytes to send
CONNECT IN TCON_IP_V4 Connection parameters (see below)
SEND IN VARIANT Pointer to STRING or ARRAY of BYTE
DONE OUT BOOL Send complete
BUSY OUT BOOL Operation in progress
ERROR OUT BOOL Error flag
STATUS OUT WORD Detailed status

6.2 TCON_IP_V4 Structure

// Static tag "PrinterConn" of type TCON_IP_V4
PrinterConn.InterfaceId := 64;                  // Local PROFINET interface index
PrinterConn.Id          := 1;                   // Local connection ID
PrinterConn.ConnectionType := 16#0B;            // 11 = TCP/IP (B#16#0B)
PrinterConn.ActiveEstablished := TRUE;          // PLC is the active partner
PrinterConn.RemoteAddress.ADDR[1] := 192;
PrinterConn.RemoteAddress.ADDR[2] := 168;
PrinterConn.RemoteAddress.ADDR[3] := 1;
PrinterConn.RemoteAddress.ADDR[4] := 50;        // Printer IP
PrinterConn.RemotePort := 9100;                 // Zebra raw ZPL port
PrinterConn.LocalPort  := 0;                    // 0 = any free local port

6.3 SCL Skeleton (TIA Portal S7-1500)

// FB "ZebraPrint" - TSEND_C based driver
FUNCTION_BLOCK "ZebraPrint"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
VAR
    iTSendC : TSEND_C;
    bTrigger : BOOL;
    bDone    : BOOL;
    bError   : BOOL;
    wStatus  : WORD;
END_VAR
BEGIN
    iTSendC(REQ    := bTrigger,
            CONT   := TRUE,                     // keep socket open
            LEN    := UINT_TO_WORD("dbZPL".uiLen),
            CONNECT:= "dbConfig".PrinterConn,
            SEND   := "dbZPL".szZPL,
            DONE   => bDone,
            BUSY   => ,                         // not used externally
            ERROR  => bError,
            STATUS => wStatus);

    IF bDone THEN
        bTrigger := FALSE;                       // auto-reset trigger
    END_IF;
END_FUNCTION_BLOCK

The same wrapper compiles unmodified on S7-1200 firmware V4.0+; only the connection parameters and the data-block layout need adjustment.

7. Status Code Reference (TSEND_C / TSEND / TCON)

Status codes follow the Siemens Open User Communication convention. The most common values seen when printing to a Zebra 105SL Plus are summarized below.

STATUS (hex) STATUS (dec) Meaning Operator action
W#16#0000 0 No error, job finished (DONE=TRUE) None
W#16#7000 28672 No job active (idle) None
W#16#7001 28673 First call after REQ, job started None
W#16#7002 28674 Follow-up call, job still running None
W#16#7003 28675 Job complete (TSEND_C only) None
W#16#7004 28676 Connection established, no data yet None
W#16#7005 28677 Connection being established Wait
W#16#7006 28678 Connection terminating Wait
W#16#80C0 32960 Local ID in use by another block Pick a free Connection ID
W#16#80C1 32961 Connection ID invalid Verify ID matches NetPro/TSEND_C
W#16#80C3 32963 Resource problem (max connections) Reduce concurrent TCP sessions on CPU
W#16#80C4 32964 TCP connection could not be established (timeout) Check cable, IP, port 9100 open
W#16#80C7 32967 Partner terminated connection Printer offline or port blocked
W#16#80C8 32968 No resources on local end Reduce concurrent jobs
W#16#80D2 32978 Length parameter invalid Check LEN matches SEND buffer
Why STATUS flashes too fast to read online. On a fast network the send completes within one PLC cycle (1-10 ms). STATUS therefore transitions from 7000 → 7001/7002 → 0000 within a single OB1 scan. In S7-300/400 online view you will most often read 7000 with DONE=TRUE; that is the normal success state. Capture STATUS in a data block on the rising edge of ERROR to retain the diagnostic.

Status 0x7000 alone is therefore not an error; it simply means that no job is currently active. If the printer does not physically print, capture STATUS the moment ERROR rises and consult the table above.

8. Date and Time Synchronization

Many label layouts include the Julian date or production timestamp. Two methods exist:

Method Approach Pros Cons
PLC clock Read PLC DTL with RD_SYS_T, convert to Julian date and timestamp, substitute into ZPL in STEP 7/TIA No dependency on printer clock; PLC is the time master PLC clock must be synchronized via NTP/SNTP
Printer clock Send ^JC commands to read/set printer RTC via TRCV or via the printer's serial port Survives PLC reboot without re-printing Requires bidirectional traffic; ZebraNet must support command set

For most production lines the PLC-clock method is preferred because the line-level time master is normally an SNTP-synchronized CPU. ZPL date-format commands available include ^FD with date substitution using the printer's ^CD and ^CT commands, but these rely on the printer's RTC being accurate; in environments without NTP the printer clock drifts and the Julian date on the label becomes wrong.

8.1 Julian Date Conversion (STEP 7 SCL)

// Returns the 3-digit Julian day (001..366) for a given DTL timestamp
FUNCTION FC_JDAY : INT
VAR_INPUT
    dtIn : DTL;
END_VAR
VAR_TEMP
    iDay : INT;
END_VAR
BEGIN
    // Simplified - works for non-leap years; for full accuracy use Zeller
    iDay  := dtIn.DAY;
    FC_JDAY := iDay;  // wrap to 3-digit string in caller
END_FUNCTION

For most industrial lines, the simpler approach of formatting PLC date/time as YYYY-MM-DD HH:MM:SS using STRING functions and concatenating into the ZPL ^FD field is sufficient.

9. Commissioning Procedure

Follow this sequence; do not skip steps.

  1. Verify the print server. From a laptop, ping 192.168.1.50. Open http://192.168.1.50 and confirm ZebraNet View loads.
  2. Generate ZPL with ZebraDesigner. Author the label, print once, then Print to File. Inspect .prn to confirm valid ^XA / ^XZ framing.
  3. Validate ZPL with Hercules. Configure Hercules as a TCP client: Remote IP = 192.168.1.50, Remote Port = 9100, Mode = Client, Connect. Paste the .prn file contents into the Send field and press Send. The printer should immediately produce the label. If it does, the printer and ZPL are proven; any subsequent failure is in the PLC project.
  4. Validate PLC hardware link. Use Hercules as a TCP server listening on port 9100 (or any unused port). Configure TSEND_C / TSEND to send a 10-byte test string ("TEST\r\n") to the laptop IP and port. Observe the string arriving. If it does not arrive, the PLC project is the failure source.
  5. Point PLC at the printer. Switch the TSEND_C / TSEND target back to 192.168.1.50:9100 and trigger a print. Monitor DONE / ERROR / STATUS at the FB instance DB.
  6. Capture STATUS on error. Latch STATUS into a separate DB on the rising edge of ERROR so that fast-cycling diagnostic values are not lost.
  7. Verify label content. Confirm that variable fields (Julian date, serial number) are populated correctly. If a field prints as a literal string (e.g. "<SERIAL_NO>"), the substitution in the PLC string build is the issue, not the printer.

10. Troubleshooting Matrix

Symptom Likely root cause Diagnostic Remediation
STATUS = W#16#0000, no print TCON never established Check TCON.DONE Verify IP, mask, gateway; verify printer power and link LED
STATUS = W#16#80C4 TCP timeout, partner unreachable ping printer from engineering station Cabling, IP conflict, firewall on managed switch
STATUS = W#16#80C7 Printer reset TCP socket Check ZebraNet event log Reduce send rate; check for malformed ZPL causing printer error
STATUS = W#16#80C1 ID mismatch Cross-check NetPro vs FB call Use the same ID value declared in NetPro
STATUS = W#16#80D2 LEN > SEND buffer size Inspect ANY pointer Increase data block size or split label into multiple sends
STATUS flashes 7000/7001/0000 but no label ZPL syntax error Send same string from Hercules Fix ^XA framing or missing ^FS terminators
Label prints once, then no further prints TCP socket closed by printer Monitor TCON.DONE Set CONT=TRUE on TSEND_C or hold REQ on TCON
Partial label / cut-off text Buffer truncated Inspect LEN vs actual string length Send full length including ^XZ
Status remains W#16#7000 forever REQ never received a rising edge Force REQ=TRUE in VAT Check trigger condition logic upstream
Garbage characters in label Encoding mismatch (UTF-8 vs ASCII) Hex dump first 32 bytes received at printer Strip high-bit characters; use ASCII-only ZPL tokens

11. Performance, Limits, and Safety

Label size. A typical 4 in × 2 in Code 128 barcode label produces 200-500 bytes of ZPL. The S7-300 CPU with a CP343-1 and a standard STRING DB of 512 bytes is more than adequate. For very long labels (full A4-equivalent industrial documents) raise the STRING length to 1024 or 2048 bytes.

Throughput. Each TSEND cycle on an S7-1500 is 1-3 ms over a 100 Mbit/s link; on an S7-315-2 PN/DP expect 5-15 ms. The Zebra 105SL Plus at 203 dpi prints a 4 in × 2 in label in roughly 1 s, so PLC transmit time is never the bottleneck.

Network load. At 10 labels/min the data rate is approximately 5 kbit/s sustained. No QoS or VLAN segmentation is required for the printer traffic alone, but isolating the line network from the office network prevents broadcast storms from disrupting print jobs.

Connection limits. S7-300 CPUs typically allow 8-16 concurrent Open User Communication connections depending on the CPU model and firmware. S7-1500 allows up to 64. Zebra printers use one TCP socket per print job; use the hold-open pattern to stay well under the limit.

Safety. PLC-driven label printing is typically used for traceability on non-safety-related processes. If the label is part of a safety-of-function chain (e.g. identifying a load-bearing component), the printer subsystem must be treated as part of the safety integrity calculation per IEC 61511 or ISO 13849, and the absence of a printed label must result in a defined safe state (reject station, line stop).

12. Additional Notes for S7-1200 and S7-1500 Variants

The procedure above is identical for S7-1200 with one caveat: the S7-1200 firmware V4.0 introduced TSEND_C; older firmware V3.x uses the separate TCON, TSEND, TRCV blocks. TIA Portal's Add new connection panel automatically generates a TCON_IP_V4 structure when you drag a TSEND_C block; simply edit the four ADDR bytes and the RemotePort member.

For S7-1500 with multiple printers, encapsulate each connection in a multi-instance DB or in a separate FB. The recommended pattern is one FB instance per printer and a centralized scheduler DB that holds the current state (idle / connecting / sending / error) for each printer. Siemens' SIMATIC S7-1500 Communication function manual provides further detail on multi-instance usage.

13. Frequently Asked Questions

Why does TSEND status show 7000 even when a label has been printed?

STATUS 7000 means "no active job", which is the normal idle state once TSEND has returned DONE=TRUE. The send typically completes in a single PLC cycle, so the only way to capture the success state is to latch the DONE bit on its rising edge into a separate data block.

Which TCP port does the Zebra 105SL Plus use for raw ZPL printing?

The raw ZPL print queue listens on TCP port 9100 by default. Port 6101 is reserved for ZebraNet status monitoring, not for label streaming. Confirm the active port via the ZebraNet web page under Network > TCP/IP Settings.

Can I use ISO-on-TCP (RFC1006) instead of TCP for the Zebra printer?

No. The Zebra print server does not implement ISO-on-TCP. Use plain TCP (protocol type 0x0B in TSEND_C) with the active-connection flag set TRUE on the PLC side.

How do I test the printer without involving the PLC?

Use Hercules SETUP utility in TCP Client mode pointing at the printer's IP and port 9100. Paste a ZPL string captured from ZebraDesigner's "Print to File" feature and press Send; a correctly framed ^XA ... ^XZ stream will print the label immediately.

Do I need to close the TCP connection after every label?

No. The recommended pattern is to hold the connection open (CONT=TRUE on TSEND_C, or REQ permanently TRUE on TCON) and resend on demand. This minimizes SYN/SYN-ACK overhead and works reliably with the Zebra 105SL Plus firmware.

What status code indicates the printer is unreachable?

W#16#80C4 indicates a TCP connection timeout, typically caused by a wrong IP, blocked port, or powered-off printer. Use a ping test to isolate which.

Does the S7-300 need a CP343-1 for this, or will the integrated PROFINET port work?

Any S7-300 CPU with an integrated PROFINET interface (such as 315-2 PN/DP) supports Open User Communication directly. CPUs with only MPI/DP require a CP343-1 advanced or CP343-1 Lean Ethernet module.

Back to blog