mirror of
https://github.com/Genaker/LoraSA.git
synced 2026-03-28 17:42:59 +01:00
Status Bar
This commit is contained in:
26
include/ui.h
26
include/ui.h
@@ -8,6 +8,9 @@
|
||||
#include <Arduino.h>
|
||||
#endif
|
||||
|
||||
#include <charts.h>
|
||||
#include <scan.h>
|
||||
|
||||
// #include <heltec_unofficial.h>
|
||||
|
||||
// (optional) major and minor tick-marks at x MHz
|
||||
@@ -31,14 +34,21 @@
|
||||
|
||||
#define SCREEN_HEIGHT 64 // ???? not used
|
||||
|
||||
// publish functions
|
||||
#ifdef Vision_Master_E290
|
||||
extern void UI_Init(DEPG0290BxS800FxX_BW *);
|
||||
#else
|
||||
extern void UI_Init(SSD1306Wire *);
|
||||
#endif
|
||||
extern void UI_displayDecorate(int, int, bool);
|
||||
extern void UI_setLedFlag(bool);
|
||||
extern void UI_Init(Display_t *);
|
||||
extern void UI_clearPlotter(void);
|
||||
extern void UI_clearTopStatus(void);
|
||||
extern void UI_drawCursor(int16_t);
|
||||
|
||||
struct StatusBar : Chart
|
||||
{
|
||||
Scan &r;
|
||||
bool ui_initialized;
|
||||
uint16_t scan_progress_count;
|
||||
|
||||
StatusBar(Display_t &d, uint16_t x, uint16_t y, uint16_t w, Scan &r)
|
||||
: Chart(d, x, y, w, LABEL_HEIGHT), r(r), ui_initialized(false),
|
||||
scan_progress_count(0) {};
|
||||
|
||||
virtual void clearStatus();
|
||||
virtual void draw() override;
|
||||
};
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
#ifndef CHARTS_H
|
||||
#define CHARTS_H
|
||||
|
||||
#ifdef Vision_Master_E290
|
||||
#include "HT_DEPG0290BxS800FxX_BW.h"
|
||||
typedef DEPG0290BxS800FxX_BW Display_t;
|
||||
#else
|
||||
#include <OLEDDisplay.h>
|
||||
typedef OLEDDisplay Display_t;
|
||||
#endif
|
||||
|
||||
#include <cstdint>
|
||||
#include <models.h>
|
||||
#include <stdlib.h>
|
||||
@@ -10,9 +17,9 @@ struct Chart
|
||||
{
|
||||
uint16_t pos_x, pos_y;
|
||||
uint16_t width, height;
|
||||
OLEDDisplay &display;
|
||||
Display_t &display;
|
||||
|
||||
Chart(OLEDDisplay &d, uint16_t x, uint16_t y, uint16_t w, uint16_t h)
|
||||
Chart(Display_t &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) {};
|
||||
|
||||
/*
|
||||
@@ -37,7 +44,7 @@ struct Chart
|
||||
*/
|
||||
struct ProgressChart : Chart
|
||||
{
|
||||
ProgressChart(OLEDDisplay &d, uint16_t x, uint16_t y, uint16_t w, uint16_t h)
|
||||
ProgressChart(Display_t &d, uint16_t x, uint16_t y, uint16_t w, uint16_t h)
|
||||
: Chart(d, x, y, w, h) {};
|
||||
|
||||
/*
|
||||
@@ -60,7 +67,7 @@ struct BarChart : ProgressChart
|
||||
bool *changed;
|
||||
bool redraw_all;
|
||||
|
||||
BarChart(OLEDDisplay &d, uint16_t x, uint16_t y, uint16_t w, uint16_t h, float min_x,
|
||||
BarChart(Display_t &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)
|
||||
: ProgressChart(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)
|
||||
@@ -81,7 +88,7 @@ struct BarChart : ProgressChart
|
||||
int y2pos(float y);
|
||||
};
|
||||
|
||||
#define LABEL_HEIGHT 6
|
||||
#define LABEL_HEIGHT 7
|
||||
#define X_AXIS_WEIGHT 1
|
||||
#define MAJOR_TICK_LENGTH 2
|
||||
#define MAJOR_TICKS 10
|
||||
@@ -92,7 +99,7 @@ struct DecoratedBarChart : Chart
|
||||
{
|
||||
BarChart bar;
|
||||
|
||||
DecoratedBarChart(OLEDDisplay &d, uint16_t x, uint16_t y, uint16_t w, uint16_t h,
|
||||
DecoratedBarChart(Display_t &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),
|
||||
bar(d, x, y + LABEL_HEIGHT, w, h - LABEL_HEIGHT - AXIS_HEIGHT, min_x, max_x,
|
||||
@@ -107,7 +114,7 @@ struct StackedChart : Chart
|
||||
Chart **charts;
|
||||
size_t charts_sz;
|
||||
|
||||
StackedChart(OLEDDisplay &d, uint16_t x, uint16_t y, uint16_t w, uint16_t h)
|
||||
StackedChart(Display_t &d, uint16_t x, uint16_t y, uint16_t w, uint16_t h)
|
||||
: Chart(d, x, y, w, h), charts(NULL), charts_sz(0) {};
|
||||
|
||||
/*
|
||||
@@ -138,7 +145,7 @@ struct WaterfallChart : Chart
|
||||
|
||||
WaterfallModel *model;
|
||||
|
||||
WaterfallChart(OLEDDisplay &d, uint16_t x, uint16_t y, uint16_t w, uint16_t h,
|
||||
WaterfallChart(Display_t &d, uint16_t x, uint16_t y, uint16_t w, uint16_t h,
|
||||
float min_x, float max_x, float level_y, float threshold,
|
||||
WaterfallModel *m)
|
||||
: Chart(d, x, y, w, h), model(m), min_x(min_x), max_x(max_x), level_y(level_y),
|
||||
@@ -157,7 +164,7 @@ struct UptimeClock : Chart
|
||||
{
|
||||
uint64_t t0;
|
||||
uint64_t t1;
|
||||
UptimeClock(OLEDDisplay &d, uint64_t t0) : Chart(d, 0, 0, 0, 0), t0(t0), t1(t0) {};
|
||||
UptimeClock(Display_t &d, uint64_t t0) : Chart(d, 0, 0, 0, 0), t0(t0), t1(t0) {};
|
||||
|
||||
void draw(uint64_t t);
|
||||
virtual void draw() override;
|
||||
|
||||
@@ -33,6 +33,20 @@ constexpr float LO_RSSI_THRESHOLD = HI_RSSI_THRESHOLD - 66;
|
||||
|
||||
struct Scan
|
||||
{
|
||||
uint64_t epoch;
|
||||
float current_frequency;
|
||||
uint64_t fr_begin;
|
||||
uint64_t fr_end;
|
||||
uint64_t drone_detection_level;
|
||||
bool sound_on;
|
||||
bool led_flag;
|
||||
uint64_t detection_count;
|
||||
|
||||
Scan()
|
||||
: epoch(0), current_frequency(0), fr_begin(0), fr_end(0),
|
||||
drone_detection_level(0), sound_on(false), led_flag(false),
|
||||
detection_count(0) {};
|
||||
|
||||
virtual float getRSSI() = 0;
|
||||
|
||||
// rssiMethod gets the data similar to the scan method,
|
||||
|
||||
195
src/main.cpp
195
src/main.cpp
@@ -172,13 +172,11 @@ constexpr int WINDOW_SIZE = 15;
|
||||
#define SINGLE_STEP (float)(RANGE / (STEPS * SCAN_RBW_FACTOR))
|
||||
|
||||
uint64_t range = (int)(FREQ_END - FREQ_BEGIN);
|
||||
uint64_t fr_begin = FREQ_BEGIN;
|
||||
uint64_t fr_end = FREQ_BEGIN;
|
||||
|
||||
uint64_t iterations = RANGE / RANGE_PER_PAGE;
|
||||
|
||||
// uint64_t range_frequency = FREQ_END - FREQ_BEGIN;
|
||||
uint64_t median_frequency = FREQ_BEGIN + FREQ_END - FREQ_BEGIN / 2;
|
||||
uint64_t median_frequency = (FREQ_BEGIN + FREQ_END) / 2;
|
||||
|
||||
// #define DISABLE_PLOT_CHART false // unused
|
||||
|
||||
@@ -190,8 +188,7 @@ bool filtered_result[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE];
|
||||
int max_bins_array_value[MAX_POWER_LEVELS];
|
||||
int max_step_range = 32;
|
||||
|
||||
// Waterfall array
|
||||
bool waterfall[STEPS], detected_y[STEPS]; // 20 - ??? steps of the waterfall
|
||||
bool detected_y[STEPS]; // 20 - ??? steps
|
||||
|
||||
// global variable
|
||||
|
||||
@@ -203,9 +200,7 @@ uint64_t drone_detection_level = DEFAULT_DRONE_DETECTION_LEVEL;
|
||||
uint64_t show_db_after = 80;
|
||||
uint64_t drone_detected_frequency_start = 0;
|
||||
uint64_t drone_detected_frequency_end = 0;
|
||||
uint64_t detection_count = 0;
|
||||
bool single_page_scan = false;
|
||||
bool SOUND_ON = false;
|
||||
|
||||
// #define PRINT_DEBUG
|
||||
#define PRINT_PROFILE_TIME
|
||||
@@ -225,7 +220,6 @@ uint64_t x, y, range_item, w = WATERFALL_START, i = 0;
|
||||
int osd_x = 1, osd_y = 2, col = 0, max_bin = 32;
|
||||
uint64_t ranges_count = 0;
|
||||
|
||||
float freq = 0;
|
||||
int rssi = 0;
|
||||
int state = 0;
|
||||
|
||||
@@ -238,7 +232,6 @@ constexpr int samples = SAMPLES_RSSI;
|
||||
|
||||
uint8_t result_index = 0;
|
||||
uint8_t button_pressed_counter = 0;
|
||||
uint64_t loop_cnt = 0;
|
||||
|
||||
#ifndef LILYGO
|
||||
// #define JOYSTICK_ENABLED
|
||||
@@ -366,6 +359,27 @@ void osdProcess()
|
||||
}
|
||||
#endif
|
||||
|
||||
struct RadioScan : Scan
|
||||
{
|
||||
float getRSSI() override;
|
||||
};
|
||||
|
||||
float RadioScan::getRSSI()
|
||||
{
|
||||
#ifdef USING_SX1280PA
|
||||
// radio.startReceive();
|
||||
// get instantaneous RSSI value
|
||||
// When PR will be merged we can use radi.getRSSI(false);
|
||||
uint8_t data[3] = {0, 0, 0}; // RssiInst, Status, RFU
|
||||
radio.mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_RSSI_INST, data, 3);
|
||||
return ((float)data[0] / (-2.0));
|
||||
#else
|
||||
return radio.getRSSI(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
RadioScan r;
|
||||
|
||||
#define WATERFALL_SENSITIVITY 0.05
|
||||
DecoratedBarChart *bar;
|
||||
WaterfallChart *waterChart;
|
||||
@@ -532,7 +546,6 @@ void setup(void)
|
||||
#endif
|
||||
float vbat;
|
||||
float resolution;
|
||||
loop_cnt = 0;
|
||||
bt_start = millis();
|
||||
wf_start = millis();
|
||||
|
||||
@@ -551,7 +564,7 @@ void setup(void)
|
||||
delay(10);
|
||||
if (button.pressed())
|
||||
{
|
||||
SOUND_ON = !SOUND_ON;
|
||||
r.sound_on = !r.sound_on;
|
||||
tone(BUZZER_PIN, 205, 100);
|
||||
delay(50);
|
||||
tone(BUZZER_PIN, 205, 100);
|
||||
@@ -662,12 +675,17 @@ void setup(void)
|
||||
xTaskCreate(logToSerialTask, "LOG_DATA_JSON", 2048, NULL, 1, NULL);
|
||||
#endif
|
||||
|
||||
stacked.reset(0, 0, display.width(), display.height());
|
||||
|
||||
bar = new DecoratedBarChart(display, 0, 0, display.width(), 0, FREQ_BEGIN, FREQ_END,
|
||||
LO_RSSI_THRESHOLD, HI_RSSI_THRESHOLD,
|
||||
-(float)show_db_after);
|
||||
|
||||
stacked.reset(0, 0, display.width(), display.height() - 6);
|
||||
size_t b = stacked.addChart(bar);
|
||||
|
||||
Chart *statusBar = new StatusBar(display, 0, 0, display.width(), r);
|
||||
|
||||
#if (WATERFALL_ENABLED == true)
|
||||
size_t *multiples = new size_t[6]{5, 3, 4, 15, 4, 3};
|
||||
WaterfallModel *model =
|
||||
new WaterfallModel((size_t)display.width(), 1000, 6, multiples);
|
||||
@@ -679,12 +697,11 @@ void setup(void)
|
||||
new WaterfallChart(display, 0, WATERFALL_START, display.width(), 0, FREQ_BEGIN,
|
||||
FREQ_END, -(float)show_db_after, WATERFALL_SENSITIVITY, model);
|
||||
|
||||
stacked.reset(0, 0, display.width(), display.height() - 6);
|
||||
|
||||
size_t b = stacked.addChart(bar);
|
||||
size_t c = stacked.addChart(waterChart);
|
||||
stacked.setHeight(c, stacked.height - WATERFALL_START - statusBar->height);
|
||||
#endif
|
||||
|
||||
stacked.setHeight(c, stacked.height - WATERFALL_START);
|
||||
size_t d = stacked.addChart(statusBar);
|
||||
stacked.setHeight(b, stacked.height);
|
||||
|
||||
#ifdef UPTIME_CLOCK
|
||||
@@ -788,12 +805,12 @@ void drone_sound_alarm(int drone_detection_level, int detection_count,
|
||||
tone_freq_db = 285 - tone_freq_db;
|
||||
}
|
||||
|
||||
if (detection_count == 1 && SOUND_ON)
|
||||
if (r.detection_count == 1 && r.sound_on)
|
||||
{
|
||||
tone(BUZZER_PIN, tone_freq_db,
|
||||
10); // same action ??? but first time
|
||||
}
|
||||
if (detection_count % 5 == 0 && SOUND_ON)
|
||||
if (r.detection_count % 5 == 0 && r.sound_on)
|
||||
{
|
||||
tone(BUZZER_PIN, tone_freq_db,
|
||||
10); // same action ??? but every 5th time
|
||||
@@ -801,7 +818,7 @@ void drone_sound_alarm(int drone_detection_level, int detection_count,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (detection_count % 20 == 0 && SOUND_ON)
|
||||
if (r.detection_count % 20 == 0 && r.sound_on)
|
||||
{
|
||||
tone(BUZZER_PIN, 205,
|
||||
10); // same action ??? but every 20th detection
|
||||
@@ -815,7 +832,7 @@ void joystickMoveCursor(int joy_x_pressed)
|
||||
if (joy_x_pressed > 0)
|
||||
{
|
||||
cursor_x_position--;
|
||||
display.drawString(cursor_x_position, 0, String((int)freq));
|
||||
display.drawString(cursor_x_position, 0, String((int)r.current_frequency));
|
||||
display.drawLine(cursor_x_position, 1, cursor_x_position, 10);
|
||||
display.display();
|
||||
delay(10);
|
||||
@@ -823,7 +840,7 @@ void joystickMoveCursor(int joy_x_pressed)
|
||||
else if (joy_x_pressed < 0)
|
||||
{
|
||||
cursor_x_position++;
|
||||
display.drawString(cursor_x_position, 0, String((int)freq));
|
||||
display.drawString(cursor_x_position, 0, String((int)r.current_frequency));
|
||||
display.drawLine(cursor_x_position, 1, cursor_x_position, 10);
|
||||
display.display();
|
||||
delay(10);
|
||||
@@ -831,7 +848,7 @@ void joystickMoveCursor(int joy_x_pressed)
|
||||
if (cursor_x_position > DISPLAY_WIDTH || cursor_x_position < 0)
|
||||
{
|
||||
cursor_x_position = 0;
|
||||
display.drawString(cursor_x_position, 0, String((int)freq));
|
||||
display.drawString(cursor_x_position, 0, String((int)r.current_frequency));
|
||||
display.drawLine(cursor_x_position, 1, cursor_x_position, 10);
|
||||
display.display();
|
||||
delay(10);
|
||||
@@ -869,45 +886,23 @@ void check_ranges()
|
||||
}
|
||||
}
|
||||
|
||||
struct RadioScan : Scan
|
||||
{
|
||||
float getRSSI() override;
|
||||
};
|
||||
|
||||
float RadioScan::getRSSI()
|
||||
{
|
||||
#ifdef USING_SX1280PA
|
||||
// radio.startReceive();
|
||||
// get instantaneous RSSI value
|
||||
// When PR will be merged we can use radi.getRSSI(false);
|
||||
uint8_t data[3] = {0, 0, 0}; // RssiInst, Status, RFU
|
||||
radio.mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_RSSI_INST, data, 3);
|
||||
return ((float)data[0] / (-2.0));
|
||||
#else
|
||||
return radio.getRSSI(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
// MAX Frequency RSSI BIN value of the samples
|
||||
int max_rssi_x = 999;
|
||||
|
||||
RadioScan r;
|
||||
|
||||
void loop(void)
|
||||
{
|
||||
UI_displayDecorate(0, 0, false); // some default values
|
||||
r.led_flag = false;
|
||||
|
||||
detection_count = 0;
|
||||
r.detection_count = 0;
|
||||
drone_detected_frequency_start = 0;
|
||||
ranges_count = 0;
|
||||
|
||||
// reset scan time
|
||||
#ifdef PRINT_PROFILE_TIME
|
||||
scan_time = 0;
|
||||
// general purpose loop counter
|
||||
loop_cnt++;
|
||||
loop_start = millis();
|
||||
#endif
|
||||
r.epoch++;
|
||||
|
||||
if (!ANIMATED_RELOAD || !single_page_scan)
|
||||
{
|
||||
@@ -923,8 +918,8 @@ void loop(void)
|
||||
RANGE_PER_PAGE = range;
|
||||
}
|
||||
|
||||
fr_begin = FREQ_BEGIN;
|
||||
fr_end = fr_begin;
|
||||
r.fr_begin = FREQ_BEGIN;
|
||||
r.fr_end = r.fr_begin;
|
||||
|
||||
// 50 is a single-screen range
|
||||
// TODO: Make 50 a variable with the option to show the full range
|
||||
@@ -946,14 +941,14 @@ void loop(void)
|
||||
range = RANGE_PER_PAGE;
|
||||
if (ranges_count == 0)
|
||||
{
|
||||
fr_begin = (range_item == 0) ? fr_begin : fr_begin += range;
|
||||
fr_end = fr_begin + RANGE_PER_PAGE;
|
||||
r.fr_begin = (range_item == 0) ? r.fr_begin : r.fr_begin + range;
|
||||
r.fr_end = r.fr_begin + RANGE_PER_PAGE;
|
||||
}
|
||||
else
|
||||
{
|
||||
fr_begin = SCAN_RANGES[range_item] / 1000;
|
||||
fr_end = SCAN_RANGES[range_item] % 1000;
|
||||
range = fr_end - fr_begin;
|
||||
r.fr_begin = SCAN_RANGES[range_item] / 1000;
|
||||
r.fr_end = SCAN_RANGES[range_item] % 1000;
|
||||
range = r.fr_end - r.fr_begin;
|
||||
}
|
||||
|
||||
#ifdef DISABLED_CODE
|
||||
@@ -964,11 +959,6 @@ void loop(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (single_page_scan == false)
|
||||
{
|
||||
UI_displayDecorate(fr_begin, fr_end, true);
|
||||
}
|
||||
|
||||
drone_detected_frequency_start = 0;
|
||||
display.setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
|
||||
@@ -999,26 +989,29 @@ void loop(void)
|
||||
// Because of the SCAN_RBW_FACTOR x is not a display coordinate anymore
|
||||
// x > STEPS on SCAN_RBW_FACTOR
|
||||
int display_x = x / SCAN_RBW_FACTOR;
|
||||
waterfall[display_x] = false;
|
||||
float step = (range * ((float)x / (STEPS * SCAN_RBW_FACTOR)));
|
||||
|
||||
freq = fr_begin + step;
|
||||
LOG("setFrequency:%f\n", freq);
|
||||
r.current_frequency = r.fr_begin + step;
|
||||
LOG("setFrequency:%f\n", r.current_frequency);
|
||||
|
||||
#ifdef USING_SX1280PA
|
||||
state = radio.setFrequency(freq); // 1280 doesn't have calibration
|
||||
state =
|
||||
radio.setFrequency(r.current_frequency); // 1280 doesn't have calibration
|
||||
radio.startReceive(RADIOLIB_SX128X_RX_TIMEOUT_INF);
|
||||
#elif USING_SX1276
|
||||
state = radio.setFrequency(freq);
|
||||
#else
|
||||
state = radio.setFrequency(freq, false); // false = no calibration need here
|
||||
state = radio.setFrequency(r.current_frequency,
|
||||
false); // false = no calibration need here
|
||||
#endif
|
||||
int radio_error_count = 0;
|
||||
if (state != RADIOLIB_ERR_NONE)
|
||||
{
|
||||
display.drawString(
|
||||
0, 64 - 10, "E(" + String(state) + "):setFrequency:" + String(freq));
|
||||
Serial.println("E(" + String(state) + "):setFrequency:" + String(freq));
|
||||
display.drawString(0, 64 - 10,
|
||||
"E(" + String(state) +
|
||||
"):setFrequency:" + String(r.current_frequency));
|
||||
Serial.println("E(" + String(state) +
|
||||
"):setFrequency:" + String(r.current_frequency));
|
||||
display.display();
|
||||
delay(2);
|
||||
radio_error_count++;
|
||||
@@ -1026,7 +1019,7 @@ void loop(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
LOG("Step:%d Freq: %f\n", x, freq);
|
||||
LOG("Step:%d Freq: %f\n", x, r.current_frequency);
|
||||
// SpectralScan Method
|
||||
#ifdef METHOD_SPECTRAL
|
||||
{
|
||||
@@ -1106,9 +1099,13 @@ void loop(void)
|
||||
rr = LO_RSSI_THRESHOLD;
|
||||
}
|
||||
|
||||
waterChart->updatePoint(millis(), freq, rr);
|
||||
r.drone_detection_level = drone_detection_level;
|
||||
|
||||
int updated = bar->bar.updatePoint(freq, rr);
|
||||
#if (WATERFALL_ENABLED == true)
|
||||
waterChart->updatePoint(millis(), r.current_frequency, rr);
|
||||
#endif
|
||||
|
||||
int updated = bar->bar.updatePoint(r.current_frequency, rr);
|
||||
|
||||
if (first_run || ANIMATED_RELOAD)
|
||||
{
|
||||
@@ -1121,30 +1118,18 @@ void loop(void)
|
||||
if (detected_y[display_x] == false) // detection threshold match
|
||||
{
|
||||
// Set LED to ON (filtered in UI component)
|
||||
UI_setLedFlag(true);
|
||||
#if (WATERFALL_ENABLED == true)
|
||||
if (single_page_scan)
|
||||
{
|
||||
// Drone detection true for waterfall
|
||||
if (!waterfall[display_x])
|
||||
{
|
||||
waterfall[display_x] = true;
|
||||
display.setColor(WHITE);
|
||||
// display.setPixel(display_x, w);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
r.led_flag = true;
|
||||
if (drone_detected_frequency_start == 0)
|
||||
{
|
||||
// mark freq start
|
||||
drone_detected_frequency_start = freq;
|
||||
drone_detected_frequency_start = r.current_frequency;
|
||||
}
|
||||
|
||||
// mark freq end ... will shift right to last detected range
|
||||
drone_detected_frequency_end = freq;
|
||||
if (SOUND_ON == true)
|
||||
drone_detected_frequency_end = r.current_frequency;
|
||||
if (r.sound_on)
|
||||
{
|
||||
drone_sound_alarm(drone_detection_level, detection_count,
|
||||
drone_sound_alarm(r.drone_detection_level, r.detection_count,
|
||||
max_rssi_x * 2);
|
||||
}
|
||||
|
||||
@@ -1165,34 +1150,13 @@ void loop(void)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if (WATERFALL_ENABLED == true)
|
||||
if ((single_page_scan) && (waterfall[display_x] != true) && new_pixel)
|
||||
{
|
||||
// If drone not found set dark pixel on the waterfall
|
||||
// TODO: make something like scrolling up if possible
|
||||
waterfall[display_x] = false;
|
||||
display.setColor(BLACK);
|
||||
// display.setPixel(display_x, w);
|
||||
display.setColor(WHITE);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef PRINT_DEBUG
|
||||
for (int y = 0; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++)
|
||||
{
|
||||
if (filtered_result[y] == 1)
|
||||
{
|
||||
LOG("Pixel:%i(%i):%i,", display_x, x, y);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef JOYSTICK_ENABLED
|
||||
// Draw joystick cursor and Frequency RSSI value
|
||||
if (display_x == cursor_x_position)
|
||||
{
|
||||
display.drawString(display_x - 1, 0, String((int)freq));
|
||||
display.drawString(display_x - 1, 0, String((int)r.current_frequency));
|
||||
display.drawLine(display_x, 1, display_x, 12);
|
||||
// if method scan RSSI we can get exact RSSI value
|
||||
display.drawString(display_x + 17, 0, "-" + String((int)max_rssi_x * 4));
|
||||
@@ -1205,7 +1169,7 @@ void loop(void)
|
||||
// count detected
|
||||
if (detected)
|
||||
{
|
||||
detection_count++;
|
||||
r.detection_count++;
|
||||
}
|
||||
|
||||
#ifdef PRINT_DEBUG
|
||||
@@ -1216,7 +1180,7 @@ void loop(void)
|
||||
display.display();
|
||||
}
|
||||
|
||||
if (buttonPressHandler(freq) == false)
|
||||
if (buttonPressHandler(r.current_frequency) == false)
|
||||
break;
|
||||
|
||||
// wait a little bit before the next scan,
|
||||
@@ -1265,15 +1229,6 @@ void loop(void)
|
||||
{
|
||||
w = WATERFALL_START;
|
||||
}
|
||||
#if (WATERFALL_ENABLED == true)
|
||||
// Draw waterfall position cursor
|
||||
if (single_page_scan)
|
||||
{
|
||||
display.setColor(BLACK);
|
||||
// display.drawHorizontalLine(0, w, STEPS);
|
||||
display.setColor(WHITE);
|
||||
}
|
||||
#endif
|
||||
|
||||
stacked.draw();
|
||||
// Render display data here
|
||||
|
||||
256
src/ui.cpp
256
src/ui.cpp
@@ -2,6 +2,8 @@
|
||||
#include "RadioLib.h"
|
||||
#include "global_config.h"
|
||||
#include "images.h"
|
||||
#include <charts.h>
|
||||
#include <scan.h>
|
||||
|
||||
// -------------------------------------------------
|
||||
// LOCAL DEFINES
|
||||
@@ -12,24 +14,9 @@
|
||||
//
|
||||
#define SCALE_TEXT_TOP (HEIGHT + X_AXIS_WEIGHT + MAJOR_TICK_LENGTH)
|
||||
|
||||
static unsigned int start_scan_text = (128 / 2) - 3;
|
||||
// initialized flag
|
||||
static bool ui_initialized = false;
|
||||
static bool led_flag = false;
|
||||
static unsigned short int scan_progress_count = 0;
|
||||
|
||||
#ifdef Vision_Master_E290
|
||||
static DEPG0290BxS800FxX_BW *display_instance;
|
||||
#else
|
||||
//(0x3c, SDA_OLED, SCL_OLED, DISPLAY_GEOMETRY);
|
||||
static SSD1306Wire *display_instance;
|
||||
#endif
|
||||
// temporary dirty import ... to be solved durring upcoming refactoring
|
||||
extern unsigned int drone_detection_level;
|
||||
extern unsigned int RANGE_PER_PAGE;
|
||||
extern unsigned int median_frequency;
|
||||
extern unsigned int detection_count;
|
||||
extern bool SOUND_ON;
|
||||
extern unsigned int drone_detected_frequency_start;
|
||||
extern unsigned int drone_detected_frequency_end;
|
||||
extern unsigned int ranges_count;
|
||||
@@ -40,230 +27,138 @@ extern unsigned int range_item;
|
||||
|
||||
extern uint64_t loop_time;
|
||||
|
||||
#ifndef Vision_Master_E290
|
||||
void UI_Init(SSD1306Wire *display_ptr)
|
||||
void UI_Init(Display_t *display_ptr)
|
||||
{
|
||||
// init pointer to display instance.
|
||||
display_instance = display_ptr;
|
||||
// check for null ???
|
||||
display_instance->clear();
|
||||
display_ptr->clear();
|
||||
// draw the UCOG welcome logo
|
||||
display_instance->drawXbm(0, 2, 128, 64, epd_bitmap_ucog);
|
||||
display_instance->display();
|
||||
display_ptr->drawXbm(0, 2, 128, 64, epd_bitmap_ucog);
|
||||
display_ptr->display();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef Vision_Master_E290
|
||||
void UI_Init(DEPG0290BxS800FxX_BW *display_ptr)
|
||||
{
|
||||
// init pointer to display instance.
|
||||
display_instance = display_ptr;
|
||||
// check for null ???
|
||||
display_instance->clear();
|
||||
// draw the UCOG welcome logo
|
||||
display_instance->drawXbm(0, 2, 128, 64, epd_bitmap_ucog);
|
||||
display_instance->display();
|
||||
}
|
||||
#endif
|
||||
|
||||
void UI_setLedFlag(bool new_status) { led_flag = new_status; }
|
||||
|
||||
void clearStatus(void)
|
||||
void StatusBar::clearStatus(void)
|
||||
{
|
||||
// clear status line
|
||||
display_instance->setColor(BLACK);
|
||||
display_instance->fillRect(0, ROW_STATUS_TEXT + 2, 128, 13);
|
||||
display_instance->setColor(WHITE);
|
||||
display.setColor(BLACK);
|
||||
display.fillRect(pos_x, pos_y, width, height);
|
||||
}
|
||||
|
||||
void UI_clearPlotter(void)
|
||||
{
|
||||
// clear the scan plot rectangle (top part)
|
||||
display_instance->setColor(BLACK);
|
||||
display_instance->fillRect(0, 10, STEPS, HEIGHT - 10);
|
||||
display_instance->setColor(WHITE);
|
||||
// display_instance->setColor(BLACK);
|
||||
// display_instance->fillRect(0, 10, STEPS, HEIGHT - 10);
|
||||
// display_instance->setColor(WHITE);
|
||||
}
|
||||
|
||||
void UI_clearTopStatus(void)
|
||||
{
|
||||
// clear the scan plot rectangle (top part)
|
||||
display_instance->setColor(BLACK);
|
||||
display_instance->fillRect(0, 0, STEPS, 10);
|
||||
display_instance->setColor(WHITE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Draws ticks on the display at regular whole intervals.
|
||||
*
|
||||
* @param every The interval between ticks in MHz.
|
||||
* @param length The length of each tick in pixels.
|
||||
*/
|
||||
void drawTicks(float every, int length)
|
||||
{
|
||||
int first_tick;
|
||||
bool correction;
|
||||
int pixels_per_step;
|
||||
int correction_number;
|
||||
int tick;
|
||||
int tick_minor;
|
||||
int median;
|
||||
|
||||
first_tick = 0;
|
||||
//+ (every - (fr_begin - (int)(fr_begin / every) * every));
|
||||
/*if (first_tick < fr_begin)
|
||||
{
|
||||
first_tick += every;
|
||||
}*/
|
||||
correction = false;
|
||||
pixels_per_step = STEPS / (RANGE_PER_PAGE / every);
|
||||
if (STEPS / RANGE_PER_PAGE != 0)
|
||||
{
|
||||
correction = true;
|
||||
}
|
||||
correction_number = STEPS - (int)(pixels_per_step * (RANGE_PER_PAGE / every));
|
||||
tick = 0;
|
||||
tick_minor = 0;
|
||||
median = (RANGE_PER_PAGE / every) / 2;
|
||||
// TODO: (RANGE_PER_PAGE / every)
|
||||
// * 2 has twice extra steps we need to figureout correct logic or minor
|
||||
// ticks is not showing to the end
|
||||
for (int t = 0; t <= (RANGE_PER_PAGE / every) * 2; t++)
|
||||
{
|
||||
// fix if pixels per step is not int and we have shift
|
||||
if (correction && t % 2 != 0 && correction_number > 1)
|
||||
{
|
||||
// pixels_per_step++;
|
||||
correction_number--;
|
||||
}
|
||||
tick += pixels_per_step;
|
||||
tick_minor = tick / 2;
|
||||
if (tick <= 128 - 3)
|
||||
{
|
||||
display_instance->drawLine(tick, HEIGHT + X_AXIS_WEIGHT, tick,
|
||||
HEIGHT + X_AXIS_WEIGHT + length);
|
||||
// Central tick
|
||||
if (tick > (128 / 2) - 3 && tick < (128 / 2) + 3)
|
||||
{
|
||||
display_instance->drawLine(tick + 1, HEIGHT + X_AXIS_WEIGHT, tick + 1,
|
||||
HEIGHT + X_AXIS_WEIGHT + length);
|
||||
}
|
||||
}
|
||||
#ifdef MINOR_TICKS
|
||||
// Fix two ticks together
|
||||
if ((tick_minor + 1 != tick) && (tick_minor - 1 != tick) &&
|
||||
(tick_minor + 2 != tick) && (tick_minor - 2 != tick))
|
||||
{
|
||||
display_instance->drawLine(tick_minor, HEIGHT + X_AXIS_WEIGHT, tick_minor,
|
||||
HEIGHT + X_AXIS_WEIGHT + MINOR_TICK_LENGTH);
|
||||
}
|
||||
// Central tick
|
||||
if (tick_minor > (128 / 2) - 3 && tick_minor < (128 / 2) + 3)
|
||||
{
|
||||
display_instance->drawLine(tick_minor + 1, HEIGHT + X_AXIS_WEIGHT,
|
||||
tick_minor + 1,
|
||||
HEIGHT + X_AXIS_WEIGHT + MINOR_TICK_LENGTH);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// display_instance->setColor(BLACK);
|
||||
// display_instance->fillRect(0, 0, STEPS, 10);
|
||||
// display_instance->setColor(WHITE);
|
||||
}
|
||||
|
||||
void UI_drawCursor(int16_t possition)
|
||||
{
|
||||
// Draw animated vertical cursor on reload process
|
||||
display_instance->setColor(BLACK);
|
||||
display_instance->drawVerticalLine(possition, 0, HEIGHT);
|
||||
display_instance->drawVerticalLine(possition + 1, 0, HEIGHT);
|
||||
display_instance->drawVerticalLine(possition + 2, 0, HEIGHT);
|
||||
display_instance->setColor(WHITE);
|
||||
// display_instance->setColor(BLACK);
|
||||
// display_instance->drawVerticalLine(possition, 0, HEIGHT);
|
||||
// display_instance->drawVerticalLine(possition + 1, 0, HEIGHT);
|
||||
// display_instance->drawVerticalLine(possition + 2, 0, HEIGHT);
|
||||
// display_instance->setColor(WHITE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decorates the display: everything but the plot itself.
|
||||
*/
|
||||
void UI_displayDecorate(int begin = 0, int end = 0, bool redraw = false)
|
||||
void StatusBar::draw()
|
||||
{
|
||||
uint16_t text_y = pos_y + height - 10;
|
||||
|
||||
if (!ui_initialized)
|
||||
{
|
||||
// Drone detection level
|
||||
display_instance->setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
display_instance->drawString(128, 0, String(drone_detection_level));
|
||||
display.setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
display.drawString(width, 0, String(r.drone_detection_level));
|
||||
}
|
||||
if (!ui_initialized || redraw)
|
||||
if (!ui_initialized)
|
||||
{
|
||||
// Clear something
|
||||
display_instance->setColor(BLACK);
|
||||
display_instance->fillRect(0, SCALE_TEXT_TOP + 1, 128, 12);
|
||||
display_instance->setColor(WHITE);
|
||||
|
||||
/* display_instance->setColor(BLACK);
|
||||
display_instance->fillRect(0, SCALE_TEXT_TOP + 1, 128, 12);
|
||||
display_instance->setColor(WHITE);
|
||||
*/
|
||||
// Drone detection level
|
||||
display_instance->setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
display_instance->drawString(128, 0, String(drone_detection_level));
|
||||
display.setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
display.drawString(pos_x + width, 0, String(r.drone_detection_level));
|
||||
// Frequency start
|
||||
display_instance->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display_instance->drawString(0, ROW_STATUS_TEXT,
|
||||
(begin == 0) ? String(FREQ_BEGIN) : String(begin));
|
||||
display.setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display.drawString(pos_x, text_y,
|
||||
(r.fr_begin == 0) ? String(FREQ_BEGIN) : String(r.fr_begin));
|
||||
|
||||
// Frequency detected
|
||||
display_instance->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display_instance->drawString(128 / 2, ROW_STATUS_TEXT,
|
||||
(begin == 0) ? String(median_frequency)
|
||||
: String(begin + ((end - begin) / 2)));
|
||||
display.setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display.drawString(pos_x + width / 2, text_y,
|
||||
(r.fr_begin == 0)
|
||||
? String(median_frequency)
|
||||
: String(r.fr_begin + ((r.fr_end - r.fr_begin) / 2)));
|
||||
// Frequency end
|
||||
display_instance->setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
display_instance->drawString(128, ROW_STATUS_TEXT,
|
||||
(end == 0) ? String(FREQ_END) : String(end));
|
||||
display.setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
display.drawString(pos_x + width, text_y,
|
||||
(r.fr_end == 0) ? String(FREQ_END) : String(r.fr_end));
|
||||
}
|
||||
|
||||
// Status text block
|
||||
if (led_flag) // 'drone' detected
|
||||
if (r.led_flag) // 'drone' detected
|
||||
{
|
||||
display_instance->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display.setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
// clear status line
|
||||
clearStatus();
|
||||
display_instance->drawString(start_scan_text + 2, ROW_STATUS_TEXT,
|
||||
String(drone_detected_frequency_start) + ">RF<" +
|
||||
String(drone_detected_frequency_end));
|
||||
display.setColor(WHITE);
|
||||
display.drawString(pos_x + width / 2, text_y,
|
||||
String(drone_detected_frequency_start) + ">RF<" +
|
||||
String(drone_detected_frequency_end));
|
||||
}
|
||||
else
|
||||
{
|
||||
// "Scanning"
|
||||
display_instance->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display.setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
// clear status line
|
||||
clearStatus();
|
||||
if (scan_progress_count == 0)
|
||||
String s = "Scan \\";
|
||||
if (scan_progress_count == 1)
|
||||
{
|
||||
display_instance->drawString(start_scan_text, ROW_STATUS_TEXT, "Scan \\");
|
||||
}
|
||||
else if (scan_progress_count == 1)
|
||||
{
|
||||
display_instance->drawString(start_scan_text, ROW_STATUS_TEXT, "Scan |");
|
||||
s = "Scan |";
|
||||
}
|
||||
else if (scan_progress_count == 2)
|
||||
{
|
||||
display_instance->drawString(start_scan_text, ROW_STATUS_TEXT, "Scan /");
|
||||
s = "Scan /";
|
||||
}
|
||||
else if (scan_progress_count == 3)
|
||||
{
|
||||
display_instance->drawString(start_scan_text, ROW_STATUS_TEXT, "Scan -");
|
||||
s = "Scan -";
|
||||
}
|
||||
scan_progress_count++;
|
||||
if (scan_progress_count >= 4)
|
||||
{
|
||||
scan_progress_count = 0;
|
||||
}
|
||||
display.setColor(WHITE);
|
||||
display.drawString(pos_x + width / 2 - 3, text_y, s);
|
||||
}
|
||||
|
||||
if (led_flag == true && detection_count >= 5)
|
||||
if (r.led_flag && r.detection_count >= 5)
|
||||
{
|
||||
digitalWrite(LED, HIGH);
|
||||
if (SOUND_ON)
|
||||
if (r.sound_on)
|
||||
{
|
||||
tone(BUZZER_PIN, 104, 100);
|
||||
}
|
||||
digitalWrite(REB_PIN, HIGH);
|
||||
led_flag = false;
|
||||
r.led_flag = false;
|
||||
}
|
||||
else if (!redraw)
|
||||
else if (!r.led_flag)
|
||||
{
|
||||
digitalWrite(LED, LOW);
|
||||
}
|
||||
@@ -271,29 +166,28 @@ void UI_displayDecorate(int begin = 0, int end = 0, bool redraw = false)
|
||||
if (ranges_count == 0)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
display_instance->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display_instance->drawString(0, ROW_STATUS_TEXT, String(loop_time));
|
||||
display.setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display.drawString(pos_x, text_y, String(loop_time));
|
||||
#else
|
||||
display_instance->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display_instance->drawString(0, ROW_STATUS_TEXT, String(FREQ_BEGIN));
|
||||
display.setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display.drawString(pos_x, text_y, String(FREQ_BEGIN));
|
||||
|
||||
#endif
|
||||
display_instance->setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
display_instance->drawString(128, ROW_STATUS_TEXT, String(FREQ_END));
|
||||
display.setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
display.drawString(pos_x + width, text_y, String(FREQ_END));
|
||||
}
|
||||
else if (ranges_count > 0)
|
||||
{
|
||||
display_instance->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display_instance->drawString(0, ROW_STATUS_TEXT,
|
||||
String(SCAN_RANGES[range_item] / 1000) + "-" +
|
||||
String(SCAN_RANGES[range_item] % 1000));
|
||||
display.setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display.drawString(pos_x, text_y,
|
||||
String(SCAN_RANGES[range_item] / 1000) + "-" +
|
||||
String(SCAN_RANGES[range_item] % 1000));
|
||||
if (range_item + 1 < iterations)
|
||||
{
|
||||
display_instance->setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
display_instance->drawString(128, ROW_STATUS_TEXT,
|
||||
String(SCAN_RANGES[range_item + 1] / 1000) +
|
||||
"-" +
|
||||
String(SCAN_RANGES[range_item + 1] % 1000));
|
||||
display.setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
display.drawString(pos_x + width, text_y,
|
||||
String(SCAN_RANGES[range_item + 1] / 1000) + "-" +
|
||||
String(SCAN_RANGES[range_item + 1] % 1000));
|
||||
}
|
||||
}
|
||||
ui_initialized = true;
|
||||
|
||||
Reference in New Issue
Block a user