Added tabs in OOK encoders app

Simplified credits scrolling
This commit is contained in:
furrtek 2017-08-28 22:17:02 +01:00
parent 6fcb2efdcf
commit cd6a1a7f3f
7 changed files with 479 additions and 428 deletions

View File

@ -29,6 +29,7 @@
namespace encoders { namespace encoders {
#define ENC_TYPES_COUNT 14 #define ENC_TYPES_COUNT 14
#define OOK_SAMPLERATE 2280000U
struct encoder_def_t { struct encoder_def_t {
std::string name; // Encoder chip ref/name std::string name; // Encoder chip ref/name

View File

@ -38,111 +38,100 @@ using namespace portapack;
namespace ui { namespace ui {
void AboutView::update() { // This is pretty much WaterfallView but in the opposite direction
size_t c; CreditsWidget::CreditsWidget(
int32_t n; Rect parent_rect
std::string text; ) : Widget { parent_rect }
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);
}
}
}
}
// Scroll text lines void CreditsWidget::paint(Painter&) {
for (c = 0; c < 10; c++) { }
y_val = text_line[c].screen_pos().y() - 16;
if (y_val < 32) { void CreditsWidget::on_show() {
text_line[c].set_parent_rect({{ text_line[c].screen_pos().x(), 200 }, { text_line[c].size() }}); clear();
text_line[c].hidden(true);
} else { const auto screen_r = screen_rect();
if (y_val < 200) { display.scroll_set_area(screen_r.top(), screen_r.bottom());
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) void CreditsWidget::on_hide() {
n = (38 - n); display.scroll_disable();
else }
n -= 3;
if (n > 3) n = 3; void CreditsWidget::new_row(
if (n < 0) n = 0; const std::array<Color, 240>& pixel_row
text_line[c].set_style(&styles[n]); ) {
} 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<Color, 240> 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<glyph.size().width(); c++) {
const auto pixel = glyph.pixels()[start + (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( AboutView::AboutView(
NavigationView& nav NavigationView& nav
) ) {
{ add_children({
add_child(&button_ok); &credits_display,
&button_ok
for (auto& text : text_line) { });
text.set("");
text.set_parent_rect({
static_cast<Coord>(0),
static_cast<Coord>(200),
0, 0
});
add_child(&text);
}
button_ok.on_select = [&nav](Button&){ button_ok.on_select = [&nav](Button&){
nav.pop(); nav.pop();

View File

@ -24,7 +24,6 @@
#define __UI_ABOUT_H__ #define __UI_ABOUT_H__
#include "ui_widget.hpp" #include "ui_widget.hpp"
#include "ui_menu.hpp"
#include "ui_navigation.hpp" #include "ui_navigation.hpp"
#include "ui_font_fixed_8x16.hpp" #include "ui_font_fixed_8x16.hpp"
@ -32,6 +31,21 @@
namespace ui { 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<Color, 240>& pixel_row);
private:
void clear();
};
class AboutView : public View { class AboutView : public View {
public: public:
AboutView(NavigationView& nav); AboutView(NavigationView& nav);
@ -43,33 +57,14 @@ public:
private: private:
void update(); void update();
uint8_t credits_index = 0; uint8_t credits_index { 0 };
uint32_t scroll = 0; uint8_t render_line { 0 };
bool second = false; Coord start_pos { 0 };
bool line_feed = false; 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 }; std::string text { };
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)
};
enum flags { enum flags {
SECTION = 0, SECTION = 0,
@ -81,30 +76,35 @@ private:
}; };
typedef struct credits_t { typedef struct credits_t {
std::string role; size_t start_pos;
std::string name; std::string text;
flags flag; int32_t delay;
} credits_t; } credits_t;
const credits_t credits[16] = { {"Portapack|HAVOC", "Git hash " GIT_REVISION, SECTION}, const credits_t credits[19] = {
{"Gurus", "J. Boone", TITLE}, { 60, "PortaPack|HAVOC", 0 },
{"M. Ossmann", "", MEMBER_LF}, { 7 * 8, "Git hash " GIT_REVISION, 16 },
{"HAVOC", "Furrtek", TITLE_LF}, { 9 * 8, "Gurus J. Boone", 0 },
{"POCSAG rx", "T. Sailer", TITLE}, { 16 * 8, "M. Ossmann", 16 },
{"E. Oenal", "", MEMBER_LF}, { 9 * 8, "HAVOC Furrtek", 16 },
{"RDS waveform", "C. Jacquet", TITLE_LF}, { 5 * 8, "POCSAG rx T. Sailer", 0 },
{"Xy. infos", "cLx", TITLE_LF}, { 16 * 8, "E. Oenal", 16 },
{"World map", "NASA", TITLE_LF}, { 2 * 8, "RDS waveform C. Jacquet", 16 },
{"Thanks", "", SECTION}, { 5 * 8, "Xy. infos cLx", 16 },
{"Rainer Matla", "Keld Norman", TITLE}, { 0, "OOK scan trick Samy Kamkar", 16 },
{"Giorgio C.", "DC1RDB", TITLE}, { 5 * 8, "World map NASA", 24 },
{"Sigmounte", "Waax", TITLE}, { 12 * 8, "Thanks", 16 },
{"Windyoona", "Channels", TITLE}, { 1 * 8, "Rainer Matla Keld Norman", 0 },
{"F4GEV", "", TITLE_LF}, { 1 * 8, " Giorgio C. DC1RDB", 0 },
{"", "MMXVII", END} { 1 * 8, " Sigmounte Waax", 0 },
}; { 1 * 8, " Windyoona Channels", 0 },
{ 1 * 8, " F4GEV", 24 },
std::array<Text, 10> text_line { }; { 12 * 8, "MMXVII", -1 }
};
CreditsWidget credits_display {
{ 0, 16, 240, 240 }
};
Button button_ok { Button button_ok {
{ 72, 272, 96, 24 }, { 72, 272, 96, 24 },

View File

@ -25,47 +25,131 @@
#include "baseband_api.hpp" #include "baseband_api.hpp"
#include "string_format.hpp" #include "string_format.hpp"
#include "portapack_persistent_memory.hpp"
#include <cstring>
#include <stdio.h>
using namespace portapack; using namespace portapack;
namespace ui { 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<name_t, value_t>;
std::vector<option_t> 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(); options_enctype.focus();
} }
EncodersView::~EncodersView() { void EncodersConfigView::on_type_change(size_t index) {
transmitter_model.disable(); std::string word_format, format_string = "";
baseband::shutdown(); size_t word_length;
} char symbol_type;
//size_t address_length;
//enc_type = index;
void EncodersView::generate_frame() { encoder_def = &encoder_defs[index];
size_t i;
numberfield_clk.set_value(encoder_def->default_speed / 1000);
debug_text.clear(); // SymField setup
word_length = encoder_def->word_length;
i = 0; symfield_word.set_length(word_length);
for (auto c : encoder_def->word_format) { size_t n = 0, i = 0;
if (c == 'S') while (n < word_length) {
debug_text += encoder_def->sync; symbol_type = encoder_def->word_format.at(i++);
else if (symbol_type == 'A') {
debug_text += encoder_def->bit_format[symfield_word.get_sym(i++)]; 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() { void EncodersConfigView::on_show() {
uint32_t n, length; // 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++) { for (n = 0; n < length; n++) {
if (debug_text[n] == '0') if (frame_symbols[n] == '0')
waveform_buffer[n] = 0; waveform_buffer[n] = 0;
else else
waveform_buffer[n] = 1; waveform_buffer[n] = 1;
@ -75,17 +159,82 @@ void EncodersView::draw_waveform() {
waveform.set_dirty(); 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() { void EncodersView::update_progress() {
char str[16]; std::string str_buffer;
// text_status.set(" "); // text_status.set(" ");
if (tx_mode == SINGLE) { if (tx_mode == SINGLE) {
strcpy(str, to_string_dec_uint(repeat_index).c_str()); str_buffer = to_string_dec_uint(repeat_index) + "/" + to_string_dec_uint(repeat_min);
strcat(str, "/"); text_status.set(str_buffer);
strcat(str, to_string_dec_uint(encoder_def->repeat_min).c_str());
text_status.set(str);
progress.set_value(repeat_index); progress.set_value(repeat_index);
/*} else if (tx_mode == SCAN) { /*} else if (tx_mode == SCAN) {
strcpy(str, to_string_dec_uint(repeat_index).c_str()); strcpy(str, to_string_dec_uint(repeat_index).c_str());
strcat(str, "/"); strcat(str, "/");
@ -107,7 +256,8 @@ void EncodersView::on_txdone(int n, const bool txdone) {
if (!txdone) { if (!txdone) {
// Repeating... // Repeating...
repeat_index = n + 1; //repeat_index = n + 1;
/*if (tx_mode == SCAN) { /*if (tx_mode == SCAN) {
scan_progress++; scan_progress++;
update_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) { void EncodersView::start_tx(const bool scan) {
char ook_bitstream[256];
uint32_t ook_bitstream_length;
(void)scan; (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 (scan) {
if (tx_mode != SCAN) { if (tx_mode != SCAN) {
@ -170,17 +318,17 @@ void EncodersView::start_tx(const bool scan) {
} else {*/ } else {*/
tx_mode = SINGLE; tx_mode = SINGLE;
repeat_index = 1; repeat_index = 1;
progress.set_max(encoder_def->repeat_min); progress.set_max(repeat_min);
update_progress(); update_progress();
//} //}
generate_frame(); view_config.generate_frame();
// Clear bitstream // Clear bitstream
memset(ook_bitstream, 0, 256); memset(ook_bitstream, 0, 256);
size_t n = 0; size_t n = 0;
for (auto c : debug_text) { for (auto c : view_config.frame_symbols) {
if (c != '0') if (c != '0')
ook_bitstream[n >> 3] |= (1 << (7 - (n & 7))); ook_bitstream[n >> 3] |= (1 << (7 - (n & 7)));
n++; n++;
@ -188,158 +336,41 @@ void EncodersView::start_tx(const bool scan) {
ook_bitstream_length = n; 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_rf_amp(true);
transmitter_model.set_baseband_bandwidth(1750000); transmitter_model.set_baseband_bandwidth(1750000);
transmitter_model.enable(); transmitter_model.enable();
memcpy(shared_memory.bb_data.data, ook_bitstream, 256);
baseband::set_ook_data( baseband::set_ook_data(
ook_bitstream_length, ook_bitstream_length,
// 2280000/2 = 1140000Hz = 0,877192982us // 2280000/2 = 1140000Hz = 0,877192982us
// numberfield_clk.value() / encoder_def->clk_per_fragment // numberfield_clk.value() / encoder_def->clk_per_fragment
// 455000 / 12 = 37917Hz = 26,37339452us // 455000 / 12 = 37917Hz = 26,37339452us
228000 / ((numberfield_clk.value() * 1000) / encoder_def->clk_per_fragment), view_config.samples_per_bit(),
encoder_def->repeat_min, repeat_min,
encoder_def->pause_symbols view_config.pause_symbols()
); );
} }
void EncodersView::on_type_change(size_t index) { EncodersView::EncodersView(
std::string word_format, format_string = ""; NavigationView& nav
size_t word_length; ) : nav_ { nav }
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<name_t, value_t>;
using options_t = std::vector<option_t>;
options_t enc_options;
size_t i;
baseband::run_image(portapack::spi_flash::image_tag_ook); baseband::run_image(portapack::spi_flash::image_tag_ook);
// Default encoder def
encoder_def = &encoder_defs[0];
add_children({ add_children({
&labels, &tab_view,
&options_enctype, &view_config,
&numberfield_clk, &view_scan,
&numberfield_bitduration,
&numberfield_wordduration,
//&field_debug,
&symfield_word,
&text_format,
//&text_format_a, // DEBUG
//&text_format_d, // DEBUG
&waveform,
&text_status, &text_status,
&progress, &progress,
&tx_view &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]() { tx_view.on_edit_frequency = [this, &nav]() {
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency()); auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.tuning_frequency());
new_view->on_changed = [this](rf::Frequency f) { new_view->on_changed = [this](rf::Frequency f) {
receiver_model.set_tuning_frequency(f); transmitter_model.set_tuning_frequency(f);
}; };
}; };

View File

@ -21,37 +21,151 @@
*/ */
#include "ui.hpp" #include "ui.hpp"
#include "ui_widget.hpp" #include "ui_tabview.hpp"
#include "ui_navigation.hpp"
#include "ui_font_fixed_8x16.hpp"
#include "ui_receiver.hpp"
#include "ui_transmitter.hpp" #include "ui_transmitter.hpp"
#include "transmitter_model.hpp"
#include "encoders.hpp" #include "encoders.hpp"
#include "de_bruijn.hpp" #include "de_bruijn.hpp"
#include "message.hpp"
#include "transmitter_model.hpp"
using namespace encoders; using namespace encoders;
namespace ui { 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 { class EncodersView : public View {
public: public:
EncodersView(NavigationView& nav); EncodersView(NavigationView& nav);
~EncodersView(); ~EncodersView();
EncodersView(const EncodersView&) = delete;
EncodersView(EncodersView&&) = delete;
EncodersView& operator=(const EncodersView&) = delete;
EncodersView& operator=(EncodersView&&) = delete;
void focus() override; void focus() override;
void on_show() override;
std::string title() const override { return "Encoders TX"; }; std::string title() const override { return "OOK transmit"; };
private: private:
void on_tuning_frequency_changed(rf::Frequency f); NavigationView& nav_;
enum tx_modes { enum tx_modes {
IDLE = 0, IDLE = 0,
@ -59,36 +173,14 @@ private:
SCAN SCAN
}; };
uint8_t enc_type = 0;
const encoder_def_t * encoder_def { };
tx_modes tx_mode = IDLE; 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 }; 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 update_progress();
void start_tx(const bool scan); void start_tx(const bool scan);
void on_txdone(int n, const bool txdone); 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 { const Style style_address {
.font = font::fixed_8x16, .font = font::fixed_8x16,
.background = Color::black(), .background = Color::black(),
@ -100,85 +192,21 @@ private:
.foreground = Color::blue(), .foreground = Color::blue(),
}; };
Labels labels { Rect view_rect = { 0, 5 * 8, 240, 168 };
{ { 1 * 8, 4 * 8 }, "Type:", Color::light_grey() },
{ { 16 * 8, 4 * 8 }, "Clk:", Color::light_grey() }, EncodersConfigView view_config { nav_, view_rect };
{ { 24 * 8, 4 * 8 }, "kHz", Color::light_grey() }, EncodersScanView view_scan { nav_, view_rect };
{ { 16 * 8, 6 * 8 }, "Bit:", Color::light_grey() },
{ { 25 * 8, 6 * 8 }, "us", Color::light_grey() }, TabView tab_view {
{ { 15 * 8, 8 * 8 }, "Word:", Color::light_grey() }, { "Config", Color::cyan(), &view_config },
{ { 26 * 8, 8 * 8 }, "us", Color::light_grey() }, { "Scan", Color::green(), &view_scan },
{ { 2 * 8, 10 * 8 }, "Word:", Color::light_grey() },
{ { 1 * 8, 17 * 8 }, "Waveform:", Color::light_grey() }
}; };
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 { Text text_status {
{ 2 * 8, 13 * 16, 128, 16 }, { 2 * 8, 13 * 16, 128, 16 },
"Ready" "Ready"
}; };
ProgressBar progress { ProgressBar progress {
{ 2 * 8, 13 * 16 + 20, 208, 16 } { 2 * 8, 13 * 16 + 20, 208, 16 }
}; };

View File

@ -219,6 +219,8 @@ void GeoMapView::focus() {
void GeoMapView::update_position(float lat, float lon) { void GeoMapView::update_position(float lat, float lon) {
lat_ = lat; lat_ = lat;
lon_ = lon; lon_ = lon;
geopos.set_lat(lat_);
geopos.set_lon(lon_);
geomap.move(lon_, lat_); geomap.move(lon_, lat_);
geomap.set_dirty(); geomap.set_dirty();
} }

View File

@ -98,7 +98,7 @@ void OOKProcessor::on_message(const Message* const p) {
const auto message = *reinterpret_cast<const OOKConfigureMessage*>(p); const auto message = *reinterpret_cast<const OOKConfigureMessage*>(p);
if (message.id == Message::ID::OOKConfigure) { 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; repeat = message.repeat - 1;
length = message.stream_length - 1; length = message.stream_length - 1;
pause = message.pause_symbols + 1; pause = message.pause_symbols + 1;