Merge pull request #11494 from haslinghuis/dshot_gpio
[betaflight.git] / src / main / pg / pg.h
blob947aa3bf51c5b4d866f518fa44b5b384e3a128f7
1 /*
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)
8 * any later version.
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/>.
21 #pragma once
23 #include <stdint.h>
24 #include <stdbool.h>
26 #include "build/build_config.h"
28 typedef uint16_t pgn_t;
30 // parameter group registry flags
31 typedef enum {
32 PGRF_NONE = 0,
33 PGRF_CLASSIFICATON_BIT = (1 << 0)
34 } pgRegistryFlags_e;
36 typedef enum {
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.
53 union {
54 void *ptr; // Pointer to init template
55 pgResetFunc *fn; // Popinter to pgResetFunc
56 } reset;
57 } pgRegistry_t;
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))
66 #ifdef __APPLE__
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)))
74 #else
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)))
82 #endif
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) \
92 do { \
93 extern const pgRegistry_t _name ##_Registry; \
94 pgReset(&_name ## _Registry); \
95 } while (0) \
96 /**/
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; }\
104 struct _dummy \
105 /**/
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; } \
114 struct _dummy \
115 /**/
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), \
125 .length = 1, \
126 .size = sizeof(_type) | PGR_SIZE_SYSTEM_FLAG, \
127 .address = (uint8_t*)&_name ## _System, \
128 .copy = (uint8_t*)&_name ## _Copy, \
129 .ptr = 0, \
130 _reset, \
132 /**/
134 #define PG_REGISTER(_type, _name, _pgn, _version) \
135 PG_REGISTER_I(_type, _name, _pgn, _version, .reset = {.ptr = 0}) \
136 /**/
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 }) \
141 /**/
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}) \
146 /**/
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), \
155 .length = _length, \
156 .size = (sizeof(_type) * _length) | PGR_SIZE_SYSTEM_FLAG, \
157 .address = (uint8_t*)&_name ## _SystemArray, \
158 .copy = (uint8_t*)&_name ## _CopyArray, \
159 .ptr = 0, \
160 _reset, \
162 /**/
164 #define PG_REGISTER_ARRAY(_type, _length, _name, _pgn, _version) \
165 PG_REGISTER_ARRAY_I(_type, _length, _name, _pgn, _version, .reset = {.ptr = 0}) \
166 /**/
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}) \
171 /**/
173 #if 0
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}) \
178 /**/
179 #endif
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 = { \
187 __VA_ARGS__ \
189 /**/
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);