LCOV - code coverage report
Current view: top level - AP_CANManager - AP_CANSensor.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 0 87 0.0 %
Date: 2026-09-09 11:02:08 Functions: 0 10 0.0 %

          Line data    Source code
       1             : /*
       2             :    This program is free software: you can redistribute it and/or modify
       3             :    it under the terms of the GNU General Public License as published by
       4             :    the Free Software Foundation, either version 3 of the License, or
       5             :    (at your option) any later version.
       6             : 
       7             :    This program is distributed in the hope that it will be useful,
       8             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
       9             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      10             :    GNU General Public License for more details.
      11             : 
      12             :    You should have received a copy of the GNU General Public License
      13             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      14             :  */
      15             : /*
      16             :   generic CAN sensor class, for easy creation of CAN sensors using proprietary protocols
      17             :  */
      18             : #include <AP_HAL/AP_HAL.h>
      19             : 
      20             : #if HAL_MAX_CAN_PROTOCOL_DRIVERS
      21             : 
      22             : #include <AP_Scheduler/AP_Scheduler.h>
      23             : #include "AP_CANSensor.h"
      24             : #include <AP_BoardConfig/AP_BoardConfig.h>
      25             : 
      26             : extern const AP_HAL::HAL& hal;
      27             : 
      28           0 : CANSensor::CANSensor(const char *driver_name, uint16_t stack_size) :
      29           0 :     _driver_name(driver_name),
      30           0 :     _stack_size(stack_size)
      31           0 : {}
      32             : 
      33             : 
      34           0 : void CANSensor::register_driver(AP_CAN::Protocol dtype)
      35             : {
      36             : #if HAL_CANMANAGER_ENABLED
      37           0 :     if (!AP::can().register_driver(dtype, this)) {
      38           0 :         if (AP::can().register_11bit_driver(dtype, this, _driver_index)) {
      39           0 :             is_aux_11bit_driver = true;
      40           0 :             _can_driver = AP::can().get_driver(_driver_index);
      41           0 :             _initialized = true;
      42             :         }
      43             :     }
      44             : #elif defined(HAL_BUILD_AP_PERIPH)
      45             :     register_driver_periph(dtype);
      46             : #endif
      47           0 : }
      48             : 
      49             : 
      50             : #ifdef HAL_BUILD_AP_PERIPH
      51             : CANSensor::CANSensor_Periph CANSensor::_periph[HAL_NUM_CAN_IFACES];
      52             : 
      53             : void CANSensor::register_driver_periph(const AP_CAN::Protocol dtype)
      54             : {
      55             :     for (uint8_t i = 0; i < HAL_NUM_CAN_IFACES; i++) {
      56             :         if (_periph[i].protocol != dtype) {
      57             :             continue;
      58             :         }
      59             : 
      60             :         if (!add_interface(_periph[i].iface)) {
      61             :             continue;
      62             :         }
      63             : 
      64             :         init(0); // TODO: allow multiple drivers
      65             :         return;
      66             :     }
      67             : }
      68             : #endif
      69             : 
      70           0 : void CANSensor::init(uint8_t driver_index)
      71             : {
      72           0 :     _driver_index = driver_index;
      73             : 
      74           0 :     if (_initialized) {
      75           0 :         return;
      76             :     }
      77             : 
      78             : #ifndef HAL_BUILD_AP_PERIPH
      79             :     // get CAN manager instance
      80           0 :     _can_driver = AP::can().get_driver(driver_index);
      81             : 
      82           0 :     if (_can_driver == nullptr) {
      83           0 :         return;
      84             :     }
      85             : #endif
      86             : 
      87             :     // start thread for receiving and sending CAN frames
      88           0 :     if (!hal.scheduler->thread_create(FUNCTOR_BIND_MEMBER(&CANSensor::loop, void), _driver_name, _stack_size, AP_HAL::Scheduler::PRIORITY_CAN, 0)) {
      89           0 :         return;
      90             :     }
      91             : 
      92           0 :     _initialized = true;
      93             : }
      94             : 
      95           0 : bool CANSensor::add_interface(AP_HAL::CANIface* can_iface)
      96             : {
      97           0 :     if (_can_iface != nullptr) {
      98           0 :         return false;
      99             :     }
     100             : 
     101           0 :     _can_iface = can_iface;
     102             : 
     103           0 :     if (_can_iface == nullptr) {
     104           0 :         return false;
     105             :     }
     106             : 
     107           0 :     if (!_can_iface->is_initialized()) {
     108           0 :         return false;
     109             :     }
     110             : 
     111           0 :     if (!_can_iface->set_event_handle(&sem_handle)) {
     112           0 :         return false;
     113             :     }
     114           0 :     return true;
     115             : }
     116             : 
     117           0 : bool CANSensor::write_frame(AP_HAL::CANFrame &out_frame, const uint32_t timeout_us)
     118             : {
     119           0 :     if (!_initialized) {
     120           0 :         return false;
     121             :     }
     122             : 
     123           0 :     if (is_aux_11bit_driver && _can_driver != nullptr) {
     124           0 :         return _can_driver->write_aux_frame(out_frame, timeout_us);
     125             :     }
     126             : 
     127           0 :     bool read_select = false;
     128           0 :     bool write_select = true;
     129           0 :     bool ret = _can_iface->select(read_select, write_select, &out_frame, AP_HAL::micros64() + timeout_us);
     130           0 :     if (!ret || !write_select) {
     131           0 :         return false;
     132             :     }
     133             : 
     134           0 :     uint64_t deadline = AP_HAL::micros64() + 2000000;
     135           0 :     return (_can_iface->send(out_frame, deadline, AP_HAL::CANIface::AbortOnError) == 1);
     136             : }
     137             : 
     138           0 : void CANSensor::loop()
     139             : {
     140           0 :     while (!hal.scheduler->is_system_initialized()) {
     141             :         // don't process packets till startup complete
     142           0 :         hal.scheduler->delay(1);
     143             :     }
     144             : 
     145             : #ifdef HAL_BUILD_AP_PERIPH
     146             :     const uint32_t LOOP_INTERVAL_US = 1000;
     147             : #else
     148           0 :     const uint32_t LOOP_INTERVAL_US = AP::scheduler().get_loop_period_us();
     149             : #endif
     150             : 
     151             :     while (true) {
     152           0 :         uint64_t deadline_us = AP_HAL::micros64() + LOOP_INTERVAL_US;
     153             : 
     154             :         // wait to receive frame
     155           0 :         bool read_select = true;
     156           0 :         bool write_select = false;
     157           0 :         bool ret = _can_iface->select(read_select, write_select, nullptr, deadline_us);
     158           0 :         if (ret && read_select) {
     159             :             uint64_t time;
     160           0 :             AP_HAL::CANIface::CanIOFlags flags {};
     161             : 
     162           0 :             AP_HAL::CANFrame frame;
     163           0 :             int16_t res = _can_iface->receive(frame, time, flags);
     164             : 
     165           0 :             if (res == 1) {
     166           0 :                 handle_frame(frame);
     167             :             }
     168             :         }
     169           0 :     }
     170             : }
     171             : 
     172             : MultiCAN::MultiCANLinkedList* MultiCAN::callbacks;
     173             : 
     174           0 : MultiCAN::MultiCAN(ForwardCanFrame cf, AP_CAN::Protocol can_type, const char *driver_name) :
     175           0 :         CANSensor(driver_name)
     176             : {
     177           0 :     if (callbacks == nullptr) {
     178           0 :         callbacks = NEW_NOTHROW MultiCANLinkedList();
     179             :     }
     180           0 :     if (callbacks == nullptr) {
     181           0 :         AP_BoardConfig::allocation_error("Failed to create multican callback");
     182             :     }
     183             : 
     184             :     // Register new driver
     185           0 :     register_driver(can_type);
     186           0 :     callbacks->register_callback(cf);
     187           0 : }
     188             : 
     189             : // handle a received frame from the CAN bus
     190           0 : void MultiCAN::handle_frame(AP_HAL::CANFrame &frame)
     191             : {
     192           0 :     if (callbacks != nullptr) {
     193           0 :         callbacks->handle_frame(frame);
     194             :     }
     195             : 
     196           0 : }
     197             : 
     198             : // register a callback for a CAN frame by adding it to the linked list
     199           0 : void MultiCAN::MultiCANLinkedList::register_callback(ForwardCanFrame callback)
     200             : {
     201           0 :     CANSensor_Multi* newNode = NEW_NOTHROW CANSensor_Multi();
     202           0 :     if (newNode == nullptr) {
     203           0 :         AP_BoardConfig::allocation_error("Failed to create multican node");
     204             :     }
     205           0 :     WITH_SEMAPHORE(sem);
     206             :     {
     207           0 :         newNode->_callback = callback;
     208           0 :         newNode->next = head;
     209           0 :         head = newNode;
     210             :     }
     211           0 : }
     212             : 
     213             : // distribute the CAN frame to the registered callbacks
     214           0 : void MultiCAN::MultiCANLinkedList::handle_frame(AP_HAL::CANFrame &frame)
     215             : {
     216           0 :     WITH_SEMAPHORE(sem);
     217           0 :     for (CANSensor_Multi* current = head; current != nullptr; current = current->next) {
     218           0 :         if (current->_callback(frame)) {
     219           0 :             return;
     220             :         }
     221             :     }
     222           0 : }
     223             : 
     224             : #endif // HAL_MAX_CAN_PROTOCOL_DRIVERS
     225             : 

Generated by: LCOV version 1.14