S7-200 SMART TCP_Recv Returns Only One Character Per Send

David Krause12 min read
S7-200SiemensTroubleshooting
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: TCP_Recv Returns One Character When Sending Multi-Byte Strings

On a Siemens SIMATIC S7-200 SMART CPU (CPU SR20, SR30, SR40, SR60, ST20, ST30, ST40, ST60, CR40, or CR60), the Open User Communication (OUC) library blocks TCP_Connect, TCP_Send, and TCP_Recv are configured to communicate with a Windows terminal emulator. The TCP connection establishes successfully, the handshake completes (Status = 0x0002), and the Done bit pulses on the receive block. The defect appears as follows:

PC send (HyperTerminal) PLC VB buffer contents Observed result
1 VB100 = 0x31 OK
17 (two characters) VB100 = 0x37 ('7') '1' lost
ABC (three characters) VB100 = 0x43 ('C') Only last character captured

The data path is correct; the loss is in application-side buffer management. The PLC receives one TCP segment per keystroke, and the user program is not buffering segments or detecting the end of a logical message.

Affected Hardware, Firmware, and Software

Item Value
CPU family S7-200 SMART (firmware ≥ V2.0 required for Open User Communication)
Standard CPUs CPU SR20, SR30, SR40, SR60
Signal-board CPUs CPU ST20, ST30, ST40, ST60
Compact CPUs CPU CR40, CR60
Programming software STEP 7 Micro/WIN SMART V2.5 or later
Library Open User Communication (TCP, UDP, ISO-on-TCP, Modbus TCP, USS)
Maximum active OUC connections 8 simultaneous (Connection IDs 1-8)
Ethernet interface PROFINET port, 10/100 Mb/s, RJ45
Open User Communication is supported only on S7-200 SMART CPUs that ship with the integrated PROFINET/Ethernet port. The S7-200 SMART does not use the S7-300/400 "Open Communication Wizard" blocks (FB63/64/65). It uses the OUC library designed specifically for Micro/WIN SMART. See the SIMATIC S7-200 SMART System Manual (English) for full block descriptions.

Root Cause Analysis

Four distinct causes can produce the "single-character" symptom. Diagnose which one applies before applying a fix.

Cause 1 – TCP Segmentation Is Independent of Application Framing

TCP is a byte-stream protocol; it does not preserve message boundaries. When HyperTerminal transmits 17 with a line ending, the kernel may emit one segment 0x31 0x37 or two segments 0x31 and 0x37, depending on Nagle algorithm, terminal echo, and time between keystrokes. TCP_Recv returns whatever bytes are currently queued; it does not wait for a logical message end.

Cause 2 – Done Bit Is Not Polled Continuously

The OUC blocks use a standard EN/ENO pattern. The Done bit (Status = 0x7002) is set for one scan only when the internal job is complete. If user logic only latches the buffer on the first rising edge, subsequent segments overwrite the buffer before being read.

Cause 3 – ASCII Mode Mismatch Between HyperTerminal and PLC

HyperTerminal can be configured to send characters in different ways: raw per keystroke, on CR (carriage return 0x0D), on LF (0x0A), or on CR+LF (0x0D 0x0A). If the PC sends 17 followed by a line terminator, the PLC receives 0x31 0x37 0x0D 0x0A. If user code reads the buffer immediately and only writes the first byte to the destination, the rest is dropped on the next scan cycle.

Cause 4 – HyperTerminal Encoding Anomaly

HyperTerminal's character map is tied to the Windows "Country" codepage. On systems set to non-Latin codepages (e.g., Eastern European), characters in the 0x80-0xFF range can be silently translated. Use Hercules SETUP, Tera Term, or PuTTY with UTF-8 or ANSI Latin-1 codepage to eliminate the variable.

S7-200 SMART Open User Communication Block Reference

Three blocks are used in this scenario. Refer to the S7-200 SMART System Manual, section on Open User Communication for the complete parameter list and timing diagrams.

TCP_Connect (UTCP_Connect) Parameters

