Industrial 7-Segment Display Control System over Embedded Linux & TCP/IP
Watch System in Action:
In this industrial automation setup, we showcase real-time remote control of a 4-digit industrial 7-segment display panel using a C host engine, Lua scripting, and TCP/IP socket communication running on the RDF-GW2 Embedded Linux Gateway. The system features seamless hot-reloading (live code updates) and a high-speed shared memory IPC architecture.
System Architecture & Software Layers
The field display control system is designed with a layered software architecture to ensure high performance, modularity, and rapid live development:
- RDF-GW2 (Embedded Linux Gateway): Located at the heart of the system, this Linux-based gateway device executes low-level hardware drivers and high-level application services simultaneously.
- C Driver Core (Segment Driver): Directly controls shift-register ICs and digital pin matrices at the hardware layer, enabling high-frequency scanning of 7-segment characters and decimal points.
- Shared Memory (/dev/shm IPC): Utilizes the Linux RAM-based `/dev/shm` filesystem for zero-latency data exchange between the C driver engine and the Lua application layer.
- Seamless Lua Engine & Hot-Reloading: The `script.lua` file is monitored by the C engine via `mtime` tracking. Code modifications deployed via SFTP are instantly loaded into the live environment without service downtime.
- TCP Socket Server & Python Client: A non-blocking TCP server listening on Port 5000 allows remote PCs, PLCs, or SCADA systems (via a Python client) to send dynamic character strings over the network to update the panel in real time.
Key Features & Operating Principles
Live Hot-Reloading
Lua code updated from VS Code is immediately detected and reloaded by the C host program without dropping active TCP socket connections or requiring a system reboot.
Remote TCP Socket Control
Text payloads like `"12.34"` or `"A.B.C.D."` sent from Python or any TCP client are automatically parsed and displayed on the 4-digit panel with sub-second latency.
Decimal Point (DP) Support
Thanks to smart string-parsing logic, dot `.` characters do not occupy an extra digit slot; instead, they automatically activate the decimal LED segment (`Bit 7 / 0x80`) of the corresponding digit.
High-Speed Shared Memory (IPC)
Leveraging Linux `/dev/shm` (Shared Memory) eliminates disk I/O overhead, allowing the Lua script and C driver to communicate through system RAM within microseconds.
Implementation Code Examples
Below are the practical implementation scripts powering the IPC write interface, non-blocking TCP server, and client communication:
1. Direct IPC Memory Writing (Basic Lua Example)
This initial script demonstrates writing character payloads directly to the RAM-backed /dev/shm/ nodes monitored by the C driver core:
-- script.lua
print("--- 7-Segment Control ---")
local function io_write(display_node, payload)
local path = "/dev/shm/" .. display_node .. "_out"
local file = io.open(path, "w")
if file then
file:write(tostring(payload))
file:close()
else
print("Error: Could not write to target shared memory " .. path)
end
end
local display1 = "display1"
local display2 = "display2"
local display3 = "display3"
local display4 = "display4"
io_write(display1, "1")
io_write(display2, " ")
io_write(display3, " ")
io_write(display4, " ")
--os.execute("sleep 1")
2. Non-Blocking TCP Display Server (Advanced Lua Service)
This production script runs on Port 5000. On each loop step, it polls for incoming socket clients, handles decimal point placement automatically, and updates shared memory:
-- /root/script.lua
local socket = require("socket")
print("--- Starting Non-Blocking TCP Display Server (Port 5000) ---")
-- Bind TCP server once on load
local server = assert(socket.bind("*", 5000))
server:settimeout(0) -- Non-blocking check
local function io_write(display_node, payload)
local path = "/dev/shm/" .. display_node .. "_out"
local file = io.open(path, "w")
if file then
file:write(tostring(payload))
file:close()
else
print("Error: Could not write to " .. path)
end
end
local function update_displays(text)
local displays = {"display1", "display2", "display3", "display4"}
local char_idx = 1
local text_len = #text
for d = 1, 4 do
if char_idx <= text_len then
local char = text:sub(char_idx, char_idx)
local payload = char
if char_idx + 1 <= text_len and text:sub(char_idx + 1, char_idx + 1) == "." then
payload = payload .. "."
char_idx = char_idx + 2
else
char_idx = char_idx + 1
end
io_write(displays[d], payload)
else
io_write(displays[d], " ")
end
end
end
-- This function will be called by C on every loop tick
function step()
local client = server:accept()
if client then
client:settimeout(0.5)
local line, err = client:receive()
if not err and line then
print("Received command: " .. line)
update_displays(line)
client:send("OK\n")
end
client:close()
end
end
3. Remote Python Socket Client
A lightweight Python script that connects to the RDF-GW2 Gateway over TCP and sends commands (e.g., python send_display.py "12.34"):
import socket
import sys
GATEWAY_IP = "192.168.1.50"
GATEWAY_PORT = 5000
def send_to_display(text: str):
"""
Sends a string payload over TCP to the 7-segment Gateway.
Examples:
- "1234" -> Displays 1, 2, 3, 4
- "1.234" -> Displays 1. on segment 1, 2, 3, 4 on rest
- "A B C" -> Displays A, space, B, space
"""
try:
# Create TCP/IP socket
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as client:
client.settimeout(2.0)
client.connect((GATEWAY_IP, GATEWAY_PORT))
# Send message terminated with a newline
message = text + "\n"
client.sendall(message.encode('utf-8'))
# Wait for acknowledgement from Gateway
response = client.recv(1024).decode('utf-8')
print(f"Gateway Response: {response.strip()}")
except Exception as e:
print(f"Error communicating with Gateway ({GATEWAY_IP}): {e}")
if __name__ == "__main__":
if len(sys.argv) > 1:
# Pass command line argument if provided: python send_display.py "12.34"
display_text = sys.argv[1]
else:
# Default test string
display_text = "0050"
print(f"Sending '{display_text}' to 7-Segment Gateway ({GATEWAY_IP})...")
send_to_display(display_text)
Unlike traditional displays with rigid firmware, this flexible Linux architecture and remote TCP connectivity make it easy to deploy as a dynamic status indicator, counter, or telemetry panel in demanding industrial environments.