mirror of https://github.com/ArduPilot/ardupilot
AP_Param: added support for dynamic parameter tables
this allows for up to 10 dynamic tables to be added by scripts. The parameter tables can have up to 63 float parameters
This commit is contained in:
parent
1ecb129afa
commit
1343af85e2
|
@ -75,6 +75,13 @@ AP_Param *AP_Param::_singleton;
|
|||
// 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;
|
||||
|
@ -183,6 +190,10 @@ uint32_t AP_Param::group_id(const struct GroupInfo *grpinfo, uint32_t base, uint
|
|||
*/
|
||||
bool AP_Param::check_frame_type(uint16_t flags)
|
||||
{
|
||||
if (flags & AP_PARAM_FLAG_HIDDEN) {
|
||||
// hidden on all frames
|
||||
return false;
|
||||
}
|
||||
uint16_t frame_flags = flags >> AP_PARAM_FRAME_TYPE_SHIFT;
|
||||
if (frame_flags == 0) {
|
||||
return true;
|
||||
|
@ -248,7 +259,7 @@ bool AP_Param::check_group_info(const struct AP_Param::GroupInfo * group_info,
|
|||
bool AP_Param::duplicate_key(uint16_t vindex, uint16_t key)
|
||||
{
|
||||
for (uint16_t i=vindex+1; i<_num_vars; i++) {
|
||||
uint16_t key2 = _var_info[i].key;
|
||||
uint16_t key2 = var_info(i).key;
|
||||
if (key2 == key) {
|
||||
// no duplicate keys allowed
|
||||
return true;
|
||||
|
@ -285,18 +296,18 @@ bool AP_Param::check_var_info(void)
|
|||
uint16_t total_size = sizeof(struct EEPROM_header);
|
||||
|
||||
for (uint16_t i=0; i<_num_vars; i++) {
|
||||
uint8_t type = _var_info[i].type;
|
||||
uint16_t key = _var_info[i].key;
|
||||
uint8_t type = var_info(i).type;
|
||||
uint16_t key = var_info(i).key;
|
||||
if (type == AP_PARAM_GROUP) {
|
||||
if (i == 0) {
|
||||
// first element can't be a group, for first() call
|
||||
return false;
|
||||
}
|
||||
const struct GroupInfo *group_info = get_group_info(_var_info[i]);
|
||||
const struct GroupInfo *group_info = get_group_info(var_info(i));
|
||||
if (group_info == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if (!check_group_info(group_info, &total_size, 0, strlen(_var_info[i].name))) {
|
||||
if (!check_group_info(group_info, &total_size, 0, strlen(var_info(i).name))) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
@ -311,7 +322,7 @@ bool AP_Param::check_var_info(void)
|
|||
if (duplicate_key(i, key)) {
|
||||
return false;
|
||||
}
|
||||
if (type != AP_PARAM_GROUP && (_var_info[i].flags & AP_PARAM_FLAG_POINTER)) {
|
||||
if (type != AP_PARAM_GROUP && (var_info(i).flags & AP_PARAM_FLAG_POINTER)) {
|
||||
// only groups can be pointers
|
||||
return false;
|
||||
}
|
||||
|
@ -378,7 +389,7 @@ bool AP_Param::adjust_group_offset(uint16_t vindex, const struct GroupInfo &grou
|
|||
if (group_info.flags & AP_PARAM_FLAG_POINTER) {
|
||||
// group_info.offset refers to a pointer
|
||||
ptrdiff_t base;
|
||||
if (!get_base(_var_info[vindex], base)) {
|
||||
if (!get_base(var_info(vindex), base)) {
|
||||
// the object is not allocated yet
|
||||
return false;
|
||||
}
|
||||
|
@ -456,11 +467,11 @@ const struct AP_Param::Info *AP_Param::find_by_header_group(struct Param_header
|
|||
if (group_id(group_info, group_base, i, group_shift) == phdr.group_element && type == phdr.type) {
|
||||
// found a group element
|
||||
ptrdiff_t base;
|
||||
if (!get_base(_var_info[vindex], base)) {
|
||||
if (!get_base(var_info(vindex), base)) {
|
||||
continue;
|
||||
}
|
||||
*ptr = (void*)(base + group_info[i].offset + group_offset);
|
||||
return &_var_info[vindex];
|
||||
return &var_info(vindex);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
|
@ -472,14 +483,14 @@ const struct AP_Param::Info *AP_Param::find_by_header(struct Param_header phdr,
|
|||
{
|
||||
// loop over all named variables
|
||||
for (uint16_t i=0; i<_num_vars; i++) {
|
||||
uint8_t type = _var_info[i].type;
|
||||
uint16_t key = _var_info[i].key;
|
||||
uint8_t type = var_info(i).type;
|
||||
uint16_t key = var_info(i).key;
|
||||
if (key != get_key(phdr)) {
|
||||
// not the right key
|
||||
continue;
|
||||
}
|
||||
if (type == AP_PARAM_GROUP) {
|
||||
const struct GroupInfo *group_info = get_group_info(_var_info[i]);
|
||||
const struct GroupInfo *group_info = get_group_info(var_info(i));
|
||||
if (group_info == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
@ -488,11 +499,11 @@ const struct AP_Param::Info *AP_Param::find_by_header(struct Param_header phdr,
|
|||
if (type == phdr.type) {
|
||||
// found it
|
||||
ptrdiff_t base;
|
||||
if (!get_base(_var_info[i], base)) {
|
||||
if (!get_base(var_info(i), base)) {
|
||||
return nullptr;
|
||||
}
|
||||
*ptr = (void*)base;
|
||||
return &_var_info[i];
|
||||
return &var_info(i);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
|
@ -510,7 +521,7 @@ const struct AP_Param::Info *AP_Param::find_var_info_group(const struct GroupInf
|
|||
uint8_t * idx) const
|
||||
{
|
||||
ptrdiff_t base;
|
||||
if (!get_base(_var_info[vindex], base)) {
|
||||
if (!get_base(var_info(vindex), base)) {
|
||||
return nullptr;
|
||||
}
|
||||
uint8_t type;
|
||||
|
@ -554,7 +565,7 @@ const struct AP_Param::Info *AP_Param::find_var_info_group(const struct GroupInf
|
|||
*group_element = group_id(group_info, group_base, i, group_shift);
|
||||
group_ret = &group_info[i];
|
||||
*idx = 0;
|
||||
return &_var_info[vindex];
|
||||
return &var_info(vindex);
|
||||
} else if (type == AP_PARAM_VECTOR3F &&
|
||||
(base+ofs+(ptrdiff_t)sizeof(float) == (ptrdiff_t) this ||
|
||||
base+ofs+2*(ptrdiff_t)sizeof(float) == (ptrdiff_t) this)) {
|
||||
|
@ -563,7 +574,7 @@ const struct AP_Param::Info *AP_Param::find_var_info_group(const struct GroupInf
|
|||
*idx = (((ptrdiff_t) this) - (base+ofs))/sizeof(float);
|
||||
*group_element = group_id(group_info, group_base, i, group_shift);
|
||||
group_ret = &group_info[i];
|
||||
return &_var_info[vindex];
|
||||
return &var_info(vindex);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
|
@ -578,13 +589,13 @@ const struct AP_Param::Info *AP_Param::find_var_info(uint32_t *
|
|||
group_ret = nullptr;
|
||||
|
||||
for (uint16_t i=0; i<_num_vars; i++) {
|
||||
uint8_t type = _var_info[i].type;
|
||||
uint8_t type = var_info(i).type;
|
||||
ptrdiff_t base;
|
||||
if (!get_base(_var_info[i], base)) {
|
||||
if (!get_base(var_info(i), base)) {
|
||||
continue;
|
||||
}
|
||||
if (type == AP_PARAM_GROUP) {
|
||||
const struct GroupInfo *group_info = get_group_info(_var_info[i]);
|
||||
const struct GroupInfo *group_info = get_group_info(var_info(i));
|
||||
if (group_info == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
@ -596,7 +607,7 @@ const struct AP_Param::Info *AP_Param::find_var_info(uint32_t *
|
|||
} else if (base == (ptrdiff_t) this) {
|
||||
*group_element = 0;
|
||||
*idx = 0;
|
||||
return &_var_info[i];
|
||||
return &var_info(i);
|
||||
} else if (type == AP_PARAM_VECTOR3F &&
|
||||
(base+(ptrdiff_t)sizeof(float) == (ptrdiff_t) this ||
|
||||
base+2*(ptrdiff_t)sizeof(float) == (ptrdiff_t) this)) {
|
||||
|
@ -604,7 +615,7 @@ const struct AP_Param::Info *AP_Param::find_var_info(uint32_t *
|
|||
// referring to.
|
||||
*idx = (((ptrdiff_t) this) - base)/sizeof(float);
|
||||
*group_element = 0;
|
||||
return &_var_info[i];
|
||||
return &var_info(i);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
|
@ -619,15 +630,15 @@ const struct AP_Param::Info *AP_Param::find_var_info_token(const ParamToken &tok
|
|||
uint8_t * idx) const
|
||||
{
|
||||
uint16_t i = token.key;
|
||||
uint8_t type = _var_info[i].type;
|
||||
uint8_t type = var_info(i).type;
|
||||
ptrdiff_t base;
|
||||
if (!get_base(_var_info[i], base)) {
|
||||
if (!get_base(var_info(i), base)) {
|
||||
return nullptr;
|
||||
}
|
||||
group_ret = nullptr;
|
||||
|
||||
if (type == AP_PARAM_GROUP) {
|
||||
const struct GroupInfo *group_info = get_group_info(_var_info[i]);
|
||||
const struct GroupInfo *group_info = get_group_info(var_info(i));
|
||||
if (group_info == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -639,7 +650,7 @@ const struct AP_Param::Info *AP_Param::find_var_info_token(const ParamToken &tok
|
|||
} else if (base == (ptrdiff_t) this) {
|
||||
*group_element = 0;
|
||||
*idx = 0;
|
||||
return &_var_info[i];
|
||||
return &var_info(i);
|
||||
} else if (type == AP_PARAM_VECTOR3F &&
|
||||
(base+(ptrdiff_t)sizeof(float) == (ptrdiff_t) this ||
|
||||
base+2*(ptrdiff_t)sizeof(float) == (ptrdiff_t) this)) {
|
||||
|
@ -647,7 +658,7 @@ const struct AP_Param::Info *AP_Param::find_var_info_token(const ParamToken &tok
|
|||
// referring to.
|
||||
*idx = (((ptrdiff_t) this) - base)/sizeof(float);
|
||||
*group_element = 0;
|
||||
return &_var_info[i];
|
||||
return &var_info(i);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -836,7 +847,7 @@ AP_Param::find_group(const char *name, uint16_t vindex, ptrdiff_t group_offset,
|
|||
}
|
||||
} else if (strcasecmp(name, group_info[i].name) == 0) {
|
||||
ptrdiff_t base;
|
||||
if (!get_base(_var_info[vindex], base)) {
|
||||
if (!get_base(var_info(vindex), base)) {
|
||||
continue;
|
||||
}
|
||||
*ptype = (enum ap_var_type)type;
|
||||
|
@ -850,7 +861,7 @@ AP_Param::find_group(const char *name, uint16_t vindex, ptrdiff_t group_offset,
|
|||
name[suffix_len+1] == 'Y' ||
|
||||
name[suffix_len+1] == 'Z')) {
|
||||
ptrdiff_t base;
|
||||
if (!get_base(_var_info[vindex], base)) {
|
||||
if (!get_base(var_info(vindex), base)) {
|
||||
continue;
|
||||
}
|
||||
AP_Float *v = (AP_Float *)(base + group_info[i].offset + group_offset);
|
||||
|
@ -876,13 +887,13 @@ AP_Param *
|
|||
AP_Param::find(const char *name, enum ap_var_type *ptype, uint16_t *flags)
|
||||
{
|
||||
for (uint16_t i=0; i<_num_vars; i++) {
|
||||
uint8_t type = _var_info[i].type;
|
||||
uint8_t type = var_info(i).type;
|
||||
if (type == AP_PARAM_GROUP) {
|
||||
uint8_t len = strnlen(_var_info[i].name, AP_MAX_NAME_SIZE);
|
||||
if (strncmp(name, _var_info[i].name, len) != 0) {
|
||||
uint8_t len = strnlen(var_info(i).name, AP_MAX_NAME_SIZE);
|
||||
if (strncmp(name, var_info(i).name, len) != 0) {
|
||||
continue;
|
||||
}
|
||||
const struct GroupInfo *group_info = get_group_info(_var_info[i]);
|
||||
const struct GroupInfo *group_info = get_group_info(var_info(i));
|
||||
if (group_info == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
@ -903,10 +914,10 @@ AP_Param::find(const char *name, enum ap_var_type *ptype, uint16_t *flags)
|
|||
// we continue looking as we want to allow top level
|
||||
// parameter to have the same prefix name as group
|
||||
// parameters, for example CAM_P_G
|
||||
} else if (strcasecmp(name, _var_info[i].name) == 0) {
|
||||
} else if (strcasecmp(name, var_info(i).name) == 0) {
|
||||
*ptype = (enum ap_var_type)type;
|
||||
ptrdiff_t base;
|
||||
if (!get_base(_var_info[i], base)) {
|
||||
if (!get_base(var_info(i), base)) {
|
||||
return nullptr;
|
||||
}
|
||||
return (AP_Param *)base;
|
||||
|
@ -938,7 +949,7 @@ AP_Param* AP_Param::find_by_name(const char* name, enum ap_var_type *ptype, Para
|
|||
for (ap = AP_Param::first(token, ptype);
|
||||
ap && *ptype != AP_PARAM_GROUP && *ptype != AP_PARAM_NONE;
|
||||
ap = AP_Param::next_scalar(token, ptype)) {
|
||||
int32_t ret = strncasecmp(name, _var_info[token->key].name, AP_MAX_NAME_SIZE);
|
||||
int32_t ret = strncasecmp(name, var_info(token->key).name, AP_MAX_NAME_SIZE);
|
||||
if (ret >= 0) {
|
||||
char buf[AP_MAX_NAME_SIZE];
|
||||
ap->copy_name_token(*token, buf, AP_MAX_NAME_SIZE);
|
||||
|
@ -963,16 +974,16 @@ bool AP_Param::find_key_by_pointer_group(const void *ptr, uint16_t vindex,
|
|||
continue;
|
||||
}
|
||||
ptrdiff_t base;
|
||||
if (!get_base(_var_info[vindex], base)) {
|
||||
if (!get_base(var_info(vindex), base)) {
|
||||
continue;
|
||||
}
|
||||
if (group_info[i].flags & AP_PARAM_FLAG_POINTER) {
|
||||
if (ptr == *(void **)(base+group_info[i].offset+offset)) {
|
||||
key = _var_info[vindex].key;
|
||||
key = var_info(vindex).key;
|
||||
return true;
|
||||
}
|
||||
} else if (ptr == (void *)(base+group_info[i].offset+offset)) {
|
||||
key = _var_info[vindex].key;
|
||||
key = var_info(vindex).key;
|
||||
return true;
|
||||
}
|
||||
ptrdiff_t new_offset = offset;
|
||||
|
@ -997,16 +1008,16 @@ bool AP_Param::find_key_by_pointer_group(const void *ptr, uint16_t vindex,
|
|||
bool AP_Param::find_key_by_pointer(const void *ptr, uint16_t &key)
|
||||
{
|
||||
for (uint16_t i=0; i<_num_vars; i++) {
|
||||
if (_var_info[i].type != AP_PARAM_GROUP) {
|
||||
if (var_info(i).type != AP_PARAM_GROUP) {
|
||||
continue;
|
||||
}
|
||||
if ((_var_info[i].flags & AP_PARAM_FLAG_POINTER) &&
|
||||
ptr == *(void **)_var_info[i].ptr) {
|
||||
key = _var_info[i].key;
|
||||
if ((var_info(i).flags & AP_PARAM_FLAG_POINTER) &&
|
||||
ptr == *(void **)var_info(i).ptr) {
|
||||
key = var_info(i).key;
|
||||
return true;
|
||||
}
|
||||
ptrdiff_t offset = 0;
|
||||
const struct GroupInfo *ginfo = get_group_info(_var_info[i]);
|
||||
const struct GroupInfo *ginfo = get_group_info(var_info(i));
|
||||
if (ginfo == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
@ -1023,11 +1034,11 @@ bool AP_Param::find_key_by_pointer(const void *ptr, uint16_t &key)
|
|||
bool AP_Param::find_top_level_key_by_pointer(const void *ptr, uint16_t &key)
|
||||
{
|
||||
for (uint16_t i=0; i<_num_vars; i++) {
|
||||
if (_var_info[i].type != AP_PARAM_GROUP) {
|
||||
if (var_info(i).type != AP_PARAM_GROUP) {
|
||||
continue;
|
||||
}
|
||||
if (ptr == (void **)_var_info[i].ptr) {
|
||||
key = _var_info[i].key;
|
||||
if (ptr == (void **)var_info(i).ptr) {
|
||||
key = var_info(i).key;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1056,9 +1067,9 @@ AP_Param *
|
|||
AP_Param::find_object(const char *name)
|
||||
{
|
||||
for (uint16_t i=0; i<_num_vars; i++) {
|
||||
if (strcasecmp(name, _var_info[i].name) == 0) {
|
||||
if (strcasecmp(name, var_info(i).name) == 0) {
|
||||
ptrdiff_t base;
|
||||
if (!get_base(_var_info[i], base)) {
|
||||
if (!get_base(var_info(i), base)) {
|
||||
return nullptr;
|
||||
}
|
||||
return (AP_Param *)base;
|
||||
|
@ -1116,8 +1127,14 @@ void AP_Param::save_sync(bool force_save, bool send_to_gcs)
|
|||
// create the header we will use to store the variable
|
||||
if (ginfo != nullptr) {
|
||||
phdr.type = ginfo->type;
|
||||
if (ginfo->flags & AP_PARAM_FLAG_HIDDEN) {
|
||||
send_to_gcs = false;
|
||||
}
|
||||
} else {
|
||||
phdr.type = info->type;
|
||||
if (info->flags & AP_PARAM_FLAG_HIDDEN) {
|
||||
send_to_gcs = false;
|
||||
}
|
||||
}
|
||||
set_key(phdr, info->key);
|
||||
phdr.group_element = group_element;
|
||||
|
@ -1463,12 +1480,12 @@ void AP_Param::setup_sketch_defaults(void)
|
|||
{
|
||||
setup();
|
||||
for (uint16_t i=0; i<_num_vars; i++) {
|
||||
uint8_t type = _var_info[i].type;
|
||||
uint8_t type = var_info(i).type;
|
||||
if (type <= AP_PARAM_FLOAT) {
|
||||
ptrdiff_t base;
|
||||
if (get_base(_var_info[i], base)) {
|
||||
if (get_base(var_info(i), base)) {
|
||||
set_value((enum ap_var_type)type, (void*)base,
|
||||
get_default_value((const AP_Param *)base, &_var_info[i].def_value));
|
||||
get_default_value((const AP_Param *)base, &var_info(i).def_value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1613,10 +1630,10 @@ AP_Param *AP_Param::first(ParamToken *token, enum ap_var_type *ptype)
|
|||
return nullptr;
|
||||
}
|
||||
if (ptype != nullptr) {
|
||||
*ptype = (enum ap_var_type)_var_info[0].type;
|
||||
*ptype = (enum ap_var_type)var_info(0).type;
|
||||
}
|
||||
ptrdiff_t base;
|
||||
if (!get_base(_var_info[0], base)) {
|
||||
if (!get_base(var_info(0), base)) {
|
||||
// should be impossible, first var needs to be non-pointer
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -1669,7 +1686,7 @@ AP_Param *AP_Param::next_group(const uint16_t vindex, const struct GroupInfo *gr
|
|||
*ptype = type;
|
||||
}
|
||||
ptrdiff_t base;
|
||||
if (!get_base(_var_info[vindex], base)) {
|
||||
if (!get_base(var_info(vindex), base)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1682,9 +1699,6 @@ AP_Param *AP_Param::next_group(const uint16_t vindex, const struct GroupInfo *gr
|
|||
((AP_Int8 *)ret)->get() == 0) {
|
||||
token->last_disabled = 1;
|
||||
}
|
||||
if (group_info[i].flags & AP_PARAM_FLAG_HIDDEN) {
|
||||
continue;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
if (group_id(group_info, group_base, i, group_shift) == token->group_element) {
|
||||
|
@ -1701,7 +1715,7 @@ AP_Param *AP_Param::next_group(const uint16_t vindex, const struct GroupInfo *gr
|
|||
*ptype = AP_PARAM_FLOAT;
|
||||
}
|
||||
ptrdiff_t base;
|
||||
if (!get_base(_var_info[vindex], base)) {
|
||||
if (!get_base(var_info(vindex), base)) {
|
||||
continue;
|
||||
}
|
||||
ptrdiff_t ofs = base + group_info[i].offset + group_offset;
|
||||
|
@ -1724,7 +1738,7 @@ AP_Param *AP_Param::next(ParamToken *token, enum ap_var_type *ptype, bool skip_d
|
|||
// illegal token
|
||||
return nullptr;
|
||||
}
|
||||
enum ap_var_type type = (enum ap_var_type)_var_info[i].type;
|
||||
enum ap_var_type type = (enum ap_var_type)var_info(i).type;
|
||||
|
||||
// allow Vector3f to be seen as 3 variables. First as a vector,
|
||||
// then as 3 separate floats
|
||||
|
@ -1733,7 +1747,7 @@ AP_Param *AP_Param::next(ParamToken *token, enum ap_var_type *ptype, bool skip_d
|
|||
if (ptype != nullptr) {
|
||||
*ptype = AP_PARAM_FLOAT;
|
||||
}
|
||||
return (AP_Param *)(((token->idx - 1u)*sizeof(float))+(ptrdiff_t)_var_info[i].ptr);
|
||||
return (AP_Param *)(((token->idx - 1u)*sizeof(float))+(ptrdiff_t)var_info(i).ptr);
|
||||
}
|
||||
|
||||
if (type != AP_PARAM_GROUP) {
|
||||
|
@ -1741,12 +1755,12 @@ AP_Param *AP_Param::next(ParamToken *token, enum ap_var_type *ptype, bool skip_d
|
|||
found_current = true;
|
||||
}
|
||||
for (; i<_num_vars; i++) {
|
||||
if (!check_frame_type(_var_info[i].flags)) {
|
||||
if (!check_frame_type(var_info(i).flags)) {
|
||||
continue;
|
||||
}
|
||||
type = (enum ap_var_type)_var_info[i].type;
|
||||
type = (enum ap_var_type)var_info(i).type;
|
||||
if (type == AP_PARAM_GROUP) {
|
||||
const struct GroupInfo *group_info = get_group_info(_var_info[i]);
|
||||
const struct GroupInfo *group_info = get_group_info(var_info(i));
|
||||
if (group_info == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
@ -1762,7 +1776,7 @@ AP_Param *AP_Param::next(ParamToken *token, enum ap_var_type *ptype, bool skip_d
|
|||
if (ptype != nullptr) {
|
||||
*ptype = type;
|
||||
}
|
||||
return (AP_Param *)(_var_info[i].ptr);
|
||||
return (AP_Param *)(var_info(i).ptr);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
|
@ -2669,7 +2683,7 @@ void AP_Param::show_all(AP_HAL::BetterStream *port, bool showKeyValues)
|
|||
ap;
|
||||
ap=AP_Param::next_scalar(&token, &type)) {
|
||||
if (showKeyValues) {
|
||||
::printf("Key %u: Index %u: GroupElement %u : ", (unsigned)_var_info[token.key].key, (unsigned)token.idx, (unsigned)token.group_element);
|
||||
::printf("Key %u: Index %u: GroupElement %u : ", (unsigned)var_info(token.key).key, (unsigned)token.idx, (unsigned)token.group_element);
|
||||
}
|
||||
show(ap, token, type, port);
|
||||
hal.scheduler->delay(1);
|
||||
|
@ -2677,3 +2691,250 @@ void AP_Param::show_all(AP_HAL::BetterStream *port, bool showKeyValues)
|
|||
}
|
||||
#endif // AP_PARAM_KEY_DUMP
|
||||
|
||||
|
||||
#if AP_PARAM_DYNAMIC_ENABLED
|
||||
/*
|
||||
allow for dynamically added parameter tables from scripts
|
||||
|
||||
The layout we create is as follows:
|
||||
- a top level Info with the given prefix, using one of the 10 possible slots in _var_info_dynamic
|
||||
- a dynamically allocated GroupInfo table, never freed, of size (num_params+2)
|
||||
- the GroupInfo table has an initial AP_Int32 hidden entry with a 32 bit CRC of the prefix
|
||||
- the last GroupInfo is a footer
|
||||
*/
|
||||
bool AP_Param::add_table(uint8_t _key, const char *prefix, uint8_t num_params)
|
||||
{
|
||||
// check if the key already exists. We only check base params to allow
|
||||
// for scripting reload without a conflict
|
||||
uint16_t key = uint16_t(_key) + AP_PARAM_DYNAMIC_KEY_BASE;
|
||||
for (uint16_t i=0; i<_num_vars_base; i++) {
|
||||
if (var_info(i).key == key) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (num_params > 63) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// we use a crc of the prefix to ensure the table key isn't re-used
|
||||
const int32_t crc = int32_t(crc32_small(0, (const uint8_t *)prefix, strlen(prefix)));
|
||||
int32_t current_crc;
|
||||
if (load_int32(key, 0, current_crc) && current_crc != crc) {
|
||||
// crc mismatch, we have a conflict with an existing use of this key
|
||||
return false;
|
||||
}
|
||||
|
||||
// create the dynamic table if needed. This is never freed
|
||||
if (_var_info_dynamic == nullptr) {
|
||||
_var_info_dynamic = (Info *)calloc(AP_PARAM_MAX_DYNAMIC, sizeof(struct Info));
|
||||
if (_var_info_dynamic == nullptr) {
|
||||
return false;
|
||||
}
|
||||
for (uint8_t i=0; i<AP_PARAM_MAX_DYNAMIC; i++) {
|
||||
auto &info = _var_info_dynamic[i];
|
||||
info.type = AP_PARAM_NONE;
|
||||
info.name = _empty_string;
|
||||
info.key = 0xFFFF;
|
||||
info.ptr = nullptr;
|
||||
info.group_info = nullptr;
|
||||
info.flags = 0;
|
||||
}
|
||||
// make tables available
|
||||
_num_vars += AP_PARAM_MAX_DYNAMIC;
|
||||
}
|
||||
|
||||
// find existing key (allows for script reload)
|
||||
uint8_t i;
|
||||
for (i=0; i<AP_PARAM_MAX_DYNAMIC; i++) {
|
||||
auto &info = _var_info_dynamic[i];
|
||||
if (info.type != AP_PARAM_NONE && info.key == key) {
|
||||
if (_dynamic_table_sizes[i] != 0 &&
|
||||
num_params > _dynamic_table_sizes[i]) {
|
||||
// can't expand the table at runtime
|
||||
return false;
|
||||
}
|
||||
if (strcmp(prefix, info.name) != 0) {
|
||||
// prefix has changed, reject as two scripts running
|
||||
// with the same key
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == AP_PARAM_MAX_DYNAMIC) {
|
||||
// find an unused slot
|
||||
for (i=0; i<AP_PARAM_MAX_DYNAMIC; i++) {
|
||||
auto &info = _var_info_dynamic[i];
|
||||
if (info.type == AP_PARAM_NONE ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i == AP_PARAM_MAX_DYNAMIC) {
|
||||
// no empty slots
|
||||
return false;
|
||||
}
|
||||
|
||||
auto &info = _var_info_dynamic[i];
|
||||
|
||||
// create memory for the array of floats if needed
|
||||
// first float is used for the crc
|
||||
if (info.ptr == nullptr) {
|
||||
info.ptr = calloc(num_params+1, sizeof(float));
|
||||
if (info.ptr == nullptr) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// allocate the name
|
||||
if (info.name == _empty_string) {
|
||||
info.name = strdup(prefix);
|
||||
if (info.name == nullptr) {
|
||||
free(const_cast<void*>(info.ptr));
|
||||
info.ptr = nullptr;
|
||||
info.name = _empty_string;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// if it doesn't exist then create the table
|
||||
if (info.group_info == nullptr) {
|
||||
info.group_info = (GroupInfo *)calloc(num_params+2, sizeof(GroupInfo));
|
||||
if (info.group_info == nullptr) {
|
||||
free(const_cast<void*>(info.ptr));
|
||||
free(const_cast<char*>(info.name));
|
||||
info.ptr = nullptr;
|
||||
info.name = _empty_string;
|
||||
return false;
|
||||
}
|
||||
// fill in footer for all entries
|
||||
for (uint8_t gi=1; gi<num_params+2; gi++) {
|
||||
auto &ginfo = const_cast<GroupInfo*>(info.group_info)[gi];
|
||||
ginfo.name = _empty_string;
|
||||
ginfo.idx = 0xff;
|
||||
}
|
||||
// hidden first parameter containing AP_Int32 crc
|
||||
auto &hinfo = const_cast<GroupInfo*>(info.group_info)[0];
|
||||
hinfo.flags = AP_PARAM_FLAG_HIDDEN;
|
||||
hinfo.name = _empty_string;
|
||||
hinfo.idx = 0;
|
||||
hinfo.offset = 0;
|
||||
hinfo.type = AP_PARAM_INT32;
|
||||
// fill in default value with the CRC. Relies on sizeof crc == sizeof float
|
||||
memcpy((uint8_t *)&hinfo.def_value, (const uint8_t *)&crc, sizeof(crc));
|
||||
}
|
||||
|
||||
// remember the table size
|
||||
if (_dynamic_table_sizes[i] == 0) {
|
||||
_dynamic_table_sizes[i] = num_params;
|
||||
}
|
||||
|
||||
// make the group active
|
||||
info.key = key;
|
||||
info.type = AP_PARAM_GROUP;
|
||||
|
||||
invalidate_count();
|
||||
|
||||
// save the CRC
|
||||
AP_Int32 *crc_param = const_cast<AP_Int32 *>((AP_Int32 *)info.ptr);
|
||||
crc_param->set(crc);
|
||||
crc_param->save(true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Load an AP_Int32 variable from EEPROM using top level key and group element. Used to confirm
|
||||
a key in add_table()
|
||||
*/
|
||||
bool AP_Param::load_int32(uint16_t key, uint32_t group_element, int32_t &value)
|
||||
{
|
||||
struct Param_header phdr;
|
||||
|
||||
phdr.type = AP_PARAM_INT32;
|
||||
set_key(phdr, key);
|
||||
phdr.group_element = group_element;
|
||||
|
||||
// scan EEPROM to find the right location
|
||||
uint16_t ofs;
|
||||
if (!scan(&phdr, &ofs)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// found it
|
||||
_storage.read_block(&value, ofs+sizeof(phdr), type_size(AP_PARAM_INT32));
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
add a parameter to a dynamic table
|
||||
*/
|
||||
bool AP_Param::add_param(uint8_t _key, uint8_t param_num, const char *pname, float default_value)
|
||||
{
|
||||
// check for valid values
|
||||
if (param_num == 0 || param_num > 63 || strlen(pname) > 16) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t key = uint16_t(_key) + AP_PARAM_DYNAMIC_KEY_BASE;
|
||||
// find the info
|
||||
uint8_t i;
|
||||
for (i=0; i<AP_PARAM_MAX_DYNAMIC; i++) {
|
||||
auto &info = _var_info_dynamic[i];
|
||||
if (info.key == key) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == AP_PARAM_MAX_DYNAMIC) {
|
||||
// not found
|
||||
return false;
|
||||
}
|
||||
|
||||
if (param_num > _dynamic_table_sizes[i]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto &info = _var_info_dynamic[i];
|
||||
if (info.ptr == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check CRC
|
||||
auto &hinfo = const_cast<GroupInfo*>(info.group_info)[0];
|
||||
const int32_t crc = *(const int32_t *)(&hinfo.def_value);
|
||||
|
||||
int32_t current_crc;
|
||||
if (load_int32(key, 0, current_crc) && current_crc != crc) {
|
||||
// crc mismatch, we have a conflict with an existing use of this key
|
||||
return false;
|
||||
}
|
||||
|
||||
auto &ginfo = const_cast<GroupInfo*>(info.group_info)[param_num];
|
||||
|
||||
if (ginfo.name == _empty_string) {
|
||||
// we don't allow name change while running
|
||||
ginfo.name = strdup(pname);
|
||||
if (ginfo.name == nullptr) {
|
||||
ginfo.name = _empty_string;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
ginfo.offset = param_num*sizeof(float);
|
||||
ginfo.idx = param_num;
|
||||
float *def_value = const_cast<float *>(&ginfo.def_value);
|
||||
*def_value = default_value;
|
||||
ginfo.type = AP_PARAM_FLOAT;
|
||||
|
||||
invalidate_count();
|
||||
|
||||
// load from storage if available
|
||||
AP_Float *pvalues = const_cast<AP_Float *>((const AP_Float *)info.ptr);
|
||||
AP_Float &p = pvalues[param_num];
|
||||
p.set_default(default_value);
|
||||
p.load();
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -46,6 +46,15 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
// allow for dynamically added tables when scripting enabled
|
||||
#define AP_PARAM_DYNAMIC_ENABLED AP_SCRIPTING_ENABLED
|
||||
|
||||
// maximum number of dynamically created tables (from scripts)
|
||||
#ifndef AP_PARAM_MAX_DYNAMIC
|
||||
#define AP_PARAM_MAX_DYNAMIC 10
|
||||
#endif
|
||||
#define AP_PARAM_DYNAMIC_KEY_BASE 300
|
||||
|
||||
/*
|
||||
flags for variables in var_info and group tables
|
||||
*/
|
||||
|
@ -201,7 +210,9 @@ public:
|
|||
uint16_t i;
|
||||
for (i=0; info[i].type != AP_PARAM_NONE; i++) ;
|
||||
_num_vars = i;
|
||||
|
||||
#if AP_PARAM_DYNAMIC_ENABLED
|
||||
_num_vars_base = _num_vars;
|
||||
#endif
|
||||
if (_singleton != nullptr) {
|
||||
AP_HAL::panic("AP_Param must be singleton");
|
||||
}
|
||||
|
@ -490,7 +501,7 @@ public:
|
|||
bool is_read_only(void) const;
|
||||
|
||||
// return the persistent top level key for the ParamToken key
|
||||
static uint16_t get_persistent_key(uint16_t key) { return _var_info[key].key; }
|
||||
static uint16_t get_persistent_key(uint16_t key) { return var_info(key).key; }
|
||||
|
||||
// count of parameters in tree
|
||||
static uint16_t count_parameters(void);
|
||||
|
@ -528,6 +539,13 @@ public:
|
|||
|
||||
static AP_Param *get_singleton() { return _singleton; }
|
||||
|
||||
#if AP_PARAM_DYNAMIC_ENABLED
|
||||
// allow for dynamically added parameter tables from scripts
|
||||
static bool add_table(uint8_t key, const char *prefix, uint8_t num_params);
|
||||
static bool add_param(uint8_t key, uint8_t param_num, const char *pname, float default_value);
|
||||
static bool load_int32(uint16_t key, uint32_t group_element, int32_t &value);
|
||||
#endif
|
||||
|
||||
private:
|
||||
static AP_Param *_singleton;
|
||||
|
||||
|
@ -698,6 +716,21 @@ private:
|
|||
static HAL_Semaphore _count_sem;
|
||||
static const struct Info * _var_info;
|
||||
|
||||
#if AP_PARAM_DYNAMIC_ENABLED
|
||||
// allow for a dynamically allocated var table
|
||||
static uint16_t _num_vars_base;
|
||||
static struct Info * _var_info_dynamic;
|
||||
static const struct AP_Param::Info &var_info(uint16_t i) {
|
||||
return i<_num_vars_base? _var_info[i] : _var_info_dynamic[i-_num_vars_base];
|
||||
}
|
||||
static uint8_t _dynamic_table_sizes[AP_PARAM_MAX_DYNAMIC];
|
||||
#else
|
||||
// simple static var table in flash
|
||||
static const struct Info &var_info(uint16_t i) {
|
||||
return _var_info[i];
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
list of overridden values from load_defaults_file()
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue