TEST(Trims, invertedThrottlePlusThrottleTrim) { MODEL_RESET(); modelDefault(0); g_model.throttleReversed = 1; g_model.thrTrim = 1; // stick max + trim max anaInValues[THR_STICK] = +1024; setTrimValue(0, THR_STICK, TRIM_MAX); evalMixes(1); EXPECT_EQ(channelOutputs[2], -1024); // stick max + trim mid anaInValues[THR_STICK] = +1024; setTrimValue(0, THR_STICK, 0); evalMixes(1); EXPECT_EQ(channelOutputs[2], -1024+250); // stick max + trim min anaInValues[THR_STICK] = +1024; setTrimValue(0, THR_STICK, TRIM_MIN); evalMixes(1); EXPECT_EQ(channelOutputs[2], -1024+500); // stick min + trim max anaInValues[THR_STICK] = -1024; setTrimValue(0, THR_STICK, TRIM_MAX); evalMixes(1); EXPECT_EQ(channelOutputs[2], +1024); // stick min + trim min anaInValues[THR_STICK] = -1024; setTrimValue(0, THR_STICK, TRIM_MIN); evalMixes(1); EXPECT_EQ(channelOutputs[2], +1024); // now the same tests with extended Trims g_model.extendedTrims = 1; // stick max + trim max anaInValues[THR_STICK] = +1024; setTrimValue(0, THR_STICK, TRIM_EXTENDED_MAX); evalMixes(1); EXPECT_EQ(channelOutputs[2], -1024); // stick max + trim mid anaInValues[THR_STICK] = +1024; setTrimValue(0, THR_STICK, 0); evalMixes(1); EXPECT_EQ(channelOutputs[2], -1024+1000); // stick max + trim min anaInValues[THR_STICK] = +1024; setTrimValue(0, THR_STICK, TRIM_EXTENDED_MIN); evalMixes(1); EXPECT_EQ(channelOutputs[2], -1024+2000); // stick min + trim max anaInValues[THR_STICK] = -1024; setTrimValue(0, THR_STICK, TRIM_EXTENDED_MAX); evalMixes(1); EXPECT_EQ(channelOutputs[2], +1024); // stick min + trim min anaInValues[THR_STICK] = -1024; setTrimValue(0, THR_STICK, TRIM_EXTENDED_MIN); evalMixes(1); EXPECT_EQ(channelOutputs[2], +1024); }
TEST(Trims, greaterTrimLink) { MODEL_RESET(); setTrimValue(1, RUD_STICK, TRIM_EXTENDED_MAX+3); // link to FP3 trim setTrimValue(3, RUD_STICK, 32); EXPECT_EQ(getRawTrimValue(getTrimFlightPhase(1, RUD_STICK), RUD_STICK), 32); }
TEST(Trims, chainedTrims) { MODEL_RESET(); setTrimValue(0, RUD_STICK, 32); setTrimValue(1, RUD_STICK, TRIM_EXTENDED_MAX+1); // link to FP0 trim setTrimValue(2, RUD_STICK, TRIM_EXTENDED_MAX+2); // link to FP1 trim EXPECT_EQ(getRawTrimValue(getTrimFlightPhase(0, RUD_STICK), RUD_STICK), 32); }
TEST(Trims, infiniteChainedTrims) { MODEL_RESET(); setTrimValue(0, 0, 32); setTrimValue(1, 0, TRIM_EXTENDED_MAX+3); // link to FP3 trim setTrimValue(2, 0, TRIM_EXTENDED_MAX+2); // link to FP1 trim setTrimValue(3, 0, TRIM_EXTENDED_MAX+3); // link to FP2 trim EXPECT_EQ(getRawTrimValue(getTrimFlightPhase(0, 2), 0), 32); }
TEST(Trims, CopyTrimsToOffset) { MODEL_RESET(); modelDefault(0); setTrimValue(0, ELE_STICK, -100); // -100 on elevator evalFunctions(); // it disables all safety channels copyTrimsToOffset(1); EXPECT_EQ(getTrimValue(0, ELE_STICK), -100); // unchanged #if defined(CPUARM) EXPECT_EQ(g_model.limitData[1].offset, -195); #else EXPECT_EQ(g_model.limitData[1].offset, -200); #endif }
TEST(getSwitch, inputWithTrim) { MODEL_RESET(); modelDefault(0); MIXER_RESET(); g_model.logicalSw[0] = { LS_FUNC_VPOS, MIXSRC_FIRST_INPUT, 0, 0 }; doMixerCalculations(); evalLogicalSwitches(); EXPECT_EQ(getSwitch(SWSRC_SW1), false); setTrimValue(0, 0, 32); doMixerCalculations(); evalLogicalSwitches(); EXPECT_EQ(getSwitch(SWSRC_SW1), true); }
TEST(Mixer, NoTrimOnInactiveMix) { MODEL_RESET(); MIXER_RESET(); g_model.mixData[0].destCh = 0; g_model.mixData[0].mltpx = MLTPX_ADD; g_model.mixData[0].srcRaw = MIXSRC_Thr; g_model.mixData[0].weight = 100; g_model.mixData[0].swtch = SWSRC_THR; g_model.mixData[0].speedUp = SLOW_STEP*5; g_model.mixData[0].speedDown = SLOW_STEP*5; setTrimValue(0, 2, 256); s_mixer_first_run_done = true; simuSetSwitch(0, 1); CHECK_SLOW_MOVEMENT(0, 1, 100); simuSetSwitch(0, -1); CHECK_SLOW_MOVEMENT(0, -1, 100); }
TEST(Trims, invertedThrottlePlusthrottleTrimWithZeroWeightOnThrottle) { MODEL_RESET(); modelDefault(0); g_model.throttleReversed = 1; g_model.thrTrim = 1; #if defined(PCBTARANIS) // the input already exists ExpoData *expo = expoAddress(THR_STICK); #else ExpoData *expo = expoAddress(0); expo->mode = 3; expo->chn = THR_STICK; #endif expo->weight = 0; // stick max + trim max anaInValues[THR_STICK] = +1024; setTrimValue(0, THR_STICK, TRIM_MAX); evalMixes(1); EXPECT_EQ(channelOutputs[2], 0); // stick max + trim mid anaInValues[THR_STICK] = +1024; setTrimValue(0, THR_STICK, 0); evalMixes(1); EXPECT_LE(abs(channelOutputs[2] - 125), 1); // stick max + trim min anaInValues[THR_STICK] = +1024; setTrimValue(0, THR_STICK, TRIM_MIN); evalMixes(1); EXPECT_EQ(channelOutputs[2], 250); // stick min + trim max anaInValues[THR_STICK] = -1024; setTrimValue(0, THR_STICK, TRIM_MAX); evalMixes(1); EXPECT_EQ(channelOutputs[2], 0); // stick min + trim mid anaInValues[THR_STICK] = -1024; setTrimValue(0, THR_STICK, 0); evalMixes(1); EXPECT_LE(abs(channelOutputs[2] - 125), 1); // stick min + trim min anaInValues[THR_STICK] = -1024; setTrimValue(0, THR_STICK, TRIM_MIN); evalMixes(1); EXPECT_EQ(channelOutputs[2], 250); // now some tests with extended Trims g_model.extendedTrims = 1; // trim min + various stick positions = should always be same value setTrimValue(0, THR_STICK, TRIM_EXTENDED_MIN); anaInValues[THR_STICK] = -1024; evalMixes(1); EXPECT_EQ(channelOutputs[2], 1000); anaInValues[THR_STICK] = -300; evalMixes(1); EXPECT_EQ(channelOutputs[2], 1000); anaInValues[THR_STICK] = +300; evalMixes(1); EXPECT_EQ(channelOutputs[2], 1000); anaInValues[THR_STICK] = +1024; evalMixes(1); EXPECT_EQ(channelOutputs[2], 1000); // trim max + various stick positions = should always be same value setTrimValue(0, THR_STICK, TRIM_EXTENDED_MAX); anaInValues[THR_STICK] = -1024; evalMixes(1); EXPECT_EQ(channelOutputs[2], 0); anaInValues[THR_STICK] = -300; evalMixes(1); EXPECT_EQ(channelOutputs[2], 0); anaInValues[THR_STICK] = +300; evalMixes(1); EXPECT_EQ(channelOutputs[2], 0); anaInValues[THR_STICK] = +1024; evalMixes(1); EXPECT_EQ(channelOutputs[2], 0); }
void menuModelPhaseOne(uint8_t event) { FlightModeData *fm = flightModeAddress(s_currIdx); putsFlightMode(13*FW, 0, s_currIdx+1, (getFlightMode()==s_currIdx ? BOLD : 0)); #if defined(GVARS) && !defined(PCBSTD) static const pm_uint8_t mstate_tab_fm1[] PROGMEM = {0, 0, 0, (uint8_t)-1, 1, 1, 1, 1, 1}; static const pm_uint8_t mstate_tab_others[] PROGMEM = {0, 0, 3, IF_ROTARY_ENCODERS(NUM_ROTARY_ENCODERS-1) 0, 0, (uint8_t)-1, 2, 2, 2, 2, 2}; check(event, 0, NULL, 0, (s_currIdx == 0) ? mstate_tab_fm1 : mstate_tab_others, DIM(mstate_tab_others)-1, ITEM_MODEL_PHASE_MAX - 1 - (s_currIdx==0 ? (ITEM_MODEL_PHASE_FADE_IN-ITEM_MODEL_PHASE_SWITCH) : 0)); TITLE(STR_MENUFLIGHTPHASE); #define PHASE_ONE_FIRST_LINE (1+1*FH) #else SUBMENU(STR_MENUFLIGHTPHASE, 3 + (s_currIdx==0 ? 0 : 2 + (bool)NUM_ROTARY_ENCODERS), {0, 0, 3, IF_ROTARY_ENCODERS(NUM_ROTARY_ENCODERS-1) 0/*, 0*/}); #define PHASE_ONE_FIRST_LINE (1+1*FH) #endif int8_t sub = m_posVert; int8_t editMode = s_editMode; #if defined(GVARS) && !defined(PCBSTD) if (s_currIdx == 0 && sub>=ITEM_MODEL_PHASE_SWITCH) sub += ITEM_MODEL_PHASE_FADE_IN-ITEM_MODEL_PHASE_SWITCH; for (uint8_t k=0; k<LCD_LINES-1; k++) { coord_t y = MENU_HEADER_HEIGHT + 1 + k*FH; int8_t i = k + s_pgOfs; if (s_currIdx == 0 && i>=ITEM_MODEL_PHASE_SWITCH) i += ITEM_MODEL_PHASE_FADE_IN-ITEM_MODEL_PHASE_SWITCH; uint8_t attr = (sub==i ? (editMode>0 ? BLINK|INVERS : INVERS) : 0); #else for (uint8_t i=0, k=0, y=PHASE_ONE_FIRST_LINE; i<ITEM_MODEL_PHASE_MAX; i++, k++, y+=FH) { if (s_currIdx == 0 && i==ITEM_MODEL_PHASE_SWITCH) i = ITEM_MODEL_PHASE_FADE_IN; uint8_t attr = (sub==k ? (editMode>0 ? BLINK|INVERS : INVERS) : 0); #endif switch(i) { case ITEM_MODEL_PHASE_NAME: editSingleName(MIXES_2ND_COLUMN, y, STR_PHASENAME, fm->name, sizeof(fm->name), event, attr); break; case ITEM_MODEL_PHASE_SWITCH: fm->swtch = switchMenuItem(MIXES_2ND_COLUMN, y, fm->swtch, attr, event); break; case ITEM_MODEL_PHASE_TRIMS: lcd_putsLeft(y, STR_TRIMS); for (uint8_t t=0; t<NUM_STICKS; t++) { putsTrimMode(MIXES_2ND_COLUMN+(t*FW), y, s_currIdx, t, m_posHorz==t ? attr : 0); if (attr && m_posHorz==t && ((editMode>0) || p1valdiff)) { int16_t v = getRawTrimValue(s_currIdx, t); if (v < TRIM_EXTENDED_MAX) v = TRIM_EXTENDED_MAX; v = checkIncDec(event, v, TRIM_EXTENDED_MAX, TRIM_EXTENDED_MAX+MAX_FLIGHT_MODES-1, EE_MODEL); if (checkIncDec_Ret) { if (v == TRIM_EXTENDED_MAX) v = 0; setTrimValue(s_currIdx, t, v); } } } break; #if ROTARY_ENCODERS > 0 case ITEM_MODEL_PHASE_ROTARY_ENCODERS: lcd_putsLeft(y, STR_ROTARY_ENCODER); for (uint8_t t=0; t<NUM_ROTARY_ENCODERS; t++) { putsRotaryEncoderMode(MIXES_2ND_COLUMN+(t*FW), y, s_currIdx, t, m_posHorz==t ? attr : 0); if (attr && m_posHorz==t && ((editMode>0) || p1valdiff)) { int16_t v = flightModeAddress(s_currIdx)->rotaryEncoders[t]; if (v < ROTARY_ENCODER_MAX) v = ROTARY_ENCODER_MAX; v = checkIncDec(event, v, ROTARY_ENCODER_MAX, ROTARY_ENCODER_MAX+MAX_FLIGHT_MODES-1, EE_MODEL); if (checkIncDec_Ret) { if (v == ROTARY_ENCODER_MAX) v = 0; flightModeAddress(s_currIdx)->rotaryEncoders[t] = v; } } } break; #endif case ITEM_MODEL_PHASE_FADE_IN: fm->fadeIn = EDIT_DELAY(0, y, event, attr, STR_FADEIN, fm->fadeIn); break; case ITEM_MODEL_PHASE_FADE_OUT: fm->fadeOut = EDIT_DELAY(0, y, event, attr, STR_FADEOUT, fm->fadeOut); break; #if defined(GVARS) && !defined(PCBSTD) case ITEM_MODEL_PHASE_GVARS_LABEL: lcd_putsLeft(y, STR_GLOBAL_VARS); break; default: { uint8_t idx = i-ITEM_MODEL_PHASE_GV1; uint8_t posHorz = m_posHorz; if (attr && posHorz > 0 && s_currIdx==0) posHorz++; putsStrIdx(INDENT_WIDTH, y, STR_GV, idx+1); editName(4*FW, y, g_model.gvars[idx].name, LEN_GVAR_NAME, event, posHorz==0 ? attr : 0); int16_t v = fm->gvars[idx]; if (v > GVAR_MAX) { uint8_t p = v - GVAR_MAX - 1; if (p >= s_currIdx) p++; putsFlightMode(11*FW, y, p+1, posHorz==1 ? attr : 0); } else { lcd_putsAtt(11*FW, y, STR_OWN, posHorz==1 ? attr : 0); } if (attr && s_currIdx>0 && posHorz==1 && (editMode>0 || p1valdiff)) { if (v < GVAR_MAX) v = GVAR_MAX; v = checkIncDec(event, v, GVAR_MAX, GVAR_MAX+MAX_FLIGHT_MODES-1, EE_MODEL); if (checkIncDec_Ret) { if (v == GVAR_MAX) v = 0; fm->gvars[idx] = v; } } uint8_t p = getGVarFlightPhase(s_currIdx, idx); lcd_outdezAtt(21*FW, y, GVAR_VALUE(idx, p), posHorz==2 ? attr : 0); if (attr && posHorz==2 && ((editMode>0) || p1valdiff)) { GVAR_VALUE(idx, p) = checkIncDec(event, GVAR_VALUE(idx, p), -GVAR_LIMIT, GVAR_LIMIT, EE_MODEL); } break; } #endif } } } #if defined(ROTARY_ENCODERS) #if ROTARY_ENCODERS > 2 #define NAME_OFS (-4-12) #define SWITCH_OFS (-FW/2-2-13) #define TRIMS_OFS (-FW/2-4-15) #define ROTARY_ENC_OFS (0) #else #define NAME_OFS (-4) #define SWITCH_OFS (-FW/2-2) #define TRIMS_OFS (-FW/2-4) #define ROTARY_ENC_OFS (2) #endif #else #define NAME_OFS 0 #define SWITCH_OFS (FW/2) #define TRIMS_OFS (FW/2) #endif void menuModelFlightModesAll(uint8_t event) { SIMPLE_MENU(STR_MENUFLIGHTPHASES, menuTabModel, e_FlightModesAll, 1+MAX_FLIGHT_MODES+1); int8_t sub = m_posVert - 1; switch (event) { CASE_EVT_ROTARY_BREAK case EVT_KEY_FIRST(KEY_ENTER): if (sub == MAX_FLIGHT_MODES) { s_editMode = 0; trimsCheckTimer = 200; // 2 seconds } // no break case EVT_KEY_FIRST(KEY_RIGHT): if (sub >= 0 && sub < MAX_FLIGHT_MODES) { s_currIdx = sub; pushMenu(menuModelPhaseOne); } break; } uint8_t att; for (uint8_t i=0; i<MAX_FLIGHT_MODES; i++) { #if defined(CPUARM) int8_t y = 1 + (1+i-s_pgOfs)*FH; if (y<1*FH+1 || y>(LCD_LINES-1)*FH+1) continue; #else uint8_t y = 1 + (i+1)*FH; #endif att = (i==sub ? INVERS : 0); FlightModeData *p = flightModeAddress(i); putsFlightMode(0, y, i+1, att|(getFlightMode()==i ? BOLD : 0)); lcd_putsnAtt(4*FW+NAME_OFS, y, p->name, sizeof(p->name), ZCHAR); if (i == 0) { lcd_puts((5+LEN_FLIGHT_MODE_NAME)*FW+SWITCH_OFS, y, STR_DEFAULT); } else { putsSwitches((5+LEN_FLIGHT_MODE_NAME)*FW+SWITCH_OFS, y, p->swtch, 0); for (uint8_t t=0; t<NUM_STICKS; t++) { putsTrimMode((9+LEN_FLIGHT_MODE_NAME+t)*FW+TRIMS_OFS, y, i, t, 0); } #if defined(CPUM2560) for (uint8_t t=0; t<NUM_ROTARY_ENCODERS; t++) { putsRotaryEncoderMode((13+LEN_FLIGHT_MODE_NAME+t)*FW+TRIMS_OFS+ROTARY_ENC_OFS, y, i, t, 0); } #endif } if (p->fadeIn || p->fadeOut) { lcd_putc(LCD_W-FW-MENUS_SCROLLBAR_WIDTH, y, (p->fadeIn && p->fadeOut) ? '*' : (p->fadeIn ? 'I' : 'O')); } } #if defined(CPUARM) if (s_pgOfs != MAX_FLIGHT_MODES-(LCD_LINES-2)) return; #endif lcd_putsLeft((LCD_LINES-1)*FH+1, STR_CHECKTRIMS); putsFlightMode(OFS_CHECKTRIMS, (LCD_LINES-1)*FH+1, mixerCurrentFlightMode+1); if (sub==MAX_FLIGHT_MODES && !trimsCheckTimer) { lcd_status_line(); } }
void OpenTxSimulator::setTrim(unsigned int idx, int value) { idx = NAMESPACE::modn12x3[4*getStickMode() + idx]; ::uint8_t phase = getTrimFlightPhase(getFlightMode(), idx); setTrimValue(phase, idx, value); }
uint8_t Translate() { if (g_eeGeneral.myVers == 0) { if (theFile.readRlc1((uint8_t*)&g_eeGeneral, 1) != 1) return 0; theFile.openRlc(FILE_GENERAL); } if (g_eeGeneral.myVers == EEPROM_VER_r584 || (g_eeGeneral.myVers >= EEPROM_ER9X_MIN && g_eeGeneral.myVers <= EEPROM_ER9X_MAX)) { alert(g_eeGeneral.myVers == EEPROM_VER_r584 ? PSTR("EEprom Data v3") : PSTR("EEprom Data Er9x"), true); message(PSTR("EEPROM Converting")); theFile.readRlc1((uint8_t*)&g_eeGeneral, sizeof(g_eeGeneral)); memset(&g_eeGeneral.frskyRssiAlarms, 0, sizeof(g_eeGeneral.frskyRssiAlarms)); if (g_eeGeneral.myVers == EEPROM_VER_r584) { // previous version had only 6 custom switches, OFF and ON values have to be shifted 6 if (g_eeGeneral.lightSw == MAX_SWITCH-6) g_eeGeneral.lightSw += 6; if (g_eeGeneral.lightSw == -MAX_SWITCH+6) g_eeGeneral.lightSw -= 6; } else { g_eeGeneral.inactivityTimer += 10; } g_eeGeneral.view = 0; // will not translate the view index EEPROM_V3::EEGeneral *old = (EEPROM_V3::EEGeneral *)&g_eeGeneral; g_eeGeneral.disableMemoryWarning = old->disableMemoryWarning; g_eeGeneral.switchWarning = old->disableSwitchWarning ? 0 : -1; for (uint8_t i=0; i<4; i++) { g_eeGeneral.trainer.mix[i].srcChn = old->trainer.mix[i].srcChn; g_eeGeneral.trainer.mix[i].mode = old->trainer.mix[i].mode; g_eeGeneral.trainer.mix[i].studWeight = old->trainer.mix[i].studWeight * 13 / 4; } for (uint8_t id=0; id<MAX_MODELS; id++) { theFile.openRlc(FILE_MODEL(id)); uint16_t sz = theFile.readRlc1((uint8_t*)&g_model, sizeof(EEPROM_V4::ModelData)); if(sz > 0) { EEPROM_V4::ModelData *v4 = (EEPROM_V4::ModelData *)&g_model; EEPROM_V3::ModelData *v3 = (EEPROM_V3::ModelData *)&g_model; SwashRingData swashR; swashR.invertELE = v4->swashInvertELE; swashR.invertAIL = v4->swashInvertAIL; swashR.invertCOL = v4->swashInvertCOL; swashR.type = v4->swashType; swashR.collectiveSource = v4->swashCollectiveSource; swashR.value = v4->swashRingValue; int8_t trims[4]; memcpy(&trims[0], &v3->trim[0], 4); int8_t trimSw = v3->trimSw; for (uint8_t i=0; i<10; i++) g_model.name[i] = char2idx(g_model.name[i]); g_model.timer1.mode = v3->tmrMode; g_model.timer1.dir = v3->tmrDir; g_model.timer1.val = v3->tmrVal; g_model.protocol = v3->protocol; g_model.ppmNCH = v3->ppmNCH; g_model.thrTrim = v3->thrTrim; g_model.trimInc = v3->trimInc; g_model.pulsePol = v3->pulsePol; if (g_eeGeneral.myVers == EEPROM_VER_r584) g_model.extendedLimits = 0; else g_model.extendedLimits = v4->extendedLimits; g_model.extendedTrims = 0; g_model.spare2 = 0; g_model.ppmDelay = v3->ppmDelay; g_model.beepANACenter = v3->beepANACenter; g_model.timer2.mode = 0; g_model.timer2.dir = 0; g_model.timer2.val = 0; for (uint8_t i=0; i<MAX_MIXERS; i++) { memmove(&g_model.mixData[i], &v3->mixData[i], sizeof(MixData)); // MixData size changed! g_model.mixData[i].mixWarn = g_model.mixData[i].phase; g_model.mixData[i].phase = 0; if (g_eeGeneral.myVers == EEPROM_VER_r584 && g_model.mixData[i].srcRaw > MIX_FULL) { g_model.mixData[i].srcRaw += 3; /* because of [CYC1:CYC3] inserted after MIX_FULL */ } } assert((char *)&g_model.limitData[0] < (char *)&v3->limitData[0]); memmove(&g_model.limitData[0], &v3->limitData[0], sizeof(LimitData)*NUM_CHNOUT); assert((char *)&g_model.expoData[0] < (char *)v3->expoData); EEPROM_V4::ExpoData expo4[4]; memcpy(&expo4[0], &v4->expoData[0], sizeof(expo4)); memset(&g_model.expoData[0], 0, sizeof(expo4)); // expos conversion uint8_t e = 0; for (uint8_t ch = 0; ch < 4 && e < MAX_EXPOS; ch++) { for (uint8_t dr = 0, pos = 0; dr < 3 && e < MAX_EXPOS; dr++, pos++) { if ((dr == 0 && !expo4[ch].drSw1) || (dr == 1 && !expo4[ch].drSw2)) dr = 2; if (dr == 2 && !expo4[ch].expo[0][0][0] && !expo4[ch].expo[0][0][1] && !expo4[ch].expo[0][1][0] && !expo4[ch].expo[0][1][1]) break; g_model.expoData[e].swtch = (dr == 0 ? -expo4[ch].drSw1 : (dr == 1 ? -expo4[ch].drSw2 : 0)); g_model.expoData[e].chn = ch; g_model.expoData[e].expo = expo4[ch].expo[pos][0][0]; g_model.expoData[e].weight = 100 + expo4[ch].expo[pos][1][0]; if (expo4[ch].expo[pos][0][0] == expo4[ch].expo[pos][0][1] && expo4[ch].expo[pos][1][0] == expo4[ch].expo[pos][1][1]) { g_model.expoData[e++].mode = 3; } else { g_model.expoData[e].mode = 2; if (e < MAX_EXPOS - 1) { g_model.expoData[e + 1].swtch = g_model.expoData[e].swtch; g_model.expoData[++e].chn = ch; g_model.expoData[e].mode = 1; g_model.expoData[e].expo = expo4[ch].expo[pos][0][1]; g_model.expoData[e++].weight = 100 + expo4[ch].expo[pos][1][1]; } } } } assert((char *)&g_model.curves5[0][0] < (char *)&v3->curves5[0][0]); memmove(&g_model.curves5[0][0], &v3->curves5[0][0], 5*MAX_CURVE5); assert((char *)&g_model.curves9[0][0] < (char *)&v3->curves9[0][0]); memmove(&g_model.curves9[0][0], &v3->curves9[0][0], 9*MAX_CURVE9); if (g_eeGeneral.myVers == EEPROM_VER_r584) { memmove(&g_model.customSw[0], &v3->customSw[0], sizeof(CustomSwData)*6); memset(&g_model.customSw[6], 0, sizeof(CustomSwData)*6); memset(&g_model.safetySw[0], 0, sizeof(SafetySwData)*NUM_CHNOUT + sizeof(SwashRingData) + sizeof(FrSkyData)); } else { assert((char *)&g_model.customSw[0] < (char *)&v4->customSw[0]); memmove(&g_model.customSw[0], &v4->customSw[0], sizeof(CustomSwData)*12); assert((char *)&g_model.safetySw[0] < (char *)&v4->safetySw[0]); memmove(&g_model.safetySw[0], &v4->safetySw[0], sizeof(SafetySwData)*NUM_CHNOUT); memcpy(&g_model.swashR, &swashR, sizeof(SwashRingData)); for (uint8_t i=0; i<2; i++) { // TODO this conversion is bad // assert(&g_model.frsky.channels[i].ratio < &v4->frsky.channels[i].ratio); g_model.frsky.channels[i].ratio = v4->frsky.channels[i].ratio; g_model.frsky.channels[i].type = v4->frsky.channels[i].type; // g_model.frsky.channels[i].offset = 0; g_model.frsky.channels[i].alarms_value[0] = v4->frsky.channels[i].alarms_value[0]; g_model.frsky.channels[i].alarms_value[1] = v4->frsky.channels[i].alarms_value[1]; g_model.frsky.channels[i].alarms_level = v4->frsky.channels[i].alarms_level; g_model.frsky.channels[i].alarms_greater = v4->frsky.channels[i].alarms_greater; g_model.frsky.channels[i].barMin = 0; g_model.frsky.channels[i].barMax = 0; } } memset(&g_model.phaseData[0], 0, sizeof(g_model.phaseData)); memset(&g_model.funcSw[0], 0, sizeof(g_model.funcSw)); if (trimSw) { g_model.funcSw[0].swtch = trimSw; g_model.funcSw[0].func = FUNC_INSTANT_TRIM; } for (uint8_t i=0; i<NUM_STICKS; i++) setTrimValue(0, i, trims[i]); g_model.ppmFrameLength = 0; theFile.writeRlc(FILE_MODEL(id), FILE_TYP_MODEL, (uint8_t*)&g_model, sizeof(g_model), 200); } } g_eeGeneral.myVers = EEPROM_VER; theFile.writeRlc(FILE_GENERAL, FILE_TYP_GENERAL, (uint8_t*)&g_eeGeneral, sizeof(EEGeneral), 200); return sizeof(EEGeneral); } return 0; }