diff --git a/Docs/source/example.rst b/Docs/source/example.rst index ce22a46..78c6fde 100644 --- a/Docs/source/example.rst +++ b/Docs/source/example.rst @@ -3,14 +3,48 @@ Examples ======== -CRSF Basic Example +IBUS Basic Example ------------------ -.. literalinclude:: ../../examples/espresiff/crsf_basic/crsf_basic.ino +Atmel AVR +^^^^^^^^^ + +.. literalinclude:: ../../examples/atmel/ibus_basic/ibus_basic.ino + :language: cpp + +RP2040 +^^^^^^ + +.. literalinclude:: ../../examples/rp2040/ibus_basic/ibus_basic.ino + :language: cpp + + +Crossfire Basic Example +------------------ + +Atmel AVR +^^^^^^^^^ + +.. literalinclude:: ../../examples/atmel/crsf_basic/crsf_basic.ino + :language: cpp + +RP2040 +^^^^^^ + +.. literalinclude:: ../../examples/rp2040/crsf_basic/crsf_basic.ino :language: cpp SBUS Basic Example ------------------ -.. literalinclude:: ../../examples/espresiff/sbus_basic/sbus_basic.ino - :language: cpp \ No newline at end of file +Atmel AVR +^^^^^^^^^ + +.. literalinclude:: ../../examples/atmel/sbus_basic/sbus_basic.ino + :language: cpp + +RP2040 +^^^^^^ + +.. literalinclude:: ../../examples/rp2040/sbus_basic/sbus_basic.ino + :language: cpp diff --git a/Docs/source/tutorial.rst b/Docs/source/tutorial.rst index a6710bd..49542d2 100644 --- a/Docs/source/tutorial.rst +++ b/Docs/source/tutorial.rst @@ -107,8 +107,81 @@ Crossfire mySerial.begin(CRSF_BAUDRATE); SerialIO *receiver = new crsf(mySerial); +Monitoring Communication +======================== +You can monitor the communication status on certain protocols, to ensure reliability of the received channel data. + +SBus +---- + +Serial Communication +^^^^^^^^^^^^^^^^^^^^ +You can monitor the serial communication using the `getSerialConnectionStatus()` method on the `receiver` instance. +This method returns `true` if the serial communication is running without errors, otherwise it returns `false`. + +.. code-block:: cpp + + #include + + rc_channels_t channelData; + sbus receiver(&Serial); + + // within your setup routine + receiver.begin(); + + // within your program loop + receiver.processIncoming(); + receiver.getChannel(&channelData); + + bool serialConnectionStatus = receiver.getSerialConnectionStatus(); + + if(!serialConnectionStatus) { + // handle failsafe of channelData + } + + +Radio connection +^^^^^^^^^^^^^^^^ +You can monitor the radio connection of the receiver using the `getFailsafe()` method on the `receiver` instance. +The failsafe indicates when the receiver has lost connection to the transmitter. +When the failsafe is activated, the channel data might be set to predefined values or hold the last known values. + +You can also monitor the quality of the connection with `getFramelost()` method on the `receiver` instance. +Usually lost frame indicates when a frame is lost between the transmitter an receiver. +Failsafe activation requires that many frames ahs been lost in a row. + +.. note:: + Some receivers might not provide any failsafe or frame loss information via SBus protocol. + In that case, the methods will always return `false`. + +.. code-block:: cpp + + #include + + rc_channels_t channelData; + sbus receiver(&Serial); + + // within your setup routine + receiver.begin(); + + // within your program loop + receiver.processIncoming(); + receiver.getChannel(&channelData); + + bool failsafe = receiver.getFailsafe(); + bool frameLost = receiver.getFramelost(); + + if(failsafe) { + // handle failsafe of channelData + } + + if(frameLost) { + // handle frame lost event + } + + See Also -^^^^^^^^ +======== - :cpp:class:`SerialIO` - :cpp:class:`sbus` - :cpp:class:`crsf` diff --git a/examples/atmel/crsf_basic/.arduino-ci.yml b/examples/atmel/crsf_basic/.arduino-ci.yml new file mode 100644 index 0000000..028c474 --- /dev/null +++ b/examples/atmel/crsf_basic/.arduino-ci.yml @@ -0,0 +1,5 @@ +compile: + platforms: + - uno + - mega2560 + - leonardo \ No newline at end of file diff --git a/examples/atmel/crsf_basic/crsf_basic.ino b/examples/atmel/crsf_basic/crsf_basic.ino new file mode 100644 index 0000000..2eebc5d --- /dev/null +++ b/examples/atmel/crsf_basic/crsf_basic.ino @@ -0,0 +1,22 @@ +/*! + * @file crsf_basic.ino + */ +#include + +rc_channels_t channelData; + +crsf receiver(&Serial); + +void setup() { + receiver.begin(); +} + +void loop() { + // setup crsf receiver + receiver.processIncoming(); + receiver.getChannel(&channelData); + + // `channelData` now contains the latest RC channel values + // You can use them by accessing the channelData e.g. channelData.channel1 to channelData.channel16 +} + diff --git a/examples/atmel/ibus_basic/ibus_basic.ino b/examples/atmel/ibus_basic/ibus_basic.ino index 8d8f2f0..f4fdea0 100644 --- a/examples/atmel/ibus_basic/ibus_basic.ino +++ b/examples/atmel/ibus_basic/ibus_basic.ino @@ -14,5 +14,8 @@ void setup() { void loop() { receiver.processIncoming(); receiver.getChannel(&channelData); + + // `channelData` now contains the latest RC channel values + // You can use them by accessing the channelData e.g. channelData.channel1 to channelData.channel16 } diff --git a/examples/atmel/sbus_basic/.arduino-ci.yml b/examples/atmel/sbus_basic/.arduino-ci.yml new file mode 100644 index 0000000..028c474 --- /dev/null +++ b/examples/atmel/sbus_basic/.arduino-ci.yml @@ -0,0 +1,5 @@ +compile: + platforms: + - uno + - mega2560 + - leonardo \ No newline at end of file diff --git a/examples/atmel/sbus_basic/sbus_basic.ino b/examples/atmel/sbus_basic/sbus_basic.ino new file mode 100644 index 0000000..2bdedb0 --- /dev/null +++ b/examples/atmel/sbus_basic/sbus_basic.ino @@ -0,0 +1,22 @@ +/*! + * @file sbus_basic.ino + */ +#include + +rc_channels_t channelData; + +sbus receiver(&Serial); + +void setup() { + receiver.begin(); +} + +void loop() { + // setup sbus receiver + receiver.processIncoming(); + receiver.getChannel(&channelData); + + // `channelData` now contains the latest RC channel values + // You can use them by accessing the channelData e.g. channelData.channel1 to channelData.channel16 +} + diff --git a/examples/rp2040/crsf_basic/.arduino-ci.yml b/examples/rp2040/crsf_basic/.arduino-ci.yml new file mode 100644 index 0000000..f08632d --- /dev/null +++ b/examples/rp2040/crsf_basic/.arduino-ci.yml @@ -0,0 +1,18 @@ +platforms: + rpipico: + board: rp2040:rp2040:rpipico + package: rp2040:rp2040 + gcc: + features: + defines: + - ARDUINO_ARCH_RP2040 + warnings: + flags: + +packages: + rp2040:rp2040: + url: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json + +compile: + platforms: + - rpipico diff --git a/examples/rp2040/crsf_basic/crsf_basic.ino b/examples/rp2040/crsf_basic/crsf_basic.ino new file mode 100644 index 0000000..9478dd0 --- /dev/null +++ b/examples/rp2040/crsf_basic/crsf_basic.ino @@ -0,0 +1,55 @@ +/*! + * @file crsf_basic.ino + */ +/* + +# Sample platformio.ini file: +# --------------------------- +[platformio] +default_envs = ws-rp2040-zero + +[env:ws-rp2040-zero] +platform = https://github.com/maxgerhardt/platform-raspberrypi.git +board = waveshare_rp2040_pizero +framework = arduino +board_build.core = earlephilhower +monitor_speed = 115200 + +lib_deps = + https://github.com/Witty-Wizard/SerialIO +*/ + +#include + +#define CRSF_TX_PIN 0 +#define CRSF_RX_PIN 1 + +rc_channels_t rcdata; +// On RP2040 or Arduino ESP32 you need to specify the TX and RX pins +crsf receiver(&Serial1, CRSF_RX_PIN, CRSF_TX_PIN, + true); // RP2040 requires the TX_PIN so to not hang up the mcu + +void setup() { + // setup crsf receiver + receiver.begin(); + + Serial.begin(115200); +} + +void loop() { + static unsigned long last_millis = millis(); + + receiver.processIncoming(); + receiver.getChannel(&rcdata); + + if (millis() > last_millis + 100) { + Serial.printf("RC: %4d %4d %4d %4d %4d %4d %4d %4d %4d %4d %4d %4d %4d %4d", + rcdata.channel1, rcdata.channel2, rcdata.channel3, + rcdata.channel4, rcdata.channel5, rcdata.channel6, + rcdata.channel7, rcdata.channel8, rcdata.channel9, + rcdata.channel10, rcdata.channel11, rcdata.channel12, + rcdata.channel13, rcdata.channel14); + Serial.println(); + last_millis = millis(); + } +} diff --git a/examples/rp2040/ibus_basic/ibus_basic.ino b/examples/rp2040/ibus_basic/ibus_basic.ino index 931e9b4..515f094 100644 --- a/examples/rp2040/ibus_basic/ibus_basic.ino +++ b/examples/rp2040/ibus_basic/ibus_basic.ino @@ -21,15 +21,16 @@ lib_deps = #include -#define SBUS_TX_PIN 0 -#define SBUS_RX_PIN 1 +#define IBUS_TX_PIN 0 +#define IBUS_RX_PIN 1 rc_channels_t rcdata; -ibus receiver(&Serial1, SBUS_RX_PIN, SBUS_TX_PIN, +// On RP2040 or Arduino ESP32 you need to specify the TX and RX pins +ibus receiver(&Serial1, IBUS_RX_PIN, IBUS_TX_PIN, true); // RP2040 requires the TX_PIN so to not hang up the mcu void setup() { - // setup sbus receiver + // setup ibus receiver receiver.begin(); Serial.begin(115200); diff --git a/examples/rp2040/sbus_basic/.arduino-ci.yml b/examples/rp2040/sbus_basic/.arduino-ci.yml new file mode 100644 index 0000000..f08632d --- /dev/null +++ b/examples/rp2040/sbus_basic/.arduino-ci.yml @@ -0,0 +1,18 @@ +platforms: + rpipico: + board: rp2040:rp2040:rpipico + package: rp2040:rp2040 + gcc: + features: + defines: + - ARDUINO_ARCH_RP2040 + warnings: + flags: + +packages: + rp2040:rp2040: + url: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json + +compile: + platforms: + - rpipico diff --git a/examples/rp2040/sbus_basic/sbus_basic.ino b/examples/rp2040/sbus_basic/sbus_basic.ino new file mode 100644 index 0000000..55a27dc --- /dev/null +++ b/examples/rp2040/sbus_basic/sbus_basic.ino @@ -0,0 +1,55 @@ +/*! + * @file sbus_basic.ino + */ +/* + +# Sample platformio.ini file: +# --------------------------- +[platformio] +default_envs = ws-rp2040-zero + +[env:ws-rp2040-zero] +platform = https://github.com/maxgerhardt/platform-raspberrypi.git +board = waveshare_rp2040_pizero +framework = arduino +board_build.core = earlephilhower +monitor_speed = 115200 + +lib_deps = + https://github.com/Witty-Wizard/SerialIO +*/ + +#include + +#define SBUS_TX_PIN 0 +#define SBUS_RX_PIN 1 + +rc_channels_t rcdata; +// On RP2040 or Arduino ESP32 you need to specify the TX and RX pins +sbus receiver(&Serial1, SBUS_RX_PIN, SBUS_TX_PIN, + true); // RP2040 requires the TX_PIN so to not hang up the mcu + +void setup() { + // setup sbus receiver + receiver.begin(); + + Serial.begin(115200); +} + +void loop() { + static unsigned long last_millis = millis(); + + receiver.processIncoming(); + receiver.getChannel(&rcdata); + + if (millis() > last_millis + 100) { + Serial.printf("RC: %4d %4d %4d %4d %4d %4d %4d %4d %4d %4d %4d %4d %4d %4d", + rcdata.channel1, rcdata.channel2, rcdata.channel3, + rcdata.channel4, rcdata.channel5, rcdata.channel6, + rcdata.channel7, rcdata.channel8, rcdata.channel9, + rcdata.channel10, rcdata.channel11, rcdata.channel12, + rcdata.channel13, rcdata.channel14); + Serial.println(); + last_millis = millis(); + } +} diff --git a/src/SerialIO.h b/src/SerialIO.h index 7bbb34d..02cc7fd 100644 --- a/src/SerialIO.h +++ b/src/SerialIO.h @@ -89,6 +89,8 @@ class SerialIO bool _inverted; ///< Indicates whether the serial signal is inverted. int _rxPin; ///< RX pin number. int _txPin; ///< TX pin number. + uint32_t _lastPacketTime = 0; ///< Timestamp of the last received packet. + bool _connectionTimeout = false; ///< Indicates whether the connection has timed out. /** * @brief Perform a left shift operation on the given byte array. diff --git a/src/sbus/sbus.cpp b/src/sbus/sbus.cpp index 4b874c1..ce8d933 100644 --- a/src/sbus/sbus.cpp +++ b/src/sbus/sbus.cpp @@ -33,9 +33,36 @@ void sbus::processIncoming() { memcpy(&_channelData, _rxData, sizeof(_channelData)); } leftShift(_rxData, sizeof(_rxData)); + + _lastPacketTime = millis(); + _connectionTimeout = false; + } + + if (millis() - _lastPacketTime > SBUS_TIMEOUT) { + _connectionTimeout = true; } } void sbus::getChannel(rc_channels_t *channelData) { memcpy(channelData, (uint8_t *)&_channelData + 1, sizeof(rc_channels_t)); +} + +bool sbus::getFailsafe() { + return _channelData.failsafe; +} + +bool sbus::getFramelost() { + return _channelData.framelost; +} + +bool sbus::getChannel17() { + return _channelData.channel17; +} + +bool sbus::getChannel18() { + return _channelData.channel18; +} + +bool sbus::getSerialConnectionStatus() { + return !_connectionTimeout; } \ No newline at end of file diff --git a/src/sbus/sbus.h b/src/sbus/sbus.h index a29abf0..8253e7d 100644 --- a/src/sbus/sbus.h +++ b/src/sbus/sbus.h @@ -42,6 +42,36 @@ class sbus : public SerialIO { * channel data will be stored. */ void getChannel(rc_channels_t *channelData) override; + + /** + * @brief Gets the failsafe status from the SBUS data. + * @return True if failsafe is active, false otherwise. + */ + bool getFailsafe(); + + /** + * @brief Gets the frame lost status from the SBUS data. + * @return True if frame lost is active, false otherwise. + */ + bool getFramelost(); + + /** + * @brief Gets the channel 17 status from the SBUS data. + * @return True if channel 17 is active, false otherwise. + */ + bool getChannel17(); + + /** + * @brief Gets the channel 18 status from the SBUS data. + * @return True if channel 18 is active, false otherwise. + */ + bool getChannel18(); + + /** + * @brief Gets the serial connection status. + * @return True if the connection is active, false if it has timed out. + */ + bool getSerialConnectionStatus(); }; #endif \ No newline at end of file diff --git a/src/sbus/sbus_protocol.h b/src/sbus/sbus_protocol.h index 7ce573c..1431d81 100644 --- a/src/sbus/sbus_protocol.h +++ b/src/sbus/sbus_protocol.h @@ -18,6 +18,7 @@ extern "C" { #define FOOTER_SBUS 0x00 ///< SBus Footer Byte #define SBUS_BAUDRATE 100000 ///< SBus baudrate #define SBUS_MAX_PACKET_SIZE 25 ///< SBus packet length +#define SBUS_TIMEOUT 200 ///< SBus timeout in milliseconds typedef struct sbus_channels_s { unsigned header : 8;