Added waveform widget and a frequency field in encoders tx

This commit is contained in:
furrtek 2017-01-09 02:45:29 +00:00
parent be3d477352
commit a0c248d567
11 changed files with 180 additions and 72 deletions

View File

@ -172,7 +172,7 @@ static constexpr uint8_t bitmap_icon_codetx_data[] = {
0xF0, 0x07, 0xF0, 0x07,
0x0C, 0x18, 0x0C, 0x18,
0x03, 0x60, 0x03, 0x60,
0xE0, 0x83, 0xE0, 0x03,
0x18, 0x0C, 0x18, 0x0C,
0x04, 0x10, 0x04, 0x10,
0xC0, 0x01, 0xC0, 0x01,

View File

@ -109,7 +109,7 @@ namespace encoders {
// HK526E // HK526E
{ {
"526 ", "526E ",
"01", "01", "01", "01",
24, 8, 24, 8,
{ "110", "100" }, { "110", "100" },

View File

@ -28,10 +28,10 @@
//TEST: Jammer //TEST: Jammer
//TEST: Frequency manager + save/load //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: Morse coder for foxhunts
//TODO: Finish EPAR tx //TODO: Finish EPAR tx
//TODO: IQ replay //TODO: IQ replay
//TODO: Waveform widget ?
//TODO: Wav visualizer //TODO: Wav visualizer
//BUG: POCSAG RX sometimes misses the first codeword after SYNC //BUG: POCSAG RX sometimes misses the first codeword after SYNC

View File

@ -61,34 +61,21 @@ void EncodersView::generate_frame() {
} }
void EncodersView::draw_waveform() { void EncodersView::draw_waveform() {
float x = 0, x_inc; uint32_t n, p = 0, length;
Coord y, prev_y = 1;
uint8_t prelude_length = 0; //encoder_def->sync.length();
// Clear length = debug_text.length();
painter_->fill_rectangle( { 0, 168, 240, 24 }, Color::black() );
x_inc = 230.0 / (debug_text.length() - prelude_length); for (n = 0; n < length; n++) {
if (debug_text[n] == '0')
for (auto c : debug_text) { //.substr(prelude_length) waveform_buffer[p] = -128;
if (c == '0')
y = 23;
else else
y = 0; waveform_buffer[p] = 127;
waveform_buffer[p + 1] = waveform_buffer[p];
// Edge p += 2;
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;
} }
}
void EncodersView::paint(Painter& painter) { waveform.set_length(length * 2);
painter_ = &painter; waveform.set_dirty();
draw_waveform();
} }
void EncodersView::update_progress() { 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) { void EncodersView::start_tx(const bool scan) {
char ook_bitstream[256]; char ook_bitstream[256];
uint32_t ook_bitstream_length; uint32_t ook_bitstream_length;
@ -198,7 +189,6 @@ void EncodersView::start_tx(const bool scan) {
ook_bitstream_length = n; ook_bitstream_length = n;
transmitter_model.set_tuning_frequency(433920000); // TODO: Make modifiable !
transmitter_model.set_baseband_configuration({ transmitter_model.set_baseband_configuration({
.mode = 0, .mode = 0,
.sampling_rate = 2280000U, .sampling_rate = 2280000U,
@ -318,6 +308,7 @@ EncodersView::EncodersView(NavigationView& nav) {
encoder_def = &encoder_defs[0]; encoder_def = &encoder_defs[0];
add_children({ { add_children({ {
&field_frequency,
&text_enctype, &text_enctype,
&options_enctype, &options_enctype,
&text_clk, &text_clk,
@ -335,11 +326,26 @@ EncodersView::EncodersView(NavigationView& nav) {
//&text_format_a, // DEBUG //&text_format_a, // DEBUG
//&text_format_d, // DEBUG //&text_format_d, // DEBUG
&text_waveform, &text_waveform,
&waveform,
&text_status, &text_status,
&progress, &progress,
&button_transmit &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<FrequencyKeypadView>(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 // Load encoder types
for (i = 0; i < ENC_TYPES_COUNT; i++) for (i = 0; i < ENC_TYPES_COUNT; i++)
enc_options.emplace_back(std::make_pair(encoder_defs[i].name, i)); enc_options.emplace_back(std::make_pair(encoder_defs[i].name, i));

View File

@ -24,6 +24,7 @@
#include "ui_widget.hpp" #include "ui_widget.hpp"
#include "ui_navigation.hpp" #include "ui_navigation.hpp"
#include "ui_font_fixed_8x16.hpp" #include "ui_font_fixed_8x16.hpp"
#include "ui_receiver.hpp"
#include "encoders.hpp" #include "encoders.hpp"
#include "message.hpp" #include "message.hpp"
#include "transmitter_model.hpp" #include "transmitter_model.hpp"
@ -39,18 +40,18 @@ public:
void focus() override; void focus() override;
void on_show() override; void on_show() override;
void paint(Painter& painter) override;
std::string title() const override { return "Encoders TX"; }; std::string title() const override { return "Encoders TX"; };
private: private:
void on_tuning_frequency_changed(rf::Frequency f);
enum tx_modes { enum tx_modes {
IDLE = 0, IDLE = 0,
SINGLE, SINGLE,
SCAN SCAN
}; };
Painter * painter_;
uint8_t enc_type = 0; uint8_t enc_type = 0;
const encoder_def_t * encoder_def; const encoder_def_t * encoder_def;
tx_modes tx_mode = IDLE; tx_modes tx_mode = IDLE;
@ -59,8 +60,8 @@ private:
//double scan_progress; //double scan_progress;
//unsigned int scan_index; //unsigned int scan_index;
std::string debug_text = "0"; std::string debug_text = "0";
//rf::Frequency f;
uint8_t repeat_index; uint8_t repeat_index;
int8_t waveform_buffer[512];
void draw_waveform(); void draw_waveform();
void on_bitfield(); void on_bitfield();
@ -92,75 +93,79 @@ private:
.foreground = Color::blue(), .foreground = Color::blue(),
}; };
FrequencyField field_frequency {
{ 1 * 8, 4 },
};
Text text_enctype { Text text_enctype {
{ 1 * 8, 24, 5 * 8, 16 }, { 1 * 8, 32, 5 * 8, 16 },
"Type:" "Type:"
}; };
OptionsField options_enctype { // Options are loaded at runtime OptionsField options_enctype { // Options are loaded at runtime
{ 6 * 8, 24 }, { 6 * 8, 32 },
7, 7,
{ {
} }
}; };
Text text_clk { Text text_clk {
{ 16 * 8, 3 * 8, 4 * 8, 16 }, { 16 * 8, 4 * 8, 4 * 8, 16 },
"Clk:" "Clk:"
}; };
NumberField numberfield_clk { NumberField numberfield_clk {
{ 21 * 8, 3 * 8 }, { 21 * 8, 4 * 8 },
3, 3,
{ 1, 500 }, { 1, 500 },
1, 1,
' ' ' '
}; };
Text text_kHz { Text text_kHz {
{ 24 * 8, 3 * 8, 3 * 8, 16 }, { 24 * 8, 4 * 8, 3 * 8, 16 },
"kHz" "kHz"
}; };
Text text_bitduration { Text text_bitduration {
{ 16 * 8, 5 * 8, 4 * 8, 16 }, { 16 * 8, 6 * 8, 4 * 8, 16 },
"Bit:" "Bit:"
}; };
NumberField numberfield_bitduration { NumberField numberfield_bitduration {
{ 21 * 8, 5 * 8 }, { 21 * 8, 6 * 8 },
4, 4,
{ 50, 9999 }, { 50, 9999 },
1, 1,
' ' ' '
}; };
Text text_us1 { Text text_us1 {
{ 25 * 8, 5 * 8, 2 * 8, 16 }, { 25 * 8, 6 * 8, 2 * 8, 16 },
"us" "us"
}; };
Text text_wordduration { Text text_wordduration {
{ 15 * 8, 7 * 8, 5 * 8, 16 }, { 15 * 8, 8 * 8, 5 * 8, 16 },
"Word:" "Word:"
}; };
NumberField numberfield_wordduration { NumberField numberfield_wordduration {
{ 21 * 8, 7 * 8 }, { 21 * 8, 8 * 8 },
5, 5,
{ 300, 99999 }, { 300, 99999 },
100, 100,
' ' ' '
}; };
Text text_us2 { Text text_us2 {
{ 26 * 8, 7 * 8, 2 * 8, 16 }, { 26 * 8, 8 * 8, 2 * 8, 16 },
"us" "us"
}; };
Text text_symfield { Text text_symfield {
{ 2 * 8, 9 * 8, 5 * 8, 16 }, { 2 * 8, 10 * 8, 5 * 8, 16 },
"Word:" "Word:"
}; };
SymField symfield_word { SymField symfield_word {
{ 2 * 8, 11 * 8 }, { 2 * 8, 12 * 8 },
20 20
}; };
Text text_format { 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 waveform {
{ 0, 160, 240, 32 },
waveform_buffer,
0,
0,
Color::yellow()
};
Text text_status { Text text_status {
{ 2 * 8, 224, 128, 16 }, { 2 * 8, 224, 128, 16 },
"Ready" "Ready"

View File

@ -39,7 +39,6 @@ Continuous (Fox-oring)
using namespace portapack; using namespace portapack;
// TODO: TX power setting
// TODO: Live keying mode: Dit on left key, dah on right ? // TODO: Live keying mode: Dit on left key, dah on right ?
namespace ui { namespace ui {
@ -98,10 +97,26 @@ void MorseView::generate_message(char * text) {
(*tone_defs).delta = 0; // 7 unit silence (*tone_defs).delta = 0; // 7 unit silence
(*tone_defs++).duration = MORSE_WORD_SPACE; (*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); baseband::set_tones_data(5000, 0, i, false, false);
} }
void MorseView::transmit_done() {
transmitter_model.disable();
}
MorseView::MorseView( MorseView::MorseView(
NavigationView& nav NavigationView& nav
) )
@ -114,25 +129,8 @@ MorseView::MorseView(
} }); } });
button_transmit.on_select = [this](Button&){ button_transmit.on_select = [this](Button&){
/*uint16_t c; //char strtest[] = "TEST";
ui::Context context; //generate_message(strtest);
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();
}; };
button_exit.on_select = [&nav](Button&){ button_exit.on_select = [&nav](Button&){

View File

@ -28,7 +28,6 @@
#include "message.hpp" #include "message.hpp"
#include "volume.hpp" #include "volume.hpp"
#include "audio.hpp" #include "audio.hpp"
//#include "transmitter_model.hpp"
#include "receiver_model.hpp" #include "receiver_model.hpp"
#include "portapack.hpp" #include "portapack.hpp"
@ -54,6 +53,7 @@ private:
//rf::Frequency f; //rf::Frequency f;
void generate_message(char * text); void generate_message(char * text);
void transmit_done();
const char foxhunt_codes[11][3] = { const char foxhunt_codes[11][3] = {
{ 'M', 'O', 'E' }, // -----. { 'M', 'O', 'E' }, // -----.
@ -192,6 +192,15 @@ private:
{ 160, 260, 64, 32 }, { 160, 260, 64, 32 },
"Exit" "Exit"
}; };
MessageHandlerRegistration message_handler_tx_done {
Message::ID::TXDone,
[this](const Message* const p) {
const auto message = *reinterpret_cast<const TXDoneMessage*>(p);
if (message.done)
transmit_done();
}
};
}; };
} /* namespace ui */ } /* namespace ui */

View File

@ -279,7 +279,7 @@ ReceiverMenuView::ReceiverMenuView(NavigationView& nav) {
// { "AFSK", ui::Color::grey(), nullptr, [&nav](){ nav.push<NotImplementedView>(); } }, // AFSKRXView // { "AFSK", ui::Color::grey(), nullptr, [&nav](){ nav.push<NotImplementedView>(); } }, // AFSKRXView
{ "Audio", ui::Color::green(), nullptr, [&nav](){ nav.push<AnalogAudioView>(); } }, { "Audio", ui::Color::green(), nullptr, [&nav](){ nav.push<AnalogAudioView>(); } },
{ "CCIR", ui::Color::grey(), nullptr, [&nav](){ nav.push<NotImplementedView>(); } }, { "CCIR", ui::Color::grey(), nullptr, [&nav](){ nav.push<NotImplementedView>(); } },
{ "Nordic/BTLE", ui::Color::grey(), &bitmap_icon_nordic_data, [&nav](){ nav.push<NotImplementedView>(); } }, { "Nordic/BTLE", ui::Color::grey(), &bitmap_icon_nordic, [&nav](){ nav.push<NotImplementedView>(); } },
{ "POCSAG 1200", ui::Color::cyan(), nullptr, [&nav](){ nav.push<POCSAGAppView>(); } }, { "POCSAG 1200", ui::Color::cyan(), nullptr, [&nav](){ nav.push<POCSAGAppView>(); } },
{ "SIGFOX", ui::Color::grey(), &bitmap_icon_foxhunt, [&nav](){ nav.push<NotImplementedView>(); } }, // SIGFRXView { "SIGFOX", ui::Color::grey(), &bitmap_icon_foxhunt, [&nav](){ nav.push<NotImplementedView>(); } }, // SIGFRXView
{ "Transponders", ui::Color::green(), nullptr, [&nav](){ nav.push<TranspondersMenuView>(); } }, { "Transponders", ui::Color::green(), nullptr, [&nav](){ nav.push<TranspondersMenuView>(); } },

View File

@ -44,7 +44,7 @@
#define DTMF_R2 (uint32_t)(852 * DTMF_DELTA_COEF) #define DTMF_R2 (uint32_t)(852 * DTMF_DELTA_COEF)
#define DTMF_R3 (uint32_t)(941 * 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 { namespace ui {

View File

@ -1285,4 +1285,66 @@ int32_t SymField::clip_value(const uint32_t index, const uint32_t value) {
return 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 */ } /* namespace ui */

View File

@ -481,6 +481,26 @@ private:
int32_t clip_value(const uint32_t index, const uint32_t value); 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 */ } /* namespace ui */
#endif/*__UI_WIDGET_H__*/ #endif/*__UI_WIDGET_H__*/