LCOV - code coverage report
Current view: top level - AP_RCProtocol - AP_RCProtocol_DroneCAN.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 8 77 10.4 %
Date: 2026-09-09 11:02:08 Functions: 2 4 50.0 %

          Line data    Source code
       1             : #include "AP_RCProtocol_config.h"
       2             : 
       3             : #if AP_RCPROTOCOL_DRONECAN_ENABLED
       4             : 
       5             : #include <AP_CANManager/AP_CANManager.h>
       6             : #include <AP_DroneCAN/AP_DroneCAN.h>
       7             : #include <AP_BoardConfig/AP_BoardConfig.h>
       8             : #include "AP_RCProtocol_DroneCAN.h"
       9             : 
      10             : AP_RCProtocol_DroneCAN::Registry AP_RCProtocol_DroneCAN::registry;
      11             : AP_RCProtocol_DroneCAN *AP_RCProtocol_DroneCAN::_singleton;
      12             : 
      13           5 : bool AP_RCProtocol_DroneCAN::subscribe_msgs(AP_DroneCAN* ap_dronecan)
      14             : {
      15           5 :     const auto driver_index = ap_dronecan->get_driver_index();
      16             : 
      17           5 :     return (Canard::allocate_sub_arg_callback(ap_dronecan, &handle_rcinput, driver_index) != nullptr);
      18             : }
      19             : 
      20           0 : AP_RCProtocol_DroneCAN* AP_RCProtocol_DroneCAN::get_dronecan_backend(AP_DroneCAN* ap_dronecan, uint8_t node_id)
      21             : {
      22           0 :     if (_singleton == nullptr) {
      23           0 :         return nullptr;
      24             :     }
      25             : 
      26           0 :     if (ap_dronecan == nullptr) {
      27           0 :         return nullptr;
      28             :     }
      29             : 
      30           0 :     for (auto &device : registry.detected_devices) {
      31           0 :         if (device.driver == nullptr) {
      32           0 :             continue;
      33             :         }
      34           0 :         if (device.ap_dronecan != ap_dronecan) {
      35           0 :             continue;
      36             :         }
      37           0 :         if (device.node_id != node_id ) {
      38           0 :             continue;
      39             :         }
      40           0 :         return device.driver;
      41             :     }
      42             : 
      43             :     // not found in registry; add it if possible.
      44           0 :     for (auto &device : registry.detected_devices) {
      45           0 :         if (device.ap_dronecan == nullptr) {
      46           0 :             device.ap_dronecan = ap_dronecan;
      47           0 :             device.node_id = node_id;
      48           0 :             device.driver = _singleton;
      49           0 :             return device.driver;
      50             :         }
      51             :     }
      52             : 
      53           0 :     return nullptr;
      54             : }
      55             : 
      56           0 : void AP_RCProtocol_DroneCAN::handle_rcinput(AP_DroneCAN *ap_dronecan, const CanardRxTransfer& transfer, const dronecan_sensors_rc_RCInput &msg)
      57             : {
      58           0 :     AP_RCProtocol_DroneCAN* driver = get_dronecan_backend(ap_dronecan, transfer.source_node_id);
      59           0 :     if (driver == nullptr) {
      60           0 :         return;
      61             :     }
      62             : 
      63           0 :     auto &rcin = driver->rcin;
      64           0 :     WITH_SEMAPHORE(rcin.sem);
      65           0 :     rcin.quality = msg.quality;
      66           0 :     rcin.status = msg.status;
      67           0 :     rcin.num_channels = MIN(msg.rcin.len, ARRAY_SIZE(rcin.channels));
      68           0 :     for (auto i=0; i<rcin.num_channels; i++) {
      69           0 :         rcin.channels[i] = msg.rcin.data[i];
      70             :     }
      71             : 
      72           0 :     rcin.last_sample_time_ms = AP_HAL::millis();
      73           0 : }
      74             : 
      75    36177494 : void AP_RCProtocol_DroneCAN::update()
      76             : {
      77             :     {
      78    36177494 :         WITH_SEMAPHORE(rcin.sem);
      79    36177494 :         if (rcin.last_sample_time_ms == last_receive_ms) {
      80             :             // no new data
      81    36177494 :             return;
      82             :         }
      83           0 :         last_receive_ms = rcin.last_sample_time_ms;
      84             : 
      85           0 :         if (rcin.bits.QUALITY_VALID) {
      86           0 :             switch (rcin.bits.QUALITY_TYPE) {
      87           0 :                 case QualityType::RSSI:
      88             :                     // as this is 0, it also provides backwards compatibility for systems not setting these bits
      89           0 :                     _rssi = rcin.quality;
      90           0 :                     break;
      91           0 :                 case QualityType::LQ_ACTIVE_ANTENNA:
      92             :                     // highest bit carries active antenna data
      93           0 :                     frontend._rc_link_status.link_quality = (rcin.quality & 0x7F);
      94           0 :                     frontend._rc_link_status.active_antenna = (rcin.quality & 0x80) ? 1 : 0;
      95           0 :                     break;
      96           0 :                 case QualityType::RSSI_DBM:
      97           0 :                     frontend._rc_link_status.rssi_dbm = rcin.quality;
      98             :                     // also set the rssi field, this avoids having to waste a slot for sending both
      99             :                     // AP rssi: -1 for unknown, 0 for no link, 255 for maximum link
     100           0 :                     if (rcin.quality < 50) {
     101           0 :                         _rssi = 255;
     102           0 :                     } else if (rcin.quality > 120) {
     103           0 :                         _rssi = 0;
     104             :                     } else {
     105           0 :                         _rssi = int16_t(roundf((120.0f - rcin.quality) * (255.0f / 70.0f)));
     106             :                     }
     107           0 :                     break;
     108           0 :                 case QualityType::SNR:
     109             :                     // SNR is shifted by 128 to support negative values
     110           0 :                     frontend._rc_link_status.snr = (int8_t)rcin.quality - 128;
     111           0 :                     break;
     112           0 :                 case QualityType::TX_POWER:
     113             :                     // carries tx power in units of 5 mW, thus can't support higher than 255*5 = 1275 mW
     114           0 :                     frontend._rc_link_status.tx_power = (int16_t)rcin.quality * 5;
     115           0 :                     break;
     116             :             }
     117             :         } else {
     118           0 :             _rssi = -1;
     119           0 :             frontend._rc_link_status.link_quality = -1;
     120           0 :             frontend._rc_link_status.rssi_dbm = -1;
     121           0 :             frontend._rc_link_status.snr = INT8_MIN;
     122           0 :             frontend._rc_link_status.tx_power = -1;
     123           0 :             frontend._rc_link_status.active_antenna = -1;
     124             :         }
     125             : 
     126           0 :         add_input(
     127           0 :             rcin.num_channels,
     128           0 :             rcin.channels,
     129           0 :             rcin.bits.FAILSAFE,
     130           0 :             _rssi,
     131           0 :             frontend._rc_link_status.link_quality
     132             :             );
     133    36177494 :     }
     134             : }
     135             : 
     136             : #endif // AP_RCPROTOCOL_DRONECAN_ENABLED

Generated by: LCOV version 1.14