<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB">
	<id>https://wiki.commander4j.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Dgarratt</id>
	<title>Commander4j - User contributions [en-gb]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.commander4j.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Dgarratt"/>
	<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=Special:Contributions/Dgarratt"/>
	<updated>2026-07-30T04:56:46Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.45.3</generator>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=Menu4j&amp;diff=1907</id>
		<title>Menu4j</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=Menu4j&amp;diff=1907"/>
		<updated>2026-07-21T14:59:32Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: /* The Menu Tree */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Menu4j (JMenuTree) is a desktop command launcher that organises shell commands, scripts, and applications into a hierarchical tree menu. It provides a configurable, script-aware alternative to Finder shortcuts and shell aliases, with support for real-time terminal output, multiple linked menu trees, and optional startup password protection.&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
Menu4j is used to organise the day-to-day development and operational commands for the Commander4j suite in a single, structured interface. Menu items can run shell scripts, open applications, pass parameters, capture output, and link to other menu tree files.&lt;br /&gt;
&lt;br /&gt;
== Running Menu4j ==&lt;br /&gt;
&lt;br /&gt;
Native install packages for Windows, macOS, and Linux are available from the [[Downloads]] page and are the preferred installation method.&lt;br /&gt;
&lt;br /&gt;
Alternatively, Menu4j can be run directly from the distribution archive. It is a Java 25 desktop (Swing) application:&lt;br /&gt;
&lt;br /&gt;
 java -jar JMenu.jar&lt;br /&gt;
&lt;br /&gt;
On first launch, if no configuration file is found, Menu4j copies a template configuration from &amp;lt;code&amp;gt;xml/config/init/config.xml&amp;lt;/code&amp;gt; and a template menu tree from &amp;lt;code&amp;gt;xml/tree/init/tree.xml&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If a startup password has been configured, you are prompted to enter it before the menu is shown. Three failed attempts close the application.&lt;br /&gt;
&lt;br /&gt;
== The Menu Tree ==&lt;br /&gt;
&lt;br /&gt;
The main window displays a JTree. There are two node types:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| Branch || A folder that contains other branches or leaves&lt;br /&gt;
|-&lt;br /&gt;
| Leaf || An executable item — a command, script, or application&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Double-click a leaf to execute it. Double-click a branch to expand or collapse it.&lt;br /&gt;
&lt;br /&gt;
=== Adding and Editing Items ===&lt;br /&gt;
&lt;br /&gt;
The right sidebar toolbar provides:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Add&#039;&#039;&#039; — insert a new branch or leaf under the selected node&lt;br /&gt;
* &#039;&#039;&#039;Edit&#039;&#039;&#039; — open the editor for the selected node&lt;br /&gt;
* &#039;&#039;&#039;Delete&#039;&#039;&#039; — remove the selected node&lt;br /&gt;
* &#039;&#039;&#039;Duplicate&#039;&#039;&#039; — copy the selected node&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:JMenuTree1.png|400px]]&lt;br /&gt;
&lt;br /&gt;
=== Leaf Properties ===&lt;br /&gt;
&lt;br /&gt;
When editing a leaf node, the following properties are available:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Property !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Description || The label shown in the menu tree&lt;br /&gt;
|-&lt;br /&gt;
| Directory || The working directory for the command&lt;br /&gt;
|-&lt;br /&gt;
| Command || The executable or system command to run&lt;br /&gt;
|-&lt;br /&gt;
| Parameters || A list of arguments to pass to the command&lt;br /&gt;
|-&lt;br /&gt;
| Shell Script Required || Whether to wrap the command in the configured shell wrapper script&lt;br /&gt;
|-&lt;br /&gt;
| Terminal Window Required || Whether to open a terminal output window to show command output&lt;br /&gt;
|-&lt;br /&gt;
| Confirm Execute || Whether to show a confirmation prompt before running&lt;br /&gt;
|-&lt;br /&gt;
| Link to Menu Tree || Whether this item opens a different tree file instead of running a command&lt;br /&gt;
|-&lt;br /&gt;
| Hint || A tooltip shown when hovering over the item&lt;br /&gt;
|-&lt;br /&gt;
| Icon || An image file to display next to the item label&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:JMenuTree2.png|600px]]&lt;br /&gt;
&lt;br /&gt;
== Executing Commands ==&lt;br /&gt;
&lt;br /&gt;
When a leaf is executed:&lt;br /&gt;
&lt;br /&gt;
# Menu4j validates that the directory and command exist&lt;br /&gt;
# If &#039;&#039;&#039;Shell Script Required&#039;&#039;&#039; is set, the command is wrapped using the script configured in Settings (typically a shell wrapper that sources the user&#039;s environment)&lt;br /&gt;
# If &#039;&#039;&#039;Terminal Window Required&#039;&#039;&#039; is set, a terminal output window opens and displays stdout and stderr in real time; otherwise the command runs silently in the background&lt;br /&gt;
# Environment variables configured in Settings are injected before execution&lt;br /&gt;
&lt;br /&gt;
=== Terminal Output Window ===&lt;br /&gt;
&lt;br /&gt;
The terminal window displays command output with configurable foreground and background colours and font (configured in Settings). A &#039;&#039;&#039;Respond&#039;&#039;&#039; button allows text to be sent to the command&#039;s standard input for interactive commands. When the command completes, the return code is displayed.&lt;br /&gt;
&lt;br /&gt;
== Multiple Tree Files ==&lt;br /&gt;
&lt;br /&gt;
A leaf node can be configured to switch to a different menu tree rather than execute a command. Set &#039;&#039;&#039;Link to Menu Tree&#039;&#039;&#039; and specify the filename. Double-clicking the leaf saves the current tree&#039;s expansion state and loads the linked tree. The application title bar updates to show the active tree filename.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
=== config.xml ===&lt;br /&gt;
&lt;br /&gt;
Located at &amp;lt;code&amp;gt;xml/config/config.xml&amp;lt;/code&amp;gt;. This file stores global settings including the active tree filename, shell script settings, colours, fonts, environment variables, system command whitelist, and the encrypted startup password.&lt;br /&gt;
&lt;br /&gt;
=== tree.xml ===&lt;br /&gt;
&lt;br /&gt;
Located at &amp;lt;code&amp;gt;xml/tree/tree.xml&amp;lt;/code&amp;gt; (or a different filename if you have switched trees). This is the menu structure file. It is written automatically when you save from the application.&lt;br /&gt;
&lt;br /&gt;
=== tree.xml.state ===&lt;br /&gt;
&lt;br /&gt;
Located alongside the tree file. Records which branches were expanded on the last exit and restores them on next launch.&lt;br /&gt;
&lt;br /&gt;
== Settings ==&lt;br /&gt;
&lt;br /&gt;
Open Settings from the toolbar to configure:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Setting !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Password || Optional startup password (stored AES-encrypted)&lt;br /&gt;
|-&lt;br /&gt;
| Shell script || Enable/disable the shell wrapper and set the script filename&lt;br /&gt;
|-&lt;br /&gt;
| Terminal colours || Foreground and background colours for the terminal output window&lt;br /&gt;
|-&lt;br /&gt;
| Tree colours || Foreground colours for leaf and branch labels&lt;br /&gt;
|-&lt;br /&gt;
| Fonts || Font choice and size for the terminal window, leaf labels, and branch labels&lt;br /&gt;
|-&lt;br /&gt;
| Environment variables || Key/value pairs injected into every executed process&lt;br /&gt;
|-&lt;br /&gt;
| System commands || Whitelist of system commands (such as &amp;lt;code&amp;gt;open&amp;lt;/code&amp;gt;) that do not require a file path to be validated&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:JMenuTree3.png|600px]]&lt;br /&gt;
&lt;br /&gt;
== Tree Navigation ==&lt;br /&gt;
&lt;br /&gt;
The top toolbar provides four buttons for expanding and collapsing the tree:&lt;br /&gt;
&lt;br /&gt;
* Expand All&lt;br /&gt;
* Expand Selected Branch&lt;br /&gt;
* Collapse Selected Branch&lt;br /&gt;
* Collapse All&lt;br /&gt;
&lt;br /&gt;
== Saving ==&lt;br /&gt;
&lt;br /&gt;
Changes to the tree structure are saved using the &#039;&#039;&#039;Save&#039;&#039;&#039; button in the sidebar toolbar. You are prompted to save if you close the application with unsaved changes.&lt;br /&gt;
&lt;br /&gt;
See also: [[LaunchPad]], [[Downloads]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=ModbusBridge&amp;diff=1906</id>
		<title>ModbusBridge</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=ModbusBridge&amp;diff=1906"/>
		<updated>2026-07-15T20:10:43Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: Updated by push_wiki.py&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;Commander4j Modbus Bridge&#039;&#039;&#039; (&#039;&#039;util_modbusBridge&#039;&#039;) is a &#039;&#039;&#039;headless service&#039;&#039;&#039; that lets applications without [https://en.wikipedia.org/wiki/Modbus Modbus/TCP] client capability set and query the values of a remote Modbus server over a simple REST API. It connects to one Modbus server, polls a fixed list of &#039;&#039;&#039;named points&#039;&#039;&#039; (configured in XML), keeps the latest values in memory, and serves them over HTTP. It also provides a live web UI to view and change values, and a second page to tail the log.&lt;br /&gt;
&lt;br /&gt;
Unlike the interactive [[ModbusClient|Commander4j Modbus Client]], the Bridge runs unattended: it auto-reconnects when the link drops and is packaged to run as an operating-system service. It reuses the same Modbus engine as the [[ModbusClient]] and is a natural companion to the [[ModbusServer]].&lt;br /&gt;
&lt;br /&gt;
If you are new to Modbus, the [[ModbusClient#A Quick Modbus Primer|Modbus primer on the Modbus Client page]] explains the terms (client/server, unit ID, and the four data tables) used throughout this page.&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Bridge is useful when:&lt;br /&gt;
&lt;br /&gt;
* An application or script that cannot speak Modbus needs to read or write a PLC or other Modbus/TCP device over plain HTTP/JSON&lt;br /&gt;
* A remote Modbus server&#039;s values should be exposed on a network as named points rather than raw addresses&lt;br /&gt;
* An unattended, always-on bridge is needed that survives link drops and restarts as a managed service&lt;br /&gt;
* A browser-based view of live values, with inline editing and a live log, is wanted without installing a desktop tool&lt;br /&gt;
* A calling application must keep working, unchanged, while the physical Modbus device is out of service (see [[#Simulated points|Simulated points]])&lt;br /&gt;
&lt;br /&gt;
The Bridge is a &#039;&#039;&#039;generic tool&#039;&#039;&#039; — any application that can issue HTTP requests can use it. Within the Commander4j suite, for example, the web Issue application (&#039;&#039;c4j_web_Issue&#039;&#039;) can use it to pulse a PLC relay when a pallet is scanned in the wrong lane, but nothing about the Bridge is specific to that (or any other) application.&lt;br /&gt;
&lt;br /&gt;
== Source Code and Releases ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Bridge is open source and hosted on GitHub:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Repository:&#039;&#039;&#039; [https://github.com/C4J/ModbusBridge https://github.com/C4J/ModbusBridge]&lt;br /&gt;
* &#039;&#039;&#039;Releases (downloads):&#039;&#039;&#039; [https://github.com/C4J/ModbusBridge/releases https://github.com/C4J/ModbusBridge/releases]&lt;br /&gt;
&lt;br /&gt;
== Running the Modbus Bridge ==&lt;br /&gt;
&lt;br /&gt;
The recommended way to install the Modbus Bridge is to download a native installer for your platform, either from the [[Downloads]] page or from the [https://github.com/C4J/ModbusBridge/releases GitHub releases page]. Native installers are provided for &#039;&#039;&#039;Windows, macOS and Linux&#039;&#039;&#039;. Each installer bundles its own Java 25 runtime, so &#039;&#039;&#039;no separate Java installation is required&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== As a service ===&lt;br /&gt;
&lt;br /&gt;
The native installer registers and starts the Bridge as an operating-system service — &#039;&#039;&#039;launchd&#039;&#039;&#039; on macOS, a &#039;&#039;&#039;Windows service&#039;&#039;&#039;, or a &#039;&#039;&#039;systemd / init&#039;&#039;&#039; unit on Linux. The service runs with its working directory set to the installation directory, so all the relative paths below resolve correctly. Stopping the service triggers an ordered shutdown so that teardown events still reach the log file.&lt;br /&gt;
&lt;br /&gt;
=== Running from the jar ===&lt;br /&gt;
&lt;br /&gt;
Alternatively the Bridge can be launched from its distribution folder:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;./start_modbusBridge.sh&amp;lt;/code&amp;gt; (macOS/Linux) or &amp;lt;code&amp;gt;start_modbusBridge.cmd&amp;lt;/code&amp;gt; (Windows), or&lt;br /&gt;
* &amp;lt;code&amp;gt;ant run&amp;lt;/code&amp;gt; to launch from compiled classes, or&lt;br /&gt;
* directly with Java:&lt;br /&gt;
&lt;br /&gt;
 java -Dlog4j2.shutdownHookEnabled=false -Dlog4j2.configurationFile=xml/config/log4j2.xml -jar modbusBridge.jar&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;modbusBridge.jar&amp;lt;/code&amp;gt; is a &#039;&#039;&#039;thin jar&#039;&#039;&#039; — it references the dependency jars in &amp;lt;code&amp;gt;lib/&amp;lt;/code&amp;gt; via its manifest, so it must be run from the project root with &amp;lt;code&amp;gt;lib/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;xml/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;web/&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;logs/&amp;lt;/code&amp;gt; alongside it. Any Java 25 runtime on the &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; will do; a bundled JRE is not required when run this way.&lt;br /&gt;
&lt;br /&gt;
The two &amp;lt;code&amp;gt;-D&amp;lt;/code&amp;gt; system properties matter, and the start scripts set them for you:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;-Dlog4j2.shutdownHookEnabled=false&amp;lt;/code&amp;gt; — lets the Bridge&#039;s own shutdown hook stop log4j2 &#039;&#039;&#039;last&#039;&#039;&#039;, so teardown events still reach the log file the tail page reads.&lt;br /&gt;
* &amp;lt;code&amp;gt;-Dlog4j2.configurationFile=xml/config/log4j2.xml&amp;lt;/code&amp;gt; — &amp;lt;code&amp;gt;log4j2.xml&amp;lt;/code&amp;gt; lives under &amp;lt;code&amp;gt;xml/config/&amp;lt;/code&amp;gt;, not on the classpath, so log4j2 must be pointed at it explicitly.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
All configuration is in &amp;lt;code&amp;gt;xml/config/config.xml&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;config&amp;gt;&lt;br /&gt;
   &amp;lt;modbus&amp;gt;&lt;br /&gt;
     &amp;lt;ip&amp;gt;127.0.0.1&amp;lt;/ip&amp;gt;&lt;br /&gt;
     &amp;lt;port&amp;gt;1502&amp;lt;/port&amp;gt;&lt;br /&gt;
     &amp;lt;id&amp;gt;1&amp;lt;/id&amp;gt;&lt;br /&gt;
     &amp;lt;pollIntervalMs&amp;gt;1000&amp;lt;/pollIntervalMs&amp;gt;&lt;br /&gt;
     &amp;lt;maxHoldMs&amp;gt;60000&amp;lt;/maxHoldMs&amp;gt;&lt;br /&gt;
   &amp;lt;/modbus&amp;gt;&lt;br /&gt;
   &amp;lt;webserver&amp;gt;&lt;br /&gt;
     &amp;lt;ip&amp;gt;0.0.0.0&amp;lt;/ip&amp;gt;&lt;br /&gt;
     &amp;lt;port&amp;gt;8080&amp;lt;/port&amp;gt;&lt;br /&gt;
   &amp;lt;/webserver&amp;gt;&lt;br /&gt;
   &amp;lt;restapi&amp;gt;&lt;br /&gt;
     &amp;lt;id name=&amp;quot;LANEA&amp;quot; point=&amp;quot;pump_run&amp;quot; caseSensitive=&amp;quot;false&amp;quot;/&amp;gt;&lt;br /&gt;
     &amp;lt;id name=&amp;quot;LANEB&amp;quot; point=&amp;quot;pump_run&amp;quot; caseSensitive=&amp;quot;false&amp;quot;/&amp;gt;&lt;br /&gt;
   &amp;lt;/restapi&amp;gt;&lt;br /&gt;
   &amp;lt;points&amp;gt;&lt;br /&gt;
     &amp;lt;point name=&amp;quot;pump_run&amp;quot;   kind=&amp;quot;COIL&amp;quot;             address=&amp;quot;0&amp;quot;   initialise=&amp;quot;false&amp;quot; value=&amp;quot;false&amp;quot;&lt;br /&gt;
            minHoldMs=&amp;quot;500&amp;quot; maxHoldMs=&amp;quot;10000&amp;quot; defaultHoldMs=&amp;quot;3000&amp;quot;/&amp;gt;&lt;br /&gt;
     &amp;lt;point name=&amp;quot;tank_level&amp;quot; kind=&amp;quot;HOLDING_REGISTER&amp;quot; address=&amp;quot;100&amp;quot; initialise=&amp;quot;false&amp;quot; value=&amp;quot;0&amp;quot;/&amp;gt;&lt;br /&gt;
     &amp;lt;point name=&amp;quot;fault&amp;quot;      kind=&amp;quot;DISCRETE_INPUT&amp;quot;   address=&amp;quot;10&amp;quot;/&amp;gt;&lt;br /&gt;
     &amp;lt;point name=&amp;quot;flow_rate&amp;quot;  kind=&amp;quot;INPUT_REGISTER&amp;quot;   address=&amp;quot;30&amp;quot;/&amp;gt;&lt;br /&gt;
   &amp;lt;/points&amp;gt;&lt;br /&gt;
 &amp;lt;/config&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;&amp;lt;modbus&amp;gt;&amp;lt;/code&amp;gt; block points the Bridge at the remote Modbus server: its host &amp;lt;code&amp;gt;&amp;lt;ip&amp;gt;&amp;lt;/code&amp;gt;, TCP &amp;lt;code&amp;gt;&amp;lt;port&amp;gt;&amp;lt;/code&amp;gt; (the Modbus standard is &#039;&#039;&#039;502&#039;&#039;&#039;; the example uses &#039;&#039;&#039;1502&#039;&#039;&#039; because ports below 1024 need root on macOS/Linux), the unit / slave &amp;lt;code&amp;gt;&amp;lt;id&amp;gt;&amp;lt;/code&amp;gt; to address, and the &amp;lt;code&amp;gt;&amp;lt;pollIntervalMs&amp;gt;&amp;lt;/code&amp;gt; between reads. The optional &amp;lt;code&amp;gt;&amp;lt;maxHoldMs&amp;gt;&amp;lt;/code&amp;gt; is the default hold cap for points that do not set their own &amp;lt;code&amp;gt;maxHoldMs&amp;lt;/code&amp;gt; attribute (60&amp;amp;nbsp;000&amp;amp;nbsp;ms if absent) — see [[#Pulse (momentary output)|Pulse]] below. The &amp;lt;code&amp;gt;&amp;lt;webserver&amp;gt;&amp;lt;/code&amp;gt; block sets the bind address for the HTTP server (&amp;lt;code&amp;gt;0.0.0.0&amp;lt;/code&amp;gt; = all interfaces) and the port it listens on. The optional &amp;lt;code&amp;gt;&amp;lt;restapi&amp;gt;&amp;lt;/code&amp;gt; block maps application-facing ids onto points — see [[#REST ids (application names for points)|REST ids]] below.&lt;br /&gt;
&lt;br /&gt;
Each &amp;lt;code&amp;gt;&amp;lt;point&amp;gt;&amp;lt;/code&amp;gt; gives a human-friendly &#039;&#039;&#039;name&#039;&#039;&#039; (how REST clients and the web UI refer to it), a Modbus data table &#039;&#039;&#039;kind&#039;&#039;&#039;, and a zero-based protocol &#039;&#039;&#039;address&#039;&#039;&#039;. Valid kinds are &amp;lt;code&amp;gt;COIL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DISCRETE_INPUT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HOLDING_REGISTER&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;INPUT_REGISTER&amp;lt;/code&amp;gt;. Only &#039;&#039;&#039;coils&#039;&#039;&#039; and &#039;&#039;&#039;holding registers&#039;&#039;&#039; are writable — discrete inputs and input registers are read-only in the Modbus data model (there is no client-write function code for them).&lt;br /&gt;
&lt;br /&gt;
=== Startup initialisation (optional) ===&lt;br /&gt;
&lt;br /&gt;
Add &amp;lt;code&amp;gt;initialise=&amp;quot;true&amp;quot; value=&amp;quot;...&amp;quot;&amp;lt;/code&amp;gt; to a writable point to have the Bridge drive it to a known state at startup:&lt;br /&gt;
&lt;br /&gt;
* On the &#039;&#039;&#039;first successful connect&#039;&#039;&#039; after the Bridge starts, it reads the point&#039;s current value and writes &amp;lt;code&amp;gt;value&amp;lt;/code&amp;gt; &#039;&#039;&#039;only if it differs&#039;&#039;&#039; (an already-correct point is left untouched). This runs once — a later link drop and reconnect does &#039;&#039;&#039;not&#039;&#039;&#039; re-apply it, so runtime REST/operator changes survive an outage.&lt;br /&gt;
* If the Modbus server is unavailable at startup, initialisation simply waits and runs on the first connect once it becomes reachable.&lt;br /&gt;
* &amp;lt;code&amp;gt;value&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt; (or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;) for coils, and a &amp;lt;code&amp;gt;0..65535&amp;lt;/code&amp;gt; integer for holding registers. &amp;lt;code&amp;gt;initialise&amp;lt;/code&amp;gt; defaults to &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Configuration is rejected at startup if &amp;lt;code&amp;gt;initialise=&amp;quot;true&amp;quot;&amp;lt;/code&amp;gt; is set on a read-only kind, or without a &amp;lt;code&amp;gt;value&amp;lt;/code&amp;gt;, or with a value that does not match the kind.&lt;br /&gt;
&lt;br /&gt;
=== Per-point pulse hold policy (optional, writable points only) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;minHoldMs&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;maxHoldMs&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;defaultHoldMs&amp;lt;/code&amp;gt; control what a [[#Pulse (momentary output)|pulse]] request may ask this point to hold for:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;minHoldMs&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;maxHoldMs&amp;lt;/code&amp;gt; are the enforced bounds — a pulse whose &amp;lt;code&amp;gt;holdMs&amp;lt;/code&amp;gt; falls outside them is rejected with &#039;&#039;&#039;400&#039;&#039;&#039;. Defaults: min &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;, max = the global &amp;lt;code&amp;gt;&amp;lt;maxHoldMs&amp;gt;&amp;lt;/code&amp;gt; (60&amp;amp;nbsp;000 if that is absent too). A tight per-point range (e.g. &amp;lt;code&amp;gt;500..10000&amp;lt;/code&amp;gt; on a relay coil) means a typo like &amp;lt;code&amp;gt;30000&amp;lt;/code&amp;gt; for &amp;lt;code&amp;gt;3000&amp;lt;/code&amp;gt; can&#039;t hold the relay closed for half a minute.&lt;br /&gt;
* &amp;lt;code&amp;gt;defaultHoldMs&amp;lt;/code&amp;gt; is the hold applied when a pulse request omits &amp;lt;code&amp;gt;holdMs&amp;lt;/code&amp;gt; entirely, and is what the web UI pre-fills in the row&#039;s hold field (it is reported by the API for other clients to use the same way). Default: &amp;lt;code&amp;gt;3000&amp;lt;/code&amp;gt; — sized for switching an electrical relay — clamped into the min/max range. Keeping callers&#039; request bodies to just &amp;lt;code&amp;gt;{&amp;quot;value&amp;quot;: 1}&amp;lt;/code&amp;gt; leaves the relay timing centralised in the config file.&lt;br /&gt;
* Config-load validation enforces &amp;lt;code&amp;gt;1 ≤ minHoldMs ≤ defaultHoldMs ≤ maxHoldMs&amp;lt;/code&amp;gt; and rejects the attributes on read-only kinds.&lt;br /&gt;
&lt;br /&gt;
=== REST ids (application names for points) ===&lt;br /&gt;
&lt;br /&gt;
The optional &amp;lt;code&amp;gt;&amp;lt;restapi&amp;gt;&amp;lt;/code&amp;gt; section maps &#039;&#039;&#039;application-facing ids&#039;&#039;&#039; onto points, separating the caller&#039;s vocabulary from the physical wiring. Each &amp;lt;code&amp;gt;&amp;lt;id&amp;gt;&amp;lt;/code&amp;gt; gives a &amp;lt;code&amp;gt;name&amp;lt;/code&amp;gt; the REST API accepts and the &amp;lt;code&amp;gt;point&amp;lt;/code&amp;gt; it resolves to; several ids may map to the same point:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;restapi&amp;gt;&lt;br /&gt;
   &amp;lt;id name=&amp;quot;LANEA&amp;quot; point=&amp;quot;PLC_Link1&amp;quot;/&amp;gt;&lt;br /&gt;
   &amp;lt;id name=&amp;quot;LANEB&amp;quot; point=&amp;quot;PLC_Link1&amp;quot;/&amp;gt;&lt;br /&gt;
   &amp;lt;id name=&amp;quot;LANEC&amp;quot; point=&amp;quot;PLC_Link1&amp;quot;/&amp;gt;&lt;br /&gt;
   &amp;lt;id name=&amp;quot;LANED&amp;quot; point=&amp;quot;PLC_Link1&amp;quot;/&amp;gt;&lt;br /&gt;
   &amp;lt;id name=&amp;quot;LANEE&amp;quot; point=&amp;quot;PLC_Link2&amp;quot;/&amp;gt;&lt;br /&gt;
 &amp;lt;/restapi&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This lets a calling application address the Bridge in its own terms — lane names, machine names, whatever its domain uses — while the mapping to real Modbus points stays in the Bridge&#039;s configuration. As an example, the Commander4j web Issue application (&#039;&#039;c4j_web_Issue&#039;&#039;) signals a wrong-lane error by pulsing a relay, using the production &#039;&#039;&#039;lane id&#039;&#039;&#039; as the point name — but several lanes may share one physical relay. Mapping all of those ids onto the single point (&amp;lt;code&amp;gt;PLC_Link1&amp;lt;/code&amp;gt; above) means the Bridge sees them as &#039;&#039;&#039;one entity&#039;&#039;&#039;, so pulses fired for different lanes in quick succession &#039;&#039;&#039;queue on that point&#039;s single pulse queue&#039;&#039;&#039; — each set→hold→reset cycle completes before the next starts, instead of several independent &amp;quot;points&amp;quot; at the same address interfering with each other&#039;s hold and reset. The same mechanism serves any application whose naming does not map one-to-one onto the physical wiring. Note the consequence: a queued pulse&#039;s HTTP response is delayed until its turn comes (up to queue-depth × hold time), so callers should use a generous timeout or call asynchronously.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Ids work everywhere a &amp;lt;code&amp;gt;{name}&amp;lt;/code&amp;gt; is accepted&#039;&#039;&#039; — &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;PUT /api/points/{name}&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;POST /api/points/{name}/pulse&amp;lt;/code&amp;gt; — and single-point responses (and error messages) echo the name the caller used. The points list, SSE stream and web UI always show the point once, under its own name; the id→point map is reported in &amp;lt;code&amp;gt;/api/status&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;&amp;quot;restIds&amp;quot;&amp;lt;/code&amp;gt;) and shown under the point&#039;s name in the web UI. Log lines record both, e.g. &amp;lt;code&amp;gt;Pulse accepted for PLC_Link1 (as LANEB)&amp;lt;/code&amp;gt;, so the originating caller stays traceable even though the wire only sees the shared point.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;caseSensitive&amp;lt;/code&amp;gt;&#039;&#039;&#039; (optional, default &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;) controls matching: by default an id matches any capitalisation (&amp;lt;code&amp;gt;LANEA&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LaneA&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;lanea&amp;lt;/code&amp;gt;). Point names themselves remain case-sensitive and stay addressable alongside the ids.&lt;br /&gt;
* &#039;&#039;&#039;Validation at load:&#039;&#039;&#039; every id must reference an existing point; ids and point names share one namespace, so exact duplicates are rejected, and a case-insensitive id reserves its whole case class (nothing else may differ from it only by capitalisation). Bad configuration fails startup loudly, like every other config error.&lt;br /&gt;
&lt;br /&gt;
=== Simulated points ===&lt;br /&gt;
&lt;br /&gt;
Add &amp;lt;code&amp;gt;simulate=&amp;quot;true&amp;quot;&amp;lt;/code&amp;gt; to any point to detach it from the wire entirely — for keeping a calling application working, without error-handling changes, while the physical Modbus device is out of service:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;point name=&amp;quot;pump_run&amp;quot; kind=&amp;quot;COIL&amp;quot; address=&amp;quot;0&amp;quot; simulate=&amp;quot;true&amp;quot; value=&amp;quot;false&amp;quot;/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;REST callers cannot tell the difference.&#039;&#039;&#039; Reads return the in-memory value (always &amp;lt;code&amp;gt;&amp;quot;valid&amp;quot;:true,&amp;quot;stale&amp;quot;:false&amp;lt;/code&amp;gt;); writes and pulses succeed with the normal responses and are visible to subsequent reads; read-only kinds still reject writes with 400. The points payload deliberately carries &#039;&#039;&#039;no&#039;&#039;&#039; simulation marker, so the client↔bridge conversation is unchanged.&lt;br /&gt;
* The poll thread never touches a simulated point, and a dead link (or &amp;lt;code&amp;gt;&amp;lt;modbus enabled=&amp;quot;false&amp;quot;&amp;gt;&amp;lt;/code&amp;gt;) does not mark it stale or fail its writes — that is the whole purpose.&lt;br /&gt;
* &amp;lt;code&amp;gt;value&amp;lt;/code&amp;gt; seeds the simulated value at startup (&amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; for bit kinds, &amp;lt;code&amp;gt;0..65535&amp;lt;/code&amp;gt; for registers; default 0). Values are held in memory only: a restart resets to the seed.&lt;br /&gt;
* &amp;lt;code&amp;gt;simulate&amp;lt;/code&amp;gt; cannot be combined with &amp;lt;code&amp;gt;initialise&amp;lt;/code&amp;gt; (there is no wire to initialise), and any kind may be simulated — a simulated &amp;lt;code&amp;gt;DISCRETE_INPUT&amp;lt;/code&amp;gt; simply reports its seed until changed at source.&lt;br /&gt;
* For the &#039;&#039;&#039;operator&#039;&#039;&#039; (not the REST caller): &amp;lt;code&amp;gt;/api/status&amp;lt;/code&amp;gt; reports the simulated point names in &amp;lt;code&amp;gt;&amp;quot;simulatedPoints&amp;quot;&amp;lt;/code&amp;gt;, and the web UI tags those rows &#039;&#039;simulated&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Disabling the Modbus link ===&lt;br /&gt;
&lt;br /&gt;
When the whole device is out of service, &amp;lt;code&amp;gt;&amp;lt;modbus enabled=&amp;quot;false&amp;quot;&amp;gt;&amp;lt;/code&amp;gt; (attribute on the &amp;lt;code&amp;gt;&amp;lt;modbus&amp;gt;&amp;lt;/code&amp;gt; element; default &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;) stops the Bridge connecting at all — no reconnect attempts, no backoff noise in the log. Real points then behave exactly as during an outage (stale reads, 503 writes) while simulated points keep working. &amp;lt;code&amp;gt;/api/status&amp;lt;/code&amp;gt; reports &amp;lt;code&amp;gt;&amp;quot;modbusEnabled&amp;quot;:false&amp;lt;/code&amp;gt; and the web UI banner says the link is disabled rather than disconnected.&lt;br /&gt;
&lt;br /&gt;
Logging is configured in &amp;lt;code&amp;gt;xml/config/log4j2.xml&amp;lt;/code&amp;gt; (rolling file at &amp;lt;code&amp;gt;logs/modbusBridge.log&amp;lt;/code&amp;gt;, 10 MB cap, 5 generations). The Bridge&#039;s own classes log at &amp;lt;code&amp;gt;debug&amp;lt;/code&amp;gt;; the Netty transport at &amp;lt;code&amp;gt;warn&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== REST API ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Behaviour&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/points&amp;lt;/code&amp;gt; || All points with current values + connection status.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/points/{name}&amp;lt;/code&amp;gt; || One point&#039;s current value. 404 if unknown. &amp;lt;code&amp;gt;{name}&amp;lt;/code&amp;gt; is a point name or a [[#REST ids (application names for points)|restapi id]] (everywhere below too); the response echoes the name the caller used.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PUT&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/points/{name}&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;{&amp;quot;value&amp;quot;: N}&amp;lt;/code&amp;gt; || Write a coil (0/1, or &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;) or holding register (0–65535). 400 for read-only kinds or out-of-range; 503 if the server is unreachable.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;POST&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/points/{name}/pulse&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;{&amp;quot;value&amp;quot;: N [, &amp;quot;holdMs&amp;quot;: N, &amp;quot;restValue&amp;quot;: N]}&amp;lt;/code&amp;gt; || Momentary output: set the point active, hold &amp;lt;code&amp;gt;holdMs&amp;lt;/code&amp;gt; (default: the point&#039;s &amp;lt;code&amp;gt;defaultHoldMs&amp;lt;/code&amp;gt;), then guarantee a reset to &amp;lt;code&amp;gt;restValue&amp;lt;/code&amp;gt; (default 0). See [[#Pulse (momentary output)|below]]. 200 once energised; 503 if it couldn&#039;t be; 409 if too many pulses are already queued for the point; 400 for read-only kinds, out-of-range values, or &amp;lt;code&amp;gt;holdMs&amp;lt;/code&amp;gt; outside the point&#039;s &amp;lt;code&amp;gt;minHoldMs..maxHoldMs&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/status&amp;lt;/code&amp;gt; || Connection health: connected, target, unit id, poll interval, max hold, last-poll time, point count, &amp;lt;code&amp;gt;modbusEnabled&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;simulatedPoints&amp;lt;/code&amp;gt; (names), &amp;lt;code&amp;gt;restIds&amp;lt;/code&amp;gt; (point → its restapi ids).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/licence&amp;lt;/code&amp;gt; || Third-party licence list (from &amp;lt;code&amp;gt;lib/license/LicenseInfo.xml&amp;lt;/code&amp;gt;).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/log/tail&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;?lines=N&amp;lt;/code&amp;gt; || Recent log lines (default 200, max 5000).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/events&amp;lt;/code&amp;gt; || Server-Sent Events stream of the full points payload, pushed on every change.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/events/log&amp;lt;/code&amp;gt; || Server-Sent Events stream of newly-appended log lines.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A write is &#039;&#039;&#039;self-correcting&#039;&#039;&#039;, not optimistic: the Bridge writes the value, then immediately reads the point back from the server, so the response and cache reflect the server&#039;s actual state. When the link is down, reads return the last snapshot flagged &amp;lt;code&amp;gt;&amp;quot;valid&amp;quot;:false,&amp;quot;stale&amp;quot;:true&amp;lt;/code&amp;gt; and writes return &#039;&#039;&#039;503&#039;&#039;&#039;. &#039;&#039;&#039;[[#Simulated points|Simulated points]]&#039;&#039;&#039; are exempt from all of this: their reads, writes and pulses always succeed against the in-memory value, link or no link, and their payloads are indistinguishable from a live point&#039;s.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
 curl http://localhost:8080/api/points&lt;br /&gt;
 curl -X PUT -H &#039;Content-Type: application/json&#039; -d &#039;{&amp;quot;value&amp;quot;:1}&#039;    http://localhost:8080/api/points/pump_run&lt;br /&gt;
 curl -X PUT -H &#039;Content-Type: application/json&#039; -d &#039;{&amp;quot;value&amp;quot;:4242}&#039; http://localhost:8080/api/points/tank_level&lt;br /&gt;
&lt;br /&gt;
=== Pulse (momentary output) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;POST /api/points/{name}/pulse&amp;lt;/code&amp;gt; sets a writable point active, holds it, then &#039;&#039;&#039;guarantees&#039;&#039;&#039; it returns to a rest value — with the timing owned by the Bridge, not the caller. It exists to drive a PLC relay safely: a dropped web session, a client crash, or a link blip during the hold can never leave the relay energised.&lt;br /&gt;
&lt;br /&gt;
The following energises &amp;lt;code&amp;gt;pump_run&amp;lt;/code&amp;gt; for 3 seconds, then resets it to 0:&lt;br /&gt;
&lt;br /&gt;
 curl -X POST -H &#039;Content-Type: application/json&#039; -d &#039;{&amp;quot;value&amp;quot;:1,&amp;quot;holdMs&amp;quot;:3000,&amp;quot;restValue&amp;quot;:0}&#039; http://localhost:8080/api/points/pump_run/pulse&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;The response is a real confirmation.&#039;&#039;&#039; &amp;lt;code&amp;gt;200&amp;lt;/code&amp;gt; means the relay was energised and its reset is scheduled; &amp;lt;code&amp;gt;503&amp;lt;/code&amp;gt; means nothing was energised (link down) and nothing is owed. The set runs on the request thread; the hold and reset run in the background.&lt;br /&gt;
* &#039;&#039;&#039;The reset is guaranteed&#039;&#039;&#039; across a dropped caller session, a link drop during the hold (it retries as the Bridge reconnects), and a graceful service stop (the reset is flushed &#039;&#039;before&#039;&#039; the Modbus link closes). It is &#039;&#039;&#039;not&#039;&#039;&#039; guaranteed across a hard kill or power loss — for that, configure a PLC-side hardware watchdog that de-energises a coil that stops being refreshed.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;holdMs&amp;lt;/code&amp;gt; is optional&#039;&#039;&#039; — when omitted, the point&#039;s configured &amp;lt;code&amp;gt;defaultHoldMs&amp;lt;/code&amp;gt; applies, so a caller can send just &amp;lt;code&amp;gt;{&amp;quot;value&amp;quot;: 1}&amp;lt;/code&amp;gt; and leave the relay timing to the Bridge&#039;s configuration. When supplied, it must be within the point&#039;s &amp;lt;code&amp;gt;minHoldMs..maxHoldMs&amp;lt;/code&amp;gt; (see [[#Per-point pulse hold policy (optional, writable points only)|the config section]]; defaults &amp;lt;code&amp;gt;1..60000&amp;lt;/code&amp;gt;) so a typo can&#039;t hold a relay for hours — set a tight per-point range on real relay coils. &#039;&#039;&#039;&amp;lt;code&amp;gt;restValue&amp;lt;/code&amp;gt;&#039;&#039;&#039; is optional (default 0). The point&#039;s bounds and its &amp;lt;code&amp;gt;defaultHoldMs&amp;lt;/code&amp;gt; are reported in every points payload for clients to discover.&lt;br /&gt;
* &#039;&#039;&#039;Concurrency:&#039;&#039;&#039; pulses on the same point run one complete set→hold→reset cycle at a time, so the relay returns to rest between them; a caller that outruns the queue gets &amp;lt;code&amp;gt;409&amp;lt;/code&amp;gt;. Pulses on different points are independent. Note that a &#039;&#039;&#039;queued&#039;&#039;&#039; pulse&#039;s HTTP response is delayed until its turn to fire (up to &amp;lt;code&amp;gt;holdMs&amp;lt;/code&amp;gt; × its position in the queue), so a client&#039;s request timeout must exceed the worst-case wait, or it may abandon a pulse that still fires server-side.&lt;br /&gt;
&lt;br /&gt;
== Web UI ==&lt;br /&gt;
&lt;br /&gt;
Open &amp;lt;code&amp;gt;http://&amp;lt;host&amp;gt;:8080/&amp;lt;/code&amp;gt; in a browser:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Points&#039;&#039;&#039; (&amp;lt;code&amp;gt;index.html&amp;lt;/code&amp;gt;) — a live table of every configured point, updated by push (SSE) with no refresh needed. Writable points have an inline editor; type a value and click &#039;&#039;&#039;Set&#039;&#039;&#039; (or press Enter) to issue the PUT. Next to it, a &#039;&#039;&#039;Pulse&#039;&#039;&#039; button with a hold-time field (pre-filled from the point&#039;s &amp;lt;code&amp;gt;defaultHoldMs&amp;lt;/code&amp;gt;, bounded by its &amp;lt;code&amp;gt;minHoldMs&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;maxHoldMs&amp;lt;/code&amp;gt;) sets the value, holds it for that time, then auto-resets to 0 — the timing runs server-side (see [[#Pulse (momentary output)|Pulse]]), so closing the page mid-hold cannot leave the point energised. You can watch the value go active and drop back live in the table. Stale values (link down) are shown in red. A manual &#039;&#039;&#039;Refresh&#039;&#039;&#039; button is kept as a fallback.&lt;br /&gt;
* &#039;&#039;&#039;Log&#039;&#039;&#039; (&amp;lt;code&amp;gt;log.html&amp;lt;/code&amp;gt;) — the recent log backlog followed live as new lines are written, with an auto-scroll toggle. &amp;lt;code&amp;gt;WARN&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;ERROR&amp;lt;/code&amp;gt; lines are colour-coded.&lt;br /&gt;
* &#039;&#039;&#039;Licences&#039;&#039;&#039; (&amp;lt;code&amp;gt;licence.html&amp;lt;/code&amp;gt;) — the third-party libraries and their licences rendered as a table (the underlying &amp;lt;code&amp;gt;/api/licence&amp;lt;/code&amp;gt; endpoint returns the same data as raw JSON).&lt;br /&gt;
&lt;br /&gt;
== Modbus Behaviour ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transport:&#039;&#039;&#039; Modbus/TCP only (no serial / RTU, no TLS), reusing the [[ModbusClient]]&#039;s Modbus engine.&lt;br /&gt;
* The poll thread reads every configured point once per &amp;lt;code&amp;gt;pollIntervalMs&amp;lt;/code&amp;gt;. A read failure tears the connection down, flags all points stale, and the Bridge auto-reconnects with exponential backoff (1 → 2 → 4 → 8 … up to 30 s), resetting on a successful connect.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;Address already in use&amp;lt;/code&amp;gt; on start&#039;&#039;&#039; — another process holds the web port (default 8080). Change &amp;lt;code&amp;gt;&amp;lt;webserver&amp;gt;&amp;lt;port&amp;gt;&amp;lt;/code&amp;gt; or free the port.&lt;br /&gt;
* &#039;&#039;&#039;All points show stale / &amp;lt;code&amp;gt;/api/status&amp;lt;/code&amp;gt; says not connected&#039;&#039;&#039; — the Modbus server is unreachable. Check &amp;lt;code&amp;gt;&amp;lt;modbus&amp;gt;&amp;lt;ip&amp;gt;/&amp;lt;port&amp;gt;&amp;lt;/code&amp;gt;, that the server is running, and that both ends use the same &#039;&#039;&#039;unit id&#039;&#039;&#039; (the server answers only its configured unit). The log shows the backoff retries.&lt;br /&gt;
* &#039;&#039;&#039;Writes return 503&#039;&#039;&#039; — the link is down at that moment; the Bridge is between reconnect attempts. Reads still return the last-known (stale) values.&lt;br /&gt;
* &#039;&#039;&#039;All points stale but no reconnect attempts in the log&#039;&#039;&#039; — the Modbus link may be switched off in the configuration: check for &amp;lt;code&amp;gt;&amp;lt;modbus enabled=&amp;quot;false&amp;quot;&amp;gt;&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;/api/status&amp;lt;/code&amp;gt; reports &amp;lt;code&amp;gt;&amp;quot;modbusEnabled&amp;quot;:false&amp;lt;/code&amp;gt; and the web UI banner shows &#039;&#039;disabled&#039;&#039; rather than &#039;&#039;disconnected&#039;&#039;).&lt;br /&gt;
* &#039;&#039;&#039;PUT returns 400 &amp;quot;read-only&amp;quot;&#039;&#039;&#039; — the named point is a &amp;lt;code&amp;gt;DISCRETE_INPUT&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;INPUT_REGISTER&amp;lt;/code&amp;gt;; those cannot be written by a Modbus client.&lt;br /&gt;
* &#039;&#039;&#039;No log lines / empty log tail page&#039;&#039;&#039; — confirm &amp;lt;code&amp;gt;-Dlog4j2.configurationFile=xml/config/log4j2.xml&amp;lt;/code&amp;gt; is set (the start scripts do this) and the process working directory is the project root, so &amp;lt;code&amp;gt;logs/&amp;lt;/code&amp;gt; is created in the right place.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[ModbusClient]] — the interactive desktop Modbus client; the Bridge reuses its Modbus engine&lt;br /&gt;
* [[ModbusServer]] — the server-side companion tool, useful as a bench target for the Bridge&lt;br /&gt;
* [[AutoLab4j]] — uses the same Modbus stack to monitor a coil and trigger a labeller on a change of state&lt;br /&gt;
* [[SocketTest]] — a raw TCP/IP testing utility&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=ModbusBridge&amp;diff=1905</id>
		<title>ModbusBridge</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=ModbusBridge&amp;diff=1905"/>
		<updated>2026-07-02T16:46:29Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: Updated by push_wiki.py&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;Commander4j Modbus Bridge&#039;&#039;&#039; (&#039;&#039;util_modbusBridge&#039;&#039;) is a &#039;&#039;&#039;headless service&#039;&#039;&#039; that lets applications without [https://en.wikipedia.org/wiki/Modbus Modbus/TCP] client capability set and query the values of a remote Modbus server over a simple REST API. It connects to one Modbus server, polls a fixed list of &#039;&#039;&#039;named points&#039;&#039;&#039; (configured in XML), keeps the latest values in memory, and serves them over HTTP. It also provides a live web UI to view and change values, and a second page to tail the log.&lt;br /&gt;
&lt;br /&gt;
Unlike the interactive [[ModbusClient|Commander4j Modbus Client]], the Bridge runs unattended: it auto-reconnects when the link drops and is packaged to run as an operating-system service. It reuses the same Modbus engine as the [[ModbusClient]] and is a natural companion to the [[ModbusServer]].&lt;br /&gt;
&lt;br /&gt;
If you are new to Modbus, the [[ModbusClient#A Quick Modbus Primer|Modbus primer on the Modbus Client page]] explains the terms (client/server, unit ID, and the four data tables) used throughout this page.&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Bridge is useful when:&lt;br /&gt;
&lt;br /&gt;
* An application or script that cannot speak Modbus needs to read or write a PLC or other Modbus/TCP device over plain HTTP/JSON&lt;br /&gt;
* A remote Modbus server&#039;s values should be exposed on a network as named points rather than raw addresses&lt;br /&gt;
* An unattended, always-on bridge is needed that survives link drops and restarts as a managed service&lt;br /&gt;
* A browser-based view of live values, with inline editing and a live log, is wanted without installing a desktop tool&lt;br /&gt;
&lt;br /&gt;
== Source Code and Releases ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Bridge is open source and hosted on GitHub:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Repository:&#039;&#039;&#039; [https://github.com/C4J/ModbusBridge https://github.com/C4J/ModbusBridge]&lt;br /&gt;
* &#039;&#039;&#039;Releases (downloads):&#039;&#039;&#039; [https://github.com/C4J/ModbusBridge/releases https://github.com/C4J/ModbusBridge/releases]&lt;br /&gt;
&lt;br /&gt;
== Running the Modbus Bridge ==&lt;br /&gt;
&lt;br /&gt;
The recommended way to install the Modbus Bridge is to download a native installer for your platform, either from the [[Downloads]] page or from the [https://github.com/C4J/ModbusBridge/releases GitHub releases page]. Native installers are provided for &#039;&#039;&#039;Windows, macOS and Linux&#039;&#039;&#039;. Each installer bundles its own Java 25 runtime, so &#039;&#039;&#039;no separate Java installation is required&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== As a service ===&lt;br /&gt;
&lt;br /&gt;
The native installer registers and starts the Bridge as an operating-system service — &#039;&#039;&#039;launchd&#039;&#039;&#039; on macOS, a &#039;&#039;&#039;Windows service&#039;&#039;&#039;, or a &#039;&#039;&#039;systemd / init&#039;&#039;&#039; unit on Linux. The service runs with its working directory set to the installation directory, so all the relative paths below resolve correctly. Stopping the service triggers an ordered shutdown so that teardown events still reach the log file.&lt;br /&gt;
&lt;br /&gt;
=== Running from the jar ===&lt;br /&gt;
&lt;br /&gt;
Alternatively the Bridge can be launched from its distribution folder:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;./start_modbusBridge.sh&amp;lt;/code&amp;gt; (macOS/Linux) or &amp;lt;code&amp;gt;start_modbusBridge.cmd&amp;lt;/code&amp;gt; (Windows), or&lt;br /&gt;
* &amp;lt;code&amp;gt;ant run&amp;lt;/code&amp;gt; to launch from compiled classes, or&lt;br /&gt;
* directly with Java:&lt;br /&gt;
&lt;br /&gt;
 java -Dlog4j2.shutdownHookEnabled=false -Dlog4j2.configurationFile=xml/config/log4j2.xml -jar modbusBridge.jar&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;modbusBridge.jar&amp;lt;/code&amp;gt; is a &#039;&#039;&#039;thin jar&#039;&#039;&#039; — it references the dependency jars in &amp;lt;code&amp;gt;lib/&amp;lt;/code&amp;gt; via its manifest, so it must be run from the project root with &amp;lt;code&amp;gt;lib/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;xml/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;web/&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;logs/&amp;lt;/code&amp;gt; alongside it. Any Java 25 runtime on the &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; will do; a bundled JRE is not required when run this way.&lt;br /&gt;
&lt;br /&gt;
The two &amp;lt;code&amp;gt;-D&amp;lt;/code&amp;gt; system properties matter, and the start scripts set them for you:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;-Dlog4j2.shutdownHookEnabled=false&amp;lt;/code&amp;gt; — lets the Bridge&#039;s own shutdown hook stop log4j2 &#039;&#039;&#039;last&#039;&#039;&#039;, so teardown events still reach the log file the tail page reads.&lt;br /&gt;
* &amp;lt;code&amp;gt;-Dlog4j2.configurationFile=xml/config/log4j2.xml&amp;lt;/code&amp;gt; — &amp;lt;code&amp;gt;log4j2.xml&amp;lt;/code&amp;gt; lives under &amp;lt;code&amp;gt;xml/config/&amp;lt;/code&amp;gt;, not on the classpath, so log4j2 must be pointed at it explicitly.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
All configuration is in &amp;lt;code&amp;gt;xml/config/config.xml&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;config&amp;gt;&lt;br /&gt;
   &amp;lt;modbus&amp;gt;&lt;br /&gt;
     &amp;lt;ip&amp;gt;127.0.0.1&amp;lt;/ip&amp;gt;&lt;br /&gt;
     &amp;lt;port&amp;gt;1502&amp;lt;/port&amp;gt;&lt;br /&gt;
     &amp;lt;id&amp;gt;1&amp;lt;/id&amp;gt;&lt;br /&gt;
     &amp;lt;pollIntervalMs&amp;gt;1000&amp;lt;/pollIntervalMs&amp;gt;&lt;br /&gt;
     &amp;lt;maxHoldMs&amp;gt;60000&amp;lt;/maxHoldMs&amp;gt;&lt;br /&gt;
   &amp;lt;/modbus&amp;gt;&lt;br /&gt;
   &amp;lt;webserver&amp;gt;&lt;br /&gt;
     &amp;lt;ip&amp;gt;0.0.0.0&amp;lt;/ip&amp;gt;&lt;br /&gt;
     &amp;lt;port&amp;gt;8080&amp;lt;/port&amp;gt;&lt;br /&gt;
   &amp;lt;/webserver&amp;gt;&lt;br /&gt;
   &amp;lt;points&amp;gt;&lt;br /&gt;
     &amp;lt;point name=&amp;quot;pump_run&amp;quot;   kind=&amp;quot;COIL&amp;quot;             address=&amp;quot;0&amp;quot;   initialise=&amp;quot;false&amp;quot; value=&amp;quot;false&amp;quot;&lt;br /&gt;
            minHoldMs=&amp;quot;500&amp;quot; maxHoldMs=&amp;quot;10000&amp;quot; defaultHoldMs=&amp;quot;3000&amp;quot;/&amp;gt;&lt;br /&gt;
     &amp;lt;point name=&amp;quot;tank_level&amp;quot; kind=&amp;quot;HOLDING_REGISTER&amp;quot; address=&amp;quot;100&amp;quot; initialise=&amp;quot;false&amp;quot; value=&amp;quot;0&amp;quot;/&amp;gt;&lt;br /&gt;
     &amp;lt;point name=&amp;quot;fault&amp;quot;      kind=&amp;quot;DISCRETE_INPUT&amp;quot;   address=&amp;quot;10&amp;quot;/&amp;gt;&lt;br /&gt;
     &amp;lt;point name=&amp;quot;flow_rate&amp;quot;  kind=&amp;quot;INPUT_REGISTER&amp;quot;   address=&amp;quot;30&amp;quot;/&amp;gt;&lt;br /&gt;
   &amp;lt;/points&amp;gt;&lt;br /&gt;
 &amp;lt;/config&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;&amp;lt;modbus&amp;gt;&amp;lt;/code&amp;gt; block points the Bridge at the remote Modbus server: its host &amp;lt;code&amp;gt;&amp;lt;ip&amp;gt;&amp;lt;/code&amp;gt;, TCP &amp;lt;code&amp;gt;&amp;lt;port&amp;gt;&amp;lt;/code&amp;gt; (the Modbus standard is &#039;&#039;&#039;502&#039;&#039;&#039;; the example uses &#039;&#039;&#039;1502&#039;&#039;&#039; because ports below 1024 need root on macOS/Linux), the unit / slave &amp;lt;code&amp;gt;&amp;lt;id&amp;gt;&amp;lt;/code&amp;gt; to address, and the &amp;lt;code&amp;gt;&amp;lt;pollIntervalMs&amp;gt;&amp;lt;/code&amp;gt; between reads. The optional &amp;lt;code&amp;gt;&amp;lt;maxHoldMs&amp;gt;&amp;lt;/code&amp;gt; is the default hold cap for points that do not set their own &amp;lt;code&amp;gt;maxHoldMs&amp;lt;/code&amp;gt; attribute (60&amp;amp;nbsp;000&amp;amp;nbsp;ms if absent) — see [[#Pulse (momentary output)|Pulse]] below. The &amp;lt;code&amp;gt;&amp;lt;webserver&amp;gt;&amp;lt;/code&amp;gt; block sets the bind address for the HTTP server (&amp;lt;code&amp;gt;0.0.0.0&amp;lt;/code&amp;gt; = all interfaces) and the port it listens on.&lt;br /&gt;
&lt;br /&gt;
Each &amp;lt;code&amp;gt;&amp;lt;point&amp;gt;&amp;lt;/code&amp;gt; gives a human-friendly &#039;&#039;&#039;name&#039;&#039;&#039; (how REST clients and the web UI refer to it), a Modbus data table &#039;&#039;&#039;kind&#039;&#039;&#039;, and a zero-based protocol &#039;&#039;&#039;address&#039;&#039;&#039;. Valid kinds are &amp;lt;code&amp;gt;COIL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DISCRETE_INPUT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HOLDING_REGISTER&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;INPUT_REGISTER&amp;lt;/code&amp;gt;. Only &#039;&#039;&#039;coils&#039;&#039;&#039; and &#039;&#039;&#039;holding registers&#039;&#039;&#039; are writable — discrete inputs and input registers are read-only in the Modbus data model (there is no client-write function code for them).&lt;br /&gt;
&lt;br /&gt;
=== Startup initialisation (optional) ===&lt;br /&gt;
&lt;br /&gt;
Add &amp;lt;code&amp;gt;initialise=&amp;quot;true&amp;quot; value=&amp;quot;...&amp;quot;&amp;lt;/code&amp;gt; to a writable point to have the Bridge drive it to a known state at startup:&lt;br /&gt;
&lt;br /&gt;
* On the &#039;&#039;&#039;first successful connect&#039;&#039;&#039; after the Bridge starts, it reads the point&#039;s current value and writes &amp;lt;code&amp;gt;value&amp;lt;/code&amp;gt; &#039;&#039;&#039;only if it differs&#039;&#039;&#039; (an already-correct point is left untouched). This runs once — a later link drop and reconnect does &#039;&#039;&#039;not&#039;&#039;&#039; re-apply it, so runtime REST/operator changes survive an outage.&lt;br /&gt;
* If the Modbus server is unavailable at startup, initialisation simply waits and runs on the first connect once it becomes reachable.&lt;br /&gt;
* &amp;lt;code&amp;gt;value&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt; (or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;) for coils, and a &amp;lt;code&amp;gt;0..65535&amp;lt;/code&amp;gt; integer for holding registers. &amp;lt;code&amp;gt;initialise&amp;lt;/code&amp;gt; defaults to &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Configuration is rejected at startup if &amp;lt;code&amp;gt;initialise=&amp;quot;true&amp;quot;&amp;lt;/code&amp;gt; is set on a read-only kind, or without a &amp;lt;code&amp;gt;value&amp;lt;/code&amp;gt;, or with a value that does not match the kind.&lt;br /&gt;
&lt;br /&gt;
=== Per-point pulse hold policy (optional, writable points only) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;minHoldMs&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;maxHoldMs&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;defaultHoldMs&amp;lt;/code&amp;gt; control what a [[#Pulse (momentary output)|pulse]] request may ask this point to hold for:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;minHoldMs&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;maxHoldMs&amp;lt;/code&amp;gt; are the enforced bounds — a pulse whose &amp;lt;code&amp;gt;holdMs&amp;lt;/code&amp;gt; falls outside them is rejected with &#039;&#039;&#039;400&#039;&#039;&#039;. Defaults: min &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;, max = the global &amp;lt;code&amp;gt;&amp;lt;maxHoldMs&amp;gt;&amp;lt;/code&amp;gt; (60&amp;amp;nbsp;000 if that is absent too). A tight per-point range (e.g. &amp;lt;code&amp;gt;500..10000&amp;lt;/code&amp;gt; on a relay coil) means a typo like &amp;lt;code&amp;gt;30000&amp;lt;/code&amp;gt; for &amp;lt;code&amp;gt;3000&amp;lt;/code&amp;gt; can&#039;t hold the relay closed for half a minute.&lt;br /&gt;
* &amp;lt;code&amp;gt;defaultHoldMs&amp;lt;/code&amp;gt; is what the web UI pre-fills in the row&#039;s hold field (and is reported by the API for other clients to use the same way). Default: &amp;lt;code&amp;gt;3000&amp;lt;/code&amp;gt; — sized for switching an electrical relay — clamped into the min/max range.&lt;br /&gt;
* Config-load validation enforces &amp;lt;code&amp;gt;1 ≤ minHoldMs ≤ defaultHoldMs ≤ maxHoldMs&amp;lt;/code&amp;gt; and rejects the attributes on read-only kinds.&lt;br /&gt;
&lt;br /&gt;
Logging is configured in &amp;lt;code&amp;gt;xml/config/log4j2.xml&amp;lt;/code&amp;gt; (rolling file at &amp;lt;code&amp;gt;logs/modbusBridge.log&amp;lt;/code&amp;gt;, 10 MB cap, 5 generations). The Bridge&#039;s own classes log at &amp;lt;code&amp;gt;debug&amp;lt;/code&amp;gt;; the Netty transport at &amp;lt;code&amp;gt;warn&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== REST API ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Behaviour&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/points&amp;lt;/code&amp;gt; || All points with current values + connection status.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/points/{name}&amp;lt;/code&amp;gt; || One point&#039;s current value. 404 if unknown.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PUT&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/points/{name}&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;{&amp;quot;value&amp;quot;: N}&amp;lt;/code&amp;gt; || Write a coil (0/1, or &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;) or holding register (0–65535). 400 for read-only kinds or out-of-range; 503 if the server is unreachable.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;POST&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/points/{name}/pulse&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;{&amp;quot;value&amp;quot;: N, &amp;quot;holdMs&amp;quot;: N, &amp;quot;restValue&amp;quot;: N}&amp;lt;/code&amp;gt; || Momentary output: set the point active, hold &amp;lt;code&amp;gt;holdMs&amp;lt;/code&amp;gt;, then guarantee a reset to &amp;lt;code&amp;gt;restValue&amp;lt;/code&amp;gt; (default 0). See [[#Pulse (momentary output)|below]]. 200 once energised; 503 if it couldn&#039;t be; 409 if too many pulses are already queued for the point; 400 for read-only kinds, out-of-range values, or &amp;lt;code&amp;gt;holdMs&amp;lt;/code&amp;gt; outside the point&#039;s &amp;lt;code&amp;gt;minHoldMs..maxHoldMs&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/status&amp;lt;/code&amp;gt; || Connection health: connected, target, unit id, poll interval, max hold, last-poll time, point count.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/licence&amp;lt;/code&amp;gt; || Third-party licence list (from &amp;lt;code&amp;gt;lib/license/LicenseInfo.xml&amp;lt;/code&amp;gt;).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/log/tail&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;?lines=N&amp;lt;/code&amp;gt; || Recent log lines (default 200, max 5000).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/events&amp;lt;/code&amp;gt; || Server-Sent Events stream of the full points payload, pushed on every change.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/events/log&amp;lt;/code&amp;gt; || Server-Sent Events stream of newly-appended log lines.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A write is &#039;&#039;&#039;self-correcting&#039;&#039;&#039;, not optimistic: the Bridge writes the value, then immediately reads the point back from the server, so the response and cache reflect the server&#039;s actual state. When the link is down, reads return the last snapshot flagged &amp;lt;code&amp;gt;&amp;quot;valid&amp;quot;:false,&amp;quot;stale&amp;quot;:true&amp;lt;/code&amp;gt; and writes return &#039;&#039;&#039;503&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
 curl http://localhost:8080/api/points&lt;br /&gt;
 curl -X PUT -H &#039;Content-Type: application/json&#039; -d &#039;{&amp;quot;value&amp;quot;:1}&#039;    http://localhost:8080/api/points/pump_run&lt;br /&gt;
 curl -X PUT -H &#039;Content-Type: application/json&#039; -d &#039;{&amp;quot;value&amp;quot;:4242}&#039; http://localhost:8080/api/points/tank_level&lt;br /&gt;
&lt;br /&gt;
=== Pulse (momentary output) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;POST /api/points/{name}/pulse&amp;lt;/code&amp;gt; sets a writable point active, holds it, then &#039;&#039;&#039;guarantees&#039;&#039;&#039; it returns to a rest value — with the timing owned by the Bridge, not the caller. It exists to drive a PLC relay safely: a dropped web session, a client crash, or a link blip during the hold can never leave the relay energised.&lt;br /&gt;
&lt;br /&gt;
The following energises &amp;lt;code&amp;gt;pump_run&amp;lt;/code&amp;gt; for 3 seconds, then resets it to 0:&lt;br /&gt;
&lt;br /&gt;
 curl -X POST -H &#039;Content-Type: application/json&#039; -d &#039;{&amp;quot;value&amp;quot;:1,&amp;quot;holdMs&amp;quot;:3000,&amp;quot;restValue&amp;quot;:0}&#039; http://localhost:8080/api/points/pump_run/pulse&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;The response is a real confirmation.&#039;&#039;&#039; &amp;lt;code&amp;gt;200&amp;lt;/code&amp;gt; means the relay was energised and its reset is scheduled; &amp;lt;code&amp;gt;503&amp;lt;/code&amp;gt; means nothing was energised (link down) and nothing is owed. The set runs on the request thread; the hold and reset run in the background.&lt;br /&gt;
* &#039;&#039;&#039;The reset is guaranteed&#039;&#039;&#039; across a dropped caller session, a link drop during the hold (it retries as the Bridge reconnects), and a graceful service stop (the reset is flushed &#039;&#039;before&#039;&#039; the Modbus link closes). It is &#039;&#039;&#039;not&#039;&#039;&#039; guaranteed across a hard kill or power loss — for that, configure a PLC-side hardware watchdog that de-energises a coil that stops being refreshed.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;holdMs&amp;lt;/code&amp;gt;&#039;&#039;&#039; must be within the point&#039;s &amp;lt;code&amp;gt;minHoldMs..maxHoldMs&amp;lt;/code&amp;gt; (see [[#Per-point pulse hold policy (optional, writable points only)|the config section]]; defaults &amp;lt;code&amp;gt;1..60000&amp;lt;/code&amp;gt;) so a typo can&#039;t hold a relay for hours — set a tight per-point range on real relay coils. &#039;&#039;&#039;&amp;lt;code&amp;gt;restValue&amp;lt;/code&amp;gt;&#039;&#039;&#039; is optional (default 0). The point&#039;s bounds and its &amp;lt;code&amp;gt;defaultHoldMs&amp;lt;/code&amp;gt; are reported in every points payload for clients to discover.&lt;br /&gt;
* &#039;&#039;&#039;Concurrency:&#039;&#039;&#039; pulses on the same point run one complete set→hold→reset cycle at a time, so the relay returns to rest between them; a caller that outruns the queue gets &amp;lt;code&amp;gt;409&amp;lt;/code&amp;gt;. Pulses on different points are independent. Note that a &#039;&#039;&#039;queued&#039;&#039;&#039; pulse&#039;s HTTP response is delayed until its turn to fire (up to &amp;lt;code&amp;gt;holdMs&amp;lt;/code&amp;gt; × its position in the queue), so a client&#039;s request timeout must exceed the worst-case wait, or it may abandon a pulse that still fires server-side.&lt;br /&gt;
&lt;br /&gt;
== Web UI ==&lt;br /&gt;
&lt;br /&gt;
Open &amp;lt;code&amp;gt;http://&amp;lt;host&amp;gt;:8080/&amp;lt;/code&amp;gt; in a browser:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Points&#039;&#039;&#039; (&amp;lt;code&amp;gt;index.html&amp;lt;/code&amp;gt;) — a live table of every configured point, updated by push (SSE) with no refresh needed. Writable points have an inline editor; type a value and click &#039;&#039;&#039;Set&#039;&#039;&#039; (or press Enter) to issue the PUT. Next to it, a &#039;&#039;&#039;Pulse&#039;&#039;&#039; button with a hold-time field (pre-filled from the point&#039;s &amp;lt;code&amp;gt;defaultHoldMs&amp;lt;/code&amp;gt;, bounded by its &amp;lt;code&amp;gt;minHoldMs&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;maxHoldMs&amp;lt;/code&amp;gt;) sets the value, holds it for that time, then auto-resets to 0 — the timing runs server-side (see [[#Pulse (momentary output)|Pulse]]), so closing the page mid-hold cannot leave the point energised. You can watch the value go active and drop back live in the table. Stale values (link down) are shown in red. A manual &#039;&#039;&#039;Refresh&#039;&#039;&#039; button is kept as a fallback.&lt;br /&gt;
* &#039;&#039;&#039;Log&#039;&#039;&#039; (&amp;lt;code&amp;gt;log.html&amp;lt;/code&amp;gt;) — the recent log backlog followed live as new lines are written, with an auto-scroll toggle. &amp;lt;code&amp;gt;WARN&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;ERROR&amp;lt;/code&amp;gt; lines are colour-coded.&lt;br /&gt;
* &#039;&#039;&#039;Licences&#039;&#039;&#039; (&amp;lt;code&amp;gt;licence.html&amp;lt;/code&amp;gt;) — the third-party libraries and their licences rendered as a table (the underlying &amp;lt;code&amp;gt;/api/licence&amp;lt;/code&amp;gt; endpoint returns the same data as raw JSON).&lt;br /&gt;
&lt;br /&gt;
== Modbus Behaviour ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transport:&#039;&#039;&#039; Modbus/TCP only (no serial / RTU, no TLS), reusing the [[ModbusClient]]&#039;s Modbus engine.&lt;br /&gt;
* The poll thread reads every configured point once per &amp;lt;code&amp;gt;pollIntervalMs&amp;lt;/code&amp;gt;. A read failure tears the connection down, flags all points stale, and the Bridge auto-reconnects with exponential backoff (1 → 2 → 4 → 8 … up to 30 s), resetting on a successful connect.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;Address already in use&amp;lt;/code&amp;gt; on start&#039;&#039;&#039; — another process holds the web port (default 8080). Change &amp;lt;code&amp;gt;&amp;lt;webserver&amp;gt;&amp;lt;port&amp;gt;&amp;lt;/code&amp;gt; or free the port.&lt;br /&gt;
* &#039;&#039;&#039;All points show stale / &amp;lt;code&amp;gt;/api/status&amp;lt;/code&amp;gt; says not connected&#039;&#039;&#039; — the Modbus server is unreachable. Check &amp;lt;code&amp;gt;&amp;lt;modbus&amp;gt;&amp;lt;ip&amp;gt;/&amp;lt;port&amp;gt;&amp;lt;/code&amp;gt;, that the server is running, and that both ends use the same &#039;&#039;&#039;unit id&#039;&#039;&#039; (the server answers only its configured unit). The log shows the backoff retries.&lt;br /&gt;
* &#039;&#039;&#039;Writes return 503&#039;&#039;&#039; — the link is down at that moment; the Bridge is between reconnect attempts. Reads still return the last-known (stale) values.&lt;br /&gt;
* &#039;&#039;&#039;PUT returns 400 &amp;quot;read-only&amp;quot;&#039;&#039;&#039; — the named point is a &amp;lt;code&amp;gt;DISCRETE_INPUT&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;INPUT_REGISTER&amp;lt;/code&amp;gt;; those cannot be written by a Modbus client.&lt;br /&gt;
* &#039;&#039;&#039;No log lines / empty log tail page&#039;&#039;&#039; — confirm &amp;lt;code&amp;gt;-Dlog4j2.configurationFile=xml/config/log4j2.xml&amp;lt;/code&amp;gt; is set (the start scripts do this) and the process working directory is the project root, so &amp;lt;code&amp;gt;logs/&amp;lt;/code&amp;gt; is created in the right place.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[ModbusClient]] — the interactive desktop Modbus client; the Bridge reuses its Modbus engine&lt;br /&gt;
* [[ModbusServer]] — the server-side companion tool, useful as a bench target for the Bridge&lt;br /&gt;
* [[AutoLab4j]] — uses the same Modbus stack to monitor a coil and trigger a labeller on a change of state&lt;br /&gt;
* [[SocketTest]] — a raw TCP/IP testing utility&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=Label_Function_Syntax&amp;diff=1904</id>
		<title>Label Function Syntax</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=Label_Function_Syntax&amp;diff=1904"/>
		<updated>2026-06-24T12:37:56Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: Updated by push_wiki.py&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;There are a number of functions which you can embed in your barcode label template to help format the data before sending to a labeller.&lt;br /&gt;
&lt;br /&gt;
Referencing field names uses this syntax.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;*fieldname*&amp;gt;&lt;br /&gt;
&lt;br /&gt;
for example&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;*SSCC*&amp;gt;  &amp;lt;*QUANTITY*&amp;gt;  &amp;lt;*DESCRIPTION*&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Functions are resolved innermost-first, so they can be nested. The result of an inner function is passed as the input to the function which encloses it.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;PADLEFT(&amp;lt;SUBSTRING(&amp;lt;*BATCH*&amp;gt;,1,3)&amp;gt;,5,0)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If a function is given the wrong number of parameters it returns the function name followed by &#039;&#039;&#039;[Incorrect number of parameters]&#039;&#039;&#039;, and a function given an invalid date/time format returns the function name followed by &#039;&#039;&#039;[Incorrect date/time format]&#039;&#039;&#039;. This makes mistakes visible on the printed label rather than failing silently.&lt;br /&gt;
&lt;br /&gt;
===DATE_CREATED===&lt;br /&gt;
&lt;br /&gt;
This function returns the date &amp;amp; time when the pallet record was created in the database and allows you to specify the format that you want it formatted in the label.&lt;br /&gt;
&lt;br /&gt;
Example usage&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;DATE_CREATED(ddMMyy)&amp;gt;&lt;br /&gt;
 &amp;lt;DATE_CREATED(dd/MM/yyyy)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the value of the DATE_CREATED field is null or blank it will return spaces instead of date.&lt;br /&gt;
&lt;br /&gt;
===DATETIME===&lt;br /&gt;
&lt;br /&gt;
The function allows you to format a datetime/timestamp field value from the database and display it in the label using the format specified.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;DATETIME(fieldname,dd/MM/yyyy  HH:mm:ss)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===EXPIRYDATE===&lt;br /&gt;
&lt;br /&gt;
When a label is printed Commander4j will automatically calculate the expiry date of the product. It is important to realise however that the application has 2 modes for recording the expiry date. It can be associated with the individual pallet number (SSCC) or it can be associated with the batch number. The mode that the system is using is defined in [[System Keys]] using the setting called &#039;&#039;&#039;EXPIRY DATE MODE&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function will retrieve the value from the appropriate table based on the setting above.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;EXPIRYDATE(MM yyyy)&amp;gt;&lt;br /&gt;
 &amp;lt;EXPIRYDATE(MM)&amp;gt;&lt;br /&gt;
 &amp;lt;EXPIRYDATE(yy)&amp;gt;&lt;br /&gt;
 &amp;lt;EXPIRYDATE(dd)&amp;gt; &amp;lt;EXPIRYDATE(MM)&amp;gt; &amp;lt;EXPIRYDATE(yyyy)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===IIF===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;IIF(param1,param2,param3,param4)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 IF param1 = param2 then&lt;br /&gt;
   return param3&lt;br /&gt;
 else&lt;br /&gt;
   return param4&lt;br /&gt;
&lt;br /&gt;
===JULIAN_YJJJ===&lt;br /&gt;
&lt;br /&gt;
This function returns the production / manufacturing data in the format {last digit of year}{Julian day number}&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;JULIAN_YJJJ()&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===LEFT===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;LEFT(fieldname,5)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===LOWERCASE===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;LOWERCASE(fieldname)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===LTRIM===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;LTRIM(fieldname)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===PADLEFT===&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;PADLEFT(fieldname,14,0)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function pads out the size of a string to the length specified using the character specified.&lt;br /&gt;
&lt;br /&gt;
It adds any additional characters to the left size of the string.&lt;br /&gt;
&lt;br /&gt;
===PADRIGHT===&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;PADRIGHT(fieldname,14,0)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function pads out the size of a string to the length specified using the character specified.&lt;br /&gt;
&lt;br /&gt;
It adds any additional characters to the right size of the string.&lt;br /&gt;
&lt;br /&gt;
===PALLET_WEIGHT_BARCODE===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;PALLET_WEIGHT_BARCODE(KG,3)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function returns the total weight of the pallet (looked up from the pallet&#039;s SSCC) formatted to the number of decimal places specified, but with the decimal point &#039;&#039;&#039;removed&#039;&#039;&#039; so that the value can be embedded directly in a barcode.&lt;br /&gt;
&lt;br /&gt;
The first parameter is the unit of measure for the weight; if it is left blank it defaults to &#039;&#039;&#039;KG&#039;&#039;&#039;. The second parameter is the number of decimal places.&lt;br /&gt;
&lt;br /&gt;
For example a weight of 123.456 KG would produce &#039;&#039;&#039;123456&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;PALLET_WEIGHT_BARCODE(KG,3)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See also [[#PALLET_WEIGHT_TEXT|PALLET_WEIGHT_TEXT]], which is identical but keeps the decimal point for human-readable display.&lt;br /&gt;
&lt;br /&gt;
===PALLET_WEIGHT_TEXT===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;PALLET_WEIGHT_TEXT(KG,3)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function returns the total weight of the pallet (looked up from the pallet&#039;s SSCC) formatted to the number of decimal places specified, for display as human-readable text on the label.&lt;br /&gt;
&lt;br /&gt;
The first parameter is the unit of measure for the weight; if it is left blank it defaults to &#039;&#039;&#039;KG&#039;&#039;&#039;. The second parameter is the number of decimal places.&lt;br /&gt;
&lt;br /&gt;
For example a weight of 123.456 KG would produce &#039;&#039;&#039;123.456&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;PALLET_WEIGHT_TEXT(KG,3)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the same as [[#PALLET_WEIGHT_BARCODE|PALLET_WEIGHT_BARCODE]] except that the decimal point is retained.&lt;br /&gt;
&lt;br /&gt;
===PRODDATE===&lt;br /&gt;
&lt;br /&gt;
This function returns the production / date of manufacture of the pallet and allows you to specify the format that you want it displayed in on the label.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;PRODDATE(dd/MM/yyyy)&amp;gt;&lt;br /&gt;
 &amp;lt;PRODDATE(ddMMyy)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the format is left blank it defaults to &#039;&#039;&#039;dd/MM/yyyy&#039;&#039;&#039;. If the date of manufacture is null it returns spaces of the same length as the format specified instead of a date.&lt;br /&gt;
&lt;br /&gt;
===RIGHT===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;RIGHT(fieldname,5)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===RTRIM===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;RTRIM(fieldname)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===SUBSTRING===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;SUBSTRING(fieldname,start,length)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function returns part of a string. &#039;&#039;&#039;start&#039;&#039;&#039; is the position of the first character to extract (the first character is position 1) and &#039;&#039;&#039;length&#039;&#039;&#039; is the number of characters to return.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;SUBSTRING(fieldname,1,3)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
would return the first 3 characters of the field. The function is bounds-safe; if the input is shorter than requested it returns as many characters as are available rather than producing an error.&lt;br /&gt;
&lt;br /&gt;
===SUBTR_LPAD===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;SUBTR_LPAD(fieldname,start,length,size,padchar)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function first left-pads the input value out to &#039;&#039;&#039;size&#039;&#039;&#039; characters using &#039;&#039;&#039;padchar&#039;&#039;&#039;, and then returns a substring of the padded value starting at position &#039;&#039;&#039;start&#039;&#039;&#039; (the first character is position 1) for &#039;&#039;&#039;length&#039;&#039;&#039; characters.&lt;br /&gt;
&lt;br /&gt;
For example, if a field contains &#039;&#039;&#039;12&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;SUBTR_LPAD(fieldname,1,4,4,0)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
would first pad the value to &#039;&#039;&#039;0012&#039;&#039;&#039; and then return the first 4 characters &#039;&#039;&#039;0012&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===TIMESTAMP===&lt;br /&gt;
&lt;br /&gt;
This function returns the current system date &amp;amp; time at the moment the label is printed, formatted using the format specified.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;TIMESTAMP(dd/MM/yyyy HH:mm:ss)&amp;gt;&lt;br /&gt;
 &amp;lt;TIMESTAMP(ddMMyy)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the format is left blank it defaults to &#039;&#039;&#039;dd/MM/yyyy HH:mm:ss&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===TRIM===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;TRIM(fieldname)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===UPPERCASE===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;UPPERCASE(fieldname)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===USERNAME===&lt;br /&gt;
&lt;br /&gt;
This function returns the name of the user currently logged on to Commander4j, in upper case.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;USERNAME()&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===VERSION===&lt;br /&gt;
&lt;br /&gt;
This function returns the version number of the Commander4j application.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;VERSION()&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=ModbusServer&amp;diff=1903</id>
		<title>ModbusServer</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=ModbusServer&amp;diff=1903"/>
		<updated>2026-06-22T14:23:09Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: Updated by push_wiki.py&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;Commander4j Modbus Server&#039;&#039;&#039; (&#039;&#039;util_modbusServer&#039;&#039;) is a desktop tool that turns your PC into a [https://en.wikipedia.org/wiki/Modbus Modbus/TCP] server — a Modbus slave, or &amp;quot;device&amp;quot;. It shows the live state of all four Modbus data tables in a single editable grid, so you can both &#039;&#039;&#039;observe&#039;&#039;&#039; what a connected Modbus client writes and &#039;&#039;&#039;drive&#039;&#039;&#039; that client by staging values for it to read. It is a test, simulation and bench tool, and is the server-side companion to the [[ModbusClient|Commander4j Modbus Client]].&lt;br /&gt;
&lt;br /&gt;
== A Quick Modbus Primer ==&lt;br /&gt;
&lt;br /&gt;
If you are new to Modbus, the following terms are used throughout this page. Modbus is a simple, widely used industrial protocol for moving numeric and on/off values between automation equipment.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Master / Client&#039;&#039;&#039; — the device that initiates requests (reads and writes). The [[ModbusClient]] is a client.&lt;br /&gt;
* &#039;&#039;&#039;Slave / Server / Device&#039;&#039;&#039; — the device that holds the data and answers requests. This tool is a server.&lt;br /&gt;
* &#039;&#039;&#039;Unit ID&#039;&#039;&#039; (also &amp;quot;slave address&amp;quot;) — a number (0–247) identifying which device a request is for. A client must use the same unit ID the server is configured to answer as.&lt;br /&gt;
* &#039;&#039;&#039;Modbus/TCP&#039;&#039;&#039; — Modbus carried over an ordinary TCP/IP network connection, as opposed to serial (RTU) wiring. These tools speak Modbus/TCP only.&lt;br /&gt;
&lt;br /&gt;
Modbus organises all data into &#039;&#039;&#039;four tables&#039;&#039;&#039;, each addressed separately starting at zero:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Table !! Holds !! Size !! Can a client write it?&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Coils&#039;&#039;&#039; || On/off output bits || 1 bit || &#039;&#039;&#039;Yes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Discrete Inputs&#039;&#039;&#039; || On/off input bits || 1 bit || No — read-only&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Input Registers&#039;&#039;&#039; || Numeric inputs (readings) || 16 bits (0–65535) || No — read-only&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Holding Registers&#039;&#039;&#039; || Numeric settings / values || 16 bits (0–65535) || &#039;&#039;&#039;Yes&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The two &amp;quot;input&amp;quot; tables represent values a device &#039;&#039;produces&#039;&#039; (sensor states, measurements), so a client can only read them. Coils and holding registers represent values a client is allowed to &#039;&#039;set&#039;&#039;. Because this server stands in for the device, it lets you edit &#039;&#039;&#039;all four&#039;&#039;&#039; tables directly — including the two a client cannot write. Each table also has a conventional &#039;&#039;&#039;reference number&#039;&#039;&#039; that operators quote instead of the raw zero-based address: coils start at 1, discrete inputs at 10001, input registers at 30001 and holding registers at 40001.&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Server is useful when:&lt;br /&gt;
&lt;br /&gt;
* Testing a Modbus master (PLC, SCADA package, or the [[ModbusClient]]) without needing the real device it normally talks to&lt;br /&gt;
* Watching exactly which coils and registers a client reads and writes, with a timestamped log of every change&lt;br /&gt;
* Staging register values in advance so a client polling the server sees a known scenario&lt;br /&gt;
* Toggling discrete inputs and input registers — values a real device produces but a client cannot write — to simulate sensor or status changes&lt;br /&gt;
* Confirming a client is configured for the correct host, port and unit ID&lt;br /&gt;
&lt;br /&gt;
== Source Code and Releases ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Server is open source and hosted on GitHub:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Repository:&#039;&#039;&#039; [https://github.com/C4J/ModbusServer https://github.com/C4J/ModbusServer]&lt;br /&gt;
* &#039;&#039;&#039;Releases (downloads):&#039;&#039;&#039; [https://github.com/C4J/ModbusServer/releases https://github.com/C4J/ModbusServer/releases]&lt;br /&gt;
&lt;br /&gt;
== Running the Modbus Server ==&lt;br /&gt;
&lt;br /&gt;
The recommended way to install the Modbus Server is to download a native installer for your platform, either from the [[Downloads]] page or from the [https://github.com/C4J/ModbusServer/releases GitHub releases page]. Native installers are provided for &#039;&#039;&#039;Windows, macOS and Linux&#039;&#039;&#039;. Each installer bundles its own Java 25 runtime, so &#039;&#039;&#039;no separate Java installation is required&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Installing creates native &#039;&#039;&#039;launchers&#039;&#039;&#039; you can run like any other desktop application (from the Start menu, Applications folder, or desktop):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Launcher !! What it does&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;ModbusServer&#039;&#039;&#039; || Starts the interactive window described below.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;ModbusServer Service&#039;&#039;&#039; || Starts the server [[#Headless (Service) Mode|headless]], with no window, using the saved configuration file. Intended for running as a background service.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Running from the jar ===&lt;br /&gt;
&lt;br /&gt;
Alternatively the tool can be run directly from its distribution folder as an ordinary Java 25 (Swing) application:&lt;br /&gt;
&lt;br /&gt;
 java -jar modbusServer.jar&lt;br /&gt;
&lt;br /&gt;
The supplied &amp;lt;code&amp;gt;start_modbusServer.sh&amp;lt;/code&amp;gt; (macOS/Linux) and &amp;lt;code&amp;gt;start_modbusServer.cmd&amp;lt;/code&amp;gt; (Windows) scripts launch it the same way. Run the jar from its own folder so the bundled &amp;lt;code&amp;gt;lib/&amp;lt;/code&amp;gt; dependencies are found alongside it.&lt;br /&gt;
&lt;br /&gt;
== The Main Window ==&lt;br /&gt;
&lt;br /&gt;
The window has three parts: a &#039;&#039;&#039;connection bar&#039;&#039;&#039; across the top, the &#039;&#039;&#039;register table&#039;&#039;&#039; in the centre with a vertical button toolbar down the right-hand side, and an &#039;&#039;&#039;activity log&#039;&#039;&#039; along the bottom.&lt;br /&gt;
&lt;br /&gt;
=== Connection Bar ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Bind address&#039;&#039;&#039; || The network interface to listen on. &amp;lt;code&amp;gt;0.0.0.0&amp;lt;/code&amp;gt; listens on all interfaces; enter a specific IP to restrict the server to one.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Port&#039;&#039;&#039; || The TCP port to listen on. The Modbus standard is &#039;&#039;&#039;502&#039;&#039;&#039;, but ports below 1024 require elevated privileges on macOS and Linux — use a high port such as &#039;&#039;&#039;1502&#039;&#039;&#039; for unprivileged testing.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Unit ID&#039;&#039;&#039; || The single slave / unit address this server answers as (0–247, default &#039;&#039;&#039;1&#039;&#039;&#039;). Requests addressed to any other unit ID are rejected, so this is a deliberate one-device simulator.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Status&#039;&#039;&#039; || Shows &#039;&#039;&#039;Stopped&#039;&#039;&#039;, or &#039;&#039;&#039;Running&#039;&#039;&#039; with the active address, port and unit ID in green.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Start / Stop&#039;&#039;&#039; button (the toggle at the top of the right-hand toolbar) binds and unbinds the server. The bind address, port and unit ID can only be changed while the server is stopped. The server can be stopped and started again without restarting the application, and &#039;&#039;&#039;all register values are kept across a stop/start&#039;&#039;&#039; — they are only lost when you exit the application.&lt;br /&gt;
&lt;br /&gt;
=== Register Table ===&lt;br /&gt;
&lt;br /&gt;
A single grid shows one row per address, with every Modbus data table side by side and colour-coded:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Column group !! Contents !! Editable here&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Address&#039;&#039;&#039; || The zero-based Modbus protocol address (the same address for the whole row). || —&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Coil&#039;&#039;&#039; || Modbus reference (1…) and an on/off checkbox. || Yes&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Discrete&#039;&#039;&#039; || Discrete input reference (10001…) and an on/off checkbox. || Yes&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Input&#039;&#039;&#039; || Input register reference (30001…), a decimal value (0–65535) and a read-only &#039;&#039;&#039;Hex&#039;&#039;&#039; view. || Yes&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Holding&#039;&#039;&#039; || Holding register reference (40001…), a decimal value (0–65535) and a read-only &#039;&#039;&#039;Hex&#039;&#039;&#039; view. || Yes&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Address&#039;&#039;&#039; is the zero-based protocol address; the &#039;&#039;&#039;Modbus Ref&#039;&#039;&#039; column in each group is the conventional reference number an operator would quote (for example coil 0 is reference 1, holding register 0 is reference 40001).&lt;br /&gt;
&lt;br /&gt;
All four tables are editable directly in this window — including discrete inputs and input registers, which a Modbus client is not allowed to write. This lets the server stand in for a real device whose inputs change. Values can be edited whether or not the server is running and whether or not a client is connected, which is useful for staging a test scenario in advance.&lt;br /&gt;
&lt;br /&gt;
Below the table, the &#039;&#039;&#039;Start address&#039;&#039;&#039; and &#039;&#039;&#039;Count&#039;&#039;&#039; fields choose which window of addresses is listed; click the tick button (Apply range) to apply them. Up to 2000 rows can be shown at once.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Zero registers&#039;&#039;&#039; button (eraser icon) on the toolbar opens a menu to clear the visible window for an individual table — Coils, Discrete Inputs, Input Registers or Holding Registers — or &#039;&#039;&#039;Zero All&#039;&#039;&#039; to clear every table at once.&lt;br /&gt;
&lt;br /&gt;
=== Activity Log ===&lt;br /&gt;
&lt;br /&gt;
Every change to a coil or register is written to the log at the bottom with a millisecond timestamp, whether it came from a connected client or from an operator edit in the window. The log keeps the most recent 400 lines. The two buttons beside it &#039;&#039;&#039;Save&#039;&#039;&#039; the log to a text file and &#039;&#039;&#039;Clear&#039;&#039;&#039; it.&lt;br /&gt;
&lt;br /&gt;
== Toolbar Buttons ==&lt;br /&gt;
&lt;br /&gt;
The vertical toolbar to the right of the register table provides, from top to bottom: &#039;&#039;&#039;Start / Stop&#039;&#039;&#039; the server, &#039;&#039;&#039;Open settings&#039;&#039;&#039;, &#039;&#039;&#039;Save settings&#039;&#039;&#039;, &#039;&#039;&#039;Zero registers&#039;&#039;&#039;, &#039;&#039;&#039;About&#039;&#039;&#039;, &#039;&#039;&#039;Licences&#039;&#039;&#039;, &#039;&#039;&#039;Help&#039;&#039;&#039; (opens this wiki page) and &#039;&#039;&#039;Close&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
The connection settings (bind address, port and unit ID) are stored in a small XML file, by default &amp;lt;code&amp;gt;xml/config/config.xml&amp;lt;/code&amp;gt; beneath the application folder:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;config&amp;gt;&lt;br /&gt;
   &amp;lt;ip&amp;gt;0.0.0.0&amp;lt;/ip&amp;gt;&lt;br /&gt;
   &amp;lt;port&amp;gt;502&amp;lt;/port&amp;gt;&lt;br /&gt;
   &amp;lt;id&amp;gt;1&amp;lt;/id&amp;gt;&lt;br /&gt;
 &amp;lt;/config&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The default settings are loaded automatically at start-up. Use the &#039;&#039;&#039;Open settings&#039;&#039;&#039; and &#039;&#039;&#039;Save settings&#039;&#039;&#039; toolbar buttons to load or store a configuration from any location. If you change the settings and then close the application, you are prompted to save the changes first.&lt;br /&gt;
&lt;br /&gt;
== Headless (Service) Mode ==&lt;br /&gt;
&lt;br /&gt;
In addition to the interactive window, the Modbus Server can run headless as a background service, started by the &#039;&#039;&#039;ModbusServer Service&#039;&#039;&#039; launcher. In this mode it loads the saved &amp;lt;code&amp;gt;xml/config/config.xml&amp;lt;/code&amp;gt;, binds the server with no user interface, and runs until the operating system asks it to stop (for example a service stop, console Ctrl-C, or system shutdown). This is why the native installer provides two launchers — &#039;&#039;&#039;ModbusServer&#039;&#039;&#039; for the window and &#039;&#039;&#039;ModbusServer Service&#039;&#039;&#039; for the headless service.&lt;br /&gt;
&lt;br /&gt;
== Using the Server and Client Together ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Server and the [[ModbusClient|Modbus Client]] are designed to be used as a pair to exercise a Modbus link from both ends without any real hardware:&lt;br /&gt;
&lt;br /&gt;
# Start this server, choose a &#039;&#039;&#039;port&#039;&#039;&#039; and &#039;&#039;&#039;unit ID&#039;&#039;&#039;, and press &#039;&#039;&#039;Start&#039;&#039;&#039;.&lt;br /&gt;
# In the [[ModbusClient]], set &#039;&#039;&#039;Server host&#039;&#039;&#039; to this machine (&amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; if both run on the same PC), set the matching &#039;&#039;&#039;port&#039;&#039;&#039; and &#039;&#039;&#039;unit ID&#039;&#039;&#039;, and press &#039;&#039;&#039;Connect&#039;&#039;&#039;.&lt;br /&gt;
# &#039;&#039;&#039;Client → Server:&#039;&#039;&#039; when the client edits a Coil or Holding Register, the value is written here and appears in this server&#039;s grid and activity log.&lt;br /&gt;
# &#039;&#039;&#039;Server → Client:&#039;&#039;&#039; edit any value here — including discrete inputs and input registers, which the client can only read — and the client&#039;s grid reflects it on its next poll.&lt;br /&gt;
&lt;br /&gt;
This makes the pair a complete bench setup: the server stands in for a device so you can develop or test a Modbus master, while the client stands in for a master so you can stage and inspect a device&#039;s data. This server can equally answer a real third-party Modbus/TCP master.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;quot;Permission denied&amp;quot; when starting&#039;&#039;&#039; — the chosen port is below 1024 (the default is 502) and the operating system requires elevated privileges to bind it. Use a port of 1024 or higher, such as 1502, or run with elevated privileges.&lt;br /&gt;
* &#039;&#039;&#039;A client&#039;s requests are rejected&#039;&#039;&#039; — the server answers only the configured &#039;&#039;&#039;Unit ID&#039;&#039;&#039;. Check the client is using the same unit ID shown in the connection bar.&lt;br /&gt;
* &#039;&#039;&#039;A startup warning about &amp;lt;code&amp;gt;sun.misc.Unsafe&amp;lt;/code&amp;gt;&#039;&#039;&#039; — harmless, and does not affect operation. The supplied start scripts suppress it; launching the jar directly may still print it.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[ModbusClient]] — the client-side companion tool&lt;br /&gt;
* [[AutoLab4j]] — uses the same Modbus stack to monitor a coil and trigger a labeller on a change of state&lt;br /&gt;
* [[SocketTest]] — a raw TCP/IP testing utility&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=ModbusClient&amp;diff=1902</id>
		<title>ModbusClient</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=ModbusClient&amp;diff=1902"/>
		<updated>2026-06-22T14:23:08Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: Updated by push_wiki.py&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;Commander4j Modbus Client&#039;&#039;&#039; (&#039;&#039;util_modbusClient&#039;&#039;) is a desktop tool that acts as a [https://en.wikipedia.org/wiki/Modbus Modbus/TCP] client — a Modbus master. It connects to a remote Modbus server (a device, PLC, or the [[ModbusServer|Commander4j Modbus Server]]), continuously polls its four data tables across a chosen address window, and shows them in a single live grid. Coil and Holding Register values can be edited to drive the connected server. It is a test, troubleshooting and bench tool, and is the client-side companion to the [[ModbusServer|Commander4j Modbus Server]].&lt;br /&gt;
&lt;br /&gt;
== A Quick Modbus Primer ==&lt;br /&gt;
&lt;br /&gt;
If you are new to Modbus, the following terms are used throughout this page. Modbus is a simple, widely used industrial protocol for moving numeric and on/off values between automation equipment.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Master / Client&#039;&#039;&#039; — the device that initiates requests (reads and writes). This tool is a client.&lt;br /&gt;
* &#039;&#039;&#039;Slave / Server / Device&#039;&#039;&#039; — the device that holds the data and answers requests. The [[ModbusServer]] is a server.&lt;br /&gt;
* &#039;&#039;&#039;Unit ID&#039;&#039;&#039; (also &amp;quot;slave address&amp;quot;) — a number (0–247) identifying which device a request is for. A client must use the same unit ID the server is configured to answer as.&lt;br /&gt;
* &#039;&#039;&#039;Modbus/TCP&#039;&#039;&#039; — Modbus carried over an ordinary TCP/IP network connection, as opposed to serial (RTU) wiring. These tools speak Modbus/TCP only.&lt;br /&gt;
&lt;br /&gt;
Modbus organises all data into &#039;&#039;&#039;four tables&#039;&#039;&#039;, each addressed separately starting at zero:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Table !! Holds !! Size !! Can a client write it?&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Coils&#039;&#039;&#039; || On/off output bits || 1 bit || &#039;&#039;&#039;Yes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Discrete Inputs&#039;&#039;&#039; || On/off input bits || 1 bit || No — read-only&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Input Registers&#039;&#039;&#039; || Numeric inputs (readings) || 16 bits (0–65535) || No — read-only&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Holding Registers&#039;&#039;&#039; || Numeric settings / values || 16 bits (0–65535) || &#039;&#039;&#039;Yes&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The two &amp;quot;input&amp;quot; tables represent values a device &#039;&#039;produces&#039;&#039; (sensor states, measurements), so a client can only read them. Coils and holding registers represent values a client is allowed to &#039;&#039;set&#039;&#039;. Each table also has a conventional &#039;&#039;&#039;reference number&#039;&#039;&#039; that operators quote instead of the raw zero-based address: coils start at 1, discrete inputs at 10001, input registers at 30001 and holding registers at 40001.&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Client is useful when:&lt;br /&gt;
&lt;br /&gt;
* Reading the live coils and registers of a PLC or other Modbus device to confirm it is responding&lt;br /&gt;
* Writing a coil or holding register to command a device during commissioning or fault-finding&lt;br /&gt;
* Checking that a device is reachable on a given host, port and unit ID&lt;br /&gt;
* Driving the [[ModbusServer]] during testing, or reading values the server is staging&lt;br /&gt;
&lt;br /&gt;
== Source Code and Releases ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Client is open source and hosted on GitHub:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Repository:&#039;&#039;&#039; [https://github.com/C4J/ModbusClient https://github.com/C4J/ModbusClient]&lt;br /&gt;
* &#039;&#039;&#039;Releases (downloads):&#039;&#039;&#039; [https://github.com/C4J/ModbusClient/releases https://github.com/C4J/ModbusClient/releases]&lt;br /&gt;
&lt;br /&gt;
== Running the Modbus Client ==&lt;br /&gt;
&lt;br /&gt;
The recommended way to install the Modbus Client is to download a native installer for your platform, either from the [[Downloads]] page or from the [https://github.com/C4J/ModbusClient/releases GitHub releases page]. Native installers are provided for &#039;&#039;&#039;Windows, macOS and Linux&#039;&#039;&#039;. Each installer bundles its own Java 25 runtime, so &#039;&#039;&#039;no separate Java installation is required&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Installing creates a native &#039;&#039;&#039;ModbusClient&#039;&#039;&#039; launcher that you run like any other desktop application — from the Start menu, Applications folder, or desktop — which opens the window described below.&lt;br /&gt;
&lt;br /&gt;
=== Running from the jar ===&lt;br /&gt;
&lt;br /&gt;
Alternatively the tool can be run directly from its distribution folder as an ordinary Java 25 (Swing) application:&lt;br /&gt;
&lt;br /&gt;
 java -jar modbusClient.jar&lt;br /&gt;
&lt;br /&gt;
The supplied &amp;lt;code&amp;gt;start_modbusClient.sh&amp;lt;/code&amp;gt; (macOS/Linux) and &amp;lt;code&amp;gt;start_modbusClient.cmd&amp;lt;/code&amp;gt; (Windows) scripts launch it the same way. Run the jar from its own folder so the bundled &amp;lt;code&amp;gt;lib/&amp;lt;/code&amp;gt; dependencies are found alongside it.&lt;br /&gt;
&lt;br /&gt;
== The Main Window ==&lt;br /&gt;
&lt;br /&gt;
The window has three parts: a &#039;&#039;&#039;connection bar&#039;&#039;&#039; across the top, the &#039;&#039;&#039;register table&#039;&#039;&#039; in the centre with a vertical button toolbar down the right-hand side, and an &#039;&#039;&#039;activity log&#039;&#039;&#039; along the bottom.&lt;br /&gt;
&lt;br /&gt;
=== Connection Bar ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Server host&#039;&#039;&#039; || The host name or IP address of the Modbus server to connect to. Defaults to &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; (this machine) for quick loopback testing against a local [[ModbusServer]].&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Port&#039;&#039;&#039; || The TCP port of the server. The Modbus standard is &#039;&#039;&#039;502&#039;&#039;&#039;; match whatever the server is listening on.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Unit ID&#039;&#039;&#039; || The unit / slave address to address requests to (0–247, default &#039;&#039;&#039;1&#039;&#039;&#039;). This must match the unit ID the server answers as, or every request will be rejected.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Status&#039;&#039;&#039; || Shows &#039;&#039;&#039;Disconnected&#039;&#039;&#039;, or &#039;&#039;&#039;Connected&#039;&#039;&#039; with the server address and unit ID in green.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Connect / Disconnect&#039;&#039;&#039; button (the toggle at the top of the right-hand toolbar) opens and closes the connection. The host, port and unit ID can only be changed while disconnected. Once connected, the client polls the server roughly four times a second and the grid updates live.&lt;br /&gt;
&lt;br /&gt;
=== Register Table ===&lt;br /&gt;
&lt;br /&gt;
A single grid shows one row per address, with every Modbus data table side by side and colour-coded:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Column group !! Contents !! Editable here&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Address&#039;&#039;&#039; || The zero-based Modbus protocol address (the same address for the whole row). || —&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Coil&#039;&#039;&#039; || Modbus reference (1…) and an on/off checkbox. || &#039;&#039;&#039;Yes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Discrete&#039;&#039;&#039; || Discrete input reference (10001…) and an on/off checkbox. || No (read-only)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Input&#039;&#039;&#039; || Input register reference (30001…), a decimal value and a read-only &#039;&#039;&#039;Hex&#039;&#039;&#039; view. || No (read-only)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Holding&#039;&#039;&#039; || Holding register reference (40001…), a decimal value (0–65535) and a read-only &#039;&#039;&#039;Hex&#039;&#039;&#039; view. || &#039;&#039;&#039;Yes&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Only the &#039;&#039;&#039;Coil&#039;&#039;&#039; and &#039;&#039;&#039;Holding Register&#039;&#039;&#039; value cells can be edited, and only while connected — because Modbus has no function code for a client to write the discrete-input and input-register tables. Editing a cell writes the new value straight through to the server; the displayed value updates immediately and is reverted if the server rejects the write.&lt;br /&gt;
&lt;br /&gt;
Below the table, the &#039;&#039;&#039;Start address&#039;&#039;&#039; and &#039;&#039;&#039;Count&#039;&#039;&#039; fields choose which window of addresses the client polls; click the tick button (Apply range) to apply them. Up to 2000 rows can be shown at once.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Zero registers&#039;&#039;&#039; button (eraser icon) on the toolbar opens a menu to clear the visible window of the writable tables — &#039;&#039;&#039;Zero Coils&#039;&#039;&#039;, &#039;&#039;&#039;Zero Holding Registers&#039;&#039;&#039;, or &#039;&#039;&#039;Zero All&#039;&#039;&#039; for both. Only the writable tables appear, because the read-only ones cannot be cleared by a client.&lt;br /&gt;
&lt;br /&gt;
=== Activity Log ===&lt;br /&gt;
&lt;br /&gt;
Connection events, writes, and any errors are written to the log at the bottom with a millisecond timestamp. The log keeps the most recent 400 lines. The two buttons beside it &#039;&#039;&#039;Save&#039;&#039;&#039; the log to a text file and &#039;&#039;&#039;Clear&#039;&#039;&#039; it. If the connection is lost (for example the server stops or the network drops), the client reports it in the log and returns to the disconnected state automatically.&lt;br /&gt;
&lt;br /&gt;
== Toolbar Buttons ==&lt;br /&gt;
&lt;br /&gt;
The vertical toolbar to the right of the register table provides, from top to bottom: &#039;&#039;&#039;Connect / Disconnect&#039;&#039;&#039;, &#039;&#039;&#039;Open settings&#039;&#039;&#039;, &#039;&#039;&#039;Save settings&#039;&#039;&#039;, &#039;&#039;&#039;Zero registers&#039;&#039;&#039;, &#039;&#039;&#039;About&#039;&#039;&#039;, &#039;&#039;&#039;Licences&#039;&#039;&#039;, &#039;&#039;&#039;Help&#039;&#039;&#039; (opens this wiki page) and &#039;&#039;&#039;Close&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
The connection settings (server host, port and unit ID) are stored in a small XML file, by default &amp;lt;code&amp;gt;xml/config/config.xml&amp;lt;/code&amp;gt; beneath the application folder:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;config&amp;gt;&lt;br /&gt;
   &amp;lt;ip&amp;gt;127.0.0.1&amp;lt;/ip&amp;gt;&lt;br /&gt;
   &amp;lt;port&amp;gt;502&amp;lt;/port&amp;gt;&lt;br /&gt;
   &amp;lt;id&amp;gt;1&amp;lt;/id&amp;gt;&lt;br /&gt;
 &amp;lt;/config&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The default settings are loaded automatically at start-up. Use the &#039;&#039;&#039;Open settings&#039;&#039;&#039; and &#039;&#039;&#039;Save settings&#039;&#039;&#039; toolbar buttons to load or store a configuration from any location. If you change the settings and then close the application, you are prompted to save the changes first.&lt;br /&gt;
&lt;br /&gt;
== Using the Client and Server Together ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Client and the [[ModbusServer|Modbus Server]] are designed to be used as a pair to exercise a Modbus link from both ends without any real hardware:&lt;br /&gt;
&lt;br /&gt;
# Start the [[ModbusServer]] on one machine (or the same machine), choose a &#039;&#039;&#039;port&#039;&#039;&#039; and &#039;&#039;&#039;unit ID&#039;&#039;&#039;, and press &#039;&#039;&#039;Start&#039;&#039;&#039;.&lt;br /&gt;
# In the Modbus Client, set &#039;&#039;&#039;Server host&#039;&#039;&#039; to that machine (&amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; if both run on the same PC), set the matching &#039;&#039;&#039;port&#039;&#039;&#039; and &#039;&#039;&#039;unit ID&#039;&#039;&#039;, and press &#039;&#039;&#039;Connect&#039;&#039;&#039;.&lt;br /&gt;
# &#039;&#039;&#039;Client → Server:&#039;&#039;&#039; edit a Coil or Holding Register in the client; the value is written to the server and appears in the server&#039;s grid and activity log.&lt;br /&gt;
# &#039;&#039;&#039;Server → Client:&#039;&#039;&#039; edit any value in the server — including discrete inputs and input registers, which the client can only read; the client&#039;s grid reflects it on the next poll.&lt;br /&gt;
&lt;br /&gt;
This makes the pair a complete bench setup: the server stands in for a device so you can develop or test a Modbus master, and the client stands in for a master so you can stage and inspect a device&#039;s data. Either tool can also be pointed at real third-party Modbus/TCP equipment.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;quot;Connection refused&amp;quot; or a timeout on Connect&#039;&#039;&#039; — check the server host and port, that the server is running and listening, and that no firewall is blocking the connection.&lt;br /&gt;
* &#039;&#039;&#039;Connected, but every read fails or the connection drops immediately&#039;&#039;&#039; — the &#039;&#039;&#039;Unit ID&#039;&#039;&#039; probably does not match the server. The client must address the exact unit ID the server answers as.&lt;br /&gt;
* &#039;&#039;&#039;A startup warning about &amp;lt;code&amp;gt;sun.misc.Unsafe&amp;lt;/code&amp;gt;&#039;&#039;&#039; — harmless, and does not affect operation. The supplied start scripts suppress it; launching the jar directly may still print it.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[ModbusServer]] — the server-side companion tool&lt;br /&gt;
* [[AutoLab4j]] — uses the same Modbus stack to monitor a coil and trigger a labeller on a change of state&lt;br /&gt;
* [[SocketTest]] — a raw TCP/IP testing utility&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=ModbusBridge&amp;diff=1901</id>
		<title>ModbusBridge</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=ModbusBridge&amp;diff=1901"/>
		<updated>2026-06-22T14:23:07Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: Updated by push_wiki.py&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;Commander4j Modbus Bridge&#039;&#039;&#039; (&#039;&#039;util_modbusBridge&#039;&#039;) is a &#039;&#039;&#039;headless service&#039;&#039;&#039; that lets applications without [https://en.wikipedia.org/wiki/Modbus Modbus/TCP] client capability set and query the values of a remote Modbus server over a simple REST API. It connects to one Modbus server, polls a fixed list of &#039;&#039;&#039;named points&#039;&#039;&#039; (configured in XML), keeps the latest values in memory, and serves them over HTTP. It also provides a live web UI to view and change values, and a second page to tail the log.&lt;br /&gt;
&lt;br /&gt;
Unlike the interactive [[ModbusClient|Commander4j Modbus Client]], the Bridge runs unattended: it auto-reconnects when the link drops and is packaged to run as an operating-system service. It reuses the same Modbus engine as the [[ModbusClient]] and is a natural companion to the [[ModbusServer]].&lt;br /&gt;
&lt;br /&gt;
If you are new to Modbus, the [[ModbusClient#A Quick Modbus Primer|Modbus primer on the Modbus Client page]] explains the terms (client/server, unit ID, and the four data tables) used throughout this page.&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Bridge is useful when:&lt;br /&gt;
&lt;br /&gt;
* An application or script that cannot speak Modbus needs to read or write a PLC or other Modbus/TCP device over plain HTTP/JSON&lt;br /&gt;
* A remote Modbus server&#039;s values should be exposed on a network as named points rather than raw addresses&lt;br /&gt;
* An unattended, always-on bridge is needed that survives link drops and restarts as a managed service&lt;br /&gt;
* A browser-based view of live values, with inline editing and a live log, is wanted without installing a desktop tool&lt;br /&gt;
&lt;br /&gt;
== Source Code and Releases ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Bridge is open source and hosted on GitHub:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Repository:&#039;&#039;&#039; [https://github.com/C4J/ModbusBridge https://github.com/C4J/ModbusBridge]&lt;br /&gt;
* &#039;&#039;&#039;Releases (downloads):&#039;&#039;&#039; [https://github.com/C4J/ModbusBridge/releases https://github.com/C4J/ModbusBridge/releases]&lt;br /&gt;
&lt;br /&gt;
== Running the Modbus Bridge ==&lt;br /&gt;
&lt;br /&gt;
The recommended way to install the Modbus Bridge is to download a native installer for your platform, either from the [[Downloads]] page or from the [https://github.com/C4J/ModbusBridge/releases GitHub releases page]. Native installers are provided for &#039;&#039;&#039;Windows, macOS and Linux&#039;&#039;&#039;. Each installer bundles its own Java 25 runtime, so &#039;&#039;&#039;no separate Java installation is required&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== As a service ===&lt;br /&gt;
&lt;br /&gt;
The native installer registers and starts the Bridge as an operating-system service — &#039;&#039;&#039;launchd&#039;&#039;&#039; on macOS, a &#039;&#039;&#039;Windows service&#039;&#039;&#039;, or a &#039;&#039;&#039;systemd / init&#039;&#039;&#039; unit on Linux. The service runs with its working directory set to the installation directory, so all the relative paths below resolve correctly. Stopping the service triggers an ordered shutdown so that teardown events still reach the log file.&lt;br /&gt;
&lt;br /&gt;
=== Running from the jar ===&lt;br /&gt;
&lt;br /&gt;
Alternatively the Bridge can be launched from its distribution folder:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;./start_modbusBridge.sh&amp;lt;/code&amp;gt; (macOS/Linux) or &amp;lt;code&amp;gt;start_modbusBridge.cmd&amp;lt;/code&amp;gt; (Windows), or&lt;br /&gt;
* &amp;lt;code&amp;gt;ant run&amp;lt;/code&amp;gt; to launch from compiled classes, or&lt;br /&gt;
* directly with Java:&lt;br /&gt;
&lt;br /&gt;
 java -Dlog4j2.shutdownHookEnabled=false -Dlog4j2.configurationFile=xml/config/log4j2.xml -jar modbusBridge.jar&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;modbusBridge.jar&amp;lt;/code&amp;gt; is a &#039;&#039;&#039;thin jar&#039;&#039;&#039; — it references the dependency jars in &amp;lt;code&amp;gt;lib/&amp;lt;/code&amp;gt; via its manifest, so it must be run from the project root with &amp;lt;code&amp;gt;lib/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;xml/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;web/&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;logs/&amp;lt;/code&amp;gt; alongside it. Any Java 25 runtime on the &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; will do; a bundled JRE is not required when run this way.&lt;br /&gt;
&lt;br /&gt;
The two &amp;lt;code&amp;gt;-D&amp;lt;/code&amp;gt; system properties matter, and the start scripts set them for you:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;-Dlog4j2.shutdownHookEnabled=false&amp;lt;/code&amp;gt; — lets the Bridge&#039;s own shutdown hook stop log4j2 &#039;&#039;&#039;last&#039;&#039;&#039;, so teardown events still reach the log file the tail page reads.&lt;br /&gt;
* &amp;lt;code&amp;gt;-Dlog4j2.configurationFile=xml/config/log4j2.xml&amp;lt;/code&amp;gt; — &amp;lt;code&amp;gt;log4j2.xml&amp;lt;/code&amp;gt; lives under &amp;lt;code&amp;gt;xml/config/&amp;lt;/code&amp;gt;, not on the classpath, so log4j2 must be pointed at it explicitly.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
All configuration is in &amp;lt;code&amp;gt;xml/config/config.xml&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;config&amp;gt;&lt;br /&gt;
   &amp;lt;modbus&amp;gt;&lt;br /&gt;
     &amp;lt;ip&amp;gt;127.0.0.1&amp;lt;/ip&amp;gt;&lt;br /&gt;
     &amp;lt;port&amp;gt;1502&amp;lt;/port&amp;gt;&lt;br /&gt;
     &amp;lt;id&amp;gt;1&amp;lt;/id&amp;gt;&lt;br /&gt;
     &amp;lt;pollIntervalMs&amp;gt;1000&amp;lt;/pollIntervalMs&amp;gt;&lt;br /&gt;
   &amp;lt;/modbus&amp;gt;&lt;br /&gt;
   &amp;lt;webserver&amp;gt;&lt;br /&gt;
     &amp;lt;ip&amp;gt;0.0.0.0&amp;lt;/ip&amp;gt;&lt;br /&gt;
     &amp;lt;port&amp;gt;8080&amp;lt;/port&amp;gt;&lt;br /&gt;
   &amp;lt;/webserver&amp;gt;&lt;br /&gt;
   &amp;lt;points&amp;gt;&lt;br /&gt;
     &amp;lt;point name=&amp;quot;pump_run&amp;quot;   kind=&amp;quot;COIL&amp;quot;             address=&amp;quot;0&amp;quot;/&amp;gt;&lt;br /&gt;
     &amp;lt;point name=&amp;quot;tank_level&amp;quot; kind=&amp;quot;HOLDING_REGISTER&amp;quot; address=&amp;quot;100&amp;quot;/&amp;gt;&lt;br /&gt;
     &amp;lt;point name=&amp;quot;fault&amp;quot;      kind=&amp;quot;DISCRETE_INPUT&amp;quot;   address=&amp;quot;10&amp;quot;/&amp;gt;&lt;br /&gt;
     &amp;lt;point name=&amp;quot;flow_rate&amp;quot;  kind=&amp;quot;INPUT_REGISTER&amp;quot;   address=&amp;quot;30&amp;quot;/&amp;gt;&lt;br /&gt;
   &amp;lt;/points&amp;gt;&lt;br /&gt;
 &amp;lt;/config&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;&amp;lt;modbus&amp;gt;&amp;lt;/code&amp;gt; block points the Bridge at the remote Modbus server: its host &amp;lt;code&amp;gt;&amp;lt;ip&amp;gt;&amp;lt;/code&amp;gt;, TCP &amp;lt;code&amp;gt;&amp;lt;port&amp;gt;&amp;lt;/code&amp;gt; (the Modbus standard is &#039;&#039;&#039;502&#039;&#039;&#039;; the example uses &#039;&#039;&#039;1502&#039;&#039;&#039; because ports below 1024 need root on macOS/Linux), the unit / slave &amp;lt;code&amp;gt;&amp;lt;id&amp;gt;&amp;lt;/code&amp;gt; to address, and the &amp;lt;code&amp;gt;&amp;lt;pollIntervalMs&amp;gt;&amp;lt;/code&amp;gt; between reads. The &amp;lt;code&amp;gt;&amp;lt;webserver&amp;gt;&amp;lt;/code&amp;gt; block sets the bind address for the HTTP server (&amp;lt;code&amp;gt;0.0.0.0&amp;lt;/code&amp;gt; = all interfaces) and the port it listens on.&lt;br /&gt;
&lt;br /&gt;
Each &amp;lt;code&amp;gt;&amp;lt;point&amp;gt;&amp;lt;/code&amp;gt; gives a human-friendly &#039;&#039;&#039;name&#039;&#039;&#039; (how REST clients and the web UI refer to it), a Modbus data table &#039;&#039;&#039;kind&#039;&#039;&#039;, and a zero-based protocol &#039;&#039;&#039;address&#039;&#039;&#039;. Valid kinds are &amp;lt;code&amp;gt;COIL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DISCRETE_INPUT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HOLDING_REGISTER&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;INPUT_REGISTER&amp;lt;/code&amp;gt;. Only &#039;&#039;&#039;coils&#039;&#039;&#039; and &#039;&#039;&#039;holding registers&#039;&#039;&#039; are writable — discrete inputs and input registers are read-only in the Modbus data model (there is no client-write function code for them).&lt;br /&gt;
&lt;br /&gt;
Logging is configured in &amp;lt;code&amp;gt;xml/config/log4j2.xml&amp;lt;/code&amp;gt; (rolling file at &amp;lt;code&amp;gt;logs/modbusBridge.log&amp;lt;/code&amp;gt;, 10 MB cap, 5 generations). The Bridge&#039;s own classes log at &amp;lt;code&amp;gt;debug&amp;lt;/code&amp;gt;; the Netty transport at &amp;lt;code&amp;gt;warn&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== REST API ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Behaviour&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/points&amp;lt;/code&amp;gt; || All points with current values + connection status.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/points/{name}&amp;lt;/code&amp;gt; || One point&#039;s current value. 404 if unknown.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PUT&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/points/{name}&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;{&amp;quot;value&amp;quot;: N}&amp;lt;/code&amp;gt; || Write a coil (0/1, or &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;) or holding register (0–65535). 400 for read-only kinds or out-of-range; 503 if the server is unreachable.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/status&amp;lt;/code&amp;gt; || Connection health: connected, target, unit id, poll interval, last-poll time, point count.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/licence&amp;lt;/code&amp;gt; || Third-party licence list (from &amp;lt;code&amp;gt;lib/license/LicenseInfo.xml&amp;lt;/code&amp;gt;).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/log/tail&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;?lines=N&amp;lt;/code&amp;gt; || Recent log lines (default 200, max 5000).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/events&amp;lt;/code&amp;gt; || Server-Sent Events stream of the full points payload, pushed on every change.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/events/log&amp;lt;/code&amp;gt; || Server-Sent Events stream of newly-appended log lines.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A write is &#039;&#039;&#039;self-correcting&#039;&#039;&#039;, not optimistic: the Bridge writes the value, then immediately reads the point back from the server, so the response and cache reflect the server&#039;s actual state. When the link is down, reads return the last snapshot flagged &amp;lt;code&amp;gt;&amp;quot;valid&amp;quot;:false,&amp;quot;stale&amp;quot;:true&amp;lt;/code&amp;gt; and writes return &#039;&#039;&#039;503&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
 curl http://localhost:8080/api/points&lt;br /&gt;
 curl -X PUT -H &#039;Content-Type: application/json&#039; -d &#039;{&amp;quot;value&amp;quot;:1}&#039;    http://localhost:8080/api/points/pump_run&lt;br /&gt;
 curl -X PUT -H &#039;Content-Type: application/json&#039; -d &#039;{&amp;quot;value&amp;quot;:4242}&#039; http://localhost:8080/api/points/tank_level&lt;br /&gt;
&lt;br /&gt;
== Web UI ==&lt;br /&gt;
&lt;br /&gt;
Open &amp;lt;code&amp;gt;http://&amp;lt;host&amp;gt;:8080/&amp;lt;/code&amp;gt; in a browser:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Points&#039;&#039;&#039; (&amp;lt;code&amp;gt;index.html&amp;lt;/code&amp;gt;) — a live table of every configured point, updated by push (SSE) with no refresh needed. Writable points have an inline editor; type a value and click &#039;&#039;&#039;Set&#039;&#039;&#039; (or press Enter) to issue the PUT. Stale values (link down) are shown in red. A manual &#039;&#039;&#039;Refresh&#039;&#039;&#039; button is kept as a fallback.&lt;br /&gt;
* &#039;&#039;&#039;Log&#039;&#039;&#039; (&amp;lt;code&amp;gt;log.html&amp;lt;/code&amp;gt;) — the recent log backlog followed live as new lines are written, with an auto-scroll toggle. &amp;lt;code&amp;gt;WARN&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;ERROR&amp;lt;/code&amp;gt; lines are colour-coded.&lt;br /&gt;
* &#039;&#039;&#039;Licences&#039;&#039;&#039; (&amp;lt;code&amp;gt;licence.html&amp;lt;/code&amp;gt;) — the third-party libraries and their licences rendered as a table (the underlying &amp;lt;code&amp;gt;/api/licence&amp;lt;/code&amp;gt; endpoint returns the same data as raw JSON).&lt;br /&gt;
&lt;br /&gt;
== Modbus Behaviour ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transport:&#039;&#039;&#039; Modbus/TCP only (no serial / RTU, no TLS), reusing the [[ModbusClient]]&#039;s Modbus engine.&lt;br /&gt;
* The poll thread reads every configured point once per &amp;lt;code&amp;gt;pollIntervalMs&amp;lt;/code&amp;gt;. A read failure tears the connection down, flags all points stale, and the Bridge auto-reconnects with exponential backoff (1 → 2 → 4 → 8 … up to 30 s), resetting on a successful connect.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;Address already in use&amp;lt;/code&amp;gt; on start&#039;&#039;&#039; — another process holds the web port (default 8080). Change &amp;lt;code&amp;gt;&amp;lt;webserver&amp;gt;&amp;lt;port&amp;gt;&amp;lt;/code&amp;gt; or free the port.&lt;br /&gt;
* &#039;&#039;&#039;All points show stale / &amp;lt;code&amp;gt;/api/status&amp;lt;/code&amp;gt; says not connected&#039;&#039;&#039; — the Modbus server is unreachable. Check &amp;lt;code&amp;gt;&amp;lt;modbus&amp;gt;&amp;lt;ip&amp;gt;/&amp;lt;port&amp;gt;&amp;lt;/code&amp;gt;, that the server is running, and that both ends use the same &#039;&#039;&#039;unit id&#039;&#039;&#039; (the server answers only its configured unit). The log shows the backoff retries.&lt;br /&gt;
* &#039;&#039;&#039;Writes return 503&#039;&#039;&#039; — the link is down at that moment; the Bridge is between reconnect attempts. Reads still return the last-known (stale) values.&lt;br /&gt;
* &#039;&#039;&#039;PUT returns 400 &amp;quot;read-only&amp;quot;&#039;&#039;&#039; — the named point is a &amp;lt;code&amp;gt;DISCRETE_INPUT&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;INPUT_REGISTER&amp;lt;/code&amp;gt;; those cannot be written by a Modbus client.&lt;br /&gt;
* &#039;&#039;&#039;No log lines / empty log tail page&#039;&#039;&#039; — confirm &amp;lt;code&amp;gt;-Dlog4j2.configurationFile=xml/config/log4j2.xml&amp;lt;/code&amp;gt; is set (the start scripts do this) and the process working directory is the project root, so &amp;lt;code&amp;gt;logs/&amp;lt;/code&amp;gt; is created in the right place.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[ModbusClient]] — the interactive desktop Modbus client; the Bridge reuses its Modbus engine&lt;br /&gt;
* [[ModbusServer]] — the server-side companion tool, useful as a bench target for the Bridge&lt;br /&gt;
* [[AutoLab4j]] — uses the same Modbus stack to monitor a coil and trigger a labeller on a change of state&lt;br /&gt;
* [[SocketTest]] — a raw TCP/IP testing utility&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=ModbusServer&amp;diff=1900</id>
		<title>ModbusServer</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=ModbusServer&amp;diff=1900"/>
		<updated>2026-06-22T14:22:36Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: Updated by push_wiki.py&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;Commander4j Modbus Server&#039;&#039;&#039; (&#039;&#039;util_modbusServer&#039;&#039;) is a desktop tool that turns your PC into a [https://en.wikipedia.org/wiki/Modbus Modbus/TCP] server — a Modbus slave, or &amp;quot;device&amp;quot;. It shows the live state of all four Modbus data tables in a single editable grid, so you can both &#039;&#039;&#039;observe&#039;&#039;&#039; what a connected Modbus client writes and &#039;&#039;&#039;drive&#039;&#039;&#039; that client by staging values for it to read. It is a test, simulation and bench tool, and is the server-side companion to the [[ModbusClient|Commander4j Modbus Client]].&lt;br /&gt;
&lt;br /&gt;
== A Quick Modbus Primer ==&lt;br /&gt;
&lt;br /&gt;
If you are new to Modbus, the following terms are used throughout this page. Modbus is a simple, widely used industrial protocol for moving numeric and on/off values between automation equipment.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Master / Client&#039;&#039;&#039; — the device that initiates requests (reads and writes). The [[ModbusClient]] is a client.&lt;br /&gt;
* &#039;&#039;&#039;Slave / Server / Device&#039;&#039;&#039; — the device that holds the data and answers requests. This tool is a server.&lt;br /&gt;
* &#039;&#039;&#039;Unit ID&#039;&#039;&#039; (also &amp;quot;slave address&amp;quot;) — a number (0–247) identifying which device a request is for. A client must use the same unit ID the server is configured to answer as.&lt;br /&gt;
* &#039;&#039;&#039;Modbus/TCP&#039;&#039;&#039; — Modbus carried over an ordinary TCP/IP network connection, as opposed to serial (RTU) wiring. These tools speak Modbus/TCP only.&lt;br /&gt;
&lt;br /&gt;
Modbus organises all data into &#039;&#039;&#039;four tables&#039;&#039;&#039;, each addressed separately starting at zero:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Table !! Holds !! Size !! Can a client write it?&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Coils&#039;&#039;&#039; || On/off output bits || 1 bit || &#039;&#039;&#039;Yes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Discrete Inputs&#039;&#039;&#039; || On/off input bits || 1 bit || No — read-only&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Input Registers&#039;&#039;&#039; || Numeric inputs (readings) || 16 bits (0–65535) || No — read-only&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Holding Registers&#039;&#039;&#039; || Numeric settings / values || 16 bits (0–65535) || &#039;&#039;&#039;Yes&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The two &amp;quot;input&amp;quot; tables represent values a device &#039;&#039;produces&#039;&#039; (sensor states, measurements), so a client can only read them. Coils and holding registers represent values a client is allowed to &#039;&#039;set&#039;&#039;. Because this server stands in for the device, it lets you edit &#039;&#039;&#039;all four&#039;&#039;&#039; tables directly — including the two a client cannot write. Each table also has a conventional &#039;&#039;&#039;reference number&#039;&#039;&#039; that operators quote instead of the raw zero-based address: coils start at 1, discrete inputs at 10001, input registers at 30001 and holding registers at 40001.&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Server is useful when:&lt;br /&gt;
&lt;br /&gt;
* Testing a Modbus master (PLC, SCADA package, or the [[ModbusClient]]) without needing the real device it normally talks to&lt;br /&gt;
* Watching exactly which coils and registers a client reads and writes, with a timestamped log of every change&lt;br /&gt;
* Staging register values in advance so a client polling the server sees a known scenario&lt;br /&gt;
* Toggling discrete inputs and input registers — values a real device produces but a client cannot write — to simulate sensor or status changes&lt;br /&gt;
* Confirming a client is configured for the correct host, port and unit ID&lt;br /&gt;
&lt;br /&gt;
== Source Code and Releases ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Server is open source and hosted on GitHub:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Repository:&#039;&#039;&#039; [https://github.com/C4J/ModbusServer https://github.com/C4J/ModbusServer]&lt;br /&gt;
* &#039;&#039;&#039;Releases (downloads):&#039;&#039;&#039; [https://github.com/C4J/ModbusServer/releases https://github.com/C4J/ModbusServer/releases]&lt;br /&gt;
&lt;br /&gt;
== Running the Modbus Server ==&lt;br /&gt;
&lt;br /&gt;
The recommended way to install the Modbus Server is to download a native installer for your platform, either from the [[Downloads]] page or from the [https://github.com/C4J/ModbusServer/releases GitHub releases page]. Native installers are provided for &#039;&#039;&#039;Windows, macOS and Linux&#039;&#039;&#039;. Each installer bundles its own Java 25 runtime, so &#039;&#039;&#039;no separate Java installation is required&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Installing creates native &#039;&#039;&#039;launchers&#039;&#039;&#039; you can run like any other desktop application (from the Start menu, Applications folder, or desktop):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Launcher !! What it does&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;ModbusServer&#039;&#039;&#039; || Starts the interactive window described below.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;ModbusServer Service&#039;&#039;&#039; || Starts the server [[#Headless (Service) Mode|headless]], with no window, using the saved configuration file. Intended for running as a background service.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Running from the jar ===&lt;br /&gt;
&lt;br /&gt;
Alternatively the tool can be run directly from its distribution folder as an ordinary Java 25 (Swing) application:&lt;br /&gt;
&lt;br /&gt;
 java -jar modbusServer.jar&lt;br /&gt;
&lt;br /&gt;
The supplied &amp;lt;code&amp;gt;start_modbusServer.sh&amp;lt;/code&amp;gt; (macOS/Linux) and &amp;lt;code&amp;gt;start_modbusServer.cmd&amp;lt;/code&amp;gt; (Windows) scripts launch it the same way. Run the jar from its own folder so the bundled &amp;lt;code&amp;gt;lib/&amp;lt;/code&amp;gt; dependencies are found alongside it.&lt;br /&gt;
&lt;br /&gt;
== The Main Window ==&lt;br /&gt;
&lt;br /&gt;
The window has three parts: a &#039;&#039;&#039;connection bar&#039;&#039;&#039; across the top, the &#039;&#039;&#039;register table&#039;&#039;&#039; in the centre with a vertical button toolbar down the right-hand side, and an &#039;&#039;&#039;activity log&#039;&#039;&#039; along the bottom.&lt;br /&gt;
&lt;br /&gt;
=== Connection Bar ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Bind address&#039;&#039;&#039; || The network interface to listen on. &amp;lt;code&amp;gt;0.0.0.0&amp;lt;/code&amp;gt; listens on all interfaces; enter a specific IP to restrict the server to one.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Port&#039;&#039;&#039; || The TCP port to listen on. The Modbus standard is &#039;&#039;&#039;502&#039;&#039;&#039;, but ports below 1024 require elevated privileges on macOS and Linux — use a high port such as &#039;&#039;&#039;1502&#039;&#039;&#039; for unprivileged testing.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Unit ID&#039;&#039;&#039; || The single slave / unit address this server answers as (0–247, default &#039;&#039;&#039;1&#039;&#039;&#039;). Requests addressed to any other unit ID are rejected, so this is a deliberate one-device simulator.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Status&#039;&#039;&#039; || Shows &#039;&#039;&#039;Stopped&#039;&#039;&#039;, or &#039;&#039;&#039;Running&#039;&#039;&#039; with the active address, port and unit ID in green.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Start / Stop&#039;&#039;&#039; button (the toggle at the top of the right-hand toolbar) binds and unbinds the server. The bind address, port and unit ID can only be changed while the server is stopped. The server can be stopped and started again without restarting the application, and &#039;&#039;&#039;all register values are kept across a stop/start&#039;&#039;&#039; — they are only lost when you exit the application.&lt;br /&gt;
&lt;br /&gt;
=== Register Table ===&lt;br /&gt;
&lt;br /&gt;
A single grid shows one row per address, with every Modbus data table side by side and colour-coded:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Column group !! Contents !! Editable here&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Address&#039;&#039;&#039; || The zero-based Modbus protocol address (the same address for the whole row). || —&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Coil&#039;&#039;&#039; || Modbus reference (1…) and an on/off checkbox. || Yes&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Discrete&#039;&#039;&#039; || Discrete input reference (10001…) and an on/off checkbox. || Yes&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Input&#039;&#039;&#039; || Input register reference (30001…), a decimal value (0–65535) and a read-only &#039;&#039;&#039;Hex&#039;&#039;&#039; view. || Yes&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Holding&#039;&#039;&#039; || Holding register reference (40001…), a decimal value (0–65535) and a read-only &#039;&#039;&#039;Hex&#039;&#039;&#039; view. || Yes&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Address&#039;&#039;&#039; is the zero-based protocol address; the &#039;&#039;&#039;Modbus Ref&#039;&#039;&#039; column in each group is the conventional reference number an operator would quote (for example coil 0 is reference 1, holding register 0 is reference 40001).&lt;br /&gt;
&lt;br /&gt;
All four tables are editable directly in this window — including discrete inputs and input registers, which a Modbus client is not allowed to write. This lets the server stand in for a real device whose inputs change. Values can be edited whether or not the server is running and whether or not a client is connected, which is useful for staging a test scenario in advance.&lt;br /&gt;
&lt;br /&gt;
Below the table, the &#039;&#039;&#039;Start address&#039;&#039;&#039; and &#039;&#039;&#039;Count&#039;&#039;&#039; fields choose which window of addresses is listed; click the tick button (Apply range) to apply them. Up to 2000 rows can be shown at once.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Zero registers&#039;&#039;&#039; button (eraser icon) on the toolbar opens a menu to clear the visible window for an individual table — Coils, Discrete Inputs, Input Registers or Holding Registers — or &#039;&#039;&#039;Zero All&#039;&#039;&#039; to clear every table at once.&lt;br /&gt;
&lt;br /&gt;
=== Activity Log ===&lt;br /&gt;
&lt;br /&gt;
Every change to a coil or register is written to the log at the bottom with a millisecond timestamp, whether it came from a connected client or from an operator edit in the window. The log keeps the most recent 400 lines. The two buttons beside it &#039;&#039;&#039;Save&#039;&#039;&#039; the log to a text file and &#039;&#039;&#039;Clear&#039;&#039;&#039; it.&lt;br /&gt;
&lt;br /&gt;
== Toolbar Buttons ==&lt;br /&gt;
&lt;br /&gt;
The vertical toolbar to the right of the register table provides, from top to bottom: &#039;&#039;&#039;Start / Stop&#039;&#039;&#039; the server, &#039;&#039;&#039;Open settings&#039;&#039;&#039;, &#039;&#039;&#039;Save settings&#039;&#039;&#039;, &#039;&#039;&#039;Zero registers&#039;&#039;&#039;, &#039;&#039;&#039;About&#039;&#039;&#039;, &#039;&#039;&#039;Licences&#039;&#039;&#039;, &#039;&#039;&#039;Help&#039;&#039;&#039; (opens this wiki page) and &#039;&#039;&#039;Close&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
The connection settings (bind address, port and unit ID) are stored in a small XML file, by default &amp;lt;code&amp;gt;xml/config/config.xml&amp;lt;/code&amp;gt; beneath the application folder:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;config&amp;gt;&lt;br /&gt;
   &amp;lt;ip&amp;gt;0.0.0.0&amp;lt;/ip&amp;gt;&lt;br /&gt;
   &amp;lt;port&amp;gt;502&amp;lt;/port&amp;gt;&lt;br /&gt;
   &amp;lt;id&amp;gt;1&amp;lt;/id&amp;gt;&lt;br /&gt;
 &amp;lt;/config&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The default settings are loaded automatically at start-up. Use the &#039;&#039;&#039;Open settings&#039;&#039;&#039; and &#039;&#039;&#039;Save settings&#039;&#039;&#039; toolbar buttons to load or store a configuration from any location. If you change the settings and then close the application, you are prompted to save the changes first.&lt;br /&gt;
&lt;br /&gt;
== Headless (Service) Mode ==&lt;br /&gt;
&lt;br /&gt;
In addition to the interactive window, the Modbus Server can run headless as a background service, started by the &#039;&#039;&#039;ModbusServer Service&#039;&#039;&#039; launcher. In this mode it loads the saved &amp;lt;code&amp;gt;xml/config/config.xml&amp;lt;/code&amp;gt;, binds the server with no user interface, and runs until the operating system asks it to stop (for example a service stop, console Ctrl-C, or system shutdown). This is why the native installer provides two launchers — &#039;&#039;&#039;ModbusServer&#039;&#039;&#039; for the window and &#039;&#039;&#039;ModbusServer Service&#039;&#039;&#039; for the headless service.&lt;br /&gt;
&lt;br /&gt;
== Using the Server and Client Together ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Server and the [[ModbusClient|Modbus Client]] are designed to be used as a pair to exercise a Modbus link from both ends without any real hardware:&lt;br /&gt;
&lt;br /&gt;
# Start this server, choose a &#039;&#039;&#039;port&#039;&#039;&#039; and &#039;&#039;&#039;unit ID&#039;&#039;&#039;, and press &#039;&#039;&#039;Start&#039;&#039;&#039;.&lt;br /&gt;
# In the [[ModbusClient]], set &#039;&#039;&#039;Server host&#039;&#039;&#039; to this machine (&amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; if both run on the same PC), set the matching &#039;&#039;&#039;port&#039;&#039;&#039; and &#039;&#039;&#039;unit ID&#039;&#039;&#039;, and press &#039;&#039;&#039;Connect&#039;&#039;&#039;.&lt;br /&gt;
# &#039;&#039;&#039;Client → Server:&#039;&#039;&#039; when the client edits a Coil or Holding Register, the value is written here and appears in this server&#039;s grid and activity log.&lt;br /&gt;
# &#039;&#039;&#039;Server → Client:&#039;&#039;&#039; edit any value here — including discrete inputs and input registers, which the client can only read — and the client&#039;s grid reflects it on its next poll.&lt;br /&gt;
&lt;br /&gt;
This makes the pair a complete bench setup: the server stands in for a device so you can develop or test a Modbus master, while the client stands in for a master so you can stage and inspect a device&#039;s data. This server can equally answer a real third-party Modbus/TCP master.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;quot;Permission denied&amp;quot; when starting&#039;&#039;&#039; — the chosen port is below 1024 (the default is 502) and the operating system requires elevated privileges to bind it. Use a port of 1024 or higher, such as 1502, or run with elevated privileges.&lt;br /&gt;
* &#039;&#039;&#039;A client&#039;s requests are rejected&#039;&#039;&#039; — the server answers only the configured &#039;&#039;&#039;Unit ID&#039;&#039;&#039;. Check the client is using the same unit ID shown in the connection bar.&lt;br /&gt;
* &#039;&#039;&#039;A startup warning about &amp;lt;code&amp;gt;sun.misc.Unsafe&amp;lt;/code&amp;gt;&#039;&#039;&#039; — harmless, and does not affect operation. The supplied start scripts suppress it; launching the jar directly may still print it.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[ModbusClient]] — the client-side companion tool&lt;br /&gt;
* [[AutoLab4j]] — an automatic labeller that uses the same Modbus stack to watch production-line signals&lt;br /&gt;
* [[SocketTest]] — a raw TCP/IP testing utility&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=ModbusClient&amp;diff=1899</id>
		<title>ModbusClient</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=ModbusClient&amp;diff=1899"/>
		<updated>2026-06-22T14:22:35Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: Updated by push_wiki.py&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;Commander4j Modbus Client&#039;&#039;&#039; (&#039;&#039;util_modbusClient&#039;&#039;) is a desktop tool that acts as a [https://en.wikipedia.org/wiki/Modbus Modbus/TCP] client — a Modbus master. It connects to a remote Modbus server (a device, PLC, or the [[ModbusServer|Commander4j Modbus Server]]), continuously polls its four data tables across a chosen address window, and shows them in a single live grid. Coil and Holding Register values can be edited to drive the connected server. It is a test, troubleshooting and bench tool, and is the client-side companion to the [[ModbusServer|Commander4j Modbus Server]].&lt;br /&gt;
&lt;br /&gt;
== A Quick Modbus Primer ==&lt;br /&gt;
&lt;br /&gt;
If you are new to Modbus, the following terms are used throughout this page. Modbus is a simple, widely used industrial protocol for moving numeric and on/off values between automation equipment.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Master / Client&#039;&#039;&#039; — the device that initiates requests (reads and writes). This tool is a client.&lt;br /&gt;
* &#039;&#039;&#039;Slave / Server / Device&#039;&#039;&#039; — the device that holds the data and answers requests. The [[ModbusServer]] is a server.&lt;br /&gt;
* &#039;&#039;&#039;Unit ID&#039;&#039;&#039; (also &amp;quot;slave address&amp;quot;) — a number (0–247) identifying which device a request is for. A client must use the same unit ID the server is configured to answer as.&lt;br /&gt;
* &#039;&#039;&#039;Modbus/TCP&#039;&#039;&#039; — Modbus carried over an ordinary TCP/IP network connection, as opposed to serial (RTU) wiring. These tools speak Modbus/TCP only.&lt;br /&gt;
&lt;br /&gt;
Modbus organises all data into &#039;&#039;&#039;four tables&#039;&#039;&#039;, each addressed separately starting at zero:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Table !! Holds !! Size !! Can a client write it?&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Coils&#039;&#039;&#039; || On/off output bits || 1 bit || &#039;&#039;&#039;Yes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Discrete Inputs&#039;&#039;&#039; || On/off input bits || 1 bit || No — read-only&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Input Registers&#039;&#039;&#039; || Numeric inputs (readings) || 16 bits (0–65535) || No — read-only&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Holding Registers&#039;&#039;&#039; || Numeric settings / values || 16 bits (0–65535) || &#039;&#039;&#039;Yes&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The two &amp;quot;input&amp;quot; tables represent values a device &#039;&#039;produces&#039;&#039; (sensor states, measurements), so a client can only read them. Coils and holding registers represent values a client is allowed to &#039;&#039;set&#039;&#039;. Each table also has a conventional &#039;&#039;&#039;reference number&#039;&#039;&#039; that operators quote instead of the raw zero-based address: coils start at 1, discrete inputs at 10001, input registers at 30001 and holding registers at 40001.&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Client is useful when:&lt;br /&gt;
&lt;br /&gt;
* Reading the live coils and registers of a PLC or other Modbus device to confirm it is responding&lt;br /&gt;
* Writing a coil or holding register to command a device during commissioning or fault-finding&lt;br /&gt;
* Checking that a device is reachable on a given host, port and unit ID&lt;br /&gt;
* Driving the [[ModbusServer]] during testing, or reading values the server is staging&lt;br /&gt;
&lt;br /&gt;
== Source Code and Releases ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Client is open source and hosted on GitHub:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Repository:&#039;&#039;&#039; [https://github.com/C4J/ModbusClient https://github.com/C4J/ModbusClient]&lt;br /&gt;
* &#039;&#039;&#039;Releases (downloads):&#039;&#039;&#039; [https://github.com/C4J/ModbusClient/releases https://github.com/C4J/ModbusClient/releases]&lt;br /&gt;
&lt;br /&gt;
== Running the Modbus Client ==&lt;br /&gt;
&lt;br /&gt;
The recommended way to install the Modbus Client is to download a native installer for your platform, either from the [[Downloads]] page or from the [https://github.com/C4J/ModbusClient/releases GitHub releases page]. Native installers are provided for &#039;&#039;&#039;Windows, macOS and Linux&#039;&#039;&#039;. Each installer bundles its own Java 25 runtime, so &#039;&#039;&#039;no separate Java installation is required&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Installing creates a native &#039;&#039;&#039;ModbusClient&#039;&#039;&#039; launcher that you run like any other desktop application — from the Start menu, Applications folder, or desktop — which opens the window described below.&lt;br /&gt;
&lt;br /&gt;
=== Running from the jar ===&lt;br /&gt;
&lt;br /&gt;
Alternatively the tool can be run directly from its distribution folder as an ordinary Java 25 (Swing) application:&lt;br /&gt;
&lt;br /&gt;
 java -jar modbusClient.jar&lt;br /&gt;
&lt;br /&gt;
The supplied &amp;lt;code&amp;gt;start_modbusClient.sh&amp;lt;/code&amp;gt; (macOS/Linux) and &amp;lt;code&amp;gt;start_modbusClient.cmd&amp;lt;/code&amp;gt; (Windows) scripts launch it the same way. Run the jar from its own folder so the bundled &amp;lt;code&amp;gt;lib/&amp;lt;/code&amp;gt; dependencies are found alongside it.&lt;br /&gt;
&lt;br /&gt;
== The Main Window ==&lt;br /&gt;
&lt;br /&gt;
The window has three parts: a &#039;&#039;&#039;connection bar&#039;&#039;&#039; across the top, the &#039;&#039;&#039;register table&#039;&#039;&#039; in the centre with a vertical button toolbar down the right-hand side, and an &#039;&#039;&#039;activity log&#039;&#039;&#039; along the bottom.&lt;br /&gt;
&lt;br /&gt;
=== Connection Bar ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Server host&#039;&#039;&#039; || The host name or IP address of the Modbus server to connect to. Defaults to &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; (this machine) for quick loopback testing against a local [[ModbusServer]].&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Port&#039;&#039;&#039; || The TCP port of the server. The Modbus standard is &#039;&#039;&#039;502&#039;&#039;&#039;; match whatever the server is listening on.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Unit ID&#039;&#039;&#039; || The unit / slave address to address requests to (0–247, default &#039;&#039;&#039;1&#039;&#039;&#039;). This must match the unit ID the server answers as, or every request will be rejected.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Status&#039;&#039;&#039; || Shows &#039;&#039;&#039;Disconnected&#039;&#039;&#039;, or &#039;&#039;&#039;Connected&#039;&#039;&#039; with the server address and unit ID in green.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Connect / Disconnect&#039;&#039;&#039; button (the toggle at the top of the right-hand toolbar) opens and closes the connection. The host, port and unit ID can only be changed while disconnected. Once connected, the client polls the server roughly four times a second and the grid updates live.&lt;br /&gt;
&lt;br /&gt;
=== Register Table ===&lt;br /&gt;
&lt;br /&gt;
A single grid shows one row per address, with every Modbus data table side by side and colour-coded:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Column group !! Contents !! Editable here&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Address&#039;&#039;&#039; || The zero-based Modbus protocol address (the same address for the whole row). || —&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Coil&#039;&#039;&#039; || Modbus reference (1…) and an on/off checkbox. || &#039;&#039;&#039;Yes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Discrete&#039;&#039;&#039; || Discrete input reference (10001…) and an on/off checkbox. || No (read-only)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Input&#039;&#039;&#039; || Input register reference (30001…), a decimal value and a read-only &#039;&#039;&#039;Hex&#039;&#039;&#039; view. || No (read-only)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Holding&#039;&#039;&#039; || Holding register reference (40001…), a decimal value (0–65535) and a read-only &#039;&#039;&#039;Hex&#039;&#039;&#039; view. || &#039;&#039;&#039;Yes&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Only the &#039;&#039;&#039;Coil&#039;&#039;&#039; and &#039;&#039;&#039;Holding Register&#039;&#039;&#039; value cells can be edited, and only while connected — because Modbus has no function code for a client to write the discrete-input and input-register tables. Editing a cell writes the new value straight through to the server; the displayed value updates immediately and is reverted if the server rejects the write.&lt;br /&gt;
&lt;br /&gt;
Below the table, the &#039;&#039;&#039;Start address&#039;&#039;&#039; and &#039;&#039;&#039;Count&#039;&#039;&#039; fields choose which window of addresses the client polls; click the tick button (Apply range) to apply them. Up to 2000 rows can be shown at once.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Zero registers&#039;&#039;&#039; button (eraser icon) on the toolbar opens a menu to clear the visible window of the writable tables — &#039;&#039;&#039;Zero Coils&#039;&#039;&#039;, &#039;&#039;&#039;Zero Holding Registers&#039;&#039;&#039;, or &#039;&#039;&#039;Zero All&#039;&#039;&#039; for both. Only the writable tables appear, because the read-only ones cannot be cleared by a client.&lt;br /&gt;
&lt;br /&gt;
=== Activity Log ===&lt;br /&gt;
&lt;br /&gt;
Connection events, writes, and any errors are written to the log at the bottom with a millisecond timestamp. The log keeps the most recent 400 lines. The two buttons beside it &#039;&#039;&#039;Save&#039;&#039;&#039; the log to a text file and &#039;&#039;&#039;Clear&#039;&#039;&#039; it. If the connection is lost (for example the server stops or the network drops), the client reports it in the log and returns to the disconnected state automatically.&lt;br /&gt;
&lt;br /&gt;
== Toolbar Buttons ==&lt;br /&gt;
&lt;br /&gt;
The vertical toolbar to the right of the register table provides, from top to bottom: &#039;&#039;&#039;Connect / Disconnect&#039;&#039;&#039;, &#039;&#039;&#039;Open settings&#039;&#039;&#039;, &#039;&#039;&#039;Save settings&#039;&#039;&#039;, &#039;&#039;&#039;Zero registers&#039;&#039;&#039;, &#039;&#039;&#039;About&#039;&#039;&#039;, &#039;&#039;&#039;Licences&#039;&#039;&#039;, &#039;&#039;&#039;Help&#039;&#039;&#039; (opens this wiki page) and &#039;&#039;&#039;Close&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
The connection settings (server host, port and unit ID) are stored in a small XML file, by default &amp;lt;code&amp;gt;xml/config/config.xml&amp;lt;/code&amp;gt; beneath the application folder:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;config&amp;gt;&lt;br /&gt;
   &amp;lt;ip&amp;gt;127.0.0.1&amp;lt;/ip&amp;gt;&lt;br /&gt;
   &amp;lt;port&amp;gt;502&amp;lt;/port&amp;gt;&lt;br /&gt;
   &amp;lt;id&amp;gt;1&amp;lt;/id&amp;gt;&lt;br /&gt;
 &amp;lt;/config&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The default settings are loaded automatically at start-up. Use the &#039;&#039;&#039;Open settings&#039;&#039;&#039; and &#039;&#039;&#039;Save settings&#039;&#039;&#039; toolbar buttons to load or store a configuration from any location. If you change the settings and then close the application, you are prompted to save the changes first.&lt;br /&gt;
&lt;br /&gt;
== Using the Client and Server Together ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Client and the [[ModbusServer|Modbus Server]] are designed to be used as a pair to exercise a Modbus link from both ends without any real hardware:&lt;br /&gt;
&lt;br /&gt;
# Start the [[ModbusServer]] on one machine (or the same machine), choose a &#039;&#039;&#039;port&#039;&#039;&#039; and &#039;&#039;&#039;unit ID&#039;&#039;&#039;, and press &#039;&#039;&#039;Start&#039;&#039;&#039;.&lt;br /&gt;
# In the Modbus Client, set &#039;&#039;&#039;Server host&#039;&#039;&#039; to that machine (&amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; if both run on the same PC), set the matching &#039;&#039;&#039;port&#039;&#039;&#039; and &#039;&#039;&#039;unit ID&#039;&#039;&#039;, and press &#039;&#039;&#039;Connect&#039;&#039;&#039;.&lt;br /&gt;
# &#039;&#039;&#039;Client → Server:&#039;&#039;&#039; edit a Coil or Holding Register in the client; the value is written to the server and appears in the server&#039;s grid and activity log.&lt;br /&gt;
# &#039;&#039;&#039;Server → Client:&#039;&#039;&#039; edit any value in the server — including discrete inputs and input registers, which the client can only read; the client&#039;s grid reflects it on the next poll.&lt;br /&gt;
&lt;br /&gt;
This makes the pair a complete bench setup: the server stands in for a device so you can develop or test a Modbus master, and the client stands in for a master so you can stage and inspect a device&#039;s data. Either tool can also be pointed at real third-party Modbus/TCP equipment.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;quot;Connection refused&amp;quot; or a timeout on Connect&#039;&#039;&#039; — check the server host and port, that the server is running and listening, and that no firewall is blocking the connection.&lt;br /&gt;
* &#039;&#039;&#039;Connected, but every read fails or the connection drops immediately&#039;&#039;&#039; — the &#039;&#039;&#039;Unit ID&#039;&#039;&#039; probably does not match the server. The client must address the exact unit ID the server answers as.&lt;br /&gt;
* &#039;&#039;&#039;A startup warning about &amp;lt;code&amp;gt;sun.misc.Unsafe&amp;lt;/code&amp;gt;&#039;&#039;&#039; — harmless, and does not affect operation. The supplied start scripts suppress it; launching the jar directly may still print it.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[ModbusServer]] — the server-side companion tool&lt;br /&gt;
* [[AutoLab4j]] — an automatic labeller that uses the same Modbus stack to watch production-line signals&lt;br /&gt;
* [[SocketTest]] — a raw TCP/IP testing utility&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=ModbusBridge&amp;diff=1898</id>
		<title>ModbusBridge</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=ModbusBridge&amp;diff=1898"/>
		<updated>2026-06-22T14:22:34Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: Updated by push_wiki.py&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;Commander4j Modbus Bridge&#039;&#039;&#039; (&#039;&#039;util_modbusBridge&#039;&#039;) is a &#039;&#039;&#039;headless service&#039;&#039;&#039; that lets applications without [https://en.wikipedia.org/wiki/Modbus Modbus/TCP] client capability set and query the values of a remote Modbus server over a simple REST API. It connects to one Modbus server, polls a fixed list of &#039;&#039;&#039;named points&#039;&#039;&#039; (configured in XML), keeps the latest values in memory, and serves them over HTTP. It also provides a live web UI to view and change values, and a second page to tail the log.&lt;br /&gt;
&lt;br /&gt;
Unlike the interactive [[ModbusClient|Commander4j Modbus Client]], the Bridge runs unattended: it auto-reconnects when the link drops and is packaged to run as an operating-system service. It reuses the same Modbus engine as the [[ModbusClient]] and is a natural companion to the [[ModbusServer]].&lt;br /&gt;
&lt;br /&gt;
If you are new to Modbus, the [[ModbusClient#A Quick Modbus Primer|Modbus primer on the Modbus Client page]] explains the terms (client/server, unit ID, and the four data tables) used throughout this page.&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Bridge is useful when:&lt;br /&gt;
&lt;br /&gt;
* An application or script that cannot speak Modbus needs to read or write a PLC or other Modbus/TCP device over plain HTTP/JSON&lt;br /&gt;
* A remote Modbus server&#039;s values should be exposed on a network as named points rather than raw addresses&lt;br /&gt;
* An unattended, always-on bridge is needed that survives link drops and restarts as a managed service&lt;br /&gt;
* A browser-based view of live values, with inline editing and a live log, is wanted without installing a desktop tool&lt;br /&gt;
&lt;br /&gt;
== Source Code and Releases ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Bridge is open source and hosted on GitHub:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Repository:&#039;&#039;&#039; [https://github.com/C4J/ModbusBridge https://github.com/C4J/ModbusBridge]&lt;br /&gt;
* &#039;&#039;&#039;Releases (downloads):&#039;&#039;&#039; [https://github.com/C4J/ModbusBridge/releases https://github.com/C4J/ModbusBridge/releases]&lt;br /&gt;
&lt;br /&gt;
== Running the Modbus Bridge ==&lt;br /&gt;
&lt;br /&gt;
The recommended way to install the Modbus Bridge is to download a native installer for your platform, either from the [[Downloads]] page or from the [https://github.com/C4J/ModbusBridge/releases GitHub releases page]. Native installers are provided for &#039;&#039;&#039;Windows, macOS and Linux&#039;&#039;&#039;. Each installer bundles its own Java 25 runtime, so &#039;&#039;&#039;no separate Java installation is required&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== As a service ===&lt;br /&gt;
&lt;br /&gt;
The native installer registers and starts the Bridge as an operating-system service — &#039;&#039;&#039;launchd&#039;&#039;&#039; on macOS, a &#039;&#039;&#039;Windows service&#039;&#039;&#039;, or a &#039;&#039;&#039;systemd / init&#039;&#039;&#039; unit on Linux. The service runs with its working directory set to the installation directory, so all the relative paths below resolve correctly. Stopping the service triggers an ordered shutdown so that teardown events still reach the log file.&lt;br /&gt;
&lt;br /&gt;
=== Running from the jar ===&lt;br /&gt;
&lt;br /&gt;
Alternatively the Bridge can be launched from its distribution folder:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;./start_modbusBridge.sh&amp;lt;/code&amp;gt; (macOS/Linux) or &amp;lt;code&amp;gt;start_modbusBridge.cmd&amp;lt;/code&amp;gt; (Windows), or&lt;br /&gt;
* &amp;lt;code&amp;gt;ant run&amp;lt;/code&amp;gt; to launch from compiled classes, or&lt;br /&gt;
* directly with Java:&lt;br /&gt;
&lt;br /&gt;
 java -Dlog4j2.shutdownHookEnabled=false -Dlog4j2.configurationFile=xml/config/log4j2.xml -jar modbusBridge.jar&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;modbusBridge.jar&amp;lt;/code&amp;gt; is a &#039;&#039;&#039;thin jar&#039;&#039;&#039; — it references the dependency jars in &amp;lt;code&amp;gt;lib/&amp;lt;/code&amp;gt; via its manifest, so it must be run from the project root with &amp;lt;code&amp;gt;lib/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;xml/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;web/&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;logs/&amp;lt;/code&amp;gt; alongside it. Any Java 25 runtime on the &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; will do; a bundled JRE is not required when run this way.&lt;br /&gt;
&lt;br /&gt;
The two &amp;lt;code&amp;gt;-D&amp;lt;/code&amp;gt; system properties matter, and the start scripts set them for you:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;-Dlog4j2.shutdownHookEnabled=false&amp;lt;/code&amp;gt; — lets the Bridge&#039;s own shutdown hook stop log4j2 &#039;&#039;&#039;last&#039;&#039;&#039;, so teardown events still reach the log file the tail page reads.&lt;br /&gt;
* &amp;lt;code&amp;gt;-Dlog4j2.configurationFile=xml/config/log4j2.xml&amp;lt;/code&amp;gt; — &amp;lt;code&amp;gt;log4j2.xml&amp;lt;/code&amp;gt; lives under &amp;lt;code&amp;gt;xml/config/&amp;lt;/code&amp;gt;, not on the classpath, so log4j2 must be pointed at it explicitly.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
All configuration is in &amp;lt;code&amp;gt;xml/config/config.xml&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;config&amp;gt;&lt;br /&gt;
   &amp;lt;modbus&amp;gt;&lt;br /&gt;
     &amp;lt;ip&amp;gt;127.0.0.1&amp;lt;/ip&amp;gt;&lt;br /&gt;
     &amp;lt;port&amp;gt;1502&amp;lt;/port&amp;gt;&lt;br /&gt;
     &amp;lt;id&amp;gt;1&amp;lt;/id&amp;gt;&lt;br /&gt;
     &amp;lt;pollIntervalMs&amp;gt;1000&amp;lt;/pollIntervalMs&amp;gt;&lt;br /&gt;
   &amp;lt;/modbus&amp;gt;&lt;br /&gt;
   &amp;lt;webserver&amp;gt;&lt;br /&gt;
     &amp;lt;ip&amp;gt;0.0.0.0&amp;lt;/ip&amp;gt;&lt;br /&gt;
     &amp;lt;port&amp;gt;8080&amp;lt;/port&amp;gt;&lt;br /&gt;
   &amp;lt;/webserver&amp;gt;&lt;br /&gt;
   &amp;lt;points&amp;gt;&lt;br /&gt;
     &amp;lt;point name=&amp;quot;pump_run&amp;quot;   kind=&amp;quot;COIL&amp;quot;             address=&amp;quot;0&amp;quot;/&amp;gt;&lt;br /&gt;
     &amp;lt;point name=&amp;quot;tank_level&amp;quot; kind=&amp;quot;HOLDING_REGISTER&amp;quot; address=&amp;quot;100&amp;quot;/&amp;gt;&lt;br /&gt;
     &amp;lt;point name=&amp;quot;fault&amp;quot;      kind=&amp;quot;DISCRETE_INPUT&amp;quot;   address=&amp;quot;10&amp;quot;/&amp;gt;&lt;br /&gt;
     &amp;lt;point name=&amp;quot;flow_rate&amp;quot;  kind=&amp;quot;INPUT_REGISTER&amp;quot;   address=&amp;quot;30&amp;quot;/&amp;gt;&lt;br /&gt;
   &amp;lt;/points&amp;gt;&lt;br /&gt;
 &amp;lt;/config&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;&amp;lt;modbus&amp;gt;&amp;lt;/code&amp;gt; block points the Bridge at the remote Modbus server: its host &amp;lt;code&amp;gt;&amp;lt;ip&amp;gt;&amp;lt;/code&amp;gt;, TCP &amp;lt;code&amp;gt;&amp;lt;port&amp;gt;&amp;lt;/code&amp;gt; (the Modbus standard is &#039;&#039;&#039;502&#039;&#039;&#039;; the example uses &#039;&#039;&#039;1502&#039;&#039;&#039; because ports below 1024 need root on macOS/Linux), the unit / slave &amp;lt;code&amp;gt;&amp;lt;id&amp;gt;&amp;lt;/code&amp;gt; to address, and the &amp;lt;code&amp;gt;&amp;lt;pollIntervalMs&amp;gt;&amp;lt;/code&amp;gt; between reads. The &amp;lt;code&amp;gt;&amp;lt;webserver&amp;gt;&amp;lt;/code&amp;gt; block sets the bind address for the HTTP server (&amp;lt;code&amp;gt;0.0.0.0&amp;lt;/code&amp;gt; = all interfaces) and the port it listens on.&lt;br /&gt;
&lt;br /&gt;
Each &amp;lt;code&amp;gt;&amp;lt;point&amp;gt;&amp;lt;/code&amp;gt; gives a human-friendly &#039;&#039;&#039;name&#039;&#039;&#039; (how REST clients and the web UI refer to it), a Modbus data table &#039;&#039;&#039;kind&#039;&#039;&#039;, and a zero-based protocol &#039;&#039;&#039;address&#039;&#039;&#039;. Valid kinds are &amp;lt;code&amp;gt;COIL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DISCRETE_INPUT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HOLDING_REGISTER&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;INPUT_REGISTER&amp;lt;/code&amp;gt;. Only &#039;&#039;&#039;coils&#039;&#039;&#039; and &#039;&#039;&#039;holding registers&#039;&#039;&#039; are writable — discrete inputs and input registers are read-only in the Modbus data model (there is no client-write function code for them).&lt;br /&gt;
&lt;br /&gt;
Logging is configured in &amp;lt;code&amp;gt;xml/config/log4j2.xml&amp;lt;/code&amp;gt; (rolling file at &amp;lt;code&amp;gt;logs/modbusBridge.log&amp;lt;/code&amp;gt;, 10 MB cap, 5 generations). The Bridge&#039;s own classes log at &amp;lt;code&amp;gt;debug&amp;lt;/code&amp;gt;; the Netty transport at &amp;lt;code&amp;gt;warn&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== REST API ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Behaviour&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/points&amp;lt;/code&amp;gt; || All points with current values + connection status.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/points/{name}&amp;lt;/code&amp;gt; || One point&#039;s current value. 404 if unknown.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PUT&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/points/{name}&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;{&amp;quot;value&amp;quot;: N}&amp;lt;/code&amp;gt; || Write a coil (0/1, or &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;) or holding register (0–65535). 400 for read-only kinds or out-of-range; 503 if the server is unreachable.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/status&amp;lt;/code&amp;gt; || Connection health: connected, target, unit id, poll interval, last-poll time, point count.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/licence&amp;lt;/code&amp;gt; || Third-party licence list (from &amp;lt;code&amp;gt;lib/license/LicenseInfo.xml&amp;lt;/code&amp;gt;).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/log/tail&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;?lines=N&amp;lt;/code&amp;gt; || Recent log lines (default 200, max 5000).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/events&amp;lt;/code&amp;gt; || Server-Sent Events stream of the full points payload, pushed on every change.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/events/log&amp;lt;/code&amp;gt; || Server-Sent Events stream of newly-appended log lines.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A write is &#039;&#039;&#039;self-correcting&#039;&#039;&#039;, not optimistic: the Bridge writes the value, then immediately reads the point back from the server, so the response and cache reflect the server&#039;s actual state. When the link is down, reads return the last snapshot flagged &amp;lt;code&amp;gt;&amp;quot;valid&amp;quot;:false,&amp;quot;stale&amp;quot;:true&amp;lt;/code&amp;gt; and writes return &#039;&#039;&#039;503&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
 curl http://localhost:8080/api/points&lt;br /&gt;
 curl -X PUT -H &#039;Content-Type: application/json&#039; -d &#039;{&amp;quot;value&amp;quot;:1}&#039;    http://localhost:8080/api/points/pump_run&lt;br /&gt;
 curl -X PUT -H &#039;Content-Type: application/json&#039; -d &#039;{&amp;quot;value&amp;quot;:4242}&#039; http://localhost:8080/api/points/tank_level&lt;br /&gt;
&lt;br /&gt;
== Web UI ==&lt;br /&gt;
&lt;br /&gt;
Open &amp;lt;code&amp;gt;http://&amp;lt;host&amp;gt;:8080/&amp;lt;/code&amp;gt; in a browser:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Points&#039;&#039;&#039; (&amp;lt;code&amp;gt;index.html&amp;lt;/code&amp;gt;) — a live table of every configured point, updated by push (SSE) with no refresh needed. Writable points have an inline editor; type a value and click &#039;&#039;&#039;Set&#039;&#039;&#039; (or press Enter) to issue the PUT. Stale values (link down) are shown in red. A manual &#039;&#039;&#039;Refresh&#039;&#039;&#039; button is kept as a fallback.&lt;br /&gt;
* &#039;&#039;&#039;Log&#039;&#039;&#039; (&amp;lt;code&amp;gt;log.html&amp;lt;/code&amp;gt;) — the recent log backlog followed live as new lines are written, with an auto-scroll toggle. &amp;lt;code&amp;gt;WARN&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;ERROR&amp;lt;/code&amp;gt; lines are colour-coded.&lt;br /&gt;
* &#039;&#039;&#039;Licences&#039;&#039;&#039; (&amp;lt;code&amp;gt;licence.html&amp;lt;/code&amp;gt;) — the third-party libraries and their licences rendered as a table (the underlying &amp;lt;code&amp;gt;/api/licence&amp;lt;/code&amp;gt; endpoint returns the same data as raw JSON).&lt;br /&gt;
&lt;br /&gt;
== Modbus Behaviour ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transport:&#039;&#039;&#039; Modbus/TCP only (no serial / RTU, no TLS), reusing the [[ModbusClient]]&#039;s Modbus engine.&lt;br /&gt;
* The poll thread reads every configured point once per &amp;lt;code&amp;gt;pollIntervalMs&amp;lt;/code&amp;gt;. A read failure tears the connection down, flags all points stale, and the Bridge auto-reconnects with exponential backoff (1 → 2 → 4 → 8 … up to 30 s), resetting on a successful connect.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;Address already in use&amp;lt;/code&amp;gt; on start&#039;&#039;&#039; — another process holds the web port (default 8080). Change &amp;lt;code&amp;gt;&amp;lt;webserver&amp;gt;&amp;lt;port&amp;gt;&amp;lt;/code&amp;gt; or free the port.&lt;br /&gt;
* &#039;&#039;&#039;All points show stale / &amp;lt;code&amp;gt;/api/status&amp;lt;/code&amp;gt; says not connected&#039;&#039;&#039; — the Modbus server is unreachable. Check &amp;lt;code&amp;gt;&amp;lt;modbus&amp;gt;&amp;lt;ip&amp;gt;/&amp;lt;port&amp;gt;&amp;lt;/code&amp;gt;, that the server is running, and that both ends use the same &#039;&#039;&#039;unit id&#039;&#039;&#039; (the server answers only its configured unit). The log shows the backoff retries.&lt;br /&gt;
* &#039;&#039;&#039;Writes return 503&#039;&#039;&#039; — the link is down at that moment; the Bridge is between reconnect attempts. Reads still return the last-known (stale) values.&lt;br /&gt;
* &#039;&#039;&#039;PUT returns 400 &amp;quot;read-only&amp;quot;&#039;&#039;&#039; — the named point is a &amp;lt;code&amp;gt;DISCRETE_INPUT&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;INPUT_REGISTER&amp;lt;/code&amp;gt;; those cannot be written by a Modbus client.&lt;br /&gt;
* &#039;&#039;&#039;No log lines / empty log tail page&#039;&#039;&#039; — confirm &amp;lt;code&amp;gt;-Dlog4j2.configurationFile=xml/config/log4j2.xml&amp;lt;/code&amp;gt; is set (the start scripts do this) and the process working directory is the project root, so &amp;lt;code&amp;gt;logs/&amp;lt;/code&amp;gt; is created in the right place.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[ModbusClient]] — the interactive desktop Modbus client; the Bridge reuses its Modbus engine&lt;br /&gt;
* [[ModbusServer]] — the server-side companion tool, useful as a bench target for the Bridge&lt;br /&gt;
* [[AutoLab4j]] — an automatic labeller that uses the same Modbus stack to watch production-line signals&lt;br /&gt;
* [[SocketTest]] — a raw TCP/IP testing utility&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=Template:Menu_Applications&amp;diff=1897</id>
		<title>Template:Menu Applications</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=Template:Menu_Applications&amp;diff=1897"/>
		<updated>2026-06-22T14:18:50Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: /* Applications */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Applications=&lt;br /&gt;
{| cellpadding=&amp;quot;8&amp;quot; style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
||[[file:AutoLab4j_256x256.png|link=[[AutoLab4j]]|100px]]&lt;br /&gt;
====[[AutoLab4j]]====&lt;br /&gt;
|&lt;br /&gt;
||[[File:Commander4j_256x256.png|link=[[Commander4j]]|100px]]&lt;br /&gt;
====[[Commander4j]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:LabelServer4j_256x256.png|link=[[LabelServer4j]]|100px]]&lt;br /&gt;
====[[LabelServer4j]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:LaunchPad_256x256.png|link=[[LaunchPad]]|100px]]&lt;br /&gt;
====[[LaunchPad]]====&lt;br /&gt;
|-&lt;br /&gt;
||[[file:LogoClient_256x256.png|link=[[LogoClient]]|100px]]&lt;br /&gt;
====[[LogoClient]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:LogoRenderer_256x256.png|link=[[LogoRenderer]]|100px]]&lt;br /&gt;
====[[LogoRenderer]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:Menu4j_256x256.png|link=[[Menu4j]]|100px]]&lt;br /&gt;
====[[Menu4j]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:Middleware4j_256x256.png|link=[[Middleware4j]]|100px]]&lt;br /&gt;
====[[Middleware4j]]====&lt;br /&gt;
|-&lt;br /&gt;
||[[file:Modbus_256x256.png|link=[[ModbusBridge]]|100px]]&lt;br /&gt;
====[[ModbusBridge]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:Modbus_256x256.png|link=[[ModbusClient]]|100px]]&lt;br /&gt;
====[[ModbusClient]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:Modbus_256x256.png|link=[[ModbusServer]]|100px]]&lt;br /&gt;
====[[ModbusServer]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:SFTGet4j_256x256.png|link=[[SFTPGet]]|100px]]&lt;br /&gt;
====[[SFTPGet]]====&lt;br /&gt;
|-&lt;br /&gt;
||[[file:SFTPSend4j_256x256.png|link=[[SFTPSend]]|100px]]&lt;br /&gt;
====[[SFTPSend]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:sftpTransfer_256x256.png|link=[[SFTPTransfer]]|100px]]&lt;br /&gt;
====[[SFTPTransfer]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:SocketTest_256x256.png|link=[[SocketTest]]|100px]]&lt;br /&gt;
====[[SocketTest]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:TreeDoc_256x256.png|link=[[TreeDoc]]|100px]]&lt;br /&gt;
====[[TreeDoc]]====&lt;br /&gt;
|-&lt;br /&gt;
||[[file:XMLViewer_256x256.png|link=[[XMLViewer]]|100px]]&lt;br /&gt;
====[[XMLViewer]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:ZPLRenderer_256x256.png|link=[[ZPLRenderer]]|100px]]&lt;br /&gt;
====[[ZPLRenderer]]====&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=ModbusBridge&amp;diff=1896</id>
		<title>ModbusBridge</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=ModbusBridge&amp;diff=1896"/>
		<updated>2026-06-22T14:00:59Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: Updated by push_wiki.py&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;Commander4j Modbus Bridge&#039;&#039;&#039; (&#039;&#039;util_modbusBridge&#039;&#039;) is a &#039;&#039;&#039;headless service&#039;&#039;&#039; that lets applications without [https://en.wikipedia.org/wiki/Modbus Modbus/TCP] client capability set and query the values of a remote Modbus server over a simple REST API. It connects to one Modbus server, polls a fixed list of &#039;&#039;&#039;named points&#039;&#039;&#039; (configured in XML), keeps the latest values in memory, and serves them over HTTP. It also provides a live web UI to view and change values, and a second page to tail the log.&lt;br /&gt;
&lt;br /&gt;
Unlike the interactive [[ModbusClient|Commander4j Modbus Client]], the Bridge runs unattended: it auto-reconnects when the link drops and is packaged to run as an operating-system service. It reuses the same Modbus engine as the [[ModbusClient]] and is a natural companion to the [[ModbusServer]].&lt;br /&gt;
&lt;br /&gt;
If you are new to Modbus, the [[ModbusClient#A Quick Modbus Primer|Modbus primer on the Modbus Client page]] explains the terms (client/server, unit ID, and the four data tables) used throughout this page.&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Bridge is useful when:&lt;br /&gt;
&lt;br /&gt;
* An application or script that cannot speak Modbus needs to read or write a PLC or other Modbus/TCP device over plain HTTP/JSON&lt;br /&gt;
* A remote Modbus server&#039;s values should be exposed on a network as named points rather than raw addresses&lt;br /&gt;
* An unattended, always-on bridge is needed that survives link drops and restarts as a managed service&lt;br /&gt;
* A browser-based view of live values, with inline editing and a live log, is wanted without installing a desktop tool&lt;br /&gt;
&lt;br /&gt;
== Source Code and Releases ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Bridge is open source and hosted on GitHub:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Repository:&#039;&#039;&#039; [https://github.com/C4J/ModbusBridge https://github.com/C4J/ModbusBridge]&lt;br /&gt;
* &#039;&#039;&#039;Releases (downloads):&#039;&#039;&#039; [https://github.com/C4J/ModbusBridge/releases https://github.com/C4J/ModbusBridge/releases]&lt;br /&gt;
&lt;br /&gt;
== Running the Modbus Bridge ==&lt;br /&gt;
&lt;br /&gt;
The recommended way to install the Modbus Bridge is to download a native installer for your platform, either from the [[Downloads]] page or from the [https://github.com/C4J/ModbusBridge/releases GitHub releases page]. Native installers are provided for &#039;&#039;&#039;Windows, macOS and Linux&#039;&#039;&#039;. Each installer bundles its own Java 25 runtime, so &#039;&#039;&#039;no separate Java installation is required&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== As a service ===&lt;br /&gt;
&lt;br /&gt;
The native installer registers and starts the Bridge as an operating-system service — &#039;&#039;&#039;launchd&#039;&#039;&#039; on macOS, a &#039;&#039;&#039;Windows service&#039;&#039;&#039;, or a &#039;&#039;&#039;systemd / init&#039;&#039;&#039; unit on Linux. The service runs with its working directory set to the installation directory, so all the relative paths below resolve correctly. Stopping the service triggers an ordered shutdown so that teardown events still reach the log file.&lt;br /&gt;
&lt;br /&gt;
=== Running from the jar ===&lt;br /&gt;
&lt;br /&gt;
Alternatively the Bridge can be launched from its distribution folder:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;./start_modbusBridge.sh&amp;lt;/code&amp;gt; (macOS/Linux) or &amp;lt;code&amp;gt;start_modbusBridge.cmd&amp;lt;/code&amp;gt; (Windows), or&lt;br /&gt;
* &amp;lt;code&amp;gt;ant run&amp;lt;/code&amp;gt; to launch from compiled classes, or&lt;br /&gt;
* directly with Java:&lt;br /&gt;
&lt;br /&gt;
 java -Dlog4j2.shutdownHookEnabled=false -Dlog4j2.configurationFile=xml/config/log4j2.xml -jar modbusBridge.jar&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;modbusBridge.jar&amp;lt;/code&amp;gt; is a &#039;&#039;&#039;thin jar&#039;&#039;&#039; — it references the dependency jars in &amp;lt;code&amp;gt;lib/&amp;lt;/code&amp;gt; via its manifest, so it must be run from the project root with &amp;lt;code&amp;gt;lib/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;xml/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;web/&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;logs/&amp;lt;/code&amp;gt; alongside it. Any Java 25 runtime on the &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; will do; a bundled JRE is not required when run this way.&lt;br /&gt;
&lt;br /&gt;
The two &amp;lt;code&amp;gt;-D&amp;lt;/code&amp;gt; system properties matter, and the start scripts set them for you:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;-Dlog4j2.shutdownHookEnabled=false&amp;lt;/code&amp;gt; — lets the Bridge&#039;s own shutdown hook stop log4j2 &#039;&#039;&#039;last&#039;&#039;&#039;, so teardown events still reach the log file the tail page reads.&lt;br /&gt;
* &amp;lt;code&amp;gt;-Dlog4j2.configurationFile=xml/config/log4j2.xml&amp;lt;/code&amp;gt; — &amp;lt;code&amp;gt;log4j2.xml&amp;lt;/code&amp;gt; lives under &amp;lt;code&amp;gt;xml/config/&amp;lt;/code&amp;gt;, not on the classpath, so log4j2 must be pointed at it explicitly.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
All configuration is in &amp;lt;code&amp;gt;xml/config/config.xml&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;config&amp;gt;&lt;br /&gt;
   &amp;lt;modbus&amp;gt;&lt;br /&gt;
     &amp;lt;ip&amp;gt;127.0.0.1&amp;lt;/ip&amp;gt;&lt;br /&gt;
     &amp;lt;port&amp;gt;1502&amp;lt;/port&amp;gt;&lt;br /&gt;
     &amp;lt;id&amp;gt;1&amp;lt;/id&amp;gt;&lt;br /&gt;
     &amp;lt;pollIntervalMs&amp;gt;1000&amp;lt;/pollIntervalMs&amp;gt;&lt;br /&gt;
   &amp;lt;/modbus&amp;gt;&lt;br /&gt;
   &amp;lt;webserver&amp;gt;&lt;br /&gt;
     &amp;lt;ip&amp;gt;0.0.0.0&amp;lt;/ip&amp;gt;&lt;br /&gt;
     &amp;lt;port&amp;gt;8080&amp;lt;/port&amp;gt;&lt;br /&gt;
   &amp;lt;/webserver&amp;gt;&lt;br /&gt;
   &amp;lt;points&amp;gt;&lt;br /&gt;
     &amp;lt;point name=&amp;quot;pump_run&amp;quot;   kind=&amp;quot;COIL&amp;quot;             address=&amp;quot;0&amp;quot;/&amp;gt;&lt;br /&gt;
     &amp;lt;point name=&amp;quot;tank_level&amp;quot; kind=&amp;quot;HOLDING_REGISTER&amp;quot; address=&amp;quot;100&amp;quot;/&amp;gt;&lt;br /&gt;
     &amp;lt;point name=&amp;quot;fault&amp;quot;      kind=&amp;quot;DISCRETE_INPUT&amp;quot;   address=&amp;quot;10&amp;quot;/&amp;gt;&lt;br /&gt;
     &amp;lt;point name=&amp;quot;flow_rate&amp;quot;  kind=&amp;quot;INPUT_REGISTER&amp;quot;   address=&amp;quot;30&amp;quot;/&amp;gt;&lt;br /&gt;
   &amp;lt;/points&amp;gt;&lt;br /&gt;
 &amp;lt;/config&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;&amp;lt;modbus&amp;gt;&amp;lt;/code&amp;gt; block points the Bridge at the remote Modbus server: its host &amp;lt;code&amp;gt;&amp;lt;ip&amp;gt;&amp;lt;/code&amp;gt;, TCP &amp;lt;code&amp;gt;&amp;lt;port&amp;gt;&amp;lt;/code&amp;gt; (the Modbus standard is &#039;&#039;&#039;502&#039;&#039;&#039;; the example uses &#039;&#039;&#039;1502&#039;&#039;&#039; because ports below 1024 need root on macOS/Linux), the unit / slave &amp;lt;code&amp;gt;&amp;lt;id&amp;gt;&amp;lt;/code&amp;gt; to address, and the &amp;lt;code&amp;gt;&amp;lt;pollIntervalMs&amp;gt;&amp;lt;/code&amp;gt; between reads. The &amp;lt;code&amp;gt;&amp;lt;webserver&amp;gt;&amp;lt;/code&amp;gt; block sets the bind address for the HTTP server (&amp;lt;code&amp;gt;0.0.0.0&amp;lt;/code&amp;gt; = all interfaces) and the port it listens on.&lt;br /&gt;
&lt;br /&gt;
Each &amp;lt;code&amp;gt;&amp;lt;point&amp;gt;&amp;lt;/code&amp;gt; gives a human-friendly &#039;&#039;&#039;name&#039;&#039;&#039; (how REST clients and the web UI refer to it), a Modbus data table &#039;&#039;&#039;kind&#039;&#039;&#039;, and a zero-based protocol &#039;&#039;&#039;address&#039;&#039;&#039;. Valid kinds are &amp;lt;code&amp;gt;COIL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DISCRETE_INPUT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HOLDING_REGISTER&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;INPUT_REGISTER&amp;lt;/code&amp;gt;. Only &#039;&#039;&#039;coils&#039;&#039;&#039; and &#039;&#039;&#039;holding registers&#039;&#039;&#039; are writable — discrete inputs and input registers are read-only in the Modbus data model (there is no client-write function code for them).&lt;br /&gt;
&lt;br /&gt;
Logging is configured in &amp;lt;code&amp;gt;xml/config/log4j2.xml&amp;lt;/code&amp;gt; (rolling file at &amp;lt;code&amp;gt;logs/modbusBridge.log&amp;lt;/code&amp;gt;, 10 MB cap, 5 generations). The Bridge&#039;s own classes log at &amp;lt;code&amp;gt;debug&amp;lt;/code&amp;gt;; the Netty transport at &amp;lt;code&amp;gt;warn&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== REST API ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Behaviour&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/points&amp;lt;/code&amp;gt; || All points with current values + connection status.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/points/{name}&amp;lt;/code&amp;gt; || One point&#039;s current value. 404 if unknown.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PUT&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/points/{name}&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;{&amp;quot;value&amp;quot;: N}&amp;lt;/code&amp;gt; || Write a coil (0/1, or &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;) or holding register (0–65535). 400 for read-only kinds or out-of-range; 503 if the server is unreachable.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/status&amp;lt;/code&amp;gt; || Connection health: connected, target, unit id, poll interval, last-poll time, point count.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/licence&amp;lt;/code&amp;gt; || Third-party licence list (from &amp;lt;code&amp;gt;lib/license/LicenseInfo.xml&amp;lt;/code&amp;gt;).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/api/log/tail&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;?lines=N&amp;lt;/code&amp;gt; || Recent log lines (default 200, max 5000).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/events&amp;lt;/code&amp;gt; || Server-Sent Events stream of the full points payload, pushed on every change.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GET&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/events/log&amp;lt;/code&amp;gt; || Server-Sent Events stream of newly-appended log lines.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A write is &#039;&#039;&#039;self-correcting&#039;&#039;&#039;, not optimistic: the Bridge writes the value, then immediately reads the point back from the server, so the response and cache reflect the server&#039;s actual state. When the link is down, reads return the last snapshot flagged &amp;lt;code&amp;gt;&amp;quot;valid&amp;quot;:false,&amp;quot;stale&amp;quot;:true&amp;lt;/code&amp;gt; and writes return &#039;&#039;&#039;503&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
 curl http://localhost:8080/api/points&lt;br /&gt;
 curl -X PUT -H &#039;Content-Type: application/json&#039; -d &#039;{&amp;quot;value&amp;quot;:1}&#039;    http://localhost:8080/api/points/pump_run&lt;br /&gt;
 curl -X PUT -H &#039;Content-Type: application/json&#039; -d &#039;{&amp;quot;value&amp;quot;:4242}&#039; http://localhost:8080/api/points/tank_level&lt;br /&gt;
&lt;br /&gt;
== Web UI ==&lt;br /&gt;
&lt;br /&gt;
Open &amp;lt;code&amp;gt;http://&amp;lt;host&amp;gt;:8080/&amp;lt;/code&amp;gt; in a browser:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Points&#039;&#039;&#039; (&amp;lt;code&amp;gt;index.html&amp;lt;/code&amp;gt;) — a live table of every configured point, updated by push (SSE) with no refresh needed. Writable points have an inline editor; type a value and click &#039;&#039;&#039;Set&#039;&#039;&#039; (or press Enter) to issue the PUT. Stale values (link down) are shown in red. A manual &#039;&#039;&#039;Refresh&#039;&#039;&#039; button is kept as a fallback.&lt;br /&gt;
* &#039;&#039;&#039;Log&#039;&#039;&#039; (&amp;lt;code&amp;gt;log.html&amp;lt;/code&amp;gt;) — the recent log backlog followed live as new lines are written, with an auto-scroll toggle. &amp;lt;code&amp;gt;WARN&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;ERROR&amp;lt;/code&amp;gt; lines are colour-coded.&lt;br /&gt;
* &#039;&#039;&#039;Licences&#039;&#039;&#039; (&amp;lt;code&amp;gt;licence.html&amp;lt;/code&amp;gt;) — the third-party libraries and their licences rendered as a table (the underlying &amp;lt;code&amp;gt;/api/licence&amp;lt;/code&amp;gt; endpoint returns the same data as raw JSON).&lt;br /&gt;
&lt;br /&gt;
== Modbus Behaviour ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transport:&#039;&#039;&#039; Modbus/TCP only (no serial / RTU, no TLS), reusing the [[ModbusClient]]&#039;s Modbus engine.&lt;br /&gt;
* The poll thread reads every configured point once per &amp;lt;code&amp;gt;pollIntervalMs&amp;lt;/code&amp;gt;. A read failure tears the connection down, flags all points stale, and the Bridge auto-reconnects with exponential backoff (1 → 2 → 4 → 8 … up to 30 s), resetting on a successful connect.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;Address already in use&amp;lt;/code&amp;gt; on start&#039;&#039;&#039; — another process holds the web port (default 8080). Change &amp;lt;code&amp;gt;&amp;lt;webserver&amp;gt;&amp;lt;port&amp;gt;&amp;lt;/code&amp;gt; or free the port.&lt;br /&gt;
* &#039;&#039;&#039;All points show stale / &amp;lt;code&amp;gt;/api/status&amp;lt;/code&amp;gt; says not connected&#039;&#039;&#039; — the Modbus server is unreachable. Check &amp;lt;code&amp;gt;&amp;lt;modbus&amp;gt;&amp;lt;ip&amp;gt;/&amp;lt;port&amp;gt;&amp;lt;/code&amp;gt;, that the server is running, and that both ends use the same &#039;&#039;&#039;unit id&#039;&#039;&#039; (the server answers only its configured unit). The log shows the backoff retries.&lt;br /&gt;
* &#039;&#039;&#039;Writes return 503&#039;&#039;&#039; — the link is down at that moment; the Bridge is between reconnect attempts. Reads still return the last-known (stale) values.&lt;br /&gt;
* &#039;&#039;&#039;PUT returns 400 &amp;quot;read-only&amp;quot;&#039;&#039;&#039; — the named point is a &amp;lt;code&amp;gt;DISCRETE_INPUT&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;INPUT_REGISTER&amp;lt;/code&amp;gt;; those cannot be written by a Modbus client.&lt;br /&gt;
* &#039;&#039;&#039;No log lines / empty log tail page&#039;&#039;&#039; — confirm &amp;lt;code&amp;gt;-Dlog4j2.configurationFile=xml/config/log4j2.xml&amp;lt;/code&amp;gt; is set (the start scripts do this) and the process working directory is the project root, so &amp;lt;code&amp;gt;logs/&amp;lt;/code&amp;gt; is created in the right place.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[ModbusClient]] — the interactive desktop Modbus client; the Bridge reuses its Modbus engine&lt;br /&gt;
* [[ModbusServer]] — the server-side companion tool, useful as a bench target for the Bridge&lt;br /&gt;
* [[AutoLab4j]] — uses the same Modbus stack to read laboratory instruments&lt;br /&gt;
* [[SocketTest]] — a raw TCP/IP testing utility&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=ModbusBridge&amp;diff=1895</id>
		<title>ModbusBridge</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=ModbusBridge&amp;diff=1895"/>
		<updated>2026-06-22T13:44:23Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: Created blank page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=Template:Menu_Applications&amp;diff=1894</id>
		<title>Template:Menu Applications</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=Template:Menu_Applications&amp;diff=1894"/>
		<updated>2026-06-22T13:43:47Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: /* Applications */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Applications=&lt;br /&gt;
{| cellpadding=&amp;quot;8&amp;quot; style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
||[[file:AutoLab4j_256x256.png|link=[[AutoLab4j]]|100px]]&lt;br /&gt;
====[[AutoLab4j]]====&lt;br /&gt;
|&lt;br /&gt;
||[[File:Commander4j_256x256.png|link=[[Commander4j]]|100px]]&lt;br /&gt;
====[[Commander4j]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:LabelServer4j_256x256.png|link=[[LabelServer4j]]|100px]]&lt;br /&gt;
====[[LabelServer4j]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:LaunchPad_256x256.png|link=[[LaunchPad]]|100px]]&lt;br /&gt;
====[[LaunchPad]]====&lt;br /&gt;
|-&lt;br /&gt;
||[[file:LogoClient_256x256.png|link=[[LogoClient]]|100px]]&lt;br /&gt;
====[[LogoClient]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:LogoRenderer_256x256.png|link=[[LogoRenderer]]|100px]]&lt;br /&gt;
====[[LogoRenderer]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:Menu4j_256x256.png|link=[[Menu4j]]|100px]]&lt;br /&gt;
====[[Menu4j]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:Middleware4j_256x256.png|link=[[Middleware4j]]|100px]]&lt;br /&gt;
====[[Middleware4j]]====&lt;br /&gt;
|-&lt;br /&gt;
||[[file:Modbus_256x256.png|link=[[ModbusClient]]|100px]]&lt;br /&gt;
====[[ModbusClient]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:Modbus_256x256.png|link=[[ModbusServer]]|100px]]&lt;br /&gt;
====[[ModbusServer]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:SFTGet4j_256x256.png|link=[[SFTPGet]]|100px]]&lt;br /&gt;
====[[SFTPGet]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:SFTPSend4j_256x256.png|link=[[SFTPSend]]|100px]]&lt;br /&gt;
====[[SFTPSend]]====&lt;br /&gt;
|-&lt;br /&gt;
||[[file:sftpTransfer_256x256.png|link=[[SFTPTransfer]]|100px]]&lt;br /&gt;
====[[SFTPTransfer]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:SocketTest_256x256.png|link=[[SocketTest]]|100px]]&lt;br /&gt;
====[[SocketTest]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:TreeDoc_256x256.png|link=[[TreeDoc]]|100px]]&lt;br /&gt;
====[[TreeDoc]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:XMLViewer_256x256.png|link=[[XMLViewer]]|100px]]&lt;br /&gt;
====[[XMLViewer]]====&lt;br /&gt;
|-&lt;br /&gt;
||[[file:ZPLRenderer_256x256.png|link=[[ZPLRenderer]]|100px]]&lt;br /&gt;
====[[ZPLRenderer]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:Modbus_256x256.png|link=[[ModbusBridge]]|100px]]&lt;br /&gt;
====[[ModbusBridge]]====&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=File:ModbusServer1.png&amp;diff=1893</id>
		<title>File:ModbusServer1.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=File:ModbusServer1.png&amp;diff=1893"/>
		<updated>2026-06-20T16:04:08Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=ModbusServer&amp;diff=1892</id>
		<title>ModbusServer</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=ModbusServer&amp;diff=1892"/>
		<updated>2026-06-20T16:03:52Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: /* Connection Bar */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;Commander4j Modbus Server&#039;&#039;&#039; (&#039;&#039;util_modbusServer&#039;&#039;) is a desktop tool that turns your PC into a [https://en.wikipedia.org/wiki/Modbus Modbus/TCP] server — a Modbus slave, or &amp;quot;device&amp;quot;. It shows the live state of all four Modbus data tables in a single editable grid, so you can both &#039;&#039;&#039;observe&#039;&#039;&#039; what a connected Modbus client writes and &#039;&#039;&#039;drive&#039;&#039;&#039; that client by staging values for it to read. It is a test, simulation and bench tool, and is the server-side companion to the [[ModbusClient|Commander4j Modbus Client]].&lt;br /&gt;
&lt;br /&gt;
== A Quick Modbus Primer ==&lt;br /&gt;
&lt;br /&gt;
If you are new to Modbus, the following terms are used throughout this page. Modbus is a simple, widely used industrial protocol for moving numeric and on/off values between automation equipment.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Master / Client&#039;&#039;&#039; — the device that initiates requests (reads and writes). The [[ModbusClient]] is a client.&lt;br /&gt;
* &#039;&#039;&#039;Slave / Server / Device&#039;&#039;&#039; — the device that holds the data and answers requests. This tool is a server.&lt;br /&gt;
* &#039;&#039;&#039;Unit ID&#039;&#039;&#039; (also &amp;quot;slave address&amp;quot;) — a number (0–247) identifying which device a request is for. A client must use the same unit ID the server is configured to answer as.&lt;br /&gt;
* &#039;&#039;&#039;Modbus/TCP&#039;&#039;&#039; — Modbus carried over an ordinary TCP/IP network connection, as opposed to serial (RTU) wiring. These tools speak Modbus/TCP only.&lt;br /&gt;
&lt;br /&gt;
Modbus organises all data into &#039;&#039;&#039;four tables&#039;&#039;&#039;, each addressed separately starting at zero:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Table !! Holds !! Size !! Can a client write it?&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Coils&#039;&#039;&#039; || On/off output bits || 1 bit || &#039;&#039;&#039;Yes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Discrete Inputs&#039;&#039;&#039; || On/off input bits || 1 bit || No — read-only&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Input Registers&#039;&#039;&#039; || Numeric inputs (readings) || 16 bits (0–65535) || No — read-only&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Holding Registers&#039;&#039;&#039; || Numeric settings / values || 16 bits (0–65535) || &#039;&#039;&#039;Yes&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The two &amp;quot;input&amp;quot; tables represent values a device &#039;&#039;produces&#039;&#039; (sensor states, measurements), so a client can only read them. Coils and holding registers represent values a client is allowed to &#039;&#039;set&#039;&#039;. Because this server stands in for the device, it lets you edit &#039;&#039;&#039;all four&#039;&#039;&#039; tables directly — including the two a client cannot write. Each table also has a conventional &#039;&#039;&#039;reference number&#039;&#039;&#039; that operators quote instead of the raw zero-based address: coils start at 1, discrete inputs at 10001, input registers at 30001 and holding registers at 40001.&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Server is useful when:&lt;br /&gt;
&lt;br /&gt;
* Testing a Modbus master (PLC, SCADA package, or the [[ModbusClient]]) without needing the real device it normally talks to&lt;br /&gt;
* Watching exactly which coils and registers a client reads and writes, with a timestamped log of every change&lt;br /&gt;
* Staging register values in advance so a client polling the server sees a known scenario&lt;br /&gt;
* Toggling discrete inputs and input registers — values a real device produces but a client cannot write — to simulate sensor or status changes&lt;br /&gt;
* Confirming a client is configured for the correct host, port and unit ID&lt;br /&gt;
&lt;br /&gt;
== Source Code and Releases ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Server is open source and hosted on GitHub:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Repository:&#039;&#039;&#039; [https://github.com/C4J/ModbusServer https://github.com/C4J/ModbusServer]&lt;br /&gt;
* &#039;&#039;&#039;Releases (downloads):&#039;&#039;&#039; [https://github.com/C4J/ModbusServer/releases https://github.com/C4J/ModbusServer/releases]&lt;br /&gt;
&lt;br /&gt;
== Running the Modbus Server ==&lt;br /&gt;
&lt;br /&gt;
The recommended way to install the Modbus Server is to download a native installer for your platform, either from the [[Downloads]] page or from the [https://github.com/C4J/ModbusServer/releases GitHub releases page]. Native installers are provided for &#039;&#039;&#039;Windows, macOS and Linux&#039;&#039;&#039;. Each installer bundles its own Java 25 runtime, so &#039;&#039;&#039;no separate Java installation is required&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Installing creates native &#039;&#039;&#039;launchers&#039;&#039;&#039; you can run like any other desktop application (from the Start menu, Applications folder, or desktop):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Launcher !! What it does&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;ModbusServer&#039;&#039;&#039; || Starts the interactive window described below.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;ModbusServer Service&#039;&#039;&#039; || Starts the server [[#Headless (Service) Mode|headless]], with no window, using the saved configuration file. Intended for running as a background service.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Running from the jar ===&lt;br /&gt;
&lt;br /&gt;
Alternatively the tool can be run directly from its distribution folder as an ordinary Java 25 (Swing) application:&lt;br /&gt;
&lt;br /&gt;
 java -jar modbusServer.jar&lt;br /&gt;
&lt;br /&gt;
The supplied &amp;lt;code&amp;gt;start_modbusServer.sh&amp;lt;/code&amp;gt; (macOS/Linux) and &amp;lt;code&amp;gt;start_modbusServer.cmd&amp;lt;/code&amp;gt; (Windows) scripts launch it the same way. Run the jar from its own folder so the bundled &amp;lt;code&amp;gt;lib/&amp;lt;/code&amp;gt; dependencies are found alongside it.&lt;br /&gt;
&lt;br /&gt;
== The Main Window ==&lt;br /&gt;
&lt;br /&gt;
The window has three parts: a &#039;&#039;&#039;connection bar&#039;&#039;&#039; across the top, the &#039;&#039;&#039;register table&#039;&#039;&#039; in the centre with a vertical button toolbar down the right-hand side, and an &#039;&#039;&#039;activity log&#039;&#039;&#039; along the bottom.&lt;br /&gt;
&lt;br /&gt;
=== Connection Bar ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Bind address&#039;&#039;&#039; || The network interface to listen on. &amp;lt;code&amp;gt;0.0.0.0&amp;lt;/code&amp;gt; listens on all interfaces; enter a specific IP to restrict the server to one.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Port&#039;&#039;&#039; || The TCP port to listen on. The Modbus standard is &#039;&#039;&#039;502&#039;&#039;&#039;, but ports below 1024 require elevated privileges on macOS and Linux — use a high port such as &#039;&#039;&#039;1502&#039;&#039;&#039; for unprivileged testing.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Unit ID&#039;&#039;&#039; || The single slave / unit address this server answers as (0–247, default &#039;&#039;&#039;1&#039;&#039;&#039;). Requests addressed to any other unit ID are rejected, so this is a deliberate one-device simulator.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Status&#039;&#039;&#039; || Shows &#039;&#039;&#039;Stopped&#039;&#039;&#039;, or &#039;&#039;&#039;Running&#039;&#039;&#039; with the active address, port and unit ID in green.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Start / Stop&#039;&#039;&#039; button (the toggle at the top of the right-hand toolbar) binds and unbinds the server. The bind address, port and unit ID can only be changed while the server is stopped. The server can be stopped and started again without restarting the application, and &#039;&#039;&#039;all register values are kept across a stop/start&#039;&#039;&#039; — they are only lost when you exit the application.&lt;br /&gt;
&lt;br /&gt;
[[File:ModbusServer1.png|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Register Table ===&lt;br /&gt;
&lt;br /&gt;
A single grid shows one row per address, with every Modbus data table side by side and colour-coded:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Column group !! Contents !! Editable here&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Address&#039;&#039;&#039; || The zero-based Modbus protocol address (the same address for the whole row). || —&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Coil&#039;&#039;&#039; || Modbus reference (1…) and an on/off checkbox. || Yes&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Discrete&#039;&#039;&#039; || Discrete input reference (10001…) and an on/off checkbox. || Yes&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Input&#039;&#039;&#039; || Input register reference (30001…), a decimal value (0–65535) and a read-only &#039;&#039;&#039;Hex&#039;&#039;&#039; view. || Yes&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Holding&#039;&#039;&#039; || Holding register reference (40001…), a decimal value (0–65535) and a read-only &#039;&#039;&#039;Hex&#039;&#039;&#039; view. || Yes&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Address&#039;&#039;&#039; is the zero-based protocol address; the &#039;&#039;&#039;Modbus Ref&#039;&#039;&#039; column in each group is the conventional reference number an operator would quote (for example coil 0 is reference 1, holding register 0 is reference 40001).&lt;br /&gt;
&lt;br /&gt;
All four tables are editable directly in this window — including discrete inputs and input registers, which a Modbus client is not allowed to write. This lets the server stand in for a real device whose inputs change. Values can be edited whether or not the server is running and whether or not a client is connected, which is useful for staging a test scenario in advance.&lt;br /&gt;
&lt;br /&gt;
Below the table, the &#039;&#039;&#039;Start address&#039;&#039;&#039; and &#039;&#039;&#039;Count&#039;&#039;&#039; fields choose which window of addresses is listed; click the tick button (Apply range) to apply them. Up to 2000 rows can be shown at once.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Zero registers&#039;&#039;&#039; button (eraser icon) on the toolbar opens a menu to clear the visible window for an individual table — Coils, Discrete Inputs, Input Registers or Holding Registers — or &#039;&#039;&#039;Zero All&#039;&#039;&#039; to clear every table at once.&lt;br /&gt;
&lt;br /&gt;
=== Activity Log ===&lt;br /&gt;
&lt;br /&gt;
Every change to a coil or register is written to the log at the bottom with a millisecond timestamp, whether it came from a connected client or from an operator edit in the window. The log keeps the most recent 400 lines. The two buttons beside it &#039;&#039;&#039;Save&#039;&#039;&#039; the log to a text file and &#039;&#039;&#039;Clear&#039;&#039;&#039; it.&lt;br /&gt;
&lt;br /&gt;
== Toolbar Buttons ==&lt;br /&gt;
&lt;br /&gt;
The vertical toolbar to the right of the register table provides, from top to bottom: &#039;&#039;&#039;Start / Stop&#039;&#039;&#039; the server, &#039;&#039;&#039;Open settings&#039;&#039;&#039;, &#039;&#039;&#039;Save settings&#039;&#039;&#039;, &#039;&#039;&#039;Zero registers&#039;&#039;&#039;, &#039;&#039;&#039;About&#039;&#039;&#039;, &#039;&#039;&#039;Licences&#039;&#039;&#039;, &#039;&#039;&#039;Help&#039;&#039;&#039; (opens this wiki page) and &#039;&#039;&#039;Close&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
The connection settings (bind address, port and unit ID) are stored in a small XML file, by default &amp;lt;code&amp;gt;xml/config/config.xml&amp;lt;/code&amp;gt; beneath the application folder:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;config&amp;gt;&lt;br /&gt;
   &amp;lt;ip&amp;gt;0.0.0.0&amp;lt;/ip&amp;gt;&lt;br /&gt;
   &amp;lt;port&amp;gt;502&amp;lt;/port&amp;gt;&lt;br /&gt;
   &amp;lt;id&amp;gt;1&amp;lt;/id&amp;gt;&lt;br /&gt;
 &amp;lt;/config&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The default settings are loaded automatically at start-up. Use the &#039;&#039;&#039;Open settings&#039;&#039;&#039; and &#039;&#039;&#039;Save settings&#039;&#039;&#039; toolbar buttons to load or store a configuration from any location. If you change the settings and then close the application, you are prompted to save the changes first.&lt;br /&gt;
&lt;br /&gt;
== Headless (Service) Mode ==&lt;br /&gt;
&lt;br /&gt;
In addition to the interactive window, the Modbus Server can run headless as a background service, started by the &#039;&#039;&#039;ModbusServer Service&#039;&#039;&#039; launcher. In this mode it loads the saved &amp;lt;code&amp;gt;xml/config/config.xml&amp;lt;/code&amp;gt;, binds the server with no user interface, and runs until the operating system asks it to stop (for example a service stop, console Ctrl-C, or system shutdown). This is why the native installer provides two launchers — &#039;&#039;&#039;ModbusServer&#039;&#039;&#039; for the window and &#039;&#039;&#039;ModbusServer Service&#039;&#039;&#039; for the headless service.&lt;br /&gt;
&lt;br /&gt;
== Using the Server and Client Together ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Server and the [[ModbusClient|Modbus Client]] are designed to be used as a pair to exercise a Modbus link from both ends without any real hardware:&lt;br /&gt;
&lt;br /&gt;
# Start this server, choose a &#039;&#039;&#039;port&#039;&#039;&#039; and &#039;&#039;&#039;unit ID&#039;&#039;&#039;, and press &#039;&#039;&#039;Start&#039;&#039;&#039;.&lt;br /&gt;
# In the [[ModbusClient]], set &#039;&#039;&#039;Server host&#039;&#039;&#039; to this machine (&amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; if both run on the same PC), set the matching &#039;&#039;&#039;port&#039;&#039;&#039; and &#039;&#039;&#039;unit ID&#039;&#039;&#039;, and press &#039;&#039;&#039;Connect&#039;&#039;&#039;.&lt;br /&gt;
# &#039;&#039;&#039;Client → Server:&#039;&#039;&#039; when the client edits a Coil or Holding Register, the value is written here and appears in this server&#039;s grid and activity log.&lt;br /&gt;
# &#039;&#039;&#039;Server → Client:&#039;&#039;&#039; edit any value here — including discrete inputs and input registers, which the client can only read — and the client&#039;s grid reflects it on its next poll.&lt;br /&gt;
&lt;br /&gt;
This makes the pair a complete bench setup: the server stands in for a device so you can develop or test a Modbus master, while the client stands in for a master so you can stage and inspect a device&#039;s data. This server can equally answer a real third-party Modbus/TCP master.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;quot;Permission denied&amp;quot; when starting&#039;&#039;&#039; — the chosen port is below 1024 (the default is 502) and the operating system requires elevated privileges to bind it. Use a port of 1024 or higher, such as 1502, or run with elevated privileges.&lt;br /&gt;
* &#039;&#039;&#039;A client&#039;s requests are rejected&#039;&#039;&#039; — the server answers only the configured &#039;&#039;&#039;Unit ID&#039;&#039;&#039;. Check the client is using the same unit ID shown in the connection bar.&lt;br /&gt;
* &#039;&#039;&#039;A startup warning about &amp;lt;code&amp;gt;sun.misc.Unsafe&amp;lt;/code&amp;gt;&#039;&#039;&#039; — harmless, and does not affect operation. The supplied start scripts suppress it; launching the jar directly may still print it.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[ModbusClient]] — the client-side companion tool&lt;br /&gt;
* [[AutoLab4j]] — uses the same Modbus stack to read laboratory instruments&lt;br /&gt;
* [[SocketTest]] — a raw TCP/IP testing utility&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=ModbusClient&amp;diff=1891</id>
		<title>ModbusClient</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=ModbusClient&amp;diff=1891"/>
		<updated>2026-06-20T16:03:12Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: /* Connection Bar */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;Commander4j Modbus Client&#039;&#039;&#039; (&#039;&#039;util_modbusClient&#039;&#039;) is a desktop tool that acts as a [https://en.wikipedia.org/wiki/Modbus Modbus/TCP] client — a Modbus master. It connects to a remote Modbus server (a device, PLC, or the [[ModbusServer|Commander4j Modbus Server]]), continuously polls its four data tables across a chosen address window, and shows them in a single live grid. Coil and Holding Register values can be edited to drive the connected server. It is a test, troubleshooting and bench tool, and is the client-side companion to the [[ModbusServer|Commander4j Modbus Server]].&lt;br /&gt;
&lt;br /&gt;
== A Quick Modbus Primer ==&lt;br /&gt;
&lt;br /&gt;
If you are new to Modbus, the following terms are used throughout this page. Modbus is a simple, widely used industrial protocol for moving numeric and on/off values between automation equipment.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Master / Client&#039;&#039;&#039; — the device that initiates requests (reads and writes). This tool is a client.&lt;br /&gt;
* &#039;&#039;&#039;Slave / Server / Device&#039;&#039;&#039; — the device that holds the data and answers requests. The [[ModbusServer]] is a server.&lt;br /&gt;
* &#039;&#039;&#039;Unit ID&#039;&#039;&#039; (also &amp;quot;slave address&amp;quot;) — a number (0–247) identifying which device a request is for. A client must use the same unit ID the server is configured to answer as.&lt;br /&gt;
* &#039;&#039;&#039;Modbus/TCP&#039;&#039;&#039; — Modbus carried over an ordinary TCP/IP network connection, as opposed to serial (RTU) wiring. These tools speak Modbus/TCP only.&lt;br /&gt;
&lt;br /&gt;
Modbus organises all data into &#039;&#039;&#039;four tables&#039;&#039;&#039;, each addressed separately starting at zero:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Table !! Holds !! Size !! Can a client write it?&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Coils&#039;&#039;&#039; || On/off output bits || 1 bit || &#039;&#039;&#039;Yes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Discrete Inputs&#039;&#039;&#039; || On/off input bits || 1 bit || No — read-only&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Input Registers&#039;&#039;&#039; || Numeric inputs (readings) || 16 bits (0–65535) || No — read-only&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Holding Registers&#039;&#039;&#039; || Numeric settings / values || 16 bits (0–65535) || &#039;&#039;&#039;Yes&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The two &amp;quot;input&amp;quot; tables represent values a device &#039;&#039;produces&#039;&#039; (sensor states, measurements), so a client can only read them. Coils and holding registers represent values a client is allowed to &#039;&#039;set&#039;&#039;. Each table also has a conventional &#039;&#039;&#039;reference number&#039;&#039;&#039; that operators quote instead of the raw zero-based address: coils start at 1, discrete inputs at 10001, input registers at 30001 and holding registers at 40001.&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Client is useful when:&lt;br /&gt;
&lt;br /&gt;
* Reading the live coils and registers of a PLC or other Modbus device to confirm it is responding&lt;br /&gt;
* Writing a coil or holding register to command a device during commissioning or fault-finding&lt;br /&gt;
* Checking that a device is reachable on a given host, port and unit ID&lt;br /&gt;
* Driving the [[ModbusServer]] during testing, or reading values the server is staging&lt;br /&gt;
&lt;br /&gt;
== Source Code and Releases ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Client is open source and hosted on GitHub:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Repository:&#039;&#039;&#039; [https://github.com/C4J/ModbusClient https://github.com/C4J/ModbusClient]&lt;br /&gt;
* &#039;&#039;&#039;Releases (downloads):&#039;&#039;&#039; [https://github.com/C4J/ModbusClient/releases https://github.com/C4J/ModbusClient/releases]&lt;br /&gt;
&lt;br /&gt;
== Running the Modbus Client ==&lt;br /&gt;
&lt;br /&gt;
The recommended way to install the Modbus Client is to download a native installer for your platform, either from the [[Downloads]] page or from the [https://github.com/C4J/ModbusClient/releases GitHub releases page]. Native installers are provided for &#039;&#039;&#039;Windows, macOS and Linux&#039;&#039;&#039;. Each installer bundles its own Java 25 runtime, so &#039;&#039;&#039;no separate Java installation is required&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Installing creates a native &#039;&#039;&#039;ModbusClient&#039;&#039;&#039; launcher that you run like any other desktop application — from the Start menu, Applications folder, or desktop — which opens the window described below.&lt;br /&gt;
&lt;br /&gt;
=== Running from the jar ===&lt;br /&gt;
&lt;br /&gt;
Alternatively the tool can be run directly from its distribution folder as an ordinary Java 25 (Swing) application:&lt;br /&gt;
&lt;br /&gt;
 java -jar modbusClient.jar&lt;br /&gt;
&lt;br /&gt;
The supplied &amp;lt;code&amp;gt;start_modbusClient.sh&amp;lt;/code&amp;gt; (macOS/Linux) and &amp;lt;code&amp;gt;start_modbusClient.cmd&amp;lt;/code&amp;gt; (Windows) scripts launch it the same way. Run the jar from its own folder so the bundled &amp;lt;code&amp;gt;lib/&amp;lt;/code&amp;gt; dependencies are found alongside it.&lt;br /&gt;
&lt;br /&gt;
== The Main Window ==&lt;br /&gt;
&lt;br /&gt;
The window has three parts: a &#039;&#039;&#039;connection bar&#039;&#039;&#039; across the top, the &#039;&#039;&#039;register table&#039;&#039;&#039; in the centre with a vertical button toolbar down the right-hand side, and an &#039;&#039;&#039;activity log&#039;&#039;&#039; along the bottom.&lt;br /&gt;
&lt;br /&gt;
=== Connection Bar ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Server host&#039;&#039;&#039; || The host name or IP address of the Modbus server to connect to. Defaults to &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; (this machine) for quick loopback testing against a local [[ModbusServer]].&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Port&#039;&#039;&#039; || The TCP port of the server. The Modbus standard is &#039;&#039;&#039;502&#039;&#039;&#039;; match whatever the server is listening on.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Unit ID&#039;&#039;&#039; || The unit / slave address to address requests to (0–247, default &#039;&#039;&#039;1&#039;&#039;&#039;). This must match the unit ID the server answers as, or every request will be rejected.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Status&#039;&#039;&#039; || Shows &#039;&#039;&#039;Disconnected&#039;&#039;&#039;, or &#039;&#039;&#039;Connected&#039;&#039;&#039; with the server address and unit ID in green.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Connect / Disconnect&#039;&#039;&#039; button (the toggle at the top of the right-hand toolbar) opens and closes the connection. The host, port and unit ID can only be changed while disconnected. Once connected, the client polls the server roughly four times a second and the grid updates live.&lt;br /&gt;
&lt;br /&gt;
[[File:ModbusClient1.png|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Register Table ===&lt;br /&gt;
&lt;br /&gt;
A single grid shows one row per address, with every Modbus data table side by side and colour-coded:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Column group !! Contents !! Editable here&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Address&#039;&#039;&#039; || The zero-based Modbus protocol address (the same address for the whole row). || —&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Coil&#039;&#039;&#039; || Modbus reference (1…) and an on/off checkbox. || &#039;&#039;&#039;Yes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Discrete&#039;&#039;&#039; || Discrete input reference (10001…) and an on/off checkbox. || No (read-only)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Input&#039;&#039;&#039; || Input register reference (30001…), a decimal value and a read-only &#039;&#039;&#039;Hex&#039;&#039;&#039; view. || No (read-only)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Holding&#039;&#039;&#039; || Holding register reference (40001…), a decimal value (0–65535) and a read-only &#039;&#039;&#039;Hex&#039;&#039;&#039; view. || &#039;&#039;&#039;Yes&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Only the &#039;&#039;&#039;Coil&#039;&#039;&#039; and &#039;&#039;&#039;Holding Register&#039;&#039;&#039; value cells can be edited, and only while connected — because Modbus has no function code for a client to write the discrete-input and input-register tables. Editing a cell writes the new value straight through to the server; the displayed value updates immediately and is reverted if the server rejects the write.&lt;br /&gt;
&lt;br /&gt;
Below the table, the &#039;&#039;&#039;Start address&#039;&#039;&#039; and &#039;&#039;&#039;Count&#039;&#039;&#039; fields choose which window of addresses the client polls; click the tick button (Apply range) to apply them. Up to 2000 rows can be shown at once.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Zero registers&#039;&#039;&#039; button (eraser icon) on the toolbar opens a menu to clear the visible window of the writable tables — &#039;&#039;&#039;Zero Coils&#039;&#039;&#039;, &#039;&#039;&#039;Zero Holding Registers&#039;&#039;&#039;, or &#039;&#039;&#039;Zero All&#039;&#039;&#039; for both. Only the writable tables appear, because the read-only ones cannot be cleared by a client.&lt;br /&gt;
&lt;br /&gt;
=== Activity Log ===&lt;br /&gt;
&lt;br /&gt;
Connection events, writes, and any errors are written to the log at the bottom with a millisecond timestamp. The log keeps the most recent 400 lines. The two buttons beside it &#039;&#039;&#039;Save&#039;&#039;&#039; the log to a text file and &#039;&#039;&#039;Clear&#039;&#039;&#039; it. If the connection is lost (for example the server stops or the network drops), the client reports it in the log and returns to the disconnected state automatically.&lt;br /&gt;
&lt;br /&gt;
== Toolbar Buttons ==&lt;br /&gt;
&lt;br /&gt;
The vertical toolbar to the right of the register table provides, from top to bottom: &#039;&#039;&#039;Connect / Disconnect&#039;&#039;&#039;, &#039;&#039;&#039;Open settings&#039;&#039;&#039;, &#039;&#039;&#039;Save settings&#039;&#039;&#039;, &#039;&#039;&#039;Zero registers&#039;&#039;&#039;, &#039;&#039;&#039;About&#039;&#039;&#039;, &#039;&#039;&#039;Licences&#039;&#039;&#039;, &#039;&#039;&#039;Help&#039;&#039;&#039; (opens this wiki page) and &#039;&#039;&#039;Close&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
The connection settings (server host, port and unit ID) are stored in a small XML file, by default &amp;lt;code&amp;gt;xml/config/config.xml&amp;lt;/code&amp;gt; beneath the application folder:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;config&amp;gt;&lt;br /&gt;
   &amp;lt;ip&amp;gt;127.0.0.1&amp;lt;/ip&amp;gt;&lt;br /&gt;
   &amp;lt;port&amp;gt;502&amp;lt;/port&amp;gt;&lt;br /&gt;
   &amp;lt;id&amp;gt;1&amp;lt;/id&amp;gt;&lt;br /&gt;
 &amp;lt;/config&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The default settings are loaded automatically at start-up. Use the &#039;&#039;&#039;Open settings&#039;&#039;&#039; and &#039;&#039;&#039;Save settings&#039;&#039;&#039; toolbar buttons to load or store a configuration from any location. If you change the settings and then close the application, you are prompted to save the changes first.&lt;br /&gt;
&lt;br /&gt;
== Using the Client and Server Together ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Client and the [[ModbusServer|Modbus Server]] are designed to be used as a pair to exercise a Modbus link from both ends without any real hardware:&lt;br /&gt;
&lt;br /&gt;
# Start the [[ModbusServer]] on one machine (or the same machine), choose a &#039;&#039;&#039;port&#039;&#039;&#039; and &#039;&#039;&#039;unit ID&#039;&#039;&#039;, and press &#039;&#039;&#039;Start&#039;&#039;&#039;.&lt;br /&gt;
# In the Modbus Client, set &#039;&#039;&#039;Server host&#039;&#039;&#039; to that machine (&amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; if both run on the same PC), set the matching &#039;&#039;&#039;port&#039;&#039;&#039; and &#039;&#039;&#039;unit ID&#039;&#039;&#039;, and press &#039;&#039;&#039;Connect&#039;&#039;&#039;.&lt;br /&gt;
# &#039;&#039;&#039;Client → Server:&#039;&#039;&#039; edit a Coil or Holding Register in the client; the value is written to the server and appears in the server&#039;s grid and activity log.&lt;br /&gt;
# &#039;&#039;&#039;Server → Client:&#039;&#039;&#039; edit any value in the server — including discrete inputs and input registers, which the client can only read; the client&#039;s grid reflects it on the next poll.&lt;br /&gt;
&lt;br /&gt;
This makes the pair a complete bench setup: the server stands in for a device so you can develop or test a Modbus master, and the client stands in for a master so you can stage and inspect a device&#039;s data. Either tool can also be pointed at real third-party Modbus/TCP equipment.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;quot;Connection refused&amp;quot; or a timeout on Connect&#039;&#039;&#039; — check the server host and port, that the server is running and listening, and that no firewall is blocking the connection.&lt;br /&gt;
* &#039;&#039;&#039;Connected, but every read fails or the connection drops immediately&#039;&#039;&#039; — the &#039;&#039;&#039;Unit ID&#039;&#039;&#039; probably does not match the server. The client must address the exact unit ID the server answers as.&lt;br /&gt;
* &#039;&#039;&#039;A startup warning about &amp;lt;code&amp;gt;sun.misc.Unsafe&amp;lt;/code&amp;gt;&#039;&#039;&#039; — harmless, and does not affect operation. The supplied start scripts suppress it; launching the jar directly may still print it.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[ModbusServer]] — the server-side companion tool&lt;br /&gt;
* [[AutoLab4j]] — uses the same Modbus stack to read Modbus printing triggers&lt;br /&gt;
* [[SocketTest]] — a raw TCP/IP testing utility&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=ModbusClient&amp;diff=1890</id>
		<title>ModbusClient</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=ModbusClient&amp;diff=1890"/>
		<updated>2026-06-20T16:02:55Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: /* The Main Window */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;Commander4j Modbus Client&#039;&#039;&#039; (&#039;&#039;util_modbusClient&#039;&#039;) is a desktop tool that acts as a [https://en.wikipedia.org/wiki/Modbus Modbus/TCP] client — a Modbus master. It connects to a remote Modbus server (a device, PLC, or the [[ModbusServer|Commander4j Modbus Server]]), continuously polls its four data tables across a chosen address window, and shows them in a single live grid. Coil and Holding Register values can be edited to drive the connected server. It is a test, troubleshooting and bench tool, and is the client-side companion to the [[ModbusServer|Commander4j Modbus Server]].&lt;br /&gt;
&lt;br /&gt;
== A Quick Modbus Primer ==&lt;br /&gt;
&lt;br /&gt;
If you are new to Modbus, the following terms are used throughout this page. Modbus is a simple, widely used industrial protocol for moving numeric and on/off values between automation equipment.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Master / Client&#039;&#039;&#039; — the device that initiates requests (reads and writes). This tool is a client.&lt;br /&gt;
* &#039;&#039;&#039;Slave / Server / Device&#039;&#039;&#039; — the device that holds the data and answers requests. The [[ModbusServer]] is a server.&lt;br /&gt;
* &#039;&#039;&#039;Unit ID&#039;&#039;&#039; (also &amp;quot;slave address&amp;quot;) — a number (0–247) identifying which device a request is for. A client must use the same unit ID the server is configured to answer as.&lt;br /&gt;
* &#039;&#039;&#039;Modbus/TCP&#039;&#039;&#039; — Modbus carried over an ordinary TCP/IP network connection, as opposed to serial (RTU) wiring. These tools speak Modbus/TCP only.&lt;br /&gt;
&lt;br /&gt;
Modbus organises all data into &#039;&#039;&#039;four tables&#039;&#039;&#039;, each addressed separately starting at zero:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Table !! Holds !! Size !! Can a client write it?&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Coils&#039;&#039;&#039; || On/off output bits || 1 bit || &#039;&#039;&#039;Yes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Discrete Inputs&#039;&#039;&#039; || On/off input bits || 1 bit || No — read-only&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Input Registers&#039;&#039;&#039; || Numeric inputs (readings) || 16 bits (0–65535) || No — read-only&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Holding Registers&#039;&#039;&#039; || Numeric settings / values || 16 bits (0–65535) || &#039;&#039;&#039;Yes&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The two &amp;quot;input&amp;quot; tables represent values a device &#039;&#039;produces&#039;&#039; (sensor states, measurements), so a client can only read them. Coils and holding registers represent values a client is allowed to &#039;&#039;set&#039;&#039;. Each table also has a conventional &#039;&#039;&#039;reference number&#039;&#039;&#039; that operators quote instead of the raw zero-based address: coils start at 1, discrete inputs at 10001, input registers at 30001 and holding registers at 40001.&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Client is useful when:&lt;br /&gt;
&lt;br /&gt;
* Reading the live coils and registers of a PLC or other Modbus device to confirm it is responding&lt;br /&gt;
* Writing a coil or holding register to command a device during commissioning or fault-finding&lt;br /&gt;
* Checking that a device is reachable on a given host, port and unit ID&lt;br /&gt;
* Driving the [[ModbusServer]] during testing, or reading values the server is staging&lt;br /&gt;
&lt;br /&gt;
== Source Code and Releases ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Client is open source and hosted on GitHub:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Repository:&#039;&#039;&#039; [https://github.com/C4J/ModbusClient https://github.com/C4J/ModbusClient]&lt;br /&gt;
* &#039;&#039;&#039;Releases (downloads):&#039;&#039;&#039; [https://github.com/C4J/ModbusClient/releases https://github.com/C4J/ModbusClient/releases]&lt;br /&gt;
&lt;br /&gt;
== Running the Modbus Client ==&lt;br /&gt;
&lt;br /&gt;
The recommended way to install the Modbus Client is to download a native installer for your platform, either from the [[Downloads]] page or from the [https://github.com/C4J/ModbusClient/releases GitHub releases page]. Native installers are provided for &#039;&#039;&#039;Windows, macOS and Linux&#039;&#039;&#039;. Each installer bundles its own Java 25 runtime, so &#039;&#039;&#039;no separate Java installation is required&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Installing creates a native &#039;&#039;&#039;ModbusClient&#039;&#039;&#039; launcher that you run like any other desktop application — from the Start menu, Applications folder, or desktop — which opens the window described below.&lt;br /&gt;
&lt;br /&gt;
=== Running from the jar ===&lt;br /&gt;
&lt;br /&gt;
Alternatively the tool can be run directly from its distribution folder as an ordinary Java 25 (Swing) application:&lt;br /&gt;
&lt;br /&gt;
 java -jar modbusClient.jar&lt;br /&gt;
&lt;br /&gt;
The supplied &amp;lt;code&amp;gt;start_modbusClient.sh&amp;lt;/code&amp;gt; (macOS/Linux) and &amp;lt;code&amp;gt;start_modbusClient.cmd&amp;lt;/code&amp;gt; (Windows) scripts launch it the same way. Run the jar from its own folder so the bundled &amp;lt;code&amp;gt;lib/&amp;lt;/code&amp;gt; dependencies are found alongside it.&lt;br /&gt;
&lt;br /&gt;
== The Main Window ==&lt;br /&gt;
&lt;br /&gt;
The window has three parts: a &#039;&#039;&#039;connection bar&#039;&#039;&#039; across the top, the &#039;&#039;&#039;register table&#039;&#039;&#039; in the centre with a vertical button toolbar down the right-hand side, and an &#039;&#039;&#039;activity log&#039;&#039;&#039; along the bottom.&lt;br /&gt;
&lt;br /&gt;
=== Connection Bar ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Server host&#039;&#039;&#039; || The host name or IP address of the Modbus server to connect to. Defaults to &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; (this machine) for quick loopback testing against a local [[ModbusServer]].&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Port&#039;&#039;&#039; || The TCP port of the server. The Modbus standard is &#039;&#039;&#039;502&#039;&#039;&#039;; match whatever the server is listening on.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Unit ID&#039;&#039;&#039; || The unit / slave address to address requests to (0–247, default &#039;&#039;&#039;1&#039;&#039;&#039;). This must match the unit ID the server answers as, or every request will be rejected.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Status&#039;&#039;&#039; || Shows &#039;&#039;&#039;Disconnected&#039;&#039;&#039;, or &#039;&#039;&#039;Connected&#039;&#039;&#039; with the server address and unit ID in green.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Connect / Disconnect&#039;&#039;&#039; button (the toggle at the top of the right-hand toolbar) opens and closes the connection. The host, port and unit ID can only be changed while disconnected. Once connected, the client polls the server roughly four times a second and the grid updates live.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:ModbusClient1.png|600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Register Table ===&lt;br /&gt;
&lt;br /&gt;
A single grid shows one row per address, with every Modbus data table side by side and colour-coded:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Column group !! Contents !! Editable here&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Address&#039;&#039;&#039; || The zero-based Modbus protocol address (the same address for the whole row). || —&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Coil&#039;&#039;&#039; || Modbus reference (1…) and an on/off checkbox. || &#039;&#039;&#039;Yes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Discrete&#039;&#039;&#039; || Discrete input reference (10001…) and an on/off checkbox. || No (read-only)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Input&#039;&#039;&#039; || Input register reference (30001…), a decimal value and a read-only &#039;&#039;&#039;Hex&#039;&#039;&#039; view. || No (read-only)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Holding&#039;&#039;&#039; || Holding register reference (40001…), a decimal value (0–65535) and a read-only &#039;&#039;&#039;Hex&#039;&#039;&#039; view. || &#039;&#039;&#039;Yes&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Only the &#039;&#039;&#039;Coil&#039;&#039;&#039; and &#039;&#039;&#039;Holding Register&#039;&#039;&#039; value cells can be edited, and only while connected — because Modbus has no function code for a client to write the discrete-input and input-register tables. Editing a cell writes the new value straight through to the server; the displayed value updates immediately and is reverted if the server rejects the write.&lt;br /&gt;
&lt;br /&gt;
Below the table, the &#039;&#039;&#039;Start address&#039;&#039;&#039; and &#039;&#039;&#039;Count&#039;&#039;&#039; fields choose which window of addresses the client polls; click the tick button (Apply range) to apply them. Up to 2000 rows can be shown at once.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Zero registers&#039;&#039;&#039; button (eraser icon) on the toolbar opens a menu to clear the visible window of the writable tables — &#039;&#039;&#039;Zero Coils&#039;&#039;&#039;, &#039;&#039;&#039;Zero Holding Registers&#039;&#039;&#039;, or &#039;&#039;&#039;Zero All&#039;&#039;&#039; for both. Only the writable tables appear, because the read-only ones cannot be cleared by a client.&lt;br /&gt;
&lt;br /&gt;
=== Activity Log ===&lt;br /&gt;
&lt;br /&gt;
Connection events, writes, and any errors are written to the log at the bottom with a millisecond timestamp. The log keeps the most recent 400 lines. The two buttons beside it &#039;&#039;&#039;Save&#039;&#039;&#039; the log to a text file and &#039;&#039;&#039;Clear&#039;&#039;&#039; it. If the connection is lost (for example the server stops or the network drops), the client reports it in the log and returns to the disconnected state automatically.&lt;br /&gt;
&lt;br /&gt;
== Toolbar Buttons ==&lt;br /&gt;
&lt;br /&gt;
The vertical toolbar to the right of the register table provides, from top to bottom: &#039;&#039;&#039;Connect / Disconnect&#039;&#039;&#039;, &#039;&#039;&#039;Open settings&#039;&#039;&#039;, &#039;&#039;&#039;Save settings&#039;&#039;&#039;, &#039;&#039;&#039;Zero registers&#039;&#039;&#039;, &#039;&#039;&#039;About&#039;&#039;&#039;, &#039;&#039;&#039;Licences&#039;&#039;&#039;, &#039;&#039;&#039;Help&#039;&#039;&#039; (opens this wiki page) and &#039;&#039;&#039;Close&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
The connection settings (server host, port and unit ID) are stored in a small XML file, by default &amp;lt;code&amp;gt;xml/config/config.xml&amp;lt;/code&amp;gt; beneath the application folder:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;config&amp;gt;&lt;br /&gt;
   &amp;lt;ip&amp;gt;127.0.0.1&amp;lt;/ip&amp;gt;&lt;br /&gt;
   &amp;lt;port&amp;gt;502&amp;lt;/port&amp;gt;&lt;br /&gt;
   &amp;lt;id&amp;gt;1&amp;lt;/id&amp;gt;&lt;br /&gt;
 &amp;lt;/config&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The default settings are loaded automatically at start-up. Use the &#039;&#039;&#039;Open settings&#039;&#039;&#039; and &#039;&#039;&#039;Save settings&#039;&#039;&#039; toolbar buttons to load or store a configuration from any location. If you change the settings and then close the application, you are prompted to save the changes first.&lt;br /&gt;
&lt;br /&gt;
== Using the Client and Server Together ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Client and the [[ModbusServer|Modbus Server]] are designed to be used as a pair to exercise a Modbus link from both ends without any real hardware:&lt;br /&gt;
&lt;br /&gt;
# Start the [[ModbusServer]] on one machine (or the same machine), choose a &#039;&#039;&#039;port&#039;&#039;&#039; and &#039;&#039;&#039;unit ID&#039;&#039;&#039;, and press &#039;&#039;&#039;Start&#039;&#039;&#039;.&lt;br /&gt;
# In the Modbus Client, set &#039;&#039;&#039;Server host&#039;&#039;&#039; to that machine (&amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; if both run on the same PC), set the matching &#039;&#039;&#039;port&#039;&#039;&#039; and &#039;&#039;&#039;unit ID&#039;&#039;&#039;, and press &#039;&#039;&#039;Connect&#039;&#039;&#039;.&lt;br /&gt;
# &#039;&#039;&#039;Client → Server:&#039;&#039;&#039; edit a Coil or Holding Register in the client; the value is written to the server and appears in the server&#039;s grid and activity log.&lt;br /&gt;
# &#039;&#039;&#039;Server → Client:&#039;&#039;&#039; edit any value in the server — including discrete inputs and input registers, which the client can only read; the client&#039;s grid reflects it on the next poll.&lt;br /&gt;
&lt;br /&gt;
This makes the pair a complete bench setup: the server stands in for a device so you can develop or test a Modbus master, and the client stands in for a master so you can stage and inspect a device&#039;s data. Either tool can also be pointed at real third-party Modbus/TCP equipment.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;quot;Connection refused&amp;quot; or a timeout on Connect&#039;&#039;&#039; — check the server host and port, that the server is running and listening, and that no firewall is blocking the connection.&lt;br /&gt;
* &#039;&#039;&#039;Connected, but every read fails or the connection drops immediately&#039;&#039;&#039; — the &#039;&#039;&#039;Unit ID&#039;&#039;&#039; probably does not match the server. The client must address the exact unit ID the server answers as.&lt;br /&gt;
* &#039;&#039;&#039;A startup warning about &amp;lt;code&amp;gt;sun.misc.Unsafe&amp;lt;/code&amp;gt;&#039;&#039;&#039; — harmless, and does not affect operation. The supplied start scripts suppress it; launching the jar directly may still print it.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[ModbusServer]] — the server-side companion tool&lt;br /&gt;
* [[AutoLab4j]] — uses the same Modbus stack to read Modbus printing triggers&lt;br /&gt;
* [[SocketTest]] — a raw TCP/IP testing utility&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=File:ModbusClient1.png&amp;diff=1889</id>
		<title>File:ModbusClient1.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=File:ModbusClient1.png&amp;diff=1889"/>
		<updated>2026-06-20T16:00:19Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=ModbusClient&amp;diff=1888</id>
		<title>ModbusClient</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=ModbusClient&amp;diff=1888"/>
		<updated>2026-06-20T15:59:45Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: /* The Main Window */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;Commander4j Modbus Client&#039;&#039;&#039; (&#039;&#039;util_modbusClient&#039;&#039;) is a desktop tool that acts as a [https://en.wikipedia.org/wiki/Modbus Modbus/TCP] client — a Modbus master. It connects to a remote Modbus server (a device, PLC, or the [[ModbusServer|Commander4j Modbus Server]]), continuously polls its four data tables across a chosen address window, and shows them in a single live grid. Coil and Holding Register values can be edited to drive the connected server. It is a test, troubleshooting and bench tool, and is the client-side companion to the [[ModbusServer|Commander4j Modbus Server]].&lt;br /&gt;
&lt;br /&gt;
== A Quick Modbus Primer ==&lt;br /&gt;
&lt;br /&gt;
If you are new to Modbus, the following terms are used throughout this page. Modbus is a simple, widely used industrial protocol for moving numeric and on/off values between automation equipment.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Master / Client&#039;&#039;&#039; — the device that initiates requests (reads and writes). This tool is a client.&lt;br /&gt;
* &#039;&#039;&#039;Slave / Server / Device&#039;&#039;&#039; — the device that holds the data and answers requests. The [[ModbusServer]] is a server.&lt;br /&gt;
* &#039;&#039;&#039;Unit ID&#039;&#039;&#039; (also &amp;quot;slave address&amp;quot;) — a number (0–247) identifying which device a request is for. A client must use the same unit ID the server is configured to answer as.&lt;br /&gt;
* &#039;&#039;&#039;Modbus/TCP&#039;&#039;&#039; — Modbus carried over an ordinary TCP/IP network connection, as opposed to serial (RTU) wiring. These tools speak Modbus/TCP only.&lt;br /&gt;
&lt;br /&gt;
Modbus organises all data into &#039;&#039;&#039;four tables&#039;&#039;&#039;, each addressed separately starting at zero:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Table !! Holds !! Size !! Can a client write it?&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Coils&#039;&#039;&#039; || On/off output bits || 1 bit || &#039;&#039;&#039;Yes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Discrete Inputs&#039;&#039;&#039; || On/off input bits || 1 bit || No — read-only&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Input Registers&#039;&#039;&#039; || Numeric inputs (readings) || 16 bits (0–65535) || No — read-only&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Holding Registers&#039;&#039;&#039; || Numeric settings / values || 16 bits (0–65535) || &#039;&#039;&#039;Yes&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The two &amp;quot;input&amp;quot; tables represent values a device &#039;&#039;produces&#039;&#039; (sensor states, measurements), so a client can only read them. Coils and holding registers represent values a client is allowed to &#039;&#039;set&#039;&#039;. Each table also has a conventional &#039;&#039;&#039;reference number&#039;&#039;&#039; that operators quote instead of the raw zero-based address: coils start at 1, discrete inputs at 10001, input registers at 30001 and holding registers at 40001.&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Client is useful when:&lt;br /&gt;
&lt;br /&gt;
* Reading the live coils and registers of a PLC or other Modbus device to confirm it is responding&lt;br /&gt;
* Writing a coil or holding register to command a device during commissioning or fault-finding&lt;br /&gt;
* Checking that a device is reachable on a given host, port and unit ID&lt;br /&gt;
* Driving the [[ModbusServer]] during testing, or reading values the server is staging&lt;br /&gt;
&lt;br /&gt;
== Source Code and Releases ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Client is open source and hosted on GitHub:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Repository:&#039;&#039;&#039; [https://github.com/C4J/ModbusClient https://github.com/C4J/ModbusClient]&lt;br /&gt;
* &#039;&#039;&#039;Releases (downloads):&#039;&#039;&#039; [https://github.com/C4J/ModbusClient/releases https://github.com/C4J/ModbusClient/releases]&lt;br /&gt;
&lt;br /&gt;
== Running the Modbus Client ==&lt;br /&gt;
&lt;br /&gt;
The recommended way to install the Modbus Client is to download a native installer for your platform, either from the [[Downloads]] page or from the [https://github.com/C4J/ModbusClient/releases GitHub releases page]. Native installers are provided for &#039;&#039;&#039;Windows, macOS and Linux&#039;&#039;&#039;. Each installer bundles its own Java 25 runtime, so &#039;&#039;&#039;no separate Java installation is required&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Installing creates a native &#039;&#039;&#039;ModbusClient&#039;&#039;&#039; launcher that you run like any other desktop application — from the Start menu, Applications folder, or desktop — which opens the window described below.&lt;br /&gt;
&lt;br /&gt;
=== Running from the jar ===&lt;br /&gt;
&lt;br /&gt;
Alternatively the tool can be run directly from its distribution folder as an ordinary Java 25 (Swing) application:&lt;br /&gt;
&lt;br /&gt;
 java -jar modbusClient.jar&lt;br /&gt;
&lt;br /&gt;
The supplied &amp;lt;code&amp;gt;start_modbusClient.sh&amp;lt;/code&amp;gt; (macOS/Linux) and &amp;lt;code&amp;gt;start_modbusClient.cmd&amp;lt;/code&amp;gt; (Windows) scripts launch it the same way. Run the jar from its own folder so the bundled &amp;lt;code&amp;gt;lib/&amp;lt;/code&amp;gt; dependencies are found alongside it.&lt;br /&gt;
&lt;br /&gt;
== The Main Window ==&lt;br /&gt;
&lt;br /&gt;
The window has three parts: a &#039;&#039;&#039;connection bar&#039;&#039;&#039; across the top, the &#039;&#039;&#039;register table&#039;&#039;&#039; in the centre with a vertical button toolbar down the right-hand side, and an &#039;&#039;&#039;activity log&#039;&#039;&#039; along the bottom.&lt;br /&gt;
&lt;br /&gt;
[[File:ModbusClient1.png|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Connection Bar ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Server host&#039;&#039;&#039; || The host name or IP address of the Modbus server to connect to. Defaults to &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; (this machine) for quick loopback testing against a local [[ModbusServer]].&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Port&#039;&#039;&#039; || The TCP port of the server. The Modbus standard is &#039;&#039;&#039;502&#039;&#039;&#039;; match whatever the server is listening on.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Unit ID&#039;&#039;&#039; || The unit / slave address to address requests to (0–247, default &#039;&#039;&#039;1&#039;&#039;&#039;). This must match the unit ID the server answers as, or every request will be rejected.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Status&#039;&#039;&#039; || Shows &#039;&#039;&#039;Disconnected&#039;&#039;&#039;, or &#039;&#039;&#039;Connected&#039;&#039;&#039; with the server address and unit ID in green.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Connect / Disconnect&#039;&#039;&#039; button (the toggle at the top of the right-hand toolbar) opens and closes the connection. The host, port and unit ID can only be changed while disconnected. Once connected, the client polls the server roughly four times a second and the grid updates live.&lt;br /&gt;
&lt;br /&gt;
=== Register Table ===&lt;br /&gt;
&lt;br /&gt;
A single grid shows one row per address, with every Modbus data table side by side and colour-coded:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Column group !! Contents !! Editable here&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Address&#039;&#039;&#039; || The zero-based Modbus protocol address (the same address for the whole row). || —&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Coil&#039;&#039;&#039; || Modbus reference (1…) and an on/off checkbox. || &#039;&#039;&#039;Yes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Discrete&#039;&#039;&#039; || Discrete input reference (10001…) and an on/off checkbox. || No (read-only)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Input&#039;&#039;&#039; || Input register reference (30001…), a decimal value and a read-only &#039;&#039;&#039;Hex&#039;&#039;&#039; view. || No (read-only)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Holding&#039;&#039;&#039; || Holding register reference (40001…), a decimal value (0–65535) and a read-only &#039;&#039;&#039;Hex&#039;&#039;&#039; view. || &#039;&#039;&#039;Yes&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Only the &#039;&#039;&#039;Coil&#039;&#039;&#039; and &#039;&#039;&#039;Holding Register&#039;&#039;&#039; value cells can be edited, and only while connected — because Modbus has no function code for a client to write the discrete-input and input-register tables. Editing a cell writes the new value straight through to the server; the displayed value updates immediately and is reverted if the server rejects the write.&lt;br /&gt;
&lt;br /&gt;
Below the table, the &#039;&#039;&#039;Start address&#039;&#039;&#039; and &#039;&#039;&#039;Count&#039;&#039;&#039; fields choose which window of addresses the client polls; click the tick button (Apply range) to apply them. Up to 2000 rows can be shown at once.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Zero registers&#039;&#039;&#039; button (eraser icon) on the toolbar opens a menu to clear the visible window of the writable tables — &#039;&#039;&#039;Zero Coils&#039;&#039;&#039;, &#039;&#039;&#039;Zero Holding Registers&#039;&#039;&#039;, or &#039;&#039;&#039;Zero All&#039;&#039;&#039; for both. Only the writable tables appear, because the read-only ones cannot be cleared by a client.&lt;br /&gt;
&lt;br /&gt;
=== Activity Log ===&lt;br /&gt;
&lt;br /&gt;
Connection events, writes, and any errors are written to the log at the bottom with a millisecond timestamp. The log keeps the most recent 400 lines. The two buttons beside it &#039;&#039;&#039;Save&#039;&#039;&#039; the log to a text file and &#039;&#039;&#039;Clear&#039;&#039;&#039; it. If the connection is lost (for example the server stops or the network drops), the client reports it in the log and returns to the disconnected state automatically.&lt;br /&gt;
&lt;br /&gt;
== Toolbar Buttons ==&lt;br /&gt;
&lt;br /&gt;
The vertical toolbar to the right of the register table provides, from top to bottom: &#039;&#039;&#039;Connect / Disconnect&#039;&#039;&#039;, &#039;&#039;&#039;Open settings&#039;&#039;&#039;, &#039;&#039;&#039;Save settings&#039;&#039;&#039;, &#039;&#039;&#039;Zero registers&#039;&#039;&#039;, &#039;&#039;&#039;About&#039;&#039;&#039;, &#039;&#039;&#039;Licences&#039;&#039;&#039;, &#039;&#039;&#039;Help&#039;&#039;&#039; (opens this wiki page) and &#039;&#039;&#039;Close&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
The connection settings (server host, port and unit ID) are stored in a small XML file, by default &amp;lt;code&amp;gt;xml/config/config.xml&amp;lt;/code&amp;gt; beneath the application folder:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;config&amp;gt;&lt;br /&gt;
   &amp;lt;ip&amp;gt;127.0.0.1&amp;lt;/ip&amp;gt;&lt;br /&gt;
   &amp;lt;port&amp;gt;502&amp;lt;/port&amp;gt;&lt;br /&gt;
   &amp;lt;id&amp;gt;1&amp;lt;/id&amp;gt;&lt;br /&gt;
 &amp;lt;/config&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The default settings are loaded automatically at start-up. Use the &#039;&#039;&#039;Open settings&#039;&#039;&#039; and &#039;&#039;&#039;Save settings&#039;&#039;&#039; toolbar buttons to load or store a configuration from any location. If you change the settings and then close the application, you are prompted to save the changes first.&lt;br /&gt;
&lt;br /&gt;
== Using the Client and Server Together ==&lt;br /&gt;
&lt;br /&gt;
The Modbus Client and the [[ModbusServer|Modbus Server]] are designed to be used as a pair to exercise a Modbus link from both ends without any real hardware:&lt;br /&gt;
&lt;br /&gt;
# Start the [[ModbusServer]] on one machine (or the same machine), choose a &#039;&#039;&#039;port&#039;&#039;&#039; and &#039;&#039;&#039;unit ID&#039;&#039;&#039;, and press &#039;&#039;&#039;Start&#039;&#039;&#039;.&lt;br /&gt;
# In the Modbus Client, set &#039;&#039;&#039;Server host&#039;&#039;&#039; to that machine (&amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; if both run on the same PC), set the matching &#039;&#039;&#039;port&#039;&#039;&#039; and &#039;&#039;&#039;unit ID&#039;&#039;&#039;, and press &#039;&#039;&#039;Connect&#039;&#039;&#039;.&lt;br /&gt;
# &#039;&#039;&#039;Client → Server:&#039;&#039;&#039; edit a Coil or Holding Register in the client; the value is written to the server and appears in the server&#039;s grid and activity log.&lt;br /&gt;
# &#039;&#039;&#039;Server → Client:&#039;&#039;&#039; edit any value in the server — including discrete inputs and input registers, which the client can only read; the client&#039;s grid reflects it on the next poll.&lt;br /&gt;
&lt;br /&gt;
This makes the pair a complete bench setup: the server stands in for a device so you can develop or test a Modbus master, and the client stands in for a master so you can stage and inspect a device&#039;s data. Either tool can also be pointed at real third-party Modbus/TCP equipment.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;quot;Connection refused&amp;quot; or a timeout on Connect&#039;&#039;&#039; — check the server host and port, that the server is running and listening, and that no firewall is blocking the connection.&lt;br /&gt;
* &#039;&#039;&#039;Connected, but every read fails or the connection drops immediately&#039;&#039;&#039; — the &#039;&#039;&#039;Unit ID&#039;&#039;&#039; probably does not match the server. The client must address the exact unit ID the server answers as.&lt;br /&gt;
* &#039;&#039;&#039;A startup warning about &amp;lt;code&amp;gt;sun.misc.Unsafe&amp;lt;/code&amp;gt;&#039;&#039;&#039; — harmless, and does not affect operation. The supplied start scripts suppress it; launching the jar directly may still print it.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[ModbusServer]] — the server-side companion tool&lt;br /&gt;
* [[AutoLab4j]] — uses the same Modbus stack to read Modbus printing triggers&lt;br /&gt;
* [[SocketTest]] — a raw TCP/IP testing utility&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=File:JMenuTree3.png&amp;diff=1887</id>
		<title>File:JMenuTree3.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=File:JMenuTree3.png&amp;diff=1887"/>
		<updated>2026-06-20T15:53:43Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=Menu4j&amp;diff=1886</id>
		<title>Menu4j</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=Menu4j&amp;diff=1886"/>
		<updated>2026-06-20T15:53:22Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: /* Settings */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Menu4j (JMenuTree) is a desktop command launcher that organises shell commands, scripts, and applications into a hierarchical tree menu. It provides a configurable, script-aware alternative to Finder shortcuts and shell aliases, with support for real-time terminal output, multiple linked menu trees, and optional startup password protection.&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
Menu4j is used to organise the day-to-day development and operational commands for the Commander4j suite in a single, structured interface. Menu items can run shell scripts, open applications, pass parameters, capture output, and link to other menu tree files.&lt;br /&gt;
&lt;br /&gt;
== Running Menu4j ==&lt;br /&gt;
&lt;br /&gt;
Native install packages for Windows, macOS, and Linux are available from the [[Downloads]] page and are the preferred installation method.&lt;br /&gt;
&lt;br /&gt;
Alternatively, Menu4j can be run directly from the distribution archive. It is a Java 25 desktop (Swing) application:&lt;br /&gt;
&lt;br /&gt;
 java -jar JMenu.jar&lt;br /&gt;
&lt;br /&gt;
On first launch, if no configuration file is found, Menu4j copies a template configuration from &amp;lt;code&amp;gt;xml/config/init/config.xml&amp;lt;/code&amp;gt; and a template menu tree from &amp;lt;code&amp;gt;xml/tree/init/tree.xml&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If a startup password has been configured, you are prompted to enter it before the menu is shown. Three failed attempts close the application.&lt;br /&gt;
&lt;br /&gt;
== The Menu Tree ==&lt;br /&gt;
&lt;br /&gt;
The main window displays a JTree. There are two node types:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| Branch || A folder that contains other branches or leaves&lt;br /&gt;
|-&lt;br /&gt;
| Leaf || An executable item — a command, script, or application&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Double-click a leaf to execute it. Double-click a branch to expand or collapse it.&lt;br /&gt;
&lt;br /&gt;
=== Adding and Editing Items ===&lt;br /&gt;
&lt;br /&gt;
The right sidebar toolbar provides:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Add&#039;&#039;&#039; — insert a new branch or leaf under the selected node&lt;br /&gt;
* &#039;&#039;&#039;Edit&#039;&#039;&#039; — open the editor for the selected node&lt;br /&gt;
* &#039;&#039;&#039;Delete&#039;&#039;&#039; — remove the selected node&lt;br /&gt;
* &#039;&#039;&#039;Duplicate&#039;&#039;&#039; — copy the selected node&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:JMenuTree1.png|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Leaf Properties ===&lt;br /&gt;
&lt;br /&gt;
When editing a leaf node, the following properties are available:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Property !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Description || The label shown in the menu tree&lt;br /&gt;
|-&lt;br /&gt;
| Directory || The working directory for the command&lt;br /&gt;
|-&lt;br /&gt;
| Command || The executable or system command to run&lt;br /&gt;
|-&lt;br /&gt;
| Parameters || A list of arguments to pass to the command&lt;br /&gt;
|-&lt;br /&gt;
| Shell Script Required || Whether to wrap the command in the configured shell wrapper script&lt;br /&gt;
|-&lt;br /&gt;
| Terminal Window Required || Whether to open a terminal output window to show command output&lt;br /&gt;
|-&lt;br /&gt;
| Confirm Execute || Whether to show a confirmation prompt before running&lt;br /&gt;
|-&lt;br /&gt;
| Link to Menu Tree || Whether this item opens a different tree file instead of running a command&lt;br /&gt;
|-&lt;br /&gt;
| Hint || A tooltip shown when hovering over the item&lt;br /&gt;
|-&lt;br /&gt;
| Icon || An image file to display next to the item label&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:JMenuTree2.png|600px]]&lt;br /&gt;
&lt;br /&gt;
== Executing Commands ==&lt;br /&gt;
&lt;br /&gt;
When a leaf is executed:&lt;br /&gt;
&lt;br /&gt;
# Menu4j validates that the directory and command exist&lt;br /&gt;
# If &#039;&#039;&#039;Shell Script Required&#039;&#039;&#039; is set, the command is wrapped using the script configured in Settings (typically a shell wrapper that sources the user&#039;s environment)&lt;br /&gt;
# If &#039;&#039;&#039;Terminal Window Required&#039;&#039;&#039; is set, a terminal output window opens and displays stdout and stderr in real time; otherwise the command runs silently in the background&lt;br /&gt;
# Environment variables configured in Settings are injected before execution&lt;br /&gt;
&lt;br /&gt;
=== Terminal Output Window ===&lt;br /&gt;
&lt;br /&gt;
The terminal window displays command output with configurable foreground and background colours and font (configured in Settings). A &#039;&#039;&#039;Respond&#039;&#039;&#039; button allows text to be sent to the command&#039;s standard input for interactive commands. When the command completes, the return code is displayed.&lt;br /&gt;
&lt;br /&gt;
== Multiple Tree Files ==&lt;br /&gt;
&lt;br /&gt;
A leaf node can be configured to switch to a different menu tree rather than execute a command. Set &#039;&#039;&#039;Link to Menu Tree&#039;&#039;&#039; and specify the filename. Double-clicking the leaf saves the current tree&#039;s expansion state and loads the linked tree. The application title bar updates to show the active tree filename.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
=== config.xml ===&lt;br /&gt;
&lt;br /&gt;
Located at &amp;lt;code&amp;gt;xml/config/config.xml&amp;lt;/code&amp;gt;. This file stores global settings including the active tree filename, shell script settings, colours, fonts, environment variables, system command whitelist, and the encrypted startup password.&lt;br /&gt;
&lt;br /&gt;
=== tree.xml ===&lt;br /&gt;
&lt;br /&gt;
Located at &amp;lt;code&amp;gt;xml/tree/tree.xml&amp;lt;/code&amp;gt; (or a different filename if you have switched trees). This is the menu structure file. It is written automatically when you save from the application.&lt;br /&gt;
&lt;br /&gt;
=== tree.xml.state ===&lt;br /&gt;
&lt;br /&gt;
Located alongside the tree file. Records which branches were expanded on the last exit and restores them on next launch.&lt;br /&gt;
&lt;br /&gt;
== Settings ==&lt;br /&gt;
&lt;br /&gt;
Open Settings from the toolbar to configure:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Setting !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Password || Optional startup password (stored AES-encrypted)&lt;br /&gt;
|-&lt;br /&gt;
| Shell script || Enable/disable the shell wrapper and set the script filename&lt;br /&gt;
|-&lt;br /&gt;
| Terminal colours || Foreground and background colours for the terminal output window&lt;br /&gt;
|-&lt;br /&gt;
| Tree colours || Foreground colours for leaf and branch labels&lt;br /&gt;
|-&lt;br /&gt;
| Fonts || Font choice and size for the terminal window, leaf labels, and branch labels&lt;br /&gt;
|-&lt;br /&gt;
| Environment variables || Key/value pairs injected into every executed process&lt;br /&gt;
|-&lt;br /&gt;
| System commands || Whitelist of system commands (such as &amp;lt;code&amp;gt;open&amp;lt;/code&amp;gt;) that do not require a file path to be validated&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:JMenuTree3.png|600px]]&lt;br /&gt;
&lt;br /&gt;
== Tree Navigation ==&lt;br /&gt;
&lt;br /&gt;
The top toolbar provides four buttons for expanding and collapsing the tree:&lt;br /&gt;
&lt;br /&gt;
* Expand All&lt;br /&gt;
* Expand Selected Branch&lt;br /&gt;
* Collapse Selected Branch&lt;br /&gt;
* Collapse All&lt;br /&gt;
&lt;br /&gt;
== Saving ==&lt;br /&gt;
&lt;br /&gt;
Changes to the tree structure are saved using the &#039;&#039;&#039;Save&#039;&#039;&#039; button in the sidebar toolbar. You are prompted to save if you close the application with unsaved changes.&lt;br /&gt;
&lt;br /&gt;
See also: [[LaunchPad]], [[Downloads]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=Menu4j&amp;diff=1885</id>
		<title>Menu4j</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=Menu4j&amp;diff=1885"/>
		<updated>2026-06-20T15:51:52Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: /* Adding and Editing Items */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Menu4j (JMenuTree) is a desktop command launcher that organises shell commands, scripts, and applications into a hierarchical tree menu. It provides a configurable, script-aware alternative to Finder shortcuts and shell aliases, with support for real-time terminal output, multiple linked menu trees, and optional startup password protection.&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
Menu4j is used to organise the day-to-day development and operational commands for the Commander4j suite in a single, structured interface. Menu items can run shell scripts, open applications, pass parameters, capture output, and link to other menu tree files.&lt;br /&gt;
&lt;br /&gt;
== Running Menu4j ==&lt;br /&gt;
&lt;br /&gt;
Native install packages for Windows, macOS, and Linux are available from the [[Downloads]] page and are the preferred installation method.&lt;br /&gt;
&lt;br /&gt;
Alternatively, Menu4j can be run directly from the distribution archive. It is a Java 25 desktop (Swing) application:&lt;br /&gt;
&lt;br /&gt;
 java -jar JMenu.jar&lt;br /&gt;
&lt;br /&gt;
On first launch, if no configuration file is found, Menu4j copies a template configuration from &amp;lt;code&amp;gt;xml/config/init/config.xml&amp;lt;/code&amp;gt; and a template menu tree from &amp;lt;code&amp;gt;xml/tree/init/tree.xml&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If a startup password has been configured, you are prompted to enter it before the menu is shown. Three failed attempts close the application.&lt;br /&gt;
&lt;br /&gt;
== The Menu Tree ==&lt;br /&gt;
&lt;br /&gt;
The main window displays a JTree. There are two node types:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| Branch || A folder that contains other branches or leaves&lt;br /&gt;
|-&lt;br /&gt;
| Leaf || An executable item — a command, script, or application&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Double-click a leaf to execute it. Double-click a branch to expand or collapse it.&lt;br /&gt;
&lt;br /&gt;
=== Adding and Editing Items ===&lt;br /&gt;
&lt;br /&gt;
The right sidebar toolbar provides:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Add&#039;&#039;&#039; — insert a new branch or leaf under the selected node&lt;br /&gt;
* &#039;&#039;&#039;Edit&#039;&#039;&#039; — open the editor for the selected node&lt;br /&gt;
* &#039;&#039;&#039;Delete&#039;&#039;&#039; — remove the selected node&lt;br /&gt;
* &#039;&#039;&#039;Duplicate&#039;&#039;&#039; — copy the selected node&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:JMenuTree1.png|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Leaf Properties ===&lt;br /&gt;
&lt;br /&gt;
When editing a leaf node, the following properties are available:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Property !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Description || The label shown in the menu tree&lt;br /&gt;
|-&lt;br /&gt;
| Directory || The working directory for the command&lt;br /&gt;
|-&lt;br /&gt;
| Command || The executable or system command to run&lt;br /&gt;
|-&lt;br /&gt;
| Parameters || A list of arguments to pass to the command&lt;br /&gt;
|-&lt;br /&gt;
| Shell Script Required || Whether to wrap the command in the configured shell wrapper script&lt;br /&gt;
|-&lt;br /&gt;
| Terminal Window Required || Whether to open a terminal output window to show command output&lt;br /&gt;
|-&lt;br /&gt;
| Confirm Execute || Whether to show a confirmation prompt before running&lt;br /&gt;
|-&lt;br /&gt;
| Link to Menu Tree || Whether this item opens a different tree file instead of running a command&lt;br /&gt;
|-&lt;br /&gt;
| Hint || A tooltip shown when hovering over the item&lt;br /&gt;
|-&lt;br /&gt;
| Icon || An image file to display next to the item label&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:JMenuTree2.png|600px]]&lt;br /&gt;
&lt;br /&gt;
== Executing Commands ==&lt;br /&gt;
&lt;br /&gt;
When a leaf is executed:&lt;br /&gt;
&lt;br /&gt;
# Menu4j validates that the directory and command exist&lt;br /&gt;
# If &#039;&#039;&#039;Shell Script Required&#039;&#039;&#039; is set, the command is wrapped using the script configured in Settings (typically a shell wrapper that sources the user&#039;s environment)&lt;br /&gt;
# If &#039;&#039;&#039;Terminal Window Required&#039;&#039;&#039; is set, a terminal output window opens and displays stdout and stderr in real time; otherwise the command runs silently in the background&lt;br /&gt;
# Environment variables configured in Settings are injected before execution&lt;br /&gt;
&lt;br /&gt;
=== Terminal Output Window ===&lt;br /&gt;
&lt;br /&gt;
The terminal window displays command output with configurable foreground and background colours and font (configured in Settings). A &#039;&#039;&#039;Respond&#039;&#039;&#039; button allows text to be sent to the command&#039;s standard input for interactive commands. When the command completes, the return code is displayed.&lt;br /&gt;
&lt;br /&gt;
== Multiple Tree Files ==&lt;br /&gt;
&lt;br /&gt;
A leaf node can be configured to switch to a different menu tree rather than execute a command. Set &#039;&#039;&#039;Link to Menu Tree&#039;&#039;&#039; and specify the filename. Double-clicking the leaf saves the current tree&#039;s expansion state and loads the linked tree. The application title bar updates to show the active tree filename.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
=== config.xml ===&lt;br /&gt;
&lt;br /&gt;
Located at &amp;lt;code&amp;gt;xml/config/config.xml&amp;lt;/code&amp;gt;. This file stores global settings including the active tree filename, shell script settings, colours, fonts, environment variables, system command whitelist, and the encrypted startup password.&lt;br /&gt;
&lt;br /&gt;
=== tree.xml ===&lt;br /&gt;
&lt;br /&gt;
Located at &amp;lt;code&amp;gt;xml/tree/tree.xml&amp;lt;/code&amp;gt; (or a different filename if you have switched trees). This is the menu structure file. It is written automatically when you save from the application.&lt;br /&gt;
&lt;br /&gt;
=== tree.xml.state ===&lt;br /&gt;
&lt;br /&gt;
Located alongside the tree file. Records which branches were expanded on the last exit and restores them on next launch.&lt;br /&gt;
&lt;br /&gt;
== Settings ==&lt;br /&gt;
&lt;br /&gt;
Open Settings from the toolbar to configure:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Setting !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Password || Optional startup password (stored AES-encrypted)&lt;br /&gt;
|-&lt;br /&gt;
| Shell script || Enable/disable the shell wrapper and set the script filename&lt;br /&gt;
|-&lt;br /&gt;
| Terminal colours || Foreground and background colours for the terminal output window&lt;br /&gt;
|-&lt;br /&gt;
| Tree colours || Foreground colours for leaf and branch labels&lt;br /&gt;
|-&lt;br /&gt;
| Fonts || Font choice and size for the terminal window, leaf labels, and branch labels&lt;br /&gt;
|-&lt;br /&gt;
| Environment variables || Key/value pairs injected into every executed process&lt;br /&gt;
|-&lt;br /&gt;
| System commands || Whitelist of system commands (such as &amp;lt;code&amp;gt;open&amp;lt;/code&amp;gt;) that do not require a file path to be validated&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tree Navigation ==&lt;br /&gt;
&lt;br /&gt;
The top toolbar provides four buttons for expanding and collapsing the tree:&lt;br /&gt;
&lt;br /&gt;
* Expand All&lt;br /&gt;
* Expand Selected Branch&lt;br /&gt;
* Collapse Selected Branch&lt;br /&gt;
* Collapse All&lt;br /&gt;
&lt;br /&gt;
== Saving ==&lt;br /&gt;
&lt;br /&gt;
Changes to the tree structure are saved using the &#039;&#039;&#039;Save&#039;&#039;&#039; button in the sidebar toolbar. You are prompted to save if you close the application with unsaved changes.&lt;br /&gt;
&lt;br /&gt;
See also: [[LaunchPad]], [[Downloads]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=Menu4j&amp;diff=1884</id>
		<title>Menu4j</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=Menu4j&amp;diff=1884"/>
		<updated>2026-06-20T15:50:56Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: /* Leaf Properties */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Menu4j (JMenuTree) is a desktop command launcher that organises shell commands, scripts, and applications into a hierarchical tree menu. It provides a configurable, script-aware alternative to Finder shortcuts and shell aliases, with support for real-time terminal output, multiple linked menu trees, and optional startup password protection.&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
Menu4j is used to organise the day-to-day development and operational commands for the Commander4j suite in a single, structured interface. Menu items can run shell scripts, open applications, pass parameters, capture output, and link to other menu tree files.&lt;br /&gt;
&lt;br /&gt;
== Running Menu4j ==&lt;br /&gt;
&lt;br /&gt;
Native install packages for Windows, macOS, and Linux are available from the [[Downloads]] page and are the preferred installation method.&lt;br /&gt;
&lt;br /&gt;
Alternatively, Menu4j can be run directly from the distribution archive. It is a Java 25 desktop (Swing) application:&lt;br /&gt;
&lt;br /&gt;
 java -jar JMenu.jar&lt;br /&gt;
&lt;br /&gt;
On first launch, if no configuration file is found, Menu4j copies a template configuration from &amp;lt;code&amp;gt;xml/config/init/config.xml&amp;lt;/code&amp;gt; and a template menu tree from &amp;lt;code&amp;gt;xml/tree/init/tree.xml&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If a startup password has been configured, you are prompted to enter it before the menu is shown. Three failed attempts close the application.&lt;br /&gt;
&lt;br /&gt;
== The Menu Tree ==&lt;br /&gt;
&lt;br /&gt;
The main window displays a JTree. There are two node types:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| Branch || A folder that contains other branches or leaves&lt;br /&gt;
|-&lt;br /&gt;
| Leaf || An executable item — a command, script, or application&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Double-click a leaf to execute it. Double-click a branch to expand or collapse it.&lt;br /&gt;
&lt;br /&gt;
=== Adding and Editing Items ===&lt;br /&gt;
&lt;br /&gt;
The right sidebar toolbar provides:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Add&#039;&#039;&#039; — insert a new branch or leaf under the selected node&lt;br /&gt;
* &#039;&#039;&#039;Edit&#039;&#039;&#039; — open the editor for the selected node&lt;br /&gt;
* &#039;&#039;&#039;Delete&#039;&#039;&#039; — remove the selected node&lt;br /&gt;
* &#039;&#039;&#039;Duplicate&#039;&#039;&#039; — copy the selected node&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:JMenuTree1.png|400px]]&lt;br /&gt;
&lt;br /&gt;
=== Leaf Properties ===&lt;br /&gt;
&lt;br /&gt;
When editing a leaf node, the following properties are available:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Property !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Description || The label shown in the menu tree&lt;br /&gt;
|-&lt;br /&gt;
| Directory || The working directory for the command&lt;br /&gt;
|-&lt;br /&gt;
| Command || The executable or system command to run&lt;br /&gt;
|-&lt;br /&gt;
| Parameters || A list of arguments to pass to the command&lt;br /&gt;
|-&lt;br /&gt;
| Shell Script Required || Whether to wrap the command in the configured shell wrapper script&lt;br /&gt;
|-&lt;br /&gt;
| Terminal Window Required || Whether to open a terminal output window to show command output&lt;br /&gt;
|-&lt;br /&gt;
| Confirm Execute || Whether to show a confirmation prompt before running&lt;br /&gt;
|-&lt;br /&gt;
| Link to Menu Tree || Whether this item opens a different tree file instead of running a command&lt;br /&gt;
|-&lt;br /&gt;
| Hint || A tooltip shown when hovering over the item&lt;br /&gt;
|-&lt;br /&gt;
| Icon || An image file to display next to the item label&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:JMenuTree2.png|600px]]&lt;br /&gt;
&lt;br /&gt;
== Executing Commands ==&lt;br /&gt;
&lt;br /&gt;
When a leaf is executed:&lt;br /&gt;
&lt;br /&gt;
# Menu4j validates that the directory and command exist&lt;br /&gt;
# If &#039;&#039;&#039;Shell Script Required&#039;&#039;&#039; is set, the command is wrapped using the script configured in Settings (typically a shell wrapper that sources the user&#039;s environment)&lt;br /&gt;
# If &#039;&#039;&#039;Terminal Window Required&#039;&#039;&#039; is set, a terminal output window opens and displays stdout and stderr in real time; otherwise the command runs silently in the background&lt;br /&gt;
# Environment variables configured in Settings are injected before execution&lt;br /&gt;
&lt;br /&gt;
=== Terminal Output Window ===&lt;br /&gt;
&lt;br /&gt;
The terminal window displays command output with configurable foreground and background colours and font (configured in Settings). A &#039;&#039;&#039;Respond&#039;&#039;&#039; button allows text to be sent to the command&#039;s standard input for interactive commands. When the command completes, the return code is displayed.&lt;br /&gt;
&lt;br /&gt;
== Multiple Tree Files ==&lt;br /&gt;
&lt;br /&gt;
A leaf node can be configured to switch to a different menu tree rather than execute a command. Set &#039;&#039;&#039;Link to Menu Tree&#039;&#039;&#039; and specify the filename. Double-clicking the leaf saves the current tree&#039;s expansion state and loads the linked tree. The application title bar updates to show the active tree filename.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
=== config.xml ===&lt;br /&gt;
&lt;br /&gt;
Located at &amp;lt;code&amp;gt;xml/config/config.xml&amp;lt;/code&amp;gt;. This file stores global settings including the active tree filename, shell script settings, colours, fonts, environment variables, system command whitelist, and the encrypted startup password.&lt;br /&gt;
&lt;br /&gt;
=== tree.xml ===&lt;br /&gt;
&lt;br /&gt;
Located at &amp;lt;code&amp;gt;xml/tree/tree.xml&amp;lt;/code&amp;gt; (or a different filename if you have switched trees). This is the menu structure file. It is written automatically when you save from the application.&lt;br /&gt;
&lt;br /&gt;
=== tree.xml.state ===&lt;br /&gt;
&lt;br /&gt;
Located alongside the tree file. Records which branches were expanded on the last exit and restores them on next launch.&lt;br /&gt;
&lt;br /&gt;
== Settings ==&lt;br /&gt;
&lt;br /&gt;
Open Settings from the toolbar to configure:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Setting !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Password || Optional startup password (stored AES-encrypted)&lt;br /&gt;
|-&lt;br /&gt;
| Shell script || Enable/disable the shell wrapper and set the script filename&lt;br /&gt;
|-&lt;br /&gt;
| Terminal colours || Foreground and background colours for the terminal output window&lt;br /&gt;
|-&lt;br /&gt;
| Tree colours || Foreground colours for leaf and branch labels&lt;br /&gt;
|-&lt;br /&gt;
| Fonts || Font choice and size for the terminal window, leaf labels, and branch labels&lt;br /&gt;
|-&lt;br /&gt;
| Environment variables || Key/value pairs injected into every executed process&lt;br /&gt;
|-&lt;br /&gt;
| System commands || Whitelist of system commands (such as &amp;lt;code&amp;gt;open&amp;lt;/code&amp;gt;) that do not require a file path to be validated&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tree Navigation ==&lt;br /&gt;
&lt;br /&gt;
The top toolbar provides four buttons for expanding and collapsing the tree:&lt;br /&gt;
&lt;br /&gt;
* Expand All&lt;br /&gt;
* Expand Selected Branch&lt;br /&gt;
* Collapse Selected Branch&lt;br /&gt;
* Collapse All&lt;br /&gt;
&lt;br /&gt;
== Saving ==&lt;br /&gt;
&lt;br /&gt;
Changes to the tree structure are saved using the &#039;&#039;&#039;Save&#039;&#039;&#039; button in the sidebar toolbar. You are prompted to save if you close the application with unsaved changes.&lt;br /&gt;
&lt;br /&gt;
See also: [[LaunchPad]], [[Downloads]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=File:JMenuTree2.png&amp;diff=1883</id>
		<title>File:JMenuTree2.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=File:JMenuTree2.png&amp;diff=1883"/>
		<updated>2026-06-20T15:50:36Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=Menu4j&amp;diff=1882</id>
		<title>Menu4j</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=Menu4j&amp;diff=1882"/>
		<updated>2026-06-20T15:50:10Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: /* Leaf Properties */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Menu4j (JMenuTree) is a desktop command launcher that organises shell commands, scripts, and applications into a hierarchical tree menu. It provides a configurable, script-aware alternative to Finder shortcuts and shell aliases, with support for real-time terminal output, multiple linked menu trees, and optional startup password protection.&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
Menu4j is used to organise the day-to-day development and operational commands for the Commander4j suite in a single, structured interface. Menu items can run shell scripts, open applications, pass parameters, capture output, and link to other menu tree files.&lt;br /&gt;
&lt;br /&gt;
== Running Menu4j ==&lt;br /&gt;
&lt;br /&gt;
Native install packages for Windows, macOS, and Linux are available from the [[Downloads]] page and are the preferred installation method.&lt;br /&gt;
&lt;br /&gt;
Alternatively, Menu4j can be run directly from the distribution archive. It is a Java 25 desktop (Swing) application:&lt;br /&gt;
&lt;br /&gt;
 java -jar JMenu.jar&lt;br /&gt;
&lt;br /&gt;
On first launch, if no configuration file is found, Menu4j copies a template configuration from &amp;lt;code&amp;gt;xml/config/init/config.xml&amp;lt;/code&amp;gt; and a template menu tree from &amp;lt;code&amp;gt;xml/tree/init/tree.xml&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If a startup password has been configured, you are prompted to enter it before the menu is shown. Three failed attempts close the application.&lt;br /&gt;
&lt;br /&gt;
== The Menu Tree ==&lt;br /&gt;
&lt;br /&gt;
The main window displays a JTree. There are two node types:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| Branch || A folder that contains other branches or leaves&lt;br /&gt;
|-&lt;br /&gt;
| Leaf || An executable item — a command, script, or application&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Double-click a leaf to execute it. Double-click a branch to expand or collapse it.&lt;br /&gt;
&lt;br /&gt;
=== Adding and Editing Items ===&lt;br /&gt;
&lt;br /&gt;
The right sidebar toolbar provides:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Add&#039;&#039;&#039; — insert a new branch or leaf under the selected node&lt;br /&gt;
* &#039;&#039;&#039;Edit&#039;&#039;&#039; — open the editor for the selected node&lt;br /&gt;
* &#039;&#039;&#039;Delete&#039;&#039;&#039; — remove the selected node&lt;br /&gt;
* &#039;&#039;&#039;Duplicate&#039;&#039;&#039; — copy the selected node&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:JMenuTree1.png|400px]]&lt;br /&gt;
&lt;br /&gt;
=== Leaf Properties ===&lt;br /&gt;
&lt;br /&gt;
When editing a leaf node, the following properties are available:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Property !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Description || The label shown in the menu tree&lt;br /&gt;
|-&lt;br /&gt;
| Directory || The working directory for the command&lt;br /&gt;
|-&lt;br /&gt;
| Command || The executable or system command to run&lt;br /&gt;
|-&lt;br /&gt;
| Parameters || A list of arguments to pass to the command&lt;br /&gt;
|-&lt;br /&gt;
| Shell Script Required || Whether to wrap the command in the configured shell wrapper script&lt;br /&gt;
|-&lt;br /&gt;
| Terminal Window Required || Whether to open a terminal output window to show command output&lt;br /&gt;
|-&lt;br /&gt;
| Confirm Execute || Whether to show a confirmation prompt before running&lt;br /&gt;
|-&lt;br /&gt;
| Link to Menu Tree || Whether this item opens a different tree file instead of running a command&lt;br /&gt;
|-&lt;br /&gt;
| Hint || A tooltip shown when hovering over the item&lt;br /&gt;
|-&lt;br /&gt;
| Icon || An image file to display next to the item label&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:JMenuTree2.png|400px]]&lt;br /&gt;
&lt;br /&gt;
== Executing Commands ==&lt;br /&gt;
&lt;br /&gt;
When a leaf is executed:&lt;br /&gt;
&lt;br /&gt;
# Menu4j validates that the directory and command exist&lt;br /&gt;
# If &#039;&#039;&#039;Shell Script Required&#039;&#039;&#039; is set, the command is wrapped using the script configured in Settings (typically a shell wrapper that sources the user&#039;s environment)&lt;br /&gt;
# If &#039;&#039;&#039;Terminal Window Required&#039;&#039;&#039; is set, a terminal output window opens and displays stdout and stderr in real time; otherwise the command runs silently in the background&lt;br /&gt;
# Environment variables configured in Settings are injected before execution&lt;br /&gt;
&lt;br /&gt;
=== Terminal Output Window ===&lt;br /&gt;
&lt;br /&gt;
The terminal window displays command output with configurable foreground and background colours and font (configured in Settings). A &#039;&#039;&#039;Respond&#039;&#039;&#039; button allows text to be sent to the command&#039;s standard input for interactive commands. When the command completes, the return code is displayed.&lt;br /&gt;
&lt;br /&gt;
== Multiple Tree Files ==&lt;br /&gt;
&lt;br /&gt;
A leaf node can be configured to switch to a different menu tree rather than execute a command. Set &#039;&#039;&#039;Link to Menu Tree&#039;&#039;&#039; and specify the filename. Double-clicking the leaf saves the current tree&#039;s expansion state and loads the linked tree. The application title bar updates to show the active tree filename.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
=== config.xml ===&lt;br /&gt;
&lt;br /&gt;
Located at &amp;lt;code&amp;gt;xml/config/config.xml&amp;lt;/code&amp;gt;. This file stores global settings including the active tree filename, shell script settings, colours, fonts, environment variables, system command whitelist, and the encrypted startup password.&lt;br /&gt;
&lt;br /&gt;
=== tree.xml ===&lt;br /&gt;
&lt;br /&gt;
Located at &amp;lt;code&amp;gt;xml/tree/tree.xml&amp;lt;/code&amp;gt; (or a different filename if you have switched trees). This is the menu structure file. It is written automatically when you save from the application.&lt;br /&gt;
&lt;br /&gt;
=== tree.xml.state ===&lt;br /&gt;
&lt;br /&gt;
Located alongside the tree file. Records which branches were expanded on the last exit and restores them on next launch.&lt;br /&gt;
&lt;br /&gt;
== Settings ==&lt;br /&gt;
&lt;br /&gt;
Open Settings from the toolbar to configure:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Setting !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Password || Optional startup password (stored AES-encrypted)&lt;br /&gt;
|-&lt;br /&gt;
| Shell script || Enable/disable the shell wrapper and set the script filename&lt;br /&gt;
|-&lt;br /&gt;
| Terminal colours || Foreground and background colours for the terminal output window&lt;br /&gt;
|-&lt;br /&gt;
| Tree colours || Foreground colours for leaf and branch labels&lt;br /&gt;
|-&lt;br /&gt;
| Fonts || Font choice and size for the terminal window, leaf labels, and branch labels&lt;br /&gt;
|-&lt;br /&gt;
| Environment variables || Key/value pairs injected into every executed process&lt;br /&gt;
|-&lt;br /&gt;
| System commands || Whitelist of system commands (such as &amp;lt;code&amp;gt;open&amp;lt;/code&amp;gt;) that do not require a file path to be validated&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tree Navigation ==&lt;br /&gt;
&lt;br /&gt;
The top toolbar provides four buttons for expanding and collapsing the tree:&lt;br /&gt;
&lt;br /&gt;
* Expand All&lt;br /&gt;
* Expand Selected Branch&lt;br /&gt;
* Collapse Selected Branch&lt;br /&gt;
* Collapse All&lt;br /&gt;
&lt;br /&gt;
== Saving ==&lt;br /&gt;
&lt;br /&gt;
Changes to the tree structure are saved using the &#039;&#039;&#039;Save&#039;&#039;&#039; button in the sidebar toolbar. You are prompted to save if you close the application with unsaved changes.&lt;br /&gt;
&lt;br /&gt;
See also: [[LaunchPad]], [[Downloads]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=Menu4j&amp;diff=1881</id>
		<title>Menu4j</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=Menu4j&amp;diff=1881"/>
		<updated>2026-06-20T15:49:10Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: /* Adding and Editing Items */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Menu4j (JMenuTree) is a desktop command launcher that organises shell commands, scripts, and applications into a hierarchical tree menu. It provides a configurable, script-aware alternative to Finder shortcuts and shell aliases, with support for real-time terminal output, multiple linked menu trees, and optional startup password protection.&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
Menu4j is used to organise the day-to-day development and operational commands for the Commander4j suite in a single, structured interface. Menu items can run shell scripts, open applications, pass parameters, capture output, and link to other menu tree files.&lt;br /&gt;
&lt;br /&gt;
== Running Menu4j ==&lt;br /&gt;
&lt;br /&gt;
Native install packages for Windows, macOS, and Linux are available from the [[Downloads]] page and are the preferred installation method.&lt;br /&gt;
&lt;br /&gt;
Alternatively, Menu4j can be run directly from the distribution archive. It is a Java 25 desktop (Swing) application:&lt;br /&gt;
&lt;br /&gt;
 java -jar JMenu.jar&lt;br /&gt;
&lt;br /&gt;
On first launch, if no configuration file is found, Menu4j copies a template configuration from &amp;lt;code&amp;gt;xml/config/init/config.xml&amp;lt;/code&amp;gt; and a template menu tree from &amp;lt;code&amp;gt;xml/tree/init/tree.xml&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If a startup password has been configured, you are prompted to enter it before the menu is shown. Three failed attempts close the application.&lt;br /&gt;
&lt;br /&gt;
== The Menu Tree ==&lt;br /&gt;
&lt;br /&gt;
The main window displays a JTree. There are two node types:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| Branch || A folder that contains other branches or leaves&lt;br /&gt;
|-&lt;br /&gt;
| Leaf || An executable item — a command, script, or application&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Double-click a leaf to execute it. Double-click a branch to expand or collapse it.&lt;br /&gt;
&lt;br /&gt;
=== Adding and Editing Items ===&lt;br /&gt;
&lt;br /&gt;
The right sidebar toolbar provides:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Add&#039;&#039;&#039; — insert a new branch or leaf under the selected node&lt;br /&gt;
* &#039;&#039;&#039;Edit&#039;&#039;&#039; — open the editor for the selected node&lt;br /&gt;
* &#039;&#039;&#039;Delete&#039;&#039;&#039; — remove the selected node&lt;br /&gt;
* &#039;&#039;&#039;Duplicate&#039;&#039;&#039; — copy the selected node&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:JMenuTree1.png|400px]]&lt;br /&gt;
&lt;br /&gt;
=== Leaf Properties ===&lt;br /&gt;
&lt;br /&gt;
When editing a leaf node, the following properties are available:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Property !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Description || The label shown in the menu tree&lt;br /&gt;
|-&lt;br /&gt;
| Directory || The working directory for the command&lt;br /&gt;
|-&lt;br /&gt;
| Command || The executable or system command to run&lt;br /&gt;
|-&lt;br /&gt;
| Parameters || A list of arguments to pass to the command&lt;br /&gt;
|-&lt;br /&gt;
| Shell Script Required || Whether to wrap the command in the configured shell wrapper script&lt;br /&gt;
|-&lt;br /&gt;
| Terminal Window Required || Whether to open a terminal output window to show command output&lt;br /&gt;
|-&lt;br /&gt;
| Confirm Execute || Whether to show a confirmation prompt before running&lt;br /&gt;
|-&lt;br /&gt;
| Link to Menu Tree || Whether this item opens a different tree file instead of running a command&lt;br /&gt;
|-&lt;br /&gt;
| Hint || A tooltip shown when hovering over the item&lt;br /&gt;
|-&lt;br /&gt;
| Icon || An image file to display next to the item label&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Executing Commands ==&lt;br /&gt;
&lt;br /&gt;
When a leaf is executed:&lt;br /&gt;
&lt;br /&gt;
# Menu4j validates that the directory and command exist&lt;br /&gt;
# If &#039;&#039;&#039;Shell Script Required&#039;&#039;&#039; is set, the command is wrapped using the script configured in Settings (typically a shell wrapper that sources the user&#039;s environment)&lt;br /&gt;
# If &#039;&#039;&#039;Terminal Window Required&#039;&#039;&#039; is set, a terminal output window opens and displays stdout and stderr in real time; otherwise the command runs silently in the background&lt;br /&gt;
# Environment variables configured in Settings are injected before execution&lt;br /&gt;
&lt;br /&gt;
=== Terminal Output Window ===&lt;br /&gt;
&lt;br /&gt;
The terminal window displays command output with configurable foreground and background colours and font (configured in Settings). A &#039;&#039;&#039;Respond&#039;&#039;&#039; button allows text to be sent to the command&#039;s standard input for interactive commands. When the command completes, the return code is displayed.&lt;br /&gt;
&lt;br /&gt;
== Multiple Tree Files ==&lt;br /&gt;
&lt;br /&gt;
A leaf node can be configured to switch to a different menu tree rather than execute a command. Set &#039;&#039;&#039;Link to Menu Tree&#039;&#039;&#039; and specify the filename. Double-clicking the leaf saves the current tree&#039;s expansion state and loads the linked tree. The application title bar updates to show the active tree filename.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
=== config.xml ===&lt;br /&gt;
&lt;br /&gt;
Located at &amp;lt;code&amp;gt;xml/config/config.xml&amp;lt;/code&amp;gt;. This file stores global settings including the active tree filename, shell script settings, colours, fonts, environment variables, system command whitelist, and the encrypted startup password.&lt;br /&gt;
&lt;br /&gt;
=== tree.xml ===&lt;br /&gt;
&lt;br /&gt;
Located at &amp;lt;code&amp;gt;xml/tree/tree.xml&amp;lt;/code&amp;gt; (or a different filename if you have switched trees). This is the menu structure file. It is written automatically when you save from the application.&lt;br /&gt;
&lt;br /&gt;
=== tree.xml.state ===&lt;br /&gt;
&lt;br /&gt;
Located alongside the tree file. Records which branches were expanded on the last exit and restores them on next launch.&lt;br /&gt;
&lt;br /&gt;
== Settings ==&lt;br /&gt;
&lt;br /&gt;
Open Settings from the toolbar to configure:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Setting !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Password || Optional startup password (stored AES-encrypted)&lt;br /&gt;
|-&lt;br /&gt;
| Shell script || Enable/disable the shell wrapper and set the script filename&lt;br /&gt;
|-&lt;br /&gt;
| Terminal colours || Foreground and background colours for the terminal output window&lt;br /&gt;
|-&lt;br /&gt;
| Tree colours || Foreground colours for leaf and branch labels&lt;br /&gt;
|-&lt;br /&gt;
| Fonts || Font choice and size for the terminal window, leaf labels, and branch labels&lt;br /&gt;
|-&lt;br /&gt;
| Environment variables || Key/value pairs injected into every executed process&lt;br /&gt;
|-&lt;br /&gt;
| System commands || Whitelist of system commands (such as &amp;lt;code&amp;gt;open&amp;lt;/code&amp;gt;) that do not require a file path to be validated&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tree Navigation ==&lt;br /&gt;
&lt;br /&gt;
The top toolbar provides four buttons for expanding and collapsing the tree:&lt;br /&gt;
&lt;br /&gt;
* Expand All&lt;br /&gt;
* Expand Selected Branch&lt;br /&gt;
* Collapse Selected Branch&lt;br /&gt;
* Collapse All&lt;br /&gt;
&lt;br /&gt;
== Saving ==&lt;br /&gt;
&lt;br /&gt;
Changes to the tree structure are saved using the &#039;&#039;&#039;Save&#039;&#039;&#039; button in the sidebar toolbar. You are prompted to save if you close the application with unsaved changes.&lt;br /&gt;
&lt;br /&gt;
See also: [[LaunchPad]], [[Downloads]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=File:JMenuTree1.png&amp;diff=1880</id>
		<title>File:JMenuTree1.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=File:JMenuTree1.png&amp;diff=1880"/>
		<updated>2026-06-20T15:48:44Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=Menu4j&amp;diff=1879</id>
		<title>Menu4j</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=Menu4j&amp;diff=1879"/>
		<updated>2026-06-20T15:48:29Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: /* Adding and Editing Items */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Menu4j (JMenuTree) is a desktop command launcher that organises shell commands, scripts, and applications into a hierarchical tree menu. It provides a configurable, script-aware alternative to Finder shortcuts and shell aliases, with support for real-time terminal output, multiple linked menu trees, and optional startup password protection.&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
Menu4j is used to organise the day-to-day development and operational commands for the Commander4j suite in a single, structured interface. Menu items can run shell scripts, open applications, pass parameters, capture output, and link to other menu tree files.&lt;br /&gt;
&lt;br /&gt;
== Running Menu4j ==&lt;br /&gt;
&lt;br /&gt;
Native install packages for Windows, macOS, and Linux are available from the [[Downloads]] page and are the preferred installation method.&lt;br /&gt;
&lt;br /&gt;
Alternatively, Menu4j can be run directly from the distribution archive. It is a Java 25 desktop (Swing) application:&lt;br /&gt;
&lt;br /&gt;
 java -jar JMenu.jar&lt;br /&gt;
&lt;br /&gt;
On first launch, if no configuration file is found, Menu4j copies a template configuration from &amp;lt;code&amp;gt;xml/config/init/config.xml&amp;lt;/code&amp;gt; and a template menu tree from &amp;lt;code&amp;gt;xml/tree/init/tree.xml&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If a startup password has been configured, you are prompted to enter it before the menu is shown. Three failed attempts close the application.&lt;br /&gt;
&lt;br /&gt;
== The Menu Tree ==&lt;br /&gt;
&lt;br /&gt;
The main window displays a JTree. There are two node types:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| Branch || A folder that contains other branches or leaves&lt;br /&gt;
|-&lt;br /&gt;
| Leaf || An executable item — a command, script, or application&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Double-click a leaf to execute it. Double-click a branch to expand or collapse it.&lt;br /&gt;
&lt;br /&gt;
=== Adding and Editing Items ===&lt;br /&gt;
&lt;br /&gt;
The right sidebar toolbar provides:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Add&#039;&#039;&#039; — insert a new branch or leaf under the selected node&lt;br /&gt;
* &#039;&#039;&#039;Edit&#039;&#039;&#039; — open the editor for the selected node&lt;br /&gt;
* &#039;&#039;&#039;Delete&#039;&#039;&#039; — remove the selected node&lt;br /&gt;
* &#039;&#039;&#039;Duplicate&#039;&#039;&#039; — copy the selected node&lt;br /&gt;
&lt;br /&gt;
[[File:JMenuTree1.png|400px]]&lt;br /&gt;
&lt;br /&gt;
=== Leaf Properties ===&lt;br /&gt;
&lt;br /&gt;
When editing a leaf node, the following properties are available:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Property !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Description || The label shown in the menu tree&lt;br /&gt;
|-&lt;br /&gt;
| Directory || The working directory for the command&lt;br /&gt;
|-&lt;br /&gt;
| Command || The executable or system command to run&lt;br /&gt;
|-&lt;br /&gt;
| Parameters || A list of arguments to pass to the command&lt;br /&gt;
|-&lt;br /&gt;
| Shell Script Required || Whether to wrap the command in the configured shell wrapper script&lt;br /&gt;
|-&lt;br /&gt;
| Terminal Window Required || Whether to open a terminal output window to show command output&lt;br /&gt;
|-&lt;br /&gt;
| Confirm Execute || Whether to show a confirmation prompt before running&lt;br /&gt;
|-&lt;br /&gt;
| Link to Menu Tree || Whether this item opens a different tree file instead of running a command&lt;br /&gt;
|-&lt;br /&gt;
| Hint || A tooltip shown when hovering over the item&lt;br /&gt;
|-&lt;br /&gt;
| Icon || An image file to display next to the item label&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Executing Commands ==&lt;br /&gt;
&lt;br /&gt;
When a leaf is executed:&lt;br /&gt;
&lt;br /&gt;
# Menu4j validates that the directory and command exist&lt;br /&gt;
# If &#039;&#039;&#039;Shell Script Required&#039;&#039;&#039; is set, the command is wrapped using the script configured in Settings (typically a shell wrapper that sources the user&#039;s environment)&lt;br /&gt;
# If &#039;&#039;&#039;Terminal Window Required&#039;&#039;&#039; is set, a terminal output window opens and displays stdout and stderr in real time; otherwise the command runs silently in the background&lt;br /&gt;
# Environment variables configured in Settings are injected before execution&lt;br /&gt;
&lt;br /&gt;
=== Terminal Output Window ===&lt;br /&gt;
&lt;br /&gt;
The terminal window displays command output with configurable foreground and background colours and font (configured in Settings). A &#039;&#039;&#039;Respond&#039;&#039;&#039; button allows text to be sent to the command&#039;s standard input for interactive commands. When the command completes, the return code is displayed.&lt;br /&gt;
&lt;br /&gt;
== Multiple Tree Files ==&lt;br /&gt;
&lt;br /&gt;
A leaf node can be configured to switch to a different menu tree rather than execute a command. Set &#039;&#039;&#039;Link to Menu Tree&#039;&#039;&#039; and specify the filename. Double-clicking the leaf saves the current tree&#039;s expansion state and loads the linked tree. The application title bar updates to show the active tree filename.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
=== config.xml ===&lt;br /&gt;
&lt;br /&gt;
Located at &amp;lt;code&amp;gt;xml/config/config.xml&amp;lt;/code&amp;gt;. This file stores global settings including the active tree filename, shell script settings, colours, fonts, environment variables, system command whitelist, and the encrypted startup password.&lt;br /&gt;
&lt;br /&gt;
=== tree.xml ===&lt;br /&gt;
&lt;br /&gt;
Located at &amp;lt;code&amp;gt;xml/tree/tree.xml&amp;lt;/code&amp;gt; (or a different filename if you have switched trees). This is the menu structure file. It is written automatically when you save from the application.&lt;br /&gt;
&lt;br /&gt;
=== tree.xml.state ===&lt;br /&gt;
&lt;br /&gt;
Located alongside the tree file. Records which branches were expanded on the last exit and restores them on next launch.&lt;br /&gt;
&lt;br /&gt;
== Settings ==&lt;br /&gt;
&lt;br /&gt;
Open Settings from the toolbar to configure:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Setting !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Password || Optional startup password (stored AES-encrypted)&lt;br /&gt;
|-&lt;br /&gt;
| Shell script || Enable/disable the shell wrapper and set the script filename&lt;br /&gt;
|-&lt;br /&gt;
| Terminal colours || Foreground and background colours for the terminal output window&lt;br /&gt;
|-&lt;br /&gt;
| Tree colours || Foreground colours for leaf and branch labels&lt;br /&gt;
|-&lt;br /&gt;
| Fonts || Font choice and size for the terminal window, leaf labels, and branch labels&lt;br /&gt;
|-&lt;br /&gt;
| Environment variables || Key/value pairs injected into every executed process&lt;br /&gt;
|-&lt;br /&gt;
| System commands || Whitelist of system commands (such as &amp;lt;code&amp;gt;open&amp;lt;/code&amp;gt;) that do not require a file path to be validated&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tree Navigation ==&lt;br /&gt;
&lt;br /&gt;
The top toolbar provides four buttons for expanding and collapsing the tree:&lt;br /&gt;
&lt;br /&gt;
* Expand All&lt;br /&gt;
* Expand Selected Branch&lt;br /&gt;
* Collapse Selected Branch&lt;br /&gt;
* Collapse All&lt;br /&gt;
&lt;br /&gt;
== Saving ==&lt;br /&gt;
&lt;br /&gt;
Changes to the tree structure are saved using the &#039;&#039;&#039;Save&#039;&#039;&#039; button in the sidebar toolbar. You are prompted to save if you close the application with unsaved changes.&lt;br /&gt;
&lt;br /&gt;
See also: [[LaunchPad]], [[Downloads]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=LogoClient&amp;diff=1878</id>
		<title>LogoClient</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=LogoClient&amp;diff=1878"/>
		<updated>2026-06-13T19:43:05Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: Updated by push_wiki.py&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;LogoClient&#039;&#039;&#039; (&#039;&#039;c4j_logoclient&#039;&#039;) is a standalone desktop application — and underlying client library — for communicating with [[Logopak]] PowerLeap label printers over the network. It connects to a labeller, transfers layout and data files to and from it, sends commands and field data, browses the printer&#039;s on-board storage and retrieves its logs. It exists so that the software-to-labeller conversation can be developed, exercised and diagnosed &#039;&#039;&#039;on an ordinary PC, in environments where no physical Logopak labeller is available&#039;&#039;&#039; to test against.&lt;br /&gt;
&lt;br /&gt;
It is the client half of a pair: where a real labeller is not to hand, [[LogoRenderer]] can emulate one, and LogoClient talks to that emulator exactly as it would talk to real hardware. Together they let you exercise the whole label-printing workflow with no hardware at all.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Disclaimer: LogoClient is an independent open-source tool and is &#039;&#039;&#039;not&#039;&#039;&#039; a Logopak product. It is not affiliated with, endorsed by, or supported by Logopak. Logopak, PowerLeap and related names are trademarks of their respective owners and are used solely to describe interoperability. The software is intended for local test and development use only — it must not be relied upon for production label printing.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
Software from Logopak DE drives labellers in production. When developing or supporting that software it is useful to be able to perform the same low-level operations by hand, and to see exactly what goes across the wire. LogoClient is that tool. It is useful when:&lt;br /&gt;
&lt;br /&gt;
* You need to &#039;&#039;&#039;send a layout or data file to a labeller&#039;&#039;&#039; and confirm it loads correctly.&lt;br /&gt;
* You want to &#039;&#039;&#039;browse, upload, download or delete files&#039;&#039;&#039; on the printer&#039;s on-board drives.&lt;br /&gt;
* You are &#039;&#039;&#039;debugging the protocol&#039;&#039;&#039; and want a live, byte-level trace of everything sent and received.&lt;br /&gt;
* You need to &#039;&#039;&#039;send raw commands or field data&#039;&#039;&#039; to a labeller and read its replies.&lt;br /&gt;
* You want to &#039;&#039;&#039;poll a labeller&#039;s pallet log&#039;&#039;&#039; and capture one file per SSCC as labels are applied.&lt;br /&gt;
* You want to &#039;&#039;&#039;develop without a physical Logopak&#039;&#039;&#039; by pointing LogoClient at the [[LogoRenderer]] printer emulator instead of real hardware.&lt;br /&gt;
&lt;br /&gt;
== Supported Printers and Protocols ==&lt;br /&gt;
&lt;br /&gt;
LogoClient supports both current Logopak controller generations:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Mode !! Hardware !! Transport&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;PL3 (TCP)&#039;&#039;&#039; || PowerLeap III || Direct TCP socket on the data ports (8000 / 8100 / 8200 / 8300). Carries the full LEAP, LAMA/LACE and LSP command set — layout activation, field data, firmware queries, file management, I/O monitoring and asynchronous reporting.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;PL6 (SFTP)&#039;&#039;&#039; || PowerLeap 6 || File transfer over SFTP (port 22). PL6 is driven by exchanging files rather than TCP commands, so this mode is focused on uploading, downloading and listing files and reading the pallet log.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Source Code and Releases ==&lt;br /&gt;
&lt;br /&gt;
LogoClient is part of the open-source Commander4j suite and is distributed under the GNU General Public License. The source code and release downloads are hosted on GitHub, and native install packages for every platform are listed on the Commander4j [[Downloads]] page.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Repository:&#039;&#039;&#039; [https://github.com/C4J/LogoClient https://github.com/C4J/LogoClient]&lt;br /&gt;
* &#039;&#039;&#039;Releases (download media):&#039;&#039;&#039; [https://github.com/C4J/LogoClient/releases https://github.com/C4J/LogoClient/releases]&lt;br /&gt;
* &#039;&#039;&#039;All Commander4j downloads:&#039;&#039;&#039; [[Downloads]]&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
Native install packages for &#039;&#039;&#039;Windows, macOS and Linux&#039;&#039;&#039; are available from the [[Downloads]] page and are the preferred installation method. Each installer bundles its own Java runtime, so &#039;&#039;&#039;no separate Java installation is required&#039;&#039;&#039;. Installing creates a native &#039;&#039;&#039;LogoClient&#039;&#039;&#039; launcher that can be started like any other desktop application.&lt;br /&gt;
&lt;br /&gt;
=== Running from the jar ===&lt;br /&gt;
&lt;br /&gt;
Alternatively the tool can be run directly as an ordinary Java (Swing) application:&lt;br /&gt;
&lt;br /&gt;
 java -jar c4j_logoclient.jar&lt;br /&gt;
&lt;br /&gt;
Running the jar requires a recent Java runtime (Java 21 or later). The bundled JSch library is required only for PL6 (SFTP); PL3 (TCP) has no external dependencies.&lt;br /&gt;
&lt;br /&gt;
== The Main Window ==&lt;br /&gt;
&lt;br /&gt;
The window has a &#039;&#039;&#039;connection bar&#039;&#039;&#039; across the top, a central &#039;&#039;&#039;file-transfer and directory area&#039;&#039;&#039;, a &#039;&#039;&#039;message pane&#039;&#039;&#039; for composing raw commands, and a pair of log panes along the bottom — an &#039;&#039;&#039;activity log&#039;&#039;&#039; and a &#039;&#039;&#039;wire trace&#039;&#039;&#039;. All transfer and command actions are disabled until a connection is open.&lt;br /&gt;
&lt;br /&gt;
=== Connecting ===&lt;br /&gt;
&lt;br /&gt;
In the connection bar you choose the connection &#039;&#039;&#039;Type&#039;&#039;&#039; (PL3 TCP or PL6 SFTP), enter the labeller&#039;s &#039;&#039;&#039;host / IP address&#039;&#039;&#039; and &#039;&#039;&#039;port&#039;&#039;&#039;, and — for PL6 — a &#039;&#039;&#039;username and password&#039;&#039;&#039;. Pressing the connect button opens the link; a status indicator shows the connected host and port. For example, the [[LogoRenderer]] emulator running on the same PC is reached at &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Options in the connection area let you list the remote directory automatically on connect, send a periodic &#039;&#039;&#039;heartbeat&#039;&#039;&#039; to detect a dropped link, and set the socket read timeout.&lt;br /&gt;
&lt;br /&gt;
=== Transferring and Managing Files ===&lt;br /&gt;
&lt;br /&gt;
The central area lists the files on the printer for a chosen remote path and file mask, showing each file&#039;s name, size, modified time and type. From here you can:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Upload&#039;&#039;&#039; a local file to the printer.&lt;br /&gt;
* &#039;&#039;&#039;Download&#039;&#039;&#039; one or more selected files to a chosen local folder.&lt;br /&gt;
* &#039;&#039;&#039;Delete&#039;&#039;&#039; selected files from the printer (with confirmation).&lt;br /&gt;
* &#039;&#039;&#039;Refresh&#039;&#039;&#039; the listing, and on PL6 navigate into sub-folders.&lt;br /&gt;
&lt;br /&gt;
PL3 exposes the printer&#039;s storage areas (&amp;lt;code&amp;gt;/c0/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/c9/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/f0/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/r0/&amp;lt;/code&amp;gt;) with file masks such as &amp;lt;code&amp;gt;*.llf&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;*.pcx&amp;lt;/code&amp;gt;; PL6 exposes its SFTP folders.&lt;br /&gt;
&lt;br /&gt;
=== Sending Commands and Field Data ===&lt;br /&gt;
&lt;br /&gt;
In PL3 mode the message pane composes and transmits raw text to the labeller. Control characters can be entered as readable tokens such as &amp;lt;code&amp;gt;&amp;lt;STX&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;lt;ETX&amp;gt;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;&amp;lt;CR&amp;gt;&amp;lt;/code&amp;gt;, and the end-of-line terminator appended on send is selectable. This is how layouts are activated, field data is sent, and LAMA/LSP queries are issued by hand. Replies appear in the activity log and the raw bytes in the wire trace.&lt;br /&gt;
&lt;br /&gt;
=== Pallet Log Polling ===&lt;br /&gt;
&lt;br /&gt;
LogoClient can poll the labeller&#039;s pallet log at a chosen interval and write the results to disk — one timestamped file per unique SSCC — into a chosen log folder. This reproduces, by hand, the &amp;quot;what was printed&amp;quot; feedback that production software collects, and works against both PL3 and PL6.&lt;br /&gt;
&lt;br /&gt;
=== Activity Log and Wire Trace ===&lt;br /&gt;
&lt;br /&gt;
Two panes record what happens. The &#039;&#039;&#039;activity log&#039;&#039;&#039; is a readable, timestamped narrative of connects, transfers, commands and errors. The &#039;&#039;&#039;wire trace&#039;&#039;&#039; shows the raw bytes in both directions — transmitted and received — with control characters rendered as tokens, which is invaluable when diagnosing exactly what a labeller sent or expected. Both panes can be saved to a text file or cleared.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
The connection details and interface preferences are saved when you quit and restored on the next start, so the tool reopens ready to reconnect to the labeller you last used.&lt;br /&gt;
&lt;br /&gt;
== Using LogoClient and LogoRenderer Together ==&lt;br /&gt;
&lt;br /&gt;
The two tools form a complete bench setup for label development with no Logopak hardware:&lt;br /&gt;
&lt;br /&gt;
# In &#039;&#039;&#039;[[LogoRenderer]]&#039;&#039;&#039;, start the &#039;&#039;&#039;printer emulator&#039;&#039;&#039; on a port (default 8000).&lt;br /&gt;
# In &#039;&#039;&#039;LogoClient&#039;&#039;&#039;, choose &#039;&#039;&#039;PL3 (TCP)&#039;&#039;&#039;, set the host to &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; and the matching port, and connect.&lt;br /&gt;
# &#039;&#039;&#039;Upload a layout&#039;&#039;&#039;, &#039;&#039;&#039;send field data&#039;&#039;&#039;, &#039;&#039;&#039;browse the emulated drives&#039;&#039;&#039; or &#039;&#039;&#039;poll the pallet log&#039;&#039;&#039; — and watch LogoRenderer render the result and log the traffic.&lt;br /&gt;
&lt;br /&gt;
In this arrangement LogoClient stands in for the driving software so you can develop and test against the renderer, while LogoRenderer stands in for the printer so you have something to talk to.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[LogoRenderer]] — the companion tool that renders labels and emulates a Logopak printer&lt;br /&gt;
* [[Middleware4j]], [[LabelServer4j]], [[AutoLab4j]] — other Commander4j components in the labelling workflow&lt;br /&gt;
* [[SocketTest]] — a raw TCP/IP testing utility&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=LogoRenderer&amp;diff=1877</id>
		<title>LogoRenderer</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=LogoRenderer&amp;diff=1877"/>
		<updated>2026-06-13T19:43:03Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: Updated by push_wiki.py&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;LogoRenderer&#039;&#039;&#039; (&#039;&#039;c4j_logorenderer&#039;&#039;) is a standalone desktop application that renders [[Logopak]] PowerLeap label layout files to a visual on-screen preview &#039;&#039;&#039;and&#039;&#039;&#039; can stand in for a physical label printer by emulating its TCP communication protocol. It exists so that label layouts and the software that drives them can be developed and tested &#039;&#039;&#039;on an ordinary PC, in environments where no physical Logopak labeller is available&#039;&#039;&#039; to test against.&lt;br /&gt;
&lt;br /&gt;
It is the rendering and printer-emulation half of a pair: [[LogoClient]] is the client that sends layouts and data to a printer, and LogoRenderer can play the part of that printer. Together they let you exercise the whole label-printing workflow with no hardware at all.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Disclaimer: LogoRenderer is an independent open-source tool and is &#039;&#039;&#039;not&#039;&#039;&#039; a Logopak product. It is not affiliated with, endorsed by, or supported by Logopak. Logopak, PowerLeap and related names are trademarks of their respective owners and are used solely to describe interoperability. The software is intended for local test and development use only — it must not be relied upon for production label printing.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
A Logopak PowerLeap labeller normally lives on the factory floor and is driven over the network by software provided by Logopak DE. When developing or supporting that software — or designing the label layouts themselves — it is often impractical to have a real labeller on the bench. LogoRenderer removes that dependency. It is useful when:&lt;br /&gt;
&lt;br /&gt;
* You need to &#039;&#039;&#039;see what a label layout will look like&#039;&#039;&#039; without printing it, by opening a &amp;lt;code&amp;gt;.llf&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.lqf&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;.ldf&amp;lt;/code&amp;gt; file and viewing a faithful preview.&lt;br /&gt;
* You are &#039;&#039;&#039;writing or debugging software that talks to a labeller&#039;&#039;&#039; and need something on the network that answers the same protocol — without owning the hardware.&lt;br /&gt;
* You want to &#039;&#039;&#039;develop without a physical Logopak&#039;&#039;&#039; altogether: render layouts, emulate the printer, and feed it from [[LogoClient]] or your own client code.&lt;br /&gt;
* You need to &#039;&#039;&#039;check field data and operator prompts&#039;&#039;&#039; (LQF query fields) by typing values and watching the rendered label update.&lt;br /&gt;
* You are &#039;&#039;&#039;tuning fonts&#039;&#039;&#039; so the on-screen rendering matches a real printed label.&lt;br /&gt;
&lt;br /&gt;
== Label and Data File Types ==&lt;br /&gt;
&lt;br /&gt;
LogoRenderer understands the PowerLeap LEAP layout family:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Extension !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.llf&amp;lt;/code&amp;gt; || Layout File — a complete label layout with all field data embedded. Opening one renders the label immediately.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.lqf&amp;lt;/code&amp;gt; || Query Layout File — a base layout containing &amp;lt;code&amp;gt;QUE&amp;lt;/code&amp;gt; operator prompts for fields that are filled in at print time. Opening one also populates the &#039;&#039;&#039;QUE Input&#039;&#039;&#039; tab so values can be typed in.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.ldf&amp;lt;/code&amp;gt; || Data File — a data-only file that references a master layout. Opening one runs its &amp;lt;code&amp;gt;LOAD&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;FD&amp;lt;/code&amp;gt; commands to load the referenced layout and populate its fields.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Layouts may reference &amp;lt;code&amp;gt;.pcx&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;.bmp&amp;lt;/code&amp;gt; images (logotypes) and a range of barcode types. A reference list of the wider Logopak file-type ecosystem is maintained alongside the project.&lt;br /&gt;
&lt;br /&gt;
== Source Code and Releases ==&lt;br /&gt;
&lt;br /&gt;
LogoRenderer is part of the open-source Commander4j suite and is distributed under the GNU General Public License. The source code and release downloads are hosted on GitHub, and native install packages for every platform are listed on the Commander4j [[Downloads]] page.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Repository:&#039;&#039;&#039; [https://github.com/C4J/LogoRenderer https://github.com/C4J/LogoRenderer]&lt;br /&gt;
* &#039;&#039;&#039;Releases (download media):&#039;&#039;&#039; [https://github.com/C4J/LogoRenderer/releases https://github.com/C4J/LogoRenderer/releases]&lt;br /&gt;
* &#039;&#039;&#039;All Commander4j downloads:&#039;&#039;&#039; [[Downloads]]&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
Native install packages for &#039;&#039;&#039;Windows, macOS and Linux&#039;&#039;&#039; are available from the [[Downloads]] page and are the preferred installation method. Each installer bundles its own Java runtime, so &#039;&#039;&#039;no separate Java installation is required&#039;&#039;&#039;. Installing creates a native &#039;&#039;&#039;LogoRenderer&#039;&#039;&#039; launcher that can be started like any other desktop application.&lt;br /&gt;
&lt;br /&gt;
=== Running from the jar ===&lt;br /&gt;
&lt;br /&gt;
Alternatively the tool can be run directly as an ordinary Java (Swing) application. It is built with Maven:&lt;br /&gt;
&lt;br /&gt;
 mvn package&lt;br /&gt;
 java -jar c4j_logorenderer.jar [file.llf]&lt;br /&gt;
&lt;br /&gt;
Running the jar requires a recent Java runtime (Java 25 or later). If a layout file is supplied on the command line it is opened on start-up; otherwise the application starts with an empty canvas. Demo layouts and data files are provided in the &amp;lt;code&amp;gt;virtual_disk/c0/&amp;lt;/code&amp;gt; folder.&lt;br /&gt;
&lt;br /&gt;
== The Main Window ==&lt;br /&gt;
&lt;br /&gt;
The window is divided into a &#039;&#039;&#039;label preview canvas&#039;&#039;&#039; on the left and a &#039;&#039;&#039;tabbed working area&#039;&#039;&#039; on the right, with a menu bar and toolbars around them and a status bar along the bottom. The title bar shows the program name, version and the name of the open file.&lt;br /&gt;
&lt;br /&gt;
The status bar reports the current file, the layout dimensions in printer dots and millimetres, the zoom level, and the number of fields in the layout.&lt;br /&gt;
&lt;br /&gt;
=== Preview Canvas ===&lt;br /&gt;
&lt;br /&gt;
The canvas shows the rendered label exactly as the layout describes it — text, scalable text, barcodes, graphic lines and boxes, and embedded logotype images. The rendering engine replicates the coordinate system and geometry of a PowerLeap III print head, including the upside-down (180°) print orientation. Clicking a rendered element highlights the source lines that produce it.&lt;br /&gt;
&lt;br /&gt;
=== Source / QUE Input / Log Tabs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Tab !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Source&#039;&#039;&#039; || Lists the raw layout commands, one per line, each with a checkbox and a plain-language description. Un-checking a line excludes it from the render, so individual elements can be toggled on and off. Selecting a line shows its properties for editing.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;QUE Input&#039;&#039;&#039; || For LQF layouts, presents one input box per operator prompt. Type values and apply them to see the populated label. This mirrors what an operator would be asked for at the machine.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Log&#039;&#039;&#039; || A colour-coded activity log showing file loads, parser messages, and all traffic to and from the printer emulator.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Viewing Controls ===&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;File&#039;&#039;&#039; menu opens and reloads layout files and exports the rendered label as a PNG image. The &#039;&#039;&#039;View&#039;&#039;&#039; menu provides zoom (preset levels, zoom in/out, and fit-to-window) and a &#039;&#039;&#039;Rotate 180°&#039;&#039;&#039; toggle that flips the preview to match the printer&#039;s print orientation.&lt;br /&gt;
&lt;br /&gt;
== Font Mapping ==&lt;br /&gt;
&lt;br /&gt;
Because Logopak fonts are not present on a development PC, LogoRenderer maps each Logopak font name to a Java font for rendering. The &#039;&#039;&#039;Settings → Font Mappings&#039;&#039;&#039; dialog lists every mapping and lets you set the Java font family (or a bundled TrueType file), style, reference cell size and calibration factors so that the on-screen text closely matches a real printed label. The mappings are stored in &amp;lt;code&amp;gt;xml/config/fonts.xml&amp;lt;/code&amp;gt;; fonts found in a layout but not yet mapped are added automatically with sensible defaults, ready to be fine-tuned.&lt;br /&gt;
&lt;br /&gt;
== The Printer Emulator ==&lt;br /&gt;
&lt;br /&gt;
This is the feature that makes hardware-free development possible. LogoRenderer can open a TCP server that emulates a Logopak PowerLeap III labeller, answering the same &#039;&#039;&#039;LEAP / LAMA&#039;&#039;&#039; protocol commands a real machine would.&lt;br /&gt;
&lt;br /&gt;
=== Starting the emulator ===&lt;br /&gt;
&lt;br /&gt;
The connection bar at the top of the window selects the &#039;&#039;&#039;IP address&#039;&#039;&#039; (default &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; for the local machine) and &#039;&#039;&#039;port&#039;&#039;&#039; (default &#039;&#039;&#039;8000&#039;&#039;&#039;, the PowerLeap III primary data port; &amp;lt;code&amp;gt;8100&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;8200&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;8300&amp;lt;/code&amp;gt; are also offered). Pressing &#039;&#039;&#039;Start Server&#039;&#039;&#039; begins listening; the Log tab shows when a client connects. Pressing the button again stops the server.&lt;br /&gt;
&lt;br /&gt;
=== What it emulates ===&lt;br /&gt;
&lt;br /&gt;
A connected client can do, against the emulator, the things it would do against a real labeller:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Browse and transfer files&#039;&#039;&#039; on an emulated drive — the &amp;lt;code&amp;gt;virtual_disk/&amp;lt;/code&amp;gt; folder provides the labeller&#039;s storage areas (&amp;lt;code&amp;gt;c0/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;c9/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;d0/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f0/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;r0/&amp;lt;/code&amp;gt;), so directory listings, downloads, uploads and deletes all behave realistically.&lt;br /&gt;
* &#039;&#039;&#039;Load a layout and send field data&#039;&#039;&#039; — when the client issues a &amp;lt;code&amp;gt;LOAD&amp;lt;/code&amp;gt; command the emulator loads that layout into the preview, and as &amp;lt;code&amp;gt;FD&amp;lt;/code&amp;gt; field-data commands arrive the on-screen label updates. The PC screen therefore shows what the real printer would be putting on a label.&lt;br /&gt;
* &#039;&#039;&#039;Retrieve logs&#039;&#039;&#039; — the emulator can serve pallet/label log files back to the client, so software that polls a labeller for &amp;quot;what was printed&amp;quot; can be tested end to end.&lt;br /&gt;
&lt;br /&gt;
=== Pallet print simulation ===&lt;br /&gt;
&lt;br /&gt;
When a loaded layout contains the pallet SSCC field, a &#039;&#039;&#039;Print Label&#039;&#039;&#039; control appears. Each press simulates a pallet print — two labels per pallet sharing one [https://en.wikipedia.org/wiki/Serial_Shipping_Container_Code SSCC] — increments the SSCC counter (persisted in &amp;lt;code&amp;gt;sscc.dat&amp;lt;/code&amp;gt;), and queues a log entry that a client can later retrieve. This lets log-polling and pallet-tracking logic be exercised without a real production run.&lt;br /&gt;
&lt;br /&gt;
== Using LogoRenderer and LogoClient Together ==&lt;br /&gt;
&lt;br /&gt;
The two tools form a complete bench setup for label development with no Logopak hardware:&lt;br /&gt;
&lt;br /&gt;
# In &#039;&#039;&#039;LogoRenderer&#039;&#039;&#039;, start the &#039;&#039;&#039;printer emulator&#039;&#039;&#039; on a port (default 8000).&lt;br /&gt;
# In &#039;&#039;&#039;[[LogoClient]]&#039;&#039;&#039;, connect in &#039;&#039;&#039;PL3 (TCP)&#039;&#039;&#039; mode to &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; on the same port.&lt;br /&gt;
# From LogoClient, &#039;&#039;&#039;upload a layout&#039;&#039;&#039;, &#039;&#039;&#039;send field data&#039;&#039;&#039;, &#039;&#039;&#039;browse the emulated drives&#039;&#039;&#039; or &#039;&#039;&#039;poll the pallet log&#039;&#039;&#039; — and watch LogoRenderer render the result and log the traffic.&lt;br /&gt;
&lt;br /&gt;
In this arrangement LogoRenderer stands in for the printer so you can develop and test a client, while LogoClient stands in for the driving software so you can drive the renderer.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[LogoClient]] — the client-side companion tool that sends layouts and data to a labeller (real or emulated)&lt;br /&gt;
* [[Middleware4j]], [[LabelServer4j]], [[AutoLab4j]] — other Commander4j components in the labelling workflow&lt;br /&gt;
* [[ZPLRenderer]] — the equivalent preview tool for Zebra ZPL labels&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=LogoClient&amp;diff=1876</id>
		<title>LogoClient</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=LogoClient&amp;diff=1876"/>
		<updated>2026-06-13T19:41:08Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: Updated by push_wiki.py&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;LogoClient&#039;&#039;&#039; (&#039;&#039;c4j_logoclient&#039;&#039;) is a standalone desktop application — and underlying client library — for communicating with [[Logopak]] PowerLeap label printers over the network. It connects to a labeller, transfers layout and data files to and from it, sends commands and field data, browses the printer&#039;s on-board storage and retrieves its logs. It exists so that the software-to-labeller conversation can be developed, exercised and diagnosed &#039;&#039;&#039;on an ordinary PC, in environments where no physical Logopak labeller is available&#039;&#039;&#039; to test against.&lt;br /&gt;
&lt;br /&gt;
It is the client half of a pair: where a real labeller is not to hand, [[LogoRenderer]] can emulate one, and LogoClient talks to that emulator exactly as it would talk to real hardware. Together they let you exercise the whole label-printing workflow with no hardware at all.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Disclaimer: LogoClient is an independent open-source tool and is &#039;&#039;&#039;not&#039;&#039;&#039; a Logopak product. It is not affiliated with, endorsed by, or supported by Logopak. Logopak, PowerLeap and related names are trademarks of their respective owners and are used solely to describe interoperability. The software is intended for local test and development use only — it must not be relied upon for production label printing.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
Software from Logopak DE drives labellers in production. When developing or supporting that software it is useful to be able to perform the same low-level operations by hand, and to see exactly what goes across the wire. LogoClient is that tool. It is useful when:&lt;br /&gt;
&lt;br /&gt;
* You need to &#039;&#039;&#039;send a layout or data file to a labeller&#039;&#039;&#039; and confirm it loads correctly.&lt;br /&gt;
* You want to &#039;&#039;&#039;browse, upload, download or delete files&#039;&#039;&#039; on the printer&#039;s on-board drives.&lt;br /&gt;
* You are &#039;&#039;&#039;debugging the protocol&#039;&#039;&#039; and want a live, byte-level trace of everything sent and received.&lt;br /&gt;
* You need to &#039;&#039;&#039;send raw commands or field data&#039;&#039;&#039; to a labeller and read its replies.&lt;br /&gt;
* You want to &#039;&#039;&#039;poll a labeller&#039;s pallet log&#039;&#039;&#039; and capture one file per SSCC as labels are applied.&lt;br /&gt;
* You want to &#039;&#039;&#039;develop without a physical Logopak&#039;&#039;&#039; by pointing LogoClient at the [[LogoRenderer]] printer emulator instead of real hardware.&lt;br /&gt;
&lt;br /&gt;
== Supported Printers and Protocols ==&lt;br /&gt;
&lt;br /&gt;
LogoClient supports both current Logopak controller generations:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Mode !! Hardware !! Transport&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;PL3 (TCP)&#039;&#039;&#039; || PowerLeap III || Direct TCP socket on the data ports (8000 / 8100 / 8200 / 8300). Carries the full LEAP, LAMA/LACE and LSP command set — layout activation, field data, firmware queries, file management, I/O monitoring and asynchronous reporting.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;PL6 (SFTP)&#039;&#039;&#039; || PowerLeap 6 || File transfer over SFTP (port 22). PL6 is driven by exchanging files rather than TCP commands, so this mode is focused on uploading, downloading and listing files and reading the pallet log.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Source Code and Releases ==&lt;br /&gt;
&lt;br /&gt;
LogoClient is part of the open-source Commander4j suite and is distributed under the GNU General Public License. The source code and release downloads are hosted on GitHub, and native install packages for every platform are listed on the Commander4j [[Downloads]] page.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Repository:&#039;&#039;&#039; [https://github.com/C4J/LogoClient https://github.com/C4J/LogoClient]&lt;br /&gt;
* &#039;&#039;&#039;Releases (download media):&#039;&#039;&#039; [https://github.com/C4J/LogoClient/releases https://github.com/C4J/LogoClient/releases]&lt;br /&gt;
* &#039;&#039;&#039;All Commander4j downloads:&#039;&#039;&#039; [[Downloads]]&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
Native install packages for &#039;&#039;&#039;Windows, macOS and Linux&#039;&#039;&#039; are available from the [[Downloads]] page and are the preferred installation method. Each installer bundles its own Java runtime, so &#039;&#039;&#039;no separate Java installation is required&#039;&#039;&#039;. Installing creates a native &#039;&#039;&#039;LogoClient&#039;&#039;&#039; launcher that can be started like any other desktop application.&lt;br /&gt;
&lt;br /&gt;
=== Running from the jar ===&lt;br /&gt;
&lt;br /&gt;
Alternatively the tool can be run directly as an ordinary Java (Swing) application:&lt;br /&gt;
&lt;br /&gt;
 java -jar c4j_logoclient.jar&lt;br /&gt;
&lt;br /&gt;
Running the jar requires a recent Java runtime (Java 21 or later). The bundled JSch library is required only for PL6 (SFTP); PL3 (TCP) has no external dependencies.&lt;br /&gt;
&lt;br /&gt;
== The Main Window ==&lt;br /&gt;
&lt;br /&gt;
The window has a &#039;&#039;&#039;connection bar&#039;&#039;&#039; across the top, a central &#039;&#039;&#039;file-transfer and directory area&#039;&#039;&#039;, a &#039;&#039;&#039;message pane&#039;&#039;&#039; for composing raw commands, and a pair of log panes along the bottom — an &#039;&#039;&#039;activity log&#039;&#039;&#039; and a &#039;&#039;&#039;wire trace&#039;&#039;&#039;. All transfer and command actions are disabled until a connection is open.&lt;br /&gt;
&lt;br /&gt;
=== Connecting ===&lt;br /&gt;
&lt;br /&gt;
In the connection bar you choose the connection &#039;&#039;&#039;Type&#039;&#039;&#039; (PL3 TCP or PL6 SFTP), enter the labeller&#039;s &#039;&#039;&#039;host / IP address&#039;&#039;&#039; and &#039;&#039;&#039;port&#039;&#039;&#039;, and — for PL6 — a &#039;&#039;&#039;username and password&#039;&#039;&#039;. Pressing the connect button opens the link; a status indicator shows the connected host and port. A real labeller is typically reached at its own network address (for example &amp;lt;code&amp;gt;192.168.1.100&amp;lt;/code&amp;gt;); the [[LogoRenderer]] emulator is reached at &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Options in the connection area let you list the remote directory automatically on connect, send a periodic &#039;&#039;&#039;heartbeat&#039;&#039;&#039; to detect a dropped link, and set the socket read timeout.&lt;br /&gt;
&lt;br /&gt;
=== Transferring and Managing Files ===&lt;br /&gt;
&lt;br /&gt;
The central area lists the files on the printer for a chosen remote path and file mask, showing each file&#039;s name, size, modified time and type. From here you can:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Upload&#039;&#039;&#039; a local file to the printer.&lt;br /&gt;
* &#039;&#039;&#039;Download&#039;&#039;&#039; one or more selected files to a chosen local folder.&lt;br /&gt;
* &#039;&#039;&#039;Delete&#039;&#039;&#039; selected files from the printer (with confirmation).&lt;br /&gt;
* &#039;&#039;&#039;Refresh&#039;&#039;&#039; the listing, and on PL6 navigate into sub-folders.&lt;br /&gt;
&lt;br /&gt;
PL3 exposes the printer&#039;s storage areas (&amp;lt;code&amp;gt;/c0/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/c9/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/f0/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/r0/&amp;lt;/code&amp;gt;) with file masks such as &amp;lt;code&amp;gt;*.llf&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;*.pcx&amp;lt;/code&amp;gt;; PL6 exposes its SFTP folders.&lt;br /&gt;
&lt;br /&gt;
=== Sending Commands and Field Data ===&lt;br /&gt;
&lt;br /&gt;
In PL3 mode the message pane composes and transmits raw text to the labeller. Control characters can be entered as readable tokens such as &amp;lt;code&amp;gt;&amp;lt;STX&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;lt;ETX&amp;gt;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;&amp;lt;CR&amp;gt;&amp;lt;/code&amp;gt;, and the end-of-line terminator appended on send is selectable. This is how layouts are activated, field data is sent, and LAMA/LSP queries are issued by hand. Replies appear in the activity log and the raw bytes in the wire trace.&lt;br /&gt;
&lt;br /&gt;
=== Pallet Log Polling ===&lt;br /&gt;
&lt;br /&gt;
LogoClient can poll the labeller&#039;s pallet log at a chosen interval and write the results to disk — one timestamped file per unique SSCC — into a chosen log folder. This reproduces, by hand, the &amp;quot;what was printed&amp;quot; feedback that production software collects, and works against both PL3 and PL6.&lt;br /&gt;
&lt;br /&gt;
=== Activity Log and Wire Trace ===&lt;br /&gt;
&lt;br /&gt;
Two panes record what happens. The &#039;&#039;&#039;activity log&#039;&#039;&#039; is a readable, timestamped narrative of connects, transfers, commands and errors. The &#039;&#039;&#039;wire trace&#039;&#039;&#039; shows the raw bytes in both directions — transmitted and received — with control characters rendered as tokens, which is invaluable when diagnosing exactly what a labeller sent or expected. Both panes can be saved to a text file or cleared.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
The connection details and interface preferences are saved when you quit and restored on the next start, so the tool reopens ready to reconnect to the labeller you last used.&lt;br /&gt;
&lt;br /&gt;
== Using LogoClient and LogoRenderer Together ==&lt;br /&gt;
&lt;br /&gt;
The two tools form a complete bench setup for label development with no Logopak hardware:&lt;br /&gt;
&lt;br /&gt;
# In &#039;&#039;&#039;[[LogoRenderer]]&#039;&#039;&#039;, start the &#039;&#039;&#039;printer emulator&#039;&#039;&#039; on a port (default 8000).&lt;br /&gt;
# In &#039;&#039;&#039;LogoClient&#039;&#039;&#039;, choose &#039;&#039;&#039;PL3 (TCP)&#039;&#039;&#039;, set the host to &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; and the matching port, and connect.&lt;br /&gt;
# &#039;&#039;&#039;Upload a layout&#039;&#039;&#039;, &#039;&#039;&#039;send field data&#039;&#039;&#039;, &#039;&#039;&#039;browse the emulated drives&#039;&#039;&#039; or &#039;&#039;&#039;poll the pallet log&#039;&#039;&#039; — and watch LogoRenderer render the result and log the traffic.&lt;br /&gt;
&lt;br /&gt;
In this arrangement LogoClient stands in for the driving software so you can develop and test against the renderer, while LogoRenderer stands in for the printer so you have something to talk to. LogoClient can equally be pointed at a real Logopak labeller when one is available.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[LogoRenderer]] — the companion tool that renders labels and emulates a Logopak printer&lt;br /&gt;
* [[Middleware4j]], [[LabelServer4j]], [[AutoLab4j]] — other Commander4j components in the labelling workflow&lt;br /&gt;
* [[SocketTest]] — a raw TCP/IP testing utility&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=LogoRenderer&amp;diff=1875</id>
		<title>LogoRenderer</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=LogoRenderer&amp;diff=1875"/>
		<updated>2026-06-13T19:41:07Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: Updated by push_wiki.py&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;LogoRenderer&#039;&#039;&#039; (&#039;&#039;c4j_logorenderer&#039;&#039;) is a standalone desktop application that renders [[Logopak]] PowerLeap label layout files to a visual on-screen preview &#039;&#039;&#039;and&#039;&#039;&#039; can stand in for a physical label printer by emulating its TCP communication protocol. It exists so that label layouts and the software that drives them can be developed and tested &#039;&#039;&#039;on an ordinary PC, in environments where no physical Logopak labeller is available&#039;&#039;&#039; to test against.&lt;br /&gt;
&lt;br /&gt;
It is the rendering and printer-emulation half of a pair: [[LogoClient]] is the client that sends layouts and data to a printer, and LogoRenderer can play the part of that printer. Together they let you exercise the whole label-printing workflow with no hardware at all.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Disclaimer: LogoRenderer is an independent open-source tool and is &#039;&#039;&#039;not&#039;&#039;&#039; a Logopak product. It is not affiliated with, endorsed by, or supported by Logopak. Logopak, PowerLeap and related names are trademarks of their respective owners and are used solely to describe interoperability. The software is intended for local test and development use only — it must not be relied upon for production label printing.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
A Logopak PowerLeap labeller normally lives on the factory floor and is driven over the network by software provided by Logopak DE. When developing or supporting that software — or designing the label layouts themselves — it is often impractical to have a real labeller on the bench. LogoRenderer removes that dependency. It is useful when:&lt;br /&gt;
&lt;br /&gt;
* You need to &#039;&#039;&#039;see what a label layout will look like&#039;&#039;&#039; without printing it, by opening a &amp;lt;code&amp;gt;.llf&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.lqf&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;.ldf&amp;lt;/code&amp;gt; file and viewing a faithful preview.&lt;br /&gt;
* You are &#039;&#039;&#039;writing or debugging software that talks to a labeller&#039;&#039;&#039; and need something on the network that answers the same protocol — without owning the hardware.&lt;br /&gt;
* You want to &#039;&#039;&#039;develop without a physical Logopak&#039;&#039;&#039; altogether: render layouts, emulate the printer, and feed it from [[LogoClient]] or your own client code.&lt;br /&gt;
* You need to &#039;&#039;&#039;check field data and operator prompts&#039;&#039;&#039; (LQF query fields) by typing values and watching the rendered label update.&lt;br /&gt;
* You are &#039;&#039;&#039;tuning fonts&#039;&#039;&#039; so the on-screen rendering matches a real printed label.&lt;br /&gt;
&lt;br /&gt;
== Label and Data File Types ==&lt;br /&gt;
&lt;br /&gt;
LogoRenderer understands the PowerLeap LEAP layout family:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Extension !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.llf&amp;lt;/code&amp;gt; || Layout File — a complete label layout with all field data embedded. Opening one renders the label immediately.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.lqf&amp;lt;/code&amp;gt; || Query Layout File — a base layout containing &amp;lt;code&amp;gt;QUE&amp;lt;/code&amp;gt; operator prompts for fields that are filled in at print time. Opening one also populates the &#039;&#039;&#039;QUE Input&#039;&#039;&#039; tab so values can be typed in.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.ldf&amp;lt;/code&amp;gt; || Data File — a data-only file that references a master layout. Opening one runs its &amp;lt;code&amp;gt;LOAD&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;FD&amp;lt;/code&amp;gt; commands to load the referenced layout and populate its fields.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Layouts may reference &amp;lt;code&amp;gt;.pcx&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;.bmp&amp;lt;/code&amp;gt; images (logotypes) and a range of barcode types. A reference list of the wider Logopak file-type ecosystem is maintained alongside the project.&lt;br /&gt;
&lt;br /&gt;
== Source Code and Releases ==&lt;br /&gt;
&lt;br /&gt;
LogoRenderer is part of the open-source Commander4j suite and is distributed under the GNU General Public License. The source code and release downloads are hosted on GitHub, and native install packages for every platform are listed on the Commander4j [[Downloads]] page.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Repository:&#039;&#039;&#039; [https://github.com/C4J/LogoRenderer https://github.com/C4J/LogoRenderer]&lt;br /&gt;
* &#039;&#039;&#039;Releases (download media):&#039;&#039;&#039; [https://github.com/C4J/LogoRenderer/releases https://github.com/C4J/LogoRenderer/releases]&lt;br /&gt;
* &#039;&#039;&#039;All Commander4j downloads:&#039;&#039;&#039; [[Downloads]]&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
Native install packages for &#039;&#039;&#039;Windows, macOS and Linux&#039;&#039;&#039; are available from the [[Downloads]] page and are the preferred installation method. Each installer bundles its own Java runtime, so &#039;&#039;&#039;no separate Java installation is required&#039;&#039;&#039;. Installing creates a native &#039;&#039;&#039;LogoRenderer&#039;&#039;&#039; launcher that can be started like any other desktop application.&lt;br /&gt;
&lt;br /&gt;
=== Running from the jar ===&lt;br /&gt;
&lt;br /&gt;
Alternatively the tool can be run directly as an ordinary Java (Swing) application. It is built with Maven:&lt;br /&gt;
&lt;br /&gt;
 mvn package&lt;br /&gt;
 java -jar c4j_logorenderer.jar [file.llf]&lt;br /&gt;
&lt;br /&gt;
Running the jar requires a recent Java runtime (Java 25 or later). If a layout file is supplied on the command line it is opened on start-up; otherwise the application starts with an empty canvas. Demo layouts and data files are provided in the &amp;lt;code&amp;gt;virtual_disk/c0/&amp;lt;/code&amp;gt; folder.&lt;br /&gt;
&lt;br /&gt;
== The Main Window ==&lt;br /&gt;
&lt;br /&gt;
The window is divided into a &#039;&#039;&#039;label preview canvas&#039;&#039;&#039; on the left and a &#039;&#039;&#039;tabbed working area&#039;&#039;&#039; on the right, with a menu bar and toolbars around them and a status bar along the bottom. The title bar shows the program name, version and the name of the open file.&lt;br /&gt;
&lt;br /&gt;
The status bar reports the current file, the layout dimensions in printer dots and millimetres, the zoom level, and the number of fields in the layout.&lt;br /&gt;
&lt;br /&gt;
=== Preview Canvas ===&lt;br /&gt;
&lt;br /&gt;
The canvas shows the rendered label exactly as the layout describes it — text, scalable text, barcodes, graphic lines and boxes, and embedded logotype images. The rendering engine replicates the coordinate system and geometry of a PowerLeap III print head, including the upside-down (180°) print orientation. Clicking a rendered element highlights the source lines that produce it.&lt;br /&gt;
&lt;br /&gt;
=== Source / QUE Input / Log Tabs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Tab !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Source&#039;&#039;&#039; || Lists the raw layout commands, one per line, each with a checkbox and a plain-language description. Un-checking a line excludes it from the render, so individual elements can be toggled on and off. Selecting a line shows its properties for editing.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;QUE Input&#039;&#039;&#039; || For LQF layouts, presents one input box per operator prompt. Type values and apply them to see the populated label. This mirrors what an operator would be asked for at the machine.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Log&#039;&#039;&#039; || A colour-coded activity log showing file loads, parser messages, and all traffic to and from the printer emulator.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Viewing Controls ===&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;File&#039;&#039;&#039; menu opens and reloads layout files and exports the rendered label as a PNG image. The &#039;&#039;&#039;View&#039;&#039;&#039; menu provides zoom (preset levels, zoom in/out, and fit-to-window) and a &#039;&#039;&#039;Rotate 180°&#039;&#039;&#039; toggle that flips the preview to match the printer&#039;s print orientation.&lt;br /&gt;
&lt;br /&gt;
== Font Mapping ==&lt;br /&gt;
&lt;br /&gt;
Because Logopak fonts are not present on a development PC, LogoRenderer maps each Logopak font name to a Java font for rendering. The &#039;&#039;&#039;Settings → Font Mappings&#039;&#039;&#039; dialog lists every mapping and lets you set the Java font family (or a bundled TrueType file), style, reference cell size and calibration factors so that the on-screen text closely matches a real printed label. The mappings are stored in &amp;lt;code&amp;gt;xml/config/fonts.xml&amp;lt;/code&amp;gt;; fonts found in a layout but not yet mapped are added automatically with sensible defaults, ready to be fine-tuned.&lt;br /&gt;
&lt;br /&gt;
== The Printer Emulator ==&lt;br /&gt;
&lt;br /&gt;
This is the feature that makes hardware-free development possible. LogoRenderer can open a TCP server that emulates a Logopak PowerLeap III labeller, answering the same &#039;&#039;&#039;LEAP / LAMA&#039;&#039;&#039; protocol commands a real machine would.&lt;br /&gt;
&lt;br /&gt;
=== Starting the emulator ===&lt;br /&gt;
&lt;br /&gt;
The connection bar at the top of the window selects the &#039;&#039;&#039;IP address&#039;&#039;&#039; (default &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; for the local machine) and &#039;&#039;&#039;port&#039;&#039;&#039; (default &#039;&#039;&#039;8000&#039;&#039;&#039;, the PowerLeap III primary data port; &amp;lt;code&amp;gt;8100&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;8200&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;8300&amp;lt;/code&amp;gt; are also offered). Pressing &#039;&#039;&#039;Start Server&#039;&#039;&#039; begins listening; the Log tab shows when a client connects. Pressing the button again stops the server.&lt;br /&gt;
&lt;br /&gt;
=== What it emulates ===&lt;br /&gt;
&lt;br /&gt;
A connected client can do, against the emulator, the things it would do against a real labeller:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Browse and transfer files&#039;&#039;&#039; on an emulated drive — the &amp;lt;code&amp;gt;virtual_disk/&amp;lt;/code&amp;gt; folder provides the labeller&#039;s storage areas (&amp;lt;code&amp;gt;c0/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;c9/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;d0/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f0/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;r0/&amp;lt;/code&amp;gt;), so directory listings, downloads, uploads and deletes all behave realistically.&lt;br /&gt;
* &#039;&#039;&#039;Load a layout and send field data&#039;&#039;&#039; — when the client issues a &amp;lt;code&amp;gt;LOAD&amp;lt;/code&amp;gt; command the emulator loads that layout into the preview, and as &amp;lt;code&amp;gt;FD&amp;lt;/code&amp;gt; field-data commands arrive the on-screen label updates. The PC screen therefore shows what the real printer would be putting on a label.&lt;br /&gt;
* &#039;&#039;&#039;Retrieve logs&#039;&#039;&#039; — the emulator can serve pallet/label log files back to the client, so software that polls a labeller for &amp;quot;what was printed&amp;quot; can be tested end to end.&lt;br /&gt;
&lt;br /&gt;
=== Pallet print simulation ===&lt;br /&gt;
&lt;br /&gt;
When a loaded layout contains the pallet SSCC field, a &#039;&#039;&#039;Print Label&#039;&#039;&#039; control appears. Each press simulates a pallet print — two labels per pallet sharing one [https://en.wikipedia.org/wiki/Serial_Shipping_Container_Code SSCC] — increments the SSCC counter (persisted in &amp;lt;code&amp;gt;sscc.dat&amp;lt;/code&amp;gt;), and queues a log entry that a client can later retrieve. This lets log-polling and pallet-tracking logic be exercised without a real production run.&lt;br /&gt;
&lt;br /&gt;
== Using LogoRenderer and LogoClient Together ==&lt;br /&gt;
&lt;br /&gt;
The two tools form a complete bench setup for label development with no Logopak hardware:&lt;br /&gt;
&lt;br /&gt;
# In &#039;&#039;&#039;LogoRenderer&#039;&#039;&#039;, start the &#039;&#039;&#039;printer emulator&#039;&#039;&#039; on a port (default 8000).&lt;br /&gt;
# In &#039;&#039;&#039;[[LogoClient]]&#039;&#039;&#039;, connect in &#039;&#039;&#039;PL3 (TCP)&#039;&#039;&#039; mode to &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; on the same port.&lt;br /&gt;
# From LogoClient, &#039;&#039;&#039;upload a layout&#039;&#039;&#039;, &#039;&#039;&#039;send field data&#039;&#039;&#039;, &#039;&#039;&#039;browse the emulated drives&#039;&#039;&#039; or &#039;&#039;&#039;poll the pallet log&#039;&#039;&#039; — and watch LogoRenderer render the result and log the traffic.&lt;br /&gt;
&lt;br /&gt;
In this arrangement LogoRenderer stands in for the printer so you can develop and test a client, while LogoClient stands in for the driving software so you can drive the renderer. Either tool can equally be pointed at a real Logopak labeller when one is available.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[LogoClient]] — the client-side companion tool that sends layouts and data to a labeller (real or emulated)&lt;br /&gt;
* [[Middleware4j]], [[LabelServer4j]], [[AutoLab4j]] — other Commander4j components in the labelling workflow&lt;br /&gt;
* [[ZPLRenderer]] — the equivalent preview tool for Zebra ZPL labels&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=LogoClient&amp;diff=1874</id>
		<title>LogoClient</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=LogoClient&amp;diff=1874"/>
		<updated>2026-06-13T19:40:36Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: Updated by push_wiki.py&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;LogoClient&#039;&#039;&#039; (&#039;&#039;c4j_logoclient&#039;&#039;) is a standalone desktop application — and underlying client library — for communicating with [[Logopak]] PowerLeap label printers over the network. It connects to a labeller, transfers layout and data files to and from it, sends commands and field data, browses the printer&#039;s on-board storage and retrieves its logs. It exists so that the software-to-labeller conversation can be developed, exercised and diagnosed &#039;&#039;&#039;on an ordinary PC, in environments where no physical Logopak labeller is available&#039;&#039;&#039; to test against.&lt;br /&gt;
&lt;br /&gt;
It is the client half of a pair: where a real labeller is not to hand, [[LogoRenderer]] can emulate one, and LogoClient talks to that emulator exactly as it would talk to real hardware. Together they let you exercise the whole label-printing workflow with no hardware at all.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Disclaimer: LogoClient is an independent open-source tool and is &#039;&#039;&#039;not&#039;&#039;&#039; a Logopak product. It is not affiliated with, endorsed by, or supported by Logopak. Logopak, PowerLeap and related names are trademarks of their respective owners and are used solely to describe interoperability. The software is intended for local test and development use only — it must not be relied upon for production label printing.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
Software from Logopak DE drives labellers in production. When developing or supporting that software it is useful to be able to perform the same low-level operations by hand, and to see exactly what goes across the wire. LogoClient is that tool. It is useful when:&lt;br /&gt;
&lt;br /&gt;
* You need to &#039;&#039;&#039;send a layout or data file to a labeller&#039;&#039;&#039; and confirm it loads correctly.&lt;br /&gt;
* You want to &#039;&#039;&#039;browse, upload, download or delete files&#039;&#039;&#039; on the printer&#039;s on-board drives.&lt;br /&gt;
* You are &#039;&#039;&#039;debugging the protocol&#039;&#039;&#039; and want a live, byte-level trace of everything sent and received.&lt;br /&gt;
* You need to &#039;&#039;&#039;send raw commands or field data&#039;&#039;&#039; to a labeller and read its replies.&lt;br /&gt;
* You want to &#039;&#039;&#039;poll a labeller&#039;s pallet log&#039;&#039;&#039; and capture one file per SSCC as labels are applied.&lt;br /&gt;
* You want to &#039;&#039;&#039;develop without a physical Logopak&#039;&#039;&#039; by pointing LogoClient at the [[LogoRenderer]] printer emulator instead of real hardware.&lt;br /&gt;
&lt;br /&gt;
== Supported Printers and Protocols ==&lt;br /&gt;
&lt;br /&gt;
LogoClient supports both current Logopak controller generations:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Mode !! Hardware !! Transport&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;PL3 (TCP)&#039;&#039;&#039; || PowerLeap III || Direct TCP socket on the data ports (8000 / 8100 / 8200 / 8300). Carries the full LEAP, LAMA/LACE and LSP command set — layout activation, field data, firmware queries, file management, I/O monitoring and asynchronous reporting.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;PL6 (SFTP)&#039;&#039;&#039; || PowerLeap 6 || File transfer over SFTP (port 22). PL6 is driven by exchanging files rather than TCP commands, so this mode is focused on uploading, downloading and listing files and reading the pallet log.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Source Code and Releases ==&lt;br /&gt;
&lt;br /&gt;
LogoClient is part of the open-source Commander4j suite and is distributed under the GNU General Public License. The source code and release downloads are hosted on GitHub, and native install packages for every platform are listed on the Commander4j [[Downloads]] page.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Repository:&#039;&#039;&#039; [https://github.com/C4J/LogoClient https://github.com/C4J/LogoClient]&lt;br /&gt;
* &#039;&#039;&#039;Releases (download media):&#039;&#039;&#039; [https://github.com/C4J/LogoClient/releases https://github.com/C4J/LogoClient/releases]&lt;br /&gt;
* &#039;&#039;&#039;All Commander4j downloads:&#039;&#039;&#039; [[Downloads]]&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
Native install packages for &#039;&#039;&#039;Windows, macOS and Linux&#039;&#039;&#039; are available from the [[Downloads]] page and are the preferred installation method. Each installer bundles its own Java runtime, so &#039;&#039;&#039;no separate Java installation is required&#039;&#039;&#039;. Installing creates a native &#039;&#039;&#039;LogoClient&#039;&#039;&#039; launcher that can be started like any other desktop application.&lt;br /&gt;
&lt;br /&gt;
=== Running from the jar ===&lt;br /&gt;
&lt;br /&gt;
Alternatively the tool can be run directly as an ordinary Java (Swing) application:&lt;br /&gt;
&lt;br /&gt;
 java -jar c4j_logoclient.jar&lt;br /&gt;
&lt;br /&gt;
Running the jar requires a recent Java runtime (Java 21 or later). The bundled JSch library is required only for PL6 (SFTP); PL3 (TCP) has no external dependencies.&lt;br /&gt;
&lt;br /&gt;
== The Main Window ==&lt;br /&gt;
&lt;br /&gt;
The window has a &#039;&#039;&#039;connection bar&#039;&#039;&#039; across the top, a central &#039;&#039;&#039;file-transfer and directory area&#039;&#039;&#039;, a &#039;&#039;&#039;message pane&#039;&#039;&#039; for composing raw commands, and a pair of log panes along the bottom — an &#039;&#039;&#039;activity log&#039;&#039;&#039; and a &#039;&#039;&#039;wire trace&#039;&#039;&#039;. All transfer and command actions are disabled until a connection is open.&lt;br /&gt;
&lt;br /&gt;
=== Connecting ===&lt;br /&gt;
&lt;br /&gt;
In the connection bar you choose the connection &#039;&#039;&#039;Type&#039;&#039;&#039; (PL3 TCP or PL6 SFTP), enter the labeller&#039;s &#039;&#039;&#039;host / IP address&#039;&#039;&#039; and &#039;&#039;&#039;port&#039;&#039;&#039;, and — for PL6 — a &#039;&#039;&#039;username and password&#039;&#039;&#039;. Pressing the connect button opens the link; a status indicator shows the connected host and port. A real labeller is typically reached at its own network address (for example &amp;lt;code&amp;gt;192.168.1.100&amp;lt;/code&amp;gt;); the [[LogoRenderer]] emulator is reached at &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Options in the connection area let you list the remote directory automatically on connect, send a periodic &#039;&#039;&#039;heartbeat&#039;&#039;&#039; to detect a dropped link, and set the socket read timeout.&lt;br /&gt;
&lt;br /&gt;
=== Transferring and Managing Files ===&lt;br /&gt;
&lt;br /&gt;
The central area lists the files on the printer for a chosen remote path and file mask, showing each file&#039;s name, size, modified time and type. From here you can:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Upload&#039;&#039;&#039; a local file to the printer.&lt;br /&gt;
* &#039;&#039;&#039;Download&#039;&#039;&#039; one or more selected files to a chosen local folder.&lt;br /&gt;
* &#039;&#039;&#039;Delete&#039;&#039;&#039; selected files from the printer (with confirmation).&lt;br /&gt;
* &#039;&#039;&#039;Refresh&#039;&#039;&#039; the listing, and on PL6 navigate into sub-folders.&lt;br /&gt;
&lt;br /&gt;
PL3 exposes the printer&#039;s storage areas (&amp;lt;code&amp;gt;/c0/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/c9/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/f0/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/r0/&amp;lt;/code&amp;gt;) with file masks such as &amp;lt;code&amp;gt;*.llf&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;*.pcx&amp;lt;/code&amp;gt;; PL6 exposes its SFTP folders.&lt;br /&gt;
&lt;br /&gt;
=== Sending Commands and Field Data ===&lt;br /&gt;
&lt;br /&gt;
In PL3 mode the message pane composes and transmits raw text to the labeller. Control characters can be entered as readable tokens such as &amp;lt;code&amp;gt;&amp;lt;STX&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;lt;ETX&amp;gt;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;&amp;lt;CR&amp;gt;&amp;lt;/code&amp;gt;, and the end-of-line terminator appended on send is selectable. This is how layouts are activated, field data is sent, and LAMA/LSP queries are issued by hand. Replies appear in the activity log and the raw bytes in the wire trace.&lt;br /&gt;
&lt;br /&gt;
=== Pallet Log Polling ===&lt;br /&gt;
&lt;br /&gt;
LogoClient can poll the labeller&#039;s pallet log at a chosen interval and write the results to disk — one timestamped file per unique SSCC — into a chosen log folder. This reproduces, by hand, the &amp;quot;what was printed&amp;quot; feedback that production software collects, and works against both PL3 and PL6.&lt;br /&gt;
&lt;br /&gt;
=== Activity Log and Wire Trace ===&lt;br /&gt;
&lt;br /&gt;
Two panes record what happens. The &#039;&#039;&#039;activity log&#039;&#039;&#039; is a readable, timestamped narrative of connects, transfers, commands and errors. The &#039;&#039;&#039;wire trace&#039;&#039;&#039; shows the raw bytes in both directions — transmitted and received — with control characters rendered as tokens, which is invaluable when diagnosing exactly what a labeller sent or expected. Both panes can be saved to a text file or cleared.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
The connection details and interface preferences are saved when you quit and restored on the next start, so the tool reopens ready to reconnect to the labeller you last used.&lt;br /&gt;
&lt;br /&gt;
== Using LogoClient and LogoRenderer Together ==&lt;br /&gt;
&lt;br /&gt;
The two tools form a complete bench setup for label development with no Logopak hardware:&lt;br /&gt;
&lt;br /&gt;
# In &#039;&#039;&#039;[[LogoRenderer]]&#039;&#039;&#039;, start the &#039;&#039;&#039;printer emulator&#039;&#039;&#039; on a port (default 8000).&lt;br /&gt;
# In &#039;&#039;&#039;LogoClient&#039;&#039;&#039;, choose &#039;&#039;&#039;PL3 (TCP)&#039;&#039;&#039;, set the host to &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; and the matching port, and connect.&lt;br /&gt;
# &#039;&#039;&#039;Upload a layout&#039;&#039;&#039;, &#039;&#039;&#039;send field data&#039;&#039;&#039;, &#039;&#039;&#039;browse the emulated drives&#039;&#039;&#039; or &#039;&#039;&#039;poll the pallet log&#039;&#039;&#039; — and watch LogoRenderer render the result and log the traffic.&lt;br /&gt;
&lt;br /&gt;
In this arrangement LogoClient stands in for the driving software so you can develop and test against the renderer, while LogoRenderer stands in for the printer so you have something to talk to. LogoClient can equally be pointed at a real Logopak labeller when one is available.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[LogoRenderer]] — the companion tool that renders labels and emulates a Logopak printer&lt;br /&gt;
* [[Middleware4j]], [[LabelServer4j]], [[AutoLab4j]] — production software that drives Logopak labellers&lt;br /&gt;
* [[SocketTest]] — a raw TCP/IP testing utility&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=LogoRenderer&amp;diff=1873</id>
		<title>LogoRenderer</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=LogoRenderer&amp;diff=1873"/>
		<updated>2026-06-13T19:40:34Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: Updated by push_wiki.py&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;LogoRenderer&#039;&#039;&#039; (&#039;&#039;c4j_logorenderer&#039;&#039;) is a standalone desktop application that renders [[Logopak]] PowerLeap label layout files to a visual on-screen preview &#039;&#039;&#039;and&#039;&#039;&#039; can stand in for a physical label printer by emulating its TCP communication protocol. It exists so that label layouts and the software that drives them can be developed and tested &#039;&#039;&#039;on an ordinary PC, in environments where no physical Logopak labeller is available&#039;&#039;&#039; to test against.&lt;br /&gt;
&lt;br /&gt;
It is the rendering and printer-emulation half of a pair: [[LogoClient]] is the client that sends layouts and data to a printer, and LogoRenderer can play the part of that printer. Together they let you exercise the whole label-printing workflow with no hardware at all.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Disclaimer: LogoRenderer is an independent open-source tool and is &#039;&#039;&#039;not&#039;&#039;&#039; a Logopak product. It is not affiliated with, endorsed by, or supported by Logopak. Logopak, PowerLeap and related names are trademarks of their respective owners and are used solely to describe interoperability. The software is intended for local test and development use only — it must not be relied upon for production label printing.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
A Logopak PowerLeap labeller normally lives on the factory floor and is driven over the network by software provided by Logopak DE. When developing or supporting that software — or designing the label layouts themselves — it is often impractical to have a real labeller on the bench. LogoRenderer removes that dependency. It is useful when:&lt;br /&gt;
&lt;br /&gt;
* You need to &#039;&#039;&#039;see what a label layout will look like&#039;&#039;&#039; without printing it, by opening a &amp;lt;code&amp;gt;.llf&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.lqf&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;.ldf&amp;lt;/code&amp;gt; file and viewing a faithful preview.&lt;br /&gt;
* You are &#039;&#039;&#039;writing or debugging software that talks to a labeller&#039;&#039;&#039; and need something on the network that answers the same protocol — without owning the hardware.&lt;br /&gt;
* You want to &#039;&#039;&#039;develop without a physical Logopak&#039;&#039;&#039; altogether: render layouts, emulate the printer, and feed it from [[LogoClient]] or your own client code.&lt;br /&gt;
* You need to &#039;&#039;&#039;check field data and operator prompts&#039;&#039;&#039; (LQF query fields) by typing values and watching the rendered label update.&lt;br /&gt;
* You are &#039;&#039;&#039;tuning fonts&#039;&#039;&#039; so the on-screen rendering matches a real printed label.&lt;br /&gt;
&lt;br /&gt;
== Label and Data File Types ==&lt;br /&gt;
&lt;br /&gt;
LogoRenderer understands the PowerLeap LEAP layout family:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Extension !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.llf&amp;lt;/code&amp;gt; || Layout File — a complete label layout with all field data embedded. Opening one renders the label immediately.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.lqf&amp;lt;/code&amp;gt; || Query Layout File — a base layout containing &amp;lt;code&amp;gt;QUE&amp;lt;/code&amp;gt; operator prompts for fields that are filled in at print time. Opening one also populates the &#039;&#039;&#039;QUE Input&#039;&#039;&#039; tab so values can be typed in.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.ldf&amp;lt;/code&amp;gt; || Data File — a data-only file that references a master layout. Opening one runs its &amp;lt;code&amp;gt;LOAD&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;FD&amp;lt;/code&amp;gt; commands to load the referenced layout and populate its fields.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Layouts may reference &amp;lt;code&amp;gt;.pcx&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;.bmp&amp;lt;/code&amp;gt; images (logotypes) and a range of barcode types. A reference list of the wider Logopak file-type ecosystem is maintained alongside the project.&lt;br /&gt;
&lt;br /&gt;
== Source Code and Releases ==&lt;br /&gt;
&lt;br /&gt;
LogoRenderer is part of the open-source Commander4j suite and is distributed under the GNU General Public License. The source code and release downloads are hosted on GitHub, and native install packages for every platform are listed on the Commander4j [[Downloads]] page.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Repository:&#039;&#039;&#039; [https://github.com/C4J/LogoRenderer https://github.com/C4J/LogoRenderer]&lt;br /&gt;
* &#039;&#039;&#039;Releases (download media):&#039;&#039;&#039; [https://github.com/C4J/LogoRenderer/releases https://github.com/C4J/LogoRenderer/releases]&lt;br /&gt;
* &#039;&#039;&#039;All Commander4j downloads:&#039;&#039;&#039; [[Downloads]]&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
Native install packages for &#039;&#039;&#039;Windows, macOS and Linux&#039;&#039;&#039; are available from the [[Downloads]] page and are the preferred installation method. Each installer bundles its own Java runtime, so &#039;&#039;&#039;no separate Java installation is required&#039;&#039;&#039;. Installing creates a native &#039;&#039;&#039;LogoRenderer&#039;&#039;&#039; launcher that can be started like any other desktop application.&lt;br /&gt;
&lt;br /&gt;
=== Running from the jar ===&lt;br /&gt;
&lt;br /&gt;
Alternatively the tool can be run directly as an ordinary Java (Swing) application. It is built with Maven:&lt;br /&gt;
&lt;br /&gt;
 mvn package&lt;br /&gt;
 java -jar c4j_logorenderer.jar [file.llf]&lt;br /&gt;
&lt;br /&gt;
Running the jar requires a recent Java runtime (Java 25 or later). If a layout file is supplied on the command line it is opened on start-up; otherwise the application starts with an empty canvas. Demo layouts and data files are provided in the &amp;lt;code&amp;gt;virtual_disk/c0/&amp;lt;/code&amp;gt; folder.&lt;br /&gt;
&lt;br /&gt;
== The Main Window ==&lt;br /&gt;
&lt;br /&gt;
The window is divided into a &#039;&#039;&#039;label preview canvas&#039;&#039;&#039; on the left and a &#039;&#039;&#039;tabbed working area&#039;&#039;&#039; on the right, with a menu bar and toolbars around them and a status bar along the bottom. The title bar shows the program name, version and the name of the open file.&lt;br /&gt;
&lt;br /&gt;
The status bar reports the current file, the layout dimensions in printer dots and millimetres, the zoom level, and the number of fields in the layout.&lt;br /&gt;
&lt;br /&gt;
=== Preview Canvas ===&lt;br /&gt;
&lt;br /&gt;
The canvas shows the rendered label exactly as the layout describes it — text, scalable text, barcodes, graphic lines and boxes, and embedded logotype images. The rendering engine replicates the coordinate system and geometry of a PowerLeap III print head, including the upside-down (180°) print orientation. Clicking a rendered element highlights the source lines that produce it.&lt;br /&gt;
&lt;br /&gt;
=== Source / QUE Input / Log Tabs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Tab !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Source&#039;&#039;&#039; || Lists the raw layout commands, one per line, each with a checkbox and a plain-language description. Un-checking a line excludes it from the render, so individual elements can be toggled on and off. Selecting a line shows its properties for editing.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;QUE Input&#039;&#039;&#039; || For LQF layouts, presents one input box per operator prompt. Type values and apply them to see the populated label. This mirrors what an operator would be asked for at the machine.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Log&#039;&#039;&#039; || A colour-coded activity log showing file loads, parser messages, and all traffic to and from the printer emulator.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Viewing Controls ===&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;File&#039;&#039;&#039; menu opens and reloads layout files and exports the rendered label as a PNG image. The &#039;&#039;&#039;View&#039;&#039;&#039; menu provides zoom (preset levels, zoom in/out, and fit-to-window) and a &#039;&#039;&#039;Rotate 180°&#039;&#039;&#039; toggle that flips the preview to match the printer&#039;s print orientation.&lt;br /&gt;
&lt;br /&gt;
== Font Mapping ==&lt;br /&gt;
&lt;br /&gt;
Because Logopak fonts are not present on a development PC, LogoRenderer maps each Logopak font name to a Java font for rendering. The &#039;&#039;&#039;Settings → Font Mappings&#039;&#039;&#039; dialog lists every mapping and lets you set the Java font family (or a bundled TrueType file), style, reference cell size and calibration factors so that the on-screen text closely matches a real printed label. The mappings are stored in &amp;lt;code&amp;gt;xml/config/fonts.xml&amp;lt;/code&amp;gt;; fonts found in a layout but not yet mapped are added automatically with sensible defaults, ready to be fine-tuned.&lt;br /&gt;
&lt;br /&gt;
== The Printer Emulator ==&lt;br /&gt;
&lt;br /&gt;
This is the feature that makes hardware-free development possible. LogoRenderer can open a TCP server that emulates a Logopak PowerLeap III labeller, answering the same &#039;&#039;&#039;LEAP / LAMA&#039;&#039;&#039; protocol commands a real machine would.&lt;br /&gt;
&lt;br /&gt;
=== Starting the emulator ===&lt;br /&gt;
&lt;br /&gt;
The connection bar at the top of the window selects the &#039;&#039;&#039;IP address&#039;&#039;&#039; (default &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; for the local machine) and &#039;&#039;&#039;port&#039;&#039;&#039; (default &#039;&#039;&#039;8000&#039;&#039;&#039;, the PowerLeap III primary data port; &amp;lt;code&amp;gt;8100&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;8200&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;8300&amp;lt;/code&amp;gt; are also offered). Pressing &#039;&#039;&#039;Start Server&#039;&#039;&#039; begins listening; the Log tab shows when a client connects. Pressing the button again stops the server.&lt;br /&gt;
&lt;br /&gt;
=== What it emulates ===&lt;br /&gt;
&lt;br /&gt;
A connected client can do, against the emulator, the things it would do against a real labeller:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Browse and transfer files&#039;&#039;&#039; on an emulated drive — the &amp;lt;code&amp;gt;virtual_disk/&amp;lt;/code&amp;gt; folder provides the labeller&#039;s storage areas (&amp;lt;code&amp;gt;c0/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;c9/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;d0/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f0/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;r0/&amp;lt;/code&amp;gt;), so directory listings, downloads, uploads and deletes all behave realistically.&lt;br /&gt;
* &#039;&#039;&#039;Load a layout and send field data&#039;&#039;&#039; — when the client issues a &amp;lt;code&amp;gt;LOAD&amp;lt;/code&amp;gt; command the emulator loads that layout into the preview, and as &amp;lt;code&amp;gt;FD&amp;lt;/code&amp;gt; field-data commands arrive the on-screen label updates. The PC screen therefore shows what the real printer would be putting on a label.&lt;br /&gt;
* &#039;&#039;&#039;Retrieve logs&#039;&#039;&#039; — the emulator can serve pallet/label log files back to the client, so software that polls a labeller for &amp;quot;what was printed&amp;quot; can be tested end to end.&lt;br /&gt;
&lt;br /&gt;
=== Pallet print simulation ===&lt;br /&gt;
&lt;br /&gt;
When a loaded layout contains the pallet SSCC field, a &#039;&#039;&#039;Print Label&#039;&#039;&#039; control appears. Each press simulates a pallet print — two labels per pallet sharing one [https://en.wikipedia.org/wiki/Serial_Shipping_Container_Code SSCC] — increments the SSCC counter (persisted in &amp;lt;code&amp;gt;sscc.dat&amp;lt;/code&amp;gt;), and queues a log entry that a client can later retrieve. This lets log-polling and pallet-tracking logic be exercised without a real production run.&lt;br /&gt;
&lt;br /&gt;
== Using LogoRenderer and LogoClient Together ==&lt;br /&gt;
&lt;br /&gt;
The two tools form a complete bench setup for label development with no Logopak hardware:&lt;br /&gt;
&lt;br /&gt;
# In &#039;&#039;&#039;LogoRenderer&#039;&#039;&#039;, start the &#039;&#039;&#039;printer emulator&#039;&#039;&#039; on a port (default 8000).&lt;br /&gt;
# In &#039;&#039;&#039;[[LogoClient]]&#039;&#039;&#039;, connect in &#039;&#039;&#039;PL3 (TCP)&#039;&#039;&#039; mode to &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; on the same port.&lt;br /&gt;
# From LogoClient, &#039;&#039;&#039;upload a layout&#039;&#039;&#039;, &#039;&#039;&#039;send field data&#039;&#039;&#039;, &#039;&#039;&#039;browse the emulated drives&#039;&#039;&#039; or &#039;&#039;&#039;poll the pallet log&#039;&#039;&#039; — and watch LogoRenderer render the result and log the traffic.&lt;br /&gt;
&lt;br /&gt;
In this arrangement LogoRenderer stands in for the printer so you can develop and test a client, while LogoClient stands in for the driving software so you can drive the renderer. Either tool can equally be pointed at a real Logopak labeller when one is available.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[LogoClient]] — the client-side companion tool that sends layouts and data to a labeller (real or emulated)&lt;br /&gt;
* [[Middleware4j]], [[LabelServer4j]], [[AutoLab4j]] — production software that drives Logopak labellers&lt;br /&gt;
* [[ZPLRenderer]] — the equivalent preview tool for Zebra ZPL labels&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=LogoClient&amp;diff=1872</id>
		<title>LogoClient</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=LogoClient&amp;diff=1872"/>
		<updated>2026-06-13T19:35:33Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;LogoClient&#039;&#039;&#039; (&#039;&#039;c4j_logoclient&#039;&#039;) is a standalone desktop application — and underlying client library — for communicating with [[Logopak]] PowerLeap label printers over the network. It connects to a labeller, transfers layout and data files to and from it, sends commands and field data, browses the printer&#039;s on-board storage and retrieves its logs. It exists so that the software-to-labeller conversation can be developed, exercised and diagnosed &#039;&#039;&#039;on an ordinary PC, in environments where no physical Logopak labeller is available&#039;&#039;&#039; to test against.&lt;br /&gt;
&lt;br /&gt;
It is the client half of a pair: where a real labeller is not to hand, [[LogoRenderer]] can emulate one, and LogoClient talks to that emulator exactly as it would talk to real hardware. Together they let you exercise the whole label-printing workflow with no hardware at all.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Disclaimer: LogoClient is an independent open-source tool and is &#039;&#039;&#039;not&#039;&#039;&#039; a Logopak product. It is not affiliated with, endorsed by, or supported by Logopak. Logopak, PowerLeap and related names are trademarks of their respective owners and are used solely to describe interoperability. The software is intended for local test and development use only — it must not be relied upon for production label printing.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
Software from Logopak DE drives labellers in production. When developing or supporting that software it is useful to be able to perform the same low-level operations by hand, and to see exactly what goes across the wire. LogoClient is that tool. It is useful when:&lt;br /&gt;
&lt;br /&gt;
* You need to &#039;&#039;&#039;send a layout or data file to a labeller&#039;&#039;&#039; and confirm it loads correctly.&lt;br /&gt;
* You want to &#039;&#039;&#039;browse, upload, download or delete files&#039;&#039;&#039; on the printer&#039;s on-board drives.&lt;br /&gt;
* You are &#039;&#039;&#039;debugging the protocol&#039;&#039;&#039; and want a live, byte-level trace of everything sent and received.&lt;br /&gt;
* You need to &#039;&#039;&#039;send raw commands or field data&#039;&#039;&#039; to a labeller and read its replies.&lt;br /&gt;
* You want to &#039;&#039;&#039;poll a labeller&#039;s pallet log&#039;&#039;&#039; and capture one file per SSCC as labels are applied.&lt;br /&gt;
* You want to &#039;&#039;&#039;develop without a physical Logopak&#039;&#039;&#039; by pointing LogoClient at the [[LogoRenderer]] printer emulator instead of real hardware.&lt;br /&gt;
&lt;br /&gt;
== Supported Printers and Protocols ==&lt;br /&gt;
&lt;br /&gt;
LogoClient supports both current Logopak controller generations:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Mode !! Hardware !! Transport&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;PL3 (TCP)&#039;&#039;&#039; || PowerLeap III || Direct TCP socket on the data ports (8000 / 8100 / 8200 / 8300). Carries the full LEAP, LAMA/LACE and LSP command set — layout activation, field data, firmware queries, file management, I/O monitoring and asynchronous reporting.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;PL6 (SFTP)&#039;&#039;&#039; || PowerLeap 6 || File transfer over SFTP (port 22). PL6 is driven by exchanging files rather than TCP commands, so this mode is focused on uploading, downloading and listing files and reading the pallet log.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Source Code and Releases ==&lt;br /&gt;
&lt;br /&gt;
LogoClient is part of the open-source Commander4j suite and is distributed under the GNU General Public License.&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
Native install packages for &#039;&#039;&#039;Windows, macOS and Linux&#039;&#039;&#039; are available from the [[Downloads]] page and are the preferred installation method. Each installer bundles its own Java runtime, so &#039;&#039;&#039;no separate Java installation is required&#039;&#039;&#039;. Installing creates a native &#039;&#039;&#039;LogoClient&#039;&#039;&#039; launcher that can be started like any other desktop application.&lt;br /&gt;
&lt;br /&gt;
=== Running from the jar ===&lt;br /&gt;
&lt;br /&gt;
Alternatively the tool can be run directly as an ordinary Java (Swing) application:&lt;br /&gt;
&lt;br /&gt;
 java -jar c4j_logoclient.jar&lt;br /&gt;
&lt;br /&gt;
Running the jar requires a recent Java runtime (Java 21 or later). The bundled JSch library is required only for PL6 (SFTP); PL3 (TCP) has no external dependencies.&lt;br /&gt;
&lt;br /&gt;
== The Main Window ==&lt;br /&gt;
&lt;br /&gt;
The window has a &#039;&#039;&#039;connection bar&#039;&#039;&#039; across the top, a central &#039;&#039;&#039;file-transfer and directory area&#039;&#039;&#039;, a &#039;&#039;&#039;message pane&#039;&#039;&#039; for composing raw commands, and a pair of log panes along the bottom — an &#039;&#039;&#039;activity log&#039;&#039;&#039; and a &#039;&#039;&#039;wire trace&#039;&#039;&#039;. All transfer and command actions are disabled until a connection is open.&lt;br /&gt;
&lt;br /&gt;
=== Connecting ===&lt;br /&gt;
&lt;br /&gt;
In the connection bar you choose the connection &#039;&#039;&#039;Type&#039;&#039;&#039; (PL3 TCP or PL6 SFTP), enter the labeller&#039;s &#039;&#039;&#039;host / IP address&#039;&#039;&#039; and &#039;&#039;&#039;port&#039;&#039;&#039;, and — for PL6 — a &#039;&#039;&#039;username and password&#039;&#039;&#039;. Pressing the connect button opens the link; a status indicator shows the connected host and port. A real labeller is typically reached at its own network address (for example &amp;lt;code&amp;gt;192.168.1.100&amp;lt;/code&amp;gt;); the [[LogoRenderer]] emulator is reached at &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Options in the connection area let you list the remote directory automatically on connect, send a periodic &#039;&#039;&#039;heartbeat&#039;&#039;&#039; to detect a dropped link, and set the socket read timeout.&lt;br /&gt;
&lt;br /&gt;
=== Transferring and Managing Files ===&lt;br /&gt;
&lt;br /&gt;
The central area lists the files on the printer for a chosen remote path and file mask, showing each file&#039;s name, size, modified time and type. From here you can:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Upload&#039;&#039;&#039; a local file to the printer.&lt;br /&gt;
* &#039;&#039;&#039;Download&#039;&#039;&#039; one or more selected files to a chosen local folder.&lt;br /&gt;
* &#039;&#039;&#039;Delete&#039;&#039;&#039; selected files from the printer (with confirmation).&lt;br /&gt;
* &#039;&#039;&#039;Refresh&#039;&#039;&#039; the listing, and on PL6 navigate into sub-folders.&lt;br /&gt;
&lt;br /&gt;
PL3 exposes the printer&#039;s storage areas (&amp;lt;code&amp;gt;/c0/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/c9/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/f0/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/r0/&amp;lt;/code&amp;gt;) with file masks such as &amp;lt;code&amp;gt;*.llf&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;*.pcx&amp;lt;/code&amp;gt;; PL6 exposes its SFTP folders.&lt;br /&gt;
&lt;br /&gt;
=== Sending Commands and Field Data ===&lt;br /&gt;
&lt;br /&gt;
In PL3 mode the message pane composes and transmits raw text to the labeller. Control characters can be entered as readable tokens such as &amp;lt;code&amp;gt;&amp;lt;STX&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;lt;ETX&amp;gt;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;&amp;lt;CR&amp;gt;&amp;lt;/code&amp;gt;, and the end-of-line terminator appended on send is selectable. This is how layouts are activated, field data is sent, and LAMA/LSP queries are issued by hand. Replies appear in the activity log and the raw bytes in the wire trace.&lt;br /&gt;
&lt;br /&gt;
=== Pallet Log Polling ===&lt;br /&gt;
&lt;br /&gt;
LogoClient can poll the labeller&#039;s pallet log at a chosen interval and write the results to disk — one timestamped file per unique SSCC — into a chosen log folder. This reproduces, by hand, the &amp;quot;what was printed&amp;quot; feedback that production software collects, and works against both PL3 and PL6.&lt;br /&gt;
&lt;br /&gt;
=== Activity Log and Wire Trace ===&lt;br /&gt;
&lt;br /&gt;
Two panes record what happens. The &#039;&#039;&#039;activity log&#039;&#039;&#039; is a readable, timestamped narrative of connects, transfers, commands and errors. The &#039;&#039;&#039;wire trace&#039;&#039;&#039; shows the raw bytes in both directions — transmitted and received — with control characters rendered as tokens, which is invaluable when diagnosing exactly what a labeller sent or expected. Both panes can be saved to a text file or cleared.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
The connection details and interface preferences are saved when you quit and restored on the next start, so the tool reopens ready to reconnect to the labeller you last used.&lt;br /&gt;
&lt;br /&gt;
== Using LogoClient and LogoRenderer Together ==&lt;br /&gt;
&lt;br /&gt;
The two tools form a complete bench setup for label development with no Logopak hardware:&lt;br /&gt;
&lt;br /&gt;
# In &#039;&#039;&#039;[[LogoRenderer]]&#039;&#039;&#039;, start the &#039;&#039;&#039;printer emulator&#039;&#039;&#039; on a port (default 8000).&lt;br /&gt;
# In &#039;&#039;&#039;LogoClient&#039;&#039;&#039;, choose &#039;&#039;&#039;PL3 (TCP)&#039;&#039;&#039;, set the host to &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; and the matching port, and connect.&lt;br /&gt;
# &#039;&#039;&#039;Upload a layout&#039;&#039;&#039;, &#039;&#039;&#039;send field data&#039;&#039;&#039;, &#039;&#039;&#039;browse the emulated drives&#039;&#039;&#039; or &#039;&#039;&#039;poll the pallet log&#039;&#039;&#039; — and watch LogoRenderer render the result and log the traffic.&lt;br /&gt;
&lt;br /&gt;
In this arrangement LogoClient stands in for the driving software so you can develop and test against the renderer, while LogoRenderer stands in for the printer so you have something to talk to. LogoClient can equally be pointed at a real Logopak labeller when one is available.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[LogoRenderer]] — the companion tool that renders labels and emulates a Logopak printer&lt;br /&gt;
* [[Middleware4j]], [[LabelServer4j]], [[AutoLab4j]] — production software that drives Logopak labellers&lt;br /&gt;
* [[SocketTest]] — a raw TCP/IP testing utility&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=Downloads&amp;diff=1871</id>
		<title>Downloads</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=Downloads&amp;diff=1871"/>
		<updated>2026-06-13T19:34:01Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Commander4j]]&lt;br /&gt;
[[Category:LabelServer4j]]&lt;br /&gt;
[[Category:AutoLab4j]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;margin:auto&amp;quot;&lt;br /&gt;
|+ GitHub Downloads&lt;br /&gt;
|-&lt;br /&gt;
! Name !! Description&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J?tab=repositories All Projects] || Overview of all Projects &lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/Commander4j-AutoLab/releases AutoLab4j] || Automatic Label Application triggered by MODBUS&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/Commander4j/releases Commander4j] || Commander4j Core Application &lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/Commander4j-LabelServer/releases LabelServer4j] || Service to send Label Data to Labellers&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/LaunchPad/releases LaunchPad] || Menu system for Macos to replicate Launchpad&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/LogoClient/releases LogoClient] || Client for communication with LogoRenderer&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/LogoRenderer/releases LogoRenderer] || Interpret and view Logopak templates.&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/Menu4j/releases Menu4j] || Java Menu (tree) for launching applications and scripts&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/Commander4j-Middleware/releases Middleware4j] || Middleware for message translation to external systems&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/ModbusClient/releases Modbus Client] || Modbus Client&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/ModbusServer/releases Modbus Server] || Modbus Server&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/sftpGet/releases SFTP Get] || Utility to collect files automatically via SFTP&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/sftpSend/releases SFTP Send] || Utility to send files automatically via SFTP&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/sftpTransfer/releases SFTP-Transfer] || SFTP Send and Receive Automatically.&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/SocketTest/releases SocketTest] || TCP/IP Client for device comms and debugging&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/TreeDoc/releases TreeDoc] || Easy way to create a document for directory structure&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/XML-Viewer/releases XML-Viewer] || Utility for viewing XML documents &lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/ZPL-Renderer/releases ZPL-Renderer] || Emulates a Zebra ZPL labeller.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=Downloads&amp;diff=1870</id>
		<title>Downloads</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=Downloads&amp;diff=1870"/>
		<updated>2026-06-13T19:31:25Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Commander4j]]&lt;br /&gt;
[[Category:LabelServer4j]]&lt;br /&gt;
[[Category:AutoLab4j]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;margin:auto&amp;quot;&lt;br /&gt;
|+ GitHub Downloads&lt;br /&gt;
|-&lt;br /&gt;
! Name !! Description&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J?tab=repositories All Projects] || Overview of all Projects &lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/Commander4j/releases Commander4j] || Commander4j Core Application &lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/Commander4j-Middleware/releases Middleware4j] || Middleware for message translation to external systems&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/Commander4j-AutoLab/releases AutoLab4j] || Automatic Label Application triggered by MODBUS&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/Commander4j-LabelServer/releases LabelServer4j] || Service to send Label Data to Labellers&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/sftpTransfer/releases SFTP-Transfer] || SFTP Send and Receive Automatically.&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/sftpSend/releases SFTP Send] || Utility to send files automatically via SFTP&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/sftpGet/releases SFTP Get] || Utility to collect files automatically via SFTP&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/Menu4j/releases Menu4j] || Java Menu (tree) for launching applications and scripts&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/SocketTest/releases SocketTest] || TCP/IP Client for device comms and debugging&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/ZPL-Renderer/releases ZPL-Renderer] || Emulates a Zebra ZPL labeller.&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/XML-Viewer/releases XML-Viewer] || Utility for viewing XML documents &lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/ModbusServer/releases Modbus Server] || Modbus Server&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/ModbusClient/releases Modbus Client] || Modbus Client&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/TreeDoc/releases TreeDoc] || Easy way to create a document for directory structure&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/LaunchPad/releases LaunchPad] || Menu system for Macos to replicate Launchpad&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/LogoRenderer/releases LogoRenderer] || Interpret and view Logopak templates.&lt;br /&gt;
|-&lt;br /&gt;
| [https://github.com/C4J/LogoClient/releases LogoClient] || Client for communication with LogoRenderer&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=LogoRenderer&amp;diff=1869</id>
		<title>LogoRenderer</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=LogoRenderer&amp;diff=1869"/>
		<updated>2026-06-13T19:28:23Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;LogoRenderer&#039;&#039;&#039; (&#039;&#039;c4j_logorenderer&#039;&#039;) is a standalone desktop application that renders [[Logopak]] PowerLeap label layout files to a visual on-screen preview &#039;&#039;&#039;and&#039;&#039;&#039; can stand in for a physical label printer by emulating its TCP communication protocol. It exists so that label layouts and the software that drives them can be developed and tested &#039;&#039;&#039;on an ordinary PC, in environments where no physical Logopak labeller is available&#039;&#039;&#039; to test against.&lt;br /&gt;
&lt;br /&gt;
It is the rendering and printer-emulation half of a pair: [[LogoClient]] is the client that sends layouts and data to a printer, and LogoRenderer can play the part of that printer. Together they let you exercise the whole label-printing workflow with no hardware at all.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Disclaimer: LogoRenderer is an independent open-source tool and is &#039;&#039;&#039;not&#039;&#039;&#039; a Logopak product. It is not affiliated with, endorsed by, or supported by Logopak. Logopak, PowerLeap and related names are trademarks of their respective owners and are used solely to describe interoperability. The software is intended for local test and development use only — it must not be relied upon for production label printing.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
A Logopak PowerLeap labeller normally lives on the factory floor and is driven over the network by software provided by Logopak DE. When developing or supporting that software — or designing the label layouts themselves — it is often impractical to have a real labeller on the bench. LogoRenderer removes that dependency. It is useful when:&lt;br /&gt;
&lt;br /&gt;
* You need to &#039;&#039;&#039;see what a label layout will look like&#039;&#039;&#039; without printing it, by opening a &amp;lt;code&amp;gt;.llf&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.lqf&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;.ldf&amp;lt;/code&amp;gt; file and viewing a faithful preview.&lt;br /&gt;
* You are &#039;&#039;&#039;writing or debugging software that talks to a labeller&#039;&#039;&#039; and need something on the network that answers the same protocol — without owning the hardware.&lt;br /&gt;
* You want to &#039;&#039;&#039;develop without a physical Logopak&#039;&#039;&#039; altogether: render layouts, emulate the printer, and feed it from [[LogoClient]] or your own client code.&lt;br /&gt;
* You need to &#039;&#039;&#039;check field data and operator prompts&#039;&#039;&#039; (LQF query fields) by typing values and watching the rendered label update.&lt;br /&gt;
* You are &#039;&#039;&#039;tuning fonts&#039;&#039;&#039; so the on-screen rendering matches a real printed label.&lt;br /&gt;
&lt;br /&gt;
== Label and Data File Types ==&lt;br /&gt;
&lt;br /&gt;
LogoRenderer understands the PowerLeap LEAP layout family:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Extension !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.llf&amp;lt;/code&amp;gt; || Layout File — a complete label layout with all field data embedded. Opening one renders the label immediately.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.lqf&amp;lt;/code&amp;gt; || Query Layout File — a base layout containing &amp;lt;code&amp;gt;QUE&amp;lt;/code&amp;gt; operator prompts for fields that are filled in at print time. Opening one also populates the &#039;&#039;&#039;QUE Input&#039;&#039;&#039; tab so values can be typed in.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.ldf&amp;lt;/code&amp;gt; || Data File — a data-only file that references a master layout. Opening one runs its &amp;lt;code&amp;gt;LOAD&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;FD&amp;lt;/code&amp;gt; commands to load the referenced layout and populate its fields.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Layouts may reference &amp;lt;code&amp;gt;.pcx&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;.bmp&amp;lt;/code&amp;gt; images (logotypes) and a range of barcode types. A reference list of the wider Logopak file-type ecosystem is maintained alongside the project.&lt;br /&gt;
&lt;br /&gt;
== Source Code and Releases ==&lt;br /&gt;
&lt;br /&gt;
LogoRenderer is part of the open-source Commander4j suite and is distributed under the GNU General Public License.&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
Native install packages for &#039;&#039;&#039;Windows, macOS and Linux&#039;&#039;&#039; are available from the [[Downloads]] page and are the preferred installation method. Each installer bundles its own Java runtime, so &#039;&#039;&#039;no separate Java installation is required&#039;&#039;&#039;. Installing creates a native &#039;&#039;&#039;LogoRenderer&#039;&#039;&#039; launcher that can be started like any other desktop application.&lt;br /&gt;
&lt;br /&gt;
=== Running from the jar ===&lt;br /&gt;
&lt;br /&gt;
Alternatively the tool can be run directly as an ordinary Java (Swing) application. It is built with Maven:&lt;br /&gt;
&lt;br /&gt;
 mvn package&lt;br /&gt;
 java -jar c4j_logorenderer.jar [file.llf]&lt;br /&gt;
&lt;br /&gt;
Running the jar requires a recent Java runtime (Java 25 or later). If a layout file is supplied on the command line it is opened on start-up; otherwise the application starts with an empty canvas. Demo layouts and data files are provided in the &amp;lt;code&amp;gt;virtual_disk/c0/&amp;lt;/code&amp;gt; folder.&lt;br /&gt;
&lt;br /&gt;
== The Main Window ==&lt;br /&gt;
&lt;br /&gt;
The window is divided into a &#039;&#039;&#039;label preview canvas&#039;&#039;&#039; on the left and a &#039;&#039;&#039;tabbed working area&#039;&#039;&#039; on the right, with a menu bar and toolbars around them and a status bar along the bottom. The title bar shows the program name, version and the name of the open file.&lt;br /&gt;
&lt;br /&gt;
The status bar reports the current file, the layout dimensions in printer dots and millimetres, the zoom level, and the number of fields in the layout.&lt;br /&gt;
&lt;br /&gt;
=== Preview Canvas ===&lt;br /&gt;
&lt;br /&gt;
The canvas shows the rendered label exactly as the layout describes it — text, scalable text, barcodes, graphic lines and boxes, and embedded logotype images. The rendering engine replicates the coordinate system and geometry of a PowerLeap III print head, including the upside-down (180°) print orientation. Clicking a rendered element highlights the source lines that produce it.&lt;br /&gt;
&lt;br /&gt;
=== Source / QUE Input / Log Tabs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Tab !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Source&#039;&#039;&#039; || Lists the raw layout commands, one per line, each with a checkbox and a plain-language description. Un-checking a line excludes it from the render, so individual elements can be toggled on and off. Selecting a line shows its properties for editing.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;QUE Input&#039;&#039;&#039; || For LQF layouts, presents one input box per operator prompt. Type values and apply them to see the populated label. This mirrors what an operator would be asked for at the machine.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Log&#039;&#039;&#039; || A colour-coded activity log showing file loads, parser messages, and all traffic to and from the printer emulator.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Viewing Controls ===&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;File&#039;&#039;&#039; menu opens and reloads layout files and exports the rendered label as a PNG image. The &#039;&#039;&#039;View&#039;&#039;&#039; menu provides zoom (preset levels, zoom in/out, and fit-to-window) and a &#039;&#039;&#039;Rotate 180°&#039;&#039;&#039; toggle that flips the preview to match the printer&#039;s print orientation.&lt;br /&gt;
&lt;br /&gt;
== Font Mapping ==&lt;br /&gt;
&lt;br /&gt;
Because Logopak fonts are not present on a development PC, LogoRenderer maps each Logopak font name to a Java font for rendering. The &#039;&#039;&#039;Settings → Font Mappings&#039;&#039;&#039; dialog lists every mapping and lets you set the Java font family (or a bundled TrueType file), style, reference cell size and calibration factors so that the on-screen text closely matches a real printed label. The mappings are stored in &amp;lt;code&amp;gt;xml/config/fonts.xml&amp;lt;/code&amp;gt;; fonts found in a layout but not yet mapped are added automatically with sensible defaults, ready to be fine-tuned.&lt;br /&gt;
&lt;br /&gt;
== The Printer Emulator ==&lt;br /&gt;
&lt;br /&gt;
This is the feature that makes hardware-free development possible. LogoRenderer can open a TCP server that emulates a Logopak PowerLeap III labeller, answering the same &#039;&#039;&#039;LEAP / LAMA&#039;&#039;&#039; protocol commands a real machine would.&lt;br /&gt;
&lt;br /&gt;
=== Starting the emulator ===&lt;br /&gt;
&lt;br /&gt;
The connection bar at the top of the window selects the &#039;&#039;&#039;IP address&#039;&#039;&#039; (default &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; for the local machine) and &#039;&#039;&#039;port&#039;&#039;&#039; (default &#039;&#039;&#039;8000&#039;&#039;&#039;, the PowerLeap III primary data port; &amp;lt;code&amp;gt;8100&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;8200&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;8300&amp;lt;/code&amp;gt; are also offered). Pressing &#039;&#039;&#039;Start Server&#039;&#039;&#039; begins listening; the Log tab shows when a client connects. Pressing the button again stops the server.&lt;br /&gt;
&lt;br /&gt;
=== What it emulates ===&lt;br /&gt;
&lt;br /&gt;
A connected client can do, against the emulator, the things it would do against a real labeller:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Browse and transfer files&#039;&#039;&#039; on an emulated drive — the &amp;lt;code&amp;gt;virtual_disk/&amp;lt;/code&amp;gt; folder provides the labeller&#039;s storage areas (&amp;lt;code&amp;gt;c0/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;c9/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;d0/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f0/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;r0/&amp;lt;/code&amp;gt;), so directory listings, downloads, uploads and deletes all behave realistically.&lt;br /&gt;
* &#039;&#039;&#039;Load a layout and send field data&#039;&#039;&#039; — when the client issues a &amp;lt;code&amp;gt;LOAD&amp;lt;/code&amp;gt; command the emulator loads that layout into the preview, and as &amp;lt;code&amp;gt;FD&amp;lt;/code&amp;gt; field-data commands arrive the on-screen label updates. The PC screen therefore shows what the real printer would be putting on a label.&lt;br /&gt;
* &#039;&#039;&#039;Retrieve logs&#039;&#039;&#039; — the emulator can serve pallet/label log files back to the client, so software that polls a labeller for &amp;quot;what was printed&amp;quot; can be tested end to end.&lt;br /&gt;
&lt;br /&gt;
=== Pallet print simulation ===&lt;br /&gt;
&lt;br /&gt;
When a loaded layout contains the pallet SSCC field, a &#039;&#039;&#039;Print Label&#039;&#039;&#039; control appears. Each press simulates a pallet print — two labels per pallet sharing one [https://en.wikipedia.org/wiki/Serial_Shipping_Container_Code SSCC] — increments the SSCC counter (persisted in &amp;lt;code&amp;gt;sscc.dat&amp;lt;/code&amp;gt;), and queues a log entry that a client can later retrieve. This lets log-polling and pallet-tracking logic be exercised without a real production run.&lt;br /&gt;
&lt;br /&gt;
== Using LogoRenderer and LogoClient Together ==&lt;br /&gt;
&lt;br /&gt;
The two tools form a complete bench setup for label development with no Logopak hardware:&lt;br /&gt;
&lt;br /&gt;
# In &#039;&#039;&#039;LogoRenderer&#039;&#039;&#039;, start the &#039;&#039;&#039;printer emulator&#039;&#039;&#039; on a port (default 8000).&lt;br /&gt;
# In &#039;&#039;&#039;[[LogoClient]]&#039;&#039;&#039;, connect in &#039;&#039;&#039;PL3 (TCP)&#039;&#039;&#039; mode to &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; on the same port.&lt;br /&gt;
# From LogoClient, &#039;&#039;&#039;upload a layout&#039;&#039;&#039;, &#039;&#039;&#039;send field data&#039;&#039;&#039;, &#039;&#039;&#039;browse the emulated drives&#039;&#039;&#039; or &#039;&#039;&#039;poll the pallet log&#039;&#039;&#039; — and watch LogoRenderer render the result and log the traffic.&lt;br /&gt;
&lt;br /&gt;
In this arrangement LogoRenderer stands in for the printer so you can develop and test a client, while LogoClient stands in for the driving software so you can drive the renderer. Either tool can equally be pointed at a real Logopak labeller when one is available.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[LogoClient]] — the client-side companion tool that sends layouts and data to a labeller (real or emulated)&lt;br /&gt;
* [[Middleware4j]], [[LabelServer4j]], [[AutoLab4j]] — production software that drives Logopak labellers&lt;br /&gt;
* [[ZPLRenderer]] — the equivalent preview tool for Zebra ZPL labels&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=LogoRenderer&amp;diff=1868</id>
		<title>LogoRenderer</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=LogoRenderer&amp;diff=1868"/>
		<updated>2026-06-13T19:27:28Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;LogoRenderer&#039;&#039;&#039; (&#039;&#039;c4j_logorenderer&#039;&#039;) is a standalone desktop application that renders [[Logopak]] PowerLeap label layout files to a visual on-screen preview &#039;&#039;&#039;and&#039;&#039;&#039; can stand in for a physical label printer by emulating its TCP communication protocol. It exists so that label layouts and the software that drives them can be developed and tested &#039;&#039;&#039;on an ordinary PC, in environments where no physical Logopak labeller is available&#039;&#039;&#039; to test against.&lt;br /&gt;
&lt;br /&gt;
It is the rendering and printer-emulation half of a pair: [[LogoClient]] is the client that sends layouts and data to a printer, and LogoRenderer can play the part of that printer. Together they let you exercise the whole label-printing workflow with no hardware at all.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Disclaimer: LogoRenderer is an independent open-source tool and is &#039;&#039;&#039;not&#039;&#039;&#039; a Logopak product. It is not affiliated with, endorsed by, or supported by Logopak. Logopak, PowerLeap and related names are trademarks of their respective owners and are used solely to describe interoperability. The software is intended for local test and development use only — it must not be relied upon for production label printing.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
A Logopak PowerLeap labeller normally lives on the factory floor and is driven over the network by software provided by Logopak DE. When developing or supporting that software — or designing the label layouts themselves — it is often impractical to have a real labeller on the bench. LogoRenderer removes that dependency. It is useful when:&lt;br /&gt;
&lt;br /&gt;
* You need to &#039;&#039;&#039;see what a label layout will look like&#039;&#039;&#039; without printing it, by opening a &amp;lt;code&amp;gt;.llf&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.lqf&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;.ldf&amp;lt;/code&amp;gt; file and viewing a faithful preview.&lt;br /&gt;
* You are &#039;&#039;&#039;writing or debugging software that talks to a labeller&#039;&#039;&#039; and need something on the network that answers the same protocol — without owning the hardware.&lt;br /&gt;
* You want to &#039;&#039;&#039;develop without a physical Logopak&#039;&#039;&#039; altogether: render layouts, emulate the printer, and feed it from [[LogoClient]] or your own client code.&lt;br /&gt;
* You need to &#039;&#039;&#039;check field data and operator prompts&#039;&#039;&#039; (LQF query fields) by typing values and watching the rendered label update.&lt;br /&gt;
* You are &#039;&#039;&#039;tuning fonts&#039;&#039;&#039; so the on-screen rendering matches a real printed label.&lt;br /&gt;
&lt;br /&gt;
== Label and Data File Types ==&lt;br /&gt;
&lt;br /&gt;
LogoRenderer understands the PowerLeap LEAP layout family:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Extension !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.llf&amp;lt;/code&amp;gt; || Layout File — a complete label layout with all field data embedded. Opening one renders the label immediately.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.lqf&amp;lt;/code&amp;gt; || Query Layout File — a base layout containing &amp;lt;code&amp;gt;QUE&amp;lt;/code&amp;gt; operator prompts for fields that are filled in at print time. Opening one also populates the &#039;&#039;&#039;QUE Input&#039;&#039;&#039; tab so values can be typed in.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.ldf&amp;lt;/code&amp;gt; || Data File — a data-only file that references a master layout. Opening one runs its &amp;lt;code&amp;gt;LOAD&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;FD&amp;lt;/code&amp;gt; commands to load the referenced layout and populate its fields.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Layouts may reference &amp;lt;code&amp;gt;.pcx&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;.bmp&amp;lt;/code&amp;gt; images (logotypes) and a range of barcode types. A reference list of the wider Logopak file-type ecosystem is maintained alongside the project.&lt;br /&gt;
&lt;br /&gt;
== Source Code and Releases ==&lt;br /&gt;
&lt;br /&gt;
LogoRenderer is part of the open-source Commander4j suite and is distributed under the GNU General Public License.&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
Native install packages for &#039;&#039;&#039;Windows, macOS and Linux&#039;&#039;&#039; are available from the [[Downloads]] page and are the preferred installation method. Each installer bundles its own Java runtime, so &#039;&#039;&#039;no separate Java installation is required&#039;&#039;&#039;. Installing creates a native &#039;&#039;&#039;LogoRenderer&#039;&#039;&#039; launcher that can be started like any other desktop application.&lt;br /&gt;
&lt;br /&gt;
=== Running from the jar ===&lt;br /&gt;
&lt;br /&gt;
Alternatively the tool can be run directly as an ordinary Java (Swing) application. It is built with Maven:&lt;br /&gt;
&lt;br /&gt;
 mvn package&lt;br /&gt;
 java -jar c4j_logorenderer.jar [file.llf]&lt;br /&gt;
&lt;br /&gt;
Running the jar requires a recent Java runtime (Java 21 or later). If a layout file is supplied on the command line it is opened on start-up; otherwise the application starts with an empty canvas. Demo layouts and data files are provided in the &amp;lt;code&amp;gt;virtual_disk/c0/&amp;lt;/code&amp;gt; folder.&lt;br /&gt;
&lt;br /&gt;
== The Main Window ==&lt;br /&gt;
&lt;br /&gt;
The window is divided into a &#039;&#039;&#039;label preview canvas&#039;&#039;&#039; on the left and a &#039;&#039;&#039;tabbed working area&#039;&#039;&#039; on the right, with a menu bar and toolbars around them and a status bar along the bottom. The title bar shows the program name, version and the name of the open file.&lt;br /&gt;
&lt;br /&gt;
The status bar reports the current file, the layout dimensions in printer dots and millimetres, the zoom level, and the number of fields in the layout.&lt;br /&gt;
&lt;br /&gt;
=== Preview Canvas ===&lt;br /&gt;
&lt;br /&gt;
The canvas shows the rendered label exactly as the layout describes it — text, scalable text, barcodes, graphic lines and boxes, and embedded logotype images. The rendering engine replicates the coordinate system and geometry of a PowerLeap III print head, including the upside-down (180°) print orientation. Clicking a rendered element highlights the source lines that produce it.&lt;br /&gt;
&lt;br /&gt;
=== Source / QUE Input / Log Tabs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Tab !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Source&#039;&#039;&#039; || Lists the raw layout commands, one per line, each with a checkbox and a plain-language description. Un-checking a line excludes it from the render, so individual elements can be toggled on and off. Selecting a line shows its properties for editing.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;QUE Input&#039;&#039;&#039; || For LQF layouts, presents one input box per operator prompt. Type values and apply them to see the populated label. This mirrors what an operator would be asked for at the machine.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Log&#039;&#039;&#039; || A colour-coded activity log showing file loads, parser messages, and all traffic to and from the printer emulator.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Viewing Controls ===&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;File&#039;&#039;&#039; menu opens and reloads layout files and exports the rendered label as a PNG image. The &#039;&#039;&#039;View&#039;&#039;&#039; menu provides zoom (preset levels, zoom in/out, and fit-to-window) and a &#039;&#039;&#039;Rotate 180°&#039;&#039;&#039; toggle that flips the preview to match the printer&#039;s print orientation.&lt;br /&gt;
&lt;br /&gt;
== Font Mapping ==&lt;br /&gt;
&lt;br /&gt;
Because Logopak fonts are not present on a development PC, LogoRenderer maps each Logopak font name to a Java font for rendering. The &#039;&#039;&#039;Settings → Font Mappings&#039;&#039;&#039; dialog lists every mapping and lets you set the Java font family (or a bundled TrueType file), style, reference cell size and calibration factors so that the on-screen text closely matches a real printed label. The mappings are stored in &amp;lt;code&amp;gt;xml/config/fonts.xml&amp;lt;/code&amp;gt;; fonts found in a layout but not yet mapped are added automatically with sensible defaults, ready to be fine-tuned.&lt;br /&gt;
&lt;br /&gt;
== The Printer Emulator ==&lt;br /&gt;
&lt;br /&gt;
This is the feature that makes hardware-free development possible. LogoRenderer can open a TCP server that emulates a Logopak PowerLeap III labeller, answering the same &#039;&#039;&#039;LEAP / LAMA&#039;&#039;&#039; protocol commands a real machine would.&lt;br /&gt;
&lt;br /&gt;
=== Starting the emulator ===&lt;br /&gt;
&lt;br /&gt;
The connection bar at the top of the window selects the &#039;&#039;&#039;IP address&#039;&#039;&#039; (default &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; for the local machine) and &#039;&#039;&#039;port&#039;&#039;&#039; (default &#039;&#039;&#039;8000&#039;&#039;&#039;, the PowerLeap III primary data port; &amp;lt;code&amp;gt;8100&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;8200&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;8300&amp;lt;/code&amp;gt; are also offered). Pressing &#039;&#039;&#039;Start Server&#039;&#039;&#039; begins listening; the Log tab shows when a client connects. Pressing the button again stops the server.&lt;br /&gt;
&lt;br /&gt;
=== What it emulates ===&lt;br /&gt;
&lt;br /&gt;
A connected client can do, against the emulator, the things it would do against a real labeller:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Browse and transfer files&#039;&#039;&#039; on an emulated drive — the &amp;lt;code&amp;gt;virtual_disk/&amp;lt;/code&amp;gt; folder provides the labeller&#039;s storage areas (&amp;lt;code&amp;gt;c0/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;c9/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;d0/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f0/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;r0/&amp;lt;/code&amp;gt;), so directory listings, downloads, uploads and deletes all behave realistically.&lt;br /&gt;
* &#039;&#039;&#039;Load a layout and send field data&#039;&#039;&#039; — when the client issues a &amp;lt;code&amp;gt;LOAD&amp;lt;/code&amp;gt; command the emulator loads that layout into the preview, and as &amp;lt;code&amp;gt;FD&amp;lt;/code&amp;gt; field-data commands arrive the on-screen label updates. The PC screen therefore shows what the real printer would be putting on a label.&lt;br /&gt;
* &#039;&#039;&#039;Retrieve logs&#039;&#039;&#039; — the emulator can serve pallet/label log files back to the client, so software that polls a labeller for &amp;quot;what was printed&amp;quot; can be tested end to end.&lt;br /&gt;
&lt;br /&gt;
=== Pallet print simulation ===&lt;br /&gt;
&lt;br /&gt;
When a loaded layout contains the pallet SSCC field, a &#039;&#039;&#039;Print Label&#039;&#039;&#039; control appears. Each press simulates a pallet print — two labels per pallet sharing one [https://en.wikipedia.org/wiki/Serial_Shipping_Container_Code SSCC] — increments the SSCC counter (persisted in &amp;lt;code&amp;gt;sscc.dat&amp;lt;/code&amp;gt;), and queues a log entry that a client can later retrieve. This lets log-polling and pallet-tracking logic be exercised without a real production run.&lt;br /&gt;
&lt;br /&gt;
== Using LogoRenderer and LogoClient Together ==&lt;br /&gt;
&lt;br /&gt;
The two tools form a complete bench setup for label development with no Logopak hardware:&lt;br /&gt;
&lt;br /&gt;
# In &#039;&#039;&#039;LogoRenderer&#039;&#039;&#039;, start the &#039;&#039;&#039;printer emulator&#039;&#039;&#039; on a port (default 8000).&lt;br /&gt;
# In &#039;&#039;&#039;[[LogoClient]]&#039;&#039;&#039;, connect in &#039;&#039;&#039;PL3 (TCP)&#039;&#039;&#039; mode to &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; on the same port.&lt;br /&gt;
# From LogoClient, &#039;&#039;&#039;upload a layout&#039;&#039;&#039;, &#039;&#039;&#039;send field data&#039;&#039;&#039;, &#039;&#039;&#039;browse the emulated drives&#039;&#039;&#039; or &#039;&#039;&#039;poll the pallet log&#039;&#039;&#039; — and watch LogoRenderer render the result and log the traffic.&lt;br /&gt;
&lt;br /&gt;
In this arrangement LogoRenderer stands in for the printer so you can develop and test a client, while LogoClient stands in for the driving software so you can drive the renderer. Either tool can equally be pointed at a real Logopak labeller when one is available.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[LogoClient]] — the client-side companion tool that sends layouts and data to a labeller (real or emulated)&lt;br /&gt;
* [[Middleware4j]], [[LabelServer4j]], [[AutoLab4j]] — production software that drives Logopak labellers&lt;br /&gt;
* [[ZPLRenderer]] — the equivalent preview tool for Zebra ZPL labels&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=LogoClient&amp;diff=1867</id>
		<title>LogoClient</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=LogoClient&amp;diff=1867"/>
		<updated>2026-06-13T19:23:13Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: Updated by push_wiki.py&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;LogoClient&#039;&#039;&#039; (&#039;&#039;c4j_logoclient&#039;&#039;) is a standalone desktop application — and underlying client library — for communicating with [[Logopak]] PowerLeap label printers over the network. It connects to a labeller, transfers layout and data files to and from it, sends commands and field data, browses the printer&#039;s on-board storage and retrieves its logs. It exists so that the software-to-labeller conversation can be developed, exercised and diagnosed &#039;&#039;&#039;on an ordinary PC, in environments where no physical Logopak labeller is available&#039;&#039;&#039; to test against.&lt;br /&gt;
&lt;br /&gt;
It is the client half of a pair: where a real labeller is not to hand, [[LogoRenderer]] can emulate one, and LogoClient talks to that emulator exactly as it would talk to real hardware. Together they let you exercise the whole label-printing workflow with no hardware at all.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Disclaimer: LogoClient is an independent open-source tool and is &#039;&#039;&#039;not&#039;&#039;&#039; a Logopak product. It is not affiliated with, endorsed by, or supported by Logopak. Logopak, PowerLeap and related names are trademarks of their respective owners and are used solely to describe interoperability. The software is intended for local test and development use only — it must not be relied upon for production label printing.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
Software such as [[Middleware4j]], [[LabelServer4j]] and [[AutoLab4j]] drives Logopak labellers in production. When developing or supporting that software it is useful to be able to perform the same low-level operations by hand, and to see exactly what goes across the wire. LogoClient is that tool. It is useful when:&lt;br /&gt;
&lt;br /&gt;
* You need to &#039;&#039;&#039;send a layout or data file to a labeller&#039;&#039;&#039; and confirm it loads correctly.&lt;br /&gt;
* You want to &#039;&#039;&#039;browse, upload, download or delete files&#039;&#039;&#039; on the printer&#039;s on-board drives.&lt;br /&gt;
* You are &#039;&#039;&#039;debugging the protocol&#039;&#039;&#039; and want a live, byte-level trace of everything sent and received.&lt;br /&gt;
* You need to &#039;&#039;&#039;send raw commands or field data&#039;&#039;&#039; to a labeller and read its replies.&lt;br /&gt;
* You want to &#039;&#039;&#039;poll a labeller&#039;s pallet log&#039;&#039;&#039; and capture one file per SSCC as labels are applied.&lt;br /&gt;
* You want to &#039;&#039;&#039;develop without a physical Logopak&#039;&#039;&#039; by pointing LogoClient at the [[LogoRenderer]] printer emulator instead of real hardware.&lt;br /&gt;
&lt;br /&gt;
== Supported Printers and Protocols ==&lt;br /&gt;
&lt;br /&gt;
LogoClient supports both current Logopak controller generations:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Mode !! Hardware !! Transport&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;PL3 (TCP)&#039;&#039;&#039; || PowerLeap III || Direct TCP socket on the data ports (8000 / 8100 / 8200 / 8300). Carries the full LEAP, LAMA/LACE and LSP command set — layout activation, field data, firmware queries, file management, I/O monitoring and asynchronous reporting.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;PL6 (SFTP)&#039;&#039;&#039; || PowerLeap 6 || File transfer over SFTP (port 22). PL6 is driven by exchanging files rather than TCP commands, so this mode is focused on uploading, downloading and listing files and reading the pallet log.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Source Code and Releases ==&lt;br /&gt;
&lt;br /&gt;
LogoClient is part of the open-source Commander4j suite and is distributed under the GNU General Public License.&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
Native install packages for &#039;&#039;&#039;Windows, macOS and Linux&#039;&#039;&#039; are available from the [[Downloads]] page and are the preferred installation method. Each installer bundles its own Java runtime, so &#039;&#039;&#039;no separate Java installation is required&#039;&#039;&#039;. Installing creates a native &#039;&#039;&#039;LogoClient&#039;&#039;&#039; launcher that can be started like any other desktop application.&lt;br /&gt;
&lt;br /&gt;
=== Running from the jar ===&lt;br /&gt;
&lt;br /&gt;
Alternatively the tool can be run directly as an ordinary Java (Swing) application:&lt;br /&gt;
&lt;br /&gt;
 java -jar c4j_logoclient.jar&lt;br /&gt;
&lt;br /&gt;
Running the jar requires a recent Java runtime (Java 21 or later). The bundled JSch library is required only for PL6 (SFTP); PL3 (TCP) has no external dependencies.&lt;br /&gt;
&lt;br /&gt;
== The Main Window ==&lt;br /&gt;
&lt;br /&gt;
The window has a &#039;&#039;&#039;connection bar&#039;&#039;&#039; across the top, a central &#039;&#039;&#039;file-transfer and directory area&#039;&#039;&#039;, a &#039;&#039;&#039;message pane&#039;&#039;&#039; for composing raw commands, and a pair of log panes along the bottom — an &#039;&#039;&#039;activity log&#039;&#039;&#039; and a &#039;&#039;&#039;wire trace&#039;&#039;&#039;. All transfer and command actions are disabled until a connection is open.&lt;br /&gt;
&lt;br /&gt;
=== Connecting ===&lt;br /&gt;
&lt;br /&gt;
In the connection bar you choose the connection &#039;&#039;&#039;Type&#039;&#039;&#039; (PL3 TCP or PL6 SFTP), enter the labeller&#039;s &#039;&#039;&#039;host / IP address&#039;&#039;&#039; and &#039;&#039;&#039;port&#039;&#039;&#039;, and — for PL6 — a &#039;&#039;&#039;username and password&#039;&#039;&#039;. Pressing the connect button opens the link; a status indicator shows the connected host and port. A real labeller is typically reached at its own network address (for example &amp;lt;code&amp;gt;192.168.1.100&amp;lt;/code&amp;gt;); the [[LogoRenderer]] emulator is reached at &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Options in the connection area let you list the remote directory automatically on connect, send a periodic &#039;&#039;&#039;heartbeat&#039;&#039;&#039; to detect a dropped link, and set the socket read timeout.&lt;br /&gt;
&lt;br /&gt;
=== Transferring and Managing Files ===&lt;br /&gt;
&lt;br /&gt;
The central area lists the files on the printer for a chosen remote path and file mask, showing each file&#039;s name, size, modified time and type. From here you can:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Upload&#039;&#039;&#039; a local file to the printer.&lt;br /&gt;
* &#039;&#039;&#039;Download&#039;&#039;&#039; one or more selected files to a chosen local folder.&lt;br /&gt;
* &#039;&#039;&#039;Delete&#039;&#039;&#039; selected files from the printer (with confirmation).&lt;br /&gt;
* &#039;&#039;&#039;Refresh&#039;&#039;&#039; the listing, and on PL6 navigate into sub-folders.&lt;br /&gt;
&lt;br /&gt;
PL3 exposes the printer&#039;s storage areas (&amp;lt;code&amp;gt;/c0/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/c9/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/f0/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/r0/&amp;lt;/code&amp;gt;) with file masks such as &amp;lt;code&amp;gt;*.llf&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;*.pcx&amp;lt;/code&amp;gt;; PL6 exposes its SFTP folders.&lt;br /&gt;
&lt;br /&gt;
=== Sending Commands and Field Data ===&lt;br /&gt;
&lt;br /&gt;
In PL3 mode the message pane composes and transmits raw text to the labeller. Control characters can be entered as readable tokens such as &amp;lt;code&amp;gt;&amp;lt;STX&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;lt;ETX&amp;gt;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;&amp;lt;CR&amp;gt;&amp;lt;/code&amp;gt;, and the end-of-line terminator appended on send is selectable. This is how layouts are activated, field data is sent, and LAMA/LSP queries are issued by hand. Replies appear in the activity log and the raw bytes in the wire trace.&lt;br /&gt;
&lt;br /&gt;
=== Pallet Log Polling ===&lt;br /&gt;
&lt;br /&gt;
LogoClient can poll the labeller&#039;s pallet log at a chosen interval and write the results to disk — one timestamped file per unique SSCC — into a chosen log folder. This reproduces, by hand, the &amp;quot;what was printed&amp;quot; feedback that production software collects, and works against both PL3 and PL6.&lt;br /&gt;
&lt;br /&gt;
=== Activity Log and Wire Trace ===&lt;br /&gt;
&lt;br /&gt;
Two panes record what happens. The &#039;&#039;&#039;activity log&#039;&#039;&#039; is a readable, timestamped narrative of connects, transfers, commands and errors. The &#039;&#039;&#039;wire trace&#039;&#039;&#039; shows the raw bytes in both directions — transmitted and received — with control characters rendered as tokens, which is invaluable when diagnosing exactly what a labeller sent or expected. Both panes can be saved to a text file or cleared.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
The connection details and interface preferences are saved when you quit and restored on the next start, so the tool reopens ready to reconnect to the labeller you last used.&lt;br /&gt;
&lt;br /&gt;
== Using LogoClient and LogoRenderer Together ==&lt;br /&gt;
&lt;br /&gt;
The two tools form a complete bench setup for label development with no Logopak hardware:&lt;br /&gt;
&lt;br /&gt;
# In &#039;&#039;&#039;[[LogoRenderer]]&#039;&#039;&#039;, start the &#039;&#039;&#039;printer emulator&#039;&#039;&#039; on a port (default 8000).&lt;br /&gt;
# In &#039;&#039;&#039;LogoClient&#039;&#039;&#039;, choose &#039;&#039;&#039;PL3 (TCP)&#039;&#039;&#039;, set the host to &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; and the matching port, and connect.&lt;br /&gt;
# &#039;&#039;&#039;Upload a layout&#039;&#039;&#039;, &#039;&#039;&#039;send field data&#039;&#039;&#039;, &#039;&#039;&#039;browse the emulated drives&#039;&#039;&#039; or &#039;&#039;&#039;poll the pallet log&#039;&#039;&#039; — and watch LogoRenderer render the result and log the traffic.&lt;br /&gt;
&lt;br /&gt;
In this arrangement LogoClient stands in for the driving software so you can develop and test against the renderer, while LogoRenderer stands in for the printer so you have something to talk to. LogoClient can equally be pointed at a real Logopak labeller when one is available.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[LogoRenderer]] — the companion tool that renders labels and emulates a Logopak printer&lt;br /&gt;
* [[Middleware4j]], [[LabelServer4j]], [[AutoLab4j]] — production software that drives Logopak labellers&lt;br /&gt;
* [[SocketTest]] — a raw TCP/IP testing utility&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=LogoRenderer&amp;diff=1866</id>
		<title>LogoRenderer</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=LogoRenderer&amp;diff=1866"/>
		<updated>2026-06-13T19:23:10Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: Updated by push_wiki.py&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;LogoRenderer&#039;&#039;&#039; (&#039;&#039;c4j_logorenderer&#039;&#039;) is a standalone desktop application that renders [[Logopak]] PowerLeap label layout files to a visual on-screen preview &#039;&#039;&#039;and&#039;&#039;&#039; can stand in for a physical label printer by emulating its TCP communication protocol. It exists so that label layouts and the software that drives them can be developed and tested &#039;&#039;&#039;on an ordinary PC, in environments where no physical Logopak labeller is available&#039;&#039;&#039; to test against.&lt;br /&gt;
&lt;br /&gt;
It is the rendering and printer-emulation half of a pair: [[LogoClient]] is the client that sends layouts and data to a printer, and LogoRenderer can play the part of that printer. Together they let you exercise the whole label-printing workflow with no hardware at all.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Disclaimer: LogoRenderer is an independent open-source tool and is &#039;&#039;&#039;not&#039;&#039;&#039; a Logopak product. It is not affiliated with, endorsed by, or supported by Logopak. Logopak, PowerLeap and related names are trademarks of their respective owners and are used solely to describe interoperability. The software is intended for local test and development use only — it must not be relied upon for production label printing.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
A Logopak PowerLeap labeller normally lives on the factory floor and is driven over the network by software such as [[Middleware4j]], [[LabelServer4j]] or [[AutoLab4j]]. When developing or supporting that software — or designing the label layouts themselves — it is often impractical to have a real labeller on the bench. LogoRenderer removes that dependency. It is useful when:&lt;br /&gt;
&lt;br /&gt;
* You need to &#039;&#039;&#039;see what a label layout will look like&#039;&#039;&#039; without printing it, by opening a &amp;lt;code&amp;gt;.llf&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.lqf&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;.ldf&amp;lt;/code&amp;gt; file and viewing a faithful preview.&lt;br /&gt;
* You are &#039;&#039;&#039;writing or debugging software that talks to a labeller&#039;&#039;&#039; and need something on the network that answers the same protocol — without owning the hardware.&lt;br /&gt;
* You want to &#039;&#039;&#039;develop without a physical Logopak&#039;&#039;&#039; altogether: render layouts, emulate the printer, and feed it from [[LogoClient]] or your own client code.&lt;br /&gt;
* You need to &#039;&#039;&#039;check field data and operator prompts&#039;&#039;&#039; (LQF query fields) by typing values and watching the rendered label update.&lt;br /&gt;
* You are &#039;&#039;&#039;tuning fonts&#039;&#039;&#039; so the on-screen rendering matches a real printed label.&lt;br /&gt;
&lt;br /&gt;
== Label and Data File Types ==&lt;br /&gt;
&lt;br /&gt;
LogoRenderer understands the PowerLeap LEAP layout family:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Extension !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.llf&amp;lt;/code&amp;gt; || Layout File — a complete label layout with all field data embedded. Opening one renders the label immediately.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.lqf&amp;lt;/code&amp;gt; || Query Layout File — a base layout containing &amp;lt;code&amp;gt;QUE&amp;lt;/code&amp;gt; operator prompts for fields that are filled in at print time. Opening one also populates the &#039;&#039;&#039;QUE Input&#039;&#039;&#039; tab so values can be typed in.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.ldf&amp;lt;/code&amp;gt; || Data File — a data-only file that references a master layout. Opening one runs its &amp;lt;code&amp;gt;LOAD&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;FD&amp;lt;/code&amp;gt; commands to load the referenced layout and populate its fields.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Layouts may reference &amp;lt;code&amp;gt;.pcx&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;.bmp&amp;lt;/code&amp;gt; images (logotypes) and a range of barcode types. A reference list of the wider Logopak file-type ecosystem is maintained alongside the project.&lt;br /&gt;
&lt;br /&gt;
== Source Code and Releases ==&lt;br /&gt;
&lt;br /&gt;
LogoRenderer is part of the open-source Commander4j suite and is distributed under the GNU General Public License.&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
Native install packages for &#039;&#039;&#039;Windows, macOS and Linux&#039;&#039;&#039; are available from the [[Downloads]] page and are the preferred installation method. Each installer bundles its own Java runtime, so &#039;&#039;&#039;no separate Java installation is required&#039;&#039;&#039;. Installing creates a native &#039;&#039;&#039;LogoRenderer&#039;&#039;&#039; launcher that can be started like any other desktop application.&lt;br /&gt;
&lt;br /&gt;
=== Running from the jar ===&lt;br /&gt;
&lt;br /&gt;
Alternatively the tool can be run directly as an ordinary Java (Swing) application. It is built with Maven:&lt;br /&gt;
&lt;br /&gt;
 mvn package&lt;br /&gt;
 java -jar c4j_logorenderer.jar [file.llf]&lt;br /&gt;
&lt;br /&gt;
Running the jar requires a recent Java runtime (Java 21 or later). If a layout file is supplied on the command line it is opened on start-up; otherwise the application starts with an empty canvas. Demo layouts and data files are provided in the &amp;lt;code&amp;gt;virtual_disk/c0/&amp;lt;/code&amp;gt; folder.&lt;br /&gt;
&lt;br /&gt;
== The Main Window ==&lt;br /&gt;
&lt;br /&gt;
The window is divided into a &#039;&#039;&#039;label preview canvas&#039;&#039;&#039; on the left and a &#039;&#039;&#039;tabbed working area&#039;&#039;&#039; on the right, with a menu bar and toolbars around them and a status bar along the bottom. The title bar shows the program name, version and the name of the open file.&lt;br /&gt;
&lt;br /&gt;
The status bar reports the current file, the layout dimensions in printer dots and millimetres, the zoom level, and the number of fields in the layout.&lt;br /&gt;
&lt;br /&gt;
=== Preview Canvas ===&lt;br /&gt;
&lt;br /&gt;
The canvas shows the rendered label exactly as the layout describes it — text, scalable text, barcodes, graphic lines and boxes, and embedded logotype images. The rendering engine replicates the coordinate system and geometry of a PowerLeap III print head, including the upside-down (180°) print orientation. Clicking a rendered element highlights the source lines that produce it.&lt;br /&gt;
&lt;br /&gt;
=== Source / QUE Input / Log Tabs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Tab !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Source&#039;&#039;&#039; || Lists the raw layout commands, one per line, each with a checkbox and a plain-language description. Un-checking a line excludes it from the render, so individual elements can be toggled on and off. Selecting a line shows its properties for editing.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;QUE Input&#039;&#039;&#039; || For LQF layouts, presents one input box per operator prompt. Type values and apply them to see the populated label. This mirrors what an operator would be asked for at the machine.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Log&#039;&#039;&#039; || A colour-coded activity log showing file loads, parser messages, and all traffic to and from the printer emulator.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Viewing Controls ===&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;File&#039;&#039;&#039; menu opens and reloads layout files and exports the rendered label as a PNG image. The &#039;&#039;&#039;View&#039;&#039;&#039; menu provides zoom (preset levels, zoom in/out, and fit-to-window) and a &#039;&#039;&#039;Rotate 180°&#039;&#039;&#039; toggle that flips the preview to match the printer&#039;s print orientation.&lt;br /&gt;
&lt;br /&gt;
== Font Mapping ==&lt;br /&gt;
&lt;br /&gt;
Because Logopak fonts are not present on a development PC, LogoRenderer maps each Logopak font name to a Java font for rendering. The &#039;&#039;&#039;Settings → Font Mappings&#039;&#039;&#039; dialog lists every mapping and lets you set the Java font family (or a bundled TrueType file), style, reference cell size and calibration factors so that the on-screen text closely matches a real printed label. The mappings are stored in &amp;lt;code&amp;gt;xml/config/fonts.xml&amp;lt;/code&amp;gt;; fonts found in a layout but not yet mapped are added automatically with sensible defaults, ready to be fine-tuned.&lt;br /&gt;
&lt;br /&gt;
== The Printer Emulator ==&lt;br /&gt;
&lt;br /&gt;
This is the feature that makes hardware-free development possible. LogoRenderer can open a TCP server that emulates a Logopak PowerLeap III labeller, answering the same &#039;&#039;&#039;LEAP / LAMA&#039;&#039;&#039; protocol commands a real machine would.&lt;br /&gt;
&lt;br /&gt;
=== Starting the emulator ===&lt;br /&gt;
&lt;br /&gt;
The connection bar at the top of the window selects the &#039;&#039;&#039;IP address&#039;&#039;&#039; (default &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; for the local machine) and &#039;&#039;&#039;port&#039;&#039;&#039; (default &#039;&#039;&#039;8000&#039;&#039;&#039;, the PowerLeap III primary data port; &amp;lt;code&amp;gt;8100&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;8200&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;8300&amp;lt;/code&amp;gt; are also offered). Pressing &#039;&#039;&#039;Start Server&#039;&#039;&#039; begins listening; the Log tab shows when a client connects. Pressing the button again stops the server.&lt;br /&gt;
&lt;br /&gt;
=== What it emulates ===&lt;br /&gt;
&lt;br /&gt;
A connected client can do, against the emulator, the things it would do against a real labeller:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Browse and transfer files&#039;&#039;&#039; on an emulated drive — the &amp;lt;code&amp;gt;virtual_disk/&amp;lt;/code&amp;gt; folder provides the labeller&#039;s storage areas (&amp;lt;code&amp;gt;c0/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;c9/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;d0/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f0/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;r0/&amp;lt;/code&amp;gt;), so directory listings, downloads, uploads and deletes all behave realistically.&lt;br /&gt;
* &#039;&#039;&#039;Load a layout and send field data&#039;&#039;&#039; — when the client issues a &amp;lt;code&amp;gt;LOAD&amp;lt;/code&amp;gt; command the emulator loads that layout into the preview, and as &amp;lt;code&amp;gt;FD&amp;lt;/code&amp;gt; field-data commands arrive the on-screen label updates. The PC screen therefore shows what the real printer would be putting on a label.&lt;br /&gt;
* &#039;&#039;&#039;Retrieve logs&#039;&#039;&#039; — the emulator can serve pallet/label log files back to the client, so software that polls a labeller for &amp;quot;what was printed&amp;quot; can be tested end to end.&lt;br /&gt;
&lt;br /&gt;
=== Pallet print simulation ===&lt;br /&gt;
&lt;br /&gt;
When a loaded layout contains the pallet SSCC field, a &#039;&#039;&#039;Print Label&#039;&#039;&#039; control appears. Each press simulates a pallet print — two labels per pallet sharing one [https://en.wikipedia.org/wiki/Serial_Shipping_Container_Code SSCC] — increments the SSCC counter (persisted in &amp;lt;code&amp;gt;sscc.dat&amp;lt;/code&amp;gt;), and queues a log entry that a client can later retrieve. This lets log-polling and pallet-tracking logic be exercised without a real production run.&lt;br /&gt;
&lt;br /&gt;
== Using LogoRenderer and LogoClient Together ==&lt;br /&gt;
&lt;br /&gt;
The two tools form a complete bench setup for label development with no Logopak hardware:&lt;br /&gt;
&lt;br /&gt;
# In &#039;&#039;&#039;LogoRenderer&#039;&#039;&#039;, start the &#039;&#039;&#039;printer emulator&#039;&#039;&#039; on a port (default 8000).&lt;br /&gt;
# In &#039;&#039;&#039;[[LogoClient]]&#039;&#039;&#039;, connect in &#039;&#039;&#039;PL3 (TCP)&#039;&#039;&#039; mode to &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; on the same port.&lt;br /&gt;
# From LogoClient, &#039;&#039;&#039;upload a layout&#039;&#039;&#039;, &#039;&#039;&#039;send field data&#039;&#039;&#039;, &#039;&#039;&#039;browse the emulated drives&#039;&#039;&#039; or &#039;&#039;&#039;poll the pallet log&#039;&#039;&#039; — and watch LogoRenderer render the result and log the traffic.&lt;br /&gt;
&lt;br /&gt;
In this arrangement LogoRenderer stands in for the printer so you can develop and test a client, while LogoClient stands in for the driving software so you can drive the renderer. Either tool can equally be pointed at a real Logopak labeller when one is available.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[LogoClient]] — the client-side companion tool that sends layouts and data to a labeller (real or emulated)&lt;br /&gt;
* [[Middleware4j]], [[LabelServer4j]], [[AutoLab4j]] — production software that drives Logopak labellers&lt;br /&gt;
* [[ZPLRenderer]] — the equivalent preview tool for Zebra ZPL labels&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=File:LogoRenderer_256x256.png&amp;diff=1865</id>
		<title>File:LogoRenderer 256x256.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=File:LogoRenderer_256x256.png&amp;diff=1865"/>
		<updated>2026-06-13T12:36:10Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=File:LogoClient_256x256.png&amp;diff=1864</id>
		<title>File:LogoClient 256x256.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=File:LogoClient_256x256.png&amp;diff=1864"/>
		<updated>2026-06-13T12:35:43Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=Template:Menu_Applications&amp;diff=1863</id>
		<title>Template:Menu Applications</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=Template:Menu_Applications&amp;diff=1863"/>
		<updated>2026-06-13T12:35:26Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: /* Applications */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Applications=&lt;br /&gt;
{| cellpadding=&amp;quot;8&amp;quot; style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
||[[file:AutoLab4j_256x256.png|link=[[AutoLab4j]]|100px]]&lt;br /&gt;
====[[AutoLab4j]]====&lt;br /&gt;
|&lt;br /&gt;
||[[File:Commander4j_256x256.png|link=[[Commander4j]]|100px]]&lt;br /&gt;
====[[Commander4j]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:LabelServer4j_256x256.png|link=[[LabelServer4j]]|100px]]&lt;br /&gt;
====[[LabelServer4j]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:LaunchPad_256x256.png|link=[[LaunchPad]]|100px]]&lt;br /&gt;
====[[LaunchPad]]====&lt;br /&gt;
|-&lt;br /&gt;
||[[file:LogoClient_256x256.png|link=[[LogoClient]]|100px]]&lt;br /&gt;
====[[LogoClient]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:LogoRenderer_256x256.png|link=[[LogoRenderer]]|100px]]&lt;br /&gt;
====[[LogoRenderer]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:Menu4j_256x256.png|link=[[Menu4j]]|100px]]&lt;br /&gt;
====[[Menu4j]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:Middleware4j_256x256.png|link=[[Middleware4j]]|100px]]&lt;br /&gt;
====[[Middleware4j]]====&lt;br /&gt;
|-&lt;br /&gt;
||[[file:Modbus_256x256.png|link=[[ModbusClient]]|100px]]&lt;br /&gt;
====[[ModbusClient]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:Modbus_256x256.png|link=[[ModbusServer]]|100px]]&lt;br /&gt;
====[[ModbusServer]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:SFTGet4j_256x256.png|link=[[SFTPGet]]|100px]]&lt;br /&gt;
====[[SFTPGet]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:SFTPSend4j_256x256.png|link=[[SFTPSend]]|100px]]&lt;br /&gt;
====[[SFTPSend]]====&lt;br /&gt;
|-&lt;br /&gt;
||[[file:sftpTransfer_256x256.png|link=[[SFTPTransfer]]|100px]]&lt;br /&gt;
====[[SFTPTransfer]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:SocketTest_256x256.png|link=[[SocketTest]]|100px]]&lt;br /&gt;
====[[SocketTest]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:TreeDoc_256x256.png|link=[[TreeDoc]]|100px]]&lt;br /&gt;
====[[TreeDoc]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:XMLViewer_256x256.png|link=[[XMLViewer]]|100px]]&lt;br /&gt;
====[[XMLViewer]]====&lt;br /&gt;
|-&lt;br /&gt;
||[[file:ZPLRenderer_256x256.png|link=[[ZPLRenderer]]|100px]]&lt;br /&gt;
====[[ZPLRenderer]]====&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=Template:Menu_Applications&amp;diff=1862</id>
		<title>Template:Menu Applications</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=Template:Menu_Applications&amp;diff=1862"/>
		<updated>2026-06-11T11:42:28Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: /* Applications */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Applications=&lt;br /&gt;
{| cellpadding=&amp;quot;8&amp;quot; style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
||[[file:AutoLab4j_256x256.png|link=[[AutoLab4j]]|100px]]&lt;br /&gt;
====[[AutoLab4j]]====&lt;br /&gt;
|&lt;br /&gt;
||[[File:Commander4j_256x256.png|link=[[Commander4j]]|100px]]&lt;br /&gt;
====[[Commander4j]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:LabelServer4j_256x256.png|link=[[LabelServer4j]]|100px]]&lt;br /&gt;
====[[LabelServer4j]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:LaunchPad_256x256.png|link=[[LaunchPad]]|100px]]&lt;br /&gt;
====[[LaunchPad]]====&lt;br /&gt;
|-&lt;br /&gt;
||[[file:Menu4j_256x256.png|link=[[Menu4j]]|100px]]&lt;br /&gt;
====[[Menu4j]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:Middleware4j_256x256.png|link=[[Middleware4j]]|100px]]&lt;br /&gt;
====[[Middleware4j]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:Modbus_256x256.png|link=[[ModbusClient]]|100px]]&lt;br /&gt;
====[[ModbusClient]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:Modbus_256x256.png|link=[[ModbusServer]]|100px]]&lt;br /&gt;
====[[ModbusServer]]====&lt;br /&gt;
|-&lt;br /&gt;
||[[file:SFTGet4j_256x256.png|link=[[SFTPGet]]|100px]]&lt;br /&gt;
====[[SFTPGet]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:SFTPSend4j_256x256.png|link=[[SFTPSend]]|100px]]&lt;br /&gt;
====[[SFTPSend]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:sftpTransfer_256x256.png|link=[[SFTPTransfer]]|100px]]&lt;br /&gt;
====[[SFTPTransfer]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:SocketTest_256x256.png|link=[[SocketTest]]|100px]]&lt;br /&gt;
====[[SocketTest]]====&lt;br /&gt;
|-&lt;br /&gt;
||[[file:TreeDoc_256x256.png|link=[[TreeDoc]]|100px]]&lt;br /&gt;
====[[TreeDoc]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:XMLViewer_256x256.png|link=[[XMLViewer]]|100px]]&lt;br /&gt;
====[[XMLViewer]]====&lt;br /&gt;
|&lt;br /&gt;
||[[file:ZPLRenderer_256x256.png|link=[[ZPLRenderer]]|100px]]&lt;br /&gt;
====[[ZPLRenderer]]====&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=Installation&amp;diff=1861</id>
		<title>Installation</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=Installation&amp;diff=1861"/>
		<updated>2026-06-10T16:50:00Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Install Database ==&lt;br /&gt;
&lt;br /&gt;
Commander4j can work with [[mySQL]], [[MSSQL]] or [[Oracle]] databases. Without going into the specifics of how each database product works the following is a checklist of what needs to be done in order to prepare the database for use with Commander4j.&lt;br /&gt;
&lt;br /&gt;
General recommendations. If we assume that your just wanting to get the application working with the least amount of work then I would recommend installing SQL Server Express for Windows based computers. For MacOS I would recommend mySQL and for Linux you have the choice of mySQL or Oracle. To be accurate most databases will work with most operating systems using Docker these days - but in the interest of simplicity I would use the previous recommendations. Apologies to any Oracle DBA&#039;s out there but I would not recommend it unless you have a lot of previous experience.&lt;br /&gt;
&lt;br /&gt;
== mySQL ==&lt;br /&gt;
&lt;br /&gt;
A detailed guide showing how to install mySQL under windows can be found [https://dev.mysql.com/doc/mysql-installation-excerpt/8.2/en/ here].&lt;br /&gt;
&lt;br /&gt;
* Create a database/schema user account for Commander4j to use.&lt;br /&gt;
* Create a user which has the newly created database as its default schema.&lt;br /&gt;
* Ensure that the new user has sufficient permissions to create tables/indexes/views etc.&lt;br /&gt;
* Better to grant too much rather than too little initially.&lt;br /&gt;
* Ensure that the database is accepting remote connections.&lt;br /&gt;
* Ensure that the user is allowed to connect remotely.&lt;br /&gt;
&lt;br /&gt;
== MariaDB ==&lt;br /&gt;
&lt;br /&gt;
Installation is fundamentally as per mySQL - however when you use the Setup4j program within Commander4j you need to make sure you select the following settings.&lt;br /&gt;
&lt;br /&gt;
 Collation      utf8mb4_general_ci&lt;br /&gt;
 Char Set       utf8mb4&lt;br /&gt;
&lt;br /&gt;
== Microsoft SQL Server ==&lt;br /&gt;
&lt;br /&gt;
A detailed guide showing how to install MS SQL Server under windows can be found [https://learn.microsoft.com/en-us/sql/database-engine/install-windows/install-sql-server?view=sql-server-ver16 here].&lt;br /&gt;
&lt;br /&gt;
* Enable the TCP/IP communication protocol as it may be disabled by default.&lt;br /&gt;
* Create a database/schema user account for Commander4j to use.&lt;br /&gt;
* Create a user which has the newly created database as its default schema.&lt;br /&gt;
* Ensure that the new user has sufficient permissions to create tables/indexes/views etc.&lt;br /&gt;
* Better to grant too much rather than too little initially.&lt;br /&gt;
* Ensure that the database is accepting remote connections.&lt;br /&gt;
* Check firewall rules allow connections on port 1433.&lt;br /&gt;
* Ensure that the user is allowed to connect remotely.&lt;br /&gt;
&lt;br /&gt;
== Oracle ==&lt;br /&gt;
&lt;br /&gt;
A detailed guide showing how to install Oracle under windows can be found [https://docs.oracle.com/en/database/oracle/oracle-database/23/install.html here].&lt;br /&gt;
&lt;br /&gt;
* Create a database/schema user account for Commander4j to use.&lt;br /&gt;
* Create a user which has the newly created database as its default schema.&lt;br /&gt;
* Ensure that the new user has sufficient permissions to create tables/indexes/views etc.&lt;br /&gt;
* Better to grant too much rather than too little initially.&lt;br /&gt;
* Ensure that the database is using TCP/IP.&lt;br /&gt;
* Ensure that the database is accepting remote connections.&lt;br /&gt;
* Check firewall rules allow connections.&lt;br /&gt;
&lt;br /&gt;
== Install Java ==&lt;br /&gt;
&lt;br /&gt;
* Java 25 is needed if you are installing:&lt;br /&gt;
** The desktop application on a Linux operating system.&lt;br /&gt;
** The web components onto a server using Apache Tomcat.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note that the web applications should be installed on a nominated server machine and not on workstations.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Recommend installing the Azul Zulu JDK from [https://www.azul.com/downloads/#zulu https://www.azul.com/downloads/#zulu].&lt;br /&gt;
&lt;br /&gt;
== Install Tomcat 11.x ==&lt;br /&gt;
&lt;br /&gt;
* Download from [http://tomcat.apache.org/ Apache Tomcat Site].&lt;br /&gt;
&lt;br /&gt;
Ensure you download the 32/64Bit Windows Service Installer package.&lt;br /&gt;
&lt;br /&gt;
== Install Commander4j ==&lt;br /&gt;
&lt;br /&gt;
* Obtain the required installation package.&lt;br /&gt;
&lt;br /&gt;
This can be downloaded from [http://www.commander4j.com Commander4j Website].&lt;br /&gt;
On a server select the &amp;quot;Full&amp;quot; install option from the setup screen — normally a user&#039;s PC will require the &amp;quot;Workstation&amp;quot; install.&lt;br /&gt;
&lt;br /&gt;
[[File:Install1.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Run the appropriate installer for your operating system.&lt;br /&gt;
&lt;br /&gt;
[[File:Install2.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Review and agree the licence agreement.&lt;br /&gt;
&lt;br /&gt;
[[File:Install3.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Select the install destination.&lt;br /&gt;
&lt;br /&gt;
[[File:Install4.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Choose the appropriate install type.&lt;br /&gt;
Select Full if you are installing the main machine (server) which will run the interfaces, and Workstation for every other machine.&lt;br /&gt;
&lt;br /&gt;
[[File:Install5.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Amend the name of the folder shortcut if needed. Typically you would change the name if you wanted to install more than one copy of the software on the same computer.&lt;br /&gt;
&lt;br /&gt;
[[File:Install6.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Allow the installer to copy files to the destination.&lt;br /&gt;
&lt;br /&gt;
[[File:Install7.png|400px]]&lt;br /&gt;
&lt;br /&gt;
The software is now installed.&lt;br /&gt;
&lt;br /&gt;
== Configure Commander4j ==&lt;br /&gt;
&lt;br /&gt;
* [[Setup4j|Setup Hosts]] (Database Connections)&lt;br /&gt;
&lt;br /&gt;
When Commander4j is initially installed you will find a number of dummy database connections already defined. You may find it easier to amend one of these rather than create a new connection. To manage the database connections run [[Setup4j]] from the Commander4j program shortcuts.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
The first step is to install and/or identify the database software that you plan to use with Commander4j. As mentioned previously this can be mySQL, Microsoft SQL Server (including SQL Express) or Oracle (including XE).&lt;br /&gt;
&lt;br /&gt;
== Configure Tomcat / Web Application ==&lt;br /&gt;
&lt;br /&gt;
The web components of Commander4j are contained in the .war files which you download. You won&#039;t need all of them and their names may change with updated releases.&lt;br /&gt;
&lt;br /&gt;
The servlet (.war) files shown below are intended to work on Zebra Mobile Computers which have the Zebra Enterprise Browser installed.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Servlet !! Purpose !! Environment !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;c4j_web_react.war&#039;&#039;&#039; || Pallet Transactions || Any Mobile Browser || * Recommended&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;c4j_web_WS.war&#039;&#039;&#039; || Quality — Product Grading || Any Mobile Browser || Only needed for Quality Control&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;c4j_web_Issue.war&#039;&#039;&#039; || Issue Pallets to Order &amp;amp; Location || Tablet Mobile Browser || Issue/Return of Stock&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Installing the web element of Commander4j is straightforward and requires copying files from the Commander4j install directory into the Tomcat directory:&lt;br /&gt;
&lt;br /&gt;
* Stop the Apache Tomcat service if it is running.&lt;br /&gt;
* Copy the file &#039;&#039;&#039;chosen_servlet.war&#039;&#039;&#039; from the Commander4j directory into the WebApps subdirectory of the Tomcat installation directory.&lt;br /&gt;
* Start the Apache Tomcat service.&lt;br /&gt;
* You should then notice that the &#039;&#039;&#039;chosen_servlet&#039;&#039;&#039; directory has been created under WebApps.&lt;br /&gt;
* Update the list of hosts the web application can connect to by copying &amp;quot;Commander4j/xml/hosts/hosts.xml&amp;quot; into &amp;quot;Tomcat/WebApps/&#039;&#039;&#039;chosen_servlet&#039;&#039;&#039;/xml/hosts&amp;quot;.&lt;br /&gt;
* Confirm this is working by opening the URL &#039;&#039;&#039;http://servername:8080/chosen_servlet/&#039;&#039;&#039;&lt;br /&gt;
* If you update the hosts.xml file for a servlet you will need to either restart Apache Tomcat or stop and start the servlet from the [http://localhost:8080/manager/html Apache Tomcat Manager].&lt;br /&gt;
* If you want to connect to a SQL Server database using Windows Integrated Authentication, copy the appropriate version of the auth DLL from the downloaded MS JDBC drivers (e.g. mssql-jdbc_auth-12.10.0.x64.dll) into the Java bin folder.&lt;br /&gt;
&lt;br /&gt;
== Create Commander4j Services ==&lt;br /&gt;
&lt;br /&gt;
See [[Install_Interface_Services|Install Interface Services]].&lt;br /&gt;
&lt;br /&gt;
== Install Local Middleware ==&lt;br /&gt;
&lt;br /&gt;
The local middleware service handles the processing of inbound and outbound interface files between Commander4j and external systems such as an ERP. It runs as a background service on the Commander4j server machine and is configured via the [[Interface_Admin|Interface Admin]] screen within the application.&lt;br /&gt;
&lt;br /&gt;
To install the interface service:&lt;br /&gt;
&lt;br /&gt;
* Ensure Commander4j has been installed using the &#039;&#039;&#039;Full&#039;&#039;&#039; install option, which includes the service wrapper components.&lt;br /&gt;
* Open Commander4j, navigate to &#039;&#039;&#039;System &amp;gt; Interface Admin&#039;&#039;&#039; and verify that your interface definitions are configured correctly.&lt;br /&gt;
* Use the &#039;&#039;&#039;Assign Service&#039;&#039;&#039; function within the application to register the interface process as a Windows service (on Windows) or configure it as a startup process on Linux/macOS.&lt;br /&gt;
* Once registered, start the service and monitor the [[Interface_Log|Interface Log]] to confirm that messages are being processed correctly.&lt;br /&gt;
&lt;br /&gt;
If you are using [[Middleware4j]] to transform files before they reach Commander4j, install and configure Middleware4j separately — see the [[Middleware4j]] wiki page for details.&lt;br /&gt;
&lt;br /&gt;
== Install Print Queues ==&lt;br /&gt;
&lt;br /&gt;
Commander4j uses two distinct methods for printing, and each requires a different type of print queue to be set up on the workstation or server.&lt;br /&gt;
&lt;br /&gt;
=== Standard Reports (JasperReports) ===&lt;br /&gt;
&lt;br /&gt;
Standard reports — such as pallet summaries, despatch notes and audit reports — are printed using JasperReports and sent to a regular operating system print queue, exactly as you would print a document from a word processor. Any printer visible to the operating system can be used. The report type is configured in the [[Modules|Modules]] screen.&lt;br /&gt;
&lt;br /&gt;
On Windows, ensure the printer is installed and visible in the Windows Printers &amp;amp; Scanners settings. On Linux, CUPS-managed queues are supported.&lt;br /&gt;
&lt;br /&gt;
=== Barcode Labels (ZPL) ===&lt;br /&gt;
&lt;br /&gt;
Barcode labels — pallet labels, case labels and sample labels — are printed by sending raw ZPL (Zebra Printer Language) commands directly to a ZPL compatible printer. This bypasses the normal print driver rendering pipeline entirely, so the print queue must be configured as a raw / pass-through queue.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Windows&#039;&#039;&#039; — install the printer using the [https://www.seagullscientific.com/support/downloads/drivers/ Seagull Scientific Generic Label] driver, or configure a &#039;&#039;Generic / Text Only&#039;&#039; queue. Do not use a standard Zebra Windows driver, as this will re-interpret the ZPL rather than passing it through.&lt;br /&gt;
* &#039;&#039;&#039;macOS&#039;&#039;&#039; — configure a raw printer queue using a tool such as [https://qz.io QZ Tray] or follow the guidance at [https://qz.io/docs/Setting-Up-A-Raw-Printer-in-OSX qz.io]. A standard macOS printer queue will not work for ZPL output.&lt;br /&gt;
* &#039;&#039;&#039;Linux&#039;&#039;&#039; — configure a CUPS raw queue pointing at the printer&#039;s IP address and port 9100.&lt;br /&gt;
&lt;br /&gt;
If a label is accidentally sent to a standard print queue rather than a raw queue, the printer will output pages of ZPL text commands instead of a label. This is harmless but confirms the queue type needs to be changed.&lt;br /&gt;
&lt;br /&gt;
See also: [[Zebra_ZPL_Label|Zebra ZPL Label]], [[Intermec_IPL_Label|Intermec IPL Label]], [[Label_Template_Syntax|Label Template Syntax]].&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=Web_Applications_Overview&amp;diff=1860</id>
		<title>Web Applications Overview</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=Web_Applications_Overview&amp;diff=1860"/>
		<updated>2026-06-10T16:49:34Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Commander4j includes three web applications that run on Apache Tomcat alongside the main desktop application. Each is deployed as a WAR file and communicates with the same database. They are designed primarily for use on mobile devices and tablets on the shop floor, where a full desktop installation is not practical.&lt;br /&gt;
&lt;br /&gt;
== Web Applications ==&lt;br /&gt;
&lt;br /&gt;
=== c4j_web_react — Pallet Confirmation and Despatch ===&lt;br /&gt;
&lt;br /&gt;
This is the primary shop-floor web application. It provides browser-based screens for operators using wireless barcode scanners or handheld devices.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key functions:&#039;&#039;&#039;&lt;br /&gt;
* Scanning SSCC barcodes to confirm pallet production against a process order&lt;br /&gt;
* Creating and managing despatch records&lt;br /&gt;
* Assigning pallets to a despatch and confirming shipment&lt;br /&gt;
* Recording waste transactions&lt;br /&gt;
* Viewing pallet information&lt;br /&gt;
* Changing user passwords&lt;br /&gt;
&lt;br /&gt;
The application uses a traditional servlet and JSP architecture. A single &#039;&#039;&#039;Process&#039;&#039;&#039; servlet handles all form submissions. Sessions time out after 60 minutes of inactivity.&lt;br /&gt;
&lt;br /&gt;
Deployed as: &#039;&#039;&#039;c4j_web_react.war&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== c4j_web_WS — Quality Panel Web Interface ===&lt;br /&gt;
&lt;br /&gt;
This application provides a REST API and browser-based interface for recording quality panel inspection results. It is designed for use by quality technicians and trained panellists on tablets.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key functions:&#039;&#039;&#039;&lt;br /&gt;
* Creating and managing panel sessions&lt;br /&gt;
* Organising samples into trays&lt;br /&gt;
* Recording graded results against each sample&lt;br /&gt;
* Progressing panels through their lifecycle (Panel → Complete → Closed)&lt;br /&gt;
&lt;br /&gt;
The application exposes a JSON REST API consumed by a browser front end. Results feed into the main Commander4j QM module and are visible in the desktop [[Results Analysis and Reporting]] screen.&lt;br /&gt;
&lt;br /&gt;
Deployed as: &#039;&#039;&#039;c4j_web_WS.war&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
See also: [[Quality Panel Web Interface]]&lt;br /&gt;
&lt;br /&gt;
=== c4j_web_Issue — Material Issue Validation ===&lt;br /&gt;
&lt;br /&gt;
This application is intended to validate that operators issue the correct raw materials to a production line. It cross-checks scanned SSCCs against the Bill of Materials for the active process order, confirms the pick location, and records the transaction.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key functions:&#039;&#039;&#039;&lt;br /&gt;
* Scanning material pallets (SSCC) for issue to a process order&lt;br /&gt;
* Validating material and location against the BOM&lt;br /&gt;
* Recording returns of unused material&lt;br /&gt;
* Viewing pallet information and transaction history&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; This application has been developed but is not yet deployed in production. It is included here for reference.&lt;br /&gt;
&lt;br /&gt;
Deployed as: &#039;&#039;&#039;c4j_web_Issue.war&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Shared Configuration ==&lt;br /&gt;
&lt;br /&gt;
All three web applications use a &#039;&#039;&#039;hosts.xml&#039;&#039;&#039; file (located in the application&#039;s &#039;&#039;&#039;xml/hosts/&#039;&#039;&#039; directory within the deployed WAR) to define their database connections. This is the same format used by the Commander4j desktop and [[Setup4j]]. When updating database connection details, each web application&#039;s hosts.xml must be updated separately.&lt;br /&gt;
&lt;br /&gt;
The [[Setup4j]] tool is used to create and maintain hosts.xml files. After editing, the updated file must be copied into the relevant folder inside each deployed WAR, and Tomcat restarted (or the application reloaded) for the change to take effect.&lt;br /&gt;
&lt;br /&gt;
== Relationship to the Desktop Application ==&lt;br /&gt;
&lt;br /&gt;
The web applications share the &#039;&#039;&#039;commander4j.jar&#039;&#039;&#039; library with the desktop application. This library provides the full database access layer, business logic, barcode utilities, and configuration handling. The web applications do not duplicate this logic — they call into the shared library directly.&lt;br /&gt;
&lt;br /&gt;
All data written by the web applications is immediately visible in the desktop application, and vice versa. There is no synchronisation step.&lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
&lt;br /&gt;
* Apache Tomcat 11.x&lt;br /&gt;
* Java 25&lt;br /&gt;
* A configured and accessible Commander4j database (MySQL, MS SQL Server, or Oracle)&lt;br /&gt;
* A valid &#039;&#039;&#039;hosts.xml&#039;&#039;&#039; deployed with each WAR&lt;br /&gt;
&lt;br /&gt;
See also: [[Installation]], [[Setup4j]], [[Production Confirmation]], [[Despatch]], [[Quality Panel Web Interface]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=Menu4j&amp;diff=1859</id>
		<title>Menu4j</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=Menu4j&amp;diff=1859"/>
		<updated>2026-06-10T16:49:12Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Menu4j (JMenuTree) is a desktop command launcher that organises shell commands, scripts, and applications into a hierarchical tree menu. It provides a configurable, script-aware alternative to Finder shortcuts and shell aliases, with support for real-time terminal output, multiple linked menu trees, and optional startup password protection.&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
Menu4j is used to organise the day-to-day development and operational commands for the Commander4j suite in a single, structured interface. Menu items can run shell scripts, open applications, pass parameters, capture output, and link to other menu tree files.&lt;br /&gt;
&lt;br /&gt;
== Running Menu4j ==&lt;br /&gt;
&lt;br /&gt;
Native install packages for Windows, macOS, and Linux are available from the [[Downloads]] page and are the preferred installation method.&lt;br /&gt;
&lt;br /&gt;
Alternatively, Menu4j can be run directly from the distribution archive. It is a Java 25 desktop (Swing) application:&lt;br /&gt;
&lt;br /&gt;
 java -jar JMenu.jar&lt;br /&gt;
&lt;br /&gt;
On first launch, if no configuration file is found, Menu4j copies a template configuration from &amp;lt;code&amp;gt;xml/config/init/config.xml&amp;lt;/code&amp;gt; and a template menu tree from &amp;lt;code&amp;gt;xml/tree/init/tree.xml&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If a startup password has been configured, you are prompted to enter it before the menu is shown. Three failed attempts close the application.&lt;br /&gt;
&lt;br /&gt;
== The Menu Tree ==&lt;br /&gt;
&lt;br /&gt;
The main window displays a JTree. There are two node types:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| Branch || A folder that contains other branches or leaves&lt;br /&gt;
|-&lt;br /&gt;
| Leaf || An executable item — a command, script, or application&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Double-click a leaf to execute it. Double-click a branch to expand or collapse it.&lt;br /&gt;
&lt;br /&gt;
=== Adding and Editing Items ===&lt;br /&gt;
&lt;br /&gt;
The right sidebar toolbar provides:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Add&#039;&#039;&#039; — insert a new branch or leaf under the selected node&lt;br /&gt;
* &#039;&#039;&#039;Edit&#039;&#039;&#039; — open the editor for the selected node&lt;br /&gt;
* &#039;&#039;&#039;Delete&#039;&#039;&#039; — remove the selected node&lt;br /&gt;
* &#039;&#039;&#039;Duplicate&#039;&#039;&#039; — copy the selected node&lt;br /&gt;
&lt;br /&gt;
=== Leaf Properties ===&lt;br /&gt;
&lt;br /&gt;
When editing a leaf node, the following properties are available:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Property !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Description || The label shown in the menu tree&lt;br /&gt;
|-&lt;br /&gt;
| Directory || The working directory for the command&lt;br /&gt;
|-&lt;br /&gt;
| Command || The executable or system command to run&lt;br /&gt;
|-&lt;br /&gt;
| Parameters || A list of arguments to pass to the command&lt;br /&gt;
|-&lt;br /&gt;
| Shell Script Required || Whether to wrap the command in the configured shell wrapper script&lt;br /&gt;
|-&lt;br /&gt;
| Terminal Window Required || Whether to open a terminal output window to show command output&lt;br /&gt;
|-&lt;br /&gt;
| Confirm Execute || Whether to show a confirmation prompt before running&lt;br /&gt;
|-&lt;br /&gt;
| Link to Menu Tree || Whether this item opens a different tree file instead of running a command&lt;br /&gt;
|-&lt;br /&gt;
| Hint || A tooltip shown when hovering over the item&lt;br /&gt;
|-&lt;br /&gt;
| Icon || An image file to display next to the item label&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Executing Commands ==&lt;br /&gt;
&lt;br /&gt;
When a leaf is executed:&lt;br /&gt;
&lt;br /&gt;
# Menu4j validates that the directory and command exist&lt;br /&gt;
# If &#039;&#039;&#039;Shell Script Required&#039;&#039;&#039; is set, the command is wrapped using the script configured in Settings (typically a shell wrapper that sources the user&#039;s environment)&lt;br /&gt;
# If &#039;&#039;&#039;Terminal Window Required&#039;&#039;&#039; is set, a terminal output window opens and displays stdout and stderr in real time; otherwise the command runs silently in the background&lt;br /&gt;
# Environment variables configured in Settings are injected before execution&lt;br /&gt;
&lt;br /&gt;
=== Terminal Output Window ===&lt;br /&gt;
&lt;br /&gt;
The terminal window displays command output with configurable foreground and background colours and font (configured in Settings). A &#039;&#039;&#039;Respond&#039;&#039;&#039; button allows text to be sent to the command&#039;s standard input for interactive commands. When the command completes, the return code is displayed.&lt;br /&gt;
&lt;br /&gt;
== Multiple Tree Files ==&lt;br /&gt;
&lt;br /&gt;
A leaf node can be configured to switch to a different menu tree rather than execute a command. Set &#039;&#039;&#039;Link to Menu Tree&#039;&#039;&#039; and specify the filename. Double-clicking the leaf saves the current tree&#039;s expansion state and loads the linked tree. The application title bar updates to show the active tree filename.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
=== config.xml ===&lt;br /&gt;
&lt;br /&gt;
Located at &amp;lt;code&amp;gt;xml/config/config.xml&amp;lt;/code&amp;gt;. This file stores global settings including the active tree filename, shell script settings, colours, fonts, environment variables, system command whitelist, and the encrypted startup password.&lt;br /&gt;
&lt;br /&gt;
=== tree.xml ===&lt;br /&gt;
&lt;br /&gt;
Located at &amp;lt;code&amp;gt;xml/tree/tree.xml&amp;lt;/code&amp;gt; (or a different filename if you have switched trees). This is the menu structure file. It is written automatically when you save from the application.&lt;br /&gt;
&lt;br /&gt;
=== tree.xml.state ===&lt;br /&gt;
&lt;br /&gt;
Located alongside the tree file. Records which branches were expanded on the last exit and restores them on next launch.&lt;br /&gt;
&lt;br /&gt;
== Settings ==&lt;br /&gt;
&lt;br /&gt;
Open Settings from the toolbar to configure:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Setting !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Password || Optional startup password (stored AES-encrypted)&lt;br /&gt;
|-&lt;br /&gt;
| Shell script || Enable/disable the shell wrapper and set the script filename&lt;br /&gt;
|-&lt;br /&gt;
| Terminal colours || Foreground and background colours for the terminal output window&lt;br /&gt;
|-&lt;br /&gt;
| Tree colours || Foreground colours for leaf and branch labels&lt;br /&gt;
|-&lt;br /&gt;
| Fonts || Font choice and size for the terminal window, leaf labels, and branch labels&lt;br /&gt;
|-&lt;br /&gt;
| Environment variables || Key/value pairs injected into every executed process&lt;br /&gt;
|-&lt;br /&gt;
| System commands || Whitelist of system commands (such as &amp;lt;code&amp;gt;open&amp;lt;/code&amp;gt;) that do not require a file path to be validated&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tree Navigation ==&lt;br /&gt;
&lt;br /&gt;
The top toolbar provides four buttons for expanding and collapsing the tree:&lt;br /&gt;
&lt;br /&gt;
* Expand All&lt;br /&gt;
* Expand Selected Branch&lt;br /&gt;
* Collapse Selected Branch&lt;br /&gt;
* Collapse All&lt;br /&gt;
&lt;br /&gt;
== Saving ==&lt;br /&gt;
&lt;br /&gt;
Changes to the tree structure are saved using the &#039;&#039;&#039;Save&#039;&#039;&#039; button in the sidebar toolbar. You are prompted to save if you close the application with unsaved changes.&lt;br /&gt;
&lt;br /&gt;
See also: [[LaunchPad]], [[Downloads]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=XML_Viewer&amp;diff=1858</id>
		<title>XML Viewer</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=XML_Viewer&amp;diff=1858"/>
		<updated>2026-06-10T16:48:56Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;XML Viewer is a desktop application for exploring XML documents as an interactive, expandable tree. It supports configurable display modes, multi-language element name translation, and adjustable tree expansion depth. It is designed for viewing structured XML files such as SAP IDoc messages, Commander4j configuration files, and production schedule exports.&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
XML Viewer makes it practical to inspect complex XML files that are difficult to read as raw text. Element names can be translated into plain-language descriptions (for example, the SAP field code &amp;lt;code&amp;gt;ABWKZ&amp;lt;/code&amp;gt; becomes &amp;quot;Deviation indicator&amp;quot; in the English translation), and the tree can be expanded to a specific depth to give a high-level overview without showing every leaf value.&lt;br /&gt;
&lt;br /&gt;
== Running XML Viewer ==&lt;br /&gt;
&lt;br /&gt;
Native install packages for Windows, macOS, and Linux are available from the [[Downloads]] page and are the preferred installation method.&lt;br /&gt;
&lt;br /&gt;
Alternatively, XML Viewer can be run directly from the distribution archive. It is a Java 25 desktop (Swing) application:&lt;br /&gt;
&lt;br /&gt;
 java -jar xmlviewer.jar [optional path to XML file]&lt;br /&gt;
&lt;br /&gt;
If a file path is provided on the command line, that file is opened immediately on launch. Otherwise, the last-opened file from the configuration is loaded.&lt;br /&gt;
&lt;br /&gt;
== Loading a Document ==&lt;br /&gt;
&lt;br /&gt;
Click the &#039;&#039;&#039;Open XML Document&#039;&#039;&#039; button in the right sidebar, or pass a file path on the command line. Only well-formed XML files are supported. Click &#039;&#039;&#039;Reload XML Document&#039;&#039;&#039; to re-read the current file after it has been changed externally.&lt;br /&gt;
&lt;br /&gt;
== Display Modes ==&lt;br /&gt;
&lt;br /&gt;
=== Standard Mode ===&lt;br /&gt;
&lt;br /&gt;
The XML hierarchy is displayed exactly as it appears in the file — elements nest within their parent elements, forming a tree that mirrors the XML structure.&lt;br /&gt;
&lt;br /&gt;
=== Flat Mode ===&lt;br /&gt;
&lt;br /&gt;
Leaf elements (those containing only text, no child elements) are collapsed into their parent&#039;s row rather than appearing as separate tree nodes. Only elements that contain child elements appear as tree nodes. This produces a more compact view of documents with many small leaf values.&lt;br /&gt;
&lt;br /&gt;
Toggle between modes using the &#039;&#039;&#039;View Mode&#039;&#039;&#039; button in the right sidebar.&lt;br /&gt;
&lt;br /&gt;
== Tree Expansion Control ==&lt;br /&gt;
&lt;br /&gt;
The top toolbar provides four buttons:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Expand All&#039;&#039;&#039; — expand every node in the tree&lt;br /&gt;
* &#039;&#039;&#039;Expand Selected&#039;&#039;&#039; — expand only the selected subtree&lt;br /&gt;
* &#039;&#039;&#039;Collapse Selected&#039;&#039;&#039; — collapse the selected subtree&lt;br /&gt;
* &#039;&#039;&#039;Collapse All&#039;&#039;&#039; — collapse everything to root level&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;−&#039;&#039;&#039; and &#039;&#039;&#039;+&#039;&#039;&#039; buttons in the toolbar adjust the current expansion level (shown as a number between the buttons). Clicking &#039;&#039;&#039;Refresh&#039;&#039;&#039; after changing the level re-expands the tree to that depth.&lt;br /&gt;
&lt;br /&gt;
The expansion level is saved in the configuration and restored on next launch.&lt;br /&gt;
&lt;br /&gt;
== Translation ==&lt;br /&gt;
&lt;br /&gt;
XML Viewer can replace technical XML element names and values with plain-language descriptions from a translation file.&lt;br /&gt;
&lt;br /&gt;
=== Enabling Translation ===&lt;br /&gt;
&lt;br /&gt;
Toggle translations using the &#039;&#039;&#039;View Translations&#039;&#039;&#039; button. The &#039;&#039;&#039;Translation&#039;&#039;&#039; dropdown at the bottom of the window selects which translation file to use. The &#039;&#039;&#039;Language&#039;&#039;&#039; dropdown selects the language within that file.&lt;br /&gt;
&lt;br /&gt;
=== Built-in Translation Files ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! File !! Contents&lt;br /&gt;
|-&lt;br /&gt;
| matmas05.xml || SAP MATMAS05 IDoc field translations&lt;br /&gt;
|-&lt;br /&gt;
| zmatmas03.xml || SAP ZMATMAS03 IDoc field translations&lt;br /&gt;
|-&lt;br /&gt;
| productionschedule.xml || Production schedule export field translations&lt;br /&gt;
|-&lt;br /&gt;
| config.xml || Commander4j configuration element translations&lt;br /&gt;
|-&lt;br /&gt;
| default.xml || Generic fallback translations&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Languages ===&lt;br /&gt;
&lt;br /&gt;
The default installation includes English, French, German, and Italian. The active language can be changed at any time from the Language dropdown.&lt;br /&gt;
&lt;br /&gt;
=== Adding Translations ===&lt;br /&gt;
&lt;br /&gt;
Translation files are XML documents located in &amp;lt;code&amp;gt;xml/translations/&amp;lt;/code&amp;gt;. Each file maps element names, attribute names, element values, and attribute values to their translated equivalents for each language. Elements without a translation entry are shown using their original name from the XML file.&lt;br /&gt;
&lt;br /&gt;
== Other Display Options ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Button !! Effect&lt;br /&gt;
|-&lt;br /&gt;
| View Icons || Show or hide the icon column next to each tree node&lt;br /&gt;
|-&lt;br /&gt;
| View Brackets || Wrap element values in &amp;lt;code&amp;gt;[ ]&amp;lt;/code&amp;gt; brackets to distinguish them from element names&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
=== config.xml ===&lt;br /&gt;
&lt;br /&gt;
Located at &amp;lt;code&amp;gt;xml/config/config.xml&amp;lt;/code&amp;gt;. Stores the last-opened file path, selected translation file, selected language, current expansion level, and the state of all four display toggles (mode, translations, brackets, icons). Updated automatically on exit.&lt;br /&gt;
&lt;br /&gt;
=== log4j2.xml ===&lt;br /&gt;
&lt;br /&gt;
Located at &amp;lt;code&amp;gt;xml/log/log4j2.xml&amp;lt;/code&amp;gt;. Controls logging to &amp;lt;code&amp;gt;logs/XML_View.log&amp;lt;/code&amp;gt;. Log files rotate at 10 MB and are retained for 14 days.&lt;br /&gt;
&lt;br /&gt;
=== fonts.xml / icons ===&lt;br /&gt;
&lt;br /&gt;
Icons are loaded from &amp;lt;code&amp;gt;images/xmlIcons/&amp;lt;/code&amp;gt;. If an icon file referenced by a translation is not found, the icon column is left blank for that element without an error.&lt;br /&gt;
&lt;br /&gt;
See also: [[TreeDoc]], [[Middleware4j]], [[Label Template Syntax]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
</feed>