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")
# 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
set(USE_LINK_GC yes)
@@ -145,37 +145,38 @@ set(CPPSRC
${COMMON}/ui_painter.cpp
${COMMON}/ui_focus.cpp
${COMMON}/msgpack.cpp
ui_navigation.cpp
ui_menu.cpp
ui_rssi.cpp
ui_channel.cpp
ui_about.cpp
ui_adsbtx.cpp
ui_afsksetup.cpp
ui_alphanum.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_sd_card_status_view.cpp
ui_sd_card_debug.cpp
ui_channel.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_record_view.cpp
ui_textentry.cpp
ui_alphanum.cpp
ui_spectrum.cpp
ui_about.cpp
ui_nuoptix.cpp
ui_adsbtx.cpp
ui_handwrite.cpp
ui_afsksetup.cpp
# ui_closecall.cpp
ui_rssi.cpp
ui_sd_card_status_view.cpp
ui_sd_card_debug.cpp
ui_setup.cpp
ui_soundboard.cpp
ui_rds.cpp
ui_lcr.cpp
ui_spectrum.cpp
ui_textentry.cpp
ui_touch_calibration.cpp
ui_whipcalc.cpp
ui_xylos.cpp
ui_numbers.cpp
ui_freqman.cpp
ui_encoders.cpp
ui_jammer.cpp
# ui_closecall.cpp
# ui_loadmodule.cpp
recent_entries.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
.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
.PHONY : ui_xylos.obj
@@ -4858,6 +4882,9 @@ help:
@echo "... ui_touch_calibration.obj"
@echo "... ui_touch_calibration.i"
@echo "... ui_touch_calibration.s"
@echo "... ui_whipcalc.obj"
@echo "... ui_whipcalc.i"
@echo "... ui_whipcalc.s"
@echo "... ui_xylos.obj"
@echo "... ui_xylos.i"
@echo "... ui_xylos.s"
+3 -2
View File
@@ -23,14 +23,15 @@
// Bitmaps generated with:
// Gimp image > indexed colors (16), then "xxd -i *.bmp"
//TEST: Imperial in whipcalc
//TEST: Numbers
//TEST: Jammer
//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: Unistroke text entry screen doesn't care about string max length parameter
//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: Show address/data bit fields in OOK TX
+22 -4
View File
@@ -33,9 +33,27 @@
using namespace portapack;
namespace ui {
void FrequencySaveView::focus() {
button_exit.focus();
}
FrequencySaveView::FrequencySaveView(
NavigationView& nav,
const rf::Frequency value
) {
add_children({ {
&button_exit
} });
void FreqManView::paint(Painter& painter) {
(void)painter;
button_exit.on_select = [this, &nav](Button&) {
nav.pop();
};
}
void FreqManView::focus() {
button_exit.focus();
}
FreqManView::FreqManView(
@@ -43,7 +61,7 @@ FreqManView::FreqManView(
) {
add_children({ {
&button_ok
&button_exit
} });
size_t n = 0;
@@ -61,7 +79,7 @@ FreqManView::FreqManView(
n++;
}
button_ok.on_select = [this, &nav](Button&) {
button_exit.on_select = [this, &nav](Button&) {
nav.pop();
};
+20 -6
View File
@@ -28,23 +28,37 @@
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 {
public:
FreqManView(NavigationView& nav);
//~FreqManView();
std::string title() const override { return "Frequency list"; };
void focus() override;
void paint(Painter& painter) override;
//void on_show() override;
//void on_hide() override;
std::string title() const override { return "Freq. manager"; };
private:
std::array<Text, 10> text_list;
Button button_ok {
Button button_exit {
{ 72, 264, 96, 32 },
"OK"
"Exit"
};
};
+6 -2
View File
@@ -51,6 +51,7 @@ void JammerView::update_text(uint8_t id, rf::Frequency f) {
std::string bw;
uint8_t c;
/*
auto mhz = to_string_dec_int(f / 1000000, 3);
auto hz100 = to_string_dec_int((f / 100) % 10000, 4, '0');
@@ -63,7 +64,8 @@ void JammerView::update_text(uint8_t id, rf::Frequency f) {
strcat(finalstr, " ");
buttons_freq[id].set_text(finalstr);
*/
for (c = 0; c < 3; c++) {
center = (frequency_range[c].min + frequency_range[c].max) / 2;
bw = to_string_dec_int(abs(frequency_range[c].max - frequency_range[c].min) / 1000, 5);
@@ -156,7 +158,7 @@ JammerView::JammerView(NavigationView& nav) {
button.on_select = button_freq_fn;
button.set_parent_rect({
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
});
button.id = n;
@@ -180,6 +182,8 @@ JammerView::JammerView(NavigationView& nav) {
checkbox_range1.set_value(range_presets[v][0].enabled);
checkbox_range2.set_value(range_presets[v][1].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
+1 -1
View File
@@ -95,7 +95,7 @@ private:
{ false, 0, 0 }},
// Sigfox
{{ true, 868000000, 868220000 }, // Center: 868.2MHz BW: 40kHz
{{ true, 868000000, 868200000 }, // Center: 868.2MHz BW: 40kHz
{ false, 0, 0 },
{ false, 0, 0 }},
+71 -33
View File
@@ -36,28 +36,26 @@
#include "ui_debug.hpp"
#include "ui_numbers.hpp"
#include "ui_whipcalc.hpp"
//#include "ui_closecall.hpp" // DEBUG
#include "ui_freqman.hpp"
#include "ui_nuoptix.hpp"
#include "ui_soundboard.hpp"
#include "ui_encoders.hpp"
#include "ui_debug.hpp"
#include "ui_rds.hpp"
#include "ui_xylos.hpp"
#include "ui_epar.hpp"
#include "ui_lcr.hpp"
#include "analog_audio_app.hpp"
//#include "ui_audiotx.hpp" // DEBUG
#include "ui_adsbtx.hpp"
#include "ui_jammer.hpp"
#include "ais_app.hpp"
#include "ert_app.hpp"
#include "tpms_app.hpp"
#include "pocsag_app.hpp"
#include "capture_app.hpp"
#include "ui_debug.hpp"
#include "core_control.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(
const std::string& title,
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( !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(); };
}
/* 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(NavigationView& nav) {
@@ -284,9 +316,10 @@ SystemMenuView::SystemMenuView(NavigationView& nav) {
//{ "Close Call RX", ui::Color::cyan(), [&nav](){ nav.push<CloseCallView>(); } },
{ "Jammer", ui::Color::orange(), [&nav](){ nav.push<JammerView>(); } },
{ "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>(); } },
{ "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>(); } },
{ "About", ui::Color::white(), [&nav](){ nav.push<AboutView>(); } }
} });
@@ -453,61 +486,66 @@ void NotImplementedView::focus() {
}
/* ModalMessageView ******************************************************/
ModalMessageView::ModalMessageView(
NavigationView& nav,
const std::string& title,
const std::string& message,
bool yesno
const modal_t type,
const std::function<void(bool)> on_choice
) : title_ { title },
yesno_ { yesno }
type_ { type },
on_choice_ { on_choice }
{
if (!yesno) {
button_done.on_select = [&nav](Button&){
nav.pop();
};
add_child(&text_message);
if (type == INFO) {
add_child(&button_ok);
add_children({ {
&text_message,
&button_done
} });
} else {
button_yes.on_select = [this,&nav](Button&){
if (on_choice) on_choice(true);
button_ok.on_select = [&nav](Button&){
nav.pop();
};
button_no.on_select = [this,&nav](Button&){
if (on_choice) on_choice(false);
nav.pop();
};
} else if (type == YESNO) {
add_children({ {
&text_message,
&button_yes,
&button_no
} });
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();
};
}
text_message.set(message);
const int text_message_width = message.size() * 8;
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.set(message);
}
void ModalMessageView::paint(Painter& painter) {
(void)painter;
portapack::display.drawBMP({64, 64}, modal_warning_bmp, false);
portapack::display.drawBMP({96, 64}, modal_warning_bmp, false);
}
void ModalMessageView::focus() {
if (!yesno_) {
button_done.focus();
} else {
if (type_ == YESNO) {
button_yes.focus();
} else {
button_ok.focus();
}
}
+21 -7
View File
@@ -40,6 +40,12 @@
namespace ui {
enum modal_t {
INFO = 0,
YESNO,
ABORT
};
class SystemStatusView : public View {
public:
std::function<void(void)> on_back;
@@ -112,8 +118,10 @@ public:
void push(View* v);
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, const modal_t type, const std::function<void(bool)> on_choice);
void focus() override;
@@ -192,6 +200,12 @@ public:
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 {
public:
SystemMenuView(NavigationView& nav);
@@ -279,23 +293,23 @@ public:
NavigationView& nav,
const std::string& title,
const std::string& message,
bool yesno
const modal_t type,
const std::function<void(bool)> on_choice
);
void paint(Painter& painter) override;
void focus() override;
std::string title() const override { return title_; };
std::function<void(bool)> on_choice;
// std::string title() const override { return title_; };
private:
const std::string title_;
const bool yesno_;
const modal_t type_;
const std::function<void(bool)> on_choice_;
Text text_message { };
Button button_done {
Button button_ok {
{ 10 * 8, 13 * 16, 10 * 8, 24 },
"OK",
};
+149 -34
View File
@@ -31,6 +31,8 @@
#include <cstring>
#include <stdio.h>
// TODO: Total transmission time (all durations / 44100)
using namespace portapack;
using namespace hackrf::one;
@@ -38,6 +40,10 @@ namespace ui {
void NumbersStationView::focus() {
button_exit.focus();
if (file_error) {
nav_.display_modal("No files", "Missing files in /numbers/", ABORT, nullptr);
}
}
NumbersStationView::~NumbersStationView() {
@@ -45,53 +51,85 @@ NumbersStationView::~NumbersStationView() {
baseband::shutdown();
}
void NumbersStationView::paint(Painter& painter) {
(void)painter;
}
void NumbersStationView::on_tuning_frequency_changed(rf::Frequency f) {
transmitter_model.set_tuning_frequency(f);
}
void NumbersStationView::prepare_audio() {
uint8_t code;
if (cnt >= sample_duration) {
/*if (!check_loop.value()) {
transmitter_model.disable();
return;
} else {
file.seek(44);
cnt = 0;
}*/
if (segment == ANNOUNCE) {
if (!announce_loop) {
segment = MESSAGE;
} else {
auto error = file.open("/numbers/announce.wav");
if (error.is_valid()) return;
sample_duration = sound_sizes[10];
file.seek(44); // Skip header
announce_loop--;
}
}
// DEBUG
file.seek(44);
cnt = 0;
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);
// Unsigned to signed, pretty stupid :/
for (size_t n = 0; n < 1024; n++)
audio_buffer[n] -= 0x80;
cnt += 1024;
if (!pause) {
size_t bytes_read = file.read(audio_buffer, 1024).value();
// Unsigned to signed, pretty stupid :/
for (size_t n = 0; n < bytes_read; n++)
audio_buffer[n] -= 0x80;
cnt += 1024;
} else {
if (pause >= 1024) {
pause -= 1024;
} else {
cnt = sample_duration;
pause = 0;
}
}
baseband::set_fifo_data(audio_buffer);
}
void NumbersStationView::play_sound(uint16_t id) {
void NumbersStationView::start_tx() {
uint32_t divider;
if (sounds[id].size == 0) return;
auto error = file.open("/numbers/" + filenames[id] + ".wav");
if (error.is_valid()) return;
sample_duration = sound_sizes[0];
cnt = sample_duration;
sample_duration = sounds[id].sample_duration;
cnt = 0;
file.seek(44); // Skip header
id_test = 0;
announce_loop = 2;
segment = ANNOUNCE;
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(
NavigationView& nav
) {
uint8_t m, d, dayofweek;
uint16_t y;
) : nav_ (nav)
{
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);
add_children({ {
&text_title,
&field_frequency,
&number_bw,
&symfield_code,
&button_tx,
&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;
rtcGetTime(&RTCD1, &datetime);
@@ -144,6 +255,10 @@ NumbersStationView::NumbersStationView(
text_title.set(day_of_week[dayofweek]);
button_tx.on_select = [this, &nav](Button&){
this->start_tx();
};
button_exit.on_select = [&nav](Button&){
nav.pop();
};
+50 -23
View File
@@ -25,7 +25,7 @@
#include "ui.hpp"
#include "ui_widget.hpp"
#include "ui_painter.hpp"
#include "ui_receiver.hpp"
#include "ui_navigation.hpp"
#include "ui_font_fixed_8x16.hpp"
#include "clock_manager.hpp"
@@ -41,44 +41,58 @@ public:
~NumbersStationView();
void focus() override;
void paint(Painter& painter) override;
std::string title() const override { return "Numbers station"; };
private:
// Different from the one in ui_soundboard.hpp, simpler
struct sound {
uint32_t size = 0;
uint32_t sample_duration = 0;
// Sequencing state machine
enum segments {
ANNOUNCE = 0,
MESSAGE,
SIGNOFF
};
sound sounds[11];
Style style_red {
.font = font::fixed_8x16,
.background = Color::red(),
.foreground = Color::black()
};
const std::string filenames[11] = {
"zero",
"one",
"two",
"three",
"four",
"five",
"six",
"seven",
"eight",
"nine",
"anounce"
NavigationView& nav_;
segments segment;
bool file_error = false;
uint32_t sound_sizes[11];
const std::vector<std::string> file_names = {
{ "0" },
{ "1" },
{ "2" },
{ "3" },
{ "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 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;
uint8_t id_test, announce_loop;
uint32_t cnt;
uint32_t sample_duration;
int8_t audio_buffer[1024];
uint32_t pause = 0;
void on_tuning_frequency_changed(rf::Frequency f);
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
// For each day of the week, max 8 messages ?
@@ -95,14 +109,27 @@ private:
"Schedule:"
};
FrequencyField field_frequency {
{ 1 * 8, 4 },
};
NumberField number_bw {
{ 11 * 8, 3 * 16 },
{ 12 * 8, 2 * 16 },
3,
{1, 150},
1,
' '
};
SymField symfield_code {
{ 1*8, 3 * 16 },
10,
false
};
Button button_tx {
{ 21 * 8, 13 * 16, 64, 32 },
"TX !"
};
Button button_exit {
{ 21 * 8, 16 * 16, 64, 32 },
"Exit"
+11 -2
View File
@@ -20,6 +20,7 @@
*/
#include "ui_receiver.hpp"
#include "ui_freqman.hpp"
#include "portapack.hpp"
using namespace portapack;
@@ -140,14 +141,22 @@ FrequencyKeypadView::FrequencyKeypadView(
button.on_select = button_fn;
button.set_parent_rect({
(n % 3) * button_w,
(n / 3) * button_h + button_h,
(n / 3) * button_h + 24,
button_w, button_h
});
button.set_text(label);
n++;
}
add_children({ {
&button_save,
&button_close
} });
button_save.on_select = [this, &nav](Button&) {
nav.push<FrequencySaveView>(this->value());
};
add_child(&button_close);
button_close.on_select = [this, &nav](Button&) {
if( on_changed ) {
on_changed(this->value());
+6 -2
View File
@@ -198,13 +198,17 @@ private:
static constexpr int text_digits = mhz_digits + 1 + submhz_digits;
Text text_value {
{ 0, 0, text_digits * button_w, button_h }
{ 0, 4, 240, 16 }
};
std::array<Button, 12> buttons;
Button button_save {
{ 0, button_h * 4 + button_h, button_w, button_h },
"Save"
};
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"
};
+9 -9
View File
@@ -74,10 +74,11 @@ void SoundBoardView::prepare_audio() {
}
pbar.set_value(cnt);
size_t bytes_read = file.read(audio_buffer, 1024).value();
file.read(audio_buffer, 1024);
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;
cnt += 1024;
@@ -87,6 +88,10 @@ void SoundBoardView::prepare_audio() {
void SoundBoardView::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) {
@@ -202,7 +207,7 @@ void SoundBoardView::on_ctcss_changed(uint32_t v) {
SoundBoardView::SoundBoardView(
NavigationView& nav
)
) : nav_ (nav)
{
std::vector<std::string> file_list;
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_page = max_sound / 21; // 21 buttons per page
+2
View File
@@ -44,6 +44,8 @@ public:
std::string title() const override { return "Soundboard"; };
private:
NavigationView& nav_;
enum tx_modes {
NORMAL = 0,
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;
// 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 };
char ccir_message[21];
+2 -2
View File
@@ -110,12 +110,12 @@ constexpr region_t bootstrap {
constexpr region_t images {
.offset = 0x10000,
.size = 0x40000,
.size = 0x70000,
};
constexpr region_t application {
.offset = 0x80000,
.size = 0x40000,
.size = 0x50000,
};
} /* 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.