mirror of
https://github.com/eried/portapack-mayhem.git
synced 2024-12-24 23:09:26 -05:00
Tones bugfix, numbers station voice files search
This commit is contained in:
parent
ee099504c3
commit
089eeeafe4
@ -174,6 +174,7 @@ set(CPPSRC
|
|||||||
ui_navigation.cpp
|
ui_navigation.cpp
|
||||||
ui_numbers.cpp
|
ui_numbers.cpp
|
||||||
ui_nuoptix.cpp
|
ui_nuoptix.cpp
|
||||||
|
ui_playdead.cpp
|
||||||
ui_pocsag_tx.cpp
|
ui_pocsag_tx.cpp
|
||||||
ui_rds.cpp
|
ui_rds.cpp
|
||||||
ui_receiver.cpp
|
ui_receiver.cpp
|
||||||
|
@ -180,6 +180,19 @@ std::vector<std::filesystem::path> scan_root_files(const std::filesystem::path&
|
|||||||
return file_list;
|
return file_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::filesystem::path> scan_root_directories(const std::filesystem::path& directory) {
|
||||||
|
|
||||||
|
std::vector<std::filesystem::path> directory_list { };
|
||||||
|
|
||||||
|
for(const auto& entry : std::filesystem::directory_iterator(directory, "*")) {
|
||||||
|
if( std::filesystem::is_directory(entry.status()) ) {
|
||||||
|
directory_list.push_back(entry.path());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return directory_list;
|
||||||
|
}
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
namespace filesystem {
|
namespace filesystem {
|
||||||
|
|
||||||
|
@ -234,6 +234,7 @@ space_info space(const path& p);
|
|||||||
} /* namespace std */
|
} /* namespace std */
|
||||||
|
|
||||||
std::vector<std::filesystem::path> scan_root_files(const std::filesystem::path& directory, const std::filesystem::path& extension);
|
std::vector<std::filesystem::path> scan_root_files(const std::filesystem::path& directory, const std::filesystem::path& extension);
|
||||||
|
std::vector<std::filesystem::path> scan_root_directories(const std::filesystem::path& directory);
|
||||||
std::filesystem::path next_filename_stem_matching_pattern(std::filesystem::path filename_stem_pattern);
|
std::filesystem::path next_filename_stem_matching_pattern(std::filesystem::path filename_stem_pattern);
|
||||||
|
|
||||||
/* Values added to FatFs FRESULT enum, values outside the FRESULT data type */
|
/* Values added to FatFs FRESULT enum, values outside the FRESULT data type */
|
||||||
|
@ -21,19 +21,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ui_navigation.hpp"
|
#include "ui_navigation.hpp"
|
||||||
//#include "ui_loadmodule.hpp"
|
|
||||||
|
|
||||||
#include "modules.h"
|
#include "modules.h"
|
||||||
|
|
||||||
#include "portapack.hpp"
|
#include "portapack.hpp"
|
||||||
#include "event_m0.hpp"
|
#include "event_m0.hpp"
|
||||||
#include "portapack_persistent_memory.hpp"
|
|
||||||
#include "bmp_splash.hpp"
|
#include "bmp_splash.hpp"
|
||||||
#include "bmp_modal_warning.hpp"
|
#include "bmp_modal_warning.hpp"
|
||||||
|
|
||||||
#include "ui_about.hpp"
|
#include "ui_about.hpp"
|
||||||
#include "ui_adsbtx.hpp"
|
#include "ui_adsbtx.hpp"
|
||||||
#include "ui_mictx.hpp"
|
|
||||||
#include "ui_bht_tx.hpp"
|
#include "ui_bht_tx.hpp"
|
||||||
#include "ui_closecall.hpp"
|
#include "ui_closecall.hpp"
|
||||||
#include "ui_cw.hpp"
|
#include "ui_cw.hpp"
|
||||||
@ -42,9 +39,11 @@
|
|||||||
#include "ui_freqman.hpp"
|
#include "ui_freqman.hpp"
|
||||||
#include "ui_jammer.hpp"
|
#include "ui_jammer.hpp"
|
||||||
#include "ui_lcr.hpp"
|
#include "ui_lcr.hpp"
|
||||||
|
#include "ui_mictx.hpp"
|
||||||
#include "ui_morse.hpp"
|
#include "ui_morse.hpp"
|
||||||
#include "ui_numbers.hpp"
|
#include "ui_numbers.hpp"
|
||||||
#include "ui_nuoptix.hpp"
|
#include "ui_nuoptix.hpp"
|
||||||
|
#include "ui_playdead.hpp"
|
||||||
#include "ui_pocsag_tx.hpp"
|
#include "ui_pocsag_tx.hpp"
|
||||||
#include "ui_rds.hpp"
|
#include "ui_rds.hpp"
|
||||||
#include "ui_sd_wipe.hpp"
|
#include "ui_sd_wipe.hpp"
|
||||||
@ -354,13 +353,14 @@ void SystemMenuView::hackrf_mode(NavigationView& nav) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SystemMenuView::SystemMenuView(NavigationView& nav) {
|
SystemMenuView::SystemMenuView(NavigationView& nav) {
|
||||||
add_items<12>({ {
|
add_items<13>({ {
|
||||||
{ "Play dead", ui::Color::red(), &bitmap_icon_playdead, [&nav](){ nav.push<PlayDeadView>(); } },
|
{ "Play dead", ui::Color::red(), &bitmap_icon_playdead, [&nav](){ nav.push<PlayDeadView>(); } },
|
||||||
{ "Receivers", ui::Color::cyan(), &bitmap_icon_receivers, [&nav](){ nav.push<ReceiverMenuView>(); } },
|
{ "Receivers", ui::Color::cyan(), &bitmap_icon_receivers, [&nav](){ nav.push<ReceiverMenuView>(); } },
|
||||||
{ "Capture", ui::Color::blue(), &bitmap_icon_capture, [&nav](){ nav.push<CaptureAppView>(); } },
|
{ "Capture", ui::Color::blue(), &bitmap_icon_capture, [&nav](){ nav.push<CaptureAppView>(); } },
|
||||||
{ "Replay", ui::Color::grey(), &bitmap_icon_replay, [&nav](){ nav.push<NotImplementedView>(); } },
|
{ "Replay", ui::Color::grey(), &bitmap_icon_replay, [&nav](){ nav.push<NotImplementedView>(); } },
|
||||||
{ "Code transmitters", ui::Color::green(), &bitmap_icon_codetx, [&nav](){ nav.push<TransmitterCodedMenuView>(); } },
|
|
||||||
{ "Audio transmitters", ui::Color::green(), &bitmap_icon_audiotx, [&nav](){ nav.push<TransmitterAudioMenuView>(); } },
|
{ "Audio transmitters", ui::Color::green(), &bitmap_icon_audiotx, [&nav](){ nav.push<TransmitterAudioMenuView>(); } },
|
||||||
|
{ "Code transmitters", ui::Color::green(), &bitmap_icon_codetx, [&nav](){ nav.push<TransmitterCodedMenuView>(); } },
|
||||||
|
{ "SSTV transmitter", ui::Color::grey(), nullptr, [&nav](){ nav.push<NotImplementedView>(); } },
|
||||||
{ "Close Call", ui::Color::orange(),&bitmap_icon_closecall, [&nav](){ nav.push<CloseCallView>(); } },
|
{ "Close Call", ui::Color::orange(),&bitmap_icon_closecall, [&nav](){ nav.push<CloseCallView>(); } },
|
||||||
{ "Jammer", ui::Color::orange(),&bitmap_icon_jammer, [&nav](){ nav.push<JammerView>(); } },
|
{ "Jammer", ui::Color::orange(),&bitmap_icon_jammer, [&nav](){ nav.push<JammerView>(); } },
|
||||||
{ "Utilities", ui::Color::purple(),&bitmap_icon_utilities, [&nav](){ nav.push<UtilitiesView>(); } },
|
{ "Utilities", ui::Color::purple(),&bitmap_icon_utilities, [&nav](){ nav.push<UtilitiesView>(); } },
|
||||||
@ -450,60 +450,6 @@ void BMPView::paint(Painter&) {
|
|||||||
portapack::display.drawBMP({(240 - 185) / 2, 0}, splash_bmp, false);
|
portapack::display.drawBMP({(240 - 185) / 2, 0}, splash_bmp, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PlayDeadView **********************************************************/
|
|
||||||
|
|
||||||
void PlayDeadView::focus() {
|
|
||||||
button_seq_entry.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayDeadView::paint(Painter& painter) {
|
|
||||||
if (!(portapack::persistent_memory::ui_config() & 16)) {
|
|
||||||
// Blank the whole display
|
|
||||||
painter.fill_rectangle(
|
|
||||||
portapack::display.screen_rect(),
|
|
||||||
style().background
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PlayDeadView::PlayDeadView(NavigationView& nav) {
|
|
||||||
rtc::RTC datetime;
|
|
||||||
|
|
||||||
portapack::persistent_memory::set_playing_dead(0x5920C1DF); // Enable
|
|
||||||
|
|
||||||
add_children({
|
|
||||||
&text_playdead1,
|
|
||||||
&text_playdead2,
|
|
||||||
&text_playdead3,
|
|
||||||
&button_seq_entry,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Seed from RTC
|
|
||||||
rtcGetTime(&RTCD1, &datetime);
|
|
||||||
text_playdead2.set("0x" + to_string_hex(lfsr_iterate(datetime.second()), 6) + "00");
|
|
||||||
|
|
||||||
text_playdead3.hidden(true);
|
|
||||||
|
|
||||||
button_seq_entry.on_dir = [this](Button&, KeyEvent key){
|
|
||||||
sequence = (sequence << 3) | (static_cast<std::underlying_type<KeyEvent>::type>(key) + 1);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
button_seq_entry.on_select = [this, &nav](Button&){
|
|
||||||
if (sequence == portapack::persistent_memory::playdead_sequence()) {
|
|
||||||
portapack::persistent_memory::set_playing_dead(0x82175E23); // Disable
|
|
||||||
if (!(portapack::persistent_memory::ui_config() & 16)) {
|
|
||||||
text_playdead3.hidden(false);
|
|
||||||
} else {
|
|
||||||
nav.pop();
|
|
||||||
nav.push<SystemMenuView>();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sequence = 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* NotImplementedView ****************************************************/
|
/* NotImplementedView ****************************************************/
|
||||||
|
|
||||||
NotImplementedView::NotImplementedView(NavigationView& nav) {
|
NotImplementedView::NotImplementedView(NavigationView& nav) {
|
||||||
|
@ -181,35 +181,6 @@ private:
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
class PlayDeadView : public View {
|
|
||||||
public:
|
|
||||||
PlayDeadView(NavigationView& nav);
|
|
||||||
|
|
||||||
void focus() override;
|
|
||||||
void paint(Painter& painter) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint32_t sequence = 0;
|
|
||||||
|
|
||||||
Text text_playdead1 {
|
|
||||||
{ 6 * 8, 7 * 16, 14 * 8, 16 },
|
|
||||||
"\x46irmwa" "re " "er\x72o\x72"
|
|
||||||
};
|
|
||||||
Text text_playdead2 {
|
|
||||||
{ 6 * 8, 9 * 16, 16 * 8, 16 },
|
|
||||||
""
|
|
||||||
};
|
|
||||||
Text text_playdead3 {
|
|
||||||
{ 6 * 8, 12 * 16, 16 * 8, 16 },
|
|
||||||
"Please reset"
|
|
||||||
};
|
|
||||||
|
|
||||||
Button button_seq_entry {
|
|
||||||
{ 240, 0, 1, 1 },
|
|
||||||
""
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
class ReceiverMenuView : public MenuView {
|
class ReceiverMenuView : public MenuView {
|
||||||
public:
|
public:
|
||||||
ReceiverMenuView(NavigationView& nav);
|
ReceiverMenuView(NavigationView& nav);
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ui_numbers.hpp"
|
#include "ui_numbers.hpp"
|
||||||
|
#include "string_format.hpp"
|
||||||
|
|
||||||
#include "portapack.hpp"
|
#include "portapack.hpp"
|
||||||
#include "hackrf_hal.hpp"
|
#include "hackrf_hal.hpp"
|
||||||
@ -29,17 +30,15 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
// TODO: Total transmission time (all durations / 44100)
|
|
||||||
|
|
||||||
using namespace portapack;
|
using namespace portapack;
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
void NumbersStationView::focus() {
|
void NumbersStationView::focus() {
|
||||||
button_exit.focus();
|
|
||||||
|
|
||||||
if (file_error)
|
if (file_error)
|
||||||
nav_.display_modal("No files", "Missing files in /numbers/", ABORT, nullptr);
|
nav_.display_modal("No voices", "No valid voices found in\nthe /numbers directory.", ABORT, nullptr);
|
||||||
|
else
|
||||||
|
button_exit.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
NumbersStationView::~NumbersStationView() {
|
NumbersStationView::~NumbersStationView() {
|
||||||
@ -54,7 +53,7 @@ void NumbersStationView::on_tuning_frequency_changed(rf::Frequency f) {
|
|||||||
void NumbersStationView::prepare_audio() {
|
void NumbersStationView::prepare_audio() {
|
||||||
uint8_t code;
|
uint8_t code;
|
||||||
|
|
||||||
if (sample_counter >= sample_duration) {
|
/*if (sample_counter >= sample_duration) {
|
||||||
if (segment == ANNOUNCE) {
|
if (segment == ANNOUNCE) {
|
||||||
if (!announce_loop) {
|
if (!announce_loop) {
|
||||||
segment = MESSAGE;
|
segment = MESSAGE;
|
||||||
@ -108,11 +107,11 @@ void NumbersStationView::prepare_audio() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
baseband::set_fifo_data(audio_buffer);
|
baseband::set_fifo_data(audio_buffer);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void NumbersStationView::start_tx() {
|
void NumbersStationView::start_tx() {
|
||||||
sample_duration = sound_sizes[10]; // Announce
|
//sample_duration = sound_sizes[10]; // Announce
|
||||||
sample_counter = sample_duration;
|
sample_counter = sample_duration;
|
||||||
|
|
||||||
code_index = 0;
|
code_index = 0;
|
||||||
@ -130,7 +129,7 @@ void NumbersStationView::start_tx() {
|
|||||||
|
|
||||||
baseband::set_audiotx_data(
|
baseband::set_audiotx_data(
|
||||||
(1536000 / 44100) - 1,
|
(1536000 / 44100) - 1,
|
||||||
number_bw.value(),
|
12000,
|
||||||
1,
|
1,
|
||||||
false,
|
false,
|
||||||
0
|
0
|
||||||
@ -150,56 +149,99 @@ void NumbersStationView::on_tick_second() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NumbersStationView::on_voice_changed(size_t index) {
|
||||||
|
std::string flags_string = "";
|
||||||
|
|
||||||
|
if (voices[index].accent) {
|
||||||
|
flags_string = "^";
|
||||||
|
}
|
||||||
|
if (voices[index].announce) {
|
||||||
|
flags_string += "A";
|
||||||
|
}
|
||||||
|
text_voice_flags.set(flags_string);
|
||||||
|
}
|
||||||
|
|
||||||
NumbersStationView::NumbersStationView(
|
NumbersStationView::NumbersStationView(
|
||||||
NavigationView& nav
|
NavigationView& nav
|
||||||
) : nav_ (nav)
|
) : nav_ (nav)
|
||||||
{
|
{
|
||||||
uint8_t c;
|
std::vector<std::filesystem::path> directory_list;
|
||||||
|
using option_t = std::pair<std::string, int32_t>;
|
||||||
|
using options_t = std::vector<option_t>;
|
||||||
|
options_t voice_options;
|
||||||
|
uint32_t c, i, ia;
|
||||||
|
bool valid;
|
||||||
//uint8_t y, m, d, dayofweek;
|
//uint8_t y, m, d, dayofweek;
|
||||||
|
|
||||||
reader = std::make_unique<WAVFileReader>();
|
reader = std::make_unique<WAVFileReader>();
|
||||||
|
|
||||||
c = 0;
|
// Search for valid voice directories
|
||||||
for (auto& file_name : file_names) {
|
directory_list = scan_root_directories("/numbers");
|
||||||
if (reader->open("/numbers/" + file_name + ".wav")) {
|
if (!directory_list.size()) {
|
||||||
if ((reader->channels() == 1) && (reader->sample_rate() == 44100) && (reader->bits_per_sample() == 8)) {
|
file_error = true;
|
||||||
sound_sizes[c] = reader->data_size();
|
return;
|
||||||
c++;
|
|
||||||
}
|
}
|
||||||
|
// This is awfully repetitive
|
||||||
|
for (const auto& dir : directory_list) {
|
||||||
|
i = 0;
|
||||||
|
for (const auto& file_name : file_names) {
|
||||||
|
valid = false;
|
||||||
|
if (reader->open("/numbers/" + dir.string() + "/" + file_name + ".wav")) {
|
||||||
|
// Check format (mono, 8 bits)
|
||||||
|
if ((reader->channels() == 1) && (reader->bits_per_sample() == 8))
|
||||||
|
valid = true;
|
||||||
}
|
}
|
||||||
|
if (!valid) {
|
||||||
|
if (i < 10)
|
||||||
|
i = 0; // Missingno, invalid voice
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (i) {
|
||||||
|
// Voice ok, are there accent files ?
|
||||||
|
ia = 0;
|
||||||
|
for (const auto& file_name : file_names) {
|
||||||
|
valid = false;
|
||||||
|
if (reader->open("/numbers/" + dir.string() + "/" + file_name + "a.wav")) {
|
||||||
|
// Check format (mono, 8 bits)
|
||||||
|
if ((reader->channels() == 1) && (reader->bits_per_sample() == 8))
|
||||||
|
valid = true;
|
||||||
|
}
|
||||||
|
if (!valid)
|
||||||
|
break;
|
||||||
|
ia++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c != 11) file_error = true;
|
voices.push_back({ dir.string(), (ia >= 10), (i == 11) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!voices.size()) {
|
||||||
|
file_error = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
baseband::run_image(portapack::spi_flash::image_tag_audio_tx);
|
baseband::run_image(portapack::spi_flash::image_tag_audio_tx);
|
||||||
|
|
||||||
add_children({
|
add_children({
|
||||||
&text_title,
|
|
||||||
&field_frequency,
|
|
||||||
&number_bw,
|
|
||||||
&text_code,
|
|
||||||
&symfield_code,
|
&symfield_code,
|
||||||
&check_armed,
|
&check_armed,
|
||||||
&button_tx_now,
|
&options_voices,
|
||||||
|
&text_voice_flags,
|
||||||
|
//&button_tx_now,
|
||||||
&button_exit
|
&button_exit
|
||||||
});
|
});
|
||||||
|
|
||||||
number_bw.set_value(75);
|
for (const auto& voice : voices)
|
||||||
check_armed.set_value(false);
|
voice_options.emplace_back(voice.dir.substr(0, 4), c);
|
||||||
|
|
||||||
field_frequency.set_value(transmitter_model.tuning_frequency());
|
options_voices.set_options(voice_options);
|
||||||
field_frequency.set_step(50000);
|
options_voices.on_change = [this](size_t i, int32_t) {
|
||||||
field_frequency.on_change = [this](rf::Frequency f) {
|
this->on_voice_changed(i);
|
||||||
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);
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
options_voices.set_selected_index(0);
|
||||||
|
|
||||||
|
check_armed.set_value(false);
|
||||||
|
|
||||||
check_armed.on_select = [this](Checkbox&, bool v) {
|
check_armed.on_select = [this](Checkbox&, bool v) {
|
||||||
if (v) {
|
if (v) {
|
||||||
@ -213,6 +255,9 @@ NumbersStationView::NumbersStationView(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
for (c = 0; c < 25; c++)
|
||||||
|
symfield_code.set_symbol_list(c, "0123456789pPE");
|
||||||
|
|
||||||
// DEBUG
|
// DEBUG
|
||||||
symfield_code.set_sym(0, 10);
|
symfield_code.set_sym(0, 10);
|
||||||
symfield_code.set_sym(1, 3);
|
symfield_code.set_sym(1, 3);
|
||||||
@ -226,9 +271,6 @@ NumbersStationView::NumbersStationView(
|
|||||||
symfield_code.set_sym(9, 0);
|
symfield_code.set_sym(9, 0);
|
||||||
symfield_code.set_sym(10, 12); // End
|
symfield_code.set_sym(10, 12); // End
|
||||||
|
|
||||||
for (c = 0; c < 25; c++)
|
|
||||||
symfield_code.set_symbol_list(c, "0123456789pPE");
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
rtc::RTC datetime;
|
rtc::RTC datetime;
|
||||||
rtcGetTime(&RTCD1, &datetime);
|
rtcGetTime(&RTCD1, &datetime);
|
||||||
@ -243,10 +285,6 @@ NumbersStationView::NumbersStationView(
|
|||||||
text_title.set(day_of_week[dayofweek]);
|
text_title.set(day_of_week[dayofweek]);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
button_tx_now.on_select = [this, &nav](Button&){
|
|
||||||
this->start_tx();
|
|
||||||
};
|
|
||||||
|
|
||||||
button_exit.on_select = [&nav](Button&){
|
button_exit.on_select = [&nav](Button&){
|
||||||
nav.pop();
|
nav.pop();
|
||||||
};
|
};
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include "baseband_api.hpp"
|
#include "baseband_api.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
#include "message.hpp"
|
#include "message.hpp"
|
||||||
|
#include "file.hpp"
|
||||||
#include "io_wave.hpp"
|
#include "io_wave.hpp"
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
@ -47,9 +48,12 @@ public:
|
|||||||
std::string title() const override { return "Numbers station"; };
|
std::string title() const override { return "Numbers station"; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NavigationView& nav_;
|
||||||
|
|
||||||
// Sequencing state machine
|
// Sequencing state machine
|
||||||
enum segments {
|
enum segments {
|
||||||
ANNOUNCE = 0,
|
IDLE = 0,
|
||||||
|
ANNOUNCE,
|
||||||
MESSAGE,
|
MESSAGE,
|
||||||
SIGNOFF
|
SIGNOFF
|
||||||
};
|
};
|
||||||
@ -60,12 +64,16 @@ private:
|
|||||||
.foreground = Color::red()
|
.foreground = Color::red()
|
||||||
};
|
};
|
||||||
|
|
||||||
NavigationView& nav_;
|
struct voice_t {
|
||||||
|
std::string dir;
|
||||||
|
bool accent;
|
||||||
|
bool announce;
|
||||||
|
};
|
||||||
|
|
||||||
segments segment;
|
segments segment { IDLE };
|
||||||
bool armed = false;
|
bool armed { false };
|
||||||
bool file_error = false;
|
bool file_error { false };
|
||||||
uint32_t sound_sizes[11];
|
std::vector<voice_t> voices;
|
||||||
|
|
||||||
const std::vector<std::string> file_names = {
|
const std::vector<std::string> file_names = {
|
||||||
{ "0" },
|
{ "0" },
|
||||||
@ -84,16 +92,17 @@ private:
|
|||||||
// const uint8_t month_table[12] = { 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 };
|
// const uint8_t month_table[12] = { 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 };
|
||||||
// const char * day_of_week[7] = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };
|
// const char * day_of_week[7] = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };
|
||||||
|
|
||||||
std::unique_ptr<WAVFileReader> reader;
|
std::unique_ptr<WAVFileReader> reader { };
|
||||||
|
|
||||||
uint8_t code_index, announce_loop;
|
uint8_t code_index, announce_loop;
|
||||||
uint32_t sample_counter;
|
uint32_t sample_counter;
|
||||||
uint32_t sample_duration;
|
uint32_t sample_duration;
|
||||||
int8_t audio_buffer[1024];
|
int8_t audio_buffer[1024];
|
||||||
uint32_t pause = 0;
|
uint32_t pause = 0;
|
||||||
bool armed_blink;
|
bool armed_blink { false };
|
||||||
SignalToken signal_token_tick_second;
|
SignalToken signal_token_tick_second { };
|
||||||
|
|
||||||
|
void on_voice_changed(size_t index);
|
||||||
void on_tick_second();
|
void on_tick_second();
|
||||||
void on_tuning_frequency_changed(rf::Frequency f);
|
void on_tuning_frequency_changed(rf::Frequency f);
|
||||||
void prepare_audio();
|
void prepare_audio();
|
||||||
@ -109,28 +118,23 @@ private:
|
|||||||
// End
|
// End
|
||||||
// Frequency list and sequence
|
// Frequency list and sequence
|
||||||
|
|
||||||
Text text_title {
|
Labels labels {
|
||||||
{ 1 * 8, 8 * 16, 11, 16 },
|
{ { 2 * 8, 5 * 8 }, "Voice: Flags:", Color::light_grey() },
|
||||||
"Schedule:"
|
{ { 1 * 8, 8 * 8 }, "Code:", Color::light_grey() }
|
||||||
};
|
};
|
||||||
|
|
||||||
FrequencyField field_frequency {
|
OptionsField options_voices {
|
||||||
{ 1 * 8, 4 },
|
{ 8 * 8, 1 * 8 },
|
||||||
|
4,
|
||||||
|
{ }
|
||||||
};
|
};
|
||||||
NumberField number_bw {
|
Text text_voice_flags {
|
||||||
{ 12 * 8, 4 },
|
{ 19 * 8, 1 * 8, 2 * 8, 16 },
|
||||||
3,
|
""
|
||||||
{1, 150},
|
|
||||||
1,
|
|
||||||
' '
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Text text_code {
|
|
||||||
{ 20, 4 * 16, 5 * 8, 16 },
|
|
||||||
"Code:"
|
|
||||||
};
|
|
||||||
SymField symfield_code {
|
SymField symfield_code {
|
||||||
{ 20, 5 * 16 },
|
{ 1 * 8, 10 * 8 },
|
||||||
25,
|
25,
|
||||||
SymField::SYMFIELD_DEF
|
SymField::SYMFIELD_DEF
|
||||||
};
|
};
|
||||||
@ -140,10 +144,10 @@ private:
|
|||||||
5,
|
5,
|
||||||
"Armed"
|
"Armed"
|
||||||
};
|
};
|
||||||
Button button_tx_now {
|
/*Button button_tx_now {
|
||||||
{ 18 * 8, 13 * 16, 10 * 8, 32 },
|
{ 18 * 8, 13 * 16, 10 * 8, 32 },
|
||||||
"TX now"
|
"TX now"
|
||||||
};
|
};*/
|
||||||
Button button_exit {
|
Button button_exit {
|
||||||
{ 21 * 8, 16 * 16, 64, 32 },
|
{ 21 * 8, 16 * 16, 64, 32 },
|
||||||
"Exit"
|
"Exit"
|
||||||
|
81
firmware/application/ui_playdead.cpp
Normal file
81
firmware/application/ui_playdead.cpp
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||||
|
* Copyright (C) 2016 Furrtek
|
||||||
|
*
|
||||||
|
* This file is part of PortaPack.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ui_playdead.hpp"
|
||||||
|
#include "portapack_persistent_memory.hpp"
|
||||||
|
#include "string_format.hpp"
|
||||||
|
|
||||||
|
namespace ui {
|
||||||
|
|
||||||
|
void PlayDeadView::focus() {
|
||||||
|
button_seq_entry.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayDeadView::paint(Painter& painter) {
|
||||||
|
if (!(portapack::persistent_memory::ui_config() & 16)) {
|
||||||
|
// Blank the whole display
|
||||||
|
painter.fill_rectangle(
|
||||||
|
portapack::display.screen_rect(),
|
||||||
|
style().background
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayDeadView::PlayDeadView(NavigationView& nav) {
|
||||||
|
rtc::RTC datetime;
|
||||||
|
|
||||||
|
portapack::persistent_memory::set_playing_dead(0x5920C1DF); // Enable
|
||||||
|
|
||||||
|
add_children({
|
||||||
|
&text_playdead1,
|
||||||
|
&text_playdead2,
|
||||||
|
&text_playdead3,
|
||||||
|
&button_seq_entry,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Seed from RTC
|
||||||
|
rtcGetTime(&RTCD1, &datetime);
|
||||||
|
text_playdead2.set("0x" + to_string_hex(lfsr_iterate(datetime.second()), 6) + "00");
|
||||||
|
|
||||||
|
text_playdead3.hidden(true);
|
||||||
|
|
||||||
|
button_seq_entry.on_dir = [this](Button&, KeyEvent key){
|
||||||
|
sequence = (sequence << 3) | (static_cast<std::underlying_type<KeyEvent>::type>(key) + 1);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
button_seq_entry.on_select = [this, &nav](Button&){
|
||||||
|
if (sequence == portapack::persistent_memory::playdead_sequence()) {
|
||||||
|
portapack::persistent_memory::set_playing_dead(0x82175E23); // Disable
|
||||||
|
if (!(portapack::persistent_memory::ui_config() & 16)) {
|
||||||
|
text_playdead3.hidden(false);
|
||||||
|
} else {
|
||||||
|
nav.pop();
|
||||||
|
nav.push<SystemMenuView>();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sequence = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace ui */
|
62
firmware/application/ui_playdead.hpp
Normal file
62
firmware/application/ui_playdead.hpp
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||||
|
* Copyright (C) 2016 Furrtek
|
||||||
|
*
|
||||||
|
* This file is part of PortaPack.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __UI_PLAYDEAD_H__
|
||||||
|
#define __UI_PLAYDEAD_H__
|
||||||
|
|
||||||
|
#include "ui.hpp"
|
||||||
|
#include "ui_navigation.hpp"
|
||||||
|
|
||||||
|
namespace ui {
|
||||||
|
|
||||||
|
class PlayDeadView : public View {
|
||||||
|
public:
|
||||||
|
PlayDeadView(NavigationView& nav);
|
||||||
|
|
||||||
|
void focus() override;
|
||||||
|
void paint(Painter& painter) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t sequence = 0;
|
||||||
|
|
||||||
|
Text text_playdead1 {
|
||||||
|
{ 6 * 8, 7 * 16, 14 * 8, 16 },
|
||||||
|
"\x46irmwa" "re " "er\x72o\x72"
|
||||||
|
};
|
||||||
|
Text text_playdead2 {
|
||||||
|
{ 6 * 8, 9 * 16, 16 * 8, 16 },
|
||||||
|
""
|
||||||
|
};
|
||||||
|
Text text_playdead3 {
|
||||||
|
{ 6 * 8, 12 * 16, 16 * 8, 16 },
|
||||||
|
"Please reset"
|
||||||
|
};
|
||||||
|
|
||||||
|
Button button_seq_entry {
|
||||||
|
{ 240, 0, 1, 1 },
|
||||||
|
""
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace ui */
|
||||||
|
|
||||||
|
#endif/*__UI_PLAYDEAD_H__*/
|
@ -130,7 +130,7 @@ void TonesProcessor::on_message(const Message* const p) {
|
|||||||
tone_deltas[c] = shared_memory.bb_data.tones_data.tone_defs[c].delta;
|
tone_deltas[c] = shared_memory.bb_data.tones_data.tone_defs[c].delta;
|
||||||
tone_durations[c] = shared_memory.bb_data.tones_data.tone_defs[c].duration;
|
tone_durations[c] = shared_memory.bb_data.tones_data.tone_defs[c].duration;
|
||||||
}
|
}
|
||||||
fm_delta = message.fm_delta * (0xFFFFFFFFULL / 1536000) * 2;
|
fm_delta = message.fm_delta * (0xFFFFFFULL / 1536000);
|
||||||
audio_out = message.audio_out;
|
audio_out = message.audio_out;
|
||||||
dual_tone = message.dual_tone;
|
dual_tone = message.dual_tone;
|
||||||
|
|
||||||
|
53
firmware/common/bmp.hpp
Normal file
53
firmware/common/bmp.hpp
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||||
|
* Copyright (C) 2016 Furrtek
|
||||||
|
*
|
||||||
|
* This file is part of PortaPack.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
struct bmp_header_t {
|
||||||
|
uint16_t signature;
|
||||||
|
uint32_t size;
|
||||||
|
uint16_t reserved_1;
|
||||||
|
uint16_t reserved_2;
|
||||||
|
uint32_t image_data;
|
||||||
|
uint32_t BIH_size;
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
|
uint16_t planes;
|
||||||
|
uint16_t bpp;
|
||||||
|
uint32_t compression;
|
||||||
|
uint32_t data_size;
|
||||||
|
uint32_t h_res;
|
||||||
|
uint32_t v_res;
|
||||||
|
uint32_t colors_count;
|
||||||
|
uint32_t icolors_count;
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
struct bmp_palette_t {
|
||||||
|
struct color_t {
|
||||||
|
uint8_t B;
|
||||||
|
uint8_t G;
|
||||||
|
uint8_t R;
|
||||||
|
uint8_t A;
|
||||||
|
} color[16];
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||||
|
* Copyright (C) 2016 Furrtek
|
||||||
*
|
*
|
||||||
* This file is part of PortaPack.
|
* This file is part of PortaPack.
|
||||||
*
|
*
|
||||||
@ -20,6 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lcd_ili9341.hpp"
|
#include "lcd_ili9341.hpp"
|
||||||
|
#include "bmp.hpp"
|
||||||
|
|
||||||
#include "portapack_io.hpp"
|
#include "portapack_io.hpp"
|
||||||
using namespace portapack;
|
using namespace portapack;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||||
|
* Copyright (C) 2016 Furrtek
|
||||||
*
|
*
|
||||||
* This file is part of PortaPack.
|
* This file is part of PortaPack.
|
||||||
*
|
*
|
||||||
@ -110,38 +111,6 @@ private:
|
|||||||
uint16_t current_position;
|
uint16_t current_position;
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
struct bmp_header_t {
|
|
||||||
uint16_t signature;
|
|
||||||
uint32_t size;
|
|
||||||
uint16_t reserved_1;
|
|
||||||
uint16_t reserved_2;
|
|
||||||
uint32_t image_data;
|
|
||||||
uint32_t BIH_size;
|
|
||||||
uint32_t width;
|
|
||||||
uint32_t height;
|
|
||||||
uint16_t planes;
|
|
||||||
uint16_t bpp;
|
|
||||||
uint32_t compression;
|
|
||||||
uint32_t data_size;
|
|
||||||
uint32_t h_res;
|
|
||||||
uint32_t v_res;
|
|
||||||
uint32_t colors_count;
|
|
||||||
uint32_t icolors_count;
|
|
||||||
};
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
struct bmp_palette_t {
|
|
||||||
struct color_t {
|
|
||||||
uint8_t B;
|
|
||||||
uint8_t G;
|
|
||||||
uint8_t R;
|
|
||||||
uint8_t A;
|
|
||||||
} color[16];
|
|
||||||
};
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
scroll_t scroll_state;
|
scroll_t scroll_state;
|
||||||
|
|
||||||
void draw_pixels(const ui::Rect r, const ui::Color* const colors, const size_t count);
|
void draw_pixels(const ui::Rect r, const ui::Color* const colors, const size_t count);
|
||||||
|
BIN
firmware/hackrf_one_usb.dfu
Normal file
BIN
firmware/hackrf_one_usb.dfu
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user