<?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-09-20T14:35:56Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.45.3</generator>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=Pallet_Issue&amp;diff=1921</id>
		<title>Pallet Issue</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=Pallet_Issue&amp;diff=1921"/>
		<updated>2026-08-20T15:36:29Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[file:Pallet_Issue.png|link=|800px]]&lt;br /&gt;
&lt;br /&gt;
Use this screen to issue either a part or full pallet to a Process Order. The transaction is written to Pallet History and can optionally create an xml interface message.&lt;br /&gt;
&lt;br /&gt;
The issue transaction will reference a number of tables within the application. It will check that the Material being issued is in the requirements for the Bill of Materials for the Process Order. It will check that the issue location (where the material is being sent) is correct. It will also check that the Pallet has an acceptable status and batch status for the location being issued to.&lt;br /&gt;
&lt;br /&gt;
[[file:Issue_Relationships.png|link=|900px]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=Pallet_Issue&amp;diff=1920</id>
		<title>Pallet Issue</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=Pallet_Issue&amp;diff=1920"/>
		<updated>2026-08-20T15:33:57Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[file:Pallet_Issue.png|link=|800px]]&lt;br /&gt;
&lt;br /&gt;
Use this screen to issue either a part or full pallet to a Process Order. The transaction is written to Pallet History and can optionally create an xml interface message.&lt;br /&gt;
&lt;br /&gt;
[[file:Issue_Relationships.png|link=|900px]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=File:Issue_Relationships.png&amp;diff=1919</id>
		<title>File:Issue Relationships.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=File:Issue_Relationships.png&amp;diff=1919"/>
		<updated>2026-08-20T15:33:28Z</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=Pallet_Issue&amp;diff=1918</id>
		<title>Pallet Issue</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=Pallet_Issue&amp;diff=1918"/>
		<updated>2026-08-20T15:33:12Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[file:Pallet_Issue.png|link=|800px]]&lt;br /&gt;
&lt;br /&gt;
Use this screen to issue either a part or full pallet to a Process Order. The transaction is written to Pallet History and can optionally create an xml interface message.&lt;br /&gt;
&lt;br /&gt;
[[file:Issue_Relationships.png|link=|1000px]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=Pallet_Issue&amp;diff=1917</id>
		<title>Pallet Issue</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=Pallet_Issue&amp;diff=1917"/>
		<updated>2026-08-20T15:10:26Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[file:Pallet_Issue.png|link=|800px]]&lt;br /&gt;
