From a0c248d567682fa27ed9339abc5860ab3b878b9c Mon Sep 17 00:00:00 2001 From: furrtek Date: Mon, 9 Jan 2017 02:45:29 +0000 Subject: [PATCH] Added waveform widget and a frequency field in encoders tx --- firmware/application/bitmap.hpp | 2 +- firmware/application/encoders.hpp | 2 +- firmware/application/main.cpp | 2 +- firmware/application/ui_encoders.cpp | 62 ++++++++++++++------------ firmware/application/ui_encoders.hpp | 47 ++++++++++++------- firmware/application/ui_morse.cpp | 40 ++++++++--------- firmware/application/ui_morse.hpp | 11 ++++- firmware/application/ui_navigation.cpp | 2 +- firmware/application/ui_nuoptix.hpp | 2 +- firmware/common/ui_widget.cpp | 62 ++++++++++++++++++++++++++ firmware/common/ui_widget.hpp | 20 +++++++++ 11 files changed, 180 insertions(+), 72 deletions(-) diff --git a/firmware/application/bitmap.hpp b/firmware/application/bitmap.hpp index 90c5cbf5..b6bdef75 100644 --- a/firmware/application/bitmap.hpp +++ b/firmware/application/bitmap.hpp @@ -172,7 +172,7 @@ static constexpr uint8_t bitmap_icon_codetx_data[] = { 0xF0, 0x07, 0x0C, 0x18, 0x03, 0x60, - 0xE0, 0x83, + 0xE0, 0x03, 0x18, 0x0C, 0x04, 0x10, 0xC0, 0x01, diff --git a/firmware/application/encoders.hpp b/firmware/application/encoders.hpp index e89ca20b..2d59443e 100644 --- a/firmware/application/encoders.hpp +++ b/firmware/application/encoders.hpp @@ -109,7 +109,7 @@ namespace encoders { // HK526E { - "526 ", + "526E ", "01", "01", 24, 8, { "110", "100" }, diff --git a/firmware/application/main.cpp b/firmware/application/main.cpp index bbfd06a8..e14348d6 100755 --- a/firmware/application/main.cpp +++ b/firmware/application/main.cpp @@ -28,10 +28,10 @@ //TEST: Jammer //TEST: Frequency manager + save/load +//TODO: "TX box" view or composite widget with frequency and bw settings, simple and advanced setup TX buttons... //TODO: Morse coder for foxhunts //TODO: Finish EPAR tx //TODO: IQ replay -//TODO: Waveform widget ? //TODO: Wav visualizer //BUG: POCSAG RX sometimes misses the first codeword after SYNC diff --git a/firmware/application/ui_encoders.cpp b/firmware/application/ui_encoders.cpp index b9bd8171..810b5370 100644 --- a/firmware/application/ui_encoders.cpp +++ b/firmware/application/ui_encoders.cpp @@ -61,34 +61,21 @@ void EncodersView::generate_frame() { } void EncodersView::draw_waveform() { - float x = 0, x_inc; - Coord y, prev_y = 1; - uint8_t prelude_length = 0; //encoder_def->sync.length(); - - // Clear - painter_->fill_rectangle( { 0, 168, 240, 24 }, Color::black() ); - - x_inc = 230.0 / (debug_text.length() - prelude_length); - - for (auto c : debug_text) { //.substr(prelude_length) - if (c == '0') - y = 23; - else - y = 0; - - // Edge - if (prev_y != y) painter_->draw_rectangle( { (Coord)x, 168, 1, 24 }, Color::yellow() ); - // Level - painter_->draw_rectangle( { (Coord)x, 168 + y, (int)ceil(x_inc), 1 }, Color::yellow() ); - - prev_y = y; - x += x_inc; - } -} + uint32_t n, p = 0, length; -void EncodersView::paint(Painter& painter) { - painter_ = &painter; - draw_waveform(); + length = debug_text.length(); + + for (n = 0; n < length; n++) { + if (debug_text[n] == '0') + waveform_buffer[p] = -128; + else + waveform_buffer[p] = 127; + waveform_buffer[p + 1] = waveform_buffer[p]; + p += 2; + } + + waveform.set_length(length * 2); + waveform.set_dirty(); } void EncodersView::update_progress() { @@ -162,6 +149,10 @@ 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; @@ -198,7 +189,6 @@ void EncodersView::start_tx(const bool scan) { ook_bitstream_length = n; - transmitter_model.set_tuning_frequency(433920000); // TODO: Make modifiable ! transmitter_model.set_baseband_configuration({ .mode = 0, .sampling_rate = 2280000U, @@ -318,6 +308,7 @@ EncodersView::EncodersView(NavigationView& nav) { encoder_def = &encoder_defs[0]; add_children({ { + &field_frequency, &text_enctype, &options_enctype, &text_clk, @@ -335,11 +326,26 @@ EncodersView::EncodersView(NavigationView& nav) { //&text_format_a, // DEBUG //&text_format_d, // DEBUG &text_waveform, + &waveform, &text_status, &progress, &button_transmit } }); + field_frequency.set_value(transmitter_model.tuning_frequency()); + field_frequency.set_step(50000); + field_frequency.on_change = [this](rf::Frequency f) { + this->on_tuning_frequency_changed(f); + }; + field_frequency.on_edit = [this, &nav]() { + // TODO: Provide separate modal method/scheme? + auto new_view = nav.push(transmitter_model.tuning_frequency()); + new_view->on_changed = [this](rf::Frequency f) { + this->on_tuning_frequency_changed(f); + this->field_frequency.set_value(f); + }; + }; + // Load encoder types for (i = 0; i < ENC_TYPES_COUNT; i++) enc_options.emplace_back(std::make_pair(encoder_defs[i].name, i)); diff --git a/firmware/application/ui_encoders.hpp b/firmware/application/ui_encoders.hpp index a3d9b9c8..8bb9124a 100644 --- a/firmware/application/ui_encoders.hpp +++ b/firmware/application/ui_encoders.hpp @@ -24,6 +24,7 @@ #include "ui_widget.hpp" #include "ui_navigation.hpp" #include "ui_font_fixed_8x16.hpp" +#include "ui_receiver.hpp" #include "encoders.hpp" #include "message.hpp" #include "transmitter_model.hpp" @@ -39,18 +40,18 @@ public: void focus() override; void on_show() override; - void paint(Painter& painter) override; std::string title() const override { return "Encoders TX"; }; private: + void on_tuning_frequency_changed(rf::Frequency f); + enum tx_modes { IDLE = 0, SINGLE, SCAN }; - Painter * painter_; uint8_t enc_type = 0; const encoder_def_t * encoder_def; tx_modes tx_mode = IDLE; @@ -59,8 +60,8 @@ private: //double scan_progress; //unsigned int scan_index; std::string debug_text = "0"; - //rf::Frequency f; uint8_t repeat_index; + int8_t waveform_buffer[512]; void draw_waveform(); void on_bitfield(); @@ -92,75 +93,79 @@ private: .foreground = Color::blue(), }; + FrequencyField field_frequency { + { 1 * 8, 4 }, + }; + Text text_enctype { - { 1 * 8, 24, 5 * 8, 16 }, + { 1 * 8, 32, 5 * 8, 16 }, "Type:" }; OptionsField options_enctype { // Options are loaded at runtime - { 6 * 8, 24 }, + { 6 * 8, 32 }, 7, { } }; Text text_clk { - { 16 * 8, 3 * 8, 4 * 8, 16 }, + { 16 * 8, 4 * 8, 4 * 8, 16 }, "Clk:" }; NumberField numberfield_clk { - { 21 * 8, 3 * 8 }, + { 21 * 8, 4 * 8 }, 3, { 1, 500 }, 1, ' ' }; Text text_kHz { - { 24 * 8, 3 * 8, 3 * 8, 16 }, + { 24 * 8, 4 * 8, 3 * 8, 16 }, "kHz" }; Text text_bitduration { - { 16 * 8, 5 * 8, 4 * 8, 16 }, + { 16 * 8, 6 * 8, 4 * 8, 16 }, "Bit:" }; NumberField numberfield_bitduration { - { 21 * 8, 5 * 8 }, + { 21 * 8, 6 * 8 }, 4, { 50, 9999 }, 1, ' ' }; Text text_us1 { - { 25 * 8, 5 * 8, 2 * 8, 16 }, + { 25 * 8, 6 * 8, 2 * 8, 16 }, "us" }; Text text_wordduration { - { 15 * 8, 7 * 8, 5 * 8, 16 }, + { 15 * 8, 8 * 8, 5 * 8, 16 }, "Word:" }; NumberField numberfield_wordduration { - { 21 * 8, 7 * 8 }, + { 21 * 8, 8 * 8 }, 5, { 300, 99999 }, 100, ' ' }; Text text_us2 { - { 26 * 8, 7 * 8, 2 * 8, 16 }, + { 26 * 8, 8 * 8, 2 * 8, 16 }, "us" }; Text text_symfield { - { 2 * 8, 9 * 8, 5 * 8, 16 }, + { 2 * 8, 10 * 8, 5 * 8, 16 }, "Word:" }; SymField symfield_word { - { 2 * 8, 11 * 8 }, + { 2 * 8, 12 * 8 }, 20 }; Text text_format { - { 2 * 8, 13 * 8, 24 * 8, 16 }, + { 2 * 8, 14 * 8, 24 * 8, 16 }, "" }; @@ -172,6 +177,14 @@ private: "Waveform:" }; + Waveform waveform { + { 0, 160, 240, 32 }, + waveform_buffer, + 0, + 0, + Color::yellow() + }; + Text text_status { { 2 * 8, 224, 128, 16 }, "Ready" diff --git a/firmware/application/ui_morse.cpp b/firmware/application/ui_morse.cpp index 83dd5613..4806bb32 100644 --- a/firmware/application/ui_morse.cpp +++ b/firmware/application/ui_morse.cpp @@ -39,7 +39,6 @@ Continuous (Fox-oring) using namespace portapack; -// TODO: TX power setting // TODO: Live keying mode: Dit on left key, dah on right ? namespace ui { @@ -98,10 +97,26 @@ void MorseView::generate_message(char * text) { (*tone_defs).delta = 0; // 7 unit silence (*tone_defs++).duration = MORSE_WORD_SPACE; - audio::set_rate(audio::Rate::Hz_24000); + transmitter_model.set_tuning_frequency(81800000); + transmitter_model.set_baseband_configuration({ + .mode = 0, + .sampling_rate = 1536000U, + .decimation_factor = 1, + }); + transmitter_model.set_rf_amp(true); + transmitter_model.set_lna(40); + transmitter_model.set_vga(40); + transmitter_model.set_baseband_bandwidth(1750000); + transmitter_model.enable(); + + //audio::set_rate(audio::Rate::Hz_24000); baseband::set_tones_data(5000, 0, i, false, false); } +void MorseView::transmit_done() { + transmitter_model.disable(); +} + MorseView::MorseView( NavigationView& nav ) @@ -114,25 +129,8 @@ MorseView::MorseView( } }); button_transmit.on_select = [this](Button&){ - /*uint16_t c; - ui::Context context; - - make_frame(); - - shared_memory.afsk_samples_per_bit = 228000/persistent_memory::afsk_bitrate(); - shared_memory.afsk_phase_inc_mark = persistent_memory::afsk_mark_freq()*(65536*1024)/2280; - shared_memory.afsk_phase_inc_space = persistent_memory::afsk_space_freq()*(65536*1024)/2280; - - for (c = 0; c < 256; c++) { - shared_memory.lcrdata[c] = this->lcrframe[c]; - } - - shared_memory.afsk_transmit_done = false; - shared_memory.afsk_repeat = 5; // DEFAULT - - text_status.set("Send...");*/ - - //transmitter_model.enable(); + //char strtest[] = "TEST"; + //generate_message(strtest); }; button_exit.on_select = [&nav](Button&){ diff --git a/firmware/application/ui_morse.hpp b/firmware/application/ui_morse.hpp index aebf709a..9d7ff2b1 100644 --- a/firmware/application/ui_morse.hpp +++ b/firmware/application/ui_morse.hpp @@ -28,7 +28,6 @@ #include "message.hpp" #include "volume.hpp" #include "audio.hpp" -//#include "transmitter_model.hpp" #include "receiver_model.hpp" #include "portapack.hpp" @@ -54,6 +53,7 @@ private: //rf::Frequency f; void generate_message(char * text); + void transmit_done(); const char foxhunt_codes[11][3] = { { 'M', 'O', 'E' }, // -----. @@ -192,6 +192,15 @@ private: { 160, 260, 64, 32 }, "Exit" }; + + MessageHandlerRegistration message_handler_tx_done { + Message::ID::TXDone, + [this](const Message* const p) { + const auto message = *reinterpret_cast(p); + if (message.done) + transmit_done(); + } + }; }; } /* namespace ui */ diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 812913f1..b2e75941 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -279,7 +279,7 @@ ReceiverMenuView::ReceiverMenuView(NavigationView& nav) { // { "AFSK", ui::Color::grey(), nullptr, [&nav](){ nav.push(); } }, // AFSKRXView { "Audio", ui::Color::green(), nullptr, [&nav](){ nav.push(); } }, { "CCIR", ui::Color::grey(), nullptr, [&nav](){ nav.push(); } }, - { "Nordic/BTLE", ui::Color::grey(), &bitmap_icon_nordic_data, [&nav](){ nav.push(); } }, + { "Nordic/BTLE", ui::Color::grey(), &bitmap_icon_nordic, [&nav](){ nav.push(); } }, { "POCSAG 1200", ui::Color::cyan(), nullptr, [&nav](){ nav.push(); } }, { "SIGFOX", ui::Color::grey(), &bitmap_icon_foxhunt, [&nav](){ nav.push(); } }, // SIGFRXView { "Transponders", ui::Color::green(), nullptr, [&nav](){ nav.push(); } }, diff --git a/firmware/application/ui_nuoptix.hpp b/firmware/application/ui_nuoptix.hpp index 7f4c0658..6afe5462 100644 --- a/firmware/application/ui_nuoptix.hpp +++ b/firmware/application/ui_nuoptix.hpp @@ -44,7 +44,7 @@ #define DTMF_R2 (uint32_t)(852 * DTMF_DELTA_COEF) #define DTMF_R3 (uint32_t)(941 * DTMF_DELTA_COEF) -#define NUOPTIX_TONE_LENGTH 75264 // 1536000*0.049 +#define NUOPTIX_TONE_LENGTH 75264 // 1536000*0.049s namespace ui { diff --git a/firmware/common/ui_widget.cpp b/firmware/common/ui_widget.cpp index c05dba72..c934e738 100644 --- a/firmware/common/ui_widget.cpp +++ b/firmware/common/ui_widget.cpp @@ -1285,4 +1285,66 @@ int32_t SymField::clip_value(const uint32_t index, const uint32_t value) { return value; } +/* Waveform **************************************************************/ + +Waveform::Waveform( + Rect parent_rect, + int8_t * data, + uint32_t length, + uint32_t offset, + Color color +) : Widget { parent_rect }, + data_ { data }, + length_ { length }, + offset_ { offset }, + color_ { color } +{ + data_ += offset_; + //set_focusable(false); +} + +void Waveform::set_offset(const uint32_t new_offset) { + if (new_offset != offset_) { + offset_ = new_offset; + set_dirty(); + } +} + +void Waveform::set_length(const uint32_t new_length) { + if (new_length != length_) { + length_ = new_length; + set_dirty(); + } +} + +void Waveform::paint(Painter& painter) { + uint32_t n, point_count; + Coord y, y_offset = screen_rect().pos.y; + Coord prev_x = screen_rect().pos.x, prev_y; + float x, x_inc; + Dim h = screen_rect().size.h; + + // Clear + painter.fill_rectangle(screen_rect(), Color::black()); + + x_inc = (float)screen_rect().size.w / length_; + point_count = length_; + const float y_scale = (float)(h - 1) / 256; // TODO: Make variable + + if (!point_count) return; + + x = prev_x + x_inc; + h = h / 2; + + prev_y = y_offset + h - (*(data_) * y_scale); + for (n = 1; n < point_count; n++) { + y = y_offset + h - (*(data_ + n) * y_scale); + display.draw_line( {prev_x, prev_y}, {(Coord)x, y}, color_); + + prev_x = x; + prev_y = y; + x += x_inc; + } +} + } /* namespace ui */ diff --git a/firmware/common/ui_widget.hpp b/firmware/common/ui_widget.hpp index 54582d4f..efbcf50e 100644 --- a/firmware/common/ui_widget.hpp +++ b/firmware/common/ui_widget.hpp @@ -481,6 +481,26 @@ private: int32_t clip_value(const uint32_t index, const uint32_t value); }; +class Waveform : public Widget { +public: + + Waveform(Rect parent_rect, int8_t * data, uint32_t length, uint32_t offset, Color color); + + Waveform(const Waveform&) = delete; + Waveform(Waveform&&) = delete; + + void set_offset(const uint32_t new_offset); + void set_length(const uint32_t new_length); + + void paint(Painter& painter) override; + +private: + int8_t * data_; + uint32_t length_; + uint32_t offset_; + Color color_; +}; + } /* namespace ui */ #endif/*__UI_WIDGET_H__*/