From c78fa6de7aee3d051de662880d82d4160d14c2f0 Mon Sep 17 00:00:00 2001 From: Sassa NF Date: Sat, 28 Sep 2024 22:36:48 +0100 Subject: [PATCH] Factor out drawing into Charts --- lib/charts/BarChart.cpp | 92 +++++++++++++++++++++++++++++++++++++++++ lib/charts/charts.h | 67 ++++++++++++++++++++++++++++++ src/main.cpp | 52 +++++++++++------------ 3 files changed, 185 insertions(+), 26 deletions(-) create mode 100644 lib/charts/BarChart.cpp create mode 100644 lib/charts/charts.h diff --git a/lib/charts/BarChart.cpp b/lib/charts/BarChart.cpp new file mode 100644 index 0000000..eacd78d --- /dev/null +++ b/lib/charts/BarChart.cpp @@ -0,0 +1,92 @@ +#include "charts.h" + +void BarChart::reset() +{ + memset(ys, 0, width * sizeof(float)); + memset(changed, false, width * sizeof(bool)); + redraw_all = true; +} + +int BarChart::updatePoint(float x, float y) +{ + if (x < min_x || x >= max_x) + { + return -1; + } + + size_t idx = width * (x - min_x) / (max_x - min_x); + if (idx >= width) + { + idx = width - 1; + } + + if (!changed[idx] || ys[idx] < y) + { + ys[idx] = y; + changed[idx] = true; + } + + return idx; +} + +void BarChart::draw() +{ + for (int x = 0; x < width; x++) + { + if (!changed[x] && !redraw_all) + continue; + + drawOne(x); + } + + redraw_all = false; +} + +void BarChart::drawOne(int x) +{ + if (x < 0) + return; + + int y = y2pos(ys[x]); + + if (y < height) + { + display.setColor(BLACK); + display.drawVerticalLine(pos_x + x, pos_y, y); + display.setColor(WHITE); + display.drawVerticalLine(pos_x + x, pos_y + y, height - y); + } + else + { + display.setColor(BLACK); + display.drawVerticalLine(pos_x + x, pos_y, height); + } + + if (x % 2 == 0) + { + display.setColor(INVERSE); + display.setPixel(pos_x + x, pos_y + y2pos(level_y)); + } + + changed[x] = false; +} + +int BarChart::x2pos(float x) +{ + if (x < min_x) + x = min_x; + if (x > max_x) + x = max_x; + + return width * (x - min_x) / (max_x - min_x); +} + +int BarChart::y2pos(float y) +{ + if (y < min_y) + y = min_y; + if (y > max_y) + y = max_y; + + return height - height * (y - min_y) / (max_y - min_y); +} diff --git a/lib/charts/charts.h b/lib/charts/charts.h new file mode 100644 index 0000000..5c8a4ce --- /dev/null +++ b/lib/charts/charts.h @@ -0,0 +1,67 @@ +#ifndef CHARTS_H +#define CHARTS_H + +#include +#include +#include + +struct Chart +{ + uint16_t pos_x, pos_y; + uint16_t width, height; + OLEDDisplay &display; + + Chart(OLEDDisplay &d, uint16_t x, uint16_t y, uint16_t w, uint16_t h) + : display(d), pos_x(x), pos_y(y), width(w), height(h) {}; + + /* + * This method resets the state and sets the reference time. + */ + virtual void reset() = 0; + + /* + * Update one data point, and return what column needs redrawing. + */ + virtual int updatePoint(float x, float y) = 0; + + /* + * If you fancy animated progress, then pass the output of updatePoint to here. + */ + virtual void drawOne(int x) = 0; + + /* + * Redraw everything that needs redrawing. + */ + virtual void draw() = 0; +}; + +struct BarChart : Chart +{ + float min_x, max_x, min_y, max_y; + float level_y; + + float *ys; + bool *changed; + bool redraw_all; + + BarChart(OLEDDisplay &d, uint16_t x, uint16_t y, uint16_t w, uint16_t h, float min_x, + float max_x, float min_y, float max_y, float level_y) + : Chart(d, x, y, w, h), min_x(min_x), max_x(max_x), min_y(min_y), max_y(max_y), + level_y(level_y), redraw_all(true) + { + ys = new float[w]; + changed = new bool[w]; + + memset(ys, 0, w * sizeof(float)); + memset(changed, 0, w * sizeof(bool)); + }; + + void reset() override; + int updatePoint(float x, float y) override; + void drawOne(int x) override; + void draw() override; + + int x2pos(float x); + int y2pos(float y); +}; +#endif diff --git a/src/main.cpp b/src/main.cpp index 6fd371a..4e232ab 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -41,6 +41,7 @@ // library internals. #define RADIOLIB_GODMODE (1) +#include #include #ifndef LILYGO @@ -365,6 +366,8 @@ void osdProcess() } #endif +BarChart *bar; + void init_radio() { // initialize SX1262 FSK modem at the initial frequency @@ -653,6 +656,14 @@ void setup(void) #ifdef LOG_DATA_JSON xTaskCreate(logToSerialTask, "LOG_DATA_JSON", 2048, NULL, 1, NULL); #endif + + bar = new BarChart(display, 0, START_LOW, display.width(), + display.height() / 2 - START_LOW, FREQ_BEGIN, FREQ_END, + LO_RSSI_THRESHOLD, HI_RSSI_THRESHOLD, + -(float)show_db_after); // LO_RSSI_THRESHOLD + (HI_RSSI_THRESHOLD - + // LO_RSSI_THRESHOLD) * 0.3); + + bar->reset(); } // Formula to translate 33 bin to approximate RSSI value @@ -1060,6 +1071,7 @@ void loop(void) detected_y[display_x] = false; #if FILTER_SPECTRUM_RESULTS + float rr; if (detected) { // calculating max window x RSSI after filters @@ -1070,6 +1082,18 @@ void loop(void) max_x_window[x_window] = abs_result; LOG("MAX x window: %i %i\n", x_window, abs_result); } + rr = -(float)result[detected_at]; + } + else + { + rr = LO_RSSI_THRESHOLD; + } + + int updated = bar->updatePoint(freq, rr); + + if (first_run || ANIMATED_RELOAD) + { + bar->drawOne(updated); } #endif @@ -1146,31 +1170,6 @@ void loop(void) } #endif - display.setColor(WHITE); - display.drawVerticalLine(display_x, START_LOW + detected_at, - min(RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE, - MAX_POWER_LEVELS - START_LOW) - - detected_at); - - // ------------------------------------------------------------- - // Draw "Detection Level line" every 2 pixel - // ------------------------------------------------------------- - if (display_x % 2 == 0) - { - if (detected_at <= drone_detection_level) - { - display.setColor(INVERSE); - } - else - { - display.setColor(WHITE); - } - display.setPixel(display_x, drone_detection_level + START_LOW); - // display.setPixel(display_x, y + START_LOW - 1); // 2 px wide - - display.setColor(WHITE); - } - #ifdef JOYSTICK_ENABLED // Draw joystick cursor and Frequency RSSI value if (display_x == cursor_x_position) @@ -1258,6 +1257,7 @@ void loop(void) } #endif + bar->draw(); #ifdef METHOD_RSSI // Printing Max Window DB. for (int x2 = 0; x2 < STEPS / WINDOW_SIZE; x2++) @@ -1270,7 +1270,7 @@ void loop(void) max_x_window[x2] = 999; } #endif - // Render display data here + // Render display data here display.display(); #ifdef OSD_ENABLED // Sometimes OSD prints entire screen with the digits.