mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2025-08-15 08:57:42 +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:
@@ -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 */
|
Reference in New Issue
Block a user