mirror of
https://github.com/eried/portapack-mayhem.git
synced 2024-10-01 01:26:06 -04:00
Added waveform widget and a frequency field in encoders tx
This commit is contained in:
parent
be3d477352
commit
a0c248d567
@ -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,
|
||||
|
@ -109,7 +109,7 @@ namespace encoders {
|
||||
|
||||
// HK526E
|
||||
{
|
||||
"526 ",
|
||||
"526E ",
|
||||
"01", "01",
|
||||
24, 8,
|
||||
{ "110", "100" },
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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"
|
||||
|
@ -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&){
|
||||
|
@ -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 */
|
||||
|
@ -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>(); } },
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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__*/
|
||||
|
Loading…
Reference in New Issue
Block a user