The MCAN TCP Bridge connects Märklin CAN (MCAN) serial adapters to TCP/IP. JMRI can connect to the bridge through its CS2 Ethernet adapter. The bridge can also serve multiple clients and serial adapters.
ant mcan-tcp-bridge-jarOutput:
dist/mcan-tcp-bridge.jar Copy this single file to the target computer.
java -jar dist/mcan-tcp-bridge.jar --list
# Single device, default port 15731 on all network interfaces
java -jar dist/mcan-tcp-bridge.jar --port COM3 # Windows
java -jar dist/mcan-tcp-bridge.jar --port /dev/ttyUSB0 # Linux
localhost:15731The bridge's --port option names one or more local serial devices. It maps each serial device to a TCP listening port.
Specify a TCP port after the serial device, otherwise the default port 15731 and following ports are used.
<serial>[:<bind_addr>][:<tcp_port>][,<serial>[:<bind_addr>][:<tcp_port>],...]
| Example | Result |
|---|---|
--port COM3 |
COM3 to TCP 15731 (all interfaces) |
--port COM3:50000 |
COM3 to TCP 50000 (all interfaces) |
--port COM3:127.0.0.1:15731 |
COM3 to localhost:15731 only |
--port COM2,COM3 |
COM2 to 15731, COM3 to 15732 |
--port COM2,COM3,COM4 |
COM2 to 15731, COM3 to 15732, COM4 to 15733 |
--port COM2:50000,COM3:50001 |
COM2 to 50000, COM3 to 50001 |
The bridge program creates one or multiple TCP servers that connect to one MCAN serial adapter each (such as the CC-Schnitte by CAN-digital-Bahn). One or multiple clients can connect to each TCP server simultaneously.
By default, the bridge is built as a part of JMRI linking to other parts of the installation. Run
mvn antrun:run -Danttarget=mcan-tcp-bridgeto build and run the bridge from JMRI source. This is suitable if you want to run the bridge on the same computer as JMRI itself and update it as part of JMRI's software lifecycle.
The standalone JAR is intended for deployment on a separate computer that has the CC-Schnitte physically connected to it via USB. Build the JAR on a machine that has the JMRI source tree checked out. Then copy it to the target computer. No JMRI installation is required on the target computer.
Using Ant:
cd /path/to/JMRI
ant mcan-tcp-bridge-jar
Using Maven:
cd /path/to/JMRI
mvn antrun:run -Danttarget=mcan-tcp-bridge-jar
This creates dist/mcan-tcp-bridge.jar, a self-contained JAR with all
dependencies embedded. Copy this single file to the target computer:
Linux / macOS:
scp dist/mcan-tcp-bridge.jar user@bridge-host:/opt/mcan-tcp-bridge/
Windows (PowerShell):
Copy-Item dist\mcan-tcp-bridge.jar \\bridge-host\share\mcan-tcp-bridge\
Or use any other file transfer method (USB stick, shared folder, etc.). Once copied, run it on the target computer as described in the Using the Bridge section below.
ant mcan-tcp-bridge
This runs the bridge using JMRI's full classpath (useful for development and debugging).
java -jar mcan-tcp-bridge.jar --list
Output example:
Available serial ports:
COM3
Description: USB Serial Port
Location: USB
Windows:
java -jar mcan-tcp-bridge.jar --port COM3
Linux:
java -jar mcan-tcp-bridge.jar --port /dev/ttyUSB0
macOS:
java -jar mcan-tcp-bridge.jar --port /dev/cu.usbserial-AB0JUFVA
The bridge can manage multiple serial adapters simultaneously, each on its own TCP port:
java -jar mcan-tcp-bridge.jar --port COM3,COM4,COM5
This creates three TCP servers:
You can also specify custom ports:
java -jar mcan-tcp-bridge.jar --port COM3:50000,COM4:50001
Usage: java -jar mcan-tcp-bridge.jar [--port <serial_spec>] [--client-for <target>] [options]
Local serial devices (--port / -p):
<serial>[:<bind_addr>][:<tcp_port>][,<serial>[:<bind_addr>][:<tcp_port>],...]
Windows: COM1, COM3, etc.
Linux: /dev/ttyUSB0, /dev/ttyACM0, etc.
macOS: /dev/cu.usbserial-*
- --port takes serial device names, not a TCP port number
- TCP listening port is embedded in each serial device specification
- First device without explicit TCP port gets 15731; subsequent devices
get auto-incremented ports (15732, 15733, ...)
- Bind address defaults to all interfaces (0.0.0.0) when omitted
Options:
--port, -p <spec> Local serial device specification (required unless using --client-for)
--client-for, -c <target> Connect to a remote CS2/bridge TCP server.
Frames from remote are forwarded to local TCP clients
and serial. Repeat for multiple upstreams.
target forms:
host default remote port 15731 for the first local bridge
host:remotePort custom remote port on the first local bridge
host:COM3,COM4 default remote port connects to two selected local bridges
host:remotePort:COM3,COM4
custom remote port connects to two selected local bridges
--baud, -b <rate> Serial baud rate for all devices (default: 500000)
--monitor, -m Enable message monitoring to stdout (decoded MCAN frames)
--list, -l List available serial ports and exit
--help, -h Show this help message
Examples:
java -jar mcan-tcp-bridge.jar --port COM3
java -jar mcan-tcp-bridge.jar --port COM3:50000
java -jar mcan-tcp-bridge.jar --port COM3 --monitor
java -jar mcan-tcp-bridge.jar --port COM3:127.0.0.1:15731
java -jar mcan-tcp-bridge.jar --port COM2,COM3:49999,COM4:50000
java -jar mcan-tcp-bridge.jar --port COM3 --client-for 192.168.1.20
java -jar mcan-tcp-bridge.jar --port COM3,COM4 --client-for 192.168.1.20:50000:COM4
The standalone marklin-poke tool sends raw 13-byte MCAN frames to a running
bridge and prints frames received while it watches the bus. Build it with
ant mcan-poke-jar. In contrast to the bridge's --port, the poke
tool's --port is a numeric TCP port.
java -jar dist/marklin-poke.jar --host localhost --port 15731 --command "AA BB CC DD EE FF 00 11 22 33 44 55 66"
--host defaults to localhost and --port defaults
to 15731. Each comma-separated frame in --command must contain
exactly 13 bytes of hexadecimal data. Spaces within a frame are ignored. Optional
--padding <ms> sets the delay between frames (default 50 ms) and
--watch <s> sets the time to collect replies (default 5 seconds).
scripts/test-mcan-bridge-relay.sh demonstrates the bridge and
marklin-poke working together as a local integration test and development aid.
After building both JARs run it from the JMRI repository root:
ant mcan-tcp-bridge-jar mcan-poke-jar
bash scripts/test-mcan-bridge-relay.sh
The script starts two bridges on local TCP ports, connects one to the other with
--client-for and uses marklin-poke to send test frames and check
that they are relayed in both directions. It does not really use serial devices and performs
bridge forwarding without MCAN hardware. The script uses ports 50500 and
50501. Make sure they are available before running it.
Configure JMRI to connect to the bridge as if it were a CS2:
localhost (or IP of bridge computer)15731(currently hardcoded as CS2/CS3 cannot customize the port in current firmware)The bridge supports USB hotplugging without requiring a restart:
Enable monitor mode to see decoded MCAN messages in real-time:
java -jar mcan-tcp-bridge.jar --port COM3 --monitor
Monitor mode displays each CAN frame formatted by MarklinMessageFormatter:
Create /etc/systemd/system/mcan-tcp-bridge.service:
[Unit]
Description=MCAN Protocol Serial to TCP Bridge
After=network.target
[Service]
Type=simple
User=jmri
WorkingDirectory=/opt/mcan-tcp-bridge
ExecStart=/usr/bin/java -jar /opt/mcan-tcp-bridge/mcan-tcp-bridge.jar --port /dev/ttyUSB0
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
Enable and start:
sudo systemctl daemon-reload
sudo systemctl enable mcan-tcp-bridge
sudo systemctl start mcan-tcp-bridge
sudo systemctl status mcan-tcp-bridge
Create a Windows service using PowerShell and native service infrastructure.
Step 1: Create a wrapper script C:\mcan-tcp-bridge\run-bridge.bat:
@echo off
cd /d C:\mcan-tcp-bridge
"C:\Program Files\Java\jdk-11\bin\java.exe" -jar mcan-tcp-bridge.jar --port COM3
Step 2: Create the service using PowerShell (run as Administrator):
# Create the service
sc.exe create McanTcpBridge `
binPath= "C:\mcan-tcp-bridge\run-bridge.bat" `
DisplayName= "MCAN TCP Bridge Service" `
start= auto
# Configure service description
sc.exe description McanTcpBridge "Bridges MCAN serial adapters to TCP/IP for JMRI"
# Start the service
sc.exe start McanTcpBridge
# Check service status
sc.exe query McanTcpBridge
Alternative: Use PowerShell script for service management:
# Create service with New-Service cmdlet
New-Service -Name "McanTcpBridge" `
-BinaryPathName "C:\mcan-tcp-bridge\run-bridge.bat" `
-DisplayName "MCAN TCP Bridge Service" `
-Description "Bridges MCAN serial adapters to TCP/IP for JMRI" `
-StartupType Automatic
# Start the service
Start-Service -Name "McanTcpBridge"
# Check service status
Get-Service -Name "McanTcpBridge"
Service Management:
# Stop service
sc.exe stop McanTcpBridge
# or: Stop-Service -Name "McanTcpBridge"
# Remove service
sc.exe delete McanTcpBridge
# or: Remove-Service -Name "McanTcpBridge"
# View service logs (Event Viewer)
Get-EventLog -LogName Application -Source "Service Control Manager" -Newest 20
Note: For production use, consider using a proper service wrapper like WinSW which provides better logging and error handling than batch file wrappers.
Error: Failed to open serial port: COM3
Solutions:
--listsudo usermod -a -G dialout $USER (then logout/login)Error: java.net.BindException: Address already in use
Solutions:
--port COM3:12346netstat -an | grep 15731Check:
localhost if on same machine)Enable debug logging:
java -Dorg.slf4j.simpleLogger.defaultLogLevel=DEBUG -jar mcan-tcp-bridge.jar --port COM3
Also check:
JMRI provides helper scripts for creating virtual serial ports that connect to the bridge. A virtual port lets serial-only software such as CAN-digital-Bahn's WeichenChef Configuration utility share the adapter with JMRI. The bridge can run on a separate computer connected to the adapter, allowing JMRI and the configuration utility to connect over the network.
Use scripts/Linux/create-mcan-virtual-port.sh (requires socat):
./scripts/Linux/create-mcan-virtual-port.sh /dev/ttyVCOM0 localhost 15731
This creates a virtual serial port /dev/ttyVCOM0 that connects to the bridge's
TCP server. Configure your programmer software to use this virtual port.
Windows virtual serial ports require third-party software beyond the scope of JMRI, such as com2tcp or com2com.
--baud).
Serial parameters are: 8 data bits, 1 stop bit, no parity, no flow control, RTS/DTR enabled.