&lt;br /&gt;
Use this screen to issue either a part or full pallet to a Process Order. The transaction is written to Pallet History and can optionally create an xml interface message.&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=Pallet_Return&amp;diff=1916</id>
		<title>Pallet Return</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=Pallet_Return&amp;diff=1916"/>
		<updated>2026-08-20T15:06:20Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[file:Pallet_Return.png|link=|600px]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=Pallet_Issue&amp;diff=1915</id>
		<title>Pallet Issue</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=Pallet_Issue&amp;diff=1915"/>
		<updated>2026-08-20T15:04:38Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[file:Pallet_Issue.png|link=|800px]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=File:Pallet_Issue.png&amp;diff=1914</id>
		<title>File:Pallet Issue.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=File:Pallet_Issue.png&amp;diff=1914"/>
		<updated>2026-08-20T15:01:27Z</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:Pallet_Return.png&amp;diff=1913</id>
		<title>File:Pallet Return.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=File:Pallet_Return.png&amp;diff=1913"/>
		<updated>2026-08-20T15:00:20Z</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=Pallet_Return&amp;diff=1912</id>
		<title>Pallet Return</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=Pallet_Return&amp;diff=1912"/>
		<updated>2026-08-20T15:00:06Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: Created page with &amp;quot; 500px&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[file:Pallet_Return.png|link=|500px]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=Pallet_Issue&amp;diff=1911</id>
		<title>Pallet Issue</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=Pallet_Issue&amp;diff=1911"/>
		<updated>2026-08-20T14:59:07Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: Created page with &amp;quot; 500px&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[file:Pallet_Issue.png|link=|500px]]&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=Template:Commander4j&amp;diff=1910</id>
		<title>Template:Commander4j</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=Template:Commander4j&amp;diff=1910"/>
		<updated>2026-08-20T14:12:37Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: /* Pallet Transactions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Getting Started=&lt;br /&gt;
*[[Introduction]]&lt;br /&gt;
*[[Overview]]&lt;br /&gt;
*[[Requirements]]&lt;br /&gt;
*[[Downloads]]&lt;br /&gt;
*[[Installation|Install]]&lt;br /&gt;
*[[Upgrading|Upgrade]]&lt;br /&gt;
*[[Setup4j|Database Configuration]]&lt;br /&gt;
*[[Default Username &amp;amp; Password]]&lt;br /&gt;
*[[Starting]]&lt;br /&gt;
*[[Logon]]&lt;br /&gt;
*[[Navigation]]&lt;br /&gt;
*[[Example Screens]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;br /&gt;
&lt;br /&gt;
=User Guide=&lt;br /&gt;
[[Category:Commander4j]]&lt;br /&gt;
===Pallet Transactions===&lt;br /&gt;
*[[Pallet Label]]&lt;br /&gt;
*[[Production Declaration]]&lt;br /&gt;
*[[Production Confirmation]]&lt;br /&gt;
*[[Pallet Admin]]&lt;br /&gt;
*[[Pallet History]]&lt;br /&gt;
*[[Pallet Issue]]&lt;br /&gt;
*[[Pallet Return]]&lt;br /&gt;
*[[Split Pallet]]&lt;br /&gt;
*[[Assign Process Order to Auto Labeller]]&lt;br /&gt;
*[[Production Lines &amp;amp; Labellers]]&lt;br /&gt;
*[[Despatch]]&lt;br /&gt;
**[[Equipment Admin]]&lt;br /&gt;
**[[Journeys]]&lt;br /&gt;
*[[Material Batches|Batches]]&lt;br /&gt;
*[[Bill of Materials]]&lt;br /&gt;
**[[Enquiries]]&lt;br /&gt;
**[[View / Edit]]&lt;br /&gt;
**Configuration&lt;br /&gt;
***[[Structure]]&lt;br /&gt;
***[[Elements]]&lt;br /&gt;
***[[Defaults]]&lt;br /&gt;
***[[Lists]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;br /&gt;
&lt;br /&gt;
===Case / Tray Labels===&lt;br /&gt;
*[[Case Label|Case &amp;amp; Tray Labels]]&lt;br /&gt;
**[[Production Lines &amp;amp; Labellers]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;br /&gt;
&lt;br /&gt;
===Quality Control Transactions===&lt;br /&gt;
*[[Quality Control Sample|Sample Labels]]&lt;br /&gt;
**[[Inspections]]&lt;br /&gt;
***[[Selection Lists]]&lt;br /&gt;
***[[Dictionary]]&lt;br /&gt;
**[[Update Samples]]&lt;br /&gt;
**[[Results Analysis and Reporting]]&lt;br /&gt;
**[[Database Schema used by Panel Samples]]&lt;br /&gt;
*Pallet Sorting&lt;br /&gt;
**[[Pallet Samples &amp;amp; Faults|Samples &amp;amp; Faults]]&lt;br /&gt;
**[[Pallet Samples Enquiries &amp;amp; Reports|Enquiries &amp;amp; Reports]]&lt;br /&gt;
***[[Pallet Sample Reasons|Reasons]]&lt;br /&gt;
***[[Pallet Sample Defect Types|Defect Types]]&lt;br /&gt;
***[[Pallet Sample Defect IDs|Defect IDs]]&lt;br /&gt;
***[[Sample Point Admin|Sample Points]]&lt;br /&gt;
***[[Pallet Sample Shift Names|Shift Names]]&lt;br /&gt;
***[[Pallet Sample Packing Lines|Packing Lines]]&lt;br /&gt;
***[[Pallet Sample Supplier Admin|Suppliers]]&lt;br /&gt;
***[[Pallet Sample Operatives|Operatives]]&lt;br /&gt;
*[[Isolate]]&lt;br /&gt;
**[[Quality Control Decisions]]&lt;br /&gt;
**[[Quality Control Reasons]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;br /&gt;
&lt;br /&gt;
===Waste Recording===&lt;br /&gt;
&lt;br /&gt;
*[[Waste Recording | Overview]]&lt;br /&gt;
*[[Waste Log]]&lt;br /&gt;
**[[Waste Transactions]]&lt;br /&gt;
**[[Waste Containers]]&lt;br /&gt;
**[[Waste Locations]]&lt;br /&gt;
**[[Waste Materials]]&lt;br /&gt;
**[[Waste Types]]&lt;br /&gt;
**[[Waste Reasons]]&lt;br /&gt;
*[[Waste Reporting]]&lt;br /&gt;
**[[Waste Reports Examples]]&lt;br /&gt;
**[[Waste Reporting IDs]]&lt;br /&gt;
**[[Waste Reporting Groups]]&lt;br /&gt;
**[[Link Location to Reporting ID]]&lt;br /&gt;
**[[Link Reporting ID to Location]]&lt;br /&gt;
&lt;br /&gt;
===Weight Checks===&lt;br /&gt;
*[[Weight Checks Data Capture]]&lt;br /&gt;
*[[Weight Check Reports]]&lt;br /&gt;
**[[Sample Point Admin]]&lt;br /&gt;
**[[Scale Admin]]&lt;br /&gt;
**[[Workstation Admin]]&lt;br /&gt;
**[[Tolerable Negative Errors]]&lt;br /&gt;
**[[Product Groups]]&lt;br /&gt;
**[[Container Codes]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;br /&gt;
===Customers===&lt;br /&gt;
*[[Customers|Customer Admin]]&lt;br /&gt;
*[[Customer Data]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;br /&gt;
[[Category:Commander4j]]&lt;br /&gt;
===Process Orders===&lt;br /&gt;
*[[Process Orders]]&lt;br /&gt;
**[[Process Order Barcode]]&lt;br /&gt;
**[[Required Resources]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;br /&gt;
===Materials===&lt;br /&gt;
*[[Materials|Material Admin]]&lt;br /&gt;
**[[Units of Measure]]&lt;br /&gt;
**[[Material Locations]]&lt;br /&gt;
**[[Material Types]]&lt;br /&gt;
**[[Material UOMs]]&lt;br /&gt;
**[[Material Data IDs]]&lt;br /&gt;
**[[Customer Data|Customer Specific Data]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Commander4j]]&lt;br /&gt;
&lt;br /&gt;
===Locations===&lt;br /&gt;
*[[Locations]]&lt;br /&gt;
&lt;br /&gt;
===Interfaces===&lt;br /&gt;
*[[Interface Admin]]&lt;br /&gt;
*[[Interface Log]]&lt;br /&gt;
*[[Request Queue]]&lt;br /&gt;
*[[Process Messages]]&lt;br /&gt;
*[[Interface Example Data Flow 1]]&lt;br /&gt;
*[[Interface Example Data Flow 2]]&lt;br /&gt;
*[[Interface Message Formats]]&lt;br /&gt;
&lt;br /&gt;
===Security===&lt;br /&gt;
*[[Users]]&lt;br /&gt;
*[[Groups]]&lt;br /&gt;
**[[Permissions]]&lt;br /&gt;
*[[Audit Reports]]&lt;br /&gt;
&lt;br /&gt;
{{Commander4j Configuration}}&lt;/div&gt;</summary>
		<author><name>Dgarratt</name></author>
	</entry>
	<entry>
		<id>https://wiki.commander4j.com/index.php?title=File:Bom_structure.png&amp;diff=1909</id>
		<title>File:Bom structure.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=File:Bom_structure.png&amp;diff=1909"/>
		<updated>2026-08-20T14:08:51Z</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=Bill_of_Materials&amp;diff=1908</id>
		<title>Bill of Materials</title>
		<link rel="alternate" type="text/html" href="https://wiki.commander4j.com/index.php?title=Bill_of_Materials&amp;diff=1908"/>
		<updated>2026-08-20T14:08:30Z</updated>

		<summary type="html">&lt;p&gt;Dgarratt: /* Viewing a BOM */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Bill of Materials (BOM) module allows you to define and manage product recipes — the ingredients or components required to manufacture a finished product. BOMs can be entered manually or imported from an external system via the XML interface.&lt;br /&gt;
