LCOV - code coverage report
Current view: top level - AP_RCProtocol - AP_RCProtocol.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 138 298 46.3 %
Date: 2026-09-09 11:02:08 Functions: 17 25 68.0 %

          Line data    Source code
       1             : /*
       2             :  * This file is free software: you can redistribute it and/or modify it
       3             :  * under the terms of the GNU General Public License as published by the
       4             :  * Free Software Foundation, either version 3 of the License, or
       5             :  * (at your option) any later version.
       6             :  *
       7             :  * This file is distributed in the hope that it will be useful, but
       8             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
       9             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
      10             :  * See the GNU General Public License for more details.
      11             :  *
      12             :  * You should have received a copy of the GNU General Public License along
      13             :  * with this program.  If not, see <http://www.gnu.org/licenses/>.
      14             :  *
      15             :  * Code by Andrew Tridgell and Siddharth Bharat Purohit
      16             :  */
      17             : 
      18             : #include "AP_RCProtocol_config.h"
      19             : 
      20             : #include "AP_RCProtocol.h"
      21             : 
      22             : #if AP_RCPROTOCOL_ENABLED
      23             : 
      24             : #include "AP_RCProtocol_PPMSum.h"
      25             : #include "AP_RCProtocol_DSM.h"
      26             : #include "AP_RCProtocol_Emlid_RCIO.h"
      27             : #include "AP_RCProtocol_IBUS.h"
      28             : #include "AP_RCProtocol_IOMCU.h"
      29             : #include "AP_RCProtocol_SBUS.h"
      30             : #include "AP_RCProtocol_SUMD.h"
      31             : #include "AP_RCProtocol_SRXL.h"
      32             : #include "AP_RCProtocol_SRXL2.h"
      33             : #include "AP_RCProtocol_CRSF.h"
      34             : #include "AP_RCProtocol_ST24.h"
      35             : #include "AP_RCProtocol_FPort.h"
      36             : #include "AP_RCProtocol_FPort2.h"
      37             : #include "AP_RCProtocol_DroneCAN.h"
      38             : #include "AP_RCProtocol_GHST.h"
      39             : #include "AP_RCProtocol_MAVLinkRadio.h"
      40             : #include "AP_RCProtocol_Joystick_SFML.h"
      41             : #include "AP_RCProtocol_UDP.h"
      42             : #include "AP_RCProtocol_FDM.h"
      43             : #include "AP_RCProtocol_Radio.h"
      44             : #include <AP_Math/AP_Math.h>
      45             : #include <RC_Channel/RC_Channel.h>
      46             : 
      47             : #include <AP_Vehicle/AP_Vehicle_Type.h>
      48             : 
      49             : #include <GCS_MAVLink/GCS.h>
      50             : 
      51             : extern const AP_HAL::HAL& hal;
      52             : 
      53        2094 : void AP_RCProtocol::init()
      54             : {
      55             : #if AP_RCPROTOCOL_PPMSUM_ENABLED
      56        2094 :     backend[AP_RCProtocol::PPMSUM] = NEW_NOTHROW AP_RCProtocol_PPMSum(*this);
      57             : #endif
      58             : #if AP_RCPROTOCOL_IBUS_ENABLED
      59        2094 :     backend[AP_RCProtocol::IBUS] = NEW_NOTHROW AP_RCProtocol_IBUS(*this);
      60             : #endif
      61             : #if AP_RCPROTOCOL_SBUS_ENABLED
      62        2094 :     backend[AP_RCProtocol::SBUS] = NEW_NOTHROW AP_RCProtocol_SBUS(*this, true, 100000);
      63             : #endif
      64             : #if AP_RCPROTOCOL_FASTSBUS_ENABLED
      65        2094 :     backend[AP_RCProtocol::FASTSBUS] = NEW_NOTHROW AP_RCProtocol_SBUS(*this, true, 200000);
      66             : #endif
      67             : #if AP_RCPROTOCOL_DSM_ENABLED
      68        2094 :     backend[AP_RCProtocol::DSM] = NEW_NOTHROW AP_RCProtocol_DSM(*this);
      69             : #endif
      70             : #if AP_RCPROTOCOL_SUMD_ENABLED
      71        2094 :     backend[AP_RCProtocol::SUMD] = NEW_NOTHROW AP_RCProtocol_SUMD(*this);
      72             : #endif
      73             : #if AP_RCPROTOCOL_SRXL_ENABLED
      74        2094 :     backend[AP_RCProtocol::SRXL] = NEW_NOTHROW AP_RCProtocol_SRXL(*this);
      75             : #endif
      76             : #if AP_RCPROTOCOL_SBUS_NI_ENABLED
      77        2094 :     backend[AP_RCProtocol::SBUS_NI] = NEW_NOTHROW AP_RCProtocol_SBUS(*this, false, 100000);
      78             : #endif
      79             : #if AP_RCPROTOCOL_SRXL2_ENABLED
      80        2094 :     backend[AP_RCProtocol::SRXL2] = NEW_NOTHROW AP_RCProtocol_SRXL2(*this);
      81             : #endif
      82             : #if AP_RCPROTOCOL_CRSF_ENABLED
      83        2094 :     backend[AP_RCProtocol::CRSF] = NEW_NOTHROW AP_RCProtocol_CRSF(*this);
      84             : #endif
      85             : #if AP_RCPROTOCOL_FPORT2_ENABLED
      86        2094 :     backend[AP_RCProtocol::FPORT2] = NEW_NOTHROW AP_RCProtocol_FPort2(*this, true);
      87             : #endif
      88             : #if AP_RCPROTOCOL_ST24_ENABLED
      89        2094 :     backend[AP_RCProtocol::ST24] = NEW_NOTHROW AP_RCProtocol_ST24(*this);
      90             : #endif
      91             : #if AP_RCPROTOCOL_FPORT_ENABLED
      92        2094 :     backend[AP_RCProtocol::FPORT] = NEW_NOTHROW AP_RCProtocol_FPort(*this, true);
      93             : #endif
      94             : #if AP_RCPROTOCOL_DRONECAN_ENABLED
      95        2094 :     backend[AP_RCProtocol::DRONECAN] = NEW_NOTHROW AP_RCProtocol_DroneCAN(*this);
      96             : #endif
      97             : #if AP_RCPROTOCOL_GHST_ENABLED
      98        2094 :     backend[AP_RCProtocol::GHST] = NEW_NOTHROW AP_RCProtocol_GHST(*this);
      99             : #endif
     100             : #if AP_RCPROTOCOL_MAVLINK_RADIO_ENABLED
     101        2094 :     backend[AP_RCProtocol::MAVLINK_RADIO] = NEW_NOTHROW AP_RCProtocol_MAVLinkRadio(*this);
     102             : #endif
     103             : #if AP_RCPROTOCOL_JOYSTICK_SFML_ENABLED
     104             :     backend[AP_RCProtocol::JOYSTICK_SFML] = NEW_NOTHROW AP_RCProtocol_Joystick_SFML(*this);
     105             : #endif
     106             : #if AP_RCPROTOCOL_UDP_ENABLED
     107        2094 :     const auto UDP_backend = NEW_NOTHROW AP_RCProtocol_UDP(*this);
     108        2094 :     backend[AP_RCProtocol::UDP] = UDP_backend;
     109             : #endif
     110             : #if AP_RCPROTOCOL_FDM_ENABLED
     111        2094 :     const auto FDM_backend = NEW_NOTHROW AP_RCProtocol_FDM(*this);;
     112        2094 :     backend[AP_RCProtocol::FDM] = FDM_backend;
     113             : #if AP_RCPROTOCOL_UDP_ENABLED
     114             :     // the UDP-Packed16Bit backend gives way to the FDM backend:
     115        2094 :     UDP_backend->set_fdm_backend(FDM_backend);
     116             : #endif  // AP_RCPROTOCOL_UDP_ENABLED
     117             : #endif  // AP_RCPROTOCOL_FDM_ENABLED
     118             : #if AP_RCPROTOCOL_RADIO_ENABLED
     119             :     backend[AP_RCProtocol::RADIO] = NEW_NOTHROW AP_RCProtocol_Radio(*this);
     120             : #endif
     121             : #if AP_RCPROTOCOL_IOMCU_ENABLED
     122             :     backend[AP_RCProtocol::IOMCU] = NEW_NOTHROW AP_RCProtocol_IOMCU(*this);
     123             : #endif  // AP_RCPROTOCOL_IOMCU_ENABLED
     124             : #if AP_RCPROTOCOL_EMLID_RCIO_ENABLED
     125             :     backend[AP_RCProtocol::EMLID_RCIO] = NEW_NOTHROW AP_RCProtocol_Emlid_RCIO(*this);
     126             : #endif
     127        2094 : }
     128             : 
     129         454 : AP_RCProtocol::~AP_RCProtocol()
     130             : {
     131        9080 :     for (uint8_t i = 0; i < ARRAY_SIZE(backend); i++) {
     132        8626 :         if (backend[i] != nullptr) {
     133        8172 :             delete backend[i];
     134        8172 :             backend[i] = nullptr;
     135             :         }
     136             :     }
     137         454 : }
     138             : 
     139   101171948 : bool AP_RCProtocol::should_search(uint32_t now_ms) const
     140             : {
     141             : #if AP_RCPROTOCOL_FDM_ENABLED && AP_RCPROTOCOL_UDP_ENABLED
     142             :     // force re-detection when FDM is active and active backend is UDP values
     143   201953951 :     if (_detected_protocol == AP_RCProtocol::UDP &&
     144   100782003 :         ((AP_RCProtocol_FDM*)backend[AP_RCProtocol::FDM])->active()) {
     145           0 :         return true;
     146             :     }
     147             : #endif  // AP_RCPROTOCOL_FDM_ENABLED && AP_RCPROTOCOL_UDP_ENABLED
     148             : #if AP_RC_CHANNEL_ENABLED && !APM_BUILD_TYPE(APM_BUILD_UNKNOWN)
     149   101171948 :     if (_detected_protocol != AP_RCProtocol::NONE && !rc().option_is_enabled(RC_Channels::Option::MULTI_RECEIVER_SUPPORT)) {
     150   100782003 :         return false;
     151             :     }
     152             : #else
     153             :     // on IOMCU don't allow protocol to change once detected
     154           0 :     if (_detected_protocol != AP_RCProtocol::NONE) {
     155           0 :         return false;
     156             :     }
     157             : #endif
     158      389945 :     return (now_ms - _last_input_ms >= 200);
     159             : }
     160             : 
     161           0 : void AP_RCProtocol::process_pulse(uint32_t width_s0, uint32_t width_s1)
     162             : {
     163           0 :     uint32_t now = AP_HAL::millis();
     164           0 :     bool searching = should_search(now);
     165             : 
     166             : #if AP_RC_CHANNEL_ENABLED
     167           0 :     rc_protocols_mask = rc().enabled_protocols();
     168             : #endif
     169             : 
     170           0 :     if (_detected_protocol != AP_RCProtocol::NONE &&
     171           0 :         !protocol_enabled(_detected_protocol)) {
     172           0 :         _detected_protocol = AP_RCProtocol::NONE;
     173             :     }
     174             :     
     175           0 :     if (_detected_protocol != AP_RCProtocol::NONE && _detected_with_bytes && !searching) {
     176             :         // we're using byte inputs, discard pulses
     177           0 :         return;
     178             :     }
     179             :     // first try current protocol
     180           0 :     if (_detected_protocol != AP_RCProtocol::NONE && !searching) {
     181           0 :         backend[_detected_protocol]->process_pulse(width_s0, width_s1);
     182           0 :         if (backend[_detected_protocol]->new_input()) {
     183           0 :             _new_input = true;
     184           0 :             _last_input_ms = now;
     185             :         }
     186           0 :         return;
     187             :     }
     188             : 
     189             :     // otherwise scan all protocols
     190           0 :     for (uint8_t i = 0; i < ARRAY_SIZE(backend); i++) {
     191           0 :         if (_disabled_for_pulses & (1U << i)) {
     192             :             // this protocol is disabled for pulse input
     193           0 :             continue;
     194             :         }
     195           0 :         if (backend[i] != nullptr) {
     196           0 :             if (!protocol_enabled(rcprotocol_t(i))) {
     197           0 :                 continue;
     198             :             }
     199           0 :             const uint32_t frame_count = backend[i]->get_rc_frame_count();
     200           0 :             const uint32_t input_count = backend[i]->get_rc_input_count();
     201           0 :             backend[i]->process_pulse(width_s0, width_s1);
     202           0 :             const uint32_t frame_count2 = backend[i]->get_rc_frame_count();
     203           0 :             if (frame_count2 > frame_count) {
     204           0 :                 if (requires_3_frames((rcprotocol_t)i) && frame_count2 < 3) {
     205           0 :                     continue;
     206             :                 }
     207           0 :                 _new_input = (input_count != backend[i]->get_rc_input_count());
     208           0 :                 _detected_protocol = (enum AP_RCProtocol::rcprotocol_t)i;
     209           0 :                 for (uint8_t j = 0; j < ARRAY_SIZE(backend); j++) {
     210           0 :                     if (backend[j]) {
     211           0 :                         backend[j]->reset_rc_frame_count();
     212             :                     }
     213             :                 }
     214           0 :                 _last_input_ms = now;
     215           0 :                 _detected_with_bytes = false;
     216           0 :                 break;
     217             :             }
     218             :         }
     219             :     }
     220             : }
     221             : 
     222             : /*
     223             :   process an array of pulses. n must be even
     224             :  */
     225           0 : void AP_RCProtocol::process_pulse_list(const uint32_t *widths, uint16_t n, bool need_swap)
     226             : {
     227           0 :     if (n & 1) {
     228           0 :         return;
     229             :     }
     230           0 :     while (n) {
     231           0 :         uint32_t widths0 = widths[0];
     232           0 :         uint32_t widths1 = widths[1];
     233           0 :         if (need_swap) {
     234           0 :             uint32_t tmp = widths1;
     235           0 :             widths1 = widths0;
     236           0 :             widths0 = tmp;
     237             :         }
     238           0 :         widths1 -= widths0;
     239           0 :         process_pulse(widths0, widths1);
     240           0 :         widths += 2;
     241           0 :         n -= 2;
     242             :     }
     243             : }
     244             : 
     245           0 : bool AP_RCProtocol::process_byte(uint8_t byte, uint32_t baudrate)
     246             : {
     247           0 :     uint32_t now = AP_HAL::millis();
     248           0 :     bool searching = should_search(now);
     249             : 
     250             : #if AP_RC_CHANNEL_ENABLED
     251           0 :     rc_protocols_mask = rc().enabled_protocols();
     252             : #endif
     253             : 
     254           0 :     if (_detected_protocol != AP_RCProtocol::NONE &&
     255           0 :         !protocol_enabled(_detected_protocol)) {
     256           0 :         _detected_protocol = AP_RCProtocol::NONE;
     257             :     }
     258             : 
     259           0 :     if (_detected_protocol != AP_RCProtocol::NONE && !_detected_with_bytes && !searching) {
     260             :         // we're using pulse inputs, discard bytes
     261           0 :         return false;
     262             :     }
     263             : 
     264             :     // first try current protocol
     265           0 :     if (_detected_protocol != AP_RCProtocol::NONE && !searching) {
     266           0 :         backend[_detected_protocol]->process_byte(byte, baudrate);
     267           0 :         if (backend[_detected_protocol]->new_input()) {
     268           0 :             _new_input = true;
     269           0 :             _last_input_ms = now;
     270             :         }
     271           0 :         return true;
     272             :     }
     273             : 
     274             :     // otherwise scan all protocols
     275           0 :     for (uint8_t i = 0; i < ARRAY_SIZE(backend); i++) {
     276           0 :         if (backend[i] != nullptr) {
     277           0 :             if (!protocol_enabled(rcprotocol_t(i))) {
     278           0 :                 continue;
     279             :             }
     280           0 :             const uint32_t frame_count = backend[i]->get_rc_frame_count();
     281           0 :             const uint32_t input_count = backend[i]->get_rc_input_count();
     282           0 :             backend[i]->process_byte(byte, baudrate);
     283           0 :             const uint32_t frame_count2 = backend[i]->get_rc_frame_count();
     284           0 :             if (frame_count2 > frame_count) {
     285           0 :                 if (requires_3_frames((rcprotocol_t)i) && frame_count2 < 3) {
     286           0 :                     continue;
     287             :                 }
     288           0 :                 _new_input = (input_count != backend[i]->get_rc_input_count());
     289           0 :                 _detected_protocol = (enum AP_RCProtocol::rcprotocol_t)i;
     290           0 :                 _last_input_ms = now;
     291           0 :                 _detected_with_bytes = true;
     292           0 :                 for (uint8_t j = 0; j < ARRAY_SIZE(backend); j++) {
     293           0 :                     if (backend[j]) {
     294           0 :                         backend[j]->reset_rc_frame_count();
     295             :                     }
     296             :                 }
     297             :                 // stop decoding pulses to save CPU
     298           0 :                 hal.rcin->pulse_input_enable(false);
     299           0 :                 return true;
     300             :             }
     301             :         }
     302             :     }
     303           0 :     return false;
     304             : }
     305             : 
     306             : // handshake if nothing else has succeeded so far
     307           4 : void AP_RCProtocol::process_handshake( uint32_t baudrate)
     308             : {
     309             :     // if we ever succeeded before then do not handshake
     310           4 :     if (_detected_protocol != AP_RCProtocol::NONE || _last_input_ms > 0) {
     311           0 :         return;
     312             :     }
     313             : 
     314             :     // otherwise handshake all protocols
     315          80 :     for (uint8_t i = 0; i < ARRAY_SIZE(backend); i++) {
     316          76 :         if (backend[i] != nullptr) {
     317          72 :             backend[i]->process_handshake(baudrate);
     318             :         }
     319             :     }
     320             : }
     321             : 
     322             : /*
     323             :   check for bytes from an additional uart. This is used to support RC
     324             :   protocols from SERIALn_PROTOCOL
     325             :  */
     326           1 : void AP_RCProtocol::SerialConfig::apply_to_uart(AP_HAL::UARTDriver *uart) const
     327             : {
     328           1 :     uart->configure_parity(parity);
     329           1 :     uart->set_stop_bits(stop_bits);
     330           1 :     if (invert_rx) {
     331           0 :         uart->set_options(uart->get_options() | AP_HAL::UARTDriver::OPTION_RXINV);
     332             :     } else {
     333           1 :         uart->set_options(uart->get_options() & ~AP_HAL::UARTDriver::OPTION_RXINV);
     334             :     }
     335           1 :     uart->begin(baud, 128, 128);
     336           1 : }
     337             : 
     338             : static const AP_RCProtocol::SerialConfig serial_configs[] {
     339             :     // BAUD PRTY STOP INVERT-RX
     340             :     // inverted and uninverted 115200 8N1:
     341             :     { 115200,  0,   1, false  },
     342             :     { 115200,  0,   1, true },
     343             :     // SBUS settings, even parity, 2 stop bits:
     344             :     { 100000,  2,   2, true },
     345             : #if AP_RCPROTOCOL_FASTSBUS_ENABLED
     346             :     // FastSBUS:
     347             :     { 200000,  2,   2, true },
     348             : #endif
     349             : #if AP_RCPROTOCOL_CRSF_ENABLED || AP_RCPROTOCOL_GHST_ENABLED
     350             :     // CrossFire:
     351             :     { 416666,  0,   1, false },
     352             :     // CRSFv3 can negotiate higher rates which are sticky on soft reboot
     353             :     { 2000000, 0,   1, false },
     354             : #endif
     355             : };
     356             : 
     357             : static_assert(ARRAY_SIZE(serial_configs) > 0, "must have at least one serial config");
     358             : 
     359   279535355 : void AP_RCProtocol::check_added_uart(void)
     360             : {
     361   279535355 :     if (!added.uart) {
     362   279535351 :         return;
     363             :     }
     364       42964 :     uint32_t now = AP_HAL::millis();
     365       42964 :     bool searching = should_search(now);
     366       42964 :     if (!searching && !_detected_with_bytes) {
     367             :         // not using this uart
     368       42960 :         return;
     369             :     }
     370           4 :     if (!added.opened) {
     371           1 :         added.opened = true;
     372           1 :         added.last_config_change_ms = AP_HAL::millis();
     373           1 :         serial_configs[added.config_num].apply_to_uart(added.uart);
     374             :     }
     375             : #if AP_RC_CHANNEL_ENABLED
     376           4 :     rc_protocols_mask = rc().enabled_protocols();
     377             : #endif
     378           4 :     const uint32_t current_baud = serial_configs[added.config_num].baud;
     379           4 :     process_handshake(current_baud);
     380             : 
     381           4 :     uint32_t n = added.uart->available();
     382           4 :     n = MIN(n, 255U);
     383           4 :     for (uint8_t i=0; i<n; i++) {
     384           0 :         int16_t b = added.uart->read();
     385           0 :         if (b >= 0) {
     386           0 :             process_byte(uint8_t(b), current_baud);
     387             :         }
     388             :     }
     389           4 :     if (searching) {
     390           4 :         if (now - added.last_config_change_ms > 1000) {
     391             :             // change configs if not detected once a second
     392           0 :             added.config_num++;
     393           0 :             if (added.config_num >= ARRAY_SIZE(serial_configs)) {
     394           0 :                 added.config_num = 0;
     395             :             }
     396           0 :             added.opened = false;
     397             :         }
     398             :     // power loss on CRSF requires re-bootstrap because the baudrate is reset to the default. The CRSF side will
     399             :     // drop back down to 416k if it has received 200 incorrect characters (or none at all)
     400           0 :     } else if (_detected_protocol != AP_RCProtocol::NONE
     401             :         // protocols that want to be able to renegotiate should return false in is_rx_active()
     402           0 :         && !backend[_detected_protocol]->is_rx_active()
     403           0 :         && now - added.last_config_change_ms > 1000) {
     404           0 :         added.opened = false;
     405             :     }
     406             : }
     407             : 
     408   243357861 : void AP_RCProtocol::update()
     409             : {
     410   243357861 :     check_added_uart();
     411   243357861 : }
     412             : 
     413             : // explicitly investigate a backend for data, as opposed to feeding
     414             : // the backend a byte (or pulse-train) at a time and having them make
     415             : // an "add_input" callback):
     416   137208537 : bool AP_RCProtocol::detect_async_protocol(rcprotocol_t protocol)
     417             : {
     418   137208537 :     auto *p = backend[protocol];
     419   137208537 :     if (p == nullptr) {
     420             :         // backend is not allocated?!
     421           0 :         return false;
     422             :     }
     423             : 
     424   137208537 :     if (_detected_protocol == protocol) {
     425             :         // we are using this protocol already, see if there is new
     426             :         // data.  Caller will handle the case where we stop presenting
     427             :         // data
     428    36079553 :         return p->new_input();
     429             :     }
     430             : 
     431             :     // we are not the currently in-use protocol.
     432   101128984 :     const uint32_t now = AP_HAL::millis();
     433             : 
     434             :     // see if another backend is providing data:
     435   101128984 :     if (!should_search(now)) {
     436             :         // apparently, yes
     437   100768205 :         return false;
     438             :     }
     439             : 
     440             : #if AP_RC_CHANNEL_ENABLED
     441      360779 :     rc_protocols_mask = rc().enabled_protocols();
     442             : #endif
     443             : 
     444      360779 :     if (!protocol_enabled(protocol)) {
     445           0 :         return false;
     446             :     }
     447             : 
     448             :     // nobody is providing data; can we provide data?
     449      360779 :     if (!p->new_input()) {
     450             :         // we can't provide data
     451      358690 :         return false;
     452             :     }
     453             : 
     454             :     // we can provide data, change the detected protocol to be us:
     455        2089 :     _detected_protocol = protocol;
     456        2089 :     return true;
     457             : }
     458             : 
     459        5029 : const char *AP_RCProtocol::detected_protocol_name() const
     460             : {
     461        5029 :     switch (_detected_protocol) {
     462             : #if AP_RCPROTOCOL_IOMCU_ENABLED
     463             :     case AP_RCProtocol::IOMCU:
     464             :         return ((AP_RCProtocol_IOMCU*)(backend[AP_RCProtocol::IOMCU]))->get_rc_protocol();
     465             : #endif
     466             :     default:
     467        5029 :         return protocol_name_from_protocol(_detected_protocol);
     468             :     }
     469             : }
     470             : 
     471        3010 : void AP_RCProtocol::announce_detected()
     472             : {
     473             :     const char *src;
     474        3010 :     const char *name = detected_protocol_name();
     475        3010 :     if (name == nullptr) {
     476         921 :         return;
     477             :     }
     478        2089 :     switch (_detected_protocol) {
     479             : #if AP_RCPROTOCOL_IOMCU_ENABLED
     480             :     case AP_RCProtocol::IOMCU:
     481             :         src = "IOMCU";
     482             :         break;
     483             : #endif
     484             :     default:
     485        2089 :         src = using_uart() ? "Bytes" : "Pulses";
     486             :     }
     487             :     (void)src;  // iofirmware doesn't use this
     488             :     (void)name;  // iofirmware doesn't use this
     489        2089 :     GCS_SEND_TEXT(MAV_SEVERITY_DEBUG, "RCInput: decoding %s (%s)", name, src);
     490             : }
     491             : 
     492    36177494 : bool AP_RCProtocol::new_input()
     493             : {
     494             :     // if we have an extra UART from a SERIALn_PROTOCOL then check it for data
     495    36177494 :     check_added_uart();
     496             : 
     497             :     // run update function on backends
     498   723549880 :     for (uint8_t i = 0; i < ARRAY_SIZE(backend); i++) {
     499   687372386 :         if (backend[i] != nullptr) {
     500   651194892 :             backend[i]->update();
     501             :         }
     502             :     }
     503             : 
     504             :     // iterate through backends which don't do either of pulse or uart
     505             :     // input, and thus won't update_new_input
     506    36177494 :     const rcprotocol_t pollable[] {
     507             : #if AP_RCPROTOCOL_DRONECAN_ENABLED
     508             :         AP_RCProtocol::DRONECAN,
     509             : #endif
     510             : #if AP_RCPROTOCOL_MAVLINK_RADIO_ENABLED
     511             :         AP_RCProtocol::MAVLINK_RADIO,
     512             : #endif
     513             : #if AP_RCPROTOCOL_JOYSTICK_SFML_ENABLED
     514             :         AP_RCProtocol::JOYSTICK_SFML,
     515             : #endif
     516             : #if AP_RCPROTOCOL_UDP_ENABLED
     517             :         AP_RCProtocol::UDP,
     518             : #endif
     519             : #if AP_RCPROTOCOL_FDM_ENABLED
     520             :         AP_RCProtocol::FDM,
     521             : #endif
     522             : #if AP_RCPROTOCOL_RADIO_ENABLED
     523             :         AP_RCProtocol::RADIO,
     524             : #endif
     525             : #if AP_RCPROTOCOL_IOMCU_ENABLED
     526             :         AP_RCProtocol::IOMCU,
     527             : #endif  // AP_RCPROTOCOL_IOMCU_ENABLED
     528             : #if AP_RCPROTOCOL_EMLID_RCIO_ENABLED
     529             :         AP_RCProtocol::EMLID_RCIO,
     530             : #endif
     531             :     };
     532   165884592 :     for (const auto protocol : pollable) {
     533   137208537 :         if (!detect_async_protocol(protocol)) {
     534   129707098 :             continue;
     535             :         }
     536     7501439 :         _new_input = true;
     537     7501439 :         _last_input_ms = AP_HAL::millis();
     538     7501439 :         break;
     539             :     }
     540             : 
     541             : #if AP_RCPROTOCOL_IOMCU_ENABLED
     542             :     // IOMCU takes precedence over serial-port-type-23 input etc:
     543             :     if (((AP_RCProtocol_IOMCU*)(backend[AP_RCProtocol::IOMCU]))->active()) {
     544             :         _detected_protocol = AP_RCProtocol::IOMCU;
     545             :     }
     546             : #endif
     547             : 
     548             :     // announce protocol changes:
     549    72351978 :     if (_detected_protocol != _last_detected_protocol ||
     550    36174484 :         using_uart() != _last_detected_using_uart) {
     551        3010 :         _last_detected_protocol = _detected_protocol;
     552        3010 :         _last_detected_using_uart = using_uart();
     553        3010 :         announce_detected();
     554             :     }
     555             : 
     556    36177494 :     bool ret = _new_input;
     557    36177494 :     _new_input = false;
     558    36177494 :     return ret;
     559             : }
     560             : 
     561     1311839 : uint8_t AP_RCProtocol::num_channels()
     562             : {
     563     1311839 :     if (_detected_protocol != AP_RCProtocol::NONE) {
     564     1310180 :         return backend[_detected_protocol]->num_channels();
     565             :     }
     566        1659 :     return 0;
     567             : }
     568             : 
     569   119958672 : uint16_t AP_RCProtocol::read(uint8_t chan)
     570             : {
     571   119958672 :     if (_detected_protocol != AP_RCProtocol::NONE) {
     572   119953024 :         return backend[_detected_protocol]->read(chan);
     573             :     }
     574        5648 :     return 0;
     575             : }
     576             : 
     577           0 : void AP_RCProtocol::read(uint16_t *pwm, uint8_t n)
     578             : {
     579           0 :     if (_detected_protocol != AP_RCProtocol::NONE) {
     580           0 :         backend[_detected_protocol]->read(pwm, n);
     581             :     }
     582           0 : }
     583             : 
     584           0 : int16_t AP_RCProtocol::get_RSSI(void) const
     585             : {
     586           0 :     if (_detected_protocol != AP_RCProtocol::NONE) {
     587           0 :         return backend[_detected_protocol]->get_RSSI();
     588             :     }
     589           0 :     return -1;
     590             : }
     591           0 : int16_t AP_RCProtocol::get_rx_link_quality(void) const
     592             : {
     593           0 :     if (_detected_protocol != AP_RCProtocol::NONE) {
     594           0 :         return backend[_detected_protocol]->get_rx_link_quality();
     595             :     }
     596           0 :     return -1;
     597             : }
     598             : /*
     599             :   ask for bind start on supported receivers (eg spektrum satellite)
     600             :  */
     601           0 : void AP_RCProtocol::start_bind()
     602             : {
     603           0 :     for (uint8_t i = 0; i < ARRAY_SIZE(backend); i++) {
     604           0 :         if (backend[i] != nullptr && protocol_enabled((rcprotocol_t)i)) {
     605           0 :             backend[i]->start_bind();
     606             :         }
     607             :     }
     608           0 : }
     609             : 
     610             : #endif  // AP_RCPROTOCOL_ENABLED
     611             : 
     612             : /*
     613             :   return protocol name
     614             :  */
     615        5029 : const char *AP_RCProtocol::protocol_name_from_protocol(rcprotocol_t protocol)
     616             : {
     617        5029 :     switch (protocol) {
     618             : #if AP_RCPROTOCOL_PPMSUM_ENABLED
     619           0 :     case PPMSUM:
     620           0 :         return "PPM";
     621             : #endif
     622             : #if AP_RCPROTOCOL_IBUS_ENABLED
     623           0 :     case IBUS:
     624           0 :         return "IBUS";
     625             : #endif
     626             : #if AP_RCPROTOCOL_SBUS_ENABLED
     627           0 :     case SBUS:
     628           0 :         return "SBUS";
     629             : #endif
     630             : #if AP_RCPROTOCOL_SBUS_NI_ENABLED
     631           0 :     case SBUS_NI:
     632           0 :         return "SBUS";
     633             : #endif
     634             : #if AP_RCPROTOCOL_FASTSBUS_ENABLED
     635           0 :     case FASTSBUS:
     636           0 :         return "FastSBUS";
     637             : #endif
     638             : #if AP_RCPROTOCOL_DSM_ENABLED
     639           0 :     case DSM:
     640           0 :         return "DSM";
     641             : #endif
     642             : #if AP_RCPROTOCOL_SUMD_ENABLED
     643           0 :     case SUMD:
     644           0 :         return "SUMD";
     645             : #endif
     646             : #if AP_RCPROTOCOL_SRXL_ENABLED
     647           0 :     case SRXL:
     648           0 :         return "SRXL";
     649             : #endif
     650             : #if AP_RCPROTOCOL_SRXL2_ENABLED
     651           0 :     case SRXL2:
     652           0 :         return "SRXL2";
     653             : #endif
     654             : #if AP_RCPROTOCOL_CRSF_ENABLED
     655           0 :     case CRSF:
     656           0 :         return "CRSF";
     657             : #endif
     658             : #if AP_RCPROTOCOL_ST24_ENABLED
     659           0 :     case ST24:
     660           0 :         return "ST24";
     661             : #endif
     662             : #if AP_RCPROTOCOL_FPORT_ENABLED
     663           0 :     case FPORT:
     664           0 :         return "FPORT";
     665             : #endif
     666             : #if AP_RCPROTOCOL_FPORT2_ENABLED
     667           0 :     case FPORT2:
     668           0 :         return "FPORT2";
     669             : #endif
     670             : #if AP_RCPROTOCOL_DRONECAN_ENABLED
     671           0 :     case DRONECAN:
     672           0 :         return "DroneCAN";
     673             : #endif
     674             : #if AP_RCPROTOCOL_GHST_ENABLED
     675           0 :     case GHST:
     676           0 :         return "GHST";
     677             : #endif
     678             : #if AP_RCPROTOCOL_MAVLINK_RADIO_ENABLED
     679           0 :     case MAVLINK_RADIO:
     680           0 :         return "MAVRadio";
     681             : #endif
     682             : #if AP_RCPROTOCOL_JOYSTICK_SFML_ENABLED
     683             :     case JOYSTICK_SFML:
     684             :         return "SFML";
     685             : #endif
     686             : #if AP_RCPROTOCOL_UDP_ENABLED
     687        4098 :     case UDP:
     688        4098 :         return "UDP";
     689             : #endif
     690             : #if AP_RCPROTOCOL_FDM_ENABLED
     691           0 :     case FDM:
     692           0 :         return "FDM";
     693             : #endif
     694             : #if AP_RCPROTOCOL_RADIO_ENABLED
     695             :     case RADIO:
     696             :         return "Radio";
     697             : #endif
     698             : #if AP_RCPROTOCOL_IOMCU_ENABLED
     699             :     case IOMCU:
     700             :         return "IOMCU";
     701             : #endif  // AP_RCPROTOCOL_IOMCU_ENABLED
     702             : #if AP_RCPROTOCOL_EMLID_RCIO_ENABLED
     703             :     case EMLID_RCIO:
     704             :         return "Emlid RCIO";
     705             : #endif
     706         931 :     case NONE:
     707         931 :         break;
     708             :     }
     709         931 :     return nullptr;
     710             : }
     711             : 
     712             : #if AP_RCPROTOCOL_ENABLED
     713             : /*
     714             :   add a uart to decode
     715             :  */
     716           1 : void AP_RCProtocol::add_uart(AP_HAL::UARTDriver* uart)
     717             : {
     718           1 :     added.uart = uart;
     719           1 :     added.uart->set_flow_control(AP_HAL::UARTDriver::FLOW_CONTROL_DISABLE);
     720           1 : }
     721             : 
     722             : // return true if a specific protocol is enabled
     723      360779 : bool AP_RCProtocol::protocol_enabled(rcprotocol_t protocol) const
     724             : {
     725      360779 :     if ((rc_protocols_mask & 1U) != 0) {
     726             :         // all protocols enabled
     727      360779 :         return true;
     728             :     }
     729           0 :     return ((1U<<(uint8_t(protocol)+1)) & rc_protocols_mask) != 0;
     730             : }
     731             : 
     732             : #if AP_RCPROTOCOL_MAVLINK_RADIO_ENABLED
     733           0 : void AP_RCProtocol::handle_radio_rc_channels(const mavlink_radio_rc_channels_t* packet)
     734             : {
     735           0 :     if (backend[AP_RCProtocol::MAVLINK_RADIO] == nullptr) {
     736           0 :         return;
     737             :     }
     738             : 
     739           0 :     backend[AP_RCProtocol::MAVLINK_RADIO]->update_radio_rc_channels(packet);
     740             : };
     741             : #endif // AP_RCPROTOCOL_MAVLINK_RADIO_ENABLED
     742             : 
     743             : namespace AP {
     744   403010575 :     AP_RCProtocol &RC()
     745             :     {
     746   403010575 :         static AP_RCProtocol rcprot;
     747   403010575 :         return rcprot;
     748             :     }
     749             : };
     750             : 
     751             : #endif  // AP_RCPROTOCOL_ENABLED

Generated by: LCOV version 1.14