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
118extern "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