mirror of
https://github.com/eried/portapack-mayhem.git
synced 2024-12-24 06:49:24 -05:00
Bias-T now works in capture mode
Simplified soundboard app, still some work to do Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
1d13389b5a
@ -36,7 +36,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++14 -fno-rtti -fno-exceptions -Weffc++ -Wuninitialized")
|
set(USE_CPPOPT "-std=c++17 -fno-rtti -fno-exceptions -Weffc++ -Wuninitialized")
|
||||||
|
|
||||||
# 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)
|
||||||
@ -238,7 +238,6 @@ set(CPPSRC
|
|||||||
apps/ui_settings.cpp
|
apps/ui_settings.cpp
|
||||||
apps/ui_siggen.cpp
|
apps/ui_siggen.cpp
|
||||||
apps/ui_sonde.cpp
|
apps/ui_sonde.cpp
|
||||||
apps/ui_soundboard.cpp
|
|
||||||
apps/ui_sstvtx.cpp
|
apps/ui_sstvtx.cpp
|
||||||
# apps/ui_test.cpp
|
# apps/ui_test.cpp
|
||||||
apps/ui_tone_search.cpp
|
apps/ui_tone_search.cpp
|
||||||
@ -247,13 +246,14 @@ set(CPPSRC
|
|||||||
apps/ui_view_wav.cpp
|
apps/ui_view_wav.cpp
|
||||||
apps/ui_whipcalc.cpp
|
apps/ui_whipcalc.cpp
|
||||||
apps/acars_app.cpp
|
apps/acars_app.cpp
|
||||||
apps/analog_audio_app.cpp
|
|
||||||
apps/ais_app.cpp
|
apps/ais_app.cpp
|
||||||
apps/tpms_app.cpp
|
apps/analog_audio_app.cpp
|
||||||
apps/pocsag_app.cpp
|
|
||||||
apps/ert_app.cpp
|
|
||||||
apps/capture_app.cpp
|
apps/capture_app.cpp
|
||||||
|
apps/ert_app.cpp
|
||||||
|
apps/pocsag_app.cpp
|
||||||
apps/replay_app.cpp
|
apps/replay_app.cpp
|
||||||
|
apps/soundboard_app.cpp
|
||||||
|
apps/tpms_app.cpp
|
||||||
protocols/aprs.cpp
|
protocols/aprs.cpp
|
||||||
protocols/ax25.cpp
|
protocols/ax25.cpp
|
||||||
protocols/bht.cpp
|
protocols/bht.cpp
|
||||||
|
@ -27,9 +27,6 @@
|
|||||||
#include "portapack.hpp"
|
#include "portapack.hpp"
|
||||||
using namespace portapack;
|
using namespace portapack;
|
||||||
|
|
||||||
#include "portapack_persistent_memory.hpp"
|
|
||||||
using namespace portapack;
|
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
CaptureAppView::CaptureAppView(NavigationView& nav) {
|
CaptureAppView::CaptureAppView(NavigationView& nav) {
|
||||||
@ -49,20 +46,20 @@ CaptureAppView::CaptureAppView(NavigationView& nav) {
|
|||||||
&waterfall,
|
&waterfall,
|
||||||
});
|
});
|
||||||
|
|
||||||
field_frequency.set_value(target_frequency());
|
field_frequency.set_value(receiver_model.tuning_frequency());
|
||||||
field_frequency.set_step(receiver_model.frequency_step());
|
field_frequency.set_step(receiver_model.frequency_step());
|
||||||
field_frequency.on_change = [this](rf::Frequency f) {
|
field_frequency.on_change = [this](rf::Frequency f) {
|
||||||
this->on_target_frequency_changed(f);
|
this->on_tuning_frequency_changed(f);
|
||||||
};
|
};
|
||||||
field_frequency.on_edit = [this, &nav]() {
|
field_frequency.on_edit = [this, &nav]() {
|
||||||
// TODO: Provide separate modal method/scheme?
|
// TODO: Provide separate modal method/scheme?
|
||||||
auto new_view = nav.push<FrequencyKeypadView>(this->target_frequency());
|
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
|
||||||
new_view->on_changed = [this](rf::Frequency f) {
|
new_view->on_changed = [this](rf::Frequency f) {
|
||||||
this->on_target_frequency_changed(f);
|
this->on_tuning_frequency_changed(f);
|
||||||
this->field_frequency.set_value(f);
|
this->field_frequency.set_value(f);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
field_frequency_step.set_by_value(receiver_model.frequency_step());
|
field_frequency_step.set_by_value(receiver_model.frequency_step());
|
||||||
field_frequency_step.on_change = [this](size_t, OptionsField::value_t v) {
|
field_frequency_step.on_change = [this](size_t, OptionsField::value_t v) {
|
||||||
receiver_model.set_frequency_step(v);
|
receiver_model.set_frequency_step(v);
|
||||||
@ -70,26 +67,19 @@ CaptureAppView::CaptureAppView(NavigationView& nav) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
option_bandwidth.on_change = [this](size_t, uint32_t base_rate) {
|
option_bandwidth.on_change = [this](size_t, uint32_t base_rate) {
|
||||||
sampling_rate = 8 * base_rate;
|
sampling_rate = 8 * base_rate; // Decimation by 8 done on baseband side
|
||||||
|
|
||||||
waterfall.on_hide();
|
waterfall.on_hide();
|
||||||
set_target_frequency(target_frequency());
|
|
||||||
record_view.set_sampling_rate(sampling_rate);
|
record_view.set_sampling_rate(sampling_rate);
|
||||||
radio::set_baseband_rate(sampling_rate);
|
receiver_model.set_sampling_rate(sampling_rate);
|
||||||
waterfall.on_show();
|
waterfall.on_show();
|
||||||
};
|
};
|
||||||
|
|
||||||
radio::enable({
|
|
||||||
tuning_frequency(),
|
|
||||||
sampling_rate,
|
|
||||||
baseband_bandwidth,
|
|
||||||
rf::Direction::Receive,
|
|
||||||
receiver_model.rf_amp(),
|
|
||||||
static_cast<int8_t>(receiver_model.lna()),
|
|
||||||
static_cast<int8_t>(receiver_model.vga()),
|
|
||||||
});
|
|
||||||
|
|
||||||
option_bandwidth.set_selected_index(7); // 500k
|
option_bandwidth.set_selected_index(7); // 500k
|
||||||
|
|
||||||
|
receiver_model.set_modulation(ReceiverModel::Mode::Capture);
|
||||||
|
receiver_model.set_baseband_bandwidth(baseband_bandwidth);
|
||||||
|
receiver_model.enable();
|
||||||
|
|
||||||
record_view.on_error = [&nav](std::string message) {
|
record_view.on_error = [&nav](std::string message) {
|
||||||
nav.display_modal("Error", message);
|
nav.display_modal("Error", message);
|
||||||
@ -97,8 +87,7 @@ CaptureAppView::CaptureAppView(NavigationView& nav) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CaptureAppView::~CaptureAppView() {
|
CaptureAppView::~CaptureAppView() {
|
||||||
radio::disable();
|
receiver_model.disable();
|
||||||
|
|
||||||
baseband::shutdown();
|
baseband::shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,21 +109,8 @@ void CaptureAppView::focus() {
|
|||||||
record_view.focus();
|
record_view.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CaptureAppView::on_target_frequency_changed(rf::Frequency f) {
|
void CaptureAppView::on_tuning_frequency_changed(rf::Frequency f) {
|
||||||
set_target_frequency(f);
|
receiver_model.set_tuning_frequency(f);
|
||||||
}
|
|
||||||
|
|
||||||
void CaptureAppView::set_target_frequency(const rf::Frequency new_value) {
|
|
||||||
persistent_memory::set_tuned_frequency(new_value);;
|
|
||||||
radio::set_tuning_frequency(tuning_frequency());
|
|
||||||
}
|
|
||||||
|
|
||||||
rf::Frequency CaptureAppView::target_frequency() const {
|
|
||||||
return persistent_memory::tuned_frequency();
|
|
||||||
}
|
|
||||||
|
|
||||||
rf::Frequency CaptureAppView::tuning_frequency() const {
|
|
||||||
return target_frequency() - (sampling_rate / 4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* namespace ui */
|
} /* namespace ui */
|
||||||
|
@ -29,9 +29,6 @@
|
|||||||
#include "ui_record_view.hpp"
|
#include "ui_record_view.hpp"
|
||||||
#include "ui_spectrum.hpp"
|
#include "ui_spectrum.hpp"
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
class CaptureAppView : public View {
|
class CaptureAppView : public View {
|
||||||
@ -53,12 +50,7 @@ private:
|
|||||||
uint32_t sampling_rate = 0;
|
uint32_t sampling_rate = 0;
|
||||||
static constexpr uint32_t baseband_bandwidth = 2500000;
|
static constexpr uint32_t baseband_bandwidth = 2500000;
|
||||||
|
|
||||||
void on_target_frequency_changed(rf::Frequency f);
|
void on_tuning_frequency_changed(rf::Frequency f);
|
||||||
|
|
||||||
rf::Frequency target_frequency() const;
|
|
||||||
void set_target_frequency(const rf::Frequency new_value);
|
|
||||||
|
|
||||||
rf::Frequency tuning_frequency() const;
|
|
||||||
|
|
||||||
Labels labels {
|
Labels labels {
|
||||||
{ { 0 * 8, 1 * 16 }, "Rate:", Color::light_grey() },
|
{ { 0 * 8, 1 * 16 }, "Rate:", Color::light_grey() },
|
||||||
|
250
firmware/application/apps/soundboard_app.cpp
Normal file
250
firmware/application/apps/soundboard_app.cpp
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// To prepare samples: for f in ./*.wav; do sox "$f" -r 48000 -c 1 -b8 --norm "conv/$f"; done
|
||||||
|
|
||||||
|
#include "soundboard_app.hpp"
|
||||||
|
#include "string_format.hpp"
|
||||||
|
#include "tonesets.hpp"
|
||||||
|
|
||||||
|
using namespace tonekey;
|
||||||
|
using namespace portapack;
|
||||||
|
|
||||||
|
namespace ui {
|
||||||
|
|
||||||
|
bool SoundBoardView::is_active() const {
|
||||||
|
return (bool)replay_thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundBoardView::stop() {
|
||||||
|
if (is_active())
|
||||||
|
replay_thread.reset();
|
||||||
|
|
||||||
|
transmitter_model.disable();
|
||||||
|
tx_view.set_transmitting(false);
|
||||||
|
|
||||||
|
//button_play.set_bitmap(&bitmap_play);
|
||||||
|
ready_signal = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundBoardView::handle_replay_thread_done(const uint32_t return_code) {
|
||||||
|
stop();
|
||||||
|
progressbar.set_value(0);
|
||||||
|
|
||||||
|
if (return_code == ReplayThread::END_OF_FILE) {
|
||||||
|
if (check_random.value()) {
|
||||||
|
lfsr_v = lfsr_iterate(lfsr_v);
|
||||||
|
playing_id = lfsr_v % file_list.size();
|
||||||
|
menu_view.set_highlighted(playing_id);
|
||||||
|
start_tx(playing_id);
|
||||||
|
} else if (check_loop.value()) {
|
||||||
|
start_tx(playing_id);
|
||||||
|
}
|
||||||
|
} else if (return_code == ReplayThread::READ_ERROR) {
|
||||||
|
file_error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundBoardView::set_ready() {
|
||||||
|
ready_signal = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundBoardView::focus() {
|
||||||
|
menu_view.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundBoardView::file_error() {
|
||||||
|
nav_.display_modal("Error", "File read error.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundBoardView::start_tx(const uint32_t id) {
|
||||||
|
auto reader = std::make_unique<WAVFileReader>();
|
||||||
|
uint32_t tone_key_index = options_tone_key.selected_index();
|
||||||
|
uint32_t sample_rate;
|
||||||
|
|
||||||
|
stop();
|
||||||
|
|
||||||
|
if (!reader->open(u"/WAV/" + file_list[id].native())) {
|
||||||
|
file_error();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
playing_id = id;
|
||||||
|
|
||||||
|
progressbar.set_max(reader->sample_count());
|
||||||
|
|
||||||
|
//button_play.set_bitmap(&bitmap_stop);
|
||||||
|
|
||||||
|
sample_rate = reader->sample_rate();
|
||||||
|
|
||||||
|
replay_thread = std::make_unique<ReplayThread>(
|
||||||
|
std::move(reader),
|
||||||
|
read_size, buffer_count,
|
||||||
|
&ready_signal,
|
||||||
|
[](uint32_t return_code) {
|
||||||
|
ReplayThreadDoneMessage message { return_code };
|
||||||
|
EventDispatcher::send_message(message);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
baseband::set_audiotx_config(
|
||||||
|
1536000 / 20, // Update vu-meter at 20Hz
|
||||||
|
transmitter_model.channel_bandwidth(),
|
||||||
|
0, // Gain is unused
|
||||||
|
TONES_F2D(tone_key_frequency(tone_key_index), 1536000)
|
||||||
|
);
|
||||||
|
baseband::set_sample_rate(sample_rate);
|
||||||
|
|
||||||
|
transmitter_model.set_sampling_rate(1536000);
|
||||||
|
transmitter_model.set_baseband_bandwidth(1750000);
|
||||||
|
transmitter_model.enable();
|
||||||
|
|
||||||
|
tx_view.set_transmitting(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*void SoundBoardView::show_infos() {
|
||||||
|
if (!reader->open(file_list[menu_view.highlighted_index()]))
|
||||||
|
return;
|
||||||
|
|
||||||
|
text_duration.set(to_string_time_ms(reader->ms_duration()));
|
||||||
|
text_title.set(reader->title().substr(0, 15));
|
||||||
|
}*/
|
||||||
|
|
||||||
|
void SoundBoardView::on_tx_progress(const uint32_t progress) {
|
||||||
|
progressbar.set_value(progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundBoardView::on_select_entry() {
|
||||||
|
tx_view.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundBoardView::refresh_list() {
|
||||||
|
auto reader = std::make_unique<WAVFileReader>();
|
||||||
|
|
||||||
|
file_list.clear();
|
||||||
|
|
||||||
|
// List directories and files, put directories up top
|
||||||
|
for (const auto& entry : std::filesystem::directory_iterator(u"WAV", u"*")) {
|
||||||
|
if (std::filesystem::is_regular_file(entry.status())) {
|
||||||
|
if (entry.path().string().length()) {
|
||||||
|
|
||||||
|
auto entry_extension = entry.path().extension().string();
|
||||||
|
|
||||||
|
for (auto &c: entry_extension)
|
||||||
|
c = toupper(c);
|
||||||
|
|
||||||
|
if (entry_extension == ".WAV") {
|
||||||
|
|
||||||
|
if (reader->open(u"/WAV/" + entry.path().native())) {
|
||||||
|
if ((reader->channels() == 1) && (reader->bits_per_sample() == 8)) {
|
||||||
|
//sounds[c].ms_duration = reader->ms_duration();
|
||||||
|
//sounds[c].path = u"WAV/" + entry.path().native();
|
||||||
|
file_list.push_back(entry.path());
|
||||||
|
if (file_list.size() == 100)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file_list.size()) {
|
||||||
|
// Hide widgets, show warning
|
||||||
|
menu_view.hidden(true);
|
||||||
|
text_empty.hidden(false);
|
||||||
|
set_dirty();
|
||||||
|
} else {
|
||||||
|
// Hide warning, show widgets
|
||||||
|
menu_view.hidden(false);
|
||||||
|
text_empty.hidden(true);
|
||||||
|
set_dirty();
|
||||||
|
|
||||||
|
menu_view.clear();
|
||||||
|
|
||||||
|
for (size_t n = 0; n < file_list.size(); n++) {
|
||||||
|
menu_view.add_item({
|
||||||
|
file_list[n].string().substr(0, 30),
|
||||||
|
ui::Color::white(),
|
||||||
|
nullptr,
|
||||||
|
[this](){
|
||||||
|
on_select_entry();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
menu_view.set_highlighted(0); // Refresh
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundBoardView::SoundBoardView(
|
||||||
|
NavigationView& nav
|
||||||
|
) : nav_ (nav)
|
||||||
|
{
|
||||||
|
baseband::run_image(portapack::spi_flash::image_tag_audio_tx);
|
||||||
|
|
||||||
|
add_children({
|
||||||
|
&labels,
|
||||||
|
&menu_view,
|
||||||
|
&text_empty,
|
||||||
|
&options_tone_key,
|
||||||
|
&text_title,
|
||||||
|
&text_duration,
|
||||||
|
&progressbar,
|
||||||
|
&check_loop,
|
||||||
|
&check_random,
|
||||||
|
&tx_view
|
||||||
|
});
|
||||||
|
|
||||||
|
refresh_list();
|
||||||
|
|
||||||
|
text_title.set(to_string_dec_uint(file_list.size()));
|
||||||
|
|
||||||
|
tone_keys_populate(options_tone_key);
|
||||||
|
options_tone_key.set_selected_index(0);
|
||||||
|
|
||||||
|
check_loop.set_value(false);
|
||||||
|
check_random.set_value(false);
|
||||||
|
|
||||||
|
tx_view.on_edit_frequency = [this, &nav]() {
|
||||||
|
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
|
||||||
|
new_view->on_changed = [this](rf::Frequency f) {
|
||||||
|
transmitter_model.set_tuning_frequency(f);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
tx_view.on_start = [this]() {
|
||||||
|
start_tx(menu_view.highlighted_index());
|
||||||
|
};
|
||||||
|
|
||||||
|
tx_view.on_stop = [this]() {
|
||||||
|
tx_view.set_transmitting(false);
|
||||||
|
stop();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundBoardView::~SoundBoardView() {
|
||||||
|
transmitter_model.disable();
|
||||||
|
baseband::shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
161
firmware/application/apps/soundboard_app.hpp
Normal file
161
firmware/application/apps/soundboard_app.hpp
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
/*
|
||||||
|
* 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_SOUNDBOARD_H__
|
||||||
|
#define __UI_SOUNDBOARD_H__
|
||||||
|
|
||||||
|
#include "ui_widget.hpp"
|
||||||
|
#include "ui_transmitter.hpp"
|
||||||
|
#include "replay_thread.hpp"
|
||||||
|
#include "baseband_api.hpp"
|
||||||
|
#include "lfsr_random.hpp"
|
||||||
|
#include "io_wave.hpp"
|
||||||
|
#include "tone_key.hpp"
|
||||||
|
|
||||||
|
namespace ui {
|
||||||
|
|
||||||
|
class SoundBoardView : public View {
|
||||||
|
public:
|
||||||
|
SoundBoardView(NavigationView& nav);
|
||||||
|
~SoundBoardView();
|
||||||
|
|
||||||
|
SoundBoardView(const SoundBoardView&) = delete;
|
||||||
|
SoundBoardView(SoundBoardView&&) = delete;
|
||||||
|
SoundBoardView& operator=(const SoundBoardView&) = delete;
|
||||||
|
SoundBoardView& operator=(SoundBoardView&&) = delete;
|
||||||
|
|
||||||
|
void focus() override;
|
||||||
|
|
||||||
|
std::string title() const override { return "Soundboard"; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
NavigationView& nav_;
|
||||||
|
|
||||||
|
enum tx_modes {
|
||||||
|
NORMAL = 0,
|
||||||
|
RANDOM
|
||||||
|
};
|
||||||
|
|
||||||
|
tx_modes tx_mode = NORMAL;
|
||||||
|
|
||||||
|
uint32_t playing_id { };
|
||||||
|
|
||||||
|
std::vector<std::filesystem::path> file_list { };
|
||||||
|
|
||||||
|
const size_t read_size { 2048 }; // Less ?
|
||||||
|
const size_t buffer_count { 3 };
|
||||||
|
std::unique_ptr<ReplayThread> replay_thread { };
|
||||||
|
bool ready_signal { false };
|
||||||
|
lfsr_word_t lfsr_v = 1;
|
||||||
|
|
||||||
|
//void show_infos();
|
||||||
|
void start_tx(const uint32_t id);
|
||||||
|
//void on_ctcss_changed(uint32_t v);
|
||||||
|
void stop();
|
||||||
|
bool is_active() const;
|
||||||
|
void set_ready();
|
||||||
|
void handle_replay_thread_done(const uint32_t return_code);
|
||||||
|
void file_error();
|
||||||
|
void on_tx_progress(const uint32_t progress);
|
||||||
|
void refresh_list();
|
||||||
|
void on_select_entry();
|
||||||
|
|
||||||
|
Labels labels {
|
||||||
|
{ { 0, 20 * 8 + 4 }, "Title:", Color::light_grey() },
|
||||||
|
{ { 0, 23 * 8 }, "Key:", Color::light_grey() }
|
||||||
|
};
|
||||||
|
|
||||||
|
MenuView menu_view {
|
||||||
|
{ 0, 2 * 8, 240, 20 * 8 },
|
||||||
|
true
|
||||||
|
};
|
||||||
|
Text text_empty {
|
||||||
|
{ 7 * 8, 12 * 8, 16 * 8, 16 },
|
||||||
|
"Empty directory !",
|
||||||
|
};
|
||||||
|
|
||||||
|
Text text_title {
|
||||||
|
{ 6 * 8, 20 * 8 + 4, 15 * 8, 16 }
|
||||||
|
};
|
||||||
|
|
||||||
|
Text text_duration {
|
||||||
|
{ 22 * 8, 20 * 8 + 4, 6 * 8, 16 }
|
||||||
|
};
|
||||||
|
|
||||||
|
OptionsField options_tone_key {
|
||||||
|
{ 4 * 8, 23 * 8 },
|
||||||
|
18,
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
Checkbox check_loop {
|
||||||
|
{ 8, 25 * 8 + 4 },
|
||||||
|
4,
|
||||||
|
"Loop"
|
||||||
|
};
|
||||||
|
|
||||||
|
Checkbox check_random {
|
||||||
|
{ 10 * 8, 25 * 8 + 4 },
|
||||||
|
6,
|
||||||
|
"Random"
|
||||||
|
};
|
||||||
|
|
||||||
|
ProgressBar progressbar {
|
||||||
|
{ 0 * 8, 30 * 8 - 4, 30 * 8, 16 }
|
||||||
|
};
|
||||||
|
|
||||||
|
TransmitterView tx_view {
|
||||||
|
16 * 16,
|
||||||
|
5000,
|
||||||
|
12
|
||||||
|
};
|
||||||
|
|
||||||
|
MessageHandlerRegistration message_handler_replay_thread_error {
|
||||||
|
Message::ID::ReplayThreadDone,
|
||||||
|
[this](const Message* const p) {
|
||||||
|
const auto message = *reinterpret_cast<const ReplayThreadDoneMessage*>(p);
|
||||||
|
this->handle_replay_thread_done(message.return_code);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
MessageHandlerRegistration message_handler_fifo_signal {
|
||||||
|
Message::ID::RequestSignal,
|
||||||
|
[this](const Message* const p) {
|
||||||
|
const auto message = static_cast<const RequestSignalMessage*>(p);
|
||||||
|
if (message->signal == RequestSignalMessage::Signal::FillRequest) {
|
||||||
|
this->set_ready();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
MessageHandlerRegistration message_handler_tx_progress {
|
||||||
|
Message::ID::TXProgress,
|
||||||
|
[this](const Message* const p) {
|
||||||
|
const auto message = *reinterpret_cast<const TXProgressMessage*>(p);
|
||||||
|
this->on_tx_progress(message.progress);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace ui */
|
||||||
|
|
||||||
|
#endif/*__UI_SOUNDBOARD_H__*/
|
@ -247,10 +247,10 @@ constexpr ClockControls si5351_clock_control_clkin {
|
|||||||
si5351_clock_control_common[4] | si5351_clock_control_ms_src_clkin,
|
si5351_clock_control_common[4] | si5351_clock_control_ms_src_clkin,
|
||||||
si5351_clock_control_common[5] | si5351_clock_control_ms_src_clkin,
|
si5351_clock_control_common[5] | si5351_clock_control_ms_src_clkin,
|
||||||
si5351_clock_control_common[6] | si5351_clock_control_ms_src_clkin,
|
si5351_clock_control_common[6] | si5351_clock_control_ms_src_clkin,
|
||||||
si5351_clock_control_common[7] | si5351_clock_control_ms_src_xtal,
|
si5351_clock_control_common[7] | si5351_clock_control_ms_src_clkin,
|
||||||
};
|
};
|
||||||
|
|
||||||
void ClockManager::init(const bool use_clkin) {
|
void ClockManager::init() {
|
||||||
/* Must be sure to run the M4 core from IRC when messing with the signal
|
/* Must be sure to run the M4 core from IRC when messing with the signal
|
||||||
* generator that sources the GP_CLKIN signal that drives the micro-
|
* generator that sources the GP_CLKIN signal that drives the micro-
|
||||||
* controller's PLL1 input.
|
* controller's PLL1 input.
|
||||||
@ -269,11 +269,23 @@ void ClockManager::init(const bool use_clkin) {
|
|||||||
clock_generator.enable_fanout();
|
clock_generator.enable_fanout();
|
||||||
clock_generator.set_pll_input_sources(si5351_pll_input_sources);
|
clock_generator.set_pll_input_sources(si5351_pll_input_sources);
|
||||||
|
|
||||||
//const bool use_clkin = false;
|
const auto clkin_present = !clock_generator.clkin_loss_of_signal();
|
||||||
|
auto clkin_valid = false;
|
||||||
|
|
||||||
|
if( clkin_present ) {
|
||||||
|
// Measure Si5351B CLKIN frequency against LPC43xx IRC oscillator
|
||||||
|
set_gp_clkin_to_clkin_direct();
|
||||||
|
start_frequency_monitor_measurement(cgu::CLK_SEL::GP_CLKIN);
|
||||||
|
wait_For_frequency_monitor_measurement_done();
|
||||||
|
const auto clkin_frequency = get_frequency_monitor_measurement_in_hertz();
|
||||||
|
|
||||||
|
// CLKIN is required to be 10MHz. FREQ_MON measurement is accurate to 1.5%
|
||||||
|
// due to LPC43xx IRC oscillator precision.
|
||||||
|
clkin_valid = (clkin_frequency >= 9850000) && (clkin_frequency <= 10150000);
|
||||||
|
}
|
||||||
|
|
||||||
clock_generator.set_clock_control(
|
clock_generator.set_clock_control(
|
||||||
use_clkin ?
|
clkin_valid ? si5351_clock_control_clkin : si5351_clock_control_xtal
|
||||||
si5351_clock_control_clkin
|
|
||||||
: si5351_clock_control_xtal
|
|
||||||
);
|
);
|
||||||
|
|
||||||
clock_generator.write(si5351_pll_a_xtal_reg);
|
clock_generator.write(si5351_pll_a_xtal_reg);
|
||||||
@ -422,6 +434,38 @@ void ClockManager::disable_gp_clkin_source() {
|
|||||||
clock_generator.disable_output(clock_generator_output_mcu_clkin);
|
clock_generator.disable_output(clock_generator_output_mcu_clkin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClockManager::set_gp_clkin_to_clkin_direct() {
|
||||||
|
clock_generator.set_clock_control(
|
||||||
|
clock_generator_output_mcu_clkin,
|
||||||
|
{ ClockControl::CLK_IDRV_2mA | ClockControl::CLK_SRC_CLKIN | ClockControl::CLK_INV_Normal | ClockControl::MS_INT_Integer | ClockControl::CLK_PDN_Power_On }
|
||||||
|
);
|
||||||
|
enable_gp_clkin_source();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClockManager::start_frequency_monitor_measurement(const cgu::CLK_SEL clk_sel) {
|
||||||
|
// Measure a clock input for 480 cycles of the LPC43xx IRC.
|
||||||
|
LPC_CGU->FREQ_MON = LPC_CGU_FREQ_MON_Type {
|
||||||
|
.RCNT = 480,
|
||||||
|
.FCNT = 0,
|
||||||
|
.MEAS = 0,
|
||||||
|
.CLK_SEL = toUType(clk_sel),
|
||||||
|
.RESERVED0 = 0
|
||||||
|
};
|
||||||
|
LPC_CGU->FREQ_MON.MEAS = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClockManager::wait_For_frequency_monitor_measurement_done() {
|
||||||
|
// FREQ_MON mechanism fails to finish if there's no clock present on selected input?!
|
||||||
|
while(LPC_CGU->FREQ_MON.MEAS == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ClockManager::get_frequency_monitor_measurement_in_hertz() {
|
||||||
|
// Measurement is only as accurate as the LPC43xx IRC oscillator,
|
||||||
|
// which is +/- 1.5%. Measurement is for 480 IRC clcocks. Scale
|
||||||
|
// the cycle count to get a value in Hertz.
|
||||||
|
return LPC_CGU->FREQ_MON.FCNT * 25000;
|
||||||
|
}
|
||||||
|
|
||||||
void ClockManager::enable_xtal_oscillator() {
|
void ClockManager::enable_xtal_oscillator() {
|
||||||
LPC_CGU->XTAL_OSC_CTRL.BYPASS = 0;
|
LPC_CGU->XTAL_OSC_CTRL.BYPASS = 0;
|
||||||
LPC_CGU->XTAL_OSC_CTRL.ENABLE = 1;
|
LPC_CGU->XTAL_OSC_CTRL.ENABLE = 1;
|
||||||
|
@ -42,7 +42,7 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void init(const bool use_clkin);
|
void init();
|
||||||
void shutdown();
|
void shutdown();
|
||||||
|
|
||||||
void run_from_irc();
|
void run_from_irc();
|
||||||
@ -66,6 +66,8 @@ public:
|
|||||||
|
|
||||||
void set_reference_ppb(const int32_t ppb);
|
void set_reference_ppb(const int32_t ppb);
|
||||||
|
|
||||||
|
uint32_t get_frequency_monitor_measurement_in_hertz();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
I2C& i2c0;
|
I2C& i2c0;
|
||||||
si5351::Si5351& clock_generator;
|
si5351::Si5351& clock_generator;
|
||||||
@ -75,6 +77,10 @@ private:
|
|||||||
|
|
||||||
void enable_gp_clkin_source();
|
void enable_gp_clkin_source();
|
||||||
void disable_gp_clkin_source();
|
void disable_gp_clkin_source();
|
||||||
|
void set_gp_clkin_to_clkin_direct();
|
||||||
|
|
||||||
|
void start_frequency_monitor_measurement(const cgu::CLK_SEL clk_sel);
|
||||||
|
void wait_For_frequency_monitor_measurement_done();
|
||||||
|
|
||||||
void enable_xtal_oscillator();
|
void enable_xtal_oscillator();
|
||||||
void disable_xtal_oscillator();
|
void disable_xtal_oscillator();
|
||||||
|
@ -306,6 +306,10 @@ public:
|
|||||||
while(device_status() & 0x80);
|
while(device_status() & 0x80);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool clkin_loss_of_signal() {
|
||||||
|
return (device_status() >> 4) & 1;
|
||||||
|
}
|
||||||
|
|
||||||
void enable_fanout() {
|
void enable_fanout() {
|
||||||
write_register(Register::FanoutEnable, 0b11010000);
|
write_register(Register::FanoutEnable, 0b11010000);
|
||||||
}
|
}
|
||||||
@ -369,6 +373,11 @@ public:
|
|||||||
update_all_clock_control();
|
update_all_clock_control();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_clock_control(const size_t n, const ClockControl::Type clock_control) {
|
||||||
|
_clock_control[n] = clock_control;
|
||||||
|
write_register(Register::CLKControl_Base + n, _clock_control[n]);
|
||||||
|
}
|
||||||
|
|
||||||
void enable_clock(const size_t n) {
|
void enable_clock(const size_t n) {
|
||||||
_clock_control[n] &= ~ClockControl::CLK_PDN_Mask;
|
_clock_control[n] &= ~ClockControl::CLK_PDN_Mask;
|
||||||
write_register(Register::CLKControl_Base + n, _clock_control[n]);
|
write_register(Register::CLKControl_Base + n, _clock_control[n]);
|
||||||
|
@ -104,7 +104,7 @@ void poll_ext_clock() {
|
|||||||
if (clkin_status != prev_clkin_status) {
|
if (clkin_status != prev_clkin_status) {
|
||||||
StatusRefreshMessage message { };
|
StatusRefreshMessage message { };
|
||||||
EventDispatcher::send_message(message);
|
EventDispatcher::send_message(message);
|
||||||
clock_manager.init(clkin_status);
|
clock_manager.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
prev_clkin_status = clkin_status;
|
prev_clkin_status = clkin_status;
|
||||||
@ -296,7 +296,7 @@ bool init() {
|
|||||||
led_rx.setup();
|
led_rx.setup();
|
||||||
led_tx.setup();
|
led_tx.setup();
|
||||||
|
|
||||||
clock_manager.init(false);
|
clock_manager.init();
|
||||||
clock_manager.set_reference_ppb(persistent_memory::correction_ppb());
|
clock_manager.set_reference_ppb(persistent_memory::correction_ppb());
|
||||||
clock_manager.run_at_full_speed();
|
clock_manager.run_at_full_speed();
|
||||||
|
|
||||||
|
@ -275,6 +275,7 @@ void ReceiverModel::update_modulation() {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Mode::SpectrumAnalysis:
|
case Mode::SpectrumAnalysis:
|
||||||
|
case Mode::Capture:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@ public:
|
|||||||
NarrowbandFMAudio = 1,
|
NarrowbandFMAudio = 1,
|
||||||
WidebandFMAudio = 2,
|
WidebandFMAudio = 2,
|
||||||
SpectrumAnalysis = 3,
|
SpectrumAnalysis = 3,
|
||||||
|
Capture = 4
|
||||||
};
|
};
|
||||||
|
|
||||||
rf::Frequency tuning_frequency() const;
|
rf::Frequency tuning_frequency() const;
|
||||||
|
@ -78,8 +78,8 @@ const tone_key_t tone_keys = {
|
|||||||
{ "38 --", 250.300 },
|
{ "38 --", 250.300 },
|
||||||
{ "50 0Z", 254.100 },
|
{ "50 0Z", 254.100 },
|
||||||
{ "Axient 28kHz", 28000.0 },
|
{ "Axient 28kHz", 28000.0 },
|
||||||
{ "Sennheiser 32.768k", 32768.0 },
|
{ "Senn. 32.768k", 32768.0 },
|
||||||
{ "Sennheiser 32.000k", 32000.0 },
|
{ "Senn. 32.000k", 32000.0 },
|
||||||
{ "Sony 32.382k", 32382.0 },
|
{ "Sony 32.382k", 32382.0 },
|
||||||
{ "Shure 19kHz", 19000.0 }
|
{ "Shure 19kHz", 19000.0 }
|
||||||
};
|
};
|
||||||
|
@ -58,7 +58,6 @@
|
|||||||
#include "ui_settings.hpp"
|
#include "ui_settings.hpp"
|
||||||
#include "ui_siggen.hpp"
|
#include "ui_siggen.hpp"
|
||||||
#include "ui_sonde.hpp"
|
#include "ui_sonde.hpp"
|
||||||
#include "ui_soundboard.hpp"
|
|
||||||
#include "ui_sstvtx.hpp"
|
#include "ui_sstvtx.hpp"
|
||||||
//#include "ui_test.hpp"
|
//#include "ui_test.hpp"
|
||||||
#include "ui_tone_search.hpp"
|
#include "ui_tone_search.hpp"
|
||||||
@ -73,6 +72,7 @@
|
|||||||
#include "ert_app.hpp"
|
#include "ert_app.hpp"
|
||||||
#include "pocsag_app.hpp"
|
#include "pocsag_app.hpp"
|
||||||
#include "replay_app.hpp"
|
#include "replay_app.hpp"
|
||||||
|
#include "soundboard_app.hpp"
|
||||||
#include "tpms_app.hpp"
|
#include "tpms_app.hpp"
|
||||||
|
|
||||||
#include "core_control.hpp"
|
#include "core_control.hpp"
|
||||||
@ -166,6 +166,8 @@ void SystemStatusView::refresh() {
|
|||||||
image_clock_status.set_bitmap(&bitmap_icon_clk_int);
|
image_clock_status.set_bitmap(&bitmap_icon_clk_int);
|
||||||
button_bias_tee.set_foreground(ui::Color::light_grey());
|
button_bias_tee.set_foreground(ui::Color::light_grey());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_dirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemStatusView::set_back_enabled(bool new_value) {
|
void SystemStatusView::set_back_enabled(bool new_value) {
|
||||||
@ -186,9 +188,7 @@ void SystemStatusView::on_stealth() {
|
|||||||
|
|
||||||
portapack::persistent_memory::set_stealth_mode(mode);
|
portapack::persistent_memory::set_stealth_mode(mode);
|
||||||
|
|
||||||
button_stealth.set_foreground(mode ? ui::Color::green() : ui::Color::light_grey());
|
button_stealth.set_foreground(mode ? Color::green() : Color::light_grey());
|
||||||
|
|
||||||
button_stealth.set_dirty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemStatusView::on_bias_tee() {
|
void SystemStatusView::on_bias_tee() {
|
||||||
@ -196,6 +196,7 @@ void SystemStatusView::on_bias_tee() {
|
|||||||
nav_.display_modal("Bias voltage", "Enable DC voltage on\nantenna connector ?", YESNO, [this](bool v) {
|
nav_.display_modal("Bias voltage", "Enable DC voltage on\nantenna connector ?", YESNO, [this](bool v) {
|
||||||
if (v) {
|
if (v) {
|
||||||
portapack::set_antenna_bias(true);
|
portapack::set_antenna_bias(true);
|
||||||
|
//radio::set_antenna_bias(true);
|
||||||
receiver_model.set_antenna_bias();
|
receiver_model.set_antenna_bias();
|
||||||
transmitter_model.set_antenna_bias();
|
transmitter_model.set_antenna_bias();
|
||||||
refresh();
|
refresh();
|
||||||
@ -203,6 +204,7 @@ void SystemStatusView::on_bias_tee() {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
portapack::set_antenna_bias(false);
|
portapack::set_antenna_bias(false);
|
||||||
|
//radio::set_antenna_bias(false);
|
||||||
receiver_model.set_antenna_bias();
|
receiver_model.set_antenna_bias();
|
||||||
transmitter_model.set_antenna_bias();
|
transmitter_model.set_antenna_bias();
|
||||||
refresh();
|
refresh();
|
||||||
@ -371,7 +373,7 @@ TransmittersMenuView::TransmittersMenuView(NavigationView& nav) {
|
|||||||
{ "Key fob", ui::Color::orange(), &bitmap_icon_keyfob, [&nav](){ nav.push<KeyfobView>(); } },
|
{ "Key fob", ui::Color::orange(), &bitmap_icon_keyfob, [&nav](){ nav.push<KeyfobView>(); } },
|
||||||
{ "Microphone", ui::Color::green(), &bitmap_icon_microphone, [&nav](){ nav.push<MicTXView>(); } },
|
{ "Microphone", ui::Color::green(), &bitmap_icon_microphone, [&nav](){ nav.push<MicTXView>(); } },
|
||||||
{ "Morse code", ui::Color::green(), &bitmap_icon_morse, [&nav](){ nav.push<MorseView>(); } },
|
{ "Morse code", ui::Color::green(), &bitmap_icon_morse, [&nav](){ nav.push<MorseView>(); } },
|
||||||
{ "NTTWorks burger pager", ui::Color::yellow(), &bitmap_icon_burger, [&nav](){ nav.push<CoasterPagerView>(); } },
|
{ "Burger pagers", ui::Color::yellow(), &bitmap_icon_burger, [&nav](){ nav.push<CoasterPagerView>(); } },
|
||||||
//{ "Nuoptix DTMF timecode", ui::Color::green(), &bitmap_icon_nuoptix, [&nav](){ nav.push<NuoptixView>(); } },
|
//{ "Nuoptix DTMF timecode", ui::Color::green(), &bitmap_icon_nuoptix, [&nav](){ nav.push<NuoptixView>(); } },
|
||||||
{ "OOK encoders", ui::Color::yellow(), &bitmap_icon_remote, [&nav](){ nav.push<EncodersView>(); } },
|
{ "OOK encoders", ui::Color::yellow(), &bitmap_icon_remote, [&nav](){ nav.push<EncodersView>(); } },
|
||||||
{ "POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav](){ nav.push<POCSAGTXView>(); } },
|
{ "POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav](){ nav.push<POCSAGTXView>(); } },
|
||||||
@ -478,10 +480,12 @@ SystemView::SystemView(
|
|||||||
navigation_view.push<PlayDeadView>();
|
navigation_view.push<PlayDeadView>();
|
||||||
} else {*/
|
} else {*/
|
||||||
|
|
||||||
|
navigation_view.push<SystemMenuView>();
|
||||||
|
|
||||||
if (portapack::persistent_memory::config_splash())
|
if (portapack::persistent_memory::config_splash())
|
||||||
navigation_view.push<BMPView>();
|
navigation_view.push<BMPView>();
|
||||||
else
|
//else
|
||||||
navigation_view.push<SystemMenuView>();
|
// navigation_view.push<SystemMenuView>();
|
||||||
|
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
@ -504,7 +508,6 @@ BMPView::BMPView(NavigationView& nav) {
|
|||||||
|
|
||||||
button_done.on_select = [this, &nav](Button&){
|
button_done.on_select = [this, &nav](Button&){
|
||||||
nav.pop();
|
nav.pop();
|
||||||
nav.push<SystemMenuView>();
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ set(USE_OPT "-O3 -g -falign-functions=16 -fno-math-errno --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++14 -fno-rtti -fno-exceptions -Weffc++ -Wuninitialized")
|
set(USE_CPPOPT "-std=c++17 -fno-rtti -fno-exceptions -Weffc++ -Wuninitialized")
|
||||||
|
|
||||||
# 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)
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
#include "proc_audiotx.hpp"
|
#include "proc_audiotx.hpp"
|
||||||
#include "portapack_shared_memory.hpp"
|
#include "portapack_shared_memory.hpp"
|
||||||
#include "sine_table_int8.hpp"
|
#include "sine_table_int8.hpp"
|
||||||
//#include "audio_output.hpp"
|
|
||||||
#include "event_m4.hpp"
|
#include "event_m4.hpp"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
@ -32,17 +31,18 @@ void AudioTXProcessor::execute(const buffer_c8_t& buffer){
|
|||||||
|
|
||||||
if (!configured) return;
|
if (!configured) return;
|
||||||
|
|
||||||
if( stream ) {
|
// Zero-order hold (poop)
|
||||||
const size_t bytes_to_read = (buffer.count / 32); // /32 (oversampling) should be == 64
|
|
||||||
bytes_read += stream->read(audio_buffer.p, bytes_to_read);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill and "stretch"
|
|
||||||
for (size_t i = 0; i < buffer.count; i++) {
|
for (size_t i = 0; i < buffer.count; i++) {
|
||||||
if (!(i & 31))
|
resample_acc += resample_inc;
|
||||||
audio_sample = audio_buffer.p[i >> 5] - 0x80;
|
if (resample_acc >= 0x10000) {
|
||||||
|
resample_acc -= 0x10000;
|
||||||
|
if (stream) {
|
||||||
|
stream->read(&audio_sample, 1);
|
||||||
|
bytes_read++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sample = tone_gen.process(audio_sample);
|
sample = tone_gen.process(audio_sample - 0x80);
|
||||||
|
|
||||||
// FM
|
// FM
|
||||||
delta = sample * fm_delta;
|
delta = sample * fm_delta;
|
||||||
@ -50,22 +50,20 @@ void AudioTXProcessor::execute(const buffer_c8_t& buffer){
|
|||||||
phase += delta;
|
phase += delta;
|
||||||
sphase = phase + (64 << 24);
|
sphase = phase + (64 << 24);
|
||||||
|
|
||||||
re = (sine_table_i8[(sphase & 0xFF000000U) >> 24]);
|
re = sine_table_i8[(sphase & 0xFF000000U) >> 24];
|
||||||
im = (sine_table_i8[(phase & 0xFF000000U) >> 24]);
|
im = sine_table_i8[(phase & 0xFF000000U) >> 24];
|
||||||
|
|
||||||
buffer.p[i] = { (int8_t)re, (int8_t)im };
|
buffer.p[i] = { (int8_t)re, (int8_t)im };
|
||||||
}
|
}
|
||||||
|
|
||||||
spectrum_samples += buffer.count;
|
progress_samples += buffer.count;
|
||||||
if( spectrum_samples >= spectrum_interval_samples ) {
|
if (progress_samples >= progress_interval_samples) {
|
||||||
spectrum_samples -= spectrum_interval_samples;
|
progress_samples -= progress_interval_samples;
|
||||||
|
|
||||||
txprogress_message.progress = bytes_read; // Inform UI about progress
|
txprogress_message.progress = bytes_read; // Inform UI about progress
|
||||||
txprogress_message.done = false;
|
txprogress_message.done = false;
|
||||||
shared_memory.application_queue.push(txprogress_message);
|
shared_memory.application_queue.push(txprogress_message);
|
||||||
}
|
}
|
||||||
|
|
||||||
//AudioOutput::fill_audio_buffer(preview_audio_buffer, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioTXProcessor::on_message(const Message* const message) {
|
void AudioTXProcessor::on_message(const Message* const message) {
|
||||||
@ -96,12 +94,8 @@ void AudioTXProcessor::on_message(const Message* const message) {
|
|||||||
void AudioTXProcessor::audio_config(const AudioTXConfigMessage& message) {
|
void AudioTXProcessor::audio_config(const AudioTXConfigMessage& message) {
|
||||||
fm_delta = message.deviation_hz * (0xFFFFFFULL / baseband_fs);
|
fm_delta = message.deviation_hz * (0xFFFFFFULL / baseband_fs);
|
||||||
tone_gen.configure(message.tone_key_delta, message.tone_key_mix_weight);
|
tone_gen.configure(message.tone_key_delta, message.tone_key_mix_weight);
|
||||||
}
|
progress_interval_samples = message.divider;
|
||||||
|
resample_acc = 0;
|
||||||
void AudioTXProcessor::samplerate_config(const SamplerateConfigMessage& message) {
|
|
||||||
baseband_fs = message.sample_rate;
|
|
||||||
baseband_thread.set_sampling_rate(baseband_fs);
|
|
||||||
spectrum_interval_samples = baseband_fs / 20;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioTXProcessor::replay_config(const ReplayConfigMessage& message) {
|
void AudioTXProcessor::replay_config(const ReplayConfigMessage& message) {
|
||||||
@ -116,6 +110,10 @@ void AudioTXProcessor::replay_config(const ReplayConfigMessage& message) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioTXProcessor::samplerate_config(const SamplerateConfigMessage& message) {
|
||||||
|
resample_inc = (((uint64_t)message.sample_rate) << 16) / baseband_fs; // 16.16 fixed point message.sample_rate
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
EventDispatcher event_dispatcher { std::make_unique<AudioTXProcessor>() };
|
EventDispatcher event_dispatcher { std::make_unique<AudioTXProcessor>() };
|
||||||
event_dispatcher.run();
|
event_dispatcher.run();
|
||||||
|
@ -35,35 +35,22 @@ public:
|
|||||||
void on_message(const Message* const msg) override;
|
void on_message(const Message* const msg) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
size_t baseband_fs = 0;
|
static constexpr size_t baseband_fs = 1536000;
|
||||||
|
|
||||||
BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Transmit };
|
BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Transmit };
|
||||||
|
|
||||||
std::array<uint8_t, 64> audio { };
|
|
||||||
const buffer_t<uint8_t> audio_buffer {
|
|
||||||
audio.data(),
|
|
||||||
audio.size(),
|
|
||||||
baseband_fs / 8
|
|
||||||
};
|
|
||||||
|
|
||||||
std::unique_ptr<StreamOutput> stream { };
|
std::unique_ptr<StreamOutput> stream { };
|
||||||
|
|
||||||
ToneGen tone_gen { };
|
ToneGen tone_gen { };
|
||||||
|
|
||||||
|
uint32_t resample_inc { }, resample_acc { };
|
||||||
uint32_t fm_delta { 0 };
|
uint32_t fm_delta { 0 };
|
||||||
uint32_t phase { 0 }, sphase { 0 };
|
uint32_t phase { 0 }, sphase { 0 };
|
||||||
int8_t out_sample { };
|
uint8_t audio_sample { };
|
||||||
int32_t sample { 0 }, audio_sample { 0 }, delta { };
|
int32_t sample { 0 }, delta { };
|
||||||
int8_t re { 0 }, im { 0 };
|
int8_t re { 0 }, im { 0 };
|
||||||
|
|
||||||
size_t spectrum_interval_samples = 0;
|
size_t progress_interval_samples, progress_samples = 0;
|
||||||
size_t spectrum_samples = 0;
|
|
||||||
|
|
||||||
//int16_t audio_data[64];
|
|
||||||
/*const buffer_s16_t preview_audio_buffer {
|
|
||||||
audio_data,
|
|
||||||
sizeof(int16_t)*64
|
|
||||||
};*/
|
|
||||||
|
|
||||||
bool configured { false };
|
bool configured { false };
|
||||||
uint32_t bytes_read { 0 };
|
uint32_t bytes_read { 0 };
|
||||||
|
@ -35,7 +35,7 @@ set(USE_OPT "-Os -g -falign-functions=16 -fno-math-errno --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++14 -fno-rtti -fno-exceptions -Weffc++ -Wuninitialized")
|
set(USE_CPPOPT "-std=c++17 -fno-rtti -fno-exceptions -Weffc++ -Wuninitialized")
|
||||||
|
|
||||||
# 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)
|
||||||
|
@ -307,6 +307,10 @@ __STATIC_INLINE void __set_FPSCR(uint32_t fpscr)
|
|||||||
#elif defined ( __GNUC__ ) /*------------------ GNU Compiler ---------------------*/
|
#elif defined ( __GNUC__ ) /*------------------ GNU Compiler ---------------------*/
|
||||||
/* GNU gcc specific functions */
|
/* GNU gcc specific functions */
|
||||||
|
|
||||||
|
#ifndef __STATIC_FORCEINLINE
|
||||||
|
#define __STATIC_FORCEINLINE __attribute__((always_inline)) static inline
|
||||||
|
#endif
|
||||||
|
|
||||||
/** \brief Enable IRQ Interrupts
|
/** \brief Enable IRQ Interrupts
|
||||||
|
|
||||||
This function enables IRQ interrupts by clearing the I-bit in the CPSR.
|
This function enables IRQ interrupts by clearing the I-bit in the CPSR.
|
||||||
@ -403,15 +407,15 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_xPSR(void)
|
|||||||
|
|
||||||
/** \brief Get Process Stack Pointer
|
/** \brief Get Process Stack Pointer
|
||||||
|
|
||||||
This function returns the current value of the Process Stack Pointer (PSP).
|
\details Returns the current value of the Process Stack Pointer (PSP).
|
||||||
|
|
||||||
\return PSP Register value
|
\return PSP Register value
|
||||||
*/
|
*/
|
||||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_PSP(void)
|
__STATIC_FORCEINLINE uint32_t __get_PSP(void)
|
||||||
{
|
{
|
||||||
register uint32_t result;
|
uint32_t result;
|
||||||
|
|
||||||
__ASM volatile ("MRS %0, psp\n" : "=r" (result) );
|
__ASM volatile ("MRS %0, psp" : "=r" (result) );
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -430,19 +434,18 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE void __set_PSP(uint32_t topOf
|
|||||||
|
|
||||||
/** \brief Get Main Stack Pointer
|
/** \brief Get Main Stack Pointer
|
||||||
|
|
||||||
This function returns the current value of the Main Stack Pointer (MSP).
|
\details Returns the current value of the Main Stack Pointer (MSP).
|
||||||
|
|
||||||
\return MSP Register value
|
\return MSP Register value
|
||||||
*/
|
*/
|
||||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_MSP(void)
|
__STATIC_FORCEINLINE uint32_t __get_MSP(void)
|
||||||
{
|
{
|
||||||
register uint32_t result;
|
uint32_t result;
|
||||||
|
|
||||||
__ASM volatile ("MRS %0, msp\n" : "=r" (result) );
|
__ASM volatile ("MRS %0, msp" : "=r" (result) );
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** \brief Set Main Stack Pointer
|
/** \brief Set Main Stack Pointer
|
||||||
|
|
||||||
This function assigns the given value to the Main Stack Pointer (MSP).
|
This function assigns the given value to the Main Stack Pointer (MSP).
|
||||||
|
@ -108,7 +108,7 @@ inline void clear() {
|
|||||||
|
|
||||||
namespace cgu {
|
namespace cgu {
|
||||||
|
|
||||||
enum class CLK_SEL {
|
enum class CLK_SEL : uint8_t {
|
||||||
RTC_32KHZ = 0x00,
|
RTC_32KHZ = 0x00,
|
||||||
IRC = 0x01,
|
IRC = 0x01,
|
||||||
ENET_RX_CLK = 0x02,
|
ENET_RX_CLK = 0x02,
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 11 KiB |
Loading…
Reference in New Issue
Block a user