Add a function to AP_Var for finding a variable by name. It is not efficient, but convenient for e.g. interactive use.

Add pseudo-constant copies of the AP_Meta_calss::Type_id for the standard AP_VarT subclasses.  This makes checking the type of a possible AP_Var much cheaper than calling ::meta_cast, as there is no object con/destruction involved.

Add some helper functions for manipulating AP_Vars from Menu interfaces.

git-svn-id: https://arducopter.googlecode.com/svn/trunk@1541 f9c3cf11-9bcb-44bc-f272-b75c42450872
This commit is contained in:
DrZiplok@gmail.com 2011-01-23 23:58:07 +00:00
parent 7f5b882e1a
commit 27c36583d0
3 changed files with 265 additions and 10 deletions

View File

@ -5,9 +5,9 @@
// 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.
/// @file AP_Var.cpp
/// @brief The AP variable store.
#if 0
# include <FastSerial.h>
@ -17,7 +17,9 @@ extern "C" { extern void delay(unsigned long); }
# define log(fmt, args...)
#endif
#include "AP_Var.h"
#include <AP_Common.h>
#include <string.h>
// Global constants exported for general use.
//
@ -133,6 +135,28 @@ void AP_Var::copy_name(char *buffer, size_t buffer_size) const
strlcat_P(buffer, _name, buffer_size);
}
// Find a variable by name.
//
AP_Var *
AP_Var::find(const char *name)
{
AP_Var *vp;
for (vp = first(); vp; vp = vp->next()) {
char name_buffer[32];
// copy the variable's name into our scratch buffer
vp->copy_name(name_buffer, sizeof(name_buffer));
// compare with the user-supplied name
if (!strcmp(name, name_buffer)) {
return vp;
}
}
return NULL;
}
// Save the variable to EEPROM, if supported
//
bool AP_Var::save(void)
@ -611,3 +635,42 @@ AP_Var_group::_serialize_unserialize(void *buf, size_t buf_size, bool do_seriali
}
return total_size;
}
// Static pseudo-constant type IDs for known AP_VarT subclasses.
//
AP_Meta_class::Type_id AP_Var::k_typeid_float; ///< meta_type_id() value for AP_Float
AP_Meta_class::Type_id AP_Var::k_typeid_float16; ///< meta_type_id() value for AP_Float16
AP_Meta_class::Type_id AP_Var::k_typeid_int32; ///< meta_type_id() value for AP_Int32
AP_Meta_class::Type_id AP_Var::k_typeid_int16; ///< meta_type_id() value for AP_Int16
AP_Meta_class::Type_id AP_Var::k_typeid_int8; ///< meta_type_id() value for AP_Int8
/// A special class used to initialise the k_typeid_* values that AP_Var exports.
///
class AP_Var_typesetup
{
public:
/// Constructor
///
/// This constructor should be run just once by creating a static instance
/// of the class. It will initialise the k_typeid_* values for the well-known
/// AP_VarT subclasses.
///
/// When a new subclass is created, a new k_typeid_* constant should also be
/// created and the list below should likewise be expanded.
///
AP_Var_typesetup(void);
};
/// Initialise AP_Var's k_typeid_* values
AP_Var_typesetup::AP_Var_typesetup(void)
{
AP_Var::k_typeid_float = AP_Meta_class::meta_type_id<AP_Float>();
AP_Var::k_typeid_float16 = AP_Meta_class::meta_type_id<AP_Float16>();
AP_Var::k_typeid_int32 = AP_Meta_class::meta_type_id<AP_Int32>();
AP_Var::k_typeid_int16 = AP_Meta_class::meta_type_id<AP_Int16>();
AP_Var::k_typeid_int8 = AP_Meta_class::meta_type_id<AP_Int8>();
}
/// Cause the AP_Var_typesetup constructor to be run.
///
static AP_Var_typesetup _typesetup __attribute__((used));

View File

