LCOV - code coverage report
Current view: top level - AP_Generator - AP_Generator_IE_2400.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 227 253 89.7 %
Date: 2026-09-09 11:02:08 Functions: 17 17 100.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             : #pragma GCC optimize("Os")
      17             : 
      18             : #include "AP_Generator_IE_2400.h"
      19             : 
      20             : #if AP_GENERATOR_IE_2400_ENABLED
      21             : 
      22             : #include <AP_Logger/AP_Logger.h>
      23             : #include <GCS_MAVLink/GCS.h>
      24             : 
      25             : extern const AP_HAL::HAL& hal;
      26             : 
      27           4 : void AP_Generator_IE_2400::init()
      28             : {
      29             :     // Call init from base class to do common setup
      30           4 :     AP_Generator_IE_FuelCell::init();
      31             : 
      32             :     // Tell frontend what measurements are available for this generator
      33           4 :     _frontend._has_current = true;
      34           4 :     _frontend._has_consumed_energy = true;
      35           4 :     _frontend._has_fuel_remaining = true;
      36           4 : }
      37             : 
      38             : // Assigns the unit specific measurements once a valid sentence is obtained
      39         719 : void AP_Generator_IE_2400::assign_measurements(const uint32_t now)
      40             : {
      41             : 
      42         719 :     if (_type == PacketType::V2_INFO) {
      43             :         // Got info packet
      44          31 :         if (_had_info) {
      45             :             // Not expecting the version to change
      46             :             return;
      47             :         }
      48           2 :         _had_info = true;
      49             : 
      50             :         // Info tells us the protocol version, so lock on straight away
      51           2 :         if (_version == ProtocolVersion::DETECTING) {
      52           2 :             if (strcmp(_info.Protocol_version, "4") == 0) {
      53           2 :                 _version = ProtocolVersion::V2;
      54             :             } else {
      55             :                 // Got a valid info packet, but don't know this protocol version
      56             :                 // Give up
      57           0 :                 _version = ProtocolVersion::UNKNOWN;
      58             :             }
      59             :         }
      60             : 
      61           2 :         GCS_SEND_TEXT(MAV_SEVERITY_INFO, "IE Fuel cell detected, PCM: %s, Ver: %s, SN: %s", _info.PCM_number, _info.Software_version, _info.Serial_number);
      62             : 
      63           2 :         return;
      64             :     }
      65             : 
      66             :     // Try and lock onto version
      67         688 :     if (_version == ProtocolVersion::DETECTING) {
      68             :         ProtocolVersion new_version = ProtocolVersion::DETECTING;
      69          64 :         switch (_type) {
      70           0 :             case PacketType::NONE:
      71             :                 // Should not get a valid packet of type none
      72           0 :                 _last_version_packet_count = 0;
      73           0 :                 return;
      74             : 
      75          44 :             case PacketType::LEGACY_DATA:
      76             :                 new_version = ProtocolVersion::LEGACY;
      77          44 :                 break;
      78             : 
      79          20 :             case PacketType::V2_DATA:
      80             :             case PacketType::V2_INFO:
      81             :                 new_version = ProtocolVersion::V2;
      82          20 :                 break;
      83             :         }
      84             : 
      85          64 :         if (_last_version == new_version) {
      86          60 :             _last_version_packet_count++;
      87             :         } else {
      88           4 :             _last_version_packet_count = 0;
      89             :         }
      90          64 :         _last_version = new_version;
      91             : 
      92             :         // If received 20 valid packets for a single protocol version then lock on
      93          64 :         if (_last_version_packet_count > 20) {
      94           2 :             _version = new_version;
      95           4 :             GCS_SEND_TEXT(MAV_SEVERITY_INFO, "Generator: IE using %s protocol", (_version == ProtocolVersion::V2) ? "V2" : "legacy" );
      96             : 
      97             :         } else {
      98             :             // Don't record any data during version detection
      99             :             return;
     100             :         }
     101             :     }
     102             : 
     103         626 :     if (_type == PacketType::V2_DATA) {
     104         326 :         memcpy(&_valid_V2, &_parsed_V2, sizeof(_valid_V2));
     105             :     }
     106             : 
     107             :     // Update internal fuel cell state
     108         626 :     _pwr_out = _parsed.pwr_out;
     109         626 :     _spm_pwr = _parsed.spm_pwr;
     110         626 :     _battery_pwr = _parsed.battery_pwr;
     111             : 
     112         626 :     _state = (State)_parsed.state;
     113         626 :     _v2_state = (V2_State)_parsed.state;
     114         626 :     _err_code = _parsed.err_code;
     115         626 :     _sub_err_code = _parsed.sub_err_code;
     116             : 
     117         626 :     _fuel_remaining = _fuel_rem;
     118             : 
     119             :     // Update battery voltage
     120         626 :     _voltage = _parsed.battery_volt;
     121             : 
     122             :     /* Calculate battery current. Convention: +current battery is discharging, -current
     123             :     battery is charging.  This is aligned with normal AP behaviour.  This is the opposite
     124             :     of IE's convention hence *-1 */
     125         626 :     if (_parsed.battery_volt > 0) {
     126         624 :         _current = -1 * _battery_pwr / _parsed.battery_volt;
     127             :     } else {
     128           2 :         _current = 0;
     129             :     }
     130             : 
     131             :     // Calculate consumed current
     132         626 :     _consumed_mah += _current * (now - _last_time_ms) * AMS_TO_MAH;
     133             : 
     134         626 :     _last_time_ms = now;
     135             : }
     136             : 
     137             : // Process characters received and extract terms for IE 2.4kW
     138        6701 : void AP_Generator_IE_2400::decode_latest_term()
     139             : {
     140             :     // Null terminate and move onto the next term
     141        6701 :     _term[_term_offset] = 0;
     142        6701 :     _term_offset = 0;
     143        6701 :     _term_number++;
     144        6701 :     _type = PacketType::NONE;
     145             : 
     146        6701 :     if (_start_char == '<') {
     147        6546 :         decode_data_packet();
     148             : 
     149         155 :     } else if (_start_char == '[') {
     150         155 :         decode_info_packet();
     151             : 
     152             :     } else {
     153           0 :         _sentence_valid = false;
     154             : 
     155             :     }
     156        6701 : }
     157             : 
     158        6546 : void AP_Generator_IE_2400::decode_data_packet()
     159             : {
     160             :     // Try and decode both protocol versions until locked on
     161        6546 :     if ((_version == ProtocolVersion::LEGACY) || (_version == ProtocolVersion::DETECTING)) {
     162        2634 :         decode_legacy_data();
     163             :     }
     164        6546 :     if ((_version == ProtocolVersion::V2) || (_version == ProtocolVersion::DETECTING)) {
     165        4460 :         decode_v2_data();
     166             :     }
     167        6546 : }
     168             : 
     169        2634 : void AP_Generator_IE_2400::decode_legacy_data()
     170             : {
     171        2634 :     switch (_term_number) {
     172         362 :         case 1: {
     173             :             // Float
     174         362 :             _parsed.tank_bar = strtof(_term, NULL);
     175             : 
     176             :             // Scale tank pressure linearly to a value between 0 and 1
     177             :             // Min = 5 bar, max = 300 bar, PRESS_GRAD = 1/295.
     178             :             const float PRESS_GRAD = 0.003389830508f;
     179         362 :             _fuel_rem = constrain_float((_parsed.tank_bar-5)*PRESS_GRAD,0,1);
     180         362 :             break;
     181             :         }
     182         362 :         case 2:
     183             :             // Float
     184         362 :             _parsed.battery_volt = strtof(_term, NULL);
     185         362 :             break;
     186             : 
     187         362 :         case 3:
     188             :             // Signed int base 10
     189         362 :             _parsed.pwr_out = strtol(_term, nullptr, 10);
     190         362 :             break;
     191             : 
     192         362 :         case 4:
     193             :             // Unsigned int base 10
     194         362 :             _parsed.spm_pwr = strtoul(_term, nullptr, 10);
     195         362 :             break;
     196             : 
     197         362 :         case 5:
     198             :             // Signed int base 10
     199         362 :             _parsed.battery_pwr = strtol(_term, nullptr, 10);
     200         362 :             break;
     201             : 
     202         362 :         case 6:
     203             :             // Unsigned int base 10
     204         362 :             _parsed.state = strtoul(_term, nullptr, 10);
     205         362 :             break;
     206             : 
     207         362 :         case 7:
     208             :             // Unsigned int base 10
     209         362 :             _parsed.err_code = strtoul(_term, nullptr, 10);
     210             :             // Sentence only declared valid when we have the expected number of terms
     211         362 :             _sentence_valid = true;
     212         362 :             _type = PacketType::LEGACY_DATA;
     213         362 :             break;
     214             : 
     215         100 :         default:
     216             :             // We have received more terms than, something has gone wrong with telemetry data, mark invalid sentence
     217         100 :             _sentence_valid = false;
     218         100 :             break;
     219             :     }
     220        2634 : }
     221             : 
     222        4460 : void AP_Generator_IE_2400::decode_v2_data()
     223             : {
     224        4460 :     switch (_term_number) {
     225         390 :         case 1:
     226         390 :             _fuel_rem = strtof(_term, NULL) * 0.01;
     227         390 :             break;
     228             : 
     229         390 :         case 2:
     230         390 :             _parsed_V2.inlet_press = strtof(_term, NULL);
     231         390 :             break;
     232             : 
     233         390 :         case 3:
     234         390 :             _parsed.battery_volt = strtof(_term, NULL);
     235         390 :             break;
     236             : 
     237         390 :         case 4:
     238         390 :             _parsed.pwr_out = strtol(_term, nullptr, 10);
     239         390 :             break;
     240             : 
     241         390 :         case 5:
     242         390 :             _parsed.spm_pwr = strtoul(_term, nullptr, 10);
     243         390 :             break;
     244             : 
     245         390 :         case 6:
     246         390 :             _parsed_V2.unit_fault = strtoul(_term, nullptr, 10);
     247         390 :             break;
     248             : 
     249         390 :         case 7:
     250         390 :             _parsed.battery_pwr = strtol(_term, nullptr, 10);
     251         390 :             break;
     252             : 
     253         346 :         case 8:
     254         346 :             _parsed.state = strtoul(_term, nullptr, 10);
     255         346 :             break;
     256             : 
     257         346 :         case 9:
     258         346 :             _parsed.err_code = strtoul(_term, nullptr, 10);
     259         346 :             break;
     260             : 
     261         346 :         case 10:
     262         346 :             _parsed.sub_err_code = strtoul(_term, nullptr, 10);
     263         346 :             break;
     264             : 
     265         346 :         case 11:
     266         346 :             strncpy(_parsed_V2.info_str, _term, ARRAY_SIZE(_parsed_V2.info_str));
     267         346 :             break;
     268             : 
     269         346 :         case 12: {
     270             :             // The inverted checksum is sent, un-invert it
     271         346 :             uint8_t checksum = ~strtoul(_term, nullptr, 10);
     272             : 
     273             :             // Sent checksum only included characters up to the checksum term
     274             :             // Add on the checksum terms to match our running total
     275        1044 :             for (uint8_t i = 0; i < ARRAY_SIZE(_term); i++) {
     276        1044 :                 if (_term[i] == 0) {
     277             :                     break;
     278             :                 }
     279         698 :                 checksum += _term[i];
     280             :             }
     281             : 
     282         346 :             _sentence_valid = checksum == _checksum;
     283         346 :             _type = PacketType::V2_DATA;
     284         346 :             break;
     285             :         }
     286             : 
     287           0 :         default:
     288             :             // We have received more terms than, something has gone wrong with telemetry data, mark invalid sentence
     289           0 :             _sentence_valid = false;
     290           0 :             break;
     291             :     }
     292        4460 : }
     293             : 
     294             : 
     295         155 : void AP_Generator_IE_2400::decode_info_packet()
     296             : {
     297             : 
     298         155 :     switch (_term_number) {
     299          31 :         case 1:
     300             :             // PCM software number
     301          31 :             strncpy(_info.PCM_number, _term, ARRAY_SIZE(_info.PCM_number));
     302          31 :             break;
     303             : 
     304          31 :         case 2:
     305             :             // Software version
     306          31 :             strncpy(_info.Software_version, _term, ARRAY_SIZE(_info.Software_version));
     307          31 :             break;
     308             : 
     309          31 :         case 3:
     310             :             // protocol version
     311          31 :             strncpy(_info.Protocol_version, _term, ARRAY_SIZE(_info.Protocol_version));
     312          31 :             break;
     313             : 
     314          31 :         case 4:
     315             :             // Hardware serial number
     316          31 :             strncpy(_info.Serial_number, _term, ARRAY_SIZE(_info.Serial_number));
     317          31 :             break;
     318             : 
     319          31 :         case 5: {
     320             :             // The inverted checksum is sent, un-invert it
     321          31 :             uint8_t checksum = ~strtoul(_term, nullptr, 10);
     322             : 
     323             :             // Sent checksum only included characters up to the checksum term
     324             :             // Add on the checksum terms to match our running total
     325          62 :             for (uint8_t i = 0; i < ARRAY_SIZE(_term); i++) {
     326          62 :                 if (_term[i] == 0) {
     327             :                     break;
     328             :                 }
     329          31 :                 checksum += _term[i];
     330             :             }
     331             : 
     332          31 :             _sentence_valid = checksum == _checksum;
     333          31 :             _type = PacketType::V2_INFO;
     334          31 :             break;
     335             :         }
     336             : 
     337           0 :         default:
     338             :             // We have received more terms than, something has gone wrong with telemetry data, mark invalid sentence
     339           0 :             _sentence_valid = false;
     340           0 :             break;
     341             :     }
     342             : 
     343         155 : }
     344             : 
     345             : // Check for failsafes
     346        1472 : AP_BattMonitor::Failsafe AP_Generator_IE_2400::update_failsafes() const
     347             : {
     348             :     // Check for error codes that lead to critical action battery monitor failsafe
     349        1472 :     if (is_critical_error(_err_code)) {
     350             :         return AP_BattMonitor::Failsafe::Critical;
     351             :     }
     352             : 
     353             :     // Check for error codes that lead to low action battery monitor failsafe
     354        1471 :     if (is_low_error(_err_code)) {
     355           1 :         return AP_BattMonitor::Failsafe::Low;
     356             :     }
     357             : 
     358             :     return AP_BattMonitor::Failsafe::None;
     359             : }
     360             : 
     361             : // Check for error codes that are deemed critical
     362        1644 : bool AP_Generator_IE_2400::is_critical_error(const uint32_t err_in) const
     363             : {
     364             :     // V2 protocol
     365        1644 :     if (_version == ProtocolVersion::V2) {
     366         837 :         return err_in >= 30;
     367             :     }
     368             : 
     369             :     // V1 protocol
     370         807 :     switch ((ErrorCode)err_in) {
     371             :         // Error codes that lead to critical action battery monitor failsafe
     372             :         case ErrorCode::BATTERY_CRITICAL:
     373             :         case ErrorCode::PRESSURE_CRITICAL:
     374             :         case ErrorCode::SYSTEM_CRITICAL:
     375             :             return true;
     376             : 
     377         807 :         default:
     378             :             // Minor internal error is always ignored and caught by the default
     379         807 :             return false;
     380             :     }
     381             : }
     382             : 
     383             : // Check for error codes that are deemed severe and would be cause to trigger a battery monitor low failsafe action
     384        1641 : bool AP_Generator_IE_2400::is_low_error(const uint32_t err_in) const
     385             : {
     386             :     // V2 protocol
     387        1641 :     if (_version == ProtocolVersion::V2) {
     388         834 :         return (err_in > 20) && (err_in < 30);
     389             :     }
     390             : 
     391             :     // V1 protocol
     392         807 :     switch ((ErrorCode)err_in) {
     393             :         // Error codes that lead to critical action battery monitor failsafe
     394             :         case ErrorCode::START_DENIED:
     395             :         case ErrorCode::PRESSURE_ALERT:
     396             :         case ErrorCode::BATTERY_LOW:
     397             :         case ErrorCode::PRESSURE_LOW:
     398             :         case ErrorCode::SPM_LOST:
     399             :             return true;
     400             : 
     401         804 :         default:
     402             :             // Minor internal error is always ignored and caught by the default
     403         804 :             return false;
     404             :     }
     405             : }
     406             : 
     407             : // Check error codes and populate message with error code
     408         172 : bool AP_Generator_IE_2400::check_for_err_code(char* msg_txt, uint8_t msg_len) const
     409             : {
     410             :     // Check if we have received an error code
     411         172 :     if (!is_critical_error(_err_code) && !is_low_error(_err_code)) {
     412             :         return false;
     413             :     }
     414             : 
     415           4 :     if (_version == ProtocolVersion::V2) {
     416           2 :         hal.util->snprintf(msg_txt, msg_len, "Fuel cell err %u.%u: %s", (unsigned)_err_code, (unsigned)_sub_err_code, _valid_V2.info_str);
     417           2 :         return true;
     418             :     }
     419             : 
     420           2 :     hal.util->snprintf(msg_txt, msg_len, "Fuel cell err code <%u>", (unsigned)_err_code);
     421           2 :     return true;
     422             : }
     423             : 
     424           2 : bool AP_Generator_IE_2400::check_for_warning_code(char* msg_txt, uint8_t msg_len) const
     425             : {
     426           2 :     if (_err_code == 0) {
     427             :         // No error nothing to do.
     428             :         return false;
     429             :     }
     430           0 :     if (is_critical_error(_err_code) || is_low_error(_err_code)) {
     431             :         // Critical or low error are already reported
     432             :         return false;
     433             :     }
     434             : 
     435           0 :     switch (_version) {
     436             :         case ProtocolVersion::DETECTING:
     437             :         case ProtocolVersion::UNKNOWN:
     438             :             break;
     439             : 
     440           0 :         case ProtocolVersion::LEGACY:
     441           0 :             if ((ErrorCode)_err_code == ErrorCode::REDUCED_POWER) {
     442           0 :                 hal.util->snprintf(msg_txt, msg_len, "Fuel cell reduced power <%u>", (unsigned)_err_code);
     443           0 :                 return true;
     444             :             }
     445             :             break;
     446             : 
     447           0 :         case ProtocolVersion::V2:
     448           0 :             hal.util->snprintf(msg_txt, msg_len, "Fuel cell warning %u.%u: %s", (unsigned)_err_code, (unsigned)_sub_err_code, _valid_V2.info_str);
     449           0 :             return true;
     450             :     }
     451             : 
     452           0 :     hal.util->snprintf(msg_txt, msg_len, "Fuel cell warning code <%u>", (unsigned)_err_code);
     453           0 :     return true;
     454             : }
     455             : 
     456             : // Check if we should notify on any change of fuel cell state
     457        3392 : void AP_Generator_IE_2400::check_status(const uint32_t now)
     458             : {
     459        3392 :     if (ErrorCode(_err_code) == ErrorCode::REDUCED_POWER) {
     460           0 :         if (now - _last_low_power_warning_ms > 5000) {
     461           0 :             gcs().send_text(MAV_SEVERITY_INFO, "Fuel cell: reduced power; conditioning needed?");
     462           0 :             _last_low_power_warning_ms = now;
     463             :         }
     464             :     }
     465        3392 :     return AP_Generator_IE_FuelCell::check_status(now);
     466             : }
     467             : 
     468             : #if HAL_LOGGING_ENABLED
     469             : // log generator status to the onboard log
     470        3392 : void AP_Generator_IE_2400::log_write()
     471             : {
     472             : #define MASK_LOG_ANY    0xFFFF
     473        3392 :     if (!AP::logger().should_log(MASK_LOG_ANY)) {
     474             :         return;
     475             :     }
     476             : 
     477        3392 :     switch (_version) {
     478             :         case ProtocolVersion::DETECTING:
     479             :         case ProtocolVersion::UNKNOWN:
     480             :             return;
     481             : 
     482        1516 :         case ProtocolVersion::LEGACY:
     483             :             // @LoggerMessage: IE24
     484             :             // @Description: Intelligent Energy Fuel Cell generator (legacy protocol)
     485             :             // @URL: https://ardupilot.club/copter/docs/common-ie24-fuelcell.html
     486             :             // @Field: TimeUS: Time since system startup
     487             :             // @Field: FUEL: Fuel remaining
     488             :             // @Field: SPMPWR: stack power module power draw
     489             :             // @Field: POUT: output power
     490             :             // @Field: ERR: error codes
     491             :             // @FieldValueEnum: ERR: AP_Generator_IE_2400::ErrorCode
     492        3032 :             AP::logger().WriteStreaming(
     493             :                 "IE24",
     494             :                 "TimeUS,FUEL,SPMPWR,POUT,ERR",
     495             :                 "s%WW-",
     496             :                 "F2---",
     497             :                 "Qfiii",
     498             :                 AP_HAL::micros64(),
     499        1516 :                 _fuel_remaining,
     500        1516 :                 _spm_pwr,
     501        1516 :                 _pwr_out,
     502             :                 _err_code
     503             :                 );
     504        1516 :             break;
     505             : 
     506        1646 :         case ProtocolVersion::V2:
     507             :             // @LoggerMessage: IEFC
     508             :             // @Description: Intelligent Energy Fuel Cell generator
     509             :             // @URL: https://ardupilot.club/copter/docs/common-ie24-fuelcell.html
     510             :             // @Field: TimeUS: Time since system startup
     511             :             // @Field: Tank: Fuel remaining
     512             :             // @Field: Inlet: Inlet pressure
     513             :             // @Field: BattV: battery voltage
     514             :             // @Field: OutPwr: output power
     515             :             // @Field: SPMPwr: stack power module power draw
     516             :             // @Field: FNo: fault number
     517             :             // @Field: BPwr: battery power draw
     518             :             // @Field: State: generator state
     519             :             // @FieldValueEnum: State: AP_Generator_IE_2400::V2_State
     520             :             // @Field: F1: error code
     521             :             // @FieldValueEnum: F1: AP_Generator_IE_2400::ErrorCode
     522             :             // @Field: F2: sub-error code
     523        3292 :             AP::logger().WriteStreaming(
     524             :                 "IEFC",
     525             :                 "TimeUS,Tank,Inlet,BattV,OutPwr,SPMPwr,FNo,BPwr,State,F1,F2",
     526             :                 "s%-vWW-W---",
     527             :                 "F----------",
     528             :                 "QfffhHBhBII",
     529             :                 AP_HAL::micros64(),
     530        1646 :                 _fuel_remaining,
     531        1646 :                 _valid_V2.inlet_press,
     532        1646 :                 _voltage,
     533        1646 :                 _pwr_out,
     534        1646 :                 _spm_pwr,
     535        1646 :                 _valid_V2.unit_fault,
     536        1646 :                 _battery_pwr,
     537        1646 :                 uint8_t(_v2_state),
     538             :                 _err_code,
     539             :                 _sub_err_code
     540             :                 );
     541        1646 :             break;
     542             :     }
     543             : 
     544             : }
     545             : #endif  // HAL_LOGGING_ENABLED
     546             : 
     547             : // Return true is fuel cell is in running state suitable for arming
     548         182 : bool AP_Generator_IE_2400::is_running() const
     549             : {
     550         182 :     switch (_version) {
     551             :         case ProtocolVersion::DETECTING:
     552             :         case ProtocolVersion::UNKNOWN:
     553             :             return false;
     554             : 
     555          82 :         case ProtocolVersion::LEGACY:
     556             :             // Can use the base class method
     557          82 :             return AP_Generator_IE_FuelCell::is_running();
     558             : 
     559          92 :         case ProtocolVersion::V2:
     560          92 :             return _v2_state == V2_State::Running;
     561             :     }
     562             : 
     563             :     return false;
     564             : }
     565             : 
     566             : // Lookup table for running state.  State code is the same for all IE units.
     567             : const AP_Generator_IE_2400::Lookup_State_V2 AP_Generator_IE_2400::lookup_state_V2[] = {
     568             :     { V2_State::FCPM_Off, "FCPM Off"},
     569             :     { V2_State::Starting, "Starting"},
     570             :     { V2_State::Running, "Running"},
     571             :     { V2_State::Stopping, "Stopping"},
     572             :     { V2_State::Go_to_Sleep, "Sleep"},
     573             : };
     574             : 
     575             : // Print msg to user updating on state change
     576        3392 : void AP_Generator_IE_2400::update_state_msg()
     577             : {
     578        3392 :     switch (_version) {
     579             :         case ProtocolVersion::DETECTING:
     580             :         case ProtocolVersion::UNKNOWN:
     581             :             break;
     582             : 
     583        1516 :         case ProtocolVersion::LEGACY:
     584             :             // Can use the base class method
     585        1516 :             AP_Generator_IE_FuelCell::update_state_msg();
     586        1516 :             break;
     587             : 
     588        1646 :         case ProtocolVersion::V2: {
     589             :             // If fuel cell state has changed send gcs message
     590        1646 :             if (_v2_state != _last_v2_state) {
     591          15 :                 for (const struct Lookup_State_V2 entry : lookup_state_V2) {
     592          14 :                     if (_v2_state == entry.option) {
     593           3 :                         GCS_SEND_TEXT(MAV_SEVERITY_INFO, "Generator: %s", entry.msg_txt);
     594           3 :                         break;
     595             :                     }
     596             :                 }
     597           4 :                 _last_v2_state = _v2_state;
     598             :             }
     599             :             break;
     600             :         }
     601             :     }
     602        3392 : }
     603             : 
     604             : #if HAL_GCS_ENABLED
     605             : // Get the MAV_SEVERITY level of a given error code
     606           2 : MAV_SEVERITY AP_Generator_IE_2400::get_mav_severity(uint32_t err_code) const
     607             : {
     608           2 :     if (err_code <= 9) {
     609             :         return MAV_SEVERITY_INFO;
     610             :     }
     611           2 :     if (err_code <= 20) {
     612           0 :         return MAV_SEVERITY_WARNING;
     613             :     }
     614             :     return MAV_SEVERITY_CRITICAL;
     615             : }
     616             : #endif // HAL_GCS_ENABLED
     617             : 
     618             : #endif  // AP_GENERATOR_IE_2400_ENABLED

Generated by: LCOV version 1.14