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 : };
|