AP_RCProtocol: reset UART on RX failure for CRSF

update CRSF timestamps to use microseconds
implement RX liveness protocol and implement for CRSF
This commit is contained in:
Andy Piper 2022-01-15 15:26:47 +00:00 committed by Randy Mackay
parent 159b50c41a
commit 7509cc5c3c
4 changed files with 37 additions and 8 deletions

View File

@ -309,6 +309,13 @@ void AP_RCProtocol::check_added_uart(void)
} }
added.opened = false; added.opened = false;
} }
// power loss on CRSF requires re-bootstrap because the baudrate is reset to the default. The CRSF side will
// drop back down to 416k if it has received 200 incorrect characters (or none at all)
} else if (_detected_protocol != AP_RCProtocol::NONE
// protocols that want to be able to renegotiate should return false in is_rx_active()
&& !backend[_detected_protocol]->is_rx_active()
&& now - added.last_config_change_ms > 1000) {
added.opened = false;
} }
} }

View File

@ -85,6 +85,11 @@ public:
bool have_UART(void) const { bool have_UART(void) const {
return frontend.added.uart != nullptr; return frontend.added.uart != nullptr;
} }
// is the receiver active, used to detect power loss and baudrate changes
virtual bool is_rx_active() const {
return true;
}
protected: protected:
struct Channels11Bit_8Chan { struct Channels11Bit_8Chan {

View File

@ -198,8 +198,6 @@ void AP_RCProtocol_CRSF::_process_byte(uint32_t timestamp_us, uint8_t byte)
_frame_ofs = 0; _frame_ofs = 0;
} }
_last_rx_time_us = timestamp_us;
// overflow check // overflow check
if (_frame_ofs >= CRSF_FRAMELEN_MAX) { if (_frame_ofs >= CRSF_FRAMELEN_MAX) {
_frame_ofs = 0; _frame_ofs = 0;
@ -250,9 +248,10 @@ void AP_RCProtocol_CRSF::_process_byte(uint32_t timestamp_us, uint8_t byte)
return; return;
} }
_last_frame_time_us = timestamp_us; _last_frame_time_us = _last_rx_frame_time_us = timestamp_us;
// decode here // decode here
if (decode_crsf_packet()) { if (decode_crsf_packet()) {
_last_tx_frame_time_us = timestamp_us; // we have received a frame from the transmitter
add_input(MAX_CHANNELS, _channels, false, _link_status.rssi, _link_status.link_quality); add_input(MAX_CHANNELS, _channels, false, _link_status.rssi, _link_status.link_quality);
} }
} }
@ -273,14 +272,15 @@ void AP_RCProtocol_CRSF::update(void)
for (uint8_t i = 0; i < n; i++) { for (uint8_t i = 0; i < n; i++) {
int16_t b = _uart->read(); int16_t b = _uart->read();
if (b >= 0) { if (b >= 0) {
_process_byte(now, uint8_t(b)); process_byte(AP_HAL::micros(), uint8_t(b));
} }
} }
} }
// never received RC frames, but have received CRSF frames so make sure we give the telemetry opportunity to run // never received RC frames, but have received CRSF frames so make sure we give the telemetry opportunity to run
uint32_t now = AP_HAL::micros(); uint32_t now = AP_HAL::micros();
if (_last_frame_time_us > 0 && !get_rc_frame_count() && now - _last_frame_time_us > CRSF_INTER_FRAME_TIME_US_250HZ) { if (_last_frame_time_us > 0 && (!get_rc_frame_count() || !is_tx_active())
&& now - _last_frame_time_us > CRSF_INTER_FRAME_TIME_US_250HZ) {
process_telemetry(false); process_telemetry(false);
_last_frame_time_us = now; _last_frame_time_us = now;
} }
@ -471,7 +471,7 @@ bool AP_RCProtocol_CRSF::process_telemetry(bool check_constraint)
if (!telem_available) { if (!telem_available) {
#if HAL_CRSF_TELEM_ENABLED && !APM_BUILD_TYPE(APM_BUILD_iofirmware) #if HAL_CRSF_TELEM_ENABLED && !APM_BUILD_TYPE(APM_BUILD_iofirmware)
if (AP_CRSF_Telem::get_telem_data(&_telemetry_frame)) { if (AP_CRSF_Telem::get_telem_data(&_telemetry_frame, is_tx_active())) {
telem_available = true; telem_available = true;
} else { } else {
return false; return false;

View File

@ -26,7 +26,9 @@
#define CRSF_FRAMELEN_MAX 64U // maximum possible framelength #define CRSF_FRAMELEN_MAX 64U // maximum possible framelength
#define CSRF_HEADER_LEN 2U // header length #define CSRF_HEADER_LEN 2U // header length
#define CRSF_FRAME_PAYLOAD_MAX (CRSF_FRAMELEN_MAX - CSRF_HEADER_LEN) // maximum size of the frame length field in a packet #define CRSF_FRAME_PAYLOAD_MAX (CRSF_FRAMELEN_MAX - CSRF_HEADER_LEN) // maximum size of the frame length field in a packet
#define CRSF_BAUDRATE 416666 #define CRSF_BAUDRATE 416666U
#define CRSF_TX_TIMEOUT 500000U // the period after which the transmitter is considered disconnected (matches copters failsafe)
#define CRSF_RX_TIMEOUT 150000U // the period after which the receiver is considered disconnected (>ping frequency)
class AP_RCProtocol_CRSF : public AP_RCProtocol_Backend { class AP_RCProtocol_CRSF : public AP_RCProtocol_Backend {
public: public:
@ -38,6 +40,20 @@ public:
// support for CRSF v3 // support for CRSF v3
bool change_baud_rate(uint32_t baudrate); bool change_baud_rate(uint32_t baudrate);
bool is_crsf_v3_active() const { return _crsf_v3_active; } bool is_crsf_v3_active() const { return _crsf_v3_active; }
// is the receiver active, used to detect power loss and baudrate changes
bool is_rx_active() const override {
// later versions of CRSFv3 will send link rate frames every 200ms
// but only before an initial failsafe
return AP_HAL::micros() < _last_rx_frame_time_us + CRSF_RX_TIMEOUT;
}
// is the transmitter active, used to adjust telemetry data
bool is_tx_active() const {
// this is the same as the Copter failsafe timeout
return AP_HAL::micros() < _last_tx_frame_time_us + CRSF_TX_TIMEOUT;
}
// get singleton instance // get singleton instance
static AP_RCProtocol_CRSF* get_singleton() { static AP_RCProtocol_CRSF* get_singleton() {
return _singleton; return _singleton;
@ -275,8 +291,9 @@ private:
void add_to_buffer(uint8_t index, uint8_t b) { ((uint8_t*)&_frame)[index] = b; } void add_to_buffer(uint8_t index, uint8_t b) { ((uint8_t*)&_frame)[index] = b; }
uint32_t _last_frame_time_us; uint32_t _last_frame_time_us;
uint32_t _last_tx_frame_time_us;
uint32_t _last_uart_start_time_ms; uint32_t _last_uart_start_time_ms;
uint32_t _last_rx_time_us; uint32_t _last_rx_frame_time_us;
uint32_t _start_frame_time_us; uint32_t _start_frame_time_us;
bool telem_available; bool telem_available;
uint32_t _new_baud_rate; uint32_t _new_baud_rate;