diff --git a/firmware/application/protocols/encoders.hpp b/firmware/application/protocols/encoders.hpp index 2d59443e..0d51a37a 100644 --- a/firmware/application/protocols/encoders.hpp +++ b/firmware/application/protocols/encoders.hpp @@ -29,6 +29,7 @@ namespace encoders { #define ENC_TYPES_COUNT 14 + #define OOK_SAMPLERATE 2280000U struct encoder_def_t { std::string name; // Encoder chip ref/name diff --git a/firmware/application/ui_about.cpp b/firmware/application/ui_about.cpp index 43b55af7..e59962b9 100644 --- a/firmware/application/ui_about.cpp +++ b/firmware/application/ui_about.cpp @@ -38,111 +38,100 @@ using namespace portapack; namespace ui { -void AboutView::update() { - size_t c; - int32_t n; - std::string text; - Coord y_val, x_pos = 0; - uint32_t flag; - - if (scroll & 1) { - if (!((scroll >> 1) & 15)) { - if (line_feed) { - line_feed = false; - } else { - // Find a free text widget - for (c = 0; c < 10; c++) - if (text_line[c].screen_pos().y() >= 200) break; - - if (c < 10) { - flag = credits[credits_index].flag & 0x3F; - line_feed = (credits[credits_index].flag & 0x40) ? true : false; - - if (flag == SECTION) { - if (!second) { - text = credits[credits_index].role; - if (credits[credits_index].name != "") - second = true; - else { - credits_index++; - line_feed = true; - } - } else { - text = credits[credits_index].name; - second = false; - line_feed = true; - credits_index++; - } - x_pos = (240 - (text.size() * 8)) / 2; - } else if (flag == TITLE) { - text = credits[credits_index].role; - x_pos = 120 - (text.size() * 8); - if (credits[credits_index].name != "") - text += " " + credits[credits_index].name; - credits_index++; - } else if (flag == MEMBER) { - if (!second) { - text = credits[credits_index].role; - if (credits[credits_index].name != "") - second = true; - else - credits_index++; - } else { - text = credits[credits_index].name; - second = false; - credits_index++; - } - x_pos = 136; - } - - if (!(flag & 0x80)) { - text_line[c].set_parent_rect({{ x_pos, 200 - 16 }, { (Dim)text.size() * 8, 17 }}); - text_line[c].set(text); - text_line[c].hidden(false); - } - } - } - } +// This is pretty much WaterfallView but in the opposite direction +CreditsWidget::CreditsWidget( + Rect parent_rect +) : Widget { parent_rect } +{ +} - // Scroll text lines - for (c = 0; c < 10; c++) { - y_val = text_line[c].screen_pos().y() - 16; - if (y_val < 32) { - text_line[c].set_parent_rect({{ text_line[c].screen_pos().x(), 200 }, { text_line[c].size() }}); - text_line[c].hidden(true); - } else { - if (y_val < 200) { - text_line[c].set_parent_rect({{ text_line[c].screen_pos().x(), y_val - 1 }, { text_line[c].size() }}); - n = (y_val - 32) >> 2; - if (n > 19) - n = (38 - n); - else - n -= 3; - if (n > 3) n = 3; - if (n < 0) n = 0; - text_line[c].set_style(&styles[n]); - } - } +void CreditsWidget::paint(Painter&) { +} + +void CreditsWidget::on_show() { + clear(); + + const auto screen_r = screen_rect(); + display.scroll_set_area(screen_r.top(), screen_r.bottom()); +} + +void CreditsWidget::on_hide() { + display.scroll_disable(); +} + +void CreditsWidget::new_row( + const std::array& pixel_row +) { + const auto draw_y = display.scroll(-1); + + display.draw_pixels( + { { 0, draw_y }, { 240, 1 } }, + pixel_row + ); +} + +void CreditsWidget::clear() { + display.fill_rectangle( + screen_rect(), + Color::black() + ); +} + +void AboutView::update() { + size_t i = 0; + std::array pixel_row; + + slow_down++; + if (slow_down & 1) return; + + if (!timer) { + if (loop) { + credits_index = 0; + loop = false; } + + text = credits[credits_index].text; + timer = credits[credits_index].delay; + start_pos = credits[credits_index].start_pos; + + if (timer < 0) { + timer = 240; + loop = true; + } else { + timer += 16; + } + + render_line = 0; + credits_index++; + } else + timer--; + + if (render_line < 16) { + for (const auto c : text) { + const auto glyph = style().font.glyph(c); + + const size_t start = (glyph.size().width() / 8) * render_line; + for(Dim c=0; c> 3)] & (1U << (c & 0x7)); + pixel_row[start_pos + i + c] = pixel ? Color::white() : Color::black(); + } + + const auto advance = glyph.advance(); + i += advance.x(); + } + render_line++; } - scroll++; + + credits_display.new_row(pixel_row); } AboutView::AboutView( NavigationView& nav -) -{ - add_child(&button_ok); - - for (auto& text : text_line) { - text.set(""); - text.set_parent_rect({ - static_cast(0), - static_cast(200), - 0, 0 - }); - add_child(&text); - } +) { + add_children({ + &credits_display, + &button_ok + }); button_ok.on_select = [&nav](Button&){ nav.pop(); diff --git a/firmware/application/ui_about.hpp b/firmware/application/ui_about.hpp index eb0d2979..e9cd3d38 100644 --- a/firmware/application/ui_about.hpp +++ b/firmware/application/ui_about.hpp @@ -24,7 +24,6 @@ #define __UI_ABOUT_H__ #include "ui_widget.hpp" -#include "ui_menu.hpp" #include "ui_navigation.hpp" #include "ui_font_fixed_8x16.hpp" @@ -32,6 +31,21 @@ namespace ui { +class CreditsWidget : public Widget { +public: + CreditsWidget(Rect parent_rect); + + void on_show() override; + void on_hide() override; + + void paint(Painter&) override; + + void new_row(const std::array& pixel_row); + +private: + void clear(); +}; + class AboutView : public View { public: AboutView(NavigationView& nav); @@ -43,33 +57,14 @@ public: private: void update(); - uint8_t credits_index = 0; - uint32_t scroll = 0; - bool second = false; - bool line_feed = false; + uint8_t credits_index { 0 }; + uint8_t render_line { 0 }; + Coord start_pos { 0 }; + uint8_t slow_down { 0 }; + int32_t timer { 0 }; + bool loop { false }; - Style styles[4] = { style_black, style_dark_grey, style_light_grey, style_white }; - - static constexpr Style style_white { - .font = font::fixed_8x16, - .background = Color::black(), - .foreground = Color(255, 255, 255) - }; - static constexpr Style style_light_grey { - .font = font::fixed_8x16, - .background = Color::black(), - .foreground = Color(170, 170, 170) - }; - static constexpr Style style_dark_grey { - .font = font::fixed_8x16, - .background = Color::black(), - .foreground = Color(85, 85, 85) - }; - static constexpr Style style_black { - .font = font::fixed_8x16, - .background = Color::black(), - .foreground = Color(0, 0, 0) - }; + std::string text { }; enum flags { SECTION = 0, @@ -81,30 +76,35 @@ private: }; typedef struct credits_t { - std::string role; - std::string name; - flags flag; + size_t start_pos; + std::string text; + int32_t delay; } credits_t; - const credits_t credits[16] = { {"Portapack|HAVOC", "Git hash " GIT_REVISION, SECTION}, - {"Gurus", "J. Boone", TITLE}, - {"M. Ossmann", "", MEMBER_LF}, - {"HAVOC", "Furrtek", TITLE_LF}, - {"POCSAG rx", "T. Sailer", TITLE}, - {"E. Oenal", "", MEMBER_LF}, - {"RDS waveform", "C. Jacquet", TITLE_LF}, - {"Xy. infos", "cLx", TITLE_LF}, - {"World map", "NASA", TITLE_LF}, - {"Thanks", "", SECTION}, - {"Rainer Matla", "Keld Norman", TITLE}, - {"Giorgio C.", "DC1RDB", TITLE}, - {"Sigmounte", "Waax", TITLE}, - {"Windyoona", "Channels", TITLE}, - {"F4GEV", "", TITLE_LF}, - {"", "MMXVII", END} - }; - - std::array text_line { }; + const credits_t credits[19] = { + { 60, "PortaPack|HAVOC", 0 }, + { 7 * 8, "Git hash " GIT_REVISION, 16 }, + { 9 * 8, "Gurus J. Boone", 0 }, + { 16 * 8, "M. Ossmann", 16 }, + { 9 * 8, "HAVOC Furrtek", 16 }, + { 5 * 8, "POCSAG rx T. Sailer", 0 }, + { 16 * 8, "E. Oenal", 16 }, + { 2 * 8, "RDS waveform C. Jacquet", 16 }, + { 5 * 8, "Xy. infos cLx", 16 }, + { 0, "OOK scan trick Samy Kamkar", 16 }, + { 5 * 8, "World map NASA", 24 }, + { 12 * 8, "Thanks", 16 }, + { 1 * 8, "Rainer Matla Keld Norman", 0 }, + { 1 * 8, " Giorgio C. DC1RDB", 0 }, + { 1 * 8, " Sigmounte Waax", 0 }, + { 1 * 8, " Windyoona Channels", 0 }, + { 1 * 8, " F4GEV", 24 }, + { 12 * 8, "MMXVII", -1 } + }; + + CreditsWidget credits_display { + { 0, 16, 240, 240 } + }; Button button_ok { { 72, 272, 96, 24 }, diff --git a/firmware/application/ui_encoders.cpp b/firmware/application/ui_encoders.cpp index 232bcad7..ef86bcf1 100644 --- a/firmware/application/ui_encoders.cpp +++ b/firmware/application/ui_encoders.cpp @@ -25,47 +25,131 @@ #include "baseband_api.hpp" #include "string_format.hpp" -#include "portapack_persistent_memory.hpp" - -#include -#include - using namespace portapack; namespace ui { -void EncodersView::focus() { +EncodersConfigView::EncodersConfigView( + NavigationView& nav, Rect parent_rect +) { + using name_t = std::string; + using value_t = int32_t; + using option_t = std::pair; + std::vector enc_options; + size_t i; + + set_parent_rect(parent_rect); + hidden(true); + + // Default encoder def + encoder_def = &encoder_defs[0]; + + add_children({ + &labels, + &options_enctype, + &numberfield_clk, + &numberfield_bitduration, + &numberfield_wordduration, + &symfield_word, + &text_format, + &waveform + }); + + // Load encoder types in option field + for (i = 0; i < ENC_TYPES_COUNT; i++) + enc_options.emplace_back(std::make_pair(encoder_defs[i].name, i)); + + options_enctype.on_change = [this](size_t index, int32_t) { + on_type_change(index); + }; + + options_enctype.set_options(enc_options); + options_enctype.set_selected_index(0); + + symfield_word.on_change = [this]() { + generate_frame(); + }; + + // Selecting input clock changes symbol and word duration + numberfield_clk.on_change = [this](int32_t value) { + // value is in kHz, new_value is in us + int32_t new_value = 1000000 / ((value * 1000) / encoder_def->clk_per_symbol); + if (new_value != numberfield_bitduration.value()) { + numberfield_bitduration.set_value(new_value, false); + numberfield_wordduration.set_value(new_value * encoder_def->word_length, false); + } + }; + + // Selecting symbol duration changes input clock and word duration + numberfield_bitduration.on_change = [this](int32_t value) { + int32_t new_value = 1000000 / (((float)value * 1000) / encoder_def->clk_per_symbol); + if (new_value != numberfield_clk.value()) { + numberfield_clk.set_value(new_value, false); + numberfield_wordduration.set_value(value * encoder_def->word_length, false); + } + }; + + // Selecting word duration changes input clock and symbol duration + numberfield_wordduration.on_change = [this](int32_t value) { + int32_t new_value = value / encoder_def->word_length; + if (new_value != numberfield_bitduration.value()) { + numberfield_bitduration.set_value(new_value, false); + numberfield_clk.set_value(1000000 / (((float)new_value * 1000) / encoder_def->clk_per_symbol), false); + } + }; +} + +void EncodersConfigView::focus() { options_enctype.focus(); } -EncodersView::~EncodersView() { - transmitter_model.disable(); - baseband::shutdown(); -} +void EncodersConfigView::on_type_change(size_t index) { + std::string word_format, format_string = ""; + size_t word_length; + char symbol_type; + //size_t address_length; + + //enc_type = index; -void EncodersView::generate_frame() { - size_t i; + encoder_def = &encoder_defs[index]; + + numberfield_clk.set_value(encoder_def->default_speed / 1000); - debug_text.clear(); - - i = 0; - for (auto c : encoder_def->word_format) { - if (c == 'S') - debug_text += encoder_def->sync; - else - debug_text += encoder_def->bit_format[symfield_word.get_sym(i++)]; + // SymField setup + word_length = encoder_def->word_length; + symfield_word.set_length(word_length); + size_t n = 0, i = 0; + while (n < word_length) { + symbol_type = encoder_def->word_format.at(i++); + if (symbol_type == 'A') { + symfield_word.set_symbol_list(n++, encoder_def->address_symbols); + format_string += 'A'; + } else if (symbol_type == 'D') { + symfield_word.set_symbol_list(n++, encoder_def->data_symbols); + format_string += 'D'; + } } - draw_waveform(); + // Ugly :( Pad to erase + format_string.append(24 - format_string.size(), ' '); + + text_format.set(format_string); + + generate_frame(); } -void EncodersView::draw_waveform() { - uint32_t n, length; +void EncodersConfigView::on_show() { + // TODO: Remove ? + //options_enctype.set_selected_index(enc_type); + //on_type_change(enc_type); +} - length = debug_text.length(); +void EncodersConfigView::draw_waveform() { + size_t length = frame_symbols.length(); + size_t n; for (n = 0; n < length; n++) { - if (debug_text[n] == '0') + if (frame_symbols[n] == '0') waveform_buffer[n] = 0; else waveform_buffer[n] = 1; @@ -75,17 +159,82 @@ void EncodersView::draw_waveform() { waveform.set_dirty(); } +void EncodersConfigView::generate_frame() { + size_t i = 0; + + frame_symbols.clear(); + + for (auto c : encoder_def->word_format) { + if (c == 'S') + frame_symbols += encoder_def->sync; + else + frame_symbols += encoder_def->bit_format[symfield_word.get_sym(i++)]; + } + + draw_waveform(); +} + +uint8_t EncodersConfigView::repeat_min() { + return encoder_def->repeat_min; +} + +uint32_t EncodersConfigView::samples_per_bit() { + return OOK_SAMPLERATE / ((numberfield_clk.value() * 1000) / encoder_def->clk_per_fragment); +} + +uint32_t EncodersConfigView::pause_symbols() { + return encoder_def->pause_symbols; +} + +void EncodersScanView::focus() { + field_debug.focus(); +} + +EncodersScanView::EncodersScanView( + NavigationView& nav, Rect parent_rect +) { + set_parent_rect(parent_rect); + hidden(true); + + add_children({ + &labels, + &field_debug, + &text_debug + }); + + // DEBUG + field_debug.on_change = [this](int32_t value) { + uint32_t l; + de_bruijn debruijn_seq; + debruijn_seq.init(value); + l = 1; + l <<= value; + l--; + if (l > 25) + l = 25; + text_debug.set(to_string_bin(debruijn_seq.compute(l), 25)); + }; +} + +void EncodersView::focus() { + tab_view.focus(); +} + +EncodersView::~EncodersView() { + transmitter_model.disable(); + baseband::shutdown(); +} + void EncodersView::update_progress() { - char str[16]; + std::string str_buffer; // text_status.set(" "); if (tx_mode == SINGLE) { - strcpy(str, to_string_dec_uint(repeat_index).c_str()); - strcat(str, "/"); - strcat(str, to_string_dec_uint(encoder_def->repeat_min).c_str()); - text_status.set(str); + str_buffer = to_string_dec_uint(repeat_index) + "/" + to_string_dec_uint(repeat_min); + text_status.set(str_buffer); progress.set_value(repeat_index); + /*} else if (tx_mode == SCAN) { strcpy(str, to_string_dec_uint(repeat_index).c_str()); strcat(str, "/"); @@ -107,7 +256,8 @@ void EncodersView::on_txdone(int n, const bool txdone) { if (!txdone) { // Repeating... - repeat_index = n + 1; + //repeat_index = n + 1; + /*if (tx_mode == SCAN) { scan_progress++; update_progress(); @@ -147,14 +297,12 @@ void EncodersView::on_txdone(int n, const bool txdone) { } } -void EncodersView::on_tuning_frequency_changed(rf::Frequency f) { - transmitter_model.set_tuning_frequency(f); -} - void EncodersView::start_tx(const bool scan) { - char ook_bitstream[256]; - uint32_t ook_bitstream_length; (void)scan; + uint8_t* ook_bitstream = shared_memory.bb_data.data; + uint32_t ook_bitstream_length; + + repeat_min = view_config.repeat_min(); /*if (scan) { if (tx_mode != SCAN) { @@ -170,17 +318,17 @@ void EncodersView::start_tx(const bool scan) { } else {*/ tx_mode = SINGLE; repeat_index = 1; - progress.set_max(encoder_def->repeat_min); + progress.set_max(repeat_min); update_progress(); //} - generate_frame(); + view_config.generate_frame(); // Clear bitstream memset(ook_bitstream, 0, 256); size_t n = 0; - for (auto c : debug_text) { + for (auto c : view_config.frame_symbols) { if (c != '0') ook_bitstream[n >> 3] |= (1 << (7 - (n & 7))); n++; @@ -188,158 +336,41 @@ void EncodersView::start_tx(const bool scan) { ook_bitstream_length = n; - transmitter_model.set_sampling_rate(2280000U); + transmitter_model.set_sampling_rate(OOK_SAMPLERATE); transmitter_model.set_rf_amp(true); transmitter_model.set_baseband_bandwidth(1750000); transmitter_model.enable(); - memcpy(shared_memory.bb_data.data, ook_bitstream, 256); - baseband::set_ook_data( ook_bitstream_length, // 2280000/2 = 1140000Hz = 0,877192982us // numberfield_clk.value() / encoder_def->clk_per_fragment // 455000 / 12 = 37917Hz = 26,37339452us - 228000 / ((numberfield_clk.value() * 1000) / encoder_def->clk_per_fragment), - encoder_def->repeat_min, - encoder_def->pause_symbols + view_config.samples_per_bit(), + repeat_min, + view_config.pause_symbols() ); } -void EncodersView::on_type_change(size_t index) { - std::string word_format, format_string = ""; - size_t word_length; - char symbol_type; - //size_t address_length; - - enc_type = index; - - encoder_def = &encoder_defs[enc_type]; - - numberfield_clk.set_value(encoder_def->default_speed / 1000); - - // SymField setup - word_length = encoder_def->word_length; - symfield_word.set_length(word_length); - size_t n = 0, i = 0; - while (n < word_length) { - symbol_type = encoder_def->word_format.at(i++); - if (symbol_type == 'A') { - symfield_word.set_symbol_list(n++, encoder_def->address_symbols); - format_string += 'A'; - } else if (symbol_type == 'D') { - symfield_word.set_symbol_list(n++, encoder_def->data_symbols); - format_string += 'D'; - } - } - - // Ugly :( Pad to erase - while (format_string.length() < 24) - format_string += ' '; - - text_format.set(format_string); - - generate_frame(); -} - -void EncodersView::on_show() { - // TODO: Remove ? - options_enctype.set_selected_index(enc_type); - on_type_change(enc_type); -} - -EncodersView::EncodersView(NavigationView& nav) { - using name_t = std::string; - using value_t = int32_t; - using option_t = std::pair; - using options_t = std::vector; - options_t enc_options; - size_t i; - +EncodersView::EncodersView( + NavigationView& nav +) : nav_ { nav } +{ baseband::run_image(portapack::spi_flash::image_tag_ook); - - // Default encoder def - encoder_def = &encoder_defs[0]; add_children({ - &labels, - &options_enctype, - &numberfield_clk, - &numberfield_bitduration, - &numberfield_wordduration, - //&field_debug, - &symfield_word, - &text_format, - //&text_format_a, // DEBUG - //&text_format_d, // DEBUG - &waveform, + &tab_view, + &view_config, + &view_scan, &text_status, &progress, &tx_view }); - // Load encoder types - for (i = 0; i < ENC_TYPES_COUNT; i++) - enc_options.emplace_back(std::make_pair(encoder_defs[i].name, i)); - - options_enctype.on_change = [this](size_t index, int32_t value) { - (void)value; - this->on_type_change(index); - }; - - options_enctype.set_options(enc_options); - options_enctype.set_selected_index(0); - - symfield_word.on_change = [this]() { - this->generate_frame(); - }; - - // DEBUG - /*field_debug.on_change = [this](int32_t value) { - uint32_t l; - de_bruijn debruijn_seq; - debruijn_seq.init(value); - l = 1; - l <<= value; - l--; - if (l > 25) - l = 25; - text_format.set(to_string_bin(debruijn_seq.compute(l), 25)); - };*/ - - // Selecting input clock changes symbol and word duration - numberfield_clk.on_change = [this](int32_t value) { - //int32_t new_value = 1000000 / (((float)value * 1000) / encoder_def->clk_per_symbol); - // value is in kHz, new_value is in us - int32_t new_value = 1000000 / ((value * 1000) / encoder_def->clk_per_symbol); - if (new_value != numberfield_bitduration.value()) { - numberfield_bitduration.set_value(new_value, false); - numberfield_wordduration.set_value(new_value * encoder_def->word_length, false); - } - }; - - // Selecting symbol duration changes input clock and word duration - numberfield_bitduration.on_change = [this](int32_t value) { - int32_t new_value = 1000000 / (((float)value * 1000) / encoder_def->clk_per_symbol); - if (new_value != numberfield_clk.value()) { - numberfield_clk.set_value(new_value, false); - numberfield_wordduration.set_value(value * encoder_def->word_length, false); - } - }; - - // Selecting word duration changes input clock and symbol duration - numberfield_wordduration.on_change = [this](int32_t value) { - int32_t new_value = value / encoder_def->word_length; - if (new_value != numberfield_bitduration.value()) { - numberfield_bitduration.set_value(new_value, false); - numberfield_clk.set_value(1000000 / (((float)new_value * 1000) / encoder_def->clk_per_symbol), false); - } - }; - tx_view.on_edit_frequency = [this, &nav]() { - auto new_view = nav.push(receiver_model.tuning_frequency()); + auto new_view = nav.push(transmitter_model.tuning_frequency()); new_view->on_changed = [this](rf::Frequency f) { - receiver_model.set_tuning_frequency(f); + transmitter_model.set_tuning_frequency(f); }; }; diff --git a/firmware/application/ui_encoders.hpp b/firmware/application/ui_encoders.hpp index f50a3877..1ba48c36 100644 --- a/firmware/application/ui_encoders.hpp +++ b/firmware/application/ui_encoders.hpp @@ -21,37 +21,151 @@ */ #include "ui.hpp" -#include "ui_widget.hpp" -#include "ui_navigation.hpp" -#include "ui_font_fixed_8x16.hpp" -#include "ui_receiver.hpp" +#include "ui_tabview.hpp" #include "ui_transmitter.hpp" +#include "transmitter_model.hpp" #include "encoders.hpp" #include "de_bruijn.hpp" -#include "message.hpp" -#include "transmitter_model.hpp" using namespace encoders; namespace ui { +class EncodersConfigView : public View { +public: + EncodersConfigView(NavigationView& nav, Rect parent_rect); + + EncodersConfigView(const EncodersConfigView&) = delete; + EncodersConfigView(EncodersConfigView&&) = delete; + EncodersConfigView& operator=(const EncodersConfigView&) = delete; + EncodersConfigView& operator=(EncodersConfigView&&) = delete; + + void focus() override; + void on_show() override; + + uint8_t repeat_min(); + uint32_t samples_per_bit(); + uint32_t pause_symbols(); + void generate_frame(); + + std::string frame_symbols = "0"; + +private: + //bool abort_scan = false; + //uint8_t scan_count; + //double scan_progress; + //unsigned int scan_index; + int8_t waveform_buffer[512]; + const encoder_def_t * encoder_def { }; + //uint8_t enc_type = 0; + + void draw_waveform(); + void on_bitfield(); + void on_type_change(size_t index); + + Labels labels { + { { 1 * 8, 0 }, "Type:", Color::light_grey() }, + { { 16 * 8, 0 }, "Clk:", Color::light_grey() }, + { { 24 * 8, 0 }, "kHz", Color::light_grey() }, + { { 16 * 8, 2 * 8 }, "Bit:", Color::light_grey() }, + { { 25 * 8, 2 * 8 }, "us", Color::light_grey() }, + { { 15 * 8, 4 * 8 }, "Word:", Color::light_grey() }, + { { 26 * 8, 4 * 8 }, "us", Color::light_grey() }, + { { 2 * 8, 6 * 8 }, "Word:", Color::light_grey() }, + { { 1 * 8, 13 * 8 }, "Waveform:", Color::light_grey() } + }; + + OptionsField options_enctype { // Options are loaded at runtime + { 6 * 8, 0 }, + 7, + { + } + }; + + NumberField numberfield_clk { + { 21 * 8, 0 }, + 3, + { 1, 500 }, + 1, + ' ' + }; + + NumberField numberfield_bitduration { + { 21 * 8, 2 * 8 }, + 4, + { 50, 9999 }, + 1, + ' ' + }; + + NumberField numberfield_wordduration { + { 21 * 8, 4 * 8 }, + 5, + { 300, 99999 }, + 100, + ' ' + }; + + SymField symfield_word { + { 2 * 8, 8 * 8 }, + 20, + SymField::SYMFIELD_DEF + }; + + Text text_format { + { 2 * 8, 10 * 8, 24 * 8, 16 }, + "" + }; + + Waveform waveform { + { 0, 16 * 8, 240, 32 }, + waveform_buffer, + 0, + 0, + true, + Color::yellow() + }; +}; + + +class EncodersScanView : public View { +public: + EncodersScanView(NavigationView& nav, Rect parent_rect); + + void focus() override; + +private: + Labels labels { + { { 1 * 8, 1 * 8 }, "Test", Color::light_grey() } + }; + + // DEBUG + NumberField field_debug { + { 1 * 8, 6 * 8 }, + 2, + { 3, 16 }, + 1, + ' ' + }; + + // DEBUG + Text text_debug { + { 1 * 8, 8 * 8, 24 * 8, 16 }, + "" + }; +}; + class EncodersView : public View { public: EncodersView(NavigationView& nav); ~EncodersView(); - EncodersView(const EncodersView&) = delete; - EncodersView(EncodersView&&) = delete; - EncodersView& operator=(const EncodersView&) = delete; - EncodersView& operator=(EncodersView&&) = delete; - void focus() override; - void on_show() override; - std::string title() const override { return "Encoders TX"; }; + std::string title() const override { return "OOK transmit"; }; private: - void on_tuning_frequency_changed(rf::Frequency f); + NavigationView& nav_; enum tx_modes { IDLE = 0, @@ -59,36 +173,14 @@ private: SCAN }; - uint8_t enc_type = 0; - const encoder_def_t * encoder_def { }; tx_modes tx_mode = IDLE; - //bool abort_scan = false; - //uint8_t scan_count; - //double scan_progress; - //unsigned int scan_index; - std::string debug_text = "0"; uint8_t repeat_index { 0 }; - int8_t waveform_buffer[512]; + uint8_t repeat_min { 0 }; - void draw_waveform(); - void on_bitfield(); - void on_type_change(size_t index); - void generate_frame(); void update_progress(); void start_tx(const bool scan); void on_txdone(int n, const bool txdone); - const Style style_val { - .font = font::fixed_8x16, - .background = Color::black(), - .foreground = Color::green(), - }; - const Style style_cancel { - .font = font::fixed_8x16, - .background = Color::black(), - .foreground = Color::red(), - }; - const Style style_address { .font = font::fixed_8x16, .background = Color::black(), @@ -100,85 +192,21 @@ private: .foreground = Color::blue(), }; - Labels labels { - { { 1 * 8, 4 * 8 }, "Type:", Color::light_grey() }, - { { 16 * 8, 4 * 8 }, "Clk:", Color::light_grey() }, - { { 24 * 8, 4 * 8 }, "kHz", Color::light_grey() }, - { { 16 * 8, 6 * 8 }, "Bit:", Color::light_grey() }, - { { 25 * 8, 6 * 8 }, "us", Color::light_grey() }, - { { 15 * 8, 8 * 8 }, "Word:", Color::light_grey() }, - { { 26 * 8, 8 * 8 }, "us", Color::light_grey() }, - { { 2 * 8, 10 * 8 }, "Word:", Color::light_grey() }, - { { 1 * 8, 17 * 8 }, "Waveform:", Color::light_grey() } + Rect view_rect = { 0, 5 * 8, 240, 168 }; + + EncodersConfigView view_config { nav_, view_rect }; + EncodersScanView view_scan { nav_, view_rect }; + + TabView tab_view { + { "Config", Color::cyan(), &view_config }, + { "Scan", Color::green(), &view_scan }, }; - OptionsField options_enctype { // Options are loaded at runtime - { 6 * 8, 32 }, - 7, - { - } - }; - - NumberField numberfield_clk { - { 21 * 8, 4 * 8 }, - 3, - { 1, 500 }, - 1, - ' ' - }; - - NumberField numberfield_bitduration { - { 21 * 8, 6 * 8 }, - 4, - { 50, 9999 }, - 1, - ' ' - }; - - NumberField numberfield_wordduration { - { 21 * 8, 8 * 8 }, - 5, - { 300, 99999 }, - 100, - ' ' - }; - - // DEBUG - /*NumberField field_debug { - { 21 * 8, 10 * 8 }, - 2, - { 3, 16 }, - 1, - ' ' - };*/ - - SymField symfield_word { - { 2 * 8, 12 * 8 }, - 20, - SymField::SYMFIELD_DEF - }; - Text text_format { - { 2 * 8, 14 * 8, 24 * 8, 16 }, - "" - }; - - //Text text_format_a; // DEBUG - //Text text_format_d; // DEBUG - - Waveform waveform { - { 0, 160, 240, 32 }, - waveform_buffer, - 0, - 0, - true, - Color::yellow() - }; - Text text_status { { 2 * 8, 13 * 16, 128, 16 }, "Ready" }; - + ProgressBar progress { { 2 * 8, 13 * 16 + 20, 208, 16 } }; diff --git a/firmware/application/ui_geomap.cpp b/firmware/application/ui_geomap.cpp index 9b68a5ce..4387cb73 100644 --- a/firmware/application/ui_geomap.cpp +++ b/firmware/application/ui_geomap.cpp @@ -219,6 +219,8 @@ void GeoMapView::focus() { void GeoMapView::update_position(float lat, float lon) { lat_ = lat; lon_ = lon; + geopos.set_lat(lat_); + geopos.set_lon(lon_); geomap.move(lon_, lat_); geomap.set_dirty(); } diff --git a/firmware/baseband/proc_ook.cpp b/firmware/baseband/proc_ook.cpp index 16794583..da27720f 100644 --- a/firmware/baseband/proc_ook.cpp +++ b/firmware/baseband/proc_ook.cpp @@ -98,7 +98,7 @@ void OOKProcessor::on_message(const Message* const p) { const auto message = *reinterpret_cast(p); if (message.id == Message::ID::OOKConfigure) { - samples_per_bit = message.samples_per_bit; + samples_per_bit = message.samples_per_bit / 10; repeat = message.repeat - 1; length = message.stream_length - 1; pause = message.pause_symbols + 1;