&lt;br /&gt;
== Structure ==&lt;br /&gt;
&lt;br /&gt;
A BOM in Commander4j is hierarchical. Each BOM has a unique &#039;&#039;&#039;BOM ID&#039;&#039;&#039; and a &#039;&#039;&#039;version number&#039;&#039;&#039;, allowing multiple versions of the same recipe to coexist. The BOM is displayed as a tree, with the finished product at the root and its components, sub-components, and associated data as branches beneath it.&lt;br /&gt;
&lt;br /&gt;
Each node in the tree has the following properties:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Data ID&#039;&#039;&#039; || The identifier of this element (e.g. a material or ingredient code)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Data Type&#039;&#039;&#039; || The classification of this element (e.g. ingredient, component, instruction)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Data String&#039;&#039;&#039; || A text value associated with this element&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Data Decimal&#039;&#039;&#039; || A numeric value such as a quantity or percentage&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Data Date&#039;&#039;&#039; || A date value if applicable&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Stage&#039;&#039;&#039; || The production stage at which this element is used, allowing filtering of the BOM by stage&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Sequence&#039;&#039;&#039; || The order of this element within its parent level&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Each node has a unique UUID that maintains its position in the tree hierarchy.&lt;br /&gt;
&lt;br /&gt;
== Viewing a BOM ==&lt;br /&gt;
&lt;br /&gt;
Enter the BOM ID (and optionally a version) to load the structure into the tree view. The tree can be expanded and collapsed at any level using the toolbar buttons. Individual nodes can be selected to view their full properties. The Stage filter allows the tree to be restricted to elements relevant to a particular production stage.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:bom_structure.png|600px]]&lt;br /&gt;
&lt;br /&gt;
== Versions ==&lt;br /&gt;
&lt;br /&gt;
Multiple versions of a BOM can exist for the same BOM ID. This allows recipe changes to be tracked over time whilst retaining historical versions for reference or reactivation.&lt;br /&gt;
&lt;br /&gt;
== Importing BOMs ==&lt;br /&gt;
&lt;br /&gt;
BOMs can be imported from XML files via the [[Interface Message Formats|XML interface]]. The import process validates the structure and auto-generates UUIDs for all nodes. This is the recommended method when the BOM originates in an ERP or recipe management system.&lt;br /&gt;
&lt;br /&gt;
Manual entry is also supported for sites that do not have an external recipe system.&lt;br /&gt;
&lt;br /&gt;
== Relationship to Material Issue ==&lt;br /&gt;
&lt;br /&gt;
The [[Web_Applications_Overview|c4j_web_Issue]] application uses BOM data to validate that operators are issuing the correct raw materials to a production line — checking the scanned material SSCC against the BOM for the active process order.&lt;br /&gt;
&lt;br /&gt;
== Database Table ==&lt;br /&gt;
&lt;br /&gt;
BOM records are stored in &amp;lt;code&amp;gt;APP_BOM&amp;lt;/code&amp;gt;, with a composite primary key of BOM ID, version, and node UUID.&lt;br /&gt;
&lt;br /&gt;
See also: [[Materials]], [[Process Orders]], [[Interface Message Formats]]&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=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>
</feed>