Parameter Type Description
EN BOOL Enable / start connection request
ConnID BYTE Connection identifier (1-8), unique per OUC session
IPaddr1..4 BYTE Remote IP octets (e.g., 192, 168, 1, 10)
RemPort WORD Remote TCP port (23 = telnet, 5001 = Hercules TCP server default)
LocPort WORD Local TCP port (0 = assign automatically)
Done BOOL TRUE for one scan when connect completes
Busy BOOL TRUE while connect is in progress
Error BOOL TRUE if connect failed
Status WORD Error / status code

TCP_Send (UTCP_Send) Parameters

Parameter Type Description
EN BOOL Trigger send on rising edge
ConnID BYTE Must match the active ConnID
DataPtr DWORD &VB pointer to data to send (e.g., &VB100)
DataLen WORD Number of bytes to transmit (1-200)
Done / Busy / Error / Status BOOL / BYTE / WORD Same semantics as TCP_Connect

TCP_Recv (UTCP_Recv) Parameters

Parameter Type Description
EN BOOL Trigger receive (level-sensitive or rising edge with re-arm logic)
ConnID BYTE Must match the active ConnID
DataPtr DWORD &VB pointer to receive buffer (e.g., &VB200)
DataLen WORD Max buffer size (1-200); PLC fills up to this many bytes
Done BOOL TRUE for one scan when bytes have been written to buffer
Busy BOOL TRUE while receive is in progress
Error BOOL TRUE on receive error
Status WORD Error / status code
Critical point: TCP_Recv.DataLen is the maximum number of bytes the PLC will accept into the buffer. The actual number of bytes received is not returned as an output. You must either (a) read the full buffer on every Done pulse and parse for a delimiter, or (b) implement a fixed-length protocol.

TCP_Recv and TCP_Connect Status Codes

Status (hex) Meaning Action
0x0000 No error, no operation OK
0x0001 Connection in progress Wait
0x0002 Connection established Proceed with send/recv
0x0003 Connection terminated Re-arm TCP_Connect
0x7000 No job active Normal idle
0x7001 Job starting (first scan with EN=1) Wait
0x7002 Job in progress, Done=1 when complete Latch result on Done
0x8001 Connection ID invalid Re-initialize
0x8002 Parameter error (DataPtr/DataLen out of range) Validate pointer and length
0x8003 Connection failed (remote refused/timeout) Check remote IP/port/firewall
0x8004 Local port already in use Change LocPort or set to 0
0x8005 No resources (max 8 connections) Close unused connections
0x8006 Send buffer overflow Reduce DataLen or rate
0x8007 Receive buffer overflow Increase DataLen or drain faster
0x8008 Connection closed by remote Re-arm TCP_Connect
0x8009 Communication timeout Check network

Step-by-Step Fix: Buffer Multi-Byte Messages Until Terminator

The robust pattern: always arm TCP_Recv with EN=1, and on every Done pulse append the buffer contents to a FIFO while scanning for a CR/LF or fixed-length terminator. The sequence below assumes CPU SR30, STEP 7 Micro/WIN SMART V2.5+, and a server port of 5001.

Prerequisites

  1. CPU S7-200 SMART with firmware ≥ V2.0 (check in System Information → CPU Information).
  2. STEP 7 Micro/WIN SMART V2.5 or later installed.
  3. Open User Communication library installed (default location: C:\Program Files (x86)\Siemens\Automation\MicroWIN SMART\Lib\Open_User_Communication).
  4. PC and PLC on the same subnet. CPU has a static IP (e.g., 192.168.1.50); the PC has a compatible static IP (e.g., 192.168.1.10).
  5. Hercules SETUP utility for reliable terminal emulation. HyperTerminal is deprecated on Windows 10/11 and has known codepage issues.

