Numbers station works, very basic

Added utilities, whip antenna length calculator
Modal errors/abort
This commit is contained in:
furrtek
2016-12-06 13:31:38 +01:00
parent d18b6d135d
commit e56fa0f479
32 changed files with 642 additions and 153 deletions
+27 -26
View File
@@ -35,7 +35,7 @@ set(USE_OPT "-Os -g --specs=nano.specs")
set(USE_COPT "-std=gnu99") set(USE_COPT "-std=gnu99")
# C++ specific options here (added to USE_OPT). # C++ specific options here (added to USE_OPT).
set(USE_CPPOPT "-std=c++11 -fno-rtti -fno-exceptions") set(USE_CPPOPT "-Wl,-Map,foo.map -std=c++11 -fno-rtti -fno-exceptions")
# Enable this if you want the linker to remove unused code and data # Enable this if you want the linker to remove unused code and data
set(USE_LINK_GC yes) set(USE_LINK_GC yes)
@@ -145,37 +145,38 @@ set(CPPSRC
${COMMON}/ui_painter.cpp ${COMMON}/ui_painter.cpp
${COMMON}/ui_focus.cpp ${COMMON}/ui_focus.cpp
${COMMON}/msgpack.cpp ${COMMON}/msgpack.cpp
ui_navigation.cpp ui_about.cpp
ui_menu.cpp ui_adsbtx.cpp
ui_rssi.cpp ui_afsksetup.cpp
ui_channel.cpp ui_alphanum.cpp
ui_audio.cpp ui_audio.cpp
ui_font_fixed_8x16.cpp
ui_setup.cpp
ui_touch_calibration.cpp
ui_debug.cpp
ui_baseband_stats_view.cpp ui_baseband_stats_view.cpp
ui_sd_card_status_view.cpp ui_channel.cpp
ui_sd_card_debug.cpp ui_debug.cpp
ui_encoders.cpp
ui_font_fixed_8x16.cpp
ui_freqman.cpp
ui_handwrite.cpp
ui_jammer.cpp
ui_lcr.cpp
ui_menu.cpp
ui_navigation.cpp
ui_numbers.cpp
ui_nuoptix.cpp
ui_rds.cpp
ui_receiver.cpp ui_receiver.cpp
ui_record_view.cpp ui_record_view.cpp
ui_textentry.cpp ui_rssi.cpp
ui_alphanum.cpp ui_sd_card_status_view.cpp
ui_spectrum.cpp ui_sd_card_debug.cpp
ui_about.cpp ui_setup.cpp
ui_nuoptix.cpp
ui_adsbtx.cpp
ui_handwrite.cpp
ui_afsksetup.cpp
# ui_closecall.cpp
ui_soundboard.cpp ui_soundboard.cpp
ui_rds.cpp ui_spectrum.cpp
ui_lcr.cpp ui_textentry.cpp
ui_touch_calibration.cpp
ui_whipcalc.cpp
ui_xylos.cpp ui_xylos.cpp
ui_numbers.cpp # ui_closecall.cpp
ui_freqman.cpp
ui_encoders.cpp
ui_jammer.cpp
# ui_loadmodule.cpp # ui_loadmodule.cpp
recent_entries.cpp recent_entries.cpp
receiver_model.cpp receiver_model.cpp
+27
View File
@@ -4302,6 +4302,30 @@ ui_touch_calibration.cpp.s:
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_touch_calibration.cpp.s cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_touch_calibration.cpp.s
.PHONY : ui_touch_calibration.cpp.s .PHONY : ui_touch_calibration.cpp.s
ui_whipcalc.obj: ui_whipcalc.cpp.obj
.PHONY : ui_whipcalc.obj
# target to build an object file
ui_whipcalc.cpp.obj:
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_whipcalc.cpp.obj
.PHONY : ui_whipcalc.cpp.obj
ui_whipcalc.i: ui_whipcalc.cpp.i
.PHONY : ui_whipcalc.i
# target to preprocess a source file
ui_whipcalc.cpp.i:
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_whipcalc.cpp.i
.PHONY : ui_whipcalc.cpp.i
ui_whipcalc.s: ui_whipcalc.cpp.s
.PHONY : ui_whipcalc.s
# target to generate assembly for a file
ui_whipcalc.cpp.s:
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_whipcalc.cpp.s
.PHONY : ui_whipcalc.cpp.s
ui_xylos.obj: ui_xylos.cpp.obj ui_xylos.obj: ui_xylos.cpp.obj
.PHONY : ui_xylos.obj .PHONY : ui_xylos.obj
@@ -4858,6 +4882,9 @@ help:
@echo "... ui_touch_calibration.obj" @echo "... ui_touch_calibration.obj"
@echo "... ui_touch_calibration.i" @echo "... ui_touch_calibration.i"
@echo "... ui_touch_calibration.s" @echo "... ui_touch_calibration.s"
@echo "... ui_whipcalc.obj"
@echo "... ui_whipcalc.i"
@echo "... ui_whipcalc.s"
@echo "... ui_xylos.obj" @echo "... ui_xylos.obj"
@echo "... ui_xylos.i" @echo "... ui_xylos.i"
@echo "... ui_xylos.s" @echo "... ui_xylos.s"
+3 -2
View File
@@ -23,14 +23,15 @@
// Bitmaps generated with: // Bitmaps generated with:
// Gimp image > indexed colors (16), then "xxd -i *.bmp" // Gimp image > indexed colors (16), then "xxd -i *.bmp"
//TEST: Imperial in whipcalc
//TEST: Numbers //TEST: Numbers
//TEST: Jammer //TEST: Jammer
//TEST: RDS //TEST: RDS
//BUG: Unistroke text entry screen doesn't care about string max length parameter //BUG (fixed ?): Soundboard crashes on exit if no wav files on sd card
//BUG (fixed ?): No audio in about when shown second time //BUG (fixed ?): No audio in about when shown second time
//BUG: Unistroke text entry screen doesn't care about string max length parameter
//BUG: POCSAG RX sometimes misses the first codeword after SYNC //BUG: POCSAG RX sometimes misses the first codeword after SYNC
//BUG: Soundboard crashes on exit if no wav files on sd card
//TODO: Use ModalMessageView with yes/no for TX //TODO: Use ModalMessageView with yes/no for TX
//TODO: Show address/data bit fields in OOK TX //TODO: Show address/data bit fields in OOK TX
+22 -4
View File
@@ -34,8 +34,26 @@ using namespace portapack;
namespace ui { namespace ui {
void FreqManView::paint(Painter& painter) { void FrequencySaveView::focus() {
(void)painter; button_exit.focus();
}
FrequencySaveView::FrequencySaveView(
NavigationView& nav,
const rf::Frequency value
) {
add_children({ {
&button_exit
} });
button_exit.on_select = [this, &nav](Button&) {
nav.pop();
};
}
void FreqManView::focus() {
button_exit.focus();
} }
FreqManView::FreqManView( FreqManView::FreqManView(
@@ -43,7 +61,7 @@ FreqManView::FreqManView(
) { ) {
add_children({ { add_children({ {
&button_ok &button_exit
} }); } });
size_t n = 0; size_t n = 0;
@@ -61,7 +79,7 @@ FreqManView::FreqManView(
n++; n++;
} }
button_ok.on_select = [this, &nav](Button&) { button_exit.on_select = [this, &nav](Button&) {
nav.pop(); nav.pop();
}; };
+20 -6
View File
@@ -28,23 +28,37 @@
namespace ui { namespace ui {
class FrequencySaveView : public View {
public:
FrequencySaveView(NavigationView& nav, const rf::Frequency value);
//~FrequencySaveView();
void focus() override;
std::string title() const override { return "Save frequency"; };
private:
Button button_exit {
{ 72, 264, 96, 32 },
"Exit"
};
};
class FreqManView : public View { class FreqManView : public View {
public: public:
FreqManView(NavigationView& nav); FreqManView(NavigationView& nav);
//~FreqManView(); //~FreqManView();
std::string title() const override { return "Frequency list"; }; void focus() override;
void paint(Painter& painter) override; std::string title() const override { return "Freq. manager"; };
//void on_show() override;
//void on_hide() override;
private: private:
std::array<Text, 10> text_list; std::array<Text, 10> text_list;
Button button_ok { Button button_exit {
{ 72, 264, 96, 32 }, { 72, 264, 96, 32 },
"OK" "Exit"
}; };
}; };
+5 -1
View File
@@ -51,6 +51,7 @@ void JammerView::update_text(uint8_t id, rf::Frequency f) {
std::string bw; std::string bw;
uint8_t c; uint8_t c;
/*
auto mhz = to_string_dec_int(f / 1000000, 3); auto mhz = to_string_dec_int(f / 1000000, 3);
auto hz100 = to_string_dec_int((f / 100) % 10000, 4, '0'); auto hz100 = to_string_dec_int((f / 100) % 10000, 4, '0');
@@ -63,6 +64,7 @@ void JammerView::update_text(uint8_t id, rf::Frequency f) {
strcat(finalstr, " "); strcat(finalstr, " ");
buttons_freq[id].set_text(finalstr); buttons_freq[id].set_text(finalstr);
*/
for (c = 0; c < 3; c++) { for (c = 0; c < 3; c++) {
center = (frequency_range[c].min + frequency_range[c].max) / 2; center = (frequency_range[c].min + frequency_range[c].max) / 2;
@@ -156,7 +158,7 @@ JammerView::JammerView(NavigationView& nav) {
button.on_select = button_freq_fn; button.on_select = button_freq_fn;
button.set_parent_rect({ button.set_parent_rect({
static_cast<Coord>(13 * 8), static_cast<Coord>(13 * 8),
static_cast<Coord>((n * 52) + 91 + (17 * (n & 1))), static_cast<Coord>(((n >> 1) * 52) + 90 + (18 * (n & 1))),
88, 18 88, 18
}); });
button.id = n; button.id = n;
@@ -180,6 +182,8 @@ JammerView::JammerView(NavigationView& nav) {
checkbox_range1.set_value(range_presets[v][0].enabled); checkbox_range1.set_value(range_presets[v][0].enabled);
checkbox_range2.set_value(range_presets[v][1].enabled); checkbox_range2.set_value(range_presets[v][1].enabled);
checkbox_range3.set_value(range_presets[v][2].enabled); checkbox_range3.set_value(range_presets[v][2].enabled);
update_text(0, 0);
}; };
options_preset.set_selected_index(8); // Sigfox, because they deserve it options_preset.set_selected_index(8); // Sigfox, because they deserve it
+1 -1
View File
@@ -95,7 +95,7 @@ private:
{ false, 0, 0 }}, { false, 0, 0 }},
// Sigfox // Sigfox
{{ true, 868000000, 868220000 }, // Center: 868.2MHz BW: 40kHz {{ true, 868000000, 868200000 }, // Center: 868.2MHz BW: 40kHz
{ false, 0, 0 }, { false, 0, 0 },
{ false, 0, 0 }}, { false, 0, 0 }},
+72 -34
View File
@@ -36,28 +36,26 @@
#include "ui_debug.hpp" #include "ui_debug.hpp"
#include "ui_numbers.hpp" #include "ui_numbers.hpp"
#include "ui_whipcalc.hpp"
//#include "ui_closecall.hpp" // DEBUG //#include "ui_closecall.hpp" // DEBUG
#include "ui_freqman.hpp" #include "ui_freqman.hpp"
#include "ui_nuoptix.hpp" #include "ui_nuoptix.hpp"
#include "ui_soundboard.hpp" #include "ui_soundboard.hpp"
#include "ui_encoders.hpp" #include "ui_encoders.hpp"
#include "ui_debug.hpp"
#include "ui_rds.hpp" #include "ui_rds.hpp"
#include "ui_xylos.hpp" #include "ui_xylos.hpp"
#include "ui_epar.hpp" #include "ui_epar.hpp"
#include "ui_lcr.hpp" #include "ui_lcr.hpp"
#include "analog_audio_app.hpp" #include "analog_audio_app.hpp"
//#include "ui_audiotx.hpp" // DEBUG
#include "ui_adsbtx.hpp" #include "ui_adsbtx.hpp"
#include "ui_jammer.hpp" #include "ui_jammer.hpp"
#include "ais_app.hpp" #include "ais_app.hpp"
#include "ert_app.hpp" #include "ert_app.hpp"
#include "tpms_app.hpp" #include "tpms_app.hpp"
#include "pocsag_app.hpp" #include "pocsag_app.hpp"
#include "capture_app.hpp" #include "capture_app.hpp"
#include "ui_debug.hpp"
#include "core_control.hpp" #include "core_control.hpp"
#include "file.hpp" #include "file.hpp"
@@ -182,13 +180,38 @@ void NavigationView::pop() {
} }
} }
void NavigationView::pop_modal() {
if( view() == modal_view ) {
modal_view = nullptr;
}
// Pop modal view and underlying app view
if( view_stack.size() > 2 ) {
free_view();
view_stack.pop_back();
free_view();
view_stack.pop_back();
update_view();
}
}
void NavigationView::display_modal( void NavigationView::display_modal(
const std::string& title, const std::string& title,
const std::string& message const std::string& message
) {
display_modal(title, message, INFO, nullptr);
}
void NavigationView::display_modal(
const std::string& title,
const std::string& message,
const modal_t type,
const std::function<void(bool)> on_choice
) { ) {
/* If a modal view is already visible, don't display another */ /* If a modal view is already visible, don't display another */
if( !modal_view ) { if( !modal_view ) {
modal_view = push<ModalMessageView>(title, message, false); modal_view = push<ModalMessageView>(title, message, type, on_choice);
} }
} }
@@ -272,6 +295,15 @@ TransmitterAudioMenuView::TransmitterAudioMenuView(NavigationView& nav) {
on_left = [&nav](){ nav.pop(); }; on_left = [&nav](){ nav.pop(); };
} }
/* UtilitiesView *****************************************************************/
UtilitiesView::UtilitiesView(NavigationView& nav) {
add_items<2>({ {
{ "Whip antenna calculator", ui::Color::green(), [&nav](){ nav.push<WhipCalcView>(); } },
{ "Notepad", ui::Color::grey(), [&nav](){ nav.push<NotImplementedView>(); } },
} });
on_left = [&nav](){ nav.pop(); };
}
/* SystemMenuView ********************************************************/ /* SystemMenuView ********************************************************/
SystemMenuView::SystemMenuView(NavigationView& nav) { SystemMenuView::SystemMenuView(NavigationView& nav) {
@@ -284,9 +316,10 @@ SystemMenuView::SystemMenuView(NavigationView& nav) {
//{ "Close Call RX", ui::Color::cyan(), [&nav](){ nav.push<CloseCallView>(); } }, //{ "Close Call RX", ui::Color::cyan(), [&nav](){ nav.push<CloseCallView>(); } },
{ "Jammer", ui::Color::orange(), [&nav](){ nav.push<JammerView>(); } }, { "Jammer", ui::Color::orange(), [&nav](){ nav.push<JammerView>(); } },
{ "Frequency manager", ui::Color::white(), [&nav](){ nav.push<FreqManView>(); } }, { "Frequency manager", ui::Color::white(), [&nav](){ nav.push<FreqManView>(); } },
{ "Utilities", ui::Color::purple(), [&nav](){ nav.push<UtilitiesView>(); } },
//{ "Analyze", ui::Color::white(), [&nav](){ nav.push<NotImplementedView>(); } }, //{ "Analyze", ui::Color::white(), [&nav](){ nav.push<NotImplementedView>(); } },
{ "Setup", ui::Color::white(), [&nav](){ nav.push<SetupMenuView>(); } }, { "Setup", ui::Color::white(), [&nav](){ nav.push<SetupMenuView>(); } },
{ "Debug", ui::Color::white(), [&nav](){ nav.push<DebugMenuView>(); } }, //{ "Debug", ui::Color::white(), [&nav](){ nav.push<DebugMenuView>(); } },
{ "HackRF", ui::Color::white(), [&nav](){ nav.push<HackRFFirmwareView>(); } }, { "HackRF", ui::Color::white(), [&nav](){ nav.push<HackRFFirmwareView>(); } },
{ "About", ui::Color::white(), [&nav](){ nav.push<AboutView>(); } } { "About", ui::Color::white(), [&nav](){ nav.push<AboutView>(); } }
} }); } });
@@ -453,61 +486,66 @@ void NotImplementedView::focus() {
} }
/* ModalMessageView ******************************************************/ /* ModalMessageView ******************************************************/
ModalMessageView::ModalMessageView( ModalMessageView::ModalMessageView(
NavigationView& nav, NavigationView& nav,
const std::string& title, const std::string& title,
const std::string& message, const std::string& message,
bool yesno const modal_t type,
const std::function<void(bool)> on_choice
) : title_ { title }, ) : title_ { title },
yesno_ { yesno } type_ { type },
on_choice_ { on_choice }
{ {
if (!yesno) { add_child(&text_message);
button_done.on_select = [&nav](Button&){
nav.pop();
};
add_children({ { if (type == INFO) {
&text_message, add_child(&button_ok);
&button_done
} });
} else {
button_yes.on_select = [this,&nav](Button&){
if (on_choice) on_choice(true);
nav.pop();
};
button_no.on_select = [this,&nav](Button&){
if (on_choice) on_choice(false);
nav.pop();
};
button_ok.on_select = [&nav](Button&){
nav.pop();
};
} else if (type == YESNO) {
add_children({ { add_children({ {
&text_message,
&button_yes, &button_yes,
&button_no &button_no
} }); } });
}
text_message.set(message); button_yes.on_select = [this, &nav](Button&){
if (on_choice_) on_choice_(true);
nav.pop();
};
button_no.on_select = [this, &nav](Button&){
if (on_choice_) on_choice_(false);
nav.pop();
};
} else {
add_child(&button_ok);
button_ok.on_select = [this, &nav](Button&){
if (on_choice_) on_choice_(true);
nav.pop_modal();
};
}
const int text_message_width = message.size() * 8; const int text_message_width = message.size() * 8;
text_message.set_parent_rect({ text_message.set_parent_rect({
(240 - text_message_width) / 2, 7 * 16, (240 - text_message_width) / 2, 8 * 16,
text_message_width, 16 text_message_width, 16
}); });
text_message.set(message);
} }
void ModalMessageView::paint(Painter& painter) { void ModalMessageView::paint(Painter& painter) {
(void)painter; (void)painter;
portapack::display.drawBMP({64, 64}, modal_warning_bmp, false); portapack::display.drawBMP({96, 64}, modal_warning_bmp, false);
} }
void ModalMessageView::focus() { void ModalMessageView::focus() {
if (!yesno_) { if (type_ == YESNO) {
button_done.focus();
} else {
button_yes.focus(); button_yes.focus();
} else {
button_ok.focus();
} }
} }
+20 -6
View File
@@ -40,6 +40,12 @@
namespace ui { namespace ui {
enum modal_t {
INFO = 0,
YESNO,
ABORT
};
class SystemStatusView : public View { class SystemStatusView : public View {
public: public:
std::function<void(void)> on_back; std::function<void(void)> on_back;
@@ -112,8 +118,10 @@ public:
void push(View* v); void push(View* v);
void pop(); void pop();
void pop_modal();
void display_modal(const std::string& title, const std::string& message); void display_modal(const std::string& title, const std::string& message);
void display_modal(const std::string& title, const std::string& message, const modal_t type, const std::function<void(bool)> on_choice);
void focus() override; void focus() override;
@@ -192,6 +200,12 @@ public:
std::string title() const override { return "Audio TX"; }; std::string title() const override { return "Audio TX"; };
}; };
class UtilitiesView : public MenuView {
public:
UtilitiesView(NavigationView& nav);
std::string title() const override { return "Utilities"; };
};
class SystemMenuView : public MenuView { class SystemMenuView : public MenuView {
public: public:
SystemMenuView(NavigationView& nav); SystemMenuView(NavigationView& nav);
@@ -279,23 +293,23 @@ public:
NavigationView& nav, NavigationView& nav,
const std::string& title, const std::string& title,
const std::string& message, const std::string& message,
bool yesno const modal_t type,
const std::function<void(bool)> on_choice
); );
void paint(Painter& painter) override; void paint(Painter& painter) override;
void focus() override; void focus() override;
std::string title() const override { return title_; }; // std::string title() const override { return title_; };
std::function<void(bool)> on_choice;
private: private:
const std::string title_; const std::string title_;
const bool yesno_; const modal_t type_;
const std::function<void(bool)> on_choice_;
Text text_message { }; Text text_message { };
Button button_done { Button button_ok {
{ 10 * 8, 13 * 16, 10 * 8, 24 }, { 10 * 8, 13 * 16, 10 * 8, 24 },
"OK", "OK",
}; };
+147 -32
View File
@@ -31,6 +31,8 @@
#include <cstring> #include <cstring>
#include <stdio.h> #include <stdio.h>
// TODO: Total transmission time (all durations / 44100)
using namespace portapack; using namespace portapack;
using namespace hackrf::one; using namespace hackrf::one;
@@ -38,6 +40,10 @@ namespace ui {
void NumbersStationView::focus() { void NumbersStationView::focus() {
button_exit.focus(); button_exit.focus();
if (file_error) {
nav_.display_modal("No files", "Missing files in /numbers/", ABORT, nullptr);
}
} }
NumbersStationView::~NumbersStationView() { NumbersStationView::~NumbersStationView() {
@@ -45,53 +51,85 @@ NumbersStationView::~NumbersStationView() {
baseband::shutdown(); baseband::shutdown();
} }
void NumbersStationView::paint(Painter& painter) {
(void)painter;
}
void NumbersStationView::on_tuning_frequency_changed(rf::Frequency f) { void NumbersStationView::on_tuning_frequency_changed(rf::Frequency f) {
transmitter_model.set_tuning_frequency(f); transmitter_model.set_tuning_frequency(f);
} }
void NumbersStationView::prepare_audio() { void NumbersStationView::prepare_audio() {
uint8_t code;
if (cnt >= sample_duration) { if (cnt >= sample_duration) {
/*if (!check_loop.value()) { if (segment == ANNOUNCE) {
transmitter_model.disable(); if (!announce_loop) {
return; segment = MESSAGE;
} else { } else {
file.seek(44); auto error = file.open("/numbers/announce.wav");
cnt = 0; if (error.is_valid()) return;
}*/
// DEBUG sample_duration = sound_sizes[10];
file.seek(44);
cnt = 0;
file.seek(44); // Skip header
announce_loop--;
}
}
if (segment == MESSAGE) {
if (id_test == 10)
transmitter_model.disable();
code = symfield_code.value(id_test);
if (code == 10) {
pause = 11025; // p: 0.25s @ 44100Hz
memset(audio_buffer, 0, 1024);
} else if (code == 11) {
pause = 33075; // P: 0.75s @ 44100Hz
memset(audio_buffer, 0, 1024);
} else {
auto error = file.open("/numbers/" + file_names[code] + ".wav");
if (error.is_valid()) return;
sample_duration = sound_sizes[code];
file.seek(44); // Skip header
}
id_test++;
}
cnt = 0;
} }
file.read(audio_buffer, 1024); if (!pause) {
size_t bytes_read = file.read(audio_buffer, 1024).value();
// Unsigned to signed, pretty stupid :/ // Unsigned to signed, pretty stupid :/
for (size_t n = 0; n < 1024; n++) for (size_t n = 0; n < bytes_read; n++)
audio_buffer[n] -= 0x80; audio_buffer[n] -= 0x80;
cnt += 1024; cnt += 1024;
} else {
if (pause >= 1024) {
pause -= 1024;
} else {
cnt = sample_duration;
pause = 0;
}
}
baseband::set_fifo_data(audio_buffer); baseband::set_fifo_data(audio_buffer);
} }
void NumbersStationView::play_sound(uint16_t id) { void NumbersStationView::start_tx() {
uint32_t divider; uint32_t divider;
if (sounds[id].size == 0) return; sample_duration = sound_sizes[0];
cnt = sample_duration;
auto error = file.open("/numbers/" + filenames[id] + ".wav"); id_test = 0;
if (error.is_valid()) return; announce_loop = 2;
segment = ANNOUNCE;
sample_duration = sounds[id].sample_duration;
cnt = 0;
file.seek(44); // Skip header
prepare_audio(); prepare_audio();
@@ -116,21 +154,94 @@ void NumbersStationView::play_sound(uint16_t id) {
); );
} }
// TODO: Copied from soundboard, make globally available
uint16_t NumbersStationView::fb_to_uint16(const std::string& fb) {
return (fb[1] << 8) + fb[0];
}
uint32_t NumbersStationView::fb_to_uint32(const std::string& fb) {
return (fb[3] << 24) + (fb[2] << 16) + (fb[1] << 8) + fb[0];
}
NumbersStationView::NumbersStationView( NumbersStationView::NumbersStationView(
NavigationView& nav NavigationView& nav
) { ) : nav_ (nav)
uint8_t m, d, dayofweek; {
uint16_t y; uint8_t c;
uint8_t y, m, d, dayofweek;
size_t size;
char file_buffer[32];
c = 0;
for (auto& file_name : file_names) {
auto error = file.open("/numbers/" + file_name + ".wav");
if (!error.is_valid()) {
file.seek(22);
file.read(file_buffer, 2);
// Is file mono ?
if (fb_to_uint16(file_buffer) == 1) {
file.seek(40);
file.read(file_buffer, 4);
size = fb_to_uint32(file_buffer);
if (!size) break;
sound_sizes[c] = size;
c++;
} else {
break;
}
} else {
break;
}
}
if (c != 11) file_error = true;
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, &text_title,
&field_frequency,
&number_bw, &number_bw,
&symfield_code,
&button_tx,
&button_exit &button_exit
} }); } });
number_bw.set_value(15); number_bw.set_value(120);
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);
};
};
// DEBUG
symfield_code.set_value(0, 10);
symfield_code.set_value(1, 3);
symfield_code.set_value(2, 4);
symfield_code.set_value(3, 11);
symfield_code.set_value(4, 6);
symfield_code.set_value(5, 1);
symfield_code.set_value(6, 9);
symfield_code.set_value(7, 7);
symfield_code.set_value(8, 8);
symfield_code.set_value(9, 0);
transmitter_model.set_tuning_frequency(103300000); // 103.3MHz
for (c = 0; c < 10; c++)
symfield_code.set_symbol_list(c, "0123456789pP");
rtc::RTC datetime; rtc::RTC datetime;
rtcGetTime(&RTCD1, &datetime); rtcGetTime(&RTCD1, &datetime);
@@ -144,6 +255,10 @@ NumbersStationView::NumbersStationView(
text_title.set(day_of_week[dayofweek]); text_title.set(day_of_week[dayofweek]);
button_tx.on_select = [this, &nav](Button&){
this->start_tx();
};
button_exit.on_select = [&nav](Button&){ button_exit.on_select = [&nav](Button&){
nav.pop(); nav.pop();
}; };
+49 -22
View File
@@ -25,7 +25,7 @@
#include "ui.hpp" #include "ui.hpp"
#include "ui_widget.hpp" #include "ui_widget.hpp"
#include "ui_painter.hpp" #include "ui_receiver.hpp"
#include "ui_navigation.hpp" #include "ui_navigation.hpp"
#include "ui_font_fixed_8x16.hpp" #include "ui_font_fixed_8x16.hpp"
#include "clock_manager.hpp" #include "clock_manager.hpp"
@@ -41,44 +41,58 @@ public:
~NumbersStationView(); ~NumbersStationView();
void focus() override; void focus() override;
void paint(Painter& painter) override;
std::string title() const override { return "Numbers station"; }; std::string title() const override { return "Numbers station"; };
private: private:
// Different from the one in ui_soundboard.hpp, simpler // Sequencing state machine
struct sound { enum segments {
uint32_t size = 0; ANNOUNCE = 0,
uint32_t sample_duration = 0; MESSAGE,
SIGNOFF
}; };
sound sounds[11]; Style style_red {
.font = font::fixed_8x16,
.background = Color::red(),
.foreground = Color::black()
};
const std::string filenames[11] = { NavigationView& nav_;
"zero",
"one", segments segment;
"two", bool file_error = false;
"three", uint32_t sound_sizes[11];
"four",
"five", const std::vector<std::string> file_names = {
"six", { "0" },
"seven", { "1" },
"eight", { "2" },
"nine", { "3" },
"anounce" { "4" },
{ "5" },
{ "6" },
{ "7" },
{ "8" },
{ "9" },
{ "announce" }
}; };
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] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; const char * day_of_week[7] = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };
File file; File file;
uint8_t id_test, announce_loop;
uint32_t cnt; uint32_t cnt;
uint32_t sample_duration; uint32_t sample_duration;
int8_t audio_buffer[1024]; int8_t audio_buffer[1024];
uint32_t pause = 0;
void on_tuning_frequency_changed(rf::Frequency f); void on_tuning_frequency_changed(rf::Frequency f);
void prepare_audio(); void prepare_audio();
void play_sound(uint16_t id); void start_tx();
uint16_t fb_to_uint16(const std::string& fb);
uint32_t fb_to_uint32(const std::string& fb);
// Schedule: save on sd card // Schedule: save on sd card
// For each day of the week, max 8 messages ? // For each day of the week, max 8 messages ?
@@ -95,14 +109,27 @@ private:
"Schedule:" "Schedule:"
}; };
FrequencyField field_frequency {
{ 1 * 8, 4 },
};
NumberField number_bw { NumberField number_bw {
{ 11 * 8, 3 * 16 }, { 12 * 8, 2 * 16 },
3, 3,
{1, 150}, {1, 150},
1, 1,
' ' ' '
}; };
SymField symfield_code {
{ 1*8, 3 * 16 },
10,
false
};
Button button_tx {
{ 21 * 8, 13 * 16, 64, 32 },
"TX !"
};
Button button_exit { Button button_exit {
{ 21 * 8, 16 * 16, 64, 32 }, { 21 * 8, 16 * 16, 64, 32 },
"Exit" "Exit"
+11 -2
View File
@@ -20,6 +20,7 @@
*/ */
#include "ui_receiver.hpp" #include "ui_receiver.hpp"
#include "ui_freqman.hpp"
#include "portapack.hpp" #include "portapack.hpp"
using namespace portapack; using namespace portapack;
@@ -140,14 +141,22 @@ FrequencyKeypadView::FrequencyKeypadView(
button.on_select = button_fn; button.on_select = button_fn;
button.set_parent_rect({ button.set_parent_rect({
(n % 3) * button_w, (n % 3) * button_w,
(n / 3) * button_h + button_h, (n / 3) * button_h + 24,
button_w, button_h button_w, button_h
}); });
button.set_text(label); button.set_text(label);
n++; n++;
} }
add_child(&button_close); add_children({ {
&button_save,
&button_close
} });
button_save.on_select = [this, &nav](Button&) {
nav.push<FrequencySaveView>(this->value());
};
button_close.on_select = [this, &nav](Button&) { button_close.on_select = [this, &nav](Button&) {
if( on_changed ) { if( on_changed ) {
on_changed(this->value()); on_changed(this->value());
+6 -2
View File
@@ -198,13 +198,17 @@ private:
static constexpr int text_digits = mhz_digits + 1 + submhz_digits; static constexpr int text_digits = mhz_digits + 1 + submhz_digits;
Text text_value { Text text_value {
{ 0, 0, text_digits * button_w, button_h } { 0, 4, 240, 16 }
}; };
std::array<Button, 12> buttons; std::array<Button, 12> buttons;
Button button_save {
{ 0, button_h * 4 + button_h, button_w, button_h },
"Save"
};
Button button_close { Button button_close {
{ 0, button_h * 4 + button_h, button_w * 3, button_h }, { button_w, button_h * 4 + button_h, button_w * 2, button_h },
"Done" "Done"
}; };
+8 -8
View File
@@ -75,9 +75,10 @@ void SoundBoardView::prepare_audio() {
pbar.set_value(cnt); pbar.set_value(cnt);
file.read(audio_buffer, 1024); size_t bytes_read = file.read(audio_buffer, 1024).value();
for (size_t n = 0; n < 1024; n++) // Unsigned to signed, pretty stupid :/
for (size_t n = 0; n < bytes_read; n++)
audio_buffer[n] -= 0x80; audio_buffer[n] -= 0x80;
cnt += 1024; cnt += 1024;
@@ -87,6 +88,10 @@ void SoundBoardView::prepare_audio() {
void SoundBoardView::focus() { void SoundBoardView::focus() {
buttons[0].focus(); buttons[0].focus();
if (!max_sound) {
nav_.display_modal("No files", "No files in /wav/ directory", ABORT, nullptr);
}
} }
void SoundBoardView::on_tuning_frequency_changed(rf::Frequency f) { void SoundBoardView::on_tuning_frequency_changed(rf::Frequency f) {
@@ -202,7 +207,7 @@ void SoundBoardView::on_ctcss_changed(uint32_t v) {
SoundBoardView::SoundBoardView( SoundBoardView::SoundBoardView(
NavigationView& nav NavigationView& nav
) ) : nav_ (nav)
{ {
std::vector<std::string> file_list; std::vector<std::string> file_list;
std::string file_name; std::string file_name;
@@ -256,11 +261,6 @@ SoundBoardView::SoundBoardView(
} }
} }
if (!c) {
nav.display_modal("No files", "No files in /wav/ directory");
nav.pop();
}
max_sound = c; max_sound = c;
max_page = max_sound / 21; // 21 buttons per page max_page = max_sound / 21; // 21 buttons per page
+2
View File
@@ -44,6 +44,8 @@ public:
std::string title() const override { return "Soundboard"; }; std::string title() const override { return "Soundboard"; };
private: private:
NavigationView& nav_;
enum tx_modes { enum tx_modes {
NORMAL = 0, NORMAL = 0,
RANDOM RANDOM
+111
View File
@@ -0,0 +1,111 @@
/*
* 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_whipcalc.hpp"
#include "ch.h"
#include "portapack.hpp"
#include "event_m0.hpp"
#include <cstring>
using namespace portapack;
namespace ui {
void WhipCalcView::focus() {
field_frequency.focus();
}
void WhipCalcView::update_result() {
double length, divider;
divider = ((double)options_type.selected_index_value() / 8.0);
// Metric
length = (speed_of_light_mps / (double)field_frequency.value()) * divider;
auto m = to_string_dec_int((int)length, 2);
auto cm = to_string_dec_int(int(length * 100.0) % 100, 2);
auto mm = to_string_dec_int(int(length * 1000.0) % 10, 1);
text_result_metric.set(m + "m " + cm + "." + mm + "cm");
// ANT500 elements for crude adjustment
length /= 0.14;
if (int(length) <= 4) {
auto elements = to_string_dec_int((int)length, 1);
text_result_ant500.set(elements + " " + frac_str[((int(length * 10.0) % 10) + 1) / 3] + "elements");
} else {
text_result_ant500.set("-");
}
// Imperial
length = (speed_of_light_fps / (double)field_frequency.value()) * divider;
auto feet = to_string_dec_int((int)length, 3);
auto inch = to_string_dec_int(int(length * 10.0) % 12, 2);
auto inch_c = to_string_dec_int(int(length * 100.0) % 10, 1);
text_result_imperial.set(feet + "ft " + inch + "." + inch_c + "in");
}
WhipCalcView::WhipCalcView(
NavigationView& nav
) {
add_children({ {
&text_frequency,
&field_frequency,
&text_type,
&options_type,
&text_result_metric,
&text_result_imperial,
&text_result_ant500,
&button_exit
} });
options_type.on_change = [this](size_t, OptionsField::value_t) {
this->update_result();
};
options_type.set_selected_index(2); // Quarter wave
field_frequency.set_value(transmitter_model.tuning_frequency());
field_frequency.set_step(500000); // 500kHz step
field_frequency.on_change = [this](rf::Frequency) {
this->update_result();
};
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->update_result();
this->field_frequency.set_value(f);
};
};
button_exit.on_select = [this, &nav](Button&) {
nav.pop();
};
}
}
+98
View File
@@ -0,0 +1,98 @@
/*
* 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_WHIPCALC_H__
#define __UI_WHIPCALC_H__
#include "ui.hpp"
#include "ui_widget.hpp"
#include "ui_receiver.hpp"
#include "ui_navigation.hpp"
#include "string_format.hpp"
namespace ui {
class WhipCalcView : public View {
public:
WhipCalcView(NavigationView& nav);
void focus() override;
std::string title() const override { return "Whip calculator"; };
private:
const double speed_of_light_mps = 299792458.0; // m/s
const double speed_of_light_fps = 983571087.90472; // feet/s
const std::string frac_str[4] = { "", "1/4 ", "1/2 ", "3/4 " };
void update_result();
Text text_frequency {
{ 2 * 8, 2 * 16, 10 * 16, 16 },
"Frequency:"
};
FrequencyField field_frequency {
{ 13 * 8, 2 * 16 },
};
Text text_type {
{ 2 * 8, 3 * 16, 5 * 16, 16 },
"Type:"
};
OptionsField options_type {
{ 8 * 8, 3 * 16 },
12,
{
{ "Full wave", 8 },
{ "Half wave", 4 },
{ "Quarter wave", 2 },
{ "3/4 wave", 6 },
{ "1/8 wave", 1 },
{ "3/8 wave", 3 },
{ "5/8 wave", 5 },
{ "7/8 wave", 7 }
}
};
Text text_result_metric {
{ 3 * 8, 5 * 16, 10 * 16, 16 },
"-"
};
Text text_result_imperial {
{ 2 * 8, 6 * 16, 10 * 16, 16 },
"-"
};
Text text_result_ant500 {
{ 2 * 8, 8 * 16, 14 * 16, 16 },
"-"
};
Button button_exit {
{ 72, 264, 96, 32 },
"Exit"
};
};
} /* namespace ui */
#endif/*__UI_WHIPCALC__*/
+6
View File
@@ -159,6 +159,12 @@ private:
tx_modes tx_mode = IDLE; tx_modes tx_mode = IDLE;
// 93.975
// 94.1625
// 94.3125
// 94.425
// 95.0625
// 95.925
const rf::Frequency xylos_freqs[7] = { 31325000, 31387500, 31437500, 31475000, 31687500, 31975000, 88000000 }; const rf::Frequency xylos_freqs[7] = { 31325000, 31387500, 31437500, 31475000, 31687500, 31975000, 88000000 };
char ccir_message[21]; char ccir_message[21];
+2 -2
View File
@@ -110,12 +110,12 @@ constexpr region_t bootstrap {
constexpr region_t images { constexpr region_t images {
.offset = 0x10000, .offset = 0x10000,
.size = 0x40000, .size = 0x70000,
}; };
constexpr region_t application { constexpr region_t application {
.offset = 0x80000, .offset = 0x80000,
.size = 0x40000, .size = 0x50000,
}; };
} /* namespace spi_flash */ } /* namespace spi_flash */
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.