In the unlikely event that you're curious about using rust to communicate with a MSP flight controller (for example inav, betaflight, multiwii even), then here's a trivial example of rust asynchronous MSP (using a "channels" pattern).
Note that this is (still) about day 4 of the author's on/off rust adventure, it may be non-idiomatic, naive etc. PRs welcome.
Bench test FC, indoors, somewhat random GPS data.
$ msptest /dev/rfcomm1
Serial port: /dev/rfcomm1
Name: BenchyMcTest
API Version: 2.4
Firmware: INAV
FW Version: 3.1.0
Git revsion: b079efca
Board: WINGFC
Extant waypoints in FC: 16 of 60, valid true
Voltage: 11.9
GPS: fix 2, sats 5, lat, lon, alt 50.9***** -1.5***** -1, spd 0.33 cog 7.7 hdop 6.59
$ msptest --help
Usage: msptest [options] [device-node]
Version: 0.10.0
Options:
-s, --slow slow mode
-1, --once Single iteration, then exit
-v, --version Show version
-h, --help print this help menu
On Linux / Macos / Windows / FreeBSD, if no device is given, the application will make a reasonable attempt to evince any valid serial device; e.g. with msptest
installed on $PATH
:
$ msptest
Serial port: /dev/ttyACM0
Name: BenchyMcTesty
API Version: 2.4
Firmware: INAV
FW Version: 6.0.0
Git revsion: 4bbd2fa5
Board: WINGFC
Extant waypoints in FC: 0 of 120, valid false
Uptime: 550s
Voltage: 0.00
GPS: fix 0, sats 0, lat, lon, alt 0.000000 0.000000 0, spd 0.00 cog 0 hdop 99.99
Elapsed 37.25s 2306 messages, rate 61.90/s
^C
^C to exit.
Note for FreeBSD, only /dev/cuaU* is recognised:
Thusly:
# This would be auto-discovered
# macos
msptest /dev/cu.usbmodem0x80000001
# Windows
# This would be auto-discovered
msptest.exe COM17
You can also use a TCP pseudo-URI (e.g. for use with the SITL):
msptest tcp://localhost:5767
and on unix platforms, UDP:
msptest udp://localhost:53285
As a short cut for cargo
commands / options, there's a Makefile
make build
: Builds a release targetmake install
: Builds a release target, installs to ~/.local/binmake debug
: Builds a debug targetmake windows
: Cross-compiles a Windows executable on sane host OSmake clean
: Clean
$ msptest
Serial port: /dev/ttyUSB0
MSP Vers: 241, (protocol v1)
Voltage: 4.20
GPS: fix 0, sats 0, 0.000000° 0.000000° 0m, spd 0.00 cog 0
Elapsed 21.64s 1298 messages, rate 59.99/s
Note the serial message rate. The changes since 1.7 / 1.8 (increased functionality, changing of task priorities etc.) have not improved serial I/O rates, despite much faster CPUs.
$ msptest /dev/ttyACM1
Serial port: /dev/ttyACM1
MSP Vers: 231, (protocol v2)
Name: BV-CC3D
API Version: 2.1
Firmware: INAV
FW Version: 1.9.254
Git revsion: e4510e11
Board: CC3D
Extant waypoints in FC: 0 of 30, valid false
Voltage: 0.00
GPS: fix 0, sats 0, 0.000000° 0.000000° 0m, spd 0.00 cog 0 hdop 0.00
Elapsed 14.31s 1427 messages, rate 99.69/s
The example has now migrated to a TUI application:
MSP Test Viewer
v0.12.0 on freebsd 13.1-RELEASE x86_64
Port : /dev/cuaU0
MW Vers : ---
Name : BenchyMcTesty
API Vers: 2.4 (MSP v2)
FC : INAV
FC Vers : 6.0.0
Build : Dec 29 2022 12:38:03 (243b867d)
Board : WINGFC
WP Info : 0 of 120, valid false
Uptime : 90563s
Power : 0.0 volts, 0.11 amps
GPS : fix 0, sats 0, 0.000000° 0.000000° 0m, 0m/s 0° hdop 99.99
Arming : NavUnsafe H/WFail RCLink (0x48800)
Rate : 5587388 messages in 90358.35s (61.8/s) (unknown: 1, crc 0)
From 0.12.0, the rate line includes the count of unknown massages and CRC errors. The CRC count should be zero; the unknown count will vary according to version:
Board : MultiWii
Rate : 1934 messages in 30.9s (62.6/s) (unknown: 649, crc 0)
Board : CC3D
FC Vers : 1.9.254
Rate : 4072 messages in 40.8s (99.7/s) (unknown: 1016, crc 0)
Board : MATEKF405
FC Vers : 6.0.0
Rate : 2384 messages in 38.5s (61.9/s) (unknown: 1, crc 0)
- MultiWii: c. 33% unknown
- Ancient INAV: c. 25% unknown
- Modern INAV: 1 unknown
The rust serialport crate is used device enumeration. Prior to version 0.10.0, the serialport crate was also used for I/O; since then a custom implementation is used.
This example uses an (unsafe) C language implementation for serial I/O, rather than the serialport crate (or even the better serial2 crate):
- serialport did not support RISC-V (at one time)
- serialport performance on Windows is poor (c. 25% of Linux / FreeBSD / Macos) and unreliable across multiple threads. The embedded implementation is thread safe and the Windows performance is close to that of the POSIX platforms.
- serial2 requires
Arc()
in order to use a separate reader thread. This rather upsets the current device independent implementation .
There is an similar Golang example; you may judge which is the cleanest / simplest.
MIT, 0BSD or similar.