[an error occurred while processing this directive]

Hardware Support: MCAN Protocol Serial-to-TCP Bridge

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.

Quick Start

  1. Building the shared library version is included in JMRI's build pipeline:
  2. Build the standalone JAR (for deployment on another computer running CC-Schnitte):
    ant mcan-tcp-bridge-jar
    Output: dist/mcan-tcp-bridge.jar Copy this single file to the target computer.
  3. List available ports:
    java -jar dist/mcan-tcp-bridge.jar --list
  4. Start bridge:
    # 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
              
  5. Configure JMRI: Add CS2 Ethernet connection to localhost:15731

Local Serial Port Specification

The 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

Overview

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.

Requirements

Building the Bridge

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-bridge
to 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.

Build Standalone JAR

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.

Run from Development Environment

ant mcan-tcp-bridge
      

This runs the bridge using JMRI's full classpath (useful for development and debugging).

Using the Bridge

List Available Serial Ports

java -jar mcan-tcp-bridge.jar --list
      

Output example:

Available serial ports:

  COM3
    Description: USB Serial Port
    Location: USB
      

Start the Bridge

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
      

Multiple Devices

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
      

Command Line Options

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
      

MCAN Poke Tool

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).

Bridge Relay Integration Test

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.

Connecting JMRI to the Bridge

Configure JMRI to connect to the bridge as if it were a CS2:

  1. Start the bridge program
  2. Open JMRI and go to Edit - Preferences
  3. Click the Connections tab
  4. Click + to add a new connection
  5. Select:
    • System manufacturer: Märklin
    • System connection: Command Station 2 (CS2)
    • Connection: Network Connection (TCP)
    • IP Address/Host Name: localhost (or IP of bridge computer)
    • Port: 15731(currently hardcoded as CS2/CS3 cannot customize the port in current firmware)
  6. Click Save and restart JMRI

Hot-Plug Support

The bridge supports USB hotplugging without requiring a restart:

Monitor Mode

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:

Running as a Service

Linux systemd Service

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
      

Windows Service

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.

Troubleshooting

Serial Port Not Found

Error: Failed to open serial port: COM3

Solutions:

  1. Check that the CC-Schnitte is plugged in
  2. Verify the port name with --list
  3. On Linux, check permissions: sudo usermod -a -G dialout $USER (then logout/login)
  4. Ensure no other program is using the port

TCP Port Already in Use

Error: java.net.BindException: Address already in use

Solutions:

  1. Use a different port by specifying it in the port argument: --port COM3:12346
  2. Check what's using port 15731: netstat -an | grep 15731
  3. Stop the conflicting process

JMRI Won't Connect

Check:

  1. Bridge is running and showing "TCP server listening on port 15731"
  2. Firewall isn't blocking port 15731
  3. Correct IP address in JMRI (use localhost if on same machine)
  4. JMRI connection type is "CS2 Ethernet" with TCP protocol

No Data Being Received

Enable debug logging:

java -Dorg.slf4j.simpleLogger.defaultLogLevel=DEBUG -jar mcan-tcp-bridge.jar --port COM3
      

Also check:

Performance

Connect virtual serial ports to the bridge

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.

Linux and macOS

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

Windows virtual serial ports require third-party software beyond the scope of JMRI, such as com2tcp or com2com.

Notes

Related Documentation