ardupilot/libraries/AP_Common/AP_Var.h
DrZiplok a3a9fe59e3 Following discussions with James, a complete rewrite of AP_Var.
The overriding principle here is to keep the use of AP_Vars as simple as possible, whilst letting the implementation do useful things behind the scenes.  To that end, we define AP_Float, AP_Int8, AP_Int16 and AP_Int32.  These are strongly typed, so that there is no ambiguity about what a variable "really" is.

The classes behave like the variables they are storing; you can use an AP_Float in most places you would use a regular float; you can add to it, multiply by it, etc.  If it has been given an address in EEPROM you can load and save it.

Variables can be given names, and if they are named then they can be looked up.  This allows e.g. a GCS or a test tool to find and traffic in variables that it may not explicitly know about.

AP_Var does not attempt to solve the problem of EEPROM address space management.

git-svn-id: https://arducopter.googlecode.com/svn/trunk@1399 f9c3cf11-9bcb-44bc-f272-b75c42450872
2011-01-02 22:14:36 +00:00

324 lines
9.6 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.
#ifndef AP_Var_H
#define AP_Var_H
#include <inttypes.h>
#include <string.h>
#include <stdint.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
#include <AP_MetaClass.h>
/// Nestable scopes for variable names.
///
/// This provides a mechanism for scoping variable names, and
/// may later be extended for other purposes.
///
/// When AP_VarBase is asked for the name of a variable, it will
/// prepend the names of all enclosing scopes. This provides a way
/// of grouping variables and saving memory when many share a large
/// common prefix.
///
class AP_VarScope
{
public:
/// Constructor
///
/// @param scopeName The name of the scope.
///
AP_VarScope(const prog_char *name,
AP_VarScope *parent = NULL) :
_name(name),
_parent(parent)
{
}
/// Copy the scope name, prefixed by any parent scope names, to a buffer.
///
/// Note that if the combination of names is larger than the buffer, the
/// result in the buffer will be truncated.
///
/// @param buffer The destination buffer
/// @param bufferSize Total size of the destination buffer.
///
void copy_name(char *buffer, size_t bufferSize) const
{
if (_parent)
_parent->copy_name(buffer, bufferSize);
strlcat_P(buffer, _name, bufferSize);
}
private:
const prog_char *_name; /// pointer to the scope name in program memory
AP_VarScope *_parent; /// pointer to a parent scope, if one exists
};
/// Base class for variables.
///
/// Provides naming and lookup services for variables.
///
class AP_VarBase : public AP_MetaClass
{
public:
/// A unique identity for variables that can be saved to EEPROM
///
/// @todo This might be used as a token for mass serialisation,
/// but for now it's just the address of the variable's backing
/// store in EEPROM.
///
typedef uint16_t AP_VarIdentity;
static const AP_VarIdentity AP_VarUnsaved = 0;
/// The largest variable that will be saved to EEPROM
///
static const size_t AP_VarMaxSize = 16;
/// Constructor
///
/// @param name An optional name by which the variable may be known.
/// @param scope An optional scope that the variable may be a contained within.
///
AP_VarBase(AP_VarIdentity identity = AP_VarUnsaved,
const prog_char *name = NULL,
AP_VarScope *scope = NULL) :
_identity(identity),
_name(name),
_scope(scope)
{
if (name) {
_link = _variables;
_variables = this;
}
}
/// Copy the variable name, prefixed by any parent class names, to a buffer.
///
/// Note that if the combination of names is larger than the buffer, the
/// result in the buffer will be truncated.
///
/// @param buffer The destination buffer
/// @param bufferSize Total size of the destination buffer.
///
void copy_name(char *buffer, size_t bufferSize) const {
if (_scope)
_scope->copy_name(buffer, bufferSize);
strlcat_P(buffer, _name, bufferSize);
}
/// Return a pointer to the n'th known variable
///
/// This interface is designed for the use of relatively low-rate clients;
/// GCS interfaces in particular. It may implement an acceleration scheme
/// for optimising the lookup of parameters.
///
/// Note that variable index numbers are not constant, they depend on the
/// the static construction order.
///
/// @param index enumerator for the variable to be returned
///
static AP_VarBase *lookup(int index);
/// Save the current value of the variable to EEPROM.
///
/// This interface works for any subclass that implements
/// serialize.
///
void save(void) {
if (_identity != AP_VarUnsaved) {
uint8_t vbuf[AP_VarMaxSize];
size_t size;
// serialise 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 *)_identity, size);
}
}
/// Load the variable from EEPROM.
///
/// This interface works for any subclass that implements
/// unserialize.
///
void load(void) {
if (_identity != AP_VarUnsaved) {
uint8_t vbuf[AP_VarMaxSize];
size_t size;
// ask the unserialiser how big the variable is
size = unserialize(NULL, 0);
// read the buffer from EEPROM
if (size <= sizeof(vbuf)) {
eeprom_read_block(vbuf, (void *)_identity, size);
unserialize(vbuf, size);
}
}
}
/// Save all variables to EEPROM
///
static void save_all(void);
/// Load all variables from EEPROM
///
static void load_all(void);
private:
const AP_VarIdentity _identity;
const prog_char *_name;
AP_VarScope *_scope;
AP_VarBase *_link;
// static state used by ::lookup
static AP_VarBase *_variables;
static AP_VarBase *_lookupHint; /// pointer to the last variable that was looked up by ::lookup
static int _lookupHintIndex; /// index of the last variable that was looked up by ::lookup
};
/// Template class for scalar variables.
///
/// Objects of this type have a value, and can be treated in many ways as though they
/// were the value.
///
/// @tparam T The scalar type of the variable
///
template<typename T>
class AP_Var : public AP_VarBase
{
public:
/// Constructor
///
/// @note Constructors for AP_Var are specialised so that they can
/// pass the correct typeCode argument to the AP_VarBase ctor.
///
/// @param initialValue Value the variable should have at startup.
/// @param identity A unique token used when saving the variable to EEPROM.
/// Note that this token must be unique, and should only be
/// changed for a variable if the EEPROM version is updated
/// to prevent the accidental unserialisation of old data
/// into the wrong variable.
/// @param name An optional name by which the variable may be known.
/// @param varClass An optional class that the variable may be a member of.
///
AP_Var<T>(T initialValue = 0,
AP_VarIdentity identity = AP_VarUnsaved,
const prog_char *name = NULL,
AP_VarScope *scope = NULL) :
AP_VarBase(identity, name, scope),
_value(initialValue)
{
}
// Serialise _value into the buffer, but only if it is big enough.
///
virtual size_t serialise(void *buf, size_t size) {
if (size >= sizeof(T))
*(T *)buf = _value;
return sizeof(T);
}
// Unserialise from the buffer, but only if it is big enough.
//
virtual size_t unserialise(void *buf, size_t size) {
if (size >= sizeof(T))
_value = *(T*)buf;
return sizeof(T);
}
/// Value getter
///
T get(void) { return _value; }
/// Value setter
///
void set(T v) { _value = v; }
/// Conversion to T returns a reference to the value, may lead to simpler
/// code than the getter/setter in some cases.
///
operator T&() { return _value; }
/// Conversion to a pointer to T returns a pointer to the value,
/// permits passing the value by reference.
///
operator T*() const { return &_value; }
// Assignment from any value that T is compatible with.
T operator = (const T v) const { return (_value = v); }
// Comparison with any value that T is compatible with (should be avoided for T == float)
bool operator == (const T &v) const { return _value == v; }
bool operator != (const T &v) const { return _value != v; }
// Negation
T operator - (void) const { return -_value; }
// Addition
T operator + (const T &v) const { return _value + v; }
T operator += (const T &v) { return (_value += v); }
// Subtraction
T operator - (const T &v) const { return _value - v; }
T operator -= (const T &v) { return (_value -= v); }
// Multiplication
T operator * (const T &v) const { return _value * v; }
T operator *= (const T &v) { return (_value *= v); }
// Division
T operator / (const T &v) const { return _value / v; }
T operator /= (const T &v) { return (_value /= v); }
// Modulus
T operator % (const T &v) const { return _value % v; }
T operator %= (const T &v) { return (_value %= v); }
// Bitwise operations
T operator & (const T &v) const { return _value & v; }
T operator &= (const T &v) { return (_value &= v); }
T operator | (const T &v) const { return _value | v; }
T operator |= (const T &v) { return (_value |= v); }
T operator ^ (const T &v) const { return _value ^ v; }
T operator ^= (const T &v) { return (_value ^= v); }
T operator << (const T &v) const { return _value << v; }
T operator <<= (const T &v) { return (_value <<= v); }
T operator >> (const T &v) const { return _value >> v; }
T operator >>= (const T &v) { return (_value >>= v); }
private:
T _value;
};
/// Convenience macro for defining instances of the AP_Var template
///
#define AP_VARDEF(_t, _n) \
typedef AP_Var<_t> AP_##_n;
AP_VARDEF(float, Float); // defines AP_Float, AP_NamedFloat and AP_SavedFloat
AP_VARDEF(int8_t, Int8); // defines AP_UInt8, AP_NamedUInt8 and AP_SavedUInt8
AP_VARDEF(int16_t, Int16); // defines AP_UInt16, AP_NamedUInt16 and AP_SavedUInt16
AP_VARDEF(int32_t, Int32); // defines AP_UInt32, AP_NamedUInt32 and AP_SavedUInt32
/// Some convenient constant AP_Vars.
extern const AP_Float AP_FloatUnity;
extern const AP_Float AP_FloatNegativeUnity;
extern const AP_Float AP_FloatZero;
#endif // AP_Var_H