mirror of
https://github.com/ArduPilot/ardupilot
synced 2025-01-04 06:58:27 -04:00
63643f73fc
AP_Vars with either a name or an address are 'interesting' (the latter so we can save_all). Add the concept of address offsets to scopes. Now we have a container that we can put AP_Vars into that can be moved around in the EEPROM. This will make it easier for things like the PID library which need to support multiple instances getting their parameters from different parts of the ROM. Improve documentation. Suck it up and admit that we aren't going to do "identity"-based addressing for the EEPROM and just call the property "address". git-svn-id: https://arducopter.googlecode.com/svn/trunk@1417 f9c3cf11-9bcb-44bc-f272-b75c42450872
212 lines
4.4 KiB
C++
212 lines
4.4 KiB
C++
// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: t -*-
|
|
//
|
|
// This is free software; you can redistribute it and/or modify it under
|
|
// the terms of the GNU Lesser General Public License as published by the
|
|
// Free Software Foundation; either version 2.1 of the License, or (at
|
|
// your option) any later version.
|
|
//
|
|
/// The AP variable interface. This allows different types
|
|
/// of variables to be passed to blocks for floating point
|
|
/// math, memory management, etc.
|
|
|
|
#include "AP_Var.h"
|
|
|
|
const AP_Float AP_GainUnity(1.0);
|
|
const AP_Float AP_GainNegativeUnity(-1.0);
|
|
const AP_Float AP_Zero(0);
|
|
|
|
// Constructor
|
|
//
|
|
AP_Var::AP_Var(AP_VarAddress address,
|
|
const prog_char *name,
|
|
const AP_VarScope *scope) :
|
|
_address(address),
|
|
_name(name),
|
|
_scope(scope)
|
|
{
|
|
// if the variable is interesting, link it into the list
|
|
if (_name || (_address != AP_VarNoAddress)) {
|
|
_link = _variables;
|
|
_variables = this;
|
|
}
|
|
}
|
|
|
|
// Destructor
|
|
//
|
|
// Removes named variables from the list.
|
|
//
|
|
AP_Var::~AP_Var(void)
|
|
{
|
|
AP_Var *p;
|
|
|
|
// only do this for variables that were considered interesting
|
|
if (_name || (_address != AP_VarNoAddress)) {
|
|
// if we are at the head of the list - for variables
|
|
// recently constructed this is usually the case
|
|
if (_variables == this) {
|
|
// remove us from the head of the list
|
|
_variables = _link;
|
|
} else {
|
|
// traverse the list looking for the entry that points to us
|
|
p = _variables;
|
|
while (p) {
|
|
// is it pointing at us?
|
|
if (p->_link == this) {
|
|
// make it point at what we point at, and done
|
|
p->_link = _link;
|
|
break;
|
|
}
|
|
// try the next one
|
|
p = p->_link;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Copy the variable name to the provided buffer.
|
|
//
|
|
void
|
|
AP_Var::copy_name(char *buffer, size_t bufferSize) const
|
|
{
|
|
buffer[0] = '\0';
|
|
if (_scope)
|
|
_scope->copy_name(buffer, bufferSize);
|
|
strlcat_P(buffer, _name, bufferSize);
|
|
}
|
|
|
|
// Compute any offsets that should be applied to a variable in this scope.
|
|
//
|
|
// Note that this depends on the default _address value for scopes being zero.
|
|
//
|
|
AP_Var::AP_VarAddress
|
|
AP_VarScope::get_address(void) const
|
|
{
|
|
AP_Var::AP_VarAddress addr = _address;
|
|
|
|
if (_parent)
|
|
addr += _parent->get_address();
|
|
|
|
return addr;
|
|
}
|
|
|
|
// Compute the address in EEPROM where the variable is stored
|
|
//
|
|
AP_Var::AP_VarAddress
|
|
AP_Var::_get_address(void) const
|
|
{
|
|
AP_VarAddress addr = _address;
|
|
|
|
// if we have an address at all
|
|
if ((addr != AP_VarNoAddress) && _scope)
|
|
addr += _scope->get_address();
|
|
|
|
return addr;
|
|
}
|
|
|
|
// Save the variable to EEPROM, if supported
|
|
//
|
|
void
|
|
AP_Var::save(void) const
|
|
{
|
|
AP_VarAddress addr = _get_address();
|
|
|
|
if (addr != AP_VarNoAddress) {
|
|
uint8_t vbuf[AP_VarMaxSize];
|
|
size_t size;
|
|
|
|
// serialize the variable into the buffer and work out how big it is
|
|
size = serialize(vbuf, sizeof(vbuf));
|
|
|
|
// if it fit in the buffer, save it to EEPROM
|
|
if (size <= sizeof(vbuf))
|
|
eeprom_write_block(vbuf, (void *)addr, size);
|
|
}
|
|
}
|
|
|
|
// Load the variable from EEPROM, if supported
|
|
//
|
|
void
|
|
AP_Var::load(void)
|
|
{
|
|
AP_VarAddress addr = _get_address();
|
|
|
|
if (addr != AP_VarNoAddress) {
|
|
uint8_t vbuf[AP_VarMaxSize];
|
|
size_t size;
|
|
|
|
// ask the unserializer how big the variable is
|
|
size = unserialize(NULL, 0);
|
|
|
|
// read the buffer from EEPROM
|
|
if (size <= sizeof(vbuf)) {
|
|
eeprom_read_block(vbuf, (void *)addr, size);
|
|
unserialize(vbuf, size);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Lookup interface for variables.
|
|
//
|
|
AP_Var *AP_Var::_variables = NULL;
|
|
AP_Var *AP_Var::_lookupHint = NULL;
|
|
int AP_Var::_lookupHintIndex = 0;
|
|
|
|
AP_Var *
|
|
AP_Var::lookup(int index)
|
|
{
|
|
AP_Var *p;
|
|
int i;
|
|
|
|
// establish initial search state
|
|
if (_lookupHintIndex && // we have a cached hint
|
|
(index >= _lookupHintIndex)) { // the desired index is at or after the hint
|
|
|
|
p = _lookupHint; // start at the hint point
|
|
i = index - _lookupHintIndex; // count only the distance from the hint to the index
|
|
} else {
|
|
|
|
p = _variables; // start at the beginning of the list
|
|
i = index; // count to the index
|
|
}
|
|
|
|
// search
|
|
while (index-- && p) // count until we hit the index or the end of the list
|
|
p = p->_link;
|
|
|
|
// update the cache on hit
|
|
if (p) {
|
|
_lookupHintIndex = i;
|
|
_lookupHint = p;
|
|
}
|
|
|
|
return(p);
|
|
}
|
|
|
|
// Save all variables that have an identity.
|
|
//
|
|
void
|
|
AP_Var::save_all(void)
|
|
{
|
|
AP_Var *p = _variables;
|
|
|
|
while (p) {
|
|
p->save();
|
|
p = p->_link;
|
|
}
|
|
}
|
|
|
|
// Load all variables that have an identity.
|
|
//
|
|
void
|
|
AP_Var::load_all(void)
|
|
{
|
|
AP_Var *p = _variables;
|
|
|
|
while (p) {
|
|
p->load();
|
|
p = p->_link;
|
|
}
|
|
}
|