/* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ // // // total up and check overflow // check size of group var_info /// @file AP_Param.cpp /// @brief The AP variable store. #include "AP_Param.h" #include #include #include #include #include #include #include #include #include #include #include #include #if CONFIG_HAL_BOARD == HAL_BOARD_SITL #include #endif #include "AP_Param_config.h" extern const AP_HAL::HAL &hal; uint16_t AP_Param::sentinal_offset; // singleton instance AP_Param *AP_Param::_singleton; #define ENABLE_DEBUG 0 #if ENABLE_DEBUG # define FATAL(fmt, args ...) AP_HAL::panic(fmt, ## args); # define Debug(fmt, args ...) do {::printf("%s:%d: " fmt "\n", __FUNCTION__, __LINE__, ## args); } while(0) #else # define FATAL(fmt, args ...) AP_HAL::panic("Bad parameter table"); # define Debug(fmt, args ...) #endif #if HAL_GCS_ENABLED #define GCS_SEND_PARAM(name, type, v) gcs().send_parameter_value(name, type, v) #else #define GCS_SEND_PARAM(name, type, v) #endif // Note about AP_Vector3f handling. // The code has special cases for AP_Vector3f to allow it to be viewed // as both a single 3 element vector and as a set of 3 AP_Float // variables. This is done to make it possible for MAVLink to see // vectors as parameters, which allows users to save their compass // offsets in MAVLink parameter files. The code involves quite a few // special cases which could be generalised to any vector/matrix type // if we end up needing this behaviour for other than AP_Vector3f // static member variables for AP_Param. // // number of rows in the _var_info[] table uint16_t AP_Param::_num_vars; #if AP_PARAM_DYNAMIC_ENABLED uint16_t AP_Param::_num_vars_base; AP_Param::Info *AP_Param::_var_info_dynamic; static const char *_empty_string = ""; uint8_t AP_Param::_dynamic_table_sizes[AP_PARAM_MAX_DYNAMIC]; #endif // cached parameter count uint16_t AP_Param::_parameter_count; uint16_t AP_Param::_count_marker; uint16_t AP_Param::_count_marker_done; HAL_Semaphore AP_Param::_count_sem; // storage and naming information about all types that can be saved const AP_Param::Info *AP_Param::_var_info; struct AP_Param::param_override *AP_Param::param_overrides; uint16_t AP_Param::param_overrides_len; uint16_t AP_Param::num_param_overrides; uint16_t AP_Param::num_read_only; ObjectBuffer_TS AP_Param::save_queue{30}; bool AP_Param::registered_save_handler; AP_Param::defaults_list *AP_Param::default_list; // we need a dummy object for the parameter save callback static AP_Param save_dummy; #if AP_PARAM_MAX_EMBEDDED_PARAM > 0 /* this holds default parameters in the normal NAME=value form for a parameter file. It can be manipulated by apj_tool.py to change the defaults on a binary without recompiling */ const AP_Param::param_defaults_struct AP_Param::param_defaults_data = { "PARMDEF", { 0x55, 0x37, 0xf4, 0xa0, 0x38, 0x5d, 0x48, 0x5b }, AP_PARAM_MAX_EMBEDDED_PARAM, 0 }; #endif // storage object StorageAccess AP_Param::_storage(StorageManager::StorageParam); // backup storage object StorageAccess AP_Param::_storage_bak(StorageManager::StorageParamBak); // flags indicating frame type uint16_t AP_Param::_frame_type_flags; // write to EEPROM void AP_Param::eeprom_write_check(const void *ptr, uint16_t ofs, uint8_t size) { _storage.write_block(ofs, ptr, size); _storage_bak.write_block(ofs, ptr, size); } bool AP_Param::_hide_disabled_groups = true; // write a sentinal value at the given offset void AP_Param::write_sentinal(uint16_t ofs) { struct Param_header phdr; phdr.type = _sentinal_type; set_key(phdr, _sentinal_key); phdr.group_element = _sentinal_group; eeprom_write_check(&phdr, ofs, sizeof(phdr)); sentinal_offset = ofs; } // erase all EEPROM variables by re-writing the header and adding // a sentinal void AP_Param::erase_all(void) { struct EEPROM_header hdr; // write the header hdr.magic[0] = k_EEPROM_magic0; hdr.magic[1] = k_EEPROM_magic1; hdr.revision = k_EEPROM_revision; hdr.spare = 0; eeprom_write_check(&hdr, 0, sizeof(hdr)); // add a sentinal directly after the header write_sentinal(sizeof(struct EEPROM_header)); } /* the 'group_id' of a element of a group is the 18 bit identifier used to distinguish between this element of the group and other elements of the same group. It is calculated using a bit shift per level of nesting, so the first level of nesting gets 6 bits the 2nd level gets the next 6 bits, and the 3rd level gets the last 6 bits. This limits groups to having at most 64 elements. */ uint32_t AP_Param::group_id(const struct GroupInfo *grpinfo, uint32_t base, uint8_t i, uint8_t shift) { if (grpinfo[i].idx == 0 && shift != 0 && !(grpinfo[i].flags & AP_PARAM_FLAG_NO_SHIFT)) { /* this is a special case for a bug in the original design. An idx of 0 shifted by n bits is still zero, which makes it indistinguishable from a different parameter. This can lead to parameter loops. We use index 63 for that case. */ return base + (63U<