Events for modular UI and other listeners

This commit is contained in:
Sassa NF
2024-10-05 16:35:01 +01:00
parent 0c760610df
commit bdd00039b2
9 changed files with 175 additions and 50 deletions
+14
View File
@@ -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 -1
View File
@@ -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();
}
+10
View File
@@ -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
View File
@@ -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);
};
+45
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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};