feat(color): spectrum analyzer peak hold (#6451)
This commit is contained in:
@@ -717,6 +717,7 @@ union ReusableBuffer
|
||||
struct {
|
||||
uint8_t bars[LCD_W];
|
||||
uint8_t max[LCD_W];
|
||||
uint8_t peak[LCD_W];
|
||||
uint32_t freq;
|
||||
uint32_t span;
|
||||
uint32_t step;
|
||||
|
||||
@@ -240,6 +240,7 @@ EdgeTxStyles::EdgeTxStyles()
|
||||
lv_style_init(&graph_position_line);
|
||||
lv_style_init(&div_line);
|
||||
lv_style_init(&div_line_edit);
|
||||
lv_style_init(&div_line_warn);
|
||||
lv_style_init(&div_line_black);
|
||||
lv_style_init(&div_line_white);
|
||||
|
||||
@@ -264,6 +265,9 @@ EdgeTxStyles::EdgeTxStyles()
|
||||
lv_style_set_line_width(&div_line_edit, 1);
|
||||
lv_style_set_line_opa(&div_line_edit, LV_OPA_COVER);
|
||||
|
||||
lv_style_set_line_width(&div_line_warn, 1);
|
||||
lv_style_set_line_opa(&div_line_warn, LV_OPA_COVER);
|
||||
|
||||
lv_style_set_line_width(&div_line_black, 1);
|
||||
lv_style_set_line_opa(&div_line_black, LV_OPA_COVER);
|
||||
|
||||
@@ -313,6 +317,7 @@ void EdgeTxStyles::applyColors()
|
||||
makeLvColor(COLOR_THEME_ACTIVE));
|
||||
lv_style_set_line_color(&div_line, makeLvColor(COLOR_THEME_SECONDARY1));
|
||||
lv_style_set_line_color(&div_line_edit, makeLvColor(COLOR_THEME_EDIT));
|
||||
lv_style_set_line_color(&div_line_warn, makeLvColor(COLOR_THEME_WARNING));
|
||||
lv_style_set_line_color(&div_line_black, makeLvColor(COLOR_THEME_PRIMARY1));
|
||||
lv_style_set_line_color(&div_line_white, makeLvColor(COLOR_THEME_PRIMARY2));
|
||||
|
||||
|
||||
@@ -220,6 +220,7 @@ class EdgeTxStyles
|
||||
lv_style_t graph_position_line;
|
||||
lv_style_t div_line;
|
||||
lv_style_t div_line_edit;
|
||||
lv_style_t div_line_warn;
|
||||
lv_style_t div_line_black;
|
||||
lv_style_t div_line_white;
|
||||
|
||||
|
||||
@@ -21,22 +21,33 @@
|
||||
|
||||
#include "radio_spectrum_analyser.h"
|
||||
|
||||
#include "libopenui.h"
|
||||
#include "edgetx.h"
|
||||
#include "libopenui.h"
|
||||
|
||||
#define SET_DIRTY() storageDirty(EE_GENERAL)
|
||||
|
||||
LAYOUT_VAL_SCALED(SCALE_HEIGHT, 15)
|
||||
constexpr coord_t SPECTRUM_HEIGHT = LCD_H - EdgeTxStyles::MENU_HEADER_HEIGHT - SCALE_HEIGHT - EdgeTxStyles::UI_ELEMENT_HEIGHT;
|
||||
constexpr coord_t SPECTRUM_HEIGHT = LCD_H - EdgeTxStyles::MENU_HEADER_HEIGHT -
|
||||
SCALE_HEIGHT -
|
||||
EdgeTxStyles::UI_ELEMENT_HEIGHT;
|
||||
|
||||
coord_t getAverage(uint8_t number, const uint8_t* value)
|
||||
template <uint8_t CNT>
|
||||
coord_t getAverage(const uint8_t* value)
|
||||
{
|
||||
uint16_t sum = 0;
|
||||
for (uint8_t i = 0; i < number; i++) {
|
||||
for (uint8_t i = 0; i < CNT; i++) {
|
||||
sum += value[i];
|
||||
}
|
||||
if (SPECTRUM_HEIGHT > 300) sum = sum * 2;
|
||||
return sum / number;
|
||||
return sum / CNT;
|
||||
}
|
||||
|
||||
template <>
|
||||
coord_t getAverage<4>(const uint8_t* value)
|
||||
{
|
||||
uint16_t sum = value[0] + value[1] + value[2] + value[3];
|
||||
if (SPECTRUM_HEIGHT > 300) sum = sum * 2;
|
||||
return sum / 4;
|
||||
}
|
||||
|
||||
class SpectrumFooterWindow : public Window
|
||||
@@ -53,13 +64,18 @@ class SpectrumFooterWindow : public Window
|
||||
// Frequency
|
||||
sprintf(label, "T: %dMHz",
|
||||
int(reusableBuffer.spectrumAnalyser.freq / 1000000));
|
||||
(new StaticText(this, rect_t{PAD_TINY, 0, FLD_W, EdgeTxStyles::UI_ELEMENT_HEIGHT}, label))
|
||||
(new StaticText(
|
||||
this, rect_t{PAD_TINY, 0, FLD_W, EdgeTxStyles::UI_ELEMENT_HEIGHT},
|
||||
label))
|
||||
->padTop(PAD_MEDIUM);
|
||||
|
||||
// Span
|
||||
sprintf(label, "S: %dMHz",
|
||||
int(reusableBuffer.spectrumAnalyser.span / 1000000));
|
||||
(new StaticText(this, rect_t{PAD_TINY + FLD_W, 0, FLD_W, EdgeTxStyles::UI_ELEMENT_HEIGHT}, label))
|
||||
(new StaticText(
|
||||
this,
|
||||
rect_t{PAD_TINY + FLD_W, 0, FLD_W, EdgeTxStyles::UI_ELEMENT_HEIGHT},
|
||||
label))
|
||||
->padTop(PAD_MEDIUM);
|
||||
} else {
|
||||
// Frequency
|
||||
@@ -84,7 +100,9 @@ class SpectrumFooterWindow : public Window
|
||||
|
||||
// Tracker
|
||||
auto tracker = new NumberEdit(
|
||||
this, rect_t{(PAD_TINY + FLD_W) * 2, 0, FLD_W, EdgeTxStyles::UI_ELEMENT_HEIGHT},
|
||||
this,
|
||||
rect_t{(PAD_TINY + FLD_W) * 2, 0, FLD_W,
|
||||
EdgeTxStyles::UI_ELEMENT_HEIGHT},
|
||||
(reusableBuffer.spectrumAnalyser.freq -
|
||||
reusableBuffer.spectrumAnalyser.span / 2) /
|
||||
1000000,
|
||||
@@ -122,8 +140,8 @@ class SpectrumScaleWindow : public Window
|
||||
int x = (frequency - startFreq) / reusableBuffer.spectrumAnalyser.step;
|
||||
if (x >= LCD_W - 1) break;
|
||||
formatNumberAsString(s, 16, frequency / 1000000, 16);
|
||||
new StaticText(this, {x - PAD_LARGE * 2, 0, PAD_LARGE * 4, SCALE_HEIGHT}, s,
|
||||
COLOR_THEME_PRIMARY1_INDEX, FONT(XS) | CENTERED);
|
||||
new StaticText(this, {x - PAD_LARGE * 2, 0, PAD_LARGE * 4, SCALE_HEIGHT},
|
||||
s, COLOR_THEME_PRIMARY1_INDEX, FONT(XS) | CENTERED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,8 +164,7 @@ class SpectrumScaleWindow : public Window
|
||||
class SpectrumWindow : public Window
|
||||
{
|
||||
public:
|
||||
SpectrumWindow(Window* parent, const rect_t& rect) :
|
||||
Window(parent, rect)
|
||||
SpectrumWindow(Window* parent, const rect_t& rect) : Window(parent, rect)
|
||||
{
|
||||
lv_style_init(&style);
|
||||
lv_style_set_line_width(&style, PAD_THREE);
|
||||
@@ -179,6 +196,10 @@ class SpectrumWindow : public Window
|
||||
line = lv_line_create(lvobj);
|
||||
lv_obj_add_style(line, &style, LV_PART_MAIN);
|
||||
barLines[i] = line;
|
||||
|
||||
line = lv_line_create(lvobj);
|
||||
etx_obj_add_style(line, styles->div_line_warn, LV_PART_MAIN);
|
||||
peakLines[i] = line;
|
||||
}
|
||||
|
||||
warning = new StaticText(
|
||||
@@ -200,13 +221,14 @@ class SpectrumWindow : public Window
|
||||
|
||||
#if defined(SIMU)
|
||||
// Geneate random data for simu
|
||||
for (coord_t x = 0; x < width() - 1; x++) {
|
||||
for (coord_t x = 0; x < width(); x++) {
|
||||
uint8_t power = rand() % 80;
|
||||
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;
|
||||
}
|
||||
if (power > reusableBuffer.spectrumAnalyser.peak[x]) {
|
||||
reusableBuffer.spectrumAnalyser.peak[x] = power;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -215,19 +237,29 @@ class SpectrumWindow : public Window
|
||||
lv_coord_t yv =
|
||||
SCALE_TOP - 1 -
|
||||
limit<int>(0,
|
||||
getAverage(step, &reusableBuffer.spectrumAnalyser.bars[x])
|
||||
getAverage<step>(&reusableBuffer.spectrumAnalyser.bars[x])
|
||||
<< 1,
|
||||
SCALE_TOP);
|
||||
lv_coord_t max_yv =
|
||||
SCALE_TOP - 1 -
|
||||
limit<int>(
|
||||
0, getAverage(step, &reusableBuffer.spectrumAnalyser.max[x]) << 1,
|
||||
0, getAverage<step>(&reusableBuffer.spectrumAnalyser.max[x]) << 1,
|
||||
SCALE_TOP);
|
||||
lv_coord_t peak_yv =
|
||||
SCALE_TOP - 1 -
|
||||
limit<int>(0,
|
||||
getAverage<step>(&reusableBuffer.spectrumAnalyser.peak[x])
|
||||
<< 1,
|
||||
SCALE_TOP);
|
||||
|
||||
maxPts[i] = {x, max_yv};
|
||||
maxPts[i + 1] = {(lv_coord_t)(x + 3), max_yv};
|
||||
lv_line_set_points(maxLines[i / 2], &maxPts[i], 2);
|
||||
|
||||
peakPts[i] = {x, peak_yv};
|
||||
peakPts[i + 1] = {(lv_coord_t)(x + 3), peak_yv};
|
||||
lv_line_set_points(peakLines[i / 2], &peakPts[i], 2);
|
||||
|
||||
barPts[i] = {(lv_coord_t)(x + 1), yv};
|
||||
barPts[i + 1] = {(lv_coord_t)(x + 1), SCALE_TOP};
|
||||
lv_line_set_points(barLines[i / 2], &barPts[i], 2);
|
||||
@@ -252,7 +284,8 @@ class SpectrumWindow : public Window
|
||||
reusableBuffer.spectrumAnalyser.span / 2;
|
||||
for (uint32_t frequency = (startFreq / 10000000) * 10000000 + 10000000;;
|
||||
frequency += 10000000) {
|
||||
lv_coord_t x = (frequency - startFreq) / reusableBuffer.spectrumAnalyser.step;
|
||||
lv_coord_t x =
|
||||
(frequency - startFreq) / reusableBuffer.spectrumAnalyser.step;
|
||||
if (x >= LCD_W - 1) break;
|
||||
vAxisPts[i * 2] = {x, 0};
|
||||
vAxisPts[i * 2 + 1] = {x, h};
|
||||
@@ -269,16 +302,17 @@ class SpectrumWindow : public Window
|
||||
}
|
||||
|
||||
protected:
|
||||
static LAYOUT_VAL_SCALED(LINE_SPACE, 40)
|
||||
static LAYOUT_VAL_SCALED(WARN_YO, 20)
|
||||
static LAYOUT_VAL_SCALED(LINE_SPACE, 40) static LAYOUT_VAL_SCALED(WARN_YO, 20)
|
||||
|
||||
lv_style_t style;
|
||||
lv_style_t style;
|
||||
lv_point_t maxPts[2 * LCD_W / 4];
|
||||
lv_point_t barPts[2 * LCD_W / 4];
|
||||
lv_point_t peakPts[2 * LCD_W / 4];
|
||||
lv_point_t hAxisPts[2 * SPECTRUM_HEIGHT / LINE_SPACE];
|
||||
lv_point_t vAxisPts[2 * 8];
|
||||
lv_obj_t* maxLines[LCD_W / 4];
|
||||
lv_obj_t* barLines[LCD_W / 4];
|
||||
lv_obj_t* peakLines[LCD_W / 4];
|
||||
lv_obj_t* vAxisLines[8];
|
||||
StaticText* warning = nullptr;
|
||||
|
||||
@@ -309,9 +343,10 @@ void RadioSpectrumAnalyser::buildBody(Window* window)
|
||||
{
|
||||
new SpectrumWindow(window, {0, 0, LCD_W, SPECTRUM_HEIGHT});
|
||||
new SpectrumScaleWindow(window, {0, SPECTRUM_HEIGHT, LCD_W, SCALE_HEIGHT});
|
||||
new SpectrumFooterWindow(
|
||||
window, {0, SPECTRUM_HEIGHT + SCALE_HEIGHT, LCD_W, EdgeTxStyles::UI_ELEMENT_HEIGHT},
|
||||
moduleIdx);
|
||||
new SpectrumFooterWindow(window,
|
||||
{0, SPECTRUM_HEIGHT + SCALE_HEIGHT, LCD_W,
|
||||
EdgeTxStyles::UI_ELEMENT_HEIGHT},
|
||||
moduleIdx);
|
||||
}
|
||||
|
||||
void RadioSpectrumAnalyser::checkEvents()
|
||||
@@ -325,7 +360,8 @@ void RadioSpectrumAnalyser::checkEvents()
|
||||
if (x != trackX) {
|
||||
trackX = x;
|
||||
trackPts[0] = {(lv_coord_t)x, EdgeTxStyles::MENU_HEADER_HEIGHT};
|
||||
trackPts[1] = {(lv_coord_t)x, (lv_coord_t)(height() - EdgeTxStyles::UI_ELEMENT_HEIGHT)};
|
||||
trackPts[1] = {(lv_coord_t)x,
|
||||
(lv_coord_t)(height() - EdgeTxStyles::UI_ELEMENT_HEIGHT)};
|
||||
lv_line_set_points(trackLine, trackPts, 2);
|
||||
}
|
||||
Page::checkEvents();
|
||||
|
||||
@@ -416,8 +416,16 @@ static void processSpectrumAnalyserFrame(uint8_t module, const uint8_t * frame)
|
||||
if (x < LCD_W) {
|
||||
reusableBuffer.spectrumAnalyser.bars[x] = max<int>(0, -SPECTRUM_ANALYSER_POWER_FLOOR + power); // we remove everything below -120dB
|
||||
#if defined(COLORLCD)
|
||||
if (reusableBuffer.spectrumAnalyser.bars[x] > reusableBuffer.spectrumAnalyser.max[x])
|
||||
reusableBuffer.spectrumAnalyser.max[x] = reusableBuffer.spectrumAnalyser.bars[x];
|
||||
if (reusableBuffer.spectrumAnalyser.bars[x] >
|
||||
reusableBuffer.spectrumAnalyser.max[x]) {
|
||||
reusableBuffer.spectrumAnalyser.max[x] =
|
||||
reusableBuffer.spectrumAnalyser.bars[x];
|
||||
}
|
||||
if (reusableBuffer.spectrumAnalyser.bars[x] >
|
||||
reusableBuffer.spectrumAnalyser.peak[x]) {
|
||||
reusableBuffer.spectrumAnalyser.peak[x] =
|
||||
reusableBuffer.spectrumAnalyser.bars[x];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,25 +164,41 @@ static void processMultiScannerPacket(const uint8_t *data, const uint8_t moduleI
|
||||
coord_t x = cur_channel*2;
|
||||
if (x < LCD_W) {
|
||||
reusableBuffer.spectrumAnalyser.bars[x] = power;
|
||||
reusableBuffer.spectrumAnalyser.bars[x+1] = power;
|
||||
if (x + 1 < LCD_W) {
|
||||
reusableBuffer.spectrumAnalyser.bars[x + 1] = power;
|
||||
}
|
||||
if (power > reusableBuffer.spectrumAnalyser.max[x]) {
|
||||
reusableBuffer.spectrumAnalyser.max[x] = power;
|
||||
reusableBuffer.spectrumAnalyser.max[x+1] = power;
|
||||
if (x + 1 < LCD_W) {
|
||||
reusableBuffer.spectrumAnalyser.max[x + 1] = power;
|
||||
}
|
||||
}
|
||||
if (power > reusableBuffer.spectrumAnalyser.peak[x]) {
|
||||
reusableBuffer.spectrumAnalyser.peak[x] = power;
|
||||
if (x + 1 < LCD_W) {
|
||||
reusableBuffer.spectrumAnalyser.peak[x + 1] = power;
|
||||
}
|
||||
}
|
||||
#elif LCD_W == 212
|
||||
coord_t x = cur_channel;
|
||||
if (x <= LCD_W) {
|
||||
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;
|
||||
}
|
||||
if (power > reusableBuffer.spectrumAnalyser.peak[x]) {
|
||||
reusableBuffer.spectrumAnalyser.peak[x] = power;
|
||||
}
|
||||
#else
|
||||
coord_t x = cur_channel/2 + 1;
|
||||
if (x <= LCD_W) {
|
||||
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;
|
||||
}
|
||||
if (power > reusableBuffer.spectrumAnalyser.peak[x]) {
|
||||
reusableBuffer.spectrumAnalyser.peak[x] = power;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (++cur_channel > MULTI_SCANNER_MAX_CHANNEL)
|
||||
|
||||
Reference in New Issue
Block a user