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
59 static inline uint16_t pgN(const pgRegistry_t
* reg
) {return reg
->pgn
& PGR_PGN_MASK
;}
60 static inline uint8_t pgVersion(const pgRegistry_t
* reg
) {return (uint8_t)(reg
->pgn
>> 12);}
61 static inline uint16_t pgSize(const pgRegistry_t
* reg
) {return reg
->size
& PGR_SIZE_MASK
;}
62 static inline uint16_t pgElementSize(const pgRegistry_t
* reg
) {return (reg
->size
& PGR_SIZE_MASK
) / reg
->length
;}
64 #define PG_PACKED __attribute__((packed))
67 extern const pgRegistry_t __pg_registry_start
[] __asm("section$start$__DATA$__pg_registry");
68 extern const pgRegistry_t __pg_registry_end
[] __asm("section$end$__DATA$__pg_registry");
69 #define PG_REGISTER_ATTRIBUTES __attribute__ ((section("__DATA,__pg_registry"), used, aligned(4)))
71 extern const uint8_t __pg_resetdata_start
[] __asm("section$start$__DATA$__pg_resetdata");
72 extern const uint8_t __pg_resetdata_end
[] __asm("section$end$__DATA$__pg_resetdata");
73 #define PG_RESETDATA_ATTRIBUTES __attribute__ ((section("__DATA,__pg_resetdata"), used, aligned(2)))
75 extern const pgRegistry_t __pg_registry_start
[];
76 extern const pgRegistry_t __pg_registry_end
[];
77 #define PG_REGISTER_ATTRIBUTES __attribute__ ((section(".pg_registry"), used, aligned(4)))
79 extern const uint8_t __pg_resetdata_start
[];
80 extern const uint8_t __pg_resetdata_end
[];
81 #define PG_RESETDATA_ATTRIBUTES __attribute__ ((section(".pg_resetdata"), used, aligned(2)))
84 #define PG_REGISTRY_SIZE (__pg_registry_end - __pg_registry_start)
86 // Helper to iterate over the PG register. Cheaper than a visitor style callback.
87 #define PG_FOREACH(_name) \
88 for (const pgRegistry_t *(_name) = __pg_registry_start; (_name) < __pg_registry_end; _name++)
90 // Reset configuration to default (by name)
91 #define PG_RESET(_name) \
93 extern const pgRegistry_t _name ##_Registry; \
94 pgReset(&_name ## _Registry); \
98 // Declare system config
99 #define PG_DECLARE(_type, _name) \
100 extern _type _name ## _System; \
101 extern _type _name ## _Copy; \
102 static inline const _type* _name(void) { return &_name ## _System; }\
103 static inline _type* _name ## Mutable(void) { return &_name ## _System; }\
107 // Declare system config array
108 #define PG_DECLARE_ARRAY(_type, _length, _name) \
109 extern _type _name ## _SystemArray[_length]; \
110 extern _type _name ## _CopyArray[_length]; \
111 static inline const _type* _name(int _index) { return &_name ## _SystemArray[_index]; } \
112 static inline _type* _name ## Mutable(int _index) { return &_name ## _SystemArray[_index]; } \
113 static inline _type (* _name ## _array(void))[_length] { return &_name ## _SystemArray; } \
117 // Register system config
118 #define PG_REGISTER_I(_type, _name, _pgn, _version, _reset) \
119 _type _name ## _System; \
120 _type _name ## _Copy; \
121 /* Force external linkage for g++. Catch multi registration */ \
122 extern const pgRegistry_t _name ## _Registry; \
123 const pgRegistry_t _name ##_Registry PG_REGISTER_ATTRIBUTES = { \
124 .pgn = _pgn | (_version << 12), \
126 .size = sizeof(_type) | PGR_SIZE_SYSTEM_FLAG, \
127 .address = (uint8_t*)&_name ## _System, \
128 .copy = (uint8_t*)&_name ## _Copy, \
134 #define PG_REGISTER(_type, _name, _pgn, _version) \
135 PG_REGISTER_I(_type, _name, _pgn, _version, .reset = {.ptr = 0}) \
138 #define PG_REGISTER_WITH_RESET_FN(_type, _name, _pgn, _version) \
139 extern void pgResetFn_ ## _name(_type *); \
140 PG_REGISTER_I(_type, _name, _pgn, _version, .reset = {.fn = (pgResetFunc*)&pgResetFn_ ## _name }) \
143 #define PG_REGISTER_WITH_RESET_TEMPLATE(_type, _name, _pgn, _version) \
144 extern const _type pgResetTemplate_ ## _name; \
145 PG_REGISTER_I(_type, _name, _pgn, _version, .reset = {.ptr = (void*)&pgResetTemplate_ ## _name}) \
148 // Register system config array
149 #define PG_REGISTER_ARRAY_I(_type, _length, _name, _pgn, _version, _reset) \
150 _type _name ## _SystemArray[_length]; \
151 _type _name ## _CopyArray[_length]; \
152 extern const pgRegistry_t _name ##_Registry; \
153 const pgRegistry_t _name ## _Registry PG_REGISTER_ATTRIBUTES = { \
154 .pgn = _pgn | (_version << 12), \
156 .size = (sizeof(_type) * _length) | PGR_SIZE_SYSTEM_FLAG, \
157 .address = (uint8_t*)&_name ## _SystemArray, \
158 .copy = (uint8_t*)&_name ## _CopyArray, \
164 #define PG_REGISTER_ARRAY(_type, _length, _name, _pgn, _version) \
165 PG_REGISTER_ARRAY_I(_type, _length, _name, _pgn, _version, .reset = {.ptr = 0}) \
168 #define PG_REGISTER_ARRAY_WITH_RESET_FN(_type, _length, _name, _pgn, _version) \
169 extern void pgResetFn_ ## _name(_type *); \
170 PG_REGISTER_ARRAY_I(_type, _length, _name, _pgn, _version, .reset = {.fn = (pgResetFunc*)&pgResetFn_ ## _name}) \
174 // ARRAY reset mechanism is not implemented yet, only few places in code would benefit from it - See pgResetInstance
175 #define PG_REGISTER_ARRAY_WITH_RESET_TEMPLATE(_type, _length, _name, _pgn, _version) \
176 extern const _type pgResetTemplate_ ## _name; \
177 PG_REGISTER_ARRAY_I(_type, _length, _name, _pgn, _version, .reset = {.ptr = (void*)&pgResetTemplate_ ## _name}) \
181 #define PG_ARRAY_ELEMENT_OFFSET(type, index, member) (index * sizeof(type) + offsetof(type, member))
183 // Emit reset defaults for config.
184 // Config must be registered with PG_REGISTER_<xxx>_WITH_RESET_TEMPLATE macro
185 #define PG_RESET_TEMPLATE(_type, _name, ...) \
186 const _type pgResetTemplate_ ## _name PG_RESETDATA_ATTRIBUTES = { \
191 #define CONVERT_PARAMETER_TO_FLOAT(param) (0.001f * param)
192 #define CONVERT_PARAMETER_TO_PERCENT(param) (0.01f * param)
194 const pgRegistry_t
* pgFind(pgn_t pgn
);
196 bool pgLoad(const pgRegistry_t
* reg
, const void *from
, int size
, int version
);
197 int pgStore(const pgRegistry_t
* reg
, void *to
, int size
);
198 void pgResetAll(void);
199 void pgResetInstance(const pgRegistry_t
*reg
, uint8_t *base
);
200 bool pgResetCopy(void *copy
, pgn_t pgn
);
201 void pgReset(const pgRegistry_t
* reg
);