Extend Backpack telemetry forwarding options (#2885)
[ExpressLRS.git] / src / lib / CONFIG / config.cpp
bloba33916327bdb6945a450dc3097dd29db422efeb9
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) || defined(RADIO_LR1121)
658 SetRate(enumRatetoIndex(RATE_LORA_200HZ));
659 #elif defined(RADIO_SX128X)
660 SetRate(enumRatetoIndex(RATE_LORA_250HZ));
661 #endif
662 SetPower(POWERMGNT::getDefaultPower());
663 #if defined(PLATFORM_ESP32)
664 // ESP32 nvs needs to commit every model
665 if (commit)
667 m_modified |= MODEL_CHANGED;
668 Commit();
670 #endif
673 #if !defined(PLATFORM_ESP32)
674 // STM32/ESP8266 just needs one commit
675 if (commit)
677 Commit();
679 #endif
681 SetModelId(0);
682 m_modified = 0;
686 * Sets ModelId used for subsequent per-model config gets
687 * Returns: true if the model has changed
689 bool
690 TxConfig::SetModelId(uint8_t modelId)
692 model_config_t *newModel = &m_config.model_config[modelId];
693 if (newModel != m_model)
695 m_model = newModel;
696 m_modelId = modelId;
697 return true;
700 return false;
702 #endif
704 /////////////////////////////////////////////////////
706 #if defined(TARGET_RX)
708 #if defined(PLATFORM_ESP8266)
709 #include "flash_hal.h"
710 #endif
712 RxConfig::RxConfig()
716 void RxConfig::Load()
718 m_modified = false;
719 m_eeprom->Get(0, m_config);
721 uint32_t version = 0;
722 if ((m_config.version & CONFIG_MAGIC_MASK) == RX_CONFIG_MAGIC)
723 version = m_config.version & ~CONFIG_MAGIC_MASK;
724 DBGLN("Config version %u", version);
726 // If version is current, all done
727 if (version == RX_CONFIG_VERSION)
729 CheckUpdateFlashedUid(false);
730 return;
733 // Can't upgrade from version <4, or when flashing a previous version, just use defaults.
734 if (version < 4 || version > RX_CONFIG_VERSION)
736 SetDefaults(true);
737 CheckUpdateFlashedUid(true);
738 return;
741 // Upgrade EEPROM, starting with defaults
742 SetDefaults(false);
743 UpgradeEepromV4();
744 UpgradeEepromV5();
745 UpgradeEepromV6();
746 UpgradeEepromV7V8();
747 m_config.version = RX_CONFIG_VERSION | RX_CONFIG_MAGIC;
748 m_modified = true;
749 Commit();
752 void RxConfig::CheckUpdateFlashedUid(bool skipDescrimCheck)
754 // No binding phrase flashed, nothing to do
755 if (!firmwareOptions.hasUID)
756 return;
757 // If already copied binding info, do not replace
758 if (!skipDescrimCheck && m_config.flash_discriminator == firmwareOptions.flash_discriminator)
759 return;
761 // Save the new UID along with this discriminator to prevent resetting every boot
762 SetUID(firmwareOptions.uid);
763 m_config.flash_discriminator = firmwareOptions.flash_discriminator;
764 // Reset the power on counter because this is following a flash, may have taken a few boots to flash
765 m_config.powerOnCounter = 0;
766 // SetUID should set this but just in case that gets removed, flash_discriminator needs to be saved
767 m_modified = true;
769 Commit();
772 // ========================================================
773 // V4 Upgrade
775 static void PwmConfigV4(v4_rx_config_pwm_t const * const v4, rx_config_pwm_t * const current)
777 current->val.failsafe = v4->val.failsafe;
778 current->val.inputChannel = v4->val.inputChannel;
779 current->val.inverted = v4->val.inverted;
782 void RxConfig::UpgradeEepromV4()
784 v4_rx_config_t v4Config;
785 m_eeprom->Get(0, v4Config);
787 if ((v4Config.version & ~CONFIG_MAGIC_MASK) == 4)
789 UpgradeUid(nullptr, v4Config.isBound ? v4Config.uid : nullptr);
790 m_config.modelId = v4Config.modelId;
791 #if defined(GPIO_PIN_PWM_OUTPUTS)
792 // OG PWMP had only 8 channels
793 for (unsigned ch=0; ch<8; ++ch)
795 PwmConfigV4(&v4Config.pwmChannels[ch], &m_config.pwmChannels[ch]);
797 #endif
801 // ========================================================
802 // V5 Upgrade
804 static void PwmConfigV5(v5_rx_config_pwm_t const * const v5, rx_config_pwm_t * const current)
806 current->val.failsafe = v5->val.failsafe;
807 current->val.inputChannel = v5->val.inputChannel;
808 current->val.inverted = v5->val.inverted;
809 current->val.narrow = v5->val.narrow;
810 current->val.mode = v5->val.mode;
811 if (v5->val.mode > som400Hz)
813 current->val.mode += 1;
817 void RxConfig::UpgradeEepromV5()
819 v5_rx_config_t v5Config;
820 m_eeprom->Get(0, v5Config);
822 if ((v5Config.version & ~CONFIG_MAGIC_MASK) == 5)
824 UpgradeUid(v5Config.onLoan ? v5Config.loanUID : nullptr, v5Config.isBound ? v5Config.uid : nullptr);
825 m_config.vbat.scale = v5Config.vbatScale;
826 m_config.power = v5Config.power;
827 m_config.antennaMode = v5Config.antennaMode;
828 m_config.forceTlmOff = v5Config.forceTlmOff;
829 m_config.rateInitialIdx = v5Config.rateInitialIdx;
830 m_config.modelId = v5Config.modelId;
832 #if defined(GPIO_PIN_PWM_OUTPUTS)
833 for (unsigned ch=0; ch<16; ++ch)
835 PwmConfigV5(&v5Config.pwmChannels[ch], &m_config.pwmChannels[ch]);
837 #endif
841 // ========================================================
842 // V6 Upgrade
844 static void PwmConfigV6(v6_rx_config_pwm_t const * const v6, rx_config_pwm_t * const current)
846 current->val.failsafe = v6->val.failsafe;
847 current->val.inputChannel = v6->val.inputChannel;
848 current->val.inverted = v6->val.inverted;
849 current->val.narrow = v6->val.narrow;
850 current->val.mode = v6->val.mode;
853 void RxConfig::UpgradeEepromV6()
855 v6_rx_config_t v6Config;
856 m_eeprom->Get(0, v6Config);
858 if ((v6Config.version & ~CONFIG_MAGIC_MASK) == 6)
860 UpgradeUid(v6Config.onLoan ? v6Config.loanUID : nullptr, v6Config.isBound ? v6Config.uid : nullptr);
861 m_config.vbat.scale = v6Config.vbatScale;
862 m_config.power = v6Config.power;
863 m_config.antennaMode = v6Config.antennaMode;
864 m_config.forceTlmOff = v6Config.forceTlmOff;
865 m_config.rateInitialIdx = v6Config.rateInitialIdx;
866 m_config.modelId = v6Config.modelId;
868 #if defined(GPIO_PIN_PWM_OUTPUTS)
869 for (unsigned ch=0; ch<16; ++ch)
871 PwmConfigV6(&v6Config.pwmChannels[ch], &m_config.pwmChannels[ch]);
873 #endif
877 // ========================================================
878 // V7/V8 Upgrade
880 void RxConfig::UpgradeEepromV7V8()
882 v7_rx_config_t v7Config;
883 m_eeprom->Get(0, v7Config);
885 bool isV8 = (v7Config.version & ~CONFIG_MAGIC_MASK) == 8;
886 if (isV8 || (v7Config.version & ~CONFIG_MAGIC_MASK) == 7)
888 UpgradeUid(v7Config.onLoan ? v7Config.loanUID : nullptr, v7Config.isBound ? v7Config.uid : nullptr);
890 m_config.vbat.scale = v7Config.vbatScale;
891 m_config.power = v7Config.power;
892 m_config.antennaMode = v7Config.antennaMode;
893 m_config.forceTlmOff = v7Config.forceTlmOff;
894 m_config.rateInitialIdx = v7Config.rateInitialIdx;
895 m_config.modelId = v7Config.modelId;
896 m_config.serialProtocol = v7Config.serialProtocol;
897 m_config.failsafeMode = v7Config.failsafeMode;
899 #if defined(GPIO_PIN_PWM_OUTPUTS)
900 for (unsigned ch=0; ch<16; ++ch)
902 m_config.pwmChannels[ch].raw = v7Config.pwmChannels[ch].raw;
903 if (!isV8 && m_config.pwmChannels[ch].val.mode > somOnOff)
904 m_config.pwmChannels[ch].val.mode += 1;
906 #endif
910 void RxConfig::UpgradeUid(uint8_t *onLoanUid, uint8_t *boundUid)
912 // Convert to traditional binding
913 // On loan? Now you own
914 if (onLoanUid)
916 memcpy(m_config.uid, onLoanUid, UID_LEN);
918 // Compiled in UID? Bind to that
919 else if (firmwareOptions.hasUID)
921 memcpy(m_config.uid, firmwareOptions.uid, UID_LEN);
922 m_config.flash_discriminator = firmwareOptions.flash_discriminator;
924 else if (boundUid)
926 // keep binding
927 memcpy(m_config.uid, boundUid, UID_LEN);
929 else
931 // No bind
932 memset(m_config.uid, 0, UID_LEN);
936 bool RxConfig::GetIsBound() const
938 if (m_config.bindStorage == BINDSTORAGE_VOLATILE)
939 return false;
940 return UID_IS_BOUND(m_config.uid);
943 bool RxConfig::IsOnLoan() const
945 if (m_config.bindStorage != BINDSTORAGE_RETURNABLE)
946 return false;
947 if (!firmwareOptions.hasUID)
948 return false;
949 return GetIsBound() && memcmp(m_config.uid, firmwareOptions.uid, UID_LEN) != 0;
952 #if defined(PLATFORM_ESP8266)
953 #define EMPTY_SECTOR ((FS_start - 0x1000 - 0x40200000) / SPI_FLASH_SEC_SIZE) // empty sector before FS area start
954 static bool erase_power_on_count = false;
955 static int realPowerOnCounter = -1;
956 uint8_t
957 RxConfig::GetPowerOnCounter() const
959 if (realPowerOnCounter == -1) {
960 byte zeros[16];
961 ESP.flashRead(EMPTY_SECTOR * SPI_FLASH_SEC_SIZE, zeros, sizeof(zeros));
962 realPowerOnCounter = sizeof(zeros);
963 for (int i=0 ; i<sizeof(zeros) ; i++) {
964 if (zeros[i] != 0) {
965 realPowerOnCounter = i;
966 break;
970 return realPowerOnCounter;
972 #endif
974 void
975 RxConfig::Commit()
977 #if defined(PLATFORM_ESP8266)
978 if (erase_power_on_count)
980 ESP.flashEraseSector(EMPTY_SECTOR);
981 erase_power_on_count = false;
983 #endif
984 if (!m_modified)
986 // No changes
987 return;
990 // Write the struct to eeprom
991 m_eeprom->Put(0, m_config);
992 m_eeprom->Commit();
994 m_modified = false;
997 // Setters
998 void
999 RxConfig::SetUID(uint8_t* uid)
1001 for (uint8_t i = 0; i < UID_LEN; ++i)
1003 m_config.uid[i] = uid[i];
1005 m_modified = true;
1008 void
1009 RxConfig::SetPowerOnCounter(uint8_t powerOnCounter)
1011 #if defined(PLATFORM_ESP8266)
1012 realPowerOnCounter = powerOnCounter;
1013 if (powerOnCounter == 0)
1015 erase_power_on_count = true;
1016 m_modified = true;
1018 else
1020 byte zeros[16] = {0};
1021 ESP.flashWrite(EMPTY_SECTOR * SPI_FLASH_SEC_SIZE, zeros, std::min((size_t)powerOnCounter, sizeof(zeros)));
1023 #else
1024 if (m_config.powerOnCounter != powerOnCounter)
1026 m_config.powerOnCounter = powerOnCounter;
1027 m_modified = true;
1029 #endif
1032 void
1033 RxConfig::SetModelId(uint8_t modelId)
1035 if (m_config.modelId != modelId)
1037 m_config.modelId = modelId;
1038 m_modified = true;
1042 void
1043 RxConfig::SetPower(uint8_t power)
1045 if (m_config.power != power)
1047 m_config.power = power;
1048 m_modified = true;
1053 void
1054 RxConfig::SetAntennaMode(uint8_t antennaMode)
1056 //0 and 1 is use for gpio_antenna_select
1057 // 2 is diversity
1058 if (m_config.antennaMode != antennaMode)
1060 m_config.antennaMode = antennaMode;
1061 m_modified = true;
1065 void
1066 RxConfig::SetDefaults(bool commit)
1068 // Reset everything to 0/false and then just set anything that zero is not appropriate
1069 memset(&m_config, 0, sizeof(m_config));
1071 m_config.version = RX_CONFIG_VERSION | RX_CONFIG_MAGIC;
1072 m_config.modelId = 0xff;
1073 m_config.power = POWERMGNT::getDefaultPower();
1074 if (GPIO_PIN_ANT_CTRL != UNDEF_PIN)
1075 m_config.antennaMode = 2; // 2 is diversity
1076 if (GPIO_PIN_NSS_2 != UNDEF_PIN)
1077 m_config.antennaMode = 0; // 0 is diversity for dual radio
1079 #if defined(GPIO_PIN_PWM_OUTPUTS)
1080 for (int ch=0; ch<PWM_MAX_CHANNELS; ++ch)
1082 uint8_t mode = som50Hz;
1083 // setup defaults for hardware defined I2C pins that are also IO pins
1084 if (ch < GPIO_PIN_PWM_OUTPUTS_COUNT)
1086 if (GPIO_PIN_PWM_OUTPUTS[ch] == GPIO_PIN_SCL)
1088 mode = somSCL;
1090 else if (GPIO_PIN_PWM_OUTPUTS[ch] == GPIO_PIN_SDA)
1092 mode = somSDA;
1095 SetPwmChannel(ch, 512, ch, false, mode, false);
1097 SetPwmChannel(2, 0, 2, false, 0, false); // ch2 is throttle, failsafe it to 988
1098 #endif
1100 m_config.teamraceChannel = AUX7; // CH11
1102 #if defined(RCVR_INVERT_TX)
1103 m_config.serialProtocol = PROTOCOL_INVERTED_CRSF;
1104 #endif
1106 if (commit)
1108 // Prevent rebinding to the flashed UID on first boot
1109 m_config.flash_discriminator = firmwareOptions.flash_discriminator;
1110 m_modified = true;
1111 Commit();
1115 void
1116 RxConfig::SetStorageProvider(ELRS_EEPROM *eeprom)
1118 if (eeprom)
1120 m_eeprom = eeprom;
1124 #if defined(GPIO_PIN_PWM_OUTPUTS)
1125 void
1126 RxConfig::SetPwmChannel(uint8_t ch, uint16_t failsafe, uint8_t inputCh, bool inverted, uint8_t mode, bool narrow)
1128 if (ch > PWM_MAX_CHANNELS)
1129 return;
1131 rx_config_pwm_t *pwm = &m_config.pwmChannels[ch];
1132 rx_config_pwm_t newConfig;
1133 newConfig.val.failsafe = failsafe;
1134 newConfig.val.inputChannel = inputCh;
1135 newConfig.val.inverted = inverted;
1136 newConfig.val.mode = mode;
1137 newConfig.val.narrow = narrow;
1138 if (pwm->raw == newConfig.raw)
1139 return;
1141 pwm->raw = newConfig.raw;
1142 m_modified = true;
1145 void
1146 RxConfig::SetPwmChannelRaw(uint8_t ch, uint32_t raw)
1148 if (ch > PWM_MAX_CHANNELS)
1149 return;
1151 rx_config_pwm_t *pwm = &m_config.pwmChannels[ch];
1152 if (pwm->raw == raw)
1153 return;
1155 pwm->raw = raw;
1156 m_modified = true;
1158 #endif
1160 void
1161 RxConfig::SetForceTlmOff(bool forceTlmOff)
1163 if (m_config.forceTlmOff != forceTlmOff)
1165 m_config.forceTlmOff = forceTlmOff;
1166 m_modified = true;
1170 void
1171 RxConfig::SetRateInitialIdx(uint8_t rateInitialIdx)
1173 if (m_config.rateInitialIdx != rateInitialIdx)
1175 m_config.rateInitialIdx = rateInitialIdx;
1176 m_modified = true;
1180 void RxConfig::SetSerialProtocol(eSerialProtocol serialProtocol)
1182 if (m_config.serialProtocol != serialProtocol)
1184 m_config.serialProtocol = serialProtocol;
1185 m_modified = true;
1189 #if defined(PLATFORM_ESP32)
1190 void RxConfig::SetSerial1Protocol(eSerial1Protocol serialProtocol)
1192 if (m_config.serial1Protocol != serialProtocol)
1194 m_config.serial1Protocol = serialProtocol;
1195 m_modified = true;
1198 #endif
1200 void RxConfig::SetTeamraceChannel(uint8_t teamraceChannel)
1202 if (m_config.teamraceChannel != teamraceChannel)
1204 m_config.teamraceChannel = teamraceChannel;
1205 m_modified = true;
1209 void RxConfig::SetTeamracePosition(uint8_t teamracePosition)
1211 if (m_config.teamracePosition != teamracePosition)
1213 m_config.teamracePosition = teamracePosition;
1214 m_modified = true;
1218 void RxConfig::SetFailsafeMode(eFailsafeMode failsafeMode)
1220 if (m_config.failsafeMode != failsafeMode)
1222 m_config.failsafeMode = failsafeMode;
1223 m_modified = true;
1227 void RxConfig::SetBindStorage(rx_config_bindstorage_t value)
1229 if (m_config.bindStorage != value)
1231 // If switching away from returnable, revert
1232 ReturnLoan();
1233 m_config.bindStorage = value;
1234 m_modified = true;
1238 void RxConfig::SetTargetSysId(uint8_t value)
1240 if (m_config.targetSysId != value)
1242 m_config.targetSysId = value;
1243 m_modified = true;
1246 void RxConfig::SetSourceSysId(uint8_t value)
1248 if (m_config.sourceSysId != value)
1250 m_config.sourceSysId = value;
1251 m_modified = true;
1255 void RxConfig::ReturnLoan()
1257 if (IsOnLoan())
1259 // go back to flashed UID if there is one
1260 // or unbind if there is not
1261 if (firmwareOptions.hasUID)
1262 memcpy(m_config.uid, firmwareOptions.uid, UID_LEN);
1263 else
1264 memset(m_config.uid, 0, UID_LEN);
1266 m_modified = true;
1270 #endif