ardupilot/libraries/AP_Common/AP_Var.h

950 lines
34 KiB
C
Raw Normal View History

// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-
//
// 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.
//
/// @file AP_Var.h
/// @brief A system for managing and storing variables that are of
/// general interest to the system.
#ifndef AP_VAR_H
#define AP_VAR_H
#include <stddef.h>
#include <string.h>
#include <stdint.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
#include "AP_MetaClass.h"
class AP_Var_group;
/// Base class for variables.
///
/// Provides naming and lookup services for variables.
///
class AP_Var : public AP_Meta_class
{
public:
/// EEPROM header
///
/// This structure is placed at the head of the EEPROM to indicate
/// that the ROM is formatted for AP_Var.
///
/// The EEPROM may thus be cheaply erased by overwriting just one
/// byte of the header magic.
///
struct EEPROM_header {
uint16_t magic;
uint8_t revision;
uint8_t spare;
};
static const uint16_t k_EEPROM_magic = 0x5041; ///< "AP"
static const uint16_t k_EEPROM_revision = 2; ///< current format revision
/// Storage key for variables that are saved in EEPROM.
///
/// The key is used to associate a known variable in memory
/// with storage for the variable in the EEPROM.
///
/// At creation time, the _key value has the k_key_not_located bit
/// set, and its value is an ordinal uniquely identifying the
/// variable. Once the address of the variable in EEPROM is known,
/// either as a result of scanning or due to allocation of new
/// space in the EEPROM, the k_key_not_located bit will be cleared
/// and the _key value gives the offset into the EEPROM where
/// the variable's data can be found.
///
typedef uint16_t Key;
/// This header is prepended to a variable stored in EEPROM.
///
/// Note that the size value is the first element in the header.
/// The sentinel entry marking the end of the EEPROM is always written
/// before updating the header of a new variable at the end of EEPROM.
/// This provides protection against corruption that might be caused
/// if the update process is interrupted.
///
struct Var_header {
/// The size of the variable, minus one.
/// This allows a variable or group to be anything from one to 64 bytes long.
///
uint8_t size:6;
/// Spare bits, currently unused
///
/// @todo One could be a parity bit?
///
uint8_t spare:2;
/// The key assigned to the variable.
///
uint8_t key;
};
/// A key value that indicates that a variable is not to be saved to EEPROM.
///
/// As the value has all bits set to 1, it's not a legal EEPROM address for any
/// EEPROM smaller than 64K (and it's too big to fit the Var_header::key field).
///
/// This value is normally the default.
///
static const Key k_key_none = 0xffff;
/// A key that has this bit set is still a key; if it has been cleared then
/// the key's value is actually an address in EEPROM.
///
static const Key k_key_not_located = (Key)1 << 15;
/// A key that has this bit set was not found during a scan of the EEPROM.
/// If this bit is set in the key, it's not useful to scan the EEPROM again
/// in an attempt to find it.
///
static const Key k_key_not_allocated = (Key)1 << 14;
/// Key assigned to the terminal entry in EEPROM.
///
static const Key k_key_sentinel = 0xff;
/// A bitmask that removes any control bits from a key giving just the
/// value.
///
static const Key k_key_mask = ~(k_key_not_located | k_key_not_allocated);
/// The largest variable that will be saved to EEPROM.
/// This affects the amount of stack space that is required by the ::save, ::load,
/// ::save_all and ::load_all functions. It should match the maximum size that can
/// be encoded in the Var_header::size field.
///
static const size_t k_size_max = 64;
/// Optional flags affecting the behavior and usage of the variable.
///
typedef uint8_t Flags;
static const Flags k_flags_none = 0;
/// The variable will not be loaded by ::load_all or saved by ::save_all, but it
/// has a key and can be loaded/saved manually.
static const Flags k_flag_no_auto_load = (1 << 0);
/// This flag is advisory; it indicates that the variable's value should not be
/// imported from outside, e.g. from a GCS.
static const Flags k_flag_no_import = (1 << 1);
/// This flag indicates that the variable is really a group; it is normally
/// set automatically by the AP_Var_group constructor.
///
static const Flags k_flag_is_group = (1 << 2);
/// This flag indicates that the variable wants to opt out of being listed.
///
static const Flags k_flag_unlisted = (1 << 3);
/// @todo Flag that indicates variable is non-volatile (auto-saved when set).
static AP_Meta_class::Type_id k_typeid_float; ///< meta_type_id() value for AP_Float
static AP_Meta_class::Type_id k_typeid_float16; ///< meta_type_id() value for AP_Float16
static AP_Meta_class::Type_id k_typeid_int32; ///< meta_type_id() value for AP_Int32
static AP_Meta_class::Type_id k_typeid_int16; ///< meta_type_id() value for AP_Int16
static AP_Meta_class::Type_id k_typeid_int8; ///< meta_type_id() value for AP_Int8
static AP_Meta_class::Type_id k_typeid_group; ///< meta_type_id() value for AP_Var_group
/// Constructor for a freestanding variable
///
/// @param key The storage key to be associated with this variable.
/// @param name An optional name by which the variable may be known.
/// @param flags Optional flags which control how the variable behaves.
///
AP_Var(Key key = k_key_none, const prog_char *name = NULL, Flags flags = k_flags_none);
/// Constructor for variable belonging to a group
///
/// @param group The group the variable belongs to.
/// @param index The position of the variable in the group.
/// @param name An optional name by which the variable may be known.
/// @param flags Optional flags which control how the variable behaves.
///
AP_Var(AP_Var_group *group, Key index, const prog_char *name, Flags flags = k_flags_none);
/// Destructor
///
/// For freestanding variables, this will remove the variable from the global list
/// of variables. The list is organised FIFO, so locally-constructed freestanding
/// variables are typically cheap to destroy as they tend to be at or very close to
/// the head of the list.
///
/// Destroying a variable that is a group member may be less efficient as the list
/// of variables that are group members is sorted by key, requiring a traversal
/// of the list up to the index before it can be removed.
///
/// Destroying a group removes all variables that are members of the group from
/// the list, requiring a complete traversal of the list of group-member variables.
/// If the group is destroyed before its members, they will also traverse the entire
/// list as they attempt to remove themselves.
///
/// The moral of the story: be careful when creating groups with local scope.
///
~AP_Var(void);
/// Copy the variable's name, prefixed by any containing group name, to a buffer.
///
/// If the variable has no name, the buffer will contain an empty string.
///
/// 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;
/// Find a variable by name.
///
/// If the variable has no name, it cannot be found by this interface.
///
/// @param name The full name of the variable to be found.
/// @return A pointer to the variable, or NULL if
/// it does not exist.
///
static AP_Var *find(const char *name);
/// Save the current value of the variable to EEPROM.
///
/// This interface works for any subclass that implements
/// AP_Meta_class::serialize.
///
/// Note that invoking this method on a variable that is a group
/// member will cause the entire group to be saved.
///
/// @return True if the variable was saved successfully.
///
bool save(void);
/// Load the variable from EEPROM.
///
/// This interface works for any subclass that implements
/// AP_Meta_class::unserialize.
///
/// If the variable has not previously been saved to EEPROM, this
/// routine will return failure.
///
/// Note that invoking this method on a variable that is a group
/// member will cause the entire group to be loaded.
///
/// @return True if the variable was loaded successfully.
///
bool load(void);
/// Save all variables to EEPROM
///
/// This routine performs a best-efforts attempt to save all
/// of the variables to EEPROM. If some fail to save, the others
/// that succeed will still all be saved.
///
/// @return False if any variable failed to save.
///
static bool save_all(void);
/// Load all variables from EEPROM
///
/// This function performs a best-efforts attempt to load all
/// of the variables from EEPROM. If some fail to load, their
/// values will remain as they are.
///
/// @return False if any variable failed to load. Note
/// That this may be caused by a variable not having
/// previously been saved.
///
static bool load_all(void);
/// Erase all variables in EEPROM.
///
/// This can be used prior to save_all to ensure that only known variables
/// will be present in the EEPROM.
///
/// It can also be used immediately prior to reset, followed by a save_all,
/// to restore all saved variables to their initial value.
///
static void erase_all(void);
/// Test for flags that may be set.
///
/// @param flagval Flag or flags to be tested
/// @return True if all of the bits in flagval are set in the flags.
///
bool has_flags(Flags flagval) const {
return (_flags & flagval) == flagval;
}
/// Returns the group that a variable belongs to
///
/// @return The parent group, or NULL if the variable is not grouped.
///
AP_Var_group *group(void) { return _group; }
/// Returns the first variable in the global list.
///
/// @return The first variable in the global list, or NULL if
/// there are none.
///
static AP_Var *first(void) { return _variables; }
/// Returns the next variable in the global list.
///
/// All standalone variables are returned first, then all grouped variables.
/// Note that groups themselves are considered standalone variables.
///
/// A caller not wishing to iterate grouped variables should test the return
/// value from this function with ::group, and if non-null, ignore it.
///
/// XXX how to ignore groups?
///
/// @return The next variable, either the next group member in order or
/// the next variable in an arbitrary order, or NULL if this is
/// the last variable in the list.
///
AP_Var *next(void);
/// Returns the first variable that is a member of a specific group.
///
/// @param group The group whose member(s) are sought.
/// @return The first variable in the group, or NULL if there are none.
///
static AP_Var *first_member(AP_Var_group *group);
/// Returns the next variable that is a member of the same group.
///
/// This will not behave correctly if called on a variable that is not a group member.
///
/// @param group The group whose member(s) are sought.
/// @return The next variable in the group, or NULL if there are none.
///
AP_Var *next_member();
/// Returns the storage key for a variable.
///
/// Note that group members do not have storage keys - the key is held by the group
/// and instead the key indicates the variable's ordering within the group.
///
/// @return The variable's key, or k_key_none if it does not have a key.
///
Key key(void);
/// Casts the value to float, if possible.
///
/// This is a convenience method for code that would rather not try to
/// meta-cast to the various subtypes. It cannot guarantee that a useful value
/// will be returned; the caller must check the returned value against NAN
/// before using it.
///
/// @return The value cast to float, or NAN if it cannot be cast.
///
virtual float cast_to_float() const;
/// Report the amount of memory being used by AP_Var subclasses.
///
/// @return The sum of sizeof(*this) for all constructed AP_Var subclass instances.
///
static uint16_t get_memory_use() { return _bytes_in_use; }
protected:
// Memory statistics
static uint16_t _bytes_in_use;
private:
AP_Var_group *_group; ///< Group that the variable may be a member of
AP_Var *_link; ///< linked list pointer to next variable
Key _key; ///< Storage key; see the discussion of Key above.
const prog_char *_name; ///< name known to external agents (GCS, etc.)
uint8_t _flags; ///< flag bits
// static state used by ::lookup
static AP_Var *_variables; ///< linked list of all freestanding variables
static AP_Var *_grouped_variables; ///< linked list of all grouped variables
// EEPROM space allocation and scanning
static uint16_t _tail_sentinel; ///< EEPROM address of the tail sentinel
static const uint16_t k_EEPROM_size = 4096; ///< XXX avr-libc doesn't consistently export this
/// Scan the EEPROM and assign addresses to any known variables
/// that have entries there.
///
/// @return True if the EEPROM was scanned successfully.
///
static bool _EEPROM_scan(void);
/// Locate this variable in the EEPROM.
///
/// @param allocate If true, and the variable does not already have
/// space allocated in EEPROM, allocate it.
/// @return True if the _key field is a valid EEPROM address with
/// space reserved for the variable to be saved. False
/// if the variable does not have a key, or space could not
/// be allocated and the variable does not already exist in
/// EEPROM.
///
bool _EEPROM_locate(bool allocate);
};
/// Variable groups.
///
/// Grouped variables are treated as a single variable when loaded from
/// or saved to EEPROM. The size limits for variables apply to the entire
/// group; thus a group cannot be larger than the largest legal variable.
///
/// When AP_Var is asked for the name of a variable that is a member
/// of a group, it will prepend the name of the group; this helps save
/// memory.
///
/// Variables belonging to a group are always sorted into the global
/// variable list after the group.
///
class AP_Var_group : public AP_Var
{
public:
/// Constructor
///
/// @param key Storage key for the group.
/// @param name An optional name prefix for members of the group.
///
AP_Var_group(Key key = k_key_none, const prog_char *name = NULL, Flags flags = k_flags_none) :
AP_Var(key, name, flags | k_flag_is_group)
{
_bytes_in_use += sizeof(*this);
}
/// Serialize the group.
///
/// Iteratively serializes the entire group into the supplied buffer.
///
/// @param buf Buffer into which serialized data should be placed.
/// @param buf_size The size of the buffer provided.
/// @return The size of the serialized data, even if that data would
/// have overflowed the buffer. If the value is less than or
/// equal to buf_size, serialization was successful.
///
virtual size_t serialize(void *buf, size_t buf_size) const;
/// Unserialize the group.
///
/// Iteratively unserializes the group from the supplied buffer.
///
/// @param buf Buffer containing serialized data.
/// @param buf_size The size of the buffer.
/// @return The number of bytes from the buffer that would be consumed
/// unserializing the data. If the value is less than or equal
/// to buf_size, unserialization was successful.
///
virtual size_t unserialize(void *buf, size_t buf_size);
private:
/// Common implementation of the group member traversal and accounting used
/// by serialize/unserialize.
///
/// @param buf Buffer containing serialized data.
/// @param buf_size The size of the buffer.
/// @param do_serialize True if the operation should serialize, false if it should
/// unserialize.
/// @return The number of bytes from the buffer that would be consumed
/// operating on the data. If the value is less than or equal
/// to buf_size, the operation was successful.
///
size_t _serialize_unserialize(void *buf, size_t buf_size, bool do_serialize);
};
/// 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_VarT : public AP_Var
{
public:
/// Constructor for non-grouped variable.
///
/// Initialises a stand-alone variable with optional initial value, storage key, name and flags.
///
/// @param default_value Value the variable should have at startup.
/// @param key Storage key for the variable. If not set, or set to AP_Var::k_key_none
/// the variable cannot be loaded from or saved to EEPROM.
/// @param name An optional name by which the variable may be known.
/// @param flags Optional flags that may affect the behaviour of the variable.
///
AP_VarT<T> (const T initial_value = 0,
Key key = k_key_none,
const prog_char *name = NULL,
Flags flags = k_flags_none) :
AP_Var(key, name, flags),
_value(initial_value)
{
_bytes_in_use += sizeof(*this);
}
/// Constructor for grouped variable.
///
/// Initialises a variable that is a member of a group with optional initial value, name and flags.
///
/// @param group The group that this variable belongs to.
/// @param index The variable's index within the group. Index values must be unique
/// within the group, as they ensure that the group's layout in EEPROM
/// is consistent.
/// @param initial_value The value the variable takes at startup.
/// @param name An optional name by which the variable may be known.
/// @param flags Optional flags that may affect the behaviour of the variable.
///
AP_VarT<T> (AP_Var_group *group, // XXX maybe make this a ref?
Key index,
T initial_value,
const prog_char *name = NULL,
Flags flags = k_flags_none) :
AP_Var(group, index, name, flags),
_value(initial_value)
{
_bytes_in_use += sizeof(*this);
}
// serialize _value into the buffer, but only if it is big enough.
//
virtual size_t serialize(void *buf, size_t size) const {
if (size >= sizeof(_value)) {
*(T *)buf = _value;
}
return sizeof(_value);
}
// Unserialize from the buffer, but only if it is big enough.
//
virtual size_t unserialize(void *buf, size_t size) {
if (size >= sizeof(_value)) {
_value = *(T *)buf;
}
return sizeof(_value);
}
/// Value getter
///
T get(void) const {
return _value;
}
/// Value setter
///
void set(T v) {
_value = v;
}
/// Combined set and save
///
bool set_and_save(T v) {
set(v);
return save();
}
/// Conversion to T returns a reference to the value.
///
/// This allows the class to be used in many situations where the value would be legal.
///
operator T &() {
return _value;
}
/// Copy assignment from self does nothing.
///
AP_VarT<T>& operator=(AP_VarT<T>& v) {
return v;
}
/// Copy assignment from T is equivalent to ::set.
///
AP_VarT<T>& operator=(T v) {
_value = v;
return *this;
}
/// AP_VarT types can implement AP_Var::cast_to_float
///
virtual float cast_to_float() const;
protected:
T _value;
};
// Implement AP_Var::cast_to_float.
//
template<typename T>
float
AP_VarT<T>::cast_to_float() const
{
return (float)_value;
}
/// Template class for structure variables.
///
/// Objects created using this variable contain an instance of the type T
///
/// Note that the size of the structure cannot be greater than AP_Var::k_size_max
/// if it is ever to be loaded or saved to EEPROM.
/// Unfortunately there is no way to assert this at compile time; a larger
/// array will compile correctly and work as expected, except that ::save and
/// ::load will always fail.
///
/// @note The initial value of the fields of the structure are set by
/// the type's constructor at the time that the template is constructed.
///
template<typename T>
class AP_VarS : public AP_Var
{
public:
/// Constructor for a non-grouped structure variable.
///
/// Initializes a stand-alone structure variable with optional storage key, name and flags.
///
/// @param key Storage key for the variable. If not set, or set to AP_Var::k_key_none
/// the variable cannot be loaded from or saved to EEPROM.
/// @param name An optional name by which the variable may be known.
/// @param flags Optional flags that may affect the behavior of the variable.
///
AP_VarS<T> (Key key = k_key_none,
const prog_char *name = NULL,
Flags flags = k_flags_none) :
AP_Var(key, name, flags)
{
_bytes_in_use += sizeof(*this);
}
/// Constructor for a grouped structure variable.
///
/// Initializes a variable that is a member of a group with optional initial value, name and flags.
///
/// @param group The group that this variable belongs to.
/// @param index The variable's index within the group. Index values must be unique
/// within the group, as they ensure that the group's layout in EEPROM
/// is consistent.
/// @param name An optional name by which the variable may be known.
/// @param flags Optional flags that may affect the behavior of the variable.
///
AP_VarS<T> (AP_Var_group *group, // XXX maybe make this a ref?
Key index,
const prog_char *name = NULL,
Flags flags = k_flags_none) :
AP_Var(group, index, name, flags)
{
_bytes_in_use += sizeof(*this);
}
// serialize _value into the buffer, but only if it is big enough.
//
virtual size_t serialize(void *buf, size_t size) const {
if (size >= sizeof(_value)) {
memcpy(buf, &_value, sizeof(_value));
}
return sizeof(_value);
}
// Unserialize from the buffer, but only if it is big enough.
//
virtual size_t unserialize(void *buf, size_t size) {
if (size >= sizeof(_value)) {
memcpy(&_value, buf, sizeof(_value));
}
return sizeof(_value);
}
/// Value getter
///
T& get() {
return _value;
}
/// Value setter
///
void set(T v) {
_value = v;
}
/// Combined set and save
///
void set_and_save(T v) {
set(v);
save();
}
// Note no attempt to do anything fancy with the assignment or cast operators.
// Implementing something that works reliably and produces readable code is not
// straightforward, so it's been deferred for now.
protected:
T _value;
};
/// Template class for array variables.
///
/// Objects created using this template behave like arrays of the type T,
/// but are stored like single variables.
///
/// Note that the size of the array cannot be greater than AP_Var::k_size_max
/// if it is ever to be loaded or saved to EEPROM.
/// Unfortunately there is no way to assert this at compile time; a larger
/// array will compile correctly and work as expected, except that ::save and
/// ::load will always fail.
///
/// For example:
///
/// AP_VarA<float,4> float_array(some_key, PSTR("some_name"));
///
/// will create float_array as an array of four floats, stored using the
/// key some_key and visible with the name 'some_name'.
///
/// @note Like regular arrays, the initial value of the members of the
/// array is zero if the object is declared with global scope, and
/// undefined if declared in a block (function, etc.).
///
/// @tparam T The scalar type of the variable
///
template<typename T, uint8_t N>
class AP_VarA : public AP_Var
{
public:
/// Constructor for non-grouped array.
///
/// Initializes a stand-alone array with optional storage key, name and flags.
///
/// @param key Storage key for the variable. If not set, or set to AP_Var::k_key_none
/// the variable cannot be loaded from or saved to EEPROM.
/// @param name An optional name by which the variable may be known.
/// @param flags Optional flags that may affect the behavior of the variable.
///
AP_VarA<T,N> (Key key = k_key_none,
const prog_char *name = NULL,
Flags flags = k_flags_none) :
AP_Var(key, name, flags)
{
_bytes_in_use += sizeof(*this);
}
/// Constructor for a grouped array.
///
/// Initializes a variable that is a member of a group with optional initial value, name and flags.
///
/// @param group The group that this variable belongs to.
/// @param index The variable's index within the group. Index values must be unique
/// within the group, as they ensure that the group's layout in EEPROM
/// is consistent.
/// @param name An optional name by which the variable may be known.
/// @param flags Optional flags that may affect the behavior of the variable.
///
AP_VarA<T,N> (AP_Var_group *group, // XXX maybe make this a ref?
Key index,
const prog_char *name = NULL,
Flags flags = k_flags_none) :
AP_Var(group, index, name, flags)
{
_bytes_in_use += sizeof(*this);
}
// serialize _value into the buffer, but only if it is big enough.
//
virtual size_t serialize(void *buf, size_t size) const {
if (size >= sizeof(_value)) {
memcpy(buf, &_value[0], sizeof(_value));
}
return sizeof(_value);
}
// Unserialize from the buffer, but only if it is big enough.
//
virtual size_t unserialize(void *buf, size_t size) {
if (size >= sizeof(_value)) {
memcpy(&_value[0], buf, sizeof(_value));
}
return sizeof(_value);
}
/// Array operator accesses members.
///
/// @note It would be nice to range-check i here, but then what would we return?
///
T &operator [](uint8_t i) {
return _value[i];
}
/// Value getter
///
/// @note Returns zero for index values out of range.
///
T get(uint8_t i) const {
if (i < N) {
return _value[i];
} else {
return (T)0;
}
}
/// Value setter
///
/// @note Attempts to set an index out of range are discarded.
///
void set(uint8_t i, T v) {
if (i < N) {
_value[i] = v;
}
}
/// Copy assignment from self does nothing.
///
AP_VarA<T,N>& operator=(AP_VarA<T,N>& v) {
return v;
}
protected:
T _value[N];
};
/// Convenience macro for defining instances of the AP_VarT template.
///
#define AP_VARDEF(_t, _n) typedef AP_VarT<_t> AP_##_n;
AP_VARDEF(float, Float); // defines AP_Float
AP_VARDEF(int8_t, Int8); // defines AP_Int8
AP_VARDEF(int16_t, Int16); // defines AP_Int16
AP_VARDEF(int32_t, Int32); // defines AP_Int32
/// Rely on built in casting for other variable types
/// to minimize template creation and save memory
#define AP_Uint8 AP_Int8
#define AP_Uint16 AP_Int16
#define AP_Uint32 AP_Int32
#define AP_Bool AP_Int8
/// Many float values can be saved as 16-bit fixed-point values, reducing EEPROM
/// consumption. AP_Float16 subclasses AP_Float and overloads serialize/unserialize
/// to achieve this.
///
/// Note that any protocol transporting serialized data should be aware that the
/// encoding used is effectively Q5.10 (one sign bit, 5 integer bits, 10 fractional bits),
/// giving an effective range of approximately +/-31.999
///
class AP_Float16 : public AP_Float
{
public:
/// Constructors mimic AP_Float::AP_Float()
///
AP_Float16(float initial_value = 0,
Key key = k_key_none,
const prog_char *name = NULL,
Flags flags = k_flags_none) :
AP_Float(initial_value, key, name, flags)
{
_bytes_in_use += sizeof(*this);
}
AP_Float16(AP_Var_group *group,
Key index,
float initial_value = 0,
const prog_char *name = NULL,
Flags flags = k_flags_none) :
AP_Float(group, index, initial_value, name, flags)
{
_bytes_in_use += sizeof(*this);
}
// Serialize _value as Q5.10.
//
virtual size_t serialize(void *buf, size_t size) const {
uint16_t *sval = (uint16_t *)buf;
if (size >= sizeof(*sval)) {
*sval = _value * 1024.0; // scale by power of 2, may be more efficient
}
return sizeof(*sval);
}
// Unserialize _value from Q5.10.
//
virtual size_t unserialize(void *buf, size_t size) {
uint16_t *sval = (uint16_t *)buf;
if (size >= sizeof(*sval)) {
_value = (float)*sval / 1024.0; // scale by power of 2, may be more efficient
return sizeof(*sval);
}
return 0;
}
// copy operators must be redefined in subclasses to get correct behavior
AP_Float16 &operator=(AP_Float16 &v) {
return v;
}
AP_Float16 &operator=(float v) {
_value = v;
return *this;
}
};
/// Some convenient constant AP_Vars.
///
/// @todo Work out why these can't be const and fix if possible.
///
/// @todo Work out how to get these into a namespace and name them properly.
///
extern AP_Float AP_Float_unity;
extern AP_Float AP_Float_negative_unity;
extern AP_Float AP_Float_zero;
/// Print the value of an AP_Var
///
/// This function knows about the types listed in the AP_Var::k_typeid_* constants,
/// and it will print their value using Serial, which is assumed to be a BetterStream
/// serial port (e.g. FastSerial).
///
/// @param vp The variable to print.
///
extern void AP_Var_print(AP_Var *vp);
#ifndef __AP_COMMON_MENU_H
# error Must include menu.h
#endif
/// Menu function for setting an AP_Var.
///
/// This function can be directly called from a Menu. It expects two args, the
/// first is the full name of a variable, the second is the value to set the variable
/// to.
///
/// This function knows about the types listed in the AP_Var::k_typeid_* constants.
///
/// @param argc The number of arguments; must be 3.
/// @param argv Arguments. argv[1] must contain a variable name, argv[2].f and .i
/// are consulted when setting the value.
/// @return Zero if the variable was set successfully, -1 if it could not be set.
///
extern int8_t AP_Var_menu_set(uint8_t argc, const Menu::arg *argv);
/// Menu function for displaying AP_Vars.
///
/// This function can be directly called from a Menu. It expects zero or one argument.
/// If no arguments are supplied, all known variables are printed. If an argument is
/// supplied, it is expected to be the name of a variable and that variable will be
/// printed.
///
/// @param argc The number of arguments, must be 1 or 2.
/// @param argv Argument array; argv[1] may be set to the name of a variable to show.
///
extern int8_t AP_Var_menu_show(uint8_t argc, const Menu::arg *argv);
#endif // AP_VAR_H