Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/master/libraries/AP_BattMonitor/AP_BattMonitor.cpp
Views: 1798
#include "AP_BattMonitor_config.h"12#if AP_BATTERY_ENABLED34#include "AP_BattMonitor.h"56#include "AP_BattMonitor_Analog.h"7#include "AP_BattMonitor_SMBus.h"8#include "AP_BattMonitor_SMBus_Solo.h"9#include "AP_BattMonitor_SMBus_Generic.h"10#include "AP_BattMonitor_SMBus_Maxell.h"11#include "AP_BattMonitor_SMBus_Rotoye.h"12#include "AP_BattMonitor_Bebop.h"13#include "AP_BattMonitor_ESC.h"14#include "AP_BattMonitor_SMBus_SUI.h"15#include "AP_BattMonitor_SMBus_NeoDesign.h"16#include "AP_BattMonitor_Sum.h"17#include "AP_BattMonitor_FuelFlow.h"18#include "AP_BattMonitor_FuelLevel_PWM.h"19#include "AP_BattMonitor_Generator.h"20#include "AP_BattMonitor_EFI.h"21#include "AP_BattMonitor_INA2xx.h"22#include "AP_BattMonitor_INA239.h"23#include "AP_BattMonitor_INA3221.h"24#include "AP_BattMonitor_LTC2946.h"25#include "AP_BattMonitor_Torqeedo.h"26#include "AP_BattMonitor_FuelLevel_Analog.h"27#include "AP_BattMonitor_Synthetic_Current.h"28#include "AP_BattMonitor_AD7091R5.h"29#include "AP_BattMonitor_Scripting.h"3031#include <AP_HAL/AP_HAL.h>3233#if HAL_ENABLE_DRONECAN_DRIVERS34#include "AP_BattMonitor_DroneCAN.h"35#endif3637#include <AP_Vehicle/AP_Vehicle_Type.h>38#include <AP_Logger/AP_Logger.h>39#include <GCS_MAVLink/GCS.h>40#include <AP_Notify/AP_Notify.h>4142extern const AP_HAL::HAL& hal;4344AP_BattMonitor *AP_BattMonitor::_singleton;4546const AP_Param::GroupInfo AP_BattMonitor::var_info[] = {47// 0 - 18, 20- 22 used by old parameter indexes4849// Monitor 15051// @Group: _52// @Path: AP_BattMonitor_Params.cpp53AP_SUBGROUPINFO(_params[0], "_", 23, AP_BattMonitor, AP_BattMonitor_Params),5455// @Group: _56// @Path: AP_BattMonitor_Analog.cpp57// @Group: _58// @Path: AP_BattMonitor_SMBus.cpp59// @Group: _60// @Path: AP_BattMonitor_Sum.cpp61// @Group: _62// @Path: AP_BattMonitor_DroneCAN.cpp63// @Group: _64// @Path: AP_BattMonitor_FuelLevel_Analog.cpp65// @Group: _66// @Path: AP_BattMonitor_Synthetic_Current.cpp67// @Group: _68// @Path: AP_BattMonitor_INA2xx.cpp69// @Group: _70// @Path: AP_BattMonitor_ESC.cpp71// @Group: _72// @Path: AP_BattMonitor_INA239.cpp73// @Group: _74// @Path: AP_BattMonitor_INA3221.cpp75// @Group: _76// @Path: AP_BattMonitor_AD7091R5.cpp77AP_SUBGROUPVARPTR(drivers[0], "_", 41, AP_BattMonitor, backend_var_info[0]),7879#if AP_BATT_MONITOR_MAX_INSTANCES > 180// @Group: 2_81// @Path: AP_BattMonitor_Params.cpp82AP_SUBGROUPINFO(_params[1], "2_", 24, AP_BattMonitor, AP_BattMonitor_Params),8384// @Group: 2_85// @Path: AP_BattMonitor_Analog.cpp86// @Group: 2_87// @Path: AP_BattMonitor_SMBus.cpp88// @Group: 2_89// @Path: AP_BattMonitor_Sum.cpp90// @Group: 2_91// @Path: AP_BattMonitor_DroneCAN.cpp92// @Group: 2_93// @Path: AP_BattMonitor_FuelLevel_Analog.cpp94// @Group: 2_95// @Path: AP_BattMonitor_Synthetic_Current.cpp96// @Group: 2_97// @Path: AP_BattMonitor_INA2xx.cpp98// @Group: 2_99// @Path: AP_BattMonitor_ESC.cpp100// @Group: 2_101// @Path: AP_BattMonitor_INA239.cpp102// @Group: 2_103// @Path: AP_BattMonitor_INA3221.cpp104// @Group: 2_105// @Path: AP_BattMonitor_AD7091R5.cpp106AP_SUBGROUPVARPTR(drivers[1], "2_", 42, AP_BattMonitor, backend_var_info[1]),107#endif108109#if AP_BATT_MONITOR_MAX_INSTANCES > 2110// @Group: 3_111// @Path: AP_BattMonitor_Params.cpp112AP_SUBGROUPINFO(_params[2], "3_", 25, AP_BattMonitor, AP_BattMonitor_Params),113114// @Group: 3_115// @Path: AP_BattMonitor_Analog.cpp116// @Group: 3_117// @Path: AP_BattMonitor_SMBus.cpp118// @Group: 3_119// @Path: AP_BattMonitor_Sum.cpp120// @Group: 3_121// @Path: AP_BattMonitor_DroneCAN.cpp122// @Group: 3_123// @Path: AP_BattMonitor_FuelLevel_Analog.cpp124// @Group: 3_125// @Path: AP_BattMonitor_Synthetic_Current.cpp126// @Group: 3_127// @Path: AP_BattMonitor_INA2xx.cpp128// @Group: 3_129// @Path: AP_BattMonitor_ESC.cpp130// @Group: 3_131// @Path: AP_BattMonitor_INA239.cpp132// @Group: 3_133// @Path: AP_BattMonitor_INA3221.cpp134// @Group: 3_135// @Path: AP_BattMonitor_AD7091R5.cpp136AP_SUBGROUPVARPTR(drivers[2], "3_", 43, AP_BattMonitor, backend_var_info[2]),137#endif138139#if AP_BATT_MONITOR_MAX_INSTANCES > 3140// @Group: 4_141// @Path: AP_BattMonitor_Params.cpp142AP_SUBGROUPINFO(_params[3], "4_", 26, AP_BattMonitor, AP_BattMonitor_Params),143144// @Group: 4_145// @Path: AP_BattMonitor_Analog.cpp146// @Group: 4_147// @Path: AP_BattMonitor_SMBus.cpp148// @Group: 4_149// @Path: AP_BattMonitor_Sum.cpp150// @Group: 4_151// @Path: AP_BattMonitor_DroneCAN.cpp152// @Group: 4_153// @Path: AP_BattMonitor_FuelLevel_Analog.cpp154// @Group: 4_155// @Path: AP_BattMonitor_Synthetic_Current.cpp156// @Group: 4_157// @Path: AP_BattMonitor_INA2xx.cpp158// @Group: 4_159// @Path: AP_BattMonitor_ESC.cpp160// @Group: 4_161// @Path: AP_BattMonitor_INA239.cpp162// @Group: 4_163// @Path: AP_BattMonitor_INA3221.cpp164// @Group: 4_165// @Path: AP_BattMonitor_AD7091R5.cpp166AP_SUBGROUPVARPTR(drivers[3], "4_", 44, AP_BattMonitor, backend_var_info[3]),167#endif168169#if AP_BATT_MONITOR_MAX_INSTANCES > 4170// @Group: 5_171// @Path: AP_BattMonitor_Params.cpp172AP_SUBGROUPINFO(_params[4], "5_", 27, AP_BattMonitor, AP_BattMonitor_Params),173174// @Group: 5_175// @Path: AP_BattMonitor_Analog.cpp176// @Group: 5_177// @Path: AP_BattMonitor_SMBus.cpp178// @Group: 5_179// @Path: AP_BattMonitor_Sum.cpp180// @Group: 5_181// @Path: AP_BattMonitor_DroneCAN.cpp182// @Group: 5_183// @Path: AP_BattMonitor_FuelLevel_Analog.cpp184// @Group: 5_185// @Path: AP_BattMonitor_Synthetic_Current.cpp186// @Group: 5_187// @Path: AP_BattMonitor_INA2xx.cpp188// @Group: 5_189// @Path: AP_BattMonitor_ESC.cpp190// @Group: 5_191// @Path: AP_BattMonitor_INA239.cpp192// @Group: 5_193// @Path: AP_BattMonitor_INA3221.cpp194// @Group: 5_195// @Path: AP_BattMonitor_AD7091R5.cpp196AP_SUBGROUPVARPTR(drivers[4], "5_", 45, AP_BattMonitor, backend_var_info[4]),197#endif198199#if AP_BATT_MONITOR_MAX_INSTANCES > 5200// @Group: 6_201// @Path: AP_BattMonitor_Params.cpp202AP_SUBGROUPINFO(_params[5], "6_", 28, AP_BattMonitor, AP_BattMonitor_Params),203204// @Group: 6_205// @Path: AP_BattMonitor_Analog.cpp206// @Group: 6_207// @Path: AP_BattMonitor_SMBus.cpp208// @Group: 6_209// @Path: AP_BattMonitor_Sum.cpp210// @Group: 6_211// @Path: AP_BattMonitor_DroneCAN.cpp212// @Group: 6_213// @Path: AP_BattMonitor_FuelLevel_Analog.cpp214// @Group: 6_215// @Path: AP_BattMonitor_Synthetic_Current.cpp216// @Group: 6_217// @Path: AP_BattMonitor_INA2xx.cpp218// @Group: 6_219// @Path: AP_BattMonitor_ESC.cpp220// @Group: 6_221// @Path: AP_BattMonitor_INA239.cpp222// @Group: 6_223// @Path: AP_BattMonitor_INA3221.cpp224// @Group: 6_225// @Path: AP_BattMonitor_AD7091R5.cpp226AP_SUBGROUPVARPTR(drivers[5], "6_", 46, AP_BattMonitor, backend_var_info[5]),227#endif228229#if AP_BATT_MONITOR_MAX_INSTANCES > 6230// @Group: 7_231// @Path: AP_BattMonitor_Params.cpp232AP_SUBGROUPINFO(_params[6], "7_", 29, AP_BattMonitor, AP_BattMonitor_Params),233234// @Group: 7_235// @Path: AP_BattMonitor_Analog.cpp236// @Group: 7_237// @Path: AP_BattMonitor_SMBus.cpp238// @Group: 7_239// @Path: AP_BattMonitor_Sum.cpp240// @Group: 7_241// @Path: AP_BattMonitor_DroneCAN.cpp242// @Group: 7_243// @Path: AP_BattMonitor_FuelLevel_Analog.cpp244// @Group: 7_245// @Path: AP_BattMonitor_Synthetic_Current.cpp246// @Group: 7_247// @Path: AP_BattMonitor_INA2xx.cpp248// @Group: 7_249// @Path: AP_BattMonitor_ESC.cpp250// @Group: 7_251// @Path: AP_BattMonitor_INA239.cpp252// @Group: 7_253// @Path: AP_BattMonitor_INA3221.cpp254// @Group: 7_255// @Path: AP_BattMonitor_AD7091R5.cpp256AP_SUBGROUPVARPTR(drivers[6], "7_", 47, AP_BattMonitor, backend_var_info[6]),257#endif258259#if AP_BATT_MONITOR_MAX_INSTANCES > 7260// @Group: 8_261// @Path: AP_BattMonitor_Params.cpp262AP_SUBGROUPINFO(_params[7], "8_", 30, AP_BattMonitor, AP_BattMonitor_Params),263264// @Group: 8_265// @Path: AP_BattMonitor_Analog.cpp266// @Group: 8_267// @Path: AP_BattMonitor_SMBus.cpp268// @Group: 8_269// @Path: AP_BattMonitor_Sum.cpp270// @Group: 8_271// @Path: AP_BattMonitor_DroneCAN.cpp272// @Group: 8_273// @Path: AP_BattMonitor_FuelLevel_Analog.cpp274// @Group: 8_275// @Path: AP_BattMonitor_Synthetic_Current.cpp276// @Group: 8_277// @Path: AP_BattMonitor_INA2xx.cpp278// @Group: 8_279// @Path: AP_BattMonitor_ESC.cpp280// @Group: 8_281// @Path: AP_BattMonitor_INA239.cpp282// @Group: 8_283// @Path: AP_BattMonitor_INA3221.cpp284// @Group: 8_285// @Path: AP_BattMonitor_AD7091R5.cpp286AP_SUBGROUPVARPTR(drivers[7], "8_", 48, AP_BattMonitor, backend_var_info[7]),287#endif288289#if AP_BATT_MONITOR_MAX_INSTANCES > 8290// @Group: 9_291// @Path: AP_BattMonitor_Params.cpp292AP_SUBGROUPINFO(_params[8], "9_", 31, AP_BattMonitor, AP_BattMonitor_Params),293294// @Group: 9_295// @Path: AP_BattMonitor_Analog.cpp296// @Group: 9_297// @Path: AP_BattMonitor_SMBus.cpp298// @Group: 9_299// @Path: AP_BattMonitor_Sum.cpp300// @Group: 9_301// @Path: AP_BattMonitor_DroneCAN.cpp302// @Group: 9_303// @Path: AP_BattMonitor_FuelLevel_Analog.cpp304// @Group: 9_305// @Path: AP_BattMonitor_Synthetic_Current.cpp306// @Group: 9_307// @Path: AP_BattMonitor_INA2xx.cpp308// @Group: 9_309// @Path: AP_BattMonitor_ESC.cpp310// @Group: 9_311// @Path: AP_BattMonitor_INA239.cpp312// @Group: 9_313// @Path: AP_BattMonitor_INA3221.cpp314// @Group: 9_315// @Path: AP_BattMonitor_AD7091R5.cpp316AP_SUBGROUPVARPTR(drivers[8], "9_", 49, AP_BattMonitor, backend_var_info[8]),317#endif318319#if AP_BATT_MONITOR_MAX_INSTANCES > 9320// @Group: A_321// @Path: AP_BattMonitor_Params.cpp322AP_SUBGROUPINFO(_params[9], "A_", 32, AP_BattMonitor, AP_BattMonitor_Params),323324// @Group: A_325// @Path: AP_BattMonitor_Analog.cpp326// @Group: A_327// @Path: AP_BattMonitor_SMBus.cpp328// @Group: A_329// @Path: AP_BattMonitor_Sum.cpp330// @Group: A_331// @Path: AP_BattMonitor_DroneCAN.cpp332// @Group: A_333// @Path: AP_BattMonitor_FuelLevel_Analog.cpp334// @Group: A_335// @Path: AP_BattMonitor_Synthetic_Current.cpp336// @Group: A_337// @Path: AP_BattMonitor_INA2xx.cpp338// @Group: A_339// @Path: AP_BattMonitor_ESC.cpp340// @Group: A_341// @Path: AP_BattMonitor_INA239.cpp342// @Group: A_343// @Path: AP_BattMonitor_INA3221.cpp344// @Group: A_345// @Path: AP_BattMonitor_AD7091R5.cpp346AP_SUBGROUPVARPTR(drivers[9], "A_", 50, AP_BattMonitor, backend_var_info[9]),347#endif348349#if AP_BATT_MONITOR_MAX_INSTANCES > 10350// @Group: B_351// @Path: AP_BattMonitor_Params.cpp352AP_SUBGROUPINFO(_params[10], "B_", 33, AP_BattMonitor, AP_BattMonitor_Params),353354// @Group: B_355// @Path: AP_BattMonitor_Analog.cpp356// @Group: B_357// @Path: AP_BattMonitor_SMBus.cpp358// @Group: B_359// @Path: AP_BattMonitor_Sum.cpp360// @Group: B_361// @Path: AP_BattMonitor_DroneCAN.cpp362// @Group: B_363// @Path: AP_BattMonitor_FuelLevel_Analog.cpp364// @Group: B_365// @Path: AP_BattMonitor_Synthetic_Current.cpp366// @Group: B_367// @Path: AP_BattMonitor_INA2xx.cpp368// @Group: B_369// @Path: AP_BattMonitor_ESC.cpp370// @Group: B_371// @Path: AP_BattMonitor_INA239.cpp372// @Group: B_373// @Path: AP_BattMonitor_INA3221.cpp374// @Group: B_375// @Path: AP_BattMonitor_AD7091R5.cpp376AP_SUBGROUPVARPTR(drivers[10], "B_", 51, AP_BattMonitor, backend_var_info[10]),377#endif378379#if AP_BATT_MONITOR_MAX_INSTANCES > 11380// @Group: C_381// @Path: AP_BattMonitor_Params.cpp382AP_SUBGROUPINFO(_params[11], "C_", 34, AP_BattMonitor, AP_BattMonitor_Params),383384// @Group: C_385// @Path: AP_BattMonitor_Analog.cpp386// @Group: C_387// @Path: AP_BattMonitor_SMBus.cpp388// @Group: C_389// @Path: AP_BattMonitor_Sum.cpp390// @Group: C_391// @Path: AP_BattMonitor_DroneCAN.cpp392// @Group: C_393// @Path: AP_BattMonitor_FuelLevel_Analog.cpp394// @Group: C_395// @Path: AP_BattMonitor_Synthetic_Current.cpp396// @Group: C_397// @Path: AP_BattMonitor_INA2xx.cpp398// @Group: C_399// @Path: AP_BattMonitor_ESC.cpp400// @Group: C_401// @Path: AP_BattMonitor_INA239.cpp402// @Group: C_403// @Path: AP_BattMonitor_INA3221.cpp404// @Group: C_405// @Path: AP_BattMonitor_AD7091R5.cpp406AP_SUBGROUPVARPTR(drivers[11], "C_", 52, AP_BattMonitor, backend_var_info[11]),407#endif408409#if AP_BATT_MONITOR_MAX_INSTANCES > 12410// @Group: D_411// @Path: AP_BattMonitor_Params.cpp412AP_SUBGROUPINFO(_params[12], "D_", 35, AP_BattMonitor, AP_BattMonitor_Params),413414// @Group: D_415// @Path: AP_BattMonitor_Analog.cpp416// @Group: D_417// @Path: AP_BattMonitor_SMBus.cpp418// @Group: D_419// @Path: AP_BattMonitor_Sum.cpp420// @Group: D_421// @Path: AP_BattMonitor_DroneCAN.cpp422// @Group: D_423// @Path: AP_BattMonitor_FuelLevel_Analog.cpp424// @Group: D_425// @Path: AP_BattMonitor_Synthetic_Current.cpp426// @Group: D_427// @Path: AP_BattMonitor_INA2xx.cpp428// @Group: D_429// @Path: AP_BattMonitor_ESC.cpp430// @Group: D_431// @Path: AP_BattMonitor_INA239.cpp432// @Group: D_433// @Path: AP_BattMonitor_INA3221.cpp434// @Group: D_435// @Path: AP_BattMonitor_AD7091R5.cpp436AP_SUBGROUPVARPTR(drivers[12], "D_", 53, AP_BattMonitor, backend_var_info[12]),437#endif438439#if AP_BATT_MONITOR_MAX_INSTANCES > 13440// @Group: E_441// @Path: AP_BattMonitor_Params.cpp442AP_SUBGROUPINFO(_params[13], "E_", 36, AP_BattMonitor, AP_BattMonitor_Params),443444// @Group: E_445// @Path: AP_BattMonitor_Analog.cpp446// @Group: E_447// @Path: AP_BattMonitor_SMBus.cpp448// @Group: E_449// @Path: AP_BattMonitor_Sum.cpp450// @Group: E_451// @Path: AP_BattMonitor_DroneCAN.cpp452// @Group: E_453// @Path: AP_BattMonitor_FuelLevel_Analog.cpp454// @Group: E_455// @Path: AP_BattMonitor_Synthetic_Current.cpp456// @Group: E_457// @Path: AP_BattMonitor_INA2xx.cpp458// @Group: E_459// @Path: AP_BattMonitor_ESC.cpp460// @Group: E_461// @Path: AP_BattMonitor_INA239.cpp462// @Group: E_463// @Path: AP_BattMonitor_INA3221.cpp464// @Group: E_465// @Path: AP_BattMonitor_AD7091R5.cpp466AP_SUBGROUPVARPTR(drivers[13], "E_", 54, AP_BattMonitor, backend_var_info[13]),467#endif468469#if AP_BATT_MONITOR_MAX_INSTANCES > 14470// @Group: F_471// @Path: AP_BattMonitor_Params.cpp472AP_SUBGROUPINFO(_params[14], "F_", 37, AP_BattMonitor, AP_BattMonitor_Params),473474// @Group: F_475// @Path: AP_BattMonitor_Analog.cpp476// @Group: F_477// @Path: AP_BattMonitor_SMBus.cpp478// @Group: F_479// @Path: AP_BattMonitor_Sum.cpp480// @Group: F_481// @Path: AP_BattMonitor_DroneCAN.cpp482// @Group: F_483// @Path: AP_BattMonitor_FuelLevel_Analog.cpp484// @Group: F_485// @Path: AP_BattMonitor_Synthetic_Current.cpp486// @Group: F_487// @Path: AP_BattMonitor_INA2xx.cpp488// @Group: F_489// @Path: AP_BattMonitor_ESC.cpp490// @Group: F_491// @Path: AP_BattMonitor_INA239.cpp492// @Group: F_493// @Path: AP_BattMonitor_INA3221.cpp494// @Group: F_495// @Path: AP_BattMonitor_AD7091R5.cpp496AP_SUBGROUPVARPTR(drivers[14], "F_", 55, AP_BattMonitor, backend_var_info[14]),497#endif498499#if AP_BATT_MONITOR_MAX_INSTANCES > 15500// @Group: G_501// @Path: AP_BattMonitor_Params.cpp502AP_SUBGROUPINFO(_params[15], "G_", 38, AP_BattMonitor, AP_BattMonitor_Params),503504// @Group: G_505// @Path: AP_BattMonitor_Analog.cpp506// @Group: G_507// @Path: AP_BattMonitor_SMBus.cpp508// @Group: G_509// @Path: AP_BattMonitor_Sum.cpp510// @Group: G_511// @Path: AP_BattMonitor_DroneCAN.cpp512// @Group: G_513// @Path: AP_BattMonitor_FuelLevel_Analog.cpp514// @Group: G_515// @Path: AP_BattMonitor_Synthetic_Current.cpp516// @Group: G_517// @Path: AP_BattMonitor_INA2xx.cpp518// @Group: G_519// @Path: AP_BattMonitor_ESC.cpp520// @Group: G_521// @Path: AP_BattMonitor_INA239.cpp522// @Group: G_523// @Path: AP_BattMonitor_INA3221.cpp524// @Group: G_525// @Path: AP_BattMonitor_AD7091R5.cpp526AP_SUBGROUPVARPTR(drivers[15], "G_", 56, AP_BattMonitor, backend_var_info[15]),527#endif528529#if AP_BATT_MONITOR_MAX_INSTANCES > 16530#error "AP_BATT_MONITOR_MAX_INSTANCES too large, reset_remaining_mask() will cause an assert above 16"531#endif532533AP_GROUPEND534};535536const AP_Param::GroupInfo *AP_BattMonitor::backend_var_info[AP_BATT_MONITOR_MAX_INSTANCES];537538// Default constructor.539// Note that the Vector/Matrix constructors already implicitly zero540// their values.541//542AP_BattMonitor::AP_BattMonitor(uint32_t log_battery_bit, battery_failsafe_handler_fn_t battery_failsafe_handler_fn, const int8_t *failsafe_priorities) :543_log_battery_bit(log_battery_bit),544_battery_failsafe_handler_fn(battery_failsafe_handler_fn),545_failsafe_priorities(failsafe_priorities)546{547AP_Param::setup_object_defaults(this, var_info);548549if (_singleton != nullptr) {550AP_HAL::panic("AP_BattMonitor must be singleton");551}552_singleton = this;553}554555// init - instantiate the battery monitors556void557AP_BattMonitor::init()558{559// check init has not been called before560if (_num_instances != 0) {561return;562}563564_highest_failsafe_priority = INT8_MAX;565566#ifdef HAL_BATT_MONITOR_DEFAULT567_params[0]._type.set_default(int8_t(HAL_BATT_MONITOR_DEFAULT));568#endif569#ifdef HAL_BATT2_MONITOR_DEFAULT570_params[1]._type.set_default(int8_t(HAL_BATT2_MONITOR_DEFAULT));571#endif572573// create each instance574for (uint8_t instance=0; instance<AP_BATT_MONITOR_MAX_INSTANCES; instance++) {575// clear out the cell voltages576memset(&state[instance].cell_voltages, 0xFF, sizeof(cells));577state[instance].instance = instance;578579const auto allocation_type = configured_type(instance);580switch (allocation_type) {581#if AP_BATTERY_ANALOG_ENABLED582case Type::ANALOG_VOLTAGE_ONLY:583case Type::ANALOG_VOLTAGE_AND_CURRENT:584drivers[instance] = NEW_NOTHROW AP_BattMonitor_Analog(*this, state[instance], _params[instance]);585break;586#endif587#if AP_BATTERY_SMBUS_SOLO_ENABLED588case Type::SOLO:589drivers[instance] = NEW_NOTHROW AP_BattMonitor_SMBus_Solo(*this, state[instance], _params[instance]);590break;591#endif592#if AP_BATTERY_SMBUS_GENERIC_ENABLED593case Type::SMBus_Generic:594drivers[instance] = NEW_NOTHROW AP_BattMonitor_SMBus_Generic(*this, state[instance], _params[instance]);595break;596#endif597#if AP_BATTERY_SMBUS_SUI_ENABLED598case Type::SUI3:599drivers[instance] = NEW_NOTHROW AP_BattMonitor_SMBus_SUI(*this, state[instance], _params[instance], 3);600break;601case Type::SUI6:602drivers[instance] = NEW_NOTHROW AP_BattMonitor_SMBus_SUI(*this, state[instance], _params[instance], 6);603break;604#endif605#if AP_BATTERY_SMBUS_MAXELL_ENABLED606case Type::MAXELL:607drivers[instance] = NEW_NOTHROW AP_BattMonitor_SMBus_Maxell(*this, state[instance], _params[instance]);608break;609#endif610#if AP_BATTERY_SMBUS_ROTOYE_ENABLED611case Type::Rotoye:612drivers[instance] = NEW_NOTHROW AP_BattMonitor_SMBus_Rotoye(*this, state[instance], _params[instance]);613break;614#endif615#if AP_BATTERY_SMBUS_NEODESIGN_ENABLED616case Type::NeoDesign:617drivers[instance] = NEW_NOTHROW AP_BattMonitor_SMBus_NeoDesign(*this, state[instance], _params[instance]);618break;619#endif620#if AP_BATTERY_BEBOP_ENABLED621case Type::BEBOP:622drivers[instance] = NEW_NOTHROW AP_BattMonitor_Bebop(*this, state[instance], _params[instance]);623break;624#endif625#if AP_BATTERY_UAVCAN_BATTERYINFO_ENABLED626case Type::UAVCAN_BatteryInfo:627drivers[instance] = NEW_NOTHROW AP_BattMonitor_DroneCAN(*this, state[instance], AP_BattMonitor_DroneCAN::UAVCAN_BATTERY_INFO, _params[instance]);628break;629#endif630#if AP_BATTERY_ESC_ENABLED631case Type::BLHeliESC:632drivers[instance] = NEW_NOTHROW AP_BattMonitor_ESC(*this, state[instance], _params[instance]);633break;634#endif635#if AP_BATTERY_SUM_ENABLED636case Type::Sum:637drivers[instance] = NEW_NOTHROW AP_BattMonitor_Sum(*this, state[instance], _params[instance], instance);638break;639#endif640#if AP_BATTERY_FUELFLOW_ENABLED641case Type::FuelFlow:642drivers[instance] = NEW_NOTHROW AP_BattMonitor_FuelFlow(*this, state[instance], _params[instance]);643break;644#endif // AP_BATTERY_FUELFLOW_ENABLED645#if AP_BATTERY_FUELLEVEL_PWM_ENABLED646case Type::FuelLevel_PWM:647drivers[instance] = NEW_NOTHROW AP_BattMonitor_FuelLevel_PWM(*this, state[instance], _params[instance]);648break;649#endif // AP_BATTERY_FUELLEVEL_PWM_ENABLED650#if AP_BATTERY_FUELLEVEL_ANALOG_ENABLED651case Type::FuelLevel_Analog:652drivers[instance] = NEW_NOTHROW AP_BattMonitor_FuelLevel_Analog(*this, state[instance], _params[instance]);653break;654#endif // AP_BATTERY_FUELLEVEL_ANALOG_ENABLED655#if HAL_GENERATOR_ENABLED656case Type::GENERATOR_ELEC:657drivers[instance] = NEW_NOTHROW AP_BattMonitor_Generator_Elec(*this, state[instance], _params[instance]);658break;659case Type::GENERATOR_FUEL:660drivers[instance] = NEW_NOTHROW AP_BattMonitor_Generator_FuelLevel(*this, state[instance], _params[instance]);661break;662#endif // HAL_GENERATOR_ENABLED663#if AP_BATTERY_INA2XX_ENABLED664case Type::INA2XX:665drivers[instance] = NEW_NOTHROW AP_BattMonitor_INA2XX(*this, state[instance], _params[instance]);666break;667#endif668#if AP_BATTERY_LTC2946_ENABLED669case Type::LTC2946:670drivers[instance] = NEW_NOTHROW AP_BattMonitor_LTC2946(*this, state[instance], _params[instance]);671break;672#endif673#if HAL_TORQEEDO_ENABLED674case Type::Torqeedo:675drivers[instance] = NEW_NOTHROW AP_BattMonitor_Torqeedo(*this, state[instance], _params[instance]);676break;677#endif678#if AP_BATTERY_SYNTHETIC_CURRENT_ENABLED679case Type::Analog_Volt_Synthetic_Current:680drivers[instance] = NEW_NOTHROW AP_BattMonitor_Synthetic_Current(*this, state[instance], _params[instance]);681break;682#endif683#if AP_BATTERY_INA239_ENABLED684case Type::INA239_SPI:685drivers[instance] = NEW_NOTHROW AP_BattMonitor_INA239(*this, state[instance], _params[instance]);686break;687#endif688#if AP_BATTERY_EFI_ENABLED689case Type::EFI:690drivers[instance] = NEW_NOTHROW AP_BattMonitor_EFI(*this, state[instance], _params[instance]);691break;692#endif // AP_BATTERY_EFI_ENABLED693#if AP_BATTERY_AD7091R5_ENABLED694case Type::AD7091R5:695drivers[instance] = NEW_NOTHROW AP_BattMonitor_AD7091R5(*this, state[instance], _params[instance]);696break;697#endif// AP_BATTERY_AD7091R5_ENABLED698#if AP_BATTERY_SCRIPTING_ENABLED699case Type::Scripting:700drivers[instance] = NEW_NOTHROW AP_BattMonitor_Scripting(*this, state[instance], _params[instance]);701break;702#endif // AP_BATTERY_SCRIPTING_ENABLED703#if AP_BATTERY_INA3221_ENABLED704case Type::INA3221:705drivers[instance] = NEW_NOTHROW AP_BattMonitor_INA3221(*this, state[instance], _params[instance]);706break;707#endif // AP_BATTERY_INA3221_ENABLED708case Type::NONE:709default:710break;711}712if (drivers[instance] != nullptr) {713state[instance].type = allocation_type;714}715// if the backend has some local parameters then make those available in the tree716if (drivers[instance] && state[instance].var_info) {717backend_var_info[instance] = state[instance].var_info;718AP_Param::load_object_from_eeprom(drivers[instance], backend_var_info[instance]);719720// param count could have changed721AP_Param::invalidate_count();722}723724// call init function for each backend725if (drivers[instance] != nullptr) {726drivers[instance]->init();727// _num_instances is actually the index for looping over instances728// the user may have BATT_MONITOR=0 and BATT2_MONITOR=7, in which case729// there will be a gap, but as we always check for drivers[instances] being nullptr730// this is safe731_num_instances = instance + 1;732733// Convert the old analog & Bus parameters to the new dynamic parameter groups734convert_dynamic_param_groups(instance);735}736}737}738739void AP_BattMonitor::convert_dynamic_param_groups(uint8_t instance)740{741AP_Param::ConversionInfo info;742if (!AP_Param::find_top_level_key_by_pointer(this, info.old_key)) {743return;744}745746char param_prefix[6] {};747char param_name[17] {};748info.new_name = param_name;749750const uint8_t param_instance = instance + 1;751// first battmonitor does not have '1' in the param name752if(param_instance == 1) {753hal.util->snprintf(param_prefix, sizeof(param_prefix), "BATT");754} else {755hal.util->snprintf(param_prefix, sizeof(param_prefix), "BATT%X", param_instance);756}757param_prefix[sizeof(param_prefix)-1] = '\0';758759hal.util->snprintf(param_name, sizeof(param_name), "%s_%s", param_prefix, "MONITOR");760param_name[sizeof(param_name)-1] = '\0';761762// Find the index of the BATTn_MONITOR which is not moving to index the moving parameters off from763AP_Param::ParamToken token = AP_Param::ParamToken {};764ap_var_type type;765AP_Param* param = AP_Param::find_by_name(param_name, &type, &token);766const uint8_t battmonitor_index = 1;767if( param == nullptr) {768// BATTn_MONITOR not found769return;770}771772const struct convert_table {773uint32_t old_group_element;774ap_var_type type;775const char* new_name;776} conversion_table[] = {777// PARAMETER_CONVERSION - Added: Aug-2021778{ 2, AP_PARAM_INT8, "VOLT_PIN" },779{ 3, AP_PARAM_INT8, "CURR_PIN" },780{ 4, AP_PARAM_FLOAT, "VOLT_MULT" },781{ 5, AP_PARAM_FLOAT, "AMP_PERVLT"},782{ 6, AP_PARAM_FLOAT, "AMP_OFFSET"},783{ 20, AP_PARAM_INT8, "I2C_BUS" },784};785786for (const auto & elem : conversion_table) {787info.old_group_element = token.group_element + ((elem.old_group_element - battmonitor_index) * 64);788info.type = elem.type;789790hal.util->snprintf(param_name, sizeof(param_name), "%s_%s", param_prefix, elem.new_name);791AP_Param::convert_old_parameter(&info, 1.0f, 0);792}793}794795// read - For all active instances read voltage & current; log BAT, BCL, POWR, MCU796void AP_BattMonitor::read()797{798#if HAL_LOGGING_ENABLED799AP_Logger *logger = AP_Logger::get_singleton();800if (logger != nullptr && logger->should_log(_log_battery_bit)) {801logger->Write_Power();802}803#endif804805const uint32_t now_ms = AP_HAL::millis();806for (uint8_t i=0; i<_num_instances; i++) {807if (drivers[i] == nullptr) {808continue;809}810if (allocated_type(i) != configured_type(i)) {811continue;812}813// allow run-time disabling; this is technically redundant814if (configured_type(i) == Type::NONE) {815continue;816}817drivers[i]->read();818drivers[i]->update_resistance_estimate();819820#if AP_BATTERY_ESC_TELEM_OUTBOUND_ENABLED821drivers[i]->update_esc_telem_outbound();822#endif823824// Update last heathy timestamp825if (state[i].healthy) {826state[i].last_healthy_ms = now_ms;827}828829#if HAL_LOGGING_ENABLED830if (logger != nullptr && logger->should_log(_log_battery_bit)) {831const uint64_t time_us = AP_HAL::micros64();832drivers[i]->Log_Write_BAT(i, time_us);833drivers[i]->Log_Write_BCL(i, time_us);834}835#endif836}837838check_failsafes();839840checkPoweringOff();841}842843// healthy - returns true if monitor is functioning844bool AP_BattMonitor::healthy(uint8_t instance) const {845return instance < _num_instances && state[instance].healthy;846}847848/// voltage - returns battery voltage in volts849float AP_BattMonitor::voltage(uint8_t instance) const850{851if (instance < _num_instances) {852return state[instance].voltage;853} else {854return 0.0f;855}856}857858/// get voltage with sag removed (based on battery current draw and resistance)859/// this will always be greater than or equal to the raw voltage860float AP_BattMonitor::voltage_resting_estimate(uint8_t instance) const861{862if (instance < _num_instances && drivers[instance] != nullptr) {863return drivers[instance]->voltage_resting_estimate();864} else {865return 0.0f;866}867}868869/// voltage - returns battery voltage in volts for GCS, may be resting voltage if option enabled870float AP_BattMonitor::gcs_voltage(uint8_t instance) const871{872if (instance >= _num_instances || drivers[instance] == nullptr) {873return 0.0f;874}875if (drivers[instance]->option_is_set(AP_BattMonitor_Params::Options::GCS_Resting_Voltage)) {876return voltage_resting_estimate(instance);877}878return state[instance].voltage;879}880881bool AP_BattMonitor::option_is_set(uint8_t instance, AP_BattMonitor_Params::Options option) const882{883if (instance >= _num_instances || drivers[instance] == nullptr) {884return false;885}886return drivers[instance]->option_is_set(option);887}888889/// current_amps - returns the instantaneous current draw in amperes890bool AP_BattMonitor::current_amps(float ¤t, uint8_t instance) const {891if ((instance < _num_instances) && (drivers[instance] != nullptr) && drivers[instance]->has_current()) {892current = state[instance].current_amps;893return true;894} else {895return false;896}897}898899/// consumed_mah - returns total current drawn since start-up in milliampere.hours900bool AP_BattMonitor::consumed_mah(float &mah, const uint8_t instance) const {901if ((instance < _num_instances) && (drivers[instance] != nullptr) && drivers[instance]->has_current()) {902const float consumed_mah = state[instance].consumed_mah;903if (isnan(consumed_mah)) {904return false;905}906mah = consumed_mah;907return true;908} else {909return false;910}911}912913/// consumed_wh - returns energy consumed since start-up in Watt.hours914bool AP_BattMonitor::consumed_wh(float &wh, const uint8_t instance) const {915if (instance < _num_instances && drivers[instance] != nullptr && drivers[instance]->has_consumed_energy()) {916wh = state[instance].consumed_wh;917return true;918} else {919return false;920}921}922923/// capacity_remaining_pct - returns true if the percentage is valid and writes to percentage argument924bool AP_BattMonitor::capacity_remaining_pct(uint8_t &percentage, uint8_t instance) const925{926if (instance < _num_instances && drivers[instance] != nullptr) {927return drivers[instance]->capacity_remaining_pct(percentage);928}929return false;930}931932/// time_remaining - returns remaining battery time933bool AP_BattMonitor::time_remaining(uint32_t &seconds, uint8_t instance) const934{935if (instance < _num_instances && drivers[instance] != nullptr && state[instance].has_time_remaining) {936seconds = state[instance].time_remaining;937return true;938}939return false;940}941942/// pack_capacity_mah - returns the capacity of the battery pack in mAh when the pack is full943int32_t AP_BattMonitor::pack_capacity_mah(uint8_t instance) const944{945if (instance < AP_BATT_MONITOR_MAX_INSTANCES) {946return _params[instance]._pack_capacity;947} else {948return 0;949}950}951952void AP_BattMonitor::check_failsafes(void)953{954if (hal.util->get_soft_armed()) {955for (uint8_t i = 0; i < _num_instances; i++) {956if (drivers[i] == nullptr) {957continue;958}959960const Failsafe type = drivers[i]->update_failsafes();961if (type <= state[i].failsafe) {962continue;963}964965int8_t action = 0;966const char *type_str = nullptr;967switch (type) {968case Failsafe::None:969continue; // should not have been called in this case970case Failsafe::Unhealthy:971// Report only for unhealthy, could add action param in the future972action = 0;973type_str = "missing, last:";974break;975case Failsafe::Low:976action = _params[i]._failsafe_low_action;977type_str = "low";978break;979case Failsafe::Critical:980action = _params[i]._failsafe_critical_action;981type_str = "critical";982break;983}984985GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "Battery %d is %s %.2fV used %.0f mAh", i + 1, type_str,986(double)voltage(i), (double)state[i].consumed_mah);987_has_triggered_failsafe = true;988#ifndef HAL_BUILD_AP_PERIPH989AP_Notify::flags.failsafe_battery = true;990#endif991state[i].failsafe = type;992993// map the desired failsafe action to a priority level994int8_t priority = 0;995if (_failsafe_priorities != nullptr) {996while (_failsafe_priorities[priority] != -1) {997if (_failsafe_priorities[priority] == action) {998break;999}1000priority++;1001}10021003}10041005// trigger failsafe if the action was equal or higher priority1006// It's valid to retrigger the same action if a different battery provoked the event1007if (priority <= _highest_failsafe_priority) {1008_battery_failsafe_handler_fn(type_str, action);1009_highest_failsafe_priority = priority;1010}1011}1012}1013}10141015// return true if any battery is pushing too much power1016bool AP_BattMonitor::overpower_detected() const1017{1018#if AP_BATTERY_WATT_MAX_ENABLED && APM_BUILD_TYPE(APM_BUILD_ArduPlane)1019for (uint8_t instance = 0; instance < _num_instances; instance++) {1020if (overpower_detected(instance)) {1021return true;1022}1023}1024#endif1025return false;1026}10271028bool AP_BattMonitor::overpower_detected(uint8_t instance) const1029{1030#if AP_BATTERY_WATT_MAX_ENABLED && APM_BUILD_TYPE(APM_BUILD_ArduPlane)1031if (instance < _num_instances && _params[instance]._watt_max > 0) {1032const float power = state[instance].current_amps * state[instance].voltage;1033return state[instance].healthy && (power > _params[instance]._watt_max);1034}1035#endif1036return false;1037}10381039bool AP_BattMonitor::has_cell_voltages(const uint8_t instance) const1040{1041if (instance < _num_instances && drivers[instance] != nullptr) {1042return drivers[instance]->has_cell_voltages();1043}10441045return false;1046}10471048// return the current cell voltages, returns the first monitor instances cells if the instance is out of range1049const AP_BattMonitor::cells & AP_BattMonitor::get_cell_voltages(const uint8_t instance) const1050{1051if (instance >= AP_BATT_MONITOR_MAX_INSTANCES) {1052return state[AP_BATT_PRIMARY_INSTANCE].cell_voltages;1053} else {1054return state[instance].cell_voltages;1055}1056}10571058// get once cell voltage (for scripting)1059bool AP_BattMonitor::get_cell_voltage(uint8_t instance, uint8_t cell, float &voltage) const1060{1061if (!has_cell_voltages(instance) ||1062cell >= AP_BATT_MONITOR_CELLS_MAX) {1063return false;1064}1065const auto &cell_voltages = get_cell_voltages(instance);1066const uint16_t voltage_mv = cell_voltages.cells[cell];1067if (voltage_mv == 0 || voltage_mv == UINT16_MAX) {1068// UINT16_MAX is used as invalid indicator1069return false;1070}1071voltage = voltage_mv*0.001;1072return true;1073}10741075// returns true if there is a temperature reading1076bool AP_BattMonitor::get_temperature(float &temperature, const uint8_t instance) const1077{1078if (instance >= _num_instances || drivers[instance] == nullptr) {1079return false;1080}10811082return drivers[instance]->get_temperature(temperature);1083}10841085#if AP_TEMPERATURE_SENSOR_ENABLED1086// return true when successfully setting a battery temperature from an external source by instance1087bool AP_BattMonitor::set_temperature(const float temperature, const uint8_t instance)1088{1089if (instance >= _num_instances || drivers[instance] == nullptr) {1090return false;1091}1092state[instance].temperature_external = temperature;1093state[instance].temperature_external_use = true;1094return true;1095}10961097// return true when successfully setting a battery temperature from an external source by serial_number1098bool AP_BattMonitor::set_temperature_by_serial_number(const float temperature, const int32_t serial_number)1099{1100bool success = false;1101for (uint8_t i = 0; i < _num_instances; i++) {1102if (drivers[i] != nullptr && get_serial_number(i) == serial_number) {1103success |= set_temperature(temperature, i);1104}1105}1106return success;1107}1108#endif // AP_TEMPERATURE_SENSOR_ENABLED11091110// return true if cycle count can be provided and fills in cycles argument1111bool AP_BattMonitor::get_cycle_count(uint8_t instance, uint16_t &cycles) const1112{1113if (instance >= _num_instances || (drivers[instance] == nullptr)) {1114return false;1115}1116return drivers[instance]->get_cycle_count(cycles);1117}11181119bool AP_BattMonitor::arming_checks(size_t buflen, char *buffer) const1120{1121char temp_buffer[MAVLINK_MSG_STATUSTEXT_FIELD_TEXT_LEN+1] {};11221123for (uint8_t i = 0; i < AP_BATT_MONITOR_MAX_INSTANCES; i++) {1124const auto expected_type = configured_type(i);11251126if (drivers[i] == nullptr && expected_type == Type::NONE) {1127continue;1128}11291130#if !AP_BATTERY_SUM_ENABLED1131// CONVERSION - Added Sep 2024 for ArduPilot 4.6 as we are1132// removing the SUM backend on 1MB boards. Give a1133// more-specific error for the sum backend:1134if (expected_type == Type::Sum) {1135hal.util->snprintf(buffer, buflen, "Battery %d %s", i + 1, "feature BATTERY_SUM not available");1136return false;1137}1138#endif11391140if (drivers[i] == nullptr || allocated_type(i) != expected_type) {1141hal.util->snprintf(buffer, buflen, "Battery %d %s", i + 1, "unhealthy");1142return false;1143}11441145if (!drivers[i]->arming_checks(temp_buffer, sizeof(temp_buffer))) {1146hal.util->snprintf(buffer, buflen, "Battery %d %s", i + 1, temp_buffer);1147return false;1148}1149}11501151return true;1152}11531154// Check's each smart battery instance for its powering off state and broadcasts notifications1155void AP_BattMonitor::checkPoweringOff(void)1156{1157for (uint8_t i = 0; i < _num_instances; i++) {1158if (state[i].is_powering_off && !state[i].powerOffNotified) {1159#ifndef HAL_BUILD_AP_PERIPH1160// Set the AP_Notify flag, which plays the power off tones1161AP_Notify::flags.powering_off = true;1162#endif11631164// Send a Mavlink broadcast announcing the shutdown1165#if HAL_GCS_ENABLED1166mavlink_command_long_t cmd_msg{};1167cmd_msg.command = MAV_CMD_POWER_OFF_INITIATED;1168cmd_msg.param1 = i+1;1169GCS_MAVLINK::send_to_components(MAVLINK_MSG_ID_COMMAND_LONG, (char*)&cmd_msg, sizeof(cmd_msg));1170GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "Vehicle %d battery %d is powering off", mavlink_system.sysid, i+1);1171#endif11721173// only send this once1174state[i].powerOffNotified = true;1175}1176}1177}11781179/*1180reset battery remaining percentage for batteries that integrate to1181calculate percentage remaining1182*/1183bool AP_BattMonitor::reset_remaining_mask(uint16_t battery_mask, float percentage)1184{1185static_assert(AP_BATT_MONITOR_MAX_INSTANCES <= 16, "More batteries are enabled then can be reset");1186bool ret = true;1187Failsafe highest_failsafe = Failsafe::None;1188for (uint8_t i = 0; i < _num_instances; i++) {1189if ((1U<<i) & battery_mask) {1190if (drivers[i] != nullptr) {1191ret &= drivers[i]->reset_remaining(percentage);1192} else {1193ret = false;1194}1195}1196if (state[i].failsafe > highest_failsafe) {1197highest_failsafe = state[i].failsafe;1198}1199}12001201// If all backends are not in failsafe then set overall failsafe state1202if (highest_failsafe == Failsafe::None) {1203_highest_failsafe_priority = INT8_MAX;1204_has_triggered_failsafe = false;1205// and reset notify flag1206AP_Notify::flags.failsafe_battery = false;1207}1208return ret;1209}12101211// Returns the mavlink charge state. The following mavlink charge states are not used1212// MAV_BATTERY_CHARGE_STATE_EMERGENCY , MAV_BATTERY_CHARGE_STATE_FAILED1213// MAV_BATTERY_CHARGE_STATE_UNHEALTHY, MAV_BATTERY_CHARGE_STATE_CHARGING1214MAV_BATTERY_CHARGE_STATE AP_BattMonitor::get_mavlink_charge_state(const uint8_t instance) const1215{1216if (instance >= _num_instances) {1217return MAV_BATTERY_CHARGE_STATE_UNDEFINED;1218}12191220switch (state[instance].failsafe) {12211222case Failsafe::None:1223case Failsafe::Unhealthy:1224if (get_mavlink_fault_bitmask(instance) != 0 || !healthy()) {1225return MAV_BATTERY_CHARGE_STATE_UNHEALTHY;1226}1227return MAV_BATTERY_CHARGE_STATE_OK;12281229case Failsafe::Low:1230return MAV_BATTERY_CHARGE_STATE_LOW;12311232case Failsafe::Critical:1233return MAV_BATTERY_CHARGE_STATE_CRITICAL;1234}12351236// Should not reach this1237return MAV_BATTERY_CHARGE_STATE_UNDEFINED;1238}12391240// Returns mavlink fault state1241uint32_t AP_BattMonitor::get_mavlink_fault_bitmask(const uint8_t instance) const1242{1243if (instance >= _num_instances || drivers[instance] == nullptr) {1244return 0;1245}1246return drivers[instance]->get_mavlink_fault_bitmask();1247}12481249// return true if state of health (as a percentage) can be provided and fills in soh_pct argument1250bool AP_BattMonitor::get_state_of_health_pct(uint8_t instance, uint8_t &soh_pct) const1251{1252if (instance >= _num_instances || drivers[instance] == nullptr) {1253return false;1254}1255return drivers[instance]->get_state_of_health_pct(soh_pct);1256}12571258// Enable/Disable (Turn on/off) MPPT power to all backends who are MPPTs1259void AP_BattMonitor::MPPT_set_powered_state_to_all(const bool power_on)1260{1261for (uint8_t i=0; i < _num_instances; i++) {1262MPPT_set_powered_state(i, power_on);1263}1264}12651266// Enable/Disable (Turn on/off) MPPT power. When disabled, the MPPT does not1267// supply energy to the system regardless if it's capable to or not. When enabled1268// it will supply energy if available.1269void AP_BattMonitor::MPPT_set_powered_state(const uint8_t instance, const bool power_on)1270{1271if (instance < _num_instances) {1272drivers[instance]->mppt_set_powered_state(power_on);1273}1274}12751276/*1277check that all configured battery monitors are healthy1278*/1279bool AP_BattMonitor::healthy() const1280{1281for (uint8_t i=0; i< _num_instances; i++) {1282if (allocated_type(i) != configured_type(i)) {1283return false;1284}1285// allow run-time disabling; this is technically redundant1286if (configured_type(i) == Type::NONE) {1287continue;1288}1289if (!healthy(i)) {1290return false;1291}1292}1293return true;1294}12951296#if AP_BATTERY_SCRIPTING_ENABLED1297/*1298handle state update from a lua script1299*/1300bool AP_BattMonitor::handle_scripting(uint8_t idx, const BattMonitorScript_State &_state)1301{1302if (idx >= _num_instances) {1303return false;1304}1305return drivers[idx]->handle_scripting(_state);1306}1307#endif13081309namespace AP {13101311AP_BattMonitor &battery()1312{1313return *AP_BattMonitor::get_singleton();1314}13151316};13171318#endif // AP_BATTERY_ENABLED131913201321