#include "Utils.h" #include #include void crash(const char* const message) { tt_app_alertdialog_start("RadioSet has crashed!", message, nullptr, 0); } void crashassert(bool assertion, const char* const message) { if (!assertion) { crash(message); } } void hexdump(Str& out, const uint8_t* data, size_t size) { out.clear(); for (size_t i = 0; i < size; ++i) { out.appendf("%02X ", data[i]); } } bool isPrintable(const uint8_t* data, size_t size) { for (size_t i = 0; i < (size - 1); ++i) { if (!isprint(data[i])) { return false; } } return true; } char *const toString(Modulation m) { switch (m) { case MODULATION_NONE: return "None"; case MODULATION_LORA: return "LoRa"; case MODULATION_FSK: return "FSK"; case MODULATION_LRFHSS: return "LR-FHSS"; default: break; } crash("Unknown modulation passed."); return "Unknown"; } char *const toString(RadioParameter p) { switch (p) { case RADIO_POWER: return "Power"; case RADIO_BOOSTEDGAIN: return "RX Boosted Gain"; case RADIO_FREQUENCY: return "Center Frequency"; case RADIO_BANDWIDTH: return "Bandwidth"; case RADIO_SPREADFACTOR: return "Spread Factor"; case RADIO_CODINGRATE: return "Coding Rate"; case RADIO_SYNCWORD: return "Sync Word"; case RADIO_PREAMBLES: return "Preamble Length"; case RADIO_FREQDIV: return "Frequency Deviation"; case RADIO_DATARATE: return "Data Rate"; case RADIO_ADDRWIDTH: return "Address Width"; case RADIO_NARROWGRID: return "Narrow Grid"; default: break; } crash("Unknown parameter passed."); return "Unknown"; } char *const toString(RadioTxState state) { switch (state) { case RADIO_TX_QUEUED: return "QUEUED"; case RADIO_TX_PENDING_TRANSMIT: return "TRANSMIT"; case RADIO_TX_TRANSMITTED: return "SENT"; case RADIO_TX_TIMEOUT: return "TIMEOUT"; case RADIO_TX_ERROR: return "ERROR"; default: break; } crash("Unknown parameter passed."); return "Unknown"; } void clownvomit(lv_obj_t *obj) { static auto rng = []() { static int color = 0xCCC0FE; const int a = 4711; const int m = 0x10001; color = (a * color) % m; return color; }; const int darken = 0x0E0E0E; const int lighten = 0xFEFEFE; auto bg = lv_color_darken(lv_color_hex(rng()), 100); lv_obj_set_style_bg_color(obj, bg, 0); uint32_t i; for(i = 0; i < lv_obj_get_child_count(obj); i++) { auto light = lv_color_lighten(lv_color_hex(rng()), 100); auto dark = lv_color_darken(lv_color_hex(rng()), 100); lv_obj_t * child = lv_obj_get_child(obj, i); lv_obj_set_style_bg_color(child, dark, 0); lv_obj_set_style_border_color(child, light, 0); lv_obj_set_style_border_width(child, 1, 0); clownvomit(child); } } static void apply_scroll_styles(lv_obj_t* obj) { static bool init = false; static lv_style_t style_scroll_focus; static lv_style_t style_scrolling; if (!init) { // Style which applies if scrollbar is focused lv_style_init(&style_scroll_focus); lv_style_set_bg_color(&style_scroll_focus, lv_color_make(0x40,0xA0,0xFF)); lv_style_set_bg_opa(&style_scroll_focus, LV_OPA_COVER); lv_style_set_border_width(&style_scroll_focus, 1); lv_style_set_border_color(&style_scroll_focus, lv_theme_get_color_primary(nullptr)); // Style which applies if scrollbar is clicked enough that it defocuses lv_style_init(&style_scrolling); lv_style_set_bg_color(&style_scrolling, lv_color_make(0x40,0xA0,0xFF)); lv_style_set_bg_opa(&style_scrolling, LV_OPA_COVER); lv_style_set_border_width(&style_scrolling, 1); auto lightprimary = lv_color_lighten(lv_theme_get_color_primary(nullptr), 50); lv_style_set_border_color(&style_scrolling, lightprimary); init = true; } lv_obj_add_style(obj, &style_scroll_focus, (lv_style_selector_t)(LV_PART_SCROLLBAR | LV_STATE_FOCUSED)); lv_obj_add_style(obj, &style_scrolling, (lv_style_selector_t)(LV_PART_SCROLLBAR | LV_STATE_PRESSED)); } void make_scrollable(lv_obj_t* obj) { // Make the object interactive, i.e focusable lv_obj_add_flag(obj, (lv_obj_flag_t)(LV_OBJ_FLAG_CLICKABLE | LV_OBJ_FLAG_SCROLL_ON_FOCUS)); // Add to default group to get it into the focus list auto* group = lv_group_get_default(); lv_group_add_obj(group, obj); // Apply style to scrollbar to make it visible if focused apply_scroll_styles(obj); }