mirror of https://github.com/ArduPilot/ardupilot
implemented typesafe PSTR()
This makes PSTR() type safe by using a 1 byte wrapper structure. Attempts to use the wrong varient of a print function will generate a compilation error. git-svn-id: https://arducopter.googlecode.com/svn/trunk@1797 f9c3cf11-9bcb-44bc-f272-b75c42450872
This commit is contained in:
parent
fd10614822
commit
211de598c3
|
@ -1,4 +1,4 @@
|
||||||
// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: t -*-
|
// -*- 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
|
// 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
|
// the terms of the GNU Lesser General Public License as published by the
|
||||||
|
@ -21,6 +21,14 @@
|
||||||
#undef round
|
#undef round
|
||||||
#undef abs
|
#undef abs
|
||||||
|
|
||||||
|
// prog_char_t is used as a wrapper type for prog_char, which is
|
||||||
|
// a character stored in flash. By using this wrapper type we can
|
||||||
|
// auto-detect at compile time if a call to a string function is using
|
||||||
|
// a flash-stored string or not
|
||||||
|
typedef struct {
|
||||||
|
char c;
|
||||||
|
} prog_char_t;
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "include/menu.h" /// simple menu subsystem
|
#include "include/menu.h" /// simple menu subsystem
|
||||||
#include "c++.h" // c++ additions
|
#include "c++.h" // c++ additions
|
||||||
|
@ -72,8 +80,25 @@
|
||||||
# undef PROGMEM
|
# undef PROGMEM
|
||||||
# define PROGMEM __attribute__(( section(".progmem.data") ))
|
# define PROGMEM __attribute__(( section(".progmem.data") ))
|
||||||
# undef PSTR
|
# undef PSTR
|
||||||
# define PSTR(s) (__extension__({static prog_char __c[] PROGMEM = (s); &__c[0];}))
|
# define PSTR(s) (__extension__({static prog_char __c[] PROGMEM = (s); \
|
||||||
|
(prog_char_t *)&__c[0];}))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static inline int strcasecmp_P(const char *str1, const prog_char_t *pstr)
|
||||||
|
{
|
||||||
|
return strcasecmp_P(str1, (const prog_char *)pstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int strcmp_P(const char *str1, const prog_char_t *pstr)
|
||||||
|
{
|
||||||
|
return strcmp_P(str1, (const prog_char *)pstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline size_t strlcat_P(char *buffer, const prog_char_t *pstr, size_t buffer_size)
|
||||||
|
{
|
||||||
|
return strlcat_P(buffer, (const prog_char *)pstr, buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ uint16_t AP_Var::_bytes_in_use;
|
||||||
|
|
||||||
// Constructor for standalone variables
|
// Constructor for standalone variables
|
||||||
//
|
//
|
||||||
AP_Var::AP_Var(Key key, const prog_char *name, Flags flags) :
|
AP_Var::AP_Var(Key key, const prog_char_t *name, Flags flags) :
|
||||||
_group(NULL),
|
_group(NULL),
|
||||||
_key(key | k_key_not_located),
|
_key(key | k_key_not_located),
|
||||||
_name(name),
|
_name(name),
|
||||||
|
@ -54,7 +54,7 @@ AP_Var::AP_Var(Key key, const prog_char *name, Flags flags) :
|
||||||
|
|
||||||
// Constructor for variables in a group
|
// Constructor for variables in a group
|
||||||
//
|
//
|
||||||
AP_Var::AP_Var(AP_Var_group *group, Key index, const prog_char *name, Flags flags) :
|
AP_Var::AP_Var(AP_Var_group *group, Key index, const prog_char_t *name, Flags flags) :
|
||||||
_group(group),
|
_group(group),
|
||||||
_key(index),
|
_key(index),
|
||||||
_name(name),
|
_name(name),
|
||||||
|
|
|
@ -161,7 +161,7 @@ public:
|
||||||
/// @param name An optional name by which the variable may be known.
|
/// @param name An optional name by which the variable may be known.
|
||||||
/// @param flags Optional flags which control how the variable behaves.
|
/// @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);
|
AP_Var(Key key = k_key_none, const prog_char_t *name = NULL, Flags flags = k_flags_none);
|
||||||
|
|
||||||
/// Constructor for variable belonging to a group
|
/// Constructor for variable belonging to a group
|
||||||
///
|
///
|
||||||
|
@ -170,7 +170,7 @@ public:
|
||||||
/// @param name An optional name by which the variable may be known.
|
/// @param name An optional name by which the variable may be known.
|
||||||
/// @param flags Optional flags which control how the variable behaves.
|
/// @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);
|
AP_Var(AP_Var_group *group, Key index, const prog_char_t *name, Flags flags = k_flags_none);
|
||||||
|
|
||||||
/// Destructor
|
/// Destructor
|
||||||
///
|
///
|
||||||
|
@ -361,7 +361,7 @@ private:
|
||||||
AP_Var_group *_group; ///< Group that the variable may be a member of
|
AP_Var_group *_group; ///< Group that the variable may be a member of
|
||||||
AP_Var *_link; ///< linked list pointer to next variable
|
AP_Var *_link; ///< linked list pointer to next variable
|
||||||
Key _key; ///< Storage key; see the discussion of Key above.
|
Key _key; ///< Storage key; see the discussion of Key above.
|
||||||
const prog_char *_name; ///< name known to external agents (GCS, etc.)
|
const prog_char_t *_name; ///< name known to external agents (GCS, etc.)
|
||||||
uint8_t _flags; ///< flag bits
|
uint8_t _flags; ///< flag bits
|
||||||
|
|
||||||
// static state used by ::lookup
|
// static state used by ::lookup
|
||||||
|
@ -415,7 +415,7 @@ public:
|
||||||
/// @param key Storage key for the group.
|
/// @param key Storage key for the group.
|
||||||
/// @param name An optional name prefix for members of 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_group(Key key = k_key_none, const prog_char_t *name = NULL, Flags flags = k_flags_none) :
|
||||||
AP_Var(key, name, flags | k_flag_is_group)
|
AP_Var(key, name, flags | k_flag_is_group)
|
||||||
{
|
{
|
||||||
_bytes_in_use += sizeof(*this);
|
_bytes_in_use += sizeof(*this);
|
||||||
|
@ -483,7 +483,7 @@ public:
|
||||||
///
|
///
|
||||||
AP_VarT<T> (const T initial_value = 0,
|
AP_VarT<T> (const T initial_value = 0,
|
||||||
Key key = k_key_none,
|
Key key = k_key_none,
|
||||||
const prog_char *name = NULL,
|
const prog_char_t *name = NULL,
|
||||||
Flags flags = k_flags_none) :
|
Flags flags = k_flags_none) :
|
||||||
AP_Var(key, name, flags),
|
AP_Var(key, name, flags),
|
||||||
_value(initial_value)
|
_value(initial_value)
|
||||||
|
@ -506,7 +506,7 @@ public:
|
||||||
AP_VarT<T> (AP_Var_group *group, // XXX maybe make this a ref?
|
AP_VarT<T> (AP_Var_group *group, // XXX maybe make this a ref?
|
||||||
Key index,
|
Key index,
|
||||||
T initial_value,
|
T initial_value,
|
||||||
const prog_char *name = NULL,
|
const prog_char_t *name = NULL,
|
||||||
Flags flags = k_flags_none) :
|
Flags flags = k_flags_none) :
|
||||||
AP_Var(group, index, name, flags),
|
AP_Var(group, index, name, flags),
|
||||||
_value(initial_value)
|
_value(initial_value)
|
||||||
|
@ -616,7 +616,7 @@ public:
|
||||||
/// @param flags Optional flags that may affect the behavior of the variable.
|
/// @param flags Optional flags that may affect the behavior of the variable.
|
||||||
///
|
///
|
||||||
AP_VarS<T> (Key key = k_key_none,
|
AP_VarS<T> (Key key = k_key_none,
|
||||||
const prog_char *name = NULL,
|
const prog_char_t *name = NULL,
|
||||||
Flags flags = k_flags_none) :
|
Flags flags = k_flags_none) :
|
||||||
AP_Var(key, name, flags)
|
AP_Var(key, name, flags)
|
||||||
{
|
{
|
||||||
|
@ -636,7 +636,7 @@ public:
|
||||||
///
|
///
|
||||||
AP_VarS<T> (AP_Var_group *group, // XXX maybe make this a ref?
|
AP_VarS<T> (AP_Var_group *group, // XXX maybe make this a ref?
|
||||||
Key index,
|
Key index,
|
||||||
const prog_char *name = NULL,
|
const prog_char_t *name = NULL,
|
||||||
Flags flags = k_flags_none) :
|
Flags flags = k_flags_none) :
|
||||||
AP_Var(group, index, name, flags)
|
AP_Var(group, index, name, flags)
|
||||||
{
|
{
|
||||||
|
@ -726,7 +726,7 @@ public:
|
||||||
/// @param flags Optional flags that may affect the behavior of the variable.
|
/// @param flags Optional flags that may affect the behavior of the variable.
|
||||||
///
|
///
|
||||||
AP_VarA<T,N> (Key key = k_key_none,
|
AP_VarA<T,N> (Key key = k_key_none,
|
||||||
const prog_char *name = NULL,
|
const prog_char_t *name = NULL,
|
||||||
Flags flags = k_flags_none) :
|
Flags flags = k_flags_none) :
|
||||||
AP_Var(key, name, flags)
|
AP_Var(key, name, flags)
|
||||||
{
|
{
|
||||||
|
@ -746,7 +746,7 @@ public:
|
||||||
///
|
///
|
||||||
AP_VarA<T,N> (AP_Var_group *group, // XXX maybe make this a ref?
|
AP_VarA<T,N> (AP_Var_group *group, // XXX maybe make this a ref?
|
||||||
Key index,
|
Key index,
|
||||||
const prog_char *name = NULL,
|
const prog_char_t *name = NULL,
|
||||||
Flags flags = k_flags_none) :
|
Flags flags = k_flags_none) :
|
||||||
AP_Var(group, index, name, flags)
|
AP_Var(group, index, name, flags)
|
||||||
{
|
{
|
||||||
|
@ -841,7 +841,7 @@ public:
|
||||||
///
|
///
|
||||||
AP_Float16(float initial_value = 0,
|
AP_Float16(float initial_value = 0,
|
||||||
Key key = k_key_none,
|
Key key = k_key_none,
|
||||||
const prog_char *name = NULL,
|
const prog_char_t *name = NULL,
|
||||||
Flags flags = k_flags_none) :
|
Flags flags = k_flags_none) :
|
||||||
AP_Float(initial_value, key, name, flags)
|
AP_Float(initial_value, key, name, flags)
|
||||||
{
|
{
|
||||||
|
@ -851,7 +851,7 @@ public:
|
||||||
AP_Float16(AP_Var_group *group,
|
AP_Float16(AP_Var_group *group,
|
||||||
Key index,
|
Key index,
|
||||||
float initial_value = 0,
|
float initial_value = 0,
|
||||||
const prog_char *name = NULL,
|
const prog_char_t *name = NULL,
|
||||||
Flags flags = k_flags_none) :
|
Flags flags = k_flags_none) :
|
||||||
AP_Float(group, index, initial_value, name, flags)
|
AP_Float(group, index, initial_value, name, flags)
|
||||||
{
|
{
|
||||||
|
|
|
@ -186,9 +186,9 @@ AP_GPS_Auto::_detect(void)
|
||||||
if (0 == tries) {
|
if (0 == tries) {
|
||||||
Serial.print('*');
|
Serial.print('*');
|
||||||
// use the FastSerial port handle so that we can use PROGMEM strings
|
// use the FastSerial port handle so that we can use PROGMEM strings
|
||||||
_fs->println_P(_mtk_set_binary);
|
_fs->println_P((const prog_char_t *)_mtk_set_binary);
|
||||||
_fs->println_P(_ublox_set_binary);
|
_fs->println_P((const prog_char_t *)_ublox_set_binary);
|
||||||
_fs->println_P(_sirf_set_binary);
|
_fs->println_P((const prog_char_t *)_sirf_set_binary);
|
||||||
|
|
||||||
// give the GPS time to react to the settings
|
// give the GPS time to react to the settings
|
||||||
delay(100);
|
delay(100);
|
||||||
|
|
|
@ -109,13 +109,13 @@ void AP_GPS_NMEA::init(void)
|
||||||
BetterStream *bs = (BetterStream *)_port;
|
BetterStream *bs = (BetterStream *)_port;
|
||||||
|
|
||||||
// send the SiRF init strings
|
// send the SiRF init strings
|
||||||
bs->print_P(_SiRF_init_string);
|
bs->print_P((const prog_char_t *)_SiRF_init_string);
|
||||||
|
|
||||||
// send the MediaTek init strings
|
// send the MediaTek init strings
|
||||||
bs->print_P(_MTK_init_string);
|
bs->print_P((const prog_char_t *)_MTK_init_string);
|
||||||
|
|
||||||
// send the ublox init strings
|
// send the ublox init strings
|
||||||
bs->print_P(_ublox_init_string);
|
bs->print_P((const prog_char_t *)_ublox_init_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AP_GPS_NMEA::read(void)
|
bool AP_GPS_NMEA::read(void)
|
||||||
|
|
|
@ -17,16 +17,16 @@
|
||||||
// Stream extensions////////////////////////////////////////////////////////////
|
// Stream extensions////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void
|
void
|
||||||
BetterStream::print_P(const prog_char *s)
|
BetterStream::print_P(const prog_char_t *s)
|
||||||
{
|
{
|
||||||
char c;
|
char c;
|
||||||
|
|
||||||
while ('\0' != (c = pgm_read_byte(s++)))
|
while ('\0' != (c = pgm_read_byte((const prog_char *)s++)))
|
||||||
write(c);
|
write(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BetterStream::println_P(const char *s)
|
BetterStream::println_P(const prog_char_t *s)
|
||||||
{
|
{
|
||||||
print_P(s);
|
print_P(s);
|
||||||
println();
|
println();
|
||||||
|
@ -43,7 +43,7 @@ BetterStream::printf(const char *fmt, ...)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BetterStream::printf_P(const char *fmt, ...)
|
BetterStream::_printf_P(const prog_char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#include <Stream.h>
|
#include <Stream.h>
|
||||||
#include <avr/pgmspace.h>
|
#include <avr/pgmspace.h>
|
||||||
|
#include <AP_Common.h>
|
||||||
|
|
||||||
class BetterStream : public Stream {
|
class BetterStream : public Stream {
|
||||||
public:
|
public:
|
||||||
|
@ -20,13 +21,15 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stream extensions
|
// Stream extensions
|
||||||
void print_P(const char *);
|
void print_P(const prog_char_t *);
|
||||||
void println_P(const char *);
|
void println_P(const prog_char_t *);
|
||||||
void printf(const char *, ...)
|
void printf(const char *, ...)
|
||||||
__attribute__ ((format(__printf__, 2, 3)));
|
__attribute__ ((format(__printf__, 2, 3)));
|
||||||
void printf_P(const char *, ...)
|
void _printf_P(const prog_char *, ...);
|
||||||
__attribute__ ((format(__printf__, 2, 3)));
|
__attribute__ ((format(__printf__, 2, 3)));
|
||||||
|
|
||||||
|
#define printf_P(fmt, ...) _printf_P((const prog_char *)fmt, ## __VA_ARGS__)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _vprintf(unsigned char, const char *, va_list)
|
void _vprintf(unsigned char, const char *, va_list)
|
||||||
__attribute__ ((format(__printf__, 3, 0)));
|
__attribute__ ((format(__printf__, 3, 0)));
|
||||||
|
|
|
@ -246,7 +246,7 @@ BetterStream::_vprintf (unsigned char in_progmem, const char *fmt, va_list ap)
|
||||||
p = PSTR("inf");
|
p = PSTR("inf");
|
||||||
if (vtype & FTOA_NAN)
|
if (vtype & FTOA_NAN)
|
||||||
p = PSTR("nan");
|
p = PSTR("nan");
|
||||||
while ( (ndigs = pgm_read_byte(p)) != 0) {
|
while ( (ndigs = pgm_read_byte((const prog_char *)p)) != 0) {
|
||||||
if (flags & FL_FLTUPP)
|
if (flags & FL_FLTUPP)
|
||||||
ndigs += 'I' - 'i';
|
ndigs += 'I' - 'i';
|
||||||
write(ndigs);
|
write(ndigs);
|
||||||
|
|
|
@ -29,7 +29,7 @@ public:
|
||||||
/// @param initial_imax Initial value for the imax term.4
|
/// @param initial_imax Initial value for the imax term.4
|
||||||
///
|
///
|
||||||
PID(AP_Var::Key key,
|
PID(AP_Var::Key key,
|
||||||
const prog_char *name,
|
const prog_char_t *name,
|
||||||
const float &initial_p = 0.0,
|
const float &initial_p = 0.0,
|
||||||
const float &initial_i = 0.0,
|
const float &initial_i = 0.0,
|
||||||
const float &initial_d = 0.0,
|
const float &initial_d = 0.0,
|
||||||
|
@ -55,7 +55,7 @@ public:
|
||||||
/// @param initial_d Initial value for the D term.
|
/// @param initial_d Initial value for the D term.
|
||||||
/// @param initial_imax Initial value for the imax term.4
|
/// @param initial_imax Initial value for the imax term.4
|
||||||
///
|
///
|
||||||
PID(const prog_char *name,
|
PID(const prog_char_t *name,
|
||||||
const float &initial_p = 0.0,
|
const float &initial_p = 0.0,
|
||||||
const float &initial_i = 0.0,
|
const float &initial_i = 0.0,
|
||||||
const float &initial_d = 0.0,
|
const float &initial_d = 0.0,
|
||||||
|
|
|
@ -18,7 +18,7 @@ class RC_Channel{
|
||||||
/// @param key EEPROM storage key for the channel trim parameters.
|
/// @param key EEPROM storage key for the channel trim parameters.
|
||||||
/// @param name Optional name for the group.
|
/// @param name Optional name for the group.
|
||||||
///
|
///
|
||||||
RC_Channel(AP_Var::Key key, const prog_char *name) :
|
RC_Channel(AP_Var::Key key, const prog_char_t *name) :
|
||||||
_group(key, name),
|
_group(key, name),
|
||||||
radio_min (&_group, 0, 1500, name ? PSTR("MIN") : 0), // suppress name if group has no name
|
radio_min (&_group, 0, 1500, name ? PSTR("MIN") : 0), // suppress name if group has no name
|
||||||
radio_trim(&_group, 1, 1500, name ? PSTR("TRIM") : 0),
|
radio_trim(&_group, 1, 1500, name ? PSTR("TRIM") : 0),
|
||||||
|
|
Loading…
Reference in New Issue