packet statistics table

This commit is contained in:
mverch67
2024-09-17 21:37:18 +02:00
parent da3db5d4d1
commit 8047231c5b
9 changed files with 309 additions and 23 deletions
+19 -12
View File
@@ -2232,7 +2232,7 @@ void create_screen_main_screen() {
lv_obj_set_pos(obj, 25, 0);
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_label_set_long_mode(obj, LV_LABEL_LONG_SCROLL_CIRCULAR);
lv_label_set_text(obj, _("Statistics"));
lv_label_set_text(obj, _("Packet Statistics"));
lv_obj_set_style_align(obj, LV_ALIGN_LEFT_MID, LV_PART_MAIN | LV_STATE_DEFAULT);
}
{
@@ -4851,26 +4851,33 @@ void create_screen_main_screen() {
lv_obj_set_size(obj, LV_PCT(88), LV_PCT(90));
lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_CHAIN|LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLL_CHAIN_HOR|LV_OBJ_FLAG_SCROLL_CHAIN_VER);
lv_obj_set_scrollbar_mode(obj, LV_SCROLLBAR_MODE_OFF);
add_style_panel_style(obj);
lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_pad_left(obj, 8, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_pad_row(obj, 5, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_pad_column(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_pad_top(obj, 8, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_pad_bottom(obj, 8, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_pad_left(obj, 2, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_pad_top(obj, 4, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_pad_bottom(obj, 3, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_layout(obj, LV_LAYOUT_FLEX, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_flex_flow(obj, LV_FLEX_FLOW_COLUMN, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_pad_right(obj, 14, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_pad_right(obj, 2, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
{
lv_obj_t *parent_obj = obj;
{
// StatisticsLabel
lv_obj_t *obj = lv_label_create(parent_obj);
objects.statistics_label = obj;
// StatisticsTable
lv_obj_t *obj = lv_table_create(parent_obj);
objects.statistics_table = obj;
lv_obj_set_pos(obj, 0, 0);
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_label_set_text(obj, "");
lv_obj_set_size(obj, LV_PCT(100), LV_PCT(100));
lv_obj_set_scrollbar_mode(obj, LV_SCROLLBAR_MODE_AUTO);
lv_obj_set_scroll_dir(obj, LV_DIR_VER);
add_style_statistics_table_style(obj);
lv_obj_set_style_pad_top(obj, 1, LV_PART_ITEMS | LV_STATE_DEFAULT);
lv_obj_set_style_pad_bottom(obj, 1, LV_PART_ITEMS | LV_STATE_DEFAULT);
lv_obj_set_style_pad_left(obj, 1, LV_PART_ITEMS | LV_STATE_DEFAULT);
lv_obj_set_style_pad_right(obj, 1, LV_PART_ITEMS | LV_STATE_DEFAULT);
lv_obj_set_style_text_align(obj, LV_TEXT_ALIGN_CENTER, LV_PART_ITEMS | LV_STATE_DEFAULT);
lv_obj_set_style_border_width(obj, 2, LV_PART_MAIN | LV_STATE_DEFAULT);
}
}
}
+1 -1
View File
@@ -372,7 +372,7 @@ typedef struct _objects_t {
lv_obj_t *signal_scanner_start_label;
lv_obj_t *snr_slider;
lv_obj_t *start_button_panel;
lv_obj_t *statistics_label;
lv_obj_t *statistics_table;
lv_obj_t *tab_page_basic_settings;
lv_obj_t *tab_page_filter;
lv_obj_t *tab_page_highlight;
+46
View File
@@ -749,6 +749,50 @@ void remove_style_positive_image_style(lv_obj_t *obj) {
lv_obj_remove_style(obj, get_style_positive_image_style_MAIN_DEFAULT(), LV_PART_MAIN | LV_STATE_DEFAULT);
};
//
// Style: StatisticsTableStyle
//
void init_style_statistics_table_style_MAIN_DEFAULT(lv_style_t *style) {
lv_style_set_text_font(style, &ui_font_montserrat_12);
};
lv_style_t *get_style_statistics_table_style_MAIN_DEFAULT() {
static lv_style_t *style;
if (!style) {
style = lv_malloc(sizeof(lv_style_t));
lv_style_init(style);
init_style_statistics_table_style_MAIN_DEFAULT(style);
}
return style;
};
void init_style_statistics_table_style_ITEMS_DEFAULT(lv_style_t *style) {
lv_style_set_bg_color(style, lv_color_hex(0xfff4f4f0));
lv_style_set_text_color(style, lv_color_hex(0xff212121));
lv_style_set_border_color(style, lv_color_hex(0xffe0e0e0));
};
lv_style_t *get_style_statistics_table_style_ITEMS_DEFAULT() {
static lv_style_t *style;
if (!style) {
style = lv_malloc(sizeof(lv_style_t));
lv_style_init(style);
init_style_statistics_table_style_ITEMS_DEFAULT(style);
}
return style;
};
void add_style_statistics_table_style(lv_obj_t *obj) {
lv_obj_add_style(obj, get_style_statistics_table_style_MAIN_DEFAULT(), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_add_style(obj, get_style_statistics_table_style_ITEMS_DEFAULT(), LV_PART_ITEMS | LV_STATE_DEFAULT);
};
void remove_style_statistics_table_style(lv_obj_t *obj) {
lv_obj_remove_style(obj, get_style_statistics_table_style_MAIN_DEFAULT(), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_remove_style(obj, get_style_statistics_table_style_ITEMS_DEFAULT(), LV_PART_ITEMS | LV_STATE_DEFAULT);
};
//
//
//
@@ -780,6 +824,7 @@ void add_style(lv_obj_t *obj, int32_t styleIndex) {
add_style_spinner_style,
add_style_settings_label_style,
add_style_positive_image_style,
add_style_statistics_table_style,
};
add_style_funcs[styleIndex](obj);
}
@@ -811,6 +856,7 @@ void remove_style(lv_obj_t *obj, int32_t styleIndex) {
remove_style_spinner_style,
remove_style_settings_label_style,
remove_style_positive_image_style,
remove_style_statistics_table_style,
};
remove_style_funcs[styleIndex](obj);
}
+6
View File
@@ -134,6 +134,12 @@ lv_style_t *get_style_positive_image_style_MAIN_DEFAULT();
void add_style_positive_image_style(lv_obj_t *obj);
void remove_style_positive_image_style(lv_obj_t *obj);
// Style: StatisticsTableStyle
lv_style_t *get_style_statistics_table_style_MAIN_DEFAULT();
lv_style_t *get_style_statistics_table_style_ITEMS_DEFAULT();
void add_style_statistics_table_style(lv_obj_t *obj);
void remove_style_statistics_table_style(lv_obj_t *obj);
#ifdef __cplusplus
+2
View File
@@ -197,6 +197,7 @@ class TFTView_320x240 : public MeshtasticView
void removeSpinner(void);
void packetDetected(const meshtastic_MeshPacket &p);
void writePacketLog(const meshtastic_MeshPacket &p);
void updateStatistics(const meshtastic_MeshPacket &p);
// lvgl event callbacks
// static void ui_event_HomeButton(lv_event_t * e);
@@ -268,6 +269,7 @@ class TFTView_320x240 : public MeshtasticView
static void ui_event_packet_log(lv_event_t *e);
static void ui_event_pin_screen_button(lv_event_t *e);
static void ui_event_statistics_table(lv_event_t *e);
static void ui_event_ok(lv_event_t *e);
static void ui_event_cancel(lv_event_t *e);
+1
View File
@@ -15,6 +15,7 @@ class Themes
static void recolorButton(lv_obj_t* obj, bool enabled, lv_opa_t opa = 255);
static void recolorText(lv_obj_t* obj, bool enabled);
static void recolorTopLabel(lv_obj_t* obj, bool alert);
static void recolorTableRow(lv_draw_fill_dsc_t* fill_draw_dsc, bool odd);
private:
Themes(void) = default;
+1 -1
View File
@@ -578,7 +578,7 @@
#define LV_TEXTAREA_DEF_PWD_SHOW_TIME 1500 /*ms*/
#endif
#define LV_USE_TABLE 0
#define LV_USE_TABLE 1
#define LV_USE_TABVIEW 1
+194 -4
View File
@@ -265,6 +265,28 @@ void TFTView_320x240::apply_hotfix(void)
lv_obj_add_flag(objects.detected_node_button, LV_OBJ_FLAG_HIDDEN);
lv_label_set_text(objects.detector_start_label, "Start");
lv_obj_clear_flag(objects.detector_start_button_panel, LV_OBJ_FLAG_HIDDEN);
// add event callback to to apply custom drawing for statistics table
lv_obj_add_event_cb(objects.statistics_table, ui_event_statistics_table, LV_EVENT_DRAW_TASK_ADDED, NULL);
lv_obj_add_flag(objects.statistics_table, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS);
// statistics table item size
lv_table_set_row_count(objects.statistics_table, 12);
lv_table_set_column_count(objects.statistics_table, 7);
lv_table_set_column_width(objects.statistics_table, 0, 57);
lv_table_set_column_width(objects.statistics_table, 1, 36);
lv_table_set_column_width(objects.statistics_table, 2, 36);
lv_table_set_column_width(objects.statistics_table, 3, 36);
lv_table_set_column_width(objects.statistics_table, 4, 36);
lv_table_set_column_width(objects.statistics_table, 5, 36);
lv_table_set_column_width(objects.statistics_table, 6, 36);
// fill table heading
lv_table_set_cell_value(objects.statistics_table, 0, 0, "Name");
lv_table_set_cell_value(objects.statistics_table, 0, 1, "Tel");
lv_table_set_cell_value(objects.statistics_table, 0, 2, "Pos");
lv_table_set_cell_value(objects.statistics_table, 0, 3, "Inf");
lv_table_set_cell_value(objects.statistics_table, 0, 4, "Trc");
lv_table_set_cell_value(objects.statistics_table, 0, 5, "Nbr");
lv_table_set_cell_value(objects.statistics_table, 0, 6, "All");
}
void TFTView_320x240::updateTheme(void)
@@ -435,7 +457,7 @@ void TFTView_320x240::ui_events_init(void)
lv_obj_add_event_cb(objects.tools_signal_scanner_button, ui_event_signal_scanner, LV_EVENT_CLICKED, 0);
lv_obj_add_event_cb(objects.tools_trace_route_button, ui_event_trace_route, LV_EVENT_CLICKED, 0);
lv_obj_add_event_cb(objects.tools_neighbors_button, ui_event_neighbors, LV_EVENT_CLICKED, 0);
// lv_obj_add_event_cb(objects.tools_statistics_button, ui_event_statistics, LV_EVENT_CLICKED, 0);
lv_obj_add_event_cb(objects.tools_statistics_button, ui_event_statistics, LV_EVENT_ALL, 0);
lv_obj_add_event_cb(objects.tools_packet_log_button, ui_event_packet_log, LV_EVENT_ALL, 0);
// tools
lv_obj_add_event_cb(objects.detector_start_button, ui_event_mesh_detector_start, LV_EVENT_CLICKED, 0);
@@ -1490,7 +1512,13 @@ void TFTView_320x240::ui_event_neighbors(lv_event_t *e)
void TFTView_320x240::ui_event_statistics(lv_event_t *e)
{
THIS->ui_set_active(objects.settings_button, objects.tools_statistics_panel, objects.top_statistics_label);
lv_event_code_t event_code = lv_event_get_code(e);
if (event_code == LV_EVENT_CLICKED) {
THIS->ui_set_active(objects.settings_button, objects.tools_statistics_panel, objects.top_statistics_panel);
} else if (event_code == LV_EVENT_LONG_PRESSED) {
// clear statistics table
THIS->updateStatistics(meshtastic_MeshPacket{.from = 0});
}
}
void TFTView_320x240::ui_event_packet_log(lv_event_t *e)
@@ -1555,7 +1583,7 @@ void TFTView_320x240::writePacketLog(const meshtastic_MeshPacket &p)
{5, "routing"}, {6, "admin"}, {7, "text message"}, {8, "waypoint"}, {9, "audio"},
{10, "sensor"}, {32, "reply"}, {33, "ip tunnel"}, {34, "paxcounter"}, {64, "serial"},
{65, "store forward"}, {66, "range test"}, {67, "telemetry"}, {68, "ZPS"}, {69, "simulator"},
{70, "trace route"}, {71, "neighbor info"}, {72, "atax"}, {73, "map report"}, {74, "power stress"},
{70, "tracert"}, {71, "neighbor info"}, {72, "atax"}, {73, "map report"}, {74, "power stress"},
{256, "private"}, {257, "atax forwarder"}};
// ignore admin packages initiated by us
@@ -1673,6 +1701,167 @@ void TFTView_320x240::writePacketLog(const meshtastic_MeshPacket &p)
lv_obj_scroll_to_view(pLabel, LV_ANIM_OFF);
}
void TFTView_320x240::updateStatistics(const meshtastic_MeshPacket &p)
{
struct Stats {
uint32_t id;
uint16_t row;
uint16_t tel;
uint16_t pos;
uint16_t inf;
uint16_t trc;
uint16_t txt;
uint16_t nbr;
uint32_t sum;
bool operator==(const Stats& rhs) const {
return id == rhs.id;
}
Stats& operator+=(const Stats& rhs) {
this->tel += rhs.tel;
this->pos += rhs.pos;
this->inf += rhs.inf;
this->trc += rhs.trc;
this->txt += rhs.txt;
this->nbr += rhs.nbr;
this->sum += 1;
return *this;
}
bool operator<(const Stats& rhs) const {
return sum > rhs.sum; // sort reverse but skip equal values
}
};
static std::list<Stats> stats;
if (p.from == 0) {
// clear table
stats.clear();
for (int i=1; i<=11; i++) {
for (int j=0; j<7; j++) {
lv_table_set_cell_value(objects.statistics_table, i, j, "");
}
}
return;
}
// update statistic for node
Stats stat = { p.from };
switch (p.decoded.portnum) {
case meshtastic_PortNum_TELEMETRY_APP: {
meshtastic_Telemetry telemetry;
if (pb_decode_from_bytes(p.decoded.payload.bytes, p.decoded.payload.size, &meshtastic_Telemetry_msg, &telemetry)) {
if (telemetry.which_variant == meshtastic_Telemetry_device_metrics_tag) {
if (p.from == ownNode)
return; // suppress (internal) battery level packets
}
}
stat.tel++;
break;
}
case meshtastic_PortNum_POSITION_APP: {
stat.pos++;
break;
}
case meshtastic_PortNum_NODEINFO_APP: {
stat.inf++;
break;
}
case meshtastic_PortNum_TRACEROUTE_APP: {
stat.trc++;
break;
}
case meshtastic_PortNum_TEXT_MESSAGE_APP: {
stat.txt++;
break;
}
case meshtastic_PortNum_NEIGHBORINFO_APP: {
stat.nbr++;
break;
}
default:
ILOG_DEBUG("unspecified packet in stats\n");
stat.sum++;
return;
}
std::list<Stats>::iterator it = std::find(stats.begin(), stats.end(), stat);
if (it == stats.end()) {
stat.row = stats.size();
stat.sum = 1;
//TODO: stop if memory limit is reached
stats.push_back(stat);
}
else {
*it += stat;
}
stats.sort();
// fill packet statistics table
char buf[10];
int row = 1;
bool move = false;
for (auto it2 : stats) {
if (it2.id == p.from || move) {
char *userData = (char *)&(nodes[it2.id]->LV_OBJ_IDX(node_lbs_idx)->user_data);
buf[0] = userData[0];
buf[1] = userData[1];
buf[2] = userData[2];
buf[3] = userData[3];
buf[4] = '\0';
// if name is empty or using glyphs then replace with short id
uint32_t width = lv_txt_get_width(buf, strlen(buf), &ui_font_montserrat_12, 0);
if (!width) {
sprintf(buf, "%04x", it2.id & 0xffff);
}
lv_table_set_cell_value(objects.statistics_table, row, 0, buf);
sprintf(buf, "%d", it2.tel);
lv_table_set_cell_value(objects.statistics_table, row, 1, buf);
sprintf(buf, "%d", it2.pos);
lv_table_set_cell_value(objects.statistics_table, row, 2, buf);
sprintf(buf, "%d", it2.inf);
lv_table_set_cell_value(objects.statistics_table, row, 3, buf);
sprintf(buf, "%d", it2.trc);
lv_table_set_cell_value(objects.statistics_table, row, 4, buf);
sprintf(buf, "%d", it2.nbr);
lv_table_set_cell_value(objects.statistics_table, row, 5, buf);
sprintf(buf, "%d", it2.sum);
lv_table_set_cell_value(objects.statistics_table, row, 6, buf);
move = true;
}
row++;
if (row > 11) // fill rows till bottom of 320x240 display
break;
}
}
void TFTView_320x240::ui_event_statistics_table(lv_event_t *e)
{
lv_draw_task_t * draw_task = lv_event_get_draw_task(e);
lv_draw_dsc_base_t * base_dsc = (lv_draw_dsc_base_t *)lv_draw_task_get_draw_dsc(draw_task);
// if the cells are drawn...
if(base_dsc->part == LV_PART_ITEMS) {
// make the texts in the first cell blueish
lv_draw_fill_dsc_t * fill_draw_dsc = lv_draw_task_get_fill_dsc(draw_task);
if(fill_draw_dsc) {
uint32_t row = base_dsc->id1;
if(row == 0) {
fill_draw_dsc->color = lv_color_mix(lv_palette_main(LV_PALETTE_BLUE), fill_draw_dsc->color, LV_OPA_20);
}
// make every 2nd row grayish
else {
Themes::recolorTableRow(fill_draw_dsc, row % 2 == 0);
}
}
}
}
/**
* @brief User widget OK button handling
*
@@ -2753,7 +2942,7 @@ void TFTView_320x240::updateHopsAway(uint32_t nodeNum, uint8_t hopsAway)
char buf[16];
sprintf(buf, "hops: %d", (int)hopsAway);
lv_label_set_text(it->second->LV_OBJ_IDX(node_sig_idx), buf);
it->second->LV_OBJ_IDX(node_sig_idx)->user_data = (void *)hopsAway;
it->second->LV_OBJ_IDX(node_sig_idx)->user_data = (void *)(unsigned long)hopsAway;
}
}
}
@@ -3253,6 +3442,7 @@ void TFTView_320x240::packetReceived(const meshtastic_MeshPacket &p)
if (packetLogEnabled) {
writePacketLog(p);
}
updateStatistics(p);
}
void TFTView_320x240::notifyResync(bool show)
+39 -5
View File
@@ -81,7 +81,14 @@ enum ThemeColor {
eBatteryPercentageText,
eColorTextLabel,
eSpinnerMainArc,
eSpinnerIndicatorArc
eSpinnerIndicatorArc,
eTableHeadingText,
eTableHeadingBg,
eTableItemText,
eTableItemBg,
eTableItemDarkBg,
eTableBorder,
eTableCellBorder
};
uint32_t themeColor[][2] = {
@@ -143,10 +150,7 @@ uint32_t themeColor[][2] = {
{0xffffffff, 0xffffffff}, // eTabButtonPressedText
{0xffb0b0b0, 0xff505050}, // eTabButtonDefaultBorder
{0xfffbfce9, 0xff303030}, // eChatMessageBg
{
255,
255,
}, // eChatMessageBgOpa
{255, 255}, // eChatMessageBgOpa
{0xff294337, 0xffffffff}, // eChatMessageText
{0xff888888, 0xff707070}, // eChatMessageBorder
{0xffffffff, 0xff404040}, // eNewMessageBg
@@ -162,6 +166,13 @@ uint32_t themeColor[][2] = {
{0xff003c9f, 0xffaafbff}, // eColorTextLabel
{0xffe0e0e0, 0xff404040}, // eSpinnerMainArc
{0xff67ea94, 0xff67ea94}, // eSpinnerIndicatorArc
{0xff212121, 0xffaafbff}, // eTableHeadingText,
{0xfff4f4f0, 0xff303030}, // eTableHeadingBg
{0xff212121, 0xffaafbff}, // eTableItemText,
{0xfff4f4f0, 0xff505050}, // eTableItemBg
{0xffd4d4d0, 0xff303030}, // eTableItemDarkBg
{0xffe0e0e0, 0xff404040}, // eTableBorder
{0xffe0e0e0, 0xff404040} // eTableCellBorder
};
#include "fonts.h"
@@ -354,6 +365,17 @@ void apply_style_positive_image_style(void)
lv_style_t *style = get_style_positive_image_style_MAIN_DEFAULT();
lv_style_set_image_recolor(style, lv_color_hex(THEME(ePositiveImageRecolor)));
};
void apply_style_statistics_table_style_MAIN_DEFAULT(void) {
lv_style_t *style = get_style_statistics_table_style_MAIN_DEFAULT();
lv_style_set_border_color(style, lv_color_hex(THEME(eTableBorder)));
};
void apply_style_statistics_table_style_ITEMS_DEFAULT(void) {
lv_style_t *style = get_style_statistics_table_style_ITEMS_DEFAULT();
lv_style_set_bg_color(style, lv_color_hex(THEME(eTableItemBg)));
lv_style_set_text_color(style, lv_color_hex(THEME(eTableItemText)));
lv_style_set_border_color(style, lv_color_hex(THEME(eTableCellBorder)));
};
}
void Themes::set(enum Theme th)
@@ -386,6 +408,8 @@ void Themes::set(enum Theme th)
apply_style_spinner_style_INDICATOR_DEFAULT();
apply_style_settings_label_style();
apply_style_positive_image_style();
apply_style_statistics_table_style_MAIN_DEFAULT();
apply_style_statistics_table_style_ITEMS_DEFAULT();
}
void Themes::initStyles(void)
@@ -469,3 +493,13 @@ void Themes::recolorTopLabel(lv_obj_t *obj, bool alert)
}
lv_obj_set_style_text_color(obj, color, LV_PART_MAIN | LV_STATE_DEFAULT);
}
void Themes::recolorTableRow(lv_draw_fill_dsc_t* fill_draw_dsc, bool odd)
{
if (odd) {
fill_draw_dsc->color = lv_color_hex(THEME(eTableItemBg));
}
else {
fill_draw_dsc->color = lv_color_hex(THEME(eTableItemDarkBg));
}
}