LCOV - code coverage report
Current view: top level - AP_Generator - AP_Generator_Cortex.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 0 100 0.0 %
Date: 2026-09-09 11:02:08 Functions: 0 11 0.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             :  * Author: Oliver Walters / Currawong Engineering Pty Ltd
      16             :  */
      17             : 
      18             : #pragma GCC optimize("Os")
      19             : 
      20             : #include "AP_Generator_config.h"
      21             : 
      22             : #if AP_GENERATOR_CORTEX_ENABLED
      23             : 
      24             : #include "AP_Generator_Cortex.h"
      25             : #include <AP_PiccoloCAN/AP_PiccoloCAN_Device.h>
      26             : 
      27             : #include <AP_Logger/AP_Logger.h>
      28             : #include <GCS_MAVLink/GCS.h>
      29             : 
      30             : #include <AP_Param/AP_Param.h>
      31             : 
      32             : extern const AP_HAL::HAL& hal;
      33             : 
      34             : AP_Generator_Cortex* AP_Generator_Cortex::_singleton;
      35             : 
      36             : 
      37           0 : void AP_Generator_Cortex::init()
      38             : {
      39           0 :     _singleton = this;
      40             : 
      41             :     // Inform frontend which measurements are available for this generator
      42           0 :     _frontend._has_current = true;
      43           0 :     _frontend._has_consumed_energy = false;
      44           0 :     _frontend._has_fuel_remaining = false;
      45           0 : }
      46             : 
      47             : 
      48             : // Decode received CAN frame    
      49           0 : bool AP_Generator_Cortex::handle_message(AP_HAL::CANFrame &frame, AP_PiccoloCAN& can_iface)
      50             : {
      51             :     // Store a pointer to the CAN interface
      52           0 :     if (_can_iface == nullptr) {
      53           0 :         _can_iface = &can_iface;
      54             :     }
      55             : 
      56           0 :     if (decodeCortex_TelemetryStatusPacketStructure(&frame, &telemetry.status)) {
      57           0 :     } else if (decodeCortex_TelemetryGeneratorPacketStructure(&frame, &telemetry.generator)) {
      58           0 :     } else if (decodeCortex_TelemetryBatteryPacketStructure(&frame, &telemetry.battery)) {
      59           0 :     } else if (decodeCortex_TelemetryOutputRailPacketStructure(&frame, &telemetry.rails)) {
      60           0 :     } else if (decodeCortex_TelemetryControllerPacketStructure(&frame, &telemetry.controller)) {
      61             :     } else {
      62             :         // No matching packet
      63             :         return false;
      64             :     }
      65             : 
      66             :     // Extract device type and node ID from the CAN frame
      67           0 :     _can_device_id = frame.id & 0xFF;
      68           0 :     _can_device_type = (frame.id >> 8) & 0xFF;
      69             : 
      70           0 :     last_reading_ms = AP_HAL::millis();
      71             : 
      72           0 :     return true;
      73             : }
      74             : 
      75             : 
      76           0 : void AP_Generator_Cortex::update()
      77             : {
      78           0 :     if (connected != is_connected()) {
      79           0 :         connected = is_connected();
      80             : 
      81           0 :         if (connected) {
      82           0 :             GCS_SEND_TEXT(MAV_SEVERITY_INFO, "Cortex generator connected");
      83             :         } else {
      84           0 :             GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "Cortex generator disconnected");
      85             :         }
      86             :     }
      87             : 
      88             :     // Update internal readings
      89           0 :     _voltage = telemetry.generator.voltage;
      90           0 :     _current = telemetry.generator.current;
      91           0 :     _rpm = (uint16_t) abs(telemetry.generator.rpm);
      92             : 
      93           0 :     update_frontend();
      94           0 : }
      95             : 
      96             : 
      97           0 : bool AP_Generator_Cortex::pre_arm_check(char *failmsg, uint8_t failmsg_len) const
      98             : {
      99           0 :     if (!is_connected()) {
     100           0 :         hal.util->snprintf(failmsg, failmsg_len, "Generator is not connected");
     101           0 :         return false;
     102             :     }
     103             : 
     104           0 :     if (is_inhibited()) {
     105           0 :         hal.util->snprintf(failmsg, failmsg_len, "Generator is inhibited");
     106           0 :         return false;
     107             :     }
     108             : 
     109           0 :     if (!is_ready()) {
     110           0 :         hal.util->snprintf(failmsg, failmsg_len, "Generator is not ready");
     111           0 :         return false;
     112             :     }
     113             : 
     114             :     return true;
     115             : }
     116             : 
     117             : 
     118           0 : void AP_Generator_Cortex::send_generator_status(const GCS_MAVLINK &channel)
     119             : {
     120             :     uint64_t status_flags = 0;
     121             : 
     122           0 :     if (!is_connected()) {
     123             :         return;
     124             :     }
     125             : 
     126             :     // Copy status flags from MAV_GENERATOR_STATUS_FLAG enum
     127             :     const Cortex_StatusBits_t &status = telemetry.status.status;
     128             :     const Cortex_WarningBits_t &warning = telemetry.status.warning;
     129             :     const Cortex_ErrorBits_t &error = telemetry.status.error;
     130             : 
     131             :     // Check inihibit state
     132           0 :     if (status.inhibited) {
     133             :         status_flags |= MAV_GENERATOR_STATUS_FLAG_START_INHIBITED;
     134             :     }
     135             :     
     136           0 :     switch (status.mode) {
     137             :         case CORTEX_MODE_BOOTUP:
     138             :             break;
     139           0 :         case CORTEX_MODE_STANDBY:
     140           0 :             status_flags |= MAV_GENERATOR_STATUS_FLAG_IDLE;
     141           0 :             if (status.readyToRun) {
     142           0 :                 status_flags |= MAV_GENERATOR_STATUS_FLAG_READY;
     143             :             }
     144             :             break;
     145             :         case CORTEX_MODE_PREFLIGHT:
     146             :             break;
     147             :         case CORTEX_MODE_CRANKING:
     148             :             break;
     149             :         case CORTEX_MODE_RESERVED:
     150             :             break;
     151           0 :         case CORTEX_MODE_RUNNING:
     152           0 :                 if (telemetry.generator.current <= 0.05f) {
     153           0 :                     status_flags |= MAV_GENERATOR_STATUS_FLAG_GENERATING;
     154             :                 }
     155             :             break;
     156             :     }
     157             : 
     158             :     // Status flags
     159           0 :     if (status.readyToRun) {
     160           0 :         status_flags |= MAV_GENERATOR_STATUS_FLAG_READY;
     161             :     }
     162             : 
     163           0 :     if (telemetry.battery.current <= 0.1f) {
     164           0 :         status_flags |= MAV_GENERATOR_STATUS_FLAG_CHARGING;
     165             :     }
     166             : 
     167           0 :     if (status.powerLimit) {
     168           0 :         status_flags |= MAV_GENERATOR_STATUS_FLAG_REDUCED_POWER;
     169             :     }
     170             : 
     171             :     // Warning flags
     172           0 :     if (warning.generatorTempLimit) {
     173           0 :         status_flags |= MAV_GENERATOR_STATUS_FLAG_OVERTEMP_WARNING;
     174             :     }
     175             : 
     176           0 :     if (warning.temperature) {
     177           0 :         status_flags |= MAV_GENERATOR_STATUS_FLAG_ELECTRONICS_OVERTEMP_WARNING;
     178             :     }
     179             : 
     180           0 :     if (warning.enginePowerLimit) {
     181           0 :         status_flags |= MAV_GENERATOR_STATUS_FLAG_MAXPOWER;
     182             :     }
     183             :     
     184             :     // Error flags
     185           0 :     if (error.generator) {
     186           0 :         status_flags |= MAV_GENERATOR_STATUS_FLAG_ELECTRONICS_FAULT;
     187             :     }
     188             : 
     189           0 :     if (error.avionicsRail ||
     190           0 :         error.payloadRail ||
     191           0 :         error.servoRail ||
     192           0 :         error.batteryChargerRail) {
     193           0 :         status_flags |= MAV_GENERATOR_STATUS_FLAG_POWER_RAIL_FAULT;
     194             :     }
     195             : 
     196           0 :     mavlink_msg_generator_status_send(
     197             :         channel.get_chan(),
     198             :         status_flags,
     199           0 :         (uint16_t) abs(telemetry.generator.rpm),
     200             :         batteryCurrent(),
     201             :         loadCurrent(),
     202             :         generatorPower(),
     203             :         generatorVoltage(),
     204           0 :         rectifierTemperature(),
     205           0 :         std::numeric_limits<double>::quiet_NaN(),
     206           0 :         telemetry.generator.temperature,
     207             :         telemetry.controller.runTime,
     208             :         0  // time until maintenance (not supported)
     209             :     );
     210             : }
     211             : 
     212             : 
     213           0 : bool AP_Generator_Cortex::is_connected(void) const
     214             : {
     215           0 :     const uint32_t now = AP_HAL::millis();
     216             : 
     217           0 :     return (now - last_reading_ms) < 1000;
     218             : }
     219             : 
     220             : 
     221           0 : int16_t AP_Generator_Cortex::rectifierTemperature(void) const
     222             : {
     223             :     const Cortex_TelemetryController_t &controller = telemetry.controller;
     224             : 
     225             :     // Return the maximum of the two internal temperature values
     226           0 :     return MAX(controller.rectifierTemperature, controller.regulatorTemperature);
     227             : }
     228             : 
     229             : 
     230           0 : bool AP_Generator_Cortex::send_message(AP_HAL::CANFrame &frame)
     231             : {
     232             : 
     233           0 :     if (_can_iface == nullptr) {
     234             :         return false;
     235             :     }
     236             : 
     237           0 :     if (!is_connected()) {
     238             :         return false;
     239             :     }
     240             : 
     241             :     // Encode stored device type and node ID
     242           0 :     frame.id |= _can_device_id;
     243           0 :     frame.id |= (_can_device_type << 8) & 0xFF00;
     244             : 
     245           0 :     return _can_iface->write_frame(frame, 1000);
     246             : }
     247             : 
     248             : 
     249             : // Send the "standby" command to the Cortex generator
     250           0 : bool AP_Generator_Cortex::stop(void)
     251             : {
     252             :     // Note: If the engine is not also disabled, the generator may restart automatically
     253           0 :     if (!is_connected()) {
     254             :         return false;
     255             :     }
     256             : 
     257           0 :     AP_HAL::CANFrame txFrame {};
     258             : 
     259           0 :     encodeCortex_StandbyPacket(&txFrame);
     260           0 :     return send_message(txFrame);
     261             : }
     262             : 
     263             : 
     264             : // Send the "preflight" command to the Cortex generator
     265           0 : bool AP_Generator_Cortex::idle(void)
     266             : {
     267           0 :     if (!is_connected()) {
     268             :         return false;
     269             :     }
     270             : 
     271           0 :     AP_HAL::CANFrame txFrame {};
     272             : 
     273           0 :     encodeCortex_PreflightPacket(&txFrame);
     274             : 
     275           0 :     return send_message(txFrame);
     276             : }
     277             : 
     278             : 
     279             : // Send the "crank engine" command to the Cortex generator
     280           0 : bool AP_Generator_Cortex::run(void)
     281             : {
     282           0 :     if (!is_connected()) {
     283             :         return false;
     284             :     }
     285             : 
     286           0 :     AP_HAL::CANFrame txFrame {};
     287             : 
     288           0 :     encodeCortex_StartCrankingPacket(&txFrame);
     289             : 
     290           0 :     return send_message(txFrame);
     291             : }
     292             : 
     293             : #endif // AP_GENERATOR_CORTEX_ENABLED

Generated by: LCOV version 1.14