vtx: fix VTX_SETTINGS_POWER_COUNT and add dummy entries to saPowerNames
[inav.git] / src / main / config / parameter_group.h
blob28a647ecb96e97ffcf7e8d2f99352d632881361e
1 /*
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/>.
18 #pragma once
20 #include <stdint.h>
21 #include <stdbool.h>
23 #include "build/build_config.h"
25 typedef uint16_t pgn_t;
27 // parameter group registry flags
28 typedef enum {
29 PGRF_NONE = 0,
30 PGRF_CLASSIFICATON_BIT = (1 << 0)
31 } pgRegistryFlags_e;
33 typedef enum {
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.
50 union {
51 void *ptr; // Pointer to init template
52 pgResetFunc *fn; // Popinter to pgResetFunc
53 } reset;
54 } pgRegistry_t;
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))
64 #ifdef __APPLE__
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)))
72 #else
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)))
80 #endif
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) \
89 PG_FOREACH(_name) \
90 if (pgIsSystem(_name)) \
91 continue; \
92 else \
93 /**/
95 // Reset configuration to default (by name)
96 // Only current profile is reset for profile based configs
97 #define PG_RESET_CURRENT(_name) \
98 do { \
99 extern const pgRegistry_t _name ##_Registry; \
100 pgResetCurrent(&_name ## _Registry); \
101 } while (0) \
102 /**/
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; }\
110 struct _dummy \
111 /**/
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; } \
120 struct _dummy \
121 /**/
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; } \
128 struct _dummy \
129 /**/
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, \
143 .ptr = 0, \
144 _reset, \
146 /**/
148 #define PG_REGISTER(_type, _name, _pgn, _version) \
149 PG_REGISTER_I(_type, _name, _pgn, _version, .reset = {.ptr = 0}) \
150 /**/
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 }) \
155 /**/
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}) \
160 /**/
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, \
172 .ptr = 0, \
173 _reset, \
175 /**/
177 #define PG_REGISTER_ARRAY(_type, _size, _name, _pgn, _version) \
178 PG_REGISTER_ARRAY_I(_type, _size, _name, _pgn, _version, .reset = {.ptr = 0}) \
179 /**/
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}) \
184 /**/
186 #ifdef UNIT_TEST
187 # define _PG_PROFILE_CURRENT_DECL(_type, _name) \
188 _type *_name ## _ProfileCurrent = &_name ## _Storage[0];
189 #else
190 # define _PG_PROFILE_CURRENT_DECL(_type, _name) \
191 _type *_name ## _ProfileCurrent;
192 #endif
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, \
206 _reset, \
208 /**/
210 #define PG_REGISTER_PROFILE(_type, _name, _pgn, _version) \
211 PG_REGISTER_PROFILE_I(_type, _name, _pgn, _version, .reset = {.ptr = 0}) \
212 /**/
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}) \
217 /**/
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}) \
222 /**/
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 = { \
229 __VA_ARGS__ \
231 /**/
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);