LCOV - code coverage report
Current view: top level - AP_Param - AP_Param.h (source / functions) Hit Total Coverage
Test: lcov.info Lines: 55 57 96.5 %
Date: 2026-09-09 11:02:08 Functions: 82 92 89.1 %

          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             : //
      17             : /// @file       AP_Param.h
      18             : /// @brief      A system for managing and storing variables that are of
      19             : ///                     general interest to the system.
      20             : #pragma once
      21             : 
      22             : #include <stddef.h>
      23             : #include <string.h>
      24             : #include <stdint.h>
      25             : #include <cmath>
      26             : #include <type_traits>
      27             : 
      28             : #include <AP_HAL/AP_HAL.h>
      29             : #include <AP_HAL/utility/RingBuffer.h>
      30             : #include <StorageManager/StorageManager.h>
      31             : #include <AP_Scripting/AP_Scripting_config.h>
      32             : 
      33             : #include "AP_Param_config.h"
      34             : 
      35             : #include "float.h"
      36             : 
      37             : #define AP_MAX_NAME_SIZE 16
      38             : 
      39             : // optionally enable debug code for dumping keys
      40             : #ifndef AP_PARAM_KEY_DUMP
      41             : #define AP_PARAM_KEY_DUMP 0
      42             : #endif
      43             : 
      44             : #ifndef AP_PARAM_DEFAULTS_ENABLED
      45             :     #if defined(HAL_GCS_ENABLED)
      46             :         #define AP_PARAM_DEFAULTS_ENABLED HAL_GCS_ENABLED
      47             :     #else
      48             :         #define AP_PARAM_DEFAULTS_ENABLED 1
      49             :     #endif
      50             : #endif
      51             : 
      52             : /*
      53             :   maximum size of embedded parameter file
      54             :  */
      55             : #ifndef AP_PARAM_MAX_EMBEDDED_PARAM
      56             :   #if FORCE_APJ_DEFAULT_PARAMETERS
      57             :     #if HAL_PROGRAM_SIZE_LIMIT_KB <= 1024
      58             :       #define AP_PARAM_MAX_EMBEDDED_PARAM 1024
      59             :     #else
      60             :       #define AP_PARAM_MAX_EMBEDDED_PARAM 8192
      61             :     #endif
      62             :   #else
      63             :     #define AP_PARAM_MAX_EMBEDDED_PARAM 0
      64             :   #endif
      65             : #endif
      66             : 
      67             : // allow for dynamically added tables when scripting enabled
      68             : #ifndef AP_PARAM_DYNAMIC_ENABLED
      69             : #define AP_PARAM_DYNAMIC_ENABLED AP_SCRIPTING_ENABLED
      70             : #endif
      71             : 
      72             : // maximum number of dynamically created tables (from scripts)
      73             : #ifndef AP_PARAM_MAX_DYNAMIC
      74             : #define AP_PARAM_MAX_DYNAMIC 10
      75             : #endif
      76             : #define AP_PARAM_DYNAMIC_KEY_BASE 300
      77             : 
      78             : /*
      79             :   flags for variables in var_info and group tables
      80             :  */
      81             : 
      82             : // a nested offset is for subgroups that are not subclasses
      83             : #define AP_PARAM_FLAG_NESTED_OFFSET (1<<0)
      84             : 
      85             : // a pointer variable is for dynamically allocated objects
      86             : #define AP_PARAM_FLAG_POINTER       (1<<1)
      87             : 
      88             : // an enable variable allows a whole subtree of variables to be made
      89             : // invisible
      90             : #define AP_PARAM_FLAG_ENABLE        (1<<2)
      91             : 
      92             : // don't shift index 0 to index 63. Use this when you know there will be
      93             : // no conflict with the parent
      94             : #define AP_PARAM_FLAG_NO_SHIFT      (1<<3)
      95             : 
      96             : // the var_info is a pointer, allowing for dynamic definition of the var_info tree
      97             : #define AP_PARAM_FLAG_INFO_POINTER  (1<<4)
      98             : 
      99             : // this parameter is visible to GCS via mavlink but should never be
     100             : // set by anything other than the ArduPilot code responsible for its
     101             : // use.
     102             : #define AP_PARAM_FLAG_INTERNAL_USE_ONLY (1<<5)
     103             : 
     104             : // hide parameter from param download
     105             : #define AP_PARAM_FLAG_HIDDEN (1<<6)
     106             : 
     107             : // Default value is a "pointer" actually its a offest from the base value, but the idea is the same
     108             : #define AP_PARAM_FLAG_DEFAULT_POINTER (1<<7)
     109             : 
     110             : // keep all flags before the FRAME tags
     111             : 
     112             : // vehicle and frame type flags, used to hide parameters when not
     113             : // relevent to a vehicle type. Use AP_Param::set_frame_type_flags() to
     114             : // enable parameters flagged in this way. frame type flags are stored
     115             : // in flags field, shifted by AP_PARAM_FRAME_TYPE_SHIFT.
     116             : #define AP_PARAM_FRAME_TYPE_SHIFT   8
     117             : 
     118             : // supported frame types for parameters
     119             : #define AP_PARAM_FRAME_COPTER       (1<<0)
     120             : #define AP_PARAM_FRAME_ROVER        (1<<1)
     121             : #define AP_PARAM_FRAME_PLANE        (1<<2)
     122             : #define AP_PARAM_FRAME_SUB          (1<<3)
     123             : #define AP_PARAM_FRAME_TRICOPTER    (1<<4)
     124             : #define AP_PARAM_FRAME_HELI         (1<<5)
     125             : #define AP_PARAM_FRAME_BLIMP        (1<<6)
     126             : 
     127             : // use __builtin_offsetof which is more or less defined by Clang and GCC to work
     128             : // on non-standard-layout C++ classes, and works in constexpr. as that isn't
     129             : // standard-compliant, it raises "-Winvalid-offsetof" which we globally disable.
     130             : // https://github.com/llvm/llvm-project/blob/5fa5ffeb6cb5bc9aa414c02513e44b8405f0e7cc/libcxx/include/__type_traits/datasizeof.h#L51
     131             : // the first comma operator operand makes the compiler see element as used by
     132             : // conjuring a class instance and passing element to an unevaluating function.
     133             : #define AP_VAROFFSET(clazz, element) ((void)sizeof(std::declval<clazz>().element), (ptrdiff_t)__builtin_offsetof(clazz, element))
     134             : 
     135             : // get the internal type of an AP_Param variable given an arbitrary class and an
     136             : // element on it. convert the element, which must be of type AP_Param or a
     137             : // subclass, into a non-reference type. then get AP_Param's vtype member, which
     138             : // is static const but varies depending on the subclass. works in constexpr!
     139             : #define AP_CLASSTYPE(clazz, element) ((uint8_t)(std::remove_reference<decltype(clazz::element)>::type::vtype))
     140             : 
     141             : // declare a group var_info line
     142             : #define AP_GROUPINFO_FLAGS(name, idx, clazz, element, def, flags) { name, AP_VAROFFSET(clazz, element), {def_value : def}, flags, idx, AP_CLASSTYPE(clazz, element)}
     143             : 
     144             : // declare a group var_info line with a frame type mask
     145             : #define AP_GROUPINFO_FRAME(name, idx, clazz, element, def, frame_flags) AP_GROUPINFO_FLAGS(name, idx, clazz, element, def, (frame_flags)<<AP_PARAM_FRAME_TYPE_SHIFT )
     146             : 
     147             : // declare a group var_info line with both flags and frame type mask
     148             : #define AP_GROUPINFO_FLAGS_FRAME(name, idx, clazz, element, def, flags, frame_flags) AP_GROUPINFO_FLAGS(name, idx, clazz, element, def, flags|((frame_flags)<<AP_PARAM_FRAME_TYPE_SHIFT) )
     149             : 
     150             : // declare a group var_info line with a default "pointer"
     151             : #define AP_GROUPINFO_FLAGS_DEFAULT_POINTER(name, idx, clazz, element, def) {  name, AP_VAROFFSET(clazz, element), {def_value_offset : AP_VAROFFSET(clazz, element) - AP_VAROFFSET(clazz, def)}, AP_PARAM_FLAG_DEFAULT_POINTER, idx, AP_CLASSTYPE(clazz, element) }
     152             : 
     153             : // declare a group var_info line
     154             : #define AP_GROUPINFO(name, idx, clazz, element, def) AP_GROUPINFO_FLAGS(name, idx, clazz, element, def, 0)
     155             : 
     156             : // declare a nested group entry in a group var_info
     157             : #define AP_NESTEDGROUPINFO(clazz, idx) { "", 0, { group_info : clazz::var_info }, 0, idx, AP_PARAM_GROUP }
     158             : 
     159             : // declare a subgroup entry in a group var_info. This is for having another arbitrary object as a member of the parameter list of
     160             : // an object
     161             : #define AP_SUBGROUPINFO(element, name, idx, thisclazz, elclazz) { name, AP_VAROFFSET(thisclazz, element), { group_info : elclazz::var_info }, AP_PARAM_FLAG_NESTED_OFFSET, idx, AP_PARAM_GROUP }
     162             : 
     163             : // declare a second parameter table for the same object
     164             : #define AP_SUBGROUPEXTENSION(name, idx, clazz, vinfo) { name, 0, { group_info : clazz::vinfo }, AP_PARAM_FLAG_NESTED_OFFSET, idx, AP_PARAM_GROUP }
     165             : 
     166             : // declare a pointer subgroup entry in a group var_info
     167             : #define AP_SUBGROUPPTR(element, name, idx, thisclazz, elclazz) { name, AP_VAROFFSET(thisclazz, element), { group_info : elclazz::var_info }, AP_PARAM_FLAG_POINTER, idx, AP_PARAM_GROUP }
     168             : 
     169             : // declare a pointer subgroup entry in a group var_info with a pointer var_info
     170             : #define AP_SUBGROUPVARPTR(element, name, idx, thisclazz, var_info) { name, AP_VAROFFSET(thisclazz, element), { group_info_ptr : &var_info }, AP_PARAM_FLAG_POINTER | AP_PARAM_FLAG_INFO_POINTER, idx, AP_PARAM_GROUP }
     171             : 
     172             : #define AP_GROUPEND     { "", 0,       { group_info : nullptr }, 0, 0xFF, AP_PARAM_NONE }
     173             : 
     174             : // Vehicle defines for info struct
     175             : #define GSCALAR(v, name, def)                { name, &AP_PARAM_VEHICLE_NAME.g.v,                   {def_value : def},                   0,                                                  Parameters::k_param_ ## v,          AP_PARAM_VEHICLE_NAME.g.v.vtype }
     176             : #define GARRAY(v, index, name, def)          { name, &AP_PARAM_VEHICLE_NAME.g.v[index],            {def_value : def},                   0,                                                  Parameters::k_param_ ## v ## index, AP_PARAM_VEHICLE_NAME.g.v[index].vtype }
     177             : #define ASCALAR(v, name, def)                { name, (const void *)&AP_PARAM_VEHICLE_NAME.aparm.v, {def_value : def},                   0,                                                  Parameters::k_param_ ## v,          AP_PARAM_VEHICLE_NAME.aparm.v.vtype }
     178             : #define GGROUP(v, name, class)               { name, &AP_PARAM_VEHICLE_NAME.g.v,                   {group_info : class::var_info},      0,                                                  Parameters::k_param_ ## v,          AP_PARAM_GROUP }
     179             : #define GOBJECT(v, name, class)              { name, (const void *)&AP_PARAM_VEHICLE_NAME.v,       {group_info : class::var_info},      0,                                                  Parameters::k_param_ ## v,          AP_PARAM_GROUP }
     180             : #define GOBJECTPTR(v, name, class)           { name, (const void *)&AP_PARAM_VEHICLE_NAME.v,       {group_info : class::var_info},      AP_PARAM_FLAG_POINTER,                              Parameters::k_param_ ## v,          AP_PARAM_GROUP }
     181             : #define GOBJECTVARPTR(v, name, var_info_ptr) { name, (const void *)&AP_PARAM_VEHICLE_NAME.v,       {group_info_ptr : var_info_ptr},     AP_PARAM_FLAG_POINTER | AP_PARAM_FLAG_INFO_POINTER, Parameters::k_param_ ## v,          AP_PARAM_GROUP }
     182             : #define GOBJECTN(v, pname, name, class)      { name, (const void *)&AP_PARAM_VEHICLE_NAME.v,       {group_info : class::var_info},      0,                                                  Parameters::k_param_ ## pname,      AP_PARAM_GROUP }
     183             : #define PARAM_VEHICLE_INFO                   { "",   (const void *)&AP_PARAM_VEHICLE_NAME,         {group_info : AP_Vehicle::var_info}, 0,                                                  Parameters::k_param_vehicle,        AP_PARAM_GROUP }
     184             : #define AP_VAREND                            { "",   nullptr,                                      {group_info : nullptr },             0,                                                  0,                                  AP_PARAM_NONE }
     185             : #define AP_GROUP_ELEM_IDX(subgrp_idx, grp_idx) (grp_idx << 6 | subgrp_idx)
     186             : 
     187             : enum ap_var_type {
     188             :     AP_PARAM_NONE    = 0,
     189             :     AP_PARAM_INT8    = 1,
     190             :     AP_PARAM_INT16   = 2,
     191             :     AP_PARAM_INT32   = 3,
     192             :     AP_PARAM_FLOAT   = 4,
     193             :     AP_PARAM_VECTOR3F= 5,
     194             :     AP_PARAM_GROUP   = 6,
     195             : };
     196             : 
     197             : 
     198             : /// Base class for variables.
     199             : ///
     200             : /// Provides naming and lookup services for variables.
     201             : ///
     202             : class AP_Param
     203             : {
     204             : public:
     205             :     // the Info and GroupInfo structures are passed by the main
     206             :     // program in setup() to give information on how variables are
     207             :     // named and their location in memory
     208             :     struct GroupInfo {
     209             :         const char *name;
     210             :         ptrdiff_t offset; // offset within the object
     211             :         union {
     212             :             const struct GroupInfo *group_info;
     213             :             const struct GroupInfo **group_info_ptr; // when AP_PARAM_FLAG_INFO_POINTER is set in flags
     214             :             const float def_value;
     215             :             ptrdiff_t def_value_offset; // Default value offset from param object, when AP_PARAM_FLAG_DEFAULT_POINTER is set in flags
     216             :         };
     217             :         uint16_t flags;
     218             :         uint8_t idx;  // identifier within the group
     219             :         uint8_t type; // AP_PARAM_*
     220             :     };
     221             :     struct Info {
     222             :         const char *name;
     223             :         const void *ptr;    // pointer to the variable in memory
     224             :         union {
     225             :             const struct GroupInfo *group_info;
     226             :             const struct GroupInfo **group_info_ptr; // when AP_PARAM_FLAG_INFO_POINTER is set in flags
     227             :             const float def_value;
     228             :             ptrdiff_t def_value_offset; // Default value offset from param object, when AP_PARAM_FLAG_DEFAULT_POINTER is set in flags
     229             :         };
     230             :         uint16_t flags;
     231             :         uint16_t key; // k_param_*
     232             :         uint8_t type; // AP_PARAM_*
     233             :     };
     234             :     struct ConversionInfo {
     235             :         uint16_t old_key; // k_param_*
     236             :         uint32_t old_group_element; // index in old object
     237             :         enum ap_var_type type; // AP_PARAM_*
     238             :         const char *new_name;
     239             :     };
     240             : 
     241             :     // param default table element
     242             :     struct defaults_table_struct {
     243             :         const char *name;   // parameter name
     244             :         float value;        // parameter value
     245             :     };
     246             : 
     247             :     // called once at startup to setup the _var_info[] table. This
     248             :     // will also check the EEPROM header and re-initialise it if the
     249             :     // wrong version is found
     250             :     static bool setup();
     251             : 
     252             :     // constructor with var_info
     253        2098 :     AP_Param(const struct Info *info)
     254             :     {
     255        2098 :         _var_info = info;
     256             :         uint16_t i;
     257      205942 :         for (i=0; info[i].type != AP_PARAM_NONE; i++) ;
     258        2098 :         _num_vars = i;
     259             : #if AP_PARAM_DYNAMIC_ENABLED
     260        2098 :         _num_vars_base = _num_vars;
     261             : #endif
     262        2098 :         if (_singleton != nullptr) {
     263           0 :             AP_HAL::panic("AP_Param must be singleton");
     264             :         }
     265        2098 :         _singleton = this;
     266        2098 :     }
     267             : 
     268             :     // empty constructor
     269     7616255 :     AP_Param() {}
     270             : 
     271             :     // a token used for first()/next() state
     272             :     typedef struct {
     273             :         uint32_t key : 9;
     274             :         uint32_t idx : 4; // offset into array types
     275             :         uint32_t group_element : 18;
     276             :         uint32_t last_disabled : 1;
     277             :     } ParamToken;
     278             : 
     279             : 
     280             :     // nesting structure for recursive call states
     281             :     struct GroupNesting {
     282             :         static const uint8_t numlevels = 2;
     283             :         uint8_t level;
     284             :         const struct GroupInfo *group_ret[numlevels];
     285             :     };
     286             : 
     287             :     // return true if AP_Param has been initialised via setup()
     288             :     static bool initialised(void);
     289             : 
     290             :     // the 'group_id' of a element of a group is the 18 bit identifier
     291             :     // used to distinguish between this element of the group and other
     292             :     // elements of the same group. It is calculated using a bit shift per
     293             :     // level of nesting, so the first level of nesting gets 6 bits the 2nd
     294             :     // level gets the next 6 bits, and the 3rd level gets the last 6
     295             :     // bits. This limits groups to having at most 64 elements.
     296             :     static uint32_t group_id(const struct GroupInfo *grpinfo, uint32_t base, uint8_t i, uint8_t shift);
     297             : 
     298             :     /// Copy the variable's name, prefixed by any containing group name, to a
     299             :     /// buffer.
     300             :     ///
     301             :     /// If the variable has no name, the buffer will contain an empty string.
     302             :     ///
     303             :     /// Note that if the combination of names is larger than the buffer, the
     304             :     /// result in the buffer will be truncated.
     305             :     ///
     306             :     /// @param  token                   token giving current variable
     307             :     /// @param  buffer                  The destination buffer
     308             :     /// @param  bufferSize              Total size of the destination buffer.
     309             :     ///
     310             :     void copy_name_info(const struct AP_Param::Info *info,
     311             :                         const struct GroupInfo *ginfo,
     312             :                         const struct GroupNesting &group_nesting,
     313             :                         uint8_t idx, char *buffer, size_t bufferSize, bool force_scalar=false) const;
     314             : 
     315             :     /// Copy the variable's name, prefixed by any containing group name, to a
     316             :     /// buffer.
     317             :     ///
     318             :     /// Uses token to look up AP_Param::Info for the variable
     319             :     void copy_name_token(const ParamToken &token, char *buffer, size_t bufferSize, bool force_scalar=false) const;
     320             : 
     321             :     /// Find a variable by name.
     322             :     ///
     323             :     /// If the variable has no name, it cannot be found by this interface.
     324             :     ///
     325             :     /// @param  name            The full name of the variable to be found.
     326             :     /// @param  flags           If non-null will be filled with parameter flags
     327             :     /// @return                 A pointer to the variable, or nullptr if
     328             :     ///                         it does not exist.
     329             :     ///
     330             :     static AP_Param * find(const char *name, enum ap_var_type *ptype, uint16_t *flags = nullptr);
     331             : 
     332             :     /// set a default value by name
     333             :     ///
     334             :     /// @param  name            The full name of the variable to be found.
     335             :     /// @param  value           The default value
     336             :     /// @return                 true if the variable is found
     337             :     static bool set_default_by_name(const char *name, float value);
     338             : 
     339             :     /// set parameter defaults from a defaults_table_struct
     340             :     ///
     341             :     /// @param table            pointer to array of defaults_table_struct structures
     342             :     /// @param count            number of elements in table array
     343             :     static void set_defaults_from_table(const struct defaults_table_struct *table, uint8_t count);
     344             : 
     345             :     /// set a value by name
     346             :     ///
     347             :     /// @param  name            The full name of the variable to be found.
     348             :     /// @param  value           The new value
     349             :     /// @return                 true if the variable is found
     350             :     static bool set_by_name(const char *name, float value);
     351             : 
     352             :     /// gat a value by name, used by scripting
     353             :     ///
     354             :     /// @param  name            The full name of the variable to be found.
     355             :     /// @param  value           A reference to the variable
     356             :     /// @return                 true if the variable is found
     357             :     static bool get(const char *name, float &value);
     358             : 
     359             :     /// set and save a value by name
     360             :     ///
     361             :     /// @param  name            The full name of the variable to be found.
     362             :     /// @param  value           The new value
     363             :     /// @return                 true if the variable is found
     364             :     static bool set_and_save_by_name(const char *name, float value);
     365             :     static bool set_and_save_by_name_ifchanged(const char *name, float value);
     366             : 
     367             :     /// Find a variable by index.
     368             :     ///
     369             :     ///
     370             :     /// @param  idx             The index of the variable
     371             :     /// @return                 A pointer to the variable, or nullptr if
     372             :     ///                         it does not exist.
     373             :     ///
     374             :     static AP_Param * find_by_index(uint16_t idx, enum ap_var_type *ptype, ParamToken *token);
     375             : 
     376             :     // by-name equivalent of find_by_index()
     377             :     static AP_Param* find_by_name(const char* name, enum ap_var_type *ptype, ParamToken *token);
     378             : 
     379             :     /// Find a variable by pointer
     380             :     ///
     381             :     ///
     382             :     /// @param  p               Pointer to variable
     383             :     /// @return                 key for variable
     384             :     static bool find_key_by_pointer_group(const void *ptr, uint16_t vindex, const struct GroupInfo *group_info,
     385             :                                           ptrdiff_t offset, uint16_t &key);
     386             :     static bool find_key_by_pointer(const void *ptr, uint16_t &key);
     387             : 
     388             :     /// Find key of top level group variable by pointer
     389             :     ///
     390             :     ///
     391             :     /// @param  p               Pointer to variable
     392             :     /// @return                 key for variable
     393             :     static bool find_top_level_key_by_pointer(const void *ptr, uint16_t &key);
     394             : 
     395             : 
     396             :     /// Notify GCS of current parameter value
     397             :     ///
     398             :     void notify() const;
     399             : 
     400             :     /// Save the current value of the variable to storage, synchronous API
     401             :     ///
     402             :     /// @param  force_save     If true then force save even if default
     403             :     ///
     404             :     /// @return                True if the variable was saved successfully.
     405             :     ///
     406             :     void save_sync(bool force_save, bool send_to_gcs);
     407             : 
     408             :     /// flush all pending parameter saves
     409             :     /// used on reboot
     410             :     static void flush(void);
     411             : 
     412             :     /// Save the current value of the variable to storage, async interface
     413             :     ///
     414             :     /// @param  force_save     If true then force save even if default
     415             :     ///
     416             :     void save(bool force_save=false);
     417             : 
     418             :     /// Load the variable from EEPROM.
     419             :     ///
     420             :     /// @return                True if the variable was loaded successfully.
     421             :     ///
     422             :     bool load(void);
     423             : 
     424             :     /// Load all variables from EEPROM
     425             :     ///
     426             :     /// This function performs a best-efforts attempt to load all
     427             :     /// of the variables from EEPROM.  If some fail to load, their
     428             :     /// values will remain as they are.
     429             :     ///
     430             :     /// @return                False if any variable failed to load
     431             :     ///
     432             :     static bool load_all();
     433             : 
     434             :     // return true if eeprom is full, used for arming check
     435      133080 :     static bool get_eeprom_full(void) {
     436      133080 :         return eeprom_full;
     437             :     }
     438             : 
     439             :     // returns storage space used:
     440        2018 :     static uint16_t storage_used() { return sentinel_offset; }
     441             : 
     442             :     // returns storage space :
     443        2018 :     static uint16_t storage_size() { return _storage.size(); }
     444             : 
     445             :     /// reoad the hal.util defaults file. Called after pointer parameters have been allocated
     446             :     ///
     447             :     static void reload_defaults_file(bool last_pass);
     448             : 
     449             :     static void load_object_from_eeprom(const void *object_pointer, const struct GroupInfo *group_info);
     450             : 
     451             :     // set a AP_Param variable to a specified value
     452             :     static void         set_value(enum ap_var_type type, void *ptr, float def_value);
     453             : 
     454             :     /*
     455             :       set a parameter to a float
     456             :     */
     457             :     void set_float(float value, enum ap_var_type var_type);
     458             : 
     459             :     // load default values for scalars in a group
     460             :     static void         setup_object_defaults(const void *object_pointer, const struct GroupInfo *group_info);
     461             : 
     462             :     // set a value directly in an object.
     463             :     // return true if the name was found and set, else false.
     464             :     // This should only be used by example code, not by mainline vehicle code
     465             :     static bool set_object_value(const void *object_pointer,
     466             :                                  const struct GroupInfo *group_info,
     467             :                                  const char *name, float value);
     468             : 
     469             :     // load default values for all scalars in the main sketch. This
     470             :     // does not recurse into the sub-objects    
     471             :     static void         setup_sketch_defaults(void);
     472             : 
     473             :     // find an old parameter and return it.
     474             :     static bool find_old_parameter(const struct ConversionInfo *info, AP_Param *value);
     475             : 
     476             :     // convert old vehicle parameters to new object parameters
     477             :     static void         convert_old_parameters(const struct ConversionInfo *conversion_table, uint8_t table_size, uint8_t flags=0);
     478             :     // convert old vehicle parameters to new object parameters with scaling - assumes we use the same scaling factor for all values in the table
     479             :     static void         convert_old_parameters_scaled(const ConversionInfo *conversion_table, uint8_t table_size, float scaler, uint8_t flags);
     480             : 
     481             :     // convert an object which was stored in a vehicle's G2 into a new
     482             :     // object in AP_Vehicle.cpp:
     483             :     struct G2ObjectConversion {
     484             :         void *object_pointer;
     485             :         const struct AP_Param::GroupInfo *var_info;
     486             :         uint16_t old_index;  // Old parameter index in g2
     487             :     };
     488             :     static void         convert_g2_objects(const void *g2, const G2ObjectConversion g2_conversions[], uint8_t num_conversions);
     489             : 
     490             :     // convert an object which was stored in a vehicle's top-level
     491             :     // Parameters object into a new object in AP_Vehicle.cpp:
     492             :     struct TopLevelObjectConversion {
     493             :         void *object_pointer;
     494             :         const struct AP_Param::GroupInfo *var_info;
     495             :         uint16_t old_index;  // Old parameter index in g
     496             :     };
     497             :     static void         convert_toplevel_objects(const TopLevelObjectConversion g2_conversions[], uint8_t num_conversions);
     498             : 
     499             :     /*
     500             :       convert width of a parameter, allowing update to wider scalar
     501             :       values without changing the parameter indexes. This will return
     502             :       true if the parameter was converted from an old parameter value
     503             :     */
     504       96647 :     bool convert_parameter_width(ap_var_type old_ptype, float scale_factor=1.0) {
     505       96647 :         return _convert_parameter_width(old_ptype, scale_factor, false);
     506             :     }
     507        7032 :     bool convert_centi_parameter(ap_var_type old_ptype) {
     508        7032 :         return convert_parameter_width(old_ptype, 0.01f);
     509             :     }
     510             :     // Converting bitmasks should be done bitwise rather than numerically
     511        6264 :     bool convert_bitmask_parameter_width(ap_var_type old_ptype) {
     512        6264 :         return _convert_parameter_width(old_ptype, 1.0, true);
     513             :     }
     514             : 
     515             :     // convert a single parameter with scaling
     516             :     enum {
     517             :         CONVERT_FLAG_REVERSE=1, // handle _REV -> _REVERSED conversion
     518             :         CONVERT_FLAG_FORCE=2    // store new value even if configured in eeprom already
     519             :     };
     520             :     static void         convert_old_parameter(const struct ConversionInfo *info, float scaler, uint8_t flags=0);
     521             : 
     522             :     // move all parameters from a class to a new location
     523             :     // is_top_level: Is true if the class had its own top level key, param_key. It is false if the class was a subgroup
     524             :     static void         convert_class(uint16_t param_key, void *object_pointer,
     525             :                                         const struct AP_Param::GroupInfo *group_info,
     526             :                                         uint16_t old_index, bool is_top_level, bool recurse_sub_groups = false);
     527             : 
     528             :     /*
     529             :       fetch a parameter value based on the index within a group. This
     530             :       is used to find the old value of a parameter that has been
     531             :       removed from an object.
     532             :     */
     533             :     static bool get_param_by_index(void *obj_ptr, uint32_t idx, ap_var_type old_ptype, void *pvalue);
     534             :     
     535             :     /// Erase all variables in EEPROM.
     536             :     ///
     537             :     static void         erase_all(void);
     538             : 
     539             :     /// Returns the first variable
     540             :     ///
     541             :     /// @return             The first variable in _var_info, or nullptr if
     542             :     ///                     there are none.
     543             :     ///
     544             :     static AP_Param *      first(ParamToken *token, enum ap_var_type *ptype, float *default_val = nullptr);
     545             : 
     546             :     /// Returns the next variable in _var_info, recursing into groups
     547             :     /// as needed
     548             :     static AP_Param *      next(ParamToken *token, enum ap_var_type *ptype) { return  next(token, ptype, false); }
     549             :     static AP_Param *      next(ParamToken *token, enum ap_var_type *ptype, bool skip_disabled, float *default_val = nullptr);
     550             : 
     551             :     /// Returns the next scalar variable in _var_info, recursing into groups
     552             :     /// as needed
     553             :     static AP_Param *       next_scalar(ParamToken *token, enum ap_var_type *ptype, float *default_val = nullptr);
     554             : 
     555             :     /// get the size of a type in bytes
     556             :     static uint8_t                              type_size(enum ap_var_type type);
     557             : 
     558             :     /// cast a variable to a float given its type
     559             :     float                   cast_to_float(enum ap_var_type type) const;
     560             : 
     561             :     // check var table for consistency
     562             :     static void             check_var_info(void);
     563             : 
     564             :     // return true if the parameter is configured
     565             :     bool configured(void) const;
     566             : 
     567             :     // return true if the parameter is read-only
     568             :     bool is_read_only(void) const;
     569             : 
     570             :     // return the persistent top level key for the ParamToken key
     571           0 :     static uint16_t get_persistent_key(uint16_t key) { return var_info(key).key; }
     572             : 
     573             :     // returns true if this parameter should be settable via the
     574             :     // MAVLink interface:
     575             :     bool allow_set_via_mavlink(uint16_t flags) const;
     576             : 
     577             :     // count of parameters in tree
     578             :     static uint16_t count_parameters(void);
     579             : 
     580             :     // invalidate parameter count
     581             :     static void invalidate_count(void);
     582             : 
     583           7 :     static void set_hide_disabled_groups(bool value) { _hide_disabled_groups = value; }
     584             : 
     585             :     // set frame type flags. Used to unhide frame specific parameters
     586        2154 :     static void set_frame_type_flags(uint16_t flags_to_set) {
     587        2154 :         invalidate_count();
     588        2154 :         _frame_type_flags |= flags_to_set;
     589        2154 :     }
     590             : 
     591             :     // check if a given frame type should be included
     592             :     static bool check_frame_type(uint16_t flags);
     593             : 
     594             : #if AP_PARAM_KEY_DUMP
     595             :     /// print the value of all variables
     596             :     static void         show_all(AP_HAL::BetterStream *port, bool showKeyValues=false);
     597             : 
     598             :     /// print the value of one variable
     599             :     static void         show(const AP_Param *param, 
     600             :                              const char *name,
     601             :                              enum ap_var_type ptype, 
     602             :                              AP_HAL::BetterStream *port);
     603             : 
     604             :     /// print the value of one variable
     605             :     static void         show(const AP_Param *param, 
     606             :                              const ParamToken &token,
     607             :                              enum ap_var_type ptype, 
     608             :                              AP_HAL::BetterStream *port);
     609             : #endif // AP_PARAM_KEY_DUMP
     610             : 
     611        5344 :     static AP_Param *get_singleton() { return _singleton; }
     612             : 
     613             : #if AP_PARAM_DYNAMIC_ENABLED
     614             :     // allow for dynamically added parameter tables from scripts
     615             :     static bool add_table(uint8_t key, const char *prefix, uint8_t num_params);
     616             :     static bool add_param(uint8_t key, uint8_t param_num, const char *pname, float default_value);
     617             :     static bool load_int32(uint16_t key, uint32_t group_element, int32_t &value);
     618             : #endif
     619             : 
     620             :     static bool load_defaults_file(const char *filename, bool last_pass);
     621             : 
     622             : protected:
     623             : 
     624             :     // store default value in linked list
     625             :     static void add_default(AP_Param *ap, float v);
     626             : 
     627             : private:
     628             :     static AP_Param *_singleton;
     629             : 
     630             :     /// EEPROM header
     631             :     ///
     632             :     /// This structure is placed at the head of the EEPROM to indicate
     633             :     /// that the ROM is formatted for AP_Param.
     634             :     ///
     635             :     struct EEPROM_header {
     636             :         uint8_t magic[2];
     637             :         uint8_t revision;
     638             :         uint8_t spare;
     639             :     };
     640             :     static_assert(sizeof(struct EEPROM_header) == 4, "Bad EEPROM_header size!");
     641             : 
     642             :     static uint16_t sentinel_offset;
     643             : 
     644             : /* This header is prepended to a variable stored in EEPROM.
     645             :  *  The meaning is as follows:
     646             :  *
     647             :  *  - key: the k_param enum value from Parameter.h in the sketch
     648             :  *
     649             :  *  - group_element: This is zero for top level parameters. For
     650             :  *                   parameters stored within an object this is divided
     651             :  *                   into 3 lots of 6 bits, allowing for three levels
     652             :  *                   of object to be stored in the eeprom
     653             :  *
     654             :  *  - type: the ap_var_type value for the variable
     655             :  */
     656             :     struct Param_header {
     657             :         // to get 9 bits for key we needed to split it into two parts to keep binary compatibility
     658             :         uint32_t key_low : 8;
     659             :         uint32_t type : 5;
     660             :         uint32_t key_high : 1;
     661             :         uint32_t group_element : 18;
     662             :     };
     663             :     static_assert(sizeof(struct Param_header) == 4, "Bad Param_header size!");
     664             : 
     665             :     // number of bits in each level of nesting of groups
     666             :     static const uint8_t        _group_level_shift = 6;
     667             :     static const uint8_t        _group_bits  = 18;
     668             : 
     669             :     static const uint16_t       _sentinel_key   = 0x1FF;
     670             :     static const uint8_t        _sentinel_type  = 0x1F;
     671             :     static const uint8_t        _sentinel_group = 0xFF;
     672             : 
     673             :     static uint16_t             _frame_type_flags;
     674             : 
     675             :     /*
     676             :       this is true if when scanning a defaults file we find all of the parameters
     677             :      */
     678             :     static bool done_all_default_params;
     679             : 
     680             :     /*
     681             :       structure for built-in defaults file that can be modified using apj_tool.py
     682             :      */
     683             : #if AP_PARAM_MAX_EMBEDDED_PARAM > 0
     684             :     struct PACKED param_defaults_struct {
     685             :         char magic_str[8];
     686             :         uint8_t param_magic[8];
     687             :         uint16_t max_length;
     688             :         volatile uint16_t length;
     689             :         volatile char data[AP_PARAM_MAX_EMBEDDED_PARAM];
     690             :     };
     691             :     static const param_defaults_struct param_defaults_data;
     692             : #endif
     693             : 
     694             : 
     695             :     static void                 check_group_info(const struct GroupInfo *group_info, uint16_t *total_size, 
     696             :                                                  uint8_t max_bits, uint8_t prefix_length);
     697             :     static bool                 duplicate_key(uint16_t vindex, uint16_t key);
     698             : 
     699             :     static bool adjust_group_offset(uint16_t vindex, const struct GroupInfo &group_info, ptrdiff_t &new_offset);
     700             :     static bool get_base(const struct Info &info, ptrdiff_t &base);
     701             : 
     702             :     /// get group_info pointer based on flags
     703             :     static const struct GroupInfo *get_group_info(const struct GroupInfo &ginfo);
     704             : 
     705             :     /// get group_info pointer based on flags
     706             :     static const struct GroupInfo *get_group_info(const struct Info &ginfo);
     707             : 
     708             :     const struct Info *         find_var_info_group(
     709             :                                     const struct GroupInfo *    group_info,
     710             :                                     uint16_t                    vindex,
     711             :                                     uint32_t                    group_base,
     712             :                                     uint8_t                     group_shift,
     713             :                                     ptrdiff_t                   group_offset,
     714             :                                     uint32_t *                  group_element,
     715             :                                     const struct GroupInfo *   &group_ret,
     716             :                                     struct GroupNesting        &group_nesting,
     717             :                                     uint8_t *                   idx) const;
     718             :     const struct Info *         find_var_info(
     719             :                                     uint32_t *                group_element,
     720             :                                     const struct GroupInfo *  &group_ret,
     721             :                                     struct GroupNesting       &group_nesting,
     722             :                                     uint8_t *                 idx) const;
     723             :     const struct Info *                 find_var_info_token(const ParamToken &token,
     724             :                                                     uint32_t *                 group_element,
     725             :                                                     const struct GroupInfo *  &group_ret,
     726             :                                                     struct GroupNesting       &group_nesting,
     727             :                                                     uint8_t *                  idx) const;
     728             :     static const struct Info *  find_by_header_group(
     729             :                                     struct Param_header phdr, void **ptr,
     730             :                                     uint16_t vindex,
     731             :                                     const struct GroupInfo *group_info,
     732             :                                     uint32_t group_base,
     733             :                                     uint8_t group_shift,
     734             :                                     ptrdiff_t group_offset);
     735             :     static const struct Info *  find_by_header(
     736             :                                     struct Param_header phdr,
     737             :                                     void **ptr);
     738             :     void                        add_vector3f_suffix(
     739             :                                     char *buffer,
     740             :                                     size_t buffer_size,
     741             :                                     uint8_t idx) const;
     742             :     static AP_Param *           find_group(
     743             :                                     const char *name,
     744             :                                     uint16_t vindex,
     745             :                                     ptrdiff_t group_offset,
     746             :                                     const struct GroupInfo *group_info,
     747             :                                     enum ap_var_type *ptype);
     748             :     static void                 write_sentinel(uint16_t ofs);
     749             :     static uint16_t             get_key(const Param_header &phdr);
     750             :     static void                 set_key(Param_header &phdr, uint16_t key);
     751             :     static bool                 is_sentinel(const Param_header &phrd);
     752             :     static bool                 scan(
     753             :                                     const struct Param_header *phdr,
     754             :                                     uint16_t *pofs);
     755             :     static void                 eeprom_write_check(
     756             :                                     const void *ptr,
     757             :                                     uint16_t ofs,
     758             :                                     uint8_t size);
     759             :     static AP_Param *           next_group(
     760             :                                     const uint16_t vindex,
     761             :                                     const struct GroupInfo *group_info,
     762             :                                     bool *found_current,
     763             :                                     const uint32_t group_base,
     764             :                                     const uint8_t group_shift,
     765             :                                     const ptrdiff_t group_offset,
     766             :                                     ParamToken *token,
     767             :                                     enum ap_var_type *ptype,
     768             :                                     bool skip_disabled,
     769             :                                     float *default_val);
     770             : 
     771             :     // find a default value given a pointer to a default value in flash
     772             :     static float get_default_value(const AP_Param *object_ptr, const struct GroupInfo &info);
     773             :     static float get_default_value(const AP_Param *object_ptr, const struct Info &info);
     774             : 
     775             :     static bool parse_param_line(char *line, char **vname, float &value, bool &read_only);
     776             : 
     777             :     /*
     778             :       load a parameter defaults file. This happens as part of load_all()
     779             :      */
     780             :     static bool count_defaults_in_file(const char *filename, uint16_t &num_defaults);
     781             :     static bool count_param_defaults(const volatile char *ptr, int32_t length, uint16_t &count);
     782             :     static bool read_param_defaults_file(const char *filename, bool last_pass, uint16_t &idx);
     783             : 
     784             :     // load a defaults.parm using AP_FileSystem:
     785             :     static void load_defaults_file_from_filesystem(const char *filename, bool lastpass);
     786             :     // load an @ROMFS defaults.parm using ROMFS API:
     787             :     static void load_defaults_file_from_romfs(const char *filename, bool lastpass);
     788             : 
     789             :     // load defaults from supplied string:
     790             :     static void load_param_defaults(const volatile char *ptr, int32_t length, bool last_pass);
     791             : 
     792             :     /*
     793             :       load defaults from embedded parameters
     794             :      */
     795             :     static bool count_embedded_param_defaults(uint16_t &count);
     796             :     static void load_embedded_param_defaults(bool last_pass);
     797             : 
     798             :     // return true if the parameter is configured in the defaults file
     799             :     bool configured_in_defaults_file(bool &read_only) const;
     800             : 
     801             :     // return true if the parameter is configured in EEPROM/FRAM
     802             :     bool configured_in_storage(void) const;
     803             : 
     804             :     /*
     805             :       convert width of a parameter, allowing update to wider scalar
     806             :       values without changing the parameter indexes. This will return
     807             :       true if the parameter was converted from an old parameter value
     808             :     */
     809             :     bool _convert_parameter_width(ap_var_type old_ptype, float scale_factor, bool bitmask);
     810             : 
     811             :     // send a parameter to all GCS instances
     812             :     void send_parameter(const char *name, enum ap_var_type param_header_type, uint8_t idx) const;
     813             : 
     814             :     static StorageAccess        _storage;
     815             :     static StorageAccess        _storage_bak;
     816             :     static uint16_t             _num_vars;
     817             :     static uint16_t             _parameter_count;
     818             :     static uint16_t             _count_marker;
     819             :     static uint16_t             _count_marker_done;
     820             :     static HAL_Semaphore        _count_sem;
     821             :     static const struct Info *  _var_info;
     822             : 
     823             : #if AP_PARAM_DYNAMIC_ENABLED
     824             :     // allow for a dynamically allocated var table
     825             :     static uint16_t             _num_vars_base;
     826             :     static struct Info *        _var_info_dynamic;
     827   537296824 :     static const struct AP_Param::Info &var_info(uint16_t i) {
     828   537296824 :         return i<_num_vars_base? _var_info[i] : _var_info_dynamic[i-_num_vars_base];
     829             :     }
     830             :     static uint8_t _dynamic_table_sizes[AP_PARAM_MAX_DYNAMIC];
     831             : #else
     832             :     // simple static var table in flash
     833             :     static const struct Info &var_info(uint16_t i) {
     834             :         return _var_info[i];
     835             :     }
     836             : #endif
     837             : 
     838             :     /*
     839             :       list of overridden values from load_defaults_file()
     840             :     */
     841             :     struct param_override {
     842             :         const AP_Param *object_ptr;
     843             :         float value;
     844             :         bool read_only; // param is marked @READONLY
     845             :     };
     846             :     static struct param_override *param_overrides;
     847             :     static uint16_t num_param_overrides;
     848             :     static uint16_t param_overrides_len;
     849             :     static uint16_t num_read_only;
     850             : 
     851             :     // values filled into the EEPROM header
     852             :     static const uint8_t        k_EEPROM_magic0      = 0x50;
     853             :     static const uint8_t        k_EEPROM_magic1      = 0x41; ///< "AP"
     854             :     static const uint8_t        k_EEPROM_revision    = 6; ///< current format revision
     855             : 
     856             :     static bool _hide_disabled_groups;
     857             : 
     858             :     // support for background saving of parameters. We pack it to reduce memory for the
     859             :     // queue
     860             :     struct PACKED param_save {
     861             :         AP_Param *param;
     862             :         bool force_save;
     863             :     };
     864             :     static ObjectBuffer_TS<struct param_save> save_queue;
     865             :     static bool registered_save_handler;
     866             : 
     867             :     // background function for saving parameters
     868             :     void save_io_handler(void);
     869             : 
     870             :     // Store default values from add_default() calls in linked list
     871             :     struct defaults_list {
     872             :         AP_Param *ap;
     873             :         float val;
     874             :         defaults_list *next;
     875             :     };
     876             :     static defaults_list *default_list;
     877             :     static void check_default(AP_Param *ap, float *default_value);
     878             :     static void purge_defaults_list_overrides(void);
     879             : 
     880             :     static bool eeprom_full;
     881             : };
     882             : 
     883             : namespace AP {
     884             :     AP_Param *param();
     885             : };
     886             : 
     887             : /// Template class for scalar variables.
     888             : ///
     889             : /// Objects of this type have a value, though the infrastructure to actually
     890             : /// treat them as a value is delegated to a type-specialized subclass.
     891             : ///
     892             : /// @tparam T                   The scalar type of the variable
     893             : /// @tparam PT                  The AP_PARAM_* type
     894             : ///
     895             : template<typename T, ap_var_type PT>
     896             : class AP_ParamTBase : public AP_Param
     897             : {
     898             : public:
     899             :     static const ap_var_type        vtype = PT;
     900             : 
     901             :     /// Value getter
     902             :     ///
     903 19062515710 :     const T &get(void) const {
     904 19062515710 :         return _value;
     905             :     }
     906             : 
     907             :     /// Value setter
     908             :     ///
     909    65792242 :     void set(const T &v) {
     910    65792242 :         _value = v;
     911    65792242 :     }
     912             : 
     913             :     // set a parameter that is an ENABLE param
     914             :     void set_enable(const T &v);
     915             :     
     916             :     /// Sets if the parameter is unconfigured
     917             :     ///
     918             :     void set_default(const T &v);
     919             : 
     920             :     /// Sets parameter and default
     921             :     ///
     922             :     void set_and_default(const T &v);
     923             : 
     924             :     /// Value setter - set value, tell GCS
     925             :     ///
     926             :     void set_and_notify(const T &v);
     927             : 
     928             :     /// Combined set and save
     929             :     ///
     930             :     void set_and_save(const T &v);
     931             : 
     932             :     /// Combined set and save, but only does the save if the value if
     933             :     /// different from the current ram value, thus saving us a
     934             :     /// scan(). This should only be used where we have not set() the
     935             :     /// value separately, as otherwise the value in EEPROM won't be
     936             :     /// updated correctly.
     937             :     void set_and_save_ifchanged(const T &v);
     938             : 
     939             :     /// AP_ParamTBase types can implement AP_Param::cast_to_float
     940             :     ///
     941             :     float cast_to_float(void) const;
     942             : 
     943             : protected:
     944             :     T _value;
     945             : };
     946             : 
     947             : template<typename T, ap_var_type PT>
     948             : class AP_ParamT : public AP_ParamTBase<T, PT> // for int and smaller types
     949             : {
     950             : public:
     951             :     /// Conversion to T returns a reference to the value. A reference is
     952             :     /// necessary as some users expect to pass a reference around.
     953             :     ///
     954             :     /// This allows the class to be used in many situations where the value
     955             :     /// would be legal.
     956             :     ///
     957             :     /// Note that this can cause strange conversions: the value can be silently
     958             :     /// converted to a smaller type, causing unexpected truncation in an
     959             :     /// expression like `int16_t v = true ? int16_param : (int8_t)0`.
     960             :     ///
     961             :     /// C numeric conversion rules can be reinstated where needed by simply
     962             :     /// calling `.get()` on the value.
     963             :     ///
     964 39218134752 :     operator const T &() const {
     965 39218134752 :         return this->_value;
     966             :     }
     967             : };
     968             : 
     969             : template<>
     970             : class AP_ParamT<float, AP_PARAM_FLOAT> : public AP_ParamTBase<float, AP_PARAM_FLOAT>
     971             : {
     972             : public:
     973             :     /// Conversion to float returns a reference to the value. A reference is
     974             :     /// necessary as some users expect to pass a reference around.
     975             :     ///
     976             :     /// This allows the class to be used in many situations where the value
     977             :     /// would be legal.
     978             :     ///
     979             :     /// We must return a float and specifically make this function a template to
     980             :     /// forbid further conversions: paraphrasing [over.ics.user] clause 3,
     981             :     /// templated user-defined conversion functions require that a further
     982             :     /// conversion be an exact match. This prevents the value from silently
     983             :     /// converting to an int and causing unexpected truncation in an expression
     984             :     /// like `float v = true ? float_param : 0`.
     985             :     ///
     986             :     /// This does also prevent implicit conversion to double, but that is a
     987             :     /// relatively small price to pay. C numeric conversion rules can be
     988             :     /// reinstated where needed by simply calling `.get()` on the value, or by
     989             :     /// manually casting to `double` or `int`.
     990             :     ///
     991             :     template<bool X = true>
     992 45971212828 :     operator const float &() const {
     993 45971212828 :         return this->_value;
     994             :     }
     995             : 
     996             :     explicit operator int () const { // convenience function for int casts
     997             :         return (int)this->_value;
     998             :     }
     999             : 
    1000   356413660 :     explicit operator double () const { // convenience function for double casts
    1001   356413660 :         return (double)this->_value;
    1002             :     }
    1003             : 
    1004             : #if defined(__clang__)
    1005             :     // inexplicably, clang will not use the built-in operator implementations
    1006             :     // for floats on two AP_ParamT<float>s, so provide them for it.
    1007             : 
    1008             :     float operator -() const { return -this->_value; } // unary minus
    1009             : 
    1010             : #define PARAM_SELF_OPER(R, OP) \
    1011             :     R operator OP (const AP_ParamT<float, AP_PARAM_FLOAT>& other) const { return this->_value OP other._value; }
    1012             : 
    1013             :     PARAM_SELF_OPER(float, +);
    1014             :     PARAM_SELF_OPER(float, -);
    1015             :     PARAM_SELF_OPER(float, *);
    1016             :     PARAM_SELF_OPER(float, /);
    1017             :     PARAM_SELF_OPER(bool, >);
    1018             :     PARAM_SELF_OPER(bool, <);
    1019             :     PARAM_SELF_OPER(bool, <=);
    1020             :     PARAM_SELF_OPER(bool, >=);
    1021             :     // != and == are unsafe on floats
    1022             : 
    1023             : #undef PARAM_SELF_OPER
    1024             : 
    1025             : #endif
    1026             : };
    1027             : 
    1028             : /// Template class for non-scalar variables, intended for non-C types.
    1029             : ///
    1030             : /// Objects of this type have an object value, and can be treated in many ways
    1031             : /// as though they were the value.
    1032             : ///
    1033             : /// @tparam T                   The scalar type of the variable
    1034             : /// @tparam PT                  AP_PARAM_* type
    1035             : ///
    1036             : template<typename T, ap_var_type PT>
    1037             : class AP_ParamV : public AP_Param
    1038             : {
    1039             : public:
    1040             : 
    1041             :     static const ap_var_type        vtype = PT;
    1042             : 
    1043             :     /// Value getter
    1044             :     ///
    1045  6115373036 :     const T &get(void) const {
    1046  6115373036 :         return _value;
    1047             :     }
    1048             : 
    1049             :     /// Value setter
    1050             :     ///
    1051      220082 :     void set(const T &v) {
    1052      220082 :         _value = v;
    1053      220082 :     }
    1054             : 
    1055             :     /// Value setter - set value, tell GCS
    1056             :     ///
    1057             :     void set_and_notify(const T &v);
    1058             : 
    1059             :     /// Combined set and save
    1060             :     ///
    1061             :     void set_and_save(const T &v);
    1062             : 
    1063             :     /// Combined set and save, but only does the save if the value is
    1064             :     /// different from the current ram value, thus saving us a
    1065             :     /// scan(). This should only be used where we have not set() the
    1066             :     /// value separately, as otherwise the value in EEPROM won't be
    1067             :     /// updated correctly.
    1068             :     void set_and_save_ifchanged(const T &v);
    1069             : 
    1070             : 
    1071             :     /// Conversion to T returns a reference to the value. A reference is
    1072             :     /// necessary as some users expect to pass a reference around.
    1073             :     ///
    1074             :     /// This allows the class to be used in many situations where the value
    1075             :     /// would be legal. As T is a user-defined class and not a C type, we don't
    1076             :     /// have to worry about weird numeric conversions.
    1077             :     ///
    1078  6795795571 :     operator const T &() const {
    1079  6795795571 :         return _value;
    1080             :     }
    1081             : 
    1082             : protected:
    1083             :     T        _value;
    1084             : };
    1085             : 
    1086             : 
    1087             : /// Convenience macro for defining instances of the AP_ParamT template.
    1088             : ///
    1089             : // declare a scalar type
    1090             : // _t is the base type
    1091             : // _suffix is the suffix on the AP_* type name
    1092             : // _pt is the enum ap_var_type type
    1093             : #define AP_PARAMDEF(_t, _suffix, _pt)   typedef AP_ParamT<_t, _pt> AP_ ## _suffix;
    1094             : AP_PARAMDEF(float, Float, AP_PARAM_FLOAT);    // defines AP_Float, requires specialization!
    1095             : AP_PARAMDEF(int8_t, Int8, AP_PARAM_INT8);     // defines AP_Int8
    1096             : AP_PARAMDEF(int16_t, Int16, AP_PARAM_INT16);  // defines AP_Int16
    1097             : AP_PARAMDEF(int32_t, Int32, AP_PARAM_INT32);  // defines AP_Int32
    1098             : 
    1099             : // declare a non-scalar type
    1100             : // this is used in AP_Math.h
    1101             : // _t is the base type
    1102             : // _suffix is the suffix on the AP_* type name
    1103             : // _pt is the enum ap_var_type type
    1104             : #define AP_PARAMDEFV(_t, _suffix, _pt)   typedef AP_ParamV<_t, _pt> AP_ ## _suffix;
    1105             : 
    1106             : // see comment in the AP_ParamT float specialization
    1107             : static_assert(not std::is_convertible<AP_Float, int>::value, "illegal conversion possible");
    1108             : 
    1109             : /*
    1110             :   template class for enum types based on AP_Int8
    1111             :  */
    1112             : template<typename eclass>
    1113             : class AP_Enum : public AP_Int8
    1114             : {
    1115             : public:
    1116  3872286105 :     operator const eclass () const {
    1117  3872286105 :         return (eclass)_value;
    1118             :     }
    1119          13 :     void set(eclass v) {
    1120          13 :         AP_Int8::set(int8_t(v));
    1121          13 :     }
    1122         381 :     void set_and_save(eclass v) {
    1123         381 :         AP_Int8::set_and_save(int8_t(v));
    1124         381 :     }
    1125             : };
    1126             : 
    1127             : template<typename eclass>
    1128             : class AP_Enum16 : public AP_Int16
    1129             : {
    1130             : public:
    1131  6876668741 :     operator const eclass () const {
    1132  6876668741 :         return (eclass)_value;
    1133             :     }
    1134             :     void set(eclass v) {
    1135             :         AP_Int16::set(int16_t(v));
    1136             :     }
    1137             :     void set_and_save(eclass v) {
    1138             :         AP_Int16::set_and_save(int16_t(v));
    1139             :     }
    1140             : };

Generated by: LCOV version 1.14