[an error occurred while processing this directive]

Märklin CAN Protocol Library

This page describes how JMRI encodes and decodes Märklin CAN (MCAN) frames. Please also read the Javadocs for the jmrix.marklin package.

Overview

Frame encoding and decoding live in the jmri.jmrix.marklin.mcan package tree. These classes do not depend on the JMRI application layer. The adapter, the monitor and standalone tools such as the MCAN TCP Bridge share the same frame handling. This independence is enforced by a unit test.

ProtocolClassifier.classify() turns every 13-byte frame into exactly one typed frame. All of them extend the common base class McanFrame, which gives access to the raw bytes and the protocol family:

Callers test the result with instanceof or switch on protocol(). Malformed input (null or not 13 bytes) is rejected with an exception rather than reported as an unknown frame.

Inside JMRI, MarklinReply.getFrame() and MarklinMessage.getFrame() return this classification, cached until the bytes change. The traffic controller hands each CdB configuration frame once to the registered CdB configuration listeners and then delivers every frame, including CdB frames, to all ordinary Märklin listeners such as the traffic monitor.

Package Structure

Each subpackage of jmri.jmrix.marklin.mcan has one responsibility:

PackageIntent
mcan Types shared by all protocol families: the frame base class McanFrame, UnknownFrame, RawFrame and FrameProtocol. McanUid is the 32-bit UID of a device on the bus (CS2, MS2, Gleisbox, ...). It provides unsigned ordering, the CS2 hash calculation and the broadcast and uninitialized values. It is not used for mfx decoder UIDs or Loc-IDs.
mcan.classify Entry point for received frames. ProtocolClassifier recognises the protocol family and calls the matching parser. It depends on mcan.cs2 and mcan.cdb Neither of those depends on it.
mcan.cs2 Märklin CS2 native protocol: Header, data and command types, Cs2Frame and its typed subclasses, frame builders and parsers grouped by command family and NativeDeviceInfo (PING reply contents).
mcan.cdb CAN-digital-Bahn configuration protocol: CdBFrameType, typed frames, frame builders and parsers, module-specific command sets (WeichenChef, LampenChef, Reporter) and the CdBDeviceClass catalogue of known module classes.
mcan.address Address arithmetic. AddressSpace handles native MS2 and throttle protocol address ranges. CdBAddressCodec and AddressEncoding convert DCC/MM/CAN user addresses to and from CdB register values. The AddressCodec interface has only one implementation and no callers yet. It may be removed.

Device UIDs in the public API are McanUid values. For example, the uid() getters on CS2 configuration frames and the targetUid/senderUid parameters of the Cs2SystemCommands builders use this type.

MCAN Protocol Structure

MCAN frames use a 13-byte format per the CS2 CAN Protocol 2.0 specification:

Bytes Field Description
0 Priority + Command[14:7] Priority (bits 7-4), Command high bits (bits 3-0)
1 Command[6:0] + Response Command low bits (bits 7-1), Response flag (bit 0)
2-3 Hash 16-bit hash/identifier
4 DLC Data Length Code (0-8 bytes in the CAN payload)
5-12 Data Up to 8 payload bytes; their meaning depends on the command

Priority Levels

Command Categories

Range Category Example Commands
0x00 System Stop (0x00), Go (0x01), Halt (0x02)
0x01-0x0A Management Speed (0x04), Direction (0x05), Function (0x06)
0x0B-0x0D Accessory Turnout control
0x18-0x1C Software PING (0x18), CAN BOOT (0x1B)
0x20-0x22 GUI GUI commands
0x10-0x12 Feedback S88 events (0x11)
0x30-0xFF Automation Automation commands

Related Classes

MarklinMessageFormatter

Formats raw MCAN frames for display and logging. Used by both JMRI's MarklinMon monitor pane and the standalone MCAN TCP Bridge monitor mode.

// Format a raw frame with device identification
String text = MarklinMessageFormatter.formatRaw(rawData, null, true);

// Format directly from raw bytes (standalone, no i18n)
String text = MarklinMessageFormatter.formatRaw(rawData, null);
      

Output example:

[MS2:0x00112233] Priority 4: Engine/Accessory Command Command: Change of speed 512 Request to Loco Address 3 0x5, 0x9, 0x47, 0x11, 0x2, 0x0, 0x0, 0x0, 0x3, 0x2, 0x0, 0x0, 0x0
      

An optional I18nProvider interface allows JMRI to supply localized strings while the same class works without JMRI runtime in the bridge.

NativeDeviceInfo

Holds the UID, device type, software version and hash reported in a CS2 native PING reply (command 0x18). Known device type codes (from CS2 CAN Protocol 2.0):

Type CodeDevice
0x0000GFP (Gleis Format Processor) 60213/60214
0x0010Gleisbox 60112/60113
0x0020Connect 6021 (60128)
0x0030MS2 (60653)
0x0050CS3
0x1300CC-Schnitte CAN/USB interface (3.x series onwards)
0xFFE0Wireless devices
0xFFFFCS2-GUI (Master)

McanDevice and McanDeviceState

McanDevice is a JMRI NamedBean representing one device on the MCAN bus. It tracks the device identity, software version, hardware version, first-seen and last-seen timestamps and a lifecycle state.

Lifecycle states (McanDeviceState):

StateMeaning
DISCOVEREDPing reply received; identity established
INITIALIZINGFollow-up parameter reads in progress
ONLINEFully initialized and actively responding
STALENo response within configured threshold
OFFLINEExplicitly disconnected or lost

Property change events are dispatched on the Swing EDT for thread safety.

McanDeviceIdentity

Immutable identity for an MCAN device. Has two concrete subtypes:

McanDeviceIdentity.Native nat = McanDeviceIdentity.forNative(McanUid.of(0x00112233L), 0x0030);
// nat.getSystemName("M") == "M:dev:uid-00112233"

McanDeviceIdentity.CdB cdb = McanDeviceIdentity.forCdB(0x22, 3);
// cdb.getSystemName("M") == "M:dev:cdb-22-03"
      

McanDeviceManager

McanDeviceManager is a JMRI AbstractManager that discovers and tracks all MCAN devices seen on the bus. It listens to both native MCAN messages (via MarklinListener) and CdB configuration frames (via CdBConfigListener).

// Discover native Marklin devices (CS2, MS2, Gleisbox, CC-Schnitte)
manager.discoverMarklinDevices();

// Discover all known CdB device classes
manager.discoverAllCdBDevices();

// Discover one specific CdB class
manager.discoverCdBDevice(CdBDeviceClass.WEICHEN_CHEF_MAGNET);
      

Here CdBDeviceClass is jmri.jmrix.marklin.mcan.cdb.CdBDeviceClass.

CdBDeviceClass

jmri.jmrix.marklin.mcan.cdb.CdBDeviceClass lists the known CdB device classes and the protocol generation used for discovery:

Class IDDeviceProtocol
0x03GleisReporter JumboNEW
0x0BStromSnifferNEW
0x0DGleisReporterNEW
0x21ReporterChef 002NEW
0x22WeichenChef Magnet M / deLuxeNEW
0x23WeichenChef ACNEW
0x26WeichenChef BasicNEW
0x27WeichenChef KombiNEW
0x2AWeichenChef MotorNEW
0x4ALampenChefOLD

References