2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
23 #include "build/build_config.h"
25 typedef uint16_t pgn_t
;
27 // parameter group registry flags
30 PGRF_CLASSIFICATON_BIT
= (1 << 0)
34 PGR_PGN_MASK
= 0x0fff,
35 PGR_PGN_VERSION_MASK
= 0xf000,
36 PGR_SIZE_MASK
= 0x0fff,
37 PGR_SIZE_SYSTEM_FLAG
= 0x0000, // documentary
38 PGR_SIZE_PROFILE_FLAG
= 0x8000 // start using flags from the top bit down
39 } pgRegistryInternal_e
;
41 // function that resets a single parameter group instance
42 typedef void (pgResetFunc
)(void * /* base */);
44 typedef struct pgRegistry_s
{
45 pgn_t pgn
; // The parameter group number, the top 4 bits are reserved for version
46 uint16_t size
; // Size of the group in RAM, the top 4 bits are reserved for flags
47 uint8_t *address
; // Address of the group in RAM.
48 uint8_t *copy
; // Address of the copy in RAM.
49 uint8_t **ptr
; // The pointer to update after loading the record into ram.
51 void *ptr
; // Pointer to init template
52 pgResetFunc
*fn
; // Popinter to pgResetFunc
56 static inline uint16_t pgN(const pgRegistry_t
* reg
) {return reg
->pgn
& PGR_PGN_MASK
;}
57 static inline uint8_t pgVersion(const pgRegistry_t
* reg
) {return (uint8_t)(reg
->pgn
>> 12);}
58 static inline uint16_t pgSize(const pgRegistry_t
* reg
) {return reg
->size
& PGR_SIZE_MASK
;}
59 static inline uint16_t pgIsSystem(const pgRegistry_t
* reg
) {return (reg
->size
& PGR_SIZE_PROFILE_FLAG
) == 0;}
60 static inline uint16_t pgIsProfile(const pgRegistry_t
* reg
) {return (reg
->size
& PGR_SIZE_PROFILE_FLAG
) == PGR_SIZE_PROFILE_FLAG
;}
62 #define PG_PACKED __attribute__((packed))
65 extern const pgRegistry_t __pg_registry_start
[] __asm("section$start$__DATA$__pg_registry");
66 extern const pgRegistry_t __pg_registry_end
[] __asm("section$end$__DATA$__pg_registry");
67 #define PG_REGISTER_ATTRIBUTES __attribute__ ((section("__DATA,__pg_registry"), used, aligned(8)))
69 extern const uint8_t __pg_resetdata_start
[] __asm("section$start$__DATA$__pg_resetdata");
70 extern const uint8_t __pg_resetdata_end
[] __asm("section$end$__DATA$__pg_resetdata");
71 #define PG_RESETDATA_ATTRIBUTES __attribute__ ((section("__DATA,__pg_resetdata"), used, aligned(2)))
73 extern const pgRegistry_t __pg_registry_start
[];
74 extern const pgRegistry_t __pg_registry_end
[];
75 #define PG_REGISTER_ATTRIBUTES __attribute__ ((section(".pg_registry"), used, aligned(4)))
77 extern const uint8_t __pg_resetdata_start
[];
78 extern const uint8_t __pg_resetdata_end
[];
79 #define PG_RESETDATA_ATTRIBUTES __attribute__ ((section(".pg_resetdata"), used, aligned(2)))
82 #define PG_REGISTRY_SIZE (__pg_registry_end - __pg_registry_start)
84 // Helper to iterate over the PG register. Cheaper than a visitor style callback.
85 #define PG_FOREACH(_name) \
86 for (const pgRegistry_t *(_name) = __pg_registry_start; (_name) < __pg_registry_end; _name++)
88 #define PG_FOREACH_PROFILE(_name) \
90 if (pgIsSystem(_name)) \
95 // Reset configuration to default (by name)
96 // Only current profile is reset for profile based configs
97 #define PG_RESET_CURRENT(_name) \
99 extern const pgRegistry_t _name ##_Registry; \
100 pgResetCurrent(&_name ## _Registry); \
104 // Declare system config
105 #define PG_DECLARE(_type, _name) \
106 extern _type _name ## _System; \
107 extern _type _name ## _Copy; \
108 static inline const _type* _name(void) { return &_name ## _System; }\
109 static inline _type* _name ## Mutable(void) { return &_name ## _System; }\
113 // Declare system config array
114 #define PG_DECLARE_ARRAY(_type, _size, _name) \
115 extern _type _name ## _SystemArray[_size]; \
116 extern _type _name ## _CopyArray[_size]; \
117 static inline const _type* _name(int _index) { return &_name ## _SystemArray[_index]; } \
118 static inline _type* _name ## Mutable(int _index) { return &_name ## _SystemArray[_index]; } \
119 static inline _type (* _name ## _array(void))[_size] { return &_name ## _SystemArray; } \
123 // Declare profile config
124 #define PG_DECLARE_PROFILE(_type, _name) \
125 extern _type *_name ## _ProfileCurrent; \
126 static inline const _type* _name(void) { return _name ## _ProfileCurrent; } \
127 static inline _type* _name ## Mutable(void) { return _name ## _ProfileCurrent; } \
132 // Register system config
133 #define PG_REGISTER_I(_type, _name, _pgn, _version, _reset) \
134 _type _name ## _System; \
135 _type _name ## _Copy; \
136 /* Force external linkage for g++. Catch multi registration */ \
137 extern const pgRegistry_t _name ## _Registry; \
138 const pgRegistry_t _name ##_Registry PG_REGISTER_ATTRIBUTES = { \
139 .pgn = _pgn | (_version << 12), \
140 .size = sizeof(_type) | PGR_SIZE_SYSTEM_FLAG, \
141 .address = (uint8_t*)&_name ## _System, \
142 .copy = (uint8_t*)&_name ## _Copy, \
148 #define PG_REGISTER(_type, _name, _pgn, _version) \
149 PG_REGISTER_I(_type, _name, _pgn, _version, .reset = {.ptr = 0}) \
152 #define PG_REGISTER_WITH_RESET_FN(_type, _name, _pgn, _version) \
153 extern void pgResetFn_ ## _name(_type *); \
154 PG_REGISTER_I(_type, _name, _pgn, _version, .reset = {.fn = (pgResetFunc*)&pgResetFn_ ## _name }) \
157 #define PG_REGISTER_WITH_RESET_TEMPLATE(_type, _name, _pgn, _version) \
158 extern const _type pgResetTemplate_ ## _name; \
159 PG_REGISTER_I(_type, _name, _pgn, _version, .reset = {.ptr = (void*)&pgResetTemplate_ ## _name}) \
162 // Register system config array
163 #define PG_REGISTER_ARRAY_I(_type, _size, _name, _pgn, _version, _reset) \
164 _type _name ## _SystemArray[_size]; \
165 _type _name ## _CopyArray[_size]; \
166 extern const pgRegistry_t _name ##_Registry; \
167 const pgRegistry_t _name ## _Registry PG_REGISTER_ATTRIBUTES = { \
168 .pgn = _pgn | (_version << 12), \
169 .size = (sizeof(_type) * _size) | PGR_SIZE_SYSTEM_FLAG, \
170 .address = (uint8_t*)&_name ## _SystemArray, \
171 .copy = (uint8_t*)&_name ## _CopyArray, \
177 #define PG_REGISTER_ARRAY(_type, _size, _name, _pgn, _version) \
178 PG_REGISTER_ARRAY_I(_type, _size, _name, _pgn, _version, .reset = {.ptr = 0}) \
181 #define PG_REGISTER_ARRAY_WITH_RESET_FN(_type, _size, _name, _pgn, _version) \
182 extern void pgResetFn_ ## _name(_type *); \
183 PG_REGISTER_ARRAY_I(_type, _size, _name, _pgn, _version, .reset = {.fn = (pgResetFunc*)&pgResetFn_ ## _name}) \
187 # define _PG_PROFILE_CURRENT_DECL(_type, _name) \
188 _type *_name ## _ProfileCurrent = &_name ## _Storage[0];
190 # define _PG_PROFILE_CURRENT_DECL(_type, _name) \
191 _type *_name ## _ProfileCurrent;
194 // register profile config
195 #define PG_REGISTER_PROFILE_I(_type, _name, _pgn, _version, _reset) \
196 STATIC_UNIT_TESTED _type _name ## _Storage[MAX_PROFILE_COUNT]; \
197 STATIC_UNIT_TESTED _type _name ## _CopyStorage[MAX_PROFILE_COUNT]; \
198 _PG_PROFILE_CURRENT_DECL(_type, _name) \
199 extern const pgRegistry_t _name ## _Registry; \
200 const pgRegistry_t _name ## _Registry PG_REGISTER_ATTRIBUTES = { \
201 .pgn = _pgn | (_version << 12), \
202 .size = sizeof(_type) | PGR_SIZE_PROFILE_FLAG, \
203 .address = (uint8_t*)&_name ## _Storage, \
204 .copy = (uint8_t*)&_name ## _CopyStorage, \
205 .ptr = (uint8_t **)&_name ## _ProfileCurrent, \
210 #define PG_REGISTER_PROFILE(_type, _name, _pgn, _version) \
211 PG_REGISTER_PROFILE_I(_type, _name, _pgn, _version, .reset = {.ptr = 0}) \
214 #define PG_REGISTER_PROFILE_WITH_RESET_FN(_type, _name, _pgn, _version) \
215 extern void pgResetFn_ ## _name(_type *); \
216 PG_REGISTER_PROFILE_I(_type, _name, _pgn, _version, .reset = {.fn = (pgResetFunc*)&pgResetFn_ ## _name}) \
219 #define PG_REGISTER_PROFILE_WITH_RESET_TEMPLATE(_type, _name, _pgn, _version) \
220 extern const _type pgResetTemplate_ ## _name; \
221 PG_REGISTER_PROFILE_I(_type, _name, _pgn, _version, .reset = {.ptr = (void*)&pgResetTemplate_ ## _name}) \
225 // Emit reset defaults for config.
226 // Config must be registered with PG_REGISTER_<xxx>_WITH_RESET_TEMPLATE macro
227 #define PG_RESET_TEMPLATE(_type, _name, ...) \
228 const _type pgResetTemplate_ ## _name PG_RESETDATA_ATTRIBUTES = { \
233 const pgRegistry_t
* pgFind(pgn_t pgn
);
235 void pgLoad(const pgRegistry_t
* reg
, int profileIndex
, const void *from
, int size
, int version
);
236 int pgStore(const pgRegistry_t
* reg
, void *to
, int size
, uint8_t profileIndex
);
237 void pgResetAll(int profileCount
);
238 void pgResetCurrent(const pgRegistry_t
*reg
);
239 bool pgResetCopy(void *copy
, pgn_t pgn
);
240 void pgReset(const pgRegistry_t
* reg
, int profileIndex
);
241 void pgActivateProfile(int profileIndex
);