px-fwlib
0.10.0
Cross-platform embedded library and documentation for 8/16/32-bit microcontrollers
generated with
Doxygen
1.9.2
px_pgm_P.h
1
#ifndef __PX_PGM_P_H__
2
#define __PX_PGM_P_H__
3
/* =============================================================================
4
____ ___ ____ ___ _ _ ___ __ __ ___ __ __ TM
5
| _ \ |_ _| / ___| / _ \ | \ | | / _ \ | \/ | |_ _| \ \/ /
6
| |_) | | | | | | | | | | \| | | | | | | |\/| | | | \ /
7
| __/ | | | |___ | |_| | | |\ | | |_| | | | | | | | / \
8
|_| |___| \____| \___/ |_| \_| \___/ |_| |_| |___| /_/\_\
9
10
Copyright (c) 2013 Pieter Conradie <https://piconomix.com>
11
12
License: MIT
13
https://github.com/piconomix/px-fwlib/blob/master/LICENSE.md
14
15
Title: px_pgm_P.h : Support for constant data stored in program memory
16
Author(s): Pieter Conradie
17
Creation Date: 2013-07-04
18
19
============================================================================= */
20
21
/**
22
* @ingroup COMMON
23
* @defgroup PX_PGM_P px_pgm_P.h : Support for constant data stored in program memory
24
*
25
* RAM saving support for architectures that require methods to store and read
26
* constant data in program memory.
27
*
28
* File(s):
29
* - common/inc/px_pgm_P.h
30
*
31
* This utility module attempts to provide a standardised method to store and
32
* read constant data in program memory for devices with separate program and
33
* data memory spaces, most notably the Microchip AVR architecture.
34
*
35
* For a great introduction, read:
36
* - [AVR-GCC and the PROGMEM Attribute](http://www.fourwalledcubicle.com/AVRArticles.php)
37
* by Dean Camera.
38
* - [avr-libc: Data in Program Space](http://www.nongnu.org/avr-libc/user-manual/pgmspace.html)
39
*
40
* Constant data that must be stored in program memory is tagged with
41
* the PX_ATTR_PGM attribute.
42
*
43
* The suffix "_P" convention is used to indicate that the function reads data
44
* stored in program memory, e.g. printf_P() vs. printf(). It is also used to
45
* indicate that a source file has been optimised to use const data stored in
46
* program memory, e.g. "px_cli_P.c" vs. "px_cli.c".
47
*
48
* The "PX_PGM_STR()" macro is used for inline declaration of a string in
49
* program memory.
50
* See <avr/pgmspace.h> from [AVR-Libc](http://www.nongnu.org/avr-libc/)
51
*
52
* For extra convenience, all-capital macros have been provided to call a
53
* program memory function AND inline declare a string in program memory:
54
*
55
* @code{.c}
56
* // Call progmem version of 'printf' and declare string in program memory
57
* printf_P(PSTR("Hello world!\n"));
58
*
59
* // Use variable argument convenience macro
60
* PX_PRINTF_P("Hello world!\n");
61
* @endcode
62
*
63
* This module also has the ability to revert to normal RAM storage for
64
* architectures that do not require it, or if PX_PGM_P_USE_RAM is defined.
65
*
66
* Example:
67
*
68
* @code{.c}
69
* #include "px_pgm_P.h"
70
*
71
* // Program memory table for the number of days in each month (non leap year)
72
* const uint8_t px_rtc_month_day_table[] PX_ATTR_PGM =
73
* {
74
* 0, // Invalid month
75
* 31, // January
76
* 28, // February
77
* 31, // March
78
* 30, // April
79
* 31, // May
80
* 30, // June
81
* 31, // July
82
* 31, // August
83
* 30, // September
84
* 31, // October
85
* 30, // November
86
* 31 // December
87
* };
88
*
89
* // String stored in program memory
90
* const char calender_str[] PX_ATTR_PGM = "Gregorian Calender\n";
91
*
92
* void report_days(uint8_t month)
93
* {
94
* uint8_t days_in_month = px_pgm_rd_u8(&px_rtc_month_day_table[month]);
95
*
96
* printf_P(calender_str);
97
* PX_PRINTF_P("Days in month = %d\n", days_in_month);
98
* }
99
* @endcode
100
*
101
* @{
102
*/
103
104
/* _____STANDARD INCLUDES____________________________________________________ */
105
#include <stdio.h>
106
107
/* _____PROJECT INCLUDES_____________________________________________________ */
108
#include "px_defs.h"
109
#include "px_compiler.h"
110
111
#if defined(PX_COMPILER_GCC_AVR) && !defined(PX_PGM_USE_RAM)
112
#include <avr/pgmspace.h>
113
#else
114
#include <string.h>
115
#endif
116
117
#ifdef __cplusplus
118
extern
"C"
{
119
#endif
120
/* _____DEFINITIONS__________________________________________________________ */
121
122
/* _____TYPE DEFINITIONS_____________________________________________________ */
123
124
/* _____GLOBAL VARIABLES_____________________________________________________ */
125
126
/* _____GLOBAL FUNCTION DECLARATIONS_________________________________________ */
127
128
/* _____MACROS_______________________________________________________________ */
129
#if defined(PX_COMPILER_GCC_AVR) && !defined(PX_PGM_P_USE_RAM)
130
131
/// Mark a variable as stored in program memory
132
#define PX_ATTR_PGM __attribute__((__progmem__))
133
134
/**
135
* Inline declaration of a string in program memory.
136
*
137
* This definition is copied from <avr/pgmspace.h> in
138
* [AVR-Libc](http://www.nongnu.org/avr-libc/)
139
*/
140
#define PX_PGM_STR(s) \
141
(__extension__({static const char __c[] PROGMEM = (s); &__c[0];}))
142
143
/// Read a uint8_t from program memory
144
#define px_pgm_rd_u8(adr) ((uint8_t)pgm_read_byte(adr))
145
/// Read a uint16_t from program memory
146
#define px_pgm_rd_u16(adr) ((uint16_t)pgm_read_word(adr))
147
/// Read a uint32_t from program memory
148
#define px_pgm_rd_u32(adr) ((uint32_t)pgm_read_dword(adr))
149
/// Read a int8_t from program memory
150
#define px_pgm_rd_s8(adr) ((int8_t)pgm_read_byte(adr))
151
/// Read a int16_t from program memory
152
#define px_pgm_rd_s16(adr) ((int16_t)pgm_read_word(adr))
153
/// Read a int32_t from program memory
154
#define px_pgm_rd_s32(adr) ((int32_t)pgm_read_dword(adr))
155
/// Read a void pointer from program memory
156
#define px_pgm_rd_void_ptr(adr) ((void*)pgm_read_word((adr)))
157
/// Read a char from program memory
158
#define px_pgm_rd_char(adr) ((char)pgm_read_byte((adr)))
159
160
/// Variable argument macro that calls @b printf_P with format string declared in program memory
161
#define PX_PRINTF_P(format, ...) printf_P(PX_PGM_STR(format), ## __VA_ARGS__)
162
163
#else
164
// Use normal RAM declarations and functions to read data
165
#define PX_ATTR_PGM
166
167
#define PX_PGM_STR(s) (s)
168
169
#define px_pgm_rd_u8(adr) (*((const uint8_t *)adr))
170
#define px_pgm_rd_u16(adr) (*((const uint16_t *)adr))
171
#define px_pgm_rd_u32(adr) (*((const uint32_t *)adr))
172
#define px_pgm_rd_s8(adr) (*((const int8_t *)adr))
173
#define px_pgm_rd_s16(adr) (*((const int16_t *)adr))
174
#define px_pgm_rd_s32(adr) (*((const int32_t *)adr))
175
#define px_pgm_rd_void_ptr(adr) (*(const void *)(adr))
176
#define px_pgm_rd_char(adr) (*((const char *)adr))
177
178
#define memchr_P(src, val, len) memchr((src), (val), (len))
179
#define memcmp_P(s1, s2, len) memcmp((s1), (s2), (len))
180
#define memccpy_P(dest, src, val, len) memccpy((dest), (src), (val), (len))
181
#define memcpy_P(dest, src, len) memcpy((dest), (src), (len))
182
#define memmem_P(s1, len1, s2, len2) memmem((s1), (len1), (s2), (len2))
183
#define memrchr_P(src, val, len) memrchr((src), (val), (len))
184
#define strcat_P(dest, src) strcat((dest), (src))
185
#define strchr_P(src, val) strchr((src), (val))
186
#define strchrnul_P(s, c) strchrnul((s), (c))
187
#define strcmp_P(s1, s2) strcmp((s1), (s2))
188
#define strcpy_P(dest, src) strcpy((dest), (src))
189
#define strcasecmp_P(s1, s2) strcasecmp((s1), (s2))
190
#define strcasestr_P(s1, s2) strcasestr((s1), (s2))
191
#define strcspn_P(s, reject) strcspn((s), (reject))
192
#define strlcat_P(dst, src, siz) strlcat((dst), (src), (siz))
193
#define strlcpy_P(dst, src, siz) strlcpy((dst), (src), (siz))
194
#define strnlen_P(src, len) strnlen((src), (len))
195
#define strncmp_P(s1, s2, len) strncmp((s1), (s2), (len))
196
#define strncasecmp_P(s1, s2, len) strncasecmp((s1), (s2), (len))
197
#define strncat_P(dest, src, len) strncat((dest), (src), (len))
198
#define strncpy_P(dest, src, len) strncpy((dest), (src), (len))
199
#define strpbrk_P(s, accept) strpbrk((s), (accept))
200
#define strrchr_P(src, val) strrchr((src), (val))
201
#define strsep_P(sp, delim) strsep((sp), (delim))
202
#define strspn_P(s, accept) strspn((s), (accept))
203
#define strstr_P(s1, s2) strstr((s1), (s2))
204
#define strtok_P(s, delim) strtok((s), (delim))
205
#define strtok_rP(string, delim, last) strtok_r((string), (delim), (last))
206
#define strlen_P(src) strlen((src))
207
208
#define vsnprintf_P(__s, __n, __fmt, ...) vsnprintf((__s), (__n), (__fmt), ## __VA_ARGS__)
209
210
#define PX_PRINTF_P(fmt, ...) printf(fmt, ## __VA_ARGS__)
211
212
#endif
213
214
#ifdef __cplusplus
215
}
216
#endif
217
218
/// @}
219
#endif