void menuTelemetryFrsky(uint8_t event) { enum NavigationDirection direction = none; switch (event) { case EVT_KEY_FIRST(KEY_EXIT): case EVT_KEY_LONG(KEY_EXIT): killEvents(event); chainMenu(menuMainView); break; case EVT_KEY_LONG(KEY_PAGE): killEvents(event); // no break; case EVT_KEY_FIRST(KEY_UP): decrTelemetryScreen(); break; case EVT_KEY_BREAK(KEY_PAGE): case EVT_KEY_FIRST(KEY_DOWN): incrTelemetryScreen(); break; case EVT_KEY_LONG(KEY_ENTER): killEvents(event); POPUP_MENU_ADD_ITEM(STR_RESET_TELEMETRY); POPUP_MENU_ADD_ITEM(STR_RESET_FLIGHT); popupMenuHandler = onMainViewMenu; break; } for (int i=0; i<=TELEMETRY_SCREEN_TYPE_MAX; i++) { if (direction == up) { if (s_frsky_view-- == 0) s_frsky_view = TELEMETRY_VIEW_MAX; } else if (direction == down) { if (s_frsky_view++ == TELEMETRY_VIEW_MAX) s_frsky_view = 0; } else { direction = down; } if (displayTelemetryScreen()) { return; } } lcdDrawTelemetryTopBar(); lcd_puts(8*FW, 3*FH, "No Telemetry Screens"); displayRssiLine(); }
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 } }
/*luadoc @function killEvents(key) Stops key state machine. @param key (number) key to be killed, can also include event type (only key part is used) @status current Introduced in 2.0.0 TODO table of events/masks */ static int luaKillEvents(lua_State *L) { uint8_t key = EVT_KEY_MASK(luaL_checkinteger(L, 1)); // prevent killing PAGE, ENT and EXIT (only in telemetry scripts) // todo add which tpye of scrip is running before p_call() if (key != KEY_EXIT && key != KEY_ENTER && key != KEY_PAGE) { killEvents(key); } return 0; }
void menuTraceBuffer(uint8_t event) { switch(event) { case EVT_KEY_LONG(KEY_ENTER): dumpTraceBuffer(); killEvents(event); break; } SIMPLE_SUBMENU("Trace Buffer " VERS_STR, TRACE_BUFFER_LEN); /* RTC time */ struct gtm t; gettime(&t); putsTime(LCD_W+1, 0, t, TIMEBLINK); uint8_t y = 0; uint8_t k = 0; int8_t sub = m_posVert; lcd_putc(0, FH, '#'); lcd_puts(4*FW, FH, "Time"); lcd_puts(14*FW, FH, "Event"); lcd_puts(20*FW, FH, "Data"); for (uint8_t i=0; i<LCD_LINES-2; i++) { y = 1 + (i+2)*FH; k = i+s_pgOfs; //item lcd_outdezAtt(0, y, k, LEFT | (sub==k ? INVERS : 0)); const struct TraceElement * te = getTraceElement(k); if (te) { //time putstime_t tme = te->time % SECS_PER_DAY; putsTimer(4*FW, y, tme, TIMEHOUR|LEFT, TIMEHOUR|LEFT); //event lcd_outdezNAtt(14*FW, y, te->event, LEADING0|LEFT, 3); //data lcd_putsn (20*FW, y, "0x", 2); lcd_outhex4(22*FW-2, y, (uint16_t)(te->data >> 16)); lcd_outhex4(25*FW, y, (uint16_t)(te->data & 0xFFFF)); } } }
void pushMenu(menuHandlerFunc newMenu) { killEvents(KEY_ENTER); if (menuLevel == 0) { if (newMenu == menuGeneralSetup) menuVerticalPositions[0] = 1; if (newMenu == menuModelSelect) menuVerticalPositions[0] = 0; } else { menuVerticalPositions[menuLevel] = menuVerticalPosition; } menuLevel++; assert(menuLevel < DIM(menuHandlers)); menuHandlers[menuLevel] = newMenu; menuEvent = EVT_ENTRY; TRACE("pushMenu(%d, %p)", menuLevel, newMenu); }
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); }
int16_t checkIncDec(uint8_t event, int16_t val, int16_t i_min, int16_t i_max, uint8_t i_flags) { int16_t newval = val; #if defined(DBLKEYS) uint8_t in = KEYS_PRESSED(); if (!(i_flags & NO_DBLKEYS) && (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); } else if (DBLKEYS_PRESSED_LFT_DWN(in)) { newval = (i_min < -100 ? -100 : i_min); } else if (DBLKEYS_PRESSED_UP_DWN(in)) { newval = 0; } else { dblkey = false; } if (dblkey) { killEvents(KEY_UP); killEvents(KEY_DOWN); killEvents(KEY_RIGHT); killEvents(KEY_LEFT); event = 0; } } #endif 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)))) { newval++; AUDIO_KEYPAD_UP(); } 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)))) { newval--; 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) { newval = checkIncDecMovedSwitch(newval); } #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; }
void check(check_event_t event, uint8_t curr, const MenuHandlerFunc *menuTab, uint8_t menuTabSize, const pm_uint8_t *horTab, uint8_t horTabMax, vertpos_t maxrow) { vertpos_t l_posVert = menuVerticalPosition; horzpos_t l_posHorz = menuHorizontalPosition; 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((MenuHandlerFunc)pgm_read_adr(&menuTab[cc])); } #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: 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(); break; 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 } 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) 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; } uint8_t maxLines = menuTab ? LCD_LINES-1 : LCD_LINES-2; if (l_posVert<1) { menuVerticalOffset=0; } else { if (l_posVert>maxLines+menuVerticalOffset) { menuVerticalOffset = l_posVert-maxLines; } else if (l_posVert<=menuVerticalOffset) { menuVerticalOffset = l_posVert-1; } } menuVerticalPosition = l_posVert; menuHorizontalPosition = l_posHorz; #if !defined(CPUM64) // cosmetics on 9x if (menuVerticalOffset > 0) { l_posVert--; if (l_posVert == menuVerticalOffset && CURSOR_NOT_ALLOWED_IN_ROW(l_posVert)) { menuVerticalOffset = l_posVert-1; } } #endif }
void menuModelFlightModesAll(uint8_t event) { MENU(STR_MENUFLIGHTPHASES, menuTabModel, e_FlightModesAll, MAX_FLIGHT_MODES+1, { NAVIGATION_LINE_BY_LINE|(ITEM_FLIGHT_MODES_LAST-1), NAVIGATION_LINE_BY_LINE|ITEM_FLIGHT_MODES_LAST, NAVIGATION_LINE_BY_LINE|ITEM_FLIGHT_MODES_LAST, NAVIGATION_LINE_BY_LINE|NAVIGATION_LINE_BY_LINE|ITEM_FLIGHT_MODES_LAST, NAVIGATION_LINE_BY_LINE|ITEM_FLIGHT_MODES_LAST, NAVIGATION_LINE_BY_LINE|ITEM_FLIGHT_MODES_LAST, NAVIGATION_LINE_BY_LINE|ITEM_FLIGHT_MODES_LAST, NAVIGATION_LINE_BY_LINE|ITEM_FLIGHT_MODES_LAST, NAVIGATION_LINE_BY_LINE|ITEM_FLIGHT_MODES_LAST, 0 }); int8_t sub = menuVerticalPosition; horzpos_t posHorz = menuHorizontalPosition; if (sub==0 && posHorz > 0) { posHorz += 1; } if (sub<MAX_FLIGHT_MODES && posHorz>=0) { displayColumnHeader(STR_PHASES_HEADERS, posHorz); } for (uint8_t i=0; i<LCD_LINES-1; i++) { coord_t y = MENU_HEADER_HEIGHT + 1 + i*FH; uint8_t k = i+menuVerticalOffset; if (k==MAX_FLIGHT_MODES) { // last line available - add the "check trims" line lcd_putsLeft((LCD_LINES-1)*FH+1, STR_CHECKTRIMS); putsFlightMode(OFS_CHECKTRIMS, (LCD_LINES-1)*FH+1, mixerCurrentFlightMode+1); if (sub==MAX_FLIGHT_MODES) { if (!trimsCheckTimer) { if (event == EVT_KEY_FIRST(KEY_ENTER)) { trimsCheckTimer = 200; // 2 seconds trims cancelled s_editMode = 1; killEvents(event); } else { lcd_status_line(); s_editMode = 0; } } else { if (event == EVT_KEY_FIRST(KEY_EXIT)) { trimsCheckTimer = 0; s_editMode = 0; killEvents(event); } } } return; } FlightModeData *p = flightModeAddress(k); putsFlightMode(0, y, k+1, (getFlightMode()==k ? BOLD : 0) | ((sub==k && menuHorizontalPosition<0) ? INVERS : 0)); for (uint8_t j=0; j<ITEM_FLIGHT_MODES_COUNT; j++) { uint8_t attr = ((sub==k && posHorz==j) ? ((s_editMode>0) ? BLINK|INVERS : INVERS) : 0); uint8_t active = (attr && s_editMode>0) ; switch (j) { case ITEM_FLIGHT_MODES_NAME: editName(4*FW-1, y, p->name, sizeof(p->name), event, attr); break; case ITEM_FLIGHT_MODES_SWITCH: if (k>0) { putsSwitches((4+LEN_FLIGHT_MODE_NAME)*FW+FW/2, y, p->swtch, attr); if (active) CHECK_INCDEC_MODELSWITCH(event, p->swtch, SWSRC_FIRST_IN_MIXES, SWSRC_LAST_IN_MIXES, isSwitchAvailableInMixes); } break; case ITEM_FLIGHT_MODES_TRIM_RUD: case ITEM_FLIGHT_MODES_TRIM_ELE: case ITEM_FLIGHT_MODES_TRIM_THR: case ITEM_FLIGHT_MODES_TRIM_AIL: { uint8_t t = j-ITEM_FLIGHT_MODES_TRIM_RUD; putsTrimMode((4+LEN_FLIGHT_MODE_NAME)*FW+j*(5*FW/2), y, k, t, attr); if (active) { trim_t & v = p->trim[t]; v.mode = checkIncDec(event, v.mode==TRIM_MODE_NONE ? -1 : v.mode, -1, k==0 ? 0 : 2*MAX_FLIGHT_MODES-1, EE_MODEL, isTrimModeAvailable); } break; } case ITEM_FLIGHT_MODES_FADE_IN: lcd_outdezAtt(32*FW-2, y, (10/DELAY_STEP)*p->fadeIn, attr|PREC1); if (active) p->fadeIn = checkIncDec(event, p->fadeIn, 0, DELAY_MAX, EE_MODEL|NO_INCDEC_MARKS); break; case ITEM_FLIGHT_MODES_FADE_OUT: lcd_outdezAtt(35*FW, y, (10/DELAY_STEP)*p->fadeOut, attr|PREC1); if (active) p->fadeOut = checkIncDec(event, p->fadeOut, 0, DELAY_MAX, EE_MODEL|NO_INCDEC_MARKS); break; } } } }
uint32_t fileList(uint8_t event, struct fileControl *fc ) { uint32_t limit ; uint32_t result = 0 ; uint8_t maxhsize ; uint32_t i ; limit = 6 ; if ( fc->nameCount < limit ) { limit = fc->nameCount ; } maxhsize = 0 ; for ( i = 0 ; i < limit ; i += 1 ) { uint32_t x ; uint32_t len ; len = x = strlen( Filenames[i] ) ; if ( x > maxhsize ) { maxhsize = x ; } if ( x > DISPLAY_CHAR_WIDTH ) { if ( ( fc->hpos + DISPLAY_CHAR_WIDTH ) > x ) { x = x - DISPLAY_CHAR_WIDTH ; } else { x = fc->hpos ; } len = DISPLAY_CHAR_WIDTH ; } else { x = 0 ; } lcd_putsn_P( 0, 16+FH*i, &Filenames[i][x], len ) ; } #if !defined(PCBTARANIS) if ( event == 0 ) { extern int32_t Rotary_diff ; if ( Rotary_diff > 0 ) { event = EVT_KEY_FIRST(KEY_DOWN) ; } else if ( Rotary_diff < 0 ) { event = EVT_KEY_FIRST(KEY_UP) ; } Rotary_diff = 0 ; } #endif if ( ( event == EVT_KEY_REPT(KEY_DOWN) ) || event == EVT_KEY_FIRST(KEY_DOWN) ) { if ( fc->vpos < limit-1 ) { fc->vpos += 1 ; } else { if ( fc->nameCount > limit ) { fc->index += 1 ; fc->nameCount = fillNames( fc->index, fc ) ; } } } if ( ( event == EVT_KEY_REPT(KEY_UP)) || ( event == EVT_KEY_FIRST(KEY_UP) ) ) { if ( fc->vpos > 0 ) { fc->vpos -= 1 ; } else { if ( fc->index ) { fc->index -= 1 ; fc->nameCount = fillNames( fc->index, fc ) ; } } } if ( ( event == EVT_KEY_REPT(MKEY_RIGHT)) || ( event == EVT_KEY_FIRST(MKEY_RIGHT) ) ) { if ( fc->hpos + DISPLAY_CHAR_WIDTH < maxhsize ) fc->hpos += 1 ; } if ( ( event == EVT_KEY_REPT(MKEY_LEFT)) || ( event == EVT_KEY_FIRST(MKEY_LEFT) ) ) { if ( fc->hpos ) fc->hpos -= 1 ; } if ( ( event == EVT_KEY_LONG(KEY_MENU) ) || ( event == EVT_KEY_BREAK(BTN_RE) ) ) { // Select file to flash killEvents(event); result = 1 ; } if ( ( event == EVT_KEY_FIRST(KEY_EXIT) ) || ( event == EVT_KEY_LONG(BTN_RE) ) ) { // Select file to flash result = 2 ; } if ( event == EVT_KEY_BREAK(KEY_MENU) ) { // Tag file result = 3 ; } #if defined(PCBTARANIS) lcd_filled_rect( 0, 2*FH+FH*fc->vpos, DISPLAY_CHAR_WIDTH*FW, 8, 0xFF, 0 ) ; #else lcd_char_inverse( 0, 2*FH+FH*fc->vpos, DISPLAY_CHAR_WIDTH*FW, 0 ) ; #endif return result ; }
void menuModelFailsafe(uint8_t event) { static bool longNames = false; bool newLongNames = false; uint8_t ch = 0; uint8_t channelStart = g_model.moduleData[g_moduleIdx].channelsStart; if (event == EVT_KEY_LONG(KEY_ENTER)) { killEvents(event); event = 0; if (s_editMode) { g_model.moduleData[g_moduleIdx].failsafeChannels[menuVerticalPosition] = channelOutputs[menuVerticalPosition+channelStart]; eeDirty(EE_MODEL); AUDIO_WARNING1(); s_editMode = 0; SEND_FAILSAFE_NOW(g_moduleIdx); } else { int16_t & failsafe = g_model.moduleData[g_moduleIdx].failsafeChannels[menuVerticalPosition]; if (failsafe < FAILSAFE_CHANNEL_HOLD) failsafe = FAILSAFE_CHANNEL_HOLD; else if (failsafe == FAILSAFE_CHANNEL_HOLD) failsafe = FAILSAFE_CHANNEL_NOPULSE; else failsafe = 0; eeDirty(EE_MODEL); AUDIO_WARNING1(); SEND_FAILSAFE_NOW(g_moduleIdx); } } SIMPLE_SUBMENU_NOTITLE(NUM_CHANNELS(g_moduleIdx)); SET_SCROLLBAR_X(0); #define COL_W (LCD_W/2) const uint8_t SLIDER_W = 64; // Column separator lcd_vline(LCD_W/2, FH, LCD_H-FH); lcd_putsCenter(0*FH, FAILSAFESET); lcd_invert_line(0); unsigned int lim = g_model.extendedLimits ? 640*2 : 512*2; for (uint8_t col=0; col<2; col++) { coord_t x = col*COL_W+1; // Channels for (uint8_t line=0; line<8; line++) { coord_t y = 9+line*7; int32_t channelValue = channelOutputs[ch+channelStart]; int32_t failsafeValue = 0; bool failsafeEditable = false; uint8_t ofs = (col ? 0 : 1); if (ch < NUM_CHANNELS(g_moduleIdx)) { failsafeValue = g_model.moduleData[g_moduleIdx].failsafeChannels[8*col+line]; failsafeEditable = true; } if (failsafeEditable) { // Channel name if present, number if not uint8_t lenLabel = ZLEN(g_model.limitData[ch+channelStart].name); if (lenLabel > 4) { newLongNames = longNames = true; } if (lenLabel > 0) lcd_putsnAtt(x+1-ofs, y, g_model.limitData[ch+channelStart].name, sizeof(g_model.limitData[ch+channelStart].name), ZCHAR | SMLSIZE); else putsChn(x+1-ofs, y, ch+1, SMLSIZE); // Value LcdFlags flags = TINSIZE; if (menuVerticalPosition == ch) { flags |= INVERS; if (s_editMode) { if (failsafeValue == FAILSAFE_CHANNEL_HOLD || failsafeValue == FAILSAFE_CHANNEL_NOPULSE) { s_editMode = 0; } else { flags |= BLINK; CHECK_INCDEC_MODELVAR(event, g_model.moduleData[g_moduleIdx].failsafeChannels[8*col+line], -lim, +lim); } } } #if defined(PPM_UNIT_PERCENT_PREC1) uint8_t wbar = (longNames ? SLIDER_W-16 : SLIDER_W-6); #else uint8_t wbar = (longNames ? SLIDER_W-10 : SLIDER_W); #endif if (failsafeValue == FAILSAFE_CHANNEL_HOLD) { lcd_putsAtt(x+COL_W-4-wbar-ofs-16, y, "HOLD", flags); failsafeValue = 0; } else if (failsafeValue == FAILSAFE_CHANNEL_NOPULSE) { lcd_putsAtt(x+COL_W-4-wbar-ofs-16, y, "NONE", flags); failsafeValue = 0; } else { #if defined(PPM_UNIT_US) lcd_outdezAtt(x+COL_W-4-wbar-ofs, y, PPM_CH_CENTER(ch)+failsafeValue/2, flags); #elif defined(PPM_UNIT_PERCENT_PREC1) lcd_outdezAtt(x+COL_W-4-wbar-ofs, y, calcRESXto1000(failsafeValue), PREC1|flags); #else lcd_outdezAtt(x+COL_W-4-wbar-ofs, y, calcRESXto1000(failsafeValue)/10, flags); #endif } // Gauge lcd_rect(x+COL_W-3-wbar-ofs, y, wbar+1, 6); unsigned int lenChannel = limit((uint8_t)1, uint8_t((abs(channelValue) * wbar/2 + lim/2) / lim), uint8_t(wbar/2)); unsigned int lenFailsafe = limit((uint8_t)1, uint8_t((abs(failsafeValue) * wbar/2 + lim/2) / lim), uint8_t(wbar/2)); coord_t xChannel = (channelValue>0) ? x+COL_W-ofs-3-wbar/2 : x+COL_W-ofs-2-wbar/2-lenChannel; coord_t xFailsafe = (failsafeValue>0) ? x+COL_W-ofs-3-wbar/2 : x+COL_W-ofs-2-wbar/2-lenFailsafe; lcd_hlineStip(xChannel, y+1, lenChannel, DOTTED, 0); lcd_hlineStip(xChannel, y+2, lenChannel, DOTTED, 0); lcd_hline(xFailsafe, y+3, lenFailsafe); lcd_hline(xFailsafe, y+4, lenFailsafe); } ch++; } } longNames = newLongNames; }
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 menuModelSetup(uint8_t event) { horzpos_t l_posHorz = menuHorizontalPosition; bool CURSOR_ON_CELL = (menuHorizontalPosition >= 0); #if defined(TARANIS_INTERNAL_PPM) MENU_TAB({ 0, 0, TIMERS_ROWS, TOPLCD_ROWS 0, 1, 0, 0, LABEL(Throttle), 0, 0, 0, LABEL(PreflightCheck), 0, 0, SW_WARN_ITEMS(), POT_WARN_ITEMS(), NAVIGATION_LINE_BY_LINE|(NUM_STICKS+NUM_POTS+NUM_ROTARY_ENCODERS-1), 0, LABEL(InternalModule), INTERNAL_MODULE_MODE_ROWS, INTERNAL_MODULE_CHANNELS_ROWS, IF_INTERNAL_MODULE_ON(IS_MODULE_XJT(INTERNAL_MODULE) ? (HAS_RF_PROTOCOL_MODELINDEX(g_model.moduleData[INTERNAL_MODULE].rfProtocol) ? (uint8_t)2 : (uint8_t)1) : (IS_MODULE_PPM(INTERNAL_MODULE) ? (uint8_t)1 : HIDDEN_ROW)), IF_INTERNAL_MODULE_ON((IS_MODULE_XJT(INTERNAL_MODULE)) ? FAILSAFE_ROWS(INTERNAL_MODULE) : HIDDEN_ROW), LABEL(ExternalModule), (IS_MODULE_XJT(EXTERNAL_MODULE) || IS_MODULE_DSM2(EXTERNAL_MODULE)) ? (uint8_t)1 : (uint8_t)0, EXTERNAL_MODULE_CHANNELS_ROWS, (IS_MODULE_XJT(EXTERNAL_MODULE) && !HAS_RF_PROTOCOL_MODELINDEX(g_model.moduleData[EXTERNAL_MODULE].rfProtocol)) ? (uint8_t)1 : (IS_MODULE_PPM(EXTERNAL_MODULE) || IS_MODULE_XJT(EXTERNAL_MODULE) || IS_MODULE_DSM2(EXTERNAL_MODULE)) ? (uint8_t)2 : HIDDEN_ROW, IF_EXTERNAL_MODULE_XJT(FAILSAFE_ROWS(EXTERNAL_MODULE)), LABEL(Trainer), 0, TRAINER_CHANNELS_ROWS(), IF_TRAINER_ON(2)}); #else MENU_TAB({ 0, 0, TIMERS_ROWS, TOPLCD_ROWS 0, 1, 0, 0, LABEL(Throttle), 0, 0, 0, LABEL(PreflightCheck), 0, 0, SW_WARN_ITEMS(), POT_WARN_ITEMS(), NAVIGATION_LINE_BY_LINE|(NUM_STICKS+NUM_POTS+NUM_ROTARY_ENCODERS-1), 0, LABEL(InternalModule), INTERNAL_MODULE_MODE_ROWS, INTERNAL_MODULE_CHANNELS_ROWS, IF_INTERNAL_MODULE_ON(HAS_RF_PROTOCOL_MODELINDEX(g_model.moduleData[INTERNAL_MODULE].rfProtocol) ? (uint8_t)2 : (uint8_t)1), IF_INTERNAL_MODULE_ON(FAILSAFE_ROWS(INTERNAL_MODULE)), LABEL(ExternalModule), EXTERNAL_MODULE_MODE_ROWS, EXTERNAL_MODULE_CHANNELS_ROWS, (IS_MODULE_XJT(EXTERNAL_MODULE) && !HAS_RF_PROTOCOL_MODELINDEX(g_model.moduleData[EXTERNAL_MODULE].rfProtocol)) ? (uint8_t)1 : (IS_MODULE_PPM(EXTERNAL_MODULE) || IS_MODULE_XJT(EXTERNAL_MODULE) || IS_MODULE_DSM2(EXTERNAL_MODULE)) ? (uint8_t)2 : HIDDEN_ROW, IF_EXTERNAL_MODULE_XJT(FAILSAFE_ROWS(EXTERNAL_MODULE)), LABEL(Trainer), 0, TRAINER_CHANNELS_ROWS(), IF_TRAINER_ON(2)}); #endif MENU_CHECK(STR_MENUSETUP, menuTabModel, e_ModelSetup, ITEM_MODEL_SETUP_MAX); #if (defined(DSM2) || defined(PXX)) if (menuEvent) { moduleFlag[0] = 0; moduleFlag[1] = 0; } #endif int sub = menuVerticalPosition; for (int i=0; i<NUM_BODY_LINES; ++i) { coord_t y = MENU_HEADER_HEIGHT + 1 + i*FH; uint8_t k = i+menuVerticalOffset; for (int j=0; j<=k; j++) { if (mstate_tab[j] == HIDDEN_ROW) k++; } LcdFlags blink = ((s_editMode>0) ? BLINK|INVERS : INVERS); LcdFlags attr = (sub == k ? blink : 0); switch(k) { case ITEM_MODEL_NAME: editSingleName(MODEL_SETUP_2ND_COLUMN, y, STR_MODELNAME, g_model.header.name, sizeof(g_model.header.name), event, attr); memcpy(modelHeaders[g_eeGeneral.currModel].name, g_model.header.name, sizeof(g_model.header.name)); break; case ITEM_MODEL_BITMAP: lcd_putsLeft(y, STR_BITMAP); if (ZEXIST(g_model.header.bitmap)) lcd_putsnAtt(MODEL_SETUP_2ND_COLUMN, y, g_model.header.bitmap, sizeof(g_model.header.bitmap), attr); else lcd_putsiAtt(MODEL_SETUP_2ND_COLUMN, y, STR_VCSWFUNC, 0, attr); if (attr && event==EVT_KEY_BREAK(KEY_ENTER) && READ_ONLY_UNLOCKED()) { s_editMode = 0; if (listSdFiles(BITMAPS_PATH, BITMAPS_EXT, sizeof(g_model.header.bitmap), g_model.header.bitmap, LIST_NONE_SD_FILE)) { popupMenuHandler = onModelSetupBitmapMenu; } else { POPUP_WARNING(STR_NO_BITMAPS_ON_SD); } } break; case ITEM_MODEL_TIMER1: editTimerMode(0, y, attr, event); break; case ITEM_MODEL_TIMER1_NAME: editSingleName(MODEL_SETUP_2ND_COLUMN, y, STR_TIMER_NAME, g_model.timers[0].name, LEN_TIMER_NAME, event, attr); break; case ITEM_MODEL_TIMER1_MINUTE_BEEP: g_model.timers[0].minuteBeep = onoffMenuItem(g_model.timers[0].minuteBeep, MODEL_SETUP_2ND_COLUMN, y, STR_MINUTEBEEP, attr, event); break; case ITEM_MODEL_TIMER1_COUNTDOWN_BEEP: g_model.timers[0].countdownBeep = selectMenuItem(MODEL_SETUP_2ND_COLUMN, y, STR_BEEPCOUNTDOWN, STR_VBEEPCOUNTDOWN, g_model.timers[0].countdownBeep, COUNTDOWN_SILENT, COUNTDOWN_COUNT-1, attr, event); break; case ITEM_MODEL_TIMER1_PERSISTENT: g_model.timers[0].persistent = selectMenuItem(MODEL_SETUP_2ND_COLUMN, y, STR_PERSISTENT, STR_VPERSISTENT, g_model.timers[0].persistent, 0, 2, attr, event); break; #if TIMERS > 1 case ITEM_MODEL_TIMER2: editTimerMode(1, y, attr, event); break; case ITEM_MODEL_TIMER2_NAME: editSingleName(MODEL_SETUP_2ND_COLUMN, y, STR_TIMER_NAME, g_model.timers[1].name, LEN_TIMER_NAME, event, attr); break; case ITEM_MODEL_TIMER2_MINUTE_BEEP: g_model.timers[1].minuteBeep = onoffMenuItem(g_model.timers[1].minuteBeep, MODEL_SETUP_2ND_COLUMN, y, STR_MINUTEBEEP, attr, event); break; case ITEM_MODEL_TIMER2_COUNTDOWN_BEEP: g_model.timers[1].countdownBeep = selectMenuItem(MODEL_SETUP_2ND_COLUMN, y, STR_BEEPCOUNTDOWN, STR_VBEEPCOUNTDOWN, g_model.timers[1].countdownBeep, COUNTDOWN_SILENT, COUNTDOWN_COUNT-1, attr, event); break; case ITEM_MODEL_TIMER2_PERSISTENT: g_model.timers[1].persistent = selectMenuItem(MODEL_SETUP_2ND_COLUMN, y, STR_PERSISTENT, STR_VPERSISTENT, g_model.timers[1].persistent, 0, 2, attr, event); break; #endif #if TIMERS > 2 case ITEM_MODEL_TIMER3: editTimerMode(2, y, attr, event); break; case ITEM_MODEL_TIMER3_NAME: editSingleName(MODEL_SETUP_2ND_COLUMN, y, STR_TIMER_NAME, g_model.timers[2].name, LEN_TIMER_NAME, event, attr); break; case ITEM_MODEL_TIMER3_MINUTE_BEEP: g_model.timers[2].minuteBeep = onoffMenuItem(g_model.timers[2].minuteBeep, MODEL_SETUP_2ND_COLUMN, y, STR_MINUTEBEEP, attr, event); break; case ITEM_MODEL_TIMER3_COUNTDOWN_BEEP: g_model.timers[2].countdownBeep = selectMenuItem(MODEL_SETUP_2ND_COLUMN, y, STR_BEEPCOUNTDOWN, STR_VBEEPCOUNTDOWN, g_model.timers[2].countdownBeep, COUNTDOWN_SILENT, COUNTDOWN_COUNT-1, attr, event); break; case ITEM_MODEL_TIMER3_PERSISTENT: g_model.timers[2].persistent = selectMenuItem(MODEL_SETUP_2ND_COLUMN, y, STR_PERSISTENT, STR_VPERSISTENT, g_model.timers[2].persistent, 0, 2, attr, event); break; #endif #if defined(REV9E) case ITEM_MODEL_TOP_LCD_TIMER: lcd_putsLeft(y, STR_TOPLCDTIMER); putsStrIdx(MODEL_SETUP_2ND_COLUMN, y, STR_TIMER, g_model.topLcdTimer+1, attr); if (attr) { g_model.topLcdTimer = checkIncDec(event, g_model.topLcdTimer, 0, TIMERS-1, EE_MODEL); } break; #endif case ITEM_MODEL_EXTENDED_LIMITS: ON_OFF_MENU_ITEM(g_model.extendedLimits, MODEL_SETUP_2ND_COLUMN, y, STR_ELIMITS, attr, event); break; case ITEM_MODEL_EXTENDED_TRIMS: ON_OFF_MENU_ITEM(g_model.extendedTrims, MODEL_SETUP_2ND_COLUMN, y, STR_ETRIMS, menuHorizontalPosition<=0 ? attr : 0, event==EVT_KEY_BREAK(KEY_ENTER) ? event : 0); lcd_putsAtt(MODEL_SETUP_2ND_COLUMN+3*FW, y, STR_RESET_BTN, (menuHorizontalPosition>0 && !NO_HIGHLIGHT()) ? attr : 0); if (attr && menuHorizontalPosition>0) { s_editMode = 0; if (event==EVT_KEY_LONG(KEY_ENTER)) { START_NO_HIGHLIGHT(); for (uint8_t i=0; i<MAX_FLIGHT_MODES; i++) { memclear(&g_model.flightModeData[i], TRIMS_ARRAY_SIZE); } eeDirty(EE_MODEL); AUDIO_WARNING1(); } } break; case ITEM_MODEL_DISPLAY_TRIMS: g_model.displayTrims = selectMenuItem(MODEL_SETUP_2ND_COLUMN, y, STR_DISPLAY_TRIMS, STR_VDISPLAYTRIMS, g_model.displayTrims, 0, 2, attr, event); break; case ITEM_MODEL_TRIM_INC: g_model.trimInc = selectMenuItem(MODEL_SETUP_2ND_COLUMN, y, STR_TRIMINC, STR_VTRIMINC, g_model.trimInc, -2, 2, attr, event); break; case ITEM_MODEL_THROTTLE_LABEL: lcd_putsLeft(y, STR_THROTTLE_LABEL); break; case ITEM_MODEL_THROTTLE_REVERSED: ON_OFF_MENU_ITEM(g_model.throttleReversed, MODEL_SETUP_2ND_COLUMN, y, STR_THROTTLEREVERSE, attr, event ) ; break; case ITEM_MODEL_THROTTLE_TRACE: { lcd_putsLeft(y, STR_TTRACE); if (attr) CHECK_INCDEC_MODELVAR_ZERO_CHECK(event, g_model.thrTraceSrc, NUM_POTS+NUM_CHNOUT, isThrottleSourceAvailable); uint8_t idx = g_model.thrTraceSrc + MIXSRC_Thr; if (idx > MIXSRC_Thr) idx += 1; if (idx >= MIXSRC_FIRST_POT+NUM_POTS) idx += MIXSRC_CH1 - MIXSRC_FIRST_POT - NUM_POTS; putsMixerSource(MODEL_SETUP_2ND_COLUMN, y, idx, attr); break; } case ITEM_MODEL_THROTTLE_TRIM: ON_OFF_MENU_ITEM(g_model.thrTrim, MODEL_SETUP_2ND_COLUMN, y, STR_TTRIM, attr, event); break; case ITEM_MODEL_PREFLIGHT_LABEL: lcd_putsLeft(y, STR_PREFLIGHT); break; case ITEM_MODEL_CHECKLIST_DISPLAY: ON_OFF_MENU_ITEM(g_model.displayChecklist, MODEL_SETUP_2ND_COLUMN, y, STR_CHECKLIST, attr, event); break; case ITEM_MODEL_THROTTLE_WARNING: g_model.disableThrottleWarning = !onoffMenuItem(!g_model.disableThrottleWarning, MODEL_SETUP_2ND_COLUMN, y, STR_THROTTLEWARNING, attr, event); break; #if defined(REV9E) case ITEM_MODEL_SWITCHES_WARNING2: case ITEM_MODEL_SWITCHES_WARNING3: case ITEM_MODEL_POTS_WARNING2: if (i==0) { if (CURSOR_MOVED_LEFT(event)) menuVerticalOffset--; else menuVerticalOffset++; } break; #endif case ITEM_MODEL_SWITCHES_WARNING: { #if defined(REV9E) if (i>=NUM_BODY_LINES-2 && getSwitchWarningsCount() > 8*(NUM_BODY_LINES-i)) { if (CURSOR_MOVED_LEFT(event)) menuVerticalOffset--; else menuVerticalOffset++; break; } #endif lcd_putsLeft(y, STR_SWITCHWARNING); swarnstate_t states = g_model.switchWarningState; char c; if (attr) { s_editMode = 0; if (!READ_ONLY()) { switch (event) { CASE_EVT_ROTARY_BREAK case EVT_KEY_BREAK(KEY_ENTER): break; case EVT_KEY_LONG(KEY_ENTER): if (menuHorizontalPosition < 0) { START_NO_HIGHLIGHT(); getMovedSwitch(); g_model.switchWarningState = switches_states; AUDIO_WARNING1(); eeDirty(EE_MODEL); } killEvents(event); break; } } } LcdFlags line = attr; int current = 0; for (int i=0; i<NUM_SWITCHES; i++) { if (SWITCH_WARNING_ALLOWED(i)) { div_t qr = div(current, 8); if (!READ_ONLY() && event==EVT_KEY_BREAK(KEY_ENTER) && line && l_posHorz==current) { g_model.switchWarningEnable ^= (1 << i); eeDirty(EE_MODEL); } uint8_t swactive = !(g_model.switchWarningEnable & (1<<i)); c = "\300-\301"[states & 0x03]; lcd_putcAtt(MODEL_SETUP_2ND_COLUMN+qr.rem*(2*FW+1), y+FH*qr.quot, 'A'+i, line && (menuHorizontalPosition==current) ? INVERS : 0); if (swactive) lcd_putc(lcdNextPos, y+FH*qr.quot, c); ++current; } states >>= 2; } if (attr && menuHorizontalPosition < 0) { #if defined(REV9E) drawFilledRect(MODEL_SETUP_2ND_COLUMN-1, y-1, 8*(2*FW+1), 1+FH*((current+7)/8)); #else drawFilledRect(MODEL_SETUP_2ND_COLUMN-1, y-1, current*(2*FW+1), FH+1); #endif } break; } case ITEM_MODEL_POTS_WARNING: #if defined(REV9E) if (i==NUM_BODY_LINES-1 && g_model.potsWarnMode) { if (CURSOR_MOVED_LEFT(event)) menuVerticalOffset--; else menuVerticalOffset++; break; } #endif lcd_putsLeft(y, STR_POTWARNING); lcd_putsiAtt(MODEL_SETUP_2ND_COLUMN, y, PSTR("\004""OFF\0""Man\0""Auto"), g_model.potsWarnMode, (menuHorizontalPosition == 0) ? attr : 0); if (attr && (menuHorizontalPosition == 0)) { CHECK_INCDEC_MODELVAR(event, g_model.potsWarnMode, POTS_WARN_OFF, POTS_WARN_AUTO); eeDirty(EE_MODEL); } if (attr) { if (menuHorizontalPosition > 0) s_editMode = 0; if (!READ_ONLY() && menuHorizontalPosition > 0) { switch (event) { case EVT_KEY_LONG(KEY_ENTER): killEvents(event); if (g_model.potsWarnMode == POTS_WARN_MANUAL) { SAVE_POT_POSITION(menuHorizontalPosition-1); AUDIO_WARNING1(); eeDirty(EE_MODEL); } break; case EVT_KEY_BREAK(KEY_ENTER): g_model.potsWarnEnabled ^= (1 << (menuHorizontalPosition-1)); eeDirty(EE_MODEL); break; } } } if (g_model.potsWarnMode) { coord_t x = MODEL_SETUP_2ND_COLUMN+28; for (int i=0; i<NUM_POTS; ++i) { if (i<NUM_XPOTS && !IS_POT_AVAILABLE(POT1+i)) { if (attr && (menuHorizontalPosition==i+1)) REPEAT_LAST_CURSOR_MOVE(); } else { #if defined(REV9E) if (i == NUM_XPOTS) { y += FH; x = MODEL_SETUP_2ND_COLUMN; } #endif LcdFlags flags = ((menuHorizontalPosition==i+1) && attr) ? BLINK : 0; if ((!attr || menuHorizontalPosition >= 0) && !(g_model.potsWarnEnabled & (1 << i))) { flags |= INVERS; } // TODO add a new function lcd_putsnAtt(x, y, STR_VSRCRAW+2+STR_VSRCRAW[0]*(NUM_STICKS+1+i), STR_VSRCRAW[0]-1, flags & ~ZCHAR); x = lcdNextPos+3; } } } if (attr && menuHorizontalPosition < 0) { #if defined(REV9E) drawFilledRect(MODEL_SETUP_2ND_COLUMN-1, y-FH-1, LCD_W-MODEL_SETUP_2ND_COLUMN-MENUS_SCROLLBAR_WIDTH+1, 2*FH+1); #else drawFilledRect(MODEL_SETUP_2ND_COLUMN-1, y-1, LCD_W-MODEL_SETUP_2ND_COLUMN-MENUS_SCROLLBAR_WIDTH+1, FH+1); #endif } break; case ITEM_MODEL_BEEP_CENTER: { lcd_putsLeft(y, STR_BEEPCTR); coord_t x = MODEL_SETUP_2ND_COLUMN; for (int i=0; i<NUM_STICKS+NUM_POTS+NUM_ROTARY_ENCODERS; i++) { if (i>=POT1 && i<POT1+NUM_XPOTS && !IS_POT_AVAILABLE(i)) { if (attr && menuHorizontalPosition == i) REPEAT_LAST_CURSOR_MOVE(); continue; } lcd_putsiAtt(x, y, STR_RETA123, i, ((menuHorizontalPosition==i) && attr) ? BLINK|INVERS : (((g_model.beepANACenter & ((BeepANACenter)1<<i)) || (attr && CURSOR_ON_LINE())) ? INVERS : 0 ) ); x += FW; } if (attr && CURSOR_ON_CELL) { if (event==EVT_KEY_BREAK(KEY_ENTER)) { if (READ_ONLY_UNLOCKED()) { s_editMode = 0; g_model.beepANACenter ^= ((BeepANACenter)1<<menuHorizontalPosition); eeDirty(EE_MODEL); } } } break; } case ITEM_MODEL_USE_GLOBAL_FUNCTIONS: lcd_putsLeft(y, STR_USE_GLOBAL_FUNCS); menu_lcd_onoff(MODEL_SETUP_2ND_COLUMN, y, !g_model.noGlobalFunctions, attr); if (attr) g_model.noGlobalFunctions = !checkIncDecModel(event, !g_model.noGlobalFunctions, 0, 1); break; case ITEM_MODEL_INTERNAL_MODULE_LABEL: lcd_putsLeft(y, TR_INTERNALRF); break; #if defined(TARANIS_INTERNAL_PPM) case ITEM_MODEL_INTERNAL_MODULE_MODE: lcd_putsLeft(y, STR_MODE); lcd_putsiAtt(MODEL_SETUP_2ND_COLUMN, y, STR_TARANIS_PROTOCOLS, g_model.moduleData[INTERNAL_MODULE].type, menuHorizontalPosition==0 ? attr : 0); if (IS_MODULE_XJT(INTERNAL_MODULE)) lcd_putsiAtt(MODEL_SETUP_2ND_COLUMN+5*FW, y, STR_XJT_PROTOCOLS, 1+g_model.moduleData[INTERNAL_MODULE].rfProtocol, menuHorizontalPosition==1 ? attr : 0); if (attr && s_editMode>0) { switch (menuHorizontalPosition) { case 0: g_model.moduleData[INTERNAL_MODULE].type = checkIncDec(event, g_model.moduleData[INTERNAL_MODULE].type, MODULE_TYPE_NONE, MODULE_TYPE_COUNT-2, EE_MODEL, isModuleAvailable); if (checkIncDec_Ret) { g_model.moduleData[INTERNAL_MODULE].rfProtocol = 0; g_model.moduleData[INTERNAL_MODULE].channelsStart = 0; g_model.moduleData[INTERNAL_MODULE].channelsCount = 0; } break; case 1: g_model.moduleData[INTERNAL_MODULE].rfProtocol = checkIncDec(event, g_model.moduleData[INTERNAL_MODULE].rfProtocol, RF_PROTO_X16, RF_PROTO_LAST, EE_MODEL, isRfProtocolAvailable); if (checkIncDec_Ret) { g_model.moduleData[INTERNAL_MODULE].channelsStart = 0; g_model.moduleData[INTERNAL_MODULE].channelsCount = 0; } } } break; #else case ITEM_MODEL_INTERNAL_MODULE_MODE: lcd_putsLeft(y, STR_MODE); lcd_putsiAtt(MODEL_SETUP_2ND_COLUMN, y, STR_XJT_PROTOCOLS, 1+g_model.moduleData[0].rfProtocol, attr); if (attr) { g_model.moduleData[INTERNAL_MODULE].rfProtocol = checkIncDec(event, g_model.moduleData[INTERNAL_MODULE].rfProtocol, RF_PROTO_OFF, RF_PROTO_LAST, EE_MODEL, isRfProtocolAvailable); if (checkIncDec_Ret) { g_model.moduleData[0].type = MODULE_TYPE_XJT; g_model.moduleData[0].channelsStart = 0; g_model.moduleData[0].channelsCount = 0; } } break; #endif case ITEM_MODEL_TRAINER_MODE: g_model.trainerMode = selectMenuItem(MODEL_SETUP_2ND_COLUMN, y, STR_MODE, STR_VTRAINERMODES, g_model.trainerMode, 0, HAS_WIRELESS_TRAINER_HARDWARE() ? TRAINER_MODE_MASTER_BATTERY_COMPARTMENT : TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE, attr, event); break; case ITEM_MODEL_EXTERNAL_MODULE_LABEL: lcd_putsLeft(y, TR_EXTERNALRF); break; case ITEM_MODEL_EXTERNAL_MODULE_MODE: lcd_putsLeft(y, STR_MODE); lcd_putsiAtt(MODEL_SETUP_2ND_COLUMN, y, STR_TARANIS_PROTOCOLS, g_model.moduleData[EXTERNAL_MODULE].type, menuHorizontalPosition==0 ? attr : 0); if (IS_MODULE_XJT(EXTERNAL_MODULE)) lcd_putsiAtt(MODEL_SETUP_2ND_COLUMN+5*FW, y, STR_XJT_PROTOCOLS, 1+g_model.moduleData[EXTERNAL_MODULE].rfProtocol, menuHorizontalPosition==1 ? attr : 0); else if (IS_MODULE_DSM2(EXTERNAL_MODULE)) lcd_putsiAtt(MODEL_SETUP_2ND_COLUMN+5*FW, y, STR_DSM_PROTOCOLS, g_model.moduleData[EXTERNAL_MODULE].rfProtocol, menuHorizontalPosition==1 ? attr : 0); if (attr && s_editMode>0) { switch (menuHorizontalPosition) { case 0: g_model.moduleData[EXTERNAL_MODULE].type = checkIncDec(event, g_model.moduleData[EXTERNAL_MODULE].type, MODULE_TYPE_NONE, MODULE_TYPE_COUNT-1, EE_MODEL, isModuleAvailable); if (checkIncDec_Ret) { g_model.moduleData[EXTERNAL_MODULE].rfProtocol = 0; g_model.moduleData[EXTERNAL_MODULE].channelsStart = 0; g_model.moduleData[EXTERNAL_MODULE].channelsCount = 0; } break; case 1: if (IS_MODULE_DSM2(EXTERNAL_MODULE)) CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].rfProtocol, DSM2_PROTO_LP45, DSM2_PROTO_DSMX); else g_model.moduleData[EXTERNAL_MODULE].rfProtocol = checkIncDec(event, g_model.moduleData[EXTERNAL_MODULE].rfProtocol, RF_PROTO_X16, RF_PROTO_LAST, EE_MODEL, isRfProtocolAvailable); if (checkIncDec_Ret) { g_model.moduleData[EXTERNAL_MODULE].channelsStart = 0; g_model.moduleData[EXTERNAL_MODULE].channelsCount = 0; } } } break; case ITEM_MODEL_TRAINER_LABEL: lcd_putsLeft(y, STR_TRAINER); break; case ITEM_MODEL_INTERNAL_MODULE_CHANNELS: case ITEM_MODEL_EXTERNAL_MODULE_CHANNELS: case ITEM_MODEL_TRAINER_CHANNELS: { uint8_t moduleIdx = CURRENT_MODULE_EDITED(k); ModuleData & moduleData = g_model.moduleData[moduleIdx]; lcd_putsLeft(y, STR_CHANNELRANGE); if ((int8_t)PORT_CHANNELS_ROWS(moduleIdx) >= 0) { lcd_putsAtt(MODEL_SETUP_2ND_COLUMN, y, STR_CH, menuHorizontalPosition==0 ? attr : 0); lcd_outdezAtt(lcdLastPos, y, moduleData.channelsStart+1, LEFT | (menuHorizontalPosition==0 ? attr : 0)); lcd_putc(lcdLastPos, y, '-'); lcd_outdezAtt(lcdLastPos + FW+1, y, moduleData.channelsStart+NUM_CHANNELS(moduleIdx), LEFT | (menuHorizontalPosition==1 ? attr : 0)); if (attr && s_editMode>0) { switch (menuHorizontalPosition) { case 0: CHECK_INCDEC_MODELVAR_ZERO(event, moduleData.channelsStart, 32-8-moduleData.channelsCount); break; case 1: CHECK_INCDEC_MODELVAR(event, moduleData.channelsCount, -4, min<int8_t>(MAX_CHANNELS(moduleIdx), 32-8-moduleData.channelsStart)); #if defined(TARANIS_INTERNAL_PPM) if ((k == ITEM_MODEL_EXTERNAL_MODULE_CHANNELS && g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_PPM) || (k == ITEM_MODEL_INTERNAL_MODULE_CHANNELS && g_model.moduleData[INTERNAL_MODULE].type == MODULE_TYPE_PPM) || (k == ITEM_MODEL_TRAINER_CHANNELS)) { SET_DEFAULT_PPM_FRAME_LENGTH(moduleIdx); } #else if ((k == ITEM_MODEL_EXTERNAL_MODULE_CHANNELS && g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_PPM) || (k == ITEM_MODEL_TRAINER_CHANNELS)) { SET_DEFAULT_PPM_FRAME_LENGTH(moduleIdx); } #endif break; } } } break; } case ITEM_MODEL_INTERNAL_MODULE_BIND: case ITEM_MODEL_EXTERNAL_MODULE_BIND: case ITEM_MODEL_TRAINER_SETTINGS: { uint8_t moduleIdx = CURRENT_MODULE_EDITED(k); ModuleData & moduleData = g_model.moduleData[moduleIdx]; if (IS_MODULE_PPM(moduleIdx)) { lcd_putsLeft(y, STR_PPMFRAME); lcd_puts(MODEL_SETUP_2ND_COLUMN+3*FW, y, STR_MS); lcd_outdezAtt(MODEL_SETUP_2ND_COLUMN, y, (int16_t)moduleData.ppmFrameLength*5 + 225, (menuHorizontalPosition<=0 ? attr : 0) | PREC1|LEFT); lcd_putc(MODEL_SETUP_2ND_COLUMN+8*FW+2, y, 'u'); lcd_outdezAtt(MODEL_SETUP_2ND_COLUMN+8*FW+2, y, (moduleData.ppmDelay*50)+300, (CURSOR_ON_LINE() || menuHorizontalPosition==1) ? attr : 0); lcd_putcAtt(MODEL_SETUP_2ND_COLUMN+10*FW, y, moduleData.ppmPulsePol ? '+' : '-', (CURSOR_ON_LINE() || menuHorizontalPosition==2) ? attr : 0); if (attr && s_editMode>0) { switch (menuHorizontalPosition) { case 0: CHECK_INCDEC_MODELVAR(event, moduleData.ppmFrameLength, -20, 35); break; case 1: CHECK_INCDEC_MODELVAR(event, moduleData.ppmDelay, -4, 10); break; case 2: CHECK_INCDEC_MODELVAR_ZERO(event, moduleData.ppmPulsePol, 1); break; } } } else { horzpos_t l_posHorz = menuHorizontalPosition; coord_t xOffsetBind = MODEL_SETUP_BIND_OFS; if (IS_MODULE_XJT(moduleIdx) && g_model.moduleData[moduleIdx].rfProtocol == RF_PROTO_D8) { xOffsetBind = 0; lcd_putsLeft(y, INDENT "Receiver"); if (attr) l_posHorz += 1; } else { lcd_putsLeft(y, STR_RXNUM); } if (IS_MODULE_XJT(moduleIdx) || IS_MODULE_DSM2(moduleIdx)) { if (xOffsetBind) lcd_outdezNAtt(MODEL_SETUP_2ND_COLUMN, y, g_model.header.modelId[moduleIdx], (l_posHorz==0 ? attr : 0) | LEADING0|LEFT, 2); if (attr && l_posHorz==0) { if (s_editMode>0) { CHECK_INCDEC_MODELVAR_ZERO(event, g_model.header.modelId[moduleIdx], IS_MODULE_DSM2(moduleIdx) ? 20 : 63); if (checkIncDec_Ret) { modelHeaders[g_eeGeneral.currModel].modelId[moduleIdx] = g_model.header.modelId[moduleIdx]; } } if (s_editMode==0 && event==EVT_KEY_BREAK(KEY_ENTER)) { checkModelIdUnique(g_eeGeneral.currModel, moduleIdx); } } lcd_putsAtt(MODEL_SETUP_2ND_COLUMN+xOffsetBind, y, STR_MODULE_BIND, l_posHorz==1 ? attr : 0); lcd_putsAtt(MODEL_SETUP_2ND_COLUMN+MODEL_SETUP_RANGE_OFS+xOffsetBind, y, STR_MODULE_RANGE, l_posHorz==2 ? attr : 0); uint8_t newFlag = 0; if (attr && l_posHorz>0 && s_editMode>0) { if (l_posHorz == 1) newFlag = MODULE_BIND; else if (l_posHorz == 2) { newFlag = MODULE_RANGECHECK; } } moduleFlag[moduleIdx] = newFlag; } } break; } case ITEM_MODEL_INTERNAL_MODULE_FAILSAFE: case ITEM_MODEL_EXTERNAL_MODULE_FAILSAFE: { uint8_t moduleIdx = CURRENT_MODULE_EDITED(k); ModuleData & moduleData = g_model.moduleData[moduleIdx]; lcd_putsLeft(y, TR_FAILSAFE); if (IS_MODULE_XJT(moduleIdx)) { lcd_putsiAtt(MODEL_SETUP_2ND_COLUMN, y, STR_VFAILSAFE, moduleData.failsafeMode, menuHorizontalPosition==0 ? attr : 0); if (moduleData.failsafeMode == FAILSAFE_CUSTOM) lcd_putsAtt(MODEL_SETUP_2ND_COLUMN + MODEL_SETUP_SET_FAILSAFE_OFS, y, STR_SET, menuHorizontalPosition==1 ? attr : 0); if (attr) { if (moduleData.failsafeMode != FAILSAFE_CUSTOM) { menuHorizontalPosition = 0; } if (menuHorizontalPosition == 0) { if (s_editMode > 0) { CHECK_INCDEC_MODELVAR_ZERO(event, moduleData.failsafeMode, FAILSAFE_LAST); if (checkIncDec_Ret) SEND_FAILSAFE_NOW(moduleIdx); } } else if (menuHorizontalPosition == 1) { s_editMode = 0; if (moduleData.failsafeMode==FAILSAFE_CUSTOM && event==EVT_KEY_FIRST(KEY_ENTER)) { g_moduleIdx = moduleIdx; pushMenu(menuModelFailsafe); } } else { drawFilledRect(MODEL_SETUP_2ND_COLUMN, y, LCD_W-MODEL_SETUP_2ND_COLUMN-MENUS_SCROLLBAR_WIDTH, 8); } } } break; } } } #if defined(PXX) if (IS_RANGECHECK_ENABLE()) { displayPopup("RSSI: "); lcd_outdezAtt(16+4*FW, 5*FH, TELEMETRY_RSSI(), BOLD); } #endif }
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; }
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); }
int checkIncDec(unsigned int event, int val, int i_min, int i_max, unsigned int i_flags, IsValueAvailable isValueAvailable, const CheckIncDecStops &stops) { int newval = val; #if defined(DBLKEYS) uint32_t in = KEYS_PRESSED(); if (!(i_flags & NO_DBLKEYS) && (EVT_KEY_MASK(event))) { bool dblkey = true; if (DBLKEYS_PRESSED_RGT_LFT(in)) { if (!isValueAvailable || isValueAvailable(-val)) { newval = -val; } } else if (DBLKEYS_PRESSED_RGT_UP(in)) { newval = (i_max > stops.max() ? stops.max() : i_max); while (isValueAvailable && !isValueAvailable(newval) && newval>i_min) { --newval; } } else if (DBLKEYS_PRESSED_LFT_DWN(in)) { newval = (i_min < stops.min() ? stops.min() : i_min); while (isValueAvailable && !isValueAvailable(newval) && newval<i_max) { ++newval; } } else if (DBLKEYS_PRESSED_UP_DWN(in)) { newval = 0; } else { dblkey = false; } if (dblkey) { killEvents(KEY_UP); killEvents(KEY_DOWN); killEvents(KEY_RIGHT); killEvents(KEY_LEFT); killEvents(KEY_PAGE); killEvents(KEY_MENU); killEvents(KEY_ENTER); killEvents(KEY_EXIT); event = 0; } } #endif if (s_editMode>0 && (IS_ROTARY_RIGHT(event) || event==EVT_KEY_FIRST(KEY_UP) || event==EVT_KEY_REPT(KEY_UP))) { 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 { AUDIO_KEYPAD_UP(); } } else if (s_editMode>0 && (IS_ROTARY_LEFT(event) || event==EVT_KEY_FIRST(KEY_DOWN) || event==EVT_KEY_REPT(KEY_DOWN))) { 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 { 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(AUTOSWITCH) if (i_flags & INCDEC_SWITCH) { newval = checkIncDecMovedSwitch(newval); } #endif #if defined(AUTOSOURCE) if (i_flags & INCDEC_SOURCE) { if (s_editMode>0) { int source = GET_MOVED_SOURCE(i_min, i_max); if (source) { newval = source; } #if defined(AUTOSWITCH) else { unsigned int 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) && stops.contains(newval) && !IS_ROTARY_EVENT(event)) { bool pause = (newval > val ? !stops.contains(newval+1) : !stops.contains(newval-1)); if (pause) { 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; } if (i_flags & INCDEC_SOURCE) { if (event == EVT_KEY_LONG(KEY_ENTER)) { killEvents(event); checkIncDecSelection = MIXSRC_NONE; if (i_min <= MIXSRC_FIRST_INPUT && i_max >= MIXSRC_FIRST_INPUT) { if (getFirstAvailable(MIXSRC_FIRST_INPUT, MIXSRC_LAST_INPUT, isInputAvailable) != MIXSRC_NONE) { POPUP_MENU_ADD_ITEM(STR_MENU_INPUTS); } } #if defined(LUA_MODEL_SCRIPTS) if (i_min <= MIXSRC_FIRST_LUA && i_max >= MIXSRC_FIRST_LUA) { if (getFirstAvailable(MIXSRC_FIRST_LUA, MIXSRC_LAST_LUA, isSourceAvailable) != MIXSRC_NONE) { POPUP_MENU_ADD_ITEM(STR_MENU_LUA); } } #endif if (i_min <= MIXSRC_FIRST_STICK && i_max >= MIXSRC_FIRST_STICK) POPUP_MENU_ADD_ITEM(STR_MENU_STICKS); if (i_min <= MIXSRC_FIRST_POT && i_max >= MIXSRC_FIRST_POT) POPUP_MENU_ADD_ITEM(STR_MENU_POTS); if (i_min <= MIXSRC_MAX && i_max >= MIXSRC_MAX) POPUP_MENU_ADD_ITEM(STR_MENU_MAX); #if defined(HELI) if (i_min <= MIXSRC_FIRST_HELI && i_max >= MIXSRC_FIRST_HELI) POPUP_MENU_ADD_ITEM(STR_MENU_HELI); #endif if (i_min <= MIXSRC_FIRST_TRIM && i_max >= MIXSRC_FIRST_TRIM) POPUP_MENU_ADD_ITEM(STR_MENU_TRIMS); if (i_min <= MIXSRC_FIRST_SWITCH && i_max >= MIXSRC_FIRST_SWITCH) POPUP_MENU_ADD_ITEM(STR_MENU_SWITCHES); if (i_min <= MIXSRC_FIRST_TRAINER && i_max >= MIXSRC_FIRST_TRAINER) POPUP_MENU_ADD_ITEM(STR_MENU_TRAINER); if (i_min <= MIXSRC_FIRST_CH && i_max >= MIXSRC_FIRST_CH) POPUP_MENU_ADD_ITEM(STR_MENU_CHANNELS); if (i_min <= MIXSRC_FIRST_GVAR && i_max >= MIXSRC_FIRST_GVAR && isValueAvailable(MIXSRC_FIRST_GVAR)) { POPUP_MENU_ADD_ITEM(STR_MENU_GVARS); } if (i_min <= MIXSRC_FIRST_TELEM && i_max >= MIXSRC_FIRST_TELEM) { for (int i = 0; i < MAX_SENSORS; i++) { TelemetrySensor * sensor = & g_model.telemetrySensors[i]; if (sensor->isAvailable()) { POPUP_MENU_ADD_ITEM(STR_MENU_TELEMETRY); break; } } } popupMenuHandler = onSourceLongEnterPress; } if (checkIncDecSelection != 0) { newval = checkIncDecSelection; if (checkIncDecSelection != MIXSRC_MAX) s_editMode = EDIT_MODIFY_FIELD; checkIncDecSelection = 0; } } else if (i_flags & INCDEC_SWITCH) { if (event == EVT_KEY_LONG(KEY_ENTER)) { killEvents(event); checkIncDecSelection = SWSRC_NONE; if (i_min <= SWSRC_FIRST_SWITCH && i_max >= SWSRC_LAST_SWITCH) POPUP_MENU_ADD_ITEM(STR_MENU_SWITCHES); if (i_min <= SWSRC_FIRST_TRIM && i_max >= SWSRC_LAST_TRIM) POPUP_MENU_ADD_ITEM(STR_MENU_TRIMS); if (i_min <= SWSRC_FIRST_LOGICAL_SWITCH && i_max >= SWSRC_LAST_LOGICAL_SWITCH) { for (int i = 0; i < NUM_LOGICAL_SWITCH; i++) { if (isValueAvailable && isValueAvailable(SWSRC_FIRST_LOGICAL_SWITCH+i)) { POPUP_MENU_ADD_ITEM(STR_MENU_LOGICAL_SWITCHES); break; } } } if (isValueAvailable && isValueAvailable(SWSRC_ON)) POPUP_MENU_ADD_ITEM(STR_MENU_OTHER); if (isValueAvailable && isValueAvailable(-newval)) POPUP_MENU_ADD_ITEM(STR_MENU_INVERT); popupMenuHandler = onSwitchLongEnterPress; s_editMode = EDIT_MODIFY_FIELD; } if (checkIncDecSelection != 0) { newval = (checkIncDecSelection == SWSRC_INVERT ? -newval : checkIncDecSelection); s_editMode = EDIT_MODIFY_FIELD; checkIncDecSelection = 0; } } return newval; }
void menuModelLimits(uint8_t event) { int sub = menuVerticalPosition; if (sub < NUM_CHNOUT) { #if defined(PPM_CENTER_ADJUSTABLE) || defined(PPM_UNIT_US) lcd_outdezAtt(13*FW, 0, PPM_CH_CENTER(sub)+channelOutputs[sub]/2, 0); lcd_puts(13*FW, 0, STR_US); #else lcd_outdezAtt(13*FW, 0, calcRESXto1000(channelOutputs[sub]), PREC1); #endif } MENU(STR_MENULIMITS, menuTabModel, e_Limits, NUM_CHNOUT+1, { NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, 0 }); if (sub<NUM_CHNOUT && menuHorizontalPosition>=0) { displayColumnHeader(STR_LIMITS_HEADERS, menuHorizontalPosition); } if (warningResult) { warningResult = 0; LimitData *ld = limitAddress(sub); ld->revert = !ld->revert; eeDirty(EE_MODEL); } for (int i=0; i<NUM_BODY_LINES; i++) { coord_t y = MENU_HEADER_HEIGHT + 1 + i*FH; uint8_t k = i+menuVerticalOffset; if (k==NUM_CHNOUT) { // last line available - add the "copy trim menu" line uint8_t attr = (sub==NUM_CHNOUT) ? INVERS : 0; lcd_putsAtt(CENTER_OFS, y, STR_TRIMS2OFFSETS, NO_HIGHLIGHT() ? 0 : attr); if (attr) { s_editMode = 0; if (event==EVT_KEY_LONG(KEY_ENTER)) { START_NO_HIGHLIGHT(); killEvents(event); moveTrimsToOffsets(); // if highlighted and menu pressed - move trims to offsets } } return; } LimitData *ld = limitAddress(k); int16_t v = (ld->revert) ? -LIMIT_OFS(ld) : LIMIT_OFS(ld); char swVal = '-'; // '-', '<', '>' if ((channelOutputs[k] - v) > 50) swVal = (ld->revert ? 127 : 126); // Switch to raw inputs? - remove trim! if ((channelOutputs[k] - v) < -50) swVal = (ld->revert ? 126 : 127); lcd_putc(LIMITS_DIRECTION_POS, y, swVal); int limit = (g_model.extendedLimits ? LIMIT_EXT_MAX : 1000); putsChn(0, y, k+1, (sub==k && menuHorizontalPosition < 0) ? INVERS : 0); if (sub==k && menuHorizontalPosition < 0 && event==EVT_KEY_LONG(KEY_ENTER) && !READ_ONLY()) { killEvents(event); POPUP_MENU_ADD_ITEM(STR_RESET); POPUP_MENU_ADD_ITEM(STR_COPY_TRIMS_TO_OFS); POPUP_MENU_ADD_ITEM(STR_COPY_STICKS_TO_OFS); popupMenuHandler = onLimitsMenu; } for (int j=0; j<ITEM_LIMITS_COUNT; j++) { LcdFlags attr = ((sub==k && menuHorizontalPosition==j) ? ((s_editMode>0) ? BLINK|INVERS : INVERS) : 0); uint8_t active = (attr && s_editMode>0) ; if (active) STICK_SCROLL_DISABLE(); switch(j) { case ITEM_LIMITS_CH_NAME: editName(LIMITS_NAME_POS, y, ld->name, sizeof(ld->name), event, attr); break; case ITEM_LIMITS_OFFSET: if (GV_IS_GV_VALUE(ld->offset, -1000, 1000) || (attr && event == EVT_KEY_LONG(KEY_ENTER))) { ld->offset = GVAR_MENU_ITEM(LIMITS_OFFSET_POS, y, ld->offset, -1000, 1000, attr|PREC1, 0, event); break; } #if defined(PPM_UNIT_US) lcd_outdezAtt(LIMITS_OFFSET_POS, y, ((int32_t)ld->offset*128) / 25, attr|PREC1); #else lcd_outdezAtt(LIMITS_OFFSET_POS, y, ld->offset, attr|PREC1); #endif if (active) { ld->offset = checkIncDec(event, ld->offset, -1000, 1000, EE_MODEL, NULL, stops1000); } else if (attr && event==EVT_KEY_LONG(KEY_MENU)) { copySticksToOffset(k); s_editMode = 0; } break; case ITEM_LIMITS_MIN: if (GV_IS_GV_VALUE(ld->min, -GV_RANGELARGE, GV_RANGELARGE) || (attr && event == EVT_KEY_LONG(KEY_ENTER))) { ld->min = GVAR_MENU_ITEM(LIMITS_MIN_POS, y, ld->min, -LIMIT_EXT_MAX, LIMIT_EXT_MAX, MIN_MAX_ATTR, 0, event); break; } lcd_outdezAtt(LIMITS_MIN_POS, y, MIN_MAX_DISPLAY(ld->min-LIMITS_MIN_MAX_OFFSET), MIN_MAX_ATTR); if (active) ld->min = LIMITS_MIN_MAX_OFFSET + checkIncDec(event, ld->min-LIMITS_MIN_MAX_OFFSET, -limit, 0, EE_MODEL, NULL, stops1000); break; case ITEM_LIMITS_MAX: if (GV_IS_GV_VALUE(ld->max, -GV_RANGELARGE, GV_RANGELARGE) || (attr && event == EVT_KEY_LONG(KEY_ENTER))) { ld->max = GVAR_MENU_ITEM(LIMITS_MAX_POS, y, ld->max, -LIMIT_EXT_MAX, LIMIT_EXT_MAX, MIN_MAX_ATTR, 0, event); break; } lcd_outdezAtt(LIMITS_MAX_POS, y, MIN_MAX_DISPLAY(ld->max+LIMITS_MIN_MAX_OFFSET), MIN_MAX_ATTR); if (active) ld->max = -LIMITS_MIN_MAX_OFFSET + checkIncDec(event, ld->max+LIMITS_MIN_MAX_OFFSET, 0, +limit, EE_MODEL, NULL, stops1000); break; case ITEM_LIMITS_DIRECTION: { uint8_t revert = ld->revert; #if defined(PPM_CENTER_ADJUSTABLE) lcd_putcAtt(LIMITS_REVERT_POS, y, revert ? 127 : 126, attr); #else lcd_putsiAtt(LIMITS_REVERT_POS, y, STR_MMMINV, revert, attr); #endif if (active) { uint8_t revert_new = checkIncDecModel(event, revert, 0, 1); if (checkIncDec_Ret && isThrottleOutput(k)) { POPUP_CONFIRMATION(STR_INVERT_THR); } else { ld->revert = revert_new; } } break; } #if defined(CURVES) case ITEM_LIMITS_CURVE: putsCurve(LIMITS_CURVE_POS, y, ld->curve, attr); if (attr && event==EVT_KEY_LONG(KEY_ENTER) && ld->curve>0) { s_curveChan = (ld->curve<0 ? -ld->curve-1 : ld->curve-1); pushMenu(menuModelCurveOne); } if (active) { CHECK_INCDEC_MODELVAR(event, ld->curve, -MAX_CURVES, +MAX_CURVES); } break; #endif #if defined(PPM_CENTER_ADJUSTABLE) case ITEM_LIMITS_PPM_CENTER: lcd_outdezAtt(LIMITS_PPM_CENTER_POS, y, PPM_CENTER+ld->ppmCenter, attr); if (active) { CHECK_INCDEC_MODELVAR(event, ld->ppmCenter, -PPM_CENTER_MAX, +PPM_CENTER_MAX); } break; #endif #if defined(PPM_LIMITS_SYMETRICAL) case ITEM_LIMITS_SYMETRICAL: lcd_putcAtt(LCD_W-FW-MENUS_SCROLLBAR_WIDTH, y, ld->symetrical ? '=' : '\306', attr); if (active) { CHECK_INCDEC_MODELVAR_ZERO(event, ld->symetrical, 1); } break; #endif } } } }
void menuModelSetup(uint8_t event) { #if defined(CPUM64) #define CURSOR_ON_CELL (true) #define MODEL_SETUP_MAX_LINES ((IS_PPM_PROTOCOL(protocol)||IS_DSM2_PROTOCOL(protocol)||IS_PXX_PROTOCOL(protocol)) ? 1+ITEM_MODEL_SETUP_MAX : ITEM_MODEL_SETUP_MAX) uint8_t protocol = g_model.protocol; MENU_TAB({ 0, 0, 2, CASE_PERSISTENT_TIMERS(0) 0, 0, 2, CASE_PERSISTENT_TIMERS(0) 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, NUM_STICKS+NUM_POTS+NUM_ROTARY_ENCODERS-1, FIELD_PROTOCOL_MAX, 2 }); #else #define CURSOR_ON_CELL (true) #define MODEL_SETUP_MAX_LINES ((IS_PPM_PROTOCOL(protocol)||IS_DSM2_PROTOCOL(protocol)||IS_PXX_PROTOCOL(protocol)) ? 1+ITEM_MODEL_SETUP_MAX : ITEM_MODEL_SETUP_MAX) uint8_t protocol = g_model.protocol; MENU_TAB({ 0, 0, 2, CASE_PERSISTENT_TIMERS(0) 0, 0, 2, CASE_PERSISTENT_TIMERS(0) 0, 0, 0, 1, 0, 0, 0, 0, 0, NUM_SWITCHES, NUM_STICKS+NUM_POTS+NUM_ROTARY_ENCODERS-1, FIELD_PROTOCOL_MAX, 2, }); #endif MENU_CHECK(menuTabModel, e_ModelSetup, MODEL_SETUP_MAX_LINES); TITLE(STR_MENUSETUP); uint8_t sub = menuVerticalPosition - 1; int8_t editMode = s_editMode; for (uint8_t i=0; i<NUM_BODY_LINES; ++i) { coord_t y = MENU_HEADER_HEIGHT + 1 + i*FH; uint8_t k = i+menuVerticalOffset; LcdFlags blink = ((editMode>0) ? BLINK|INVERS : INVERS); LcdFlags attr = (sub == k ? blink : 0); switch(k) { case ITEM_MODEL_NAME: editSingleName(MODEL_SETUP_2ND_COLUMN, y, STR_MODELNAME, g_model.header.name, sizeof(g_model.header.name), event, attr); break; case ITEM_MODEL_TIMER1: case ITEM_MODEL_TIMER2: case ITEM_MODEL_TIMER1_MINUTE_BEEP: case ITEM_MODEL_TIMER2_MINUTE_BEEP: case ITEM_MODEL_TIMER1_COUNTDOWN_BEEP: case ITEM_MODEL_TIMER2_COUNTDOWN_BEEP: { TimerData *timer = &g_model.timers[k>=ITEM_MODEL_TIMER2 ? 1 : 0]; if (k==ITEM_MODEL_TIMER1_MINUTE_BEEP || k==ITEM_MODEL_TIMER2_MINUTE_BEEP) { timer->minuteBeep = onoffMenuItem(timer->minuteBeep, MODEL_SETUP_2ND_COLUMN, y, STR_MINUTEBEEP, attr, event); } else if (k==ITEM_MODEL_TIMER1_COUNTDOWN_BEEP || k==ITEM_MODEL_TIMER2_COUNTDOWN_BEEP) { timer->countdownBeep = onoffMenuItem(timer->countdownBeep, MODEL_SETUP_2ND_COLUMN, y, STR_BEEPCOUNTDOWN, attr, event); } else { lcdDrawStringWithIndex(0*FW, y, STR_TIMER, k>=ITEM_MODEL_TIMER2 ? 2 : 1); lcdPutsTimerMode(MODEL_SETUP_2ND_COLUMN, y, timer->mode, menuHorizontalPosition==0 ? attr : 0); putsTimer(MODEL_SETUP_2ND_COLUMN+5*FW-2+5*FWNUM+1, y, timer->start, menuHorizontalPosition==1 ? attr : 0, menuHorizontalPosition==2 ? attr : 0); if (attr && (editMode>0 || p1valdiff)) { div_t qr = div(timer->start, 60); switch (menuHorizontalPosition) { case 0: CHECK_INCDEC_MODELVAR_CHECK(event, timer->mode, SWSRC_FIRST, TMRMODE_COUNT+SWSRC_LAST-1/*SWSRC_None removed*/, isSwitchAvailableInTimers); break; case 1: CHECK_INCDEC_MODELVAR_ZERO(event, qr.quot, 59); timer->start = qr.rem + qr.quot*60; break; case 2: qr.rem -= checkIncDecModel(event, qr.rem+2, 1, 62)-2; timer->start -= qr.rem ; #if defined(CPUM2560) if ((int16_t)timer->start < 0) timer->start=0; if ((int16_t)timer->start > 5999) timer->start=32399; // 8:59:59 #endif break; } } } break; } #if defined(CPUM2560) case ITEM_MODEL_TIMER1_PERSISTENT: case ITEM_MODEL_TIMER2_PERSISTENT: { TimerData &timer = g_model.timers[k==ITEM_MODEL_TIMER2_PERSISTENT]; timer.persistent = selectMenuItem(MODEL_SETUP_2ND_COLUMN, y, STR_PERSISTENT, STR_VPERSISTENT, timer.persistent, 0, 2, attr, event); break; } #endif case ITEM_MODEL_EXTENDED_LIMITS: ON_OFF_MENU_ITEM(g_model.extendedLimits, MODEL_SETUP_2ND_COLUMN, y, STR_ELIMITS, attr, event); break; case ITEM_MODEL_EXTENDED_TRIMS: #if defined(CPUM64) ON_OFF_MENU_ITEM(g_model.extendedTrims, MODEL_SETUP_2ND_COLUMN, y, STR_ETRIMS, attr, event); #else ON_OFF_MENU_ITEM(g_model.extendedTrims, MODEL_SETUP_2ND_COLUMN, y, STR_ETRIMS, menuHorizontalPosition<=0 ? attr : 0, event==EVT_KEY_BREAK(KEY_ENTER) ? event : 0); lcdDrawTextAtt(MODEL_SETUP_2ND_COLUMN+3*FW, y, STR_RESET_BTN, (menuHorizontalPosition>0 && !NO_HIGHLIGHT()) ? attr : 0); if (attr && menuHorizontalPosition>0) { s_editMode = 0; if (event==EVT_KEY_LONG(KEY_ENTER)) { START_NO_HIGHLIGHT(); for (uint8_t i=0; i<MAX_FLIGHT_MODES; i++) { memclear(&g_model.flightModeData[i], TRIMS_ARRAY_SIZE); } eeDirty(EE_MODEL); AUDIO_WARNING1(); } } #endif break; case ITEM_MODEL_TRIM_INC: g_model.trimInc = selectMenuItem(MODEL_SETUP_2ND_COLUMN, y, STR_TRIMINC, STR_VTRIMINC, g_model.trimInc, -2, 2, attr, event); break; case ITEM_MODEL_THROTTLE_REVERSED: ON_OFF_MENU_ITEM(g_model.throttleReversed, MODEL_SETUP_2ND_COLUMN, y, STR_THROTTLEREVERSE, attr, event ) ; break; case ITEM_MODEL_THROTTLE_TRACE: { lcdDrawTextLeft(y, STR_TTRACE); if (attr) CHECK_INCDEC_MODELVAR_ZERO(event, g_model.thrTraceSrc, NUM_POTS+NUM_CHNOUT); uint8_t idx = g_model.thrTraceSrc + MIXSRC_Thr; if (idx > MIXSRC_Thr) idx += 1; if (idx >= MIXSRC_FIRST_POT+NUM_POTS) idx += MIXSRC_CH1 - MIXSRC_FIRST_POT - NUM_POTS; putsMixerSource(MODEL_SETUP_2ND_COLUMN, y, idx, attr); break; } case ITEM_MODEL_THROTTLE_TRIM: ON_OFF_MENU_ITEM(g_model.thrTrim, MODEL_SETUP_2ND_COLUMN, y, STR_TTRIM, attr, event); break; case ITEM_MODEL_THROTTLE_WARNING: g_model.disableThrottleWarning = !onoffMenuItem(!g_model.disableThrottleWarning, MODEL_SETUP_2ND_COLUMN, y, STR_THROTTLEWARNING, attr, event); break; case ITEM_MODEL_SWITCHES_WARNING: { lcdDrawTextLeft(y, STR_SWITCHWARNING); swarnstate_t states = g_model.switchWarningState; char c; if (attr) { s_editMode = 0; if (!READ_ONLY()) { switch (event) { CASE_EVT_ROTARY_BREAK case EVT_KEY_BREAK(KEY_ENTER): #if defined(CPUM64) g_model.switchWarningEnable ^= (1 << menuHorizontalPosition); eeDirty(EE_MODEL); #else if (menuHorizontalPosition < NUM_SWITCHES-1) { g_model.switchWarningEnable ^= (1 << menuHorizontalPosition); eeDirty(EE_MODEL); } #endif break; case EVT_KEY_LONG(KEY_ENTER): #if defined(CPUM64) getMovedSwitch(); g_model.switchWarningState = switches_states; AUDIO_WARNING1(); eeDirty(EE_MODEL); #else if (menuHorizontalPosition == NUM_SWITCHES-1) { START_NO_HIGHLIGHT(); getMovedSwitch(); g_model.switchWarningState = switches_states; AUDIO_WARNING1(); eeDirty(EE_MODEL); } #endif killEvents(event); break; } } } LcdFlags line = attr; for (uint8_t i=0; i<NUM_SWITCHES-1/*not on TRN switch*/; i++) { uint8_t swactive = !(g_model.switchWarningEnable & 1 << i); attr = 0; if (IS_3POS(i)) { c = '0'+(states & 0x03); states >>= 2; } else { if ((states & 0x01) && swactive) attr = INVERS; c = pgm_read_byte(STR_VSWITCHES - 2 + 9 + (3*(i+1))); states >>= 1; } if (line && (menuHorizontalPosition == i)) { attr = BLINK; if (swactive) attr |= INVERS; } lcdDrawCharAtt(MODEL_SETUP_2ND_COLUMN+i*FW, y, (swactive || (attr & BLINK)) ? c : '-', attr); #if !defined(CPUM64) lcdDrawTextAtt(MODEL_SETUP_2ND_COLUMN+(NUM_SWITCHES*FW), y, PSTR("<]"), (menuHorizontalPosition == NUM_SWITCHES-1 && !NO_HIGHLIGHT()) ? line : 0); #endif } break; } case ITEM_MODEL_BEEP_CENTER: lcdDrawTextLeft(y, STR_BEEPCTR); for (uint8_t i=0; i<NUM_STICKS+NUM_POTS+NUM_ROTARY_ENCODERS; i++) { // TODO flash saving, \001 not needed in STR_RETA123 coord_t x = MODEL_SETUP_2ND_COLUMN+i*FW; lcdDrawTextAtIndex(x, y, STR_RETA123, i, ((menuHorizontalPosition==i) && attr) ? BLINK|INVERS : (((g_model.beepANACenter & ((BeepANACenter)1<<i)) || (attr && CURSOR_ON_LINE())) ? INVERS : 0 ) ); } if (attr && CURSOR_ON_CELL) { if (event==EVT_KEY_BREAK(KEY_ENTER) || p1valdiff) { if (READ_ONLY_UNLOCKED()) { s_editMode = 0; g_model.beepANACenter ^= ((BeepANACenter)1<<menuHorizontalPosition); eeDirty(EE_MODEL); } } } break; case ITEM_MODEL_PPM1_PROTOCOL: lcdDrawTextLeft(y, NO_INDENT(STR_PROTO)); lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_VPROTOS, protocol, menuHorizontalPosition<=0 ? attr : 0); if (IS_PPM_PROTOCOL(protocol)) { lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN+7*FW, y, STR_NCHANNELS, g_model.ppmNCH+2, menuHorizontalPosition!=0 ? attr : 0); } else if (menuHorizontalPosition>0 && attr) { MOVE_CURSOR_FROM_HERE(); } if (attr && (editMode>0 || p1valdiff || (!IS_PPM_PROTOCOL(protocol) && !IS_DSM2_PROTOCOL(protocol)))) { switch (menuHorizontalPosition) { case 0: CHECK_INCDEC_MODELVAR_ZERO(event, g_model.protocol, PROTO_MAX-1); break; case 1: CHECK_INCDEC_MODELVAR(event, g_model.ppmNCH, -2, 4); g_model.ppmFrameLength = g_model.ppmNCH * 8; break; } } break; #if 0 case ITEM_MODEL_PPM2_PROTOCOL: lcdDrawTextLeft(y, PSTR("Port2")); lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_VPROTOS, 0, 0); lcdDrawTextAtt(MODEL_SETUP_2ND_COLUMN+4*FW+3, y, STR_CH, menuHorizontalPosition<=0 ? attr : 0); lcdDrawNumberAttUnit(lcdLastPos, y, g_model.moduleData[1].channelsStart+1, LEFT | (menuHorizontalPosition<=0 ? attr : 0)); lcdDrawChar(lcdLastPos, y, '-'); lcdDrawNumberAttUnit(lcdLastPos + FW+1, y, g_model.moduleData[1].channelsStart+8+g_model.moduleData[1].channelsCount, LEFT | (menuHorizontalPosition!=0 ? attr : 0)); if (attr && (editMode>0 || p1valdiff)) { switch (menuHorizontalPosition) { case 0: CHECK_INCDEC_MODELVAR_ZERO(event, g_model.moduleData[1].channelsStart, 32-8-g_model.moduleData[1].channelsCount); SET_DEFAULT_PPM_FRAME_LENGTH(1); break; case 1: CHECK_INCDEC_MODELVAR(event, g_model.moduleData[1].channelsCount, -4, min<int8_t>(8, 32-8-g_model.moduleData[1].channelsStart)); SET_DEFAULT_PPM_FRAME_LENGTH(1); break; } } break; case ITEM_MODEL_PPM2_PARAMS: lcdDrawTextLeft(y, STR_PPMFRAME); lcdDrawText(MODEL_SETUP_2ND_COLUMN+3*FW, y, STR_MS); lcdDrawNumberAttUnit(MODEL_SETUP_2ND_COLUMN, y, (int16_t)g_model.moduleData[1].ppmFrameLength*5 + 225, (menuHorizontalPosition<=0 ? attr : 0) | PREC1|LEFT); lcdDrawChar(MODEL_SETUP_2ND_COLUMN+8*FW+2, y, 'u'); lcdDrawNumberAttUnit(MODEL_SETUP_2ND_COLUMN+8*FW+2, y, (g_model.moduleData[1].ppmDelay*50)+300, (menuHorizontalPosition < 0 || menuHorizontalPosition==1) ? attr : 0); lcdDrawCharAtt(MODEL_SETUP_2ND_COLUMN+10*FW, y, g_model.moduleData[1].ppmPulsePol ? '+' : '-', (menuHorizontalPosition < 0 || menuHorizontalPosition==2) ? attr : 0); if (attr && (editMode>0 || p1valdiff)) { switch (menuHorizontalPosition) { case 0: CHECK_INCDEC_MODELVAR(event, g_model.moduleData[1].ppmFrameLength, -20, 35); break; case 1: CHECK_INCDEC_MODELVAR(event, g_model.moduleData[1].ppmDelay, -4, 10); break; case 2: CHECK_INCDEC_MODELVAR_ZERO(event, g_model.moduleData[1].ppmPulsePol, 1); break; } } break; #endif case ITEM_MODEL_PPM1_PARAMS: if (IS_PPM_PROTOCOL(protocol)) { lcdDrawTextLeft(y, STR_PPMFRAME); lcdDrawText(MODEL_SETUP_2ND_COLUMN+3*FW, y, STR_MS); lcdDrawNumberAttUnit(MODEL_SETUP_2ND_COLUMN, y, (int16_t)g_model.ppmFrameLength*5 + 225, (menuHorizontalPosition<=0 ? attr : 0) | PREC1|LEFT); lcdDrawChar(MODEL_SETUP_2ND_COLUMN+8*FW+2, y, 'u'); lcdDrawNumberAttUnit(MODEL_SETUP_2ND_COLUMN+8*FW+2, y, (g_model.ppmDelay*50)+300, (CURSOR_ON_LINE() || menuHorizontalPosition==1) ? attr : 0); lcdDrawCharAtt(MODEL_SETUP_2ND_COLUMN+10*FW, y, g_model.pulsePol ? '+' : '-', (CURSOR_ON_LINE() || menuHorizontalPosition==2) ? attr : 0); if (attr && (editMode>0 || p1valdiff)) { switch (menuHorizontalPosition) { case 0: CHECK_INCDEC_MODELVAR(event, g_model.ppmFrameLength, -20, 35); break; case 1: CHECK_INCDEC_MODELVAR(event, g_model.ppmDelay, -4, 10); break; case 2: CHECK_INCDEC_MODELVAR_ZERO(event, g_model.pulsePol, 1); break; } } } #if defined(DSM2) || defined(PXX) else if (IS_DSM2_PROTOCOL(protocol) || IS_PXX_PROTOCOL(protocol)) { if (attr && menuHorizontalPosition > 1) { REPEAT_LAST_CURSOR_MOVE(); // limit 3 column row to 2 colums (Rx_Num and RANGE fields) } lcdDrawTextLeft(y, STR_RXNUM); lcdDrawNumberNAtt(MODEL_SETUP_2ND_COLUMN, y, g_model.header.modelId[0], (menuHorizontalPosition<=0 ? attr : 0) | LEADING0|LEFT, 2); if (attr && (menuHorizontalPosition==0 && (editMode>0 || p1valdiff))) { CHECK_INCDEC_MODELVAR_ZERO(event, g_model.header.modelId[0], 99); } #if defined(PXX) if (protocol == PROTO_PXX) { lcdDrawTextAtt(MODEL_SETUP_2ND_COLUMN+4*FW, y, STR_SYNCMENU, menuHorizontalPosition!=0 ? attr : 0); uint8_t newFlag = 0; if (attr && menuHorizontalPosition>0 && editMode>0) { // send reset code newFlag = MODULE_BIND; } moduleFlag[0] = newFlag; } #endif #if defined(DSM2) if (IS_DSM2_PROTOCOL(protocol)) { lcdDrawTextAtt(MODEL_SETUP_2ND_COLUMN+4*FW, y, STR_MODULE_RANGE, menuHorizontalPosition!=0 ? attr : 0); moduleFlag[0] = (attr && menuHorizontalPosition>0 && editMode>0) ? MODULE_RANGECHECK : 0; // [MENU] key toggles range check mode } #endif } #endif break; } }
void menuGeneralSdManager(uint8_t _event) { if (s_warning_result) { s_warning_result = 0; displayPopup(STR_FORMATTING); closeLogs(); audioQueue.stopSD(); if (f_mkfs(0, 1, 0) == FR_OK) { f_chdir("/"); REFRESH_FILES(); } else { POPUP_WARNING(STR_SDCARD_ERROR); } } int lastPos = m_posVert; uint8_t event = (EVT_KEY_MASK(_event) == KEY_ENTER ? 0 : _event); SIMPLE_MENU(SD_IS_HC() ? STR_SDHC_CARD : STR_SD_CARD, menuTabGeneral, e_Sd, reusableBuffer.sdmanager.count); int index = m_posVert-s_pgOfs; switch(_event) { case EVT_ENTRY: f_chdir(ROOT_PATH); REFRESH_FILES(); lastPos = -1; break; case EVT_KEY_LONG(KEY_MENU): if (!READ_ONLY() && s_editMode == 0) { killEvents(_event); MENU_ADD_ITEM(STR_SD_INFO); MENU_ADD_ITEM(STR_SD_FORMAT); menuHandler = onSdManagerMenu; } break; case EVT_KEY_BREAK(KEY_EXIT): REFRESH_FILES(); break; case EVT_KEY_BREAK(KEY_ENTER): if (s_editMode > 0) { break; } else { if (!reusableBuffer.sdmanager.lines[index][SD_SCREEN_FILE_LENGTH+1]) { f_chdir(reusableBuffer.sdmanager.lines[index]); s_pgOfs = 0; m_posVert = 1; index = 1; REFRESH_FILES(); killEvents(_event); return; } } // no break case EVT_KEY_LONG(KEY_ENTER): if (s_editMode == 0) { killEvents(_event); char *line = reusableBuffer.sdmanager.lines[index]; char *ext = getFileExtension(line, SD_SCREEN_FILE_LENGTH+1); if (ext) { if (!strcasecmp(ext, SOUNDS_EXT)) { MENU_ADD_ITEM(STR_PLAY_FILE); } else if (!strcasecmp(ext, BITMAPS_EXT)) { if (!READ_ONLY() && (ext-line) <= (int)sizeof(g_model.header.bitmap)) { MENU_ADD_ITEM(STR_ASSIGN_BITMAP); } } else if (!strcasecmp(ext, TEXT_EXT)) { MENU_ADD_ITEM(STR_VIEW_TEXT); } #if defined(LUA) else if (!strcasecmp(ext, SCRIPTS_EXT)) { MENU_ADD_ITEM(STR_EXECUTE_FILE); } #endif else if (!READ_ONLY() && !strcasecmp(ext, FIRMWARE_EXT)) { TCHAR lfn[_MAX_LFN + 1]; getSelectionFullPath(lfn); if (isBootloader(lfn)) { MENU_ADD_ITEM(STR_FLASH_BOOTLOADER); } } else if (!READ_ONLY() && !strcasecmp(ext, SPORT_FIRMWARE_EXT)) { MENU_ADD_ITEM(STR_FLASH_EXTERNAL_DEVICE); MENU_ADD_ITEM(STR_FLASH_INTERNAL_MODULE); } } if (!READ_ONLY()) { if (line[SD_SCREEN_FILE_LENGTH+1]) // it's a file MENU_ADD_ITEM(STR_COPY_FILE); if (clipboard.type == CLIPBOARD_TYPE_SD_FILE) MENU_ADD_ITEM(STR_PASTE); MENU_ADD_ITEM(STR_RENAME_FILE); MENU_ADD_ITEM(STR_DELETE_FILE); } menuHandler = onSdManagerMenu; } break; } if (reusableBuffer.sdmanager.offset != s_pgOfs) { FILINFO fno; DIR dir; char *fn; /* This function is assuming non-Unicode cfg. */ TCHAR lfn[_MAX_LFN + 1]; fno.lfname = lfn; fno.lfsize = sizeof(lfn); if (s_pgOfs == 0) { reusableBuffer.sdmanager.offset = 0; memset(reusableBuffer.sdmanager.lines, 0, sizeof(reusableBuffer.sdmanager.lines)); } else if (s_pgOfs == reusableBuffer.sdmanager.count-7) { reusableBuffer.sdmanager.offset = s_pgOfs; memset(reusableBuffer.sdmanager.lines, 0, sizeof(reusableBuffer.sdmanager.lines)); } else if (s_pgOfs > reusableBuffer.sdmanager.offset) { memmove(reusableBuffer.sdmanager.lines[0], reusableBuffer.sdmanager.lines[1], 6*sizeof(reusableBuffer.sdmanager.lines[0])); memset(reusableBuffer.sdmanager.lines[6], 0xff, SD_SCREEN_FILE_LENGTH); reusableBuffer.sdmanager.lines[6][SD_SCREEN_FILE_LENGTH+1] = 1; } else { memmove(reusableBuffer.sdmanager.lines[1], reusableBuffer.sdmanager.lines[0], 6*sizeof(reusableBuffer.sdmanager.lines[0])); memset(reusableBuffer.sdmanager.lines[0], 0, sizeof(reusableBuffer.sdmanager.lines[0])); } reusableBuffer.sdmanager.count = 0; FRESULT res = f_opendir(&dir, "."); /* Open the directory */ if (res == FR_OK) { for (;;) { res = f_readdir(&dir, &fno); /* Read a directory item */ if (res != FR_OK || fno.fname[0] == 0) break; /* Break on error or end of dir */ if (fno.fname[0] == '.' && fno.fname[1] == '\0') continue; /* Ignore dot entry */ #if _USE_LFN fn = *fno.lfname ? fno.lfname : fno.fname; #else fn = fno.fname; #endif if (strlen(fn) > SD_SCREEN_FILE_LENGTH) continue; reusableBuffer.sdmanager.count++; bool isfile = !(fno.fattrib & AM_DIR); if (s_pgOfs == 0) { for (int i=0; i<NUM_BODY_LINES; i++) { char *line = reusableBuffer.sdmanager.lines[i]; if (line[0] == '\0' || isFilenameLower(isfile, fn, line)) { if (i < 6) memmove(reusableBuffer.sdmanager.lines[i+1], line, sizeof(reusableBuffer.sdmanager.lines[i]) * (6-i)); memset(line, 0, sizeof(reusableBuffer.sdmanager.lines[i])); strcpy(line, fn); line[SD_SCREEN_FILE_LENGTH+1] = isfile; break; } } } else if (reusableBuffer.sdmanager.offset == s_pgOfs) { for (int8_t i=6; i>=0; i--) { char *line = reusableBuffer.sdmanager.lines[i]; if (line[0] == '\0' || isFilenameGreater(isfile, fn, line)) { if (i > 0) memmove(reusableBuffer.sdmanager.lines[0], reusableBuffer.sdmanager.lines[1], sizeof(reusableBuffer.sdmanager.lines[0]) * i); memset(line, 0, sizeof(reusableBuffer.sdmanager.lines[i])); strcpy(line, fn); line[SD_SCREEN_FILE_LENGTH+1] = isfile; break; } } } else if (s_pgOfs > reusableBuffer.sdmanager.offset) { if (isFilenameGreater(isfile, fn, reusableBuffer.sdmanager.lines[5]) && isFilenameLower(isfile, fn, reusableBuffer.sdmanager.lines[6])) { memset(reusableBuffer.sdmanager.lines[6], 0, sizeof(reusableBuffer.sdmanager.lines[0])); strcpy(reusableBuffer.sdmanager.lines[6], fn); reusableBuffer.sdmanager.lines[6][SD_SCREEN_FILE_LENGTH+1] = isfile; } } else { if (isFilenameLower(isfile, fn, reusableBuffer.sdmanager.lines[1]) && isFilenameGreater(isfile, fn, reusableBuffer.sdmanager.lines[0])) { memset(reusableBuffer.sdmanager.lines[0], 0, sizeof(reusableBuffer.sdmanager.lines[0])); strcpy(reusableBuffer.sdmanager.lines[0], fn); reusableBuffer.sdmanager.lines[0][SD_SCREEN_FILE_LENGTH+1] = isfile; } } } } } reusableBuffer.sdmanager.offset = s_pgOfs; for (int i=0; i<NUM_BODY_LINES; i++) { coord_t y = MENU_HEADER_HEIGHT + 1 + i*FH; lcdNextPos = 0; LcdFlags attr = (index == i ? BSS|INVERS : BSS); if (reusableBuffer.sdmanager.lines[i][0]) { if (!reusableBuffer.sdmanager.lines[i][SD_SCREEN_FILE_LENGTH+1]) { lcd_putcAtt(0, y, '[', s_editMode == EDIT_MODIFY_STRING ? 0 : attr); } if (s_editMode == EDIT_MODIFY_STRING && attr) { editName(lcdNextPos, y, reusableBuffer.sdmanager.lines[i], SD_SCREEN_FILE_LENGTH-4, _event, attr, 0); if (s_editMode == 0) { unsigned int len = effectiveLen(reusableBuffer.sdmanager.lines[i], SD_SCREEN_FILE_LENGTH-LEN_FILE_EXTENSION); char * ext = getFileExtension(reusableBuffer.sdmanager.originalName, sizeof(reusableBuffer.sdmanager.originalName)); if (ext) { strAppend(&reusableBuffer.sdmanager.lines[i][len], ext); } f_rename(reusableBuffer.sdmanager.originalName, reusableBuffer.sdmanager.lines[i]); REFRESH_FILES(); } } else { lcd_putsAtt(lcdNextPos, y, reusableBuffer.sdmanager.lines[i], attr); } if (!reusableBuffer.sdmanager.lines[i][SD_SCREEN_FILE_LENGTH+1]) { lcd_putcAtt(lcdNextPos, y, ']', s_editMode == EDIT_MODIFY_STRING ? 0 : attr); } } } char *ext = getFileExtension(reusableBuffer.sdmanager.lines[index], SD_SCREEN_FILE_LENGTH+1); if (ext && !strcasecmp(ext, BITMAPS_EXT)) { if (lastPos != m_posVert) { if (bmpLoad(modelBitmap, reusableBuffer.sdmanager.lines[index], MODEL_BITMAP_WIDTH, MODEL_BITMAP_HEIGHT)) { memcpy(modelBitmap, logo_taranis, MODEL_BITMAP_SIZE); } } lcd_bmp(22*FW+2, 2*FH+FH/2, modelBitmap); } }
void menuCustomFunctions(uint8_t event, CustomFunctionData * functions, CustomFunctionsContext * functionsContext) { int8_t sub = menuVerticalPosition - 1; #if !defined(CPUM64) || defined(AUTOSWITCH) uint8_t eeFlags = EE_MODEL; #endif for (uint8_t i=0; i<LCD_LINES-1; i++) { coord_t y = MENU_HEADER_HEIGHT + 1 + i*FH; uint8_t k = i+menuVerticalOffset; CustomFunctionData *cfn = &functions[k]; uint8_t func = CFN_FUNC(cfn); for (uint8_t j=0; j<5; j++) { uint8_t attr = ((sub==k && menuHorizontalPosition==j) ? ((s_editMode>0) ? BLINK|INVERS : INVERS) : 0); uint8_t active = (attr && (s_editMode>0 || p1valdiff)); switch (j) { case 0: lcdPutsSwitches(MODEL_CUSTOM_FUNC_1ST_COLUMN, y, CFN_SWITCH(cfn), attr | ((functionsContext->activeSwitches & ((MASK_CFN_TYPE)1 << k)) ? BOLD : 0)); if (active || AUTOSWITCH_ENTER_LONG()) CHECK_INCDEC_SWITCH(event, CFN_SWITCH(cfn), SWSRC_FIRST, SWSRC_LAST, eeFlags, isSwitchAvailableInCustomFunctions); break; case 1: if (CFN_SWITCH(cfn)) { lcdDrawTextAtIndex(MODEL_CUSTOM_FUNC_2ND_COLUMN, y, STR_VFSWFUNC, func, attr); if (active) { CHECK_INCDEC_MODELVAR_ZERO(event, CFN_FUNC(cfn), FUNC_MAX-1); if (checkIncDec_Ret) CFN_RESET(cfn); } } else { j = 4; // skip other fields if (sub==k && menuHorizontalPosition > 0) { REPEAT_LAST_CURSOR_MOVE(); } } break; case 2: { int8_t maxParam = NUM_CHNOUT-1; #if defined(OVERRIDE_CHANNEL_FUNCTION) if (func == FUNC_OVERRIDE_CHANNEL) { putsChn(lcdNextPos, y, CFN_CH_INDEX(cfn)+1, attr); } else #endif if (func == FUNC_TRAINER) { maxParam = 4; putsMixerSource(lcdNextPos, y, MIXSRC_Rud+CFN_CH_INDEX(cfn)-1, attr); } #if defined(GVARS) else if (func == FUNC_ADJUST_GVAR) { maxParam = MAX_GVARS-1; lcdDrawStringWithIndex(lcdNextPos, y, STR_GV, CFN_GVAR_INDEX(cfn)+1, attr); if (active) CHECK_INCDEC_MODELVAR_ZERO(event, CFN_GVAR_INDEX(cfn), maxParam); break; } #endif else if (attr) { REPEAT_LAST_CURSOR_MOVE(); } if (active) CHECK_INCDEC_MODELVAR_ZERO(event, CFN_CH_INDEX(cfn), maxParam); break; } case 3: { INCDEC_DECLARE_VARS(eeFlags); int16_t val_displayed = CFN_PARAM(cfn); int8_t val_min = 0; uint8_t val_max = 255; if (func == FUNC_RESET) { val_max = FUNC_RESET_PARAM_LAST; lcdDrawTextAtIndex(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, STR_VFSWRESET, CFN_PARAM(cfn), attr); } #if defined(OVERRIDE_CHANNEL_FUNCTION) else if (func == FUNC_OVERRIDE_CHANNEL) { val_displayed = (int8_t)CFN_PARAM(cfn); val_min = -LIMIT_EXT_PERCENT; val_max = +LIMIT_EXT_PERCENT; lcdDrawNumberAttUnit(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr|LEFT); } #endif #if defined(AUDIO) else if (func == FUNC_PLAY_SOUND) { val_max = AU_FRSKY_LAST-AU_FRSKY_FIRST-1; lcdDrawTextAtIndex(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, STR_FUNCSOUNDS, val_displayed, attr); } #endif #if defined(HAPTIC) else if (func == FUNC_HAPTIC) { val_max = 3; lcdDrawNumberAttUnit(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr|LEFT); } #endif #if defined(VOICE) else if (func == FUNC_PLAY_TRACK) { #if defined(GVARS) if (attr && event==EVT_KEY_LONG(KEY_ENTER)) { killEvents(event); s_editMode = !s_editMode; active = true; val_displayed = (val_displayed > 250 ? 0 : 251); } if (val_displayed > 250) { lcdDrawStringWithIndex(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, STR_GV, val_displayed-250, attr); } else { lcdDrawNumberAttUnit(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed+PROMPT_CUSTOM_BASE, attr|LEFT); } #else lcdDrawNumberAttUnit(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed+PROMPT_CUSTOM_BASE, attr|LEFT); #endif } else if (func == FUNC_PLAY_BOTH) { lcdDrawCharAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN+3*FWNUM, y, '|', attr); lcdDrawNumberAttUnit(MODEL_CUSTOM_FUNC_3RD_COLUMN+3*FWNUM, y, val_displayed+PROMPT_CUSTOM_BASE, attr); lcdDrawNumberAttUnit(MODEL_CUSTOM_FUNC_3RD_COLUMN+2+3*FWNUM, y, (val_displayed+PROMPT_CUSTOM_BASE+1)%10, attr|LEFT); } else if (func == FUNC_PLAY_VALUE) { val_max = MIXSRC_FIRST_TELEM + TELEM_DISPLAY_MAX - 1; putsMixerSource(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr); INCDEC_ENABLE_CHECK(functionsContext == &globalFunctionsContext ? isSourceAvailableInGlobalFunctions : isSourceAvailable); } #endif #if defined(SDCARD) else if (func == FUNC_LOGS) { if (val_displayed) { lcdDrawNumberAttUnit(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr|PREC1|LEFT); lcdDrawChar(lcdLastPos, y, 's'); } else { lcdDrawTextAtIndex(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, STR_MMMINV, 0, attr); } } #endif #if defined(GVARS) else if (func == FUNC_ADJUST_GVAR) { switch (CFN_GVAR_MODE(cfn)) { case FUNC_ADJUST_GVAR_CONSTANT: val_displayed = (int16_t)CFN_PARAM(cfn); val_min = -CFN_GVAR_CST_MAX; val_max = +CFN_GVAR_CST_MAX; lcdDrawNumberAttUnit(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr|LEFT); break; case FUNC_ADJUST_GVAR_SOURCE: val_max = MIXSRC_LAST_CH; putsMixerSource(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr); INCDEC_SET_FLAG(eeFlags | INCDEC_SOURCE); INCDEC_ENABLE_CHECK(isSourceAvailable); break; case FUNC_ADJUST_GVAR_GVAR: val_max = MAX_GVARS-1; lcdDrawStringWithIndex(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, STR_GV, val_displayed+1, attr); break; default: // FUNC_ADJUST_GVAR_INC val_max = 1; lcdDrawTextAtIndex(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, PSTR("\003-=1+=1"), val_displayed, attr); break; } if (attr && event==EVT_KEY_LONG(KEY_ENTER)) { killEvents(event); s_editMode = !s_editMode; active = true; CFN_GVAR_MODE(cfn) += 1; val_displayed = 0; } } #endif else if (attr) { REPEAT_LAST_CURSOR_MOVE(); } if (active) { CFN_PARAM(cfn) = CHECK_INCDEC_PARAM(event, val_displayed, val_min, val_max); } break; } case 4: if (HAS_ENABLE_PARAM(func)) { menu_lcd_onoff(MODEL_CUSTOM_FUNC_4TH_COLUMN_ONOFF, y, CFN_ACTIVE(cfn), attr); if (active) CHECK_INCDEC_MODELVAR_ZERO(event, CFN_ACTIVE(cfn), 1); } else if (HAS_REPEAT_PARAM(func)) { if (CFN_PLAY_REPEAT(cfn) == 0) { lcdDrawCharAtt(MODEL_CUSTOM_FUNC_4TH_COLUMN_ONOFF+3, y, '-', attr); } else { lcdDrawNumberAttUnit(MODEL_CUSTOM_FUNC_4TH_COLUMN+2+FW, y, CFN_PLAY_REPEAT(cfn)*CFN_PLAY_REPEAT_MUL, attr); } if (active) CHECK_INCDEC_MODELVAR_ZERO(event, CFN_PLAY_REPEAT(cfn), 60/CFN_PLAY_REPEAT_MUL); } else if (attr) { REPEAT_LAST_CURSOR_MOVE(); } break; } } } }
void menuTelemetryFrsky(uint8_t event) { if (event == EVT_KEY_FIRST(KEY_EXIT)) { killEvents(event); chainMenu(menuMainView); return; } switch (event) { case EVT_KEY_BREAK(KEY_UP): if (s_frsky_view-- == 0) s_frsky_view = FRSKY_VIEW_MAX; break; #if defined(PCBTARANIS) case EVT_KEY_BREAK(KEY_PAGE): #endif case EVT_KEY_BREAK(KEY_DOWN): if (s_frsky_view++ == FRSKY_VIEW_MAX) s_frsky_view = 0; break; #if defined(PCBTARANIS) case EVT_KEY_LONG(KEY_ENTER): killEvents(event); MENU_ADD_ITEM(STR_RESET_TELEMETRY); MENU_ADD_ITEM(STR_RESET_FLIGHT); menuHandler = onMainViewMenu; break; #else case EVT_KEY_FIRST(KEY_ENTER): telemetryReset(); break; #endif } lcdDrawTelemetryTopBar(); if (s_frsky_view < MAX_FRSKY_SCREENS) { FrSkyScreenData & screen = g_model.frsky.screens[s_frsky_view]; #if defined(GAUGES) if (g_model.frsky.screensType & (1<<s_frsky_view)) { // Custom Screen with gauges uint8_t barHeight = 5; for (int8_t i=3; i>=0; i--) { FrSkyBarData & bar = screen.bars[i]; uint8_t source = bar.source; getvalue_t barMin = convertBarTelemValue(source, bar.barMin); getvalue_t barMax = convertBarTelemValue(source, 255-bar.barMax); if (source && barMax > barMin) { uint8_t y = barHeight+6+i*(barHeight+6); lcd_putsiAtt(0, y+barHeight-5, STR_VTELEMCHNS, source, 0); lcd_rect(25, y, BAR_WIDTH+1, barHeight+2); getvalue_t value = getValue(MIXSRC_FIRST_TELEM+source-1); #if LCD_W >= 212 putsTelemetryChannel(27+BAR_WIDTH, y+barHeight-6, source-1, value, LEFT); #endif getvalue_t threshold = 0; uint8_t thresholdX = 0; if (source <= TELEM_TM2) threshold = 0; else if (source <= TELEM_RSSI_RX) threshold = getRssiAlarmValue(source-TELEM_RSSI_TX); else if (source <= TELEM_A2) threshold = g_model.frsky.channels[source-TELEM_A1].alarms_value[0]; #if defined(FRSKY_HUB) else threshold = convertBarTelemValue(source, barsThresholds[source-TELEM_ALT]); #endif if (threshold) { thresholdX = barCoord(threshold, barMin, barMax); if (thresholdX == 100) thresholdX = 0; } uint8_t width = barCoord(value, barMin, barMax); // reversed barshade for T1/T2 uint8_t barShade = ((threshold > value) ? DOTTED : SOLID); if (source == TELEM_T1 || source == TELEM_T2) barShade = -barShade; lcd_filled_rect(26, y+1, width, barHeight, barShade); for (uint8_t j=24; j<99; j+=25) if (j>thresholdX || j>width) lcd_vline(j*BAR_WIDTH/100+26, y+1, barHeight); if (thresholdX) { lcd_vlineStip(26+thresholdX, y-2, barHeight+3, DOTTED); lcd_hline(25+thresholdX, y-2, 3); } } else { barHeight += 2; } } displayRssiLine(); } else #endif { // Custom Screen with numbers uint8_t fields_count = 0; for (uint8_t i=0; i<4; i++) { for (uint8_t j=0; j<NUM_LINE_ITEMS; j++) { uint8_t field = screen.lines[i].sources[j]; if (i==3 && j==0) { #if LCD_W >= 212 lcd_vline(69, 8, 48); lcd_vline(141, 8, 48); #else lcd_vline(63, 8, 48); #endif if (TELEMETRY_STREAMING()) { #if defined(FRSKY_HUB) if (field == TELEM_ACC) { lcd_putsLeft(STATUS_BAR_Y, STR_ACCEL); lcd_outdezNAtt(4*FW, STATUS_BAR_Y, frskyData.hub.accelX, LEFT|PREC2); lcd_outdezNAtt(10*FW, STATUS_BAR_Y, frskyData.hub.accelY, LEFT|PREC2); lcd_outdezNAtt(16*FW, STATUS_BAR_Y, frskyData.hub.accelZ, LEFT|PREC2); break; } #if defined(GPS) else if (field == TELEM_GPS_TIME) { displayGpsTime(); return; } #endif #endif } else { displayRssiLine(); return; } } if (field) { fields_count++; getvalue_t value = getValue(MIXSRC_FIRST_TELEM+field-1); uint8_t att = (i==3 ? NO_UNIT : DBLSIZE|NO_UNIT); #if LCD_W >= 212 xcoord_t pos[] = {0, 71, 143, 214}; #else xcoord_t pos[] = {0, 65, 130}; #endif putsTelemetryChannel(pos[j+1]-2, 1+FH+2*FH*i, field-1, value, att); if (field >= TELEM_TM1 && field <= TELEM_TM2 && i!=3) { // there is not enough space on LCD for displaying "Tmr1" or "Tmr2" and still see the - sign, we write "T1" or "T2" instead field = field-TELEM_TM1+TELEM_T1; } lcd_putsiAtt(pos[j], 1+FH+2*FH*i, STR_VTELEMCHNS, field, 0); } } } lcd_status_line(); if (fields_count == 0) putEvent(event == EVT_KEY_BREAK(KEY_UP) ? event : EVT_KEY_BREAK(KEY_DOWN)); } } else if (s_frsky_view == e_frsky_voltages) { // Volts / Amps / Watts / mAh uint8_t analog = 0; #if defined(CPUARM) lcd_putsiAtt(0, 2*FH, STR_VOLTSRC, g_model.frsky.voltsSource, 0); #else lcd_putsiAtt(0, 2*FH, STR_AMPSRC, g_model.frsky.voltsSource+1, 0); #endif switch (g_model.frsky.voltsSource) { #if defined(CPUARM) case FRSKY_VOLTS_SOURCE_RXBATT: putsTelemetryChannel(3*FW+6*FW+4, FH+1, TELEM_RXBATT-1, frskyData.analog[TELEM_ANA_RXBATT].value, DBLSIZE); break; #endif case FRSKY_VOLTS_SOURCE_A1: case FRSKY_VOLTS_SOURCE_A2: #if defined(CPUARM) case FRSKY_VOLTS_SOURCE_A3: case FRSKY_VOLTS_SOURCE_A4: #endif displayVoltageScreenLine(2*FH, g_model.frsky.voltsSource); analog = 1+g_model.frsky.voltsSource; break; #if defined(FRSKY_HUB) case FRSKY_VOLTS_SOURCE_FAS: putsTelemetryChannel(3*FW+6*FW+4, FH+1, TELEM_VFAS-1, frskyData.hub.vfas, DBLSIZE); break; case FRSKY_VOLTS_SOURCE_CELLS: putsTelemetryChannel(3*FW+6*FW+4, FH+1, TELEM_CELLS_SUM-1, frskyData.hub.cellsSum, DBLSIZE); break; #endif } if (g_model.frsky.currentSource) { lcd_putsiAtt(0, 4*FH, STR_AMPSRC, g_model.frsky.currentSource, 0); switch(g_model.frsky.currentSource) { case FRSKY_CURRENT_SOURCE_A1: case FRSKY_CURRENT_SOURCE_A2: #if defined(CPUARM) case FRSKY_CURRENT_SOURCE_A3: case FRSKY_CURRENT_SOURCE_A4: #endif displayVoltageScreenLine(4*FH, g_model.frsky.currentSource-1); break; #if defined(FRSKY_HUB) case FRSKY_CURRENT_SOURCE_FAS: putsTelemetryChannel(3*FW+6*FW+4, 3*FH+1, TELEM_CURRENT-1, frskyData.hub.current, DBLSIZE); break; #endif } putsTelemetryChannel(4, 5*FH+1, TELEM_POWER-1, frskyData.hub.power, LEFT|DBLSIZE); putsTelemetryChannel(3*FW+4+4*FW+6*FW+FW, 5*FH+1, TELEM_CONSUMPTION-1, frskyData.hub.currentConsumption, DBLSIZE); } else { displayVoltageScreenLine(analog > 0 ? 5*FH : 4*FH, analog ? 2-analog : 0); if (analog == 0) displayVoltageScreenLine(6*FH, 1); } #if defined(FRSKY_HUB) // Cells voltage if (frskyData.hub.cellsCount > 0) { uint8_t y = 1*FH; for (uint8_t k=0; k<frskyData.hub.cellsCount && k<6; k++) { #if defined(GAUGES) uint8_t attr = (barsThresholds[THLD_CELL] && frskyData.hub.cellVolts[k] < barsThresholds[THLD_CELL]) ? BLINK|PREC2 : PREC2; #else uint8_t attr = PREC2; #endif lcd_outdezNAtt(LCD_W, y, TELEMETRY_CELL_VOLTAGE(k), attr, 4); y += 1*FH; } #if defined(PCBTARANIS) if (frskyData.hub.cellsCount > 6) { y = 1*FH; for (uint8_t k=6; k<frskyData.hub.cellsCount && k<12; k++) { #if defined(GAUGES) uint8_t attr = (barsThresholds[THLD_CELL] && frskyData.hub.cellVolts[k] < barsThresholds[THLD_CELL]) ? BLINK|PREC2 : PREC2; #else uint8_t attr = PREC2; #endif lcd_outdezNAtt(LCD_W-3*FW-2, y, TELEMETRY_CELL_VOLTAGE(k), attr, 4); y += 1*FH; } lcd_vline(LCD_W-6*FW-4, 8, 47); } else #endif lcd_vline(LCD_W-3*FW-2, 8, 47); } #endif displayRssiLine(); } #if defined(FRSKY_HUB) else if (s_frsky_view == e_frsky_after_flight) { uint8_t line=1*FH+1; if (IS_GPS_AVAILABLE()) { // Latitude lcd_putsLeft(line, STR_LATITUDE); displayGpsCoord(line, frskyData.hub.gpsLatitudeNS, frskyData.hub.gpsLatitude_bp, frskyData.hub.gpsLatitude_ap); // Longitude line+=1*FH+1; lcd_putsLeft(line, STR_LONGITUDE); displayGpsCoord(line, frskyData.hub.gpsLongitudeEW, frskyData.hub.gpsLongitude_bp, frskyData.hub.gpsLongitude_ap); displayGpsTime(); line+=1*FH+1; } // Rssi lcd_putsLeft(line, STR_MINRSSI); #if defined(PCBTARANIS) lcd_outdezNAtt(TELEM_2ND_COLUMN, line, frskyData.rssi[0].min, LEFT|LEADING0, 2); #else lcd_puts(TELEM_2ND_COLUMN, line, STR_TX); lcd_outdezNAtt(TELEM_2ND_COLUMN+3*FW, line, frskyData.rssi[1].min, LEFT|LEADING0, 2); lcd_puts(TELEM_2ND_COLUMN+6*FW, line, STR_RX); lcd_outdezNAtt(TELEM_2ND_COLUMN+9*FW, line, frskyData.rssi[0].min, LEFT|LEADING0, 2); #endif } #endif }
void menuMainView(uint8_t event) { STICK_SCROLL_DISABLE(); uint8_t view = g_eeGeneral.view; uint8_t view_base = view & 0x0f; switch(event) { case EVT_ENTRY: killEvents(KEY_EXIT); killEvents(KEY_UP); killEvents(KEY_DOWN); break; /* TODO if timer2 is OFF, it's possible to use this timer2 as in er9x... case EVT_KEY_BREAK(KEY_MENU): if (view_base == VIEW_TIMER2) { Timer2_running = !Timer2_running; AUDIO_KEYPAD_UP(); } break; */ case EVT_KEY_BREAK(KEY_RIGHT): case EVT_KEY_BREAK(KEY_LEFT): if (view_base <= VIEW_INPUTS) { #if defined(PCBSKY9X) if (view_base == VIEW_INPUTS) g_eeGeneral.view ^= ALTERNATE_VIEW; else g_eeGeneral.view = (g_eeGeneral.view + (4*ALTERNATE_VIEW) + ((event==EVT_KEY_BREAK(KEY_LEFT)) ? -ALTERNATE_VIEW : ALTERNATE_VIEW)) % (4*ALTERNATE_VIEW); #else g_eeGeneral.view ^= ALTERNATE_VIEW; #endif eeDirty(EE_GENERAL); AUDIO_KEYPAD_UP(); } break; #if defined(NAVIGATION_MENUS) case EVT_KEY_CONTEXT_MENU: killEvents(event); #if defined(CPUARM) if (modelHasNotes()) { MENU_ADD_ITEM(STR_VIEW_NOTES); } #endif #if defined(CPUARM) MENU_ADD_ITEM(STR_RESET_SUBMENU); #else MENU_ADD_ITEM(STR_RESET_TIMER1); MENU_ADD_ITEM(STR_RESET_TIMER2); #if defined(FRSKY) MENU_ADD_ITEM(STR_RESET_TELEMETRY); #endif MENU_ADD_ITEM(STR_RESET_FLIGHT); #endif MENU_ADD_ITEM(STR_STATISTICS); #if defined(CPUARM) MENU_ADD_ITEM(STR_ABOUT_US); #endif menuHandler = onMainViewMenu; break; #endif #if MENUS_LOCK != 2 /*no menus*/ case EVT_KEY_LONG(KEY_MENU):// go to last menu pushMenu(lastPopMenu()); killEvents(event); break; CASE_EVT_ROTARY_BREAK case EVT_KEY_MODEL_MENU: pushMenu(menuModelSelect); killEvents(event); break; CASE_EVT_ROTARY_LONG case EVT_KEY_GENERAL_MENU: pushMenu(menuGeneralSetup); killEvents(event); break; #endif case EVT_KEY_BREAK(KEY_UP): case EVT_KEY_BREAK(KEY_DOWN): g_eeGeneral.view = (event == EVT_KEY_BREAK(KEY_UP) ? (view_base == VIEW_COUNT-1 ? 0 : view_base+1) : (view_base == 0 ? VIEW_COUNT-1 : view_base-1)); eeDirty(EE_GENERAL); AUDIO_KEYPAD_UP(); break; case EVT_KEY_STATISTICS: chainMenu(menuStatisticsView); killEvents(event); break; case EVT_KEY_TELEMETRY: #if defined(FRSKY) if (!IS_FAI_ENABLED()) chainMenu(menuTelemetryFrsky); #elif defined(JETI) JETI_EnableRXD(); // enable JETI-Telemetry reception chainMenu(menuTelemetryJeti); #elif defined(ARDUPILOT) ARDUPILOT_EnableRXD(); // enable ArduPilot-Telemetry reception chainMenu(menuTelemetryArduPilot); #elif defined(NMEA) NMEA_EnableRXD(); // enable NMEA-Telemetry reception chainMenu(menuTelemetryNMEA); #elif defined(MAVLINK) chainMenu(menuTelemetryMavlink); #else chainMenu(menuStatisticsDebug); #endif killEvents(event); break; case EVT_KEY_FIRST(KEY_EXIT): #if defined(GVARS) && !defined(PCBSTD) if (s_gvar_timer > 0) { s_gvar_timer = 0; } #endif if (view == VIEW_TIMER2) { timerReset(1); } AUDIO_KEYPAD_UP(); break; #if !defined(NAVIGATION_MENUS) case EVT_KEY_LONG(KEY_EXIT): flightReset(); AUDIO_KEYPAD_UP(); break; #endif } { // Flight Mode Name uint8_t mode = mixerCurrentFlightMode; lcd_putsnAtt(PHASE_X, PHASE_Y, g_model.flightModeData[mode].name, sizeof(g_model.flightModeData[mode].name), ZCHAR|PHASE_FLAGS); // Model Name putsModelName(MODELNAME_X, MODELNAME_Y, g_model.header.name, g_eeGeneral.currModel, BIGSIZE); // Main Voltage (or alarm if any) displayVoltageOrAlarm(); // Timers displayTimers(); // Trims sliders displayTrims(mode); } if (view_base < VIEW_INPUTS) { // scroll bar lcd_hlineStip(38, 34, 54, DOTTED); #if defined(PCBSKY9X) lcd_hline(38 + (g_eeGeneral.view / ALTERNATE_VIEW) * 13, 34, 13, SOLID); #else lcd_hline((g_eeGeneral.view & ALTERNATE_VIEW) ? 64 : 38, 34, 26, SOLID); #endif for (uint8_t i=0; i<8; i++) { uint8_t x0,y0; #if defined(PCBSKY9X) uint8_t chan = 8*(g_eeGeneral.view / ALTERNATE_VIEW) + i; #else uint8_t chan = (g_eeGeneral.view & ALTERNATE_VIEW) ? 8+i : i; #endif int16_t val = channelOutputs[chan]; switch(view_base) { case VIEW_OUTPUTS_VALUES: x0 = (i%4*9+3)*FW/2; y0 = i/4*FH+40; #if defined(PPM_UNIT_US) lcd_outdezAtt(x0+4*FW , y0, PPM_CH_CENTER(chan)+val/2, 0); #elif defined(PPM_UNIT_PERCENT_PREC1) lcd_outdezAtt(x0+4*FW , y0, calcRESXto1000(val), PREC1); #else lcd_outdezAtt(x0+4*FW , y0, calcRESXto1000(val)/10, 0); // G: Don't like the decimal part* #endif break; case VIEW_OUTPUTS_BARS: #define WBAR2 (50/2) x0 = i<4 ? LCD_W/4+2 : LCD_W*3/4-2; y0 = 38+(i%4)*5; uint16_t lim = g_model.extendedLimits ? 640*2 : 512*2; int8_t len = (abs(val) * WBAR2 + lim/2) / lim; if(len>WBAR2) len = WBAR2; // prevent bars from going over the end - comment for debugging lcd_hlineStip(x0-WBAR2, y0, WBAR2*2+1, DOTTED); lcd_vline(x0,y0-2,5); if (val>0) x0+=1; else x0-=len; lcd_hline(x0,y0+1,len); lcd_hline(x0,y0-1,len); break; } } } else if (view_base == VIEW_INPUTS) { if (view == VIEW_INPUTS) { // Sticks + Pots doMainScreenGraphics(); // Switches for (uint8_t i=SWSRC_THR; i<=SWSRC_TRN; i++) { int8_t sw = (i == SWSRC_TRN ? (switchState(SW_ID0) ? SWSRC_ID0 : (switchState(SW_ID1) ? SWSRC_ID1 : SWSRC_ID2)) : i); uint8_t x = 2*FW-2, y = i*FH+1; if (i>=SWSRC_AIL) { x = 17*FW-1; y -= 3*FH; } putsSwitches(x, y, sw, getSwitch(i) ? INVERS : 0); } } else { #if defined(PCBMEGA2560) && defined(ROTARY_ENCODERS) for (uint8_t i=0; i<NUM_ROTARY_ENCODERS; i++) { int16_t val = getRotaryEncoder(i); int8_t len = limit((int16_t)0, (int16_t)(((val+1024) * BAR_HEIGHT) / 2048), (int16_t)BAR_HEIGHT); #if ROTARY_ENCODERS > 2 #define V_BAR_W 5 V_BAR(LCD_W/2-8+V_BAR_W*i, LCD_H-8, len); #else #define V_BAR_W 5 V_BAR(LCD_W/2-3+V_BAR_W*i, LCD_H-8, len); #endif } #endif // PCBGRUVIN9X && ROTARY_ENCODERS // Logical Switches #if defined(PCBSKY9X) for (uint8_t i=0; i<NUM_LOGICAL_SWITCH; i++) { int8_t len = getSwitch(SWSRC_SW1+i) ? BAR_HEIGHT : 1; uint8_t x = VSWITCH_X(i); lcd_vline(x-1, VSWITCH_Y-len, len); lcd_vline(x, VSWITCH_Y-len, len); } #elif defined(CPUM2560) for (uint8_t i=0; i<NUM_LOGICAL_SWITCH; i++) putsSwitches(2*FW-3 + (i/3)*(i/3>2 ? 3*FW+2 : (3*FW-1)) + (i/3>2 ? 2*FW : 0), 4*FH+1 + (i%3)*FH, SWSRC_SW1+i, getSwitch(SWSRC_SW1+i) ? INVERS : 0); #elif !defined(PCBSTD) for (uint8_t i=0; i<NUM_LOGICAL_SWITCH; i++) putsSwitches(2*FW-2 + (i/3)*(4*FW-1), 4*FH+1 + (i%3)*FH, SWSRC_SW1+i, getSwitch(SWSRC_SW1+i) ? INVERS : 0); #else for (uint8_t i=0; i<NUM_LOGICAL_SWITCH; i++) putsSwitches(2*FW-3 + (i/3)*(4*FW), 4*FH+1 + (i%3)*FH, SWSRC_SW1+i, getSwitch(SWSRC_SW1+i) ? INVERS : 0); #endif } } else { // timer2 #if defined(TRANSLATIONS_CZ) #define TMR2_LBL_COL (20-FW/2+1) #else #define TMR2_LBL_COL (20-FW/2+5) #endif putsTimer(33+FW+2+10*FWNUM-4, FH*5, timersStates[1].val, DBLSIZE, DBLSIZE); putsTimerMode(timersStates[1].val >= 0 ? TMR2_LBL_COL : TMR2_LBL_COL-7, FH*6, g_model.timers[1].mode); // lcd_outdezNAtt(33+11*FW, FH*6, s_timerVal_10ms[1], LEADING0, 2); // 1/100s } // And ! in case of unexpected shutdown if (unexpectedShutdown) { lcd_putcAtt(REBOOT_X, 0*FH, '!', INVERS); } #if defined(GVARS) && !defined(PCBSTD) if (s_gvar_timer > 0) { s_gvar_timer--; s_warning = STR_GLOBAL_VAR; displayBox(); lcd_putsnAtt(16, 5*FH, g_model.gvars[s_gvar_last].name, LEN_GVAR_NAME, ZCHAR); lcd_putsAtt(16+7*FW, 5*FH, PSTR("[\010]"), BOLD); lcd_outdezAtt(16+7*FW+4*FW+FW/2, 5*FH, GVAR_VALUE(s_gvar_last, getGVarFlightPhase(mixerCurrentFlightMode, s_gvar_last)), BOLD); s_warning = NULL; } #endif #if defined(DSM2) if (moduleFlag[0] == MODULE_BIND) { // Issue 98 lcd_putsAtt(15*FW, 0, PSTR("BIND"), 0); } #endif }
void menuUp1(uint8_t event) { FRESULT fr ; struct fileControl *fc = &FileControl ; static uint8_t mounted = 0 ; static uint32_t state ; static uint32_t firmwareAddress ; uint32_t i ; uint32_t width ; if (UpdateItem == UPDATE_TYPE_BOOTLOADER ) // Bootloader { TITLE( "UPDATE BOOT" ) ; } else { #ifdef PCBX9D if (UpdateItem == UPDATE_TYPE_SPORT_INT ) { TITLE( "UPDATE Int. XJT" ) ; } else { TITLE( "UPDATE Ext. SPort" ) ; } #endif #ifdef PCBSKY #ifndef REVX if (UpdateItem == UPDATE_TYPE_COPROCESSOR ) { TITLE( "UPDATE COPROC" ) ; } else { TITLE( "UPDATE SPort" ) ; } #else if (UpdateItem == UPDATE_TYPE_SPORT_EXT ) { TITLE( "UPDATE SPort" ) ; } #endif #endif } switch(event) { case EVT_ENTRY: state = UPDATE_NO_FILES ; if ( mounted == 0 ) { #if defined(PCBTARANIS) fr = f_mount(0, &g_FATFS_Obj) ; #else fr = f_mount(0, &g_FATFS) ; #endif #ifdef PCBX9D unlockFlash() ; #endif } else { fr = FR_OK ; } if ( fr == FR_OK) { mounted = 1 ; } if ( mounted ) { fr = f_chdir( (TCHAR *)"\\firmware" ) ; if ( fr == FR_OK ) { state = UPDATE_NO_FILES ; fc->index = 0 ; fr = f_opendir( &Dj, (TCHAR *) "." ) ; if ( fr == FR_OK ) { if ( (UpdateItem > 1 ) ) { fc->ext[0] = 'F' ; fc->ext[1] = 'R' ; fc->ext[2] = 'K' ; } else { fc->ext[0] = 'B' ; fc->ext[1] = 'I' ; fc->ext[2] = 'N' ; } fc->ext[3] = 0 ; fc->index = 0 ; fc->nameCount = fillNames( 0, fc ) ; fc->hpos = 0 ; fc->vpos = 0 ; if ( fc->nameCount ) { state = UPDATE_FILE_LIST ; } } } } break ; case EVT_KEY_FIRST(KEY_EXIT): if ( state < UPDATE_ACTION ) { chainMenu(menuUpdate) ; killEvents(event) ; } break ; } switch ( state ) { case UPDATE_NO_FILES : lcd_puts_Pleft( 4*FH, "\005No Files" ) ; lcd_outdez( 21*FW, 4*FH, mounted ) ; break ; case UPDATE_FILE_LIST : SportVerValid = 0 ; if ( fileList( event, &FileControl ) == 1 ) { state = UPDATE_CONFIRM ; } break ; case UPDATE_CONFIRM : if ( (UpdateItem > UPDATE_TYPE_BOOTLOADER ) ) { #ifdef PCBX9D if ( (UpdateItem == UPDATE_TYPE_SPORT_INT ) ) { lcd_puts_Pleft( 2*FH, "Flash Int. XJT from" ) ; } else { lcd_puts_Pleft( 2*FH, "Flash Ext.SP from" ) ; } SportVerValid = 0 ; #else #ifndef REVX if ( (UpdateItem == UPDATE_TYPE_COPROCESSOR ) ) { lcd_puts_Pleft( 2*FH, "Flash Co-Proc. from" ) ; } else { lcd_puts_Pleft( 2*FH, "Flash SPort from" ) ; } CoProcReady = 0 ; #else lcd_puts_Pleft( 2*FH, "Flash SPort from" ) ; #endif #endif } else { lcd_puts_Pleft( 2*FH, "Flash Bootloader from" ) ; } cpystr( cpystr( (uint8_t *)FlashFilename, (uint8_t *)"\\firmware\\" ), (uint8_t *)Filenames[fc->vpos] ) ; #if defined(PCBTARANIS) lcd_putsnAtt( 0, 4*FH, Filenames[fc->vpos], DISPLAY_CHAR_WIDTH, 0 ) ; #else lcd_putsnAtt0( 0, 4*FH, Filenames[fc->vpos], DISPLAY_CHAR_WIDTH, 0 ) ; #endif if ( event == EVT_KEY_LONG(KEY_MENU) ) { state = UPDATE_SELECTED ; } if ( event == EVT_KEY_LONG(KEY_EXIT) ) { state = UPDATE_FILE_LIST ; // Canceled } break ; case UPDATE_SELECTED : f_open( &FlashFile, FlashFilename, FA_READ ) ; f_read( &FlashFile, (BYTE *)FileData, 1024, &BlockCount ) ; i = 1 ; if (UpdateItem == UPDATE_TYPE_BOOTLOADER ) // Bootloader { i = validateFile( (uint32_t *) FileData ) ; } if ( i == 0 ) { state = UPDATE_INVALID ; } else { if (UpdateItem == UPDATE_TYPE_BOOTLOADER ) // Bootloader { #ifdef PCBX9D firmwareAddress = 0x08000000 ; #endif #ifdef PCBSKY firmwareAddress = 0x00400000 ; #endif } #ifdef PCBSKY #ifndef REVX else if (UpdateItem == UPDATE_TYPE_COPROCESSOR ) // Bootloader { firmwareAddress = 0x00000080 ; if ( check_ready() == 0 ) { CoProcReady = 1 ; } } #endif #endif else { // SPort update SportState = SPORT_START ; FirmwareSize = FileSize[fc->vpos] ; BlockInUse = 0 ; f_read( &FlashFile, (BYTE *)ExtraFileData, 1024, &XblockCount ) ; } BytesFlashed = 0 ; BlockOffset = 0 ; ByteEnd = 1024 ; state = UPDATE_ACTION ; } break ; case UPDATE_INVALID : lcd_puts_Pleft( 2*FH, "Invalid File" ) ; lcd_puts_Pleft( 4*FH, "Press EXIT" ) ; if ( event == EVT_KEY_FIRST(KEY_EXIT) ) { state = UPDATE_FILE_LIST ; // Canceled killEvents(event) ; } break ; case UPDATE_ACTION : // Do the flashing lcd_puts_Pleft( 3*FH, "Flashing" ) ; if (UpdateItem == UPDATE_TYPE_BOOTLOADER ) // Bootloader { width = ByteEnd >> 9 ; if ( BytesFlashed < ByteEnd ) { program( (uint32_t *)firmwareAddress, &((uint32_t *)FileData)[BlockOffset] ) ; // size is 256 bytes BlockOffset += 64 ; // 32-bit words (256 bytes) firmwareAddress += 256 ; BytesFlashed += 256 ; } else { if ( ByteEnd >= 32768 ) { state = UPDATE_COMPLETE ; } else { f_read( &FlashFile, (BYTE *)FileData, 1024, &BlockCount ) ; ByteEnd += 1024 ; BlockOffset = 0 ; } } } #ifdef PCBSKY #ifndef REVX else if (UpdateItem == UPDATE_TYPE_COPROCESSOR ) // CoProcessor
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 menuModelSelect(uint8_t event) { if (s_warning_result) { s_warning_result = 0; eeDeleteModel(m_posVert); // delete file s_copyMode = 0; event = EVT_ENTRY_UP; } uint8_t _event_ = (IS_ROTARY_BREAK(event) || IS_ROTARY_LONG(event) ? 0 : event); if ((s_copyMode && EVT_KEY_MASK(event) == KEY_EXIT) || event == EVT_KEY_BREAK(KEY_EXIT)) { _event_ -= KEY_EXIT; } int8_t oldSub = m_posVert; check_submenu_simple(_event_, MAX_MODELS-1); #if defined(NAVIGATION_POT2) if (event==0 && p2valdiff<0) { event = EVT_KEY_FIRST(KEY_RIGHT); } #endif if (s_editMode > 0) s_editMode = 0; #if !defined(CPUARM) if (event) { eeFlush(); // flush eeprom write } #endif int8_t sub = m_posVert; switch (event) { case EVT_ENTRY: m_posVert = sub = g_eeGeneral.currModel; if (sub >= LCD_LINES-1) s_pgOfs = sub-LCD_LINES+2; s_copyMode = 0; s_editMode = EDIT_MODE_INIT; eeCheck(true); break; case EVT_KEY_LONG(KEY_EXIT): killEvents(event); if (s_copyMode && s_copyTgtOfs == 0 && g_eeGeneral.currModel != sub && eeModelExists(sub)) { POPUP_CONFIRMATION(STR_DELETEMODEL); #if defined(CPUARM) SET_WARNING_INFO(modelHeaders[sub].name, sizeof(g_model.header.name), ZCHAR); #else char * name = reusableBuffer.modelsel.mainname; eeLoadModelName(sub, name); SET_WARNING_INFO(name, sizeof(g_model.header.name), ZCHAR); #endif } else { s_copyMode = 0; m_posVert = g_eeGeneral.currModel; } break; #if defined(ROTARY_ENCODER_NAVIGATION) case EVT_ROTARY_LONG: killEvents(event); if (s_editMode < 0) { popMenu(); break; } else if (!s_copyMode) { m_posVert = sub = g_eeGeneral.currModel; s_copyMode = 0; s_editMode = EDIT_MODE_INIT; } // no break #endif case EVT_KEY_BREAK(KEY_EXIT): if (s_copyMode) { sub = m_posVert = (s_copyMode == MOVE_MODE || s_copySrcRow<0) ? (MAX_MODELS+sub+s_copyTgtOfs) % MAX_MODELS : s_copySrcRow; s_copyMode = 0; } else if (m_posVert != g_eeGeneral.currModel) { m_posVert = g_eeGeneral.currModel; } else { popMenu(); } break; #if defined(ROTARY_ENCODER_NAVIGATION) case EVT_ROTARY_BREAK: if (s_editMode == -1) { s_editMode = 0; break; } // no break; #endif case EVT_KEY_LONG(KEY_ENTER): case EVT_KEY_BREAK(KEY_ENTER): s_editMode = 0; if (READ_ONLY()) { if (g_eeGeneral.currModel != sub && eeModelExists(sub)) { selectModel(sub); } } else if (s_copyMode && (s_copyTgtOfs || s_copySrcRow>=0)) { displayPopup(s_copyMode==COPY_MODE ? STR_COPYINGMODEL : STR_MOVINGMODEL); eeCheck(true); // force writing of current model data before this is changed uint8_t cur = (MAX_MODELS + sub + s_copyTgtOfs) % MAX_MODELS; if (s_copyMode == COPY_MODE) { if (!eeCopyModel(cur, s_copySrcRow)) { cur = sub; } } s_copySrcRow = g_eeGeneral.currModel; // to update the currModel value while (sub != cur) { uint8_t src = cur; cur = (s_copyTgtOfs > 0 ? cur+MAX_MODELS-1 : cur+1) % MAX_MODELS; eeSwapModels(src, cur); if (src == s_copySrcRow) s_copySrcRow = cur; else if (cur == s_copySrcRow) s_copySrcRow = src; } if (s_copySrcRow != g_eeGeneral.currModel) { g_eeGeneral.currModel = s_copySrcRow; eeDirty(EE_GENERAL); } s_copyMode = 0; event = EVT_ENTRY_UP; } else if (event == EVT_KEY_LONG(KEY_ENTER) || IS_ROTARY_BREAK(event)) { s_copyMode = 0; killEvents(event); #if defined(NAVIGATION_MENUS) if (g_eeGeneral.currModel != sub) { if (eeModelExists(sub)) { MENU_ADD_ITEM(STR_SELECT_MODEL); MENU_ADD_SD_ITEM(STR_BACKUP_MODEL); MENU_ADD_ITEM(STR_COPY_MODEL); MENU_ADD_ITEM(STR_MOVE_MODEL); MENU_ADD_ITEM(STR_DELETE_MODEL); } else { #if defined(SDCARD) MENU_ADD_ITEM(STR_CREATE_MODEL); MENU_ADD_ITEM(STR_RESTORE_MODEL); #else selectModel(sub); #endif } } else { MENU_ADD_SD_ITEM(STR_BACKUP_MODEL); MENU_ADD_ITEM(STR_COPY_MODEL); MENU_ADD_ITEM(STR_MOVE_MODEL); } menuHandler = onModelSelectMenu; #else if (g_eeGeneral.currModel != sub) { selectModel(sub); } #endif } else if (eeModelExists(sub)) { s_copyMode = (s_copyMode == COPY_MODE ? MOVE_MODE : COPY_MODE); s_copyTgtOfs = 0; s_copySrcRow = -1; } break; #if defined(ROTARY_ENCODER_NAVIGATION) case EVT_ROTARY_LEFT: case EVT_ROTARY_RIGHT: #endif case EVT_KEY_FIRST(KEY_LEFT): case EVT_KEY_FIRST(KEY_RIGHT): #if defined(ROTARY_ENCODER_NAVIGATION) if ((!IS_ROTARY_RIGHT(event) && !IS_ROTARY_LEFT(event)) || s_editMode < 0) { #endif if (sub == g_eeGeneral.currModel) { chainMenu((IS_ROTARY_RIGHT(event) || event == EVT_KEY_FIRST(KEY_RIGHT)) ? menuModelSetup : menuTabModel[DIM(menuTabModel)-1]); } else { AUDIO_WARNING2(); } break; #if defined(ROTARY_ENCODER_NAVIGATION) } // no break #endif case EVT_KEY_FIRST(KEY_MOVE_UP): case EVT_KEY_REPT(KEY_MOVE_UP): case EVT_KEY_FIRST(KEY_MOVE_DOWN): case EVT_KEY_REPT(KEY_MOVE_DOWN): if (s_copyMode) { int8_t next_ofs = s_copyTgtOfs + oldSub - m_posVert; if (next_ofs == MAX_MODELS || next_ofs == -MAX_MODELS) next_ofs = 0; if (s_copySrcRow < 0 && s_copyMode==COPY_MODE) { s_copySrcRow = oldSub; // find a hole (in the first empty slot above / below) sub = eeFindEmptyModel(s_copySrcRow, IS_ROTARY_DOWN(event) || event==EVT_KEY_FIRST(KEY_MOVE_DOWN)); if (sub < 0) { // no free room for duplicating the model AUDIO_ERROR(); sub = oldSub; s_copyMode = 0; } next_ofs = 0; m_posVert = sub; } s_copyTgtOfs = next_ofs; } break; } #if !defined(PCBSKY9X) lcd_puts(9*FW-(LEN_FREE-4)*FW, 0, STR_FREE); if (event) reusableBuffer.modelsel.eepromfree = EeFsGetFree(); lcd_outdezAtt(17*FW, 0, reusableBuffer.modelsel.eepromfree, 0); #endif #if defined(ROTARY_ENCODER_NAVIGATION) displayScreenIndex(e_ModelSelect, DIM(menuTabModel), (sub == g_eeGeneral.currModel) ? ((IS_RE_NAVIGATION_ENABLE() && s_editMode < 0) ? INVERS|BLINK : INVERS) : 0); #else displayScreenIndex(e_ModelSelect, DIM(menuTabModel), (sub == g_eeGeneral.currModel) ? INVERS : 0); #endif TITLE(STR_MENUMODELSEL); for (uint8_t i=0; i<LCD_LINES-1; i++) { coord_t y = MENU_HEADER_HEIGHT + 1 + i*FH; uint8_t k = i+s_pgOfs; lcd_outdezNAtt(3*FW+2, y, k+1, LEADING0+((!s_copyMode && sub==k) ? INVERS : 0), 2); if (s_copyMode == MOVE_MODE || (s_copyMode == COPY_MODE && s_copySrcRow >= 0)) { if (k == sub) { if (s_copyMode == COPY_MODE) { k = s_copySrcRow; lcd_putc(MODELSEL_W-FW, y, '+'); } else { k = sub + s_copyTgtOfs; } } else if (s_copyTgtOfs < 0 && ((k < sub && k >= sub+s_copyTgtOfs) || (k-MAX_MODELS < sub && k-MAX_MODELS >= sub+s_copyTgtOfs))) k += 1; else if (s_copyTgtOfs > 0 && ((k > sub && k <= sub+s_copyTgtOfs) || (k+MAX_MODELS > sub && k+MAX_MODELS <= sub+s_copyTgtOfs))) k += MAX_MODELS-1; } k %= MAX_MODELS; if (eeModelExists(k)) { #if defined(PCBSKY9X) putsModelName(4*FW, y, modelHeaders[k].name, k, 0); #else char * name = reusableBuffer.modelsel.listnames[i]; if (event) eeLoadModelName(k, name); putsModelName(4*FW, y, name, k, 0); lcd_outdezAtt(20*FW, y, eeModelSize(k), 0); #endif if (k==g_eeGeneral.currModel && (s_copyMode!=COPY_MODE || s_copySrcRow<0 || i+s_pgOfs!=(vertpos_t)sub)) lcd_putc(1, y, '*'); } if (s_copyMode && (vertpos_t)sub==i+s_pgOfs) { drawFilledRect(9, y, MODELSEL_W-1-9, 7); lcd_rect(8, y-1, MODELSEL_W-1-7, 9, s_copyMode == COPY_MODE ? SOLID : DOTTED); } } }
void menuCustomFunctions(uint8_t event, CustomFunctionData * functions, CustomFunctionsContext * functionsContext) { int8_t sub = menuVerticalPosition - 1; #if defined(CPUARM) uint8_t eeFlags = (functions == g_model.customFn) ? EE_MODEL : EE_GENERAL; #elif !defined(CPUM64) || defined(AUTOSWITCH) uint8_t eeFlags = EE_MODEL; #endif for (uint8_t i=0; i<LCD_LINES-1; i++) { coord_t y = MENU_HEADER_HEIGHT + 1 + i*FH; uint8_t k = i+menuVerticalOffset; CustomFunctionData *cfn = &functions[k]; uint8_t func = CFN_FUNC(cfn); for (uint8_t j=0; j<5; j++) { uint8_t attr = ((sub==k && menuHorizontalPosition==j) ? ((s_editMode>0) ? BLINK|INVERS : INVERS) : 0); uint8_t active = (attr && (s_editMode>0 || p1valdiff)); switch (j) { case 0: putsSwitches(MODEL_CUSTOM_FUNC_1ST_COLUMN, y, CFN_SWITCH(cfn), attr | ((functionsContext->activeSwitches & ((MASK_CFN_TYPE)1 << k)) ? BOLD : 0)); if (active || AUTOSWITCH_ENTER_LONG()) CHECK_INCDEC_SWITCH(event, CFN_SWITCH(cfn), SWSRC_FIRST, SWSRC_LAST, eeFlags, isSwitchAvailableInCustomFunctions); #if defined(CPUARM) if (func == FUNC_OVERRIDE_CHANNEL && functions != g_model.customFn) { func = CFN_FUNC(cfn) = func+1; } #endif break; case 1: if (CFN_SWITCH(cfn)) { lcd_putsiAtt(MODEL_CUSTOM_FUNC_2ND_COLUMN, y, STR_VFSWFUNC, func, attr); if (active) { #if defined(CPUARM) CFN_FUNC(cfn) = checkIncDec(event, CFN_FUNC(cfn), 0, FUNC_MAX-1, eeFlags, isAssignableFunctionAvailable); #else CHECK_INCDEC_MODELVAR_ZERO(event, CFN_FUNC(cfn), FUNC_MAX-1); #endif if (checkIncDec_Ret) CFN_RESET(cfn); } } else { j = 4; // skip other fields if (sub==k && menuHorizontalPosition > 0) { REPEAT_LAST_CURSOR_MOVE(); } } break; case 2: { int8_t maxParam = NUM_CHNOUT-1; #if defined(OVERRIDE_CHANNEL_FUNCTION) if (func == FUNC_OVERRIDE_CHANNEL) { putsChn(lcdNextPos, y, CFN_CH_INDEX(cfn)+1, attr); } else #endif if (func == FUNC_TRAINER) { maxParam = 4; #if defined(CPUARM) putsMixerSource(lcdNextPos, y, CFN_CH_INDEX(cfn)==0 ? 0 : MIXSRC_Rud+CFN_CH_INDEX(cfn)-1, attr); #else putsMixerSource(lcdNextPos, y, MIXSRC_Rud+CFN_CH_INDEX(cfn)-1, attr); #endif } #if defined(GVARS) else if (func == FUNC_ADJUST_GVAR) { maxParam = MAX_GVARS-1; putsStrIdx(lcdNextPos, y, STR_GV, CFN_GVAR_INDEX(cfn)+1, attr); #if defined(CPUARM) if (active) CFN_GVAR_INDEX(cfn) = checkIncDec(event, CFN_GVAR_INDEX(cfn), 0, maxParam, eeFlags); #else if (active) CHECK_INCDEC_MODELVAR_ZERO(event, CFN_GVAR_INDEX(cfn), maxParam); #endif break; } #endif #if defined(CPUARM) else if (func == FUNC_SET_TIMER) { maxParam = MAX_TIMERS-1; lcd_putsiAtt(lcdNextPos, y, STR_VFSWRESET, CFN_TIMER_INDEX(cfn), attr); if (active) CFN_TIMER_INDEX(cfn) = checkIncDec(event, CFN_TIMER_INDEX(cfn), 0, maxParam, eeFlags); break; } #endif else if (attr) { REPEAT_LAST_CURSOR_MOVE(); } if (active) CHECK_INCDEC_MODELVAR_ZERO(event, CFN_CH_INDEX(cfn), maxParam); break; } case 3: { INCDEC_DECLARE_VARS(eeFlags); int16_t val_displayed = CFN_PARAM(cfn); #if defined(CPUARM) int16_t val_min = 0; int16_t val_max = 255; #else int8_t val_min = 0; uint8_t val_max = 255; #endif if (func == FUNC_RESET) { val_max = FUNC_RESET_PARAM_LAST; lcd_putsiAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, STR_VFSWRESET, CFN_PARAM(cfn), attr); } #if defined(OVERRIDE_CHANNEL_FUNCTION) else if (func == FUNC_OVERRIDE_CHANNEL) { #if !defined(CPUARM) val_displayed = (int8_t)CFN_PARAM(cfn); #endif val_min = -LIMIT_EXT_PERCENT; val_max = +LIMIT_EXT_PERCENT; lcd_outdezAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr|LEFT); } #endif #if defined(CPUARM) else if (func >= FUNC_SET_FAILSAFE && func <= FUNC_BIND) { val_max = NUM_MODULES-1; lcd_putsiAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, "\004Int.Ext.", CFN_PARAM(cfn), attr); } #endif #if defined(CPUARM) else if (func == FUNC_SET_TIMER) { val_max = 539*60+59; putsTimer(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr|LEFT, attr); } #endif #if defined(AUDIO) else if (func == FUNC_PLAY_SOUND) { val_max = AU_FRSKY_LAST-AU_FRSKY_FIRST-1; lcd_putsiAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, STR_FUNCSOUNDS, val_displayed, attr); } #endif #if defined(HAPTIC) else if (func == FUNC_HAPTIC) { val_max = 3; lcd_outdezAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr|LEFT); } #endif #if defined(CPUARM) && defined(SDCARD) else if (func == FUNC_PLAY_TRACK || func == FUNC_BACKGND_MUSIC || func == FUNC_PLAY_SCRIPT) { coord_t x = (func == FUNC_PLAY_TRACK ? MODEL_CUSTOM_FUNC_2ND_COLUMN + FW + FW*strlen(TR_PLAY_TRACK) : MODEL_CUSTOM_FUNC_3RD_COLUMN); if (ZEXIST(cfn->play.name)) lcd_putsnAtt(x, y, cfn->play.name, sizeof(cfn->play.name), attr); else lcd_putsiAtt(x, y, STR_VCSWFUNC, 0, attr); if (active && event==EVT_KEY_BREAK(KEY_ENTER)) { s_editMode = 0; char directory[256]; if (func==FUNC_PLAY_SCRIPT) { strcpy(directory, SCRIPTS_FUNCS_PATH); } else { strcpy(directory, SOUNDS_PATH); strncpy(directory+SOUNDS_PATH_LNG_OFS, currentLanguagePack->id, 2); } if (listSdFiles(directory, func==FUNC_PLAY_SCRIPT ? SCRIPTS_EXT : SOUNDS_EXT, sizeof(cfn->play.name), cfn->play.name)) { popupMenuHandler = onCustomFunctionsFileSelectionMenu; } else { POPUP_WARNING(func==FUNC_PLAY_SCRIPT ? STR_NO_SCRIPTS_ON_SD : STR_NO_SOUNDS_ON_SD); popupMenuFlags = 0; } } break; } else if (func == FUNC_PLAY_VALUE) { val_max = MIXSRC_LAST_TELEM; putsMixerSource(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr); INCDEC_ENABLE_CHECK(isSourceAvailable); } #endif #if defined(CPUARM) else if (func == FUNC_VOLUME) { val_max = MIXSRC_LAST_CH; putsMixerSource(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr); INCDEC_SET_FLAG(eeFlags | INCDEC_SOURCE); INCDEC_ENABLE_CHECK(isSourceAvailable); } #elif defined(VOICE) else if (func == FUNC_PLAY_TRACK) { #if defined(GVARS) if (attr && event==EVT_KEY_LONG(KEY_ENTER)) { killEvents(event); s_editMode = !s_editMode; active = true; val_displayed = (val_displayed > 250 ? 0 : 251); } if (val_displayed > 250) { putsStrIdx(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, STR_GV, val_displayed-250, attr); } else { lcd_outdezAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed+PROMPT_CUSTOM_BASE, attr|LEFT); } #else lcd_outdezAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed+PROMPT_CUSTOM_BASE, attr|LEFT); #endif } else if (func == FUNC_PLAY_BOTH) { lcd_putcAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN+3*FWNUM, y, '|', attr); lcd_outdezAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN+3*FWNUM, y, val_displayed+PROMPT_CUSTOM_BASE, attr); lcd_outdezAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN+2+3*FWNUM, y, (val_displayed+PROMPT_CUSTOM_BASE+1)%10, attr|LEFT); } else if (func == FUNC_PLAY_VALUE) { val_max = MIXSRC_FIRST_TELEM + TELEM_DISPLAY_MAX - 1; putsMixerSource(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr); INCDEC_ENABLE_CHECK(functionsContext == &globalFunctionsContext ? isSourceAvailableInGlobalFunctions : isSourceAvailable); } #endif #if defined(SDCARD) else if (func == FUNC_LOGS) { if (val_displayed) { lcd_outdezAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr|PREC1|LEFT); lcd_putc(lcdLastPos, y, 's'); } else { lcd_putsiAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, STR_MMMINV, 0, attr); } } #endif #if defined(GVARS) else if (func == FUNC_ADJUST_GVAR) { switch (CFN_GVAR_MODE(cfn)) { case FUNC_ADJUST_GVAR_CONSTANT: val_displayed = (int16_t)CFN_PARAM(cfn); val_min = -CFN_GVAR_CST_MAX; val_max = +CFN_GVAR_CST_MAX; lcd_outdezAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr|LEFT); break; case FUNC_ADJUST_GVAR_SOURCE: val_max = MIXSRC_LAST_CH; putsMixerSource(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr); INCDEC_SET_FLAG(eeFlags | INCDEC_SOURCE); INCDEC_ENABLE_CHECK(isSourceAvailable); break; case FUNC_ADJUST_GVAR_GVAR: val_max = MAX_GVARS-1; putsStrIdx(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, STR_GV, val_displayed+1, attr); break; default: // FUNC_ADJUST_GVAR_INC val_max = 1; lcd_putsiAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, PSTR("\003-=1+=1"), val_displayed, attr); break; } if (attr && event==EVT_KEY_LONG(KEY_ENTER)) { killEvents(event); s_editMode = !s_editMode; active = true; CFN_GVAR_MODE(cfn) += 1; #if defined(CPUARM) CFN_GVAR_MODE(cfn) &= 0x03; #endif val_displayed = 0; } } #endif else if (attr) { REPEAT_LAST_CURSOR_MOVE(); } if (active) { CFN_PARAM(cfn) = CHECK_INCDEC_PARAM(event, val_displayed, val_min, val_max); } break; } case 4: if (HAS_ENABLE_PARAM(func)) { menu_lcd_onoff(MODEL_CUSTOM_FUNC_4TH_COLUMN_ONOFF, y, CFN_ACTIVE(cfn), attr); #if defined(CPUARM) if (active) CFN_ACTIVE(cfn) = checkIncDec(event, CFN_ACTIVE(cfn), 0, 1, eeFlags); #else if (active) CHECK_INCDEC_MODELVAR_ZERO(event, CFN_ACTIVE(cfn), 1); #endif } else if (HAS_REPEAT_PARAM(func)) { if (CFN_PLAY_REPEAT(cfn) == 0) { lcd_putcAtt(MODEL_CUSTOM_FUNC_4TH_COLUMN_ONOFF+3, y, '-', attr); } #if defined(CPUARM) else if (CFN_PLAY_REPEAT(cfn) == CFN_PLAY_REPEAT_NOSTART) { lcd_putsAtt(MODEL_CUSTOM_FUNC_4TH_COLUMN_ONOFF, y, "!-", attr); } #endif else { lcd_outdezAtt(MODEL_CUSTOM_FUNC_4TH_COLUMN+2+FW, y, CFN_PLAY_REPEAT(cfn)*CFN_PLAY_REPEAT_MUL, attr); } #if defined(CPUARM) if (active) CFN_PLAY_REPEAT(cfn) = checkIncDec(event, CFN_PLAY_REPEAT(cfn)==CFN_PLAY_REPEAT_NOSTART?-1:CFN_PLAY_REPEAT(cfn), -1, 60/CFN_PLAY_REPEAT_MUL, eeFlags); #else if (active) CHECK_INCDEC_MODELVAR_ZERO(event, CFN_PLAY_REPEAT(cfn), 60/CFN_PLAY_REPEAT_MUL); #endif } else if (attr) { REPEAT_LAST_CURSOR_MOVE(); } break; } } } }
void menuModelTelemetry(uint8_t event) { MENU(STR_MENUTELEMETRY, menuTabModel, e_Telemetry, ITEM_TELEMETRY_MAX+1, {0, TELEMETRY_TYPE_ROWS CHANNELS_ROWS RSSI_ROWS SENSORS_ROWS USRDATA_ROWS CASE_VARIO(LABEL(Vario)) CASE_VARIO(0) CASE_VARIO(VARIO_RANGE_ROWS) TELEMETRY_SCREEN_ROWS(0), TELEMETRY_SCREEN_ROWS(1), CASE_CPUARM(TELEMETRY_SCREEN_ROWS(2)) CASE_CPUARM(TELEMETRY_SCREEN_ROWS(3))}); uint8_t sub = m_posVert - 1; switch (event) { case EVT_KEY_BREAK(KEY_DOWN): case EVT_KEY_BREAK(KEY_UP): case EVT_KEY_BREAK(KEY_LEFT): case EVT_KEY_BREAK(KEY_RIGHT): if (s_editMode>0 && sub<=ITEM_TELEMETRY_RSSI_ALARM2) frskySendAlarms(); // update FrSky module when edit mode exited break; } for (uint8_t i=0; i<LCD_LINES-1; i++) { coord_t y = MENU_HEADER_HEIGHT + 1 + i*FH; uint8_t k = i + s_pgOfs; #if defined(CPUARM) for (int j=0; j<=k; j++) { if (mstate_tab[j+1] == HIDDEN_ROW) k++; } #endif uint8_t blink = ((s_editMode>0) ? BLINK|INVERS : INVERS); uint8_t attr = (sub == k ? blink : 0); #if !defined(CPUARM) uint8_t ch = TELEMETRY_CURRENT_EDIT_CHANNEL(k); FrSkyChannelData & channel = g_model.frsky.channels[ch]; uint8_t dest = TELEM_A1-1+ch; #endif #if defined(CPUARM) if (k>=ITEM_TELEMETRY_SENSOR1 && k<ITEM_TELEMETRY_SENSOR1+MAX_SENSORS) { int index = k-ITEM_TELEMETRY_SENSOR1; lcd_outdezAtt(INDENT_WIDTH, y, index+1, LEFT|attr); lcd_putcAtt(lcdLastPos, y, ':', attr); lcd_putsnAtt(3*FW, y, g_model.telemetrySensors[index].label, TELEM_LABEL_LEN, ZCHAR); if (telemetryItems[index].isFresh()) { lcd_putc(16*FW, y, '*'); } TelemetryItem & telemetryItem = telemetryItems[index]; if (telemetryItem.isAvailable()) { bool isOld = telemetryItem.isOld(); lcdNextPos = TELEM_COL2; if (isOld) lcd_putc(lcdNextPos, y, '['); putsTelemetryChannelValue(lcdNextPos, y, index, getValue(MIXSRC_FIRST_TELEM+3*index), LEFT); if (isOld) lcd_putc(lcdLastPos, y, ']'); } else { lcd_putsAtt(TELEM_COL2, y, "---", 0); // TODO shortcut } if (attr) { s_editMode = 0; s_currIdx = index; if (event == EVT_KEY_LONG(KEY_ENTER)) { killEvents(event); MENU_ADD_ITEM(STR_EDIT); MENU_ADD_ITEM(STR_COPY); MENU_ADD_ITEM(STR_DELETE); menuHandler = onSensorMenu; } else if (event == EVT_KEY_BREAK(KEY_ENTER)) { pushMenu(menuModelSensor); } } } else #endif switch (k) { #if defined(CPUARM) case ITEM_TELEMETRY_PROTOCOL_TYPE: g_model.telemetryProtocol = selectMenuItem(TELEM_COL2, y, STR_TELEMETRY_TYPE, "\017FrSky S.PORT\0 FrSky D\0 FrSky D (cable)", g_model.telemetryProtocol, PROTOCOL_TELEMETRY_FIRST, CASE_PCBSKY9X(PROTOCOL_FRSKY_D_SECONDARY) attr, event); break; #endif #if defined(CPUARM) case ITEM_TELEMETRY_SENSORS_LABEL: lcd_putsLeft(y, STR_TELEMETRY_SENSORS); break; case ITEM_TELEMETRY_NEWSENSOR: lcd_putsAtt(0, y, STR_TELEMETRY_NEWSENSOR, attr); if (attr && event==EVT_KEY_BREAK(KEY_ENTER)) { s_editMode = 0; int res = availableTelemetryIndex(); if (res >= 0) { s_currIdx = res; pushMenu(menuModelSensor); } else { POPUP_WARNING(STR_TELEMETRYFULL); } } break; case ITEM_TELEMETRY_IGNORE_SENSORID: ON_OFF_MENU_ITEM(g_model.ignoreSensorIds, TELEM_COL2, y, STR_IGNOREIDS, attr, event); break; #endif #if !defined(CPUARM) case ITEM_TELEMETRY_A1_LABEL: case ITEM_TELEMETRY_A2_LABEL: lcd_putsLeft(y, STR_ACHANNEL); lcd_outdezAtt(2*FW, y, ch+1, 0); putsTelemetryChannelValue(TELEM_COL2+6*FW, y, dest, frskyData.analog[ch].value, LEFT); break; case ITEM_TELEMETRY_A1_RANGE: case ITEM_TELEMETRY_A2_RANGE: lcd_putsLeft(y, STR_RANGE); putsTelemetryChannelValue(TELEM_COL2, y, dest, 255-channel.offset, (m_posHorz<=0 ? attr : 0)|NO_UNIT|LEFT); lcd_putsiAtt(lcdLastPos, y, STR_VTELEMUNIT, channel.type, m_posHorz!=0 ? attr : 0); if (attr && (s_editMode>0 || p1valdiff)) { if (m_posHorz == 0) { uint16_t ratio = checkIncDec(event, channel.ratio, 0, 256, EE_MODEL); if (checkIncDec_Ret) { if (ratio == 127 && channel.multiplier > 0) { channel.multiplier--; channel.ratio = 255; } else if (ratio == 256) { if (channel.multiplier < FRSKY_MULTIPLIER_MAX) { channel.multiplier++; channel.ratio = 128; } } else { channel.ratio = ratio; } } } else { CHECK_INCDEC_MODELVAR_ZERO(event, channel.type, UNIT_A1A2_MAX); } } break; case ITEM_TELEMETRY_A1_OFFSET: case ITEM_TELEMETRY_A2_OFFSET: lcd_putsLeft(y, STR_OFFSET); putsTelemetryChannelValue(TELEM_COL2, y, dest, 0, LEFT|attr); if (attr) channel.offset = checkIncDec(event, channel.offset, -256, 256, EE_MODEL); break; case ITEM_TELEMETRY_A1_ALARM1: case ITEM_TELEMETRY_A1_ALARM2: case ITEM_TELEMETRY_A2_ALARM1: case ITEM_TELEMETRY_A2_ALARM2: { uint8_t alarm = ((k==ITEM_TELEMETRY_A1_ALARM1 || k==ITEM_TELEMETRY_A2_ALARM1) ? 0 : 1); lcd_putsLeft(y, STR_ALARM); lcd_putsiAtt(TELEM_COL2, y, STR_VALARM, ALARM_LEVEL(ch, alarm), m_posHorz<=0 ? attr : 0); lcd_putsiAtt(TELEM_COL2+4*FW, y, STR_VALARMFN, ALARM_GREATER(ch, alarm), (CURSOR_ON_LINE() || m_posHorz==1) ? attr : 0); putsTelemetryChannelValue(TELEM_COL2+6*FW, y, dest, channel.alarms_value[alarm], ((CURSOR_ON_LINE() || m_posHorz==2) ? attr : 0) | LEFT); if (attr && (s_editMode>0 || p1valdiff)) { uint8_t t; switch (m_posHorz) { case 0: t = ALARM_LEVEL(ch, alarm); channel.alarms_level = (channel.alarms_level & ~(3<<(2*alarm))) + (checkIncDecModel(event, t, 0, 3) << (2*alarm)); break; case 1: t = ALARM_GREATER(ch, alarm); if (t != checkIncDecModel(event, t, 0, 1)) { channel.alarms_greater ^= (1 << alarm); frskySendAlarms(); } break; case 2: channel.alarms_value[alarm] = checkIncDec(event, channel.alarms_value[alarm], 0, 255, EE_MODEL); break; } } break; } #endif case ITEM_TELEMETRY_RSSI_LABEL: lcd_putsLeft(y, PSTR("RSSI")); break; case ITEM_TELEMETRY_RSSI_ALARM1: case ITEM_TELEMETRY_RSSI_ALARM2: { uint8_t alarm = k-ITEM_TELEMETRY_RSSI_ALARM1; lcd_putsLeft(y, STR_ALARM); lcd_putsiAtt(TELEM_COL2, y, STR_VALARM, ((2+alarm+g_model.frsky.rssiAlarms[alarm].level)%4), m_posHorz<=0 ? attr : 0); lcd_putc(TELEM_COL2+4*FW, y, '<'); lcd_outdezNAtt(TELEM_COL2+6*FW, y, getRssiAlarmValue(alarm), LEFT|(m_posHorz!=0 ? attr : 0), 3); if (attr && (s_editMode>0 || p1valdiff)) { switch (m_posHorz) { case 0: CHECK_INCDEC_MODELVAR(event, g_model.frsky.rssiAlarms[alarm].level, -3, 2); // circular (saves flash) break; case 1: CHECK_INCDEC_MODELVAR(event, g_model.frsky.rssiAlarms[alarm].value, -30, 30); break; } } break; } #if !defined(CPUARM) #if defined(FRSKY_HUB) || defined(WS_HOW_HIGH) case ITEM_TELEMETRY_USR_LABEL: lcd_putsLeft(y, STR_USRDATA); break; case ITEM_TELEMETRY_USR_PROTO: lcd_putsLeft(y, STR_PROTO); lcd_putsiAtt(TELEM_COL2, y, STR_VTELPROTO, g_model.frsky.usrProto, attr); if (attr) CHECK_INCDEC_MODELVAR_ZERO(event, g_model.frsky.usrProto, USR_PROTO_LAST); break; case ITEM_TELEMETRY_USR_BLADES: lcd_putsLeft(y, STR_BLADES); lcd_outdezAtt(TELEM_COL2+FWNUM, y, 2+g_model.frsky.blades, attr); if (attr) CHECK_INCDEC_MODELVAR_ZERO(event, g_model.frsky.blades, MAX_BLADES); break; #endif case ITEM_TELEMETRY_USR_VOLTAGE_SOURCE: lcd_putsLeft(y, STR_VOLTAGE); lcd_putsiAtt(TELEM_COL2, y, STR_AMPSRC, g_model.frsky.voltsSource+1, attr); if (attr) CHECK_INCDEC_MODELVAR_ZERO(event, g_model.frsky.voltsSource, FRSKY_VOLTS_SOURCE_LAST); break; case ITEM_TELEMETRY_USR_CURRENT_SOURCE: lcd_putsLeft(y, STR_CURRENT); lcd_putsiAtt(TELEM_COL2, y, STR_AMPSRC, g_model.frsky.currentSource, attr); if (attr) CHECK_INCDEC_MODELVAR_ZERO(event, g_model.frsky.currentSource, FRSKY_CURRENT_SOURCE_LAST); break; #if defined(FAS_OFFSET) || !defined(CPUM64) case ITEM_TELEMETRY_FAS_OFFSET: lcd_putsLeft(y, STR_FAS_OFFSET); lcd_outdezAtt(TELEM_COL2, y, g_model.frsky.fasOffset, attr|LEFT|PREC1); lcd_outdezAtt(TELEM_COL2+6*FW, y, frskyData.hub.current, LEFT|PREC1); lcd_putc(TELEM_COL2+8*FW, y, 'A'); if (attr) g_model.frsky.fasOffset = checkIncDec(event, g_model.frsky.fasOffset, -120, 120, EE_MODEL); break; #endif #endif #if defined(VARIO) case ITEM_TELEMETRY_VARIO_LABEL: lcd_putsLeft(y, STR_VARIO); break; case ITEM_TELEMETRY_VARIO_SOURCE: lcd_putsLeft(y, STR_SOURCE); #if defined(CPUARM) putsMixerSource(TELEM_COL2, y, g_model.frsky.varioSource ? MIXSRC_FIRST_TELEM+3*(g_model.frsky.varioSource-1) : 0, attr); if (attr) { g_model.frsky.varioSource = checkIncDec(event, g_model.frsky.varioSource, 0, MAX_SENSORS, EE_MODEL|NO_INCDEC_MARKS, isSensorAvailable); } #else lcd_putsiAtt(TELEM_COL2, y, STR_VARIOSRC, g_model.frsky.varioSource, attr); if (attr) CHECK_INCDEC_MODELVAR(event, g_model.frsky.varioSource, 0, VARIO_SOURCE_LAST); #endif break; case ITEM_TELEMETRY_VARIO_RANGE: lcd_putsLeft(y, STR_LIMIT); #if defined(PCBSTD) lcd_outdezAtt(TELEM_COL2, y, 5+g_model.frsky.varioCenterMax, (m_posHorz==0 ? attr : 0)|PREC1|LEFT); lcd_outdezAtt(TELEM_COL2+8*FW, y, 10+g_model.frsky.varioMax, (m_posHorz==1 ? attr : 0)); if (attr && (s_editMode>0 || p1valdiff)) { switch (m_posHorz) { case 0: CHECK_INCDEC_MODELVAR(event, g_model.frsky.varioCenterMax, -15, +15); break; case 1: CHECK_INCDEC_MODELVAR(event, g_model.frsky.varioMax, -7, 7); break; } } #else lcd_outdezAtt(TELEM_COL2, y, -10+g_model.frsky.varioMin, (m_posHorz<=0 ? attr : 0)|LEFT); lcd_outdezAtt(TELEM_COL2+7*FW-2, y, -5+g_model.frsky.varioCenterMin, ((CURSOR_ON_LINE() || m_posHorz==1) ? attr : 0)|PREC1); lcd_outdezAtt(TELEM_COL2+10*FW, y, 5+g_model.frsky.varioCenterMax, ((CURSOR_ON_LINE() || m_posHorz==2) ? attr : 0)|PREC1); lcd_outdezAtt(TELEM_COL2+13*FW+2, y, 10+g_model.frsky.varioMax, ((CURSOR_ON_LINE() || m_posHorz==3) ? attr : 0)); if (attr && (s_editMode>0 || p1valdiff)) { switch (m_posHorz) { case 0: CHECK_INCDEC_MODELVAR(event, g_model.frsky.varioMin, -7, 7); break; case 1: CHECK_INCDEC_MODELVAR(event, g_model.frsky.varioCenterMin, -16, 5+min<int8_t>(10, g_model.frsky.varioCenterMax+5)); break; case 2: CHECK_INCDEC_MODELVAR(event, g_model.frsky.varioCenterMax, -5+max<int8_t>(-10, g_model.frsky.varioCenterMin-5), +15); break; case 3: CHECK_INCDEC_MODELVAR(event, g_model.frsky.varioMax, -7, 7); break; } } #endif break; #endif case ITEM_TELEMETRY_SCREEN_LABEL1: case ITEM_TELEMETRY_SCREEN_LABEL2: #if defined(CPUARM) case ITEM_TELEMETRY_SCREEN_LABEL3: case ITEM_TELEMETRY_SCREEN_LABEL4: { uint8_t screenIndex = TELEMETRY_CURRENT_EDIT_SCREEN(k); putsStrIdx(0*FW, y, STR_SCREEN, screenIndex+1); TelemetryScreenType oldScreenType = TELEMETRY_SCREEN_TYPE(screenIndex); TelemetryScreenType newScreenType = (TelemetryScreenType)selectMenuItem(TELEM_SCRTYPE_COL, y, PSTR(""), STR_VTELEMSCREENTYPE, oldScreenType, 0, TELEMETRY_SCREEN_TYPE_MAX, (m_posHorz==0 ? attr : 0), event); if (newScreenType != oldScreenType) { g_model.frsky.screensType = (g_model.frsky.screensType & (~(0x03 << (2*screenIndex)))) | (newScreenType << (2*screenIndex)); memset(&g_model.frsky.screens[screenIndex], 0, sizeof(g_model.frsky.screens[screenIndex])); } break; } #else { uint8_t screenIndex = (k < ITEM_TELEMETRY_SCREEN_LABEL2 ? 1 : 2); putsStrIdx(0*FW, y, STR_SCREEN, screenIndex); #if defined(GAUGES) bool screenType = g_model.frsky.screensType & screenIndex; if (screenType != (bool)selectMenuItem(TELEM_SCRTYPE_COL, y, PSTR(""), STR_VTELEMSCREENTYPE, screenType, 0, 1, attr, event)) g_model.frsky.screensType ^= screenIndex; #endif break; } #endif case ITEM_TELEMETRY_SCREEN_LINE1: case ITEM_TELEMETRY_SCREEN_LINE2: case ITEM_TELEMETRY_SCREEN_LINE3: case ITEM_TELEMETRY_SCREEN_LINE4: case ITEM_TELEMETRY_SCREEN_LINE5: case ITEM_TELEMETRY_SCREEN_LINE6: case ITEM_TELEMETRY_SCREEN_LINE7: case ITEM_TELEMETRY_SCREEN_LINE8: #if defined(CPUARM) case ITEM_TELEMETRY_SCREEN_LINE9: case ITEM_TELEMETRY_SCREEN_LINE10: case ITEM_TELEMETRY_SCREEN_LINE11: case ITEM_TELEMETRY_SCREEN_LINE12: case ITEM_TELEMETRY_SCREEN_LINE13: case ITEM_TELEMETRY_SCREEN_LINE14: case ITEM_TELEMETRY_SCREEN_LINE15: case ITEM_TELEMETRY_SCREEN_LINE16: #endif { uint8_t screenIndex, lineIndex; if (k < ITEM_TELEMETRY_SCREEN_LABEL2) { screenIndex = 0; lineIndex = k-ITEM_TELEMETRY_SCREEN_LINE1; } #if defined(CPUARM) else if (k >= ITEM_TELEMETRY_SCREEN_LABEL4) { screenIndex = 3; lineIndex = k-ITEM_TELEMETRY_SCREEN_LINE13; } else if (k >= ITEM_TELEMETRY_SCREEN_LABEL3) { screenIndex = 2; lineIndex = k-ITEM_TELEMETRY_SCREEN_LINE9; } #endif else { screenIndex = 1; lineIndex = k-ITEM_TELEMETRY_SCREEN_LINE5; } #if defined(GAUGES) if (IS_BARS_SCREEN(screenIndex)) { FrSkyBarData & bar = g_model.frsky.screens[screenIndex].bars[lineIndex]; source_t barSource = bar.source; #if defined(CPUARM) putsMixerSource(TELEM_COL1, y, barSource, m_posHorz==0 ? attr : 0); if (barSource) { putsChannelValue(TELEM_BARS_COLMIN, y, barSource, bar.barMin, (m_posHorz==1 ? attr : 0) | LEFT); putsChannelValue(TELEM_BARS_COLMAX, y, barSource, bar.barMax, (m_posHorz==2 ? attr : 0) | LEFT); } #else lcd_putsiAtt(TELEM_COL1, y, STR_VTELEMCHNS, barSource, m_posHorz==0 ? attr : 0); if (barSource) { putsTelemetryChannelValue(TELEM_BARS_COLMIN, y, barSource-1, convertBarTelemValue(barSource, bar.barMin), (m_posHorz==1 ? attr : 0) | LEFT); putsTelemetryChannelValue(TELEM_BARS_COLMAX, y, barSource-1, convertBarTelemValue(barSource, 255-bar.barMax), (m_posHorz==2 ? attr : 0) | LEFT); } #endif else if (attr) { MOVE_CURSOR_FROM_HERE(); } if (attr && (s_editMode>0 || p1valdiff)) { switch (m_posHorz) { case 0: #if defined(CPUARM) bar.source = CHECK_INCDEC_MODELVAR_ZERO_CHECK(event, barSource, MIXSRC_LAST_TELEM, isSourceAvailable); #else bar.source = CHECK_INCDEC_MODELVAR_ZERO(event, barSource, TELEM_DISPLAY_MAX); #endif if (checkIncDec_Ret) { bar.barMin = 0; #if defined(CPUARM) bar.barMax = 0; #else bar.barMax = 255 - maxBarTelemValue(bar.source); #endif } break; case 1: #if defined(CPUARM) bar.barMin = checkIncDec(event, bar.barMin, -30000, bar.barMax, EE_MODEL|NO_INCDEC_MARKS); #else bar.barMin = checkIncDec(event, bar.barMin, 0, 254-bar.barMax, EE_MODEL|NO_INCDEC_MARKS); #endif break; case 2: #if defined(CPUARM) bar.barMax = checkIncDec(event, bar.barMax, bar.barMin, 30000, EE_MODEL|NO_INCDEC_MARKS); #else bar.barMax = 255 - checkIncDec(event, 255-bar.barMax, bar.barMin+1, maxBarTelemValue(barSource), EE_MODEL|NO_INCDEC_MARKS); #endif break; } } } else #endif { for (uint8_t c=0; c<NUM_LINE_ITEMS; c++) { uint8_t cellAttr = (m_posHorz==c ? attr : 0); source_t & value = g_model.frsky.screens[screenIndex].lines[lineIndex].sources[c]; uint8_t pos[] = {INDENT_WIDTH, TELEM_COL2}; #if defined(CPUARM) putsMixerSource(pos[c], y, value, cellAttr); if (cellAttr && (s_editMode>0 || p1valdiff)) { CHECK_INCDEC_MODELVAR_ZERO_CHECK(event, value, MIXSRC_LAST_TELEM, isSourceAvailable); } #else lcd_putsiAtt(pos[c], y, STR_VTELEMCHNS, value, cellAttr); if (cellAttr && (s_editMode>0 || p1valdiff)) { CHECK_INCDEC_MODELVAR_ZERO_CHECK(event, value, (lineIndex==3 && c==0) ? TELEM_STATUS_MAX : TELEM_DISPLAY_MAX, isTelemetrySourceAvailable); } #endif } if (attr && m_posHorz == NUM_LINE_ITEMS) { REPEAT_LAST_CURSOR_MOVE(); } } break; } } } }
void menuCustomFunctions(uint8_t event, CustomFunctionData * functions, CustomFunctionsContext * functionsContext) { int sub = menuVerticalPosition; uint8_t eeFlags = (functions == g_model.customFn) ? EE_MODEL : EE_GENERAL; if (menuHorizontalPosition<0 && event==EVT_KEY_LONG(KEY_ENTER) && !READ_ONLY()) { killEvents(event); CustomFunctionData *cfn = &functions[sub]; if (!CFN_EMPTY(cfn)) POPUP_MENU_ADD_ITEM(STR_COPY); if (clipboard.type == CLIPBOARD_TYPE_CUSTOM_FUNCTION) POPUP_MENU_ADD_ITEM(STR_PASTE); if (!CFN_EMPTY(cfn) && CFN_EMPTY(&functions[NUM_CFN-1])) POPUP_MENU_ADD_ITEM(STR_INSERT); if (!CFN_EMPTY(cfn)) POPUP_MENU_ADD_ITEM(STR_CLEAR); for (int i=sub+1; i<NUM_CFN; i++) { if (!CFN_EMPTY(&functions[i])) { POPUP_MENU_ADD_ITEM(STR_DELETE); break; } } popupMenuHandler = onCustomFunctionsMenu; } for (int i=0; i<NUM_BODY_LINES; i++) { coord_t y = MENU_HEADER_HEIGHT + 1 + i*FH; int k = i+menuVerticalOffset; putsStrIdx(0, y, functions == g_model.customFn ? STR_SF : STR_GF, k+1, (sub==k && menuHorizontalPosition<0) ? INVERS : 0); CustomFunctionData *cfn = &functions[k]; uint8_t func = CFN_FUNC(cfn); for (uint8_t j=0; j<5; j++) { uint8_t attr = ((sub==k && menuHorizontalPosition==j) ? ((s_editMode>0) ? BLINK|INVERS : INVERS) : 0); uint8_t active = (attr && s_editMode>0); switch (j) { case 0: putsSwitches(MODEL_CUSTOM_FUNC_1ST_COLUMN, y, CFN_SWITCH(cfn), attr | ((functionsContext->activeSwitches & ((MASK_CFN_TYPE)1 << k)) ? BOLD : 0)); if (active || AUTOSWITCH_ENTER_LONG()) CHECK_INCDEC_SWITCH(event, CFN_SWITCH(cfn), SWSRC_FIRST, SWSRC_LAST, eeFlags, isSwitchAvailableInCustomFunctions); if (func == FUNC_OVERRIDE_CHANNEL && functions != g_model.customFn) { func = CFN_FUNC(cfn) = func+1; } break; case 1: if (CFN_SWITCH(cfn)) { lcd_putsiAtt(MODEL_CUSTOM_FUNC_2ND_COLUMN, y, STR_VFSWFUNC, func, attr); if (active) { func = CFN_FUNC(cfn) = checkIncDec(event, CFN_FUNC(cfn), 0, FUNC_MAX-1, eeFlags, isAssignableFunctionAvailable); if (checkIncDec_Ret) CFN_RESET(cfn); } } else { j = 4; // skip other fields if (sub==k && menuHorizontalPosition > 0) { REPEAT_LAST_CURSOR_MOVE(); } } break; case 2: { int8_t maxParam = NUM_CHNOUT-1; #if defined(OVERRIDE_CHANNEL_FUNCTION) if (func == FUNC_OVERRIDE_CHANNEL) { putsChn(lcdNextPos, y, CFN_CH_INDEX(cfn)+1, attr); } else #endif if (func == FUNC_TRAINER) { maxParam = 4; putsMixerSource(lcdNextPos, y, CFN_CH_INDEX(cfn)==0 ? 0 : MIXSRC_Rud+CFN_CH_INDEX(cfn)-1, attr); } #if defined(GVARS) else if (func == FUNC_ADJUST_GVAR) { maxParam = MAX_GVARS-1; putsStrIdx(lcdNextPos, y, STR_GV, CFN_GVAR_INDEX(cfn)+1, attr); if (active) CFN_GVAR_INDEX(cfn) = checkIncDec(event, CFN_GVAR_INDEX(cfn), 0, maxParam, eeFlags); break; } #endif else if (func == FUNC_SET_TIMER) { maxParam = TIMERS-1; putsStrIdx(lcdNextPos, y, STR_TIMER, CFN_TIMER_INDEX(cfn)+1, attr); if (active) CFN_TIMER_INDEX(cfn) = checkIncDec(event, CFN_TIMER_INDEX(cfn), 0, maxParam, eeFlags); break; } else if (attr) { REPEAT_LAST_CURSOR_MOVE(); } if (active) CHECK_INCDEC_MODELVAR_ZERO(event, CFN_CH_INDEX(cfn), maxParam); break; } case 3: { INCDEC_DECLARE_VARS(eeFlags); int16_t val_displayed = CFN_PARAM(cfn); int16_t val_min = 0; int16_t val_max = 255; if (func == FUNC_RESET) { val_max = FUNC_RESET_PARAM_FIRST_TELEM+lastUsedTelemetryIndex(); int param = CFN_PARAM(cfn); if (param < FUNC_RESET_PARAM_FIRST_TELEM) { lcd_putsiAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, STR_VFSWRESET, param, attr); } else { TelemetrySensor * sensor = & g_model.telemetrySensors[param-FUNC_RESET_PARAM_FIRST_TELEM]; lcd_putsnAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, sensor->label, TELEM_LABEL_LEN, attr|ZCHAR); } if (active) INCDEC_ENABLE_CHECK(functionsContext == &globalFunctionsContext ? isSourceAvailableInGlobalResetSpecialFunction : isSourceAvailableInResetSpecialFunction); } #if defined(OVERRIDE_CHANNEL_FUNCTION) else if (func == FUNC_OVERRIDE_CHANNEL) { val_min = -LIMIT_EXT_PERCENT; val_max = +LIMIT_EXT_PERCENT; lcd_outdezAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr|LEFT); } #endif else if (func >= FUNC_SET_FAILSAFE && func <= FUNC_BIND) { val_max = NUM_MODULES-1; lcd_putsiAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, "\004Int.Ext.", CFN_PARAM(cfn), attr); } else if (func == FUNC_SET_TIMER) { val_max = 59*60+59; putsTimer(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr|LEFT, attr); } else if (func == FUNC_PLAY_SOUND) { val_max = AU_FRSKY_LAST-AU_FRSKY_FIRST-1; lcd_putsiAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, STR_FUNCSOUNDS, val_displayed, attr); } #if defined(HAPTIC) else if (func == FUNC_HAPTIC) { val_max = 3; lcd_outdezAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr|LEFT); } #endif #if defined(SDCARD) else if (func == FUNC_PLAY_TRACK || func == FUNC_BACKGND_MUSIC || func == FUNC_PLAY_SCRIPT) { coord_t x = MODEL_CUSTOM_FUNC_3RD_COLUMN; if (ZEXIST(cfn->play.name)) lcd_putsnAtt(x, y, cfn->play.name, sizeof(cfn->play.name), attr); else lcd_putsiAtt(x, y, STR_VCSWFUNC, 0, attr); if (active && event==EVT_KEY_BREAK(KEY_ENTER)) { s_editMode = 0; char directory[256]; if (func==FUNC_PLAY_SCRIPT) { strcpy(directory, SCRIPTS_FUNCS_PATH); } else { strcpy(directory, SOUNDS_PATH); strncpy(directory+SOUNDS_PATH_LNG_OFS, currentLanguagePack->id, 2); } if (listSdFiles(directory, func==FUNC_PLAY_SCRIPT ? SCRIPTS_EXT : SOUNDS_EXT, sizeof(cfn->play.name), cfn->play.name)) { popupMenuHandler = onCustomFunctionsFileSelectionMenu; } else { POPUP_WARNING(func==FUNC_PLAY_SCRIPT ? STR_NO_SCRIPTS_ON_SD : STR_NO_SOUNDS_ON_SD); } } break; } else if (func == FUNC_PLAY_VALUE) { val_max = MIXSRC_LAST_TELEM; putsMixerSource(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr); if (active) { INCDEC_SET_FLAG(eeFlags | INCDEC_SOURCE); INCDEC_ENABLE_CHECK(functionsContext == &globalFunctionsContext ? isSourceAvailableInGlobalFunctions : isSourceAvailable); } } #endif else if (func == FUNC_VOLUME) { val_max = MIXSRC_LAST_CH; putsMixerSource(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr); if (active) { INCDEC_SET_FLAG(eeFlags | INCDEC_SOURCE); INCDEC_ENABLE_CHECK(isSourceAvailable); } } else if (func == FUNC_LOGS) { if (val_displayed) { lcd_outdezAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr|PREC1|LEFT); lcd_putc(lcdLastPos, y, 's'); } else { lcd_putsiAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, STR_MMMINV, 0, attr); } } #if defined(REVPLUS) else if (func == FUNC_BACKLIGHT) { displaySlider(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, CFN_PARAM(cfn), 100, attr); if (active) INCDEC_SET_FLAG(eeFlags | NO_INCDEC_MARKS); val_min = 0; val_max = 100; } #endif #if defined(GVARS) else if (func == FUNC_ADJUST_GVAR) { switch (CFN_GVAR_MODE(cfn)) { case FUNC_ADJUST_GVAR_CONSTANT: val_displayed = (int16_t)CFN_PARAM(cfn); val_min = -CFN_GVAR_CST_MAX; val_max = +CFN_GVAR_CST_MAX; lcd_outdezAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr|LEFT); break; case FUNC_ADJUST_GVAR_SOURCE: val_max = MIXSRC_LAST_CH; putsMixerSource(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr); if (active) { INCDEC_SET_FLAG(eeFlags | INCDEC_SOURCE); INCDEC_ENABLE_CHECK(isSourceAvailable); } break; case FUNC_ADJUST_GVAR_GVAR: val_max = MAX_GVARS-1; putsStrIdx(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, STR_GV, val_displayed+1, attr); break; default: // FUNC_ADJUST_GVAR_INC #if 0 // TODO 2.2.X val_min = -100; val_max = +100; if (val_displayed < 0) lcd_putsAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, "-=", attr); else lcd_putsAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, "+=", attr); lcd_outdezAtt(lcdNextPos, y, abs(val_displayed), attr|LEFT); #endif val_max = 1; lcd_putsiAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, PSTR("\003-=1+=1"), val_displayed, attr); break; } } #endif else if (attr) { REPEAT_LAST_CURSOR_MOVE(); } if (active || event==EVT_KEY_LONG(KEY_ENTER)) { CFN_PARAM(cfn) = CHECK_INCDEC_PARAM(event, val_displayed, val_min, val_max); if (func == FUNC_ADJUST_GVAR && attr && event==EVT_KEY_LONG(KEY_ENTER)) { killEvents(event); if (CFN_GVAR_MODE(cfn) != FUNC_ADJUST_GVAR_CONSTANT) POPUP_MENU_ADD_ITEM(STR_CONSTANT); if (CFN_GVAR_MODE(cfn) != FUNC_ADJUST_GVAR_SOURCE) POPUP_MENU_ADD_ITEM(STR_MIXSOURCE); if (CFN_GVAR_MODE(cfn) != FUNC_ADJUST_GVAR_GVAR) POPUP_MENU_ADD_ITEM(STR_GLOBALVAR); if (CFN_GVAR_MODE(cfn) != FUNC_ADJUST_GVAR_INC) POPUP_MENU_ADD_ITEM(STR_INCDEC); popupMenuHandler = onAdjustGvarSourceLongEnterPress; s_editMode = EDIT_MODIFY_FIELD; } } break; } case 4: if (HAS_ENABLE_PARAM(func)) { menu_lcd_onoff(MODEL_CUSTOM_FUNC_4TH_COLUMN_ONOFF, y, CFN_ACTIVE(cfn), attr); if (active) CFN_ACTIVE(cfn) = checkIncDec(event, CFN_ACTIVE(cfn), 0, 1, eeFlags); } else if (HAS_REPEAT_PARAM(func)) { if (CFN_PLAY_REPEAT(cfn) == 0) { lcd_putsAtt(MODEL_CUSTOM_FUNC_4TH_COLUMN+2, y, "1x", attr); } else if (CFN_PLAY_REPEAT(cfn) == CFN_PLAY_REPEAT_NOSTART) { lcd_putcAtt(MODEL_CUSTOM_FUNC_4TH_COLUMN-1, y, '!', attr); lcd_putsAtt(MODEL_CUSTOM_FUNC_4TH_COLUMN+2, y, "1x", attr); } else { lcd_outdezAtt(MODEL_CUSTOM_FUNC_4TH_COLUMN+2+FW, y, CFN_PLAY_REPEAT(cfn)*CFN_PLAY_REPEAT_MUL, attr); lcd_putcAtt(MODEL_CUSTOM_FUNC_4TH_COLUMN+2+FW, y, 's', attr); } if (active) CFN_PLAY_REPEAT(cfn) = checkIncDec(event, CFN_PLAY_REPEAT(cfn)==CFN_PLAY_REPEAT_NOSTART?-1:CFN_PLAY_REPEAT(cfn), -1, 60/CFN_PLAY_REPEAT_MUL, eeFlags); } else if (attr) { REPEAT_LAST_CURSOR_MOVE(); } break; } } } }
void menuStatisticsDebug(uint8_t event) { TITLE(STR_MENUDEBUG); switch(event) { case EVT_KEY_LONG(KEY_ENTER): g_eeGeneral.mAhUsed = 0; g_eeGeneral.globalTimer = 0; eeDirty(EE_GENERAL); sessionTimer = 0; killEvents(event); AUDIO_KEYPAD_UP(); break; case EVT_KEY_FIRST(KEY_ENTER): #if defined(LUA) maxLuaInterval = 0; maxLuaDuration = 0; #endif maxMixerDuration = 0; AUDIO_KEYPAD_UP(); break; #if defined(DEBUG_TRACE_BUFFER) case EVT_KEY_FIRST(KEY_UP): pushMenu(menuTraceBuffer); return; #endif case EVT_KEY_FIRST(KEY_DOWN): chainMenu(menuStatisticsView); break; case EVT_KEY_FIRST(KEY_EXIT): chainMenu(menuMainView); break; } lcd_putsLeft(MENU_DEBUG_Y_FREE_RAM, "Free Mem"); lcd_outdezAtt(MENU_DEBUG_COL1_OFS, MENU_DEBUG_Y_FREE_RAM, getAvailableMemory(), LEFT); lcd_puts(lcdLastPos, MENU_DEBUG_Y_FREE_RAM, "b"); #if defined(LUA) lcd_putsLeft(MENU_DEBUG_Y_LUA, "Lua scripts"); lcd_putsAtt(MENU_DEBUG_COL1_OFS, MENU_DEBUG_Y_LUA+1, "[Duration]", SMLSIZE); lcd_outdezAtt(lcdLastPos, MENU_DEBUG_Y_LUA, 10*maxLuaDuration, LEFT); lcd_putsAtt(lcdLastPos+2, MENU_DEBUG_Y_LUA+1, "[Interval]", SMLSIZE); lcd_outdezAtt(lcdLastPos, MENU_DEBUG_Y_LUA, 10*maxLuaInterval, LEFT); #endif lcd_putsLeft(MENU_DEBUG_Y_MIXMAX, STR_TMIXMAXMS); lcd_outdezAtt(MENU_DEBUG_COL1_OFS, MENU_DEBUG_Y_MIXMAX, DURATION_MS_PREC2(maxMixerDuration), PREC2|LEFT); lcd_puts(lcdLastPos, MENU_DEBUG_Y_MIXMAX, "ms"); lcd_putsLeft(MENU_DEBUG_Y_RTOS, STR_FREESTACKMINB); lcd_putsAtt(MENU_DEBUG_COL1_OFS, MENU_DEBUG_Y_RTOS+1, "[M]", SMLSIZE); lcd_outdezAtt(lcdLastPos, MENU_DEBUG_Y_RTOS, stack_free(0), UNSIGN|LEFT); lcd_putsAtt(lcdLastPos+2, MENU_DEBUG_Y_RTOS+1, "[X]", SMLSIZE); lcd_outdezAtt(lcdLastPos, MENU_DEBUG_Y_RTOS, stack_free(1), UNSIGN|LEFT); lcd_putsAtt(lcdLastPos+2, MENU_DEBUG_Y_RTOS+1, "[A]", SMLSIZE); lcd_outdezAtt(lcdLastPos, MENU_DEBUG_Y_RTOS, stack_free(2), UNSIGN|LEFT); lcd_putsAtt(lcdLastPos+2, MENU_DEBUG_Y_RTOS+1, "[I]", SMLSIZE); lcd_outdezAtt(lcdLastPos, MENU_DEBUG_Y_RTOS, stack_free(255), UNSIGN|LEFT); lcd_puts(3*FW, 7*FH+1, STR_MENUTORESET); lcd_status_line(); }
void menuModelExpoMix(uint8_t expo, uint8_t event) { uint8_t sub = m_posVert; if (s_editMode > 0) s_editMode = 0; uint8_t chn = (expo ? expoAddress(s_currIdx)->chn+1 : mixAddress(s_currIdx)->destCh+1); switch (event) { case EVT_ENTRY: case EVT_ENTRY_UP: s_copyMode = 0; s_copyTgtOfs = 0; break; case EVT_KEY_LONG(KEY_EXIT): if (s_copyMode && s_copyTgtOfs == 0) { deleteExpoMix(expo, s_currIdx); killEvents(event); event = 0; } // no break case EVT_KEY_BREAK(KEY_EXIT): if (s_copyMode) { if (s_copyTgtOfs) { // cancel the current copy / move operation if (s_copyMode == COPY_MODE) { deleteExpoMix(expo, s_currIdx); } else { do { swapExpoMix(expo, s_currIdx, s_copyTgtOfs > 0); s_copyTgtOfs += (s_copyTgtOfs < 0 ? +1 : -1); } while (s_copyTgtOfs != 0); eeDirty(EE_MODEL); } m_posVert = s_copySrcRow; s_copyTgtOfs = 0; } s_copyMode = 0; event = 0; } break; case EVT_KEY_BREAK(KEY_ENTER): if ((!s_currCh || (s_copyMode && !s_copyTgtOfs)) && !READ_ONLY()) { s_copyMode = (s_copyMode == COPY_MODE ? MOVE_MODE : COPY_MODE); s_copySrcIdx = s_currIdx; s_copySrcCh = chn; s_copySrcRow = sub; break; } // no break case EVT_KEY_LONG(KEY_ENTER): killEvents(event); if (s_copyTgtOfs) { s_copyMode = 0; s_copyTgtOfs = 0; } else { if (READ_ONLY()) { if (!s_currCh) { pushMenu(expo ? menuModelExpoOne : menuModelMixOne); } } else { if (s_copyMode) s_currCh = 0; if (s_currCh) { if (reachExpoMixCountLimit(expo)) break; insertExpoMix(expo, s_currIdx); pushMenu(expo ? menuModelExpoOne : menuModelMixOne); s_copyMode = 0; } else { event = 0; s_copyMode = 0; MENU_ADD_ITEM(STR_EDIT); MENU_ADD_ITEM(STR_INSERT_BEFORE); MENU_ADD_ITEM(STR_INSERT_AFTER); MENU_ADD_ITEM(STR_COPY); MENU_ADD_ITEM(STR_MOVE); MENU_ADD_ITEM(STR_DELETE); menuHandler = onExpoMixMenu; } } } break; case EVT_KEY_LONG(KEY_LEFT): case EVT_KEY_LONG(KEY_RIGHT): if (s_copyMode && !s_copyTgtOfs) { if (reachExpoMixCountLimit(expo)) break; s_currCh = chn; if (event == EVT_KEY_LONG(KEY_RIGHT)) { s_currIdx++; m_posVert++; } insertExpoMix(expo, s_currIdx); pushMenu(expo ? menuModelExpoOne : menuModelMixOne); s_copyMode = 0; killEvents(event); } break; case EVT_KEY_FIRST(KEY_MOVE_UP): case EVT_KEY_REPT(KEY_MOVE_UP): case EVT_KEY_FIRST(KEY_MOVE_DOWN): case EVT_KEY_REPT(KEY_MOVE_DOWN): if (s_copyMode) { uint8_t key = (event & 0x1f); uint8_t next_ofs = (key==KEY_MOVE_UP ? s_copyTgtOfs - 1 : s_copyTgtOfs + 1); if (s_copyTgtOfs==0 && s_copyMode==COPY_MODE) { // insert a mix on the same channel (just above / just below) if (reachExpoMixCountLimit(expo)) break; copyExpoMix(expo, s_currIdx); if (key==KEY_MOVE_DOWN) s_currIdx++; else if (sub-s_pgOfs >= 6) s_pgOfs++; } else if (next_ofs==0 && s_copyMode==COPY_MODE) { // delete the mix deleteExpoMix(expo, s_currIdx); if (key==KEY_MOVE_UP) s_currIdx--; } else { // only swap the mix with its neighbor if (!swapExpoMix(expo, s_currIdx, key==KEY_MOVE_UP)) break; eeDirty(EE_MODEL); } s_copyTgtOfs = next_ofs; } break; } if (expo) { lcd_outdezAtt(FW*sizeof(TR_MENUINPUTS)+FW+FW/2, 0, getExpoMixCount(true)); lcd_puts(FW*sizeof(TR_MENUINPUTS)+FW+FW/2, 0, STR_MAX(MAX_EXPOS)); // Value uint8_t index = expoAddress(s_currIdx)->chn; if (!s_currCh) { lcd_outdezAtt(127, 2, calcRESXto1000(anas[index]), PREC1|TINSIZE); } SIMPLE_MENU(STR_MENUINPUTS, menuTabModel, e_InputsAll, s_maxLines); // Gauge if (!s_currCh) { drawGauge(127, 1, 58, 6, anas[index], 1024); } } else { lcd_outdezAtt(FW*sizeof(TR_MIXER)+FW+FW/2, 0, getExpoMixCount(false)); lcd_puts(FW*sizeof(TR_MIXER)+FW+FW/2, 0, STR_MAX(MAX_MIXERS)); // Value uint8_t index = mixAddress(s_currIdx)->destCh; if (!s_currCh) { displayHeaderChannelName(index); lcd_outdezAtt(127, 2, calcRESXto1000(ex_chans[index]), PREC1|TINSIZE); } SIMPLE_MENU(STR_MIXER, menuTabModel, e_MixAll, s_maxLines); // Gauge if (!s_currCh) { drawGauge(127, 1, 58, 6, ex_chans[index], 1024); } } sub = m_posVert; s_currCh = 0; int cur = 0; int i = 0; for (int ch=1; ch<=(expo ? NUM_INPUTS : NUM_CHNOUT); ch++) { void *pointer = NULL; MixData * &md = (MixData * &)pointer; ExpoData * &ed = (ExpoData * &)pointer; coord_t y = MENU_HEADER_HEIGHT+1+(cur-s_pgOfs)*FH; if (expo ? (i<MAX_EXPOS && (ed=expoAddress(i))->chn+1 == ch && EXPO_VALID(ed)) : (i<MAX_MIXERS && (md=mixAddress(i))->srcRaw && md->destCh+1 == ch)) { if (cur-s_pgOfs >= 0 && cur-s_pgOfs < NUM_BODY_LINES) { if (expo) { putsMixerSource(0, y, ch, 0); } else { putsChn(0, y, ch, 0); // show CHx } } uint8_t mixCnt = 0; do { if (s_copyMode) { if (s_copyMode == MOVE_MODE && cur-s_pgOfs >= 0 && cur-s_pgOfs < NUM_BODY_LINES && s_copySrcCh == ch && s_copyTgtOfs != 0 && i == (s_copySrcIdx + (s_copyTgtOfs<0))) { lcd_rect(expo ? 18 : 22, y-1, expo ? LCD_W-18 : LCD_W-22, 9, DOTTED); cur++; y+=FH; } if (s_currIdx == i) { sub = m_posVert = cur; s_currCh = ch; } } else if (sub == cur) { s_currIdx = i; } if (cur-s_pgOfs >= 0 && cur-s_pgOfs < NUM_BODY_LINES) { uint8_t attr = ((s_copyMode || sub != cur) ? 0 : INVERS); if (expo) { GVAR_MENU_ITEM(EXPO_LINE_WEIGHT_POS, y, ed->weight, MIN_EXPO_WEIGHT, 100, attr | (isExpoActive(i) ? BOLD : 0), 0, 0); displayExpoLine(y, ed); if (ed->mode!=3) { lcd_putc(EXPO_LINE_SIDE_POS, y, ed->mode == 2 ? 126 : 127); } } else { if (mixCnt > 0) lcd_putsiAtt(FW, y, STR_VMLTPX2, md->mltpx, 0); putsMixerSource(MIX_LINE_SRC_POS, y, md->srcRaw, 0); gvarWeightItem(MIX_LINE_WEIGHT_POS, y, md, attr | (isMixActive(i) ? BOLD : 0), 0); displayMixLine(y, md); char cs = ' '; if (md->speedDown || md->speedUp) cs = 'S'; if (md->delayUp || md->delayDown) cs = (cs =='S' ? '*' : 'D'); lcd_putc(MIX_LINE_DELAY_POS, y, cs); } if (s_copyMode) { if ((s_copyMode==COPY_MODE || s_copyTgtOfs == 0) && s_copySrcCh == ch && i == (s_copySrcIdx + (s_copyTgtOfs<0))) { /* draw a border around the raw on selection mode (copy/move) */ lcd_rect(expo ? EXPO_LINE_SELECT_POS : 22, y-1, expo ? (LCD_W-EXPO_LINE_SELECT_POS) : (LCD_W-22), 9, s_copyMode == COPY_MODE ? SOLID : DOTTED); } if (cur == sub) { /* invert the raw when it's the current one */ drawFilledRect(expo ? EXPO_LINE_SELECT_POS+1 : 23, y, expo ? (LCD_W-EXPO_LINE_SELECT_POS-2) : (LCD_W-24), 7); } } } cur++; y+=FH; mixCnt++; i++; if (expo) ed++; else md++; } while (expo ? (i<MAX_EXPOS && ed->chn+1 == ch && EXPO_VALID(ed)) : (i<MAX_MIXERS && md->srcRaw && md->destCh+1 == ch)); if (s_copyMode == MOVE_MODE && cur-s_pgOfs >= 0 && cur-s_pgOfs < NUM_BODY_LINES && s_copySrcCh == ch && i == (s_copySrcIdx + (s_copyTgtOfs<0))) { lcd_rect(expo ? EXPO_LINE_SELECT_POS : 22, y-1, expo ? LCD_W-EXPO_LINE_SELECT_POS : LCD_W-22, 9, DOTTED); cur++; y+=FH; } } else { uint8_t attr = 0; if (sub == cur) { s_currIdx = i; s_currCh = ch; if (!s_copyMode) { attr = INVERS; } } if (cur-s_pgOfs >= 0 && cur-s_pgOfs < NUM_BODY_LINES) { if (expo) { putsMixerSource(0, y, ch, attr); } else { putsChn(0, y, ch, attr); // show CHx } if (s_copyMode == MOVE_MODE && s_copySrcCh == ch) { lcd_rect(expo ? EXPO_LINE_SELECT_POS : 22, y-1, expo ? (LCD_W-EXPO_LINE_SELECT_POS) : (LCD_W-22), 9, DOTTED); } } cur++; y+=FH; } } s_maxLines = cur; if (sub >= s_maxLines-1) m_posVert = s_maxLines-1; }