Allow LR1121 single RF path (#2998)
[ExpressLRS.git] / src / lib / CONFIG / config.cpp
blob33db6954468c1ceed5362183d5a8104d169a6e00
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 TxConfig::TxConfig() :
102 m_model(m_config.model_config)
106 #if defined(PLATFORM_ESP32)
107 void TxConfig::Load()
109 m_modified = 0;
111 // Initialize NVS
112 esp_err_t err = nvs_flash_init();
113 if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND)
115 ESP_ERROR_CHECK(nvs_flash_erase());
116 err = nvs_flash_init();
118 ESP_ERROR_CHECK( err );
119 ESP_ERROR_CHECK(nvs_open("ELRS", NVS_READWRITE, &handle));
121 // Try to load the version and make sure it is a TX config
122 uint32_t version = 0;
123 if (nvs_get_u32(handle, "tx_version", &version) == ESP_OK && ((version & CONFIG_MAGIC_MASK) == TX_CONFIG_MAGIC))
124 version = version & ~CONFIG_MAGIC_MASK;
125 DBGLN("Config version %u", version);
127 // Can't upgrade from version <5, or when flashing a previous version, just use defaults.
128 if (version < 5 || version > TX_CONFIG_VERSION)
130 SetDefaults(true);
131 return;
134 SetDefaults(false);
136 uint32_t value;
137 uint8_t value8;
138 // vtx (v5)
139 if (nvs_get_u32(handle, "vtx", &value) == ESP_OK)
141 m_config.vtxBand = value >> 24;
142 m_config.vtxChannel = value >> 16;
143 m_config.vtxPower = value >> 8;
144 m_config.vtxPitmode = value;
147 // fanthresh (v5)
148 if (nvs_get_u8(handle, "fanthresh", &value8) == ESP_OK)
149 m_config.powerFanThreshold = value8;
151 // Both of these were added to config v5 without incrementing the version
152 if (nvs_get_u32(handle, "fan", &value) == ESP_OK)
153 m_config.fanMode = value;
154 if (nvs_get_u32(handle, "motion", &value) == ESP_OK)
155 m_config.motionMode = value;
157 if (version >= 6)
159 // dvr (v6)
160 if (nvs_get_u8(handle, "dvraux", &value8) == ESP_OK)
161 m_config.dvrAux = value8;
162 if (nvs_get_u8(handle, "dvrstartdelay", &value8) == ESP_OK)
163 m_config.dvrStartDelay = value8;
164 if (nvs_get_u8(handle, "dvrstopdelay", &value8) == ESP_OK)
165 m_config.dvrStopDelay = value8;
167 else
169 // Need to write the dvr defaults
170 m_modified |= MAIN_CHANGED;
173 if (version >= 7) {
174 // load button actions
175 if (nvs_get_u32(handle, "button1", &value) == ESP_OK)
176 m_config.buttonColors[0].raw = value;
177 if (nvs_get_u32(handle, "button2", &value) == ESP_OK)
178 m_config.buttonColors[1].raw = value;
179 // backpackdisable was actually added after 7, but if not found will default to 0 (enabled)
180 if (nvs_get_u8(handle, "backpackdisable", &value8) == ESP_OK)
181 m_config.backpackDisable = value8;
182 if (nvs_get_u8(handle, "backpacktlmen", &value8) == ESP_OK)
183 m_config.backpackTlmMode = value8;
186 for(unsigned i=0; i<CONFIG_TX_MODEL_CNT; i++)
188 char model[10] = "model";
189 itoa(i, model+5, 10);
190 if (nvs_get_u32(handle, model, &value) == ESP_OK)
192 if (version >= 7)
194 U32_to_Model(value, &m_config.model_config[i]);
196 else
198 // Upgrade v6 to v7 directly writing to nvs instead of calling Commit() over and over
199 v6_model_config_t v6model;
200 U32_to_Model(value, &v6model);
201 model_config_t * const newModel = &m_config.model_config[i];
202 ModelV6toV7(&v6model, newModel);
203 nvs_set_u32(handle, model, Model_to_U32(newModel));
206 } // for each model
208 if (version != TX_CONFIG_VERSION)
210 Commit();
213 #else // STM32/ESP8266
214 void TxConfig::Load()
216 m_modified = 0;
217 m_eeprom->Get(0, m_config);
219 uint32_t version = 0;
220 if ((m_config.version & CONFIG_MAGIC_MASK) == TX_CONFIG_MAGIC)
221 version = m_config.version & ~CONFIG_MAGIC_MASK;
222 DBGLN("Config version %u", version);
224 // If version is current, all done
225 if (version == TX_CONFIG_VERSION)
226 return;
228 // Can't upgrade from version <5, or when flashing a previous version, just use defaults.
229 if (version < 5 || version > TX_CONFIG_VERSION)
231 SetDefaults(true);
232 return;
235 // Upgrade EEPROM, starting with defaults
236 SetDefaults(false);
238 if (version == 5)
240 UpgradeEepromV5ToV6();
241 version = 6;
244 if (version == 6)
246 UpgradeEepromV6ToV7();
250 void TxConfig::UpgradeEepromV5ToV6()
252 v5_tx_config_t v5Config;
253 v6_tx_config_t v6Config = { 0 }; // default the new fields to 0
255 // Populate the prev version struct from eeprom
256 m_eeprom->Get(0, v5Config);
258 // Copy prev values to current config struct
259 // This only workse because v5 and v6 are the same up to the new fields
260 // which have already been set to 0
261 memcpy(&v6Config, &v5Config, sizeof(v5Config));
262 v6Config.version = 6U | TX_CONFIG_MAGIC;
263 m_eeprom->Put(0, v6Config);
264 m_eeprom->Commit();
267 void TxConfig::UpgradeEepromV6ToV7()
269 v6_tx_config_t v6Config;
271 // Populate the prev version struct from eeprom
272 m_eeprom->Get(0, v6Config);
274 // Manual field copying as some fields have moved
275 #define LAZY(member) m_config.member = v6Config.member
276 LAZY(vtxBand);
277 LAZY(vtxChannel);
278 LAZY(vtxPower);
279 LAZY(vtxPitmode);
280 LAZY(powerFanThreshold);
281 LAZY(fanMode);
282 LAZY(motionMode);
283 LAZY(dvrAux);
284 LAZY(dvrStartDelay);
285 LAZY(dvrStopDelay);
286 #undef LAZY
288 for (unsigned i=0; i<CONFIG_TX_MODEL_CNT; i++)
290 ModelV6toV7(&v6Config.model_config[i], &m_config.model_config[i]);
293 m_modified = ALL_CHANGED;
295 // Full Commit now
296 m_config.version = 7U | TX_CONFIG_MAGIC;
297 Commit();
299 #endif
301 void
302 TxConfig::Commit()
304 if (!m_modified)
306 // No changes
307 return;
309 #if defined(PLATFORM_ESP32)
310 // Write parts to NVS
311 if (m_modified & MODEL_CHANGED)
313 uint32_t value = Model_to_U32(m_model);
314 char model[10] = "model";
315 itoa(m_modelId, model+5, 10);
316 nvs_set_u32(handle, model, value);
318 if (m_modified & VTX_CHANGED)
320 uint32_t value =
321 m_config.vtxBand << 24 |
322 m_config.vtxChannel << 16 |
323 m_config.vtxPower << 8 |
324 m_config.vtxPitmode;
325 nvs_set_u32(handle, "vtx", value);
327 if (m_modified & FAN_CHANGED)
329 uint32_t value = m_config.fanMode;
330 nvs_set_u32(handle, "fan", value);
332 if (m_modified & MOTION_CHANGED)
334 uint32_t value = m_config.motionMode;
335 nvs_set_u32(handle, "motion", value);
337 if (m_modified & MAIN_CHANGED)
339 nvs_set_u8(handle, "fanthresh", m_config.powerFanThreshold);
341 nvs_set_u8(handle, "backpackdisable", m_config.backpackDisable);
342 nvs_set_u8(handle, "backpacktlmen", m_config.backpackTlmMode);
343 nvs_set_u8(handle, "dvraux", m_config.dvrAux);
344 nvs_set_u8(handle, "dvrstartdelay", m_config.dvrStartDelay);
345 nvs_set_u8(handle, "dvrstopdelay", m_config.dvrStopDelay);
347 if (m_modified & BUTTON_CHANGED)
349 nvs_set_u32(handle, "button1", m_config.buttonColors[0].raw);
350 nvs_set_u32(handle, "button2", m_config.buttonColors[1].raw);
352 nvs_set_u32(handle, "tx_version", m_config.version);
353 nvs_commit(handle);
354 #else
355 // Write the struct to eeprom
356 m_eeprom->Put(0, m_config);
357 m_eeprom->Commit();
358 #endif
359 m_modified = 0;
362 // Setters
363 void
364 TxConfig::SetRate(uint8_t rate)
366 if (GetRate() != rate)
368 m_model->rate = rate;
369 m_modified |= MODEL_CHANGED;
373 void
374 TxConfig::SetTlm(uint8_t tlm)
376 if (GetTlm() != tlm)
378 m_model->tlm = tlm;
379 m_modified |= MODEL_CHANGED;
383 void
384 TxConfig::SetPower(uint8_t power)
386 if (GetPower() != power)
388 m_model->power = power;
389 m_modified |= MODEL_CHANGED;
393 void
394 TxConfig::SetDynamicPower(bool dynamicPower)
396 if (GetDynamicPower() != dynamicPower)
398 m_model->dynamicPower = dynamicPower;
399 m_modified |= MODEL_CHANGED;
403 void
404 TxConfig::SetBoostChannel(uint8_t boostChannel)
406 if (GetBoostChannel() != boostChannel)
408 m_model->boostChannel = boostChannel;
409 m_modified |= MODEL_CHANGED;
413 void
414 TxConfig::SetSwitchMode(uint8_t switchMode)
416 if (GetSwitchMode() != switchMode)
418 m_model->switchMode = switchMode;
419 m_modified |= MODEL_CHANGED;
423 void
424 TxConfig::SetAntennaMode(uint8_t txAntenna)
426 if (GetAntennaMode() != txAntenna)
428 m_model->txAntenna = txAntenna;
429 m_modified |= MODEL_CHANGED;
433 void
434 TxConfig::SetLinkMode(uint8_t linkMode)
436 if (GetLinkMode() != linkMode)
438 m_model->linkMode = linkMode;
440 if (linkMode == TX_MAVLINK_MODE)
442 m_model->tlm = TLM_RATIO_1_2;
443 m_model->switchMode = smHybridOr16ch; // Force Hybrid / 16ch/2 switch modes for mavlink
445 m_modified |= MODEL_CHANGED | MAIN_CHANGED;
449 void
450 TxConfig::SetModelMatch(bool modelMatch)
452 if (GetModelMatch() != modelMatch)
454 m_model->modelMatch = modelMatch;
455 m_modified |= MODEL_CHANGED;
459 void
460 TxConfig::SetVtxBand(uint8_t vtxBand)
462 if (m_config.vtxBand != vtxBand)
464 m_config.vtxBand = vtxBand;
465 m_modified |= VTX_CHANGED;
469 void
470 TxConfig::SetVtxChannel(uint8_t vtxChannel)
472 if (m_config.vtxChannel != vtxChannel)
474 m_config.vtxChannel = vtxChannel;
475 m_modified |= VTX_CHANGED;
479 void
480 TxConfig::SetVtxPower(uint8_t vtxPower)
482 if (m_config.vtxPower != vtxPower)
484 m_config.vtxPower = vtxPower;
485 m_modified |= VTX_CHANGED;
489 void
490 TxConfig::SetVtxPitmode(uint8_t vtxPitmode)
492 if (m_config.vtxPitmode != vtxPitmode)
494 m_config.vtxPitmode = vtxPitmode;
495 m_modified |= VTX_CHANGED;
499 void
500 TxConfig::SetPowerFanThreshold(uint8_t powerFanThreshold)
502 if (m_config.powerFanThreshold != powerFanThreshold)
504 m_config.powerFanThreshold = powerFanThreshold;
505 m_modified |= MAIN_CHANGED;
509 void
510 TxConfig::SetStorageProvider(ELRS_EEPROM *eeprom)
512 if (eeprom)
514 m_eeprom = eeprom;
518 void
519 TxConfig::SetFanMode(uint8_t fanMode)
521 if (m_config.fanMode != fanMode)
523 m_config.fanMode = fanMode;
524 m_modified |= FAN_CHANGED;
528 void
529 TxConfig::SetMotionMode(uint8_t motionMode)
531 if (m_config.motionMode != motionMode)
533 m_config.motionMode = motionMode;
534 m_modified |= MOTION_CHANGED;
538 void
539 TxConfig::SetDvrAux(uint8_t dvrAux)
541 if (GetDvrAux() != dvrAux)
543 m_config.dvrAux = dvrAux;
544 m_modified |= MAIN_CHANGED;
548 void
549 TxConfig::SetDvrStartDelay(uint8_t dvrStartDelay)
551 if (GetDvrStartDelay() != dvrStartDelay)
553 m_config.dvrStartDelay = dvrStartDelay;
554 m_modified |= MAIN_CHANGED;
558 void
559 TxConfig::SetDvrStopDelay(uint8_t dvrStopDelay)
561 if (GetDvrStopDelay() != dvrStopDelay)
563 m_config.dvrStopDelay = dvrStopDelay;
564 m_modified |= MAIN_CHANGED;
568 void
569 TxConfig::SetBackpackDisable(bool backpackDisable)
571 if (m_config.backpackDisable != backpackDisable)
573 m_config.backpackDisable = backpackDisable;
574 m_modified |= MAIN_CHANGED;
578 void
579 TxConfig::SetBackpackTlmMode(uint8_t mode)
581 if (m_config.backpackTlmMode != mode)
583 m_config.backpackTlmMode = mode;
584 m_modified |= MAIN_CHANGED;
588 void
589 TxConfig::SetButtonActions(uint8_t button, tx_button_color_t *action)
591 if (m_config.buttonColors[button].raw != action->raw) {
592 m_config.buttonColors[button].raw = action->raw;
593 m_modified |= BUTTON_CHANGED;
597 void
598 TxConfig::SetPTRStartChannel(uint8_t ptrStartChannel)
600 if (ptrStartChannel != m_model->ptrStartChannel) {
601 m_model->ptrStartChannel = ptrStartChannel;
602 m_modified |= MODEL_CHANGED;
606 void
607 TxConfig::SetPTREnableChannel(uint8_t ptrEnableChannel)
609 if (ptrEnableChannel != m_model->ptrEnableChannel) {
610 m_model->ptrEnableChannel = ptrEnableChannel;
611 m_modified |= MODEL_CHANGED;
615 void
616 TxConfig::SetDefaults(bool commit)
618 // Reset everything to 0/false and then just set anything that zero is not appropriate
619 memset(&m_config, 0, sizeof(m_config));
621 m_config.version = TX_CONFIG_VERSION | TX_CONFIG_MAGIC;
622 m_config.powerFanThreshold = PWR_250mW;
623 m_modified = ALL_CHANGED;
625 if (commit)
627 m_modified = ALL_CHANGED;
630 // Set defaults for button 1
631 tx_button_color_t default_actions1 = {
632 .val = {
633 .color = 226, // R:255 G:0 B:182
634 .actions = {
635 {false, 2, ACTION_BIND},
636 {true, 0, ACTION_INCREASE_POWER}
640 m_config.buttonColors[0].raw = default_actions1.raw;
642 // Set defaults for button 2
643 tx_button_color_t default_actions2 = {
644 .val = {
645 .color = 3, // R:0 G:0 B:255
646 .actions = {
647 {false, 1, ACTION_GOTO_VTX_CHANNEL},
648 {true, 0, ACTION_SEND_VTX}
652 m_config.buttonColors[1].raw = default_actions2.raw;
654 for (unsigned i=0; i<CONFIG_TX_MODEL_CNT; i++)
656 SetModelId(i);
657 #if defined(RADIO_SX127X)
658 SetRate(enumRatetoIndex(RATE_LORA_200HZ));
659 #elif defined(RADIO_LR1121)
660 SetRate(enumRatetoIndex(POWER_OUTPUT_VALUES_COUNT == 0 ? RATE_LORA_250HZ : RATE_LORA_200HZ));
661 #elif defined(RADIO_SX128X)
662 SetRate(enumRatetoIndex(RATE_LORA_250HZ));
663 #endif
664 SetPower(POWERMGNT::getDefaultPower());
665 #if defined(PLATFORM_ESP32)
666 // ESP32 nvs needs to commit every model
667 if (commit)
669 m_modified |= MODEL_CHANGED;
670 Commit();
672 #endif
675 #if !defined(PLATFORM_ESP32)
676 // STM32/ESP8266 just needs one commit
677 if (commit)
679 Commit();
681 #endif
683 SetModelId(0);
684 m_modified = 0;
688 * Sets ModelId used for subsequent per-model config gets
689 * Returns: true if the model has changed
691 bool
692 TxConfig::SetModelId(uint8_t modelId)
694 model_config_t *newModel = &m_config.model_config[modelId];
695 if (newModel != m_model)
697 m_model = newModel;
698 m_modelId = modelId;
699 return true;
702 return false;
704 #endif
706 /////////////////////////////////////////////////////
708 #if defined(TARGET_RX)
710 #if defined(PLATFORM_ESP8266)
711 #include "flash_hal.h"
712 #endif
714 RxConfig::RxConfig()
718 void RxConfig::Load()
720 m_modified = false;
721 m_eeprom->Get(0, m_config);
723 uint32_t version = 0;
724 if ((m_config.version & CONFIG_MAGIC_MASK) == RX_CONFIG_MAGIC)
725 version = m_config.version & ~CONFIG_MAGIC_MASK;
726 DBGLN("Config version %u", version);
728 // If version is current, all done
729 if (version == RX_CONFIG_VERSION)
731 CheckUpdateFlashedUid(false);
732 return;
735 // Can't upgrade from version <4, or when flashing a previous version, just use defaults.
736 if (version < 4 || version > RX_CONFIG_VERSION)
738 SetDefaults(true);
739 CheckUpdateFlashedUid(true);
740 return;
743 // Upgrade EEPROM, starting with defaults
744 SetDefaults(false);
745 UpgradeEepromV4();
746 UpgradeEepromV5();
747 UpgradeEepromV6();
748 UpgradeEepromV7V8();
749 m_config.version = RX_CONFIG_VERSION | RX_CONFIG_MAGIC;
750 m_modified = true;
751 Commit();
754 void RxConfig::CheckUpdateFlashedUid(bool skipDescrimCheck)
756 // No binding phrase flashed, nothing to do
757 if (!firmwareOptions.hasUID)
758 return;
759 // If already copied binding info, do not replace
760 if (!skipDescrimCheck && m_config.flash_discriminator == firmwareOptions.flash_discriminator)
761 return;
763 // Save the new UID along with this discriminator to prevent resetting every boot
764 SetUID(firmwareOptions.uid);
765 m_config.flash_discriminator = firmwareOptions.flash_discriminator;
766 // Reset the power on counter because this is following a flash, may have taken a few boots to flash
767 m_config.powerOnCounter = 0;
768 // SetUID should set this but just in case that gets removed, flash_discriminator needs to be saved
769 m_modified = true;
771 Commit();
774 // ========================================================
775 // V4 Upgrade
777 static void PwmConfigV4(v4_rx_config_pwm_t const * const v4, rx_config_pwm_t * const current)
779 current->val.failsafe = v4->val.failsafe;
780 current->val.inputChannel = v4->val.inputChannel;
781 current->val.inverted = v4->val.inverted;
784 void RxConfig::UpgradeEepromV4()
786 v4_rx_config_t v4Config;
787 m_eeprom->Get(0, v4Config);
789 if ((v4Config.version & ~CONFIG_MAGIC_MASK) == 4)
791 UpgradeUid(nullptr, v4Config.isBound ? v4Config.uid : nullptr);
792 m_config.modelId = v4Config.modelId;
793 #if defined(GPIO_PIN_PWM_OUTPUTS)
794 // OG PWMP had only 8 channels
795 for (unsigned ch=0; ch<8; ++ch)
797 PwmConfigV4(&v4Config.pwmChannels[ch], &m_config.pwmChannels[ch]);
799 #endif
803 // ========================================================
804 // V5 Upgrade
806 static void PwmConfigV5(v5_rx_config_pwm_t const * const v5, rx_config_pwm_t * const current)
808 current->val.failsafe = v5->val.failsafe;
809 current->val.inputChannel = v5->val.inputChannel;
810 current->val.inverted = v5->val.inverted;
811 current->val.narrow = v5->val.narrow;
812 current->val.mode = v5->val.mode;
813 if (v5->val.mode > som400Hz)
815 current->val.mode += 1;
819 void RxConfig::UpgradeEepromV5()
821 v5_rx_config_t v5Config;
822 m_eeprom->Get(0, v5Config);
824 if ((v5Config.version & ~CONFIG_MAGIC_MASK) == 5)
826 UpgradeUid(v5Config.onLoan ? v5Config.loanUID : nullptr, v5Config.isBound ? v5Config.uid : nullptr);
827 m_config.vbat.scale = v5Config.vbatScale;
828 m_config.power = v5Config.power;
829 m_config.antennaMode = v5Config.antennaMode;
830 m_config.forceTlmOff = v5Config.forceTlmOff;
831 m_config.rateInitialIdx = v5Config.rateInitialIdx;
832 m_config.modelId = v5Config.modelId;
834 #if defined(GPIO_PIN_PWM_OUTPUTS)
835 for (unsigned ch=0; ch<16; ++ch)
837 PwmConfigV5(&v5Config.pwmChannels[ch], &m_config.pwmChannels[ch]);
839 #endif
843 // ========================================================
844 // V6 Upgrade
846 static void PwmConfigV6(v6_rx_config_pwm_t const * const v6, rx_config_pwm_t * const current)
848 current->val.failsafe = v6->val.failsafe;
849 current->val.inputChannel = v6->val.inputChannel;
850 current->val.inverted = v6->val.inverted;
851 current->val.narrow = v6->val.narrow;
852 current->val.mode = v6->val.mode;
855 void RxConfig::UpgradeEepromV6()
857 v6_rx_config_t v6Config;
858 m_eeprom->Get(0, v6Config);
860 if ((v6Config.version & ~CONFIG_MAGIC_MASK) == 6)
862 UpgradeUid(v6Config.onLoan ? v6Config.loanUID : nullptr, v6Config.isBound ? v6Config.uid : nullptr);
863 m_config.vbat.scale = v6Config.vbatScale;
864 m_config.power = v6Config.power;
865 m_config.antennaMode = v6Config.antennaMode;
866 m_config.forceTlmOff = v6Config.forceTlmOff;
867 m_config.rateInitialIdx = v6Config.rateInitialIdx;
868 m_config.modelId = v6Config.modelId;
870 #if defined(GPIO_PIN_PWM_OUTPUTS)
871 for (unsigned ch=0; ch<16; ++ch)
873 PwmConfigV6(&v6Config.pwmChannels[ch], &m_config.pwmChannels[ch]);
875 #endif
879 // ========================================================
880 // V7/V8 Upgrade
882 void RxConfig::UpgradeEepromV7V8()
884 v7_rx_config_t v7Config;
885 m_eeprom->Get(0, v7Config);
887 bool isV8 = (v7Config.version & ~CONFIG_MAGIC_MASK) == 8;
888 if (isV8 || (v7Config.version & ~CONFIG_MAGIC_MASK) == 7)
890 UpgradeUid(v7Config.onLoan ? v7Config.loanUID : nullptr, v7Config.isBound ? v7Config.uid : nullptr);
892 m_config.vbat.scale = v7Config.vbatScale;
893 m_config.power = v7Config.power;
894 m_config.antennaMode = v7Config.antennaMode;
895 m_config.forceTlmOff = v7Config.forceTlmOff;
896 m_config.rateInitialIdx = v7Config.rateInitialIdx;
897 m_config.modelId = v7Config.modelId;
898 m_config.serialProtocol = v7Config.serialProtocol;
899 m_config.failsafeMode = v7Config.failsafeMode;
901 #if defined(GPIO_PIN_PWM_OUTPUTS)
902 for (unsigned ch=0; ch<16; ++ch)
904 m_config.pwmChannels[ch].raw = v7Config.pwmChannels[ch].raw;
905 if (!isV8 && m_config.pwmChannels[ch].val.mode > somOnOff)
906 m_config.pwmChannels[ch].val.mode += 1;
908 #endif
912 void RxConfig::UpgradeUid(uint8_t *onLoanUid, uint8_t *boundUid)
914 // Convert to traditional binding
915 // On loan? Now you own
916 if (onLoanUid)
918 memcpy(m_config.uid, onLoanUid, UID_LEN);
920 // Compiled in UID? Bind to that
921 else if (firmwareOptions.hasUID)
923 memcpy(m_config.uid, firmwareOptions.uid, UID_LEN);
924 m_config.flash_discriminator = firmwareOptions.flash_discriminator;
926 else if (boundUid)
928 // keep binding
929 memcpy(m_config.uid, boundUid, UID_LEN);
931 else
933 // No bind
934 memset(m_config.uid, 0, UID_LEN);
938 bool RxConfig::GetIsBound() const
940 if (m_config.bindStorage == BINDSTORAGE_VOLATILE)
941 return false;
942 return UID_IS_BOUND(m_config.uid);
945 bool RxConfig::IsOnLoan() const
947 if (m_config.bindStorage != BINDSTORAGE_RETURNABLE)
948 return false;
949 if (!firmwareOptions.hasUID)
950 return false;
951 return GetIsBound() && memcmp(m_config.uid, firmwareOptions.uid, UID_LEN) != 0;
954 #if defined(PLATFORM_ESP8266)
955 #define EMPTY_SECTOR ((FS_start - 0x1000 - 0x40200000) / SPI_FLASH_SEC_SIZE) // empty sector before FS area start
956 static bool erase_power_on_count = false;
957 static int realPowerOnCounter = -1;
958 uint8_t
959 RxConfig::GetPowerOnCounter() const
961 if (realPowerOnCounter == -1) {
962 byte zeros[16];
963 ESP.flashRead(EMPTY_SECTOR * SPI_FLASH_SEC_SIZE, zeros, sizeof(zeros));
964 realPowerOnCounter = sizeof(zeros);
965 for (int i=0 ; i<sizeof(zeros) ; i++) {
966 if (zeros[i] != 0) {
967 realPowerOnCounter = i;
968 break;
972 return realPowerOnCounter;
974 #endif
976 void
977 RxConfig::Commit()
979 #if defined(PLATFORM_ESP8266)
980 if (erase_power_on_count)
982 ESP.flashEraseSector(EMPTY_SECTOR);
983 erase_power_on_count = false;
985 #endif
986 if (!m_modified)
988 // No changes
989 return;
992 // Write the struct to eeprom
993 m_eeprom->Put(0, m_config);
994 m_eeprom->Commit();
996 m_modified = false;
999 // Setters
1000 void
1001 RxConfig::SetUID(uint8_t* uid)
1003 for (uint8_t i = 0; i < UID_LEN; ++i)
1005 m_config.uid[i] = uid[i];
1007 m_modified = true;
1010 void
1011 RxConfig::SetPowerOnCounter(uint8_t powerOnCounter)
1013 #if defined(PLATFORM_ESP8266)
1014 realPowerOnCounter = powerOnCounter;
1015 if (powerOnCounter == 0)
1017 erase_power_on_count = true;
1018 m_modified = true;
1020 else
1022 byte zeros[16] = {0};
1023 ESP.flashWrite(EMPTY_SECTOR * SPI_FLASH_SEC_SIZE, zeros, std::min((size_t)powerOnCounter, sizeof(zeros)));
1025 #else
1026 if (m_config.powerOnCounter != powerOnCounter)
1028 m_config.powerOnCounter = powerOnCounter;
1029 m_modified = true;
1031 #endif
1034 void
1035 RxConfig::SetModelId(uint8_t modelId)
1037 if (m_config.modelId != modelId)
1039 m_config.modelId = modelId;
1040 m_modified = true;
1044 void
1045 RxConfig::SetPower(uint8_t power)
1047 if (m_config.power != power)
1049 m_config.power = power;
1050 m_modified = true;
1055 void
1056 RxConfig::SetAntennaMode(uint8_t antennaMode)
1058 //0 and 1 is use for gpio_antenna_select
1059 // 2 is diversity
1060 if (m_config.antennaMode != antennaMode)
1062 m_config.antennaMode = antennaMode;
1063 m_modified = true;
1067 void
1068 RxConfig::SetDefaults(bool commit)
1070 // Reset everything to 0/false and then just set anything that zero is not appropriate
1071 memset(&m_config, 0, sizeof(m_config));
1073 m_config.version = RX_CONFIG_VERSION | RX_CONFIG_MAGIC;
1074 m_config.modelId = 0xff;
1075 m_config.power = POWERMGNT::getDefaultPower();
1076 if (GPIO_PIN_ANT_CTRL != UNDEF_PIN)
1077 m_config.antennaMode = 2; // 2 is diversity
1078 if (GPIO_PIN_NSS_2 != UNDEF_PIN)
1079 m_config.antennaMode = 0; // 0 is diversity for dual radio
1081 #if defined(GPIO_PIN_PWM_OUTPUTS)
1082 for (int ch=0; ch<PWM_MAX_CHANNELS; ++ch)
1084 uint8_t mode = som50Hz;
1085 // setup defaults for hardware defined I2C pins that are also IO pins
1086 if (ch < GPIO_PIN_PWM_OUTPUTS_COUNT)
1088 if (GPIO_PIN_PWM_OUTPUTS[ch] == GPIO_PIN_SCL)
1090 mode = somSCL;
1092 else if (GPIO_PIN_PWM_OUTPUTS[ch] == GPIO_PIN_SDA)
1094 mode = somSDA;
1097 SetPwmChannel(ch, 512, ch, false, mode, false);
1099 SetPwmChannel(2, 0, 2, false, 0, false); // ch2 is throttle, failsafe it to 988
1100 #endif
1102 m_config.teamraceChannel = AUX7; // CH11
1104 #if defined(RCVR_INVERT_TX)
1105 m_config.serialProtocol = PROTOCOL_INVERTED_CRSF;
1106 #endif
1108 if (commit)
1110 // Prevent rebinding to the flashed UID on first boot
1111 m_config.flash_discriminator = firmwareOptions.flash_discriminator;
1112 m_modified = true;
1113 Commit();
1117 void
1118 RxConfig::SetStorageProvider(ELRS_EEPROM *eeprom)
1120 if (eeprom)
1122 m_eeprom = eeprom;
1126 #if defined(GPIO_PIN_PWM_OUTPUTS)
1127 void
1128 RxConfig::SetPwmChannel(uint8_t ch, uint16_t failsafe, uint8_t inputCh, bool inverted, uint8_t mode, bool narrow)
1130 if (ch > PWM_MAX_CHANNELS)
1131 return;
1133 rx_config_pwm_t *pwm = &m_config.pwmChannels[ch];
1134 rx_config_pwm_t newConfig;
1135 newConfig.val.failsafe = failsafe;
1136 newConfig.val.inputChannel = inputCh;
1137 newConfig.val.inverted = inverted;
1138 newConfig.val.mode = mode;
1139 newConfig.val.narrow = narrow;
1140 if (pwm->raw == newConfig.raw)
1141 return;
1143 pwm->raw = newConfig.raw;
1144 m_modified = true;
1147 void
1148 RxConfig::SetPwmChannelRaw(uint8_t ch, uint32_t raw)
1150 if (ch > PWM_MAX_CHANNELS)
1151 return;
1153 rx_config_pwm_t *pwm = &m_config.pwmChannels[ch];
1154 if (pwm->raw == raw)
1155 return;
1157 pwm->raw = raw;
1158 m_modified = true;
1160 #endif
1162 void
1163 RxConfig::SetForceTlmOff(bool forceTlmOff)
1165 if (m_config.forceTlmOff != forceTlmOff)
1167 m_config.forceTlmOff = forceTlmOff;
1168 m_modified = true;
1172 void
1173 RxConfig::SetRateInitialIdx(uint8_t rateInitialIdx)
1175 if (m_config.rateInitialIdx != rateInitialIdx)
1177 m_config.rateInitialIdx = rateInitialIdx;
1178 m_modified = true;
1182 void RxConfig::SetSerialProtocol(eSerialProtocol serialProtocol)
1184 if (m_config.serialProtocol != serialProtocol)
1186 m_config.serialProtocol = serialProtocol;
1187 m_modified = true;
1191 #if defined(PLATFORM_ESP32)
1192 void RxConfig::SetSerial1Protocol(eSerial1Protocol serialProtocol)
1194 if (m_config.serial1Protocol != serialProtocol)
1196 m_config.serial1Protocol = serialProtocol;
1197 m_modified = true;
1200 #endif
1202 void RxConfig::SetTeamraceChannel(uint8_t teamraceChannel)
1204 if (m_config.teamraceChannel != teamraceChannel)
1206 m_config.teamraceChannel = teamraceChannel;
1207 m_modified = true;
1211 void RxConfig::SetTeamracePosition(uint8_t teamracePosition)
1213 if (m_config.teamracePosition != teamracePosition)
1215 m_config.teamracePosition = teamracePosition;
1216 m_modified = true;
1220 void RxConfig::SetFailsafeMode(eFailsafeMode failsafeMode)
1222 if (m_config.failsafeMode != failsafeMode)
1224 m_config.failsafeMode = failsafeMode;
1225 m_modified = true;
1229 void RxConfig::SetBindStorage(rx_config_bindstorage_t value)
1231 if (m_config.bindStorage != value)
1233 // If switching away from returnable, revert
1234 ReturnLoan();
1235 m_config.bindStorage = value;
1236 m_modified = true;
1240 void RxConfig::SetTargetSysId(uint8_t value)
1242 if (m_config.targetSysId != value)
1244 m_config.targetSysId = value;
1245 m_modified = true;
1248 void RxConfig::SetSourceSysId(uint8_t value)
1250 if (m_config.sourceSysId != value)
1252 m_config.sourceSysId = value;
1253 m_modified = true;
1257 void RxConfig::ReturnLoan()
1259 if (IsOnLoan())
1261 // go back to flashed UID if there is one
1262 // or unbind if there is not
1263 if (firmwareOptions.hasUID)
1264 memcpy(m_config.uid, firmwareOptions.uid, UID_LEN);
1265 else
1266 memset(m_config.uid, 0, UID_LEN);
1268 m_modified = true;
1272 #endif