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

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

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"

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

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();
};

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"
};
};

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

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 }},

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();
}
}

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",
};

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();
};

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"

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());

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"
};

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

View File

@ -44,6 +44,8 @@ public:
std::string title() const override { return "Soundboard"; };
private:
NavigationView& nav_;
enum tx_modes {
NORMAL = 0,
RANDOM

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();
};
}
}

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__*/

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];

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.

BIN
sdcard/numbers/0.wav Normal file

Binary file not shown.

BIN
sdcard/numbers/1.wav Normal file

Binary file not shown.

BIN
sdcard/numbers/2.wav Normal file

Binary file not shown.

BIN
sdcard/numbers/3.wav Normal file

Binary file not shown.

BIN
sdcard/numbers/4.wav Normal file

Binary file not shown.

BIN
sdcard/numbers/5.wav Normal file

Binary file not shown.

BIN
sdcard/numbers/6.wav Normal file

Binary file not shown.

BIN
sdcard/numbers/7.wav Normal file

Binary file not shown.

BIN
sdcard/numbers/8.wav Normal file

Binary file not shown.

BIN
sdcard/numbers/9.wav Normal file

Binary file not shown.

BIN
sdcard/numbers/announce.wav Normal file

Binary file not shown.

Binary file not shown.