Procedure

  1. Reserve V memory. Allocate a 200-byte receive scratch buffer VB200..VB399 and a 200-byte assembly buffer VB400..VB599. Also allocate a counter VW600 for "bytes in assembly buffer" and a "terminator received" flag VB610.0.
  2. Configure TCP_Connect (one-shot). Set ConnID = 1, IPaddr1..4 = 192, 168, 1, 10, RemPort = 5001, LocPort = 0. Drive EN with a one-shot from the first scan, gated by a connection-failed retry timer.
  3. Configure TCP_Recv (continuously armed). Set ConnID = 1, DataPtr = &VB200, DataLen = 200. Wire EN to SM0.0 (always TRUE) AND a "not in error state" boolean. The block re-arms automatically after each Done pulse.
  4. Implement FIFO copy on Done. In a sub-routine triggered by the rising edge of TCP_Recv.Done:
    • Copy VB200..VB(200+DataLen-1) byte-by-byte to VB400+VW600.
    • Increment VW600 by the number of bytes copied (use a fixed assumption of 200 if actual length is unknown, and rely on the terminator to mark end).
    • Scan the freshly-copied range for 0x0D (CR) or 0x0A (LF). When found, set VB610.0 = 1.
  5. Process complete message. In a network that tests VB610.0, copy the assembly buffer to the application variable area, reset VW600 = 0, clear VB400..VB599, and reset VB610.0 = 0.
  6. Send response (optional). Drive TCP_Send with a rising edge after processing. Set DataPtr = &VB700, DataLen = actual response length.

Sample Ladder Excerpt (Conceptual)

Network 1 - TCP_Connect (one-shot on first scan)
   SM0.1        TCP_Connect_EN   (EN)
                ConnID=1
                IP: 192.168.1.10:5001
                LocPort=0
                -> TCP_Connect.Done  -> Set M0.0 (Connected)
                -> TCP_Connect.Error -> Set M0.1 (ConnectError)

Network 2 - TCP_Recv continuously armed
   SM0.0        TCP_Recv_EN       (EN)
   NOT M0.1     (gate on no error)
                ConnID=1
                DataPtr = &VB200
                DataLen = 200
                -> TCP_Recv.Done  -> SBR_0  (Process_Recv)

Network 3 - SBR_0: copy and scan for terminator
   FOR VW700 = 0 TO 199
     VB[400 + VW600 + VW700] = VB[200 + VW700]
   NEXT
   VW600 = VW600 + 200
   FOR VW700 = 0 TO 199
     IF VB[400 + VW700] == 0x0D THEN
       SET VB610.0
       EXIT FOR
     END_IF
   NEXT

ASCII Framing Alternatives

Strategy PC send pattern PLC detection Pros Cons
CR/LF terminator Adds 0x0D 0x0A after every command Scan buffer for 0x0D or 0x0A Simple, human-readable, works with terminal 0x0D/0x0A cannot appear in payload
Fixed length Pads to constant byte count Count bytes in FIFO Predictable timing Wastes bandwidth on short messages
Length prefix First byte = payload length Read first byte, then N more Efficient, no escaping needed More complex logic
STX/ETX framing 0x02 ... 0x03 Look for 0x02, then 0x03 Industry-standard, many libraries Needs byte-stuffing if 0x02/0x03 in data

Replace HyperTerminal With Hercules SETUP

HyperTerminal Private Edition (last release 2008) is not shipped with Windows 10/11. It exhibits three problems on modern systems:

  1. Codepage substitution: characters above 0x7F are remapped based on Windows regional settings.
  2. No raw byte view: it forces an ANSI/UTF display, hiding protocol bytes.
  3. No persistent log: it is not possible to capture a session for post-mortem.

Hercules SETUP is a freeware utility by HW-Group. To configure a TCP server on port 5001:

  1. Launch Hercules, click the TCP Server tab.
  2. Set Port = 5001.
  3. Click Listen. The status panel reads Listening on 0.0.0.0 : 5001.
  4. Type 17<Enter> in the Send box and click Send. Switch to hex view to confirm the bytes 31 37 0D 0A.

Alternatives: Tera Term (free, supports VT100 and hex view) or PuTTY with Connection type: Raw.

Verification Procedure

  1. Watch TCP_Recv.Done in a status table. It must pulse on every segment arrival, not just on the first.
  2. Monitor VB200..VB220 in a status table. After sending 17 from the PC, the buffer must read 31 37 0D 0A (assuming CR+LF).
  3. Confirm VW600 grows with each segment. After three Done pulses from a single line, the count must equal the number of bytes sent (typically 4 for 17\r\n).
  4. Trigger on VB610.0. Set a watch on this flag – it must transition to 1 the instant a CR/LF is seen in the assembly buffer.
  5. Wireshark cross-check. Capture the PC Ethernet port with Wireshark filter tcp.port == 5001. Confirm segment boundaries match what the PLC receives.
  6. Load test. Send 100 commands of 20 characters each from a script (Python socket, nc on Linux, or Hercules "send file"). All 100 must reach the application variable area intact.

