Gemini/Diversity 900 (#1993)
[ExpressLRS.git] / src / lib / CONFIG / config.cpp
blob6f763a07ebb57f22efc91e1d8b72b141e113f739
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)
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;
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)
190 if (version >= 7)
192 U32_to_Model(value, &m_config.model_config[i]);
194 else
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));
204 } // for each model
206 if (version != TX_CONFIG_VERSION)
208 Commit();
211 #else // STM32/ESP8266
212 void TxConfig::Load()
214 m_modified = 0;
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)
224 return;
226 // Can't upgrade from version <5, or when flashing a previous version, just use defaults.
227 if (version < 5 || version > TX_CONFIG_VERSION)
229 SetDefaults(true);
230 return;
233 // Upgrade EEPROM, starting with defaults
234 SetDefaults(false);
236 if (version == 5)
238 UpgradeEepromV5ToV6();
239 version = 6;
242 if (version == 6)
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);
262 m_eeprom->Commit();
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
274 LAZY(vtxBand);
275 LAZY(vtxChannel);
276 LAZY(vtxPower);
277 LAZY(vtxPitmode);
278 LAZY(powerFanThreshold);
279 LAZY(fanMode);
280 LAZY(motionMode);
281 LAZY(dvrAux);
282 LAZY(dvrStartDelay);
283 LAZY(dvrStopDelay);
284 #undef LAZY
286 for (unsigned i=0; i<64; i++)
288 ModelV6toV7(&v6Config.model_config[i], &m_config.model_config[i]);
291 m_modified = ALL_CHANGED;
293 // Full Commit now
294 m_config.version = 7U | TX_CONFIG_MAGIC;
295 Commit();
297 #endif
299 void
300 TxConfig::Commit()
302 if (!m_modified)
304 // No changes
305 return;
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)
318 uint32_t value =
319 m_config.vtxBand << 24 |
320 m_config.vtxChannel << 16 |
321 m_config.vtxPower << 8 |
322 m_config.vtxPitmode;
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);
350 nvs_commit(handle);
351 #else
352 // Write the struct to eeprom
353 m_eeprom->Put(0, m_config);
354 m_eeprom->Commit();
355 #endif
356 m_modified = 0;
359 // Setters
360 void
361 TxConfig::SetRate(uint8_t rate)
363 if (GetRate() != rate)
365 m_model->rate = rate;
366 m_modified |= MODEL_CHANGED;
370 void
371 TxConfig::SetTlm(uint8_t tlm)
373 if (GetTlm() != tlm)
375 m_model->tlm = tlm;
376 m_modified |= MODEL_CHANGED;
380 void
381 TxConfig::SetPower(uint8_t power)
383 if (GetPower() != power)
385 m_model->power = power;
386 m_modified |= MODEL_CHANGED;
390 void
391 TxConfig::SetDynamicPower(bool dynamicPower)
393 if (GetDynamicPower() != dynamicPower)
395 m_model->dynamicPower = dynamicPower;
396 m_modified |= MODEL_CHANGED;
400 void
401 TxConfig::SetBoostChannel(uint8_t boostChannel)
403 if (GetBoostChannel() != boostChannel)
405 m_model->boostChannel = boostChannel;
406 m_modified |= MODEL_CHANGED;
410 void
411 TxConfig::SetSwitchMode(uint8_t switchMode)
413 if (GetSwitchMode() != switchMode)
415 m_model->switchMode = switchMode;
416 m_modified |= MODEL_CHANGED;
420 void
421 TxConfig::SetAntennaMode(uint8_t txAntenna)
423 if (GetAntennaMode() != txAntenna)
425 m_model->txAntenna = txAntenna;
426 m_modified |= MODEL_CHANGED;
430 void
431 TxConfig::SetModelMatch(bool modelMatch)
433 if (GetModelMatch() != modelMatch)
435 m_model->modelMatch = modelMatch;
436 m_modified |= MODEL_CHANGED;
440 void
441 TxConfig::SetVtxBand(uint8_t vtxBand)
443 if (m_config.vtxBand != vtxBand)
445 m_config.vtxBand = vtxBand;
446 m_modified |= VTX_CHANGED;
450 void
451 TxConfig::SetVtxChannel(uint8_t vtxChannel)
453 if (m_config.vtxChannel != vtxChannel)
455 m_config.vtxChannel = vtxChannel;
456 m_modified |= VTX_CHANGED;
460 void
461 TxConfig::SetVtxPower(uint8_t vtxPower)
463 if (m_config.vtxPower != vtxPower)
465 m_config.vtxPower = vtxPower;
466 m_modified |= VTX_CHANGED;
470 void
471 TxConfig::SetVtxPitmode(uint8_t vtxPitmode)
473 if (m_config.vtxPitmode != vtxPitmode)
475 m_config.vtxPitmode = vtxPitmode;
476 m_modified |= VTX_CHANGED;
480 void
481 TxConfig::SetPowerFanThreshold(uint8_t powerFanThreshold)
483 if (m_config.powerFanThreshold != powerFanThreshold)
485 m_config.powerFanThreshold = powerFanThreshold;
486 m_modified |= MAIN_CHANGED;
490 void
491 TxConfig::SetStorageProvider(ELRS_EEPROM *eeprom)
493 if (eeprom)
495 m_eeprom = eeprom;
499 void
500 TxConfig::SetFanMode(uint8_t fanMode)
502 if (m_config.fanMode != fanMode)
504 m_config.fanMode = fanMode;
505 m_modified |= FAN_CHANGED;
509 void
510 TxConfig::SetMotionMode(uint8_t motionMode)
512 if (m_config.motionMode != motionMode)
514 m_config.motionMode = motionMode;
515 m_modified |= MOTION_CHANGED;
519 void
520 TxConfig::SetDvrAux(uint8_t dvrAux)
522 if (GetDvrAux() != dvrAux)
524 m_config.dvrAux = dvrAux;
525 m_modified |= MAIN_CHANGED;
529 void
530 TxConfig::SetDvrStartDelay(uint8_t dvrStartDelay)
532 if (GetDvrStartDelay() != dvrStartDelay)
534 m_config.dvrStartDelay = dvrStartDelay;
535 m_modified |= MAIN_CHANGED;
539 void
540 TxConfig::SetDvrStopDelay(uint8_t dvrStopDelay)
542 if (GetDvrStopDelay() != dvrStopDelay)
544 m_config.dvrStopDelay = dvrStopDelay;
545 m_modified |= MAIN_CHANGED;
549 void
550 TxConfig::SetBackpackDisable(bool backpackDisable)
552 if (m_config.backpackDisable != backpackDisable)
554 m_config.backpackDisable = backpackDisable;
555 m_modified |= MAIN_CHANGED;
559 void
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;
568 void
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;
578 if (commit)
580 m_modified = ALL_CHANGED;
583 // Set defaults for button 1
584 tx_button_color_t default_actions1 = {
585 .val = {
586 .color = 226, // R:255 G:0 B:182
587 .actions = {
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 = {
597 .val = {
598 .color = 3, // R:0 G:0 B:255
599 .actions = {
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++)
609 SetModelId(i);
610 #if defined(RADIO_SX127X)
611 SetRate(enumRatetoIndex(RATE_LORA_200HZ));
612 #elif defined(RADIO_SX128X)
613 SetRate(enumRatetoIndex(RATE_LORA_250HZ));
614 #endif
615 SetPower(POWERMGNT::getDefaultPower());
616 #if defined(PLATFORM_ESP32)
617 // ESP32 nvs needs to commit every model
618 if (commit)
620 m_modified |= MODEL_CHANGED;
621 Commit();
623 #endif
626 #if !defined(PLATFORM_ESP32)
627 // STM32/ESP8266 just needs one commit
628 if (commit)
630 Commit();
632 #endif
634 SetModelId(0);
635 m_modified = 0;
639 * Sets ModelId used for subsequent per-model config gets
640 * Returns: true if the model has changed
642 bool
643 TxConfig::SetModelId(uint8_t modelId)
645 model_config_t *newModel = &m_config.model_config[modelId];
646 if (newModel != m_model)
648 m_model = newModel;
649 m_modelId = modelId;
650 return true;
653 return false;
655 #endif
657 /////////////////////////////////////////////////////
659 #if defined(TARGET_RX)
661 RxConfig::RxConfig()
665 void RxConfig::Load()
667 m_modified = false;
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)
677 return;
679 // Can't upgrade from version <4, or when flashing a previous version, just use defaults.
680 if (version < 4 || version > RX_CONFIG_VERSION)
682 SetDefaults(true);
683 return;
686 // Upgrade EEPROM, starting with defaults
687 SetDefaults(false);
688 UpgradeEepromV4();
689 UpgradeEepromV5();
690 m_config.version = RX_CONFIG_VERSION | RX_CONFIG_MAGIC;
691 m_modified = true;
692 Commit();
695 // ========================================================
696 // V4 Upgrade
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 // ========================================================
725 // V5 Upgrade
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 // ========================================================
764 void
765 RxConfig::Commit()
767 if (!m_modified)
769 // No changes
770 return;
773 // Write the struct to eeprom
774 m_eeprom->Put(0, m_config);
775 m_eeprom->Commit();
777 m_modified = false;
780 // Setters
781 void
782 RxConfig::SetIsBound(bool isBound)
784 if (m_config.isBound != isBound)
786 m_config.isBound = isBound;
787 m_modified = true;
791 void
792 RxConfig::SetUID(uint8_t* uid)
794 for (uint8_t i = 0; i < UID_LEN; ++i)
796 m_config.uid[i] = uid[i];
798 m_modified = true;
801 void
802 RxConfig::SetOnLoan(bool isLoaned)
804 if (m_config.onLoan != isLoaned)
806 m_config.onLoan = isLoaned;
807 m_modified = true;
811 void
812 RxConfig::SetOnLoanUID(uint8_t* uid)
814 for (uint8_t i = 0; i < UID_LEN; ++i)
816 m_config.loanUID[i] = uid[i];
818 m_modified = true;
821 void
822 RxConfig::SetPowerOnCounter(uint8_t powerOnCounter)
824 if (m_config.powerOnCounter != powerOnCounter)
826 m_config.powerOnCounter = powerOnCounter;
827 m_modified = true;
831 void
832 RxConfig::SetModelId(uint8_t modelId)
834 if (m_config.modelId != modelId)
836 m_config.modelId = modelId;
837 m_modified = true;
841 void
842 RxConfig::SetPower(uint8_t power)
844 if (m_config.power != power)
846 m_config.power = power;
847 m_modified = true;
852 void
853 RxConfig::SetAntennaMode(uint8_t antennaMode)
855 //0 and 1 is use for gpio_antenna_select
856 // 2 is diversity
857 if (m_config.antennaMode != antennaMode)
859 m_config.antennaMode = antennaMode;
860 m_modified = true;
864 void
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
882 #endif
884 if (commit)
886 m_modified = true;
887 Commit();
891 void
892 RxConfig::SetStorageProvider(ELRS_EEPROM *eeprom)
894 if (eeprom)
896 m_eeprom = eeprom;
900 #if defined(GPIO_PIN_PWM_OUTPUTS)
901 void
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)
905 return;
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)
915 return;
917 pwm->raw = newConfig.raw;
918 m_modified = true;
921 void
922 RxConfig::SetPwmChannelRaw(uint8_t ch, uint32_t raw)
924 if (ch > PWM_MAX_CHANNELS)
925 return;
927 rx_config_pwm_t *pwm = &m_config.pwmChannels[ch];
928 if (pwm->raw == raw)
929 return;
931 pwm->raw = raw;
932 m_modified = true;
934 #endif
936 void
937 RxConfig::SetForceTlmOff(bool forceTlmOff)
939 if (m_config.forceTlmOff != forceTlmOff)
941 m_config.forceTlmOff = forceTlmOff;
942 m_modified = true;
946 void
947 RxConfig::SetRateInitialIdx(uint8_t rateInitialIdx)
949 if (m_config.rateInitialIdx != rateInitialIdx)
951 m_config.rateInitialIdx = rateInitialIdx;
952 m_modified = true;
957 #endif