mirror of
https://github.com/Genaker/LoraSA.git
synced 2026-05-14 13:25:58 +02:00
Events for modular UI and other listeners
This commit is contained in:
@@ -102,6 +102,20 @@ int BarChart::y2pos(float y)
|
||||
return height - height * (y - min_y) / (max_y - min_y);
|
||||
}
|
||||
|
||||
void BarChart::onEvent(Event &e)
|
||||
{
|
||||
if (e.type != DETECTED)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int u = updatePoint(e.emitter.current_frequency, e.detected.rssi);
|
||||
if (e.emitter.animated)
|
||||
{
|
||||
drawOne(u);
|
||||
}
|
||||
}
|
||||
|
||||
void DecoratedBarChart::reset(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
|
||||
{
|
||||
Chart::reset(x, y, w, h);
|
||||
|
||||
@@ -12,7 +12,8 @@ size_t StackedChart::addChart(Chart *c)
|
||||
cc[charts_sz] = c;
|
||||
free(charts);
|
||||
|
||||
c->reset(pos_x + c->pos_x, pos_y + c->pos_y, trim_w(c->pos_x, c->width, width), c->height);
|
||||
c->reset(pos_x + c->pos_x, pos_y + c->pos_y, trim_w(c->pos_x, c->width, width),
|
||||
c->height);
|
||||
charts = cc;
|
||||
return charts_sz++;
|
||||
}
|
||||
@@ -82,3 +83,13 @@ void StackedChart::draw()
|
||||
for (int i = 0; i < charts_sz; i++)
|
||||
charts[i]->draw();
|
||||
}
|
||||
|
||||
void StackedChart::onEvent(Event &e)
|
||||
{
|
||||
if (e.type != SCAN_TASK_COMPLETE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
draw();
|
||||
}
|
||||
|
||||
@@ -55,3 +55,13 @@ int WaterfallChart::x2pos(float x)
|
||||
|
||||
return width * (x - min_x) / (max_x - min_x);
|
||||
}
|
||||
|
||||
void WaterfallChart::onEvent(Event &e)
|
||||
{
|
||||
if (e.type != DETECTED)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
updatePoint(e.time_ms, e.detected.freq, e.detected.rssi);
|
||||
}
|
||||
|
||||
+8
-3
@@ -10,6 +10,7 @@ typedef OLEDDisplay Display_t;
|
||||
#endif
|
||||
|
||||
#include <cstdint>
|
||||
#include <events.h>
|
||||
#include <models.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -58,7 +59,7 @@ struct ProgressChart : Chart
|
||||
virtual void drawOne(int x) = 0;
|
||||
};
|
||||
|
||||
struct BarChart : ProgressChart
|
||||
struct BarChart : ProgressChart, Listener
|
||||
{
|
||||
float min_x, max_x, min_y, max_y;
|
||||
float level_y;
|
||||
@@ -83,6 +84,7 @@ struct BarChart : ProgressChart
|
||||
int updatePoint(float x, float y) override;
|
||||
void drawOne(int x) override;
|
||||
void draw() override;
|
||||
void onEvent(Event &) override;
|
||||
|
||||
int x2pos(float x);
|
||||
int y2pos(float y);
|
||||
@@ -109,7 +111,7 @@ struct DecoratedBarChart : Chart
|
||||
void draw() override;
|
||||
};
|
||||
|
||||
struct StackedChart : Chart
|
||||
struct StackedChart : Chart, Listener
|
||||
{
|
||||
Chart **charts;
|
||||
size_t charts_sz;
|
||||
@@ -134,9 +136,11 @@ struct StackedChart : Chart
|
||||
void reset(uint16_t x, uint16_t y, uint16_t w, uint16_t h) override;
|
||||
|
||||
void draw() override;
|
||||
|
||||
void onEvent(Event &e) override;
|
||||
};
|
||||
|
||||
struct WaterfallChart : Chart
|
||||
struct WaterfallChart : Chart, Listener
|
||||
{
|
||||
float min_x, max_x;
|
||||
float level_y, threshold;
|
||||
@@ -156,6 +160,7 @@ struct WaterfallChart : Chart
|
||||
void reset(uint16_t x, uint16_t y, uint16_t w, uint16_t h) override;
|
||||
|
||||
void draw() override;
|
||||
void onEvent(Event &e) override;
|
||||
|
||||
int x2pos(float x);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
#ifndef LORASA_EVENTS_H
|
||||
#define LORASA_EVENTS_H
|
||||
|
||||
struct Event;
|
||||
enum EventType
|
||||
{
|
||||
DETECTED = 0,
|
||||
SCAN_TASK_COMPLETE,
|
||||
_MAX_EVENT_TYPE // unused as event type
|
||||
};
|
||||
struct Listener;
|
||||
|
||||
#include <cstdint>
|
||||
#include <scan.h>
|
||||
|
||||
struct Event
|
||||
{
|
||||
EventType type;
|
||||
uint64_t epoch;
|
||||
uint64_t time_ms;
|
||||
|
||||
Scan &emitter;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
float rssi;
|
||||
float freq;
|
||||
bool trigger;
|
||||
bool detected;
|
||||
size_t detected_at;
|
||||
} detected;
|
||||
};
|
||||
|
||||
Event(Scan &emitter, EventType type, uint64_t time_ms)
|
||||
: emitter(emitter), type(type), epoch(emitter.epoch), time_ms(time_ms) {};
|
||||
};
|
||||
|
||||
struct Listener
|
||||
{
|
||||
virtual void onEvent(Event &event) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
+42
-3
@@ -66,8 +66,8 @@ uint16_t Scan::rssiMethod(size_t samples, uint16_t *result, size_t res_size)
|
||||
return max_signal;
|
||||
}
|
||||
|
||||
size_t Scan::detect(uint16_t *result, bool *filtered_result, size_t result_size,
|
||||
int samples)
|
||||
Event Scan::detect(uint16_t *result, bool *filtered_result, size_t result_size,
|
||||
int samples)
|
||||
{
|
||||
size_t max_rssi_x = result_size;
|
||||
|
||||
@@ -122,7 +122,46 @@ size_t Scan::detect(uint16_t *result, bool *filtered_result, size_t result_size,
|
||||
}
|
||||
}
|
||||
|
||||
return max_rssi_x;
|
||||
Event event(*this, EventType::DETECTED, 0);
|
||||
event.epoch = epoch;
|
||||
event.detected.detected = max_rssi_x < result_size;
|
||||
event.detected.freq = current_frequency;
|
||||
event.detected.rssi =
|
||||
event.detected.detected ? -(float)result[max_rssi_x] : LO_RSSI_THRESHOLD;
|
||||
event.detected.detected_at = max_rssi_x;
|
||||
event.detected.trigger =
|
||||
event.detected.detected && event.detected.rssi >= trigger_level;
|
||||
detection_count++;
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
size_t Scan::addEventListener(EventType t, Listener &l)
|
||||
{
|
||||
size_t c = listener_count[(size_t)t];
|
||||
Listener **new_list = new Listener *[c + 1];
|
||||
new_list[c] = &l;
|
||||
listener_count[(size_t)t] = c + 1;
|
||||
|
||||
if (c > 0)
|
||||
{
|
||||
Listener **old_list = eventListeners[(size_t)t];
|
||||
memcpy(new_list, old_list, c * sizeof(Listener *));
|
||||
delete[] old_list;
|
||||
}
|
||||
|
||||
eventListeners[(size_t)t] = new_list;
|
||||
return c;
|
||||
}
|
||||
|
||||
void Scan::fireEvent(Event &event)
|
||||
{
|
||||
Listener **list = eventListeners[(size_t)event.type];
|
||||
size_t c = listener_count[(size_t)event.type];
|
||||
for (int i = 0; i < c; i++)
|
||||
{
|
||||
list[i]->onEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+15
-4
@@ -1,4 +1,5 @@
|
||||
#include <cstdint>
|
||||
#include <events.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef LORASA_CORE_H
|
||||
@@ -41,11 +42,18 @@ struct Scan
|
||||
bool sound_on;
|
||||
bool led_flag;
|
||||
uint64_t detection_count;
|
||||
bool animated;
|
||||
float trigger_level;
|
||||
|
||||
Listener **eventListeners[(size_t)EventType::_MAX_EVENT_TYPE];
|
||||
size_t listener_count[(size_t)EventType::_MAX_EVENT_TYPE];
|
||||
|
||||
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) {};
|
||||
drone_detection_level(0), sound_on(false), led_flag(false), detection_count(0),
|
||||
animated(false), trigger_level(0), listener_count{
|
||||
0,
|
||||
} {};
|
||||
|
||||
virtual float getRSSI() = 0;
|
||||
|
||||
@@ -57,8 +65,11 @@ struct Scan
|
||||
// those values that represent a detection event.
|
||||
// It returns index that represents strongest signal at which a detection event
|
||||
// occurred.
|
||||
static size_t detect(uint16_t *result, bool *filtered_result, size_t result_size,
|
||||
int samples);
|
||||
Event detect(uint16_t *result, bool *filtered_result, size_t result_size,
|
||||
int samples);
|
||||
|
||||
size_t addEventListener(EventType t, Listener &l);
|
||||
void fireEvent(Event &e);
|
||||
};
|
||||
|
||||
// Remove reading without neighbors
|
||||
|
||||
+24
-37
@@ -42,6 +42,7 @@
|
||||
#define RADIOLIB_GODMODE (1)
|
||||
|
||||
#include <charts.h>
|
||||
#include <events.h>
|
||||
#include <scan.h>
|
||||
|
||||
#ifndef LILYGO
|
||||
@@ -197,7 +198,7 @@ bool first_run, new_pixel, detected_x = false;
|
||||
// drone detection flag
|
||||
bool detected = false;
|
||||
uint64_t drone_detection_level = DEFAULT_DRONE_DETECTION_LEVEL;
|
||||
uint64_t show_db_after = 80;
|
||||
#define TRIGGER_LEVEL -80.0
|
||||
uint64_t drone_detected_frequency_start = 0;
|
||||
uint64_t drone_detected_frequency_end = 0;
|
||||
bool single_page_scan = false;
|
||||
@@ -675,12 +676,14 @@ void setup(void)
|
||||
xTaskCreate(logToSerialTask, "LOG_DATA_JSON", 2048, NULL, 1, NULL);
|
||||
#endif
|
||||
|
||||
r.trigger_level = TRIGGER_LEVEL;
|
||||
stacked.reset(0, 0, display.width(), display.height());
|
||||
r.addEventListener(SCAN_TASK_COMPLETE, stacked);
|
||||
|
||||
bar = new DecoratedBarChart(display, 0, 0, display.width(), 0, FREQ_BEGIN, FREQ_END,
|
||||
LO_RSSI_THRESHOLD, HI_RSSI_THRESHOLD,
|
||||
-(float)show_db_after);
|
||||
LO_RSSI_THRESHOLD, HI_RSSI_THRESHOLD, r.trigger_level);
|
||||
|
||||
r.addEventListener(DETECTED, bar->bar);
|
||||
size_t b = stacked.addChart(bar);
|
||||
|
||||
Chart *statusBar = new StatusBar(display, 0, 0, display.width(), r);
|
||||
@@ -695,10 +698,12 @@ void setup(void)
|
||||
|
||||
waterChart =
|
||||
new WaterfallChart(display, 0, WATERFALL_START, display.width(), 0, FREQ_BEGIN,
|
||||
FREQ_END, -(float)show_db_after, WATERFALL_SENSITIVITY, model);
|
||||
FREQ_END, r.trigger_level, WATERFALL_SENSITIVITY, model);
|
||||
|
||||
size_t c = stacked.addChart(waterChart);
|
||||
stacked.setHeight(c, stacked.height - WATERFALL_START - statusBar->height);
|
||||
|
||||
r.addEventListener(DETECTED, *waterChart);
|
||||
#endif
|
||||
|
||||
size_t d = stacked.addChart(statusBar);
|
||||
@@ -1053,6 +1058,7 @@ void loop(void)
|
||||
LOG("METHOD RSSI");
|
||||
uint16_t max_rssi = r.rssiMethod(SAMPLES_RSSI, result,
|
||||
RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE);
|
||||
|
||||
if (max_x_rssi[display_x] > max_rssi)
|
||||
{
|
||||
max_x_rssi[display_x] = max_rssi;
|
||||
@@ -1077,42 +1083,24 @@ void loop(void)
|
||||
display.setColor(WHITE);
|
||||
}
|
||||
#endif
|
||||
size_t detected_at = r.detect(
|
||||
result, filtered_result, RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE, samples);
|
||||
Event event = r.detect(result, filtered_result,
|
||||
RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE, samples);
|
||||
event.time_ms = millis();
|
||||
|
||||
size_t detected_at = event.detected.detected_at;
|
||||
if (max_rssi_x > detected_at)
|
||||
{
|
||||
// MAx bin Value not RSSI
|
||||
max_rssi_x = detected_at;
|
||||
}
|
||||
|
||||
detected = detected_at < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE;
|
||||
detected = event.detected.detected;
|
||||
detected_y[display_x] = false;
|
||||
|
||||
float rr;
|
||||
if (detected)
|
||||
{
|
||||
rr = -(float)result[detected_at];
|
||||
}
|
||||
else
|
||||
{
|
||||
rr = LO_RSSI_THRESHOLD;
|
||||
}
|
||||
|
||||
float rr = event.detected.rssi;
|
||||
r.drone_detection_level = drone_detection_level;
|
||||
|
||||
#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)
|
||||
{
|
||||
bar->bar.drawOne(updated);
|
||||
}
|
||||
|
||||
if (detected_at <= drone_detection_level)
|
||||
if (event.detected.trigger)
|
||||
{
|
||||
// check if we should alarm about a drone presence
|
||||
if (detected_y[display_x] == false) // detection threshold match
|
||||
@@ -1152,6 +1140,8 @@ void loop(void)
|
||||
}
|
||||
}
|
||||
|
||||
r.fireEvent(event);
|
||||
|
||||
#ifdef JOYSTICK_ENABLED
|
||||
// Draw joystick cursor and Frequency RSSI value
|
||||
if (display_x == cursor_x_position)
|
||||
@@ -1166,16 +1156,10 @@ void loop(void)
|
||||
#ifdef PRINT_PROFILE_TIME
|
||||
scan_time += (millis() - scan_start_time);
|
||||
#endif
|
||||
// count detected
|
||||
if (detected)
|
||||
{
|
||||
r.detection_count++;
|
||||
}
|
||||
|
||||
#ifdef PRINT_DEBUG
|
||||
Serial.println("....\n");
|
||||
#endif
|
||||
if (first_run || ANIMATED_RELOAD)
|
||||
if (r.animated)
|
||||
{
|
||||
display.display();
|
||||
}
|
||||
@@ -1230,7 +1214,10 @@ void loop(void)
|
||||
w = WATERFALL_START;
|
||||
}
|
||||
|
||||
stacked.draw();
|
||||
{
|
||||
Event event(r, SCAN_TASK_COMPLETE, millis());
|
||||
r.fireEvent(event);
|
||||
}
|
||||
// Render display data here
|
||||
|
||||
#ifdef UPTIME_CLOCK
|
||||
|
||||
+5
-2
@@ -48,14 +48,17 @@ void test_detect()
|
||||
uint16_t samples[test_sz] = {20, 50, 55, 60, 0, 70, 75, 80, 0, 90, 0, 100, 110};
|
||||
bool result[test_sz];
|
||||
|
||||
size_t r = Scan::detect(samples, result, test_sz, 1);
|
||||
TestScan test_scan({}, 0);
|
||||
Event e = test_scan.detect(samples, result, test_sz, 1);
|
||||
size_t r = e.detected.detected_at;
|
||||
|
||||
bool expect[test_sz] = {1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1};
|
||||
|
||||
TEST_ASSERT_EQUAL_INT16(0, r);
|
||||
TEST_ASSERT_EQUAL_INT8_ARRAY(expect, result, test_sz);
|
||||
|
||||
r = Scan::detect(samples, result, test_sz, 2);
|
||||
Event e2 = test_scan.detect(samples, result, test_sz, 2);
|
||||
r = e2.detected.detected_at;
|
||||
|
||||
bool expect2[test_sz] = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user