mirror of
https://github.com/eried/portapack-mayhem.git
synced 2025-01-11 15:29:28 -05:00
Numbers station works, very basic
Added utilities, whip antenna length calculator Modal errors/abort
This commit is contained in:
parent
d18b6d135d
commit
e56fa0f479
@ -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
|
||||||
|
@ -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"
|
||||||
|
@ -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
|
||||||
|
@ -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();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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"
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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 }},
|
||||||
|
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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",
|
||||||
};
|
};
|
||||||
|
@ -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--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
file.read(audio_buffer, 1024);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
};
|
};
|
||||||
|
@ -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"
|
||||||
|
@ -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());
|
||||||
|
@ -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"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
firmware/application/ui_whipcalc.cpp
Normal file
111
firmware/application/ui_whipcalc.cpp
Normal 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
firmware/application/ui_whipcalc.hpp
Normal file
98
firmware/application/ui_whipcalc.hpp
Normal 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__*/
|
@ -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];
|
||||||
|
@ -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.
BIN
sdcard/numbers/0.wav
Normal file
BIN
sdcard/numbers/0.wav
Normal file
Binary file not shown.
BIN
sdcard/numbers/1.wav
Normal file
BIN
sdcard/numbers/1.wav
Normal file
Binary file not shown.
BIN
sdcard/numbers/2.wav
Normal file
BIN
sdcard/numbers/2.wav
Normal file
Binary file not shown.
BIN
sdcard/numbers/3.wav
Normal file
BIN
sdcard/numbers/3.wav
Normal file
Binary file not shown.
BIN
sdcard/numbers/4.wav
Normal file
BIN
sdcard/numbers/4.wav
Normal file
Binary file not shown.
BIN
sdcard/numbers/5.wav
Normal file
BIN
sdcard/numbers/5.wav
Normal file
Binary file not shown.
BIN
sdcard/numbers/6.wav
Normal file
BIN
sdcard/numbers/6.wav
Normal file
Binary file not shown.
BIN
sdcard/numbers/7.wav
Normal file
BIN
sdcard/numbers/7.wav
Normal file
Binary file not shown.
BIN
sdcard/numbers/8.wav
Normal file
BIN
sdcard/numbers/8.wav
Normal file
Binary file not shown.
BIN
sdcard/numbers/9.wav
Normal file
BIN
sdcard/numbers/9.wav
Normal file
Binary file not shown.
BIN
sdcard/numbers/announce.wav
Normal file
BIN
sdcard/numbers/announce.wav
Normal file
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user