@ -9,12 +9,6 @@
/// @file AP_Var.h
/// @brief A system for managing and storing variables that are of
/// general interest to the system.
///
///
/// 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
@ -152,6 +146,12 @@ public:
///
static const Flags k_flag_unlisted = (1 << 3);
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
/// Constructor for a freestanding variable
///
/// @param key The storage key to be associated with this variable.
@ -201,6 +201,16 @@ public:
///
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
@ -622,4 +632,47 @@ 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

View File

@ -0,0 +1,139 @@
// -*- 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_menufuncs.cpp
/// @brief Useful functions compatible with the menu system for
/// managing AP_Var variables.
#include <FastSerial.h>
#include <AP_Common.h>
void
AP_Var_print(AP_Var *vp)
{
// try to print from variable types that we know
if (vp->meta_type_id() == AP_Var::k_typeid_float) {
AP_Float *v = (AP_Float *)vp;
Serial.printf_P(PSTR("%f"), v->get());
} else if (vp->meta_type_id() == AP_Var::k_typeid_float16) {
AP_Float16 *v = (AP_Float16 *)vp;
Serial.printf_P(PSTR("%f"), v->get());
} else if (vp->meta_type_id() == AP_Var::k_typeid_int32) {
AP_Int32 *v = (AP_Int32 *)vp;
Serial.printf_P(PSTR("%ld"), v->get());
} else if (vp->meta_type_id() == AP_Var::k_typeid_int16) {
AP_Int16 *v = (AP_Int16 *)vp;
Serial.printf_P(PSTR("%d"), v->get());
} else if (vp->meta_type_id() == AP_Var::k_typeid_int8) {
AP_Int8 *v = (AP_Int8 *)vp;
Serial.printf_P(PSTR("%d"), v->get());
} else {
Serial.print_P(PSTR("??"));
}
}
int8_t
AP_Var_menu_set(uint8_t argc, const Menu::arg *argv)
{
AP_Var *vp;
// check argument count
if (argc != 3) {
Serial.println_P(PSTR("missing name or value"));
return -1;
}
Serial.printf_P(PSTR("%s: "), argv[1].str);
// search for the variable
vp = AP_Var::find(argv[1].str);
if (NULL == vp) {
Serial.println_P(PSTR("not found"));
return -1;
}
// try to assign to variable types that we know
if (vp->meta_type_id() == AP_Var::k_typeid_float) {
AP_Float *v = (AP_Float *)vp;
v->set(argv[2].f);
} else if (vp->meta_type_id() == AP_Var::k_typeid_float16) {
AP_Float16 *v = (AP_Float16 *)vp;
v->set(argv[2].f);
} else if (vp->meta_type_id() == AP_Var::k_typeid_int32) {
AP_Int32 *v = (AP_Int32 *)vp;
v->set(argv[2].i);
} else if (vp->meta_type_id() == AP_Var::k_typeid_int16) {
AP_Int16 *v = (AP_Int16 *)vp;
v->set(argv[2].i);
} else if (vp->meta_type_id() == AP_Var::k_typeid_int8) {
AP_Int8 *v = (AP_Int8 *)vp;
v->set(argv[2].i);
} else {
Serial.println_P(PSTR("unknown type"));
return -1;
}
AP_Var_print(vp);
Serial.println();
return 0;
}
int8_t
AP_Var_menu_show(uint8_t argc, const Menu::arg *argv)
{
AP_Var *vp;
// if no arguments, show all variables
if (argc == 1) {
for (vp = AP_Var::first(); vp; vp = vp->next()) {
char name_buffer[32];
// get a displayable name for the variable
vp->copy_name(name_buffer, sizeof(name_buffer));
if (name_buffer[0] == 0) {
strcpy_P(name_buffer, PSTR("??"));
}
// print name and value
Serial.printf_P(PSTR("%-32.32s: "), name_buffer);
AP_Var_print(vp);
Serial.println();
}
return 0;
}
// show variable by name
Serial.printf_P(PSTR("%s: "), argv[1].str);
vp = AP_Var::find(argv[1].str);
if (NULL == vp) {
Serial.println_P(PSTR("not found"));
return -1;
}
AP_Var_print(vp);
Serial.println();
return 0;
}