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
|
||||
// the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -21,6 +21,14 @@
|
|||
#undef round
|
||||
#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 "include/menu.h" /// simple menu subsystem
|
||||
#include "c++.h" // c++ additions
|
||||
|
@ -72,8 +80,25 @@
|
|||
# undef PROGMEM
|
||||
# define PROGMEM __attribute__(( section(".progmem.data") ))
|
||||
# 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
|
||||
|
||||
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
|
||||
//
|
||||
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),
|
||||
_key(key | k_key_not_located),
|
||||
_name(name),
|
||||
|
@ -54,7 +54,7 @@ AP_Var::AP_Var(Key key, const prog_char *name, Flags flags) :
|
|||
|
||||
// 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),
|
||||
_key(index),
|
||||
_name(name),
|
||||
|
|
|
@ -161,7 +161,7 @@ public:
|
|||
/// @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);
|
||||
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
|
||||
///
|
||||
|
@ -170,7 +170,7 @@ public:
|
|||
/// @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);
|
||||
AP_Var(AP_Var_group *group, Key index, const prog_char_t *name, Flags flags = k_flags_none);
|
||||
|
||||
/// Destructor
|
||||
///
|
||||
|
@ -361,7 +361,7 @@ 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.)
|
||||
const prog_char_t *_name; ///< name known to external agents (GCS, etc.)
|
||||
uint8_t _flags; ///< flag bits
|
||||
|
||||
// static state used by ::lookup
|
||||
|
@ -415,7 +415,7 @@ public:
|
|||
/// @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_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)
|
||||
{
|
||||
_bytes_in_use += sizeof(*this);
|
||||
|
@ -483,7 +483,7 @@ public:
|
|||
///
|
||||
AP_VarT<T> (const T initial_value = 0,
|
||||
Key key = k_key_none,
|
||||
const prog_char *name = NULL,
|
||||
const prog_char_t *name = NULL,
|
||||
Flags flags = k_flags_none) :
|
||||
AP_Var(key, name, flags),
|
||||
_value(initial_value)
|
||||
|
@ -506,7 +506,7 @@ public:
|
|||
AP_VarT<T> (AP_Var_group *group, // XXX maybe make this a ref?
|
||||
Key index,
|
||||
T initial_value,
|
||||
const prog_char *name = NULL,
|
||||
const prog_char_t *name = NULL,
|
||||
Flags flags = k_flags_none) :
|
||||
AP_Var(group, index, name, flags),
|
||||
_value(initial_value)
|
||||
|
@ -616,7 +616,7 @@ public:
|
|||
/// @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,
|
||||
const prog_char_t *name = NULL,
|
||||
Flags flags = k_flags_none) :
|
||||
AP_Var(key, name, flags)
|
||||
{
|
||||
|
@ -636,7 +636,7 @@ public:
|
|||
///
|
||||
AP_VarS<T> (AP_Var_group *group, // XXX maybe make this a ref?
|
||||
Key index,
|
||||
const prog_char *name = NULL,
|
||||
const prog_char_t *name = NULL,
|
||||
Flags flags = k_flags_none) :
|
||||
AP_Var(group, index, name, flags)
|
||||
{
|
||||
|
@ -726,7 +726,7 @@ public:
|
|||
/// @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,
|
||||
const prog_char_t *name = NULL,
|
||||
Flags flags = k_flags_none) :
|
||||
AP_Var(key, name, flags)
|
||||
{
|
||||
|
@ -746,7 +746,7 @@ public:
|
|||
///
|
||||
AP_VarA<T,N> (AP_Var_group *group, // XXX maybe make this a ref?
|
||||
Key index,
|
||||
const prog_char *name = NULL,
|
||||
const prog_char_t *name = NULL,
|
||||
Flags flags = k_flags_none) :
|
||||
AP_Var(group, index, name, flags)
|
||||
{
|
||||
|
@ -841,7 +841,7 @@ public:
|
|||
///
|
||||
AP_Float16(float initial_value = 0,
|
||||
Key key = k_key_none,
|
||||
const prog_char *name = NULL,
|
||||
const prog_char_t *name = NULL,
|
||||
Flags flags = k_flags_none) :
|
||||
AP_Float(initial_value, key, name, flags)
|
||||
{
|
||||
|
@ -851,7 +851,7 @@ public:
|
|||
AP_Float16(AP_Var_group *group,
|
||||
Key index,
|
||||
float initial_value = 0,
|
||||
const prog_char *name = NULL,
|
||||
const prog_char_t *name = NULL,
|
||||
Flags flags = k_flags_none) :
|
||||
AP_Float(group, index, initial_value, name, flags)
|
||||
{
|
||||
|
|
|
@ -186,9 +186,9 @@ AP_GPS_Auto::_detect(void)
|
|||
if (0 == tries) {
|
||||
Serial.print('*');
|
||||
// use the FastSerial port handle so that we can use PROGMEM strings
|
||||
_fs->println_P(_mtk_set_binary);
|
||||
_fs->println_P(_ublox_set_binary);
|
||||
_fs->println_P(_sirf_set_binary);
|
||||
_fs->println_P((const prog_char_t *)_mtk_set_binary);
|
||||
_fs->println_P((const prog_char_t *)_ublox_set_binary);
|
||||
_fs->println_P((const prog_char_t *)_sirf_set_binary);
|
||||
|
||||
// give the GPS time to react to the settings
|
||||
delay(100);
|
||||
|
|
|
@ -109,13 +109,13 @@ void AP_GPS_NMEA::init(void)
|
|||
BetterStream *bs = (BetterStream *)_port;
|
||||
|
||||
// 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
|
||||
bs->print_P(_MTK_init_string);
|
||||
bs->print_P((const prog_char_t *)_MTK_init_string);
|
||||
|
||||
// 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)
|
||||
|
|
|
@ -17,16 +17,16 @@
|
|||
// Stream extensions////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
BetterStream::print_P(const prog_char *s)
|
||||
BetterStream::print_P(const prog_char_t *s)
|
||||
{
|
||||
char c;
|
||||
|
||||
while ('\0' != (c = pgm_read_byte(s++)))
|
||||
while ('\0' != (c = pgm_read_byte((const prog_char *)s++)))
|
||||
write(c);
|
||||
}
|
||||
|
||||
void
|
||||
BetterStream::println_P(const char *s)
|
||||
BetterStream::println_P(const prog_char_t *s)
|
||||
{
|
||||
print_P(s);
|
||||
println();
|
||||
|
@ -43,7 +43,7 @@ BetterStream::printf(const char *fmt, ...)
|
|||
}
|
||||
|
||||
void
|
||||
BetterStream::printf_P(const char *fmt, ...)
|
||||
BetterStream::_printf_P(const prog_char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <Stream.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <AP_Common.h>
|
||||
|
||||
class BetterStream : public Stream {
|
||||
public:
|
||||
|
@ -20,13 +21,15 @@ public:
|
|||
}
|
||||
|
||||
// Stream extensions
|
||||
void print_P(const char *);
|
||||
void println_P(const char *);
|
||||
void print_P(const prog_char_t *);
|
||||
void println_P(const prog_char_t *);
|
||||
void printf(const char *, ...)
|
||||
__attribute__ ((format(__printf__, 2, 3)));
|
||||
void printf_P(const char *, ...)
|
||||
void _printf_P(const prog_char *, ...);
|
||||
__attribute__ ((format(__printf__, 2, 3)));
|
||||
|
||||
#define printf_P(fmt, ...) _printf_P((const prog_char *)fmt, ## __VA_ARGS__)
|
||||
|
||||
private:
|
||||
void _vprintf(unsigned char, const char *, va_list)
|
||||
__attribute__ ((format(__printf__, 3, 0)));
|
||||
|
|
|
@ -246,7 +246,7 @@ BetterStream::_vprintf (unsigned char in_progmem, const char *fmt, va_list ap)
|
|||
p = PSTR("inf");
|
||||
if (vtype & FTOA_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)
|
||||
ndigs += 'I' - 'i';
|
||||
write(ndigs);
|
||||
|
|
|
@ -29,7 +29,7 @@ public:
|
|||
/// @param initial_imax Initial value for the imax term.4
|
||||
///
|
||||
PID(AP_Var::Key key,
|
||||
const prog_char *name,
|
||||
const prog_char_t *name,
|
||||
const float &initial_p = 0.0,
|
||||
const float &initial_i = 0.0,
|
||||
const float &initial_d = 0.0,
|
||||
|
@ -55,7 +55,7 @@ public:
|
|||
/// @param initial_d Initial value for the D term.
|
||||
/// @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_i = 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 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),
|
||||
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),
|
||||
|
|
Loading…
Reference in New Issue