1
0
Fork 0
mirror of https://github.com/EdgeTX/edgetx.git synced 2025-07-23 16:25:12 +03:00

Spectrum analyser reworked (#6836)

* Spectrum analyser reworked

* Fix typo

* Cosmetics

* Cosmetics

* yet another overall look update

* T16 compilations fixes

* Various Taranis compile  fixes

* Cosmetics

* Cosmetics

* Cosmetics

* Cosmetics fixes
This commit is contained in:
3djc 2019-10-10 15:42:35 +02:00 committed by GitHub
parent 7094a744d6
commit 891c13e98d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 284 additions and 131 deletions

View file

@ -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,

View file

@ -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; i<SPECTRUM_FIELDS_MAX; i++) {
LcdFlags attr = (menuHorizontalPosition == i ? (s_editMode>0 ? 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<int>(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<LCD_W; xv++) {
coord_t yv = MENU_FOOTER_TOP - 1 - limit<int>(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<int>(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<int>(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<LCD_W; xv++) {
coord_t yv = MENU_FOOTER_TOP - 1 - limit<int>(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<coord_t>(MENU_HEADER_HEIGHT + 1, peak_y - FH);
lcdDrawNumber(limit<coord_t>(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;
}

View file

@ -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

View file

@ -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()

View file

@ -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; i<SPECTRUM_FIELDS_MAX; i++) {
LcdFlags attr = (menuHorizontalPosition == i ? (s_editMode>0 ? 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<LCD_W; i++) {
uint8_t h = min<uint8_t >(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<int8_t>(FH, LCD_H - peak_y - FH);
lcdDrawNumber(min<uint8_t>(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<LCD_W; i++) {
uint8_t h = min<uint8_t >(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);
}

View file

@ -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

View file

@ -545,4 +545,3 @@ void check(event_t event, uint8_t curr, const MenuHandlerFunc *menuTab, uint8_t
menuHorizontalPosition = l_posHorz;
}

View file

@ -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;

View file

@ -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)

View file

@ -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

View file

@ -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,18 +249,18 @@ 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)
#if defined(MULTIMODULE) //&& defined(INTMODULE_USART)
UartMultiPulses multi;
#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)

View file

@ -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)

View file

@ -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

View file

@ -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()

View file

@ -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<int>(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

View file

@ -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