Most ZIMO devices, especially the MXULF, a device for updating and testing model railway decoders, support many different serial protocols. ULF_COM aims to provide an overview of the supported protocols and, above all, to help identify and switch over the currently active one. The following protocols are currently supported:
Protocol | Description | Supported by |
---|---|---|
ULF_DCC_EIN | DCC as ASCII | MXULF, ZSP |
ULF_DECUP_EIN | MX ZPP and ZSU updates via tracks | MXULF, Z21, ZCS, ZSP |
ULF_MDU_EIN | MS/N ZPP and ZSU updates via tracks | MXULF, Z21 |
ULF_MX1BIN | Original MX1 command and control | JMRI, MX1, MXULF, Rocrail, TrainController, ZCS |
ULF_SUSIV2 | ZPP updates via SUSI | MXULF, ZSP |
Table of Contents
The support of many different protocols unfortunately makes the exact process of when and how to switch between them a bit confusing. The default mode that is active after the reset was always the MX1 binary protocol. Special commands that do not correspond to the binary protocol scheme were added later to switch to other modes or to perform other tasks (e.g. status queries).
Mode | Enter | Leave |
---|---|---|
ULF_DCC_EIN | "DCC_EIN\r" |
"RESET\r" |
ULF_DECUP_EIN | "DECUP_EIN\r" |
"RESET\r" |
ULF_MDU_EIN | "MDU_EIN\r" |
"RESET\r" |
ULF_MX1BIN | Receive any binary schema ("\x01\x01.+?(?<!\x10)\x17" ) |
"RESET\r" |
ULF_SUSIV2 | "SUSIV2\r" |
"RESET\r" |
The following flowchart shows how to switch between the protocols. Receipt of any binary protocol command results in a switch to binary protocol. In order to switch to one of the other operating modes, the name of the protocol including carriage return character must be received. All modes can be exited by receiving a "RESET\r"
command. This will restore the initial state.
The ULF_COM library contains various helper functions that can help with recognizing the mode from a string. Please refer to Usage chapter for further details.
- C++23 compatible compiler
- CMake ( >= 3.25 )
This library is meant to be consumed with CMake.
# Either by including it with CPM
cpmaddpackage("gh:ZIMO-Elektronik/[email protected]")
# or the FetchContent module
FetchContent_Declare(
DCC
GIT_REPOSITORY "https://github.com/ZIMO-Elektronik/ULF_COM"
GIT_TAG v0.0.1)
target_link_libraries(YourTarget INTERFACE ULF::COM)
If the build is running as a top-level CMake project then tests and a small example will be generated.
cmake -Bbuild
cmake --build build --target ULF_COMExamples
To check whether a string contains an MX1 binary protocol frame or a command, the two functions str2mx1bin
or str2cmd
can be used. Both functions expect that the searched schema is at the beginning of the string. In order to be able to distinguish between an error case and the case where the data is still incomplete, the return value of both functions is std::expected<std::optional<std::string_view>, std::errc>
. If the pattern is not recognized at all, i.e. in the event of an error, then a std::errc
is returned. If something is found but the data is not yet complete, a std::nullopt
is returned. Otherwise the found data is returned as std::string_view
. The following snippet shows how str2cmd
can be used.
// Check if character stream contains valid command
auto maybe_cmd{ulf::com::str2cmd("DCC_EIN\r and then some")};
// Could be command
if (maybe_cmd) {
// Already complete?
if (*maybe_cmd) {
// Complete command
auto cmd{**maybe_cmd};
std::cout << cmd << "\n";
}
// No, still missing characters
else {}
}
// Error, not command
else {}
// Or, more concise
if (maybe_cmd == "DCC_EIN\r"sv) std::cout << "Command found\n";
And the same pattern can also be applied to str2mx1bin
.
// Check if character stream contains valid MX1 binary
auto maybe_mx1bin{ulf::com::str2mx1bin("\x01\x01"
"data\x17")};
// Could be MX1 binary
if (maybe_mx1bin) {
// Already complete?
if (*maybe_mx1bin) {
// Complete MX1 binary
auto mx1bin{**maybe_mx1bin};
std::cout << mx1bin << "\n";
}
// No, still missing characters
else {}
}
// Error, not MX1 binary scheme
else {}
Alternatively, the monadic extensions of std::expected
and std::optional
can be used.
Also part of this library is the ping
function, which can be used to generate a response to the "PING\r"
command. There are two overloads available, one that only takes the device name and a version, and one that also allows specifying a hardware revision.
// Replies to "PING\r"
auto ping{ulf::com::ping("MyDevice", "1.2.3")};
auto ping_with_rev{ulf::com::ping("MyDevice", "1.2.3", 'B')};