Directory transmitter renamed to radio

This commit is contained in:
Bertrand Songis
2013-12-02 07:13:57 +01:00
parent f4df52a033
commit 942e658c8e
707 changed files with 0 additions and 0 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+417
View File
@@ -0,0 +1,417 @@
/*
* Authors (alphabetical order)
* - Andre Bernet <bernet.andre@gmail.com>
* - Andreas Weitl
* - Bertrand Songis <bsongis@gmail.com>
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
* - Cameron Weeks <th9xer@gmail.com>
* - Erez Raviv
* - Gabriel Birkus
* - Jean-Pierre Parisy
* - Karl Szmutny
* - Michael Blandford
* - Michal Hlavinka
* - Pat Mackenzie
* - Philip Moss
* - Rob Thomson
* - Romolo Manfredini <romolo.manfredini@gmail.com>
* - Thomas Husterer
*
* opentx is based on code named
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
* and the original (and ongoing) project by
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef menus_h
#define menus_h
#define NO_HI_LEN 25
void displayScreenIndex(uint8_t index, uint8_t count, uint8_t attr);
inline void displayColumnHeader(const char **headers, uint8_t index)
{
lcd_putsAtt(17*FW, 0, headers[index], 0);
}
#if !defined(CPUM64)
void displayScrollbar(xcoord_t x, uint8_t y, uint8_t h, uint16_t offset, uint16_t count, uint8_t visible);
#endif
#if LCD_W >= 212
extern uint8_t scrollbar_X;
#define SET_SCROLLBAR_X(x) scrollbar_X = (x);
#else
#define SET_SCROLLBAR_X(x)
#endif
#if LCD_W >= 212
#if defined(TRANSLATIONS_FR)
#define MENU_COLUMNS 1
#define COLUMN_X 0
#else
#define MENU_COLUMNS 2
#endif
#define MENUS_SCROLLBAR_WIDTH 2
#define MENU_COLUMN2_X (8 + LCD_W / 2)
#define lcd_putsColumnLeft(x, y, str) lcd_puts((x > (LCD_W-10*FW-MENUS_SCROLLBAR_WIDTH)) ? MENU_COLUMN2_X : 0, y, str)
#else
#define MENUS_SCROLLBAR_WIDTH 0
#define MENU_COLUMNS 1
#define COLUMN_X 0
#define lcd_putsColumnLeft(x, y, str) lcd_putsLeft(y, str)
#endif
// Menus related stuff ...
#if defined(SDCARD)
typedef uint16_t vertpos_t;
#else
typedef uint8_t vertpos_t;
#endif
#if defined(PCBTARANIS)
typedef uint8_t & check_event_t;
#define horzpos_t int8_t
#else
typedef uint8_t check_event_t;
#define horzpos_t uint8_t
#endif
extern vertpos_t m_posVert;
extern horzpos_t m_posHorz;
extern vertpos_t s_pgOfs;
extern uint8_t s_noHi;
extern uint8_t s_noScroll;
void menu_lcd_onoff(uint8_t x, uint8_t y, uint8_t value, LcdFlags attr);
typedef void (*MenuFuncP)(uint8_t event);
typedef void (*MenuFuncP_PROGMEM)(uint8_t event);
extern const MenuFuncP_PROGMEM menuTabModel[];
extern MenuFuncP g_menuStack[5];
extern uint8_t g_menuStackPtr;
/// goto given Menu, but substitute current menu in menuStack
void chainMenu(MenuFuncP newMenu);
/// goto given Menu, store current menu in menuStack
void pushMenu(MenuFuncP newMenu);
/// return to last menu in menustack
void popMenu();
///deliver address of last menu which was popped from
inline MenuFuncP lastPopMenu()
{
return g_menuStack[g_menuStackPtr+1];
}
void drawPotsBars();
void doMainScreenGraphics();
void menuFirstCalib(uint8_t event);
void onMainViewMenu(const char *result);
void menuMainView(uint8_t event);
void menuGeneralDiagAna(uint8_t event);
#if defined(FRSKY)
void menuTelemetryFrsky(uint8_t event);
#endif
void menuGeneralSetup(uint8_t event);
void menuGeneralCalib(uint8_t event);
void menuModelSelect(uint8_t event);
void menuModelCustomFunctions(uint8_t event);
void menuStatisticsView(uint8_t event);
void menuStatisticsDebug(uint8_t event);
void menuAboutView(uint8_t event);
#if defined(NAVIGATION_POT1)
extern int16_t p1valdiff;
#else
#define p1valdiff 0
#endif
#if defined(NAVIGATION_POT2)
extern int8_t p2valdiff;
#else
#define p2valdiff 0
#endif
extern int8_t checkIncDec_Ret; // global helper vars
#define EDIT_SELECT_MENU -1
#define EDIT_SELECT_FIELD 0
#define EDIT_MODIFY_FIELD 1
#define EDIT_MODIFY_STRING 2
extern int8_t s_editMode; // global editmode
// checkIncDec flags
#define EE_GENERAL 0x01
#define EE_MODEL 0x02
#define NO_INCDEC_MARKS 0x04
#define INCDEC_SWITCH 0x08
#define INCDEC_SOURCE 0x10
#define DBLKEYS_1000 0x20
// mawrow special values
#define TITLE_ROW ((uint8_t)-1)
#define HIDDEN_ROW ((uint8_t)-2)
#if defined(CPUARM)
typedef bool (*IsValueAvailable)(int16_t);
int16_t checkIncDec(uint8_t event, int16_t i_pval, int16_t i_min, int16_t i_max, uint8_t i_flags=0, IsValueAvailable isValueAvailable=NULL);
#else
int16_t checkIncDec(uint8_t event, int16_t i_pval, int16_t i_min, int16_t i_max, uint8_t i_flags=0);
#endif
#if defined(CPUM64)
int8_t checkIncDecModel(uint8_t event, int8_t i_val, int8_t i_min, int8_t i_max);
int8_t checkIncDecModelZero(uint8_t event, int8_t i_val, int8_t i_max);
int8_t checkIncDecGen(uint8_t event, int8_t i_val, int8_t i_min, int8_t i_max);
#else
#define checkIncDecModel(event, i_val, i_min, i_max) checkIncDec(event, i_val, i_min, i_max, EE_MODEL)
#define checkIncDecModelZero(event, i_val, i_max) checkIncDec(event, i_val, 0, i_max, EE_MODEL)
#define checkIncDecGen(event, i_val, i_min, i_max) checkIncDec(event, i_val, i_min, i_max, EE_GENERAL)
#endif
#define CHECK_INCDEC_MODELVAR(event, var, min, max) \
var = checkIncDecModel(event,var,min,max)
#define CHECK_INCDEC_MODELVAR_ZERO(event, var, max) \
var = checkIncDecModelZero(event,var,max)
#if defined(CPUARM)
bool isSwitchAvailable(int16_t swtch);
#define AUTOSWITCH_ENTER_LONG() (attr && event==EVT_KEY_LONG(KEY_ENTER))
#define CHECK_INCDEC_MODELSWITCH(event, var, min, max) \
var = checkIncDec(event,var,min,max,EE_MODEL|INCDEC_SWITCH|NO_INCDEC_MARKS, isSwitchAvailable)
#elif defined(AUTOSWITCH)
#define AUTOSWITCH_ENTER_LONG() (attr && event==EVT_KEY_LONG(KEY_ENTER))
#define CHECK_INCDEC_MODELSWITCH(event, var, min, max) \
var = checkIncDec(event,var,min,max,EE_MODEL|INCDEC_SWITCH)
#else
#define AUTOSWITCH_ENTER_LONG() (0)
#define CHECK_INCDEC_MODELSWITCH CHECK_INCDEC_MODELVAR
#endif
#if defined(CPUARM)
bool isSourceAvailable(int16_t source);
bool isInputSourceAvailable(int16_t source);
#define CHECK_INCDEC_MODELSOURCE(event, var, min, max) \
var = checkIncDec(event,var,min,max,EE_MODEL|INCDEC_SOURCE|NO_INCDEC_MARKS, isSourceAvailable)
#elif defined(AUTOSOURCE)
#define CHECK_INCDEC_MODELSOURCE(event, var, min, max) \
var = checkIncDec(event,var,min,max,EE_MODEL|INCDEC_SOURCE|NO_INCDEC_MARKS)
#else
#define CHECK_INCDEC_MODELSOURCE CHECK_INCDEC_MODELVAR
#endif
#define CHECK_INCDEC_GENVAR(event, var, min, max) \
var = checkIncDecGen(event,var,min,max)
#if defined(PCBTARANIS)
#define NAVIGATION_LINE_BY_LINE 0x40
#else
#define NAVIGATION_LINE_BY_LINE 0
#endif
bool check(check_event_t event, uint8_t curr, const MenuFuncP *menuTab, uint8_t menuTabSize, const pm_uint8_t *subTab, uint8_t subTabMax, vertpos_t maxrow);
bool check_simple(check_event_t event, uint8_t curr, const MenuFuncP *menuTab, uint8_t menuTabSize, vertpos_t maxrow);
bool check_submenu_simple(check_event_t event, uint8_t maxrow);
void title(const pm_char * s);
#define TITLE(str) title(str)
#if defined(CPUARM)
#define MENU_TAB(...) const uint8_t mstate_tab[] = __VA_ARGS__
#else
#define MENU_TAB(...) static const pm_uint8_t mstate_tab[] PROGMEM = __VA_ARGS__
#endif
#define MENU_CHECK(tab, menu, lines_count) \
check(event, menu, tab, DIM(tab), mstate_tab, DIM(mstate_tab)-1, (lines_count)-1)
#define MENU(title, tab, menu, lines_count, ...) \
MENU_TAB(__VA_ARGS__); \
if (!MENU_CHECK(tab, menu, lines_count)) return; \
TITLE(title)
#define SIMPLE_MENU_NOTITLE(tab, menu, lines_count) \
if (!check_simple(event,menu,tab,DIM(tab),(lines_count)-1)) return;
#define SIMPLE_MENU(title, tab, menu, lines_count) \
SIMPLE_MENU_NOTITLE(tab, menu, lines_count); \
TITLE(title)
#define SUBMENU_NOTITLE(lines_count, ...) { \
MENU_TAB(__VA_ARGS__); \
if (!check(event,0,NULL,0,mstate_tab,DIM(mstate_tab)-1,(lines_count)-1)) return; }
#define SUBMENU(title, lines_count, ...) \
MENU_TAB(__VA_ARGS__); \
if (!check(event,0,NULL,0,mstate_tab,DIM(mstate_tab)-1,(lines_count)-1)) return; \
TITLE(title)
#define SIMPLE_SUBMENU_NOTITLE(lines_count) \
if (!check_submenu_simple(event,(lines_count)-1)) return;
#define SIMPLE_SUBMENU(title, lines_count) \
SIMPLE_SUBMENU_NOTITLE(lines_count); \
TITLE(title)
#if defined(CPUARM)
typedef int select_menu_value_t;
#else
typedef int8_t select_menu_value_t;
#endif
select_menu_value_t selectMenuItem(uint8_t x, uint8_t y, const pm_char *label, const pm_char *values, select_menu_value_t value, select_menu_value_t min, select_menu_value_t max, LcdFlags attr, uint8_t event);
uint8_t onoffMenuItem(uint8_t value, uint8_t x, uint8_t y, const pm_char *label, LcdFlags attr, uint8_t event );
int8_t switchMenuItem(uint8_t x, uint8_t y, int8_t value, LcdFlags attr, uint8_t event);
#if defined(CPUARM) && defined(GVARS)
#define GVAR_MENU_ITEM(x, y, v, min, max, lcdattr, editflags, event) gvarMenuItem(x, y, v, min, max, lcdattr, editflags, event)
#else
#define GVAR_MENU_ITEM(x, y, v, min, max, lcdattr, editflags, event) gvarMenuItem(x, y, v, min, max, lcdattr, event)
#endif
#if defined(GVARS)
#if defined(CPUARM)
int16_t gvarMenuItem(uint8_t x, uint8_t y, int16_t value, int16_t min, int16_t max, LcdFlags attr, uint8_t editflags, uint8_t event);
#else
int16_t gvarMenuItem(uint8_t x, uint8_t y, int16_t value, int16_t min, int16_t max, LcdFlags attr, uint8_t event); // @@@ open.20.fsguruh
#endif
#define displayGVar(x, y, v, min, max) GVAR_MENU_ITEM(x, y, v, min, max, 0, 0, 0)
#else
int8_t gvarMenuItem(uint8_t x, uint8_t y, int8_t value, int16_t min, int16_t max, LcdFlags attr, uint8_t event);
#define displayGVar(x, y, v, min, max) lcd_outdez8(x, y, v)
#endif
#define WARNING_TYPE_ASTERISK 0
#define WARNING_TYPE_CONFIRM 1
#define WARNING_TYPE_INPUT 2
extern const pm_char * s_warning;
extern const pm_char * s_warning_info;
extern uint8_t s_warning_info_len;
extern uint8_t s_warning_result;
extern uint8_t s_warning_type;
extern const pm_char * s_global_warning;
#define WARNING_LINE_X 16
#define WARNING_LINE_Y 3*FH
#if LCD_W >= 212
#define WARNING_LINE_LEN 30
#else
#define WARNING_LINE_LEN 20
#endif
void displayBox();
void displayPopup(const pm_char * pstr);
void displayWarning(uint8_t event);
#if defined(CPUARM)
extern void (*popupFunc)(uint8_t event);
extern int16_t s_warning_input_value;
extern int16_t s_warning_input_min;
extern int16_t s_warning_input_max;
#endif
#if defined(CPUARM)
#define DISPLAY_WARNING (*popupFunc)
#define POPUP_WARNING(s) (s_warning = s, popupFunc = displayWarning)
#define POPUP_CONFIRMATION(s) (s_warning = s, s_warning_type = WARNING_TYPE_CONFIRM, popupFunc = displayWarning)
#define POPUP_INPUT(s, func, start, min, max) (s_warning = s, s_warning_type = WARNING_TYPE_INPUT, popupFunc = func, s_warning_input_value = start, s_warning_input_min = min, s_warning_input_max = max)
#else
#define DISPLAY_WARNING displayWarning
#define POPUP_WARNING(s) s_warning = s
#define POPUP_CONFIRMATION(s) (s_warning = s, s_warning_type = WARNING_TYPE_CONFIRM)
#endif
#if defined(SDCARD) || (defined(ROTARY_ENCODER_NAVIGATION) && !defined(CPUM64))
#define NAVIGATION_MENUS
#define MENU_ADD_ITEM(s) s_menu[s_menu_count++] = s
#define MENU_MAX_LINES 6
#if defined(SDCARD)
#define MENU_ADD_SD_ITEM(s) MENU_ADD_ITEM(s)
#else
#define MENU_ADD_SD_ITEM(s)
#endif
#define MENU_LINE_LENGTH (LEN_MODEL_NAME+1)
extern const char *s_menu[MENU_MAX_LINES];
extern uint16_t s_menu_count;
extern uint8_t s_menu_flags;
extern uint16_t s_menu_offset;
const char * displayMenu(uint8_t event);
extern void (*menuHandler)(const char *result);
#else
#define s_menu_count 0
#endif
#if defined(SDCARD)
#define STATUS_LINE_LENGTH 32
extern char statusLineMsg[STATUS_LINE_LENGTH];
void showStatusLine();
void drawStatusLine();
#else
#define drawStatusLine()
#endif
#if defined(PCBTARANIS)
void menuChannelsView(uint8_t event);
void pushMenuTextView(const char *filename);
#endif
#define LABEL(...) (uint8_t)-1
#if defined(PCBTARANIS)
#define KEY_MOVE_UP KEY_PLUS
#define KEY_MOVE_DOWN KEY_MINUS
#define CURSOR_MOVED_LEFT(event) (EVT_KEY_MASK(event) == KEY_PLUS)
#define CURSOR_MOVED_RIGHT(event) (EVT_KEY_MASK(event) == KEY_MINUS)
#define CASE_EVT_ROTARY_MOVE_RIGHT CASE_EVT_ROTARY_LEFT
#define CASE_EVT_ROTARY_MOVE_LEFT CASE_EVT_ROTARY_RIGHT
#define IS_ROTARY_MOVE_RIGHT IS_ROTARY_LEFT
#define IS_ROTARY_MOVE_LEFT IS_ROTARY_RIGHT
#else
#define KEY_MOVE_UP KEY_UP
#define KEY_MOVE_DOWN KEY_DOWN
#define CURSOR_MOVED_LEFT(event) (IS_ROTARY_LEFT(event) || EVT_KEY_MASK(event) == KEY_LEFT)
#define CURSOR_MOVED_RIGHT(event) (IS_ROTARY_RIGHT(event) || EVT_KEY_MASK(event) == KEY_RIGHT)
#define CASE_EVT_ROTARY_MOVE_RIGHT CASE_EVT_ROTARY_RIGHT
#define CASE_EVT_ROTARY_MOVE_LEFT CASE_EVT_ROTARY_LEFT
#define IS_ROTARY_MOVE_RIGHT IS_ROTARY_RIGHT
#define IS_ROTARY_MOVE_LEFT IS_ROTARY_LEFT
#endif
#if defined(PCBTARANIS)
#define REPEAT_LAST_CURSOR_MOVE() { if (CURSOR_MOVED_LEFT(event) || CURSOR_MOVED_RIGHT(event)) putEvent(event); else m_posHorz = 0; }
#define MOVE_CURSOR_FROM_HERE() if (m_posHorz > 0) REPEAT_LAST_CURSOR_MOVE()
#elif defined(ROTARY_ENCODER_NAVIGATION)
#define REPEAT_LAST_CURSOR_MOVE() { if (EVT_KEY_MASK(event) >= 0x0e) putEvent(event); else m_posHorz = 0; }
#define MOVE_CURSOR_FROM_HERE() if (m_posHorz > 0) REPEAT_LAST_CURSOR_MOVE()
#else
#define REPEAT_LAST_CURSOR_MOVE() m_posHorz = 0;
#define MOVE_CURSOR_FROM_HERE() REPEAT_LAST_CURSOR_MOVE()
#endif
#if defined(PCBTARANIS)
#define POS_VERT_INIT (menuTab ? (MAXCOL((uint16_t)1) == 255 ? 2 : 1) : 0)
#define POS_HORZ_INIT(posVert) ((COLATTR(posVert) & NAVIGATION_LINE_BY_LINE) ? -1 : 0)
#define EDIT_MODE_INIT 0 // TODO enum
#else
#define POS_VERT_INIT 0
#define POS_HORZ_INIT(posVert) 0
#define EDIT_MODE_INIT -1
#endif
#endif
+177
View File
@@ -0,0 +1,177 @@
/*
* Authors (alphabetical order)
* - Andre Bernet <bernet.andre@gmail.com>
* - Andreas Weitl
* - Bertrand Songis <bsongis@gmail.com>
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
* - Cameron Weeks <th9xer@gmail.com>
* - Erez Raviv
* - Gabriel Birkus
* - Jean-Pierre Parisy
* - Karl Szmutny
* - Michael Blandford
* - Michal Hlavinka
* - Pat Mackenzie
* - Philip Moss
* - Rob Thomson
* - Romolo Manfredini <romolo.manfredini@gmail.com>
* - Thomas Husterer
*
* opentx is based on code named
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
* and the original (and ongoing) project by
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include "../opentx.h"
#if defined(PCBTARANIS)
const pm_uchar about_bmp[] PROGMEM = {
#include "../bitmaps/about_taranis.lbm"
};
#else
const pm_uchar about_bmp[] PROGMEM = {
#include "../bitmaps/about_9x.lbm"
};
#endif
enum AboutScreens {
ABOUT_OPENTX,
ABOUT_BERTRAND,
ABOUT_MIKE,
ABOUT_ROMOLO,
ABOUT_ANDRE,
ABOUT_ROB,
ABOUT_MARTIN,
ABOUT_HARDWARE,
ABOUT_PARENTS,
ABOUT_END,
ABOUT_COUNT,
};
#if defined(PCBTARANIS)
#define ABOUT_X 62
#define ABOUT_INDENT 6
#else
#define ABOUT_X 2
#define ABOUT_INDENT 4
#endif
void menuAboutView(uint8_t event)
{
static uint8_t screenIndex;
static uint8_t greyIndex;
switch(event)
{
case EVT_ENTRY:
screenIndex = 0;
greyIndex = 0;
break;
case EVT_KEY_FIRST(KEY_DOWN):
screenIndex < ABOUT_PARENTS ? screenIndex++ : screenIndex = ABOUT_OPENTX;
greyIndex = 0;
break;
case EVT_KEY_FIRST(KEY_UP):
screenIndex > ABOUT_OPENTX ? screenIndex-- : screenIndex = ABOUT_PARENTS;
greyIndex = 0;
break;
case EVT_KEY_FIRST(KEY_EXIT):
chainMenu(menuMainView);
return;
}
#if defined(PCBTARANIS)
lcd_bmp(0, 0, about_bmp);
lcd_putsAtt(64, 0, STR_ABOUTUS, DBLSIZE);
lcd_hline(ABOUT_X, 18, 120);
lcd_hline(ABOUT_X, 19, 130, GREY_DEFAULT);
LcdFlags att = GREY(max(0, 15-greyIndex/2));
#else
lcd_putsAtt(17, 0, STR_ABOUTUS, DBLSIZE|INVERS);
lcd_hline(17, 16, LCD_W-17);
lcd_img(8, 0, about_bmp, 0);
LcdFlags att = 0;
#endif
uint8_t screenDuration = 150;
switch (screenIndex) {
case ABOUT_OPENTX:
case ABOUT_END:
lcd_putsAtt(ABOUT_X, 22, STR_ABOUT_OPENTX_1, SMLSIZE);
lcd_putsAtt(ABOUT_X, 30, STR_ABOUT_OPENTX_2, SMLSIZE);
lcd_putsAtt(ABOUT_X, 38, STR_ABOUT_OPENTX_3, SMLSIZE);
lcd_putsAtt(ABOUT_X, 46, STR_ABOUT_OPENTX_4, SMLSIZE);
lcd_putsAtt(ABOUT_X, 54, STR_ABOUT_OPENTX_5, SMLSIZE);
screenDuration = 255;
break;
case ABOUT_BERTRAND:
lcd_putsAtt(ABOUT_X, 24, STR_ABOUT_BERTRAND_1, att);
lcd_putsAtt(ABOUT_X+ABOUT_INDENT, 36, STR_ABOUT_BERTRAND_2, att|SMLSIZE);
lcd_putsAtt(ABOUT_X+ABOUT_INDENT, 44, STR_ABOUT_BERTRAND_3, att|SMLSIZE);
break;
case ABOUT_MIKE:
lcd_putsAtt(ABOUT_X, 24, STR_ABOUT_MIKE_1, att);
lcd_putsAtt(ABOUT_X+ABOUT_INDENT, 36, STR_ABOUT_MIKE_2, att|SMLSIZE);
lcd_putsAtt(ABOUT_X+ABOUT_INDENT, 44, STR_ABOUT_MIKE_3, att|SMLSIZE);
lcd_putsAtt(ABOUT_X+ABOUT_INDENT-1, 52, STR_ABOUT_MIKE_4, att|SMLSIZE);
break;
case ABOUT_ROMOLO:
lcd_putsAtt(ABOUT_X, 24, STR_ABOUT_ROMOLO_1, att);
lcd_putsAtt(ABOUT_X+ABOUT_INDENT, 36, STR_ABOUT_ROMOLO_2, att|SMLSIZE);
lcd_putsAtt(ABOUT_X+ABOUT_INDENT, 44, STR_ABOUT_ROMOLO_3, att|SMLSIZE);
break;
case ABOUT_ANDRE:
lcd_putsAtt(ABOUT_X, 24, STR_ABOUT_ANDRE_1, att);
lcd_putsAtt(ABOUT_X+ABOUT_INDENT, 36, STR_ABOUT_ANDRE_2, att|SMLSIZE);
lcd_putsAtt(ABOUT_X+ABOUT_INDENT, 44, STR_ABOUT_ANDRE_3, att|SMLSIZE);
break;
case ABOUT_ROB:
lcd_putsAtt(ABOUT_X, 24, STR_ABOUT_ROB_1, att);
lcd_putsAtt(ABOUT_X+ABOUT_INDENT, 36, STR_ABOUT_ROB_2, att|SMLSIZE);
break;
case ABOUT_MARTIN:
lcd_putsAtt(ABOUT_X, 24, STR_ABOUT_MARTIN_1, att);
lcd_putsAtt(ABOUT_X+ABOUT_INDENT, 36, STR_ABOUT_MARTIN_2, att|SMLSIZE);
break;
case ABOUT_HARDWARE:
lcd_putsAtt(ABOUT_X, 24, STR_ABOUT_HARDWARE_1, att);
lcd_putsAtt(ABOUT_X+ABOUT_INDENT, 36, STR_ABOUT_HARDWARE_2, att|SMLSIZE);
lcd_putsAtt(ABOUT_X+ABOUT_INDENT, 44, STR_ABOUT_HARDWARE_3, att|SMLSIZE);
break;
case ABOUT_PARENTS:
lcd_putsAtt(ABOUT_X, 24, STR_ABOUT_PARENTS_1, att);
lcd_putsAtt(ABOUT_X+ABOUT_INDENT, 36, STR_ABOUT_PARENTS_2, att|SMLSIZE);
lcd_putsAtt(ABOUT_X+ABOUT_INDENT, 44, STR_ABOUT_PARENTS_3, att|SMLSIZE);
lcd_putsAtt(ABOUT_X+ABOUT_INDENT-1, 52, STR_ABOUT_PARENTS_4, att|SMLSIZE);
screenDuration = 255;
break;
}
if (++greyIndex == screenDuration) {
greyIndex = 0;
if (++screenIndex == ABOUT_COUNT) {
chainMenu(menuMainView);
}
}
}
+116
View File
@@ -0,0 +1,116 @@
/*
* Authors (alphabetical order)
* - Andre Bernet <bernet.andre@gmail.com>
* - Andreas Weitl
* - Bertrand Songis <bsongis@gmail.com>
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
* - Cameron Weeks <th9xer@gmail.com>
* - Erez Raviv
* - Gabriel Birkus
* - Jean-Pierre Parisy
* - Karl Szmutny
* - Michael Blandford
* - Michal Hlavinka
* - Pat Mackenzie
* - Philip Moss
* - Rob Thomson
* - Romolo Manfredini <romolo.manfredini@gmail.com>
* - Thomas Husterer
*
* opentx is based on code named
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
* and the original (and ongoing) project by
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include "../opentx.h"
void menuChannelsView(uint8_t event)
{
static bool longNames = false;
bool newLongNames = false;
static bool secondPage = false;
uint8_t ch;
switch(event)
{
case EVT_KEY_BREAK(KEY_EXIT):
popMenu();
return;
case EVT_KEY_FIRST(KEY_RIGHT):
case EVT_KEY_FIRST(KEY_LEFT):
secondPage = !secondPage;
break;
}
if (secondPage)
ch = 16;
else
ch = 0;
lcd_putsCenter(0*FH, CHANNELS_MONITOR);
lcd_invert_line(0);
// Column separator
lcd_vline(LCD_W/2, FH, LCD_H-FH);
for (uint8_t col=0; col<2; col++) {
uint8_t x = col*LCD_W/2+1;
// Channels
for (uint8_t line=0; line<8; line++) {
uint8_t y = 9+line*7;
int32_t val = channelOutputs[ch];
uint8_t ofs = (col ? 0 : 1);
// Channel name if present, number if not
uint8_t lenLabel = ZLEN(g_model.limitData[ch].name);
if (lenLabel > 4) {
newLongNames = longNames = true;
}
if (lenLabel > 0)
lcd_putsnAtt(x+1-ofs, y, g_model.limitData[ch].name, sizeof(g_model.limitData[ch].name), ZCHAR | SMLSIZE);
else
putsChn(x+1-ofs, y, ch+1, SMLSIZE);
// Value
#if defined(PPM_UNIT_US)
uint8_t wbar = (longNames ? 54 : 64);
lcd_outdezAtt(x+LCD_W/2-3-wbar-ofs, y+1, PPM_CH_CENTER(ch)+val/2, TINSIZE);
#elif defined(PPM_UNIT_PERCENT_PREC1)
uint8_t wbar = (longNames ? 48 : 58);
lcd_outdezAtt(x+LCD_W/2-3-wbar-ofs, y+1, calcRESXto1000(val), PREC1|TINSIZE);
#else
uint8_t wbar = (longNames ? 54 : 64);
lcd_outdezAtt(x+LCD_W/2-3-wbar-ofs, y+1, calcRESXto1000(val)/10, TINSIZE); // G: Don't like the decimal part*
#endif
// Gauge
lcd_rect(x+LCD_W/2-3-wbar-ofs, y, wbar+1, 6);
uint16_t lim = g_model.extendedLimits ? 640*2 : 512*2;
uint8_t len = limit((uint8_t)1, uint8_t((abs(val) * wbar/2 + lim/2) / lim), uint8_t(wbar/2));
uint8_t x0 = (val>0) ? x+LCD_W/2-ofs-3-wbar/2 : x+LCD_W/2-ofs-2-wbar/2-len;
lcd_hline(x0, y+1, len);
lcd_hline(x0, y+2, len);
lcd_hline(x0, y+3, len);
lcd_hline(x0, y+4, len);
ch++;
}
}
longNames = newLongNames;
}
+866
View File
@@ -0,0 +1,866 @@
/*
* Authors (alphabetical order)
* - Andre Bernet <bernet.andre@gmail.com>
* - Andreas Weitl
* - Bertrand Songis <bsongis@gmail.com>
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
* - Cameron Weeks <th9xer@gmail.com>
* - Erez Raviv
* - Gabriel Birkus
* - Jean-Pierre Parisy
* - Karl Szmutny
* - Michael Blandford
* - Michal Hlavinka
* - Pat Mackenzie
* - Philip Moss
* - Rob Thomson
* - Romolo Manfredini <romolo.manfredini@gmail.com>
* - Thomas Husterer
*
* opentx is based on code named
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
* and the original (and ongoing) project by
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include "../opentx.h"
#if LCD_W >= 212
#define BIGSIZE MIDSIZE
#define BOX_WIDTH 31
#define BOX_CENTERY (LCD_H-BOX_WIDTH/2-10)
#define LBOX_CENTERX (BOX_WIDTH/2 + 17)
#define RBOX_CENTERX (LCD_W-LBOX_CENTERX)
#define MODELNAME_X (15)
#define MODELNAME_Y (11)
#define VBATT_X (MODELNAME_X+26)
#define VBATT_Y (FH+3)
#define VBATTUNIT_X (VBATT_X-2)
#define VBATTUNIT_Y VBATT_Y
#define BITMAP_X ((LCD_W-64)/2)
#define BITMAP_Y (LCD_H/2)
#define PHASE_X BITMAP_X
#define PHASE_Y (3*FH)
#define PHASE_FLAGS (0)
#define TIMERS_X 145
#define TIMER1_Y 20
#define TIMER2_Y 45
#define TIMERS_R 193
#define REBOOT_X (LCD_W-FW)
#define VSWITCH_X(i) (((i>=NUM_CSW*3/4) ? BITMAP_X+28 : ((i>=NUM_CSW/2) ? BITMAP_X+25 : ((i>=NUM_CSW/4) ? 21 : 18))) + 3*i)
#define VSWITCH_Y (LCD_H-9)
#define BAR_HEIGHT (31-9)
#define TRIM_LH_X (32+9)
#define TRIM_LV_X 10
#define TRIM_RV_X (LCD_W-11)
#define TRIM_RH_X (LCD_W-32-9)
#else
#define BIGSIZE DBLSIZE
#define BOX_WIDTH 23
#define BOX_CENTERY (LCD_H-9-BOX_WIDTH/2)
#define LBOX_CENTERX (LCD_W/4 + 10)
#define RBOX_CENTERX (3*LCD_W/4 - 10)
#define MODELNAME_X (2*FW-2)
#define MODELNAME_Y (0)
#define PHASE_X (6*FW)
#define PHASE_Y (2*FH)
#define PHASE_FLAGS 0
#define VBATT_X (6*FW)
#define VBATT_Y (2*FH)
#define VBATTUNIT_X (VBATT_X-1)
#define VBATTUNIT_Y (3*FH)
#define REBOOT_X (20*FW-3)
#define VSWITCH_X(i) (16 + 3*i)
#define VSWITCH_Y (LCD_H-8)
#define BAR_HEIGHT (BOX_WIDTH-1l)
#define TRIM_LH_X (LCD_W*1/4+2)
#define TRIM_LV_X 3
#define TRIM_RV_X (LCD_W-4)
#define TRIM_RH_X (LCD_W*3/4-2)
#endif
#define TRIM_LEN 27
#define MARKER_WIDTH 5
#define BOX_LIMIT (BOX_WIDTH-MARKER_WIDTH)
#if defined(PCBTARANIS)
const pm_uchar logo_taranis[] PROGMEM = {
#include "../bitmaps/logo_taranis.lbm"
};
const pm_uchar icons[] PROGMEM = {
#include "../bitmaps/icons.lbm"
};
#define ICON_RSSI 0, 9
#define ICON_SPEAKER0 9, 8
#define ICON_SPEAKER1 17, 8
#define ICON_SPEAKER2 25, 8
#define ICON_SPEAKER3 33, 8
#define ICON_SD 41, 11
#define ICON_LOGS 51, 11
#define ICON_TRAINER 61, 11
#define ICON_TRAINEE 71, 11
#define ICON_USB 81, 11
#define ICON_REBOOT 91, 11
#define ICON_ALTITUDE 102, 9
#endif
void drawPotsBars()
{
// Optimization by Mike Blandford
uint8_t x, y, len ; // declare temporary variables
for (x=LCD_W/2-5, y=NUM_STICKS; y<NUM_STICKS+NUM_POTS; x+=5, y++) {
len = ((calibratedStick[y]+RESX)*BAR_HEIGHT/(RESX*2))+1l; // calculate once per loop
V_BAR(x, LCD_H-8, len)
}
}
void drawStick(uint8_t centrex, int16_t xval, int16_t yval)
{
lcd_square(centrex-BOX_WIDTH/2, BOX_CENTERY-BOX_WIDTH/2, BOX_WIDTH);
DO_CROSS(centrex, BOX_CENTERY, 3);
lcd_square(centrex + (xval/((2*RESX)/BOX_LIMIT)) - MARKER_WIDTH/2, BOX_CENTERY - (yval/((2*RESX)/BOX_LIMIT)) - MARKER_WIDTH/2, MARKER_WIDTH, ROUND);
}
void doMainScreenGraphics()
{
int16_t calibStickVert = calibratedStick[CONVERT_MODE(1)];
if (g_model.throttleReversed && CONVERT_MODE(1) == THR_STICK)
calibStickVert = -calibStickVert;
drawStick(LBOX_CENTERX, calibratedStick[CONVERT_MODE(0)], calibStickVert);
calibStickVert = calibratedStick[CONVERT_MODE(2)];
if (g_model.throttleReversed && CONVERT_MODE(2) == THR_STICK)
calibStickVert = -calibStickVert;
drawStick(RBOX_CENTERX, calibratedStick[CONVERT_MODE(3)], calibStickVert);
#if !defined(PCBTARANIS)
drawPotsBars();
#endif
}
void displayTrims(uint8_t phase)
{
for (uint8_t i=0; i<4; i++) {
static xcoord_t x[4] = {TRIM_LH_X, TRIM_LV_X, TRIM_RV_X, TRIM_RH_X};
static uint8_t vert[4] = {0,1,1,0};
uint8_t xm, ym;
xm = x[CONVERT_MODE(i)];
uint8_t att = ROUND;
int16_t val = getTrimValue(phase, i);
if (val < -125 || val > 125)
att = BLINK|INVERS|ROUND;
if (val < -(TRIM_LEN+1)*4)
val = -(TRIM_LEN+1);
else if (val > (TRIM_LEN+1)*4)
val = TRIM_LEN+1;
else
val /= 4;
if (vert[i]) {
ym = 31;
lcd_vline(xm, ym-TRIM_LEN, TRIM_LEN*2);
if (i!=2 || !g_model.thrTrim) {
lcd_vline(xm-1, ym-1, 3);
lcd_vline(xm+1, ym-1, 3);
}
ym -= val;
}
else {
ym = 60;
lcd_hline(xm-TRIM_LEN, ym, TRIM_LEN*2);
lcd_hline(xm-1, ym-1, 3);
lcd_hline(xm-1, ym+1, 3);
xm += val;
}
lcd_square(xm-3, ym-3, 7, att);
}
}
#if defined(PCBTARANIS)
void displaySliders()
{
for (uint8_t i=NUM_STICKS; i<NUM_STICKS+NUM_POTS; i++) {
xcoord_t x = (i%2 ? LCD_W-5 : 3);
int8_t y = (i>NUM_STICKS+1 ? LCD_H/2+1 : 1);
lcd_vline(x, y, LCD_H/2-2);
lcd_vline(x+1, y, LCD_H/2-2);
y += LCD_H/2-4;
y -= ((calibratedStick[i]+RESX)*(LCD_H/2-4)/(RESX*2)); // calculate once per loop
lcd_vline(x-1, y, 2);
lcd_vline(x+2, y, 2);
}
}
#define BAR_X 14
#define BAR_Y 1
#define BAR_W 184
#define BAR_H 9
#define BAR_NOTIFS_X BAR_X+133
#define BAR_VOLUME_X BAR_X+147
#define BAR_TIME_X BAR_X+168
void displayTopBarGauge(xcoord_t x, int count, bool blinking=false)
{
if (!blinking || BLINK_ON_PHASE)
lcd_filled_rect(x+1, BAR_Y+2, 11, 5, SOLID, ERASE);
count = min(10, count);
for (int i=0; i<count; i+=2)
lcd_vline(x+2+i, BAR_Y+3, 3);
}
#define LCD_NOTIF_ICON(x, icon) \
lcd_bmp(x, BAR_Y, icons, icon); \
lcd_hline(x, BAR_Y+8, 11)
void displayTopBar()
{
uint8_t batt_icon_x;
uint8_t altitude_icon_x;
/* Tx voltage */
putsVBat(BAR_X+2, BAR_Y+1, LEFT);
batt_icon_x = lcdLastPos;
lcd_rect(batt_icon_x+FW, BAR_Y+1, 13, 7);
lcd_vline(batt_icon_x+FW+13, BAR_Y+2, 5);
if (frskyData.rssi[0].value > 0) {
/* RSSI */
LCD_ICON(batt_icon_x+3*FW+3, BAR_Y, ICON_RSSI);
lcd_rect(batt_icon_x+5*FW, BAR_Y+1, 13, 7);
/* Rx voltage */
lcdint_t voltage = 0;
uint8_t channel = 0;
if (g_model.frsky.voltsSource <= 1) {
channel = TELEM_A1+g_model.frsky.voltsSource-1;
voltage = frskyData.analog[g_model.frsky.voltsSource].value;
}
else if (g_model.frsky.voltsSource == 2) {
channel = TELEM_VFAS-1;
voltage = frskyData.hub.vfas;
}
else if (g_model.frsky.voltsSource == 3) {
channel = TELEM_CELLS_SUM-1;
voltage = frskyData.hub.cellsSum;
}
if (voltage > 0) {
putsTelemetryChannel(batt_icon_x+7*FW+2, BAR_Y+1, channel, voltage, LEFT);
altitude_icon_x = lcdLastPos+1;
}
else {
altitude_icon_x = batt_icon_x+7*FW+3;
}
/* Altitude */
if (g_model.frsky.altitudeDisplayed && frskyData.hub.baroAltitudeOffset) {
LCD_ICON(altitude_icon_x, BAR_Y, ICON_ALTITUDE);
putsTelemetryValue(altitude_icon_x+2*FW-1, BAR_Y+1, TELEMETRY_ALT_BP, UNIT_METERS, LEFT);
}
}
/* Notifs icons */
xcoord_t x = BAR_NOTIFS_X;
if (unexpectedShutdown) {
LCD_NOTIF_ICON(x, ICON_REBOOT);
x -= 12;
}
if (usbPlugged()) {
LCD_NOTIF_ICON(x, ICON_USB);
x -= 12;
}
if (TRAINER_CONNECTED() && SLAVE_MODE()) {
LCD_NOTIF_ICON(x, ICON_TRAINEE);
x -= 12;
}
else if (TRAINER_CONNECTED() && !SLAVE_MODE()) {
LCD_NOTIF_ICON(x, ICON_TRAINER);
x -= 12;
}
if (isFunctionActive(FUNC_LOGS)) {
LCD_NOTIF_ICON(x, ICON_LOGS);
x -= 12;
}
/* SD ICON, not really needed
if (sdMounted()) {
LCD_NOTIF_ICON(x, ICON_SD);
} */
/* Audio volume */
if (requiredSpeakerVolume == 0)
LCD_ICON(BAR_VOLUME_X, BAR_Y, ICON_SPEAKER0);
else if (requiredSpeakerVolume < 10)
LCD_ICON(BAR_VOLUME_X, BAR_Y, ICON_SPEAKER1);
else if (requiredSpeakerVolume < 20)
LCD_ICON(BAR_VOLUME_X, BAR_Y, ICON_SPEAKER2);
else
LCD_ICON(BAR_VOLUME_X, BAR_Y, ICON_SPEAKER3);
/* RTC time */
struct gtm t;
gettime(&t);
lcd_putcAtt(BAR_TIME_X-1, BAR_Y+1, ':', BLINK);
lcd_outdezNAtt(BAR_TIME_X+1, BAR_Y+1, t.tm_hour, LEADING0, 2);
lcd_outdezNAtt(BAR_TIME_X+3*FWNUM-1, BAR_Y+1, t.tm_min, LEADING0, 2);
/* The background */
lcd_filled_rect(BAR_X, BAR_Y, BAR_W, BAR_H, SOLID, FILL_WHITE|GREY_DEFAULT|ROUND);
/* The inside of the Batt gauge */
int count = 10 * (g_vbat100mV - g_eeGeneral.vBatMin - 90) / (30 + g_eeGeneral.vBatMax - g_eeGeneral.vBatMin);
displayTopBarGauge(batt_icon_x+FW, count, g_vbat100mV <= g_eeGeneral.vBatWarn);
/* The inside of the RSSI gauge */
if (frskyData.rssi[0].value > 0) {
displayTopBarGauge(batt_icon_x+5*FW, frskyData.rssi[0].value / 10, frskyData.rssi[0].value < getRssiAlarmValue(0));
}
}
#endif
#if LCD_W >= 212
void displayTimers()
{
// Main timer
if (g_model.timers[0].mode) {
TimerState & timerState = timersStates[0];
putsTime(TIMERS_X, TIMER1_Y, timerState.val, MIDSIZE|LEFT, MIDSIZE|LEFT);
putsTmrMode(TIMERS_X, TIMER1_Y-6, g_model.timers[0].mode, STRCONDENSED|SMLSIZE);
if (g_model.timers[0].persistent) lcd_putcAtt(TIMERS_R, TIMER1_Y+1, 'P', SMLSIZE);
if (timerState.val < 0) {
if (BLINK_ON_PHASE) {
lcd_filled_rect(TIMERS_X-7, TIMER1_Y-7, 60, 19);
}
}
}
// Second timer
if (g_model.timers[1].mode) {
TimerState & timerState = timersStates[1];
putsTime(TIMERS_X, TIMER2_Y, timerState.val, MIDSIZE|LEFT, MIDSIZE|LEFT);
putsTmrMode(TIMERS_X, TIMER2_Y-6, g_model.timers[1].mode, STRCONDENSED|SMLSIZE);
if (g_model.timers[1].persistent) lcd_putcAtt(TIMERS_R, TIMER2_Y+1, 'P', SMLSIZE);
if (timerState.val < 0) {
if (BLINK_ON_PHASE) {
lcd_filled_rect(TIMERS_X-7, TIMER2_Y-7, 60, 19);
}
}
}
}
#else
void displayTimers()
{
// Main timer
if (g_model.timers[0].mode) {
TimerState & timerState = timersStates[0];
uint8_t att = DBLSIZE | (timerState.val<0 ? BLINK|INVERS : 0);
putsTime(12*FW+2+10*FWNUM-4, FH*2, timerState.val, att, att);
putsTmrMode(timerState.val >= 0 ? 9*FW-FW/2+3 : 9*FW-FW/2-4, FH*3, g_model.timers[0].mode, STRCONDENSED);
}
}
#endif
void displayBattVoltage()
{
#if defined(BATTGRAPH)
putsVBat(VBATT_X-8, VBATT_Y+1, 0);
lcd_filled_rect(VBATT_X-25, VBATT_Y+9, 22, 5);
lcd_vline(VBATT_X-3, VBATT_Y+10, 3);
uint8_t count = limit<uint8_t>(2, 20 * (g_vbat100mV - g_eeGeneral.vBatMin - 90) / (30 + g_eeGeneral.vBatMax - g_eeGeneral.vBatMin), 20);
for (uint8_t i=0; i<count; i+=2)
lcd_vline(VBATT_X-24+i, VBATT_Y+10, 3);
if (g_vbat100mV > g_eeGeneral.vBatWarn || BLINK_ON_PHASE)
lcd_filled_rect(VBATT_X-26, VBATT_Y, 25, 15);
#else
LcdFlags att = (g_vbat100mV <= g_eeGeneral.vBatWarn ? BLINK|INVERS : 0) | BIGSIZE;
putsVBat(VBATT_X-1, VBATT_Y, att|NO_UNIT);
#if LCD_W >= 212
lcd_putcAtt(VBATTUNIT_X, VBATTUNIT_Y, 'v', MIDSIZE);
#else
lcd_putc(VBATT_X, VBATTUNIT_Y, 'V');
#endif
#endif
}
#if defined(PCBSKY9X)
void displayVoltageOrAlarm()
{
if (g_vbat100mV > g_eeGeneral.vBatWarn && g_eeGeneral.temperatureWarn && getTemperature() >= g_eeGeneral.temperatureWarn) {
putsTelemetryValue(6*FW-1, 3*FH, getTemperature(), UNIT_DEGREES, BLINK|INVERS|DBLSIZE);
}
else if (g_vbat100mV > g_eeGeneral.vBatWarn && g_eeGeneral.mAhWarn && (g_eeGeneral.mAhUsed + Current_used * (488 + g_eeGeneral.currentCalib)/8192/36) / 500 >= g_eeGeneral.mAhWarn) {
putsTelemetryValue(7*FW-1, 3*FH, (g_eeGeneral.mAhUsed + Current_used*(488 + g_eeGeneral.currentCalib)/8192/36)/10, UNIT_MAH, BLINK|INVERS|DBLSIZE);
}
else {
displayBattVoltage();
}
}
#else
#define displayVoltageOrAlarm() displayBattVoltage()
#endif
#if defined(PCBTARANIS)
#define EVT_KEY_MODEL_MENU EVT_KEY_BREAK(KEY_MENU)
#define EVT_KEY_GENERAL_MENU EVT_KEY_LONG(KEY_MENU)
#define EVT_KEY_TELEMETRY EVT_KEY_LONG(KEY_PAGE)
#define EVT_KEY_CONTEXT_MENU EVT_KEY_LONG(KEY_ENTER)
#else
#define EVT_KEY_MODEL_MENU EVT_KEY_LONG(KEY_RIGHT)
#define EVT_KEY_GENERAL_MENU EVT_KEY_LONG(KEY_LEFT)
#define EVT_KEY_TELEMETRY EVT_KEY_LONG(KEY_DOWN)
#define EVT_KEY_STATISTICS EVT_KEY_LONG(KEY_UP)
#define EVT_KEY_CONTEXT_MENU EVT_KEY_BREAK(KEY_MENU)
#endif
#if defined(PCBTARANIS)
void menuMainViewChannelsMonitor(uint8_t event)
{
switch(event) {
case EVT_KEY_BREAK(KEY_PAGE):
case EVT_KEY_BREAK(KEY_EXIT):
chainMenu(menuMainView);
return;
}
return menuChannelsView(event);
}
#endif
#if defined(NAVIGATION_MENUS)
void onMainViewMenu(const char *result)
{
if (result == STR_RESET_TIMER1) {
resetTimer(0);
}
else if (result == STR_RESET_TIMER2) {
resetTimer(1);
}
#if defined(FRSKY)
else if (result == STR_RESET_TELEMETRY) {
resetTelemetry();
}
#endif
else if (result == STR_RESET_FLIGHT) {
resetAll();
}
else if (result == STR_STATISTICS) {
chainMenu(menuStatisticsView);
}
#if defined(CPUARM)
else if (result == STR_ABOUT_US) {
chainMenu(menuAboutView);
}
#endif
}
#endif
void menuMainView(uint8_t event)
{
STICK_SCROLL_DISABLE();
#if !defined(PCBTARANIS)
uint8_t view = g_eeGeneral.view;
uint8_t view_base = view & 0x0f;
#endif
uint8_t _event = event;
if (s_global_warning) {
event = 0;
}
switch(event)
{
case EVT_ENTRY:
killEvents(KEY_EXIT);
killEvents(KEY_UP);
killEvents(KEY_DOWN);
break;
#if !defined(PCBTARANIS)
/* 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;
#endif
#if defined(NAVIGATION_MENUS)
case EVT_KEY_CONTEXT_MENU:
killEvents(event);
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);
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*/
#if !defined(PCBTARANIS)
case EVT_KEY_LONG(KEY_MENU):// go to last menu
pushMenu(lastPopMenu());
killEvents(event);
break;
#endif
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
#if defined(PCBTARANIS)
case EVT_KEY_BREAK(KEY_PAGE):
eeDirty(EE_GENERAL);
g_eeGeneral.view += 1;
if (g_eeGeneral.view >= VIEW_COUNT) {
g_eeGeneral.view = 0;
chainMenu(menuMainViewChannelsMonitor);
return;
}
break;
#else
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;
#endif
#if !defined(PCBTARANIS)
case EVT_KEY_STATISTICS:
chainMenu(menuStatisticsView);
killEvents(event);
return;
#endif
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);
return;
case EVT_KEY_FIRST(KEY_EXIT):
if (s_global_warning) {
s_global_warning = NULL;
}
#if defined(GVARS) && !defined(PCBSTD)
else if (s_gvar_timer > 0) {
s_gvar_timer = 0;
}
#endif
#if !defined(PCBTARANIS)
else if (view == VIEW_TIMER2) {
resetTimer(1);
}
#endif
AUDIO_KEYPAD_UP();
break;
#if !defined(NAVIGATION_MENUS)
case EVT_KEY_LONG(KEY_EXIT):
resetAll();
AUDIO_KEYPAD_UP();
break;
#endif
}
{
// Flight Phase Name
uint8_t phase = s_perout_flight_phase;
lcd_putsnAtt(PHASE_X, PHASE_Y, g_model.phaseData[phase].name, sizeof(g_model.phaseData[phase].name), ZCHAR|PHASE_FLAGS);
// Model Name
putsModelName(MODELNAME_X, MODELNAME_Y, g_model.header.name, g_eeGeneral.currModel, BIGSIZE);
#if !defined(PCBTARANIS)
// Main Voltage (or alarm if any)
displayVoltageOrAlarm();
// Timers
displayTimers();
#endif
// Trims sliders
displayTrims(phase);
}
#if defined(PCBTARANIS)
// Top bar
displayTopBar();
// Sliders (Pots / Sliders)
displaySliders();
lcd_bmp(BITMAP_X, BITMAP_Y, modelBitmap);
// Switches
for (uint8_t i=0; i<8; i++) {
getvalue_t sw;
getvalue_t val;
// TODO simplify this + reuse code in checkSwitches() + Menu MODELSETUP
switch(i) {
case 5:
sw = getValue(MIXSRC_SF) > 0 ? 3*i+2 : 3*i+1;
break;
case 6:
val = getValue(MIXSRC_SG);
sw = ((val < 0) ? 3*i : ((val == 0) ? 3*i+1 : 3*i+2));
break;
case 7:
sw = getValue(MIXSRC_SH) > 0 ? 3*i+1 : 3*i;
break;
default:
{
val = getValue(MIXSRC_SA+i);
sw = ((val < 0) ? 3*i+1 : ((val == 0) ? 3*i+2 : 3*i+3));
break;
}
}
putsSwitches((g_eeGeneral.view == VIEW_INPUTS) ? (i<4 ? 8*FW+3 : 24*FW+1) : (i<4 ? 3*FW+2 : 8*FW-1), (i%4)*FH+3*FH, sw, 0);
}
if (g_eeGeneral.view == VIEW_TIMERS) {
displayTimers();
}
else if (g_eeGeneral.view == VIEW_INPUTS) {
// Sticks
doMainScreenGraphics();
}
else {
// Custom Switches
uint8_t sw = 0;
for (uint8_t line=0; line<4; line++) {
for (uint8_t col=0; col<8; col++) {
uint8_t x = LCD_W/2+7*FW+col*FW;
uint8_t y = LCD_H/2-7+line*8;
lcd_putcAtt(x, y, sw>=9 ? 'A'+sw-9 : '1'+sw, SMLSIZE);
if (getSwitch(SWSRC_SW1+sw))
lcd_filled_rect(x-1, y-1, 6, 8);
sw++;
}
}
}
#else // PCBTARANIS
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(PCBGRUVIN9X) && 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
// Custom Switches
#if defined(PCBSKY9X)
for (uint8_t i=0; i<NUM_CSW; 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(PCBGRUVIN9X) && ROTARY_ENCODERS > 2
for (uint8_t i=0; i<NUM_CSW; i++)
putsSwitches(2*FW-2 + (i/3)*(4*FW-2) + (i/3>1 ? 3*FW+6 : 0), 4*FH+1 + (i%3)*FH, SWSRC_SW1+i, getSwitch(SWSRC_SW1+i) ? INVERS : 0);
#elif defined(PCBGRUVIN9X)
for (uint8_t i=0; i<NUM_CSW; i++)
putsSwitches(2*FW-2 + (i/3)*(4*FW-2) + (i/3>1 ? 3*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_CSW; 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_CSW; i++)
putsSwitches(2*FW-2 + (i/3)*(5*FW), 4*FH+1 + (i%3)*FH, SWSRC_SW1+i, getSwitch(SWSRC_SW1+i) ? INVERS : 0);
#endif
}
}
else { // timer2
putsTime(33+FW+2+10*FWNUM-4, FH*5, timersStates[1].val, DBLSIZE, DBLSIZE);
putsTmrMode(timersStates[1].val >= 0 ? 20-FW/2+5 : 20-FW/2-2, FH*6, g_model.timers[1].mode, STRCONDENSED);
// lcd_outdezNAtt(33+11*FW, FH*6, s_timerVal_10ms[1], LEADING0, 2); // 1/100s
}
#endif // PCBTARANIS
#if !defined(PCBTARANIS)
// And ! in case of unexpected shutdown
if (unexpectedShutdown) {
lcd_putcAtt(REBOOT_X, 0*FH, '!', INVERS);
}
#endif
if (s_global_warning) {
s_warning = s_global_warning;
displayWarning(_event);
if (!s_warning) s_global_warning = NULL;
s_warning = NULL;
}
#if defined(GVARS) && !defined(PCBSTD)
else if (s_gvar_timer > 0) {
s_gvar_timer--;
#if LCD_W >= 212
lcd_filled_rect(BITMAP_X, BITMAP_Y, 64, 32, SOLID, ERASE);
lcd_rect(BITMAP_X, BITMAP_Y, 64, 32);
putsStrIdx(BITMAP_X+FW, BITMAP_Y+FH-1, STR_GV, s_gvar_last+1);
lcd_putsnAtt(BITMAP_X+4*FW+FW/2, BITMAP_Y+FH-1, g_model.gvars[s_gvar_last].name, LEN_GVAR_NAME, ZCHAR);
lcd_putsAtt(BITMAP_X+FW, BITMAP_Y+2*FH+3, PSTR("[\010]"), BOLD);
lcd_outdezAtt(BITMAP_X+5*FW+FW/2, BITMAP_Y+2*FH+3, GVAR_VALUE(s_gvar_last, s_perout_flight_phase), BOLD);
#else
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, s_perout_flight_phase), BOLD);
s_warning = NULL;
#endif
}
#endif
#if defined(DSM2)
if (dsm2Flag == DSM2_BIND_FLAG) // Issue 98
lcd_putsAtt(15*FW, 0, PSTR("BIND"), 0);
#endif
}
+534
View File
@@ -0,0 +1,534 @@
/*
* Authors (alphabetical order)
* - Andre Bernet <bernet.andre@gmail.com>
* - Andreas Weitl
* - Bertrand Songis <bsongis@gmail.com>
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
* - Cameron Weeks <th9xer@gmail.com>
* - Erez Raviv
* - Gabriel Birkus
* - Gerard Valade <gerard.valade@gmail.com>
* - Jean-Pierre Parisy
* - Karl Szmutny
* - Michael Blandford
* - Michal Hlavinka
* - Pat Mackenzie
* - Philip Moss
* - Rienk de Jong
* - Rob Thomson
* - Romolo Manfredini <romolo.manfredini@gmail.com>
* - Thomas Husterer
*
* opentx is based on code named
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
* and the original (and ongoing) project by
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*! \file view_mavlink.cpp
* Mavlink menu
* Contains the menu specific code for Mavlink support.
*/
#include "gui/view_mavlink.h"
// Globals declaration
/*! \brief Top Mavlink Menu definition
* \details Registers button events and handles that info. Buttons select menus,
* these are launched from the MAVLINK_menu switch statement. Setup menu is
* lanuched by the menu button. On exit (with exit button) the mavlink
* extension is reinitialized.
*/
void menuTelemetryMavlink(uint8_t event) {
switch (event) // new event received, branch accordingly
{
case EVT_ENTRY:
MAVLINK_menu = MENU_INFO;
break;
case EVT_KEY_FIRST(KEY_UP):
if (MAVLINK_menu > 0)
{
MAVLINK_menu--;
break;
}
else
{
chainMenu(menuMainView);
return;
}
case EVT_KEY_FIRST(KEY_DOWN):
if (MAVLINK_menu < MAX_MAVLINK_MENU - 1)
MAVLINK_menu++;
break;
case EVT_KEY_FIRST(KEY_MENU):
return;
case EVT_KEY_FIRST(KEY_EXIT):
chainMenu(menuMainView);
return;
}
switch (MAVLINK_menu) {
case MENU_INFO:
menuTelemetryMavlinkInfos();
break;
case MENU_MODE:
menuTelemetryMavlinkFlightMode();
break;
case MENU_BATT:
menuTelemetryMavlinkBattery();
break;
case MENU_NAV:
menuTelemetryMavlinkNavigation();
break;
case MENU_GPS:
menuTelemetryMavlinkGPS();
break;
#ifdef DUMP_RX_TX
case MENU_DUMP_TX:
case MENU_DUMP_RX:
menuTelemetryMavlinkDump(event);
break;
#endif
default:
break;
}
}
/*! \brief Float variable display helper
* \param x x position on the screen
* \param y y position on the screen
* \param val value to display
* \param percis precision to display
* \param mode Use one of the defines in lcd.h line 81
* \details The maximum value is 9999. The position is the position of the ones, see below for explanation "*" marks
* the x position.
* \verbatim
*
9999.9999 \endverbatim
*/
void lcd_outdezFloat(uint8_t x, uint8_t y, float val, uint8_t precis, uint8_t mode) {
char c;
int16_t lnum = val;
uint8_t x1 = x;
val -= lnum;
uint8_t xinc = FWNUM;
if (mode & DBLSIZE)
xinc *= 2;
int8_t i = 0;
lnum = abs(lnum);
for (; i < 4; i++) {
c = (lnum % 10) + '0';
x1 -= xinc;
lcd_putcAtt(x1, y, c, mode);
lnum /= 10;
if (lnum == 0) {
break;
}
}
if (lnum != 0) {
// Error number too big
x1 = x;
for (i = 0; i < 4; i++) {
x1 -= FW;
lcd_putcAtt(x1, y, '?', mode);
}
} else {
if (val < 0) {
val = -val;
x1 -= xinc;
lcd_putcAtt(x1, y, '-', mode);
}
if (precis)
{
uint8_t y_temp = y;
if (mode & DBLSIZE)
y_temp += FH;
lcd_putcAtt(x, y_temp, '.', (mode & (~DBLSIZE)));
x -= (xinc / 2);
}
for (i = 0; i < precis; i++) {
val *= 10;
int a = val;
c = a + '0';
x += xinc;
lcd_putcAtt(x, y, c, mode);
val -= a;
}
}
}
/*! \brief Fightmode string printer
* \details Decodes the flight mode from Mavlink custom mode enum to a string.
* This funtion can handle ArduPilot and ArduCoper code.
* To support new autopilot pilots add a STR_MAVLINK_... to the translations,
* and if requred a lut (see arduplane for examle) if there are unused modes
* in the sequence.
*/
void print_mav_mode(uint8_t x, uint8_t y, uint32_t custom_mode, uint8_t attr) //, const char * mode_text_p)
{
uint8_t mode = (uint8_t) custom_mode;
switch (telemetry_data.type_autopilot) {
case MAVLINK_ARDUCOPTER:
lcd_putsiAtt(x,y,STR_MAVLINK_AC_MODES,mode,attr);
break;
case MAVLINK_ARDUPLANE:
lcd_putsiAtt(x,y,STR_MAVLINK_AP_MODES,ap_modes_lut[custom_mode],attr);
break;
default:
lcd_putsAtt (FW, y, PSTR("INV. MAV TYPE"), attr);
break;
}
}
/*! \brief Menu header
* \details Small helper function to print the standard header on the screen.
*/
void mav_title(const pm_char * s, uint8_t index)
{
lcd_putsAtt(0, 0, PSTR("MAVLINK"), INVERS);
lcd_puts(10 * FW, 0, s);
displayScreenIndex(index, MAX_MAVLINK_MENU, INVERS);
lcd_putc(7 * FW, 0, (mav_heartbeat > 0) ? '*' : ' ');
if (telemetry_data.active)
lcd_putcAtt(8 * FW, 0, 'A', BLINK);
}
/*! \brief Global info menu
* \details Quick status overview menu. The menu should contain current mode,
* armed | disarmed, battery status and RSSI info. Menu must be clean and
* readable with a quick glance.
* \todo Make menu as described as above.
*/
void menuTelemetryMavlinkInfos(void) {
mav_title(STR_MAVLINK_INFOS, MAVLINK_menu);
uint8_t x1, x2, xnum, y;
x1 = FW;
x2 = 7 * FW;
xnum = x2 + 5 * FWNUM;
y = FH;
/*
char * ptr = mav_statustext;
for (uint8_t j = 0; j < LEN_STATUSTEXT; j++) {
if (*ptr == 0) {
lcd_putc(x1, y, ' ');
} else {
lcd_putc(x1, y, *ptr++);
}
x1 += FW;
}
x1 = FW;
y += FH;
*/
if (telemetry_data.status) {
lcd_putsnAtt(x1, y, STR_MAVLINK_MODE, 4, 0);
if (telemetry_data.active)
lcd_putsnAtt(x2, y, PSTR("A"), 1, 0);
lcd_outdezAtt(xnum, y, telemetry_data.mode, 0);
y += FH;
lcd_puts(x1, y, PSTR("BATT"));
lcd_outdezNAtt(xnum, y, telemetry_data.vbat, PREC1, 5);
y += FH;
lcd_puts(x1, y, PSTR("DROP"));
lcd_outdezAtt(xnum, y, telemetry_data.packet_drop, 0);
/* y += FH;
lcd_puts(x1, y, PSTR("FIX"));
lcd_outdezAtt(xnum, y, telemetry_data.packet_fixed, 0);
y += FH;
lcd_puts(x1, y, PSTR("MAV Comp"));
lcd_outdezAtt(xnum, y, telemetry_data.mav_compid, 0);
y += FH;
lcd_puts(x1, y, PSTR("MAV Sys"));
lcd_outdezAtt(xnum, y, telemetry_data.mav_sysid, 0);
y += FH;
lcd_puts(x1, y, PSTR("Rad Comp"));
lcd_outdezAtt(xnum, y, telemetry_data.radio_compid, 0);
y += FH;
lcd_puts(x1, y, PSTR("Rad Sys"));
lcd_outdezAtt(xnum, y, telemetry_data.radio_sysid, 0);
*/
}
}
/*! \brief Flight mode menu
* \details Clear display of current flight mode.
* \todo Add functionality to change flight mode.
*/
void menuTelemetryMavlinkFlightMode(void) {
mav_title(STR_MAVLINK_MODE, MAVLINK_menu);
uint8_t x, y;
x = 0;
y = FH;
lcd_puts (x, y, STR_MAVLINK_CUR_MODE);
y += FH;
print_mav_mode(FW, y, telemetry_data.custom_mode, DBLSIZE);
y += 2 * FH;
char * ptr = mav_statustext;
for (uint8_t j = 0; j < LEN_STATUSTEXT; j++) {
if (*ptr == 0) {
lcd_putc(x, y, ' ');
} else {
lcd_putc(x, y, *ptr++);
}
x += FW;
}
y += FH;
x = 0;
if (telemetry_data.active)
lcd_putsAtt (FW, y, STR_MAVLINK_ARMED, DBLSIZE);
}
/*! \brief Batterystatus dislplay
* \details Shows flight batery status.
* Also RC and PC RSSI are in this menu.
*/
void menuTelemetryMavlinkBattery(void) {
mav_title(STR_MAVLINK_BAT_MENU_TITLE, MAVLINK_menu);
uint8_t x, y, ynum;
x = 7 * FWNUM;
// x = xnum + 0 * FW;
ynum = 2 * FH;
y = 3 * FH;
lcd_puts(0, 1*FH, STR_MAVLINK_BATTERY_LABEL);
lcd_outdezAtt(x, ynum, telemetry_data.vbat, (DBLSIZE | PREC1 | UNSIGN));
lcd_puts(x, y, PSTR("V"));
x += 4 * (2 * FWNUM);
lcd_outdezAtt(x, ynum, telemetry_data.ibat, (DBLSIZE | PREC1 | UNSIGN));
lcd_puts(x, y, PSTR("A"));
x += 4 * (2 * FWNUM);
lcd_outdezAtt(x, ynum, telemetry_data.rem_bat, (DBLSIZE | UNSIGN));
lcd_puts(x, y, PSTR("%"));
y += FH;
ynum += 3 * FH;
x = 0;
lcd_puts (x, y, STR_MAVLINK_RC_RSSI_LABEL);
lcd_outdezAtt(x + 7 * FWNUM, ynum, telemetry_data.rc_rssi, (DBLSIZE | UNSIGN));
lcd_puts(x + 7 * FWNUM, ynum + FH, PSTR("%"));
if (g_model.mavlink.pc_rssi_en)
{
x += 8 * (2 * FWNUM);
lcd_puts(x, y, STR_MAVLINK_PC_RSSI_LABEL);
lcd_outdezAtt(x + 7 * FWNUM, ynum, telemetry_data.pc_rssi, (DBLSIZE));
lcd_puts(x + 7 * FWNUM, ynum + FH, PSTR("%"));
}
}
/*! \brief Navigation dislplay
* \details Shows Navigation telemetry.
* Altitude in this menu is the relative (to the home location) altitude. This
* is the same altitude used by the waypoints.
* \todo Add a similar menu to fly back to the home location.
*/
void menuTelemetryMavlinkNavigation(void) {
mav_title(STR_MAVLINK_NAV_MENU_TITLE, MAVLINK_menu);
uint8_t x, y, ynum;
x = 7 * FWNUM;
// x = xnum + 0 * FW;
ynum = 2 * FH;
y = FH;
x = 0;
lcd_puts (x, y, STR_MAVLINK_COURSE);
lcd_outdezAtt(x + 7 * FWNUM, ynum, telemetry_data.course, (DBLSIZE | UNSIGN));
lcd_puts(x + 7 * FWNUM, ynum, PSTR("o"));
x += 8 * (2 * FWNUM);
lcd_puts(x, y, STR_MAVLINK_HEADING);
lcd_outdezAtt(x + 7 * FWNUM, ynum, telemetry_data.heading, (DBLSIZE | UNSIGN));
lcd_puts(x + 7 * FWNUM, ynum, PSTR("o"));
y += 3 * FH;
ynum += 3 * FH;
x = 0;
lcd_puts (x, y, STR_MAVLINK_BEARING);
lcd_outdezAtt(x + 7 * FWNUM, ynum, telemetry_data.bearing, (DBLSIZE | UNSIGN));
lcd_puts(x + 7 * FWNUM, ynum, PSTR("o"));
x += 8 * (2 * FWNUM);
lcd_puts(x, y, STR_MAVLINK_ALTITUDE);
lcd_outdezFloat(x + 4 * FWNUM - 1, ynum, telemetry_data.loc_current.rel_alt, 1, (DBLSIZE));
lcd_puts(x + 7 * FWNUM, ynum + FH, PSTR("m"));
}
/*! \brief GPS information menu
* \details Menu gives a lot of info from the gps like fix type, position,
* attitude, heading and velocity. Text is small and the user must focus to
* read it.
* \todo Text is small. Should we do something about this or leaf it like this.
* I don't think will be used much when a user is concentrated on flying.
*/
void menuTelemetryMavlinkGPS(void) {
mav_title(STR_MAVLINK_GPS, MAVLINK_menu);
uint8_t x1, x2, xnum, xnum2, y;
x1 = FW;
x2 = x1 + 12 * FW;
xnum = 7 * FW + 3 * FWNUM;
xnum2 = xnum + 11 * FWNUM;
y = FH;
lcd_putsnAtt(x1, y, STR_MAVLINK_GPS, 3, 0);
if (telemetry_data.fix_type < 2) {
lcd_putsnAtt(xnum, y, STR_MAVLINK_NO_FIX, 6, 0);
} else {
lcd_outdezNAtt(xnum, y, telemetry_data.fix_type, 0, 3);
lcd_puts(xnum, y, PSTR("D"));
}
lcd_puts(x2, y, STR_MAVLINK_SAT);
lcd_outdezNAtt(xnum2, y, telemetry_data.satellites_visible, 0, 2);
// if (telemetry_data.fix_type > 0) {
y += FH;
lcd_puts(x1, y, STR_MAVLINK_HDOP);
lcd_outdezFloat(xnum, y, telemetry_data.eph, 2);
y += FH;
lcd_puts(x1, y, STR_MAVLINK_LAT);
lcd_outdezFloat(xnum, y, telemetry_data.loc_current.lat, 2);
lcd_putsnAtt(x2, y, STR_MAVLINK_LON, 3, 0);
lcd_outdezFloat(xnum2, y, telemetry_data.loc_current.lon, 2);
y += FH;
lcd_putsnAtt(x1, y, STR_MAVLINK_ALTITUDE, 3, 0);
lcd_outdezAtt(xnum, y, telemetry_data.loc_current.gps_alt, 0);
y += FH;
lcd_putsnAtt(x1, y, STR_MAVLINK_COURSE, 6, 0);
lcd_outdezFloat(xnum, y, telemetry_data.course, 2);
y += FH;
lcd_putsnAtt(x1, y, PSTR("V"), 1, 0);
lcd_outdezAtt(xnum, y, telemetry_data.v, 0);
//}
}
#ifdef DUMP_RX_TX
//! \brief Display one byte as hex.
void lcd_outhex2(uint8_t x, uint8_t y, uint8_t val) {
x += FWNUM * 2;
for (int i = 0; i < 2; i++) {
x -= FWNUM;
char c = val & 0xf;
c = c > 9 ? c + 'A' - 10 : c + '0';
lcd_putcAtt(x, y, c, c >= 'A' ? CONDENSED : 0);
val >>= 4;
}
}
//! \brief Hex dump of the current mavlink message.
void menuTelemetryMavlinkDump(uint8_t event) {
uint8_t x = 0;
uint8_t y = FH;
uint16_t count = 0;
uint16_t bufferLen = 0;
uint8_t *ptr = NULL;
switch (MAVLINK_menu) {
case MENU_DUMP_RX:
mav_dump_rx = 1;
mav_title(PSTR("RX"), MAVLINK_menu);
bufferLen = mavlinkRxBufferCount;
ptr = mavlinkRxBuffer;
break;
case MENU_DUMP_TX:
mav_title(PSTR("TX"), MAVLINK_menu);
bufferLen = serialTxBufferCount;
ptr = ptrTxISR;
break;
default:
break;
}
for (uint16_t var = 0; var < bufferLen; var++) {
uint8_t byte = *ptr++;
lcd_outhex2(x, y, byte);
x += 2 * FW;
count++;
if (count > 8) {
count = 0;
x = 0;
y += FH;
if (y == (6 * FH))
break;
}
}
}
#endif
/*! \brief Mavlink General setup menu.
* \details Setup menu for generic mavlink settings.
* Current menu items
* - RC RSSI scale item. Used to adjust the scale of the RSSI indicator to match
* the actual rssi value
* - PC RSSI enable item. Can be used to dissable PC RSSI display if not used.
* This funcion is called from the model setup menus, not directly by the
* telemetry menus
*/
void menuTelemetryMavlinkSetup(uint8_t event) {
MENU(STR_MAVMENUSETUP_TITLE, menuTabModel, e_MavSetup, ITEM_MAVLINK_MAX + 1, {0, 0, 1/*to force edit mode*/});
uint8_t sub = m_posVert - 1;
for (uint8_t i=0; i<LCD_LINES-1; i++) {
uint8_t y = 1 + 1*FH + i*FH;
uint8_t k = i+s_pgOfs;
uint8_t blink = ((s_editMode>0) ? BLINK|INVERS : INVERS);
uint8_t attr = (sub == k ? blink : 0);
switch(k) {
case ITEM_MAVLINK_RC_RSSI_SCALE:
lcd_putsLeft(y, STR_MAVLINK_RC_RSSI_SCALE_LABEL);
lcd_outdezAtt(RADIO_SETUP_2ND_COLUMN, y, (25 + g_model.mavlink.rc_rssi_scale * 5), attr|LEFT);
lcd_putc(lcdLastPos, y, '%');
if (attr) CHECK_INCDEC_MODELVAR(event, g_model.mavlink.rc_rssi_scale, 0, 15);
break;
case ITEM_MAVLINK_PC_RSSI_EN:
g_model.mavlink.pc_rssi_en = onoffMenuItem(g_model.mavlink.pc_rssi_en,
RADIO_SETUP_2ND_COLUMN,
y,
STR_MAVLINK_PC_RSSI_EN_LABEL,
attr,
event);
break;
}
}
}
+100
View File
@@ -0,0 +1,100 @@
/*
* Authors (alphabetical order)
* - Andre Bernet <bernet.andre@gmail.com>
* - Andreas Weitl
* - Bertrand Songis <bsongis@gmail.com>
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
* - Cameron Weeks <th9xer@gmail.com>
* - Erez Raviv
* - Gabriel Birkus
* - Gerard Valade <gerard.valade@gmail.com>
* - Jean-Pierre Parisy
* - Karl Szmutny
* - Michael Blandford
* - Michal Hlavinka
* - Pat Mackenzie
* - Philip Moss
* - Rienk de Jong
* - Rob Thomson
* - Romolo Manfredini <romolo.manfredini@gmail.com>
* - Thomas Husterer
*
* opentx is based on code named
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
* and the original (and ongoing) project by
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*! \file view_mavlink.h
* Mavlink menu include file
*/
#ifndef _VIEW_MAVLINK_H_
#define _VIEW_MAVLINK_H_
#include "opentx.h"
#include "telemetry/mavlink.h"
#include "gui/menus.h"
#include "serial.h"
#define APSIZE (BSS | DBLSIZE)
void menuTelemetryMavlink(uint8_t event);
void displayScreenIndex(uint8_t index, uint8_t count, uint8_t attr);
void lcd_outdezFloat(uint8_t x, uint8_t y, float val, uint8_t precis, uint8_t mode = 0);
void mav_title(const pm_char * s, uint8_t index);
void menuTelemetryMavlinkInfos(void);
void menuTelemetryMavlinkFlightMode(void);
void menuTelemetryMavlinkBattery(void);
void menuTelemetryMavlinkNavigation(void);
void menuTelemetryMavlinkGPS(void);
#ifdef DUMP_RX_TX
void lcd_outhex2(uint8_t x, uint8_t y, uint8_t val);
void menuTelemetryMavlinkDump(uint8_t event);
#endif
void menuTelemetryMavlinkSetup(uint8_t event);
/*! \brief Mavlink menu enumerator
* \details Used to create a readable case statement for the
* \link menuTelemetryMavlink menuTelemetryMavlink \endlink funtion.
*/
enum mavlink_menu_ {
MENU_INFO = 0, //
MENU_MODE,
MENU_BATT,
MENU_NAV,
MENU_GPS, //
#ifdef DUMP_RX_TX
MENU_DUMP_RX, //
MENU_DUMP_TX, //
#endif
MAX_MAVLINK_MENU
};
//! \brief Pointer array to mavlink settings menus.
const MenuFuncP_PROGMEM menuTabMav[] PROGMEM = {
menuTelemetryMavlinkSetup
};
//! \brief Mavlink setup menu configuration items list.
enum menuMavlinkSetupItems {
ITEM_MAVLINK_RC_RSSI_SCALE,
ITEM_MAVLINK_PC_RSSI_EN,
ITEM_MAVLINK_MAX
};
//! \brief Menu index varible, initialized on info menu.
uint8_t MAVLINK_menu = MENU_INFO;
#endif
+208
View File
@@ -0,0 +1,208 @@
/*
* Authors (alphabetical order)
* - Andre Bernet <bernet.andre@gmail.com>
* - Andreas Weitl
* - Bertrand Songis <bsongis@gmail.com>
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
* - Cameron Weeks <th9xer@gmail.com>
* - Erez Raviv
* - Gabriel Birkus
* - Jean-Pierre Parisy
* - Karl Szmutny
* - Michael Blandford
* - Michal Hlavinka
* - Pat Mackenzie
* - Philip Moss
* - Rob Thomson
* - Romolo Manfredini <romolo.manfredini@gmail.com>
* - Thomas Husterer
*
* opentx is based on code named
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
* and the original (and ongoing) project by
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include "../opentx.h"
void menuStatisticsView(uint8_t event)
{
TITLE(STR_MENUSTAT);
switch(event)
{
#if !defined(PCBTARANIS) || defined(DEBUG)
case EVT_KEY_FIRST(KEY_UP):
chainMenu(menuStatisticsDebug);
return;
#endif
#if defined(PCBTARANIS)
case EVT_KEY_LONG(KEY_MENU):
g_eeGeneral.globalTimer = 0;
break;
#endif
case EVT_KEY_FIRST(KEY_EXIT):
chainMenu(menuMainView);
return;
}
lcd_puts( 1*FW, FH*1, STR_TM1TM2);
putsTime( 5*FW+5*FWNUM+1, FH*1, timersStates[0].val, 0, 0);
putsTime( 12*FW+5*FWNUM+1, FH*1, timersStates[1].val, 0, 0);
lcd_puts( 1*FW, FH*2, STR_THRTHP);
putsTime( 5*FW+5*FWNUM+1, FH*2, s_timeCumThr, 0, 0);
putsTime( 12*FW+5*FWNUM+1, FH*2, s_timeCum16ThrP/16, 0, 0);
lcd_puts( 17*FW, FH*0, STR_TOT);
putsTime( 12*FW+5*FWNUM+1, FH*0, s_timeCumTot, 0, 0);
#if defined(PCBTARANIS)
putsTime(21*FW+5*FWNUM+1, 0*FH, g_eeGeneral.globalTimer + sessionTimer, 0, 0);
#endif
#if defined(THRTRACE)
uint8_t traceRd = (s_traceCnt < 0 ? s_traceWr : 0);
const uint8_t x=5;
const uint8_t y=60;
lcd_hline(x-3,y,MAXTRACE+3+3);
lcd_vline(x,y-32,32+3);
for (uint8_t i=0; i<MAXTRACE; i+=6) {
lcd_vline(x+i+6,y-1,3);
}
for (uint8_t i=1; i<=MAXTRACE; i++) {
lcd_vline(x+i, y-s_traceBuf[traceRd], s_traceBuf[traceRd]);
traceRd++;
if (traceRd>=MAXTRACE) traceRd = 0;
if (traceRd==s_traceWr) break;
}
#endif
}
#if defined(CPUARM)
#define MENU_DEBUG_COL_OFS (11*FW-2)
#else
#define MENU_DEBUG_COL_OFS (14*FW)
#endif
void menuStatisticsDebug(uint8_t event)
{
TITLE(STR_MENUDEBUG);
switch(event)
{
#if defined(CPUARM)
case EVT_KEY_LONG(KEY_MENU):
g_eeGeneral.mAhUsed = 0;
g_eeGeneral.globalTimer = 0;
eeDirty(EE_GENERAL);
#if defined(PCBSKY9X)
Current_used = 0;
#endif
sessionTimer = 0;
killEvents(event);
AUDIO_KEYPAD_UP();
break;
#endif
case EVT_KEY_FIRST(KEY_MENU):
#if !defined(CPUARM)
g_tmr1Latency_min = 0xff;
g_tmr1Latency_max = 0;
#endif
maxMixerDuration = 0;
AUDIO_KEYPAD_UP();
break;
case EVT_KEY_FIRST(KEY_DOWN):
chainMenu(menuStatisticsView);
return;
case EVT_KEY_FIRST(KEY_EXIT):
chainMenu(menuMainView);
return;
}
#if defined(PCBSKY9X)
if ((ResetReason&RSTC_SR_RSTTYP) == (2<<8)) {
lcd_puts(LCD_W-8*FW, 0*FH, "WATCHDOG");
}
else if (unexpectedShutdown) {
lcd_puts(LCD_W-13*FW, 0*FH, "UNEXP.SHTDOWN");
}
#endif
#if defined(PCBSKY9X) && !defined(REVA)
lcd_putsLeft(1*FH, STR_CPU_CURRENT);
putsTelemetryValue(MENU_DEBUG_COL_OFS, 1*FH, getCurrent(), UNIT_MILLIAMPS, 0);
uint32_t current_scale = 488 + g_eeGeneral.currentCalib;
putsTelemetryValue(20*FW+2, 1*FH, Current_max*10*current_scale/8192, UNIT_RAW, 0);
lcd_putsLeft(2*FH, STR_CPU_MAH);
putsTelemetryValue(MENU_DEBUG_COL_OFS, 2*FH, g_eeGeneral.mAhUsed + Current_used*current_scale/8192/36, UNIT_MAH, PREC1);
putsTime(17*FW+5*FWNUM+1, 2*FH, g_eeGeneral.globalTimer + sessionTimer, 0, 0);
#endif
#if defined(PCBSKY9X)
lcd_putsLeft(3*FH, STR_CPU_TEMP);
putsTelemetryValue(MENU_DEBUG_COL_OFS, 3*FH, getTemperature(), UNIT_DEGREES, 0);
putsTelemetryValue(20*FW+2, 3*FH, maxTemperature+g_eeGeneral.temperatureCalib, UNIT_DEGREES, 0);
#endif
#if defined(PCBSKY9X)
lcd_putsLeft(4*FH, STR_COPROC_TEMP);
if (Coproc_read==0) {
lcd_putsAtt(9*FW+2, 4*FH, PSTR("Co Proc NACK"),INVERS);
}
else if (Coproc_read==0x81) {
lcd_putsAtt(9*FW+2, 4*FH, PSTR("Inst.TinyApp"),INVERS);
}
else if (Coproc_read<3) {
lcd_putsAtt(9*FW+2, 4*FH, PSTR("Upgr.TinyApp"),INVERS);
}
else {
putsTelemetryValue(MENU_DEBUG_COL_OFS, 4*FH, Coproc_temp, UNIT_DEGREES, 0);
putsTelemetryValue(20*FW+2, 4*FH, Coproc_maxtemp, UNIT_DEGREES, 0);
}
#elif defined(PCBTARANIS) && !defined(SIMU)
lcd_putsLeft(4*FH, "Free Mem");
lcd_outdezAtt(MENU_DEBUG_COL_OFS, 4*FH, 0x20020000 - (unsigned int)heap, LEFT);
#endif
#if defined(CPUARM)
lcd_putsLeft(5*FH, STR_TMIXMAXMS);
lcd_outdezAtt(MENU_DEBUG_COL_OFS, 5*FH, (maxMixerDuration)/20, PREC2|LEFT);
lcd_puts(lcdLastPos, 5*FH, "ms");
lcd_putsLeft(6*FH, STR_FREESTACKMINB);
lcd_putsAtt(MENU_DEBUG_COL_OFS-1, 6*FH+1, "[Main]", SMLSIZE);
lcd_outdezAtt(lcdLastPos, 6*FH, stack_free(0), UNSIGN|LEFT);
lcd_putsAtt(lcdLastPos+2, 6*FH+1, "[Mix]", SMLSIZE);
lcd_outdezAtt(lcdLastPos, 6*FH, stack_free(1), UNSIGN|LEFT);
lcd_putsAtt(lcdLastPos+2, 6*FH+1, "[Audio]", SMLSIZE);
lcd_outdezAtt(lcdLastPos, 6*FH, stack_free(2), UNSIGN|LEFT);
#else
lcd_putsLeft(1*FH, STR_TMR1LATMAXUS);
lcd_outdez8(MENU_DEBUG_COL_OFS , 1*FH, g_tmr1Latency_max/2 );
lcd_putsLeft(2*FH, STR_TMR1LATMINUS);
lcd_outdez8(MENU_DEBUG_COL_OFS , 2*FH, g_tmr1Latency_min/2 );
lcd_putsLeft(3*FH, STR_TMR1JITTERUS);
lcd_outdez8(MENU_DEBUG_COL_OFS , 3*FH, (g_tmr1Latency_max - g_tmr1Latency_min) /2 );
lcd_putsLeft(4*FH, STR_TMIXMAXMS);
lcd_outdezAtt(MENU_DEBUG_COL_OFS, 4*FH, (maxMixerDuration*100)/16, PREC2);
lcd_putsLeft(5*FH, STR_FREESTACKMINB);
lcd_outdezAtt(14*FW, 5*FH, stack_free(), UNSIGN) ;
#endif
lcd_puts(3*FW, 7*FH+1, STR_MENUTORESET);
lcd_status_line();
}
+417
View File
@@ -0,0 +1,417 @@
/*
* Authors (alphabetical order)
* - Andre Bernet <bernet.andre@gmail.com>
* - Andreas Weitl
* - Bertrand Songis <bsongis@gmail.com>
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
* - Cameron Weeks <th9xer@gmail.com>
* - Erez Raviv
* - Gabriel Birkus
* - Jean-Pierre Parisy
* - Karl Szmutny
* - Michael Blandford
* - Michal Hlavinka
* - Pat Mackenzie
* - Philip Moss
* - Rob Thomson
* - Romolo Manfredini <romolo.manfredini@gmail.com>
* - Thomas Husterer
*
* opentx is based on code named
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
* and the original (and ongoing) project by
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include "../opentx.h"
#define STATUS_BAR_Y (7*FH+1)
#if LCD_W >= 212
#define TELEM_2ND_COLUMN (11*FW)
#else
#define TELEM_2ND_COLUMN (10*FW)
#endif
#if defined(FRSKY_HUB) && defined(GAUGES)
uint8_t barsThresholds[THLD_MAX];
#endif
enum FrskyViews {
e_frsky_custom_screen_1,
e_frsky_custom_screen_2,
IF_CPUARM(e_frsky_custom_screen_3)
e_frsky_voltages,
e_frsky_after_flight,
FRSKY_VIEW_MAX = e_frsky_after_flight
};
static uint8_t s_frsky_view = e_frsky_custom_screen_1;
#if defined(PCBTARANIS)
void displayRssiLine()
{
if (TELEMETRY_STREAMING()) {
lcd_hline(0, 55, 212, 0); // separator
uint8_t rssi = min((uint8_t)99, frskyData.rssi[0].value);
lcd_putsLeft(STATUS_BAR_Y, STR_RX); lcd_outdezNAtt(4*FW, STATUS_BAR_Y, rssi, LEADING0, 2);
lcd_rect(25, 57, 78, 7);
lcd_filled_rect(26, 58, 19*rssi/25, 5, (rssi < getRssiAlarmValue(0)) ? DOTTED : SOLID);
}
else {
lcd_putsAtt(7*FW, STATUS_BAR_Y, STR_NODATA, BLINK);
lcd_status_line();
}
}
#else
void displayRssiLine()
{
if (TELEMETRY_STREAMING()) {
lcd_hline(0, 55, 128, 0); // separator
uint8_t rssi = min((uint8_t)99, frskyData.rssi[1].value);
lcd_putsLeft(STATUS_BAR_Y, STR_TX); lcd_outdezNAtt(4*FW, STATUS_BAR_Y, rssi, LEADING0, 2);
lcd_rect(25, 57, 38, 7);
lcd_filled_rect(26, 58, 4*rssi/11, 5, (rssi < getRssiAlarmValue(0)) ? DOTTED : SOLID);
rssi = min((uint8_t)99, frskyData.rssi[0].value);
lcd_puts(105, STATUS_BAR_Y, STR_RX); lcd_outdezNAtt(105+4*FW-1, STATUS_BAR_Y, rssi, LEADING0, 2);
lcd_rect(65, 57, 38, 7);
uint8_t v = 4*rssi/11;
lcd_filled_rect(66+36-v, 58, v, 5, (rssi < getRssiAlarmValue(0)) ? DOTTED : SOLID);
}
else {
lcd_putsAtt(7*FW, STATUS_BAR_Y, STR_NODATA, BLINK);
lcd_status_line();
}
}
#endif
#if defined(FRSKY) && defined(FRSKY_HUB) && defined(GPS)
void displayGpsTime()
{
uint8_t att = (TELEMETRY_STREAMING() ? LEFT|LEADING0 : LEFT|LEADING0|BLINK);
lcd_outdezNAtt(CENTER_OFS+6*FW+5, STATUS_BAR_Y, frskyData.hub.hour, att, 2);
lcd_putcAtt(CENTER_OFS+8*FW+2, STATUS_BAR_Y, ':', att);
lcd_outdezNAtt(CENTER_OFS+9*FW+2, STATUS_BAR_Y, frskyData.hub.min, att, 2);
lcd_putcAtt(CENTER_OFS+11*FW-1, STATUS_BAR_Y, ':', att);
lcd_outdezNAtt(CENTER_OFS+12*FW-1, STATUS_BAR_Y, frskyData.hub.sec, att, 2);
lcd_status_line();
}
void displayGpsCoord(uint8_t y, char direction, int16_t bp, int16_t ap)
{
if (frskyData.hub.gpsFix >= 0) {
if (!direction) direction = '-';
lcd_outdezAtt(TELEM_2ND_COLUMN, y, bp / 100, LEFT); // ddd before '.'
lcd_putc(lcdLastPos, y, '@');
uint8_t mn = bp % 100; // TODO div_t
if (g_eeGeneral.gpsFormat == 0) {
lcd_putc(lcdLastPos+FWNUM, y, direction);
lcd_outdezNAtt(lcdLastPos+FW+FW+1, y, mn, LEFT|LEADING0, 2); // mm before '.'
lcd_vline(lcdLastPos, y, 2);
uint16_t ss = ap * 6;
lcd_outdezAtt(lcdLastPos+3, y, ss / 1000, LEFT); // ''
lcd_plot(lcdLastPos, y+FH-2, 0); // small decimal point
lcd_outdezAtt(lcdLastPos+2, y, ss % 1000, LEFT); // ''
lcd_vline(lcdLastPos, y, 2);
lcd_vline(lcdLastPos+2, y, 2);
}
else {
lcd_outdezNAtt(lcdLastPos+FW, y, mn, LEFT|LEADING0, 2); // mm before '.'
lcd_plot(lcdLastPos, y+FH-2, 0); // small decimal point
lcd_outdezNAtt(lcdLastPos+2, y, ap, LEFT|UNSIGN|LEADING0, 4); // after '.'
lcd_putc(lcdLastPos+1, y, direction);
}
}
else {
// no fix
lcd_puts(TELEM_2ND_COLUMN, y, STR_VCSWFUNC+1/*----*/);
}
}
#else
#define displayGpsTime()
#define displayGpsCoord(...)
#endif
NOINLINE uint8_t getRssiAlarmValue(uint8_t alarm)
{
return (45 - 3*alarm + g_model.frsky.rssiAlarms[alarm].value);
}
void displayVoltageScreenLine(uint8_t y, uint8_t index)
{
putsStrIdx(0, y, STR_A, index+1, 0);
if (TELEMETRY_STREAMING()) {
putsTelemetryChannel(3*FW+6*FW+4, y-FH+1, index+TELEM_A1-1, frskyData.analog[index].value, DBLSIZE);
lcd_putc(12*FW-1, y-FH, '<'); putsTelemetryChannel(17*FW, y-FH, index+TELEM_A1-1, frskyData.analog[index].min, NO_UNIT);
lcd_putc(12*FW, y, '>'); putsTelemetryChannel(17*FW, y, index+TELEM_A1-1, frskyData.analog[index].max, NO_UNIT);
}
}
#if LCD_W >= 212
#define BAR_WIDTH 160
#else
#define BAR_WIDTH 100
#endif
uint8_t barCoord(int16_t value, int16_t min, int16_t max)
{
return limit((uint8_t)0, (uint8_t)(((int32_t)(BAR_WIDTH-1) * (value - min)) / (max - min)), (uint8_t)BAR_WIDTH);
}
void menuTelemetryFrsky(uint8_t event)
{
if (event == EVT_KEY_FIRST(KEY_EXIT)) {
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):
resetTelemetry();
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 = convertTelemValue(source, bar.barMin);
getvalue_t barMax = convertTelemValue(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 = convertTelemValue(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;
lcd_putsiAtt(0, 2*FH, STR_VOLTSRC, g_model.frsky.voltsSource+1, 0);
switch(g_model.frsky.voltsSource) {
case 0:
case 1:
displayVoltageScreenLine(2*FH, g_model.frsky.voltsSource);
analog = 1+g_model.frsky.voltsSource;
break;
#if defined(FRSKY_HUB)
case 2:
putsTelemetryChannel(3*FW+6*FW+4, FH+1, TELEM_VFAS-1, frskyData.hub.vfas, DBLSIZE);
break;
case 3:
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_VOLTSRC, g_model.frsky.currentSource, 0);
switch(g_model.frsky.currentSource) {
case 1:
case 2:
displayVoltageScreenLine(4*FH, g_model.frsky.currentSource-1);
break;
#if defined(FRSKY_HUB)
case 3:
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, frskyData.hub.cellVolts[k] * 2, attr, 4);
y += 1*FH;
}
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
}
+153
View File
@@ -0,0 +1,153 @@
/*
* Authors (alphabetical order)
* - Andre Bernet <bernet.andre@gmail.com>
* - Andreas Weitl
* - Bertrand Songis <bsongis@gmail.com>
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
* - Cameron Weeks <th9xer@gmail.com>
* - Erez Raviv
* - Gabriel Birkus
* - Jean-Pierre Parisy
* - Karl Szmutny
* - Michael Blandford
* - Michal Hlavinka
* - Pat Mackenzie
* - Philip Moss
* - Rob Thomson
* - Romolo Manfredini <romolo.manfredini@gmail.com>
* - Thomas Husterer
*
* opentx is based on code named
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
* and the original (and ongoing) project by
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include "../opentx.h"
#define TEXT_FILENAME_MAXLEN 40
#define TEXT_FILE_MAXSIZE 1000
char s_text_file[TEXT_FILENAME_MAXLEN];
char s_text_screen[LCD_LINES-1][LCD_COLS+1];
void readTextFile(int & lines_count)
{
FIL file;
int result;
char c;
unsigned int sz;
int line_length = 0;
int escape = 0;
char escape_chars[2];
int current_line = 0;
memset(s_text_screen, 0, sizeof(s_text_screen));
result = f_open(&file, s_text_file, FA_OPEN_EXISTING | FA_READ);
if (result == FR_OK) {
for (int i=0; i<TEXT_FILE_MAXSIZE && f_read(&file, &c, 1, &sz)==FR_OK && sz==1 && (lines_count==0 || current_line-s_pgOfs<LCD_LINES-1); i++) {
if (c == '\n') {
++current_line;
line_length = 0;
escape = 0;
}
else if (c!='\r' && current_line>=s_pgOfs && current_line-s_pgOfs<LCD_LINES-1 && line_length<LCD_COLS) {
if (c=='\\' && escape==0) {
escape = 1;
continue;
}
else if (c!='\\' && escape>0 && escape<3) {
escape_chars[escape-1] = c;
if (escape == 2 && !strncmp(escape_chars, "up", 2)) {
c = '\300';
}
else if (escape == 2 && !strncmp(escape_chars, "dn", 2)) {
c = '\301';
}
else {
escape++;
continue;
}
}
escape = 0;
s_text_screen[current_line-s_pgOfs][line_length++] = c;
}
}
f_close(&file);
}
if (lines_count == 0) {
lines_count = current_line;
}
}
void menuTextView(uint8_t event)
{
static int lines_count;
switch (event) {
case EVT_ENTRY:
s_pgOfs = 0;
lines_count = 0;
readTextFile(lines_count);
break;
case EVT_KEY_BREAK(KEY_UP):
if (s_pgOfs == 0)
break;
else
s_pgOfs--;
// no break;
case EVT_KEY_BREAK(KEY_DOWN):
if (event == EVT_KEY_BREAK(KEY_DOWN)) {
if (s_pgOfs+LCD_LINES-1 >= lines_count)
break;
else
++s_pgOfs;
}
readTextFile(lines_count);
break;
case EVT_KEY_BREAK(KEY_EXIT):
popMenu();
return;
}
for (int i=0; i<LCD_LINES-1; i++) {
lcd_puts(0, i*FH+FH+1, s_text_screen[i]);
}
char *title = s_text_file;
#if defined(SIMU)
if (!strncmp(title, "./", 2)) title += 2;
#else
// TODO?
#endif
lcd_puts(LCD_W/2-strlen(title)*FW/2, 0, title);
lcd_invert_line(0);
if (lines_count > LCD_LINES-1) {
displayScrollbar(LCD_W-1, FH, LCD_H-FH, s_pgOfs, lines_count, LCD_LINES-1);
}
}
void pushMenuTextView(const char *filename)
{
if (strlen(filename) < TEXT_FILENAME_MAXLEN) {
strcpy(s_text_file, filename);
pushMenu(menuTextView);
}
}