This is a client-server command line interface for the SWTbahn. The server is connected to the BiDiB interface and provides a REST API. The client side provides a command line interface which connects to the web service to execute the commands. The command line interface was developed by Nicolas Gross as part of his work for the libbidib project.
- C compiler
- Libraries: onion, libpam, libgnutls, libgcrypt, libpthread, libglib-2.0, libyaml, libbidib
- ForeC command line compiler: forecc
- KIELER command line compiler: kico.jar
- Path to the folder that contains
kico.jar
has to be defined in the environment variableKIELER_PATH
- Path to the folder that contains
- BahnDSL command line compiler: bahnc
- Path to the folder that contains the
bahnc
has to be defined in the environment variableBAHNDSL_PATH
- Path to the folder that contains the
- SCCharts verifier: SWTbahn Verifier (SWT internal repository)
- python3
- Python libraries: click, requests, pyaml (
pip3 install click requests pyaml
)
- Web browser
- Clone the repository
- Install the necessary dependencies (remember to run
ldconfig
aftermake install
for libbidib if you are on Linux) - Navigate to the directory where the build files should be generated
- Execute
cmake <path-to-project-root>/server
- Execute
make
To run the unit tests, execute make test
from within the build directory. Each unit test can be executed to display more detailed test results, e.g., ./server_bahn_util_tests
.
- Build the executable (see section Build)
- Create the configuration files for your track (see libbidib documentation)
- Connect the BiDiB interface to the server
- Check on which serial device the board is connected:
dmesg | grep tty
- Start the server:
./swtbahn-server <serial-device> <config-directory> <IP> <port>
(IP is the IP-address under which the server can be reached and port specifies on which port the server listens)
For example:./swtbahn-server /dev/ttyUSB0 ../../configurations/swtbahn-lite/ 141.13.106.27 2048
- Quit the server with Ctrl-C if you're done
-
The client is located under
<project-root>/client/swtbahn
-
Use the
--help
flag to get information about parameters, options, ... -
Use the config command to setup the client:
swtbahn config <hostname> <port> <default-track-output>
, where hostname is the IP and port the port which you used when you started the server. The is the name of the track output which should be used if no track output is explicitly specified when issuing a command.
For example:./swtbahn config 141.13.106.27 2048 master
This will create a config file in the current working directory. Dont use the client from a different working directory for the current session, otherwise it won't find the configuration file. If you really want to use two logically different clients on the same device, you could just run the clients from different working directories which will lead to distinct configs. -
Now you can use the commands from the categories
swtbahn admin
,swtbahn controller
,swtbahn driver
andswtbahn monitor
. If the system was not started byswtbahn admin startup
, all the other commands won't work.For example:
./swtbahn admin startup
./swtbahn monitor get_segments
./swtbahn monitor get_trains
./swtbahn driver grab cargo
./swtbahn driver set_dcc_speed -b 5
-
If you're done, you should shut the system down gracefully by invoking
swtbahn admin shutdown
- Use a web browser to navigate to
<IP>:<port>/assets/client.html
- Set the main track output (default is
master
). - Click the
Startup
button. - To be a train driver, select a train and click the
Grab
button. Enter a speed between0
(stop) and127
(max speed), and click theDrive
button. - To control a point, type the name of a point (see the YAML configuration file),
select a position, and click the
Set
button. - To control a signal, type the name of a signal (see the YAML configuration file),
select an aspect, and click the
Set
button.
Use ssh
to the log in remotely. Suppose the Raspberry Pi is located at 141.13.106.30
.
Then use the command ssh [email protected]
.
There are two Raspberry Pis with the hostnames raspberrypi1
and raspberrypi2
.
The Raspberry Pi documentation
lists several strategies for finding the IP address of a Raspberry Pi.
If you change the Raspberry Pi's hostname, e.g., by editing /etc/hostname
or by using
the Raspberry Pi Configuration application, Avahi will automatically change the .local mDNS address.
The MAC address of all Raspberry Pis begin with b8:27:eb
.
-
macOS: Try and resolve the Raspberry Pi's hostname, e.g., raspberrypi1.local, with multicast DNS:
ping raspberrypi1.local
If this fails, try the strategy for Linux.
-
Linux: Use
ifconfig
to find your subnet, e.g.,192.168.1._
. Use thenmap
command to scan your subnet for connected devices, and look for the Raspberry Pi's hostname in the results:nmap -sn 192.168.1.0/24
-
Windows: Use
ipconfig
to find your subnet, e.g.,192.168.1._
. Install nmap and open the command line as an administrator for nmap to display the hostnames in its results. Use thenmap
command to scan your subnet for connected devices, and look for the Raspberry Pi's hostname in the results:nmap -sn 192.168.1.0/24
Use the command
nmap -sn 192.168.1.0/24 | findstr /i "b8:27:eb"
to quickly see a list of Raspberry Pis (MAC addresses only).
Use scp
on your client computer. For example, suppose the Raspberry Pi is located at
141.13.106.30
and has the user pi
. To copy the the file /var/log/syslog
from the
Raspberry Pi via the user pi
, use the command scp [email protected]:/var/log/syslog syslog
Train engines (and ther plugins) defined as SCCharts (*.sctx) files can be verified against certain
properties before they are uploaded to the sever. Verification is on by default and
can be configured to true
(On) or false
(Off) via the /admin/set-verification-option
endpoint.
For the command line client, use the command swtbahn admin set-verification-option <true/false>
.
When verification has been turned on and an SCCharts file is uploaded, the server sends a request to SWTbahn Verifier (SWT internal repository), which...
- checks that the SCCharts file defines a set of safety properties (invariants, LTLs),
- compiles the SCCharts file to a format that can be verified (e.g., using nuSmv),
- verifies the safety properties, and
- sends verification results back to the server.
If all safety properties hold, the server processes the SCCharts file, e.g., by compiling and loading the file as a plugin. Otherwise, if any safety property does not hold, the server does not process the SCCharts file any further and reports the failure to the client.
The sever communicates with SWTbahn Verifier via websockets with JSON messages. A typical verification session is as follows:
- swtbahn-cli server receives an upload request for an SCCharts file;
- swtbahn-cli server establishes a websocket connection with SWTbahn Verifier;
- swtbahn-cli server sends the SCCharts file as a JSON message to SWTbahn Verifier;
- SWTbahn Verifier responds by either
- acknowledging the request to verify the SCCharts file and proceeding with the verification, or
- rejecting the request;
- swtbahn-cli responds by either
- waiting for the verification results on the websocket connection, or
- stopping the processing of the SCCharts file;
- for the case that SWTbahn Verifier proceeded with the verification, after the verification has finished, SWTbahn Verifier sends the results as a JSON message to the swtbahn-cli server; and
- swtbahn-cli receives the results, closes the websocket connection, and processes the results.
Grab-ids are used as tokens for trains. A client needs to grab a train before he
can invoke commands for controlling the train. A train could only be grabbed by
one client at a time.
Session-ids are used to check wether a grab-id was given out to the client on
the current session or on a previous session.
When is a new session-id created?
- If a user issues
swtbahn admin startup
and the system is not running already
When is the session-id invalidated?
- If a user issues
swtbahn admin shutdown
When is a grab-id created?
- If a client issues
swtbahn driver grab <train>
and the train is available
When is a grab-id invalidated?
- If a client issues
swtbahn driver release
and the train was grabbed by this client
When is the session-id fetched?
- If the user issues
swtbahn driver grab <train>
and the train is available and the client has not already grabbed a train
When is the session-id reset?
- If the user issues
swtbahn driver release
- If the user issues any
swtbahn driver
command and the session-id or grab-id is not the same as the one at the server - If the user issues
swtbahn admin shutdown
and the system was running - If the user issues
swtbahn config
When is a grab-id fetched?
- If the user issues
swtbahn driver grab <train>
and the train is available and the client has not already grabbed a train
When is a grab-id reset?
- If the user issues
swtbahn driver release
- If the user issues any
swtbahn driver
command and the session-id or grab-id is not the same as the one at the server - If the user issues
swtbahn admin shutdown
and the system was running - If the user issues
swtbahn config
We try to use a consistent logging format in all request handlers. General workflow of how request handlers generate log messages:
- Parse form data.
- Validate form data. If validation fails, make a log on
ERROR
level and stop processing. - Make a log on log level
NOTICE
that represents the start of processing, with- start
at the end of the log. - Process request. If processing causes an error, make a log on the
ERROR
orWARNING
log level with- abort
at the end of the log and stop processing. - Processing concluded. Indicate this by printing the log message of Step 3 again, on the same log level, with
- finish
instead of- start
at the end.
For request handlers that barely do any "processing" at all; e.g. where only a status variable is updated, they only generate one log message that ends with - done
.
Request handlers that only return information (getters) also use the - done
pattern instead of start
and finish
, and use the log level INFO
for the - done
log.
As an example, when a request is made to set point10 to the normal state, the request handler (handler_set_point
) generates the following log messages when the processing is successful:
LOG_NOTICE:
Request: Set point - point: point10 state: normal - start
Intervening log messages from internal processing
LOG_NOTICE:Request: Set point - point: point10 state: normal - finish
If the above request was instead made with an unsupported state, e.g., foobar
, then the request handler would generate the following log messages to say that the processing was stopped because of invalid parameters:
LOG_NOTICE:
Request: Set point - point: point10 state: foobar - start
Intervening log messages from internal processing
LOG_ERR:Request: Set point - point: point10 state: foobar - invalid parameters - abort
If the above request forgot to specify the state, i.e., the state parameter is null
, then the request handler would only generate the following log message to say that the parameter validation failed:
LOG_ERR:
Request: Set point - invalid parameters