mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2024-12-04 23:45:26 +00:00
Remove dead code (#2304)
* remove dead code, playdead * removed Nuoptix * remove ui_loadmodule * removed modules.h * removed replay_app * removed handwrite * removed numbers, script * remove emu_cc1101 * removed noop, old pocsag * removed unused abouts * removed tone_search * fix format * forgot to remove * removed unused py * removed modules.h too
This commit is contained in:
parent
1b3359b050
commit
66aa20161d
@ -191,7 +191,6 @@ set(CPPSRC
|
||||
core_control.cpp
|
||||
database.cpp
|
||||
de_bruijn.cpp
|
||||
#emu_cc1101.cpp
|
||||
rfm69.cpp
|
||||
event_m0.cpp
|
||||
file_reader.cpp
|
||||
@ -246,7 +245,6 @@ set(CPPSRC
|
||||
hw/touch_adc.cpp
|
||||
ui_baseband_stats_view.cpp
|
||||
ui_navigation.cpp
|
||||
ui_playdead.cpp
|
||||
ui_record_view.cpp
|
||||
ui_sd_card_status_view.cpp
|
||||
ui/ui_alphanum.cpp
|
||||
@ -270,28 +268,21 @@ set(CPPSRC
|
||||
ui/ui_bmpview.cpp
|
||||
apps/ais_app.cpp
|
||||
apps/analog_audio_app.cpp
|
||||
# apps/analog_tv_app.cpp
|
||||
apps/ble_comm_app.cpp
|
||||
apps/ble_rx_app.cpp
|
||||
apps/ble_tx_app.cpp
|
||||
apps/capture_app.cpp
|
||||
apps/ert_app.cpp
|
||||
# apps/gps_sim_app.cpp
|
||||
# apps/lge_app.cpp
|
||||
apps/pocsag_app.cpp
|
||||
# apps/replay_app.cpp
|
||||
apps/soundboard_app.cpp
|
||||
# apps/tpms_app.cpp
|
||||
apps/ui_about_simple.cpp
|
||||
apps/ui_adsb_rx.cpp
|
||||
# apps/ui_adsb_tx.cpp #moved to ext
|
||||
apps/ui_aprs_rx.cpp
|
||||
apps/ui_aprs_tx.cpp
|
||||
apps/ui_battinfo.cpp
|
||||
apps/ui_bht_tx.cpp
|
||||
apps/ui_bmp_file_viewer.cpp
|
||||
apps/ui_btle_rx.cpp
|
||||
# apps/ui_coasterp.cpp
|
||||
apps/ui_debug.cpp
|
||||
apps/ui_debug_max17055.cpp
|
||||
apps/ui_dfu_menu.cpp
|
||||
@ -302,16 +293,10 @@ set(CPPSRC
|
||||
apps/ui_freqman.cpp
|
||||
apps/ui_fsk_rx.cpp
|
||||
apps/ui_iq_trim.cpp
|
||||
# apps/ui_jammer.cpp
|
||||
# apps/ui_keyfob.cpp
|
||||
# apps/ui_lcr.cpp
|
||||
apps/ui_level.cpp
|
||||
apps/ui_looking_glass_app.cpp
|
||||
apps/ui_mictx.cpp
|
||||
apps/ui_modemsetup.cpp
|
||||
# apps/ui_morse.cpp
|
||||
# apps/ui_nrf_rx.cpp
|
||||
# apps/ui_nuoptix.cpp
|
||||
apps/ui_playlist.cpp
|
||||
apps/ui_pocsag_tx.cpp
|
||||
apps/ui_rds.cpp
|
||||
@ -325,16 +310,11 @@ set(CPPSRC
|
||||
apps/ui_settings.cpp
|
||||
apps/ui_siggen.cpp
|
||||
apps/ui_sonde.cpp
|
||||
# apps/ui_spectrum_painter_image.cpp
|
||||
# apps/ui_spectrum_painter_text.cpp
|
||||
# apps/ui_spectrum_painter.cpp
|
||||
apps/ui_ss_viewer.cpp
|
||||
# apps/ui_sstvtx.cpp #moved to ext
|
||||
apps/ui_standalone_view.cpp
|
||||
apps/ui_subghzd.cpp
|
||||
# apps/ui_test.cpp
|
||||
apps/ui_text_editor.cpp
|
||||
apps/ui_tone_search.cpp
|
||||
apps/ui_touch_calibration.cpp
|
||||
apps/ui_touchtunes.cpp
|
||||
apps/ui_view_wav.cpp
|
||||
@ -345,14 +325,8 @@ set(CPPSRC
|
||||
protocols/bht.cpp
|
||||
protocols/dcs.cpp
|
||||
protocols/encoders.cpp
|
||||
# protocols/lcr.cpp
|
||||
protocols/modems.cpp
|
||||
protocols/rds.cpp
|
||||
# ui_handwrite.cpp
|
||||
# ui_loadmodule.cpp
|
||||
# ui_numbers.cpp
|
||||
# ui_replay_view.cpp
|
||||
# ui_script.cpp
|
||||
ui_sd_card_debug.cpp
|
||||
config_mode.cpp
|
||||
${CPLD_20150901_DATA_CPP}
|
||||
|
@ -1,224 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyleft (ↄ) 2022 NotPike
|
||||
*
|
||||
* 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 "replay_app.hpp"
|
||||
#include "string_format.hpp"
|
||||
|
||||
#include "ui_fileman.hpp"
|
||||
#include "io_file.hpp"
|
||||
#include "io_convert.hpp"
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
#include "metadata_file.hpp"
|
||||
#include "portapack.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace ui {
|
||||
|
||||
void ReplayAppView::set_ready() {
|
||||
ready_signal = true;
|
||||
}
|
||||
|
||||
void ReplayAppView::on_file_changed(const fs::path& new_file_path) {
|
||||
file_path = new_file_path;
|
||||
File::Size file_size{};
|
||||
|
||||
{ // Get the size of the data file.
|
||||
File data_file;
|
||||
auto error = data_file.open(file_path);
|
||||
if (error) {
|
||||
file_error();
|
||||
return;
|
||||
}
|
||||
|
||||
file_size = data_file.size();
|
||||
}
|
||||
|
||||
// Get original record frequency if available.
|
||||
auto metadata_path = get_metadata_path(file_path);
|
||||
auto metadata = read_metadata_file(metadata_path);
|
||||
|
||||
if (metadata) {
|
||||
field_frequency.set_value(metadata->center_frequency);
|
||||
sample_rate = metadata->sample_rate;
|
||||
} else {
|
||||
// TODO: This is interesting because it implies that the
|
||||
// The capture will just be replayed at the freq set on the
|
||||
// FrequencyField. Is that an intentional behavior?
|
||||
sample_rate = 500000;
|
||||
}
|
||||
|
||||
// UI Fixup.
|
||||
text_sample_rate.set(unit_auto_scale(sample_rate, 3, 0) + "Hz");
|
||||
progressbar.set_max(file_size);
|
||||
text_filename.set(truncate(file_path.filename().string(), 12));
|
||||
|
||||
uint8_t sample_size = capture_file_sample_size(current()->path);
|
||||
auto duration = ms_duration(file_size, sample_rate, sample_size);
|
||||
text_duration.set(to_string_time_ms(duration));
|
||||
|
||||
button_play.focus();
|
||||
}
|
||||
|
||||
void ReplayAppView::on_tx_progress(const uint32_t progress) {
|
||||
progressbar.set_value(progress);
|
||||
}
|
||||
|
||||
void ReplayAppView::focus() {
|
||||
button_open.focus();
|
||||
}
|
||||
|
||||
void ReplayAppView::file_error() {
|
||||
nav_.display_modal("Error", "File read error.");
|
||||
}
|
||||
|
||||
bool ReplayAppView::is_active() const {
|
||||
return (bool)replay_thread;
|
||||
}
|
||||
|
||||
void ReplayAppView::toggle() {
|
||||
if (is_active()) {
|
||||
stop(false);
|
||||
} else {
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
void ReplayAppView::start() {
|
||||
stop(false);
|
||||
|
||||
std::unique_ptr<stream::Reader> reader;
|
||||
|
||||
auto p = std::make_unique<FileConvertReader>();
|
||||
auto open_error = p->open(file_path);
|
||||
if (open_error.is_valid()) {
|
||||
file_error();
|
||||
return; // Fixes TX bug if there's a file error
|
||||
} else {
|
||||
reader = std::move(p);
|
||||
}
|
||||
|
||||
if (reader) {
|
||||
button_play.set_bitmap(&bitmap_stop);
|
||||
baseband::set_sample_rate(sample_rate, OversampleRate::x8);
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
transmitter_model.set_sampling_rate(sample_rate * toUType(OversampleRate::x8));
|
||||
transmitter_model.set_baseband_bandwidth(baseband_bandwidth);
|
||||
transmitter_model.enable();
|
||||
|
||||
if (portapack::persistent_memory::stealth_mode()) {
|
||||
DisplaySleepMessage message;
|
||||
EventDispatcher::send_message(message);
|
||||
}
|
||||
}
|
||||
|
||||
void ReplayAppView::stop(const bool do_loop) {
|
||||
if (is_active())
|
||||
replay_thread.reset();
|
||||
|
||||
if (do_loop && check_loop.value()) {
|
||||
start();
|
||||
} else {
|
||||
transmitter_model.disable();
|
||||
button_play.set_bitmap(&bitmap_play);
|
||||
}
|
||||
|
||||
ready_signal = false;
|
||||
}
|
||||
|
||||
void ReplayAppView::handle_replay_thread_done(const uint32_t return_code) {
|
||||
if (return_code == ReplayThread::END_OF_FILE) {
|
||||
stop(true);
|
||||
} else if (return_code == ReplayThread::READ_ERROR) {
|
||||
stop(false);
|
||||
file_error();
|
||||
}
|
||||
|
||||
progressbar.set_value(0);
|
||||
}
|
||||
|
||||
ReplayAppView::ReplayAppView(
|
||||
NavigationView& nav)
|
||||
: nav_(nav) {
|
||||
baseband::run_image(portapack::spi_flash::image_tag_replay);
|
||||
|
||||
add_children({
|
||||
&button_open,
|
||||
&text_filename,
|
||||
&text_sample_rate,
|
||||
&text_duration,
|
||||
&progressbar,
|
||||
&field_frequency,
|
||||
&tx_view, // now it handles previous rfgain, rfamp.
|
||||
&check_loop,
|
||||
&button_play,
|
||||
&waterfall,
|
||||
});
|
||||
|
||||
button_play.on_select = [this](ImageButton&) {
|
||||
this->toggle();
|
||||
};
|
||||
|
||||
button_open.on_select = [this, &nav](Button&) {
|
||||
auto open_view = nav.push<FileLoadView>(".C*");
|
||||
open_view->on_changed = [this](fs::path new_file_path) {
|
||||
on_file_changed(new_file_path);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
ReplayAppView::~ReplayAppView() {
|
||||
transmitter_model.disable();
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
void ReplayAppView::on_hide() {
|
||||
stop(false);
|
||||
// TODO: Terrible kludge because widget system doesn't notify Waterfall that
|
||||
// it's being shown or hidden.
|
||||
waterfall.on_hide();
|
||||
View::on_hide();
|
||||
}
|
||||
|
||||
void ReplayAppView::set_parent_rect(const Rect new_parent_rect) {
|
||||
View::set_parent_rect(new_parent_rect);
|
||||
|
||||
const ui::Rect waterfall_rect{0, header_height, new_parent_rect.width(), new_parent_rect.height() - header_height};
|
||||
waterfall.set_parent_rect(waterfall_rect);
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
@ -1,146 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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 __REPLAY_APP_HPP__
|
||||
#define __REPLAY_APP_HPP__
|
||||
|
||||
#include "app_settings.hpp"
|
||||
#include "radio_state.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_receiver.hpp"
|
||||
#include "ui_freq_field.hpp"
|
||||
#include "replay_thread.hpp"
|
||||
#include "ui_spectrum.hpp"
|
||||
#include "ui_transmitter.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace ui {
|
||||
|
||||
class ReplayAppView : public View {
|
||||
public:
|
||||
ReplayAppView(NavigationView& nav);
|
||||
~ReplayAppView();
|
||||
|
||||
void on_hide() override;
|
||||
void set_parent_rect(const Rect new_parent_rect) override;
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "Replay"; };
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
TxRadioState radio_state_{};
|
||||
app_settings::SettingsManager settings_{
|
||||
"tx_replay", app_settings::Mode::TX};
|
||||
|
||||
static constexpr ui::Dim header_height = 3 * 16;
|
||||
|
||||
uint32_t sample_rate = 0;
|
||||
int32_t tx_gain{47};
|
||||
bool rf_amp{true}; // aux private var to store temporal, Replay App rf_amp user selection.
|
||||
static constexpr uint32_t baseband_bandwidth = 2500000;
|
||||
const size_t read_size{16384};
|
||||
const size_t buffer_count{3};
|
||||
|
||||
void on_file_changed(const std::filesystem::path& new_file_path);
|
||||
void on_tx_progress(const uint32_t progress);
|
||||
|
||||
void toggle();
|
||||
void start();
|
||||
void stop(const bool do_loop);
|
||||
bool is_active() const;
|
||||
void set_ready();
|
||||
void handle_replay_thread_done(const uint32_t return_code);
|
||||
void file_error();
|
||||
|
||||
std::filesystem::path file_path{};
|
||||
std::unique_ptr<ReplayThread> replay_thread{};
|
||||
bool ready_signal{false};
|
||||
|
||||
Button button_open{
|
||||
{0 * 8, 0 * 16, 10 * 8, 2 * 16},
|
||||
"Open file"};
|
||||
|
||||
Text text_filename{
|
||||
{11 * 8, 0 * 16, 12 * 8, 16},
|
||||
"-"};
|
||||
Text text_sample_rate{
|
||||
{24 * 8, 0 * 16, 6 * 8, 16},
|
||||
"-"};
|
||||
|
||||
Text text_duration{
|
||||
{11 * 8, 1 * 16, 6 * 8, 16},
|
||||
"-"};
|
||||
ProgressBar progressbar{
|
||||
{18 * 8, 1 * 16, 12 * 8, 16}};
|
||||
|
||||
TxFrequencyField field_frequency{
|
||||
{0 * 8, 2 * 16},
|
||||
nav_};
|
||||
|
||||
TransmitterView2 tx_view{
|
||||
{11 * 8, 2 * 16},
|
||||
/*short_ui*/ true};
|
||||
|
||||
Checkbox check_loop{
|
||||
{21 * 8, 2 * 16},
|
||||
4,
|
||||
"Loop",
|
||||
true};
|
||||
ImageButton button_play{
|
||||
{28 * 8, 2 * 16, 2 * 8, 1 * 16},
|
||||
&bitmap_play,
|
||||
Theme::getInstance()->fg_green->foreground,
|
||||
Theme::getInstance()->fg_green->background};
|
||||
|
||||
spectrum::WaterfallView waterfall{};
|
||||
|
||||
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 /*__REPLAY_APP_HPP__*/
|
@ -1,138 +0,0 @@
|
||||
/*
|
||||
* 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 "cpld_update.hpp"
|
||||
#include "portapack.hpp"
|
||||
#include "event_m0.hpp"
|
||||
|
||||
#include "ui_about.hpp"
|
||||
|
||||
#include "portapack_shared_memory.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
#include "lpc43xx_cpp.hpp"
|
||||
|
||||
#include <math.h>
|
||||
#include <cstring>
|
||||
|
||||
using namespace lpc43xx;
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
|
||||
// This is pretty much WaterfallView but in the opposite direction
|
||||
CreditsWidget::CreditsWidget(
|
||||
Rect parent_rect)
|
||||
: Widget{parent_rect} {
|
||||
}
|
||||
|
||||
void CreditsWidget::paint(Painter&) {
|
||||
}
|
||||
|
||||
void CreditsWidget::on_show() {
|
||||
clear();
|
||||
|
||||
const auto screen_r = screen_rect();
|
||||
display.scroll_set_area(screen_r.top(), screen_r.bottom());
|
||||
}
|
||||
|
||||
void CreditsWidget::on_hide() {
|
||||
display.scroll_disable();
|
||||
}
|
||||
|
||||
void CreditsWidget::new_row(
|
||||
const std::array<Color, 240>& pixel_row) {
|
||||
// Glitch be here (see comment in main.cpp)
|
||||
const auto draw_y = display.scroll(-1);
|
||||
|
||||
display.draw_pixels(
|
||||
{{0, draw_y - 1}, {240, 1}},
|
||||
pixel_row);
|
||||
}
|
||||
|
||||
void CreditsWidget::clear() {
|
||||
display.fill_rectangle(
|
||||
screen_rect(),
|
||||
Theme::getInstance()->bg_darkest->background);
|
||||
}
|
||||
|
||||
void AboutView::update() {
|
||||
size_t i = 0;
|
||||
std::array<Color, 240> pixel_row;
|
||||
|
||||
slow_down++;
|
||||
if (slow_down % 3 < 2) return;
|
||||
|
||||
if (!timer) {
|
||||
if (loop) {
|
||||
credits_index = 0;
|
||||
loop = false;
|
||||
}
|
||||
|
||||
text = credits[credits_index].text;
|
||||
timer = credits[credits_index].delay;
|
||||
start_pos = credits[credits_index].start_pos;
|
||||
|
||||
if (timer < 0) {
|
||||
timer = 240;
|
||||
loop = true;
|
||||
} else
|
||||
timer += 16;
|
||||
|
||||
render_line = 0;
|
||||
credits_index++;
|
||||
} else
|
||||
timer--;
|
||||
|
||||
if (render_line < 16) {
|
||||
for (const auto c : text) {
|
||||
const auto glyph = style().font.glyph(c);
|
||||
|
||||
const size_t start = (glyph.size().width() / 8) * render_line;
|
||||
for (Dim c = 0; c < glyph.size().width(); c++) {
|
||||
const auto pixel = glyph.pixels()[start + (c >> 3)] & (1U << (c & 0x7));
|
||||
pixel_row[start_pos + i + c] = pixel ? Theme::getInstance()->bg_darkest->foreground : Theme::getInstance()->bg_darkest->background;
|
||||
}
|
||||
|
||||
const auto advance = glyph.advance();
|
||||
i += advance.x();
|
||||
}
|
||||
render_line++;
|
||||
}
|
||||
|
||||
credits_display.new_row(pixel_row);
|
||||
}
|
||||
|
||||
AboutView::AboutView(
|
||||
NavigationView& nav) {
|
||||
add_children({&credits_display,
|
||||
&button_ok});
|
||||
|
||||
button_ok.on_select = [&nav](Button&) {
|
||||
nav.pop();
|
||||
};
|
||||
}
|
||||
|
||||
void AboutView::focus() {
|
||||
button_ok.focus();
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
@ -1,119 +0,0 @@
|
||||
/*
|
||||
* 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_ABOUT_H__
|
||||
#define __UI_ABOUT_H__
|
||||
|
||||
#include "ui_widget.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace ui {
|
||||
|
||||
class CreditsWidget : public Widget {
|
||||
public:
|
||||
CreditsWidget(Rect parent_rect);
|
||||
|
||||
void on_show() override;
|
||||
void on_hide() override;
|
||||
|
||||
void paint(Painter&) override;
|
||||
|
||||
void new_row(const std::array<Color, 240>& pixel_row);
|
||||
|
||||
private:
|
||||
void clear();
|
||||
};
|
||||
|
||||
class AboutView : public View {
|
||||
public:
|
||||
AboutView(NavigationView& nav);
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "About"; };
|
||||
|
||||
private:
|
||||
void update();
|
||||
|
||||
uint8_t credits_index{0};
|
||||
uint8_t render_line{0};
|
||||
Coord start_pos{0};
|
||||
uint8_t slow_down{0};
|
||||
int32_t timer{0};
|
||||
bool loop{false};
|
||||
|
||||
std::string text{};
|
||||
|
||||
typedef struct credits_t {
|
||||
size_t start_pos;
|
||||
std::string text;
|
||||
int32_t delay;
|
||||
} credits_t;
|
||||
|
||||
// TODO: Make this dinamically centered and parse \n as the delay value so it is easy to maintain
|
||||
const credits_t credits[26] = {
|
||||
// 012345678901234567890123456789
|
||||
{60, "PortaPack Mayhem", 0},
|
||||
{60, "PortaPack|HAVOC", 0},
|
||||
{11 * 8, "Gurus J. Boone", 0},
|
||||
{18 * 8, "M. Ossmann", 16},
|
||||
{11 * 8, "HAVOC Furrtek", 16},
|
||||
{7 * 8, "POCSAG rx T. Sailer", 0},
|
||||
{18 * 8, "E. Oenal", 16},
|
||||
{0 * 8, "Radiosonde infos F4GMU", 0},
|
||||
{18 * 8, "RS1729", 16},
|
||||
{4 * 8, "RDS waveform C. Jacquet", 16},
|
||||
{7 * 8, "Xy. infos cLx", 16},
|
||||
{2 * 8, "OOK scan trick Samy Kamkar", 16},
|
||||
{7 * 8, "World map NASA", 16},
|
||||
{0 * 8, "TouchTunes infos Notpike", 16},
|
||||
{4 * 8, "Subaru infos Tom", 0},
|
||||
{18 * 8, "Wimmenhove", 16},
|
||||
{1 * 8, "GPS,TV,BTLE,NRF Shao", 24},
|
||||
{6 * 8, "Thanks & donators", 16},
|
||||
{1 * 8, "Rainer Matla Keld Norman", 0},
|
||||
{1 * 8, " Giorgio C. DC1RDB", 0},
|
||||
{1 * 8, " Sigmounte Waax", 0},
|
||||
{1 * 8, " Windyoona Channels", 0},
|
||||
{1 * 8, " F4GEV Pyr3x", 0},
|
||||
{1 * 8, " HB3YOE", 24},
|
||||
{11 * 8, "MMXVIII", -1}};
|
||||
|
||||
CreditsWidget credits_display{
|
||||
{0, 16, 240, 240}};
|
||||
|
||||
Button button_ok{
|
||||
{72, 272, 96, 24},
|
||||
"OK"};
|
||||
|
||||
MessageHandlerRegistration message_handler_update{
|
||||
Message::ID::DisplayFrameSync,
|
||||
[this](const Message* const) {
|
||||
this->update();
|
||||
}};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
#endif /*__UI_ABOUT_H__*/
|
@ -1,413 +0,0 @@
|
||||
/*
|
||||
* 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 <ch.h>
|
||||
|
||||
#include "demofont.hpp"
|
||||
#include "ymdata.hpp"
|
||||
|
||||
#include "cpld_update.hpp"
|
||||
#include "portapack.hpp"
|
||||
#include "audio.hpp"
|
||||
#include "event_m0.hpp"
|
||||
|
||||
#include "ui_about.hpp"
|
||||
#include "touch.hpp"
|
||||
#include "sine_table.hpp"
|
||||
|
||||
#include "portapack_shared_memory.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
#include "lpc43xx_cpp.hpp"
|
||||
|
||||
#include <math.h>
|
||||
#include <cstring>
|
||||
|
||||
using namespace lpc43xx;
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
|
||||
void AboutView::on_show() {
|
||||
transmitter_model.set_target_frequency(1337000000); // TODO: Change
|
||||
transmitter_model.set_baseband_configuration({
|
||||
.mode = 0,
|
||||
.sampling_rate = 1536000,
|
||||
.decimation_factor = 1,
|
||||
});
|
||||
transmitter_model.set_rf_amp(true);
|
||||
transmitter_model.set_lna(40);
|
||||
transmitter_model.set_vga(40);
|
||||
transmitter_model.enable();
|
||||
|
||||
baseband::set_audiotx_data(32, 50, false, 0);
|
||||
|
||||
// audio::headphone::set_volume(volume_t::decibel(0 - 99) + audio::headphone::volume_range().max);
|
||||
}
|
||||
|
||||
void AboutView::render_video() {
|
||||
uint8_t p, r, luma, chroma, cy;
|
||||
ui::Color cc;
|
||||
char ch;
|
||||
float s;
|
||||
|
||||
// Send framebuffer to LCD. Gotta go fast !
|
||||
display.render_box({30, 112}, {180, 72}, framebuffer);
|
||||
|
||||
// Clear framebuffer to black
|
||||
memset(framebuffer, 0, 180 * 72 * sizeof(ui::Color));
|
||||
|
||||
// Drum hit palette animation
|
||||
if (drum > 1) drum--;
|
||||
|
||||
// Render copper bars from Y buffer
|
||||
for (p = 0; p < 72; p++) {
|
||||
luma = copperbuffer[p] & 0x0F; // 0 is transparent
|
||||
if (luma) {
|
||||
chroma = copperbuffer[p] >> 4;
|
||||
cc = ui::Color(std::min((coppercolor[chroma][0] / luma) * drum, 255), std::min((coppercolor[chroma][1] / luma) * drum, 255), std::min((coppercolor[chroma][2] / luma) * drum, 255));
|
||||
for (r = 0; r < 180; r++)
|
||||
framebuffer[(p * 180) + r] = cc;
|
||||
}
|
||||
}
|
||||
|
||||
// Scroll in/out state machine
|
||||
if (anim_state == 0) {
|
||||
// Scroll in
|
||||
if (ofy < 8) {
|
||||
ofy++;
|
||||
anim_state = 0;
|
||||
} else {
|
||||
anim_state = 1;
|
||||
}
|
||||
if (ofx < (int16_t)(180 - (strlen(credits[credits_index].name) * 16) - 8)) {
|
||||
ofx += 8;
|
||||
anim_state = 0;
|
||||
}
|
||||
} else if (anim_state == 1) {
|
||||
// Just wait
|
||||
if (credits_timer == (30 * 3)) {
|
||||
credits_timer = 0;
|
||||
anim_state = 2;
|
||||
} else {
|
||||
credits_timer++;
|
||||
}
|
||||
} else {
|
||||
// Scroll out
|
||||
if (credits[credits_index].change == true) {
|
||||
if (ofy > -24) {
|
||||
ofy--;
|
||||
anim_state = 2;
|
||||
} else {
|
||||
anim_state = 0;
|
||||
}
|
||||
} else {
|
||||
anim_state = 0;
|
||||
}
|
||||
if (ofx < 180) {
|
||||
ofx += 8;
|
||||
anim_state = 2;
|
||||
}
|
||||
|
||||
// Switch to next text
|
||||
if (anim_state == 0) {
|
||||
if (credits_index == 9)
|
||||
credits_index = 0;
|
||||
else
|
||||
credits_index++;
|
||||
ofx = -(strlen(credits[credits_index].name) * 16) - 16;
|
||||
}
|
||||
}
|
||||
|
||||
// Sine text ("role")
|
||||
p = 0;
|
||||
while ((ch = credits[credits_index].role[p])) {
|
||||
draw_demoglyph({(ui::Coord)(8 + (p * 16)), (ui::Coord)(ofy + (sine_table_f32[((p * 16) + (phase >> 5)) & 0xFF] * 8))}, ch, paletteA);
|
||||
p++;
|
||||
}
|
||||
|
||||
// Scroll text (name)
|
||||
p = 0;
|
||||
while ((ch = credits[credits_index].name[p])) {
|
||||
draw_demoglyph({(ui::Coord)(ofx + (p * 16)), 56}, ch, paletteB);
|
||||
p++;
|
||||
}
|
||||
|
||||
// Clear bars Y buffer
|
||||
memset(copperbuffer, 0, 72);
|
||||
|
||||
// Render bars to Y buffer
|
||||
for (p = 0; p < 5; p++) {
|
||||
cy = copperbars[p];
|
||||
for (r = 0; r < 16; r++)
|
||||
copperbuffer[cy + r] = copperluma[r] + (p << 4);
|
||||
}
|
||||
|
||||
// Animate bars positions
|
||||
for (p = 0; p < 5; p++) {
|
||||
s = sine_table_f32[((p * 32) + (phase / 24)) & 0xFF];
|
||||
s += sine_table_f32[((p * 16) + (phase / 35)) & 0xFF];
|
||||
copperbars[p] = 28 + (uint8_t)(s * 14);
|
||||
}
|
||||
|
||||
phase += 128;
|
||||
}
|
||||
|
||||
void AboutView::draw_demoglyph(ui::Point p, char ch, ui::Color* pal) {
|
||||
uint8_t x, y, c, cl, cr;
|
||||
uint16_t che;
|
||||
int16_t lbx, il;
|
||||
|
||||
// Map ASCII to font bitmap
|
||||
if ((ch >= 32) && (ch < 96))
|
||||
che = char_map[ch - 32];
|
||||
else
|
||||
che = 0xFF;
|
||||
|
||||
if (che < 0xFF) {
|
||||
che = (che * 128) + 48; // Start in bitmap
|
||||
|
||||
il = (180 * p.y) + p.x; // Start il framebuffer
|
||||
|
||||
for (y = 0; y < 16; y++) {
|
||||
if (p.y + y >= 72) break; // Over bottom of framebuffer, abort
|
||||
if (p.y + y >= 0) {
|
||||
for (x = 0; x < 8; x++) {
|
||||
c = demofont_bin[x + (y * 8) + che]; // Split byte in 2 4BPP pixels
|
||||
cl = c >> 4;
|
||||
cr = c & 0x0F;
|
||||
lbx = p.x + (x * 2);
|
||||
if (cl && (lbx < 180) && (lbx >= 0)) framebuffer[il] = pal[cl];
|
||||
lbx++;
|
||||
il++;
|
||||
if (cr && (lbx < 180) && (lbx >= 0)) framebuffer[il] = pal[cr];
|
||||
il++;
|
||||
}
|
||||
il += 180 - 16;
|
||||
} else {
|
||||
il += 180;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AboutView::render_audio() {
|
||||
uint8_t i, ymdata;
|
||||
uint16_t ym_render_cnt;
|
||||
|
||||
// This is heavily inspired by MAME's ay8910.cpp and the YM2149's datasheet
|
||||
|
||||
// Render 1024 music samples
|
||||
for (ym_render_cnt = 0; ym_render_cnt < 1024; ym_render_cnt++) {
|
||||
// Update registers at 48000/960 = 50Hz
|
||||
if (ym_sample_cnt == 0) {
|
||||
// "Decompress" on the fly and update YM registers
|
||||
for (i = 0; i < 14; i++) {
|
||||
if (!ym_regs[i].cnt) {
|
||||
// New run
|
||||
ymdata = ymdata_bin[ym_regs[i].ptr++];
|
||||
ym_regs[i].cnt = ymdata & 0x7F;
|
||||
if (ymdata & 0x80) {
|
||||
ym_regs[i].same = true;
|
||||
ym_regs[i].value = ymdata_bin[ym_regs[i].ptr++];
|
||||
} else {
|
||||
ym_regs[i].same = false;
|
||||
}
|
||||
// Detect drum on channel B
|
||||
if (i == 3)
|
||||
if (ym_regs[3].value > 2) drum = 4;
|
||||
}
|
||||
if (ym_regs[i].same == false) {
|
||||
ym_regs[i].value = ymdata_bin[ym_regs[i].ptr++];
|
||||
if (i == 13) {
|
||||
// Update envelope attributes
|
||||
ym_env_att = (ym_regs[13].value & 4) ? 0x1F : 0x00;
|
||||
if (!(ym_regs[13].value & 8)) {
|
||||
ym_env_hold = 1;
|
||||
ym_env_alt = ym_env_att;
|
||||
} else {
|
||||
ym_env_hold = ym_regs[13].value & 1;
|
||||
ym_env_alt = ym_regs[13].value & 2;
|
||||
}
|
||||
// Reset envelope counter
|
||||
ym_env_step = 0x1F;
|
||||
ym_env_holding = 0;
|
||||
ym_env_vol = (ym_env_step ^ ym_env_att);
|
||||
}
|
||||
}
|
||||
ym_regs[i].cnt--;
|
||||
}
|
||||
ym_frame++;
|
||||
}
|
||||
|
||||
// Square wave oscillators
|
||||
// 2457600/16/48000 = 3.2, but 4 sounds better than 3...
|
||||
for (i = 0; i < 3; i++) {
|
||||
ym_osc_cnt[i] += 4;
|
||||
if (ym_osc_cnt[i] >= (ym_regs[i * 2].value | ((ym_regs[(i * 2) + 1].value & 0x0f) << 8))) {
|
||||
ym_osc_cnt[i] = 0;
|
||||
ym_osc_out[i] ^= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Noise generator
|
||||
ym_noise_cnt += 4;
|
||||
if (ym_noise_cnt >= ((ym_regs[6].value & 0x1F) * 2)) {
|
||||
ym_noise_cnt = 0;
|
||||
ym_rng ^= (((ym_rng & 1) ^ ((ym_rng >> 3) & 1)) << 17);
|
||||
ym_rng >>= 1;
|
||||
}
|
||||
|
||||
// Mix tones and noise
|
||||
for (i = 0; i < 3; i++)
|
||||
ym_ch[i] = (ym_osc_out[i] | ((ym_regs[7].value >> i) & 1)) & ((ym_rng & 1) | ((ym_regs[7].value >> (i + 3)) & 1));
|
||||
|
||||
// Envelope generator
|
||||
if (!ym_env_holding) {
|
||||
ym_env_cnt += 8;
|
||||
if (ym_env_cnt >= (ym_regs[11].value | (ym_regs[12].value << 8))) {
|
||||
ym_env_cnt = 0;
|
||||
ym_env_step--;
|
||||
if (ym_env_step < 0) {
|
||||
if (ym_env_hold) {
|
||||
if (ym_env_alt)
|
||||
ym_env_att ^= 0x1F;
|
||||
ym_env_holding = 1;
|
||||
ym_env_step = 0;
|
||||
} else {
|
||||
if (ym_env_alt && (ym_env_step & 0x20))
|
||||
ym_env_att ^= 0x1F;
|
||||
ym_env_step &= 0x1F;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ym_env_vol = (ym_env_step ^ ym_env_att);
|
||||
|
||||
ym_out = 0;
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (ym_regs[i + 8].value & 0x10) {
|
||||
// Envelope mode
|
||||
ym_out += (ym_ch[i] ? ym_env_vol : 0);
|
||||
} else {
|
||||
// Fixed mode
|
||||
ym_out += (ym_ch[i] ? (ym_regs[i + 8].value & 0x0F) : 0);
|
||||
}
|
||||
}
|
||||
|
||||
ym_buffer[ym_render_cnt] = (ym_out * 2) - 45;
|
||||
|
||||
if (ym_sample_cnt < 960) {
|
||||
ym_sample_cnt++;
|
||||
} else {
|
||||
ym_sample_cnt = 0;
|
||||
}
|
||||
|
||||
// Loop
|
||||
if (ym_frame == ym_frames) ym_init();
|
||||
}
|
||||
}
|
||||
|
||||
void AboutView::update() {
|
||||
if (framebuffer) {
|
||||
// Update 1 out of 2 frames, 60Hz is very laggy
|
||||
if (refresh_cnt & 1) render_video();
|
||||
refresh_cnt++;
|
||||
}
|
||||
|
||||
// Slowly increase volume to avoid jumpscare
|
||||
if (headphone_vol < (70 << 2)) {
|
||||
audio::headphone::set_volume(volume_t::decibel((headphone_vol / 4) - 99) + audio::headphone::volume_range().max);
|
||||
headphone_vol++;
|
||||
}
|
||||
}
|
||||
|
||||
void AboutView::ym_init() {
|
||||
uint8_t reg;
|
||||
|
||||
for (reg = 0; reg < 14; reg++) {
|
||||
ym_regs[reg].cnt = 0;
|
||||
// Pick up start pointers for each YM registers RLE blocks
|
||||
ym_regs[reg].ptr = ((uint16_t)(ymdata_bin[(reg * 2) + 3]) << 8) + ymdata_bin[(reg * 2) + 2];
|
||||
ym_regs[reg].same = false; // Useless ?
|
||||
ym_regs[reg].value = 0; // Useless ?
|
||||
}
|
||||
|
||||
ym_frame = 0;
|
||||
}
|
||||
|
||||
AboutView::AboutView(
|
||||
NavigationView& nav) {
|
||||
uint8_t p, c;
|
||||
|
||||
baseband::run_image(portapack::spi_flash::image_tag_audio_tx);
|
||||
|
||||
add_children({{
|
||||
&text_title,
|
||||
&text_firmware,
|
||||
&text_cpld_hackrf,
|
||||
&text_cpld_hackrf_status,
|
||||
&button_ok,
|
||||
}});
|
||||
|
||||
if (cpld_hackrf_verify_eeprom()) {
|
||||
text_cpld_hackrf_status.set(" OK");
|
||||
} else {
|
||||
text_cpld_hackrf_status.set("BAD");
|
||||
}
|
||||
|
||||
// Politely ask for about 26kB
|
||||
framebuffer = (ui::Color*)chHeapAlloc(0x0, 180 * 72 * sizeof(ui::Color));
|
||||
|
||||
if (framebuffer) {
|
||||
memset(framebuffer, 0, 180 * 72 * sizeof(ui::Color));
|
||||
|
||||
// Copy original font palette
|
||||
c = 0;
|
||||
for (p = 0; p < 48; p += 3)
|
||||
paletteA[c++] = ui::Color(demofont_bin[p], demofont_bin[p + 1], demofont_bin[p + 2]);
|
||||
|
||||
// Increase red in another one
|
||||
c = 0;
|
||||
for (p = 0; p < 48; p += 3)
|
||||
paletteB[c++] = ui::Color(std::min(demofont_bin[p] + 64, 255), demofont_bin[p + 1], demofont_bin[p + 2]);
|
||||
}
|
||||
|
||||
// Init YM synth
|
||||
ym_frames = ((uint16_t)(ymdata_bin[1]) << 8) + ymdata_bin[0];
|
||||
ym_init();
|
||||
|
||||
button_ok.on_select = [this, &nav](Button&) {
|
||||
if (framebuffer) chHeapFree(framebuffer); // Do NOT forget this
|
||||
nav.pop();
|
||||
};
|
||||
}
|
||||
|
||||
AboutView::~AboutView() {
|
||||
transmitter_model.disable();
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
void AboutView::focus() {
|
||||
button_ok.focus();
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
@ -1,168 +0,0 @@
|
||||
/*
|
||||
* 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_ABOUT_H__
|
||||
#define __UI_ABOUT_H__
|
||||
|
||||
#include "ui_widget.hpp"
|
||||
#include "ui_menu.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "transmitter_model.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace ui {
|
||||
|
||||
class AboutView : public View {
|
||||
public:
|
||||
AboutView(NavigationView& nav);
|
||||
~AboutView();
|
||||
|
||||
void on_show() override;
|
||||
void focus() override;
|
||||
|
||||
private:
|
||||
void ym_init();
|
||||
void update();
|
||||
void render_video();
|
||||
void render_audio();
|
||||
void draw_demoglyph(ui::Point p, char ch, ui::Color* pal);
|
||||
uint16_t debug_cnt = 0;
|
||||
|
||||
typedef struct ymreg_t {
|
||||
uint8_t value;
|
||||
uint8_t cnt;
|
||||
uint16_t ptr;
|
||||
bool same;
|
||||
} ymreg_t;
|
||||
|
||||
uint16_t headphone_vol = 5 << 2;
|
||||
|
||||
ymreg_t ym_regs[14];
|
||||
uint16_t ym_frames;
|
||||
uint16_t ym_frame;
|
||||
uint8_t drum = 0;
|
||||
uint16_t ym_osc_cnt[3];
|
||||
uint32_t ym_rng = 1;
|
||||
uint16_t ym_noise_cnt;
|
||||
uint8_t ym_env_att, ym_env_hold, ym_env_alt, ym_env_holding, ym_env_vol;
|
||||
int8_t ym_env_step;
|
||||
uint16_t ym_env_cnt;
|
||||
uint8_t ym_osc_out[3];
|
||||
uint8_t ym_ch[3];
|
||||
uint8_t ym_out;
|
||||
uint16_t ym_sample_cnt = 0;
|
||||
|
||||
int8_t ym_buffer[1024];
|
||||
|
||||
uint8_t refresh_cnt;
|
||||
ui::Color paletteA[16];
|
||||
ui::Color paletteB[16];
|
||||
ui::Color* framebuffer;
|
||||
uint32_t phase = 0;
|
||||
uint8_t copperbars[5] = {0};
|
||||
uint8_t copperbuffer[72] = {0};
|
||||
|
||||
uint8_t anim_state = 0;
|
||||
uint8_t credits_index = 0;
|
||||
uint16_t credits_timer = 0;
|
||||
|
||||
int16_t ofx = -180, ofy = -24;
|
||||
|
||||
const uint8_t char_map[64] = {0xFF, 27, 46, 0xFF, 0xFF, 0xFF, 28, 45,
|
||||
58, 59, 0xFF, 43, 40, 57, 26, 42,
|
||||
29, 30, 31, 32, 33, 34, 35, 36,
|
||||
37, 38, 41, 0xFF, 0xFF, 0xFF, 0xFF, 44,
|
||||
0xFF, 0, 1, 2, 3, 4, 5, 6,
|
||||
7, 8, 9, 10, 11, 12, 13, 14,
|
||||
15, 16, 17, 18, 19, 20, 21, 22,
|
||||
23, 24, 25, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
|
||||
const uint8_t copperluma[16] = {8, 7, 6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6, 7, 8};
|
||||
const uint8_t coppercolor[5][3] = {{255, 0, 0},
|
||||
{0, 255, 0},
|
||||
{0, 0, 255},
|
||||
{255, 0, 255},
|
||||
{255, 255, 0}};
|
||||
|
||||
typedef struct credits_t {
|
||||
char role[12];
|
||||
char name[12];
|
||||
bool change;
|
||||
} credits_t;
|
||||
|
||||
// 0123456789A 0123456789A
|
||||
const credits_t credits[10] = {{"GURUS", "J. BOONE", false},
|
||||
{"GURUS", "M. OSSMANN", true},
|
||||
{"BUGS", "FURRTEK", true},
|
||||
{"RDS WAVE", "C. JACQUET", true},
|
||||
{"POCSAG RX", "T. SAILER", false},
|
||||
{"POCSAG RX", "E. OENAL", true},
|
||||
{"XYLOS DATA", "CLX", true},
|
||||
{"GREETS TO", "SIGMOUNTE", false},
|
||||
{"GREETS TO", "WINDYOONA", true},
|
||||
{"THIS MUSIC", "BIG ALEC", true}};
|
||||
|
||||
Text text_title{
|
||||
{100, 32, 40, 16},
|
||||
"About",
|
||||
};
|
||||
|
||||
Text text_firmware{
|
||||
{0, 236, 240, 16},
|
||||
"Version " VERSION_STRING,
|
||||
};
|
||||
|
||||
Text text_cpld_hackrf{
|
||||
{0, 252, 11 * 8, 16},
|
||||
"HackRF CPLD",
|
||||
};
|
||||
|
||||
Text text_cpld_hackrf_status{
|
||||
{240 - 3 * 8, 252, 3 * 8, 16},
|
||||
"???"};
|
||||
|
||||
Button button_ok{
|
||||
{72, 272, 96, 24},
|
||||
"OK"};
|
||||
|
||||
MessageHandlerRegistration message_handler_update{
|
||||
Message::ID::DisplayFrameSync,
|
||||
[this](const Message* const) {
|
||||
this->update();
|
||||
}};
|
||||
|
||||
MessageHandlerRegistration message_handler_fifo_signal{
|
||||
Message::ID::FIFOSignal,
|
||||
[this](const Message* const p) {
|
||||
const auto message = static_cast<const FIFOSignalMessage*>(p);
|
||||
if (message->signaltype == 1) {
|
||||
this->render_audio();
|
||||
baseband::set_fifo_data(ym_buffer);
|
||||
}
|
||||
}};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
#endif /*__UI_ABOUT_H__*/
|
@ -1,288 +0,0 @@
|
||||
/*
|
||||
* 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_numbers.hpp"
|
||||
#include "string_format.hpp"
|
||||
|
||||
#include "portapack.hpp"
|
||||
#include "hackrf_hal.hpp"
|
||||
#include "portapack_shared_memory.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
|
||||
// TODO: This app takes way too much space, find a way to shrink/simplify or make it an SD card module (loadable)
|
||||
|
||||
void NumbersStationView::focus() {
|
||||
if (file_error)
|
||||
nav_.display_modal("No voices", "No valid voices found in\nthe /numbers directory.", ABORT);
|
||||
else
|
||||
button_exit.focus();
|
||||
}
|
||||
|
||||
NumbersStationView::~NumbersStationView() {
|
||||
transmitter_model.disable();
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
NumbersStationView::wav_file_t* NumbersStationView::get_wav(uint32_t index) {
|
||||
return ¤t_voice->available_wavs[index];
|
||||
}
|
||||
|
||||
void NumbersStationView::prepare_audio() {
|
||||
uint8_t code;
|
||||
wav_file_t* wav_file;
|
||||
|
||||
if (sample_counter >= sample_length) {
|
||||
if (segment == ANNOUNCE) {
|
||||
if (!announce_loop) {
|
||||
code_index = 0;
|
||||
segment = MESSAGE;
|
||||
} else {
|
||||
wav_file = get_wav(11);
|
||||
reader->open(current_voice->dir + file_names[wav_file->index].name + ".wav");
|
||||
sample_length = wav_file->length;
|
||||
announce_loop--;
|
||||
}
|
||||
}
|
||||
|
||||
if (segment == MESSAGE) {
|
||||
if (code_index == 25) {
|
||||
transmitter_model.disable();
|
||||
return;
|
||||
}
|
||||
|
||||
code = symfield_code.get_offset(code_index);
|
||||
|
||||
if (code >= 10) {
|
||||
memset(audio_buffer, 0, 1024);
|
||||
if (code == 10) {
|
||||
pause = 11025; // p: 0.25s @ 44100Hz
|
||||
} else if (code == 11) {
|
||||
pause = 33075; // P: 0.75s @ 44100Hz
|
||||
} else if (code == 12) {
|
||||
transmitter_model.disable();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
wav_file = get_wav(code);
|
||||
reader->open(current_voice->dir + file_names[code].name + ".wav");
|
||||
sample_length = wav_file->length;
|
||||
}
|
||||
code_index++;
|
||||
}
|
||||
sample_counter = 0;
|
||||
}
|
||||
|
||||
if (!pause) {
|
||||
auto bytes_read = reader->read(audio_buffer, 1024).value();
|
||||
|
||||
// Unsigned to signed, pretty stupid :/
|
||||
for (size_t n = 0; n < bytes_read; n++)
|
||||
audio_buffer[n] -= 0x80;
|
||||
for (size_t n = bytes_read; n < 1024; n++)
|
||||
audio_buffer[n] = 0;
|
||||
|
||||
sample_counter += 1024;
|
||||
} else {
|
||||
if (pause >= 1024) {
|
||||
pause -= 1024;
|
||||
} else {
|
||||
sample_counter = sample_length;
|
||||
pause = 0;
|
||||
}
|
||||
}
|
||||
|
||||
baseband::set_fifo_data(audio_buffer);
|
||||
}
|
||||
|
||||
void NumbersStationView::start_tx() {
|
||||
// sample_length = sound_sizes[10]; // Announce
|
||||
sample_counter = sample_length;
|
||||
|
||||
code_index = 0;
|
||||
announce_loop = 2;
|
||||
segment = ANNOUNCE;
|
||||
|
||||
prepare_audio();
|
||||
|
||||
transmitter_model.set_rf_amp(true);
|
||||
transmitter_model.enable();
|
||||
|
||||
baseband::set_audiotx_data(
|
||||
(1536000 / 44100) - 1, // TODO: Read wav file's samplerate
|
||||
12000,
|
||||
1,
|
||||
false,
|
||||
0);
|
||||
}
|
||||
|
||||
void NumbersStationView::on_tick_second() {
|
||||
armed_blink = not armed_blink;
|
||||
|
||||
if (armed_blink)
|
||||
check_armed.set_style(Theme::getInstance()->fg_red);
|
||||
else
|
||||
check_armed.set_style(&style());
|
||||
|
||||
check_armed.set_dirty();
|
||||
}
|
||||
|
||||
void NumbersStationView::on_voice_changed(size_t index) {
|
||||
std::string code_list;
|
||||
|
||||
for (const auto& wavs : voices[index].available_wavs)
|
||||
code_list += wavs.code;
|
||||
|
||||
symfield_code.set_symbol_list(code_list);
|
||||
current_voice = &voices[index];
|
||||
}
|
||||
|
||||
bool NumbersStationView::check_wav_validity(const std::string dir, const std::string file) {
|
||||
if (reader->open("/numbers/" + dir + "/" + file)) {
|
||||
// Check format (mono, 8 bits)
|
||||
if ((reader->channels() == 1) && (reader->bits_per_sample() == 8))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
NumbersStationView::NumbersStationView(
|
||||
NavigationView& nav)
|
||||
: nav_(nav) {
|
||||
std::vector<std::filesystem::path> directory_list;
|
||||
using option_t = std::pair<std::string, int32_t>;
|
||||
using options_t = std::vector<option_t>;
|
||||
options_t voice_options;
|
||||
voice_t temp_voice{};
|
||||
bool valid;
|
||||
uint32_t c;
|
||||
// uint8_t y, m, d, dayofweek;
|
||||
|
||||
reader = std::make_unique<WAVFileReader>();
|
||||
|
||||
// Search for valid voice directories
|
||||
directory_list = scan_root_directories("/numbers");
|
||||
if (!directory_list.size()) {
|
||||
file_error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& dir : directory_list) {
|
||||
c = 0;
|
||||
for (const auto& file_name : file_names) {
|
||||
valid = check_wav_validity(dir.string(), file_name.name + ".wav");
|
||||
if ((!valid) && (file_name.required)) {
|
||||
temp_voice.available_wavs.clear();
|
||||
break; // Invalid required file means invalid voice
|
||||
} else if (valid) {
|
||||
temp_voice.available_wavs.push_back({file_name.code, c++, 0, 0}); // TODO: Needs length and samplerate
|
||||
}
|
||||
}
|
||||
if (!temp_voice.available_wavs.empty()) {
|
||||
// Voice can be used, are there accent files ?
|
||||
c = 0;
|
||||
for (const auto& file_name : file_names) {
|
||||
valid = check_wav_validity(dir.string(), file_name.name + "a.wav");
|
||||
if ((!valid) && (file_name.required)) {
|
||||
c = 0;
|
||||
break; // Invalid required file means accents can't be used
|
||||
} else if (valid) {
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
temp_voice.accent = c ? true : false;
|
||||
temp_voice.dir = dir.string();
|
||||
|
||||
voices.push_back(temp_voice);
|
||||
}
|
||||
}
|
||||
|
||||
if (voices.empty()) {
|
||||
file_error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
baseband::run_image(portapack::spi_flash::image_tag_audio_tx);
|
||||
|
||||
add_children({&labels,
|
||||
&symfield_code,
|
||||
&check_armed,
|
||||
&options_voices,
|
||||
&text_voice_flags,
|
||||
//&button_tx_now,
|
||||
&button_exit});
|
||||
|
||||
for (const auto& voice : voices)
|
||||
voice_options.emplace_back(voice.dir.substr(0, 4), 0);
|
||||
|
||||
options_voices.set_options(voice_options);
|
||||
options_voices.on_change = [this](size_t i, int32_t) {
|
||||
this->on_voice_changed(i);
|
||||
};
|
||||
options_voices.set_selected_index(0);
|
||||
|
||||
check_armed.set_value(false);
|
||||
|
||||
check_armed.on_select = [this](Checkbox&, bool v) {
|
||||
if (v) {
|
||||
armed_blink = false;
|
||||
signal_token_tick_second = rtc_time::signal_tick_second += [this]() {
|
||||
this->on_tick_second();
|
||||
};
|
||||
} else {
|
||||
check_armed.set_style(&style());
|
||||
rtc_time::signal_tick_second -= signal_token_tick_second;
|
||||
}
|
||||
};
|
||||
|
||||
// DEBUG
|
||||
symfield_code.set_offset(0, 10);
|
||||
symfield_code.set_offset(1, 3);
|
||||
symfield_code.set_offset(2, 4);
|
||||
symfield_code.set_offset(3, 11);
|
||||
symfield_code.set_offset(4, 6);
|
||||
symfield_code.set_offset(5, 1);
|
||||
symfield_code.set_offset(6, 9);
|
||||
symfield_code.set_offset(7, 7);
|
||||
symfield_code.set_offset(8, 8);
|
||||
symfield_code.set_offset(9, 0);
|
||||
symfield_code.set_offset(10, 12); // End
|
||||
|
||||
/*
|
||||
dayofweek = rtc_time::current_day_of_week();
|
||||
text_title.set(day_of_week[dayofweek]);
|
||||
*/
|
||||
|
||||
button_exit.on_select = [&nav](Button&) {
|
||||
nav.pop();
|
||||
};
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
@ -1,175 +0,0 @@
|
||||
/*
|
||||
* 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_NUMBERS_H__
|
||||
#define __UI_NUMBERS_H__
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
#include "ui_receiver.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "rtc_time.hpp"
|
||||
#include "clock_manager.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
#include "utility.hpp"
|
||||
#include "message.hpp"
|
||||
#include "file.hpp"
|
||||
#include "io_wave.hpp"
|
||||
#include "radio_state.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
class NumbersStationView : public View {
|
||||
public:
|
||||
NumbersStationView(NavigationView& nav);
|
||||
~NumbersStationView();
|
||||
|
||||
NumbersStationView(const NumbersStationView&) = delete;
|
||||
NumbersStationView(NumbersStationView&&) = delete;
|
||||
NumbersStationView& operator=(const NumbersStationView&) = delete;
|
||||
NumbersStationView& operator=(NumbersStationView&&) = delete;
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "Station"; };
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
|
||||
TxRadioState radio_state_{
|
||||
0 /* frequency */,
|
||||
1750000 /* bandwidth */,
|
||||
1536000 /* sampling rate */
|
||||
};
|
||||
|
||||
// Sequencing state machine
|
||||
enum segments {
|
||||
IDLE = 0,
|
||||
ANNOUNCE,
|
||||
MESSAGE,
|
||||
SIGNOFF
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
char code;
|
||||
uint32_t index;
|
||||
uint32_t length;
|
||||
uint32_t samplerate;
|
||||
} wav_file_t;
|
||||
|
||||
struct voice_t {
|
||||
std::string dir;
|
||||
std::vector<wav_file_t> available_wavs;
|
||||
bool accent;
|
||||
};
|
||||
|
||||
std::vector<voice_t> voices{};
|
||||
voice_t* current_voice{};
|
||||
|
||||
struct wav_file_list_t {
|
||||
std::string name;
|
||||
bool required;
|
||||
char code;
|
||||
};
|
||||
|
||||
const std::vector<wav_file_list_t> file_names = {
|
||||
{"0", true, '0'},
|
||||
{"1", true, '1'},
|
||||
{"2", true, '2'},
|
||||
{"3", true, '3'},
|
||||
{"4", true, '4'},
|
||||
{"5", true, '5'},
|
||||
{"6", true, '6'},
|
||||
{"7", true, '7'},
|
||||
{"8", true, '8'},
|
||||
{"9", true, '9'},
|
||||
{"announce", false, 'A'}};
|
||||
|
||||
segments segment{IDLE};
|
||||
bool armed{false};
|
||||
bool file_error{false};
|
||||
|
||||
// const uint8_t month_table[12] = { 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 };
|
||||
// const char * day_of_week[7] = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };
|
||||
|
||||
std::unique_ptr<WAVFileReader> reader{};
|
||||
|
||||
uint8_t code_index{0}, announce_loop{0};
|
||||
uint32_t sample_counter{0};
|
||||
uint32_t sample_length{0};
|
||||
int8_t audio_buffer[1024]{};
|
||||
uint32_t pause{0};
|
||||
bool armed_blink{false};
|
||||
SignalToken signal_token_tick_second{};
|
||||
|
||||
wav_file_t* get_wav(uint32_t index);
|
||||
bool check_wav_validity(const std::string dir, const std::string file);
|
||||
void on_voice_changed(size_t index);
|
||||
void on_tick_second();
|
||||
void prepare_audio();
|
||||
void start_tx();
|
||||
|
||||
Labels labels{
|
||||
{{2 * 8, 5 * 8}, "Voice: Flags:", Theme::getInstance()->fg_light->foreground},
|
||||
{{1 * 8, 8 * 8}, "Code:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
OptionsField options_voices{
|
||||
{8 * 8, 1 * 8},
|
||||
4,
|
||||
{}};
|
||||
Text text_voice_flags{
|
||||
{19 * 8, 1 * 8, 2 * 8, 16},
|
||||
""};
|
||||
|
||||
SymField symfield_code{
|
||||
{1 * 8, 10 * 8},
|
||||
25,
|
||||
SymField::Type::Custom};
|
||||
|
||||
Checkbox check_armed{
|
||||
{2 * 8, 13 * 16},
|
||||
5,
|
||||
"Armed"};
|
||||
|
||||
/*
|
||||
Button button_tx_now {
|
||||
{ 18 * 8, 13 * 16, 10 * 8, 32 },
|
||||
"TX now"};
|
||||
*/
|
||||
|
||||
Button button_exit{
|
||||
{21 * 8, 16 * 16, 64, 32},
|
||||
"Exit"};
|
||||
|
||||
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->prepare_audio();
|
||||
}
|
||||
}};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
#endif /*__UI_NUMBERS_H__*/
|
@ -1,185 +0,0 @@
|
||||
/*
|
||||
* 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_nuoptix.hpp"
|
||||
|
||||
#include "ch.h"
|
||||
#include "portapack.hpp"
|
||||
#include "lfsr_random.hpp"
|
||||
#include "string_format.hpp"
|
||||
|
||||
#include "portapack_shared_memory.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
|
||||
void NuoptixView::focus() {
|
||||
number_timecode.focus();
|
||||
}
|
||||
|
||||
NuoptixView::~NuoptixView() {
|
||||
transmitter_model.disable();
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
void NuoptixView::on_tx_progress(const uint32_t progress, const bool done) {
|
||||
if (done)
|
||||
transmit(false);
|
||||
else
|
||||
progressbar.set_value(progress);
|
||||
}
|
||||
|
||||
void NuoptixView::transmit(bool setup) {
|
||||
uint8_t mod, tone_code;
|
||||
uint8_t c;
|
||||
uint8_t dtmf_message[6];
|
||||
rtc::RTC datetime;
|
||||
|
||||
if (!tx_mode) {
|
||||
transmitter_model.disable();
|
||||
return;
|
||||
}
|
||||
|
||||
if (tx_mode == IMPROVISE)
|
||||
timecode = lfsr_iterate(timecode) % 1999; // Could be 9999 but that would be one long audio track !
|
||||
|
||||
if (setup) {
|
||||
progressbar.set_max(6 * 2);
|
||||
|
||||
if (tx_mode == IMPROVISE) {
|
||||
// Seed from RTC
|
||||
rtcGetTime(&RTCD1, &datetime);
|
||||
timecode = datetime.day() + datetime.second();
|
||||
} else {
|
||||
timecode = number_timecode.value();
|
||||
}
|
||||
|
||||
transmitter_model.set_rf_amp(true);
|
||||
transmitter_model.enable();
|
||||
|
||||
dtmf_message[0] = '*'; // "Pre-tone for restart" method #1
|
||||
dtmf_message[1] = 'A'; // "Restart" method #1
|
||||
} else {
|
||||
dtmf_message[0] = '#';
|
||||
dtmf_message[1] = (timecode / 1000) % 10;
|
||||
chThdSleepMilliseconds(92); // 141-49ms
|
||||
number_timecode.set_value(timecode);
|
||||
}
|
||||
|
||||
progressbar.set_value(0);
|
||||
|
||||
dtmf_message[2] = (timecode / 100) % 10;
|
||||
dtmf_message[3] = (timecode / 10) % 10;
|
||||
dtmf_message[4] = timecode % 10;
|
||||
|
||||
mod = 0;
|
||||
for (c = 1; c < 5; c++)
|
||||
if (dtmf_message[c] <= 9)
|
||||
mod += dtmf_message[c];
|
||||
|
||||
mod = 10 - (mod % 10);
|
||||
if (mod == 10) mod = 0; // Is this right ?
|
||||
|
||||
text_mod.set("Mod: " + to_string_dec_uint(mod));
|
||||
|
||||
dtmf_message[5] = mod;
|
||||
|
||||
for (c = 0; c < 6; c++) {
|
||||
tone_code = dtmf_message[c];
|
||||
|
||||
if (tone_code == 'A')
|
||||
tone_code = 10;
|
||||
else if (tone_code == 'B')
|
||||
tone_code = 11;
|
||||
else if (tone_code == 'C')
|
||||
tone_code = 12;
|
||||
else if (tone_code == 'D')
|
||||
tone_code = 13;
|
||||
else if (tone_code == '#')
|
||||
tone_code = 14;
|
||||
else if (tone_code == '*')
|
||||
tone_code = 15;
|
||||
|
||||
shared_memory.bb_data.tones_data.message[c * 2] = tone_code;
|
||||
shared_memory.bb_data.tones_data.message[c * 2 + 1] = 0xFF; // Silence
|
||||
}
|
||||
|
||||
for (c = 0; c < 16; c++) {
|
||||
baseband::set_tone(c * 2, dtmf_deltas[c][0], NUOPTIX_TONE_LENGTH);
|
||||
baseband::set_tone(c * 2 + 1, dtmf_deltas[c][1], NUOPTIX_TONE_LENGTH);
|
||||
}
|
||||
shared_memory.bb_data.tones_data.silence = NUOPTIX_TONE_LENGTH; // 49ms tone, 49ms space
|
||||
|
||||
audio::set_rate(audio::Rate::Hz_24000);
|
||||
|
||||
baseband::set_tones_config(transmitter_model.channel_bandwidth(), 0, 6 * 2, true, true);
|
||||
|
||||
timecode++;
|
||||
}
|
||||
|
||||
NuoptixView::NuoptixView(
|
||||
NavigationView& nav) {
|
||||
baseband::run_image(portapack::spi_flash::image_tag_tones);
|
||||
|
||||
add_children({&number_timecode,
|
||||
&text_timecode,
|
||||
&text_mod,
|
||||
&progressbar,
|
||||
&tx_view});
|
||||
|
||||
number_timecode.set_value(1);
|
||||
|
||||
tx_view.on_edit_frequency = [this, &nav]() {
|
||||
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.target_frequency());
|
||||
new_view->on_changed = [this](rf::Frequency f) {
|
||||
transmitter_model.set_target_frequency(f);
|
||||
};
|
||||
};
|
||||
|
||||
tx_view.on_start = [this]() {
|
||||
tx_view.set_transmitting(true);
|
||||
tx_mode = NORMAL;
|
||||
transmit(true);
|
||||
};
|
||||
|
||||
tx_view.on_stop = [this]() {
|
||||
tx_view.set_transmitting(false);
|
||||
tx_mode = IDLE;
|
||||
};
|
||||
|
||||
/*button_impro.on_select = [this](Button&){
|
||||
if (tx_mode == IMPROVISE) {
|
||||
tx_mode = IDLE;
|
||||
button_impro.set_text("IMPROVISE");
|
||||
} else if (tx_mode == IDLE) {
|
||||
tx_mode = IMPROVISE;
|
||||
button_impro.set_text("STOP");
|
||||
transmit(true);
|
||||
}
|
||||
};*/
|
||||
}
|
||||
|
||||
} // namespace ui
|
@ -1,109 +0,0 @@
|
||||
/*
|
||||
* 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_NUOPTIX_H__
|
||||
#define __UI_NUOPTIX_H__
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_transmitter.hpp"
|
||||
#include "rtc_time.hpp"
|
||||
#include "tonesets.hpp"
|
||||
#include "message.hpp"
|
||||
#include "volume.hpp"
|
||||
#include "audio.hpp"
|
||||
#include "radio_state.hpp"
|
||||
|
||||
#define NUOPTIX_TONE_LENGTH ((TONES_SAMPLERATE * 0.049) - 1) // 49ms
|
||||
|
||||
namespace ui {
|
||||
|
||||
class NuoptixView : public View {
|
||||
public:
|
||||
NuoptixView(NavigationView& nav);
|
||||
~NuoptixView();
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "Nuoptix sync"; };
|
||||
|
||||
private:
|
||||
enum tx_modes {
|
||||
IDLE = 0,
|
||||
NORMAL,
|
||||
IMPROVISE
|
||||
};
|
||||
|
||||
TxRadioState radio_state_{
|
||||
0 /* frequency */,
|
||||
1750000 /* bandwidth */,
|
||||
1536000 /* sampling rate */
|
||||
};
|
||||
|
||||
tx_modes tx_mode{IDLE};
|
||||
|
||||
void transmit(bool setup);
|
||||
void on_tx_progress(const uint32_t progress, const bool done);
|
||||
|
||||
uint32_t timecode{0};
|
||||
|
||||
Text text_timecode{
|
||||
{10 * 8, 2 * 16, 9 * 8, 16},
|
||||
"Timecode:"};
|
||||
|
||||
NumberField number_timecode{
|
||||
{13 * 8, 3 * 16},
|
||||
4,
|
||||
{1, 9999},
|
||||
1,
|
||||
'0'};
|
||||
|
||||
Text text_mod{
|
||||
{10 * 8, 5 * 16, 6 * 8, 16},
|
||||
"Mod: "};
|
||||
|
||||
ProgressBar progressbar{
|
||||
{16, 14 * 16, 208, 16}};
|
||||
|
||||
/*Button button_impro {
|
||||
{ 64, 184, 112, 40 },
|
||||
"IMPROVISE"
|
||||
};*/
|
||||
|
||||
TransmitterView tx_view{
|
||||
16 * 16,
|
||||
10000,
|
||||
15};
|
||||
|
||||
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, message.done);
|
||||
}};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
#endif /*__UI_NUOPTIX_H__*/
|
@ -28,7 +28,6 @@
|
||||
#include "file.hpp"
|
||||
#include "file_reader.hpp"
|
||||
#include "tone_key.hpp"
|
||||
#include "replay_app.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include "ui_fileman.hpp"
|
||||
#include "io_file.hpp"
|
||||
|
@ -1,106 +0,0 @@
|
||||
/*
|
||||
* 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_script.hpp"
|
||||
|
||||
#include "portapack.hpp"
|
||||
#include "event_m0.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
|
||||
void ScriptView::on_frequency_select() {
|
||||
// button_edit_freq.focus();
|
||||
}
|
||||
|
||||
void ScriptView::on_edit_freq(rf::Frequency f) {
|
||||
(void)f;
|
||||
// frequencies[menu_view.highlighted()].value = f;
|
||||
setup_list();
|
||||
}
|
||||
|
||||
void ScriptView::on_edit_desc(NavigationView& nav) {
|
||||
(void)nav;
|
||||
}
|
||||
|
||||
void ScriptView::on_delete() {
|
||||
// frequencies.erase(frequencies.begin() + menu_view.highlighted());
|
||||
setup_list();
|
||||
}
|
||||
|
||||
void ScriptView::setup_list() {
|
||||
// size_t n;
|
||||
|
||||
menu_view.clear();
|
||||
|
||||
/*for (n = 0; n < frequencies.size(); n++) {
|
||||
menu_view.add_item({ freqman_item_string(frequencies[n]), Theme::getInstance()->bg_darkest->foreground, nullptr, [this](){ on_frequency_select(); } });
|
||||
}*/
|
||||
|
||||
menu_view.set_parent_rect({0, 0, 240, 168});
|
||||
menu_view.set_highlighted(menu_view.highlighted()); // Refresh
|
||||
}
|
||||
|
||||
void ScriptView::focus() {
|
||||
menu_view.focus();
|
||||
}
|
||||
|
||||
ScriptView::ScriptView(
|
||||
NavigationView& nav) {
|
||||
add_children({&menu_view,
|
||||
&text_edit,
|
||||
&button_edit_freq,
|
||||
&button_edit_desc,
|
||||
&button_del,
|
||||
&button_exit});
|
||||
|
||||
setup_list();
|
||||
|
||||
button_edit_freq.on_select = [this, &nav](Button&) {
|
||||
/*auto new_view = nav.push<FrequencyKeypadView>(frequencies[menu_view.highlighted()].value);
|
||||
new_view->on_changed = [this](rf::Frequency f) {
|
||||
on_edit_freq(f);
|
||||
};*/
|
||||
};
|
||||
|
||||
button_edit_desc.on_select = [this, &nav](Button&) {
|
||||
on_edit_desc(nav);
|
||||
};
|
||||
|
||||
button_del.on_select = [this, &nav](Button&) {
|
||||
nav.push<ModalMessageView>("Confirm", "Are you sure?", YESNO,
|
||||
[this](bool choice) {
|
||||
if (choice) {
|
||||
on_delete();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
button_exit.on_select = [this, &nav](Button&) {
|
||||
nav.pop();
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace ui
|
@ -1,88 +0,0 @@
|
||||
/*
|
||||
* 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.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
#include "ui_painter.hpp"
|
||||
#include "ui_menu.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_receiver.hpp"
|
||||
#include "ui_textentry.hpp"
|
||||
#include "rtc_time.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
enum script_keyword {
|
||||
STOP = 0,
|
||||
WAIT_N,
|
||||
WAIT_RTC,
|
||||
IF,
|
||||
LOOP,
|
||||
END,
|
||||
TX,
|
||||
RX
|
||||
};
|
||||
|
||||
struct script_line {
|
||||
script_keyword keyword;
|
||||
};
|
||||
|
||||
class ScriptView : public View {
|
||||
public:
|
||||
ScriptView(NavigationView& nav);
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "Script editor"; };
|
||||
|
||||
private:
|
||||
void on_frequency_select();
|
||||
void on_edit_freq(rf::Frequency f);
|
||||
void on_edit_desc(NavigationView& nav);
|
||||
void on_delete();
|
||||
void setup_list();
|
||||
|
||||
std::vector<script_line> script{};
|
||||
|
||||
MenuView menu_view{
|
||||
{0, 0, 240, 168},
|
||||
true};
|
||||
|
||||
Text text_edit{
|
||||
{16, 194, 5 * 8, 16},
|
||||
"Edit:"};
|
||||
Button button_edit_freq{
|
||||
{16, 194 + 16, 88, 32},
|
||||
"Frequency"};
|
||||
Button button_edit_desc{
|
||||
{16, 194 + 16 + 34, 88, 32},
|
||||
"Description"};
|
||||
Button button_del{
|
||||
{160, 192, 72, 64},
|
||||
"Delete"};
|
||||
|
||||
Button button_exit{
|
||||
{160, 264, 72, 32},
|
||||
"Exit"};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2018 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_tone_search.hpp"
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
#include "string_format.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
|
||||
void ToneSearchView::focus() {
|
||||
// field_frequency_min.focus();
|
||||
}
|
||||
|
||||
ToneSearchView::~ToneSearchView() {
|
||||
receiver_model.disable();
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
ToneSearchView::ToneSearchView(
|
||||
NavigationView& nav)
|
||||
: nav_(nav) {
|
||||
// baseband::run_image(portapack::spi_flash::image_tag_wideband_spectrum);
|
||||
|
||||
add_children({
|
||||
&labels,
|
||||
&field_lna,
|
||||
&field_vga,
|
||||
&field_rf_amp,
|
||||
});
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2018 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 "receiver_model.hpp"
|
||||
|
||||
#include "ui_receiver.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
class ToneSearchView : public View {
|
||||
public:
|
||||
ToneSearchView(NavigationView& nav);
|
||||
~ToneSearchView();
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "Tone search"; };
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 0 * 8}, "LNA: VGA: AMP:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
LNAGainField field_lna{
|
||||
{4 * 8, 0 * 16}};
|
||||
|
||||
VGAGainField field_vga{
|
||||
{11 * 8, 0 * 16}};
|
||||
|
||||
RFAmpField field_rf_amp{
|
||||
{18 * 8, 0 * 16}};
|
||||
|
||||
/*
|
||||
MessageHandlerRegistration message_handler_frame_sync {
|
||||
Message::ID::DisplayFrameSync,
|
||||
[this](const Message* const) {
|
||||
if( this->fifo ) {
|
||||
ChannelSpectrum channel_spectrum;
|
||||
while( fifo->out(channel_spectrum) ) {
|
||||
this->on_channel_spectrum(channel_spectrum);
|
||||
}
|
||||
}
|
||||
this->do_timers();
|
||||
}
|
||||
};*/
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2017 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 "emu_cc1101.hpp"
|
||||
|
||||
namespace cc1101 {
|
||||
|
||||
void CC1101Emu::whitening_init() {
|
||||
whitening_pn = 0x1FF;
|
||||
}
|
||||
|
||||
// See TI app note DN509
|
||||
uint8_t CC1101Emu::whiten_byte(uint8_t byte) {
|
||||
uint_fast8_t new_bit;
|
||||
|
||||
byte ^= (whitening_pn & 0xFF);
|
||||
|
||||
for (size_t step = 0; step < 8; step++) {
|
||||
new_bit = (whitening_pn & 1) ^ ((whitening_pn >> 5) & 1);
|
||||
whitening_pn >>= 1;
|
||||
whitening_pn |= (new_bit << 8);
|
||||
}
|
||||
|
||||
return byte;
|
||||
}
|
||||
|
||||
} /* namespace cc1101 */
|
@ -96,7 +96,6 @@ Continuous (Fox-oring)
|
||||
// Multimon-style stuff:
|
||||
// TODO: DMR detector
|
||||
// TODO: GSM channel detector
|
||||
// TODO: Playdead amnesia and login
|
||||
// TODO: Setup: Play dead by default ? Enable/disable ?
|
||||
|
||||
// Old or low-priority stuff:
|
||||
@ -106,7 +105,6 @@ Continuous (Fox-oring)
|
||||
// TODO: Check more OOK encoders
|
||||
// BUG (fixed ?): No audio in about when shown second time
|
||||
// TODO: Show MD5 mismatches for modules not found, etc...
|
||||
// TODO: Module name/filename in modules.hpp to indicate requirement in case it's not found ui_loadmodule
|
||||
// BUG: Description doesn't show up first time going to system>module info (UI drawn on top)
|
||||
// TODO: Two players tic-tac-toe
|
||||
// TODO: Analog TV pong game
|
||||
|
@ -1,344 +0,0 @@
|
||||
/*
|
||||
* 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_handwrite.hpp"
|
||||
|
||||
#include "portapack.hpp"
|
||||
#include "hackrf_hal.hpp"
|
||||
#include "portapack_shared_memory.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
|
||||
void HandWriteView::paint(Painter& painter) {
|
||||
_painter = &painter;
|
||||
}
|
||||
|
||||
HandWriteView::HandWriteView(
|
||||
NavigationView& nav,
|
||||
std::string* str,
|
||||
size_t max_length)
|
||||
: TextEntryView(nav, str, max_length) {
|
||||
size_t n;
|
||||
|
||||
// Handwriting alphabet definition here
|
||||
handwriting = &handwriting_unistroke;
|
||||
|
||||
add_children({&button_case});
|
||||
|
||||
const auto button_fn = [this](Button& button) {
|
||||
this->on_button(button);
|
||||
};
|
||||
|
||||
n = 0;
|
||||
for (auto& button : num_buttons) {
|
||||
add_child(&button);
|
||||
button.on_select = button_fn;
|
||||
button.set_parent_rect({static_cast<Coord>(n * 24),
|
||||
static_cast<Coord>(236),
|
||||
24, 28});
|
||||
const std::string label{
|
||||
(char)(n + '0')};
|
||||
button.set_text(label);
|
||||
button.id = n + '0';
|
||||
n++;
|
||||
}
|
||||
|
||||
n = 0;
|
||||
for (auto& button : special_buttons) {
|
||||
add_child(&button);
|
||||
button.on_select = button_fn;
|
||||
button.set_parent_rect({static_cast<Coord>(50 + n * 24),
|
||||
static_cast<Coord>(270),
|
||||
24, 28});
|
||||
const std::string label{
|
||||
(char)(special_chars[n])};
|
||||
button.set_text(label);
|
||||
button.id = special_chars[n];
|
||||
n++;
|
||||
}
|
||||
|
||||
button_case.on_select = [this, &nav](Button&) {
|
||||
if (_lowercase == true) {
|
||||
_lowercase = false;
|
||||
button_case.set_text("LC");
|
||||
} else {
|
||||
_lowercase = true;
|
||||
button_case.set_text("UC");
|
||||
}
|
||||
};
|
||||
|
||||
button_ok.on_select = [this, &nav](Button&) {
|
||||
if (on_changed)
|
||||
on_changed(_str);
|
||||
nav.pop();
|
||||
};
|
||||
|
||||
update_text();
|
||||
}
|
||||
|
||||
bool HandWriteView::on_touch(const TouchEvent event) {
|
||||
if (event.type == ui::TouchEvent::Type::Start) {
|
||||
stroke_index = 0;
|
||||
move_wait = 3;
|
||||
tracing = true;
|
||||
}
|
||||
if (event.type == ui::TouchEvent::Type::End) {
|
||||
tracing = false;
|
||||
guess_letter();
|
||||
}
|
||||
if (event.type == ui::TouchEvent::Type::Move) {
|
||||
if (tracing)
|
||||
current_pos = event.point;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void HandWriteView::clear_zone(const Color color, const bool flash) {
|
||||
display.fill_rectangle(
|
||||
{{0, 32}, {240, 216}},
|
||||
color);
|
||||
if (flash) {
|
||||
flash_timer = 8;
|
||||
} else {
|
||||
// Draw grid
|
||||
_painter->draw_rectangle(
|
||||
{{0, 32}, {80, 216}},
|
||||
Color::grey());
|
||||
_painter->draw_rectangle(
|
||||
{{80, 32}, {80, 216}},
|
||||
Color::grey());
|
||||
_painter->draw_rectangle(
|
||||
{{160, 32}, {80, 216}},
|
||||
Color::grey());
|
||||
_painter->draw_rectangle(
|
||||
{{0, 104}, {240, 72}},
|
||||
Color::grey());
|
||||
}
|
||||
}
|
||||
|
||||
void HandWriteView::guess_letter() {
|
||||
uint32_t symbol, match, count, stroke_idx, stroke_data;
|
||||
Condition cond;
|
||||
Direction dir;
|
||||
bool matched;
|
||||
|
||||
// Letter guessing
|
||||
if (stroke_index) {
|
||||
for (symbol = 0; symbol < handwriting->letter_count; symbol++) {
|
||||
count = handwriting->letter[symbol].count;
|
||||
matched = false;
|
||||
if (count) {
|
||||
// We have a count match to do
|
||||
if ((count == 1) && (stroke_index == 1)) matched = true;
|
||||
if ((count == 2) && (stroke_index == 2)) matched = true;
|
||||
if ((count == 3) && (stroke_index > 2)) matched = true;
|
||||
} else {
|
||||
matched = true;
|
||||
}
|
||||
if (matched) {
|
||||
for (match = 0; match < 3; match++) {
|
||||
cond = handwriting->letter[symbol].match[match].cond;
|
||||
dir = handwriting->letter[symbol].match[match].dir;
|
||||
if ((cond != cond_empty) && (dir != dir_empty)) {
|
||||
if (cond == last) {
|
||||
if (stroke_index)
|
||||
stroke_idx = stroke_index - 1;
|
||||
else
|
||||
stroke_idx = 0;
|
||||
} else if (cond == stroke_a)
|
||||
stroke_idx = 0;
|
||||
else if (cond == stroke_b)
|
||||
stroke_idx = 1;
|
||||
else if (cond == stroke_c)
|
||||
stroke_idx = 2;
|
||||
else
|
||||
stroke_idx = 3;
|
||||
if (stroke_idx >= stroke_index) break;
|
||||
stroke_data = stroke_list[stroke_idx];
|
||||
if ((dir & 0xF0) == 0xF0) {
|
||||
if ((dir & 0x0F) != (stroke_data & 0x0F)) break;
|
||||
} else if ((dir & 0x0F) == 0x0F) {
|
||||
if ((dir & 0xF0) != (stroke_data & 0xF0)) break;
|
||||
} else {
|
||||
if (dir != (int32_t)stroke_data) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (match == 3)
|
||||
break;
|
||||
else
|
||||
matched = false;
|
||||
}
|
||||
}
|
||||
if (matched) {
|
||||
if (symbol) {
|
||||
if (_lowercase)
|
||||
char_add('a' + symbol - 1);
|
||||
else
|
||||
char_add('A' + symbol - 1);
|
||||
clear_zone(Color::green(), true); // Green flash
|
||||
} else {
|
||||
if (_cursor_pos) {
|
||||
char_delete();
|
||||
clear_zone(Color::yellow(), true); // Yellow flash
|
||||
} else {
|
||||
clear_zone(Color::red(), true); // Red flash
|
||||
}
|
||||
}
|
||||
} else {
|
||||
clear_zone(Color::red(), true); // Red flash
|
||||
}
|
||||
} else {
|
||||
// Short tap is space
|
||||
char_add(' ');
|
||||
clear_zone(Color::green(), true); // Green flash
|
||||
}
|
||||
update_text();
|
||||
stroke_index = 0;
|
||||
}
|
||||
|
||||
void HandWriteView::add_stroke(uint8_t dir) {
|
||||
if (stroke_index < 8) {
|
||||
stroke_list[stroke_index] = dir;
|
||||
stroke_index++;
|
||||
} else {
|
||||
guess_letter();
|
||||
}
|
||||
}
|
||||
|
||||
void HandWriteView::sample_pen() {
|
||||
int16_t diff_x, diff_y;
|
||||
uint8_t dir, dir_ud, dir_lr, stroke_prev;
|
||||
|
||||
draw_cursor();
|
||||
|
||||
if (flash_timer) {
|
||||
if (flash_timer == 1) clear_zone(Color::black(), false);
|
||||
flash_timer--;
|
||||
}
|
||||
|
||||
if (!(sample_skip & 1)) {
|
||||
if (tracing) {
|
||||
if (move_wait) {
|
||||
move_wait--; // ~100ms delay to get rid of jitter from touch start
|
||||
} else {
|
||||
diff_x = current_pos.x() - last_pos.x();
|
||||
diff_y = current_pos.y() - last_pos.y();
|
||||
|
||||
if (current_pos.y() <= 240) {
|
||||
display.fill_rectangle(
|
||||
{{current_pos.x(), current_pos.y()}, {4, 4}},
|
||||
Color::grey());
|
||||
}
|
||||
|
||||
dir = 0; // UL by default
|
||||
if (abs(diff_x) > 7) {
|
||||
if (diff_x > 0)
|
||||
dir |= 0x01; // R
|
||||
} else {
|
||||
dir |= 0x02; // ?
|
||||
}
|
||||
if (abs(diff_y) > 7) {
|
||||
if (diff_y > 0)
|
||||
dir |= 0x10; // D
|
||||
} else {
|
||||
dir |= 0x20; // ?
|
||||
}
|
||||
|
||||
// Need at least two identical directions to validate stroke
|
||||
if ((dir & 0x11) == (dir_prev & 0x11))
|
||||
dir_cnt++;
|
||||
else
|
||||
dir_cnt = 0;
|
||||
dir_prev = dir;
|
||||
|
||||
if (dir_cnt > 1) {
|
||||
dir_cnt = 0;
|
||||
if (stroke_index) {
|
||||
if ((stroke_list[stroke_index - 1] != dir) && (dir != 0x22)) {
|
||||
// Register stroke if different from last one
|
||||
dir_ud = (dir & 0xF0);
|
||||
dir_lr = (dir & 0x0F);
|
||||
stroke_prev = stroke_list[stroke_index - 1];
|
||||
if (dir_ud == 0x20) {
|
||||
// LR changed
|
||||
if ((stroke_prev & 0x0F) != dir_lr) add_stroke(dir);
|
||||
} else if (dir_lr == 0x02) {
|
||||
// UD changed
|
||||
if ((stroke_prev & 0xF0) != dir_ud) add_stroke(dir);
|
||||
} else {
|
||||
// Add direction
|
||||
if (((stroke_prev & 0xF0) == 0x20) && (dir_ud != 0x20)) {
|
||||
// Add UD
|
||||
if ((stroke_prev & 0x0F) == dir_lr) {
|
||||
// Replace totally
|
||||
stroke_list[stroke_index - 1] = dir;
|
||||
} else if (dir_lr == 0x02) {
|
||||
// Merge UD
|
||||
stroke_list[stroke_index - 1] = dir_ud | (stroke_prev & 0x0F);
|
||||
} else {
|
||||
add_stroke(dir);
|
||||
}
|
||||
} else if (((stroke_prev & 0x0F) == 0x02) && (dir_lr != 0x02)) {
|
||||
// Add LR
|
||||
if ((stroke_prev & 0xF0) == dir_ud) {
|
||||
// Replace totally
|
||||
stroke_list[stroke_index - 1] = dir;
|
||||
} else if (dir_ud == 0x20) {
|
||||
// Merge LR
|
||||
stroke_list[stroke_index - 1] = dir_lr | (stroke_prev & 0xF0);
|
||||
} else {
|
||||
add_stroke(dir);
|
||||
}
|
||||
} else {
|
||||
add_stroke(dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Register first stroke
|
||||
if (dir != 0x22) add_stroke(dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
last_pos = current_pos;
|
||||
}
|
||||
}
|
||||
|
||||
sample_skip++;
|
||||
}
|
||||
|
||||
void HandWriteView::on_show() {
|
||||
clear_zone(Color::black(), false);
|
||||
}
|
||||
|
||||
void HandWriteView::on_button(Button& button) {
|
||||
char_add(button.id);
|
||||
update_text();
|
||||
}
|
||||
|
||||
} // namespace ui
|
@ -1,88 +0,0 @@
|
||||
/*
|
||||
* 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 __UNISTROKE_H__
|
||||
#define __UNISTROKE_H__
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
#include "ui_painter.hpp"
|
||||
#include "ui_textentry.hpp"
|
||||
#include "unistroke.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
class HandWriteView : public TextEntryView {
|
||||
public:
|
||||
HandWriteView(NavigationView& nav, std::string* str, size_t max_length);
|
||||
|
||||
HandWriteView(const HandWriteView&) = delete;
|
||||
HandWriteView(HandWriteView&&) = delete;
|
||||
HandWriteView& operator=(const HandWriteView&) = delete;
|
||||
HandWriteView& operator=(HandWriteView&&) = delete;
|
||||
|
||||
void paint(Painter& painter) override;
|
||||
void on_show() override;
|
||||
bool on_touch(const TouchEvent event) override;
|
||||
|
||||
private:
|
||||
const char special_chars[5] = {'\'', '.', '?', '!', '='};
|
||||
|
||||
const HandWriting* handwriting{};
|
||||
Painter* _painter{};
|
||||
uint8_t dir_cnt{0};
|
||||
uint8_t dir_prev{0};
|
||||
uint8_t flash_timer{0};
|
||||
bool tracing{false};
|
||||
uint8_t stroke_index{0};
|
||||
uint8_t sample_skip{0}, move_wait{0};
|
||||
uint8_t stroke_list[8];
|
||||
Point start_pos{}, current_pos{}, last_pos{};
|
||||
bool _lowercase = false;
|
||||
|
||||
void sample_pen();
|
||||
void add_stroke(uint8_t dir);
|
||||
void guess_letter();
|
||||
void clear_zone(const Color color, const bool flash);
|
||||
void on_button(Button& button);
|
||||
|
||||
std::array<Button, 10> num_buttons{};
|
||||
std::array<Button, 5> special_buttons{};
|
||||
|
||||
Button button_case{
|
||||
{8, 270, 32, 28},
|
||||
"UC"};
|
||||
|
||||
Button button_ok{
|
||||
{190, 270, 40, 28},
|
||||
"OK"};
|
||||
|
||||
MessageHandlerRegistration message_handler_sample{
|
||||
Message::ID::DisplayFrameSync,
|
||||
[this](const Message* const) {
|
||||
this->sample_pen();
|
||||
}};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
#endif /*__UNISTROKE_H__*/
|
@ -1,170 +0,0 @@
|
||||
/*
|
||||
* 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_loadmodule.hpp"
|
||||
|
||||
#include "ch.h"
|
||||
|
||||
#include "ff.h"
|
||||
#include "event_m0.hpp"
|
||||
#include "hackrf_gpio.hpp"
|
||||
#include "portapack.hpp"
|
||||
#include "portapack_shared_memory.hpp"
|
||||
#include "hackrf_hal.hpp"
|
||||
#include "string_format.hpp"
|
||||
|
||||
#include "ui_rds.hpp"
|
||||
#include "ui_xylos.hpp"
|
||||
#include "ui_epar.hpp"
|
||||
#include "ui_lcr.hpp"
|
||||
#include "analog_audio_app.hpp"
|
||||
#include "ui_soundboard.hpp"
|
||||
#include "ui_debug.hpp"
|
||||
#include "ui_closecall.hpp"
|
||||
#include "ui_audiotx.hpp"
|
||||
#include "ui_jammer.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
|
||||
void LoadModuleView::focus() {
|
||||
button_ok.focus();
|
||||
}
|
||||
|
||||
void LoadModuleView::on_show() {
|
||||
char md5_signature[16];
|
||||
uint8_t c;
|
||||
|
||||
memcpy(md5_signature, (const void*)(0x10087FF0), 16);
|
||||
for (c = 0; c < 16; c++) {
|
||||
if (md5_signature[c] != _hash[c]) break;
|
||||
}
|
||||
// text_info.set(to_string_hex(*((unsigned int*)0x10087FF0), 8));
|
||||
|
||||
if (c == 16) {
|
||||
text_info.set("Module already loaded :)");
|
||||
_mod_loaded = true;
|
||||
} else {
|
||||
text_info.set("Loading module");
|
||||
loadmodule();
|
||||
}
|
||||
}
|
||||
|
||||
int LoadModuleView::load_image() {
|
||||
const char magic[6] = {'P', 'P', 'M', ' ', 0x02, 0x00};
|
||||
UINT bw;
|
||||
uint8_t i;
|
||||
uint32_t cnt;
|
||||
char md5sum[16];
|
||||
FILINFO modinfo;
|
||||
FIL modfile;
|
||||
DIR rootdir;
|
||||
FRESULT res;
|
||||
|
||||
// Scan SD card root directory for files with the right MD5 fingerprint at the right location
|
||||
if (f_opendir(&rootdir, "/") == FR_OK) {
|
||||
for (;;) {
|
||||
res = f_readdir(&rootdir, &modinfo);
|
||||
if (res != FR_OK || modinfo.fname[0] == 0) break; // Reached last file, abort
|
||||
// Only care about files with .bin extension
|
||||
if ((!(modinfo.fattrib & AM_DIR)) && (modinfo.fname[9] == 'B') && (modinfo.fname[10] == 'I') && (modinfo.fname[11] == 'N')) {
|
||||
res = f_open(&modfile, modinfo.fname, FA_OPEN_EXISTING | FA_READ);
|
||||
if (res != FR_OK) return 0;
|
||||
// Magic bytes and version check
|
||||
f_read(&modfile, &md5sum, 6, &bw);
|
||||
for (i = 0; i < 6; i++)
|
||||
if (md5sum[i] != magic[i]) break;
|
||||
if (i == 6) {
|
||||
f_lseek(&modfile, 26);
|
||||
f_read(&modfile, &md5sum, 16, &bw);
|
||||
for (i = 0; i < 16; i++)
|
||||
if (md5sum[i] != _hash[i]) break;
|
||||
// f_read can't read more than 512 bytes at a time ?
|
||||
if (i == 16) {
|
||||
f_lseek(&modfile, 512);
|
||||
for (cnt = 0; cnt < 64; cnt++) {
|
||||
if (f_read(&modfile, reinterpret_cast<void*>(portapack::memory::map::m4_code.base() + (cnt * 512)), 512, &bw)) return 0;
|
||||
}
|
||||
f_close(&modfile);
|
||||
f_closedir(&rootdir);
|
||||
LPC_RGU->RESET_CTRL[0] = (1 << 13);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
f_close(&modfile);
|
||||
}
|
||||
}
|
||||
f_closedir(&rootdir);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LoadModuleView::loadmodule() {
|
||||
// baseband::shutdown();
|
||||
|
||||
/*EventDispatcher::message_map().register_handler(Message::ID::ReadyForSwitch,
|
||||
[this](Message* const p) {
|
||||
(void)p;*/
|
||||
if (load_image()) {
|
||||
text_infob.set("Module loaded :)");
|
||||
_mod_loaded = true;
|
||||
} else {
|
||||
text_info.set("Module not found :(");
|
||||
_mod_loaded = false;
|
||||
}
|
||||
// }
|
||||
//);
|
||||
}
|
||||
|
||||
LoadModuleView::LoadModuleView(
|
||||
NavigationView& nav,
|
||||
const char* hash,
|
||||
ViewID viewid) {
|
||||
add_children({&text_info,
|
||||
&text_infob,
|
||||
&button_ok});
|
||||
|
||||
_hash = hash;
|
||||
|
||||
button_ok.on_select = [this, &nav, viewid](Button&) {
|
||||
nav.pop();
|
||||
if (_mod_loaded == true) {
|
||||
if (viewid == AudioTX) nav.push<AudioTXView>();
|
||||
if (viewid == Xylos) nav.push<XylosView>();
|
||||
if (viewid == EPAR) nav.push<EPARView>();
|
||||
if (viewid == LCR) nav.push<LCRView>();
|
||||
if (viewid == SoundBoard) nav.push<SoundBoardView>();
|
||||
if (viewid == AnalogAudio) nav.push<AnalogAudioView>();
|
||||
if (viewid == RDS) nav.push<RDSView>();
|
||||
if (viewid == CloseCall) nav.push<CloseCallView>();
|
||||
if (viewid == Receiver) nav.push<ReceiverMenuView>();
|
||||
if (viewid == Jammer) nav.push<JammerView>();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
@ -1,70 +0,0 @@
|
||||
/*
|
||||
* 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.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
#include "ui_painter.hpp"
|
||||
#include "ui_menu.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "core_control.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
enum ViewID {
|
||||
Receiver,
|
||||
AudioTX,
|
||||
CloseCall,
|
||||
Xylos,
|
||||
EPAR,
|
||||
LCR,
|
||||
SoundBoard,
|
||||
AnalogAudio,
|
||||
RDS,
|
||||
Jammer
|
||||
};
|
||||
|
||||
class LoadModuleView : public View {
|
||||
public:
|
||||
LoadModuleView(NavigationView& nav, const char* hash, ViewID viewid);
|
||||
void loadmodule();
|
||||
|
||||
void on_show() override;
|
||||
void focus() override;
|
||||
|
||||
private:
|
||||
int load_image(void);
|
||||
const char* _hash;
|
||||
bool _mod_loaded = false;
|
||||
|
||||
Text text_info{
|
||||
{8, 64, 224, 16},
|
||||
"-"};
|
||||
Text text_infob{
|
||||
{8, 64 + 16, 224, 16},
|
||||
"-"};
|
||||
|
||||
Button button_ok{
|
||||
{88, 128, 64, 32},
|
||||
"OK"};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
@ -24,8 +24,6 @@
|
||||
|
||||
#include "ui_navigation.hpp"
|
||||
|
||||
// #include "modules.h"
|
||||
|
||||
#include "bmp_modal_warning.hpp"
|
||||
#include "bmp_splash.hpp"
|
||||
#include "event_m0.hpp"
|
||||
@ -35,12 +33,10 @@
|
||||
|
||||
#include "ui_about_simple.hpp"
|
||||
#include "ui_adsb_rx.hpp"
|
||||
// #include "ui_adsb_tx.hpp" //moved to ext
|
||||
#include "ui_aprs_rx.hpp"
|
||||
#include "ui_aprs_tx.hpp"
|
||||
#include "ui_bht_tx.hpp"
|
||||
#include "ui_btle_rx.hpp"
|
||||
// #include "ui_coasterp.hpp" //moved to ext
|
||||
#include "ui_debug.hpp"
|
||||
#include "ui_encoders.hpp"
|
||||
#include "ui_fileman.hpp"
|
||||
@ -49,17 +45,10 @@
|
||||
#include "ui_freqman.hpp"
|
||||
#include "ui_fsk_rx.hpp"
|
||||
#include "ui_iq_trim.hpp"
|
||||
// #include "ui_jammer.hpp" //moved to ext
|
||||
// #include "ui_keyfob.hpp" //moved to ext
|
||||
// #include "ui_lcr.hpp"
|
||||
#include "ui_level.hpp"
|
||||
#include "ui_looking_glass_app.hpp"
|
||||
#include "ui_mictx.hpp"
|
||||
// #include "ui_morse.hpp" //moved to ext
|
||||
// #include "ui_nrf_rx.hpp" //moved to ext
|
||||
// #include "ui_numbers.hpp"
|
||||
// #include "ui_nuoptix.hpp"
|
||||
// #include "ui_playdead.hpp"
|
||||
|
||||
#include "ui_playlist.hpp"
|
||||
#include "ui_pocsag_tx.hpp"
|
||||
#include "ui_rds.hpp"
|
||||
@ -72,12 +61,9 @@
|
||||
#include "ui_settings.hpp"
|
||||
#include "ui_siggen.hpp"
|
||||
#include "ui_sonde.hpp"
|
||||
// #include "ui_spectrum_painter.hpp" //moved to ext app
|
||||
#include "ui_ss_viewer.hpp"
|
||||
// #include "ui_sstvtx.hpp" //moved to ext
|
||||
// #include "ui_test.hpp"
|
||||
#include "ui_text_editor.hpp"
|
||||
#include "ui_tone_search.hpp"
|
||||
#include "ui_touchtunes.hpp"
|
||||
#include "ui_view_wav.hpp"
|
||||
#include "ui_weatherstation.hpp"
|
||||
@ -88,18 +74,13 @@
|
||||
|
||||
#include "ais_app.hpp"
|
||||
#include "analog_audio_app.hpp"
|
||||
// #include "analog_tv_app.hpp" //moved to ext
|
||||
// #include "ble_comm_app.hpp"
|
||||
#include "ble_rx_app.hpp"
|
||||
#include "ble_tx_app.hpp"
|
||||
#include "capture_app.hpp"
|
||||
#include "ert_app.hpp"
|
||||
// #include "gps_sim_app.hpp" //moved to ext
|
||||
// #include "lge_app.hpp" //moved to ext
|
||||
#include "pocsag_app.hpp"
|
||||
#include "replay_app.hpp"
|
||||
#include "soundboard_app.hpp"
|
||||
// #include "tpms_app.hpp" //moved to ext
|
||||
|
||||
#include "core_control.hpp"
|
||||
#include "file.hpp"
|
||||
@ -142,7 +123,6 @@ static NavigationView::AppMap generate_app_map(const NavigationView::AppList& ap
|
||||
// TODO(u-foka): Check consistency of command names (where we add rx/tx postfix)
|
||||
const NavigationView::AppList NavigationView::appList = {
|
||||
/* HOME ******************************************************************/
|
||||
//{"playdead", "Play dead", HOME, Color::red(), &bitmap_icon_playdead, new ViewFactory<PlayDeadView>()},
|
||||
{nullptr, "Receive", HOME, Color::cyan(), &bitmap_icon_receivers, new ViewFactory<ReceiversMenuView>()},
|
||||
{nullptr, "Transmit", HOME, Color::cyan(), &bitmap_icon_transmit, new ViewFactory<TransmittersMenuView>()},
|
||||
{"capture", "Capture", HOME, Color::red(), &bitmap_icon_capture, new ViewFactory<CaptureAppView>()},
|
||||
@ -154,13 +134,11 @@ const NavigationView::AppList NavigationView::appList = {
|
||||
{nullptr, "Utilities", HOME, Color::cyan(), &bitmap_icon_utilities, new ViewFactory<UtilitiesMenuView>()},
|
||||
{nullptr, "Settings", HOME, Color::cyan(), &bitmap_icon_setup, new ViewFactory<SettingsMenuView>()},
|
||||
{nullptr, "Debug", HOME, Color::light_grey(), &bitmap_icon_debug, new ViewFactory<DebugMenuView>()},
|
||||
//{"about", "About", HOME, Color::cyan(), nullptr, new ViewFactory<AboutView>()},
|
||||
/* RX ********************************************************************/
|
||||
{"adsbrx", "ADS-B", RX, Color::green(), &bitmap_icon_adsb, new ViewFactory<ADSBRxView>()},
|
||||
{"ais", "AIS Boats", RX, Color::green(), &bitmap_icon_ais, new ViewFactory<AISAppView>()},
|
||||
{"aprsrx", "APRS", RX, Color::green(), &bitmap_icon_aprs, new ViewFactory<APRSRXView>()},
|
||||
{"audio", "Audio", RX, Color::green(), &bitmap_icon_speaker, new ViewFactory<AnalogAudioView>()},
|
||||
//{"btle", "BTLE", RX, Color::yellow(), &bitmap_icon_btle, new ViewFactory<BTLERxView>()},
|
||||
//{"blecomm", "BLE Comm", RX, ui::Color::orange(), &bitmap_icon_btle, new ViewFactory<BLECommView>()},
|
||||
{"blerx", "BLE Rx", RX, Color::green(), &bitmap_icon_btle, new ViewFactory<BLERxView>()},
|
||||
{"ert", "ERT Meter", RX, Color::green(), &bitmap_icon_ert, new ViewFactory<ERTAppView>()},
|
||||
@ -169,10 +147,8 @@ const NavigationView::AppList NavigationView::appList = {
|
||||
{"radiosonde", "Radiosnde", RX, Color::green(), &bitmap_icon_sonde, new ViewFactory<SondeView>()},
|
||||
{"recon", "Recon", RX, Color::green(), &bitmap_icon_scanner, new ViewFactory<ReconView>()},
|
||||
{"search", "Search", RX, Color::yellow(), &bitmap_icon_search, new ViewFactory<SearchView>()},
|
||||
//{"tmps", "TPMS Cars", RX, Color::green(), &bitmap_icon_tpms, new ViewFactory<TPMSAppView>()},
|
||||
{"subghzd", "SubGhzD", RX, Color::yellow(), &bitmap_icon_remote, new ViewFactory<SubGhzDView>()},
|
||||
{"weather", "Weather", RX, Color::green(), &bitmap_icon_thermometer, new ViewFactory<WeatherView>()},
|
||||
//{"fskrx", "FSK RX", RX, Color::yellow(), &bitmap_icon_remote, new ViewFactory<FskxRxMainView>()},
|
||||
//{"dmr", "DMR", RX, Color::dark_grey(), &bitmap_icon_dmr, new ViewFactory<NotImplementedView>()},
|
||||
//{"sigfox", "SIGFOX", RX, Color::dark_grey(), &bitmap_icon_fox, new ViewFactory<NotImplementedView>()},
|
||||
//{"lora", "LoRa", RX, Color::dark_grey(), &bitmap_icon_lora, new ViewFactory<NotImplementedView>()},
|
||||
@ -183,13 +159,10 @@ const NavigationView::AppList NavigationView::appList = {
|
||||
{"aprstx", "APRS TX", TX, ui::Color::green(), &bitmap_icon_aprs, new ViewFactory<APRSTXView>()},
|
||||
{"bht", "BHT Xy/EP", TX, ui::Color::green(), &bitmap_icon_bht, new ViewFactory<BHTView>()},
|
||||
{"bletx", "BLE Tx", TX, ui::Color::green(), &bitmap_icon_btle, new ViewFactory<BLETxView>()},
|
||||
//{"morse", "Morse", TX, ui::Color::green(), &bitmap_icon_morse, new ViewFactory<MorseView>()}, //moved to ext
|
||||
//{"nuoptixdtmf", "Nuoptix DTMF", TX, ui::Color::green(), &bitmap_icon_nuoptix, new ViewFactory<NuoptixView>()},
|
||||
{"ooktx", "OOK", TX, ui::Color::yellow(), &bitmap_icon_remote, new ViewFactory<EncodersView>()},
|
||||
{"pocsagtx", "POCSAG TX", TX, ui::Color::green(), &bitmap_icon_pocsag, new ViewFactory<POCSAGTXView>()},
|
||||
{"rdstx", "RDS", TX, ui::Color::green(), &bitmap_icon_rds, new ViewFactory<RDSView>()},
|
||||
{"soundbrd", "Soundbrd", TX, ui::Color::green(), &bitmap_icon_soundboard, new ViewFactory<SoundBoardView>()},
|
||||
//{"sstvtx", "SSTV", TX, ui::Color::green(), &bitmap_icon_sstv, new ViewFactory<SSTVTXView>()}, //moved to ext
|
||||
{"touchtune", "TouchTune", TX, ui::Color::green(), &bitmap_icon_touchtunes, new ViewFactory<TouchTunesView>()},
|
||||
/* UTILITIES *************************************************************/
|
||||
{"antennalength", "Antenna Length", UTILITIES, Color::green(), &bitmap_icon_tools_antenna, new ViewFactory<WhipCalcView>()},
|
||||
@ -200,7 +173,7 @@ const NavigationView::AppList NavigationView::appList = {
|
||||
{nullptr, "SD Over USB", UTILITIES, Color::yellow(), &bitmap_icon_hackrf, new ViewFactory<SdOverUsbView>()},
|
||||
{"signalgen", "Signal Gen", UTILITIES, Color::green(), &bitmap_icon_cwgen, new ViewFactory<SigGenView>()},
|
||||
//{"testapp", "Test App", UTILITIES, Color::dark_grey(), nullptr, new ViewFactory<TestView>()},
|
||||
//{"tonesearch", "Tone Search", UTILITIES, Color::dark_grey(), nullptr, new ViewFactory<ToneSearchView>()},
|
||||
|
||||
{"wavview", "Wav View", UTILITIES, Color::yellow(), &bitmap_icon_soundboard, new ViewFactory<ViewWavView>()},
|
||||
// Dangerous apps.
|
||||
{nullptr, "Flash Utility", UTILITIES, Color::red(), &bitmap_icon_temperature, new ViewFactory<FlashUtilityView>()},
|
||||
|
@ -1,82 +0,0 @@
|
||||
/*
|
||||
* 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_playdead.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
#include "string_format.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
|
||||
void PlayDeadView::focus() {
|
||||
button_seq_entry.focus();
|
||||
}
|
||||
|
||||
void PlayDeadView::paint(Painter& painter) {
|
||||
if (persistent_memory::config_login()) {
|
||||
// Blank the whole display
|
||||
painter.fill_rectangle(
|
||||
display.screen_rect(),
|
||||
style().background);
|
||||
}
|
||||
}
|
||||
|
||||
PlayDeadView::PlayDeadView(NavigationView& nav) {
|
||||
rtc::RTC datetime;
|
||||
|
||||
persistent_memory::set_playing_dead(0x5920C1DF); // Enable
|
||||
|
||||
add_children({
|
||||
&text_playdead1,
|
||||
&text_playdead2,
|
||||
&text_playdead3,
|
||||
&button_seq_entry,
|
||||
});
|
||||
|
||||
// Seed from RTC
|
||||
rtcGetTime(&RTCD1, &datetime);
|
||||
text_playdead2.set("0x" + to_string_hex(lfsr_iterate(datetime.second()), 6) + "00");
|
||||
|
||||
text_playdead3.hidden(true);
|
||||
|
||||
button_seq_entry.on_dir = [this](Button&, KeyEvent key) {
|
||||
sequence = (sequence << 3) | (static_cast<std::underlying_type<KeyEvent>::type>(key) + 1);
|
||||
return true;
|
||||
};
|
||||
|
||||
button_seq_entry.on_select = [this, &nav](Button&) {
|
||||
if (sequence == persistent_memory::playdead_sequence()) {
|
||||
persistent_memory::set_playing_dead(0x82175E23); // Disable
|
||||
if (persistent_memory::config_login()) {
|
||||
text_playdead3.hidden(false);
|
||||
} else {
|
||||
nav.pop();
|
||||
nav.push<SystemMenuView>();
|
||||
}
|
||||
} else {
|
||||
sequence = 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
@ -1,60 +0,0 @@
|
||||
/*
|
||||
* 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_PLAYDEAD_H__
|
||||
#define __UI_PLAYDEAD_H__
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
class PlayDeadView : public View {
|
||||
public:
|
||||
PlayDeadView(NavigationView& nav);
|
||||
|
||||
void focus() override;
|
||||
void paint(Painter& painter) override;
|
||||
|
||||
private:
|
||||
uint32_t sequence = 0;
|
||||
|
||||
Text text_playdead1{
|
||||
{6 * 8, 7 * 16, 14 * 8, 16},
|
||||
"\x46irmwa"
|
||||
"re "
|
||||
"er\x72o\x72"};
|
||||
Text text_playdead2{
|
||||
{6 * 8, 9 * 16, 16 * 8, 16},
|
||||
""};
|
||||
Text text_playdead3{
|
||||
{6 * 8, 12 * 16, 16 * 8, 16},
|
||||
"Please reset"};
|
||||
|
||||
Button button_seq_entry{
|
||||
{240, 0, 1, 1},
|
||||
""};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
#endif /*__UI_PLAYDEAD_H__*/
|
@ -424,13 +424,6 @@ set(MODE_CPPSRC
|
||||
)
|
||||
DeclareTargets(PNFM nfm_audio)
|
||||
|
||||
#### No op
|
||||
#
|
||||
#set(MODE_CPPSRC
|
||||
# proc_noop.cpp
|
||||
#)
|
||||
#DeclareTargets(PNOP no_operation)
|
||||
|
||||
### OOK
|
||||
|
||||
set(MODE_CPPSRC
|
||||
@ -438,12 +431,6 @@ set(MODE_CPPSRC
|
||||
)
|
||||
DeclareTargets(POOK ook)
|
||||
|
||||
#### POCSAG RX
|
||||
#
|
||||
#set(MODE_CPPSRC
|
||||
# proc_pocsag.cpp
|
||||
#)
|
||||
#DeclareTargets(PPOC pocsag)
|
||||
|
||||
### POCSAG2 RX
|
||||
|
||||
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 "proc_noop.hpp"
|
||||
#include "event_m4.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
void NOOPProcessor::execute(const buffer_c8_t& buffer) {
|
||||
for (size_t i = 0; i < buffer.count; i++) {
|
||||
buffer.p[i] = {0, 0};
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
EventDispatcher event_dispatcher{std::make_unique<NOOPProcessor>()};
|
||||
event_dispatcher.run();
|
||||
return 0;
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 __PROC_NOOP_H__
|
||||
#define __PROC_NOOP_H__
|
||||
|
||||
#include "baseband_processor.hpp"
|
||||
#include "baseband_thread.hpp"
|
||||
|
||||
class NOOPProcessor : public BasebandProcessor {
|
||||
public:
|
||||
void execute(const buffer_c8_t& buffer) override;
|
||||
|
||||
private:
|
||||
/* NB: Threads should be the last members in the class definition. */
|
||||
BasebandThread baseband_thread{1536000, this, baseband::Direction::Transmit};
|
||||
};
|
||||
|
||||
#endif
|
@ -1,539 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu)
|
||||
* Copyright (C) 2012-2014 Elias Oenal (multimon-ng@eliasoenal.com)
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyright (C) 2016 Kyle Reed
|
||||
*
|
||||
* 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 "proc_pocsag.hpp"
|
||||
|
||||
#include "dsp_iir_config.hpp"
|
||||
#include "event_m4.hpp"
|
||||
#include "audio_dma.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
void POCSAGProcessor::execute(const buffer_c8_t& buffer) {
|
||||
if (!configured) return;
|
||||
|
||||
// Get 24kHz audio
|
||||
const auto decim_0_out = decim_0.execute(buffer, dst_buffer);
|
||||
const auto decim_1_out = decim_1.execute(decim_0_out, dst_buffer);
|
||||
const auto channel_out = channel_filter.execute(decim_1_out, dst_buffer);
|
||||
auto audio = demod.execute(channel_out, audio_buffer);
|
||||
|
||||
// If squelching, check for audio before smoothing because smoothing
|
||||
// causes the squelch noise detection to fail. Likely because squelch
|
||||
// looks for HF noise and smoothing is basically a lowpass filter.
|
||||
// NB: Squelch in this processor is only for the the audio output.
|
||||
// Squelching will likely drop data "noise" and break processing.
|
||||
if (squelch_.enabled()) {
|
||||
bool has_audio = squelch_.execute(audio);
|
||||
squelch_history = (squelch_history << 1) | (has_audio ? 1 : 0);
|
||||
}
|
||||
|
||||
smooth.Process(audio.p, audio.count);
|
||||
processDemodulatedSamples(audio.p, 16);
|
||||
extractFrames();
|
||||
|
||||
samples_processed += buffer.count;
|
||||
if (samples_processed >= stat_update_threshold) {
|
||||
send_stats();
|
||||
samples_processed = 0;
|
||||
}
|
||||
|
||||
// Clear the output before sending to audio chip.
|
||||
// Only clear the audio buffer when there hasn't been any audio for a while.
|
||||
if (squelch_.enabled() && squelch_history == 0) {
|
||||
for (size_t i = 0; i < audio.count; ++i) {
|
||||
audio.p[i] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
audio_output.write(audio);
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
//
|
||||
// ====================================================================
|
||||
int POCSAGProcessor::OnDataWord(uint32_t word, int pos) {
|
||||
packet.set(pos, word);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
//
|
||||
// ====================================================================
|
||||
int POCSAGProcessor::OnDataFrame(int len, int baud) {
|
||||
if (len > 0) {
|
||||
packet.set_bitrate(baud);
|
||||
packet.set_flag(pocsag::PacketFlag::NORMAL);
|
||||
packet.set_timestamp(Timestamp::now());
|
||||
const POCSAGPacketMessage message(packet);
|
||||
shared_memory.application_queue.push(message);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void POCSAGProcessor::on_message(const Message* const message) {
|
||||
switch (message->id) {
|
||||
case Message::ID::POCSAGConfigure:
|
||||
configure();
|
||||
break;
|
||||
|
||||
case Message::ID::NBFMConfigure: {
|
||||
auto config = reinterpret_cast<const NBFMConfigureMessage*>(message);
|
||||
squelch_.set_threshold(config->squelch_level / 100.0);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void POCSAGProcessor::configure() {
|
||||
constexpr size_t decim_0_input_fs = baseband_fs;
|
||||
constexpr size_t decim_0_output_fs = decim_0_input_fs / decim_0.decimation_factor;
|
||||
|
||||
constexpr size_t decim_1_input_fs = decim_0_output_fs;
|
||||
constexpr size_t decim_1_output_fs = decim_1_input_fs / decim_1.decimation_factor;
|
||||
|
||||
constexpr size_t channel_filter_input_fs = decim_1_output_fs;
|
||||
const size_t channel_filter_output_fs = channel_filter_input_fs / 2;
|
||||
|
||||
const size_t demod_input_fs = channel_filter_output_fs;
|
||||
|
||||
decim_0.configure(taps_11k0_decim_0.taps);
|
||||
decim_1.configure(taps_11k0_decim_1.taps);
|
||||
channel_filter.configure(taps_11k0_channel.taps, 2);
|
||||
demod.configure(demod_input_fs, 4'500); // FSK +/- 4k5Hz.
|
||||
|
||||
// Smoothing should be roughly sample rate over max baud
|
||||
// 24k / 3.2k = 7.5
|
||||
smooth.SetSize(8);
|
||||
|
||||
// Don't have audio process the stream.
|
||||
audio_output.configure(false);
|
||||
|
||||
// Set up the frame extraction, limits of baud
|
||||
setFrameExtractParams(demod_input_fs, 4000, 300, 32);
|
||||
|
||||
// Mark the class as ready to accept data
|
||||
configured = true;
|
||||
}
|
||||
|
||||
void POCSAGProcessor::send_stats() const {
|
||||
POCSAGStatsMessage message(m_fifo.codeword, m_numCode, m_gotSync, getRate());
|
||||
shared_memory.application_queue.push(message);
|
||||
}
|
||||
|
||||
// -----------------------------
|
||||
// Frame extractraction methods
|
||||
// -----------------------------
|
||||
#define BAUD_STABLE (104)
|
||||
#define MAX_CONSEC_SAME (32)
|
||||
#define MAX_WITHOUT_SINGLE (64)
|
||||
#define MAX_BAD_TRANS (10)
|
||||
|
||||
#define M_SYNC (0x7cd215d8)
|
||||
#define M_NOTSYNC (0x832dea27)
|
||||
|
||||
#define M_IDLE (0x7a89c197)
|
||||
|
||||
// ====================================================================
|
||||
//
|
||||
// ====================================================================
|
||||
inline int bitsDiff(unsigned long left, unsigned long right) {
|
||||
unsigned long xord = left ^ right;
|
||||
int count = 0;
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if ((xord & 0x01) != 0) ++count;
|
||||
xord = xord >> 1;
|
||||
}
|
||||
return (count);
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
//
|
||||
// ====================================================================
|
||||
void POCSAGProcessor::initFrameExtraction() {
|
||||
m_averageSymbolLen_1024 = m_maxSymSamples_1024;
|
||||
m_lastStableSymbolLen_1024 = m_minSymSamples_1024;
|
||||
|
||||
m_badTransitions = 0;
|
||||
m_bitsStart = 0;
|
||||
m_bitsEnd = 0;
|
||||
m_inverted = false;
|
||||
|
||||
resetVals();
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
//
|
||||
// ====================================================================
|
||||
void POCSAGProcessor::resetVals() {
|
||||
// Reset the parameters
|
||||
// --------------------
|
||||
m_goodTransitions = 0;
|
||||
m_badTransitions = 0;
|
||||
m_averageSymbolLen_1024 = m_maxSymSamples_1024;
|
||||
m_shortestGoodTrans_1024 = m_maxSymSamples_1024;
|
||||
m_valMid = 0;
|
||||
|
||||
// And reset the counts
|
||||
// --------------------
|
||||
m_lastTransPos_1024 = 0;
|
||||
m_lastBitPos_1024 = 0;
|
||||
m_lastSample = 0;
|
||||
m_sampleNo = 0;
|
||||
m_nextBitPos_1024 = m_maxSymSamples_1024;
|
||||
m_nextBitPosInt = (long)m_nextBitPos_1024;
|
||||
|
||||
// Extraction
|
||||
m_fifo.numBits = 0;
|
||||
m_gotSync = false;
|
||||
m_numCode = 0;
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
//
|
||||
// ====================================================================
|
||||
void POCSAGProcessor::setFrameExtractParams(long a_samplesPerSec, long a_maxBaud, long a_minBaud, long maxRunOfSameValue) {
|
||||
m_samplesPerSec = a_samplesPerSec;
|
||||
m_minSymSamples_1024 = (uint32_t)(1024.0f * (float)a_samplesPerSec / (float)a_maxBaud);
|
||||
m_maxSymSamples_1024 = (uint32_t)(1024.0f * (float)a_samplesPerSec / (float)a_minBaud);
|
||||
m_maxRunOfSameValue = maxRunOfSameValue;
|
||||
|
||||
m_shortestGoodTrans_1024 = m_maxSymSamples_1024;
|
||||
m_averageSymbolLen_1024 = m_maxSymSamples_1024;
|
||||
m_lastStableSymbolLen_1024 = m_minSymSamples_1024;
|
||||
|
||||
m_nextBitPos_1024 = m_averageSymbolLen_1024 / 2;
|
||||
m_nextBitPosInt = m_nextBitPos_1024 >> 10;
|
||||
|
||||
initFrameExtraction();
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
//
|
||||
// ====================================================================
|
||||
int POCSAGProcessor::processDemodulatedSamples(float* sampleBuff, int noOfSamples) {
|
||||
bool transition = false;
|
||||
uint32_t samplePos_1024 = 0;
|
||||
uint32_t len_1024 = 0;
|
||||
|
||||
// Loop through the block of data
|
||||
// ------------------------------
|
||||
for (int pos = 0; pos < noOfSamples; ++pos) {
|
||||
m_sample = sampleBuff[pos];
|
||||
m_valMid += (m_sample - m_valMid) / 1024.0f;
|
||||
|
||||
++m_sampleNo;
|
||||
|
||||
// Detect Transition
|
||||
// -----------------
|
||||
transition = !((m_lastSample < m_valMid) ^ (m_sample >= m_valMid)); // use XOR for speed
|
||||
|
||||
// If this is a transition
|
||||
// -----------------------
|
||||
if (transition) {
|
||||
// Calculate samples since last trans
|
||||
// ----------------------------------
|
||||
int32_t fractional_1024 = (int32_t)(((m_sample - m_valMid) * 1024) / (m_sample - m_lastSample));
|
||||
if (fractional_1024 < 0) {
|
||||
fractional_1024 = -fractional_1024;
|
||||
}
|
||||
|
||||
samplePos_1024 = (m_sampleNo << 10) - fractional_1024;
|
||||
len_1024 = samplePos_1024 - m_lastTransPos_1024;
|
||||
m_lastTransPos_1024 = samplePos_1024;
|
||||
|
||||
// If symbol is large enough to be valid
|
||||
// -------------------------------------
|
||||
if (len_1024 > m_minSymSamples_1024) {
|
||||
// Check for shortest good transition
|
||||
// ----------------------------------
|
||||
if ((len_1024 < m_shortestGoodTrans_1024) &&
|
||||
(m_goodTransitions < BAUD_STABLE)) // detect change of symbol size
|
||||
{
|
||||
int32_t fractionOfShortest_1024 = (len_1024 << 10) / m_shortestGoodTrans_1024;
|
||||
|
||||
// If currently at half the baud rate
|
||||
// ----------------------------------
|
||||
if ((fractionOfShortest_1024 > 410) && (fractionOfShortest_1024 < 614)) // 0.4 and 0.6
|
||||
{
|
||||
m_averageSymbolLen_1024 /= 2;
|
||||
m_shortestGoodTrans_1024 = len_1024;
|
||||
}
|
||||
// If currently at the wrong baud rate
|
||||
// -----------------------------------
|
||||
else if (fractionOfShortest_1024 < 768) // 0.75
|
||||
{
|
||||
m_averageSymbolLen_1024 = len_1024;
|
||||
m_shortestGoodTrans_1024 = len_1024;
|
||||
m_goodTransitions = 0;
|
||||
m_lastSingleBitPos_1024 = samplePos_1024 - len_1024;
|
||||
}
|
||||
}
|
||||
|
||||
// Calc the number of bits since events
|
||||
// ------------------------------------
|
||||
int32_t halfSymbol_1024 = m_averageSymbolLen_1024 / 2;
|
||||
int bitsSinceLastTrans = max((uint32_t)1, (len_1024 + halfSymbol_1024) / m_averageSymbolLen_1024);
|
||||
int bitsSinceLastSingle = (((m_sampleNo << 10) - m_lastSingleBitPos_1024) + halfSymbol_1024) / m_averageSymbolLen_1024;
|
||||
|
||||
// Check for single bit
|
||||
// --------------------
|
||||
if (bitsSinceLastTrans == 1) {
|
||||
m_lastSingleBitPos_1024 = samplePos_1024;
|
||||
}
|
||||
|
||||
// If too long since last transition
|
||||
// ---------------------------------
|
||||
if (bitsSinceLastTrans > MAX_CONSEC_SAME) {
|
||||
resetVals();
|
||||
}
|
||||
// If too long sice last single bit
|
||||
// --------------------------------
|
||||
else if (bitsSinceLastSingle > MAX_WITHOUT_SINGLE) {
|
||||
resetVals();
|
||||
} else {
|
||||
// If this is a good transition
|
||||
// ----------------------------
|
||||
int32_t offsetFromExtectedTransition_1024 = len_1024 - (bitsSinceLastTrans * m_averageSymbolLen_1024);
|
||||
if (offsetFromExtectedTransition_1024 < 0) {
|
||||
offsetFromExtectedTransition_1024 = -offsetFromExtectedTransition_1024;
|
||||
}
|
||||
if (offsetFromExtectedTransition_1024 < ((int32_t)m_averageSymbolLen_1024 / 4)) // Has to be within 1/4 of symbol to be good
|
||||
{
|
||||
++m_goodTransitions;
|
||||
uint32_t bitsCount = min((uint32_t)BAUD_STABLE, m_goodTransitions);
|
||||
|
||||
uint32_t propFromPrevious = m_averageSymbolLen_1024 * bitsCount;
|
||||
uint32_t propFromCurrent = (len_1024 / bitsSinceLastTrans);
|
||||
m_averageSymbolLen_1024 = (propFromPrevious + propFromCurrent) / (bitsCount + 1);
|
||||
m_badTransitions = 0;
|
||||
// if ( len < m_shortestGoodTrans ){m_shortestGoodTrans = len;}
|
||||
// Store the old symbol size
|
||||
if (m_goodTransitions >= BAUD_STABLE) {
|
||||
m_lastStableSymbolLen_1024 = m_averageSymbolLen_1024;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the point of the last bit if not yet stable
|
||||
// -----------------------------------------------
|
||||
if ((m_goodTransitions < BAUD_STABLE) || (m_badTransitions > 0)) {
|
||||
m_lastBitPos_1024 = samplePos_1024 - (m_averageSymbolLen_1024 / 2);
|
||||
}
|
||||
|
||||
// Calculate the exact positiom of the next bit
|
||||
// --------------------------------------------
|
||||
int32_t thisPlusHalfsymbol_1024 = samplePos_1024 + (m_averageSymbolLen_1024 / 2);
|
||||
int32_t lastPlusSymbol = m_lastBitPos_1024 + m_averageSymbolLen_1024;
|
||||
m_nextBitPos_1024 = lastPlusSymbol + ((thisPlusHalfsymbol_1024 - lastPlusSymbol) / 16);
|
||||
|
||||
// Check for bad pos error
|
||||
// -----------------------
|
||||
if (m_nextBitPos_1024 < samplePos_1024) m_nextBitPos_1024 += m_averageSymbolLen_1024;
|
||||
|
||||
// Calculate integer sample after next bit
|
||||
// ---------------------------------------
|
||||
m_nextBitPosInt = (m_nextBitPos_1024 >> 10) + 1;
|
||||
|
||||
} // symbol is large enough to be valid
|
||||
else {
|
||||
// Bad transition, so reset the counts
|
||||
// -----------------------------------
|
||||
++m_badTransitions;
|
||||
if (m_badTransitions > MAX_BAD_TRANS) {
|
||||
resetVals();
|
||||
}
|
||||
}
|
||||
} // end of if transition
|
||||
|
||||
// Reached the point of the next bit
|
||||
// ---------------------------------
|
||||
if (m_sampleNo >= m_nextBitPosInt) {
|
||||
// Everything is good so extract a bit
|
||||
// -----------------------------------
|
||||
if (m_goodTransitions > 20) {
|
||||
// Store value at the center of bit
|
||||
// --------------------------------
|
||||
storeBit();
|
||||
}
|
||||
// Check for long 1 or zero
|
||||
// ------------------------
|
||||
uint32_t bitsSinceLastTrans = ((m_sampleNo << 10) - m_lastTransPos_1024) / m_averageSymbolLen_1024;
|
||||
if (bitsSinceLastTrans > m_maxRunOfSameValue) {
|
||||
resetVals();
|
||||
}
|
||||
|
||||
// Store the point of the last bit
|
||||
// -------------------------------
|
||||
m_lastBitPos_1024 = m_nextBitPos_1024;
|
||||
|
||||
// Calculate the exact point of the next bit
|
||||
// -----------------------------------------
|
||||
m_nextBitPos_1024 += m_averageSymbolLen_1024;
|
||||
|
||||
// Look for the bit after the next bit pos
|
||||
// ---------------------------------------
|
||||
m_nextBitPosInt = (m_nextBitPos_1024 >> 10) + 1;
|
||||
|
||||
} // Reached the point of the next bit
|
||||
|
||||
m_lastSample = m_sample;
|
||||
|
||||
} // Loop through the block of data
|
||||
|
||||
return getNoOfBits();
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
//
|
||||
// ====================================================================
|
||||
void POCSAGProcessor::storeBit() {
|
||||
if (++m_bitsStart >= BIT_BUF_SIZE) {
|
||||
m_bitsStart = 0;
|
||||
}
|
||||
|
||||
// Calculate the bit value
|
||||
float sample = (m_sample + m_lastSample) / 2;
|
||||
// int32_t sample_1024 = m_sample_1024;
|
||||
bool bit = sample > m_valMid;
|
||||
|
||||
// If buffer not full
|
||||
if (m_bitsStart != m_bitsEnd) {
|
||||
// Decide on output val
|
||||
if (bit) {
|
||||
m_bits[m_bitsStart] = 0;
|
||||
} else {
|
||||
m_bits[m_bitsStart] = 1;
|
||||
}
|
||||
}
|
||||
// Throw away bits if the buffer is full
|
||||
else {
|
||||
if (--m_bitsStart <= -1) {
|
||||
m_bitsStart = BIT_BUF_SIZE - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
//
|
||||
// ====================================================================
|
||||
int POCSAGProcessor::extractFrames() {
|
||||
int msgCnt = 0;
|
||||
// While there is unread data in the bits buffer
|
||||
//----------------------------------------------
|
||||
while (getNoOfBits() > 0) {
|
||||
m_fifo.codeword = (m_fifo.codeword << 1) + getBit();
|
||||
m_fifo.numBits++;
|
||||
|
||||
// If number of bits in fifo equals 32
|
||||
//------------------------------------
|
||||
if (m_fifo.numBits >= 32) {
|
||||
// Not got sync
|
||||
// ------------
|
||||
if (!m_gotSync) {
|
||||
if (bitsDiff(m_fifo.codeword, M_SYNC) <= 2) {
|
||||
m_inverted = false;
|
||||
m_gotSync = true;
|
||||
m_numCode = -1;
|
||||
m_fifo.numBits = 0;
|
||||
} else if (bitsDiff(m_fifo.codeword, M_NOTSYNC) <= 2) {
|
||||
m_inverted = true;
|
||||
m_gotSync = true;
|
||||
m_numCode = -1;
|
||||
m_fifo.numBits = 0;
|
||||
} else {
|
||||
// Cause it to load one more bit
|
||||
m_fifo.numBits = 31;
|
||||
}
|
||||
} // Not got sync
|
||||
else {
|
||||
// Increment the word count
|
||||
// ------------------------
|
||||
++m_numCode; // It got set to -1 when a sync was found, now count the 16 words
|
||||
uint32_t val = m_inverted ? ~m_fifo.codeword : m_fifo.codeword;
|
||||
OnDataWord(val, m_numCode);
|
||||
|
||||
// If at the end of a 16 word block
|
||||
// --------------------------------
|
||||
if (m_numCode >= 15) {
|
||||
msgCnt += OnDataFrame(m_numCode + 1, (m_samplesPerSec << 10) / m_lastStableSymbolLen_1024);
|
||||
m_gotSync = false;
|
||||
m_numCode = -1;
|
||||
}
|
||||
m_fifo.numBits = 0;
|
||||
}
|
||||
} // If number of bits in fifo equals 32
|
||||
} // While there is unread data in the bits buffer
|
||||
return msgCnt;
|
||||
} // extractFrames
|
||||
|
||||
// ====================================================================
|
||||
//
|
||||
// ====================================================================
|
||||
short POCSAGProcessor::getBit() {
|
||||
if (m_bitsEnd != m_bitsStart) {
|
||||
if (++m_bitsEnd >= BIT_BUF_SIZE) {
|
||||
m_bitsEnd = 0;
|
||||
}
|
||||
return m_bits[m_bitsEnd];
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
//
|
||||
// ====================================================================
|
||||
int POCSAGProcessor::getNoOfBits() {
|
||||
int bits = m_bitsEnd - m_bitsStart;
|
||||
if (bits < 0) {
|
||||
bits += BIT_BUF_SIZE;
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
//
|
||||
// ====================================================================
|
||||
uint32_t POCSAGProcessor::getRate() const {
|
||||
return ((m_samplesPerSec << 10) + 512) / m_lastStableSymbolLen_1024;
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
//
|
||||
// ====================================================================
|
||||
int main() {
|
||||
audio::dma::init_audio_out();
|
||||
|
||||
EventDispatcher event_dispatcher{std::make_unique<POCSAGProcessor>()};
|
||||
event_dispatcher.run();
|
||||
return 0;
|
||||
}
|
@ -1,233 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu)
|
||||
* Copyright (C) 2012-2014 Elias Oenal (multimon-ng@eliasoenal.com)
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyright (C) 2023 Kyle Reed
|
||||
*
|
||||
* 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 __PROC_POCSAG_H__
|
||||
#define __PROC_POCSAG_H__
|
||||
|
||||
#include "baseband_processor.hpp"
|
||||
#include "baseband_thread.hpp"
|
||||
#include "rssi_thread.hpp"
|
||||
|
||||
#include "dsp_decimate.hpp"
|
||||
#include "dsp_demodulate.hpp"
|
||||
|
||||
#include "pocsag_packet.hpp"
|
||||
|
||||
#include "pocsag.hpp"
|
||||
#include "message.hpp"
|
||||
#include "audio_output.hpp"
|
||||
#include "portapack_shared_memory.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <bitset>
|
||||
using namespace std;
|
||||
|
||||
// Class used to smooth demodulated waveform prior to decoding
|
||||
// -----------------------------------------------------------
|
||||
template <class ValType, class CalcType>
|
||||
class SmoothVals {
|
||||
protected:
|
||||
ValType* m_lastVals; // Previous N values
|
||||
int m_size; // The size N
|
||||
CalcType m_sumVal; // Running sum of lastVals
|
||||
int m_pos; // Current position in last vals ring buffer
|
||||
int m_count; //
|
||||
|
||||
public:
|
||||
SmoothVals()
|
||||
: m_lastVals(NULL), m_size(1), m_sumVal(0), m_pos(0), m_count(0) {
|
||||
m_lastVals = new ValType[m_size];
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
virtual ~SmoothVals() {
|
||||
delete[] m_lastVals;
|
||||
}
|
||||
|
||||
SmoothVals(const SmoothVals<float, float>&) {
|
||||
}
|
||||
|
||||
SmoothVals& operator=(const SmoothVals<float, float>&) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// Set size of smoothing
|
||||
// --------------------------------------------------
|
||||
void SetSize(int size) {
|
||||
m_size = std::max(size, 1);
|
||||
m_pos = 0;
|
||||
delete[] m_lastVals;
|
||||
m_lastVals = new ValType[m_size];
|
||||
m_sumVal = 0;
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// Get size of smoothing
|
||||
// --------------------------------------------------
|
||||
int Size() { return m_size; }
|
||||
|
||||
// --------------------------------------------------
|
||||
// In place processing
|
||||
// --------------------------------------------------
|
||||
void Process(ValType* valBuff, int numVals) {
|
||||
ValType tmpVal;
|
||||
|
||||
if (m_count > (1024 * 10)) {
|
||||
// Recalculate the sum value occasionaly, stops accumulated errors when using float
|
||||
m_count = 0;
|
||||
m_sumVal = 0;
|
||||
for (int i = 0; i < m_size; ++i) {
|
||||
m_sumVal += (CalcType)m_lastVals[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Use a rolling smoothed value while processing the buffer
|
||||
for (int buffPos = 0; buffPos < numVals; ++buffPos) {
|
||||
m_pos++;
|
||||
if (m_pos >= m_size) {
|
||||
m_pos = 0;
|
||||
}
|
||||
|
||||
m_sumVal -= (CalcType)m_lastVals[m_pos]; // Subtract the oldest value
|
||||
m_lastVals[m_pos] = valBuff[buffPos]; // Store the new value
|
||||
m_sumVal += (CalcType)m_lastVals[m_pos]; // Add on the new value
|
||||
|
||||
tmpVal = (ValType)(m_sumVal / m_size); // Scale by number of values smoothed
|
||||
valBuff[buffPos] = tmpVal;
|
||||
}
|
||||
|
||||
m_count += numVals;
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------
|
||||
// Class to process base band data to pocsag frames
|
||||
// --------------------------------------------------
|
||||
class POCSAGProcessor : public BasebandProcessor {
|
||||
public:
|
||||
void execute(const buffer_c8_t& buffer) override;
|
||||
void on_message(const Message* const message) override;
|
||||
|
||||
int OnDataFrame(int len, int baud);
|
||||
int OnDataWord(uint32_t word, int pos);
|
||||
|
||||
private:
|
||||
static constexpr size_t baseband_fs = 3072000;
|
||||
static constexpr uint8_t stat_update_interval = 10;
|
||||
static constexpr uint32_t stat_update_threshold =
|
||||
baseband_fs / stat_update_interval;
|
||||
|
||||
std::array<complex16_t, 512> dst{};
|
||||
const buffer_c16_t dst_buffer{
|
||||
dst.data(),
|
||||
dst.size()};
|
||||
std::array<float, 32> audio{};
|
||||
const buffer_f32_t audio_buffer{
|
||||
audio.data(),
|
||||
audio.size()};
|
||||
|
||||
dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0{};
|
||||
dsp::decimate::FIRC16xR16x32Decim8 decim_1{};
|
||||
dsp::decimate::FIRAndDecimateComplex channel_filter{};
|
||||
dsp::demodulate::FM demod{};
|
||||
SmoothVals<float, float> smooth = {};
|
||||
|
||||
AudioOutput audio_output{};
|
||||
|
||||
bool configured = false;
|
||||
pocsag::POCSAGPacket packet{};
|
||||
|
||||
uint32_t samples_processed = 0;
|
||||
|
||||
void configure();
|
||||
void send_stats() const;
|
||||
|
||||
// ----------------------------------------
|
||||
// Frame extractraction methods and members
|
||||
// ----------------------------------------
|
||||
void initFrameExtraction();
|
||||
struct FIFOStruct {
|
||||
unsigned long codeword;
|
||||
int numBits;
|
||||
};
|
||||
|
||||
#define BIT_BUF_SIZE (64)
|
||||
|
||||
void resetVals();
|
||||
void setFrameExtractParams(long a_samplesPerSec, long a_maxBaud = 8000, long a_minBaud = 200, long maxRunOfSameValue = 32);
|
||||
|
||||
int processDemodulatedSamples(float* sampleBuff, int noOfSamples);
|
||||
int extractFrames();
|
||||
|
||||
void storeBit();
|
||||
short getBit();
|
||||
|
||||
int getNoOfBits();
|
||||
uint32_t getRate() const;
|
||||
|
||||
uint32_t m_averageSymbolLen_1024{0};
|
||||
uint32_t m_lastStableSymbolLen_1024{0};
|
||||
|
||||
uint32_t m_samplesPerSec{0};
|
||||
uint32_t m_goodTransitions{0};
|
||||
uint32_t m_badTransitions{0};
|
||||
|
||||
uint32_t m_sampleNo{0};
|
||||
float m_sample{0};
|
||||
float m_valMid{0.0f};
|
||||
float m_lastSample{0.0f};
|
||||
|
||||
uint32_t m_lastTransPos_1024{0};
|
||||
uint32_t m_lastSingleBitPos_1024{0};
|
||||
|
||||
uint32_t m_nextBitPosInt{0}; // Integer rounded up version to save on ops
|
||||
uint32_t m_nextBitPos_1024{0};
|
||||
uint32_t m_lastBitPos_1024{0};
|
||||
|
||||
uint32_t m_shortestGoodTrans_1024{0};
|
||||
uint32_t m_minSymSamples_1024{0};
|
||||
uint32_t m_maxSymSamples_1024{0};
|
||||
uint32_t m_maxRunOfSameValue{0};
|
||||
|
||||
bitset<(size_t)BIT_BUF_SIZE> m_bits{0};
|
||||
long m_bitsStart{0};
|
||||
long m_bitsEnd{0};
|
||||
|
||||
FIFOStruct m_fifo{0, 0};
|
||||
bool m_gotSync{false};
|
||||
int m_numCode{0};
|
||||
bool m_inverted{false};
|
||||
|
||||
FMSquelch squelch_{};
|
||||
uint64_t squelch_history = 0;
|
||||
|
||||
/* NB: Threads should be the last members in the class definition. */
|
||||
BasebandThread baseband_thread{baseband_fs, this, baseband::Direction::Receive};
|
||||
RSSIThread rssi_thread{};
|
||||
};
|
||||
|
||||
#endif /*__PROC_POCSAG_H__*/
|
@ -1,111 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2017 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 __EMU_CC1101_H__
|
||||
#define __EMU_CC1101_H__
|
||||
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace cc1101 {
|
||||
|
||||
// Data rate (Bauds)
|
||||
// Whitening: Everything except preamble and sync word, init value = 111111111
|
||||
// Packet format: preamble, sync word, (opt) length, (opt) address, payload, (opt) CRC
|
||||
// Preamble: 8*n bits of 10101010
|
||||
// Sync word: 2 bytes (can be repeated twice)
|
||||
// Length: 1 byte (address + payload)
|
||||
// 2-FSK: 0=-dev, 1=+dev
|
||||
// 4-FSK: 00=-1/3dev, 01=-dev, 10=1/3dev, 11=+dev (preamble and sync are in 2-FSK)
|
||||
// OOK: PA on or off
|
||||
// ASK: Power can be adjusted
|
||||
// FEC: ?
|
||||
|
||||
class CC1101Emu {
|
||||
public:
|
||||
// CC1101Emu();
|
||||
//~CC1101Emu();
|
||||
|
||||
enum packet_mode_t {
|
||||
FIXED_LENGTH,
|
||||
VARIABLE_LENGTH,
|
||||
INFINITE_LENGTH
|
||||
};
|
||||
|
||||
enum modulation_t {
|
||||
TWO_FSK,
|
||||
GFSK,
|
||||
OOK,
|
||||
FOUR_FSK,
|
||||
MSK,
|
||||
};
|
||||
|
||||
void set_sync_word(const uint16_t sync_word) {
|
||||
sync_word_ = sync_word;
|
||||
};
|
||||
void set_address(const uint8_t address) {
|
||||
address_ = address;
|
||||
};
|
||||
void set_packet_length(const uint8_t packet_length) {
|
||||
packet_length_ = packet_length;
|
||||
};
|
||||
void set_data_config(const bool CRC, const bool manchester, const bool whitening) {
|
||||
CRC_ = CRC;
|
||||
manchester_ = manchester;
|
||||
whitening_ = whitening;
|
||||
};
|
||||
void set_packet_mode(const packet_mode_t packet_mode) {
|
||||
packet_mode_ = packet_mode;
|
||||
};
|
||||
void set_modulation(const modulation_t modulation) {
|
||||
modulation_ = modulation;
|
||||
}
|
||||
void set_num_preamble(const uint8_t num_preamble) { // 2, 3, 4, 6, 8, 12, 16, or 24
|
||||
num_preamble_ = num_preamble;
|
||||
};
|
||||
void set_deviation(const size_t deviation) {
|
||||
deviation_ = deviation;
|
||||
};
|
||||
|
||||
private:
|
||||
uint16_t sync_word_{0xD391};
|
||||
uint8_t address_{0x00};
|
||||
uint8_t packet_length_{0};
|
||||
bool CRC_{false};
|
||||
bool manchester_{false};
|
||||
bool whitening_{true};
|
||||
packet_mode_t packet_mode_{VARIABLE_LENGTH};
|
||||
modulation_t modulation_{TWO_FSK};
|
||||
uint8_t num_preamble_{4};
|
||||
size_t deviation_{4000};
|
||||
|
||||
uint16_t whitening_pn{0x1FF};
|
||||
|
||||
void whitening_init();
|
||||
uint8_t whiten_byte(uint8_t byte);
|
||||
};
|
||||
|
||||
} /* namespace cc1101 */
|
||||
|
||||
#endif /*__EMU_CC1101_H__*/
|
@ -1,36 +0,0 @@
|
||||
const char md5_baseband[16] = {
|
||||
0xb8,
|
||||
0x9e,
|
||||
0x9b,
|
||||
0x08,
|
||||
0x44,
|
||||
0x34,
|
||||
0x04,
|
||||
0x20,
|
||||
0x0b,
|
||||
0xbc,
|
||||
0x60,
|
||||
0x7e,
|
||||
0x67,
|
||||
0x88,
|
||||
0x53,
|
||||
0xf7,
|
||||
};
|
||||
const char md5_baseband_tx[16] = {
|
||||
0xd5,
|
||||
0xaf,
|
||||
0x76,
|
||||
0xd5,
|
||||
0xa3,
|
||||
0x32,
|
||||
0x5d,
|
||||
0x9a,
|
||||
0x9d,
|
||||
0x83,
|
||||
0x46,
|
||||
0x37,
|
||||
0x02,
|
||||
0x2d,
|
||||
0xd0,
|
||||
0x57,
|
||||
};
|
@ -184,10 +184,9 @@ struct data_t {
|
||||
int32_t modem_baudrate;
|
||||
int32_t modem_repeat;
|
||||
|
||||
// Play dead unlock (Used?)
|
||||
uint32_t playdead_magic;
|
||||
uint32_t playing_dead;
|
||||
uint32_t playdead_sequence;
|
||||
uint32_t UNUSED_2;
|
||||
uint32_t UNUSED_3;
|
||||
uint32_t UNUSED_4;
|
||||
|
||||
// UI Config
|
||||
ui_config_t ui_config;
|
||||
@ -269,11 +268,9 @@ struct data_t {
|
||||
afsk_space_freq(afsk_space_reset_value),
|
||||
modem_baudrate(modem_baudrate_reset_value),
|
||||
modem_repeat(modem_repeat_reset_value),
|
||||
|
||||
playdead_magic(), // TODO: Unused?
|
||||
playing_dead(), // TODO: Unused?
|
||||
playdead_sequence(), // TODO: Unused?
|
||||
|
||||
UNUSED_2(0),
|
||||
UNUSED_3(0),
|
||||
UNUSED_4(0),
|
||||
ui_config(),
|
||||
|
||||
pocsag_last_address(0), // TODO: A better default?
|
||||
@ -1221,9 +1218,6 @@ bool debug_dump() {
|
||||
pmem_dump_file.write_line("afsk_space_freq: " + to_string_dec_int(data->afsk_space_freq));
|
||||
pmem_dump_file.write_line("modem_baudrate: " + to_string_dec_int(data->modem_baudrate));
|
||||
pmem_dump_file.write_line("modem_repeat: " + to_string_dec_int(data->modem_repeat));
|
||||
pmem_dump_file.write_line("playdead_magic: " + to_string_dec_uint(data->playdead_magic));
|
||||
pmem_dump_file.write_line("playing_dead: " + to_string_dec_uint(data->playing_dead));
|
||||
pmem_dump_file.write_line("playdead_sequence: " + to_string_dec_uint(data->playdead_sequence));
|
||||
pmem_dump_file.write_line("pocsag_last_address: " + to_string_dec_uint(data->pocsag_last_address));
|
||||
pmem_dump_file.write_line("pocsag_ignore_address: " + to_string_dec_uint(data->pocsag_ignore_address));
|
||||
pmem_dump_file.write_line("tone_mix: " + to_string_dec_uint(data->tone_mix));
|
||||
|
@ -189,12 +189,6 @@ void set_modem_baudrate(const int32_t new_value);
|
||||
uint8_t modem_repeat();
|
||||
void set_modem_repeat(const uint32_t new_value);
|
||||
|
||||
uint32_t playing_dead();
|
||||
void set_playing_dead(const uint32_t new_value);
|
||||
|
||||
uint32_t playdead_sequence();
|
||||
void set_playdead_sequence(const uint32_t new_value);
|
||||
|
||||
bool stealth_mode();
|
||||
void set_stealth_mode(const bool v);
|
||||
|
||||
|
@ -1,117 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (C) 2016 Furrtek
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
import sys
|
||||
import struct
|
||||
import md5
|
||||
|
||||
usage_message = """
|
||||
Baseband module package file generator
|
||||
|
||||
Usage: <command> <module_name> <module_name>...
|
||||
"""
|
||||
|
||||
def read_image(path):
|
||||
f = open(path, 'rb')
|
||||
data = f.read()
|
||||
f.close()
|
||||
return data
|
||||
|
||||
def write_file(data, path):
|
||||
f = open(path, 'wb')
|
||||
f.write(data)
|
||||
f.close()
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
print(usage_message)
|
||||
sys.exit(-1)
|
||||
|
||||
data = bytearray()
|
||||
h_data = bytearray()
|
||||
name = bytearray()
|
||||
info = bytearray()
|
||||
description = bytearray()
|
||||
data_default_byte = bytearray((0,))
|
||||
|
||||
sys.argv = sys.argv[1:]
|
||||
|
||||
# Format for module file:
|
||||
# Magic (4), Version (2), Length (4), Name (16), MD5 (16), Description (214)
|
||||
# 0x00 pad bytes (256)
|
||||
# Module binary (padded to 32768-16)
|
||||
# MD5 (16) again, so that module code can read it (dirty...)
|
||||
|
||||
for args in sys.argv:
|
||||
m = md5.new()
|
||||
data = read_image(args + '/build/' + args + '.bin')
|
||||
data_r = data
|
||||
|
||||
# Magic bytes
|
||||
info = 'PPM '
|
||||
|
||||
# Version
|
||||
info += struct.pack('H', 2)
|
||||
|
||||
# Length
|
||||
info += struct.pack('I', len(data))
|
||||
|
||||
# Module name
|
||||
name = read_image(args + '/name')
|
||||
if len(name) > 16:
|
||||
name = name[0:15]
|
||||
pad_size = 16 - len(name)
|
||||
name += (data_default_byte * pad_size)
|
||||
info += name
|
||||
|
||||
# Module MD5 footprint
|
||||
m.update(data)
|
||||
digest = m.digest()
|
||||
pad_size = 16 - len(digest)
|
||||
digest += (data_default_byte * pad_size)
|
||||
info += digest
|
||||
|
||||
# Module description
|
||||
description = read_image(args + '/description')
|
||||
if len(description) > 214:
|
||||
description = description[0:213]
|
||||
pad_size = 214 - len(description)
|
||||
description += (data_default_byte * pad_size)
|
||||
info += description
|
||||
|
||||
# Header padding to fit in SD card sector
|
||||
info += (data_default_byte * 256)
|
||||
|
||||
# Binary padding
|
||||
data = info + data
|
||||
pad_size = (32768 + 512 - 16) - len(data)
|
||||
data += (data_default_byte * pad_size)
|
||||
data += digest
|
||||
write_file(data, args + '.bin')
|
||||
|
||||
# Add to modules.h
|
||||
md5sum = ''
|
||||
for byte in digest:
|
||||
md5sum += '0x' + format(byte, '02x') + ','
|
||||
h_data += 'const char md5_' + args.replace('-','_') + '[16] = {' + md5sum + '};\n'
|
||||
|
||||
# Update original binary with MD5 footprint
|
||||
write_file(data[512:(32768+512)], args + '/build/' + args + '_inc.bin')
|
||||
|
||||
write_file(h_data, 'common/modules.h')
|
Loading…
Reference in New Issue
Block a user