void varioWakeup() { static tmr10ms_t s_varioTmr; tmr10ms_t tmr10ms = get_tmr10ms(); if (isFunctionActive(FUNC_VARIO)) { #if defined(AUDIO) cli(); int16_t verticalSpeed = frskyData.hub.varioSpeed; sei(); #if defined(PCBSTD) int16_t varioCenterMax = (int16_t)g_model.frsky.varioCenterMax * 10 + 50; if (verticalSpeed >= varioCenterMax) { verticalSpeed = verticalSpeed - varioCenterMax; int16_t varioMax = (10+(int16_t)g_model.frsky.varioMax) * 100; if (verticalSpeed > varioMax) verticalSpeed = varioMax; verticalSpeed = (verticalSpeed * 10) / ((varioMax-varioCenterMax) / 100); if ((int16_t)(s_varioTmr-tmr10ms) < 0) { uint8_t SoundVarioBeepTime = (1600 - verticalSpeed) / 100; uint8_t SoundVarioBeepFreq = (verticalSpeed * 10 + 16000) >> 8; s_varioTmr = tmr10ms + (SoundVarioBeepTime*2); AUDIO_VARIO(SoundVarioBeepFreq, SoundVarioBeepTime); } }
void eeDirty(uint8_t msk) { uint8_t lmask = msk & 7 ; if(!lmask) return; s_eeDirtyMsk |= lmask; s_eeDirtyTime10ms = get_tmr10ms() ; s_eeLongTimer = msk >> 4 ; }
void displayMixLine(coord_t y, MixData *md) { if (md->name[0]) lcd_putsnAtt(EXPO_LINE_NAME_POS, y, md->name, sizeof(md->name), ZCHAR); if (!md->flightModes || ((md->curve.value || md->swtch) && ((get_tmr10ms() / 200) & 1))) displayMixInfos(y, md); else displayFlightModes(MIX_LINE_FM_POS, y, md->flightModes); }
void setRotarySwIdx(int8_t idx) { if (rotarySwIdx != idx) { rotarySwIdx = idx; if (rotarySwIdx >= 0) { rotarySwChanged = (get_tmr10ms() >> 3) + 3; #ifdef MAVLINK uint8_t send = g_model.rotarySw[rotarySwIdx].typeRotary == ROTARY_TYPE_MAVLINK ? 1 : 0; MAVLINK_ReqMode(g_model.rotarySw[rotarySwIdx].numMode, send); #endif }
void displayExpoLine(coord_t y, ExpoData *ed) { putsMixerSource(EXPO_LINE_SRC_POS, y, ed->srcRaw, 0); if (ed->carryTrim != TRIM_ON) { lcd_putc(EXPO_LINE_TRIM_POS, y, ed->carryTrim > 0 ? '-' : STR_RETA123[-ed->carryTrim]); } if (!ed->flightModes || ((ed->curve.value || ed->swtch) && ((get_tmr10ms() / 200) & 1))) displayExpoInfos(y, ed); else displayFlightModes(EXPO_LINE_FM_POS, y, ed->flightModes); if (ed->name[0]) { lcd_putsnAtt(EXPO_LINE_NAME_POS, y, ed->name, sizeof(ed->name), ZCHAR); } }
/* ON / OFF version */ lcd_putsiAtt(x, y, STR_OFFON, value, attr ? INVERS:0) ; #endif } void displayScreenIndex(uint8_t index, uint8_t count, uint8_t attr) { lcd_outdezAtt(LCD_W, 0, count, attr); xcoord_t x = 1+LCD_W-FW*(count>9 ? 3 : 2); lcd_putcAtt(x, 0, '/', attr); lcd_outdezAtt(x, 0, index+1, attr); } #if !defined(CPUM64) void displayScrollbar(xcoord_t x, uint8_t y, uint8_t h, uint16_t offset, uint16_t count, uint8_t visible) { lcd_vlineStip(x, y, h, SOLID, ERASE); lcd_vlineStip(x, y, h, DOTTED); uint8_t yofs = (h * offset) / count; uint8_t yhgt = (h * visible) / count; if (yhgt + yofs > h) yhgt = h - yofs; lcd_vlineStip(x, y + yofs, yhgt, SOLID, FORCE); } #endif #if defined(NAVIGATION_POT1) int16_t p1valdiff; #endif #if defined(NAVIGATION_POT2) int8_t p2valdiff; #endif uint8_t switchToMix(uint8_t source) { #if defined(PCBTARANIS) if (source <= 5*3) return MIXSRC_FIRST_SWITCH + (source-1) / 3; else if (source <= 17) return MIXSRC_SF; else if (source <= 20) return MIXSRC_SG; else return MIXSRC_SH; #else if (source <= 3) return MIXSRC_3POS; else return MIXSRC_FIRST_SWITCH - 3 + source; #endif } int8_t checkIncDec_Ret; #if defined(CPUARM) int16_t checkIncDec(uint8_t event, int16_t val, int16_t i_min, int16_t i_max, uint8_t i_flags, IsValueAvailable isValueAvailable) #else int16_t checkIncDec(uint8_t event, int16_t val, int16_t i_min, int16_t i_max, uint8_t i_flags) #endif { int16_t newval = val; #if defined(DBLKEYS) uint8_t in = KEYS_PRESSED(); if (EVT_KEY_MASK(event)) { bool dblkey = true; if (DBLKEYS_PRESSED_RGT_LFT(in)) newval = -val; else if (DBLKEYS_PRESSED_RGT_UP(in)) { newval = (i_max > 100 ? 100 : i_max); #if defined(CPUARM) if (i_flags & DBLKEYS_1000) newval *= 10; #endif } else if (DBLKEYS_PRESSED_LFT_DWN(in)) { newval = (i_min < -100 ? -100 : i_min); #if defined(CPUARM) if (i_flags & DBLKEYS_1000) newval *= 10; #endif } else if (DBLKEYS_PRESSED_UP_DWN(in)) newval = 0; else dblkey = false; #if defined(CPUARM) #endif if (dblkey) { killEvents(KEY_UP); killEvents(KEY_DOWN); killEvents(KEY_RIGHT); killEvents(KEY_LEFT); #if defined(PCBTARANIS) killEvents(KEY_PAGE); killEvents(KEY_MENU); killEvents(KEY_ENTER); killEvents(KEY_EXIT); #endif event = 0; } } #endif #if defined(PCBTARANIS) if (s_editMode>0 && (IS_ROTARY_RIGHT(event) || event==EVT_KEY_FIRST(KEY_UP) || event==EVT_KEY_REPT(KEY_UP))) { #else if (event==EVT_KEY_FIRST(KEY_RIGHT) || event==EVT_KEY_REPT(KEY_RIGHT) || (s_editMode>0 && (IS_ROTARY_RIGHT(event) || event==EVT_KEY_FIRST(KEY_UP) || event==EVT_KEY_REPT(KEY_UP)))) { #endif #if defined(CPUARM) do { if (IS_KEY_REPT(event) && (i_flags & INCDEC_REP10)) { newval += min(10, i_max-val); } else { newval++; } } while (isValueAvailable && !isValueAvailable(newval) && newval<=i_max); if (newval > i_max) { newval = val; killEvents(event); AUDIO_WARNING2(); } else #else newval++; #endif AUDIO_KEYPAD_UP(); } #if defined(PCBTARANIS) else if (s_editMode>0 && (IS_ROTARY_LEFT(event) || event==EVT_KEY_FIRST(KEY_DOWN) || event==EVT_KEY_REPT(KEY_DOWN))) { #else else if (event==EVT_KEY_FIRST(KEY_LEFT) || event==EVT_KEY_REPT(KEY_LEFT) || (s_editMode>0 && (IS_ROTARY_LEFT(event) || event==EVT_KEY_FIRST(KEY_DOWN) || event==EVT_KEY_REPT(KEY_DOWN)))) { #endif #if defined(CPUARM) do { if (IS_KEY_REPT(event) && (i_flags & INCDEC_REP10)) { newval -= min(10, val-i_min); } else { newval--; } } while (isValueAvailable && !isValueAvailable(newval) && newval>=i_min); if (newval < i_min) { newval = val; killEvents(event); AUDIO_WARNING2(); } else #else newval--; #endif AUDIO_KEYPAD_DOWN(); } if (!READ_ONLY() && i_min==0 && i_max==1 && (event==EVT_KEY_BREAK(KEY_ENTER) || IS_ROTARY_BREAK(event))) { s_editMode = 0; newval = !val; } #if defined(NAVIGATION_POT1) // change values based on P1 newval -= p1valdiff; p1valdiff = 0; #endif #if defined(AUTOSWITCH) if (i_flags & INCDEC_SWITCH) { if (s_editMode>0) { int8_t swtch = getMovedSwitch(); if (swtch) { #if defined(PCBTARANIS) if(swtch == SWSRC_SH2) newval = (newval == SWSRC_SH2 ? SWSRC_SH0 : SWSRC_SH2); else if(swtch != SWSRC_SH0) newval = swtch; #else if (IS_MOMENTARY(newval) && IS_MOMENTARY(swtch)) newval = -newval; else newval = swtch; #endif } } } #endif #if defined(AUTOSOURCE) if (i_flags & INCDEC_SOURCE) { if (s_editMode>0) { int8_t source = GET_MOVED_SOURCE(i_min, i_max); if (source) { newval = source; } #if defined(AUTOSWITCH) else { uint8_t swtch = abs(getMovedSwitch()); if (swtch) { newval = switchToMix(swtch); } } #endif } } #endif if (newval > i_max || newval < i_min) { newval = (newval > i_max ? i_max : i_min); killEvents(event); AUDIO_WARNING2(); } if (newval != val) { if (!(i_flags & NO_INCDEC_MARKS) && (newval != i_max) && (newval != i_min) && (newval==0 || newval==-100 || newval==+100) && !IS_ROTARY_EVENT(event)) { pauseEvents(event); // delay before auto-repeat continues if (newval>val) // without AUDIO it's optimized, because the 2 sounds are the same AUDIO_KEYPAD_UP(); else AUDIO_KEYPAD_DOWN(); } eeDirty(i_flags & (EE_GENERAL|EE_MODEL)); checkIncDec_Ret = (newval > val ? 1 : -1); } else { checkIncDec_Ret = 0; } return newval; } #if defined(CPUM64) int8_t checkIncDecModel(uint8_t event, int8_t i_val, int8_t i_min, int8_t i_max) { return checkIncDec(event, i_val, i_min, i_max, EE_MODEL); } int8_t checkIncDecModelZero(uint8_t event, int8_t i_val, int8_t i_max) { return checkIncDecModel(event, i_val, 0, i_max); } int8_t checkIncDecGen(uint8_t event, int8_t i_val, int8_t i_min, int8_t i_max) { return checkIncDec(event, i_val, i_min, i_max, EE_GENERAL); } #endif bool check_simple(check_event_t event, uint8_t curr, const MenuFuncP *menuTab, uint8_t menuTabSize, vertpos_t maxrow) { return check(event, curr, menuTab, menuTabSize, 0, 0, maxrow); } bool check_submenu_simple(check_event_t event, uint8_t maxrow) { return check_simple(event, 0, 0, 0, maxrow); } void title(const pm_char * s) { lcd_putsAtt(0, 0, s, INVERS); } #define SCROLL_TH 64 #define SCROLL_POT1_TH 32 #if defined(CPUARM) #define CURSOR_NOT_ALLOWED_IN_ROW(row) ((int8_t)MAXCOL(row) < 0) #else #define CURSOR_NOT_ALLOWED_IN_ROW(row) (MAXCOL(row) == TITLE_ROW) #endif #if defined(PCBTARANIS) #define MAXCOL_RAW(row) (horTab ? pgm_read_byte(horTab+min(row, (vertpos_t)horTabMax)) : (const uint8_t)0) #define MAXCOL(row) (MAXCOL_RAW(row) >= HIDDEN_ROW ? MAXCOL_RAW(row) : (const uint8_t)(MAXCOL_RAW(row) & (~NAVIGATION_LINE_BY_LINE))) #define COLATTR(row) (MAXCOL_RAW(row) == (uint8_t)-1 ? (const uint8_t)0 : (const uint8_t)(MAXCOL_RAW(row) & NAVIGATION_LINE_BY_LINE)) #else #define MAXCOL(row) (horTab ? pgm_read_byte(horTab+min(row, (vertpos_t)horTabMax)) : (const uint8_t)0) #endif #define INC(val, min, max) if (val<max) {val++;} else {val=min;} #define DEC(val, min, max) if (val>min) {val--;} else {val=max;} #if LCD_W >= 212 uint8_t scrollbar_X = LCD_W-1; #endif #if defined(CPUARM) bool modelHasNotes() { char filename[sizeof(MODELS_PATH)+1+sizeof(g_model.header.name)+sizeof(TEXT_EXT)] = MODELS_PATH "/"; char *buf = strcat_modelname(&filename[sizeof(MODELS_PATH)], g_eeGeneral.currModel); strcpy(buf, TEXT_EXT); return isFileAvailable(filename); } void pushModelNotes() { char filename[sizeof(MODELS_PATH)+1+sizeof(g_model.header.name)+sizeof(TEXT_EXT)] = MODELS_PATH "/"; char *buf = strcat_modelname(&filename[sizeof(MODELS_PATH)], g_eeGeneral.currModel); strcpy(buf, TEXT_EXT); pushMenuTextView(filename); } #endif #if defined(PCBTARANIS) void onLongMenuPress(const char *result) { if (result == STR_VIEW_CHANNELS) { pushMenu(menuChannelsView); } else if (result == STR_VIEW_NOTES) { pushModelNotes(); } } #endif #if defined(CPUARM) tmr10ms_t menuEntryTime; #endif #if defined(PCBTARANIS) bool check(check_event_t event, uint8_t curr, const MenuFuncP *menuTab, uint8_t menuTabSize, const pm_uint8_t *horTab, uint8_t horTabMax, vertpos_t maxrow, uint8_t flags) { vertpos_t l_posVert = m_posVert; horzpos_t l_posHorz = m_posHorz; uint8_t maxcol = MAXCOL(l_posVert); #define scrollUD 0 if (p2valdiff || scrollUD || p1valdiff) backlightOn(); // on keypress turn the light on if (menuTab) { uint8_t attr = 0; int8_t cc = curr; switch (event) { case EVT_KEY_LONG(KEY_MENU): if (menuTab == menuTabModel) { killEvents(event); if (modelHasNotes()) { MENU_ADD_SD_ITEM(STR_VIEW_CHANNELS); MENU_ADD_ITEM(STR_VIEW_NOTES); menuHandler = onLongMenuPress; } else { pushMenu(menuChannelsView); return false; } } break; case EVT_KEY_LONG(KEY_PAGE): if (curr > 0) cc = curr - 1; else cc = menuTabSize-1; killEvents(event); break; case EVT_KEY_BREAK(KEY_PAGE): if (curr < (menuTabSize-1)) cc = curr + 1; else cc = 0; break; } if (!calibrationState && cc != curr) { chainMenu((MenuFuncP)pgm_read_adr(&menuTab[cc])); return false; } if (!(flags&CHECK_FLAG_NO_SCREEN_INDEX)) { displayScreenIndex(curr, menuTabSize, attr); } lcd_filled_rect(0, 0, LCD_W, FH, SOLID, FILL_WHITE|GREY_DEFAULT); } DISPLAY_PROGRESS_BAR(menuTab ? lcdLastPos-2*FW-((curr+1)/10*FWNUM)-2 : 20*FW+1); if (s_editMode<=0) { if (scrollUD) { l_posVert = limit((int8_t)0, (int8_t)(l_posVert - scrollUD), (int8_t)maxrow); l_posHorz = min((uint8_t)l_posHorz, MAXCOL(l_posVert)); } if (p2valdiff && l_posVert>0) { l_posHorz = limit((int8_t)0, (int8_t)((uint8_t)l_posHorz - p2valdiff), (int8_t)maxcol); } } switch(event) { case EVT_ENTRY: menuEntryTime = get_tmr10ms(); l_posVert = POS_VERT_INIT; l_posHorz = POS_HORZ_INIT(l_posVert); SET_SCROLLBAR_X(LCD_W-1); #if defined(ROTARY_ENCODER_NAVIGATION) if (menuTab) { s_editMode = EDIT_MODE_INIT; break; } // no break #else s_editMode = EDIT_MODE_INIT; break; #endif case EVT_ENTRY_UP: menuEntryTime = get_tmr10ms(); s_editMode = 0; l_posHorz = POS_HORZ_INIT(l_posVert); SET_SCROLLBAR_X(LCD_W-1); break; case EVT_ROTARY_BREAK: if (s_editMode > 1) break; if (m_posHorz < 0 && maxcol > 0 && READ_ONLY_UNLOCKED()) { l_posHorz = 0; break; } if (!menuTab || l_posVert>0) { if (READ_ONLY_UNLOCKED()) { s_editMode = (s_editMode<=0); } } break; #if defined(ROTARY_ENCODER_NAVIGATION) case EVT_ROTARY_LONG: if (s_editMode > 1) break; killEvents(event); if (l_posVert != POS_VERT_INIT) { l_posVert = POS_VERT_INIT; s_editMode = EDIT_MODE_INIT; break; } // no break #endif case EVT_KEY_LONG(KEY_EXIT): s_editMode = 0; // TODO needed? we call ENTRY_UP after which does the same popMenu(); return false; case EVT_KEY_BREAK(KEY_EXIT): #if defined(ROTARY_ENCODER_NAVIGATION) if (s_editMode == 0) s_editMode = EDIT_MODE_INIT; else #endif if (s_editMode>0) { s_editMode = 0; break; } if (l_posHorz >= 0 && (COLATTR(l_posVert) & NAVIGATION_LINE_BY_LINE)) { l_posHorz = -1; } else { uint8_t posVertInit = POS_VERT_INIT; if (s_pgOfs != 0 || l_posVert != posVertInit) { s_pgOfs = 0; l_posVert = posVertInit; l_posHorz = POS_HORZ_INIT(l_posVert); } else { popMenu(); return false; } } break; CASE_EVT_ROTARY_MOVE_RIGHT if (s_editMode != 0) break; if ((COLATTR(l_posVert) & NAVIGATION_LINE_BY_LINE)) { if (l_posHorz >= 0) { INC(l_posHorz, 0, maxcol); break; } } else { if (l_posHorz < maxcol) { l_posHorz++; break; } else { l_posHorz = 0; if (!IS_ROTARY_MOVE_RIGHT(event)) break; } } do { INC(l_posVert, POS_VERT_INIT, maxrow); } while (CURSOR_NOT_ALLOWED_IN_ROW(l_posVert)); s_editMode = 0; // if we go down, we must be in this mode l_posHorz = POS_HORZ_INIT(l_posVert); break; CASE_EVT_ROTARY_MOVE_LEFT if (s_editMode != 0) break; if ((COLATTR(l_posVert) & NAVIGATION_LINE_BY_LINE)) { if (l_posHorz >= 0) { DEC(l_posHorz, 0, maxcol); break; } } else { if (l_posHorz > 0) { l_posHorz--; break; } else if (IS_ROTARY_MOVE_LEFT(event) && s_editMode == 0) { l_posHorz = 0xff; } else { l_posHorz = maxcol; break; } } do { DEC(l_posVert, POS_VERT_INIT, maxrow); } while (CURSOR_NOT_ALLOWED_IN_ROW(l_posVert)); s_editMode = 0; // if we go up, we must be in this mode if ((COLATTR(l_posVert) & NAVIGATION_LINE_BY_LINE)) l_posHorz = -1; else l_posHorz = min((uint8_t)l_posHorz, MAXCOL(l_posVert)); break; } #if defined(CPUARM) if (l_posVert<1) { s_pgOfs=0; } else if (menuTab && horTab) { if (maxrow > LCD_LINES-1) { while (1) { vertpos_t line = s_pgOfs+1; for (int numLines=0; line<=maxrow && numLines<LCD_LINES-1; line++) { if (MAXCOL(line) != HIDDEN_ROW) { numLines++; } } int max = line - s_pgOfs - 1; if (l_posVert > max+s_pgOfs) { s_pgOfs++; } else if (l_posVert < 1+s_pgOfs) { s_pgOfs--; } else { break; } } } } else { uint8_t max = menuTab ? LCD_LINES-1 : LCD_LINES-2; if (l_posVert>max+s_pgOfs) { s_pgOfs = l_posVert-max; } else if (l_posVert<1+s_pgOfs) { s_pgOfs = l_posVert-1; } } #if LCD_W >= 212 if (maxrow > LCD_LINES-1 && scrollbar_X) displayScrollbar(scrollbar_X, FH, LCD_H-FH, s_pgOfs, menuTab ? maxrow : maxrow+1, LCD_LINES-1); #endif #else uint8_t max = menuTab ? LCD_LINES-1 : LCD_LINES-2; if (l_posVert<1) s_pgOfs=0; else if (l_posVert>max+s_pgOfs) s_pgOfs = l_posVert-max; else if (l_posVert<1+s_pgOfs) s_pgOfs = l_posVert-1; #endif m_posVert = l_posVert; m_posHorz = l_posHorz; if (s_pgOfs > 0) { l_posVert--; if (l_posVert == s_pgOfs && CURSOR_NOT_ALLOWED_IN_ROW(l_posVert)) { s_pgOfs = l_posVert-1; } } return true; } #else // defined(PCBTARANIS) bool check(check_event_t event, uint8_t curr, const MenuFuncP *menuTab, uint8_t menuTabSize, const pm_uint8_t *horTab, uint8_t horTabMax, vertpos_t maxrow) { vertpos_t l_posVert = m_posVert; horzpos_t l_posHorz = m_posHorz; uint8_t maxcol = MAXCOL(l_posVert); #if defined(NAVIGATION_POT1) // check pot 1 - if changed -> scroll values static int16_t p1val; static int16_t p1valprev; p1valdiff = (p1val-calibratedStick[6]) / SCROLL_POT1_TH; if (p1valdiff) { p1valdiff = (p1valprev-calibratedStick[6]) / 2; p1val = calibratedStick[6]; } p1valprev = calibratedStick[6]; #endif #if defined(NAVIGATION_POT2) // check pot 2 - if changed -> scroll menu static int16_t p2valprev; p2valdiff = (p2valprev-calibratedStick[4]) / SCROLL_TH; if (p2valdiff) p2valprev = calibratedStick[4]; #endif #if defined(NAVIGATION_POT3) // check pot 3 if changed -> cursor down/up static int16_t p3valprev; int8_t scrollUD = (p3valprev-calibratedStick[5]) / SCROLL_TH; if (scrollUD) p3valprev = calibratedStick[5]; #else #define scrollUD 0 #endif if (p2valdiff || scrollUD || p1valdiff) backlightOn(); // on keypress turn the light on if (menuTab) { uint8_t attr = 0; if (l_posVert==0 && !calibrationState) { attr = INVERS; int8_t cc = curr; if (p2valdiff) { cc = limit((int8_t)0, (int8_t)(cc - p2valdiff), (int8_t)(menuTabSize-1)); } switch(event) { #if defined(ROTARY_ENCODER_NAVIGATION) case EVT_ROTARY_BREAK: if (s_editMode < 0 && maxrow > 0) { s_editMode = 0; // TODO ? l_posVert = (horTab && horTab[1]==0xff) ? 2 : 1; l_posHorz = 0; } else { s_editMode = -1; } event = 0; break; #endif #if defined(ROTARY_ENCODER_NAVIGATION) case EVT_ROTARY_LEFT: if (s_editMode >= 0) break; #endif case EVT_KEY_FIRST(KEY_LEFT): if (curr > 0) cc = curr - 1; else cc = menuTabSize-1; break; #if defined(ROTARY_ENCODER_NAVIGATION) case EVT_ROTARY_RIGHT: if (s_editMode >= 0) break; #endif case EVT_KEY_FIRST(KEY_RIGHT): if (curr < (menuTabSize-1)) cc = curr + 1; else cc = 0; break; } if (cc != curr) { chainMenu((MenuFuncP)pgm_read_adr(&menuTab[cc])); return false; } #if defined(ROTARY_ENCODER_NAVIGATION) if (IS_RE_NAVIGATION_ENABLE() && s_editMode < 0) attr = INVERS|BLINK; #endif } calibrationState = 0; displayScreenIndex(curr, menuTabSize, attr); } DISPLAY_PROGRESS_BAR(menuTab ? lcdLastPos-2*FW-((curr+1)/10*FWNUM)-2 : 20*FW+1); if (s_editMode<=0) { if (scrollUD) { l_posVert = limit((int8_t)0, (int8_t)(l_posVert - scrollUD), (int8_t)maxrow); l_posHorz = min((uint8_t)l_posHorz, MAXCOL(l_posVert)); } if (p2valdiff && l_posVert>0) { l_posHorz = limit((int8_t)0, (int8_t)((uint8_t)l_posHorz - p2valdiff), (int8_t)maxcol); } } switch(event) { case EVT_ENTRY: #if defined(CPUARM) menuEntryTime = get_tmr10ms(); #endif l_posVert = POS_VERT_INIT; l_posHorz = POS_HORZ_INIT(l_posVert); SET_SCROLLBAR_X(LCD_W-1); #if defined(ROTARY_ENCODER_NAVIGATION) if (menuTab) { s_editMode = EDIT_MODE_INIT; break; } // no break #else s_editMode = EDIT_MODE_INIT; break; #endif #if defined(ROTARY_ENCODER_NAVIGATION) case EVT_ENTRY_UP: s_editMode = 0; SET_SCROLLBAR_X(LCD_W-1); break; case EVT_ROTARY_BREAK: if (s_editMode > 1) break; #endif case EVT_KEY_FIRST(KEY_ENTER): if (!menuTab || l_posVert>0) { if (READ_ONLY_UNLOCKED()) { s_editMode = (s_editMode<=0); } } break; #if defined(ROTARY_ENCODER_NAVIGATION) case EVT_ROTARY_LONG: if (s_editMode > 1) break; killEvents(event); if (l_posVert != POS_VERT_INIT) { l_posVert = POS_VERT_INIT; s_editMode = EDIT_MODE_INIT; break; } // no break #endif case EVT_KEY_LONG(KEY_EXIT): s_editMode = 0; // TODO needed? we call ENTRY_UP after which does the same popMenu(); return false; case EVT_KEY_BREAK(KEY_EXIT): #if defined(ROTARY_ENCODER_NAVIGATION) if (s_editMode == 0) s_editMode = EDIT_MODE_INIT; else #endif if (s_editMode>0) { s_editMode = 0; break; } if (l_posVert==0 || !menuTab) { popMenu(); // beeps itself return false; } else { AUDIO_MENUS(); l_posVert = 0; l_posHorz = 0; } break; case EVT_KEY_REPT(KEY_RIGHT): //inc if (l_posHorz==maxcol) break; // no break case EVT_KEY_FIRST(KEY_RIGHT)://inc if (!horTab || s_editMode>0) break; #if defined(ROTARY_ENCODER_NAVIGATION) CASE_EVT_ROTARY_MOVE_RIGHT if (s_editMode != 0) break; if (l_posHorz < maxcol) { l_posHorz++; break; } else { l_posHorz = 0; if (!IS_ROTARY_MOVE_RIGHT(event)) break; } #else INC(l_posHorz, 0, maxcol); break; #endif case EVT_KEY_REPT(KEY_DOWN): //inc if (!IS_ROTARY_RIGHT(event) && l_posVert==maxrow) break; // no break case EVT_KEY_FIRST(KEY_DOWN): //inc if (s_editMode>0) break; do { INC(l_posVert, POS_VERT_INIT, maxrow); } while (CURSOR_NOT_ALLOWED_IN_ROW(l_posVert)); #if defined(ROTARY_ENCODER_NAVIGATION) s_editMode = 0; // if we go down, we must be in this mode #endif l_posHorz = min(l_posHorz, MAXCOL(l_posVert)); break; case EVT_KEY_REPT(KEY_LEFT): //dec if (l_posHorz==0) break; // no break case EVT_KEY_FIRST(KEY_LEFT)://dec if (!horTab || s_editMode>0) break; #if defined(ROTARY_ENCODER_NAVIGATION) CASE_EVT_ROTARY_MOVE_LEFT if (s_editMode != 0) break; if (l_posHorz > 0) { l_posHorz--; break; } else if (IS_ROTARY_MOVE_LEFT(event) && s_editMode == 0) { l_posHorz = 0xff; } else { l_posHorz = maxcol; break; } #else DEC(l_posHorz, 0, maxcol); break; #endif case EVT_KEY_REPT(KEY_UP): //dec if (!IS_ROTARY_LEFT(event) && l_posVert==0) break; // no break case EVT_KEY_FIRST(KEY_UP): //dec if (s_editMode>0) break; do { DEC(l_posVert, POS_VERT_INIT, maxrow); } while (CURSOR_NOT_ALLOWED_IN_ROW(l_posVert)); #if defined(ROTARY_ENCODER_NAVIGATION) || defined(PCBTARANIS) s_editMode = 0; // if we go up, we must be in this mode #endif l_posHorz = min((uint8_t)l_posHorz, MAXCOL(l_posVert)); break; } #if defined(CPUARM) if (l_posVert<1) s_pgOfs=0; else if (menuTab && horTab) { vertpos_t realPosVert = l_posVert; vertpos_t realPgOfs = s_pgOfs; vertpos_t realMaxrow = maxrow; for (vertpos_t i=1; i<=maxrow; i++) { if (MAXCOL(i) == HIDDEN_ROW) { realMaxrow--; if (i < l_posVert) realPosVert--; if (i < s_pgOfs) realPgOfs--; } } if (realPosVert>(LCD_LINES-1)+realPgOfs) realPgOfs = realPosVert-(LCD_LINES-1); else if (realPosVert<1+realPgOfs) realPgOfs = realPosVert-1; s_pgOfs = realPgOfs; for (vertpos_t i=1; i<=realPgOfs; i++) { if (MAXCOL(i) == HIDDEN_ROW) { s_pgOfs++; } } maxrow = realMaxrow; } else { uint8_t max = menuTab ? LCD_LINES-1 : LCD_LINES-2; if (l_posVert>max+s_pgOfs) s_pgOfs = l_posVert-max; else if (l_posVert<1+s_pgOfs) s_pgOfs = l_posVert-1; } #if LCD_W >= 212 if (maxrow > LCD_LINES-1 && scrollbar_X) displayScrollbar(scrollbar_X, FH, LCD_H-FH, s_pgOfs, menuTab ? maxrow : maxrow+1, LCD_LINES-1); #endif #else uint8_t max = menuTab ? LCD_LINES-1 : LCD_LINES-2; if (l_posVert<1) s_pgOfs=0; else if (l_posVert>max+s_pgOfs) s_pgOfs = l_posVert-max; else if (l_posVert<1+s_pgOfs) s_pgOfs = l_posVert-1; #endif m_posVert = l_posVert; m_posHorz = l_posHorz; #if !defined(CPUM64) // cosmetics on 9x if (s_pgOfs > 0) { l_posVert--; if (l_posVert == s_pgOfs && CURSOR_NOT_ALLOWED_IN_ROW(l_posVert)) s_pgOfs = l_posVert-1; } #endif return true; } #endif MenuFuncP g_menuStack[5]; uint8_t g_menuPos[4]; uint8_t g_menuStackPtr = 0; vertpos_t m_posVert; horzpos_t m_posHorz; void popMenu() { assert(g_menuStackPtr>0); g_menuStackPtr = g_menuStackPtr-1; AUDIO_KEYPAD_UP(); m_posHorz = 0; m_posVert = g_menuPos[g_menuStackPtr]; (*g_menuStack[g_menuStackPtr])(EVT_ENTRY_UP); } void chainMenu(MenuFuncP newMenu) { g_menuStack[g_menuStackPtr] = newMenu; (*newMenu)(EVT_ENTRY); AUDIO_MENUS(); } void pushMenu(MenuFuncP newMenu) { killEvents(KEY_ENTER); if (g_menuStackPtr == 0) { if (newMenu == menuGeneralSetup) g_menuPos[0] = 1; if (newMenu == menuModelSelect) g_menuPos[0] = 0; } else { g_menuPos[g_menuStackPtr] = m_posVert; } g_menuStackPtr++; assert(g_menuStackPtr < DIM(g_menuStack)); AUDIO_MENUS(); g_menuStack[g_menuStackPtr] = newMenu; (*newMenu)(EVT_ENTRY); } const pm_char * s_warning = NULL; const pm_char * s_warning_info; uint8_t s_warning_info_len; uint8_t s_warning_type; uint8_t s_warning_result = 0; #if defined(CPUARM) uint8_t s_warning_info_flags = ZCHAR; int16_t s_warning_input_value; int16_t s_warning_input_min; int16_t s_warning_input_max; #endif void displayBox() { lcd_filled_rect(10, 16, LCD_W-20, 40, SOLID, ERASE); lcd_rect(10, 16, LCD_W-20, 40); #if defined(CPUARM) lcd_putsn(WARNING_LINE_X, WARNING_LINE_Y, s_warning, WARNING_LINE_LEN); #else lcd_puts(WARNING_LINE_X, WARNING_LINE_Y, s_warning); #endif // could be a place for a s_warning_info } void displayPopup(const pm_char * pstr) { s_warning = pstr; displayBox(); s_warning = NULL; lcdRefresh(); } void displayWarning(uint8_t event) { s_warning_result = false; displayBox(); if (s_warning_info) lcd_putsnAtt(16, WARNING_LINE_Y+FH, s_warning_info, s_warning_info_len, WARNING_INFO_FLAGS); lcd_puts(16, WARNING_LINE_Y+2*FH, s_warning_type == WARNING_TYPE_ASTERISK ? STR_EXIT : STR_POPUPS); switch (event) { #if defined(ROTARY_ENCODER_NAVIGATION) case EVT_ROTARY_BREAK: #endif case EVT_KEY_BREAK(KEY_ENTER): if (s_warning_type == WARNING_TYPE_ASTERISK) break; s_warning_result = true; // no break #if defined(ROTARY_ENCODER_NAVIGATION) case EVT_ROTARY_LONG: killEvents(event); #endif case EVT_KEY_BREAK(KEY_EXIT): s_warning = NULL; s_warning_type = WARNING_TYPE_ASTERISK; break; #if defined(CPUARM) default: if (s_warning_type != WARNING_TYPE_INPUT) break; s_editMode = EDIT_MODIFY_FIELD; s_warning_input_value = checkIncDec(event, s_warning_input_value, s_warning_input_min, s_warning_input_max); s_editMode = EDIT_SELECT_FIELD; break; #endif } } select_menu_value_t selectMenuItem(uint8_t x, uint8_t y, const pm_char *label, const pm_char *values, select_menu_value_t value, select_menu_value_t min, select_menu_value_t max, LcdFlags attr, uint8_t event) { lcd_putsColumnLeft(x, y, label); if (values) lcd_putsiAtt(x, y, values, value-min, attr); if (attr) value = checkIncDec(event, value, min, max, (g_menuPos[0] == 0) ? EE_MODEL : EE_GENERAL); return value; } uint8_t onoffMenuItem(uint8_t value, uint8_t x, uint8_t y, const pm_char *label, LcdFlags attr, uint8_t event ) { #if defined(GRAPHICS) menu_lcd_onoff(x, y, value, attr); return selectMenuItem(x, y, label, NULL, value, 0, 1, attr, event); #else return selectMenuItem(x, y, label, STR_OFFON, value, 0, 1, attr, event); #endif } int8_t switchMenuItem(uint8_t x, uint8_t y, int8_t value, LcdFlags attr, uint8_t event) { lcd_putsColumnLeft(x, y, STR_SWITCH); putsSwitches(x, y, value, attr); if (attr) CHECK_INCDEC_MODELSWITCH(event, value, SWSRC_FIRST_SHORT_LIST, SWSRC_LAST_SHORT_LIST); return value; } #if !defined(CPUM64) void displaySlider(uint8_t x, uint8_t y, uint8_t value, uint8_t max, uint8_t attr) { lcd_putc(x+(value*4*FW)/max, y, '$'); lcd_hline(x, y+3, 5*FW-1, SOLID); if (attr && (!(attr & BLINK) || !BLINK_ON_PHASE)) lcd_filled_rect(x, y, 5*FW-1, FH-1); } #elif defined(GRAPHICS) void display5posSlider(uint8_t x, uint8_t y, uint8_t value, uint8_t attr) { lcd_putc(x+2*FW+(value*FW), y, '$'); lcd_hline(x, y+3, 5*FW-1, SOLID); if (attr && (!(attr & BLINK) || !BLINK_ON_PHASE)) lcd_filled_rect(x, y, 5*FW-1, FH-1); } #endif #if defined(GVARS) #if defined(CPUARM) int16_t gvarMenuItem(uint8_t x, uint8_t y, int16_t value, int16_t min, int16_t max, LcdFlags attr, uint8_t editflags, uint8_t event) #else int16_t gvarMenuItem(uint8_t x, uint8_t y, int16_t value, int16_t min, int16_t max, LcdFlags attr, uint8_t event) #endif { uint16_t delta = GV_GET_GV1_VALUE(max); bool invers = (attr & INVERS); // TRACE("gvarMenuItem(val=%d min=%d max=%d)", value, min, max); if (invers && event == EVT_KEY_LONG(KEY_ENTER)) { s_editMode = !s_editMode; #if defined(CPUARM) if (attr & PREC1) value = (GV_IS_GV_VALUE(value, min, max) ? GET_GVAR(value, min, max, mixerCurrentFlightMode)*10 : delta); else value = (GV_IS_GV_VALUE(value, min, max) ? GET_GVAR(value, min, max, mixerCurrentFlightMode) : delta); #else value = (GV_IS_GV_VALUE(value, min, max) ? GET_GVAR(value, min, max, mixerCurrentFlightMode) : delta); #endif eeDirty(EE_MODEL); } if (GV_IS_GV_VALUE(value, min, max)) { if (attr & LEFT) attr -= LEFT; /* because of ZCHAR */ else x -= 2*FW+FWNUM; #if defined(CPUARM) attr &= ~PREC1; #endif int8_t idx = (int16_t) GV_INDEX_CALC_DELTA(value, delta); if (invers) { CHECK_INCDEC_MODELVAR(event, idx, -MAX_GVARS, MAX_GVARS-1); } if (idx < 0) { value = (int16_t) GV_CALC_VALUE_IDX_NEG(idx, delta); idx = -idx; lcd_putcAtt(x-6, y, '-', attr); } else { value = (int16_t) GV_CALC_VALUE_IDX_POS(idx, delta); idx++; } putsStrIdx(x, y, STR_GV, idx, attr); } else { lcd_outdezAtt(x, y, value, attr); #if defined(CPUARM) if (invers) value = checkIncDec(event, value, min, max, EE_MODEL | editflags); #else if (invers) value = checkIncDec(event, value, min, max, EE_MODEL); #endif } return value; } #else int16_t gvarMenuItem(uint8_t x, uint8_t y, int16_t value, int16_t min, int16_t max, LcdFlags attr, uint8_t event) { lcd_outdezAtt(x, y, value, attr); if (attr&INVERS) value = checkIncDec(event, value, min, max, EE_MODEL); return value; } #endif void repeatLastCursorMove(uint8_t event) { if (CURSOR_MOVED_LEFT(event) || CURSOR_MOVED_RIGHT(event)) { putEvent(event); } else { m_posHorz = 0; } } #if LCD_W >= 212 #define MENU_X 30 #define MENU_Y 16 #define MENU_W LCD_W-60 #else #define MENU_X 10 #define MENU_Y 16 #define MENU_W LCD_W-20 #endif #if defined(CPUARM) void (*popupFunc)(uint8_t event) = NULL; #endif #if defined(NAVIGATION_MENUS) const char *s_menu[MENU_MAX_LINES]; uint8_t s_menu_item = 0; uint16_t s_menu_count = 0; uint8_t s_menu_flags = 0; uint16_t s_menu_offset = 0; void (*menuHandler)(const char *result); const char * displayMenu(uint8_t event) { const char * result = NULL; uint8_t display_count = min(s_menu_count, (uint16_t)MENU_MAX_LINES); uint8_t y = (display_count >= 5 ? MENU_Y - FH - 1 : MENU_Y); lcd_filled_rect(MENU_X, y, MENU_W, display_count * (FH+1) + 2, SOLID, ERASE); lcd_rect(MENU_X, y, MENU_W, display_count * (FH+1) + 2); for (uint8_t i=0; i<display_count; i++) { lcd_putsAtt(MENU_X+6, i*(FH+1) + y + 2, s_menu[i], s_menu_flags); if (i == s_menu_item) lcd_filled_rect(MENU_X+1, i*(FH+1) + y + 1, MENU_W-2, 9); } if (s_menu_count > display_count) { displayScrollbar(MENU_X+MENU_W-1, y+1, MENU_MAX_LINES * (FH+1), s_menu_offset, s_menu_count, MENU_MAX_LINES); } switch(event) { #if defined(ROTARY_ENCODER_NAVIGATION) CASE_EVT_ROTARY_LEFT #endif case EVT_KEY_FIRST(KEY_MOVE_UP): case EVT_KEY_REPT(KEY_MOVE_UP): if (s_menu_item > 0) { s_menu_item--; } #if defined(SDCARD) else if (s_menu_offset > 0) { s_menu_offset--; result = STR_UPDATE_LIST; } #endif else { s_menu_item = display_count - 1; #if defined(SDCARD) if (s_menu_count > MENU_MAX_LINES) { s_menu_offset = s_menu_count - display_count; result = STR_UPDATE_LIST; } #endif } break; #if defined(ROTARY_ENCODER_NAVIGATION) CASE_EVT_ROTARY_RIGHT #endif case EVT_KEY_FIRST(KEY_MOVE_DOWN): case EVT_KEY_REPT(KEY_MOVE_DOWN): if (s_menu_item < display_count - 1 && s_menu_offset + s_menu_item + 1 < s_menu_count) { s_menu_item++; } #if defined(SDCARD) else if (s_menu_count > s_menu_offset + display_count) { s_menu_offset++; result = STR_UPDATE_LIST; } #endif else { s_menu_item = 0; #if defined(SDCARD) if (s_menu_offset) { s_menu_offset = 0; result = STR_UPDATE_LIST; } #endif } break; CASE_EVT_ROTARY_BREAK case EVT_KEY_BREAK(KEY_ENTER): result = s_menu[s_menu_item]; // no break #if defined(ROTARY_ENCODER_NAVIGATION) CASE_EVT_ROTARY_LONG killEvents(event); #endif case EVT_KEY_BREAK(KEY_EXIT): s_menu_count = 0; s_menu_item = 0; s_menu_flags = 0; s_menu_offset = 0; break; } return result; } #endif #if defined(SDCARD) char statusLineMsg[STATUS_LINE_LENGTH]; tmr10ms_t statusLineTime = 0; uint8_t statusLineHeight = 0; void showStatusLine() { statusLineTime = get_tmr10ms(); } #define STATUS_LINE_DELAY (3 * 100) /* 3s */ void drawStatusLine() { if (statusLineTime) { if ((tmr10ms_t)(get_tmr10ms() - statusLineTime) <= (tmr10ms_t)STATUS_LINE_DELAY) { if (statusLineHeight < FH) statusLineHeight++; } else if (statusLineHeight) { statusLineHeight--; } else { statusLineTime = 0; } lcd_filled_rect(0, LCD_H-statusLineHeight, LCD_W, FH, SOLID, ERASE); lcd_putsAtt(5, LCD_H+1-statusLineHeight, statusLineMsg, BSS); lcd_filled_rect(0, LCD_H-statusLineHeight, LCD_W, FH, SOLID); } }
void writeLogs() { static const pm_char * error_displayed = NULL; if (isFunctionActive(FUNCTION_LOGS) && logDelay > 0) { tmr10ms_t tmr10ms = get_tmr10ms(); if (lastLogTime == 0 || (tmr10ms_t)(tmr10ms - lastLogTime) >= (tmr10ms_t)logDelay*10) { lastLogTime = tmr10ms; if (!g_oLogFile.fs) { const pm_char * result = openLogs(); if (result != NULL) { if (result != error_displayed) { error_displayed = result; POPUP_WARNING(result); } return; } } #if defined(RTCLOCK) { static struct gtm utm; static gtime_t lastRtcTime = 0; if ( g_rtcTime != lastRtcTime ) { lastRtcTime = g_rtcTime; gettime(&utm); } f_printf(&g_oLogFile, "%4d-%02d-%02d,%02d:%02d:%02d.%02d0,", utm.tm_year+1900, utm.tm_mon+1, utm.tm_mday, utm.tm_hour, utm.tm_min, utm.tm_sec, g_ms100); } #else f_printf(&g_oLogFile, "%d,", tmr10ms); #endif #if defined(FRSKY) #if !defined(CPUARM) f_printf(&g_oLogFile, "%d,%d,%d,", frskyStreaming, RAW_FRSKY_MINMAX(frskyData.rssi[0]), RAW_FRSKY_MINMAX(frskyData.rssi[1])); for (uint8_t i=0; i<MAX_FRSKY_A_CHANNELS; i++) { int16_t converted_value = applyChannelRatio(i, RAW_FRSKY_MINMAX(frskyData.analog[i])); f_printf(&g_oLogFile, "%d.%02d,", converted_value/100, converted_value%100); } #if defined(FRSKY_HUB) TELEMETRY_BARO_ALT_PREPARE(); if (IS_USR_PROTO_FRSKY_HUB()) { f_printf(&g_oLogFile, "%4d-%02d-%02d,%02d:%02d:%02d,%03d.%04d%c,%03d.%04d%c,%03d.%02d," TELEMETRY_GPS_SPEED_FORMAT TELEMETRY_GPS_ALT_FORMAT TELEMETRY_BARO_ALT_FORMAT TELEMETRY_VSPEED_FORMAT TELEMETRY_ASPEED_FORMAT "%d,%d,%d,%d," TELEMETRY_CELLS_FORMAT TELEMETRY_CURRENT_FORMAT "%d," TELEMETRY_VFAS_FORMAT "%d,%d,%d,", frskyData.hub.year+2000, frskyData.hub.month, frskyData.hub.day, frskyData.hub.hour, frskyData.hub.min, frskyData.hub.sec, frskyData.hub.gpsLongitude_bp, frskyData.hub.gpsLongitude_ap, frskyData.hub.gpsLongitudeEW ? frskyData.hub.gpsLongitudeEW : '-', frskyData.hub.gpsLatitude_bp, frskyData.hub.gpsLatitude_ap, frskyData.hub.gpsLatitudeNS ? frskyData.hub.gpsLatitudeNS : '-', frskyData.hub.gpsCourse_bp, frskyData.hub.gpsCourse_ap, TELEMETRY_GPS_SPEED_ARGS TELEMETRY_GPS_ALT_ARGS TELEMETRY_BARO_ALT_ARGS TELEMETRY_VSPEED_ARGS TELEMETRY_ASPEED_ARGS frskyData.hub.temperature1, frskyData.hub.temperature2, frskyData.hub.rpm, frskyData.hub.fuelLevel, TELEMETRY_CELLS_ARGS TELEMETRY_CURRENT_ARGS frskyData.hub.currentConsumption, TELEMETRY_VFAS_ARGS frskyData.hub.accelX, frskyData.hub.accelY, frskyData.hub.accelZ); } #endif #if defined(WS_HOW_HIGH) if (IS_USR_PROTO_WS_HOW_HIGH()) { f_printf(&g_oLogFile, "%d,", TELEMETRY_RELATIVE_BARO_ALT_BP); } #endif #endif #if defined(CPUARM) for (int i=0; i<MAX_SENSORS; i++) { TelemetrySensor & sensor = g_model.telemetrySensors[i]; TelemetryItem & telemetryItem = telemetryItems[i]; if (sensor.logs) { if (sensor.unit == UNIT_GPS) { if (telemetryItem.gps.longitudeEW && telemetryItem.gps.latitudeNS) f_printf(&g_oLogFile, "%03d.%04d%c %03d.%04d%c,", telemetryItem.gps.longitude_bp, telemetryItem.gps.longitude_ap, telemetryItem.gps.longitudeEW, telemetryItem.gps.latitude_bp, telemetryItem.gps.latitude_ap, telemetryItem.gps.latitudeNS); else f_printf(&g_oLogFile, ","); } else if (sensor.unit == UNIT_DATETIME) { if (telemetryItem.datetime.datestate) f_printf(&g_oLogFile, "%4d-%02d-%02d %02d:%02d:%02d,", telemetryItem.datetime.year, telemetryItem.datetime.month, telemetryItem.datetime.day, telemetryItem.datetime.hour, telemetryItem.datetime.min, telemetryItem.datetime.sec); else f_printf(&g_oLogFile, ","); } else if (sensor.prec == 2) { div_t qr = div(telemetryItem.value, 100); if (telemetryItem.value < 0) f_printf(&g_oLogFile, "-"); f_printf(&g_oLogFile, "%d.%02d,", abs(qr.quot), abs(qr.rem)); } else if (sensor.prec == 1) { div_t qr = div(telemetryItem.value, 10); if (telemetryItem.value < 0) f_printf(&g_oLogFile, "-"); f_printf(&g_oLogFile, "%d.%d,", abs(qr.quot), abs(qr.rem)); } else { f_printf(&g_oLogFile, "%d,", telemetryItem.value); } } } #endif #endif for (uint8_t i=0; i<NUM_STICKS+NUM_POTS; i++) { f_printf(&g_oLogFile, "%d,", calibratedStick[i]); } #if defined(PCBTARANIS) int result = f_printf(&g_oLogFile, "%d,%d,%d,%d,%d,%d,%d,%d\n", get3PosState(SA), get3PosState(SB), get3PosState(SC), get3PosState(SD), get3PosState(SE), get2PosState(SF), get3PosState(SG), get2PosState(SH)); #endif if (result<0 && !error_displayed) { error_displayed = STR_SDCARD_ERROR; POPUP_WARNING(STR_SDCARD_ERROR); closeLogs(); } } } else { error_displayed = NULL; if (g_oLogFile.fs) { closeLogs(); } } }
bool check(check_event_t event, uint8_t curr, const MenuFuncP *menuTab, uint8_t menuTabSize, const pm_uint8_t *horTab, uint8_t horTabMax, vertpos_t maxrow) { vertpos_t l_posVert = m_posVert; horzpos_t l_posHorz = m_posHorz; uint8_t maxcol = MAXCOL(l_posVert); #if defined(NAVIGATION_POT1) // check pot 1 - if changed -> scroll values static int16_t p1val; static int16_t p1valprev; p1valdiff = (p1val-calibratedStick[6]) / SCROLL_POT1_TH; if (p1valdiff) { p1valdiff = (p1valprev-calibratedStick[6]) / 2; p1val = calibratedStick[6]; } p1valprev = calibratedStick[6]; #endif #if defined(NAVIGATION_POT2) // check pot 2 - if changed -> scroll menu static int16_t p2valprev; p2valdiff = (p2valprev-calibratedStick[4]) / SCROLL_TH; if (p2valdiff) p2valprev = calibratedStick[4]; #endif #if defined(NAVIGATION_POT3) // check pot 3 if changed -> cursor down/up static int16_t p3valprev; int8_t scrollUD = (p3valprev-calibratedStick[5]) / SCROLL_TH; if (scrollUD) p3valprev = calibratedStick[5]; #else #define scrollUD 0 #endif if (p2valdiff || scrollUD || p1valdiff) backlightOn(); // on keypress turn the light on if (menuTab) { uint8_t attr = 0; if (l_posVert==0 && !calibrationState) { attr = INVERS; int8_t cc = curr; if (p2valdiff) { cc = limit((int8_t)0, (int8_t)(cc - p2valdiff), (int8_t)(menuTabSize-1)); } switch(event) { #if defined(ROTARY_ENCODER_NAVIGATION) case EVT_ROTARY_BREAK: if (s_editMode < 0 && maxrow > 0) { s_editMode = 0; // TODO ? l_posVert = (horTab && horTab[1]==0xff) ? 2 : 1; l_posHorz = 0; } else { s_editMode = -1; } event = 0; break; #endif #if defined(ROTARY_ENCODER_NAVIGATION) case EVT_ROTARY_LEFT: if (s_editMode >= 0) break; #endif case EVT_KEY_FIRST(KEY_LEFT): if (curr > 0) cc = curr - 1; else cc = menuTabSize-1; break; #if defined(ROTARY_ENCODER_NAVIGATION) case EVT_ROTARY_RIGHT: if (s_editMode >= 0) break; #endif case EVT_KEY_FIRST(KEY_RIGHT): if (curr < (menuTabSize-1)) cc = curr + 1; else cc = 0; break; } if (cc != curr) { chainMenu((MenuFuncP)pgm_read_adr(&menuTab[cc])); return false; } #if defined(ROTARY_ENCODER_NAVIGATION) if (IS_RE_NAVIGATION_ENABLE() && s_editMode < 0) attr = INVERS|BLINK; #endif } calibrationState = 0; displayScreenIndex(curr, menuTabSize, attr); } DISPLAY_PROGRESS_BAR(menuTab ? lcdLastPos-2*FW-((curr+1)/10*FWNUM)-2 : 20*FW+1); if (s_editMode<=0) { if (scrollUD) { l_posVert = limit((int8_t)0, (int8_t)(l_posVert - scrollUD), (int8_t)maxrow); l_posHorz = min((uint8_t)l_posHorz, MAXCOL(l_posVert)); } if (p2valdiff && l_posVert>0) { l_posHorz = limit((int8_t)0, (int8_t)((uint8_t)l_posHorz - p2valdiff), (int8_t)maxcol); } } switch(event) { case EVT_ENTRY: #if defined(CPUARM) menuEntryTime = get_tmr10ms(); #endif l_posVert = POS_VERT_INIT; l_posHorz = POS_HORZ_INIT(l_posVert); SET_SCROLLBAR_X(LCD_W-1); #if defined(ROTARY_ENCODER_NAVIGATION) if (menuTab) { s_editMode = EDIT_MODE_INIT; break; } // no break #else s_editMode = EDIT_MODE_INIT; break; #endif #if defined(ROTARY_ENCODER_NAVIGATION) case EVT_ENTRY_UP: s_editMode = 0; SET_SCROLLBAR_X(LCD_W-1); break; case EVT_ROTARY_BREAK: if (s_editMode > 1) break; #endif case EVT_KEY_FIRST(KEY_ENTER): if (!menuTab || l_posVert>0) { if (READ_ONLY_UNLOCKED()) { s_editMode = (s_editMode<=0); } } break; #if defined(ROTARY_ENCODER_NAVIGATION) case EVT_ROTARY_LONG: if (s_editMode > 1) break; killEvents(event); if (l_posVert != POS_VERT_INIT) { l_posVert = POS_VERT_INIT; s_editMode = EDIT_MODE_INIT; break; } // no break #endif case EVT_KEY_LONG(KEY_EXIT): s_editMode = 0; // TODO needed? we call ENTRY_UP after which does the same popMenu(); return false; case EVT_KEY_BREAK(KEY_EXIT): #if defined(ROTARY_ENCODER_NAVIGATION) if (s_editMode == 0) s_editMode = EDIT_MODE_INIT; else #endif if (s_editMode>0) { s_editMode = 0; break; } if (l_posVert==0 || !menuTab) { popMenu(); // beeps itself return false; } else { AUDIO_MENUS(); l_posVert = 0; l_posHorz = 0; } break; case EVT_KEY_REPT(KEY_RIGHT): //inc if (l_posHorz==maxcol) break; // no break case EVT_KEY_FIRST(KEY_RIGHT)://inc if (!horTab || s_editMode>0) break; #if defined(ROTARY_ENCODER_NAVIGATION) CASE_EVT_ROTARY_MOVE_RIGHT if (s_editMode != 0) break; if (l_posHorz < maxcol) { l_posHorz++; break; } else { l_posHorz = 0; if (!IS_ROTARY_MOVE_RIGHT(event)) break; } #else INC(l_posHorz, 0, maxcol); break; #endif case EVT_KEY_REPT(KEY_DOWN): //inc if (!IS_ROTARY_RIGHT(event) && l_posVert==maxrow) break; // no break case EVT_KEY_FIRST(KEY_DOWN): //inc if (s_editMode>0) break; do { INC(l_posVert, POS_VERT_INIT, maxrow); } while (CURSOR_NOT_ALLOWED_IN_ROW(l_posVert)); #if defined(ROTARY_ENCODER_NAVIGATION) s_editMode = 0; // if we go down, we must be in this mode #endif l_posHorz = min(l_posHorz, MAXCOL(l_posVert)); break; case EVT_KEY_REPT(KEY_LEFT): //dec if (l_posHorz==0) break; // no break case EVT_KEY_FIRST(KEY_LEFT)://dec if (!horTab || s_editMode>0) break; #if defined(ROTARY_ENCODER_NAVIGATION) CASE_EVT_ROTARY_MOVE_LEFT if (s_editMode != 0) break; if (l_posHorz > 0) { l_posHorz--; break; } else if (IS_ROTARY_MOVE_LEFT(event) && s_editMode == 0) { l_posHorz = 0xff; } else { l_posHorz = maxcol; break; } #else DEC(l_posHorz, 0, maxcol); break; #endif case EVT_KEY_REPT(KEY_UP): //dec if (!IS_ROTARY_LEFT(event) && l_posVert==0) break; // no break case EVT_KEY_FIRST(KEY_UP): //dec if (s_editMode>0) break; do { DEC(l_posVert, POS_VERT_INIT, maxrow); } while (CURSOR_NOT_ALLOWED_IN_ROW(l_posVert)); #if defined(ROTARY_ENCODER_NAVIGATION) || defined(PCBTARANIS) s_editMode = 0; // if we go up, we must be in this mode #endif l_posHorz = min((uint8_t)l_posHorz, MAXCOL(l_posVert)); break; } #if defined(CPUARM) if (l_posVert<1) s_pgOfs=0; else if (menuTab && horTab) { vertpos_t realPosVert = l_posVert; vertpos_t realPgOfs = s_pgOfs; vertpos_t realMaxrow = maxrow; for (vertpos_t i=1; i<=maxrow; i++) { if (MAXCOL(i) == HIDDEN_ROW) { realMaxrow--; if (i < l_posVert) realPosVert--; if (i < s_pgOfs) realPgOfs--; } } if (realPosVert>(LCD_LINES-1)+realPgOfs) realPgOfs = realPosVert-(LCD_LINES-1); else if (realPosVert<1+realPgOfs) realPgOfs = realPosVert-1; s_pgOfs = realPgOfs; for (vertpos_t i=1; i<=realPgOfs; i++) { if (MAXCOL(i) == HIDDEN_ROW) { s_pgOfs++; } } maxrow = realMaxrow; } else { uint8_t max = menuTab ? LCD_LINES-1 : LCD_LINES-2; if (l_posVert>max+s_pgOfs) s_pgOfs = l_posVert-max; else if (l_posVert<1+s_pgOfs) s_pgOfs = l_posVert-1; } #if LCD_W >= 212 if (maxrow > LCD_LINES-1 && scrollbar_X) displayScrollbar(scrollbar_X, FH, LCD_H-FH, s_pgOfs, menuTab ? maxrow : maxrow+1, LCD_LINES-1); #endif #else uint8_t max = menuTab ? LCD_LINES-1 : LCD_LINES-2; if (l_posVert<1) s_pgOfs=0; else if (l_posVert>max+s_pgOfs) s_pgOfs = l_posVert-max; else if (l_posVert<1+s_pgOfs) s_pgOfs = l_posVert-1; #endif m_posVert = l_posVert; m_posHorz = l_posHorz; #if !defined(CPUM64) // cosmetics on 9x if (s_pgOfs > 0) { l_posVert--; if (l_posVert == s_pgOfs && CURSOR_NOT_ALLOWED_IN_ROW(l_posVert)) s_pgOfs = l_posVert-1; } #endif return true; }
bool check(check_event_t event, uint8_t curr, const MenuFuncP *menuTab, uint8_t menuTabSize, const pm_uint8_t *horTab, uint8_t horTabMax, vertpos_t maxrow, uint8_t flags) { vertpos_t l_posVert = m_posVert; horzpos_t l_posHorz = m_posHorz; uint8_t maxcol = MAXCOL(l_posVert); #define scrollUD 0 if (p2valdiff || scrollUD || p1valdiff) backlightOn(); // on keypress turn the light on if (menuTab) { uint8_t attr = 0; int8_t cc = curr; switch (event) { case EVT_KEY_LONG(KEY_MENU): if (menuTab == menuTabModel) { killEvents(event); if (modelHasNotes()) { MENU_ADD_SD_ITEM(STR_VIEW_CHANNELS); MENU_ADD_ITEM(STR_VIEW_NOTES); menuHandler = onLongMenuPress; } else { pushMenu(menuChannelsView); return false; } } break; case EVT_KEY_LONG(KEY_PAGE): if (curr > 0) cc = curr - 1; else cc = menuTabSize-1; killEvents(event); break; case EVT_KEY_BREAK(KEY_PAGE): if (curr < (menuTabSize-1)) cc = curr + 1; else cc = 0; break; } if (!calibrationState && cc != curr) { chainMenu((MenuFuncP)pgm_read_adr(&menuTab[cc])); return false; } if (!(flags&CHECK_FLAG_NO_SCREEN_INDEX)) { displayScreenIndex(curr, menuTabSize, attr); } lcd_filled_rect(0, 0, LCD_W, FH, SOLID, FILL_WHITE|GREY_DEFAULT); } DISPLAY_PROGRESS_BAR(menuTab ? lcdLastPos-2*FW-((curr+1)/10*FWNUM)-2 : 20*FW+1); if (s_editMode<=0) { if (scrollUD) { l_posVert = limit((int8_t)0, (int8_t)(l_posVert - scrollUD), (int8_t)maxrow); l_posHorz = min((uint8_t)l_posHorz, MAXCOL(l_posVert)); } if (p2valdiff && l_posVert>0) { l_posHorz = limit((int8_t)0, (int8_t)((uint8_t)l_posHorz - p2valdiff), (int8_t)maxcol); } } switch(event) { case EVT_ENTRY: menuEntryTime = get_tmr10ms(); l_posVert = POS_VERT_INIT; l_posHorz = POS_HORZ_INIT(l_posVert); SET_SCROLLBAR_X(LCD_W-1); #if defined(ROTARY_ENCODER_NAVIGATION) if (menuTab) { s_editMode = EDIT_MODE_INIT; break; } // no break #else s_editMode = EDIT_MODE_INIT; break; #endif case EVT_ENTRY_UP: menuEntryTime = get_tmr10ms(); s_editMode = 0; l_posHorz = POS_HORZ_INIT(l_posVert); SET_SCROLLBAR_X(LCD_W-1); break; case EVT_ROTARY_BREAK: if (s_editMode > 1) break; if (m_posHorz < 0 && maxcol > 0 && READ_ONLY_UNLOCKED()) { l_posHorz = 0; break; } if (!menuTab || l_posVert>0) { if (READ_ONLY_UNLOCKED()) { s_editMode = (s_editMode<=0); } } break; #if defined(ROTARY_ENCODER_NAVIGATION) case EVT_ROTARY_LONG: if (s_editMode > 1) break; killEvents(event); if (l_posVert != POS_VERT_INIT) { l_posVert = POS_VERT_INIT; s_editMode = EDIT_MODE_INIT; break; } // no break #endif case EVT_KEY_LONG(KEY_EXIT): s_editMode = 0; // TODO needed? we call ENTRY_UP after which does the same popMenu(); return false; case EVT_KEY_BREAK(KEY_EXIT): #if defined(ROTARY_ENCODER_NAVIGATION) if (s_editMode == 0) s_editMode = EDIT_MODE_INIT; else #endif if (s_editMode>0) { s_editMode = 0; break; } if (l_posHorz >= 0 && (COLATTR(l_posVert) & NAVIGATION_LINE_BY_LINE)) { l_posHorz = -1; } else { uint8_t posVertInit = POS_VERT_INIT; if (s_pgOfs != 0 || l_posVert != posVertInit) { s_pgOfs = 0; l_posVert = posVertInit; l_posHorz = POS_HORZ_INIT(l_posVert); } else { popMenu(); return false; } } break; CASE_EVT_ROTARY_MOVE_RIGHT if (s_editMode != 0) break; if ((COLATTR(l_posVert) & NAVIGATION_LINE_BY_LINE)) { if (l_posHorz >= 0) { INC(l_posHorz, 0, maxcol); break; } } else { if (l_posHorz < maxcol) { l_posHorz++; break; } else { l_posHorz = 0; if (!IS_ROTARY_MOVE_RIGHT(event)) break; } } do { INC(l_posVert, POS_VERT_INIT, maxrow); } while (CURSOR_NOT_ALLOWED_IN_ROW(l_posVert)); s_editMode = 0; // if we go down, we must be in this mode l_posHorz = POS_HORZ_INIT(l_posVert); break; CASE_EVT_ROTARY_MOVE_LEFT if (s_editMode != 0) break; if ((COLATTR(l_posVert) & NAVIGATION_LINE_BY_LINE)) { if (l_posHorz >= 0) { DEC(l_posHorz, 0, maxcol); break; } } else { if (l_posHorz > 0) { l_posHorz--; break; } else if (IS_ROTARY_MOVE_LEFT(event) && s_editMode == 0) { l_posHorz = 0xff; } else { l_posHorz = maxcol; break; } } do { DEC(l_posVert, POS_VERT_INIT, maxrow); } while (CURSOR_NOT_ALLOWED_IN_ROW(l_posVert)); s_editMode = 0; // if we go up, we must be in this mode if ((COLATTR(l_posVert) & NAVIGATION_LINE_BY_LINE)) l_posHorz = -1; else l_posHorz = min((uint8_t)l_posHorz, MAXCOL(l_posVert)); break; } #if defined(CPUARM) if (l_posVert<1) { s_pgOfs=0; } else if (menuTab && horTab) { if (maxrow > LCD_LINES-1) { while (1) { vertpos_t line = s_pgOfs+1; for (int numLines=0; line<=maxrow && numLines<LCD_LINES-1; line++) { if (MAXCOL(line) != HIDDEN_ROW) { numLines++; } } int max = line - s_pgOfs - 1; if (l_posVert > max+s_pgOfs) { s_pgOfs++; } else if (l_posVert < 1+s_pgOfs) { s_pgOfs--; } else { break; } } } } else { uint8_t max = menuTab ? LCD_LINES-1 : LCD_LINES-2; if (l_posVert>max+s_pgOfs) { s_pgOfs = l_posVert-max; } else if (l_posVert<1+s_pgOfs) { s_pgOfs = l_posVert-1; } } #if LCD_W >= 212 if (maxrow > LCD_LINES-1 && scrollbar_X) displayScrollbar(scrollbar_X, FH, LCD_H-FH, s_pgOfs, menuTab ? maxrow : maxrow+1, LCD_LINES-1); #endif #else uint8_t max = menuTab ? LCD_LINES-1 : LCD_LINES-2; if (l_posVert<1) s_pgOfs=0; else if (l_posVert>max+s_pgOfs) s_pgOfs = l_posVert-max; else if (l_posVert<1+s_pgOfs) s_pgOfs = l_posVert-1; #endif m_posVert = l_posVert; m_posHorz = l_posHorz; if (s_pgOfs > 0) { l_posVert--; if (l_posVert == s_pgOfs && CURSOR_NOT_ALLOWED_IN_ROW(l_posVert)) { s_pgOfs = l_posVert-1; } } return true; }
void showStatusLine() { statusLineTime = get_tmr10ms(); }
// TODO test when disk full void writeLogs() { static const pm_char * error_displayed = NULL; if (isFunctionActive(FUNCTION_LOGS) && logDelay > 0) { tmr10ms_t tmr10ms = get_tmr10ms(); if (lastLogTime == 0 || (tmr10ms_t)(tmr10ms - lastLogTime) >= (tmr10ms_t)logDelay*10) { lastLogTime = tmr10ms; if (!g_oLogFile.fs) { const pm_char * result = openLogs(); if (result != NULL) { if (result != error_displayed) { error_displayed = result; POPUP_WARNING(result); } return; } } #if defined(RTCLOCK) struct gtm utm; gettime(&utm); f_printf(&g_oLogFile, "%4d-%02d-%02d,%02d:%02d:%02d.%02d0,", utm.tm_year+1900, utm.tm_mon+1, utm.tm_mday, utm.tm_hour, utm.tm_min, utm.tm_sec, g_ms100); #else f_printf(&g_oLogFile, "%d,", tmr10ms); #endif #if defined(FRSKY) #if defined(PCBTARANIS) && defined(REVPLUS) f_printf(&g_oLogFile, "%d,", RAW_FRSKY_MINMAX(frskyData.rssi[0])); #elif defined(CPUARM) f_printf(&g_oLogFile, "%d,%d,", RAW_FRSKY_MINMAX(frskyData.swr), RAW_FRSKY_MINMAX(frskyData.rssi[0])); #else f_printf(&g_oLogFile, "%d,%d,%d,", frskyStreaming, RAW_FRSKY_MINMAX(frskyData.rssi[0]), RAW_FRSKY_MINMAX(frskyData.rssi[1])); #endif for (uint8_t i=0; i<MAX_FRSKY_A_CHANNELS; i++) { int16_t converted_value = applyChannelRatio(i, RAW_FRSKY_MINMAX(frskyData.analog[i])); f_printf(&g_oLogFile, "%d.%02d,", converted_value/100, converted_value%100); } #endif #if defined(FRSKY_HUB) TELEMETRY_BARO_ALT_PREPARE(); if (IS_USR_PROTO_FRSKY_HUB()) { f_printf(&g_oLogFile, "%4d-%02d-%02d,%02d:%02d:%02d,%03d.%04d%c,%03d.%04d%c,%03d.%02d," TELEMETRY_GPS_SPEED_FORMAT TELEMETRY_GPS_ALT_FORMAT TELEMETRY_BARO_ALT_FORMAT TELEMETRY_VSPEED_FORMAT TELEMETRY_ASPEED_FORMAT "%d,%d,%d,%d," TELEMETRY_CELLS_FORMAT TELEMETRY_CURRENT_FORMAT "%d," TELEMETRY_VFAS_FORMAT "%d,%d,%d,", frskyData.hub.year+2000, frskyData.hub.month, frskyData.hub.day, frskyData.hub.hour, frskyData.hub.min, frskyData.hub.sec, frskyData.hub.gpsLongitude_bp, frskyData.hub.gpsLongitude_ap, frskyData.hub.gpsLongitudeEW ? frskyData.hub.gpsLongitudeEW : '-', frskyData.hub.gpsLatitude_bp, frskyData.hub.gpsLatitude_ap, frskyData.hub.gpsLatitudeNS ? frskyData.hub.gpsLatitudeNS : '-', frskyData.hub.gpsCourse_bp, frskyData.hub.gpsCourse_ap, TELEMETRY_GPS_SPEED_ARGS TELEMETRY_GPS_ALT_ARGS TELEMETRY_BARO_ALT_ARGS TELEMETRY_VSPEED_ARGS TELEMETRY_ASPEED_ARGS frskyData.hub.temperature1, frskyData.hub.temperature2, frskyData.hub.rpm, frskyData.hub.fuelLevel, TELEMETRY_CELLS_ARGS TELEMETRY_CURRENT_ARGS frskyData.hub.currentConsumption, TELEMETRY_VFAS_ARGS frskyData.hub.accelX, frskyData.hub.accelY, frskyData.hub.accelZ); } #endif #if defined(WS_HOW_HIGH) if (IS_USR_PROTO_WS_HOW_HIGH()) { f_printf(&g_oLogFile, "%d,", TELEMETRY_RELATIVE_BARO_ALT_BP); } #endif for (uint8_t i=0; i<NUM_STICKS+NUM_POTS; i++) { f_printf(&g_oLogFile, "%d,", calibratedStick[i]); } #if defined(PCBTARANIS) int result = f_printf(&g_oLogFile, "%d,%d,%d,%d,%d,%d,%d,%d\n", get3PosState(SA), get3PosState(SB), get3PosState(SC), get3PosState(SD), get3PosState(SE), get2PosState(SF), get3PosState(SG), get2PosState(SH)); #else int result = f_printf(&g_oLogFile, "%d,%d,%d,%d,%d,%d,%d\n", get2PosState(THR), get2PosState(RUD), get2PosState(ELE), get3PosState(ID), get2PosState(AIL), get2PosState(GEA), get2PosState(TRN)); #endif if (result<0 && !error_displayed) { error_displayed = STR_SDCARD_ERROR; POPUP_WARNING(STR_SDCARD_ERROR); closeLogs(); } } } else { error_displayed = NULL; if (g_oLogFile.fs) { closeLogs(); } } }
void check(const char *name, check_event_t event, uint8_t curr, const menuHandlerFunc *menuTab, uint8_t menuTabSize, const pm_uint8_t *horTab, uint8_t horTabMax, vertpos_t rowcount, uint8_t flags) { vertpos_t l_posVert = menuVerticalPosition; horzpos_t l_posHorz = menuHorizontalPosition; uint8_t maxcol = MAXCOL(l_posVert); if (menuTab) { int cc = curr; switch (event) { case EVT_KEY_LONG(KEY_MENU): if (menuTab == menuTabModel) { killEvents(event); if (modelHasNotes()) { POPUP_MENU_ADD_SD_ITEM(STR_VIEW_CHANNELS); POPUP_MENU_ADD_ITEM(STR_VIEW_NOTES); popupMenuHandler = onLongMenuPress; } else { pushMenu(menuChannelsView); } } break; case EVT_KEY_LONG(KEY_PAGE): if (curr > 0) cc = curr - 1; else cc = menuTabSize-1; killEvents(event); break; case EVT_KEY_BREAK(KEY_PAGE): if (curr < (menuTabSize-1)) cc = curr + 1; else cc = 0; break; } if (!calibrationState && cc != curr) { chainMenu((menuHandlerFunc)pgm_read_adr(&menuTab[cc])); } if (!(flags&CHECK_FLAG_NO_SCREEN_INDEX)) { displayScreenIndex(curr, menuTabSize, 0); } drawFilledRect(0, 0, LCD_W, MENU_HEADER_HEIGHT, SOLID, FILL_WHITE|GREY_DEFAULT); } DISPLAY_PROGRESS_BAR(menuTab ? lcdLastPos-2*FW-((curr+1)/10*FWNUM)-2 : 20*FW+1); switch(event) { case EVT_ENTRY: menuEntryTime = get_tmr10ms(); l_posVert = POS_VERT_INIT; l_posHorz = POS_HORZ_INIT(l_posVert); SET_SCROLLBAR_X(LCD_W-1); s_editMode = EDIT_MODE_INIT; break; case EVT_ENTRY_UP: menuEntryTime = get_tmr10ms(); s_editMode = 0; l_posHorz = POS_HORZ_INIT(l_posVert); SET_SCROLLBAR_X(LCD_W-1); break; case EVT_ROTARY_BREAK: if (s_editMode > 1) break; if (menuHorizontalPosition < 0 && maxcol > 0 && READ_ONLY_UNLOCKED()) { l_posHorz = 0; break; } if (READ_ONLY_UNLOCKED()) { s_editMode = (s_editMode<=0); } break; case EVT_KEY_LONG(KEY_EXIT): s_editMode = 0; // TODO needed? we call ENTRY_UP after which does the same popMenu(); break; case EVT_KEY_BREAK(KEY_EXIT): if (s_editMode>0) { s_editMode = 0; break; } if (l_posHorz >= 0 && (COLATTR(l_posVert) & NAVIGATION_LINE_BY_LINE)) { l_posHorz = -1; } else { uint8_t posVertInit = POS_VERT_INIT; if (menuVerticalOffset != 0 || l_posVert != posVertInit) { menuVerticalOffset = 0; l_posVert = posVertInit; l_posHorz = POS_HORZ_INIT(l_posVert); } else { popMenu(); } } break; CASE_EVT_ROTARY_MOVE_RIGHT if (s_editMode != 0) break; if ((COLATTR(l_posVert) & NAVIGATION_LINE_BY_LINE)) { if (l_posHorz >= 0) { INC(l_posHorz, 0, maxcol); break; } } else { if (l_posHorz < maxcol) { l_posHorz++; break; } else { l_posHorz = 0; if (!IS_ROTARY_MOVE_RIGHT(event)) break; } } do { INC(l_posVert, POS_VERT_INIT, rowcount-1); } while (CURSOR_NOT_ALLOWED_IN_ROW(l_posVert)); s_editMode = 0; // if we go down, we must be in this mode l_posHorz = POS_HORZ_INIT(l_posVert); break; CASE_EVT_ROTARY_MOVE_LEFT if (s_editMode != 0) break; if ((COLATTR(l_posVert) & NAVIGATION_LINE_BY_LINE)) { if (l_posHorz >= 0) { DEC(l_posHorz, 0, maxcol); break; } } else { if (l_posHorz > 0) { l_posHorz--; break; } else if (IS_ROTARY_MOVE_LEFT(event) && s_editMode == 0) { l_posHorz = 0xff; } else { l_posHorz = maxcol; break; } } do { DEC(l_posVert, POS_VERT_INIT, rowcount-1); } while (CURSOR_NOT_ALLOWED_IN_ROW(l_posVert)); s_editMode = 0; // if we go up, we must be in this mode if ((COLATTR(l_posVert) & NAVIGATION_LINE_BY_LINE)) l_posHorz = -1; else l_posHorz = min((uint8_t)l_posHorz, MAXCOL(l_posVert)); break; } int linesCount = rowcount; if (l_posVert == 0 || (l_posVert==1 && MAXCOL(vertpos_t(0)) >= HIDDEN_ROW) || (l_posVert==2 && MAXCOL(vertpos_t(0)) >= HIDDEN_ROW && MAXCOL(vertpos_t(1)) >= HIDDEN_ROW)) { menuVerticalOffset = 0; if (horTab) { linesCount = 0; for (int i=0; i<rowcount; i++) { if (i>horTabMax || horTab[i] != HIDDEN_ROW) { linesCount++; } } } } else if (horTab) { if (rowcount > NUM_BODY_LINES) { while (1) { vertpos_t firstLine = 0; for (int numLines=0; firstLine<rowcount && numLines<menuVerticalOffset; firstLine++) { if (firstLine>=horTabMax || horTab[firstLine] != HIDDEN_ROW) { numLines++; } } if (l_posVert < firstLine) { menuVerticalOffset--; } else { vertpos_t lastLine = firstLine; for (int numLines=0; lastLine<rowcount && numLines<NUM_BODY_LINES; lastLine++) { if (lastLine>=horTabMax || horTab[lastLine] != HIDDEN_ROW) { numLines++; } } if (l_posVert >= lastLine) { menuVerticalOffset++; } else { linesCount = menuVerticalOffset + NUM_BODY_LINES; for (int i=lastLine; i<rowcount; i++) { if (i>horTabMax || horTab[i] != HIDDEN_ROW) { linesCount++; } } break; } } } } } else { if (l_posVert>=NUM_BODY_LINES+menuVerticalOffset) { menuVerticalOffset = l_posVert-NUM_BODY_LINES+1; } else if (l_posVert<menuVerticalOffset) { menuVerticalOffset = l_posVert; } } if (scrollbar_X && linesCount > NUM_BODY_LINES) { displayScrollbar(scrollbar_X, MENU_HEADER_HEIGHT, LCD_H-MENU_HEADER_HEIGHT, menuVerticalOffset, linesCount, NUM_BODY_LINES); } if (name) { title(name); } menuVerticalPosition = l_posVert; menuHorizontalPosition = l_posHorz; }
void boardInit() { RCC_AHB1PeriphClockCmd(PWR_RCC_AHB1Periph | KEYS_RCC_AHB1Periph | LCD_RCC_AHB1Periph | BACKLIGHT_RCC_AHB1Periph | ADC_RCC_AHB1Periph | I2C_RCC_AHB1Periph | SD_RCC_AHB1Periph | HAPTIC_RCC_AHB1Periph | INTMODULE_RCC_AHB1Periph | EXTMODULE_RCC_AHB1Periph | TELEMETRY_RCC_AHB1Periph | SERIAL_RCC_AHB1Periph | TRAINER_RCC_AHB1Periph | HEARTBEAT_RCC_AHB1Periph, ENABLE); RCC_APB1PeriphClockCmd(LCD_RCC_APB1Periph | BACKLIGHT_RCC_APB1Periph | INTERRUPT_5MS_APB1Periph | TIMER_2MHz_APB1Periph | I2C_RCC_APB1Periph | SD_RCC_APB1Periph | TRAINER_RCC_APB1Periph | TELEMETRY_RCC_APB1Periph | SERIAL_RCC_APB1Periph, ENABLE); RCC_APB2PeriphClockCmd(BACKLIGHT_RCC_APB2Periph | ADC_RCC_APB2Periph | HAPTIC_RCC_APB2Periph | INTMODULE_RCC_APB2Periph | EXTMODULE_RCC_APB2Periph | HEARTBEAT_RCC_APB2Periph, ENABLE); #if !defined(REV9E) // some REV9E boards need that the pwrInit() is moved a little bit later pwrInit(); #endif keysInit(); adcInit(); delaysInit(); lcdInit(); // delaysInit() must be called before audioInit(); init2MhzTimer(); init5msTimer(); __enable_irq(); i2cInit(); usbInit(); #if defined(HAPTIC) hapticInit(); #endif #if defined(REV9E) bluetoothInit(BLUETOOTH_DEFAULT_BAUDRATE); #endif #if defined(DEBUG) DBGMCU_APB1PeriphConfig(DBGMCU_IWDG_STOP|DBGMCU_TIM1_STOP|DBGMCU_TIM2_STOP|DBGMCU_TIM3_STOP|DBGMCU_TIM6_STOP|DBGMCU_TIM8_STOP|DBGMCU_TIM10_STOP|DBGMCU_TIM13_STOP|DBGMCU_TIM14_STOP, ENABLE); #endif #if defined(REV9E) if (!WAS_RESET_BY_WATCHDOG_OR_SOFTWARE()) { lcd_clear(); lcd_bmp(76, 2, bmp_lock, 0, 60); lcdRefresh(); lcdRefreshWait(); tmr10ms_t start = get_tmr10ms(); tmr10ms_t duration = 0; uint8_t pwr_on = 0; while (pwrPressed()) { duration = get_tmr10ms() - start; if (duration < PWR_PRESS_DURATION_MIN) { unsigned index = duration / (PWR_PRESS_DURATION_MIN / 4); lcd_clear(); lcd_bmp(76, 2, bmp_startup, index*60, 60); } else if (duration >= PWR_PRESS_DURATION_MAX) { displaySleepBitmap(); turnBacklightOff(); } else { if (pwr_on != 1) { pwr_on = 1; pwrInit(); backlightInit(); haptic.play(15, 3, PLAY_NOW); } } lcdRefresh(); lcdRefreshWait(); } if (duration < PWR_PRESS_DURATION_MIN || duration >= PWR_PRESS_DURATION_MAX) { boardOff(); } } else { pwrInit(); backlightInit(); } topLcdInit(); #else backlightInit(); #endif }
void eeCheck(bool immediately) { EepromActive = 0 ; uint8_t msk = s_eeDirtyMsk; if(!msk) return; EepromActive = '1' + s_eeLongTimer ; if( !immediately ) { if ( ( get_tmr10ms() - s_eeDirtyTime10ms) < WRITE_DELAY_10MS) return ; if ( s_eeLongTimer ) { if ( --s_eeLongTimer ) { s_eeDirtyTime10ms = get_tmr10ms() ; return ; } } } s_eeLongTimer = 0 ; if ( Ee_lock ) return ; Ee_lock = EE_LOCK ; // Lock eeprom writing from recursion if ( msk & EE_TRIM ) { Ee_lock |= EE_TRIM_LOCK ; // So the lower levels know what is happening } if(msk & EE_GENERAL) { EepromActive = '2' ; s_eeDirtyMsk &= ~EE_GENERAL ; if(theWriteFile.writeRlc(FILE_TMP, FILE_TYP_GENERAL, (uint8_t*)&g_eeGeneral, sizeof(EEGeneral),20) == sizeof(EEGeneral)) { EFile::swap(FILE_GENERAL,FILE_TMP); }else{ if(theWriteFile.write_errno()==ERR_TMO){ s_eeDirtyMsk |= EE_GENERAL; //try again s_eeDirtyTime10ms = get_tmr10ms() - WRITE_DELAY_10MS; if(heartbeat == 0x3) { wdt_reset(); heartbeat = 0; } }else{ alert(Str_EEPROM_Overflow); } } //first finish GENERAL, then MODEL !!avoid Toggle effect } else if(msk & EE_MODEL) { EepromActive = '3' ; s_eeDirtyMsk &= ~(EE_MODEL | EE_TRIM) ; if(theWriteFile.writeRlc(FILE_TMP, FILE_TYP_MODEL, (uint8_t*)&g_model, sizeof(g_model),20) == sizeof(g_model)) { EFile::swap(FILE_MODEL(g_eeGeneral.currModel),FILE_TMP); }else{ if(theWriteFile.write_errno()==ERR_TMO){ s_eeDirtyMsk |= EE_MODEL; //try again if ( msk & EE_TRIM ) { s_eeDirtyMsk |= EE_TRIM; //try again } s_eeDirtyTime10ms = get_tmr10ms() - WRITE_DELAY_10MS; if(heartbeat == 0x3) { wdt_reset(); heartbeat = 0; } }else{ if ( ( msk & EE_TRIM ) == 0 ) // Don't stop if trim adjust { alert(Str_EEPROM_Overflow); } } } } Ee_lock = 0 ; // UnLock eeprom writing }
/*luadoc @function getTime() Return the time since the radio was started in multiple of 10ms @retval number Number of 10ms ticks since the radio was started Example: run time: 12.54 seconds, return value: 1254 @status current Introduced in 2.0.0 */ static int luaGetTime(lua_State *L) { lua_pushunsigned(L, get_tmr10ms()); return 1; }
void perMain() { #if defined(PCBSKY9X) && !defined(REVA) calcConsumption(); #endif checkSpeakerVolume(); checkEeprom(); sdMountPoll(); writeLogs(); handleUsbConnection(); checkTrainerSettings(); checkBattery(); uint8_t evt = getEvent(false); if (evt && (g_eeGeneral.backlightMode & e_backlight_mode_keys)) backlightOn(); // on keypress turn the light on checkBacklight(); #if defined(NAVIGATION_STICKS) uint8_t sticks_evt = getSticksNavigationEvent(); if (sticks_evt) evt = sticks_evt; #endif #if defined(USB_MASS_STORAGE) if (usbPlugged()) { // disable access to menus lcd_clear(); menuMainView(0); lcdRefresh(); return; } #endif #if defined(LUA) uint32_t t0 = get_tmr10ms(); static uint32_t lastLuaTime = 0; uint16_t interval = (lastLuaTime == 0 ? 0 : (t0 - lastLuaTime)); lastLuaTime = t0; if (interval > maxLuaInterval) { maxLuaInterval = interval; } // run Lua scripts that don't use LCD (to use CPU time while LCD DMA is running) luaTask(0, RUN_MIX_SCRIPT | RUN_FUNC_SCRIPT | RUN_TELEM_BG_SCRIPT, false); // wait for LCD DMA to finish before continuing, because code from this point // is allowed to change the contents of LCD buffer // // WARNING: make sure no code above this line does any change to the LCD display buffer! // lcdRefreshWait(); // draw LCD from menus or from Lua script // run Lua scripts that use LCD bool standaloneScriptWasRun = luaTask(evt, RUN_STNDAL_SCRIPT, true); bool refreshScreen = true; if (!standaloneScriptWasRun) { refreshScreen = !luaTask(evt, RUN_TELEM_FG_SCRIPT, true); } t0 = get_tmr10ms() - t0; if (t0 > maxLuaDuration) { maxLuaDuration = t0; } if (!standaloneScriptWasRun) #else lcdRefreshWait(); // WARNING: make sure no code above this line does any change to the LCD display buffer! const bool refreshScreen = true; #endif { // normal GUI from menus const char *warn = s_warning; uint8_t menu = s_menu_count; if (refreshScreen) { lcd_clear(); } if (menuEvent) { m_posVert = menuEvent == EVT_ENTRY_UP ? g_menuPos[g_menuStackPtr] : 0; m_posHorz = 0; evt = menuEvent; menuEvent = 0; AUDIO_MENUS(); } g_menuStack[g_menuStackPtr]((warn || menu) ? 0 : evt); if (warn) DISPLAY_WARNING(evt); if (menu) { const char * result = displayMenu(evt); if (result) { menuHandler(result); putEvent(EVT_MENU_UP); } } drawStatusLine(); } lcdRefresh(); #if defined(REV9E) && !defined(SIMU) topLcdRefreshStart(); setTopFirstTimer(getValue(MIXSRC_FIRST_TIMER+g_model.topLcdTimer)); setTopSecondTimer(g_eeGeneral.globalTimer + sessionTimer); setTopRssi(TELEMETRY_RSSI()); setTopBatteryValue(g_vbat100mV); setTopBatteryState(GET_TXBATT_BARS(), IS_TXBATT_WARNING()); topLcdRefreshEnd(); #endif #if defined(REV9E) && !defined(SIMU) bluetoothWakeup(); #endif #if defined(PCBTARANIS) if (requestScreenshot) { requestScreenshot = false; writeScreenshot(); } #endif }
void evalFunctions() #endif { MASK_FUNC_TYPE newActiveFunctions = 0; MASK_CFN_TYPE newActiveSwitches = 0; #if defined(ROTARY_ENCODERS) && defined(GVARS) static rotenc_t rePreviousValues[ROTARY_ENCODERS]; #endif #if defined(OVERRIDE_CHANNEL_FUNCTION) for (uint8_t i=0; i<NUM_CHNOUT; i++) { safetyCh[i] = OVERRIDE_CHANNEL_UNDEFINED; } #endif #if defined(GVARS) for (uint8_t i=0; i<NUM_STICKS; i++) { trimGvar[i] = -1; } #endif for (uint8_t i=0; i<NUM_CFN; i++) { const CustomFunctionData *cfn = &functions[i]; int8_t swtch = CFN_SWITCH(cfn); if (swtch) { MASK_CFN_TYPE switch_mask = ((MASK_CFN_TYPE)1 << i); #if defined(CPUARM) bool active = getSwitch(swtch, IS_PLAY_FUNC(CFN_FUNC(cfn)) ? GETSWITCH_MIDPOS_DELAY : 0); #else bool active = getSwitch(swtch); #endif if (HAS_ENABLE_PARAM(CFN_FUNC(cfn))) { active &= (bool)CFN_ACTIVE(cfn); } if (active || IS_PLAY_BOTH_FUNC(CFN_FUNC(cfn))) { switch (CFN_FUNC(cfn)) { #if defined(OVERRIDE_CHANNEL_FUNCTION) case FUNC_OVERRIDE_CHANNEL: safetyCh[CFN_CH_INDEX(cfn)] = CFN_PARAM(cfn); break; #endif case FUNC_TRAINER: { uint8_t mask = 0x0f; if (CFN_CH_INDEX(cfn) > 0) { mask = (1<<(CFN_CH_INDEX(cfn)-1)); } newActiveFunctions |= mask; break; } case FUNC_INSTANT_TRIM: newActiveFunctions |= (1 << FUNCTION_INSTANT_TRIM); if (!isFunctionActive(FUNCTION_INSTANT_TRIM)) { #if defined(GUI) if (g_menuStack[0] == menuMainView #if defined(FRSKY) || g_menuStack[0] == menuTelemetryFrsky #endif #if defined(PCBTARANIS) || g_menuStack[0] == menuMainViewChannelsMonitor || g_menuStack[0] == menuChannelsView #endif ) #endif { instantTrim(); } } break; case FUNC_RESET: switch (CFN_PARAM(cfn)) { case FUNC_RESET_TIMER1: case FUNC_RESET_TIMER2: #if defined(CPUARM) case FUNC_RESET_TIMER3: #endif timerReset(CFN_PARAM(cfn)); break; case FUNC_RESET_FLIGHT: flightReset(); break; #if defined(FRSKY) case FUNC_RESET_TELEMETRY: telemetryReset(); break; #endif #if ROTARY_ENCODERS > 0 case FUNC_RESET_ROTENC1: #if ROTARY_ENCODERS > 1 case FUNC_RESET_ROTENC2: #endif g_rotenc[CFN_PARAM(cfn)-FUNC_RESET_ROTENC1] = 0; break; #endif } #if defined(CPUARM) if (CFN_PARAM(cfn)>=FUNC_RESET_PARAM_FIRST_TELEM) { TelemetryItem * telemetryItem = & telemetryItems[CFN_PARAM(cfn)-FUNC_RESET_PARAM_FIRST_TELEM]; telemetryItem->clear(); } #endif break; #if defined(CPUARM) case FUNC_SET_TIMER: { timerSet(CFN_TIMER_INDEX(cfn), CFN_PARAM(cfn)); break; } #endif #if 0 //defined(DANGEROUS_MODULE_FUNCTIONS) case FUNC_RANGECHECK: case FUNC_BIND: case FUNC_MODULE_OFF: { unsigned int moduleIndex = CFN_PARAM(cfn); if (moduleIndex < NUM_MODULES) { moduleFlag[moduleIndex] = 1 + CFN_FUNC(cfn) - FUNC_RANGECHECK; } break; } #endif #if defined(GVARS) case FUNC_ADJUST_GVAR: if (CFN_GVAR_MODE(cfn) == 0) { SET_GVAR(CFN_GVAR_INDEX(cfn), CFN_PARAM(cfn), mixerCurrentFlightMode); } else if (CFN_GVAR_MODE(cfn) == 2) { SET_GVAR(CFN_GVAR_INDEX(cfn), GVAR_VALUE(CFN_PARAM(cfn), mixerCurrentFlightMode), mixerCurrentFlightMode); } else if (CFN_GVAR_MODE(cfn) == 3) { if (!(functionsContext.activeSwitches & switch_mask)) { SET_GVAR(CFN_GVAR_INDEX(cfn), GVAR_VALUE(CFN_GVAR_INDEX(cfn), getGVarFlightPhase(mixerCurrentFlightMode, CFN_GVAR_INDEX(cfn))) + (CFN_PARAM(cfn) ? +1 : -1), mixerCurrentFlightMode); } } else if (CFN_PARAM(cfn) >= MIXSRC_TrimRud && CFN_PARAM(cfn) <= MIXSRC_TrimAil) { trimGvar[CFN_PARAM(cfn)-MIXSRC_TrimRud] = CFN_GVAR_INDEX(cfn); } #if defined(ROTARY_ENCODERS) else if (CFN_PARAM(cfn) >= MIXSRC_REa && CFN_PARAM(cfn) < MIXSRC_TrimRud) { int8_t scroll = rePreviousValues[CFN_PARAM(cfn)-MIXSRC_REa] - (g_rotenc[CFN_PARAM(cfn)-MIXSRC_REa] / ROTARY_ENCODER_GRANULARITY); if (scroll) { SET_GVAR(CFN_GVAR_INDEX(cfn), GVAR_VALUE(CFN_GVAR_INDEX(cfn), getGVarFlightPhase(mixerCurrentFlightMode, CFN_GVAR_INDEX(cfn))) + scroll, mixerCurrentFlightMode); } } #endif else { SET_GVAR(CFN_GVAR_INDEX(cfn), calcRESXto100(getValue(CFN_PARAM(cfn))), mixerCurrentFlightMode); } break; #endif #if defined(CPUARM) && defined(SDCARD) case FUNC_VOLUME: { getvalue_t raw = getValue(CFN_PARAM(cfn)); //only set volume if input changed more than hysteresis if (abs(requiredSpeakerVolumeRawLast - raw) > VOLUME_HYSTERESIS) { requiredSpeakerVolumeRawLast = raw; } requiredSpeakerVolume = ((1024 + requiredSpeakerVolumeRawLast) * VOLUME_LEVEL_MAX) / 2048; break; } #endif #if defined(CPUARM) && defined(SDCARD) case FUNC_PLAY_SOUND: case FUNC_PLAY_TRACK: case FUNC_PLAY_VALUE: #if defined(HAPTIC) case FUNC_HAPTIC: #endif { tmr10ms_t tmr10ms = get_tmr10ms(); uint8_t repeatParam = CFN_PLAY_REPEAT(cfn); if (!IS_SILENCE_PERIOD_ELAPSED() && repeatParam == CFN_PLAY_REPEAT_NOSTART) { functionsContext.lastFunctionTime[i] = tmr10ms; } if (!functionsContext.lastFunctionTime[i] || (repeatParam && repeatParam!=CFN_PLAY_REPEAT_NOSTART && (signed)(tmr10ms-functionsContext.lastFunctionTime[i])>=100*repeatParam)) { if (!IS_PLAYING(i+1)) { functionsContext.lastFunctionTime[i] = tmr10ms; if (CFN_FUNC(cfn) == FUNC_PLAY_SOUND) { AUDIO_PLAY(AU_FRSKY_FIRST+CFN_PARAM(cfn)); } else if (CFN_FUNC(cfn) == FUNC_PLAY_VALUE) { PLAY_VALUE(CFN_PARAM(cfn), i+1); } #if defined(HAPTIC) else if (CFN_FUNC(cfn) == FUNC_HAPTIC) { haptic.event(AU_FRSKY_LAST+CFN_PARAM(cfn)); } #endif else { playCustomFunctionFile(cfn, i+1); } } } break; } case FUNC_BACKGND_MUSIC: newActiveFunctions |= (1 << FUNCTION_BACKGND_MUSIC); if (!IS_PLAYING(i+1)) { playCustomFunctionFile(cfn, i+1); } break; case FUNC_BACKGND_MUSIC_PAUSE: newActiveFunctions |= (1 << FUNCTION_BACKGND_MUSIC_PAUSE); break; #elif defined(VOICE) case FUNC_PLAY_SOUND: case FUNC_PLAY_TRACK: case FUNC_PLAY_BOTH: case FUNC_PLAY_VALUE: { tmr10ms_t tmr10ms = get_tmr10ms(); uint8_t repeatParam = CFN_PLAY_REPEAT(cfn); if (!functionsContext.lastFunctionTime[i] || (CFN_FUNC(cfn)==FUNC_PLAY_BOTH && active!=(bool)(functionsContext.activeSwitches&switch_mask)) || (repeatParam && (signed)(tmr10ms-functionsContext.lastFunctionTime[i])>=1000*repeatParam)) { functionsContext.lastFunctionTime[i] = tmr10ms; uint8_t param = CFN_PARAM(cfn); if (CFN_FUNC(cfn) == FUNC_PLAY_SOUND) { AUDIO_PLAY(AU_FRSKY_FIRST+param); } else if (CFN_FUNC(cfn) == FUNC_PLAY_VALUE) { PLAY_VALUE(param, i+1); } else { #if defined(GVARS) if (CFN_FUNC(cfn) == FUNC_PLAY_TRACK && param > 250) param = GVAR_VALUE(param-251, getGVarFlightPhase(mixerCurrentFlightMode, param-251)); #endif PUSH_CUSTOM_PROMPT(active ? param : param+1, i+1); } } if (!active) { // PLAY_BOTH would change activeFnSwitches otherwise switch_mask = 0; } break; } #else case FUNC_PLAY_SOUND: { tmr10ms_t tmr10ms = get_tmr10ms(); uint8_t repeatParam = CFN_PLAY_REPEAT(cfn); if (!functionsContext.lastFunctionTime[i] || (repeatParam && (signed)(tmr10ms-functionsContext.lastFunctionTime[i])>=1000*repeatParam)) { functionsContext.lastFunctionTime[i] = tmr10ms; AUDIO_PLAY(AU_FRSKY_FIRST+CFN_PARAM(cfn)); } break; } #endif #if defined(FRSKY) && defined(VARIO) case FUNC_VARIO: newActiveFunctions |= (1 << FUNCTION_VARIO); break; #endif #if defined(HAPTIC) && !defined(CPUARM) case FUNC_HAPTIC: { tmr10ms_t tmr10ms = get_tmr10ms(); uint8_t repeatParam = CFN_PLAY_REPEAT(cfn); if (!functionsContext.lastFunctionTime[i] || (repeatParam && (signed)(tmr10ms-functionsContext.lastFunctionTime[i])>=1000*repeatParam)) { functionsContext.lastFunctionTime[i] = tmr10ms; haptic.event(AU_FRSKY_LAST+CFN_PARAM(cfn)); } break; } #endif #if defined(SDCARD) case FUNC_LOGS: if (CFN_PARAM(cfn)) { newActiveFunctions |= (1 << FUNCTION_LOGS); logDelay = CFN_PARAM(cfn); } break; #endif case FUNC_BACKLIGHT: newActiveFunctions |= (1 << FUNCTION_BACKLIGHT); break; #if defined(PCBTARANIS) case FUNC_SCREENSHOT: if (!(functionsContext.activeSwitches & switch_mask)) { requestScreenshot = true; } break; #endif #if defined(DEBUG) case FUNC_TEST: testFunc(); break; #endif } newActiveSwitches |= switch_mask; } else { functionsContext.lastFunctionTime[i] = 0; } } } functionsContext.activeSwitches = newActiveSwitches; functionsContext.activeFunctions = newActiveFunctions; #if defined(ROTARY_ENCODERS) && defined(GVARS) for (uint8_t i=0; i<ROTARY_ENCODERS; i++) { rePreviousValues[i] = (g_rotenc[i] / ROTARY_ENCODER_GRANULARITY); } #endif }