Troubleshooting Matrix

Symptom Likely cause Fix
Connection never completes, Status=0x8003 Wrong remote IP/port, PC firewall blocking 5001 ping PC from PLC (use ping block), open Windows Firewall port 5001
Connection completes, but TCP_Recv.Done never pulses PC not sending data, or EN not continuously driven Drive EN with SM0.0 and a NOT-error gate; verify with Hercules "Send" button
Only first byte captured, others lost Logic reads VB200 only; doesn't loop to VB200+N Implement FIFO copy from VB200 to VB400+VW600 on every Done
Receives garbage / wrong characters Codepage mismatch (HyperTerminal) Switch to Hercules or Tera Term in ASCII Latin-1/UTF-8
Receives echoes of sent data Local echo on, server echoes input Disable echo in Hercules; design protocol to ignore echoed characters
Status=0x8007 receive buffer overflow PLC not draining buffer fast enough Increase FIFO size, shorten scan time, or implement socket flush on error
Works for low rate, fails at high rate Scan time too long; blocks queue up Lower priority of TCP_Recv execution, or use a one-shot EN with a "Drain Complete" flag
Status=0x8004 on TCP_Connect Local port already in use (e.g., by another OUC connection) Use LocPort=0 (auto) or unique port per ConnID
Bytes appear corrupted on PLC side Endianness or data type mismatch in DataPtr Use byte pointer &VBxxx, not &VWxxx or &VDxxx

Performance and Limit Reference

Parameter Value
Max active OUC connections per CPU 8
Connection ID range 1-8
Max payload per TCP_Send / TCP_Recv 200 bytes
Theoretical throughput ~8-10 MB/s on PROFINET port (depends on scan time and OUC load)
Recommended minimum scan time for full-rate TCP_Recv ≤ 20 ms
Port range restrictions Avoid privileged ports < 1024 unless required; avoid well-known ports (80, 443, 502, 44818, etc.)

Safety and Liveness Checks

  1. Watchdog on TCP_Connect failure. If Error remains TRUE for > 5 s, drop and re-arm with a 1 s delay to avoid thrashing the OUC state machine.
  2. Limit assembly buffer growth. If VW600 > 190 without a terminator detected, discard the buffer and reset the counter. This prevents an attacker (or noisy line) from filling V memory.
  3. Validate payload. If a command frame has unknown length or unknown opcode, drop it and reply with NAK. Do not act on incomplete frames.

Why does TCP_Recv give me only one byte even though I sent multiple characters?

TCP is a byte stream with no inherent message boundaries. Each Done pulse from TCP_Recv returns whatever bytes were in the receive queue at that instant, often just one TCP segment. Implement a FIFO in user logic and look for a terminator (CR, LF, length prefix, or STX/ETX) to assemble complete messages.

Does TCP_Recv return the actual number of bytes received?

No. The DataLen input is the maximum buffer size (1-200), and the actual received byte count is not exposed as an output. Parse the buffer for a delimiter, or use a fixed-length protocol, to know when a message is complete.

Can I use HyperTerminal on Windows 10/11 for S7-200 SMART TCP testing?

HyperTerminal is deprecated and not shipped with Windows 10/11. Even HyperTerminal Private Edition 2008 has known codepage and hex-view limitations. Use Hercules SETUP, Tera Term, or PuTTY in raw mode for reliable, repeatable TCP testing.

How many OUC connections can a single S7-200 SMART CPU maintain?

Up to 8 simultaneous Open User Communication connections, with Connection IDs 1 through 8. Each consumes internal resources; plan the connection table carefully if you also need S7/PG communication, Modbus TCP server, and PUT/GET.

Which firmware version first added Open User Communication to the S7-200 SMART?

Open User Communication (TCP, UDP, ISO-on-TCP, Modbus TCP, USS) was added in S7-200 SMART CPU firmware V2.0 (released 2013). CPUs with firmware V1.x do not support the OUC library.

Back to blog