mirror of
https://github.com/eried/portapack-mayhem.git
synced 2025-03-10 00:39:19 -04:00
Finally found what was eating all the RAM :D
Re-enabled the tone key selector in Soundboard Soundboard now uses OutputStream, like Replay Constexpr'd a bunch of consts which were going to BSS section Exiting an app now goes back to main menu Cleaned up Message array
This commit is contained in:
parent
2d3a6313cc
commit
b29c1d9749
@ -217,7 +217,7 @@ set(CPPSRC
|
|||||||
apps/ui_aprs_tx.cpp
|
apps/ui_aprs_tx.cpp
|
||||||
apps/ui_bht_tx.cpp
|
apps/ui_bht_tx.cpp
|
||||||
apps/ui_coasterp.cpp
|
apps/ui_coasterp.cpp
|
||||||
apps/ui_debug.cpp
|
# apps/ui_debug.cpp
|
||||||
apps/ui_encoders.cpp
|
apps/ui_encoders.cpp
|
||||||
apps/ui_fileman.cpp
|
apps/ui_fileman.cpp
|
||||||
apps/ui_freqman.cpp
|
apps/ui_freqman.cpp
|
||||||
|
@ -142,7 +142,7 @@ void POCSAGAppView::on_packet(const POCSAGPacketMessage * message) {
|
|||||||
std::string alphanum_text = "";
|
std::string alphanum_text = "";
|
||||||
|
|
||||||
if (message->packet.flag() != NORMAL)
|
if (message->packet.flag() != NORMAL)
|
||||||
console.writeln("\n\x1B\x0CRX ERROR: " + pocsag::flag_str(message->packet.flag()));
|
console.writeln("\n\x1B\x0CRC ERROR: " + pocsag::flag_str(message->packet.flag()));
|
||||||
else {
|
else {
|
||||||
pocsag_decode_batch(message->packet, &pocsag_state);
|
pocsag_decode_batch(message->packet, &pocsag_state);
|
||||||
|
|
||||||
|
@ -161,6 +161,8 @@ void ReplayAppView::stop(const bool do_loop) {
|
|||||||
radio::disable();
|
radio::disable();
|
||||||
button_play.set_bitmap(&bitmap_play);
|
button_play.set_bitmap(&bitmap_play);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ready_signal = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReplayAppView::handle_replay_thread_done(const uint32_t return_code) {
|
void ReplayAppView::handle_replay_thread_done(const uint32_t return_code) {
|
||||||
|
@ -62,10 +62,11 @@ void CreditsWidget::on_hide() {
|
|||||||
void CreditsWidget::new_row(
|
void CreditsWidget::new_row(
|
||||||
const std::array<Color, 240>& pixel_row
|
const std::array<Color, 240>& pixel_row
|
||||||
) {
|
) {
|
||||||
|
// Glitch be here (see comment in main.cpp)
|
||||||
const auto draw_y = display.scroll(-1);
|
const auto draw_y = display.scroll(-1);
|
||||||
|
|
||||||
display.draw_pixels(
|
display.draw_pixels(
|
||||||
{ { 0, draw_y }, { 240, 1 } },
|
{ { 0, draw_y - 1 }, { 240, 1 } },
|
||||||
pixel_row
|
pixel_row
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ void EncodersConfigView::on_type_change(size_t index) {
|
|||||||
symfield_word.set_length(word_length);
|
symfield_word.set_length(word_length);
|
||||||
size_t n = 0, i = 0;
|
size_t n = 0, i = 0;
|
||||||
while (n < word_length) {
|
while (n < word_length) {
|
||||||
symbol_type = encoder_def->word_format.at(i++);
|
symbol_type = encoder_def->word_format[i++];
|
||||||
if (symbol_type == 'A') {
|
if (symbol_type == 'A') {
|
||||||
symfield_word.set_symbol_list(n++, encoder_def->address_symbols);
|
symfield_word.set_symbol_list(n++, encoder_def->address_symbols);
|
||||||
format_string += 'A';
|
format_string += 'A';
|
||||||
|
@ -51,11 +51,11 @@ void MicTXView::on_tx_progress(const bool done) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MicTXView::configure_baseband() {
|
void MicTXView::configure_baseband() {
|
||||||
baseband::set_audiotx_data(
|
baseband::set_audiotx_config(
|
||||||
sampling_rate / 20, // Update vu-meter at 20Hz
|
sampling_rate / 20, // Update vu-meter at 20Hz
|
||||||
transmitting ? transmitter_model.channel_bandwidth() : 0,
|
transmitting ? transmitter_model.channel_bandwidth() : 0,
|
||||||
mic_gain,
|
mic_gain,
|
||||||
TONES_F2D(tone_key_frequency(tone_key_index)),
|
TONES_F2D(tone_key_frequency(tone_key_index), sampling_rate),
|
||||||
0.2 // 20% mix
|
0.2 // 20% mix
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
// To prepare samples: for f in ./*.wav; do sox "$f" -r 48000 -c 1 -b8 --norm "conv/$f"; done
|
// To prepare samples: for f in ./*.wav; do sox "$f" -r 48000 -c 1 -b8 --norm "conv/$f"; done
|
||||||
|
|
||||||
#include "ui_soundboard.hpp"
|
#include "ui_soundboard.hpp"
|
||||||
|
|
||||||
#include "lfsr_random.hpp"
|
#include "lfsr_random.hpp"
|
||||||
#include "string_format.hpp"
|
#include "string_format.hpp"
|
||||||
#include "tonesets.hpp"
|
#include "tonesets.hpp"
|
||||||
@ -33,6 +32,7 @@ using namespace portapack;
|
|||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
|
// TODO: Use Sharebrained's PRNG
|
||||||
void SoundBoardView::do_random() {
|
void SoundBoardView::do_random() {
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
|
|
||||||
@ -43,45 +43,42 @@ void SoundBoardView::do_random() {
|
|||||||
|
|
||||||
play_sound(id);
|
play_sound(id);
|
||||||
|
|
||||||
buttons[id % 18].focus();
|
buttons[id % 15].focus();
|
||||||
page = id / 18;
|
page = id / 15;
|
||||||
|
|
||||||
refresh_buttons(id);
|
refresh_buttons(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundBoardView::prepare_audio() {
|
bool SoundBoardView::is_active() const {
|
||||||
|
return (bool)replay_thread;
|
||||||
|
}
|
||||||
|
|
||||||
if (sample_counter >= sample_duration) {
|
void SoundBoardView::stop(const bool do_loop) {
|
||||||
if (tx_mode == NORMAL) {
|
if( is_active() )
|
||||||
if (!check_loop.value()) {
|
replay_thread.reset();
|
||||||
pbar.set_value(0);
|
|
||||||
transmitter_model.disable();
|
if (do_loop && check_loop.value()) {
|
||||||
return;
|
play_sound(playing_id);
|
||||||
} else {
|
} else {
|
||||||
reader->rewind();
|
radio::disable();
|
||||||
sample_counter = 0;
|
//button_play.set_bitmap(&bitmap_play);
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pbar.set_value(0);
|
|
||||||
transmitter_model.disable();
|
|
||||||
if (check_loop.value())
|
|
||||||
do_random();
|
|
||||||
}
|
}
|
||||||
|
ready_signal = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundBoardView::handle_replay_thread_done(const uint32_t return_code) {
|
||||||
|
if (return_code == ReplayThread::END_OF_FILE) {
|
||||||
|
stop(true);
|
||||||
|
} else if (return_code == ReplayThread::READ_ERROR) {
|
||||||
|
stop(false);
|
||||||
|
file_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
pbar.set_value(sample_counter);
|
progressbar.set_value(0);
|
||||||
|
}
|
||||||
|
|
||||||
auto bytes_read = reader->read(audio_buffer, 512).value();
|
void SoundBoardView::set_ready() {
|
||||||
|
ready_signal = true;
|
||||||
// Unsigned to signed, pretty stupid :/
|
|
||||||
for (size_t n = 0; n < bytes_read; n++)
|
|
||||||
audio_buffer[n] -= 0x80;
|
|
||||||
for (size_t n = bytes_read; n < 512; n++)
|
|
||||||
audio_buffer[n] = 0;
|
|
||||||
|
|
||||||
sample_counter += 512;
|
|
||||||
|
|
||||||
baseband::set_fifo_data(audio_buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundBoardView::focus() {
|
void SoundBoardView::focus() {
|
||||||
@ -95,41 +92,60 @@ void SoundBoardView::on_tuning_frequency_changed(rf::Frequency f) {
|
|||||||
transmitter_model.set_tuning_frequency(f);
|
transmitter_model.set_tuning_frequency(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SoundBoardView::file_error() {
|
||||||
|
nav_.display_modal("Error", "File read error.");
|
||||||
|
}
|
||||||
|
|
||||||
void SoundBoardView::play_sound(uint16_t id) {
|
void SoundBoardView::play_sound(uint16_t id) {
|
||||||
uint32_t tone_key_index;
|
uint32_t sample_rate = 0;
|
||||||
uint32_t divider;
|
|
||||||
|
|
||||||
if (sounds[id].size == 0) return;
|
auto reader = std::make_unique<WAVFileReader>();
|
||||||
|
uint32_t tone_key_index = options_tone_key.selected_index();
|
||||||
|
|
||||||
if (!reader->open(sounds[id].path)) return;
|
stop(false);
|
||||||
|
|
||||||
sample_duration = sounds[id].sample_duration;
|
if(!reader->open(sounds[id].path)) {
|
||||||
|
file_error();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
pbar.set_max(sample_duration);
|
playing_id = id;
|
||||||
pbar.set_value(0);
|
|
||||||
|
|
||||||
sample_counter = 0;
|
progressbar.set_max(reader->sample_count());
|
||||||
|
sample_rate = reader->sample_rate() * 32;
|
||||||
|
|
||||||
prepare_audio();
|
if( reader ) {
|
||||||
|
//button_play.set_bitmap(&bitmap_stop);
|
||||||
|
baseband::set_sample_rate(sample_rate);
|
||||||
|
|
||||||
transmitter_model.set_sampling_rate(1536000U);
|
replay_thread = std::make_unique<ReplayThread>(
|
||||||
transmitter_model.set_rf_amp(true);
|
std::move(reader),
|
||||||
transmitter_model.set_lna(40);
|
read_size, buffer_count,
|
||||||
transmitter_model.set_vga(40);
|
&ready_signal,
|
||||||
transmitter_model.set_baseband_bandwidth(1750000);
|
[](uint32_t return_code) {
|
||||||
transmitter_model.enable();
|
ReplayThreadDoneMessage message { return_code };
|
||||||
|
EventDispatcher::send_message(message);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
tone_key_index = 0; //options_tone_key.selected_index();
|
baseband::set_audiotx_config(
|
||||||
|
0,
|
||||||
divider = (1536000 / sounds[id].sample_rate) - 1;
|
|
||||||
|
|
||||||
baseband::set_audiotx_data(
|
|
||||||
divider,
|
|
||||||
number_bw.value() * 1000,
|
number_bw.value() * 1000,
|
||||||
10,
|
10,
|
||||||
TONES_F2D(tone_key_frequency(tone_key_index)),
|
TONES_F2D(tone_key_frequency(tone_key_index), sample_rate),
|
||||||
0.2 // 20% mix
|
0.2 // 20% mix
|
||||||
);
|
);
|
||||||
|
|
||||||
|
radio::enable({
|
||||||
|
receiver_model.tuning_frequency(),
|
||||||
|
sample_rate,
|
||||||
|
1750000,
|
||||||
|
rf::Direction::Transmit,
|
||||||
|
receiver_model.rf_amp(),
|
||||||
|
static_cast<int8_t>(receiver_model.lna()),
|
||||||
|
static_cast<int8_t>(receiver_model.vga())
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundBoardView::show_infos(uint16_t id) {
|
void SoundBoardView::show_infos(uint16_t id) {
|
||||||
@ -144,7 +160,7 @@ void SoundBoardView::refresh_buttons(uint16_t id) {
|
|||||||
text_page.set("Page " + to_string_dec_uint(page + 1) + "/" + to_string_dec_uint(max_page));
|
text_page.set("Page " + to_string_dec_uint(page + 1) + "/" + to_string_dec_uint(max_page));
|
||||||
|
|
||||||
for (auto& button : buttons) {
|
for (auto& button : buttons) {
|
||||||
n_sound = (page * 18) + n;
|
n_sound = (page * 15) + n;
|
||||||
|
|
||||||
button.id = n_sound;
|
button.id = n_sound;
|
||||||
|
|
||||||
@ -180,38 +196,31 @@ bool SoundBoardView::change_page(Button& button, const KeyEvent key) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SoundBoardView::on_tx_progress(const uint32_t progress) {
|
||||||
|
progressbar.set_value(progress);
|
||||||
|
}
|
||||||
|
|
||||||
SoundBoardView::SoundBoardView(
|
SoundBoardView::SoundBoardView(
|
||||||
NavigationView& nav
|
NavigationView& nav
|
||||||
) : nav_ (nav)
|
) : nav_ (nav)
|
||||||
{
|
{
|
||||||
std::vector<std::filesystem::path> file_list;
|
auto reader = std::make_unique<WAVFileReader>();
|
||||||
std::string title;
|
uint8_t c = 0;
|
||||||
uint8_t c;
|
|
||||||
|
|
||||||
reader = std::make_unique<WAVFileReader>();
|
for(const auto& entry : std::filesystem::directory_iterator(u"WAV", u"*.WAV")) {
|
||||||
|
if( std::filesystem::is_regular_file(entry.status()) ) {
|
||||||
file_list = scan_root_files(u"WAV", u"*.WAV");
|
if (reader->open(u"WAV/" + entry.path().native())) {
|
||||||
|
|
||||||
c = 0;
|
|
||||||
for (auto& path : file_list) {
|
|
||||||
if (reader->open(u"WAV/" + path.native())) {
|
|
||||||
if ((reader->channels() == 1) && (reader->bits_per_sample() == 8)) {
|
if ((reader->channels() == 1) && (reader->bits_per_sample() == 8)) {
|
||||||
sounds[c].size = reader->data_size();
|
|
||||||
sounds[c].sample_duration = reader->data_size(); // / (reader->bits_per_sample() / 8);
|
|
||||||
sounds[c].sample_rate = reader->sample_rate();
|
|
||||||
//if (reader->bits_per_sample() > 8)
|
|
||||||
// sounds[c].sixteenbit = true;
|
|
||||||
//else
|
|
||||||
// sounds[c].sixteenbit = false;
|
|
||||||
sounds[c].ms_duration = reader->ms_duration();
|
sounds[c].ms_duration = reader->ms_duration();
|
||||||
sounds[c].path = u"WAV/" + path.native();
|
sounds[c].path = u"WAV/" + entry.path().native();
|
||||||
title = reader->title().substr(0, 20);
|
std::string title = reader->title().substr(0, 20);
|
||||||
if (title != "")
|
if (title != "")
|
||||||
sounds[c].title = title;
|
sounds[c].title = title;
|
||||||
else
|
else
|
||||||
sounds[c].title = "-";
|
sounds[c].title = "-";
|
||||||
c++;
|
c++;
|
||||||
if (c == 54) break; // Limit to 54 files (3 pages)
|
if (c == 60) break; // Limit to 60 files (4 pages)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -219,24 +228,24 @@ SoundBoardView::SoundBoardView(
|
|||||||
baseband::run_image(portapack::spi_flash::image_tag_audio_tx);
|
baseband::run_image(portapack::spi_flash::image_tag_audio_tx);
|
||||||
|
|
||||||
max_sound = c;
|
max_sound = c;
|
||||||
max_page = (max_sound + 18 - 1) / 18; // 3 * 6 = 18 buttons per page
|
max_page = (max_sound + 15 - 1) / 15; // 3 * 5 = 15 buttons per page
|
||||||
|
|
||||||
add_children({
|
add_children({
|
||||||
&labels,
|
&labels,
|
||||||
&field_frequency,
|
&field_frequency,
|
||||||
&number_bw,
|
&number_bw,
|
||||||
//&options_tone_key,
|
&options_tone_key,
|
||||||
&text_title,
|
&text_title,
|
||||||
&text_page,
|
&text_page,
|
||||||
&text_duration,
|
&text_duration,
|
||||||
&pbar,
|
&progressbar,
|
||||||
&check_loop,
|
&check_loop,
|
||||||
&button_random,
|
&button_random,
|
||||||
&button_exit
|
&button_exit
|
||||||
});
|
});
|
||||||
|
|
||||||
//tone_keys_populate(options_tone_key);
|
tone_keys_populate(options_tone_key);
|
||||||
//options_tone_key.set_selected_index(0);
|
options_tone_key.set_selected_index(0);
|
||||||
|
|
||||||
const auto button_fn = [this](Button& button) {
|
const auto button_fn = [this](Button& button) {
|
||||||
tx_mode = NORMAL;
|
tx_mode = NORMAL;
|
||||||
@ -260,8 +269,8 @@ SoundBoardView::SoundBoardView(
|
|||||||
button.on_dir = button_dir;
|
button.on_dir = button_dir;
|
||||||
button.set_parent_rect({
|
button.set_parent_rect({
|
||||||
static_cast<Coord>((n % 3) * 78 + 3),
|
static_cast<Coord>((n % 3) * 78 + 3),
|
||||||
static_cast<Coord>((n / 3) * 30 + 24),
|
static_cast<Coord>((n / 3) * 38 + 24),
|
||||||
78, 30
|
78, 38
|
||||||
});
|
});
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "ui.hpp"
|
#include "ui.hpp"
|
||||||
#include "ui_widget.hpp"
|
#include "ui_widget.hpp"
|
||||||
#include "ui_font_fixed_8x16.hpp"
|
#include "ui_font_fixed_8x16.hpp"
|
||||||
|
#include "replay_thread.hpp"
|
||||||
#include "baseband_api.hpp"
|
#include "baseband_api.hpp"
|
||||||
#include "ui_receiver.hpp"
|
#include "ui_receiver.hpp"
|
||||||
#include "io_wave.hpp"
|
#include "io_wave.hpp"
|
||||||
@ -59,10 +60,6 @@ private:
|
|||||||
|
|
||||||
struct sound {
|
struct sound {
|
||||||
std::filesystem::path path { };
|
std::filesystem::path path { };
|
||||||
bool sixteenbit = false;
|
|
||||||
uint32_t sample_rate = 0;
|
|
||||||
uint32_t size = 0;
|
|
||||||
uint32_t sample_duration = 0;
|
|
||||||
uint32_t ms_duration = 0;
|
uint32_t ms_duration = 0;
|
||||||
std::string title { };
|
std::string title { };
|
||||||
};
|
};
|
||||||
@ -73,13 +70,15 @@ private:
|
|||||||
|
|
||||||
uint32_t lfsr_v = 0x13377331;
|
uint32_t lfsr_v = 0x13377331;
|
||||||
|
|
||||||
std::unique_ptr<WAVFileReader> reader { };
|
sound sounds[60]; // 5 pages * 12 buttons
|
||||||
|
|
||||||
sound sounds[54]; // 3 pages * 18 buttons
|
|
||||||
uint32_t max_sound { };
|
uint32_t max_sound { };
|
||||||
uint8_t max_page { };
|
uint8_t max_page { };
|
||||||
|
uint32_t playing_id { };
|
||||||
|
|
||||||
int8_t audio_buffer[512];
|
const size_t read_size { 2048 }; // Less ?
|
||||||
|
const size_t buffer_count { 3 };
|
||||||
|
std::unique_ptr<ReplayThread> replay_thread { };
|
||||||
|
bool ready_signal { false };
|
||||||
|
|
||||||
Style style_a {
|
Style style_a {
|
||||||
.font = font::fixed_8x16,
|
.font = font::fixed_8x16,
|
||||||
@ -102,7 +101,7 @@ private:
|
|||||||
.foreground = { 153, 102, 255 }
|
.foreground = { 153, 102, 255 }
|
||||||
};
|
};
|
||||||
|
|
||||||
std::array<Button, 18> buttons { };
|
std::array<Button, 15> buttons { };
|
||||||
const Style * styles[4] = { &style_a, &style_b, &style_c, &style_d };
|
const Style * styles[4] = { &style_a, &style_b, &style_c, &style_d };
|
||||||
|
|
||||||
void on_tuning_frequency_changed(rf::Frequency f);
|
void on_tuning_frequency_changed(rf::Frequency f);
|
||||||
@ -112,8 +111,13 @@ private:
|
|||||||
bool change_page(Button& button, const KeyEvent key);
|
bool change_page(Button& button, const KeyEvent key);
|
||||||
void refresh_buttons(uint16_t id);
|
void refresh_buttons(uint16_t id);
|
||||||
void play_sound(uint16_t id);
|
void play_sound(uint16_t id);
|
||||||
void prepare_audio();
|
|
||||||
void on_ctcss_changed(uint32_t v);
|
void on_ctcss_changed(uint32_t v);
|
||||||
|
void stop(const bool do_loop);
|
||||||
|
bool is_active() const;
|
||||||
|
void set_ready();
|
||||||
|
void handle_replay_thread_done(const uint32_t return_code);
|
||||||
|
void file_error();
|
||||||
|
void on_tx_progress(const uint32_t progress);
|
||||||
|
|
||||||
Labels labels {
|
Labels labels {
|
||||||
{ { 10 * 8, 4 }, "BW: kHz", Color::light_grey() }
|
{ { 10 * 8, 4 }, "BW: kHz", Color::light_grey() }
|
||||||
@ -138,21 +142,21 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
Text text_title {
|
Text text_title {
|
||||||
{ 1 * 8, 26 * 8, 20 * 8, 16 },
|
{ 1 * 8, 28 * 8, 20 * 8, 16 },
|
||||||
"-"
|
"-"
|
||||||
};
|
};
|
||||||
|
|
||||||
Text text_page {
|
Text text_page {
|
||||||
{ 22 * 8 - 4, 26 * 8, 8 * 8, 16 },
|
{ 22 * 8 - 4, 28 * 8, 8 * 8, 16 },
|
||||||
"Page -/-"
|
"Page -/-"
|
||||||
};
|
};
|
||||||
|
|
||||||
Text text_duration {
|
Text text_duration {
|
||||||
{ 1 * 8, 30 * 8, 5 * 8, 16 }
|
{ 1 * 8, 31 * 8, 5 * 8, 16 }
|
||||||
};
|
};
|
||||||
|
|
||||||
ProgressBar pbar {
|
ProgressBar progressbar {
|
||||||
{ 9 * 8, 30 * 8, 20 * 8, 16 }
|
{ 9 * 8, 31 * 8, 20 * 8, 16 }
|
||||||
};
|
};
|
||||||
|
|
||||||
Checkbox check_loop {
|
Checkbox check_loop {
|
||||||
@ -171,15 +175,31 @@ private:
|
|||||||
"Exit"
|
"Exit"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
MessageHandlerRegistration message_handler_replay_thread_error {
|
||||||
|
Message::ID::ReplayThreadDone,
|
||||||
|
[this](const Message* const p) {
|
||||||
|
const auto message = *reinterpret_cast<const ReplayThreadDoneMessage*>(p);
|
||||||
|
this->handle_replay_thread_done(message.return_code);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
MessageHandlerRegistration message_handler_fifo_signal {
|
MessageHandlerRegistration message_handler_fifo_signal {
|
||||||
Message::ID::RequestSignal,
|
Message::ID::RequestSignal,
|
||||||
[this](const Message* const p) {
|
[this](const Message* const p) {
|
||||||
const auto message = static_cast<const RequestSignalMessage*>(p);
|
const auto message = static_cast<const RequestSignalMessage*>(p);
|
||||||
if (message->signal == RequestSignalMessage::Signal::FillRequest) {
|
if (message->signal == RequestSignalMessage::Signal::FillRequest) {
|
||||||
this->prepare_audio();
|
this->set_ready();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
MessageHandlerRegistration message_handler_tx_progress {
|
||||||
|
Message::ID::TXProgress,
|
||||||
|
[this](const Message* const p) {
|
||||||
|
const auto message = *reinterpret_cast<const TXProgressMessage*>(p);
|
||||||
|
this->on_tx_progress(message.progress);
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace ui */
|
} /* namespace ui */
|
||||||
|
@ -45,7 +45,10 @@ ToneSearchView::ToneSearchView(
|
|||||||
//baseband::run_image(portapack::spi_flash::image_tag_wideband_spectrum);
|
//baseband::run_image(portapack::spi_flash::image_tag_wideband_spectrum);
|
||||||
|
|
||||||
add_children({
|
add_children({
|
||||||
&labels
|
&labels,
|
||||||
|
&field_lna,
|
||||||
|
&field_vga,
|
||||||
|
&field_rf_amp,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,19 @@ private:
|
|||||||
NavigationView& nav_;
|
NavigationView& nav_;
|
||||||
|
|
||||||
Labels labels {
|
Labels labels {
|
||||||
{ { 1 * 8, 0 }, "Min: Max: LNA VGA", Color::light_grey() }
|
{ { 0 * 8, 0 * 8 }, "LNA: VGA: AMP:", Color::light_grey() }
|
||||||
|
};
|
||||||
|
|
||||||
|
LNAGainField field_lna {
|
||||||
|
{ 4 * 8, 0 * 16 }
|
||||||
|
};
|
||||||
|
|
||||||
|
VGAGainField field_vga {
|
||||||
|
{ 11 * 8, 0 * 16 }
|
||||||
|
};
|
||||||
|
|
||||||
|
RFAmpField field_rf_amp {
|
||||||
|
{ 18 * 8, 0 * 16 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -152,7 +152,7 @@ void kill_afsk() {
|
|||||||
send_message(&message);
|
send_message(&message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_audiotx_data(const uint32_t divider, const float deviation_hz, const float audio_gain,
|
void set_audiotx_config(const uint32_t divider, const float deviation_hz, const float audio_gain,
|
||||||
const uint32_t tone_key_delta, const float tone_key_mix_weight) {
|
const uint32_t tone_key_delta, const float tone_key_mix_weight) {
|
||||||
const AudioTXConfigMessage message {
|
const AudioTXConfigMessage message {
|
||||||
divider,
|
divider,
|
||||||
@ -240,7 +240,7 @@ void set_spectrum(const size_t sampling_rate, const size_t trigger) {
|
|||||||
|
|
||||||
void set_siggen_tone(const uint32_t tone) {
|
void set_siggen_tone(const uint32_t tone) {
|
||||||
const SigGenToneMessage message {
|
const SigGenToneMessage message {
|
||||||
TONES_F2D(tone)
|
TONES_F2D(tone, TONES_SAMPLERATE)
|
||||||
};
|
};
|
||||||
send_message(&message);
|
send_message(&message);
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ void set_tones_config(const uint32_t bw, const uint32_t pre_silence, const uint1
|
|||||||
const bool dual_tone, const bool audio_out);
|
const bool dual_tone, const bool audio_out);
|
||||||
void kill_tone();
|
void kill_tone();
|
||||||
void set_sstv_data(const uint8_t vis_code, const uint32_t pixel_duration);
|
void set_sstv_data(const uint8_t vis_code, const uint32_t pixel_duration);
|
||||||
void set_audiotx_data(const uint32_t divider, const float deviation_hz, const float audio_gain,
|
void set_audiotx_config(const uint32_t divider, const float deviation_hz, const float audio_gain,
|
||||||
const uint32_t tone_key_delta, const float tone_key_mix_weight);
|
const uint32_t tone_key_delta, const float tone_key_mix_weight);
|
||||||
void set_fifo_data(const int8_t * data);
|
void set_fifo_data(const int8_t * data);
|
||||||
void set_pitch_rssi(int32_t avg, bool enabled);
|
void set_pitch_rssi(int32_t avg, bool enabled);
|
||||||
|
@ -23,6 +23,10 @@
|
|||||||
// Color bitmaps generated with:
|
// Color bitmaps generated with:
|
||||||
// Gimp image > indexed colors (16), then "xxd -i *.bmp"
|
// Gimp image > indexed colors (16), then "xxd -i *.bmp"
|
||||||
|
|
||||||
|
// Note about available RAM:
|
||||||
|
// Check what ends up in the BSS section by looking at the map files !
|
||||||
|
// Use constexpr where possible or make sure const are in .cpp files, not headers !
|
||||||
|
|
||||||
//TEST: Goertzel
|
//TEST: Goertzel
|
||||||
//TEST: Menuview refresh, seems to blink a lot
|
//TEST: Menuview refresh, seems to blink a lot
|
||||||
//TEST: Check AFSK transmit end, skips last bits ?
|
//TEST: Check AFSK transmit end, skips last bits ?
|
||||||
@ -31,8 +35,8 @@
|
|||||||
//BUG: (Workaround ok) CPLD-related rx ok, tx bad, see portapack.cpp lines 214+ to disable CPLD overlay
|
//BUG: (Workaround ok) CPLD-related rx ok, tx bad, see portapack.cpp lines 214+ to disable CPLD overlay
|
||||||
//BUG: SCANNER Lock on frequency, if frequency jump, still locked on first one
|
//BUG: SCANNER Lock on frequency, if frequency jump, still locked on first one
|
||||||
//BUG: SCANNER Multiple slices
|
//BUG: SCANNER Multiple slices
|
||||||
|
//GLITCH: The about view scroller sometimes misses lines because of a race condition between the display scrolling and drawing the line
|
||||||
|
|
||||||
//TODO: Disable Nuoptix timecode TX, useless (almost)
|
|
||||||
//TODO: Move Touchtunes remote to Custom remote
|
//TODO: Move Touchtunes remote to Custom remote
|
||||||
//TODO: Use escapes \x1B to set colors in text, it works !
|
//TODO: Use escapes \x1B to set colors in text, it works !
|
||||||
//TODO: Open files in File Manager
|
//TODO: Open files in File Manager
|
||||||
|
@ -38,22 +38,22 @@ namespace encoders {
|
|||||||
void bitstream_append(size_t& bitstream_length, uint32_t bit_count, uint32_t bits);
|
void bitstream_append(size_t& bitstream_length, uint32_t bit_count, uint32_t bits);
|
||||||
|
|
||||||
struct encoder_def_t {
|
struct encoder_def_t {
|
||||||
std::string name; // Encoder chip ref/name
|
char name[16]; // Encoder chip ref/name
|
||||||
std::string address_symbols; // List of possible symbols like "01", "01F"...
|
char address_symbols[8]; // List of possible symbols like "01", "01F"...
|
||||||
std::string data_symbols; // Same
|
char data_symbols[8]; // Same
|
||||||
uint16_t clk_per_symbol; // Oscillator periods per symbol
|
uint16_t clk_per_symbol; // Oscillator periods per symbol
|
||||||
uint16_t clk_per_fragment; // Oscillator periods per symbol fragment (state)
|
uint16_t clk_per_fragment; // Oscillator periods per symbol fragment (state)
|
||||||
std::vector<std::string> bit_format; // List of fragments for each symbol in previous *_symbols list order
|
char bit_format[4][20]; // List of fragments for each symbol in previous *_symbols list order
|
||||||
uint8_t word_length; // Total # of symbols (not counting sync)
|
uint8_t word_length; // Total # of symbols (not counting sync)
|
||||||
std::string word_format; // A for Address, D for Data, S for sync
|
char word_format[32]; // A for Address, D for Data, S for sync
|
||||||
std::string sync; // Like bit_format
|
char sync[64]; // Like bit_format
|
||||||
uint32_t default_speed; // Default encoder clk frequency (often set by shitty resistor)
|
uint32_t default_speed; // Default encoder clk frequency (often set by shitty resistor)
|
||||||
uint8_t repeat_min; // Minimum repeat count
|
uint8_t repeat_min; // Minimum repeat count
|
||||||
uint16_t pause_symbols; // Length of pause between repeats in symbols
|
uint16_t pause_symbols; // Length of pause between repeats in symbols
|
||||||
};
|
};
|
||||||
|
|
||||||
// Warning ! If this is changed, make sure that ENCODER_UM3750 is still valid !
|
// Warning ! If this is changed, make sure that ENCODER_UM3750 is still valid !
|
||||||
const encoder_def_t encoder_defs[ENC_TYPES_COUNT] = {
|
constexpr encoder_def_t encoder_defs[ENC_TYPES_COUNT] = {
|
||||||
// PT2260-R2
|
// PT2260-R2
|
||||||
{
|
{
|
||||||
"2260-R2",
|
"2260-R2",
|
||||||
|
@ -40,14 +40,14 @@ enum ModemModulation {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct modem_def_t {
|
struct modem_def_t {
|
||||||
std::string name;
|
char name[16];
|
||||||
ModemModulation modulation;
|
ModemModulation modulation;
|
||||||
uint16_t mark_freq;
|
uint16_t mark_freq;
|
||||||
uint16_t space_freq;
|
uint16_t space_freq;
|
||||||
uint16_t baudrate;
|
uint16_t baudrate;
|
||||||
};
|
};
|
||||||
|
|
||||||
const modem_def_t modem_defs[MODEM_DEF_COUNT] = {
|
constexpr modem_def_t modem_defs[MODEM_DEF_COUNT] = {
|
||||||
{ "Bell202", AFSK, 1200, 2200, 1200 },
|
{ "Bell202", AFSK, 1200, 2200, 1200 },
|
||||||
{ "Bell103", AFSK, 1270, 1070, 300 },
|
{ "Bell103", AFSK, 1270, 1070, 300 },
|
||||||
{ "V21", AFSK, 980, 1180, 300 },
|
{ "V21", AFSK, 980, 1180, 300 },
|
||||||
|
@ -88,7 +88,7 @@ uint32_t ReplayThread::run() {
|
|||||||
if (prefill_buffer == nullptr) {
|
if (prefill_buffer == nullptr) {
|
||||||
buffers.put_app(prefill_buffer);
|
buffers.put_app(prefill_buffer);
|
||||||
} else {
|
} else {
|
||||||
size_t blocks = 16384 / 512;
|
size_t blocks = config.read_size / 512;
|
||||||
|
|
||||||
for (size_t c = 0; c < blocks; c++) {
|
for (size_t c = 0; c < blocks; c++) {
|
||||||
auto read_result = reader->read(&((uint8_t*)prefill_buffer->data())[c * 512], 512);
|
auto read_result = reader->read(&((uint8_t*)prefill_buffer->data())[c * 512], 512);
|
||||||
@ -97,7 +97,7 @@ uint32_t ReplayThread::run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
prefill_buffer->set_size(16384);
|
prefill_buffer->set_size(config.read_size);
|
||||||
|
|
||||||
buffers.put(prefill_buffer);
|
buffers.put(prefill_buffer);
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ const char unit_prefix[7] { 'n', 'u', 'm', 0, 'k', 'M', 'G' };
|
|||||||
|
|
||||||
// TODO: Allow l=0 to not fill/justify? Already using this way in ui_spectrum.hpp...
|
// TODO: Allow l=0 to not fill/justify? Already using this way in ui_spectrum.hpp...
|
||||||
std::string to_string_bin(const uint32_t n, const uint8_t l = 0);
|
std::string to_string_bin(const uint32_t n, const uint8_t l = 0);
|
||||||
std::string to_string_dec_uint(const uint32_t n, const int32_t l = 0, const char fill = '0');
|
std::string to_string_dec_uint(const uint32_t n, const int32_t l = 0, const char fill = ' ');
|
||||||
std::string to_string_dec_int(const int32_t n, const int32_t l = 0, const char fill = 0);
|
std::string to_string_dec_int(const int32_t n, const int32_t l = 0, const char fill = 0);
|
||||||
std::string to_string_hex(const uint64_t n, const int32_t l = 0);
|
std::string to_string_hex(const uint64_t n, const int32_t l = 0);
|
||||||
std::string to_string_hex_array(uint8_t * const array, const int32_t l = 0);
|
std::string to_string_hex_array(uint8_t * const array, const int32_t l = 0);
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
#include "ui_aprs_tx.hpp"
|
#include "ui_aprs_tx.hpp"
|
||||||
#include "ui_bht_tx.hpp"
|
#include "ui_bht_tx.hpp"
|
||||||
#include "ui_coasterp.hpp"
|
#include "ui_coasterp.hpp"
|
||||||
#include "ui_debug.hpp"
|
//#include "ui_debug.hpp"
|
||||||
#include "ui_encoders.hpp"
|
#include "ui_encoders.hpp"
|
||||||
#include "ui_fileman.hpp"
|
#include "ui_fileman.hpp"
|
||||||
#include "ui_freqman.hpp"
|
#include "ui_freqman.hpp"
|
||||||
@ -329,20 +329,20 @@ void NavigationView::focus() {
|
|||||||
|
|
||||||
ReceiversMenuView::ReceiversMenuView(NavigationView& nav) {
|
ReceiversMenuView::ReceiversMenuView(NavigationView& nav) {
|
||||||
add_items({
|
add_items({
|
||||||
{ "ADS-B: Planes", ui::Color::green(), &bitmap_icon_adsb, [&nav](){ nav.push<ADSBRxView>(); }, },
|
{ "ADS-B: Planes", ui::Color::green(), &bitmap_icon_adsb, [&nav](){ nav.replace<ADSBRxView>(); }, },
|
||||||
{ "AIS: Boats", ui::Color::green(), &bitmap_icon_ais, [&nav](){ nav.push<AISAppView>(); } },
|
{ "AIS: Boats", ui::Color::green(), &bitmap_icon_ais, [&nav](){ nav.replace<AISAppView>(); } },
|
||||||
{ "AFSK", ui::Color::yellow(),&bitmap_icon_receivers, [&nav](){ nav.push<AFSKRxView>(); } },
|
{ "AFSK", ui::Color::yellow(),&bitmap_icon_receivers, [&nav](){ nav.replace<AFSKRxView>(); } },
|
||||||
{ "APRS", ui::Color::grey(), &bitmap_icon_aprs, [&nav](){ nav.push<NotImplementedView>(); } },
|
{ "APRS", ui::Color::grey(), &bitmap_icon_aprs, [&nav](){ nav.replace<NotImplementedView>(); } },
|
||||||
{ "Audio", ui::Color::green(), &bitmap_icon_speaker, [&nav](){ nav.push<AnalogAudioView>(false); } },
|
{ "Audio", ui::Color::green(), &bitmap_icon_speaker, [&nav](){ nav.replace<AnalogAudioView>(false); } },
|
||||||
{ "DMR framing", ui::Color::grey(), &bitmap_icon_dmr, [&nav](){ nav.push<NotImplementedView>(); } },
|
{ "DMR framing", ui::Color::grey(), &bitmap_icon_dmr, [&nav](){ nav.replace<NotImplementedView>(); } },
|
||||||
{ "ERT: Utility Meters", ui::Color::green(), &bitmap_icon_ert, [&nav](){ nav.push<ERTAppView>(); } },
|
{ "ERT: Utility Meters", ui::Color::green(), &bitmap_icon_ert, [&nav](){ nav.replace<ERTAppView>(); } },
|
||||||
{ "POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav](){ nav.push<POCSAGAppView>(); } },
|
{ "POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav](){ nav.replace<POCSAGAppView>(); } },
|
||||||
{ "SIGFOX", ui::Color::grey(), &bitmap_icon_fox, [&nav](){ nav.push<NotImplementedView>(); } }, // SIGFRXView
|
{ "SIGFOX", ui::Color::grey(), &bitmap_icon_fox, [&nav](){ nav.replace<NotImplementedView>(); } }, // SIGFRXView
|
||||||
{ "LoRa", ui::Color::grey(), &bitmap_icon_lora, [&nav](){ nav.push<NotImplementedView>(); } },
|
{ "LoRa", ui::Color::grey(), &bitmap_icon_lora, [&nav](){ nav.replace<NotImplementedView>(); } },
|
||||||
{ "Radiosondes", ui::Color::yellow(),&bitmap_icon_sonde, [&nav](){ nav.push<SondeView>(); } },
|
{ "Radiosondes", ui::Color::yellow(),&bitmap_icon_sonde, [&nav](){ nav.replace<SondeView>(); } },
|
||||||
{ "SSTV", ui::Color::grey(), &bitmap_icon_sstv, [&nav](){ nav.push<NotImplementedView>(); } },
|
{ "SSTV", ui::Color::grey(), &bitmap_icon_sstv, [&nav](){ nav.replace<NotImplementedView>(); } },
|
||||||
{ "TETRA framing", ui::Color::grey(), &bitmap_icon_tetra, [&nav](){ nav.push<NotImplementedView>(); } },
|
{ "TETRA framing", ui::Color::grey(), &bitmap_icon_tetra, [&nav](){ nav.replace<NotImplementedView>(); } },
|
||||||
{ "TPMS: Cars", ui::Color::green(), &bitmap_icon_tpms, [&nav](){ nav.push<TPMSAppView>(); } },
|
{ "TPMS: Cars", ui::Color::green(), &bitmap_icon_tpms, [&nav](){ nav.replace<TPMSAppView>(); } },
|
||||||
});
|
});
|
||||||
on_left = [&nav](){ nav.pop(); };
|
on_left = [&nav](){ nav.pop(); };
|
||||||
|
|
||||||
@ -383,7 +383,7 @@ UtilitiesMenuView::UtilitiesMenuView(NavigationView& nav) {
|
|||||||
{ "File manager", ui::Color::yellow(), &bitmap_icon_file, [&nav](){ nav.push<FileManagerView>(); } },
|
{ "File manager", ui::Color::yellow(), &bitmap_icon_file, [&nav](){ nav.push<FileManagerView>(); } },
|
||||||
{ "Notepad", ui::Color::grey(), &bitmap_icon_notepad, [&nav](){ nav.push<NotImplementedView>(); } },
|
{ "Notepad", ui::Color::grey(), &bitmap_icon_notepad, [&nav](){ nav.push<NotImplementedView>(); } },
|
||||||
{ "Signal generator", ui::Color::green(), &bitmap_icon_cwgen, [&nav](){ nav.push<SigGenView>(); } },
|
{ "Signal generator", ui::Color::green(), &bitmap_icon_cwgen, [&nav](){ nav.push<SigGenView>(); } },
|
||||||
{ "Tone search", ui::Color::grey(), nullptr, [&nav](){ nav.push<NotImplementedView>(); } }, // ToneSearchView
|
{ "Tone search", ui::Color::grey(), nullptr, [&nav](){ nav.push<ToneSearchView>(); } },
|
||||||
{ "Whip antenna length", ui::Color::yellow(), nullptr, [&nav](){ nav.push<WhipCalcView>(); } },
|
{ "Whip antenna length", ui::Color::yellow(), nullptr, [&nav](){ nav.push<WhipCalcView>(); } },
|
||||||
{ "Wipe SD card", ui::Color::red(), nullptr, [&nav](){ nav.push<WipeSDView>(); } },
|
{ "Wipe SD card", ui::Color::red(), nullptr, [&nav](){ nav.push<WipeSDView>(); } },
|
||||||
});
|
});
|
||||||
@ -466,10 +466,12 @@ SystemView::SystemView(
|
|||||||
(portapack::persistent_memory::ui_config() & 16)) { // Login option
|
(portapack::persistent_memory::ui_config() & 16)) { // Login option
|
||||||
navigation_view.push<PlayDeadView>();
|
navigation_view.push<PlayDeadView>();
|
||||||
} else {*/
|
} else {*/
|
||||||
|
|
||||||
if (portapack::persistent_memory::config_splash())
|
if (portapack::persistent_memory::config_splash())
|
||||||
navigation_view.push<BMPView>();
|
navigation_view.push<BMPView>();
|
||||||
else
|
else
|
||||||
navigation_view.push<SystemMenuView>();
|
navigation_view.push<SystemMenuView>();
|
||||||
|
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,8 +70,14 @@ public:
|
|||||||
T* push(Args&&... args) {
|
T* push(Args&&... args) {
|
||||||
return reinterpret_cast<T*>(push_view(std::unique_ptr<View>(new T(*this, std::forward<Args>(args)...))));
|
return reinterpret_cast<T*>(push_view(std::unique_ptr<View>(new T(*this, std::forward<Args>(args)...))));
|
||||||
}
|
}
|
||||||
|
template<class T, class... Args>
|
||||||
|
T* replace(Args&&... args) {
|
||||||
|
pop();
|
||||||
|
return reinterpret_cast<T*>(push_view(std::unique_ptr<View>(new T(*this, std::forward<Args>(args)...))));
|
||||||
|
}
|
||||||
|
|
||||||
void push(View* v);
|
void push(View* v);
|
||||||
|
void replace(View* v);
|
||||||
|
|
||||||
void pop();
|
void pop();
|
||||||
void pop_modal();
|
void pop_modal();
|
||||||
|
@ -30,29 +30,19 @@
|
|||||||
|
|
||||||
void AudioTXProcessor::execute(const buffer_c8_t& buffer){
|
void AudioTXProcessor::execute(const buffer_c8_t& buffer){
|
||||||
|
|
||||||
// This is called at 1536000/2048 = 750Hz
|
|
||||||
|
|
||||||
if (!configured) return;
|
if (!configured) return;
|
||||||
|
|
||||||
for (size_t i = 0; i<buffer.count; i++) {
|
if( stream ) {
|
||||||
|
const size_t bytes_to_read = (buffer.count / 32); // /32 (oversampling) should be == 64
|
||||||
// Audio preview sample generation @ 1536000/divider
|
bytes_read += stream->read(audio_buffer.p, bytes_to_read);
|
||||||
if (!as) {
|
|
||||||
as = divider;
|
|
||||||
audio_fifo.out(out_sample);
|
|
||||||
sample = (int32_t)out_sample;
|
|
||||||
//preview_audio_buffer.p[ai++] = sample << 8;
|
|
||||||
|
|
||||||
if ((audio_fifo.len() < 512) && (asked == false)) {
|
|
||||||
// Ask application to fill up fifo
|
|
||||||
shared_memory.application_queue.push(sig_message);
|
|
||||||
asked = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
as--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sample = tone_gen.process(sample);
|
// Fill and "stretch"
|
||||||
|
for (size_t i = 0; i < buffer.count; i++) {
|
||||||
|
if (!(i & 31))
|
||||||
|
audio_sample = audio_buffer.p[i >> 5] - 0x80;
|
||||||
|
|
||||||
|
sample = tone_gen.process(audio_sample);
|
||||||
|
|
||||||
// FM
|
// FM
|
||||||
delta = sample * fm_delta;
|
delta = sample * fm_delta;
|
||||||
@ -63,29 +53,39 @@ void AudioTXProcessor::execute(const buffer_c8_t& buffer){
|
|||||||
re = (sine_table_i8[(sphase & 0xFF000000U) >> 24]);
|
re = (sine_table_i8[(sphase & 0xFF000000U) >> 24]);
|
||||||
im = (sine_table_i8[(phase & 0xFF000000U) >> 24]);
|
im = (sine_table_i8[(phase & 0xFF000000U) >> 24]);
|
||||||
|
|
||||||
buffer.p[i] = {re, im};
|
buffer.p[i] = { (int8_t)re, (int8_t)im };
|
||||||
|
}
|
||||||
|
|
||||||
|
spectrum_samples += buffer.count;
|
||||||
|
if( spectrum_samples >= spectrum_interval_samples ) {
|
||||||
|
spectrum_samples -= spectrum_interval_samples;
|
||||||
|
|
||||||
|
txprogress_message.progress = bytes_read; // Inform UI about progress
|
||||||
|
txprogress_message.done = false;
|
||||||
|
shared_memory.application_queue.push(txprogress_message);
|
||||||
}
|
}
|
||||||
|
|
||||||
//AudioOutput::fill_audio_buffer(preview_audio_buffer, true);
|
//AudioOutput::fill_audio_buffer(preview_audio_buffer, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioTXProcessor::on_message(const Message* const msg) {
|
void AudioTXProcessor::on_message(const Message* const message) {
|
||||||
const auto message = *reinterpret_cast<const AudioTXConfigMessage*>(msg);
|
switch(message->id) {
|
||||||
|
|
||||||
switch(msg->id) {
|
|
||||||
case Message::ID::AudioTXConfig:
|
case Message::ID::AudioTXConfig:
|
||||||
fm_delta = message.deviation_hz * (0xFFFFFFULL / baseband_fs);
|
audio_config(*reinterpret_cast<const AudioTXConfigMessage*>(message));
|
||||||
divider = message.divider;
|
break;
|
||||||
as = 0;
|
|
||||||
|
|
||||||
tone_gen.configure(message.tone_key_delta, message.tone_key_mix_weight);
|
case Message::ID::ReplayConfig:
|
||||||
|
configured = false;
|
||||||
|
bytes_read = 0;
|
||||||
|
replay_config(*reinterpret_cast<const ReplayConfigMessage*>(message));
|
||||||
|
break;
|
||||||
|
|
||||||
configured = true;
|
case Message::ID::SamplerateConfig:
|
||||||
|
samplerate_config(*reinterpret_cast<const SamplerateConfigMessage*>(message));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Message::ID::FIFOData:
|
case Message::ID::FIFOData:
|
||||||
audio_fifo.in(static_cast<const FIFODataMessage*>(msg)->data, 512);
|
configured = true;
|
||||||
asked = false;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -93,6 +93,30 @@ void AudioTXProcessor::on_message(const Message* const msg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioTXProcessor::audio_config(const AudioTXConfigMessage& message) {
|
||||||
|
fm_delta = message.deviation_hz * (0xFFFFFFULL / baseband_fs);
|
||||||
|
|
||||||
|
tone_gen.configure(message.tone_key_delta, message.tone_key_mix_weight);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioTXProcessor::samplerate_config(const SamplerateConfigMessage& message) {
|
||||||
|
baseband_fs = message.sample_rate;
|
||||||
|
baseband_thread.set_sampling_rate(baseband_fs);
|
||||||
|
spectrum_interval_samples = baseband_fs / 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioTXProcessor::replay_config(const ReplayConfigMessage& message) {
|
||||||
|
if( message.config ) {
|
||||||
|
|
||||||
|
stream = std::make_unique<StreamOutput>(message.config);
|
||||||
|
|
||||||
|
// Tell application that the buffers and FIFO pointers are ready, prefill
|
||||||
|
shared_memory.application_queue.push(sig_message);
|
||||||
|
} else {
|
||||||
|
stream.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
EventDispatcher event_dispatcher { std::make_unique<AudioTXProcessor>() };
|
EventDispatcher event_dispatcher { std::make_unique<AudioTXProcessor>() };
|
||||||
event_dispatcher.run();
|
event_dispatcher.run();
|
||||||
|
@ -23,10 +23,10 @@
|
|||||||
#ifndef __PROC_AUDIOTX_H__
|
#ifndef __PROC_AUDIOTX_H__
|
||||||
#define __PROC_AUDIOTX_H__
|
#define __PROC_AUDIOTX_H__
|
||||||
|
|
||||||
#include "fifo.hpp"
|
|
||||||
#include "baseband_processor.hpp"
|
#include "baseband_processor.hpp"
|
||||||
#include "baseband_thread.hpp"
|
#include "baseband_thread.hpp"
|
||||||
#include "tone_gen.hpp"
|
#include "tone_gen.hpp"
|
||||||
|
#include "stream_output.hpp"
|
||||||
|
|
||||||
class AudioTXProcessor : public BasebandProcessor {
|
class AudioTXProcessor : public BasebandProcessor {
|
||||||
public:
|
public:
|
||||||
@ -35,27 +35,29 @@ public:
|
|||||||
void on_message(const Message* const msg) override;
|
void on_message(const Message* const msg) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr size_t baseband_fs = 1536000U;
|
size_t baseband_fs = 0;
|
||||||
|
|
||||||
bool configured = false;
|
|
||||||
|
|
||||||
BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Transmit };
|
BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Transmit };
|
||||||
|
|
||||||
int8_t audio_fifo_data[2048] { };
|
std::array<uint8_t, 64> audio { };
|
||||||
FIFO<int8_t> audio_fifo = { audio_fifo_data, 11 }; // 43ms @ 48000Hz
|
const buffer_t<uint8_t> audio_buffer {
|
||||||
|
audio.data(),
|
||||||
|
audio.size(),
|
||||||
|
baseband_fs / 8
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<StreamOutput> stream { };
|
||||||
|
|
||||||
ToneGen tone_gen { };
|
ToneGen tone_gen { };
|
||||||
|
|
||||||
uint32_t fm_delta { 0 };
|
uint32_t fm_delta { 0 };
|
||||||
uint32_t divider { };
|
|
||||||
uint32_t as { 0 };
|
|
||||||
uint32_t phase { 0 }, sphase { 0 };
|
uint32_t phase { 0 }, sphase { 0 };
|
||||||
int8_t out_sample { };
|
int8_t out_sample { };
|
||||||
int32_t sample { 0 }, delta { };
|
int32_t sample { 0 }, audio_sample { 0 }, delta { };
|
||||||
|
|
||||||
int8_t re { 0 }, im { 0 };
|
int8_t re { 0 }, im { 0 };
|
||||||
|
|
||||||
bool asked { false };
|
size_t spectrum_interval_samples = 0;
|
||||||
|
size_t spectrum_samples = 0;
|
||||||
|
|
||||||
//int16_t audio_data[64];
|
//int16_t audio_data[64];
|
||||||
/*const buffer_s16_t preview_audio_buffer {
|
/*const buffer_s16_t preview_audio_buffer {
|
||||||
@ -63,6 +65,14 @@ private:
|
|||||||
sizeof(int16_t)*64
|
sizeof(int16_t)*64
|
||||||
};*/
|
};*/
|
||||||
|
|
||||||
|
bool configured { false };
|
||||||
|
uint32_t bytes_read { 0 };
|
||||||
|
|
||||||
|
void samplerate_config(const SamplerateConfigMessage& message);
|
||||||
|
void audio_config(const AudioTXConfigMessage& message);
|
||||||
|
void replay_config(const ReplayConfigMessage& message);
|
||||||
|
|
||||||
|
TXProgressMessage txprogress_message { };
|
||||||
RequestSignalMessage sig_message { RequestSignalMessage::Signal::FillRequest };
|
RequestSignalMessage sig_message { RequestSignalMessage::Signal::FillRequest };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -96,16 +96,16 @@ public:
|
|||||||
SigGenConfig = 43,
|
SigGenConfig = 43,
|
||||||
SigGenTone = 44,
|
SigGenTone = 44,
|
||||||
|
|
||||||
POCSAGPacket = 50,
|
POCSAGPacket = 45,
|
||||||
ADSBFrame = 51,
|
ADSBFrame = 46,
|
||||||
AFSKData = 52,
|
AFSKData = 47,
|
||||||
TestAppPacket = 53,
|
TestAppPacket = 48,
|
||||||
|
|
||||||
RequestSignal = 60,
|
RequestSignal = 49,
|
||||||
FIFOData = 61,
|
FIFOData = 50,
|
||||||
|
|
||||||
AudioLevelReport = 70,
|
AudioLevelReport = 51,
|
||||||
CodedSquelch = 71,
|
CodedSquelch = 52,
|
||||||
MAX
|
MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ size_t morse_encode(std::string& message, const uint32_t time_unit_ms,
|
|||||||
// Setup tone "symbols"
|
// Setup tone "symbols"
|
||||||
for (c = 0; c < 5; c++) {
|
for (c = 0; c < 5; c++) {
|
||||||
if (c < 2)
|
if (c < 2)
|
||||||
delta = TONES_F2D(tone); // Dot and dash
|
delta = TONES_F2D(tone, TONES_SAMPLERATE); // Dot and dash
|
||||||
else
|
else
|
||||||
delta = 0; // Pause
|
delta = 0; // Pause
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ const uint32_t morse_symbols[5] = {
|
|||||||
size_t morse_encode(std::string& message, const uint32_t time_unit_ms,
|
size_t morse_encode(std::string& message, const uint32_t time_unit_ms,
|
||||||
const uint32_t tone, uint32_t * const time_units);
|
const uint32_t tone, uint32_t * const time_units);
|
||||||
|
|
||||||
const std::string foxhunt_codes[11] = {
|
constexpr char foxhunt_codes[11][4] = {
|
||||||
{ "MOE" }, // -----.
|
{ "MOE" }, // -----.
|
||||||
{ "MOI" }, // -----..
|
{ "MOI" }, // -----..
|
||||||
{ "MOS" }, // -----...
|
{ "MOS" }, // -----...
|
||||||
@ -60,7 +60,7 @@ const std::string foxhunt_codes[11] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 0=dot 1=dash
|
// 0=dot 1=dash
|
||||||
const uint16_t morse_ITU[63] = {
|
constexpr uint16_t morse_ITU[63] = {
|
||||||
// Code Size
|
// Code Size
|
||||||
0b1010110000000110, // !: 101011- 110
|
0b1010110000000110, // !: 101011- 110
|
||||||
0b0100100000000110, // ": 010010- 110
|
0b0100100000000110, // ": 010010- 110
|
||||||
@ -127,7 +127,7 @@ const uint16_t morse_ITU[63] = {
|
|||||||
0b0011010000000110 // _: 001101- 110
|
0b0011010000000110 // _: 001101- 110
|
||||||
};
|
};
|
||||||
|
|
||||||
const uint16_t prosigns[12] = {
|
constexpr uint16_t prosigns[12] = {
|
||||||
// Code Size
|
// Code Size
|
||||||
0b0001110000001001, // <SOS>: 000111000 1001
|
0b0001110000001001, // <SOS>: 000111000 1001
|
||||||
0b0101000000000100, // <AA>: 0101----- 0100
|
0b0101000000000100, // <AA>: 0101----- 0100
|
||||||
|
@ -44,7 +44,7 @@ enum sstv_color_seq {
|
|||||||
#define SSTV_MODES_NB 6
|
#define SSTV_MODES_NB 6
|
||||||
|
|
||||||
// From http://www.graphics.stanford.edu/~seander/bithacks.html, nice !
|
// From http://www.graphics.stanford.edu/~seander/bithacks.html, nice !
|
||||||
inline uint8_t sstv_parity(uint8_t code) {
|
constexpr inline uint8_t sstv_parity(uint8_t code) {
|
||||||
uint8_t out = code;
|
uint8_t out = code;
|
||||||
out ^= code >> 4;
|
out ^= code >> 4;
|
||||||
out &= 0x0F;
|
out &= 0x0F;
|
||||||
@ -63,7 +63,7 @@ struct sstv_scanline {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct sstv_mode {
|
struct sstv_mode {
|
||||||
std::string name;
|
char name[16];
|
||||||
uint8_t vis_code;
|
uint8_t vis_code;
|
||||||
bool color; // Unused for now
|
bool color; // Unused for now
|
||||||
sstv_color_seq color_sequence;
|
sstv_color_seq color_sequence;
|
||||||
@ -78,7 +78,7 @@ struct sstv_mode {
|
|||||||
//std::pair<uint16_t, uint16_t> luma_range;
|
//std::pair<uint16_t, uint16_t> luma_range;
|
||||||
};
|
};
|
||||||
|
|
||||||
const sstv_mode sstv_modes[SSTV_MODES_NB] = {
|
constexpr sstv_mode sstv_modes[SSTV_MODES_NB] = {
|
||||||
{ "Scottie 1", sstv_parity(60), true, SSTV_COLOR_GBR, 320, 256, SSTV_MS2S(0.4320), true, 2, true, SSTV_MS2S(9), SSTV_MS2S(1.5) },
|
{ "Scottie 1", sstv_parity(60), true, SSTV_COLOR_GBR, 320, 256, SSTV_MS2S(0.4320), true, 2, true, SSTV_MS2S(9), SSTV_MS2S(1.5) },
|
||||||
{ "Scottie 2", sstv_parity(56), true, SSTV_COLOR_GBR, 320, 256, SSTV_MS2S(0.2752), true, 2, true, SSTV_MS2S(9), SSTV_MS2S(1.5) },
|
{ "Scottie 2", sstv_parity(56), true, SSTV_COLOR_GBR, 320, 256, SSTV_MS2S(0.2752), true, 2, true, SSTV_MS2S(9), SSTV_MS2S(1.5) },
|
||||||
{ "Scottie DX", sstv_parity(76), true, SSTV_COLOR_GBR, 320, 256, SSTV_MS2S(1.08), true, 2, true, SSTV_MS2S(9), SSTV_MS2S(1.5) },
|
{ "Scottie DX", sstv_parity(76), true, SSTV_COLOR_GBR, 320, 256, SSTV_MS2S(1.08), true, 2, true, SSTV_MS2S(9), SSTV_MS2S(1.5) },
|
||||||
|
@ -26,38 +26,37 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#define TONES_SAMPLERATE 1536000
|
#define TONES_SAMPLERATE 1536000
|
||||||
#define TONES_DELTA_COEF ((1ULL << 32) / TONES_SAMPLERATE)
|
#define TONES_DELTA_COEF(sr) ((1ULL << 32) / sr)
|
||||||
|
#define TONES_F2D(f, sr) (uint32_t)(f * TONES_DELTA_COEF(sr))
|
||||||
#define TONES_F2D(f) (uint32_t)(f * TONES_DELTA_COEF)
|
|
||||||
|
|
||||||
#define BEEP_TONES_NB 6
|
#define BEEP_TONES_NB 6
|
||||||
|
|
||||||
#define DTMF_C0 TONES_F2D(1209)
|
#define DTMF_C0 TONES_F2D(1209, TONES_SAMPLERATE)
|
||||||
#define DTMF_C1 TONES_F2D(1336)
|
#define DTMF_C1 TONES_F2D(1336, TONES_SAMPLERATE)
|
||||||
#define DTMF_C2 TONES_F2D(1477)
|
#define DTMF_C2 TONES_F2D(1477, TONES_SAMPLERATE)
|
||||||
#define DTMF_C3 TONES_F2D(1633)
|
#define DTMF_C3 TONES_F2D(1633, TONES_SAMPLERATE)
|
||||||
#define DTMF_R0 TONES_F2D(697)
|
#define DTMF_R0 TONES_F2D(697, TONES_SAMPLERATE)
|
||||||
#define DTMF_R1 TONES_F2D(770)
|
#define DTMF_R1 TONES_F2D(770, TONES_SAMPLERATE)
|
||||||
#define DTMF_R2 TONES_F2D(852)
|
#define DTMF_R2 TONES_F2D(852, TONES_SAMPLERATE)
|
||||||
#define DTMF_R3 TONES_F2D(941)
|
#define DTMF_R3 TONES_F2D(941, TONES_SAMPLERATE)
|
||||||
|
|
||||||
const std::array<uint32_t, 16> ccir_deltas = {
|
const std::array<uint32_t, 16> ccir_deltas = {
|
||||||
TONES_F2D(1981),
|
TONES_F2D(1981, TONES_SAMPLERATE),
|
||||||
TONES_F2D(1124),
|
TONES_F2D(1124, TONES_SAMPLERATE),
|
||||||
TONES_F2D(1197),
|
TONES_F2D(1197, TONES_SAMPLERATE),
|
||||||
TONES_F2D(1275),
|
TONES_F2D(1275, TONES_SAMPLERATE),
|
||||||
TONES_F2D(1358),
|
TONES_F2D(1358, TONES_SAMPLERATE),
|
||||||
TONES_F2D(1446),
|
TONES_F2D(1446, TONES_SAMPLERATE),
|
||||||
TONES_F2D(1540),
|
TONES_F2D(1540, TONES_SAMPLERATE),
|
||||||
TONES_F2D(1640),
|
TONES_F2D(1640, TONES_SAMPLERATE),
|
||||||
TONES_F2D(1747),
|
TONES_F2D(1747, TONES_SAMPLERATE),
|
||||||
TONES_F2D(1860),
|
TONES_F2D(1860, TONES_SAMPLERATE),
|
||||||
TONES_F2D(2400),
|
TONES_F2D(2400, TONES_SAMPLERATE),
|
||||||
TONES_F2D(930),
|
TONES_F2D(930, TONES_SAMPLERATE),
|
||||||
TONES_F2D(2247),
|
TONES_F2D(2247, TONES_SAMPLERATE),
|
||||||
TONES_F2D(991),
|
TONES_F2D(991, TONES_SAMPLERATE),
|
||||||
TONES_F2D(2110),
|
TONES_F2D(2110, TONES_SAMPLERATE),
|
||||||
TONES_F2D(1055)
|
TONES_F2D(1055, TONES_SAMPLERATE)
|
||||||
};
|
};
|
||||||
|
|
||||||
// 0123456789ABCD#*
|
// 0123456789ABCD#*
|
||||||
@ -81,50 +80,50 @@ const uint32_t dtmf_deltas[16][2] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const std::array<uint32_t, 16> eia_deltas = {
|
const std::array<uint32_t, 16> eia_deltas = {
|
||||||
TONES_F2D(600),
|
TONES_F2D(600, TONES_SAMPLERATE),
|
||||||
TONES_F2D(741),
|
TONES_F2D(741, TONES_SAMPLERATE),
|
||||||
TONES_F2D(882),
|
TONES_F2D(882, TONES_SAMPLERATE),
|
||||||
TONES_F2D(1023),
|
TONES_F2D(1023, TONES_SAMPLERATE),
|
||||||
TONES_F2D(1164),
|
TONES_F2D(1164, TONES_SAMPLERATE),
|
||||||
TONES_F2D(1305),
|
TONES_F2D(1305, TONES_SAMPLERATE),
|
||||||
TONES_F2D(1446),
|
TONES_F2D(1446, TONES_SAMPLERATE),
|
||||||
TONES_F2D(1587),
|
TONES_F2D(1587, TONES_SAMPLERATE),
|
||||||
TONES_F2D(1728),
|
TONES_F2D(1728, TONES_SAMPLERATE),
|
||||||
TONES_F2D(1869),
|
TONES_F2D(1869, TONES_SAMPLERATE),
|
||||||
TONES_F2D(2151),
|
TONES_F2D(2151, TONES_SAMPLERATE),
|
||||||
TONES_F2D(2433),
|
TONES_F2D(2433, TONES_SAMPLERATE),
|
||||||
TONES_F2D(2010),
|
TONES_F2D(2010, TONES_SAMPLERATE),
|
||||||
TONES_F2D(2292),
|
TONES_F2D(2292, TONES_SAMPLERATE),
|
||||||
TONES_F2D(459),
|
TONES_F2D(459, TONES_SAMPLERATE),
|
||||||
TONES_F2D(1091)
|
TONES_F2D(1091, TONES_SAMPLERATE)
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::array<uint32_t, 16> zvei_deltas = {
|
const std::array<uint32_t, 16> zvei_deltas = {
|
||||||
TONES_F2D(2400),
|
TONES_F2D(2400, TONES_SAMPLERATE),
|
||||||
TONES_F2D(1060),
|
TONES_F2D(1060, TONES_SAMPLERATE),
|
||||||
TONES_F2D(1160),
|
TONES_F2D(1160, TONES_SAMPLERATE),
|
||||||
TONES_F2D(1270),
|
TONES_F2D(1270, TONES_SAMPLERATE),
|
||||||
TONES_F2D(1400),
|
TONES_F2D(1400, TONES_SAMPLERATE),
|
||||||
TONES_F2D(1530),
|
TONES_F2D(1530, TONES_SAMPLERATE),
|
||||||
TONES_F2D(1670),
|
TONES_F2D(1670, TONES_SAMPLERATE),
|
||||||
TONES_F2D(1830),
|
TONES_F2D(1830, TONES_SAMPLERATE),
|
||||||
TONES_F2D(2000),
|
TONES_F2D(2000, TONES_SAMPLERATE),
|
||||||
TONES_F2D(2200),
|
TONES_F2D(2200, TONES_SAMPLERATE),
|
||||||
TONES_F2D(2800),
|
TONES_F2D(2800, TONES_SAMPLERATE),
|
||||||
TONES_F2D(810),
|
TONES_F2D(810, TONES_SAMPLERATE),
|
||||||
TONES_F2D(970),
|
TONES_F2D(970, TONES_SAMPLERATE),
|
||||||
TONES_F2D(885),
|
TONES_F2D(885, TONES_SAMPLERATE),
|
||||||
TONES_F2D(2600),
|
TONES_F2D(2600, TONES_SAMPLERATE),
|
||||||
TONES_F2D(680)
|
TONES_F2D(680, TONES_SAMPLERATE)
|
||||||
};
|
};
|
||||||
|
|
||||||
const uint32_t beep_deltas[BEEP_TONES_NB] = {
|
const uint32_t beep_deltas[BEEP_TONES_NB] = {
|
||||||
TONES_F2D(1475),
|
TONES_F2D(1475, TONES_SAMPLERATE),
|
||||||
TONES_F2D(740),
|
TONES_F2D(740, TONES_SAMPLERATE),
|
||||||
TONES_F2D(587),
|
TONES_F2D(587, TONES_SAMPLERATE),
|
||||||
TONES_F2D(1109),
|
TONES_F2D(1109, TONES_SAMPLERATE),
|
||||||
TONES_F2D(831),
|
TONES_F2D(831, TONES_SAMPLERATE),
|
||||||
TONES_F2D(740)
|
TONES_F2D(740, TONES_SAMPLERATE)
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif/*__TONESETS_H__*/
|
#endif/*__TONESETS_H__*/
|
||||||
|
48
firmware/tools/world_map.py
Normal file
48
firmware/tools/world_map.py
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
# Copyright (C) 2017 Furrtek
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; see the file COPYING. If not, write to
|
||||||
|
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
# Boston, MA 02110-1301, USA.
|
||||||
|
#
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
import sys
|
||||||
|
import struct
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
outfile = open('../../sdcard/world_map.bin', 'wb')
|
||||||
|
|
||||||
|
im = Image.open("../../sdcard/world_map.jpg")
|
||||||
|
pix = im.load()
|
||||||
|
|
||||||
|
outfile.write(struct.pack('H', im.size[0]))
|
||||||
|
outfile.write(struct.pack('H', im.size[1]))
|
||||||
|
|
||||||
|
for y in range (0, im.size[1]):
|
||||||
|
line = ''
|
||||||
|
for x in range (0, im.size[0]):
|
||||||
|
# RRRRRGGGGGGBBBBB
|
||||||
|
#pixel_lcd = (pix[x, y][0] >> 3) << 11
|
||||||
|
#pixel_lcd |= (pix[x, y][1] >> 2) << 5
|
||||||
|
#pixel_lcd |= (pix[x, y][2] >> 3)
|
||||||
|
# RRRGGGBB to
|
||||||
|
# RRR00GGG000BB000
|
||||||
|
pixel_lcd = (pix[x, y][0] >> 5) << 5
|
||||||
|
pixel_lcd |= (pix[x, y][1] >> 5) << 2
|
||||||
|
pixel_lcd |= (pix[x, y][2] >> 6)
|
||||||
|
line += struct.pack('B', pixel_lcd)
|
||||||
|
outfile.write(line)
|
||||||
|
print(str(y) + '/' + str(im.size[1]) + '\r', end="")
|
BIN
sdcard/world_map.jpg
Normal file
BIN
sdcard/world_map.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 MiB |
Loading…
x
Reference in New Issue
Block a user