2 #include "config_legacy.h"
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
)
25 uint8_t padding
[sizeof(uint32_t)-sizeof(T
)];
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)
39 uint8_t padding
[sizeof(uint32_t)-sizeof(T
)];
44 converter
.val
.model
= *model
;
48 static uint8_t RateV6toV7(uint8_t rateV6
)
50 #if defined(RADIO_SX127X) || defined(RADIO_LR1121)
57 // 100Hz, 50Hz, 25Hz all move up one
58 // to make room for 100Hz Full
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
72 static uint8_t RatioV6toV7(uint8_t ratioV6
)
74 // All shifted up for Std telem
78 static uint8_t SwitchesV6toV7(uint8_t switchesV6
)
80 // 0 was removed, Wide(2) became 0, Hybrid(1) became 1
83 case 1: return (uint8_t)smHybridOr16ch
;
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()
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
)
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
;
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
;
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
;
169 // Need to write the dvr defaults
170 m_modified
|= MAIN_CHANGED
;
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
)
194 U32_to_Model(value
, &m_config
.model_config
[i
]);
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
));
208 if (version
!= TX_CONFIG_VERSION
)
213 #else // STM32/ESP8266
214 void TxConfig::Load()
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
)
228 // Can't upgrade from version <5, or when flashing a previous version, just use defaults.
229 if (version
< 5 || version
> TX_CONFIG_VERSION
)
235 // Upgrade EEPROM, starting with defaults
240 UpgradeEepromV5ToV6();
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
);
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
280 LAZY(powerFanThreshold
);
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
;
296 m_config
.version
= 7U | TX_CONFIG_MAGIC
;
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
)
321 m_config
.vtxBand
<< 24 |
322 m_config
.vtxChannel
<< 16 |
323 m_config
.vtxPower
<< 8 |
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
);
355 // Write the struct to eeprom
356 m_eeprom
->Put(0, m_config
);
364 TxConfig::SetRate(uint8_t rate
)
366 if (GetRate() != rate
)
368 m_model
->rate
= rate
;
369 m_modified
|= MODEL_CHANGED
;
374 TxConfig::SetTlm(uint8_t tlm
)
379 m_modified
|= MODEL_CHANGED
;
384 TxConfig::SetPower(uint8_t power
)
386 if (GetPower() != power
)
388 m_model
->power
= power
;
389 m_modified
|= MODEL_CHANGED
;
394 TxConfig::SetDynamicPower(bool dynamicPower
)
396 if (GetDynamicPower() != dynamicPower
)
398 m_model
->dynamicPower
= dynamicPower
;
399 m_modified
|= MODEL_CHANGED
;
404 TxConfig::SetBoostChannel(uint8_t boostChannel
)
406 if (GetBoostChannel() != boostChannel
)
408 m_model
->boostChannel
= boostChannel
;
409 m_modified
|= MODEL_CHANGED
;
414 TxConfig::SetSwitchMode(uint8_t switchMode
)
416 if (GetSwitchMode() != switchMode
)
418 m_model
->switchMode
= switchMode
;
419 m_modified
|= MODEL_CHANGED
;
424 TxConfig::SetAntennaMode(uint8_t txAntenna
)
426 if (GetAntennaMode() != txAntenna
)
428 m_model
->txAntenna
= txAntenna
;
429 m_modified
|= MODEL_CHANGED
;
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
;
450 TxConfig::SetModelMatch(bool modelMatch
)
452 if (GetModelMatch() != modelMatch
)
454 m_model
->modelMatch
= modelMatch
;
455 m_modified
|= MODEL_CHANGED
;
460 TxConfig::SetVtxBand(uint8_t vtxBand
)
462 if (m_config
.vtxBand
!= vtxBand
)
464 m_config
.vtxBand
= vtxBand
;
465 m_modified
|= VTX_CHANGED
;
470 TxConfig::SetVtxChannel(uint8_t vtxChannel
)
472 if (m_config
.vtxChannel
!= vtxChannel
)
474 m_config
.vtxChannel
= vtxChannel
;
475 m_modified
|= VTX_CHANGED
;
480 TxConfig::SetVtxPower(uint8_t vtxPower
)
482 if (m_config
.vtxPower
!= vtxPower
)
484 m_config
.vtxPower
= vtxPower
;
485 m_modified
|= VTX_CHANGED
;
490 TxConfig::SetVtxPitmode(uint8_t vtxPitmode
)
492 if (m_config
.vtxPitmode
!= vtxPitmode
)
494 m_config
.vtxPitmode
= vtxPitmode
;
495 m_modified
|= VTX_CHANGED
;
500 TxConfig::SetPowerFanThreshold(uint8_t powerFanThreshold
)
502 if (m_config
.powerFanThreshold
!= powerFanThreshold
)
504 m_config
.powerFanThreshold
= powerFanThreshold
;
505 m_modified
|= MAIN_CHANGED
;
510 TxConfig::SetStorageProvider(ELRS_EEPROM
*eeprom
)
519 TxConfig::SetFanMode(uint8_t fanMode
)
521 if (m_config
.fanMode
!= fanMode
)
523 m_config
.fanMode
= fanMode
;
524 m_modified
|= FAN_CHANGED
;
529 TxConfig::SetMotionMode(uint8_t motionMode
)
531 if (m_config
.motionMode
!= motionMode
)
533 m_config
.motionMode
= motionMode
;
534 m_modified
|= MOTION_CHANGED
;
539 TxConfig::SetDvrAux(uint8_t dvrAux
)
541 if (GetDvrAux() != dvrAux
)
543 m_config
.dvrAux
= dvrAux
;
544 m_modified
|= MAIN_CHANGED
;
549 TxConfig::SetDvrStartDelay(uint8_t dvrStartDelay
)
551 if (GetDvrStartDelay() != dvrStartDelay
)
553 m_config
.dvrStartDelay
= dvrStartDelay
;
554 m_modified
|= MAIN_CHANGED
;
559 TxConfig::SetDvrStopDelay(uint8_t dvrStopDelay
)
561 if (GetDvrStopDelay() != dvrStopDelay
)
563 m_config
.dvrStopDelay
= dvrStopDelay
;
564 m_modified
|= MAIN_CHANGED
;
569 TxConfig::SetBackpackDisable(bool backpackDisable
)
571 if (m_config
.backpackDisable
!= backpackDisable
)
573 m_config
.backpackDisable
= backpackDisable
;
574 m_modified
|= MAIN_CHANGED
;
579 TxConfig::SetBackpackTlmMode(uint8_t mode
)
581 if (m_config
.backpackTlmMode
!= mode
)
583 m_config
.backpackTlmMode
= mode
;
584 m_modified
|= MAIN_CHANGED
;
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
;
598 TxConfig::SetPTRStartChannel(uint8_t ptrStartChannel
)
600 if (ptrStartChannel
!= m_model
->ptrStartChannel
) {
601 m_model
->ptrStartChannel
= ptrStartChannel
;
602 m_modified
|= MODEL_CHANGED
;
607 TxConfig::SetPTREnableChannel(uint8_t ptrEnableChannel
)
609 if (ptrEnableChannel
!= m_model
->ptrEnableChannel
) {
610 m_model
->ptrEnableChannel
= ptrEnableChannel
;
611 m_modified
|= MODEL_CHANGED
;
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
;
627 m_modified
= ALL_CHANGED
;
630 // Set defaults for button 1
631 tx_button_color_t default_actions1
= {
633 .color
= 226, // R:255 G:0 B:182
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
= {
645 .color
= 3, // R:0 G:0 B:255
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
++)
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
));
664 SetPower(POWERMGNT::getDefaultPower());
665 #if defined(PLATFORM_ESP32)
666 // ESP32 nvs needs to commit every model
669 m_modified
|= MODEL_CHANGED
;
675 #if !defined(PLATFORM_ESP32)
676 // STM32/ESP8266 just needs one commit
688 * Sets ModelId used for subsequent per-model config gets
689 * Returns: true if the model has changed
692 TxConfig::SetModelId(uint8_t modelId
)
694 model_config_t
*newModel
= &m_config
.model_config
[modelId
];
695 if (newModel
!= m_model
)
706 /////////////////////////////////////////////////////
708 #if defined(TARGET_RX)
710 #if defined(PLATFORM_ESP8266)
711 #include "flash_hal.h"
718 void RxConfig::Load()
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);
735 // Can't upgrade from version <4, or when flashing a previous version, just use defaults.
736 if (version
< 4 || version
> RX_CONFIG_VERSION
)
739 CheckUpdateFlashedUid(true);
743 // Upgrade EEPROM, starting with defaults
749 m_config
.version
= RX_CONFIG_VERSION
| RX_CONFIG_MAGIC
;
754 void RxConfig::CheckUpdateFlashedUid(bool skipDescrimCheck
)
756 // No binding phrase flashed, nothing to do
757 if (!firmwareOptions
.hasUID
)
759 // If already copied binding info, do not replace
760 if (!skipDescrimCheck
&& m_config
.flash_discriminator
== firmwareOptions
.flash_discriminator
)
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
774 // ========================================================
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
]);
803 // ========================================================
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
]);
843 // ========================================================
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
]);
879 // ========================================================
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;
912 void RxConfig::UpgradeUid(uint8_t *onLoanUid
, uint8_t *boundUid
)
914 // Convert to traditional binding
915 // On loan? Now you own
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
;
929 memcpy(m_config
.uid
, boundUid
, UID_LEN
);
934 memset(m_config
.uid
, 0, UID_LEN
);
938 bool RxConfig::GetIsBound() const
940 if (m_config
.bindStorage
== BINDSTORAGE_VOLATILE
)
942 return UID_IS_BOUND(m_config
.uid
);
945 bool RxConfig::IsOnLoan() const
947 if (m_config
.bindStorage
!= BINDSTORAGE_RETURNABLE
)
949 if (!firmwareOptions
.hasUID
)
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;
959 RxConfig::GetPowerOnCounter() const
961 if (realPowerOnCounter
== -1) {
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
++) {
967 realPowerOnCounter
= i
;
972 return realPowerOnCounter
;
979 #if defined(PLATFORM_ESP8266)
980 if (erase_power_on_count
)
982 ESP
.flashEraseSector(EMPTY_SECTOR
);
983 erase_power_on_count
= false;
992 // Write the struct to eeprom
993 m_eeprom
->Put(0, m_config
);
1001 RxConfig::SetUID(uint8_t* uid
)
1003 for (uint8_t i
= 0; i
< UID_LEN
; ++i
)
1005 m_config
.uid
[i
] = uid
[i
];
1011 RxConfig::SetPowerOnCounter(uint8_t powerOnCounter
)
1013 #if defined(PLATFORM_ESP8266)
1014 realPowerOnCounter
= powerOnCounter
;
1015 if (powerOnCounter
== 0)
1017 erase_power_on_count
= true;
1022 byte zeros
[16] = {0};
1023 ESP
.flashWrite(EMPTY_SECTOR
* SPI_FLASH_SEC_SIZE
, zeros
, std::min((size_t)powerOnCounter
, sizeof(zeros
)));
1026 if (m_config
.powerOnCounter
!= powerOnCounter
)
1028 m_config
.powerOnCounter
= powerOnCounter
;
1035 RxConfig::SetModelId(uint8_t modelId
)
1037 if (m_config
.modelId
!= modelId
)
1039 m_config
.modelId
= modelId
;
1045 RxConfig::SetPower(uint8_t power
)
1047 if (m_config
.power
!= power
)
1049 m_config
.power
= power
;
1056 RxConfig::SetAntennaMode(uint8_t antennaMode
)
1058 //0 and 1 is use for gpio_antenna_select
1060 if (m_config
.antennaMode
!= antennaMode
)
1062 m_config
.antennaMode
= antennaMode
;
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
)
1092 else if (GPIO_PIN_PWM_OUTPUTS
[ch
] == GPIO_PIN_SDA
)
1097 SetPwmChannel(ch
, 512, ch
, false, mode
, false);
1099 SetPwmChannel(2, 0, 2, false, 0, false); // ch2 is throttle, failsafe it to 988
1102 m_config
.teamraceChannel
= AUX7
; // CH11
1104 #if defined(RCVR_INVERT_TX)
1105 m_config
.serialProtocol
= PROTOCOL_INVERTED_CRSF
;
1110 // Prevent rebinding to the flashed UID on first boot
1111 m_config
.flash_discriminator
= firmwareOptions
.flash_discriminator
;
1118 RxConfig::SetStorageProvider(ELRS_EEPROM
*eeprom
)
1126 #if defined(GPIO_PIN_PWM_OUTPUTS)
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
)
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
)
1143 pwm
->raw
= newConfig
.raw
;
1148 RxConfig::SetPwmChannelRaw(uint8_t ch
, uint32_t raw
)
1150 if (ch
> PWM_MAX_CHANNELS
)
1153 rx_config_pwm_t
*pwm
= &m_config
.pwmChannels
[ch
];
1154 if (pwm
->raw
== raw
)
1163 RxConfig::SetForceTlmOff(bool forceTlmOff
)
1165 if (m_config
.forceTlmOff
!= forceTlmOff
)
1167 m_config
.forceTlmOff
= forceTlmOff
;
1173 RxConfig::SetRateInitialIdx(uint8_t rateInitialIdx
)
1175 if (m_config
.rateInitialIdx
!= rateInitialIdx
)
1177 m_config
.rateInitialIdx
= rateInitialIdx
;
1182 void RxConfig::SetSerialProtocol(eSerialProtocol serialProtocol
)
1184 if (m_config
.serialProtocol
!= serialProtocol
)
1186 m_config
.serialProtocol
= serialProtocol
;
1191 #if defined(PLATFORM_ESP32)
1192 void RxConfig::SetSerial1Protocol(eSerial1Protocol serialProtocol
)
1194 if (m_config
.serial1Protocol
!= serialProtocol
)
1196 m_config
.serial1Protocol
= serialProtocol
;
1202 void RxConfig::SetTeamraceChannel(uint8_t teamraceChannel
)
1204 if (m_config
.teamraceChannel
!= teamraceChannel
)
1206 m_config
.teamraceChannel
= teamraceChannel
;
1211 void RxConfig::SetTeamracePosition(uint8_t teamracePosition
)
1213 if (m_config
.teamracePosition
!= teamracePosition
)
1215 m_config
.teamracePosition
= teamracePosition
;
1220 void RxConfig::SetFailsafeMode(eFailsafeMode failsafeMode
)
1222 if (m_config
.failsafeMode
!= failsafeMode
)
1224 m_config
.failsafeMode
= failsafeMode
;
1229 void RxConfig::SetBindStorage(rx_config_bindstorage_t value
)
1231 if (m_config
.bindStorage
!= value
)
1233 // If switching away from returnable, revert
1235 m_config
.bindStorage
= value
;
1240 void RxConfig::SetTargetSysId(uint8_t value
)
1242 if (m_config
.targetSysId
!= value
)
1244 m_config
.targetSysId
= value
;
1248 void RxConfig::SetSourceSysId(uint8_t value
)
1250 if (m_config
.sourceSysId
!= value
)
1252 m_config
.sourceSysId
= value
;
1257 void RxConfig::ReturnLoan()
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
);
1266 memset(m_config
.uid
, 0, UID_LEN
);