msp: expose number of vtx power levels, bands and channels
[inav.git] / src / main / fc / settings.c
blob109f430f843cc2e40e764862bed17fec76cceabb
1 #include <string.h>
2 #include <stdint.h>
4 #include "platform.h"
6 #include "common/string_light.h"
7 #include "common/utils.h"
9 #include "settings_generated.h"
11 #include "fc/settings.h"
13 #include "config/general_settings.h"
14 #include "flight/rpm_filter.h"
15 #include "settings_generated.c"
17 static bool settingGetWord(char *buf, int idx)
19 if (idx == 0) {
20 return false;
22 const uint8_t *ptr = settingNamesWords;
23 char *bufPtr = buf;
24 int used_bits = 0;
25 int word = 1;
26 for(;;) {
27 int shift = 8 - SETTINGS_WORDS_BITS_PER_CHAR - used_bits;
28 char chr;
29 if (shift > 0) {
30 chr = (*ptr >> shift) & (0xff >> (8 - SETTINGS_WORDS_BITS_PER_CHAR));
31 } else {
32 chr = (*ptr & (0xff >> (8 - (SETTINGS_WORDS_BITS_PER_CHAR + shift)))) << -shift;
33 ptr++;
34 chr |= (*ptr) >> (8 + shift);
36 if (word == idx) {
37 if (chr == 0) {
38 // Finished copying the word
39 *bufPtr++ = '\0';
40 break;
42 char c;
43 if (chr < 27) {
44 c = 'a' + (chr - 1);
45 } else {
46 c = wordSymbols[chr - 27];
48 *bufPtr++ = c;
49 } else {
50 if (chr == 0) {
51 // Word end
52 word++;
55 used_bits = (used_bits + SETTINGS_WORDS_BITS_PER_CHAR) % 8;
57 return true;
60 void settingGetName(const setting_t *val, char *buf)
62 uint8_t bpos = 0;
63 uint16_t n = 0;
64 char word[SETTING_MAX_WORD_LENGTH];
65 #ifndef SETTING_ENCODED_NAME_USES_BYTE_INDEXING
66 uint8_t shift = 0;
67 #endif
68 for (uint8_t ii = 0; ii < SETTING_ENCODED_NAME_MAX_BYTES; ii++) {
69 #ifdef SETTING_ENCODED_NAME_USES_BYTE_INDEXING
70 n = val->encoded_name[ii];
71 #else
72 // Decode a variable size uint
73 uint16_t b = val->encoded_name[ii];
74 if (b >= 0x80) {
75 // More bytes follow
76 n |= (b&0x7f) << shift;
77 shift += 7;
78 continue;
80 // Final byte
81 n |= b << shift;
82 #endif
83 if (!settingGetWord(word, n)) {
84 // No more words
85 break;
87 if (bpos > 0) {
88 // Word separator
89 buf[bpos++] = '_';
91 strcpy(&buf[bpos], word);
92 bpos += strlen(word);
93 #ifndef SETTING_ENCODED_NAME_USES_BYTE_INDEXING
94 // Reset shift and n
95 shift = 0;
96 n = 0;
97 #endif
99 buf[bpos] = '\0';
102 bool settingNameContains(const setting_t *val, char *buf, const char *cmdline)
104 settingGetName(val, buf);
105 return strstr(buf, cmdline) != NULL;
108 bool settingNameIsExactMatch(const setting_t *val, char *buf, const char *cmdline, uint8_t var_name_length)
110 settingGetName(val, buf);
111 return sl_strncasecmp(cmdline, buf, strlen(buf)) == 0 && var_name_length == strlen(buf);
114 const setting_t *settingFind(const char *name)
116 char buf[SETTING_MAX_NAME_LENGTH];
117 for (int ii = 0; ii < SETTINGS_TABLE_COUNT; ii++) {
118 const setting_t *setting = &settingsTable[ii];
119 settingGetName(setting, buf);
120 if (strcmp(buf, name) == 0) {
121 return setting;
124 return NULL;
127 const setting_t *settingGet(unsigned index)
129 return index < SETTINGS_TABLE_COUNT ? &settingsTable[index] : NULL;
132 unsigned settingGetIndex(const setting_t *val)
134 return val - settingsTable;
137 bool settingsValidate(unsigned *invalidIndex)
139 for (unsigned ii = 0; ii < SETTINGS_TABLE_COUNT; ii++) {
140 const setting_t *setting = settingGet(ii);
141 setting_min_t min = settingGetMin(setting);
142 setting_max_t max = settingGetMax(setting);
143 void *ptr = settingGetValuePointer(setting);
144 bool isValid = false;
145 switch (SETTING_TYPE(setting)) {
146 case VAR_UINT8:
148 uint8_t *value = ptr;
149 isValid = *value >= min && *value <= max;
150 break;
152 case VAR_INT8:
154 int8_t *value = ptr;
155 isValid = *value >= min && *value <= (int8_t)max;
156 break;
158 case VAR_UINT16:
160 uint16_t *value = ptr;
161 isValid = *value >= min && *value <= max;
162 break;
164 case VAR_INT16:
166 int16_t *value = ptr;
167 isValid = *value >= min && *value <= (int16_t)max;
168 break;
170 case VAR_UINT32:
172 uint32_t *value = ptr;
173 isValid = *value >= (uint32_t)min && *value <= max;
174 break;
176 case VAR_FLOAT:
178 float *value = ptr;
179 isValid = *value >= min && *value <= max;
180 break;
182 case VAR_STRING:
183 // We assume all strings are valid
184 isValid = true;
185 break;
187 if (!isValid) {
188 if (invalidIndex) {
189 *invalidIndex = ii;
191 return false;
194 return true;
197 size_t settingGetValueSize(const setting_t *val)
199 switch (SETTING_TYPE(val)) {
200 case VAR_UINT8:
201 FALLTHROUGH;
202 case VAR_INT8:
203 return 1;
204 case VAR_UINT16:
205 FALLTHROUGH;
206 case VAR_INT16:
207 return 2;
208 case VAR_UINT32:
209 FALLTHROUGH;
210 case VAR_FLOAT:
211 return 4;
212 case VAR_STRING:
213 return settingGetMax(val);
215 return 0; // Unreachable
218 pgn_t settingGetPgn(const setting_t *val)
220 uint16_t pos = val - (const setting_t *)settingsTable;
221 uint16_t acc = 0;
222 for (uint8_t ii = 0; ii < SETTINGS_PGN_COUNT; ii++) {
223 acc += settingsPgnCounts[ii];
224 if (acc > pos) {
225 return settingsPgn[ii];
228 return -1;
231 static uint16_t getValueOffset(const setting_t *value)
233 switch (SETTING_SECTION(value)) {
234 case MASTER_VALUE:
235 return value->offset;
236 case PROFILE_VALUE:
237 return value->offset + sizeof(pidProfile_t) * getConfigProfile();
238 case CONTROL_RATE_VALUE:
239 return value->offset + sizeof(controlRateConfig_t) * getConfigProfile();
240 case EZ_TUNE_VALUE:
241 return value->offset + sizeof(ezTuneSettings_t) * getConfigProfile();
242 case BATTERY_CONFIG_VALUE:
243 return value->offset + sizeof(batteryProfile_t) * getConfigBatteryProfile();
244 case MIXER_CONFIG_VALUE:
245 return value->offset + sizeof(mixerProfile_t) * getConfigMixerProfile();
247 return 0;
250 void *settingGetValuePointer(const setting_t *val)
252 const pgRegistry_t *pg = pgFind(settingGetPgn(val));
253 return pg->address + getValueOffset(val);
256 const void * settingGetCopyValuePointer(const setting_t *val)
258 const pgRegistry_t *pg = pgFind(settingGetPgn(val));
259 return pg->copy + getValueOffset(val);
262 setting_min_t settingGetMin(const setting_t *val)
264 if (SETTING_MODE(val) == MODE_LOOKUP) {
265 return 0;
267 return settingMinMaxTable[SETTING_INDEXES_GET_MIN(val)];
270 setting_max_t settingGetMax(const setting_t *val)
272 if (SETTING_MODE(val) == MODE_LOOKUP) {
273 return settingLookupTables[val->config.lookup.tableIndex].valueCount - 1;
275 return settingMinMaxTable[SETTING_INDEXES_GET_MAX(val)];
278 const lookupTableEntry_t * settingLookupTable(const setting_t *val)
280 if (SETTING_MODE(val) == MODE_LOOKUP && val->config.lookup.tableIndex < LOOKUP_TABLE_COUNT) {
281 return &settingLookupTables[val->config.lookup.tableIndex];
283 return NULL;
286 const char * settingLookupValueName(const setting_t *val, unsigned v)
288 const lookupTableEntry_t *table = settingLookupTable(val);
289 if (table && v < table->valueCount) {
290 return table->values[v];
292 return NULL;
295 size_t settingGetValueNameMaxSize(const setting_t *val)
297 size_t maxSize = 0;
298 const lookupTableEntry_t *table = settingLookupTable(val);
299 if (table) {
300 for (unsigned ii = 0; ii < table->valueCount; ii++) {
301 maxSize = MAX(maxSize, strlen(table->values[ii]));
304 return maxSize;
307 const char * settingGetString(const setting_t *val)
309 if (SETTING_TYPE(val) == VAR_STRING) {
310 return settingGetValuePointer(val);
312 return NULL;
315 void settingSetString(const setting_t *val, const char *s, size_t size)
317 if (SETTING_TYPE(val) == VAR_STRING) {
318 char *p = settingGetValuePointer(val);
319 size_t copySize = MIN(size, settingGetMax(val));
320 memcpy(p, s, copySize);
321 p[copySize] = '\0';
325 setting_max_t settingGetStringMaxLength(const setting_t *val)
327 if (SETTING_TYPE(val) == VAR_STRING) {
328 // Max string length is stored as its max
329 return settingGetMax(val);
331 return 0;
334 bool settingsGetParameterGroupIndexes(pgn_t pg, uint16_t *start, uint16_t *end)
336 unsigned acc = 0;
337 for (int ii = 0; ii < SETTINGS_PGN_COUNT; ii++) {
338 if (settingsPgn[ii] == pg) {
339 if (start) {
340 *start = acc;
342 if (end) {
343 *end = acc + settingsPgnCounts[ii] - 1;
345 return true;
347 acc += settingsPgnCounts[ii];
349 return false;