From 9eca49df42f6e645cb504887aea222a0e8e805b5 Mon Sep 17 00:00:00 2001 From: 3djc Date: Fri, 26 Apr 2019 13:12:47 +0200 Subject: [PATCH] Horus : Tools --- radio/src/gui/480x272/gui.h | 1 + radio/src/gui/480x272/menu_radio.cpp | 3 +- radio/src/gui/480x272/menus.h | 4 + radio/src/gui/480x272/radio_power_meter.cpp | 126 ++++++++++++++++++ .../gui/480x272/radio_spectrum_analyser.cpp | 105 +++++++++++++++ radio/src/gui/480x272/radio_tools.cpp | 80 +++++++++++ radio/src/gui/common/colorlcd/widgets.cpp | 26 ++++ radio/src/targets/horus/CMakeLists.txt | 3 + 8 files changed, 347 insertions(+), 1 deletion(-) create mode 100644 radio/src/gui/480x272/radio_power_meter.cpp create mode 100644 radio/src/gui/480x272/radio_spectrum_analyser.cpp create mode 100644 radio/src/gui/480x272/radio_tools.cpp diff --git a/radio/src/gui/480x272/gui.h b/radio/src/gui/480x272/gui.h index 38e683b22..faceac2b9 100644 --- a/radio/src/gui/480x272/gui.h +++ b/radio/src/gui/480x272/gui.h @@ -87,6 +87,7 @@ void drawCurveVerticalScale(int x); void drawCurveHorizontalScale(); void drawCurveCoord(int x, int y, const char * text, bool active=false); void drawCurvePoint(int x, int y, LcdFlags color); +void drawPower(coord_t x, coord_t y, int8_t dBm, LcdFlags att = 0); extern Layout * customScreens[MAX_CUSTOM_SCREENS]; extern Topbar * topbar; diff --git a/radio/src/gui/480x272/menu_radio.cpp b/radio/src/gui/480x272/menu_radio.cpp index eab69242e..a86fc0935 100644 --- a/radio/src/gui/480x272/menu_radio.cpp +++ b/radio/src/gui/480x272/menu_radio.cpp @@ -2,7 +2,7 @@ * Copyright (C) OpenTX * * Based on code named - * th9x - http://code.google.com/p/th9x + * th9x - http://code.google.com/p/th9x * er9x - http://code.google.com/p/er9x * gruvin9x - http://code.google.com/p/gruvin9x * @@ -23,6 +23,7 @@ const MenuHandlerFunc menuTabGeneral[] = { menuRadioSetup, menuRadioSdManager, + menuRadioTools, menuRadioSpecialFunctions, menuRadioTrainer, menuRadioHardware, diff --git a/radio/src/gui/480x272/menus.h b/radio/src/gui/480x272/menus.h index dbd1000ab..b61d9a4dd 100644 --- a/radio/src/gui/480x272/menus.h +++ b/radio/src/gui/480x272/menus.h @@ -194,6 +194,7 @@ extern const MenuHandlerFunc menuTabModel[MENU_MODEL_PAGES_COUNT]; enum EnumTabRadio { MENU_RADIO_SETUP, MENU_RADIO_SD_MANAGER, + MENU_RADIO_TOOLS, MENU_RADIO_SPECIAL_FUNCTIONS, MENU_RADIO_TRAINER, MENU_RADIO_HARDWARE, @@ -203,6 +204,7 @@ enum EnumTabRadio { bool menuRadioSetup(event_t event); bool menuRadioSdManager(event_t event); +bool menuRadioTools(event_t event); bool menuRadioSpecialFunctions(event_t event); bool menuRadioTrainer(event_t event); bool menuRadioVersion(event_t event); @@ -261,6 +263,8 @@ bool menuAboutView(event_t event); bool menuMainViewChannelsMonitor(event_t event); bool menuTextView(event_t event); bool menuScreensTheme(event_t event); +bool menuRadioSpectrumAnalyser(event_t event); +bool menuRadioPowerMeter(event_t event); typedef uint16_t FlightModesType; diff --git a/radio/src/gui/480x272/radio_power_meter.cpp b/radio/src/gui/480x272/radio_power_meter.cpp new file mode 100644 index 000000000..1e4983c19 --- /dev/null +++ b/radio/src/gui/480x272/radio_power_meter.cpp @@ -0,0 +1,126 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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 +#include "opentx.h" + +extern uint8_t g_moduleIdx; + +enum PowerMeterFields { + POWER_METER_FREQ_RANGE, + POWER_METER_ATTENUATOR, + POWER_METER_MAX, + POWER_METER_POWER, + POWER_METER_PEAK, + POWER_METER_FIELDS_MAX +}; + +#define POWER_METER_MARGIN_2ND_COLUMN 180 + +bool menuRadioPowerMeter(event_t event) +{ + SIMPLE_SUBMENU(STR_MENU_POWER_METER, ICON_RADIO, POWER_METER_FIELDS_MAX-1); + + if (TELEMETRY_STREAMING()) { + lcdDrawCenteredText(LCD_H/2, STR_TURN_OFF_RECEIVER); + if (event == EVT_KEY_FIRST(KEY_EXIT)) { + killEvents(event); + popMenu(); + } + return true; + } + + if (menuEvent) { + lcdDrawCenteredText(LCD_H/2, STR_STOPPING); + lcdRefresh(); + moduleState[g_moduleIdx].mode = MODULE_MODE_NORMAL; + /* wait 1s to resume normal operation before leaving */ + watchdogSuspend(1000); + RTOS_WAIT_MS(1000); + return true; + } + + if (moduleState[g_moduleIdx].mode != MODULE_MODE_POWER_METER) { + memclear(&reusableBuffer.powerMeter, sizeof(reusableBuffer.powerMeter)); + reusableBuffer.powerMeter.freq = 2400000000; + reusableBuffer.powerMeter.attn = 4; + moduleState[g_moduleIdx].mode = MODULE_MODE_POWER_METER; + } + + // The warning + if (reusableBuffer.powerMeter.attn != 0) + lcdDrawCenteredText(MENU_CONTENT_TOP, STR_POWERMETER_ATTN_NEEDED, BOLD); + + for (uint8_t i=0; i 0 ? INVERS | BLINK : INVERS) : 0); + coord_t y = MENU_CONTENT_TOP + 30 + i * FH; + + switch (i) { + case POWER_METER_FREQ_RANGE: + lcdDrawText(MENUS_MARGIN_LEFT, y, STR_POWERMETER_FREQ); + lcdDrawNumber(POWER_METER_MARGIN_2ND_COLUMN, y, reusableBuffer.powerMeter.freq / 1000000, LEFT | attr); + lcdDrawText(lcdNextPos, y, " MHz band"); + if (attr) { + reusableBuffer.powerMeter.freq = checkIncDec(event, reusableBuffer.powerMeter.freq == 900000000, 0, 1) ? 900000000 : 2400000000; + if (checkIncDec_Ret) { + reusableBuffer.powerMeter.power = 0; + reusableBuffer.powerMeter.peak = 0; + } + } + break; + + case POWER_METER_ATTENUATOR: + lcdDrawText(MENUS_MARGIN_LEFT, y, STR_POWERMETER_ATTN); + lcdDrawNumber(POWER_METER_MARGIN_2ND_COLUMN, y, -10 * reusableBuffer.powerMeter.attn, LEFT | attr); + lcdDrawText(lcdNextPos, y, " dB"); + if (attr) { + reusableBuffer.powerMeter.attn = checkIncDec(event, reusableBuffer.powerMeter.attn, 0, 5, 0); + } + break; + + case POWER_METER_MAX: + lcdDrawText(MENUS_MARGIN_LEFT, y, STR_MAX); + lcdDrawNumber(POWER_METER_MARGIN_2ND_COLUMN, y, -10 + 10 * reusableBuffer.powerMeter.attn); + lcdDrawText(lcdNextPos, y, "dBm/ "); + drawPower(lcdNextPos, y, -10 + 10 * reusableBuffer.powerMeter.attn, 0); + if (attr) { + reusableBuffer.powerMeter.attn = checkIncDec(event, reusableBuffer.powerMeter.attn, 0, 5, 0); + } + break; + + case POWER_METER_POWER: + lcdDrawText(MENUS_MARGIN_LEFT, y, STR_POWERMETER_POWER); + if (reusableBuffer.powerMeter.power) { + lcdDrawNumber(POWER_METER_MARGIN_2ND_COLUMN, y, reusableBuffer.powerMeter.power + reusableBuffer.powerMeter.attn * 1000, LEFT | PREC2); + lcdDrawText(lcdNextPos, y, "dBm"); + } + break; + + case POWER_METER_PEAK: + lcdDrawText(MENUS_MARGIN_LEFT, y, STR_POWERMETER_PEAK); + if (reusableBuffer.powerMeter.peak) { + lcdDrawNumber(POWER_METER_MARGIN_2ND_COLUMN, y, reusableBuffer.powerMeter.peak + reusableBuffer.powerMeter.attn * 1000, LEFT | PREC2); + lcdDrawText(lcdNextPos, y, "dBm"); + } + break; + } + } + return true; +} diff --git a/radio/src/gui/480x272/radio_spectrum_analyser.cpp b/radio/src/gui/480x272/radio_spectrum_analyser.cpp new file mode 100644 index 000000000..f6ebbbc7a --- /dev/null +++ b/radio/src/gui/480x272/radio_spectrum_analyser.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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 "opentx.h" + +extern uint8_t g_moduleIdx; + +enum SpectrumFields { + SPECTRUM_FREQUENCY, + SPECTRUM_SPAN, + SPECTRUM_FIELDS_MAX +}; + +bool menuRadioSpectrumAnalyser(event_t event) +{ + SIMPLE_SUBMENU(STR_MENU_SPECTRUM_ANALYSER, ICON_RADIO, 1); + + if (TELEMETRY_STREAMING()) { + lcdDrawCenteredText(LCD_H/2, STR_TURN_OFF_RECEIVER ); + if (event == EVT_KEY_FIRST(KEY_EXIT)) { + killEvents(event); + popMenu(); + } + return true; + } + + if (menuEvent) { + lcdDrawCenteredText(LCD_H/2, STR_STOPPING ); + lcdRefresh(); + moduleState[g_moduleIdx].mode = MODULE_MODE_NORMAL; + /* wait 1s to resume normal operation before leaving */ + watchdogSuspend(1000); + RTOS_WAIT_MS(1000); + return true; + } + + if (moduleState[g_moduleIdx].mode != MODULE_MODE_SPECTRUM_ANALYSER) { + memclear(reusableBuffer.spectrumAnalyser.bars, sizeof(reusableBuffer.spectrumAnalyser.bars)); + reusableBuffer.spectrumAnalyser.span = 40000000; // 40MHz + reusableBuffer.spectrumAnalyser.freq = 2440000000; // 2440MHz + reusableBuffer.spectrumAnalyser.step = reusableBuffer.spectrumAnalyser.span / LCD_W; + moduleState[g_moduleIdx].mode = MODULE_MODE_SPECTRUM_ANALYSER; + } + + for (uint8_t i=0; i0 ? INVERS|BLINK : INVERS) : 0); + + switch (i) { + case SPECTRUM_FREQUENCY: { + uint16_t frequency = reusableBuffer.spectrumAnalyser.freq / 1000000; + lcdDrawText(1, MENU_CONTENT_TOP + 10, "F:", 0); + lcdDrawNumber(lcdNextPos + 2, 10, frequency, attr); + lcdDrawText(lcdNextPos + 2, 10, "MHz", 0); + if (attr) { + reusableBuffer.spectrumAnalyser.freq = uint32_t(checkIncDec(event, frequency, 2400, 2485, 0)) * 1000000; + } + break; + } + + case SPECTRUM_SPAN: + uint8_t span = reusableBuffer.spectrumAnalyser.span / 1000000; + lcdDrawText(lcdNextPos + 5, MENU_CONTENT_TOP + 10, "S:", 0); + lcdDrawNumber(lcdNextPos + 2, MENU_CONTENT_TOP + 10, reusableBuffer.spectrumAnalyser.span/1000000, attr); + lcdDrawText(lcdNextPos + 2, MENU_CONTENT_TOP + 10, "MHz", 0); + if (attr) { + reusableBuffer.spectrumAnalyser.span = checkIncDec(event, span, 1, 80, 0) * 1000000; + } + break; + } + } + + uint8_t peak_y = 1; + uint8_t peak_x = 0; + for (coord_t i=0; i(reusableBuffer.spectrumAnalyser.bars[i] >> 1, 128); + if (h > peak_y) { + peak_x = i; + peak_y = h; + } + lcdDrawSolidVerticalLine(i, LCD_H - h, h, TEXT_COLOR); + } + + int8_t y = max(FH, LCD_H - peak_y - FH); + lcdDrawNumber(min(100, peak_x), y, ((reusableBuffer.spectrumAnalyser.freq - reusableBuffer.spectrumAnalyser.span / 2) + peak_x * (reusableBuffer.spectrumAnalyser.span / 128)) / 1000000, TINSIZE); + lcdDrawText(lcdNextPos, y, "M", TINSIZE); + + return true; +} diff --git a/radio/src/gui/480x272/radio_tools.cpp b/radio/src/gui/480x272/radio_tools.cpp new file mode 100644 index 000000000..902ba72cc --- /dev/null +++ b/radio/src/gui/480x272/radio_tools.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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 "opentx.h" + +extern uint8_t g_moduleIdx; + +void addRadioTool(uint8_t index, const char * label, bool (* tool)(event_t), uint8_t module) +{ + int8_t sub = menuVerticalPosition; + LcdFlags attr = (sub == index ? INVERS : 0); + coord_t y = MENU_CONTENT_TOP + index * FH; + lcdDrawNumber(3, y, index + 1, LEADING0|LEFT, 2); + lcdDrawText(30, y, label, (sub == index ? INVERS : 0)); + if (attr && s_editMode > 0) { + s_editMode = 0; + g_moduleIdx = module; + pushMenu(tool); + } +} + +bool menuRadioTools(event_t event) +{ + uint8_t spectrum_modules = 0, power_modules = 0; + + if (event == EVT_ENTRY || event == EVT_ENTRY_UP) { + memclear(&reusableBuffer.hardwareAndSettings, sizeof(reusableBuffer.hardwareAndSettings)); + + for (uint8_t module = 0; module < NUM_MODULES; module++) { + if (isModulePXX2(module) && (module == INTERNAL_MODULE ? IS_INTERNAL_MODULE_ON() : IS_EXTERNAL_MODULE_ON())) { + moduleState[module].readModuleInformation(&reusableBuffer.hardwareAndSettings.modules[module], PXX2_HW_INFO_TX_ID, PXX2_HW_INFO_TX_ID); + } + } + + } + + for (uint8_t module = 0; module < NUM_MODULES; module++) { + if (isModuleOptionAvailable(reusableBuffer.hardwareAndSettings.modules[module].information.modelID, MODULE_OPTION_SPECTRUM_ANALYSER)) { + spectrum_modules++; + } + if (isModuleOptionAvailable(reusableBuffer.hardwareAndSettings.modules[module].information.modelID, MODULE_OPTION_POWER_METER)) { + power_modules++; + } + } + + MENU(STR_MENUTOOLS, RADIO_ICONS, menuTabGeneral, MENU_RADIO_TOOLS, spectrum_modules + power_modules, {0,0,0,0}); + + + uint8_t menu_index = 0; + + if (isModuleOptionAvailable(reusableBuffer.hardwareAndSettings.modules[INTERNAL_MODULE].information.modelID, MODULE_OPTION_SPECTRUM_ANALYSER)) + addRadioTool(menu_index++, "Spectrum (INT)", menuRadioSpectrumAnalyser, INTERNAL_MODULE); + + if (isModuleOptionAvailable(reusableBuffer.hardwareAndSettings.modules[INTERNAL_MODULE].information.modelID, MODULE_OPTION_POWER_METER)) + addRadioTool(menu_index++, "Power Meter (INT)", menuRadioPowerMeter, INTERNAL_MODULE); + + if (isModuleOptionAvailable(reusableBuffer.hardwareAndSettings.modules[EXTERNAL_MODULE].information.modelID, MODULE_OPTION_SPECTRUM_ANALYSER)) + addRadioTool(menu_index++, "Spectrum (EXT)", menuRadioSpectrumAnalyser, EXTERNAL_MODULE); + + if (isModuleOptionAvailable(reusableBuffer.hardwareAndSettings.modules[EXTERNAL_MODULE].information.modelID, MODULE_OPTION_POWER_METER)) + addRadioTool(menu_index++, "Power Meter (EXT)", menuRadioPowerMeter, EXTERNAL_MODULE); + +} \ No newline at end of file diff --git a/radio/src/gui/common/colorlcd/widgets.cpp b/radio/src/gui/common/colorlcd/widgets.cpp index 0dd0a4a39..1c0f801cb 100644 --- a/radio/src/gui/common/colorlcd/widgets.cpp +++ b/radio/src/gui/common/colorlcd/widgets.cpp @@ -93,3 +93,29 @@ void runFatalErrorScreen(const char * message) } } } + +void drawPower(coord_t x, coord_t y, int8_t dBm, LcdFlags att) +{ + float power_W_PREC1 = pow(10.0, (dBm - 30.0) / 10.0) * 10; + if (dBm >= 30) { + lcdDrawNumber(x, y, power_W_PREC1, PREC1 | att); + lcdDrawText(lcdNextPos, y, "W", att); + } + else if (dBm < 10) { + uint16_t power_MW_PREC1 = round(power_W_PREC1 * 1000); + lcdDrawNumber(x, y, power_MW_PREC1, PREC1 | att); + lcdDrawText(lcdNextPos, y, "mW", att); + } + else { + uint16_t power_MW = round(power_W_PREC1 * 100); + if (power_MW >= 50) { + power_MW = (power_MW / 5) * 5; + lcdDrawNumber(x, y, power_MW, att); + lcdDrawText(lcdNextPos, y, "mW", att); + } + else { + lcdDrawNumber(x, y, power_MW, att); + lcdDrawText(lcdNextPos, y, "mW", att); + } + } +} diff --git a/radio/src/targets/horus/CMakeLists.txt b/radio/src/targets/horus/CMakeLists.txt index d0c70b433..b7797db21 100644 --- a/radio/src/targets/horus/CMakeLists.txt +++ b/radio/src/targets/horus/CMakeLists.txt @@ -91,6 +91,9 @@ set(GUI_SRC bitmaps.cpp radio_sdmanager.cpp radio_hardware.cpp + radio_power_meter.cpp + radio_spectrum_analyser.cpp + radio_tools.cpp model_inputs.cpp model_mixes.cpp model_curves.cpp