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)
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
;
184 for(unsigned i
=0; i
<64; i
++)
186 char model
[10] = "model";
187 itoa(i
, model
+5, 10);
188 if (nvs_get_u32(handle
, model
, &value
) == ESP_OK
)
192 U32_to_Model(value
, &m_config
.model_config
[i
]);
196 // Upgrade v6 to v7 directly writing to nvs instead of calling Commit() over and over
197 v6_model_config_t v6model
;
198 U32_to_Model(value
, &v6model
);
199 model_config_t
* const newModel
= &m_config
.model_config
[i
];
200 ModelV6toV7(&v6model
, newModel
);
201 nvs_set_u32(handle
, model
, Model_to_U32(newModel
));
206 if (version
!= TX_CONFIG_VERSION
)
211 #else // STM32/ESP8266
212 void TxConfig::Load()
215 m_eeprom
->Get(0, m_config
);
217 uint32_t version
= 0;
218 if ((m_config
.version
& CONFIG_MAGIC_MASK
) == TX_CONFIG_MAGIC
)
219 version
= m_config
.version
& ~CONFIG_MAGIC_MASK
;
220 DBGLN("Config version %u", version
);
222 // If version is current, all done
223 if (version
== TX_CONFIG_VERSION
)
226 // Can't upgrade from version <5, or when flashing a previous version, just use defaults.
227 if (version
< 5 || version
> TX_CONFIG_VERSION
)
233 // Upgrade EEPROM, starting with defaults
238 UpgradeEepromV5ToV6();
244 UpgradeEepromV6ToV7();
248 void TxConfig::UpgradeEepromV5ToV6()
250 v5_tx_config_t v5Config
;
251 v6_tx_config_t v6Config
= { 0 }; // default the new fields to 0
253 // Populate the prev version struct from eeprom
254 m_eeprom
->Get(0, v5Config
);
256 // Copy prev values to current config struct
257 // This only workse because v5 and v6 are the same up to the new fields
258 // which have already been set to 0
259 memcpy(&v6Config
, &v5Config
, sizeof(v5Config
));
260 v6Config
.version
= 6U | TX_CONFIG_MAGIC
;
261 m_eeprom
->Put(0, v6Config
);
265 void TxConfig::UpgradeEepromV6ToV7()
267 v6_tx_config_t v6Config
;
269 // Populate the prev version struct from eeprom
270 m_eeprom
->Get(0, v6Config
);
272 // Manual field copying as some fields have moved
273 #define LAZY(member) m_config.member = v6Config.member
278 LAZY(powerFanThreshold
);
286 for (unsigned i
=0; i
<64; i
++)
288 ModelV6toV7(&v6Config
.model_config
[i
], &m_config
.model_config
[i
]);
291 m_modified
= ALL_CHANGED
;
294 m_config
.version
= 7U | TX_CONFIG_MAGIC
;
307 #if defined(PLATFORM_ESP32)
308 // Write parts to NVS
309 if (m_modified
& MODEL_CHANGED
)
311 uint32_t value
= Model_to_U32(m_model
);
312 char model
[10] = "model";
313 itoa(m_modelId
, model
+5, 10);
314 nvs_set_u32(handle
, model
, value
);
316 if (m_modified
& VTX_CHANGED
)
319 m_config
.vtxBand
<< 24 |
320 m_config
.vtxChannel
<< 16 |
321 m_config
.vtxPower
<< 8 |
323 nvs_set_u32(handle
, "vtx", value
);
325 if (m_modified
& FAN_CHANGED
)
327 uint32_t value
= m_config
.fanMode
;
328 nvs_set_u32(handle
, "fan", value
);
330 if (m_modified
& MOTION_CHANGED
)
332 uint32_t value
= m_config
.motionMode
;
333 nvs_set_u32(handle
, "motion", value
);
335 if (m_modified
& MAIN_CHANGED
)
337 nvs_set_u8(handle
, "fanthresh", m_config
.powerFanThreshold
);
339 nvs_set_u8(handle
, "backpackdisable", m_config
.backpackDisable
);
340 nvs_set_u8(handle
, "dvraux", m_config
.dvrAux
);
341 nvs_set_u8(handle
, "dvrstartdelay", m_config
.dvrStartDelay
);
342 nvs_set_u8(handle
, "dvrstopdelay", m_config
.dvrStopDelay
);
344 if (m_modified
& BUTTON_CHANGED
)
346 nvs_set_u32(handle
, "button1", m_config
.buttonColors
[0].raw
);
347 nvs_set_u32(handle
, "button2", m_config
.buttonColors
[1].raw
);
349 nvs_set_u32(handle
, "tx_version", m_config
.version
);
352 // Write the struct to eeprom
353 m_eeprom
->Put(0, m_config
);
361 TxConfig::SetRate(uint8_t rate
)
363 if (GetRate() != rate
)
365 m_model
->rate
= rate
;
366 m_modified
|= MODEL_CHANGED
;
371 TxConfig::SetTlm(uint8_t tlm
)
376 m_modified
|= MODEL_CHANGED
;
381 TxConfig::SetPower(uint8_t power
)
383 if (GetPower() != power
)
385 m_model
->power
= power
;
386 m_modified
|= MODEL_CHANGED
;
391 TxConfig::SetDynamicPower(bool dynamicPower
)
393 if (GetDynamicPower() != dynamicPower
)
395 m_model
->dynamicPower
= dynamicPower
;
396 m_modified
|= MODEL_CHANGED
;
401 TxConfig::SetBoostChannel(uint8_t boostChannel
)
403 if (GetBoostChannel() != boostChannel
)
405 m_model
->boostChannel
= boostChannel
;
406 m_modified
|= MODEL_CHANGED
;
411 TxConfig::SetSwitchMode(uint8_t switchMode
)
413 if (GetSwitchMode() != switchMode
)
415 m_model
->switchMode
= switchMode
;
416 m_modified
|= MODEL_CHANGED
;
421 TxConfig::SetAntennaMode(uint8_t txAntenna
)
423 if (GetAntennaMode() != txAntenna
)
425 m_model
->txAntenna
= txAntenna
;
426 m_modified
|= MODEL_CHANGED
;
431 TxConfig::SetModelMatch(bool modelMatch
)
433 if (GetModelMatch() != modelMatch
)
435 m_model
->modelMatch
= modelMatch
;
436 m_modified
|= MODEL_CHANGED
;
441 TxConfig::SetVtxBand(uint8_t vtxBand
)
443 if (m_config
.vtxBand
!= vtxBand
)
445 m_config
.vtxBand
= vtxBand
;
446 m_modified
|= VTX_CHANGED
;
451 TxConfig::SetVtxChannel(uint8_t vtxChannel
)
453 if (m_config
.vtxChannel
!= vtxChannel
)
455 m_config
.vtxChannel
= vtxChannel
;
456 m_modified
|= VTX_CHANGED
;
461 TxConfig::SetVtxPower(uint8_t vtxPower
)
463 if (m_config
.vtxPower
!= vtxPower
)
465 m_config
.vtxPower
= vtxPower
;
466 m_modified
|= VTX_CHANGED
;
471 TxConfig::SetVtxPitmode(uint8_t vtxPitmode
)
473 if (m_config
.vtxPitmode
!= vtxPitmode
)
475 m_config
.vtxPitmode
= vtxPitmode
;
476 m_modified
|= VTX_CHANGED
;
481 TxConfig::SetPowerFanThreshold(uint8_t powerFanThreshold
)
483 if (m_config
.powerFanThreshold
!= powerFanThreshold
)
485 m_config
.powerFanThreshold
= powerFanThreshold
;
486 m_modified
|= MAIN_CHANGED
;
491 TxConfig::SetStorageProvider(ELRS_EEPROM
*eeprom
)
500 TxConfig::SetFanMode(uint8_t fanMode
)
502 if (m_config
.fanMode
!= fanMode
)
504 m_config
.fanMode
= fanMode
;
505 m_modified
|= FAN_CHANGED
;
510 TxConfig::SetMotionMode(uint8_t motionMode
)
512 if (m_config
.motionMode
!= motionMode
)
514 m_config
.motionMode
= motionMode
;
515 m_modified
|= MOTION_CHANGED
;
520 TxConfig::SetDvrAux(uint8_t dvrAux
)
522 if (GetDvrAux() != dvrAux
)
524 m_config
.dvrAux
= dvrAux
;
525 m_modified
|= MAIN_CHANGED
;
530 TxConfig::SetDvrStartDelay(uint8_t dvrStartDelay
)
532 if (GetDvrStartDelay() != dvrStartDelay
)
534 m_config
.dvrStartDelay
= dvrStartDelay
;
535 m_modified
|= MAIN_CHANGED
;
540 TxConfig::SetDvrStopDelay(uint8_t dvrStopDelay
)
542 if (GetDvrStopDelay() != dvrStopDelay
)
544 m_config
.dvrStopDelay
= dvrStopDelay
;
545 m_modified
|= MAIN_CHANGED
;
550 TxConfig::SetBackpackDisable(bool backpackDisable
)
552 if (m_config
.backpackDisable
!= backpackDisable
)
554 m_config
.backpackDisable
= backpackDisable
;
555 m_modified
|= MAIN_CHANGED
;
560 TxConfig::SetButtonActions(uint8_t button
, tx_button_color_t
*action
)
562 if (m_config
.buttonColors
[button
].raw
!= action
->raw
) {
563 m_config
.buttonColors
[button
].raw
= action
->raw
;
564 m_modified
|= BUTTON_CHANGED
;
569 TxConfig::SetDefaults(bool commit
)
571 // Reset everything to 0/false and then just set anything that zero is not appropriate
572 memset(&m_config
, 0, sizeof(m_config
));
574 m_config
.version
= TX_CONFIG_VERSION
| TX_CONFIG_MAGIC
;
575 m_config
.powerFanThreshold
= PWR_250mW
;
576 m_modified
= ALL_CHANGED
;
580 m_modified
= ALL_CHANGED
;
583 // Set defaults for button 1
584 tx_button_color_t default_actions1
= {
586 .color
= 226, // R:255 G:0 B:182
588 {false, 2, ACTION_BIND
},
589 {true, 0, ACTION_INCREASE_POWER
}
593 m_config
.buttonColors
[0].raw
= default_actions1
.raw
;
595 // Set defaults for button 2
596 tx_button_color_t default_actions2
= {
598 .color
= 3, // R:0 G:0 B:255
600 {false, 1, ACTION_GOTO_VTX_CHANNEL
},
601 {true, 0, ACTION_SEND_VTX
}
605 m_config
.buttonColors
[1].raw
= default_actions2
.raw
;
607 for (unsigned i
=0; i
<64; i
++)
610 #if defined(RADIO_SX127X)
611 SetRate(enumRatetoIndex(RATE_LORA_200HZ
));
612 #elif defined(RADIO_SX128X)
613 SetRate(enumRatetoIndex(RATE_LORA_250HZ
));
615 SetPower(POWERMGNT::getDefaultPower());
616 #if defined(PLATFORM_ESP32)
617 // ESP32 nvs needs to commit every model
620 m_modified
|= MODEL_CHANGED
;
626 #if !defined(PLATFORM_ESP32)
627 // STM32/ESP8266 just needs one commit
639 * Sets ModelId used for subsequent per-model config gets
640 * Returns: true if the model has changed
643 TxConfig::SetModelId(uint8_t modelId
)
645 model_config_t
*newModel
= &m_config
.model_config
[modelId
];
646 if (newModel
!= m_model
)
657 /////////////////////////////////////////////////////
659 #if defined(TARGET_RX)
665 void RxConfig::Load()
668 m_eeprom
->Get(0, m_config
);
670 uint32_t version
= 0;
671 if ((m_config
.version
& CONFIG_MAGIC_MASK
) == RX_CONFIG_MAGIC
)
672 version
= m_config
.version
& ~CONFIG_MAGIC_MASK
;
673 DBGLN("Config version %u", version
);
675 // If version is current, all done
676 if (version
== RX_CONFIG_VERSION
)
679 // Can't upgrade from version <4, or when flashing a previous version, just use defaults.
680 if (version
< 4 || version
> RX_CONFIG_VERSION
)
686 // Upgrade EEPROM, starting with defaults
690 m_config
.version
= RX_CONFIG_VERSION
| RX_CONFIG_MAGIC
;
695 // ========================================================
698 static void PwmConfigV4(v4_rx_config_pwm_t
const * const v4
, rx_config_pwm_t
* const current
)
700 current
->val
.failsafe
= v4
->val
.failsafe
;
701 current
->val
.inputChannel
= v4
->val
.inputChannel
;
702 current
->val
.inverted
= v4
->val
.inverted
;
705 void RxConfig::UpgradeEepromV4()
707 v4_rx_config_t v4Config
;
708 m_eeprom
->Get(0, v4Config
);
710 if ((v4Config
.version
& ~CONFIG_MAGIC_MASK
) == 4)
712 m_config
.isBound
= v4Config
.isBound
;
713 m_config
.modelId
= v4Config
.modelId
;
714 memcpy(m_config
.uid
, v4Config
.uid
, sizeof(v4Config
.uid
));
716 // OG PWMP had only 8 channels
717 for (unsigned ch
=0; ch
<8; ++ch
)
719 PwmConfigV4(&v4Config
.pwmChannels
[ch
], &m_config
.pwmChannels
[ch
]);
724 // ========================================================
727 static void PwmConfigV5(v5_rx_config_pwm_t
const * const v5
, rx_config_pwm_t
* const current
)
729 current
->val
.failsafe
= v5
->val
.failsafe
;
730 current
->val
.inputChannel
= v5
->val
.inputChannel
;
731 current
->val
.inverted
= v5
->val
.inverted
;
732 current
->val
.narrow
= v5
->val
.narrow
;
733 current
->val
.mode
= v5
->val
.mode
;
734 if (v5
->val
.mode
> som400Hz
)
736 current
->val
.mode
+= 1;
740 void RxConfig::UpgradeEepromV5()
742 v5_rx_config_t v5Config
;
743 m_eeprom
->Get(0, v5Config
);
744 if ((v5Config
.version
& ~CONFIG_MAGIC_MASK
) == 5)
746 memcpy(m_config
.uid
, v5Config
.uid
, sizeof(v5Config
.uid
));
747 m_config
.vbatScale
= v5Config
.vbatScale
;
748 m_config
.isBound
= v5Config
.isBound
;
749 m_config
.power
= v5Config
.power
;
750 m_config
.antennaMode
= v5Config
.antennaMode
;
751 m_config
.forceTlmOff
= v5Config
.forceTlmOff
;
752 m_config
.rateInitialIdx
= v5Config
.rateInitialIdx
;
753 m_config
.modelId
= v5Config
.modelId
;
755 for (unsigned ch
=0; ch
<16; ++ch
)
757 PwmConfigV5(&v5Config
.pwmChannels
[ch
], &m_config
.pwmChannels
[ch
]);
762 // ========================================================
773 // Write the struct to eeprom
774 m_eeprom
->Put(0, m_config
);
782 RxConfig::SetIsBound(bool isBound
)
784 if (m_config
.isBound
!= isBound
)
786 m_config
.isBound
= isBound
;
792 RxConfig::SetUID(uint8_t* uid
)
794 for (uint8_t i
= 0; i
< UID_LEN
; ++i
)
796 m_config
.uid
[i
] = uid
[i
];
802 RxConfig::SetOnLoan(bool isLoaned
)
804 if (m_config
.onLoan
!= isLoaned
)
806 m_config
.onLoan
= isLoaned
;
812 RxConfig::SetOnLoanUID(uint8_t* uid
)
814 for (uint8_t i
= 0; i
< UID_LEN
; ++i
)
816 m_config
.loanUID
[i
] = uid
[i
];
822 RxConfig::SetPowerOnCounter(uint8_t powerOnCounter
)
824 if (m_config
.powerOnCounter
!= powerOnCounter
)
826 m_config
.powerOnCounter
= powerOnCounter
;
832 RxConfig::SetModelId(uint8_t modelId
)
834 if (m_config
.modelId
!= modelId
)
836 m_config
.modelId
= modelId
;
842 RxConfig::SetPower(uint8_t power
)
844 if (m_config
.power
!= power
)
846 m_config
.power
= power
;
853 RxConfig::SetAntennaMode(uint8_t antennaMode
)
855 //0 and 1 is use for gpio_antenna_select
857 if (m_config
.antennaMode
!= antennaMode
)
859 m_config
.antennaMode
= antennaMode
;
865 RxConfig::SetDefaults(bool commit
)
867 // Reset everything to 0/false and then just set anything that zero is not appropriate
868 memset(&m_config
, 0, sizeof(m_config
));
870 m_config
.version
= RX_CONFIG_VERSION
| RX_CONFIG_MAGIC
;
871 m_config
.modelId
= 0xff;
872 m_config
.power
= POWERMGNT::getDefaultPower();
873 if (GPIO_PIN_ANT_CTRL
!= UNDEF_PIN
)
874 m_config
.antennaMode
= 2; // 2 is diversity
875 if (GPIO_PIN_NSS_2
!= UNDEF_PIN
)
876 m_config
.antennaMode
= 0; // 0 is diversity for dual radio
878 #if defined(GPIO_PIN_PWM_OUTPUTS)
879 for (unsigned int ch
=0; ch
<PWM_MAX_CHANNELS
; ++ch
)
880 SetPwmChannel(ch
, 512, ch
, false, 0, false);
881 SetPwmChannel(2, 0, 2, false, 0, false); // ch2 is throttle, failsafe it to 988
892 RxConfig::SetStorageProvider(ELRS_EEPROM
*eeprom
)
900 #if defined(GPIO_PIN_PWM_OUTPUTS)
902 RxConfig::SetPwmChannel(uint8_t ch
, uint16_t failsafe
, uint8_t inputCh
, bool inverted
, uint8_t mode
, bool narrow
)
904 if (ch
> PWM_MAX_CHANNELS
)
907 rx_config_pwm_t
*pwm
= &m_config
.pwmChannels
[ch
];
908 rx_config_pwm_t newConfig
;
909 newConfig
.val
.failsafe
= failsafe
;
910 newConfig
.val
.inputChannel
= inputCh
;
911 newConfig
.val
.inverted
= inverted
;
912 newConfig
.val
.mode
= mode
;
913 newConfig
.val
.narrow
= narrow
;
914 if (pwm
->raw
== newConfig
.raw
)
917 pwm
->raw
= newConfig
.raw
;
922 RxConfig::SetPwmChannelRaw(uint8_t ch
, uint32_t raw
)
924 if (ch
> PWM_MAX_CHANNELS
)
927 rx_config_pwm_t
*pwm
= &m_config
.pwmChannels
[ch
];
937 RxConfig::SetForceTlmOff(bool forceTlmOff
)
939 if (m_config
.forceTlmOff
!= forceTlmOff
)
941 m_config
.forceTlmOff
= forceTlmOff
;
947 RxConfig::SetRateInitialIdx(uint8_t rateInitialIdx
)
949 if (m_config
.rateInitialIdx
!= rateInitialIdx
)
951 m_config
.rateInitialIdx
= rateInitialIdx
;