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,
0x0C, 0x18,
0x03, 0x60,
0xE0, 0x83,
0xE0, 0x03,
0x18, 0x0C,
0x04, 0x10,
0xC0, 0x01,

View File

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

View File

@ -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

View File

@ -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<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
for (i = 0; i < ENC_TYPES_COUNT; 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_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"

View File

@ -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&){

View File

@ -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<const TXDoneMessage*>(p);
if (message.done)
transmit_done();
}
};
};
} /* namespace ui */

View File

@ -279,7 +279,7 @@ ReceiverMenuView::ReceiverMenuView(NavigationView& nav) {
// { "AFSK", ui::Color::grey(), nullptr, [&nav](){ nav.push<NotImplementedView>(); } }, // AFSKRXView
{ "Audio", ui::Color::green(), nullptr, [&nav](){ nav.push<AnalogAudioView>(); } },
{ "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>(); } },
{ "SIGFOX", ui::Color::grey(), &bitmap_icon_foxhunt, [&nav](){ nav.push<NotImplementedView>(); } }, // SIGFRXView
{ "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_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 {

View File

@ -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 */

View File

@ -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__*/