Co-authored-by: Peter Feerick <5500713+pfeerick@users.noreply.github.com> Co-authored-by: radiosky <839034809@qq.com> Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
813 lines
30 KiB
C++
813 lines
30 KiB
C++
/*
|
|
* Copyright (C) EdgeTX
|
|
*
|
|
* Based on code named
|
|
* opentx - https://github.com/opentx/opentx
|
|
* th9x - http://code.google.com/p/th9x
|
|
* er9x - http://code.google.com/p/er9x
|
|
* gruvin9x - http://code.google.com/p/gruvin9x
|
|
*
|
|
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
|
*
|
|
* 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 "edgetx.h"
|
|
|
|
#include "hal/adc_driver.h"
|
|
#include "hal/switch_driver.h"
|
|
#include "hal/module_port.h"
|
|
#include "hal/rgbleds.h"
|
|
|
|
#include "analogs.h"
|
|
#include "switches.h"
|
|
|
|
#if defined(BLUETOOTH)
|
|
#include "bluetooth_driver.h"
|
|
#endif
|
|
|
|
#if defined(CROSSFIRE)
|
|
#include "telemetry/crossfire.h"
|
|
#endif
|
|
|
|
#if LCD_W >= 212
|
|
#define HW_SETTINGS_COLUMN1 12*FW
|
|
#define HW_SETTINGS_COLUMN2 (20*FW - 3)
|
|
#define HW_SETTINGS_COLUMN3 HW_SETTINGS_COLUMN2
|
|
#else
|
|
#define HW_SETTINGS_COLUMN1 30
|
|
#define HW_SETTINGS_COLUMN2 (HW_SETTINGS_COLUMN1 + 5*FW)
|
|
#define HW_SETTINGS_COLUMN3 HW_SETTINGS_COLUMN2 + FW
|
|
#endif
|
|
|
|
#if defined(BATTGRAPH)
|
|
#define CASE_BATTGRAPH(x) x,
|
|
#else
|
|
#define CASE_BATTGRAPH(x)
|
|
#endif
|
|
|
|
enum {
|
|
ITEM_RADIO_HARDWARE_LABEL_STICKS = 0,
|
|
ITEM_RADIO_HARDWARE_STICK,
|
|
ITEM_RADIO_HARDWARE_STICK_END = ITEM_RADIO_HARDWARE_STICK + MAX_STICKS - 1,
|
|
ITEM_RADIO_HARDWARE_LABEL_POTS,
|
|
ITEM_RADIO_HARDWARE_POT,
|
|
ITEM_RADIO_HARDWARE_POT_END = ITEM_RADIO_HARDWARE_POT + MAX_POTS - 1,
|
|
ITEM_RADIO_HARDWARE_LABEL_SWITCHES,
|
|
ITEM_RADIO_HARDWARE_SWITCH,
|
|
ITEM_RADIO_HARDWARE_SWITCH_END = ITEM_RADIO_HARDWARE_SWITCH + MAX_SWITCHES - 1,
|
|
#if defined(FUNCTION_SWITCHES)
|
|
ITEM_RADIO_HARDWARE_LABEL_CFS,
|
|
ITEM_RADIO_HARDWARE_CFS,
|
|
ITEM_RADIO_HARDWARE_CFS_END = ITEM_RADIO_HARDWARE_CFS + MAX_SWITCHES - 1,
|
|
#endif
|
|
CASE_BATTGRAPH(ITEM_RADIO_HARDWARE_BATT_RANGE)
|
|
ITEM_RADIO_HARDWARE_BATTERY_CALIB,
|
|
ITEM_RADIO_HARDWARE_RTC_BATTERY,
|
|
ITEM_RADIO_HARDWARE_RTC_CHECK,
|
|
#if defined(AUDIO_MUTE_GPIO)
|
|
ITEM_RADIO_HARDWARE_AUDIO_MUTE,
|
|
#endif
|
|
ITEM_RADIO_HARDWARE_LABEL_INTERNAL_MODULE,
|
|
ITEM_RADIO_HARDWARE_INTERNAL_MODULE_TYPE,
|
|
ITEM_RADIO_HARDWARE_INTERNAL_MODULE_BAUDRATE,
|
|
ITEM_RADIO_HARDWARE_SERIAL_SAMPLE_MODE,
|
|
#if defined(BLUETOOTH)
|
|
ITEM_RADIO_HARDWARE_BLUETOOTH_MODE,
|
|
ITEM_RADIO_HARDWARE_BLUETOOTH_PAIRING_CODE,
|
|
ITEM_RADIO_HARDWARE_BLUETOOTH_LOCAL_ADDR,
|
|
ITEM_RADIO_HARDWARE_BLUETOOTH_DISTANT_ADDR,
|
|
ITEM_RADIO_HARDWARE_BLUETOOTH_NAME,
|
|
#endif
|
|
#if defined(EXTERNAL_ANTENNA)
|
|
ITEM_RADIO_HARDWARE_EXTERNAL_ANTENNA,
|
|
#endif
|
|
ITEM_RADIO_HARDWARE_SERIAL_PORT_LABEL,
|
|
ITEM_RADIO_HARDWARE_SERIAL_PORT,
|
|
ITEM_RADIO_HARDWARE_SERIAL_PORT_END = ITEM_RADIO_HARDWARE_SERIAL_PORT + MAX_SERIAL_PORTS - 1,
|
|
ITEM_RADIO_HARDWARE_JITTER_FILTER,
|
|
ITEM_RADIO_HARDWARE_RAS,
|
|
ITEM_RADIO_HARDWARE_SPORT_UPDATE_POWER,
|
|
#if (defined(BACKLIGHT_GPIO) || OLED_SCREEN) && (LCD_W == 128)
|
|
ITEM_RADIO_HARDWARE_SCREEN_LABEL,
|
|
ITEM_RADIO_HARDWARE_SCREEN_INVERT,
|
|
#endif
|
|
ITEM_RADIO_HARDWARE_DEBUG,
|
|
#if defined(FUNCTION_SWITCHES)
|
|
ITEM_RADIO_HARDWARE_DEBUG_FS,
|
|
#endif
|
|
ITEM_RADIO_HARDWARE_MAX
|
|
};
|
|
|
|
#if defined(EXTERNAL_ANTENNA)
|
|
static void onHardwareAntennaSwitchConfirm(const char * result)
|
|
{
|
|
if (result == STR_OK) {
|
|
// Switch to external antenna confirmation
|
|
g_eeGeneral.antennaMode = reusableBuffer.radioHardware.antennaMode;
|
|
storageDirty(EE_GENERAL);
|
|
// Consent already obtained above; mark enabled so checkExternalAntenna()
|
|
// applies the GPIO instead of asking again.
|
|
globalData.externalAntennaEnabled = true;
|
|
checkExternalAntenna();
|
|
}
|
|
else {
|
|
reusableBuffer.radioHardware.antennaMode = g_eeGeneral.antennaMode;
|
|
}
|
|
}
|
|
#endif // defined(EXTERNAL_ANTENNA)
|
|
|
|
#if defined(FUNCTION_SWITCHES)
|
|
#define RADIO_SETUP_2ND_COLUMN (LCD_W-11*FW)
|
|
extern const char* _fct_sw_start[];
|
|
extern int swIndex;
|
|
|
|
extern bool checkCFSTypeAvailable(int val);
|
|
|
|
enum CFSFields {
|
|
CFS_FIELD_TYPE,
|
|
CFS_FIELD_NAME,
|
|
CFS_FIELD_START,
|
|
#if defined(FUNCTION_SWITCHES_RGB_LEDS)
|
|
CFS_FIELD_COLOR_LABEL,
|
|
CFS_FIELD_ON_COLOR,
|
|
CFS_FIELD_ON_LUA_OVERRIDE,
|
|
CFS_FIELD_OFF_COLOR,
|
|
CFS_FIELD_OFF_LUA_OVERRIDE,
|
|
#endif
|
|
CFS_FIELD_COUNT
|
|
};
|
|
|
|
#if defined(FUNCTION_SWITCHES_RGB_LEDS)
|
|
extern bool menuCFSpreview;
|
|
extern void menuCFSColor(coord_t y, RGBLedColor& color, const char* title, LcdFlags attr, event_t event);
|
|
#endif
|
|
|
|
static void menuRadioCFSOne(event_t event)
|
|
{
|
|
std::string s(CHAR_SWITCH);
|
|
s += switchGetDefaultName(swIndex);
|
|
|
|
int config = g_eeGeneral.switchType(swIndex);
|
|
uint8_t group = g_eeGeneral.switchGroup(swIndex);
|
|
int startPos = g_eeGeneral.switchStart(swIndex);
|
|
|
|
SUBMENU(s.c_str(), CFS_FIELD_COUNT,
|
|
{
|
|
0,
|
|
(uint8_t)((config != SWITCH_NONE && config != SWITCH_GLOBAL) ? 0 : HIDDEN_ROW),
|
|
(uint8_t)((config != SWITCH_NONE && config != SWITCH_TOGGLE && config != SWITCH_GLOBAL && group == 0) ? 0 : HIDDEN_ROW),
|
|
#if defined(FUNCTION_SWITCHES_RGB_LEDS)
|
|
(uint8_t)((config != SWITCH_NONE && config != SWITCH_GLOBAL) ? LABEL() : HIDDEN_ROW),
|
|
(uint8_t)((config != SWITCH_NONE && config != SWITCH_GLOBAL) ? 3 : HIDDEN_ROW),
|
|
(uint8_t)((config != SWITCH_NONE && config != SWITCH_GLOBAL) ? 0 : HIDDEN_ROW),
|
|
(uint8_t)((config != SWITCH_NONE && config != SWITCH_GLOBAL) ? 3 : HIDDEN_ROW),
|
|
(uint8_t)((config != SWITCH_NONE && config != SWITCH_GLOBAL) ? 0 : HIDDEN_ROW),
|
|
#endif
|
|
});
|
|
|
|
int8_t sub = menuVerticalPosition;
|
|
int8_t editMode = s_editMode;
|
|
|
|
coord_t y = MENU_HEADER_HEIGHT + 1;
|
|
|
|
#if defined(FUNCTION_SWITCHES_RGB_LEDS)
|
|
menuCFSpreview = false;
|
|
#endif
|
|
|
|
for (int k = 0; k < NUM_BODY_LINES; k += 1) {
|
|
int i = k + menuVerticalOffset;
|
|
for (int j = 0; j <= i; j += 1) {
|
|
if (j < (int)DIM(mstate_tab) && mstate_tab[j] == HIDDEN_ROW) {
|
|
i += 1;
|
|
}
|
|
}
|
|
LcdFlags attr = (sub == i ? (editMode > 0 ? BLINK | INVERS : INVERS) : 0);
|
|
|
|
switch(i) {
|
|
case CFS_FIELD_TYPE:
|
|
config = editChoice(RADIO_SETUP_2ND_COLUMN, y, STR_SWITCH_TYPE, STR_SWTYPES, config, SWITCH_NONE, SWITCH_3POS, attr, event, 0, checkCFSTypeAvailable);
|
|
if (attr && checkIncDec_Ret) {
|
|
g_eeGeneral.switchSetType(swIndex, (SwitchConfig)config);
|
|
if (config == SWITCH_NONE) {
|
|
#if defined(FUNCTION_SWITCHES_RGB_LEDS)
|
|
if (g_model.getSwitchType(swIndex) == SWITCH_NONE)
|
|
fsLedRGB(switchGetCustomSwitchIdx(swIndex), 0);
|
|
#endif
|
|
} else if (config == SWITCH_TOGGLE) {
|
|
setFSLogicalState(swIndex, 0);
|
|
g_eeGeneral.switchSetStart(swIndex, FS_START_PREVIOUS); // Toggle switches do not have startup position
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CFS_FIELD_NAME:
|
|
editSingleName(RADIO_SETUP_2ND_COLUMN, y, STR_NAME, g_eeGeneral.switchName(swIndex),
|
|
LEN_SWITCH_NAME, event, (attr != 0),
|
|
editMode);
|
|
break;
|
|
|
|
case CFS_FIELD_START:
|
|
lcdDrawText(0, y, STR_SWITCH_STARTUP);
|
|
lcdDrawText(RADIO_SETUP_2ND_COLUMN, y, _fct_sw_start[startPos], attr ? (s_editMode ? INVERS + BLINK : INVERS) : 0);
|
|
if (attr) {
|
|
startPos = checkIncDec(event, startPos, FS_START_OFF, FS_START_PREVIOUS, EE_MODEL);
|
|
g_eeGeneral.switchSetStart(swIndex, (fsStartPositionType)startPos);
|
|
}
|
|
break;
|
|
|
|
#if defined(FUNCTION_SWITCHES_RGB_LEDS)
|
|
case CFS_FIELD_COLOR_LABEL:
|
|
lcdDrawText(0, y, STR_BLCOLOR);
|
|
lcdDrawText(LCD_W - 6 * FW, y, "R", RIGHT | SMLSIZE);
|
|
lcdDrawText(LCD_W - 3 * FW, y, "G", RIGHT | SMLSIZE);
|
|
lcdDrawText(LCD_W, y, "B", RIGHT | SMLSIZE);
|
|
break;
|
|
|
|
case CFS_FIELD_ON_COLOR:
|
|
menuCFSColor(y, g_eeGeneral.switchOnColor(swIndex), STR_OFFON[1], attr, event);
|
|
break;
|
|
|
|
case CFS_FIELD_ON_LUA_OVERRIDE:
|
|
g_eeGeneral.cfsSetOnColorLuaOverride(swIndex, editCheckBox(g_eeGeneral.cfsOnColorLuaOverride(swIndex), LCD_W - 2 * FW, y, STR_LUA_OVERRIDE, attr, event, INDENT_WIDTH));
|
|
break;
|
|
|
|
case CFS_FIELD_OFF_COLOR:
|
|
menuCFSColor(y, g_eeGeneral.switchOffColor(swIndex), STR_OFFON[0], attr, event);
|
|
break;
|
|
|
|
case CFS_FIELD_OFF_LUA_OVERRIDE:
|
|
g_eeGeneral.cfsSetOffColorLuaOverride(swIndex, editCheckBox(g_eeGeneral.cfsOffColorLuaOverride(swIndex), LCD_W - 2 * FW, y, STR_LUA_OVERRIDE, attr, event, INDENT_WIDTH));
|
|
break;
|
|
#endif
|
|
}
|
|
|
|
y += FH;
|
|
}
|
|
|
|
#if defined(FUNCTION_SWITCHES_RGB_LEDS)
|
|
if (!menuCFSpreview)
|
|
setFSEditOverride(-1, 0);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
static uint8_t _dispSerialPort(uint8_t port_nr)
|
|
{
|
|
auto port = serialGetPort(port_nr);
|
|
if (!port || !port->name) return HIDDEN_ROW;
|
|
return 0;
|
|
}
|
|
|
|
static bool _isAux1ModeAvailable(int m) { return isSerialModeAvailable(SP_AUX1, m); }
|
|
static bool _isAux2ModeAvailable(int m) { return isSerialModeAvailable(SP_AUX2, m); }
|
|
static bool _isVCPModeAvailable(int m) { return isSerialModeAvailable(SP_VCP, m); }
|
|
|
|
static const IsValueAvailable _isSerialModeAvailable[MAX_SERIAL_PORTS] = {
|
|
_isAux1ModeAvailable, _isAux2ModeAvailable, _isVCPModeAvailable
|
|
};
|
|
|
|
static void _init_menu_tab_array(uint8_t* tab, size_t len)
|
|
{
|
|
memset((void*)tab, READONLY_ROW, sizeof(MENU_TAB_ARRAY_TYPE) * len);
|
|
tab += HEADER_LINE; // skip header line
|
|
|
|
tab[ITEM_RADIO_HARDWARE_LABEL_STICKS] = 0; // calib button
|
|
auto max_sticks = adcGetMaxInputs(ADC_INPUT_MAIN);
|
|
for (int i = ITEM_RADIO_HARDWARE_STICK; i <= ITEM_RADIO_HARDWARE_STICK_END; i++) {
|
|
uint8_t idx = i - ITEM_RADIO_HARDWARE_STICK;
|
|
tab[i] = idx < max_sticks ? 1 : HIDDEN_ROW;
|
|
}
|
|
|
|
auto max_pots = adcGetMaxInputs(ADC_INPUT_FLEX);
|
|
for (int i = ITEM_RADIO_HARDWARE_POT; i <= ITEM_RADIO_HARDWARE_POT_END; i++) {
|
|
uint8_t idx = i - ITEM_RADIO_HARDWARE_POT;
|
|
tab[i] = idx < max_pots ? (IS_POT_MULTIPOS(idx) ? 1 : 2) : HIDDEN_ROW;
|
|
}
|
|
|
|
int max_switches = switchGetMaxAllSwitches();
|
|
for (int i = ITEM_RADIO_HARDWARE_SWITCH; i <= ITEM_RADIO_HARDWARE_SWITCH_END; i++) {
|
|
uint8_t idx = i - ITEM_RADIO_HARDWARE_SWITCH;
|
|
if (idx < max_switches && !switchIsCustomSwitch(idx)) {
|
|
tab[i] = switchIsFlex(idx) ? 2 : 1;
|
|
} else {
|
|
tab[i] = HIDDEN_ROW;
|
|
}
|
|
}
|
|
#if defined (FUNCTION_SWITCHES)
|
|
for (int i = ITEM_RADIO_HARDWARE_CFS; i <= ITEM_RADIO_HARDWARE_CFS_END; i++) {
|
|
uint8_t idx = i - ITEM_RADIO_HARDWARE_CFS;
|
|
if (idx < max_switches && switchIsCustomSwitch(idx)) {
|
|
tab[i] = 0;
|
|
} else {
|
|
tab[i] = HIDDEN_ROW;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(BATTGRAPH)
|
|
tab[ITEM_RADIO_HARDWARE_BATT_RANGE] = 1;
|
|
#endif
|
|
tab[ITEM_RADIO_HARDWARE_BATTERY_CALIB] = 0;
|
|
tab[ITEM_RADIO_HARDWARE_RTC_BATTERY] = READONLY_ROW;
|
|
tab[ITEM_RADIO_HARDWARE_RTC_CHECK] = 0;
|
|
#if defined(AUDIO_MUTE_GPIO)
|
|
tab[ITEM_RADIO_HARDWARE_AUDIO_MUTE] = 0;
|
|
#endif
|
|
#if defined(HARDWARE_INTERNAL_MODULE)
|
|
tab[ITEM_RADIO_HARDWARE_INTERNAL_MODULE_TYPE] = 0;
|
|
tab[ITEM_RADIO_HARDWARE_INTERNAL_MODULE_BAUDRATE] =
|
|
isInternalModuleCrossfire() ? (uint8_t)0 : HIDDEN_ROW;
|
|
#else
|
|
memset((void*)&tab[ITEM_RADIO_HARDWARE_LABEL_INTERNAL_MODULE], HIDDEN_ROW, 3);
|
|
#endif
|
|
|
|
#if defined(HARDWARE_EXTERNAL_MODULE) && (defined(STM32F2) || defined(STM32F4))
|
|
tab[ITEM_RADIO_HARDWARE_SERIAL_SAMPLE_MODE] = 0;
|
|
#else
|
|
tab[ITEM_RADIO_HARDWARE_SERIAL_SAMPLE_MODE] = HIDDEN_ROW;
|
|
#endif
|
|
|
|
#if defined(BLUETOOTH)
|
|
bool has_bt = IS_BLUETOOTH_CHIP_PRESENT();
|
|
tab[ITEM_RADIO_HARDWARE_BLUETOOTH_MODE] = has_bt ? 0 : HIDDEN_ROW;
|
|
|
|
bool bt_telem = g_eeGeneral.bluetoothMode == BLUETOOTH_TELEMETRY;
|
|
tab[ITEM_RADIO_HARDWARE_BLUETOOTH_PAIRING_CODE] = bt_telem ? READONLY_ROW : HIDDEN_ROW;
|
|
|
|
bool bt_off = g_eeGeneral.bluetoothMode == BLUETOOTH_OFF;
|
|
tab[ITEM_RADIO_HARDWARE_BLUETOOTH_LOCAL_ADDR] = bt_off ? HIDDEN_ROW : READONLY_ROW;
|
|
tab[ITEM_RADIO_HARDWARE_BLUETOOTH_DISTANT_ADDR] = bt_off ? HIDDEN_ROW : READONLY_ROW;
|
|
tab[ITEM_RADIO_HARDWARE_BLUETOOTH_NAME] = bt_off ? HIDDEN_ROW : 0;
|
|
#endif
|
|
|
|
#if defined(EXTERNAL_ANTENNA)
|
|
tab[ITEM_RADIO_HARDWARE_EXTERNAL_ANTENNA] =
|
|
#if defined(INTMODULE_ANTSEL_GPIO)
|
|
0;
|
|
#else
|
|
g_eeGeneral.internalModule == MODULE_TYPE_XJT_PXX1 ? 0 : HIDDEN_ROW;
|
|
#endif
|
|
#endif
|
|
|
|
bool has_serial = false;
|
|
for (int i = 0; i < MAX_SERIAL_PORTS; i++) {
|
|
uint8_t idx = ITEM_RADIO_HARDWARE_SERIAL_PORT + i;
|
|
auto r = _dispSerialPort(i);
|
|
tab[idx] = r;
|
|
has_serial = has_serial || (!r);
|
|
}
|
|
tab[ITEM_RADIO_HARDWARE_SERIAL_PORT_LABEL] = has_serial ? READONLY_ROW : HIDDEN_ROW;
|
|
tab[ITEM_RADIO_HARDWARE_JITTER_FILTER] = 0;
|
|
tab[ITEM_RADIO_HARDWARE_RAS] = READONLY_ROW;
|
|
|
|
auto mod_desc = modulePortGetModuleDescription(SPORT_MODULE);
|
|
if (mod_desc && mod_desc->set_pwr) {
|
|
tab[ITEM_RADIO_HARDWARE_SPORT_UPDATE_POWER] = 0;
|
|
} else {
|
|
tab[ITEM_RADIO_HARDWARE_SPORT_UPDATE_POWER] = HIDDEN_ROW;
|
|
}
|
|
|
|
#if (defined(BACKLIGHT_GPIO) || OLED_SCREEN) && (LCD_W == 128)
|
|
tab[ITEM_RADIO_HARDWARE_SCREEN_LABEL] = READONLY_ROW;
|
|
tab[ITEM_RADIO_HARDWARE_SCREEN_INVERT] = 0;
|
|
#endif
|
|
|
|
tab[ITEM_RADIO_HARDWARE_DEBUG] = 1;
|
|
#if defined(FUNCTION_SWITCHES)
|
|
tab[ITEM_RADIO_HARDWARE_DEBUG_FS] = 0;
|
|
#endif
|
|
}
|
|
|
|
static bool editInversion(bool state, event_t event, coord_t y, LcdFlags flags)
|
|
{
|
|
lcdDrawChar(LCD_W - 8, y, state ? 127 : 126, flags);
|
|
if (flags & (~RIGHT)) state = checkIncDec(event, state, 0, 1, EE_GENERAL);
|
|
return state;
|
|
}
|
|
|
|
void menuRadioHardware(event_t event)
|
|
{
|
|
uint8_t old_editMode = s_editMode;
|
|
|
|
uint8_t MENU_TAB_ARRAY_NAME[HEADER_LINE + ITEM_RADIO_HARDWARE_MAX];
|
|
_init_menu_tab_array(MENU_TAB_ARRAY_NAME, HEADER_LINE + ITEM_RADIO_HARDWARE_MAX);
|
|
|
|
MENU_CHECK(menuTabGeneral, MENU_RADIO_HARDWARE, HEADER_LINE + ITEM_RADIO_HARDWARE_MAX);
|
|
title(STR_HARDWARE);
|
|
|
|
uint8_t sub = menuVerticalPosition - HEADER_LINE;
|
|
|
|
#if defined(BLUETOOTH)
|
|
if (g_eeGeneral.bluetoothMode != BLUETOOTH_OFF && !IS_BLUETOOTH_CHIP_PRESENT()) {
|
|
g_eeGeneral.bluetoothMode = BLUETOOTH_OFF;
|
|
storageDirty(EE_GENERAL);
|
|
}
|
|
#endif
|
|
|
|
if (menuEvent) {
|
|
disableVBatBridge();
|
|
}
|
|
else if (event == EVT_ENTRY) {
|
|
enableVBatBridge();
|
|
#if defined(EXTERNAL_ANTENNA)
|
|
reusableBuffer.radioHardware.antennaMode = g_eeGeneral.antennaMode;
|
|
#endif
|
|
}
|
|
|
|
for (uint8_t 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 + HEADER_LINE] == HIDDEN_ROW) {
|
|
k++;
|
|
}
|
|
}
|
|
LcdFlags blink = ((s_editMode>0) ? BLINK|INVERS : INVERS);
|
|
LcdFlags attr = (sub == k ? blink : 0);
|
|
|
|
switch(k) {
|
|
case ITEM_RADIO_HARDWARE_LABEL_STICKS:
|
|
lcdDrawTextAlignedLeft(y, STR_STICKS);
|
|
lcdDrawText(HW_SETTINGS_COLUMN2, y, STR_CALIBRATION, attr);
|
|
if (attr && event == EVT_KEY_BREAK(KEY_ENTER)) {
|
|
pushMenu(menuRadioCalibration);
|
|
}
|
|
break;
|
|
|
|
case ITEM_RADIO_HARDWARE_LABEL_POTS:
|
|
lcdDrawTextAlignedLeft(y, STR_POTS);
|
|
break;
|
|
|
|
case ITEM_RADIO_HARDWARE_LABEL_SWITCHES:
|
|
lcdDrawTextAlignedLeft(y, STR_SWITCHES);
|
|
break;
|
|
|
|
#if defined(FUNCTION_SWITCHES)
|
|
case ITEM_RADIO_HARDWARE_LABEL_CFS:
|
|
lcdDrawTextAlignedLeft(y, STR_FUNCTION_SWITCHES);
|
|
break;
|
|
#endif
|
|
|
|
#if defined(BATTGRAPH)
|
|
case ITEM_RADIO_HARDWARE_BATT_RANGE:
|
|
lcdDrawTextAlignedLeft(y, STR_BATTERY_RANGE);
|
|
putsVolts(HW_SETTINGS_COLUMN3, y, 90+g_eeGeneral.vBatMin, (menuHorizontalPosition==0 ? attr : 0)|NO_UNIT);
|
|
lcdDrawChar(lcdNextPos, y, '-');
|
|
putsVolts(lcdNextPos, y, 120+g_eeGeneral.vBatMax, (menuHorizontalPosition>0 ? attr : 0)|NO_UNIT);
|
|
if (attr && s_editMode>0) {
|
|
if (menuHorizontalPosition==0)
|
|
CHECK_INCDEC_GENVAR(event, g_eeGeneral.vBatMin, -60, g_eeGeneral.vBatMax+29); // min=3.0V
|
|
else
|
|
CHECK_INCDEC_GENVAR(event, g_eeGeneral.vBatMax, g_eeGeneral.vBatMin-29, +40); // max=16.0V
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
case ITEM_RADIO_HARDWARE_BATTERY_CALIB:
|
|
lcdDrawTextAlignedLeft(y, STR_BATT_CALIB);
|
|
putsVolts(HW_SETTINGS_COLUMN3, y, getBatteryVoltage(), attr|PREC2|LEFT);
|
|
if (attr) {
|
|
CHECK_INCDEC_GENVAR(event, g_eeGeneral.txVoltageCalibration, -127, 127);
|
|
}
|
|
break;
|
|
|
|
case ITEM_RADIO_HARDWARE_RTC_BATTERY:
|
|
lcdDrawTextAlignedLeft(y, STR_RTC_BATT);
|
|
putsVolts(HW_SETTINGS_COLUMN3, y, getRTCBatteryVoltage(), PREC2|LEFT);
|
|
break;
|
|
|
|
case ITEM_RADIO_HARDWARE_RTC_CHECK:
|
|
g_eeGeneral.disableRtcWarning = 1 - editCheckBox(1 - g_eeGeneral.disableRtcWarning, HW_SETTINGS_COLUMN2, y, STR_RTC_CHECK, attr, event);
|
|
break;
|
|
|
|
case ITEM_RADIO_HARDWARE_LABEL_INTERNAL_MODULE:
|
|
lcdDrawTextAlignedLeft(y, STR_INTERNALRF);
|
|
break;
|
|
|
|
case ITEM_RADIO_HARDWARE_INTERNAL_MODULE_TYPE: {
|
|
g_eeGeneral.internalModule =
|
|
editChoice(HW_SETTINGS_COLUMN2, y, STR_TYPE,
|
|
STR_MODULE_PROTOCOLS,
|
|
g_eeGeneral.internalModule, MODULE_TYPE_NONE,
|
|
MODULE_TYPE_MAX, attr, event, INDENT_WIDTH, isInternalModuleSupported);
|
|
if (g_model.moduleData[INTERNAL_MODULE].type !=
|
|
g_eeGeneral.internalModule) {
|
|
memclear(&g_model.moduleData[INTERNAL_MODULE], sizeof(ModuleData));
|
|
storageDirty(EE_MODEL);
|
|
storageDirty(EE_GENERAL);
|
|
#if defined(CROSSFIRE) && defined(USB_SERIAL)
|
|
// If USB-VCP was off, set it to CLI to enable passthrough flashing
|
|
if (isInternalModuleCrossfire() && serialGetMode(SP_VCP) == UART_MODE_NONE)
|
|
serialSetMode(SP_VCP, UART_MODE_CLI);
|
|
#endif
|
|
}
|
|
} break;
|
|
|
|
#if defined(AUDIO_MUTE_GPIO)
|
|
case ITEM_RADIO_HARDWARE_AUDIO_MUTE:
|
|
g_eeGeneral.audioMuteEnable = editCheckBox(g_eeGeneral.audioMuteEnable, HW_SETTINGS_COLUMN2, y, STR_AUDIO_MUTE, attr, event);
|
|
break;
|
|
#endif
|
|
|
|
case ITEM_RADIO_HARDWARE_INTERNAL_MODULE_BAUDRATE:
|
|
lcdDrawTextIndented(y, STR_BAUDRATE);
|
|
lcdDrawTextAtIndex(HW_SETTINGS_COLUMN2, y, STR_CRSF_BAUDRATE, CROSSFIRE_STORE_TO_INDEX(g_eeGeneral.internalModuleBaudrate),attr | LEFT);
|
|
if (attr) {
|
|
g_eeGeneral.internalModuleBaudrate = CROSSFIRE_INDEX_TO_STORE(checkIncDecModel(event, CROSSFIRE_STORE_TO_INDEX(g_eeGeneral.internalModuleBaudrate), 0, CROSSFIRE_MAX_INTERNAL_BAUDRATE));
|
|
if (checkIncDec_Ret) {
|
|
restartModule(INTERNAL_MODULE);
|
|
}
|
|
}
|
|
break;
|
|
|
|
#if defined(STM32F2) || defined(STM32F4)
|
|
case ITEM_RADIO_HARDWARE_SERIAL_SAMPLE_MODE:
|
|
g_eeGeneral.uartSampleMode = editChoice(HW_SETTINGS_COLUMN2, y, STR_SAMPLE_MODE, STR_SAMPLE_MODES, g_eeGeneral.uartSampleMode, 0, UART_SAMPLE_MODE_MAX, attr, event);
|
|
if (attr && checkIncDec_Ret) {
|
|
restartModule(EXTERNAL_MODULE);
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
#if defined(BLUETOOTH)
|
|
case ITEM_RADIO_HARDWARE_BLUETOOTH_MODE:
|
|
lcdDrawTextAlignedLeft(y, STR_BLUETOOTH);
|
|
lcdDrawTextAtIndex(HW_SETTINGS_COLUMN2, y, STR_BLUETOOTH_MODES, g_eeGeneral.bluetoothMode, attr);
|
|
if (attr) {
|
|
g_eeGeneral.bluetoothMode = checkIncDecGen(event, g_eeGeneral.bluetoothMode, BLUETOOTH_OFF, BLUETOOTH_MAX);
|
|
}
|
|
break;
|
|
|
|
case ITEM_RADIO_HARDWARE_BLUETOOTH_PAIRING_CODE:
|
|
lcdDrawTextIndented(y, STR_BLUETOOTH_PIN_CODE);
|
|
lcdDrawText(HW_SETTINGS_COLUMN2, y, "000000");
|
|
break;
|
|
|
|
case ITEM_RADIO_HARDWARE_BLUETOOTH_LOCAL_ADDR:
|
|
lcdDrawTextIndented(y, STR_BLUETOOTH_LOCAL_ADDR);
|
|
lcdDrawText(HW_SETTINGS_COLUMN2, y, bluetooth.localAddr[0] == '\0' ? "---" : bluetooth.localAddr);
|
|
break;
|
|
|
|
case ITEM_RADIO_HARDWARE_BLUETOOTH_DISTANT_ADDR:
|
|
lcdDrawTextIndented(y, STR_BLUETOOTH_DIST_ADDR);
|
|
lcdDrawText(HW_SETTINGS_COLUMN2, y, bluetooth.distantAddr[0] == '\0' ? "---" : bluetooth.distantAddr);
|
|
break;
|
|
|
|
case ITEM_RADIO_HARDWARE_BLUETOOTH_NAME:
|
|
lcdDrawTextIndented(y, STR_NAME);
|
|
editName(HW_SETTINGS_COLUMN2, y, g_eeGeneral.bluetoothName,
|
|
LEN_BLUETOOTH_NAME, event, (attr != 0), attr, old_editMode);
|
|
break;
|
|
#endif
|
|
|
|
#if defined(EXTERNAL_ANTENNA)
|
|
case ITEM_RADIO_HARDWARE_EXTERNAL_ANTENNA:
|
|
reusableBuffer.radioHardware.antennaMode = editChoice(HW_SETTINGS_COLUMN2, y, STR_ANTENNA, STR_ANTENNA_MODES, reusableBuffer.radioHardware.antennaMode, ANTENNA_MODE_INTERNAL, ANTENNA_MODE_EXTERNAL, attr, event);
|
|
if (!s_editMode && reusableBuffer.radioHardware.antennaMode != g_eeGeneral.antennaMode) {
|
|
if (!isExternalAntennaEnabled() && (reusableBuffer.radioHardware.antennaMode == ANTENNA_MODE_EXTERNAL || (reusableBuffer.radioHardware.antennaMode == ANTENNA_MODE_PER_MODEL && g_model.moduleData[INTERNAL_MODULE].antennaMode == ANTENNA_MODE_EXTERNAL))) {
|
|
POPUP_CONFIRMATION(STR_ANTENNACONFIRM1, onHardwareAntennaSwitchConfirm);
|
|
SET_WARNING_INFO(STR_ANTENNACONFIRM2, strlen(STR_ANTENNACONFIRM2), 0);
|
|
}
|
|
else {
|
|
g_eeGeneral.antennaMode = reusableBuffer.radioHardware.antennaMode;
|
|
checkExternalAntenna();
|
|
}
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
case ITEM_RADIO_HARDWARE_SERIAL_PORT_LABEL:
|
|
lcdDrawTextAlignedLeft(y, STR_AUX_SERIAL_MODE);
|
|
break;
|
|
|
|
case ITEM_RADIO_HARDWARE_JITTER_FILTER:
|
|
g_eeGeneral.noJitterFilter =
|
|
1 - editCheckBox(1 - g_eeGeneral.noJitterFilter,
|
|
HW_SETTINGS_COLUMN2, y, STR_JITTER_FILTER, attr,
|
|
event);
|
|
break;
|
|
|
|
case ITEM_RADIO_HARDWARE_RAS:
|
|
#if defined(HARDWARE_INTERNAL_RAS)
|
|
lcdDrawTextAlignedLeft(y, "RAS");
|
|
if (telemetryData.swrInternal.isFresh())
|
|
lcdDrawNumber(HW_SETTINGS_COLUMN2, y, telemetryData.swrInternal.value());
|
|
else
|
|
lcdDrawText(HW_SETTINGS_COLUMN2, y, "---");
|
|
lcdDrawText(lcdNextPos, y, "/");
|
|
#else
|
|
lcdDrawTextAlignedLeft(y, "Ext. RAS");
|
|
lcdNextPos = HW_SETTINGS_COLUMN2;
|
|
#endif
|
|
if (telemetryData.swrExternal.isFresh())
|
|
lcdDrawNumber(lcdNextPos, y, telemetryData.swrExternal.value());
|
|
else
|
|
lcdDrawText(lcdNextPos, y, "---");
|
|
break;
|
|
|
|
case ITEM_RADIO_HARDWARE_SPORT_UPDATE_POWER:
|
|
g_eeGeneral.sportUpdatePower = editChoice(HW_SETTINGS_COLUMN2, y, STR_SPORT_UPDATE_POWER_MODE, STR_SPORT_UPDATE_POWER_MODES, g_eeGeneral.sportUpdatePower, 0, 1, attr, event);
|
|
if (attr && checkIncDec_Ret) {
|
|
modulePortSetPower(SPORT_MODULE, g_eeGeneral.sportUpdatePower);
|
|
}
|
|
break;
|
|
|
|
#if (defined(BACKLIGHT_GPIO) || OLED_SCREEN) && (LCD_W == 128)
|
|
case ITEM_RADIO_HARDWARE_SCREEN_LABEL:
|
|
lcdDrawTextAlignedLeft(y, STR_SCREEN);
|
|
break;
|
|
case ITEM_RADIO_HARDWARE_SCREEN_INVERT:
|
|
{
|
|
lcdDrawText(INDENT_WIDTH, y, STR_MENU_INVERT);
|
|
bool inv = g_eeGeneral.invertLCD;
|
|
g_eeGeneral.invertLCD = editCheckBox(g_eeGeneral.invertLCD, HW_SETTINGS_COLUMN2, y, nullptr, attr, event);
|
|
if (inv != g_eeGeneral.invertLCD)
|
|
lcdSetInvert(g_eeGeneral.invertLCD);
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
case ITEM_RADIO_HARDWARE_DEBUG:
|
|
lcdDrawTextAlignedLeft(y, STR_DEBUG);
|
|
lcdDrawText(HW_SETTINGS_COLUMN2, y, STR_ANALOGS_BTN, menuHorizontalPosition == 0 ? attr : 0);
|
|
lcdDrawText(lcdLastRightPos + 2, y, STR_KEYS_BTN, menuHorizontalPosition == 1 ? attr : 0);
|
|
if (attr && event == EVT_KEY_BREAK(KEY_ENTER)) {
|
|
if (menuHorizontalPosition == 0)
|
|
pushMenu(menuRadioDiagAnalogs);
|
|
else
|
|
pushMenu(menuRadioDiagKeys);
|
|
}
|
|
break;
|
|
#if defined(FUNCTION_SWITCHES)
|
|
case ITEM_RADIO_HARDWARE_DEBUG_FS:
|
|
lcdDrawText(HW_SETTINGS_COLUMN2, y, STR_FS_BTN, attr);
|
|
if (attr && event == EVT_KEY_BREAK(KEY_ENTER)) {
|
|
pushMenu(menuRadioDiagFS);
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
if (k <= ITEM_RADIO_HARDWARE_STICK_END) {
|
|
// Sticks
|
|
int idx = k - ITEM_RADIO_HARDWARE_STICK;
|
|
|
|
editStickHardwareSettings(HW_SETTINGS_COLUMN1, y, idx, event,
|
|
menuHorizontalPosition == 0 ? attr : 0, old_editMode);
|
|
// ADC inversion
|
|
setStickInversion(idx, editInversion(getStickInversion(idx), event, y, menuHorizontalPosition == 1 ? attr : 0));
|
|
|
|
} else if (k <= ITEM_RADIO_HARDWARE_POT_END) {
|
|
// Pots & sliders
|
|
int idx = k - ITEM_RADIO_HARDWARE_POT;
|
|
|
|
// draw hw name
|
|
LcdFlags flags = menuHorizontalPosition < 0 ? attr : 0;
|
|
lcdDrawText(INDENT_WIDTH, y, CHAR_POT, flags);
|
|
lcdDrawText(lcdNextPos, y, adcGetInputLabel(ADC_INPUT_FLEX, idx), flags);
|
|
|
|
// draw custom name
|
|
if (analogHasCustomLabel(ADC_INPUT_FLEX, idx) ||
|
|
(attr && s_editMode > 0 && menuHorizontalPosition == 0)) {
|
|
editName(HW_SETTINGS_COLUMN1, y,
|
|
(char*)analogGetCustomLabel(ADC_INPUT_FLEX, idx), LEN_ANA_NAME, event,
|
|
attr && menuHorizontalPosition == 0, 0, old_editMode);
|
|
} else {
|
|
lcdDrawMMM(HW_SETTINGS_COLUMN1, y, menuHorizontalPosition==0 ? attr : 0);
|
|
}
|
|
|
|
// pot config
|
|
uint8_t potType = getPotType(idx);
|
|
potType = editChoice(HW_SETTINGS_COLUMN2, y, "", STR_POTTYPES, potType,
|
|
FLEX_NONE, FLEX_SWITCH,
|
|
menuHorizontalPosition == 1 ? attr : 0, event);
|
|
if (checkIncDec_Ret) switchFixFlexConfig();
|
|
setPotType(idx, potType);
|
|
|
|
if (!IS_POT_MULTIPOS(idx)) {
|
|
// ADC inversion
|
|
setPotInversion(idx, editInversion(getPotInversion(idx), event, y, menuHorizontalPosition == 2 ? attr : 0));
|
|
} else if (getPotInversion(idx)) {
|
|
setPotInversion(idx, 0);
|
|
storageDirty(EE_GENERAL);
|
|
}
|
|
} else if (k <= ITEM_RADIO_HARDWARE_SWITCH_END) {
|
|
// Switches
|
|
int index = k - ITEM_RADIO_HARDWARE_SWITCH;
|
|
int config = g_eeGeneral.switchType(index);
|
|
|
|
LcdFlags flags = menuHorizontalPosition < 0 ? attr : 0;
|
|
lcdDrawText(INDENT_WIDTH, y, CHAR_SWITCH, flags);
|
|
lcdDrawText(lcdNextPos, y, switchGetDefaultName(index), flags);
|
|
|
|
if (switchIsFlex(index)) {
|
|
// flexSwitch source
|
|
flags = menuHorizontalPosition == 0 ? attr : 0;
|
|
auto source = switchGetFlexConfig(index);
|
|
lcdDrawText(HW_SETTINGS_COLUMN1, y, (source < 0) ? STR_NONE : adcGetInputLabel(ADC_INPUT_FLEX, source), flags);
|
|
if (flags & (~RIGHT)) source = checkIncDec(event, source, -1, adcGetMaxInputs(ADC_INPUT_FLEX) - 1, EE_GENERAL, isFlexSwitchSourceValid);
|
|
switchConfigFlex(index, source);
|
|
|
|
//Name
|
|
flags = menuHorizontalPosition == 1 ? attr : 0;
|
|
if (g_eeGeneral.switchHasCustomName(index) ||
|
|
(attr && s_editMode > 0 && menuHorizontalPosition == 1)) {
|
|
editName(HW_SETTINGS_COLUMN2, y,
|
|
g_eeGeneral.getSwitchCustomName(index), LEN_SWITCH_NAME,
|
|
event, flags, 0, old_editMode);
|
|
} else {
|
|
lcdDrawMMM(HW_SETTINGS_COLUMN2, y, flags);
|
|
}
|
|
|
|
// Switch type
|
|
flags = menuHorizontalPosition == 2 ? attr : 0;
|
|
config = editChoice(HW_SETTINGS_COLUMN2 + 25, y, "", STR_SWTYPES, config,
|
|
SWITCH_NONE, switchGetMaxType(index), flags, event);
|
|
|
|
if (attr && checkIncDec_Ret) {
|
|
g_eeGeneral.switchSetType(index, (SwitchConfig)config);
|
|
}
|
|
} else {
|
|
flags = menuHorizontalPosition == 0 ? attr : 0;
|
|
if (g_eeGeneral.switchHasCustomName(index) ||
|
|
(attr && s_editMode > 0 && menuHorizontalPosition == 0)) {
|
|
editName(HW_SETTINGS_COLUMN1, y,
|
|
g_eeGeneral.getSwitchCustomName(index), LEN_SWITCH_NAME,
|
|
event, flags, 0, old_editMode);
|
|
} else {
|
|
lcdDrawMMM(HW_SETTINGS_COLUMN1, y, flags);
|
|
}
|
|
|
|
flags = menuHorizontalPosition == 1 ? attr : 0;
|
|
config =
|
|
editChoice(HW_SETTINGS_COLUMN2, y, "", STR_SWTYPES, config,
|
|
SWITCH_NONE, switchGetMaxType(index), flags, event);
|
|
|
|
if (attr && checkIncDec_Ret) {
|
|
g_eeGeneral.switchSetType(index, (SwitchConfig)config);
|
|
}
|
|
}
|
|
#if defined(FUNCTION_SWITCHES)
|
|
} else if (k <= ITEM_RADIO_HARDWARE_CFS_END) {
|
|
// Customisable Switches
|
|
int index = k - ITEM_RADIO_HARDWARE_CFS;
|
|
int config = g_eeGeneral.switchType(index);
|
|
|
|
lcdDrawText(INDENT_WIDTH, y, CHAR_SWITCH, attr);
|
|
lcdDrawText(lcdNextPos, y, switchGetDefaultName(index), attr);
|
|
|
|
lcdDrawText(HW_SETTINGS_COLUMN2, y, STR_SWTYPES[config]);
|
|
|
|
if (attr && event == EVT_KEY_BREAK(KEY_ENTER)) {
|
|
swIndex = index;
|
|
pushMenu(menuRadioCFSOne);
|
|
}
|
|
|
|
if (config != SWITCH_NONE) {
|
|
if (g_eeGeneral.switchName(index)[0]) {
|
|
char s[LEN_SWITCH_NAME + 1];
|
|
strAppend(s, g_eeGeneral.switchName(index), LEN_SWITCH_NAME);
|
|
lcdDrawText(HW_SETTINGS_COLUMN1, y, s);
|
|
} else {
|
|
lcdDrawMMM(HW_SETTINGS_COLUMN1, y, 0);
|
|
}
|
|
|
|
uint8_t group = g_eeGeneral.switchGroup(index);
|
|
// lcdDrawText(30 + 13 * FW, y, STR_FSGROUPS[group]);
|
|
|
|
if (config != SWITCH_TOGGLE && group == 0) {
|
|
int startPos = g_eeGeneral.switchStart(index);
|
|
lcdDrawText(30 + 15 * FW, y, _fct_sw_start[startPos]);
|
|
}
|
|
}
|
|
#endif
|
|
} else if (k <= ITEM_RADIO_HARDWARE_SERIAL_PORT_END) {
|
|
auto port_nr = k - ITEM_RADIO_HARDWARE_SERIAL_PORT;
|
|
auto port = serialGetPort(port_nr);
|
|
if (port && port->name) {
|
|
lcdDrawTextIndented(y, port->name);
|
|
|
|
auto mode = serialGetMode(port_nr);
|
|
mode = editChoice(HW_SETTINGS_COLUMN2, y, nullptr,
|
|
STR_AUX_SERIAL_MODES, mode, 0, UART_MODE_MAX, attr,
|
|
event, 0, _isSerialModeAvailable[port_nr]);
|
|
|
|
if (attr && checkIncDec_Ret) {
|
|
serialSetMode(port_nr, mode);
|
|
serialInit(port_nr, mode);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|