diff --git a/radio/src/gui/128x64/menus.h b/radio/src/gui/128x64/menus.h index 4f1428a6f..a8e47db57 100644 --- a/radio/src/gui/128x64/menus.h +++ b/radio/src/gui/128x64/menus.h @@ -52,7 +52,7 @@ enum MenuRadioIndexes { MENU_RADIO_SETUP, CASE_SDCARD(MENU_RADIO_SD_MANAGER) -#if defined(LUA) || defined(PXX2) +#if defined(LUA) || defined(PXX2) || defined(MULTIMODULE) MENU_RADIO_TOOLS, #endif MENU_RADIO_SPECIAL_FUNCTIONS, diff --git a/radio/src/gui/480x272/radio_spectrum_analyser.cpp b/radio/src/gui/480x272/radio_spectrum_analyser.cpp index 260fbc767..88f4529c8 100644 --- a/radio/src/gui/480x272/radio_spectrum_analyser.cpp +++ b/radio/src/gui/480x272/radio_spectrum_analyser.cpp @@ -22,20 +22,41 @@ extern uint8_t g_moduleIdx; -enum SpectrumFields { +enum SpectrumFields +{ SPECTRUM_FREQUENCY, SPECTRUM_SPAN, + SPECTRUM_TRACK, SPECTRUM_FIELDS_MAX }; +coord_t getAverage(uint8_t number, uint8_t * value) +{ + uint16_t sum = 0; + for (uint8_t i = 0; i < number; i++) { + sum += value[i]; + } + return sum / number; +} + +#define SPECTRUM_ROW (isModuleMultimodule(g_moduleIdx) ? READONLY_ROW : (uint8_t)0) +constexpr uint8_t GREYBAR_HEIGHT = 12; + bool menuRadioSpectrumAnalyser(event_t event) { - SUBMENU(STR_MENU_SPECTRUM_ANALYSER, ICON_RADIO_SPECTRUM_ANALYSER, 1, {1}); + SUBMENU(STR_MENU_SPECTRUM_ANALYSER, ICON_RADIO_SPECTRUM_ANALYSER, SPECTRUM_FIELDS_MAX, { + SPECTRUM_ROW, //Freq + SPECTRUM_ROW, //Span + 0 //Track + }); if (menuEvent) { - lcdDrawCenteredText(LCD_H/2, STR_STOPPING); + lcdDrawCenteredText(LCD_H / 2, STR_STOPPING); lcdRefresh(); - moduleState[g_moduleIdx].readModuleInformation(&reusableBuffer.moduleSetup.pxx2.moduleInformation, PXX2_HW_INFO_TX_ID, PXX2_HW_INFO_TX_ID); + if (isModulePXX2(g_moduleIdx)) + moduleState[g_moduleIdx].readModuleInformation(&reusableBuffer.moduleSetup.pxx2.moduleInformation, PXX2_HW_INFO_TX_ID, PXX2_HW_INFO_TX_ID); + else if (isModuleMultimodule((g_moduleIdx))) + moduleState[g_moduleIdx].mode = MODULE_MODE_NORMAL; /* wait 1s to resume normal operation before leaving */ watchdogSuspend(1000); RTOS_WAIT_MS(1000); @@ -44,7 +65,7 @@ bool menuRadioSpectrumAnalyser(event_t event) if (moduleState[g_moduleIdx].mode != MODULE_MODE_SPECTRUM_ANALYSER) { if (TELEMETRY_STREAMING()) { - lcdDrawCenteredText(LCD_H/2, STR_TURN_OFF_RECEIVER); + POPUP_WARNING(STR_TURN_OFF_RECEIVER); if (event == EVT_KEY_FIRST(KEY_EXIT)) { killEvents(event); popMenu(); @@ -62,7 +83,10 @@ bool menuRadioSpectrumAnalyser(event_t event) reusableBuffer.spectrumAnalyser.freqMax = 930; } else { - reusableBuffer.spectrumAnalyser.spanDefault = 40; // 40MHz + if (isModuleMultimodule(g_moduleIdx)) + reusableBuffer.spectrumAnalyser.spanDefault = 80; // 80MHz + else + reusableBuffer.spectrumAnalyser.spanDefault = 40; // 40MHz reusableBuffer.spectrumAnalyser.spanMax = 80; reusableBuffer.spectrumAnalyser.freqDefault = 2440; // 2440MHz reusableBuffer.spectrumAnalyser.freqMin = 2400; @@ -71,13 +95,14 @@ bool menuRadioSpectrumAnalyser(event_t event) reusableBuffer.spectrumAnalyser.span = reusableBuffer.spectrumAnalyser.spanDefault * 1000000; reusableBuffer.spectrumAnalyser.freq = reusableBuffer.spectrumAnalyser.freqDefault * 1000000; + reusableBuffer.spectrumAnalyser.track = reusableBuffer.spectrumAnalyser.freq; reusableBuffer.spectrumAnalyser.step = reusableBuffer.spectrumAnalyser.span / LCD_W; reusableBuffer.spectrumAnalyser.dirty = true; moduleState[g_moduleIdx].mode = MODULE_MODE_SPECTRUM_ANALYSER; } - for (uint8_t i=0; i0 ? INVERS|BLINK : INVERS) : 0); + for (uint8_t i = 0; i < SPECTRUM_FIELDS_MAX; i++) { + LcdFlags attr = (menuVerticalPosition == i ? (s_editMode > 0 ? INVERS | BLINK : INVERS) : 0); switch (i) { case SPECTRUM_FREQUENCY: { @@ -94,10 +119,10 @@ bool menuRadioSpectrumAnalyser(event_t event) break; } - case SPECTRUM_SPAN: + case SPECTRUM_SPAN: { uint8_t span = reusableBuffer.spectrumAnalyser.span / 1000000; lcdDrawText(MENUS_MARGIN_LEFT + 100, MENU_FOOTER_TOP, "S:", TEXT_INVERTED_COLOR); - lcdDrawNumber(lcdNextPos + 2, MENU_FOOTER_TOP, reusableBuffer.spectrumAnalyser.span/1000000, attr | TEXT_INVERTED_COLOR); + lcdDrawNumber(lcdNextPos + 2, MENU_FOOTER_TOP, reusableBuffer.spectrumAnalyser.span / 1000000, attr | TEXT_INVERTED_COLOR); lcdDrawText(lcdNextPos + 2, MENU_FOOTER_TOP, "MHz", TEXT_INVERTED_COLOR); if (attr) { reusableBuffer.spectrumAnalyser.span = checkIncDec(event, span, 1, reusableBuffer.spectrumAnalyser.spanMax, 0) * 1000000; @@ -107,70 +132,72 @@ bool menuRadioSpectrumAnalyser(event_t event) } } break; + } + + case SPECTRUM_TRACK: { + uint16_t track = reusableBuffer.spectrumAnalyser.track / 1000000; + lcdDrawText(lcdNextPos + 10, MENU_FOOTER_TOP, "T:", TEXT_INVERTED_COLOR); + lcdDrawNumber(lcdNextPos + 2, MENU_FOOTER_TOP, reusableBuffer.spectrumAnalyser.track / 1000000, attr | TEXT_INVERTED_COLOR); + lcdDrawText(lcdNextPos + 2, MENU_FOOTER_TOP, "MHz", TEXT_INVERTED_COLOR); + if (attr) { + reusableBuffer.spectrumAnalyser.track = uint32_t( + checkIncDec(event, track, (reusableBuffer.spectrumAnalyser.freq - reusableBuffer.spectrumAnalyser.span / 2) / 1000000, + (reusableBuffer.spectrumAnalyser.freq + reusableBuffer.spectrumAnalyser.span / 2) / 1000000, 0)) * 1000000; + if (checkIncDec_Ret) { + reusableBuffer.spectrumAnalyser.dirty = true; + } + } + break; + } } } - + // Draw fixed part (scale,..) + lcdDrawFilledRect(0, MENU_FOOTER_TOP - GREYBAR_HEIGHT, LCD_W, GREYBAR_HEIGHT, SOLID, CURVE_AXIS_COLOR); for (uint32_t frequency = ((reusableBuffer.spectrumAnalyser.freq - reusableBuffer.spectrumAnalyser.span / 2) / 10000000) * 10000000 + 10000000; ; frequency += 10000000) { int offset = frequency - (reusableBuffer.spectrumAnalyser.freq - reusableBuffer.spectrumAnalyser.span / 2); int x = offset / reusableBuffer.spectrumAnalyser.step; if (x >= LCD_W - 1) break; lcdDrawVerticalLine(x, MENU_HEADER_HEIGHT, LCD_H - MENU_HEADER_HEIGHT - MENU_FOOTER_HEIGHT, STASHED, CURVE_AXIS_COLOR); + + if ((frequency / 1000000) % 2 == 0) { + lcdDrawNumber(x, MENU_FOOTER_TOP - GREYBAR_HEIGHT - 1, frequency / 1000000, TINSIZE | TEXT_COLOR | CENTERED); + } } - for (uint8_t power = 20; ; power += 20) { + for (uint8_t power = 20;; power += 20) { int y = MENU_FOOTER_TOP - 1 - limit(0, power << 1, LCD_H - MENU_HEADER_HEIGHT - MENU_FOOTER_HEIGHT); if (y <= MENU_HEADER_HEIGHT) break; lcdDrawHorizontalLine(0, y, LCD_W, STASHED, CURVE_AXIS_COLOR); } - coord_t peak_y = LCD_H; - coord_t peak_x = 0; + // Draw Tracker + int offset = reusableBuffer.spectrumAnalyser.track - (reusableBuffer.spectrumAnalyser.freq - reusableBuffer.spectrumAnalyser.span / 2); + int x = offset / reusableBuffer.spectrumAnalyser.step; + lcdDrawVerticalLine(x, MENU_HEADER_HEIGHT, LCD_H - MENU_HEADER_HEIGHT - MENU_FOOTER_HEIGHT - GREYBAR_HEIGHT, SOLID, TEXT_COLOR); - coord_t prev_yv = (coord_t)-1; - for (coord_t xv=0; xv(0, reusableBuffer.spectrumAnalyser.bars[xv] << 1, LCD_H - MENU_HEADER_HEIGHT - MENU_FOOTER_HEIGHT); - if (prev_yv != (coord_t)-1) { - if (yv < peak_y) { - peak_x = xv; - peak_y = yv; - } - if (prev_yv < yv) { - for (int y=prev_yv; y<=yv; y+=1) { - lcdDrawPoint(xv, y, TEXT_COLOR); - } - } - else { - for (int y=yv; y<=prev_yv; y+=1) { - lcdDrawPoint(xv, y, TEXT_COLOR); - } + // Draw spectrum data + constexpr uint8_t step = 4; + + for (coord_t xv = 0; xv <= LCD_W - step; xv += 4) { + coord_t yv = MENU_FOOTER_TOP - 1 - limit(0, getAverage(step, &reusableBuffer.spectrumAnalyser.bars[xv]) << 1, LCD_H - MENU_HEADER_HEIGHT - MENU_FOOTER_HEIGHT); + coord_t max_yv = MENU_FOOTER_TOP - 1 - limit(0, getAverage(step, &reusableBuffer.spectrumAnalyser.max[xv]) << 1, LCD_H - MENU_HEADER_HEIGHT - MENU_FOOTER_HEIGHT); + + // Signal bar + lcdDrawSolidFilledRect(xv, yv, step - 1, LCD_H - yv - MENU_FOOTER_HEIGHT - GREYBAR_HEIGHT, TEXT_INVERTED_BGCOLOR); + lcdDrawRect(xv, yv, step - 1, LCD_H - yv - MENU_FOOTER_HEIGHT - GREYBAR_HEIGHT); + + // Signal max + lcdDrawLine(xv, max_yv, xv + step, max_yv); + + // Decay max values + if (max_yv < yv) { // Those value are INVERTED (MENU_FOOTER_TOP - value) + for (uint8_t i = 0; i < step; i++) { + reusableBuffer.spectrumAnalyser.max[xv + i] -= 1; } } - prev_yv = yv; } - prev_yv = (coord_t)-1; - for (coord_t xv=0; xv(0, reusableBuffer.spectrumAnalyser.max[xv] << 1, LCD_H - MENU_HEADER_HEIGHT - MENU_FOOTER_HEIGHT); - if (prev_yv != (coord_t)-1) { - if (prev_yv < yv) { - for (int y=prev_yv; y<=yv; y+=1) { - lcdDrawPoint(xv, y, TEXT_INVERTED_BGCOLOR); - } - } - else { - for (int y=yv; y<=prev_yv; y+=1) { - lcdDrawPoint(xv, y, TEXT_INVERTED_BGCOLOR); - } - } - } - prev_yv = yv; - } - - coord_t y = max(MENU_HEADER_HEIGHT + 1, peak_y - FH); - lcdDrawNumber(limit(20, peak_x, LCD_W - 20), y, ((reusableBuffer.spectrumAnalyser.freq - reusableBuffer.spectrumAnalyser.span / 2) + peak_x * (reusableBuffer.spectrumAnalyser.span / LCD_W)) / 1000000, TINSIZE | CENTERED); - lcdDrawText(lcdNextPos, y, "M", TINSIZE); - return true; -} +} \ No newline at end of file diff --git a/radio/src/gui/480x272/radio_tools.cpp b/radio/src/gui/480x272/radio_tools.cpp index cf560fd71..a11ba0103 100644 --- a/radio/src/gui/480x272/radio_tools.cpp +++ b/radio/src/gui/480x272/radio_tools.cpp @@ -85,17 +85,21 @@ bool menuRadioTools(event_t event) uint8_t index = 0; -#if defined(PXX2) - if (isPXX2ModuleOptionAvailable(reusableBuffer.radioTools.modules[INTERNAL_MODULE].information.modelID, MODULE_OPTION_SPECTRUM_ANALYSER)) +#if defined(INTERNAL_MODULE_PXX2) + if (isPXX2ModuleOptionAvailable(reusableBuffer.hardwareAndSettings.modules[INTERNAL_MODULE].information.modelID, MODULE_OPTION_SPECTRUM_ANALYSER)) addRadioModuleTool(index++, STR_SPECTRUM_ANALYSER_INT, menuRadioSpectrumAnalyser, INTERNAL_MODULE); - if (isPXX2ModuleOptionAvailable(reusableBuffer.radioTools.modules[INTERNAL_MODULE].information.modelID, MODULE_OPTION_POWER_METER)) + if (isPXX2ModuleOptionAvailable(reusableBuffer.hardwareAndSettings.modules[INTERNAL_MODULE].information.modelID, MODULE_OPTION_POWER_METER)) addRadioModuleTool(index++, STR_POWER_METER_INT, menuRadioPowerMeter, INTERNAL_MODULE); - - if (isPXX2ModuleOptionAvailable(reusableBuffer.radioTools.modules[EXTERNAL_MODULE].information.modelID, MODULE_OPTION_SPECTRUM_ANALYSER)) +#elif defined(INTERNAL_MODULE_MULTI) + addRadioModuleTool(index++, STR_SPECTRUM_ANALYSER_INT, menuRadioSpectrumAnalyser, INTERNAL_MODULE); +#endif +#if defined(PXX2)|| defined(MULTIMODULE) + if (isPXX2ModuleOptionAvailable(reusableBuffer.hardwareAndSettings.modules[EXTERNAL_MODULE].information.modelID, MODULE_OPTION_SPECTRUM_ANALYSER) || isModuleMultimodule(EXTERNAL_MODULE)) addRadioModuleTool(index++, STR_SPECTRUM_ANALYSER_EXT, menuRadioSpectrumAnalyser, EXTERNAL_MODULE); - - if (isPXX2ModuleOptionAvailable(reusableBuffer.radioTools.modules[EXTERNAL_MODULE].information.modelID, MODULE_OPTION_POWER_METER)) +#endif +#if defined(PXX2) + if (isPXX2ModuleOptionAvailable(reusableBuffer.hardwareAndSettings.modules[EXTERNAL_MODULE].information.modelID, MODULE_OPTION_POWER_METER)) addRadioModuleTool(index++, STR_POWER_METER_EXT, menuRadioPowerMeter, EXTERNAL_MODULE); #endif diff --git a/radio/src/gui/common/stdlcd/CMakeLists.txt b/radio/src/gui/common/stdlcd/CMakeLists.txt index 2da32d37a..0d3f726b3 100644 --- a/radio/src/gui/common/stdlcd/CMakeLists.txt +++ b/radio/src/gui/common/stdlcd/CMakeLists.txt @@ -18,7 +18,7 @@ set(GUI_SRC model_curve_edit.cpp ) -if(PXX2 OR LUA) +if(PXX2 OR LUA OR MULTIMODULE) set(GUI_SRC ${GUI_SRC} ../common/stdlcd/radio_tools.cpp) endif() @@ -36,8 +36,14 @@ endif() if(PXX2) set(GUI_SRC ${GUI_SRC} - ../common/stdlcd/radio_spectrum_analyser.cpp ../common/stdlcd/radio_power_meter.cpp ) endif() +if(PXX2 OR MULTIMODULE) + set(GUI_SRC + ${GUI_SRC} + ../common/stdlcd/radio_spectrum_analyser.cpp + ) +endif() + diff --git a/radio/src/gui/common/stdlcd/radio_spectrum_analyser.cpp b/radio/src/gui/common/stdlcd/radio_spectrum_analyser.cpp index a122dd7ba..ab96c52d5 100644 --- a/radio/src/gui/common/stdlcd/radio_spectrum_analyser.cpp +++ b/radio/src/gui/common/stdlcd/radio_spectrum_analyser.cpp @@ -25,12 +25,19 @@ extern uint8_t g_moduleIdx; enum SpectrumFields { SPECTRUM_FREQUENCY, SPECTRUM_SPAN, + SPECTRUM_TRACK, SPECTRUM_FIELDS_MAX }; +#define SPECTRUM_ROW (isModuleMultimodule(g_moduleIdx) ? READONLY_ROW : (uint8_t)0) + void menuRadioSpectrumAnalyser(event_t event) { - SUBMENU(STR_MENU_SPECTRUM_ANALYSER, 1, {1}); + SUBMENU(STR_MENU_SPECTRUM_ANALYSER, SPECTRUM_FIELDS_MAX, { + SPECTRUM_ROW, //Freq + SPECTRUM_ROW, //Span + 0 //Tracker + }); if (menuEvent) { lcdDrawCenteredText(LCD_H/2, STR_STOPPING); @@ -62,7 +69,10 @@ void menuRadioSpectrumAnalyser(event_t event) reusableBuffer.spectrumAnalyser.freqMax = 930; } else { - reusableBuffer.spectrumAnalyser.spanDefault = 40; // 40MHz + if (isModuleMultimodule(g_moduleIdx)) + reusableBuffer.spectrumAnalyser.spanDefault = 80; // 80MHz + else + reusableBuffer.spectrumAnalyser.spanDefault = 40; // 40MHz reusableBuffer.spectrumAnalyser.spanMax = 80; reusableBuffer.spectrumAnalyser.freqDefault = 2440; // 2440MHz reusableBuffer.spectrumAnalyser.freqMin = 2400; @@ -71,20 +81,22 @@ void menuRadioSpectrumAnalyser(event_t event) reusableBuffer.spectrumAnalyser.span = reusableBuffer.spectrumAnalyser.spanDefault * 1000000; reusableBuffer.spectrumAnalyser.freq = reusableBuffer.spectrumAnalyser.freqDefault * 1000000; + reusableBuffer.spectrumAnalyser.track = reusableBuffer.spectrumAnalyser.freq; reusableBuffer.spectrumAnalyser.step = reusableBuffer.spectrumAnalyser.span / LCD_W; reusableBuffer.spectrumAnalyser.dirty = true; moduleState[g_moduleIdx].mode = MODULE_MODE_SPECTRUM_ANALYSER; } for (uint8_t i=0; i0 ? INVERS|BLINK : INVERS) : 0); + uint8_t sub = menuVerticalPosition; + LcdFlags attr = (sub==i ? (s_editMode>0 ? BLINK|INVERS : INVERS) : 0); switch (i) { case SPECTRUM_FREQUENCY: { uint16_t frequency = reusableBuffer.spectrumAnalyser.freq / 1000000; - lcdDrawText(1, 10, "F:", 0); - lcdDrawNumber(lcdLastRightPos + 2, 10, frequency, attr); - lcdDrawText(lcdLastRightPos + 2, 10, "MHz", 0); + lcdDrawText(1, 10, "F:", SMLSIZE); + lcdDrawNumber(lcdLastRightPos + 1, 10, frequency, attr|SMLSIZE); + lcdDrawText(lcdLastRightPos + 1, 10, "MHz", SMLSIZE); if (attr) { reusableBuffer.spectrumAnalyser.freq = uint32_t(checkIncDec(event, frequency, reusableBuffer.spectrumAnalyser.freqMin, reusableBuffer.spectrumAnalyser.freqMax, 0)) * 1000000; if (checkIncDec_Ret) { @@ -94,11 +106,11 @@ void menuRadioSpectrumAnalyser(event_t event) break; } - case SPECTRUM_SPAN: + case SPECTRUM_SPAN: { uint8_t span = reusableBuffer.spectrumAnalyser.span / 1000000; - lcdDrawText(lcdLastRightPos + 5, 10, "S:", 0); - lcdDrawNumber(lcdLastRightPos + 2, 10, reusableBuffer.spectrumAnalyser.span/1000000, attr); - lcdDrawText(lcdLastRightPos + 2, 10, "MHz", 0); + lcdDrawText(lcdLastRightPos + 2, 10, "S:", SMLSIZE); + lcdDrawNumber(lcdLastRightPos + 1, 10, reusableBuffer.spectrumAnalyser.span / 1000000, attr | SMLSIZE); + lcdDrawText(lcdLastRightPos + 1, 10, "MHz", SMLSIZE); if (attr) { reusableBuffer.spectrumAnalyser.span = checkIncDec(event, span, 1, reusableBuffer.spectrumAnalyser.spanMax, 0) * 1000000; if (checkIncDec_Ret) { @@ -107,21 +119,42 @@ void menuRadioSpectrumAnalyser(event_t event) } } break; + } + + case SPECTRUM_TRACK: { + uint16_t track = reusableBuffer.spectrumAnalyser.track / 1000000; + lcdDrawText(lcdNextPos + 2, 10, "T:", SMLSIZE); + lcdDrawNumber(lcdNextPos + 1, 10, reusableBuffer.spectrumAnalyser.track / 1000000, attr | SMLSIZE); + lcdDrawText(lcdNextPos + 1, 10, "MHz", SMLSIZE); + if (attr) { + reusableBuffer.spectrumAnalyser.track = uint32_t( + checkIncDec(event, track, (reusableBuffer.spectrumAnalyser.freq - reusableBuffer.spectrumAnalyser.span / 2) / 1000000, + (reusableBuffer.spectrumAnalyser.freq + reusableBuffer.spectrumAnalyser.span / 2) / 1000000, 0)) * 1000000; + if (checkIncDec_Ret) { + reusableBuffer.spectrumAnalyser.dirty = true; + } + } + break; + } } } - uint8_t peak_y = 1; - uint8_t peak_x = 0; + // Signal bar for (uint8_t i=0; i(reusableBuffer.spectrumAnalyser.bars[i] >> 1, LCD_H); - if (h > peak_y) { - peak_x = i; - peak_y = h; - } lcdDrawSolidVerticalLine(i, LCD_H - h, h); } - 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 / LCD_W)) / 1000000, TINSIZE); - lcdDrawText(lcdLastRightPos, y, "M", TINSIZE); -} + // Signal max + for (uint8_t i=0; i(reusableBuffer.spectrumAnalyser.max[i] >> 1, LCD_H); + lcdDrawPoint(i, LCD_H - h); + if (reusableBuffer.spectrumAnalyser.max[i] > 1) + reusableBuffer.spectrumAnalyser.max[i] -= 1; + } + + // Draw Tracker + int offset = reusableBuffer.spectrumAnalyser.track - (reusableBuffer.spectrumAnalyser.freq - reusableBuffer.spectrumAnalyser.span / 2); + int x = offset / reusableBuffer.spectrumAnalyser.step; + lcdDrawVerticalLine(x, 10+FH+1, LCD_H, SOLID); +} \ No newline at end of file diff --git a/radio/src/gui/common/stdlcd/radio_tools.cpp b/radio/src/gui/common/stdlcd/radio_tools.cpp index 1ac177c21..b2d13cba5 100644 --- a/radio/src/gui/common/stdlcd/radio_tools.cpp +++ b/radio/src/gui/common/stdlcd/radio_tools.cpp @@ -82,17 +82,21 @@ void menuRadioTools(event_t event) uint8_t index = 0; -#if defined(PXX2) - if (isPXX2ModuleOptionAvailable(reusableBuffer.radioTools.modules[INTERNAL_MODULE].information.modelID, MODULE_OPTION_SPECTRUM_ANALYSER)) +#if defined(INTERNAL_MODULE_PXX2) + if (isPXX2ModuleOptionAvailable(reusableBuffer.hardwareAndSettings.modules[INTERNAL_MODULE].information.modelID, MODULE_OPTION_SPECTRUM_ANALYSER)) addRadioModuleTool(index++, STR_SPECTRUM_ANALYSER_INT, menuRadioSpectrumAnalyser, INTERNAL_MODULE); - if (isPXX2ModuleOptionAvailable(reusableBuffer.radioTools.modules[INTERNAL_MODULE].information.modelID, MODULE_OPTION_POWER_METER)) + if (isPXX2ModuleOptionAvailable(reusableBuffer.hardwareAndSettings.modules[INTERNAL_MODULE].information.modelID, MODULE_OPTION_POWER_METER)) addRadioModuleTool(index++, STR_POWER_METER_INT, menuRadioPowerMeter, INTERNAL_MODULE); - - if (isPXX2ModuleOptionAvailable(reusableBuffer.radioTools.modules[EXTERNAL_MODULE].information.modelID, MODULE_OPTION_SPECTRUM_ANALYSER)) +#elif defined(INTERNAL_MODULE_MULTI) + addRadioModuleTool(index++, STR_SPECTRUM_ANALYSER_INT, menuRadioSpectrumAnalyser, INTERNAL_MODULE); +#endif +#if defined(PXX2)|| defined(MULTIMODULE) + if (isPXX2ModuleOptionAvailable(reusableBuffer.hardwareAndSettings.modules[EXTERNAL_MODULE].information.modelID, MODULE_OPTION_SPECTRUM_ANALYSER) || isModuleMultimodule(EXTERNAL_MODULE)) addRadioModuleTool(index++, STR_SPECTRUM_ANALYSER_EXT, menuRadioSpectrumAnalyser, EXTERNAL_MODULE); - - if (isPXX2ModuleOptionAvailable(reusableBuffer.radioTools.modules[EXTERNAL_MODULE].information.modelID, MODULE_OPTION_POWER_METER)) +#endif +#if defined(PXX2) + if (isPXX2ModuleOptionAvailable(reusableBuffer.hardwareAndSettings.modules[EXTERNAL_MODULE].information.modelID, MODULE_OPTION_POWER_METER)) addRadioModuleTool(index++, STR_POWER_METER_EXT, menuRadioPowerMeter, EXTERNAL_MODULE); #endif diff --git a/radio/src/gui/navigation/navigation_x9d.cpp b/radio/src/gui/navigation/navigation_x9d.cpp index 911455211..a5d6fc332 100644 --- a/radio/src/gui/navigation/navigation_x9d.cpp +++ b/radio/src/gui/navigation/navigation_x9d.cpp @@ -373,7 +373,7 @@ void check(event_t event, uint8_t curr, const MenuHandlerFunc *menuTab, uint8_t break; case EVT_KEY_BREAK(KEY_ENTER): - if (s_editMode > 1) + if (s_editMode > 1) break; if (menuHorizontalPosition < 0 && maxcol > 0 && READ_ONLY_UNLOCKED()) { l_posHorz = 0; @@ -545,4 +545,3 @@ void check(event_t event, uint8_t curr, const MenuHandlerFunc *menuTab, uint8_t menuHorizontalPosition = l_posHorz; } - diff --git a/radio/src/opentx.h b/radio/src/opentx.h index 7a7ec1974..34931dd44 100644 --- a/radio/src/opentx.h +++ b/radio/src/opentx.h @@ -1187,12 +1187,11 @@ union ReusableBuffer struct { uint8_t bars[LCD_W]; -#if defined(COLORLCD) uint8_t max[LCD_W]; -#endif uint32_t freq; uint32_t span; uint32_t step; + uint32_t track; uint8_t spanDefault; uint8_t spanMax; uint16_t freqDefault; diff --git a/radio/src/pulses/multi.cpp b/radio/src/pulses/multi.cpp index 9ceb57886..7c686546f 100644 --- a/radio/src/pulses/multi.cpp +++ b/radio/src/pulses/multi.cpp @@ -37,7 +37,7 @@ void sendChannels(uint8_t moduleIdx); static void sendMulti(uint8_t moduleIdx, uint8_t b) { -#if defined(INTERNAL_MODULE_MULTI) +#if defined(HARDWARE_INTERNAL_MODULE) if (moduleIdx == INTERNAL_MODULE) { intmodulePulsesData.multi.sendByte(b); } @@ -171,6 +171,15 @@ void sendFrameProtocolHeader(uint8_t moduleIdx, bool failsafe) int8_t optionValue = g_model.moduleData[moduleIdx].multi.optionValue; uint8_t protoByte = 0; + + if (moduleState[moduleIdx].mode == MODULE_MODE_SPECTRUM_ANALYSER) { + sendMulti(moduleIdx, (uint8_t) 0x54); // Header byte + sendMulti(moduleIdx, (uint8_t) 54); // Spectrum custom protocol + sendMulti(moduleIdx, (uint8_t) 0); + sendMulti(moduleIdx, (uint8_t) 0); + return; + } + if (moduleState[moduleIdx].mode == MODULE_MODE_BIND) protoByte |= MULTI_SEND_BIND; else if (moduleState[moduleIdx].mode == MODULE_MODE_RANGECHECK) diff --git a/radio/src/pulses/pulses.cpp b/radio/src/pulses/pulses.cpp index e771d4e90..6d869e484 100755 --- a/radio/src/pulses/pulses.cpp +++ b/radio/src/pulses/pulses.cpp @@ -287,7 +287,7 @@ void setupPulsesExternalModule(uint8_t protocol) } #if defined(HARDWARE_INTERNAL_MODULE) -void enablePulsesInternalModule(uint8_t protocol) +static void enablePulsesInternalModule(uint8_t protocol) { // start new protocol hardware here diff --git a/radio/src/pulses/pulses.h b/radio/src/pulses/pulses.h index 9fa17a196..8dc12ee68 100644 --- a/radio/src/pulses/pulses.h +++ b/radio/src/pulses/pulses.h @@ -41,6 +41,12 @@ #define IS_DSM2_PROTOCOL(protocol) (0) #endif +#if defined(DSM2_SERIAL) + #define IS_DSM2_SERIAL_PROTOCOL(protocol) (IS_DSM2_PROTOCOL(protocol)) +#else + #define IS_DSM2_SERIAL_PROTOCOL(protocol) (0) +#endif + #if defined(MULTIMODULE) #define IS_MULTIMODULE_PROTOCOL(protocol) (protocol==PROTOCOL_CHANNELS_MULTIMODULE) #if !defined(DSM2) @@ -147,7 +153,8 @@ PACK(struct ModuleState { uint8_t paused:1; uint8_t spare:7; uint16_t counter; - union { + union + { ModuleInformation * moduleInformation; ModuleSettings * moduleSettings; ReceiverSettings * receiverSettings; @@ -165,12 +172,14 @@ PACK(struct ModuleState { moduleInformation->maximum = last; mode = MODULE_MODE_GET_HARDWARE_INFO; } + void readModuleSettings(ModuleSettings * destination) { moduleSettings = destination; moduleSettings->state = PXX2_SETTINGS_READ; mode = MODULE_MODE_MODULE_SETTINGS; } + void writeModuleSettings(ModuleSettings * source) { moduleSettings = source; @@ -178,12 +187,14 @@ PACK(struct ModuleState { moduleSettings->timeout = 0; mode = MODULE_MODE_MODULE_SETTINGS; } + void readReceiverSettings(ReceiverSettings * destination) { receiverSettings = destination; receiverSettings->state = PXX2_SETTINGS_READ; mode = MODULE_MODE_RECEIVER_SETTINGS; } + void writeReceiverSettings(ReceiverSettings * source) { receiverSettings = source; @@ -238,21 +249,21 @@ PACK(struct CrossfirePulsesData { union InternalModulePulsesData { #if defined(PXX1) - #if defined(INTMODULE_USART) - UartPxx1Pulses pxx_uart; - #else - PwmPxx1Pulses pxx; - #endif +#if defined(INTMODULE_USART) + UartPxx1Pulses pxx_uart; +#else + PwmPxx1Pulses pxx; +#endif #endif #if defined(PXX2) Pxx2Pulses pxx2; #endif -#if defined(INTERNAL_MODULE_MULTI) //&& defined(INTMODULE_USART) - UartMultiPulses multi; +#if defined(MULTIMODULE) //&& defined(INTMODULE_USART) + UartMultiPulses multi; #endif - + #if defined(INTERNAL_MODULE_PPM) PpmPulsesData ppm; #endif @@ -260,14 +271,14 @@ union InternalModulePulsesData { union ExternalModulePulsesData { #if defined(PXX1) - #if defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML) - UartPxx1Pulses pxx_uart; - #endif - #if defined(PPM_PIN_SERIAL) - SerialPxx1Pulses pxx; - #else - PwmPxx1Pulses pxx; - #endif +#if defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML) + UartPxx1Pulses pxx_uart; +#endif +#if defined(PPM_PIN_SERIAL) + SerialPxx1Pulses pxx; +#else + PwmPxx1Pulses pxx; +#endif #endif #if defined(PXX2) @@ -417,4 +428,4 @@ inline bool isModuleInBeepMode() return false; } -#endif // _PULSES_H_ +#endif // _PULSES_H_ \ No newline at end of file diff --git a/radio/src/targets/horus/CMakeLists.txt b/radio/src/targets/horus/CMakeLists.txt index 14015b25e..bc16f5961 100644 --- a/radio/src/targets/horus/CMakeLists.txt +++ b/radio/src/targets/horus/CMakeLists.txt @@ -2,6 +2,7 @@ option(DISK_CACHE "Enable SD card disk cache" ON) option(UNEXPECTED_SHUTDOWN "Enable the Unexpected Shutdown screen" ON) option(PXX1 "PXX1 protocol support" ON) option(PXX2 "PXX2 protocol support" OFF) +option(MULTIMODULE "DIY Multiprotocol TX Module (https://github.com/pascallanger/DIY-Multiprotocol-TX-Module)" ON) set(PWR_BUTTON "PRESS" CACHE STRING "Pwr button type (PRESS/SWITCH)") set(CPU_TYPE STM32F4) @@ -146,16 +147,16 @@ set(GUI_SRC rle.cpp ) -if(PXX2 OR LUA) +if(PXX2 OR LUA OR MULTIMODULE) set(GUI_SRC ${GUI_SRC} radio_tools.cpp) endif() +if(PXX2 OR MULTIMODULE) + set(GUI_SRC ${GUI_SRC} radio_spectrum_analyser.cpp) +endif() + if(PXX2) - set(GUI_SRC - ${GUI_SRC} - radio_spectrum_analyser.cpp - radio_power_meter.cpp - ) + set(GUI_SRC ${GUI_SRC} radio_power_meter.cpp) endif() if(DISK_CACHE) diff --git a/radio/src/targets/horus/board.cpp b/radio/src/targets/horus/board.cpp index 40900a099..0ec6e9746 100644 --- a/radio/src/targets/horus/board.cpp +++ b/radio/src/targets/horus/board.cpp @@ -49,7 +49,7 @@ void watchdogInit(unsigned int duration) extern "C" void initialise_monitor_handles(); #endif -#if defined(PCBX10) +#if defined(PCBX10) && !defined(RADIO_T16) void sportUpdateInit() { GPIO_InitTypeDef GPIO_InitStructure; @@ -171,7 +171,7 @@ void boardInit() DBGMCU_APB1PeriphConfig(DBGMCU_IWDG_STOP|DBGMCU_TIM1_STOP|DBGMCU_TIM2_STOP|DBGMCU_TIM3_STOP|DBGMCU_TIM4_STOP|DBGMCU_TIM5_STOP|DBGMCU_TIM6_STOP|DBGMCU_TIM7_STOP|DBGMCU_TIM8_STOP|DBGMCU_TIM9_STOP|DBGMCU_TIM10_STOP|DBGMCU_TIM11_STOP|DBGMCU_TIM12_STOP|DBGMCU_TIM13_STOP|DBGMCU_TIM14_STOP, ENABLE); #endif -#if defined(PCBX10) +#if defined(PCBX10) && !defined(RADIO_T16) ledInit(); sportUpdateInit(); #endif diff --git a/radio/src/targets/horus/board.h b/radio/src/targets/horus/board.h index 3d891cb8a..c9d72c8ab 100644 --- a/radio/src/targets/horus/board.h +++ b/radio/src/targets/horus/board.h @@ -569,7 +569,7 @@ void telemetryClearFifo(); extern uint32_t telemetryErrors; // Sport update driver -#if defined(PCBX10) +#if defined(PCBX10) && !defined(RADIO_T16) void sportUpdatePowerOn(); void sportUpdatePowerOff(); #define SPORT_UPDATE_POWER_ON() sportUpdatePowerOn() diff --git a/radio/src/telemetry/multi.cpp b/radio/src/telemetry/multi.cpp index 8225975e4..e7ff0487e 100644 --- a/radio/src/telemetry/multi.cpp +++ b/radio/src/telemetry/multi.cpp @@ -21,10 +21,12 @@ #include "telemetry.h" #include "multi.h" +extern uint8_t g_moduleIdx; + enum MultiPacketTypes : uint8_t { MultiStatus = 1, - FrSkySportTelemtry, + FrSkySmoduleIdxTelemtry, FrSkyHubTelemetry, SpektrumTelemetry, DSMBindPacket, @@ -138,7 +140,14 @@ void setMultiTelemetryBufferState(uint8_t, MultiBufferState state) static MultiBufferState guessProtocol(uint8_t module) { - if (g_model.moduleData[module].getMultiProtocol(false) == MODULE_SUBTYPE_MULTI_DSM2) + uint32_t moduleIdx = EXTERNAL_MODULE; +#if defined(INTERNAL_MODULE_MULTI) + if (isModuleMultimodule(INTERNAL_MODULE)) { + moduleIdx = INTERNAL_MODULE; + } +#endif + + if (g_model.moduleData[moduleIdx].getMultiProtocol(false) == MODULE_SUBTYPE_MULTI_DSM2) return SpektrumTelemetryFallback; else if (g_model.moduleData[module].getMultiProtocol(false) == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) return FlyskyTelemetryFallback; @@ -146,6 +155,44 @@ static MultiBufferState guessProtocol(uint8_t module) return FrskyTelemetryFallback; } +static void processMultiScannerPacket(const uint8_t *data) +{ + uint8_t cur_channel = data[0]; + if (moduleState[g_moduleIdx].mode == MODULE_MODE_SPECTRUM_ANALYSER) { + for (uint8_t channel = 0; channel <5; channel++) { + uint8_t power = max(0,(data[channel+1] - 34) >> 1); // remove everything below -120dB + +#if LCD_W == 480 + coord_t x = cur_channel*2; + if (x < LCD_W) { + reusableBuffer.spectrumAnalyser.bars[x] = power; + reusableBuffer.spectrumAnalyser.bars[x+1] = power; + if (power > reusableBuffer.spectrumAnalyser.max[x]) { + reusableBuffer.spectrumAnalyser.max[x] = power; + reusableBuffer.spectrumAnalyser.max[x+1] = power; + } +#elif LCD_W == 212 + coord_t x = cur_channel; + if (x <= LCD_W) { + reusableBuffer.spectrumAnalyser.bars[x] = power; + if (power > reusableBuffer.spectrumAnalyser.max[x]) { + reusableBuffer.spectrumAnalyser.max[x] = power; + } +#else + coord_t x = cur_channel/2 + 1; + if (x <= LCD_W) { + reusableBuffer.spectrumAnalyser.bars[x] = power; + if (power > reusableBuffer.spectrumAnalyser.max[x]) { + reusableBuffer.spectrumAnalyser.max[x] = power; + } +#endif + } + if (++cur_channel > MULTI_SCANNER_MAX_CHANNEL) + cur_channel = 0; + } + } +} + static void processMultiStatusPacket(const uint8_t * data, uint8_t module) { MultiModuleStatus &status = getMultiModuleStatus(module); @@ -248,11 +295,11 @@ static void processMultiTelemetryPaket(const uint8_t * packet, uint8_t module) TRACE("[MP] Received Frsky HUB telemetry len %d < 4", len); break; - case FrSkySportTelemtry: + case FrSkySmoduleIdxTelemtry: if (len >= 4) sportProcessTelemetryPacket(data); else - TRACE("[MP] Received sport telemetry len %d < 4", len); + TRACE("[MP] Received smoduleIdx telemetry len %d < 4", len); break; case InputSync: @@ -269,11 +316,17 @@ static void processMultiTelemetryPaket(const uint8_t * packet, uint8_t module) #if defined(LUA) case FrskySportPolling: if (len >= 1 && outputTelemetryBuffer.destination == TELEMETRY_ENDPOINT_SPORT && data[0] == outputTelemetryBuffer.sport.physicalId) { - TRACE("MP Sending sport data out."); + TRACE("MP Sending smoduleIdx data out."); sportSendBuffer(outputTelemetryBuffer.data, outputTelemetryBuffer.size); } break; #endif + case SpectrumScannerPacket: + if (len == 6) + processMultiScannerPacket(data); + else + TRACE("[MP] Received spectrum scanner len %d != 6", len); + break; default: TRACE("[MP] Unkown multi packet type 0x%02X, len %d", type, len); @@ -319,7 +372,7 @@ void MultiModuleSyncStatus::calcAdjustedRefreshRate(uint16_t newRefreshRate, uin return; } - // Caluclate how many samples went into the reported input Lag (*10) + // Caluclate how many samples went into the remoduleIdxed input Lag (*10) int numsamples = interval * 10000 / targetRefreshRate; // Convert lagDifference to ps diff --git a/radio/src/telemetry/multi.h b/radio/src/telemetry/multi.h index 1bfd1ded6..83f3de6fb 100644 --- a/radio/src/telemetry/multi.h +++ b/radio/src/telemetry/multi.h @@ -80,10 +80,17 @@ Type 0x06 Flysky AFHDS2 telemetry data data[0] = RSSI value data[1-28] telemetry data +Type 0x0B Spectrum Scanner telemetry data + length: 6 + data[0] = start channel (2400 + x*0.333 Mhz) + data[1-5] power levels + */ void processMultiTelemetryData(uint8_t data, uint8_t module); +#define MULTI_SCANNER_MAX_CHANNEL 249 + // This should be put into the Module definition if other modules gain this functionality struct MultiModuleSyncStatus { uint32_t adjustedRefreshRate; // in ps