uploaded 3 days ago
Z21 protocol for open LAN interface

readme

# Z21

[![build](https://github.com/ZIMO-Elektronik/Z21/actions/workflows/build.yml/badge.svg)](https://github.com/ZIMO-Elektronik/Z21/actions/workflows/build.yml) [![tests](https://github.com/ZIMO-Elektronik/Z21/actions/workflows/tests.yml/badge.svg)](https://github.com/ZIMO-Elektronik/Z21/actions/workflows/tests.yml) [![license](https://img.shields.io/github/license/ZIMO-Elektronik/Z21)](https://github.com/ZIMO-Elektronik/Z21/raw/master/LICENSE)

<img src="https://github.com/ZIMO-Elektronik/Z21/raw/master/data/images/logo.png" width="15%" align="right">

The [ROCO](https://www.roco.cc/ren/) [Z21](https://www.z21.eu/en) is a command station with support for LocoNet, R-Bus and XpressNet devices. It has an open LAN interface with a well-documented protocol that has been continuously developed since then. This C++ library of the same name contains platform-independent code for the server-side (i.e. the part that runs on a command station) implementation of the protocol.

<details>
  <summary>Table of Contents</summary>
  <ol>
    <li><a href="#protocol">Protocol</a></li>
    <li><a href="#features">Features</a></li>
    <li><a href="#getting-started">Getting Started</a></li>
      <ul>
        <li><a href="#prerequisites">Prerequisites</a></li>
        <li><a href="#installation">Installation</a></li>
        <li><a href="#build">Build</a></li>
      </ul>
    <li><a href="#usage">Usage</a></li>
      <ul>
        <li><a href="#server">Server</a></li>
        <li><a href="#interfaces">Interfaces</a></li>
      </ul>
  </ol>
</details>

## Protocol
The official documentation of the protocol can be downloaded from the ROCO homepage in English and German.

| English                                                                                                                                                                               | German                                                                                                                                                       |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [Z21 LAN protocol V1.13](https://www.z21.eu/media/Kwc_Basic_DownloadTag_Component/root-en-main_47-1652-959-downloadTag-download/default/d559b9cf/1699290380/z21-lan-protokoll-en.pdf) | [Z21 LAN Protokoll V1.13](https://www.z21.eu/media/Kwc_Basic_DownloadTag_Component/47-1652-959-downloadTag/default/69bad87e/1699290251/z21-lan-protokoll.pdf)|

## Features
- Platform-independent
- Fine grained [interfaces](#interfaces) ( :ballot_box_with_check: done / :negative_squared_cross_mark: todo)
  - Can :negative_squared_cross_mark:
  - Driving :ballot_box_with_check:
  - FastClock :negative_squared_cross_mark:
  - LocoNet :negative_squared_cross_mark:
  - Programming :ballot_box_with_check:
  - RailCom :ballot_box_with_check:
  - RBus :negative_squared_cross_mark:
  - Settings :ballot_box_with_check:
  - Switching :ballot_box_with_check:
  - System :ballot_box_with_check:
  - ZLink :negative_squared_cross_mark:
  - Logging :ballot_box_with_check:
- Examples for Linux, Windows and ESP32

## Getting Started

### Prerequisites
- C++23 compatible compiler
- [CMake](https://cmake.org/) ( >= 3.25 )
- Optional
  - for building [ESP32](https://www.espressif.com/en/products/socs/esp32) example
    - [ESP-IDF](https://github.com/espressif/esp-idf) ( >= 5.0.3 )

### Installation
This library is meant to be consumed with CMake,

```cmake
# Either by including it with CPM
cpmaddpackage("gh:ZIMO-Elektronik/Z21@0.3.1")

# or the FetchContent module
FetchContent_Declare(
  DCC
  GIT_REPOSITORY "https://github.com/ZIMO-Elektronik/Z21"
  GIT_TAG v0.3.1)

target_link_libraries(YourTarget PRIVATE Z21::Z21)
```

or, on [ESP32 platforms](https://www.espressif.com/en/products/socs/esp32), with the [IDF Component Manager](https://docs.espressif.com/projects/idf-component-manager/en/latest/) by adding it to a `idf_component.yml` file.
```yaml
dependencies:
  zimo-elektronik/z21:
    version: "0.3.1"
```

### Build
The library itself is header-only, so technically it can't be built. However, if run as top-level CMake project then, depending on the target platform, different examples can be built.

#### Host
On host platforms a simulator example running a Z21 server can be built.
```sh
cmake -Bbuild
cmake --build build --target Z21Sim
```

The simulator allows you to try out the library directly in a simple GUI. The application starts a Z21 server to which you can connect directly via [Z21 app](https://www.z21.eu/en/products/z21-app). You can then control locomotives, switch turnouts or simulate various errors such as a short circuit.
![Z21Sim](https://github.com/ZIMO-Elektronik/Z21/raw/master/data/images/Z21Sim.png)

#### ESP32
On [ESP32 platforms](https://www.espressif.com/en/products/socs/esp32) examples from the [examples](https://github.com/ZIMO-Elektronik/DCC/raw/master/examples) subfolder can be built directly using the [IDF Frontend](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/tools/idf-py.html).

```sh
idf.py create-project-from-example "zimo-elektronik/z21^0.3.1:esp32"
```

## Usage

### Server
To create a server it is necessary to derive from `z21::server::Base`. The class uses a mixture of static and dynamic polymorphism, where the desired interfaces must be passed as template arguments, but the actual implementations of these interfaces are classic virtual methods. The interfaces have no dependencies on each other and can be freely selected according to requirements. The only exception to this is the [System interface](#system), which is **mandatory** because it covers basic functions of the protocol. An implementation of such an (almost) minimal version can be found in the [POSIX/ESP32 example](https://github.com/ZIMO-Elektronik/Z21/tree/master/examples/posix).

This example is also an excellent way to see what receiving and transmitting data might look like. The Z21 protocol uses [UDP](https://en.wikipedia.org/wiki/User_Datagram_Protocol) over port 21105 or 21106, although control applications on the client should prefer 21105.

#### Receiving
The following snippet shows what a task that reads data via [recvfrom](https://pubs.opengroup.org/onlinepubs/000095399/functions/recvfrom.html) and passes it to the server can look like.
```cpp
void server_task(int sock) {
  // IPv4 Internet domain socket address
  sockaddr_in dest_addr_ip4;
  socklen_t socklen{sizeof(dest_addr_ip4)};

  // Receive buffer
  std::array<uint8_t, Z21_MAX_PAYLOAD_SIZE> rx;

  // Receive UDP datasets using recvfrom and execute them in an endless loop
  for (Server server;;) {
    if (auto const len{recvfrom(sock,
                                std::bit_cast<char*>(data(rx)),
                                sizeof(rx) - 1,
                                0,
                                std::bit_cast<sockaddr*>(&dest_addr_ip4),
                                &socklen)};
        len < 0) {
      printf("recvfrom failed %s\n", strerror(errno));
      std::exit(-1);
    } else if (len > 0) {
      server.receive({sock, std::bit_cast<sockaddr*>(&dest_addr_ip4), socklen},
                     {data(rx), static_cast<size_t>(len)});
      server.execute();
    }

    std::this_thread::sleep_for(10ms);
  }
}
```

#### Transmitting
Analogous to recvfrom, [sendto](https://pubs.opengroup.org/onlinepubs/009604499/functions/sendto.html) can be used to implement the pure virtual method `transmit` of the [System interface](#system).
```cpp
void Server::transmit(z21::Socket const& sock,
                      std::span<uint8_t const> datasets) {
  // Transmit UDP datasets using sendto
  if (auto const len{sendto(sock.fd,
                            std::bit_cast<char*>(data(datasets)),
                            size(datasets),
                            0,
                            std::bit_cast<sockaddr*>(&sock.addr),
                            sock.len)};
      len < 0) {
    fprintf(stderr, "sendto failed %s", strerror(errno));
    std::exit(-1);
  }
}
```

### Interfaces

| Interface                        | Responsibility                                                         |
| -------------------------------- | ---------------------------------------------------------------------- |
| [Can](#can)                      | Send and receive messages from CAN occupancy detectors                 |
| [Driving](#driving)              | Control mobile decoders                                                |
| [FastClock](#fastclock)          | Control fast clock                                                     |
| [LocoNet](#loconet)              | Send and receive messages from LocoNet gateway                         |
| [Programming](#programming)      | Reading and writing decoder CVs in service or POM mode                 |
| [RailCom](#railcom)              | Reading RailCom data of mobile decoders                                |
| [RBus](#rbus)                    | Send and receive messages from R-Bus feedback modules                  |
| [Settings](#settings)            | Change persistently stored settings                                    |
| [Switching](#switching)          | Control stationary decoders                                            |
| [System](#system) (**required**) | System features (e.g. track power, get hardware information, ...)      |
| [ZLink](#zlink)                  | Send and receive messages from zLink devices                           |
|                                  |                                                                        |
| [Logging](#logging)              | Print received and transmitted UDP datasets (not part of Z21 protocol) |

#### Can
:construction:

#### Driving
:construction:

#### FastClock
:construction:

#### LocoNet
:construction:

#### Programming
:construction:

#### RailCom
:construction:

#### RBus
:construction:

#### Settings
:construction:

#### Switching
:construction:

#### System
:construction:

#### ZLink
:construction:

#### Logging
:construction:

## All Commands
| Command                      | Reply                               | Broadcast                    |
| ---------------------------- | ----------------------------------- | ---------------------------- |
| lanGetSerialNumber           | replyToLanGetSerialNumber           |                              |
| lanGetCommonSettings         | replyToLanGetCommonSettings         |                              |
| lanSetCommonSettings         |                                     |                              |
| lanGetMmDccSettings          | lanGetMmDccSettings                 |                              |
| lanSetMmDccSettings          |                                     |                              |
| lanGetCode                   | replyToLanGetCode                   |                              |
| lanGetHwInfo                 | replyToLanGetHwInfo                 |                              |
| lanLogoff                    | -                                   |                              |
| lanXGetVersion               | replyToLanXGetVersion               |                              |
| lanXGetStatus                | lanXStatusChanged                   |                              |
| lanXSetTrackPowerOff         | lanXBcTrackPowerOff                 | lanXBcTrackPowerOff          |
| lanXSetTrackPowerOn          | lanXBcTrackPowerOn                  | lanXBcTrackPowerOn           |
| lanXDccReadRegister          | lanXCv[NackSc\|Nack\|Result] (n.a.) | lanXBcProgrammingMode (n.a.) |
| lanXCvRead                   | lanXCv[NackSc\|Nack\|Result]        | lanXBcProgrammingMode        |
| lanXDccWriteRegister         | lanXCv[NackSc\|Nack\|Result] (n.a.) | lanXBcProgrammingMode (n.a.) |
| lanXCvWrite                  | lanXCv[NackSc\|Nack\|Result]        | lanXBcProgrammingMode        |
| lanXMmWriteByte (n.a.)       | lanXCv[NackSc\|Nack\|Result] (n.a.) | lanXBcProgrammingMode (n.a.) |
| lanXGetTurnoutInfo           |                                     | lanXTurnoutInfo              |
| lanXGetExtAccessoryInfo      |                                     | lanXExtAccessoryInfo         |
| lanXSetTurnout               |                                     | lanXTurnoutInfo              |
| lanXSetExtAccessory          |                                     | lanXExtAccessoryInfo         |
| lanXSetStop                  | lanXBcStopped                       |                              |
| lanXSetLocoEStop             |                                     | lanXLocoInfo                 |
| lanXPurgeLoco                | -                                   |                              |
| lanXGetLocoInfo              | lanXLocoInfo                        |                              |
| lanXSetLocoDrive             | -                                   | lanXLocoInfo                 |
| lanXSetLocoFunction          | -                                   | lanXLocoInfo                 |
| lanXSetLocoFunctionGroup     | -                                   | lanXLocoInfo                 |
| lanXSetLocoBinaryState       | -                                   |                              |
| lanXCvPom                    | lanXCv[NackSc\|Nack\|Result]        |                              |
| lanXCvPomAccessory           | lanXCv[NackSc\|Nack\|Result]        |                              |
| lanXGetFirmwareVersion       | replyToLanXGetFirmwareVersion       |                              |
| lanSetBroadcastFlags         | -                                   |                              |
| lanGetBroadcastFlags         | replyToLanGetBroadcastFlags         |                              |
| lanGetLocoMode               | replyToLanGetLocoMode               |                              |
| lanSetLocoMode               | -                                   |                              |
| lanGetTurnoutMode            | replyToLanGetTurnoutMode            |                              |
| lanSetTurnoutMode            | -                                   |                              |
| lanRmBusGetData              |                                     |                              |
| lanRmBusProgramModule        |                                     |                              |
| lanSystemStateGetData        | lanSystemStateDataChanged           |                              |
| lanRailComGetData            | lanRailComDataChanged               |                              |
| lanLocoNetFromLan            |                                     |                              |
| lanLocoNetDispatchAddr       |                                     |                              |
| lanLocoNetDetector           |                                     |                              |
| lanCanDetector               |                                     |                              |
| lanCanDeviceGetDescription   |                                     |                              |
| lanCanDeviceSetDescription   |                                     |                              |
| lanCanBoosterSetTrackPower   |                                     |                              |
| lanFastClockControl          |                                     |                              |
| lanFastClockSettingsGet      |                                     |                              |
| lanFastClockSettingsSet      |                                     |                              |
| lanBoosterSetPower           |                                     |                              |
| lanBoosterGetDescription     |                                     |                              |
| lanBoosterSetDescription     |                                     |                              |
| lanBoosterSystemStateGetData |                                     |                              |
| lanDecoderGetDescription     |                                     |                              |
| lanDecoderSetDescription     |                                     |                              |
| lanDecoderSystemStateGetData |                                     |                              |
| lanZLinkGetHwInfo            |                                     |                              |

## Broadcasts
| Broadcast                           |
| ----------------------------------- |
| lanXTurnoutInfo                     |
| lanXExtAccessoryInfo                |
| lanXBcTrackPowerOff                 |
| lanXBcTrackPowerOn                  |
| lanXBcProgrammingMode               |
| lanXBcTrackShortCircuit             |
| lanXBcStopped                       |
| lanXLocoInfo                        |
| lanRmbusDataChanged                 |
| lanSystemStateDataChanged           |
| lanRailComDataChanged               |
| lanCanBoosterSystemStateDataChanged |
| lanBoosterSystemStateDataChanged    |
| lanDecoderSystemStateDataChanged    |

Links

Supports all targets

Maintainer

  • Vincent Hamp <hamp@zimo.at>

License: MPL-2.0

To add this component to your project, run:

idf.py add-dependency "zimo-elektronik/z21^0.3.1"

or download archive

Stats

  • Archive size
    Archive size ~ 656.67 KB
  • Downloaded in total
    Downloaded in total 71 times
  • Downloaded this version
    This version: 0 times

Badge

zimo-elektronik/z21 version: 0.3.1
|