ardupilot/libraries/AP_Common/AP_Var.cpp

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