Merge branch 'master' into change-to-sending-expresslrs_RFrates_e-in-sync-packet
[ExpressLRS.git] / src / lib / CONFIG / config.cpp
blob09444148bf7dd1927504aaa87b76205c7ae8f7eb
1 #include "config.h"
2 #include "config_legacy.h"
3 #include "common.h"
4 #include "POWERMGNT.h"
5 #include "OTA.h"
6 #include "helpers.h"
7 #include "logging.h"
9 #if defined(TARGET_TX)
11 #define MODEL_CHANGED bit(1)
12 #define VTX_CHANGED bit(2)
13 #define MAIN_CHANGED bit(3) // catch-all for global config item
14 #define FAN_CHANGED bit(4)
15 #define MOTION_CHANGED bit(5)
16 #define BUTTON_CHANGED bit(6)
17 #define ALL_CHANGED (MODEL_CHANGED | VTX_CHANGED | MAIN_CHANGED | FAN_CHANGED | MOTION_CHANGED | BUTTON_CHANGED)
19 // Really awful but safe(?) type punning of model_config_t/v6_model_config_t to and from uint32_t
20 template<class T> static const void U32_to_Model(uint32_t const u32, T * const model)
22 union {
23 union {
24 T model;
25 uint8_t padding[sizeof(uint32_t)-sizeof(T)];
26 } val;
27 uint32_t u32;
28 } converter = { .u32 = u32 };
30 *model = converter.val.model;
33 template<class T> static const uint32_t Model_to_U32(T const * const model)
35 // clear the entire union because the assignment will only fill sizeof(T)
36 union {
37 union {
38 T model;
39 uint8_t padding[sizeof(uint32_t)-sizeof(T)];
40 } val;
41 uint32_t u32;
42 } converter = { 0 };
44 converter.val.model = *model;
45 return converter.u32;
48 static uint8_t RateV6toV7(uint8_t rateV6)
50 #if defined(RADIO_SX127X) || defined(RADIO_LR1121)
51 if (rateV6 == 0)
53 // 200Hz stays same
54 return 0;
57 // 100Hz, 50Hz, 25Hz all move up one
58 // to make room for 100Hz Full
59 return rateV6 + 1;
60 #else // RADIO_2400
61 switch (rateV6)
63 case 0: return 4; // 500Hz
64 case 1: return 6; // 250Hz
65 case 2: return 7; // 150Hz
66 case 3: return 9; // 50Hz
67 default: return 4; // 500Hz
69 #endif // RADIO_2400
72 static uint8_t RatioV6toV7(uint8_t ratioV6)
74 // All shifted up for Std telem
75 return ratioV6 + 1;
78 static uint8_t SwitchesV6toV7(uint8_t switchesV6)
80 // 0 was removed, Wide(2) became 0, Hybrid(1) became 1
81 switch (switchesV6)
83 case 1: return (uint8_t)smHybridOr16ch;
84 case 2:
85 default:
86 return (uint8_t)smWideOr8ch;
90 static void ModelV6toV7(v6_model_config_t const * const v6, model_config_t * const v7)
92 v7->rate = RateV6toV7(v6->rate);
93 v7->tlm = RatioV6toV7(v6->tlm);
94 v7->power = v6->power;
95 v7->switchMode = SwitchesV6toV7(v6->switchMode);
96 v7->modelMatch = v6->modelMatch;
97 v7->dynamicPower = v6->dynamicPower;
98 v7->boostChannel = v6->boostChannel;
101 static void ModelV7toV8(v7_model_config_t const * const v7, model_config_t * const v8)
103 v8->rate = v7->rate;
104 v8->tlm = v7->tlm;
105 v8->power = v7->power;
106 v8->switchMode = v7->switchMode;
107 v8->boostChannel = v7->boostChannel;
108 v8->dynamicPower = v7->dynamicPower;
109 v8->modelMatch = v7->modelMatch;
110 v8->txAntenna = v7->txAntenna;
111 v8->ptrStartChannel = v7->ptrStartChannel;
112 v8->ptrEnableChannel = v7->ptrEnableChannel;
113 v8->linkMode = v7->linkMode;
116 TxConfig::TxConfig() :
117 m_model(m_config.model_config)
121 #if defined(PLATFORM_ESP32)
122 void TxConfig::Load()
124 m_modified = 0;
126 // Initialize NVS
127 esp_err_t err = nvs_flash_init();
128 if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND)
130 ESP_ERROR_CHECK(nvs_flash_erase());
131 err = nvs_flash_init();
133 ESP_ERROR_CHECK( err );
134 ESP_ERROR_CHECK(nvs_open("ELRS", NVS_READWRITE, &handle));
136 // Try to load the version and make sure it is a TX config
137 uint32_t version = 0;
138 if (nvs_get_u32(handle, "tx_version", &version) == ESP_OK && ((version & CONFIG_MAGIC_MASK) == TX_CONFIG_MAGIC))
139 version = version & ~CONFIG_MAGIC_MASK;
140 DBGLN("Config version %u", version);
142 // Can't upgrade from version <5, or when flashing a previous version, just use defaults.
143 if (version < 5 || version > TX_CONFIG_VERSION)
145 SetDefaults(true);
146 return;
149 SetDefaults(false);
151 uint32_t value;
152 uint8_t value8;
153 // vtx (v5)
154 if (nvs_get_u32(handle, "vtx", &value) == ESP_OK)
156 m_config.vtxBand = value >> 24;
157 m_config.vtxChannel = value >> 16;
158 m_config.vtxPower = value >> 8;
159 m_config.vtxPitmode = value;
162 // fanthresh (v5)
163 if (nvs_get_u8(handle, "fanthresh", &value8) == ESP_OK)
164 m_config.powerFanThreshold = value8;
166 // Both of these were added to config v5 without incrementing the version
167 if (nvs_get_u32(handle, "fan", &value) == ESP_OK)
168 m_config.fanMode = value;
169 if (nvs_get_u32(handle, "motion", &value) == ESP_OK)
170 m_config.motionMode = value;
172 if (version >= 6)
174 // dvr (v6)
175 if (nvs_get_u8(handle, "dvraux", &value8) == ESP_OK)
176 m_config.dvrAux = value8;
177 if (nvs_get_u8(handle, "dvrstartdelay", &value8) == ESP_OK)
178 m_config.dvrStartDelay = value8;
179 if (nvs_get_u8(handle, "dvrstopdelay", &value8) == ESP_OK)
180 m_config.dvrStopDelay = value8;
182 else
184 // Need to write the dvr defaults
185 m_modified |= MAIN_CHANGED;
188 if (version >= 7) {
189 // load button actions
190 if (nvs_get_u32(handle, "button1", &value) == ESP_OK)
191 m_config.buttonColors[0].raw = value;
192 if (nvs_get_u32(handle, "button2", &value) == ESP_OK)
193 m_config.buttonColors[1].raw = value;
194 // backpackdisable was actually added after 7, but if not found will default to 0 (enabled)
195 if (nvs_get_u8(handle, "backpackdisable", &value8) == ESP_OK)
196 m_config.backpackDisable = value8;
197 if (nvs_get_u8(handle, "backpacktlmen", &value8) == ESP_OK)
198 m_config.backpackTlmMode = value8;
201 for(unsigned i=0; i<CONFIG_TX_MODEL_CNT; i++)
203 char model[10] = "model";
204 itoa(i, model+5, 10);
205 if (nvs_get_u32(handle, model, &value) == ESP_OK)
207 if (version == 6)
209 // Upgrade v6 to v7 directly writing to nvs instead of calling Commit() over and over
210 v6_model_config_t v6model;
211 U32_to_Model(value, &v6model);
212 model_config_t * const newModel = &m_config.model_config[i];
213 ModelV6toV7(&v6model, newModel);
214 nvs_set_u32(handle, model, Model_to_U32(newModel));
217 if (version <= 7)
219 // Upgrade v7 to v8 directly writing to nvs instead of calling Commit() over and over
220 v7_model_config_t v7model;
221 U32_to_Model(value, &v7model);
222 model_config_t * const newModel = &m_config.model_config[i];
223 ModelV7toV8(&v7model, newModel);
224 nvs_set_u32(handle, model, Model_to_U32(newModel));
227 if (version == TX_CONFIG_VERSION)
229 U32_to_Model(value, &m_config.model_config[i]);
232 } // for each model
234 if (version != TX_CONFIG_VERSION)
236 Commit();
239 #else // ESP8266
240 void TxConfig::Load()
242 m_modified = 0;
243 m_eeprom->Get(0, m_config);
245 uint32_t version = 0;
246 if ((m_config.version & CONFIG_MAGIC_MASK) == TX_CONFIG_MAGIC)
247 version = m_config.version & ~CONFIG_MAGIC_MASK;
248 DBGLN("Config version %u", version);
250 // If version is current, all done
251 if (version == TX_CONFIG_VERSION)
252 return;
254 // Can't upgrade from version <5, or when flashing a previous version, just use defaults.
255 if (version < 5 || version > TX_CONFIG_VERSION)
257 SetDefaults(true);
258 return;
261 // Upgrade EEPROM, starting with defaults
262 SetDefaults(false);
264 if (version == 5)
266 UpgradeEepromV5ToV6();
267 version = 6;
270 if (version == 6)
272 UpgradeEepromV6ToV7();
273 version = 7;
276 if (version == 7)
278 UpgradeEepromV7ToV8();
282 void TxConfig::UpgradeEepromV5ToV6()
284 v5_tx_config_t v5Config;
285 v6_tx_config_t v6Config = { 0 }; // default the new fields to 0
287 // Populate the prev version struct from eeprom
288 m_eeprom->Get(0, v5Config);
290 // Copy prev values to current config struct
291 // This only workse because v5 and v6 are the same up to the new fields
292 // which have already been set to 0
293 memcpy(&v6Config, &v5Config, sizeof(v5Config));
294 v6Config.version = 6U | TX_CONFIG_MAGIC;
295 m_eeprom->Put(0, v6Config);
296 m_eeprom->Commit();
299 void TxConfig::UpgradeEepromV6ToV7()
301 v6_tx_config_t v6Config;
303 // Populate the prev version struct from eeprom
304 m_eeprom->Get(0, v6Config);
306 // Manual field copying as some fields have moved
307 #define LAZY(member) m_config.member = v6Config.member
308 LAZY(vtxBand);
309 LAZY(vtxChannel);
310 LAZY(vtxPower);
311 LAZY(vtxPitmode);
312 LAZY(powerFanThreshold);
313 LAZY(fanMode);
314 LAZY(motionMode);
315 LAZY(dvrAux);
316 LAZY(dvrStartDelay);
317 LAZY(dvrStopDelay);
318 #undef LAZY
320 for (unsigned i=0; i<CONFIG_TX_MODEL_CNT; i++)
322 ModelV6toV7(&v6Config.model_config[i], &m_config.model_config[i]);
325 m_modified = ALL_CHANGED;
327 // Full Commit now
328 m_config.version = 7U | TX_CONFIG_MAGIC;
329 Commit();
332 void TxConfig::UpgradeEepromV7ToV8()
334 v7_tx_config_t v7Config;
336 // Populate the prev version struct from eeprom
337 m_eeprom->Get(0, v7Config);
339 for (unsigned i=0; i<CONFIG_TX_MODEL_CNT; i++)
341 ModelV7toV8(&v7Config.model_config[i], &m_config.model_config[i]);
344 m_modified = ALL_CHANGED;
346 // Full Commit now
347 m_config.version = 8U | TX_CONFIG_MAGIC;
348 Commit();
350 #endif
352 void
353 TxConfig::Commit()
355 if (!m_modified)
357 // No changes
358 return;
360 #if defined(PLATFORM_ESP32)
361 // Write parts to NVS
362 if (m_modified & MODEL_CHANGED)
364 uint32_t value = Model_to_U32(m_model);
365 char model[10] = "model";
366 itoa(m_modelId, model+5, 10);
367 nvs_set_u32(handle, model, value);
369 if (m_modified & VTX_CHANGED)
371 uint32_t value =
372 m_config.vtxBand << 24 |
373 m_config.vtxChannel << 16 |
374 m_config.vtxPower << 8 |
375 m_config.vtxPitmode;
376 nvs_set_u32(handle, "vtx", value);
378 if (m_modified & FAN_CHANGED)
380 uint32_t value = m_config.fanMode;
381 nvs_set_u32(handle, "fan", value);
383 if (m_modified & MOTION_CHANGED)
385 uint32_t value = m_config.motionMode;
386 nvs_set_u32(handle, "motion", value);
388 if (m_modified & MAIN_CHANGED)
390 nvs_set_u8(handle, "fanthresh", m_config.powerFanThreshold);
392 nvs_set_u8(handle, "backpackdisable", m_config.backpackDisable);
393 nvs_set_u8(handle, "backpacktlmen", m_config.backpackTlmMode);
394 nvs_set_u8(handle, "dvraux", m_config.dvrAux);
395 nvs_set_u8(handle, "dvrstartdelay", m_config.dvrStartDelay);
396 nvs_set_u8(handle, "dvrstopdelay", m_config.dvrStopDelay);
398 if (m_modified & BUTTON_CHANGED)
400 nvs_set_u32(handle, "button1", m_config.buttonColors[0].raw);
401 nvs_set_u32(handle, "button2", m_config.buttonColors[1].raw);
403 nvs_set_u32(handle, "tx_version", m_config.version);
404 nvs_commit(handle);
405 #else
406 // Write the struct to eeprom
407 m_eeprom->Put(0, m_config);
408 m_eeprom->Commit();
409 #endif
410 m_modified = 0;
413 // Setters
414 void
415 TxConfig::SetRate(uint8_t rate)
417 if (GetRate() != rate)
419 m_model->rate = rate;
420 m_modified |= MODEL_CHANGED;
424 void
425 TxConfig::SetTlm(uint8_t tlm)
427 if (GetTlm() != tlm)
429 m_model->tlm = tlm;
430 m_modified |= MODEL_CHANGED;
434 void
435 TxConfig::SetPower(uint8_t power)
437 if (GetPower() != power)
439 m_model->power = power;
440 m_modified |= MODEL_CHANGED;
444 void
445 TxConfig::SetDynamicPower(bool dynamicPower)
447 if (GetDynamicPower() != dynamicPower)
449 m_model->dynamicPower = dynamicPower;
450 m_modified |= MODEL_CHANGED;
454 void
455 TxConfig::SetBoostChannel(uint8_t boostChannel)
457 if (GetBoostChannel() != boostChannel)
459 m_model->boostChannel = boostChannel;
460 m_modified |= MODEL_CHANGED;
464 void
465 TxConfig::SetSwitchMode(uint8_t switchMode)
467 if (GetSwitchMode() != switchMode)
469 m_model->switchMode = switchMode;
470 m_modified |= MODEL_CHANGED;
474 void
475 TxConfig::SetAntennaMode(uint8_t txAntenna)
477 if (GetAntennaMode() != txAntenna)
479 m_model->txAntenna = txAntenna;
480 m_modified |= MODEL_CHANGED;
484 void
485 TxConfig::SetLinkMode(uint8_t linkMode)
487 if (GetLinkMode() != linkMode)
489 m_model->linkMode = linkMode;
491 if (linkMode == TX_MAVLINK_MODE)
493 m_model->tlm = TLM_RATIO_1_2;
494 m_model->switchMode = smHybridOr16ch; // Force Hybrid / 16ch/2 switch modes for mavlink
496 m_modified |= MODEL_CHANGED | MAIN_CHANGED;
500 void
501 TxConfig::SetModelMatch(bool modelMatch)
503 if (GetModelMatch() != modelMatch)
505 m_model->modelMatch = modelMatch;
506 m_modified |= MODEL_CHANGED;
510 void
511 TxConfig::SetVtxBand(uint8_t vtxBand)
513 if (m_config.vtxBand != vtxBand)
515 m_config.vtxBand = vtxBand;
516 m_modified |= VTX_CHANGED;
520 void
521 TxConfig::SetVtxChannel(uint8_t vtxChannel)
523 if (m_config.vtxChannel != vtxChannel)
525 m_config.vtxChannel = vtxChannel;
526 m_modified |= VTX_CHANGED;
530 void
531 TxConfig::SetVtxPower(uint8_t vtxPower)
533 if (m_config.vtxPower != vtxPower)
535 m_config.vtxPower = vtxPower;
536 m_modified |= VTX_CHANGED;
540 void
541 TxConfig::SetVtxPitmode(uint8_t vtxPitmode)
543 if (m_config.vtxPitmode != vtxPitmode)
545 m_config.vtxPitmode = vtxPitmode;
546 m_modified |= VTX_CHANGED;
550 void
551 TxConfig::SetPowerFanThreshold(uint8_t powerFanThreshold)
553 if (m_config.powerFanThreshold != powerFanThreshold)
555 m_config.powerFanThreshold = powerFanThreshold;
556 m_modified |= MAIN_CHANGED;
560 void
561 TxConfig::SetStorageProvider(ELRS_EEPROM *eeprom)
563 if (eeprom)
565 m_eeprom = eeprom;
569 void
570 TxConfig::SetFanMode(uint8_t fanMode)
572 if (m_config.fanMode != fanMode)
574 m_config.fanMode = fanMode;
575 m_modified |= FAN_CHANGED;
579 void
580 TxConfig::SetMotionMode(uint8_t motionMode)
582 if (m_config.motionMode != motionMode)
584 m_config.motionMode = motionMode;
585 m_modified |= MOTION_CHANGED;
589 void
590 TxConfig::SetDvrAux(uint8_t dvrAux)
592 if (GetDvrAux() != dvrAux)
594 m_config.dvrAux = dvrAux;
595 m_modified |= MAIN_CHANGED;
599 void
600 TxConfig::SetDvrStartDelay(uint8_t dvrStartDelay)
602 if (GetDvrStartDelay() != dvrStartDelay)
604 m_config.dvrStartDelay = dvrStartDelay;
605 m_modified |= MAIN_CHANGED;
609 void
610 TxConfig::SetDvrStopDelay(uint8_t dvrStopDelay)
612 if (GetDvrStopDelay() != dvrStopDelay)
614 m_config.dvrStopDelay = dvrStopDelay;
615 m_modified |= MAIN_CHANGED;
619 void
620 TxConfig::SetBackpackDisable(bool backpackDisable)
622 if (m_config.backpackDisable != backpackDisable)
624 m_config.backpackDisable = backpackDisable;
625 m_modified |= MAIN_CHANGED;
629 void
630 TxConfig::SetBackpackTlmMode(uint8_t mode)
632 if (m_config.backpackTlmMode != mode)
634 m_config.backpackTlmMode = mode;
635 m_modified |= MAIN_CHANGED;
639 void
640 TxConfig::SetButtonActions(uint8_t button, tx_button_color_t *action)
642 if (m_config.buttonColors[button].raw != action->raw) {
643 m_config.buttonColors[button].raw = action->raw;
644 m_modified |= BUTTON_CHANGED;
648 void
649 TxConfig::SetPTRStartChannel(uint8_t ptrStartChannel)
651 if (ptrStartChannel != m_model->ptrStartChannel) {
652 m_model->ptrStartChannel = ptrStartChannel;
653 m_modified |= MODEL_CHANGED;
657 void
658 TxConfig::SetPTREnableChannel(uint8_t ptrEnableChannel)
660 if (ptrEnableChannel != m_model->ptrEnableChannel) {
661 m_model->ptrEnableChannel = ptrEnableChannel;
662 m_modified |= MODEL_CHANGED;
666 void
667 TxConfig::SetDefaults(bool commit)
669 // Reset everything to 0/false and then just set anything that zero is not appropriate
670 memset(&m_config, 0, sizeof(m_config));
672 m_config.version = TX_CONFIG_VERSION | TX_CONFIG_MAGIC;
673 m_config.powerFanThreshold = PWR_250mW;
674 m_modified = ALL_CHANGED;
676 if (commit)
678 m_modified = ALL_CHANGED;
681 // Set defaults for button 1
682 tx_button_color_t default_actions1 = {
683 .val = {
684 .color = 226, // R:255 G:0 B:182
685 .actions = {
686 {false, 2, ACTION_BIND},
687 {true, 0, ACTION_INCREASE_POWER}
691 m_config.buttonColors[0].raw = default_actions1.raw;
693 // Set defaults for button 2
694 tx_button_color_t default_actions2 = {
695 .val = {
696 .color = 3, // R:0 G:0 B:255
697 .actions = {
698 {false, 1, ACTION_GOTO_VTX_CHANNEL},
699 {true, 0, ACTION_SEND_VTX}
703 m_config.buttonColors[1].raw = default_actions2.raw;
705 for (unsigned i=0; i<CONFIG_TX_MODEL_CNT; i++)
707 SetModelId(i);
708 #if defined(RADIO_SX127X)
709 SetRate(enumRatetoIndex(RATE_LORA_200HZ));
710 #elif defined(RADIO_LR1121)
711 SetRate(enumRatetoIndex(POWER_OUTPUT_VALUES_COUNT == 0 ? RATE_LORA_250HZ : RATE_LORA_200HZ));
712 #elif defined(RADIO_SX128X)
713 SetRate(enumRatetoIndex(RATE_LORA_2G4_250HZ));
714 #endif
715 SetPower(POWERMGNT::getDefaultPower());
716 #if defined(PLATFORM_ESP32)
717 // ESP32 nvs needs to commit every model
718 if (commit)
720 m_modified |= MODEL_CHANGED;
721 Commit();
723 #endif
726 #if !defined(PLATFORM_ESP32)
727 // ESP8266 just needs one commit
728 if (commit)
730 Commit();
732 #endif
734 SetModelId(0);
735 m_modified = 0;
739 * Sets ModelId used for subsequent per-model config gets
740 * Returns: true if the model has changed
742 bool
743 TxConfig::SetModelId(uint8_t modelId)
745 model_config_t *newModel = &m_config.model_config[modelId];
746 if (newModel != m_model)
748 m_model = newModel;
749 m_modelId = modelId;
750 return true;
753 return false;
755 #endif
757 /////////////////////////////////////////////////////
759 #if defined(TARGET_RX)
761 #if defined(PLATFORM_ESP8266)
762 #include "flash_hal.h"
763 #endif
765 RxConfig::RxConfig()
769 void RxConfig::Load()
771 m_modified = false;
772 m_eeprom->Get(0, m_config);
774 uint32_t version = 0;
775 if ((m_config.version & CONFIG_MAGIC_MASK) == RX_CONFIG_MAGIC)
776 version = m_config.version & ~CONFIG_MAGIC_MASK;
777 DBGLN("Config version %u", version);
779 // If version is current, all done
780 if (version == RX_CONFIG_VERSION)
782 CheckUpdateFlashedUid(false);
783 return;
786 // Can't upgrade from version <4, or when flashing a previous version, just use defaults.
787 if (version < 4 || version > RX_CONFIG_VERSION)
789 SetDefaults(true);
790 CheckUpdateFlashedUid(true);
791 return;
794 // Upgrade EEPROM, starting with defaults
795 SetDefaults(false);
796 UpgradeEepromV4();
797 UpgradeEepromV5();
798 UpgradeEepromV6();
799 UpgradeEepromV7V8();
800 UpgradeEepromV9();
801 m_config.version = RX_CONFIG_VERSION | RX_CONFIG_MAGIC;
802 m_modified = true;
803 Commit();
806 void RxConfig::CheckUpdateFlashedUid(bool skipDescrimCheck)
808 // No binding phrase flashed, nothing to do
809 if (!firmwareOptions.hasUID)
810 return;
811 // If already copied binding info, do not replace
812 if (!skipDescrimCheck && m_config.flash_discriminator == firmwareOptions.flash_discriminator)
813 return;
815 // Save the new UID along with this discriminator to prevent resetting every boot
816 SetUID(firmwareOptions.uid);
817 m_config.flash_discriminator = firmwareOptions.flash_discriminator;
818 // Reset the power on counter because this is following a flash, may have taken a few boots to flash
819 m_config.powerOnCounter = 0;
820 // SetUID should set this but just in case that gets removed, flash_discriminator needs to be saved
821 m_modified = true;
823 Commit();
826 // ========================================================
827 // V4 Upgrade
829 static void PwmConfigV4(v4_rx_config_pwm_t const * const v4, rx_config_pwm_t * const current)
831 current->val.failsafe = v4->val.failsafe;
832 current->val.inputChannel = v4->val.inputChannel;
833 current->val.inverted = v4->val.inverted;
836 void RxConfig::UpgradeEepromV4()
838 v4_rx_config_t v4Config;
839 m_eeprom->Get(0, v4Config);
841 if ((v4Config.version & ~CONFIG_MAGIC_MASK) == 4)
843 UpgradeUid(nullptr, v4Config.isBound ? v4Config.uid : nullptr);
844 m_config.modelId = v4Config.modelId;
845 #if defined(GPIO_PIN_PWM_OUTPUTS)
846 // OG PWMP had only 8 channels
847 for (unsigned ch=0; ch<8; ++ch)
849 PwmConfigV4(&v4Config.pwmChannels[ch], &m_config.pwmChannels[ch]);
851 #endif
855 // ========================================================
856 // V5 Upgrade
858 static void PwmConfigV5(v5_rx_config_pwm_t const * const v5, rx_config_pwm_t * const current)
860 current->val.failsafe = v5->val.failsafe;
861 current->val.inputChannel = v5->val.inputChannel;
862 current->val.inverted = v5->val.inverted;
863 current->val.narrow = v5->val.narrow;
864 current->val.mode = v5->val.mode;
865 if (v5->val.mode > som400Hz)
867 current->val.mode += 1;
871 void RxConfig::UpgradeEepromV5()
873 v5_rx_config_t v5Config;
874 m_eeprom->Get(0, v5Config);
876 if ((v5Config.version & ~CONFIG_MAGIC_MASK) == 5)
878 UpgradeUid(v5Config.onLoan ? v5Config.loanUID : nullptr, v5Config.isBound ? v5Config.uid : nullptr);
879 m_config.vbat.scale = v5Config.vbatScale;
880 m_config.power = v5Config.power;
881 m_config.antennaMode = v5Config.antennaMode;
882 m_config.forceTlmOff = v5Config.forceTlmOff;
883 m_config.rateInitialIdx = v5Config.rateInitialIdx;
884 m_config.modelId = v5Config.modelId;
886 #if defined(GPIO_PIN_PWM_OUTPUTS)
887 for (unsigned ch=0; ch<16; ++ch)
889 PwmConfigV5(&v5Config.pwmChannels[ch], &m_config.pwmChannels[ch]);
891 #endif
895 // ========================================================
896 // V6 Upgrade
898 static void PwmConfigV6(v6_rx_config_pwm_t const * const v6, rx_config_pwm_t * const current)
900 current->val.failsafe = v6->val.failsafe;
901 current->val.inputChannel = v6->val.inputChannel;
902 current->val.inverted = v6->val.inverted;
903 current->val.narrow = v6->val.narrow;
904 current->val.mode = v6->val.mode;
907 void RxConfig::UpgradeEepromV6()
909 v6_rx_config_t v6Config;
910 m_eeprom->Get(0, v6Config);
912 if ((v6Config.version & ~CONFIG_MAGIC_MASK) == 6)
914 UpgradeUid(v6Config.onLoan ? v6Config.loanUID : nullptr, v6Config.isBound ? v6Config.uid : nullptr);
915 m_config.vbat.scale = v6Config.vbatScale;
916 m_config.power = v6Config.power;
917 m_config.antennaMode = v6Config.antennaMode;
918 m_config.forceTlmOff = v6Config.forceTlmOff;
919 m_config.rateInitialIdx = v6Config.rateInitialIdx;
920 m_config.modelId = v6Config.modelId;
922 #if defined(GPIO_PIN_PWM_OUTPUTS)
923 for (unsigned ch=0; ch<16; ++ch)
925 PwmConfigV6(&v6Config.pwmChannels[ch], &m_config.pwmChannels[ch]);
927 #endif
931 // ========================================================
932 // V7/V8 Upgrade
934 void RxConfig::UpgradeEepromV7V8()
936 v7_rx_config_t v7Config;
937 m_eeprom->Get(0, v7Config);
939 bool isV8 = (v7Config.version & ~CONFIG_MAGIC_MASK) == 8;
940 if (isV8 || (v7Config.version & ~CONFIG_MAGIC_MASK) == 7)
942 UpgradeUid(v7Config.onLoan ? v7Config.loanUID : nullptr, v7Config.isBound ? v7Config.uid : nullptr);
944 m_config.vbat.scale = v7Config.vbatScale;
945 m_config.power = v7Config.power;
946 m_config.antennaMode = v7Config.antennaMode;
947 m_config.forceTlmOff = v7Config.forceTlmOff;
948 m_config.rateInitialIdx = v7Config.rateInitialIdx;
949 m_config.modelId = v7Config.modelId;
950 m_config.serialProtocol = v7Config.serialProtocol;
951 m_config.failsafeMode = v7Config.failsafeMode;
953 #if defined(GPIO_PIN_PWM_OUTPUTS)
954 for (unsigned ch=0; ch<16; ++ch)
956 m_config.pwmChannels[ch].raw = v7Config.pwmChannels[ch].raw;
957 if (!isV8 && m_config.pwmChannels[ch].val.mode > somOnOff)
958 m_config.pwmChannels[ch].val.mode += 1;
960 #endif
964 // ========================================================
965 // V9 Upgrade
967 void RxConfig::UpgradeEepromV9()
969 v9_rx_config_t v9Config;
970 m_eeprom->Get(0, v9Config);
972 if ((v9Config.version & ~CONFIG_MAGIC_MASK) == 9)
974 m_config.powerOnCounter = v9Config.powerOnCounter;
975 m_config.forceTlmOff = v9Config.forceTlmOff;
976 m_config.rateInitialIdx = v9Config.rateInitialIdx;
980 void RxConfig::UpgradeUid(uint8_t *onLoanUid, uint8_t *boundUid)
982 // Convert to traditional binding
983 // On loan? Now you own
984 if (onLoanUid)
986 memcpy(m_config.uid, onLoanUid, UID_LEN);
988 // Compiled in UID? Bind to that
989 else if (firmwareOptions.hasUID)
991 memcpy(m_config.uid, firmwareOptions.uid, UID_LEN);
992 m_config.flash_discriminator = firmwareOptions.flash_discriminator;
994 else if (boundUid)
996 // keep binding
997 memcpy(m_config.uid, boundUid, UID_LEN);
999 else
1001 // No bind
1002 memset(m_config.uid, 0, UID_LEN);
1006 bool RxConfig::GetIsBound() const
1008 if (m_config.bindStorage == BINDSTORAGE_VOLATILE)
1009 return false;
1010 return UID_IS_BOUND(m_config.uid);
1013 bool RxConfig::IsOnLoan() const
1015 if (m_config.bindStorage != BINDSTORAGE_RETURNABLE)
1016 return false;
1017 if (!firmwareOptions.hasUID)
1018 return false;
1019 return GetIsBound() && memcmp(m_config.uid, firmwareOptions.uid, UID_LEN) != 0;
1022 #if defined(PLATFORM_ESP8266)
1023 #define EMPTY_SECTOR ((FS_start - 0x1000 - 0x40200000) / SPI_FLASH_SEC_SIZE) // empty sector before FS area start
1024 static bool erase_power_on_count = false;
1025 static int realPowerOnCounter = -1;
1026 uint8_t
1027 RxConfig::GetPowerOnCounter() const
1029 if (realPowerOnCounter == -1) {
1030 byte zeros[16];
1031 ESP.flashRead(EMPTY_SECTOR * SPI_FLASH_SEC_SIZE, zeros, sizeof(zeros));
1032 realPowerOnCounter = sizeof(zeros);
1033 for (int i=0 ; i<sizeof(zeros) ; i++) {
1034 if (zeros[i] != 0) {
1035 realPowerOnCounter = i;
1036 break;
1040 return realPowerOnCounter;
1042 #endif
1044 void
1045 RxConfig::Commit()
1047 #if defined(PLATFORM_ESP8266)
1048 if (erase_power_on_count)
1050 ESP.flashEraseSector(EMPTY_SECTOR);
1051 erase_power_on_count = false;
1053 #endif
1054 if (!m_modified)
1056 // No changes
1057 return;
1060 // Write the struct to eeprom
1061 m_eeprom->Put(0, m_config);
1062 m_eeprom->Commit();
1064 m_modified = false;
1067 // Setters
1068 void
1069 RxConfig::SetUID(uint8_t* uid)
1071 for (uint8_t i = 0; i < UID_LEN; ++i)
1073 m_config.uid[i] = uid[i];
1075 m_modified = true;
1078 void
1079 RxConfig::SetPowerOnCounter(uint8_t powerOnCounter)
1081 #if defined(PLATFORM_ESP8266)
1082 realPowerOnCounter = powerOnCounter;
1083 if (powerOnCounter == 0)
1085 erase_power_on_count = true;
1086 m_modified = true;
1088 else
1090 byte zeros[16] = {0};
1091 ESP.flashWrite(EMPTY_SECTOR * SPI_FLASH_SEC_SIZE, zeros, std::min((size_t)powerOnCounter, sizeof(zeros)));
1093 #else
1094 if (m_config.powerOnCounter != powerOnCounter)
1096 m_config.powerOnCounter = powerOnCounter;
1097 m_modified = true;
1099 #endif
1102 void
1103 RxConfig::SetModelId(uint8_t modelId)
1105 if (m_config.modelId != modelId)
1107 m_config.modelId = modelId;
1108 m_modified = true;
1112 void
1113 RxConfig::SetPower(uint8_t power)
1115 if (m_config.power != power)
1117 m_config.power = power;
1118 m_modified = true;
1123 void
1124 RxConfig::SetAntennaMode(uint8_t antennaMode)
1126 //0 and 1 is use for gpio_antenna_select
1127 // 2 is diversity
1128 if (m_config.antennaMode != antennaMode)
1130 m_config.antennaMode = antennaMode;
1131 m_modified = true;
1135 void
1136 RxConfig::SetDefaults(bool commit)
1138 // Reset everything to 0/false and then just set anything that zero is not appropriate
1139 memset(&m_config, 0, sizeof(m_config));
1141 m_config.version = RX_CONFIG_VERSION | RX_CONFIG_MAGIC;
1142 m_config.modelId = 0xff;
1143 m_config.power = POWERMGNT::getDefaultPower();
1144 if (GPIO_PIN_ANT_CTRL != UNDEF_PIN)
1145 m_config.antennaMode = 2; // 2 is diversity
1146 if (GPIO_PIN_NSS_2 != UNDEF_PIN)
1147 m_config.antennaMode = 0; // 0 is diversity for dual radio
1149 #if defined(GPIO_PIN_PWM_OUTPUTS)
1150 for (int ch=0; ch<PWM_MAX_CHANNELS; ++ch)
1152 uint8_t mode = som50Hz;
1153 // setup defaults for hardware defined I2C pins that are also IO pins
1154 if (ch < GPIO_PIN_PWM_OUTPUTS_COUNT)
1156 if (GPIO_PIN_PWM_OUTPUTS[ch] == GPIO_PIN_SCL)
1158 mode = somSCL;
1160 else if (GPIO_PIN_PWM_OUTPUTS[ch] == GPIO_PIN_SDA)
1162 mode = somSDA;
1165 SetPwmChannel(ch, 512, ch, false, mode, false);
1167 SetPwmChannel(2, 0, 2, false, 0, false); // ch2 is throttle, failsafe it to 988
1168 #endif
1170 m_config.teamraceChannel = AUX7; // CH11
1172 #if defined(RCVR_INVERT_TX)
1173 m_config.serialProtocol = PROTOCOL_INVERTED_CRSF;
1174 #endif
1176 if (commit)
1178 // Prevent rebinding to the flashed UID on first boot
1179 m_config.flash_discriminator = firmwareOptions.flash_discriminator;
1180 m_modified = true;
1181 Commit();
1185 void
1186 RxConfig::SetStorageProvider(ELRS_EEPROM *eeprom)
1188 if (eeprom)
1190 m_eeprom = eeprom;
1194 #if defined(GPIO_PIN_PWM_OUTPUTS)
1195 void
1196 RxConfig::SetPwmChannel(uint8_t ch, uint16_t failsafe, uint8_t inputCh, bool inverted, uint8_t mode, bool narrow)
1198 if (ch > PWM_MAX_CHANNELS)
1199 return;
1201 rx_config_pwm_t *pwm = &m_config.pwmChannels[ch];
1202 rx_config_pwm_t newConfig;
1203 newConfig.val.failsafe = failsafe;
1204 newConfig.val.inputChannel = inputCh;
1205 newConfig.val.inverted = inverted;
1206 newConfig.val.mode = mode;
1207 newConfig.val.narrow = narrow;
1208 if (pwm->raw == newConfig.raw)
1209 return;
1211 pwm->raw = newConfig.raw;
1212 m_modified = true;
1215 void
1216 RxConfig::SetPwmChannelRaw(uint8_t ch, uint32_t raw)
1218 if (ch > PWM_MAX_CHANNELS)
1219 return;
1221 rx_config_pwm_t *pwm = &m_config.pwmChannels[ch];
1222 if (pwm->raw == raw)
1223 return;
1225 pwm->raw = raw;
1226 m_modified = true;
1228 #endif
1230 void
1231 RxConfig::SetForceTlmOff(bool forceTlmOff)
1233 if (m_config.forceTlmOff != forceTlmOff)
1235 m_config.forceTlmOff = forceTlmOff;
1236 m_modified = true;
1240 void
1241 RxConfig::SetRateInitialIdx(uint8_t rateInitialIdx)
1243 if (m_config.rateInitialIdx != rateInitialIdx)
1245 m_config.rateInitialIdx = rateInitialIdx;
1246 m_modified = true;
1250 void RxConfig::SetSerialProtocol(eSerialProtocol serialProtocol)
1252 if (m_config.serialProtocol != serialProtocol)
1254 m_config.serialProtocol = serialProtocol;
1255 m_modified = true;
1259 #if defined(PLATFORM_ESP32)
1260 void RxConfig::SetSerial1Protocol(eSerial1Protocol serialProtocol)
1262 if (m_config.serial1Protocol != serialProtocol)
1264 m_config.serial1Protocol = serialProtocol;
1265 m_modified = true;
1268 #endif
1270 void RxConfig::SetTeamraceChannel(uint8_t teamraceChannel)
1272 if (m_config.teamraceChannel != teamraceChannel)
1274 m_config.teamraceChannel = teamraceChannel;
1275 m_modified = true;
1279 void RxConfig::SetTeamracePosition(uint8_t teamracePosition)
1281 if (m_config.teamracePosition != teamracePosition)
1283 m_config.teamracePosition = teamracePosition;
1284 m_modified = true;
1288 void RxConfig::SetFailsafeMode(eFailsafeMode failsafeMode)
1290 if (m_config.failsafeMode != failsafeMode)
1292 m_config.failsafeMode = failsafeMode;
1293 m_modified = true;
1297 void RxConfig::SetBindStorage(rx_config_bindstorage_t value)
1299 if (m_config.bindStorage != value)
1301 // If switching away from returnable, revert
1302 ReturnLoan();
1303 m_config.bindStorage = value;
1304 m_modified = true;
1308 void RxConfig::SetTargetSysId(uint8_t value)
1310 if (m_config.targetSysId != value)
1312 m_config.targetSysId = value;
1313 m_modified = true;
1316 void RxConfig::SetSourceSysId(uint8_t value)
1318 if (m_config.sourceSysId != value)
1320 m_config.sourceSysId = value;
1321 m_modified = true;
1325 void RxConfig::ReturnLoan()
1327 if (IsOnLoan())
1329 // go back to flashed UID if there is one
1330 // or unbind if there is not
1331 if (firmwareOptions.hasUID)
1332 memcpy(m_config.uid, firmwareOptions.uid, UID_LEN);
1333 else
1334 memset(m_config.uid, 0, UID_LEN);
1336 m_modified = true;
1340 #endif