LCOV - code coverage report
Current view: top level - AP_RCProtocol - AP_RCProtocol_Backend.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 39 94 41.5 %
Date: 2026-09-09 11:02:08 Functions: 6 9 66.7 %

          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             : #if AP_RCPROTOCOL_ENABLED
      21             : 
      22             : #include "AP_RCProtocol.h"
      23             : #include <AP_Math/AP_Math.h>
      24             : #include <RC_Channel/RC_Channel.h>
      25             : #include <AP_Vehicle/AP_Vehicle_Type.h>
      26             : #include <AP_Logger/AP_Logger.h>
      27             : #include <AP_VideoTX/AP_VideoTX_config.h>
      28             : 
      29             : // for video TX configuration:
      30             : #if AP_VIDEOTX_ENABLED
      31             : #include <AP_VideoTX/AP_VideoTX.h>
      32             : #include "spm_srxl.h"
      33             : #endif
      34             : 
      35             : 
      36             : 
      37       37692 : AP_RCProtocol_Backend::AP_RCProtocol_Backend(AP_RCProtocol &_frontend) :
      38       37692 :     frontend(_frontend)
      39       37692 : {}
      40             : 
      41    36440332 : bool AP_RCProtocol_Backend::new_input()
      42             : {
      43    36440332 :     bool ret = rc_input_count != last_rc_input_count;
      44    36440332 :     if (ret) {
      45     7501439 :         last_rc_input_count = rc_input_count;
      46             :     }
      47    36440332 :     return ret;
      48             : }
      49             : 
      50     1310180 : uint8_t AP_RCProtocol_Backend::num_channels() const
      51             : {
      52     1310180 :     return _num_channels;
      53             : }
      54             : 
      55   119953024 : uint16_t AP_RCProtocol_Backend::read(uint8_t chan)
      56             : {
      57   119953024 :     return _pwm_values[chan];
      58             : }
      59             : 
      60           0 : void AP_RCProtocol_Backend::read(uint16_t *pwm, uint8_t n)
      61             : {
      62           0 :     if (n >= MAX_RCIN_CHANNELS) {
      63           0 :         n = MAX_RCIN_CHANNELS;
      64             :     }
      65           0 :     memcpy(pwm, _pwm_values, n*sizeof(pwm[0]));
      66           0 : }
      67             : 
      68             : /*
      69             :   provide input from a backend
      70             :  */
      71     7510171 : void AP_RCProtocol_Backend::add_input(uint8_t num_values, uint16_t *values, bool in_failsafe, int16_t _rssi, int16_t _rx_link_quality)
      72             : {
      73     7510171 :     num_values = MIN(num_values, MAX_RCIN_CHANNELS);
      74     7510171 :     memcpy(_pwm_values, values, num_values*sizeof(uint16_t));
      75     7510171 :     _num_channels = num_values;
      76     7510171 :     rc_frame_count++;
      77     7510171 :     frontend.set_failsafe_active(in_failsafe);
      78             : #if !AP_RC_CHANNEL_ENABLED
      79             :     // failsafed is sorted out in AP_IOMCU.cpp
      80             :     in_failsafe = false;
      81             : #else
      82     7510171 :     if (rc().option_is_enabled(RC_Channels::Option::IGNORE_FAILSAFE)) {
      83           0 :         in_failsafe = false;
      84             :     }
      85             : #endif
      86     7510171 :     if (!in_failsafe) {
      87     7508631 :         rc_input_count++;
      88             :     }
      89     7510171 :     rssi = _rssi;
      90     7510171 :     rx_link_quality = _rx_link_quality;
      91     7510171 : }
      92             : 
      93             : 
      94             : /*
      95             :   decode channels from the standard 11bit format (used by CRSF, SBUS, FPort and FPort2)
      96             :   must be used on multiples of 8 channels
      97             : */
      98        2560 : void AP_RCProtocol_Backend::decode_11bit_channels(const uint8_t* data, uint8_t nchannels, uint16_t *values, uint16_t mult, uint16_t div, uint16_t offset)
      99             : {
     100             : #define CHANNEL_SCALE(x) ((int32_t(x) * mult) / div + offset)
     101        5120 :     while (nchannels >= 8) {
     102        2560 :         const Channels11Bit_8Chan* channels = (const Channels11Bit_8Chan*)data;
     103        2560 :         values[0] = CHANNEL_SCALE(channels->ch0);
     104        2560 :         values[1] = CHANNEL_SCALE(channels->ch1);
     105        2560 :         values[2] = CHANNEL_SCALE(channels->ch2);
     106        2560 :         values[3] = CHANNEL_SCALE(channels->ch3);
     107        2560 :         values[4] = CHANNEL_SCALE(channels->ch4);
     108        2560 :         values[5] = CHANNEL_SCALE(channels->ch5);
     109        2560 :         values[6] = CHANNEL_SCALE(channels->ch6);
     110        2560 :         values[7] = CHANNEL_SCALE(channels->ch7);
     111             : 
     112        2560 :         nchannels -= 8;
     113        2560 :         data += sizeof(*channels);
     114        2560 :         values += 8;
     115             :     }
     116        2560 : }
     117             : 
     118             : #if AP_VIDEOTX_ENABLED
     119             : // configure the video transmitter, the input values are Spektrum-oriented
     120           0 : void AP_RCProtocol_Backend::configure_vtx(uint8_t band, uint8_t channel, uint8_t power, uint8_t pitmode)
     121             : {
     122           0 :     AP_VideoTX& vtx = AP::vtx();
     123             :     // VTX Band (0 = Fatshark, 1 = Raceband, 2 = E, 3 = B, 4 = A)
     124             :     // map to TBS band A, B, E, Race, Airwave, LoRace
     125           0 :     switch (band) {
     126           0 :     case VTX_BAND_FATSHARK:
     127           0 :         vtx.set_configured_band(AP_VideoTX::VideoBand::FATSHARK);
     128           0 :         break;
     129           0 :     case VTX_BAND_RACEBAND:
     130           0 :         vtx.set_configured_band(AP_VideoTX::VideoBand::RACEBAND);
     131           0 :         break;
     132           0 :     case VTX_BAND_E_BAND:
     133           0 :         vtx.set_configured_band(AP_VideoTX::VideoBand::BAND_E);
     134           0 :         break;
     135           0 :     case VTX_BAND_B_BAND:
     136           0 :         vtx.set_configured_band(AP_VideoTX::VideoBand::BAND_B);
     137           0 :         break;
     138           0 :     case VTX_BAND_A_BAND:
     139           0 :         vtx.set_configured_band(AP_VideoTX::VideoBand::BAND_A);
     140           0 :         break;
     141           0 :     default:
     142           0 :         break;
     143             :     }
     144             :     // VTX Channel (0-7)
     145           0 :     vtx.set_configured_channel(channel);
     146           0 :     if (pitmode) {
     147           0 :         vtx.set_configured_options(vtx.get_options() | uint8_t(AP_VideoTX::VideoOptions::VTX_PITMODE));
     148             :     } else {
     149           0 :         vtx.set_configured_options(vtx.get_options() & ~uint8_t(AP_VideoTX::VideoOptions::VTX_PITMODE));
     150             :     }
     151             : 
     152           0 :     switch (power) {
     153           0 :     case VTX_POWER_1MW_14MW:
     154             :     case VTX_POWER_15MW_25MW:
     155           0 :         vtx.set_configured_power_mw(25);
     156           0 :         break;
     157           0 :     case VTX_POWER_26MW_99MW:
     158             :     case VTX_POWER_100MW_299MW:
     159           0 :         vtx.set_configured_power_mw(100);
     160           0 :         break;
     161           0 :     case VTX_POWER_300MW_600MW:
     162           0 :         vtx.set_configured_power_mw(400);
     163           0 :         break;
     164           0 :     case VTX_POWER_601_PLUS:
     165           0 :         vtx.set_configured_power_mw(800);
     166           0 :         break;
     167           0 :     default:
     168           0 :         break;
     169             :     }
     170           0 : }
     171             : #endif  // AP_VIDEOTX_ENABLED
     172             : 
     173             : /*
     174             :   optionally log RC input data
     175             :  */
     176           0 : void AP_RCProtocol_Backend::log_data(AP_RCProtocol::rcprotocol_t prot, uint32_t timestamp, const uint8_t *data, uint8_t len) const
     177             : {
     178             : #if HAL_LOGGING_ENABLED && AP_RC_CHANNEL_ENABLED
     179             : 
     180             : #if (CONFIG_HAL_BOARD == HAL_BOARD_SITL || CONFIG_HAL_BOARD == HAL_BOARD_LINUX)
     181           0 :     if (RC_Channels::get_singleton() == nullptr) { // allow running without RC_Channels if we are doing the examples
     182           0 :         return;
     183             :     }
     184             : #endif
     185           0 :     if (rc().option_is_enabled(RC_Channels::Option::LOG_RAW_DATA)) {
     186           0 :         uint32_t u32[10] {};
     187           0 :         if (len > sizeof(u32)) {
     188           0 :             len = sizeof(u32);
     189             :         }
     190           0 :         memcpy(u32, data, len);
     191             : // @LoggerMessage: RCDA
     192             : // @Description: Raw RC data
     193             : // @Field: TimeUS: Time since system startup
     194             : // @Field: TS: data arrival timestamp
     195             : // @Field: Prot: Protocol currently being decoded
     196             : // @Field: Len: Number of valid bytes in message
     197             : // @Field: U0: first quartet of bytes
     198             : // @Field: U1: second quartet of bytes
     199             : // @Field: U2: third quartet of bytes
     200             : // @Field: U3: fourth quartet of bytes
     201             : // @Field: U4: fifth quartet of bytes
     202             : // @Field: U5: sixth quartet of bytes
     203             : // @Field: U6: seventh quartet of bytes
     204             : // @Field: U7: eight quartet of bytes
     205             : // @Field: U8: ninth quartet of bytes
     206             : // @Field: U9: tenth quartet of bytes
     207           0 :         AP::logger().WriteStreaming("RCDA", "TimeUS,TS,Prot,Len,U0,U1,U2,U3,U4,U5,U6,U7,U8,U9", "QIBBIIIIIIIIII",
     208             :                            AP_HAL::micros64(),
     209             :                            timestamp,
     210             :                            (uint8_t)prot,
     211             :                            len,
     212             :                            u32[0], u32[1], u32[2], u32[3], u32[4],
     213             :                            u32[5], u32[6], u32[7], u32[8], u32[9]);
     214             :     }
     215             : #endif  // HAL_LOGGING_ENABLED && AP_RC_CHANNEL_ENABLED
     216             : }
     217             : 
     218             : #endif  // AP_RCPROTOCOL_ENABLED

Generated by: LCOV version 1.14