2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
26 #include "build/build_config.h"
28 typedef uint16_t pgn_t
;
30 // parameter group registry flags
33 PGRF_CLASSIFICATON_BIT
= (1 << 0)
37 PGR_PGN_MASK
= 0x0fff,
38 PGR_PGN_VERSION_MASK
= 0xf000,
39 PGR_SIZE_MASK
= 0x0fff,
40 PGR_SIZE_SYSTEM_FLAG
= 0x0000 // documentary
41 } pgRegistryInternal_e
;
43 // function that resets a single parameter group instance
44 typedef void (pgResetFunc
)(void * /* base */);
46 typedef struct pgRegistry_s
{
47 pgn_t pgn
; // The parameter group number, the top 4 bits are reserved for version
48 uint8_t length
; // The number of elements in the group
49 uint16_t size
; // Size of the group in RAM, the top 4 bits are reserved for flags
50 uint8_t *address
; // Address of the group in RAM.
51 uint8_t *copy
; // Address of the copy in RAM.
52 uint8_t **ptr
; // The pointer to update after loading the record into ram.
54 void *ptr
; // Pointer to init template
55 pgResetFunc
*fn
; // Popinter to pgResetFunc
57 uint32_t *fnv_hash
; // Used to detect if config has changed prior to write
60 static inline uint16_t pgN(const pgRegistry_t
* reg
) {return reg
->pgn
& PGR_PGN_MASK
;}
61 static inline uint8_t pgVersion(const pgRegistry_t
* reg
) {return (uint8_t)(reg
->pgn
>> 12);}
62 static inline uint16_t pgSize(const pgRegistry_t
* reg
) {return reg
->size
& PGR_SIZE_MASK
;}
63 static inline uint16_t pgElementSize(const pgRegistry_t
* reg
) {return (reg
->size
& PGR_SIZE_MASK
) / reg
->length
;}
65 #define PG_PACKED __attribute__((packed))
68 extern const pgRegistry_t __pg_registry_start
[] __asm("section$start$__DATA$__pg_registry");
69 extern const pgRegistry_t __pg_registry_end
[] __asm("section$end$__DATA$__pg_registry");
70 #define PG_REGISTER_ATTRIBUTES __attribute__ ((section("__DATA,__pg_registry"), used, aligned(4)))
72 extern const uint8_t __pg_resetdata_start
[] __asm("section$start$__DATA$__pg_resetdata");
73 extern const uint8_t __pg_resetdata_end
[] __asm("section$end$__DATA$__pg_resetdata");
74 #define PG_RESETDATA_ATTRIBUTES __attribute__ ((section("__DATA,__pg_resetdata"), used, aligned(2)))
76 extern const pgRegistry_t __pg_registry_start
[];
77 extern const pgRegistry_t __pg_registry_end
[];
78 #define PG_REGISTER_ATTRIBUTES __attribute__ ((section(".pg_registry"), used, aligned(4)))
80 extern const uint8_t __pg_resetdata_start
[];
81 extern const uint8_t __pg_resetdata_end
[];
82 #define PG_RESETDATA_ATTRIBUTES __attribute__ ((section(".pg_resetdata"), used, aligned(2)))
85 #define PG_REGISTRY_SIZE (__pg_registry_end - __pg_registry_start)
87 // Helper to iterate over the PG register. Cheaper than a visitor style callback.
88 #define PG_FOREACH(_name) \
89 for (const pgRegistry_t *(_name) = __pg_registry_start; (_name) < __pg_registry_end; _name++)
91 // Reset configuration to default (by name)
92 #define PG_RESET(_name) \
94 extern const pgRegistry_t _name ##_Registry; \
95 pgReset(&_name ## _Registry); \
99 // Declare system config
100 #define PG_DECLARE(_type, _name) \
101 extern _type _name ## _System; \
102 extern _type _name ## _Copy; \
103 static inline const _type* _name(void) { return &_name ## _System; }\
104 static inline _type* _name ## Mutable(void) { return &_name ## _System; }\
108 // Declare system config array
109 #define PG_DECLARE_ARRAY(_type, _length, _name) \
110 extern _type _name ## _SystemArray[_length]; \
111 extern _type _name ## _CopyArray[_length]; \
112 static inline const _type* _name(int _index) { return &_name ## _SystemArray[_index]; } \
113 static inline _type* _name ## Mutable(int _index) { return &_name ## _SystemArray[_index]; } \
114 static inline _type (* _name ## _array(void))[_length] { return &_name ## _SystemArray; } \
118 // Register system config
119 #define PG_REGISTER_I(_type, _name, _pgn, _version, _reset) \
120 _type _name ## _System; \
121 _type _name ## _Copy; \
122 uint32_t _name ## _fnv_hash; \
123 /* Force external linkage for g++. Catch multi registration */ \
124 extern const pgRegistry_t _name ## _Registry; \
125 const pgRegistry_t _name ##_Registry PG_REGISTER_ATTRIBUTES = { \
126 .pgn = _pgn | (_version << 12), \
128 .size = sizeof(_type) | PGR_SIZE_SYSTEM_FLAG, \
129 .address = (uint8_t*)&_name ## _System, \
130 .fnv_hash = &_name ## _fnv_hash, \
131 .copy = (uint8_t*)&_name ## _Copy, \
137 #define PG_REGISTER(_type, _name, _pgn, _version) \
138 PG_REGISTER_I(_type, _name, _pgn, _version, .reset = {.ptr = 0}) \
141 #define PG_REGISTER_WITH_RESET_FN(_type, _name, _pgn, _version) \
142 extern void pgResetFn_ ## _name(_type *); \
143 PG_REGISTER_I(_type, _name, _pgn, _version, .reset = {.fn = (pgResetFunc*)&pgResetFn_ ## _name }) \
146 #define PG_REGISTER_WITH_RESET_TEMPLATE(_type, _name, _pgn, _version) \
147 extern const _type pgResetTemplate_ ## _name; \
148 PG_REGISTER_I(_type, _name, _pgn, _version, .reset = {.ptr = (void*)&pgResetTemplate_ ## _name}) \
151 // Register system config array
152 #define PG_REGISTER_ARRAY_I(_type, _length, _name, _pgn, _version, _reset) \
153 _type _name ## _SystemArray[_length]; \
154 _type _name ## _CopyArray[_length]; \
155 uint32_t _name ## _fnv_hash; \
156 extern const pgRegistry_t _name ##_Registry; \
157 const pgRegistry_t _name ## _Registry PG_REGISTER_ATTRIBUTES = { \
158 .pgn = _pgn | (_version << 12), \
160 .size = (sizeof(_type) * _length) | PGR_SIZE_SYSTEM_FLAG, \
161 .address = (uint8_t*)&_name ## _SystemArray, \
162 .fnv_hash = &_name ## _fnv_hash, \
163 .copy = (uint8_t*)&_name ## _CopyArray, \
169 #define PG_REGISTER_ARRAY(_type, _length, _name, _pgn, _version) \
170 PG_REGISTER_ARRAY_I(_type, _length, _name, _pgn, _version, .reset = {.ptr = 0}) \
173 #define PG_REGISTER_ARRAY_WITH_RESET_FN(_type, _length, _name, _pgn, _version) \
174 extern void pgResetFn_ ## _name(_type *); \
175 PG_REGISTER_ARRAY_I(_type, _length, _name, _pgn, _version, .reset = {.fn = (pgResetFunc*)&pgResetFn_ ## _name}) \
179 // ARRAY reset mechanism is not implemented yet, only few places in code would benefit from it - See pgResetInstance
180 #define PG_REGISTER_ARRAY_WITH_RESET_TEMPLATE(_type, _length, _name, _pgn, _version) \
181 extern const _type pgResetTemplate_ ## _name; \
182 PG_REGISTER_ARRAY_I(_type, _length, _name, _pgn, _version, .reset = {.ptr = (void*)&pgResetTemplate_ ## _name}) \
186 #define PG_ARRAY_ELEMENT_OFFSET(type, index, member) (index * sizeof(type) + offsetof(type, member))
188 // Emit reset defaults for config.
189 // Config must be registered with PG_REGISTER_<xxx>_WITH_RESET_TEMPLATE macro
190 #define PG_RESET_TEMPLATE(_type, _name, ...) \
191 const _type pgResetTemplate_ ## _name PG_RESETDATA_ATTRIBUTES = { \
196 #define CONVERT_PARAMETER_TO_FLOAT(param) (0.001f * param)
197 #define CONVERT_PARAMETER_TO_PERCENT(param) (0.01f * param)
199 const pgRegistry_t
* pgFind(pgn_t pgn
);
201 bool pgLoad(const pgRegistry_t
* reg
, const void *from
, int size
, int version
);
202 int pgStore(const pgRegistry_t
* reg
, void *to
, int size
);
203 void pgResetAll(void);
204 void pgResetInstance(const pgRegistry_t
*reg
, uint8_t *base
);
205 bool pgResetCopy(void *copy
, pgn_t pgn
);
206 void pgReset(const pgRegistry_t
* reg
);