mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-08-24 00:19:02 +00:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| eb22af84ff | |||
| 6dc25813e2 | |||
| 4ee00c0031 | |||
| 55525ed4ad | |||
| 84dcfe29a7 | |||
| 1ebe956557 | |||
| ae656f07bf | |||
| d5c894b322 | |||
| 9cea76a9f3 | |||
| ead9449609 | |||
| fff63e056a | |||
| 42da7443b4 | |||
| ee10081854 | |||
| b38d1012fa | |||
| 5075349d2d | |||
| 8497b62c13 |
@@ -1 +1 @@
|
||||
v2.0.1
|
||||
v2.0.2
|
||||
|
||||
@@ -1 +1 @@
|
||||
v2.0.2
|
||||
v2.1.0
|
||||
|
||||
@@ -9,9 +9,7 @@
|
||||
|
||||
This is a fork of the [Havoc](https://github.com/furrtek/portapack-havoc/) firmware, which itself was a fork of the [PortaPack](https://github.com/sharebrained/portapack-hackrf) firmware, an add-on for the [HackRF](http://greatscottgadgets.com/hackrf/). A fork is a derivate, in this case one that has extra features and fixes when compared to the older versions.
|
||||
|
||||
[<img src="https://raw.githubusercontent.com/wiki/portapack-mayhem/mayhem-firmware/img/hw_overview_h2_front.png" height="400">](https://github.com/portapack-mayhem/mayhem-firmware/wiki/Hardware-overview) [<img src="https://raw.githubusercontent.com/wiki/portapack-mayhem/mayhem-firmware/img/hw_overview_h2_inside.png" height="400">](https://github.com/portapack-mayhem/mayhem-firmware/wiki/Hardware-overview#portapack-internals)
|
||||
|
||||
*[PortaPack H2+HackRF+battery](https://www.ebay.com/itm/116382397447) (clone) with a custom [3d printed case](https://github.com/portapack-mayhem/mayhem-firmware/wiki/3d-printed-enclosure)*
|
||||
[<img src="https://github.com/user-attachments/assets/dea337ab-fb64-4a2a-b419-69afd272e815" height="400">](https://github.com/portapack-mayhem/mayhem-firmware/wiki/PortaPack-Versions#new-h4m-mayhem-edition) [<img src="https://camo.githubusercontent.com/5c1f1da0688240ac7b2ccca0c8dbfd1d73f2540741ad8b1828ba4d5ea68af248/68747470733a2f2f6769746875622d70726f64756374696f6e2d757365722d61737365742d3632313064662e73332e616d617a6f6e6177732e636f6d2f343339333937392f3239353533323731382d38653562363631632d663934362d346365652d386232642d3061363135663737313566342e706e67" height="400">](https://github.com/portapack-mayhem/mayhem-firmware/wiki/PortaPack-Versions#h2m-mayhem-edition)
|
||||
|
||||
# What is this?
|
||||
|
||||
@@ -28,7 +26,7 @@ This repository expands upon the previous work by many people and aims to consta
|
||||
## What to buy?
|
||||
|
||||
<!---not direct to h4m but to opensourcesdrlab https://share.hackrf.app/TUOLYI--->
|
||||
:heavy_check_mark:  The fabulous [PortaPack H4M Mayhem](https://share.hackrf.app/0STXCA), featuring numerous improvements and accessories. Sold by our friends at [OpenSourceSDRLab](https://share.hackrf.app/99SAMT). Join their giveaways on discord (check the badge on top).
|
||||
:heavy_check_mark:  The fabulous H4M [complete](https://share.hackrf.app/TUOLYI) or [upgrade](https://share.hackrf.app/FPLM1H), featuring numerous improvements and accessories. Sold by our friends at [OpenSourceSDRLab](https://share.hackrf.app/99SAMT). Join their giveaways on discord (check the badge on top).
|
||||
|
||||
:heavy_check_mark: A recommended one is this [PortaPack H2](https://www.ebay.com/itm/116382397447), that includes everything you need with the plastic case "inspired" on [this](https://github.com/portapack-mayhem/mayhem-firmware/wiki/3d-printed-enclosure).
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
namespace ui::external_app::audio_test {
|
||||
|
||||
AudioTestView::AudioTestView(NavigationView& nav)
|
||||
: nav_{nav} {
|
||||
@@ -103,4 +103,4 @@ void AudioTestView::update_audio_beep() {
|
||||
baseband::request_beep_stop();
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
} /* namespace ui::external_app::audio_test */
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_receiver.hpp"
|
||||
|
||||
namespace ui {
|
||||
namespace ui::external_app::audio_test {
|
||||
|
||||
class AudioTestView : public View {
|
||||
public:
|
||||
@@ -96,6 +96,6 @@ class AudioTestView : public View {
|
||||
Theme::getInstance()->bg_dark->background};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
} /* namespace ui::external_app::audio_test */
|
||||
|
||||
#endif /*__UI_AUDIO_TEST_H__*/
|
||||
|
||||
+16
-1
@@ -134,6 +134,18 @@ set(EXTCPPSRC
|
||||
#mcu_temperature
|
||||
external/mcu_temperature/main.cpp
|
||||
external/mcu_temperature/mcu_temperature.cpp
|
||||
|
||||
#fmradio
|
||||
external/fmradio/main.cpp
|
||||
external/fmradio/ui_fmradio.cpp
|
||||
|
||||
#tuner
|
||||
external/tuner/main.cpp
|
||||
external/tuner/ui_tuner.cpp
|
||||
|
||||
#metronome
|
||||
external/metronome/main.cpp
|
||||
external/metronome/ui_metronome.cpp
|
||||
)
|
||||
|
||||
set(EXTAPPLIST
|
||||
@@ -167,6 +179,9 @@ set(EXTAPPLIST
|
||||
ook_editor
|
||||
shoppingcart_lock
|
||||
flippertx
|
||||
remote
|
||||
remote
|
||||
mcu_temperature
|
||||
fmradio
|
||||
tuner
|
||||
metronome
|
||||
)
|
||||
|
||||
+21
@@ -55,6 +55,9 @@ MEMORY
|
||||
ram_external_app_ook_editor(rwx) : org = 0xADCE0000, len = 32k
|
||||
ram_external_app_remote(rwx) : org = 0xADCF0000, len = 32k
|
||||
ram_external_app_mcu_temperature(rwx) : org = 0xADD00000, len = 32k
|
||||
ram_external_app_fmradio(rwx) : org = 0xADD10000, len = 32k
|
||||
ram_external_app_tuner(rwx) : org = 0xADD20000, len = 32k
|
||||
ram_external_app_metronome(rwx) : org = 0xADD30000, len = 32k
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
@@ -251,4 +254,22 @@ SECTIONS
|
||||
KEEP(*(.external_app.app_mcu_temperature.application_information));
|
||||
*(*ui*external_app*mcu_temperature*);
|
||||
} > ram_external_app_mcu_temperature
|
||||
|
||||
.external_app_fmradio : ALIGN(4) SUBALIGN(4)
|
||||
{
|
||||
KEEP(*(.external_app.app_fmradio.application_information));
|
||||
*(*ui*external_app*fmradio*);
|
||||
} > ram_external_app_fmradio
|
||||
|
||||
.external_app_tuner : ALIGN(4) SUBALIGN(4)
|
||||
{
|
||||
KEEP(*(.external_app.app_tuner.application_information));
|
||||
*(*ui*external_app*tuner*);
|
||||
} > ram_external_app_tuner
|
||||
|
||||
.external_app_metronome : ALIGN(4) SUBALIGN(4)
|
||||
{
|
||||
KEEP(*(.external_app.app_metronome.application_information));
|
||||
*(*ui*external_app*metronome*);
|
||||
} > ram_external_app_metronome
|
||||
}
|
||||
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2024 HTotoo
|
||||
*
|
||||
* 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_fmradio.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "external_app.hpp"
|
||||
|
||||
namespace ui::external_app::fmradio {
|
||||
void initialize_app(ui::NavigationView& nav) {
|
||||
nav.push<FmRadioView>();
|
||||
}
|
||||
} // namespace ui::external_app::fmradio
|
||||
|
||||
extern "C" {
|
||||
|
||||
__attribute__((section(".external_app.app_fmradio.application_information"), used)) application_information_t _application_information_fmradio = {
|
||||
/*.memory_location = */ (uint8_t*)0x00000000,
|
||||
/*.externalAppEntry = */ ui::external_app::fmradio::initialize_app,
|
||||
/*.header_version = */ CURRENT_HEADER_VERSION,
|
||||
/*.app_version = */ VERSION_MD5,
|
||||
|
||||
/*.app_name = */ "FM Radio",
|
||||
/*.bitmap_data = */ {
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x04,
|
||||
0x20,
|
||||
0x12,
|
||||
0x48,
|
||||
0x8A,
|
||||
0x51,
|
||||
0xCA,
|
||||
0x53,
|
||||
0xCA,
|
||||
0x53,
|
||||
0x8A,
|
||||
0x51,
|
||||
0x12,
|
||||
0x48,
|
||||
0x84,
|
||||
0x21,
|
||||
0xC0,
|
||||
0x03,
|
||||
0x40,
|
||||
0x02,
|
||||
0x60,
|
||||
0x06,
|
||||
0x20,
|
||||
0x04,
|
||||
0x30,
|
||||
0x0C,
|
||||
0xF0,
|
||||
0x0F,
|
||||
},
|
||||
/*.icon_color = */ ui::Color::green().v,
|
||||
/*.menu_location = */ app_location_t::RX,
|
||||
/*.desired_menu_position = */ -1,
|
||||
|
||||
/*.m4_app_tag = portapack::spi_flash::image_tag_wfm_audio */ {'P', 'W', 'F', 'M'},
|
||||
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright (C) 2024 HTotoo
|
||||
*
|
||||
* 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_fmradio.hpp"
|
||||
|
||||
#include "audio.hpp"
|
||||
#include "rtc_time.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
using namespace modems;
|
||||
using namespace ui;
|
||||
|
||||
namespace ui::external_app::fmradio {
|
||||
|
||||
void FmRadioView::focus() {
|
||||
field_frequency.focus();
|
||||
}
|
||||
|
||||
FmRadioView::FmRadioView(NavigationView& nav)
|
||||
: nav_{nav} {
|
||||
baseband::run_image(portapack::spi_flash::image_tag_wfm_audio);
|
||||
|
||||
add_children({&rssi,
|
||||
&field_rf_amp,
|
||||
&field_lna,
|
||||
&field_vga,
|
||||
&field_volume,
|
||||
&field_frequency,
|
||||
&btn_fav_save,
|
||||
&txt_save_help,
|
||||
&btn_fav_0,
|
||||
&btn_fav_1,
|
||||
&btn_fav_2,
|
||||
&btn_fav_3,
|
||||
&btn_fav_4,
|
||||
&btn_fav_5,
|
||||
&btn_fav_6,
|
||||
&btn_fav_7,
|
||||
&btn_fav_8,
|
||||
&btn_fav_9,
|
||||
&audio,
|
||||
&waveform});
|
||||
|
||||
txt_save_help.visible(false);
|
||||
for (uint8_t i = 0; i < 12; ++i) {
|
||||
if (freq_fav_list[i] == 0) {
|
||||
freq_fav_list[i] = 87000000;
|
||||
}
|
||||
}
|
||||
|
||||
if (field_frequency.value() == 0) {
|
||||
field_frequency.set_value(87000000);
|
||||
}
|
||||
|
||||
receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio);
|
||||
|
||||
field_frequency.set_step(25000);
|
||||
receiver_model.enable();
|
||||
audio::output::start();
|
||||
|
||||
btn_fav_0.on_select = [this](Button&) {
|
||||
on_btn_clicked(0);
|
||||
};
|
||||
btn_fav_1.on_select = [this](Button&) {
|
||||
on_btn_clicked(1);
|
||||
};
|
||||
btn_fav_2.on_select = [this](Button&) {
|
||||
on_btn_clicked(2);
|
||||
};
|
||||
btn_fav_3.on_select = [this](Button&) {
|
||||
on_btn_clicked(3);
|
||||
};
|
||||
btn_fav_4.on_select = [this](Button&) {
|
||||
on_btn_clicked(4);
|
||||
};
|
||||
btn_fav_5.on_select = [this](Button&) {
|
||||
on_btn_clicked(5);
|
||||
};
|
||||
btn_fav_6.on_select = [this](Button&) {
|
||||
on_btn_clicked(6);
|
||||
};
|
||||
btn_fav_7.on_select = [this](Button&) {
|
||||
on_btn_clicked(7);
|
||||
};
|
||||
btn_fav_8.on_select = [this](Button&) {
|
||||
on_btn_clicked(8);
|
||||
};
|
||||
btn_fav_9.on_select = [this](Button&) {
|
||||
on_btn_clicked(9);
|
||||
};
|
||||
|
||||
btn_fav_save.on_select = [this](Button&) {
|
||||
save_fav = !save_fav;
|
||||
txt_save_help.set_text(save_fav ? "Select slot" : "");
|
||||
txt_save_help.visible(save_fav);
|
||||
txt_save_help.set_dirty();
|
||||
};
|
||||
|
||||
update_fav_btn_texts();
|
||||
}
|
||||
|
||||
void FmRadioView::on_btn_clicked(uint8_t i) {
|
||||
if (save_fav) {
|
||||
save_fav = false;
|
||||
freq_fav_list[i] = field_frequency.value();
|
||||
update_fav_btn_texts();
|
||||
txt_save_help.visible(save_fav);
|
||||
txt_save_help.set_text("");
|
||||
txt_save_help.set_dirty();
|
||||
return;
|
||||
}
|
||||
field_frequency.set_value(freq_fav_list[i]);
|
||||
}
|
||||
|
||||
std::string FmRadioView::to_nice_freq(rf::Frequency freq) {
|
||||
std::string nice = to_string_dec_uint(freq / 1000000);
|
||||
nice += ".";
|
||||
nice += to_string_dec_uint((freq / 10000) % 100);
|
||||
return nice;
|
||||
}
|
||||
|
||||
void FmRadioView::update_fav_btn_texts() {
|
||||
btn_fav_0.set_text(to_nice_freq(freq_fav_list[0]));
|
||||
btn_fav_1.set_text(to_nice_freq(freq_fav_list[1]));
|
||||
btn_fav_2.set_text(to_nice_freq(freq_fav_list[2]));
|
||||
btn_fav_3.set_text(to_nice_freq(freq_fav_list[3]));
|
||||
btn_fav_4.set_text(to_nice_freq(freq_fav_list[4]));
|
||||
btn_fav_5.set_text(to_nice_freq(freq_fav_list[5]));
|
||||
btn_fav_6.set_text(to_nice_freq(freq_fav_list[6]));
|
||||
btn_fav_7.set_text(to_nice_freq(freq_fav_list[7]));
|
||||
btn_fav_8.set_text(to_nice_freq(freq_fav_list[8]));
|
||||
btn_fav_9.set_text(to_nice_freq(freq_fav_list[9]));
|
||||
}
|
||||
|
||||
FmRadioView::~FmRadioView() {
|
||||
receiver_model.disable();
|
||||
baseband::shutdown();
|
||||
audio::output::stop();
|
||||
}
|
||||
|
||||
void FmRadioView::on_audio_spectrum() {
|
||||
for (size_t i = 0; i < audio_spectrum_data->db.size(); i++)
|
||||
audio_spectrum[i] = ((int16_t)audio_spectrum_data->db[i] - 127) * 256;
|
||||
waveform.set_dirty();
|
||||
}
|
||||
|
||||
} // namespace ui::external_app::fmradio
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (C) 2024 HTotoo
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
FUTURE TODO: implement search function.
|
||||
*/
|
||||
|
||||
#ifndef __UI_fmradio_H__
|
||||
#define __UI_fmradio_H__
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_language.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_receiver.hpp"
|
||||
#include "ui_geomap.hpp"
|
||||
#include "ui_freq_field.hpp"
|
||||
#include "ui_spectrum.hpp"
|
||||
#include "ui_record_view.hpp"
|
||||
#include "app_settings.hpp"
|
||||
#include "radio_state.hpp"
|
||||
#include "log_file.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
using namespace ui;
|
||||
|
||||
namespace ui::external_app::fmradio {
|
||||
|
||||
#define FMR_BTNGRID_TOP 60
|
||||
|
||||
class FmRadioView : public View {
|
||||
public:
|
||||
FmRadioView(NavigationView& nav);
|
||||
FmRadioView& operator=(const FmRadioView&) = delete;
|
||||
FmRadioView(const FmRadioView&) = delete;
|
||||
~FmRadioView();
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "FM radio"; };
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
RxRadioState radio_state_{};
|
||||
int16_t audio_spectrum[128]{0};
|
||||
bool audio_spectrum_update = false;
|
||||
AudioSpectrum* audio_spectrum_data{nullptr};
|
||||
rf::Frequency freq_fav_list[12] = {0};
|
||||
|
||||
app_settings::SettingsManager settings_{
|
||||
"rx_fmradio",
|
||||
app_settings::Mode::RX,
|
||||
{{"favlist0"sv, &freq_fav_list[0]},
|
||||
{"favlist1"sv, &freq_fav_list[1]},
|
||||
{"favlist2"sv, &freq_fav_list[2]},
|
||||
{"favlist3"sv, &freq_fav_list[3]},
|
||||
{"favlist4"sv, &freq_fav_list[4]},
|
||||
{"favlist5"sv, &freq_fav_list[5]},
|
||||
{"favlist6"sv, &freq_fav_list[6]},
|
||||
{"favlist7"sv, &freq_fav_list[7]},
|
||||
{"favlist8"sv, &freq_fav_list[8]},
|
||||
{"favlist9"sv, &freq_fav_list[9]},
|
||||
{"favlist10"sv, &freq_fav_list[10]},
|
||||
{"favlist11"sv, &freq_fav_list[11]}}};
|
||||
|
||||
RFAmpField field_rf_amp{
|
||||
{13 * 8, 0 * 16}};
|
||||
LNAGainField field_lna{
|
||||
{15 * 8, 0 * 16}};
|
||||
VGAGainField field_vga{
|
||||
{18 * 8, 0 * 16}};
|
||||
RSSI rssi{
|
||||
{21 * 8, 0, 6 * 8, 4}};
|
||||
AudioVolumeField field_volume{
|
||||
{28 * 8, 0 * 16}};
|
||||
|
||||
RxFrequencyField field_frequency{
|
||||
{0 * 8, 0 * 16},
|
||||
nav_};
|
||||
|
||||
TextField txt_save_help{
|
||||
{2, FMR_BTNGRID_TOP + 6 * 34 - 20, 12 * 8, 16},
|
||||
" "};
|
||||
|
||||
Audio audio{
|
||||
{21 * 8, 10, 6 * 8, 4}};
|
||||
|
||||
Waveform waveform{
|
||||
{0, 20, 30 * 8, 2 * 16},
|
||||
audio_spectrum,
|
||||
128,
|
||||
0,
|
||||
false,
|
||||
Theme::getInstance()->bg_darkest->foreground};
|
||||
|
||||
Button btn_fav_0{{2, FMR_BTNGRID_TOP + 0 * 34, 10 * 8, 28}, "---"};
|
||||
Button btn_fav_1{{2 + 15 * 8, FMR_BTNGRID_TOP + 0 * 34, 10 * 8, 28}, "---"};
|
||||
Button btn_fav_2{{2, FMR_BTNGRID_TOP + 1 * 34, 10 * 8, 28}, "---"};
|
||||
Button btn_fav_3{{2 + 15 * 8, FMR_BTNGRID_TOP + 1 * 34, 10 * 8, 28}, "---"};
|
||||
Button btn_fav_4{{2, FMR_BTNGRID_TOP + 2 * 34, 10 * 8, 28}, "---"};
|
||||
Button btn_fav_5{{2 + 15 * 8, FMR_BTNGRID_TOP + 2 * 34, 10 * 8, 28}, "---"};
|
||||
Button btn_fav_6{{2, FMR_BTNGRID_TOP + 3 * 34, 10 * 8, 28}, "---"};
|
||||
Button btn_fav_7{{2 + 15 * 8, FMR_BTNGRID_TOP + 3 * 34, 10 * 8, 28}, "---"};
|
||||
Button btn_fav_8{{2, FMR_BTNGRID_TOP + 4 * 34, 10 * 8, 28}, "---"};
|
||||
Button btn_fav_9{{2 + 15 * 8, FMR_BTNGRID_TOP + 4 * 34, 10 * 8, 28}, "---"};
|
||||
|
||||
Button btn_fav_save{{2, FMR_BTNGRID_TOP + 6 * 34, 7 * 8, 1 * 28}, "Save"};
|
||||
bool save_fav = false;
|
||||
void on_btn_clicked(uint8_t i);
|
||||
void update_fav_btn_texts();
|
||||
std::string to_nice_freq(rf::Frequency freq);
|
||||
void on_audio_spectrum();
|
||||
|
||||
MessageHandlerRegistration message_handler_audio_spectrum{
|
||||
Message::ID::AudioSpectrum,
|
||||
[this](const Message* const p) {
|
||||
const auto message = *reinterpret_cast<const AudioSpectrumMessage*>(p);
|
||||
audio_spectrum_data = message.data;
|
||||
audio_spectrum_update = true;
|
||||
}};
|
||||
MessageHandlerRegistration message_handler_frame_sync{
|
||||
Message::ID::DisplayFrameSync,
|
||||
[this](const Message* const) {
|
||||
if (audio_spectrum_update) {
|
||||
audio_spectrum_update = false;
|
||||
on_audio_spectrum();
|
||||
}
|
||||
}};
|
||||
};
|
||||
|
||||
} // namespace ui::external_app::fmradio
|
||||
|
||||
#endif /*__UI_fmradio_H__*/
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Bernd
|
||||
*
|
||||
* 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_metronome.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "external_app.hpp"
|
||||
|
||||
namespace ui::external_app::metronome {
|
||||
void initialize_app(ui::NavigationView& nav) {
|
||||
nav.push<MetronomeView>();
|
||||
}
|
||||
} // namespace ui::external_app::metronome
|
||||
|
||||
extern "C" {
|
||||
|
||||
__attribute__((section(".external_app.app_metronome.application_information"), used)) application_information_t _application_information_metronome = {
|
||||
/*.memory_location = */ (uint8_t*)0x00000000,
|
||||
/*.externalAppEntry = */ ui::external_app::metronome::initialize_app,
|
||||
/*.header_version = */ CURRENT_HEADER_VERSION,
|
||||
/*.app_version = */ VERSION_MD5,
|
||||
|
||||
/*.app_name = */ "Metronome",
|
||||
/*.bitmap_data = */ {
|
||||
0x00,
|
||||
0x00,
|
||||
0xC0,
|
||||
0x43,
|
||||
0x20,
|
||||
0x66,
|
||||
0xA0,
|
||||
0x34,
|
||||
0x20,
|
||||
0x18,
|
||||
0xB0,
|
||||
0x0C,
|
||||
0x10,
|
||||
0x04,
|
||||
0x10,
|
||||
0x06,
|
||||
0x10,
|
||||
0x0B,
|
||||
0x98,
|
||||
0x19,
|
||||
0x08,
|
||||
0x10,
|
||||
0xF8,
|
||||
0x1F,
|
||||
0xF8,
|
||||
0x1F,
|
||||
0xF8,
|
||||
0x1F,
|
||||
0xF0,
|
||||
0x0F,
|
||||
0x00,
|
||||
0x00,
|
||||
|
||||
},
|
||||
/*.icon_color = */ ui::Color::cyan().v,
|
||||
/*.menu_location = */ app_location_t::UTILITIES,
|
||||
/*.desired_menu_position = */ -1,
|
||||
|
||||
/*.m4_app_tag = portapack::spi_flash::image_tag_none */ {'P', 'A', 'B', 'P'},
|
||||
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* copyleft 2024 sommermorgentraum
|
||||
*
|
||||
* 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_metronome.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
#include "audio.hpp"
|
||||
#include "portapack.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui::external_app::metronome {
|
||||
|
||||
MetronomeView::MetronomeView(NavigationView& nav)
|
||||
: nav_{nav} {
|
||||
baseband::run_prepared_image(portapack::memory::map::m4_code.base()); // proc_audio_beep baseband is external too
|
||||
|
||||
add_children({
|
||||
&labels,
|
||||
&field_volume,
|
||||
&button_play_stop,
|
||||
&field_rythm_unaccent_time,
|
||||
&field_rythm_accent_time,
|
||||
&field_accent_beep_tune,
|
||||
&field_unaccent_beep_tune,
|
||||
&field_beep_flash_duration,
|
||||
&field_bpm,
|
||||
&progressbar,
|
||||
});
|
||||
|
||||
field_bpm.set_value(120);
|
||||
field_rythm_accent_time.set_value(4);
|
||||
field_rythm_unaccent_time.set_value(4);
|
||||
field_accent_beep_tune.set_value(880);
|
||||
field_unaccent_beep_tune.set_value(440);
|
||||
field_beep_flash_duration.set_value(100);
|
||||
button_play_stop.on_select = [this]() {
|
||||
if (playing_) {
|
||||
stop_play();
|
||||
} else {
|
||||
play();
|
||||
}
|
||||
};
|
||||
|
||||
field_volume.set_value(0); // seems that a change is required to force update, so setting to 0 first
|
||||
field_volume.set_value(99);
|
||||
|
||||
audio::set_rate(audio::Rate::Hz_48000);
|
||||
|
||||
audio::output::start();
|
||||
}
|
||||
|
||||
MetronomeView::~MetronomeView() {
|
||||
should_exit = true;
|
||||
if (thread) {
|
||||
chThdWait(thread);
|
||||
thread = nullptr;
|
||||
}
|
||||
receiver_model.disable();
|
||||
baseband::shutdown();
|
||||
audio::output::stop();
|
||||
}
|
||||
|
||||
void MetronomeView::focus() {
|
||||
field_bpm.focus();
|
||||
}
|
||||
|
||||
void MetronomeView::stop_play() {
|
||||
if (playing_) {
|
||||
playing_ = false;
|
||||
button_play_stop.set_bitmap(&bitmap_icon_replay);
|
||||
baseband::request_beep_stop();
|
||||
progressbar.set_value(0);
|
||||
progressbar.set_style(Theme::getInstance()->fg_light);
|
||||
}
|
||||
}
|
||||
|
||||
void MetronomeView::play() {
|
||||
if (!playing_) {
|
||||
playing_ = true;
|
||||
current_beat_ = 0;
|
||||
button_play_stop.set_bitmap(&bitmap_icon_sleep);
|
||||
|
||||
if (!thread) {
|
||||
thread = chThdCreateFromHeap(NULL, 1024, NORMALPRIO + 10, MetronomeView::static_fn, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MetronomeView::beep_accent_beat() {
|
||||
baseband::request_audio_beep(field_accent_beep_tune.value(), 48000, field_beep_flash_duration.value());
|
||||
}
|
||||
|
||||
void MetronomeView::beep_unaccent_beat() {
|
||||
baseband::request_audio_beep(field_unaccent_beep_tune.value(), 48000, field_beep_flash_duration.value());
|
||||
}
|
||||
|
||||
// TODO: draw the beat
|
||||
// void MetronomeView::paint(Painter& painter) {
|
||||
// View::paint(painter);
|
||||
|
||||
// painter.fill_rectangle(
|
||||
// {visual_x, visual_y, visual_width, visual_height},
|
||||
// Theme::getInstance()->bg_darkest->background);
|
||||
|
||||
// if (playing_) {
|
||||
// const bool is_accent_beat = (current_beat_ % field_rythm_accent_time.value()) == 0;
|
||||
|
||||
// const Color beat_color = is_accent_beat ?
|
||||
// Theme::getInstance()->fg_red->foreground :
|
||||
// Theme::getInstance()->fg_green->foreground;
|
||||
|
||||
// painter.fill_rectangle(
|
||||
// {visual_x + visual_width/4,
|
||||
// visual_y + visual_height/4,
|
||||
// visual_width/2,
|
||||
// visual_height/2},
|
||||
// beat_color);
|
||||
// }
|
||||
// }
|
||||
|
||||
msg_t MetronomeView::static_fn(void* arg) {
|
||||
auto obj = static_cast<MetronomeView*>(arg);
|
||||
obj->run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MetronomeView::run() {
|
||||
while (!should_exit) {
|
||||
if (!playing_) {
|
||||
chThdSleepMilliseconds(100);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t base_interval = (60 * 1000) / field_bpm.value(); // quarter note as 1 beat
|
||||
|
||||
uint32_t beats_per_measure = field_rythm_unaccent_time.value(); // how many beates per bar
|
||||
progressbar.set_max(beats_per_measure);
|
||||
uint32_t beat_unit = field_rythm_accent_time.value(); // which note type (quarter, eighth, etc.) as 1 beat
|
||||
|
||||
uint32_t actual_interval = (base_interval * 4) / beat_unit; // e.g. when beat_unit==8 it's 1/2 of base_interval AKA eighths notes
|
||||
|
||||
uint32_t beat_in_measure = current_beat_ % beats_per_measure; // current beat in this bar (need to decide accent or unaccent)
|
||||
progressbar.set_value(beat_in_measure + 1);
|
||||
|
||||
// accent beat is the first beat of this bar
|
||||
if (beat_in_measure == 0) {
|
||||
beep_accent_beat();
|
||||
progressbar.set_style(Theme::getInstance()->fg_red);
|
||||
} else {
|
||||
beep_unaccent_beat();
|
||||
progressbar.set_style(Theme::getInstance()->fg_green);
|
||||
}
|
||||
|
||||
current_beat_++;
|
||||
chThdSleepMilliseconds(actual_interval);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ui::external_app::metronome
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* copyleft 2024 sommermorgentraum
|
||||
*
|
||||
* 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_METRONOME_H__
|
||||
#define __UI_METRONOME_H__
|
||||
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_receiver.hpp"
|
||||
#include "audio.hpp"
|
||||
#include "ch.h"
|
||||
|
||||
namespace ui::external_app::metronome {
|
||||
|
||||
class MetronomeView : public View {
|
||||
public:
|
||||
MetronomeView(NavigationView& nav);
|
||||
~MetronomeView();
|
||||
MetronomeView(const MetronomeView& other) = delete;
|
||||
MetronomeView& operator=(const MetronomeView& other) = delete;
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "Metronome"; };
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
|
||||
void beep_accent_beat(); // e.g. 3 of 3/4 beat
|
||||
void beep_unaccent_beat(); // e.g. 4 of 3/4 beat
|
||||
void stop_play();
|
||||
void play();
|
||||
// void paint(Painter& painter) override;
|
||||
|
||||
Thread* thread{nullptr};
|
||||
bool should_exit{false};
|
||||
static msg_t static_fn(void* arg);
|
||||
void run();
|
||||
|
||||
bool playing_{false};
|
||||
uint32_t current_beat_{0};
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 1 * 16}, "BPM:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 2 * 16}, "Accent Beep Tune:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 3 * 16}, "Unaccent Beep Tune:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 4 * 16}, "Rhythm:", Theme::getInstance()->fg_light->foreground},
|
||||
{{(sizeof("Rhythm:") + 1) * 8 + 4 * 8, 4 * 16}, "/", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 5 * 16}, "Beep Flash Duration:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 6 * 16}, "Volume:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
NumberField field_bpm{
|
||||
{(sizeof("BPM:") + 1) * 8, 1 * 16},
|
||||
4,
|
||||
{1, 1000},
|
||||
1,
|
||||
' '};
|
||||
|
||||
NumberField field_rythm_unaccent_time{// e.g. 3 in 3/4 beat
|
||||
{(sizeof("Rhythm:") + 1) * 8, 4 * 16},
|
||||
2,
|
||||
{1, 99},
|
||||
1,
|
||||
' '};
|
||||
|
||||
NumberField field_rythm_accent_time{// e.g. 4 in 3/4 beat
|
||||
{(sizeof("Rhythm:") + 1) * 8 + 5 * 8, 4 * 16},
|
||||
2,
|
||||
{1, 99},
|
||||
1,
|
||||
' '};
|
||||
|
||||
NumberField field_beep_flash_duration{
|
||||
{(sizeof("Beep Flash Duration:") + 1) * 8, 5 * 16},
|
||||
3,
|
||||
{10, 999},
|
||||
1,
|
||||
' '};
|
||||
|
||||
NumberField field_accent_beep_tune{
|
||||
{(sizeof("Accent Beep Tune:") + 1) * 8, 2 * 16},
|
||||
5,
|
||||
{380, 24000},
|
||||
20,
|
||||
' '};
|
||||
|
||||
NumberField field_unaccent_beep_tune{
|
||||
{(sizeof("Unaccent Beep Tune:") + 1) * 8, 3 * 16},
|
||||
5,
|
||||
{380, 24000},
|
||||
20,
|
||||
' '};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{(sizeof("Volume:") + 1) * 8, 6 * 16}};
|
||||
|
||||
NewButton button_play_stop{
|
||||
{0 * 16, 16 * 16, screen_width, screen_height - 16 * 16},
|
||||
{},
|
||||
&bitmap_icon_replay,
|
||||
Theme::getInstance()->fg_red->foreground};
|
||||
|
||||
ProgressBar progressbar{
|
||||
{0 * 16, 8 * 16, screen_width, screen_height - 14 * 16}};
|
||||
};
|
||||
|
||||
} // namespace ui::external_app::metronome
|
||||
|
||||
#endif /*__UI_METRONOME_H__*/
|
||||
+2
-3
@@ -232,9 +232,8 @@ MorseView::MorseView(
|
||||
set_foxhunt(foxhunt_code);
|
||||
};
|
||||
|
||||
options_modulation.on_change = [this](size_t i, int32_t value) {
|
||||
(void)i; // avoid unused warning
|
||||
mode_cw = (bool)value;
|
||||
options_modulation.on_change = [this](size_t, OptionsField::value_t v) {
|
||||
mode_cw = (bool)v;
|
||||
};
|
||||
|
||||
options_loop.on_change = [this](size_t i, uint32_t value) {
|
||||
|
||||
+7
-2
@@ -41,6 +41,11 @@ using namespace morse;
|
||||
|
||||
namespace ui::external_app::morse_tx {
|
||||
|
||||
enum Modulation {
|
||||
FM = 0,
|
||||
CW = 1
|
||||
};
|
||||
|
||||
class MorseView : public View {
|
||||
public:
|
||||
MorseView(NavigationView& nav);
|
||||
@@ -137,8 +142,8 @@ class MorseView : public View {
|
||||
OptionsField options_modulation{
|
||||
{15 * 8, 10 * 8},
|
||||
2,
|
||||
{{"CW", true},
|
||||
{"FM", false}}};
|
||||
{{"CW", Modulation::CW},
|
||||
{"FM", Modulation::FM}}};
|
||||
|
||||
OptionsField options_loop{
|
||||
{9 * 8, 12 * 8},
|
||||
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Bernd
|
||||
*
|
||||
* 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_tuner.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "external_app.hpp"
|
||||
|
||||
namespace ui::external_app::tuner {
|
||||
void initialize_app(ui::NavigationView& nav) {
|
||||
nav.push<TunerView>();
|
||||
}
|
||||
} // namespace ui::external_app::tuner
|
||||
|
||||
extern "C" {
|
||||
|
||||
__attribute__((section(".external_app.app_tuner.application_information"), used)) application_information_t _application_information_tuner = {
|
||||
/*.memory_location = */ (uint8_t*)0x00000000,
|
||||
/*.externalAppEntry = */ ui::external_app::tuner::initialize_app,
|
||||
/*.header_version = */ CURRENT_HEADER_VERSION,
|
||||
/*.app_version = */ VERSION_MD5,
|
||||
|
||||
/*.app_name = */ "Tuner",
|
||||
/*.bitmap_data = */ {
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x22,
|
||||
0x44,
|
||||
0x21,
|
||||
0x84,
|
||||
0x2D,
|
||||
0xB4,
|
||||
0x25,
|
||||
0xA4,
|
||||
0x25,
|
||||
0xA4,
|
||||
0x2D,
|
||||
0xB4,
|
||||
0x61,
|
||||
0x86,
|
||||
0xC2,
|
||||
0x43,
|
||||
0x80,
|
||||
0x01,
|
||||
0x80,
|
||||
0x01,
|
||||
0x80,
|
||||
0x01,
|
||||
0x80,
|
||||
0x01,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
},
|
||||
/*.icon_color = */ ui::Color::cyan().v,
|
||||
/*.menu_location = */ app_location_t::UTILITIES,
|
||||
/*.desired_menu_position = */ -1,
|
||||
|
||||
/*.m4_app_tag = portapack::spi_flash::image_tag_none */ {'P', 'A', 'B', 'P'},
|
||||
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
|
||||
};
|
||||
}
|
||||
+256
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* copyleft 2024 sommermorgentraum
|
||||
*
|
||||
* 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_tuner.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
#include "audio.hpp"
|
||||
#include "portapack.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui::external_app::tuner {
|
||||
|
||||
TunerView::TunerView(NavigationView& nav)
|
||||
: nav_{nav} {
|
||||
baseband::run_prepared_image(portapack::memory::map::m4_code.base()); // proc_audio_beep baseband is external too
|
||||
|
||||
add_children({
|
||||
&labels,
|
||||
&field_volume,
|
||||
&options_instrument,
|
||||
&options_note,
|
||||
&button_play_stop,
|
||||
&text_note_frequency,
|
||||
&text_note_octave_shift,
|
||||
});
|
||||
|
||||
audio::set_rate(audio::Rate::Hz_24000);
|
||||
|
||||
options_instrument.on_change = [this](size_t, int32_t value) {
|
||||
const Instrument* selected_instrument = nullptr;
|
||||
|
||||
switch (value) {
|
||||
case 0:
|
||||
selected_instrument = &guitar;
|
||||
break;
|
||||
case 1:
|
||||
selected_instrument = &violin;
|
||||
break;
|
||||
case 2:
|
||||
selected_instrument = &pitch_fork;
|
||||
break;
|
||||
}
|
||||
|
||||
if (selected_instrument) {
|
||||
update_notes_for_instrument(*selected_instrument);
|
||||
}
|
||||
|
||||
update_current_note();
|
||||
};
|
||||
|
||||
options_note.on_change = [this](size_t, int32_t index) {
|
||||
const Instrument* current_instrument = nullptr;
|
||||
switch (options_instrument.selected_index_value()) {
|
||||
case 0:
|
||||
current_instrument = &guitar;
|
||||
break;
|
||||
case 1:
|
||||
current_instrument = &violin;
|
||||
break;
|
||||
case 2:
|
||||
current_instrument = &pitch_fork;
|
||||
break;
|
||||
}
|
||||
|
||||
if (current_instrument) {
|
||||
auto it = current_instrument->notes.begin();
|
||||
std::advance(it, index);
|
||||
if (it != current_instrument->notes.end()) {
|
||||
current_note_frequency = it->second.frequency;
|
||||
current_note_sample_rate = it->second.sample_rate;
|
||||
current_note_octave_shift = it->second.octave_shift;
|
||||
}
|
||||
}
|
||||
|
||||
update_current_note();
|
||||
};
|
||||
|
||||
button_play_stop.on_select = [this]() {
|
||||
if (current_note_playing) {
|
||||
stop_play();
|
||||
} else {
|
||||
play_change_note();
|
||||
}
|
||||
};
|
||||
|
||||
options_instrument.set_selected_index(0);
|
||||
update_notes_for_instrument(guitar);
|
||||
update_current_note();
|
||||
|
||||
field_volume.set_value(0); // seems that a change is required to force update, so setting to 0 first
|
||||
field_volume.set_value(99);
|
||||
|
||||
audio::set_rate(audio::Rate::Hz_24000);
|
||||
audio::output::start();
|
||||
}
|
||||
|
||||
TunerView::~TunerView() {
|
||||
receiver_model.disable();
|
||||
baseband::shutdown();
|
||||
audio::output::stop();
|
||||
}
|
||||
|
||||
void TunerView::focus() {
|
||||
options_instrument.focus();
|
||||
}
|
||||
|
||||
void TunerView::update_notes_for_instrument(const Instrument& instrument) {
|
||||
std::vector<OptionsField::option_t> note_options;
|
||||
size_t index = 0;
|
||||
|
||||
for (const auto& note_pair : instrument.notes) {
|
||||
note_options.emplace_back(OptionsField::option_t{
|
||||
note_pair.first,
|
||||
index++});
|
||||
}
|
||||
|
||||
options_note.set_options(note_options);
|
||||
if (!note_options.empty()) {
|
||||
options_note.set_selected_index(0);
|
||||
}
|
||||
}
|
||||
|
||||
void TunerView::update_current_note() {
|
||||
const Instrument* current_instrument = nullptr;
|
||||
|
||||
switch (options_instrument.selected_index_value()) {
|
||||
case 0:
|
||||
current_instrument = &guitar;
|
||||
break;
|
||||
case 1:
|
||||
current_instrument = &violin;
|
||||
break;
|
||||
case 2:
|
||||
current_instrument = &pitch_fork;
|
||||
break;
|
||||
}
|
||||
|
||||
if (current_instrument) {
|
||||
std::string note_name = options_note.selected_index_name();
|
||||
|
||||
// map
|
||||
auto note_it = current_instrument->notes.find(note_name);
|
||||
if (note_it != current_instrument->notes.end()) {
|
||||
current_note_frequency = note_it->second.frequency;
|
||||
current_note_sample_rate = note_it->second.sample_rate;
|
||||
current_note_octave_shift = note_it->second.octave_shift;
|
||||
|
||||
text_note_frequency.set(std::to_string(current_note_frequency));
|
||||
text_note_octave_shift.set(std::to_string(current_note_octave_shift));
|
||||
|
||||
set_dirty();
|
||||
|
||||
if (current_note_playing) {
|
||||
play_change_note();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TunerView::stop_play() {
|
||||
baseband::request_beep_stop();
|
||||
current_note_playing = false;
|
||||
button_play_stop.set_bitmap(&bitmap_icon_replay);
|
||||
}
|
||||
|
||||
void TunerView::play_change_note() {
|
||||
if (current_note_playing) {
|
||||
baseband::request_beep_stop();
|
||||
audio::set_rate(current_note_sample_rate);
|
||||
baseband::request_audio_beep(current_note_frequency, protected_sample_rate(current_note_sample_rate), 0);
|
||||
} else {
|
||||
audio::set_rate(current_note_sample_rate);
|
||||
baseband::request_audio_beep(current_note_frequency, protected_sample_rate(current_note_sample_rate), 0);
|
||||
}
|
||||
current_note_playing = true;
|
||||
button_play_stop.set_bitmap(&bitmap_icon_sleep);
|
||||
set_dirty();
|
||||
}
|
||||
|
||||
uint32_t TunerView::protected_sample_rate(audio::Rate r) {
|
||||
switch (r) {
|
||||
case audio::Rate::Hz_12000:
|
||||
return 12000;
|
||||
case audio::Rate::Hz_24000:
|
||||
return 24000;
|
||||
case audio::Rate::Hz_48000:
|
||||
return 48000;
|
||||
default:
|
||||
return 24000;
|
||||
}
|
||||
}
|
||||
|
||||
void TunerView::paint(Painter& painter) {
|
||||
View::paint(painter);
|
||||
|
||||
painter.fill_rectangle(
|
||||
{screen_width / 4, 8 * 16, screen_width / 2, 6 * 16},
|
||||
Theme::getInstance()->bg_darkest->background);
|
||||
|
||||
if (!current_note_playing) return;
|
||||
|
||||
painter.fill_rectangle(
|
||||
{screen_width / 4, 10 * 16, 2, 2 * 16},
|
||||
Theme::getInstance()->fg_light->foreground);
|
||||
|
||||
painter.fill_rectangle(
|
||||
{screen_width / 4, 12 * 16, screen_width / 4 * 2 + 2, 2},
|
||||
Theme::getInstance()->fg_light->foreground);
|
||||
|
||||
painter.fill_rectangle(
|
||||
{(screen_width / 4) * 3, 10 * 16, 2, 2 * 16},
|
||||
Theme::getInstance()->fg_light->foreground);
|
||||
|
||||
painter.draw_string(
|
||||
{screen_width / 4 - 2 * 8, 8 * 16},
|
||||
(current_note_octave_shift == 0) ? *Theme::getInstance()->bg_darkest : *Theme::getInstance()->fg_red,
|
||||
std::to_string(current_note_frequency));
|
||||
|
||||
int16_t real_frequency = current_note_frequency;
|
||||
if (current_note_octave_shift > 0) {
|
||||
for (int i = 0; i < current_note_octave_shift; i++) {
|
||||
real_frequency *= 2;
|
||||
}
|
||||
} else if (current_note_octave_shift < 0) {
|
||||
for (int i = 0; i > current_note_octave_shift; i--) {
|
||||
real_frequency /= 2;
|
||||
}
|
||||
}
|
||||
painter.draw_string({(screen_width / 4) * 3 - 2 * 8, 8 * 16},
|
||||
(current_note_octave_shift == 0) ? *Theme::getInstance()->bg_darkest : *Theme::getInstance()->fg_red,
|
||||
std::to_string(real_frequency));
|
||||
|
||||
painter.draw_string({screen_width / 2 - 3 * 16, 13 * 16},
|
||||
(current_note_octave_shift == 0) ? *Theme::getInstance()->bg_darkest : *Theme::getInstance()->fg_red,
|
||||
std::to_string(current_note_octave_shift) + " * 8ev");
|
||||
}
|
||||
|
||||
} // namespace ui::external_app::tuner
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* copyleft 2024 sommermorgentraum
|
||||
*
|
||||
* 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_TUNER_H__
|
||||
#define __UI_TUNER_H__
|
||||
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_receiver.hpp"
|
||||
#include "audio.hpp"
|
||||
|
||||
namespace ui::external_app::tuner {
|
||||
|
||||
struct Instrument {
|
||||
std::string name;
|
||||
struct NoteInfo {
|
||||
uint16_t frequency;
|
||||
audio::Rate sample_rate; // tune samplerate to allow for freqs
|
||||
int8_t octave_shift;
|
||||
// PP hardware can't handle some extremely low/high frequencies, this indicates how much the freq that were played is shifted up/down,
|
||||
// for example, if shift is -2 and note is A3, it means the real string should play A5 but PP's speaker plays A3
|
||||
};
|
||||
std::map<std::string, NoteInfo> notes; // this is for fast looking : O(log(n)) , usage `auto note = guitar.notes["A4"];`
|
||||
};
|
||||
|
||||
class TunerView : public View {
|
||||
public:
|
||||
TunerView(NavigationView& nav);
|
||||
~TunerView();
|
||||
TunerView(const TunerView& other) = delete;
|
||||
TunerView& operator=(const TunerView& other) = delete;
|
||||
|
||||
void focus() override;
|
||||
void update_audio_beep();
|
||||
|
||||
std::string title() const override { return "Tuner"; };
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
bool beep{false};
|
||||
|
||||
void update_notes_for_instrument(const Instrument& instrument);
|
||||
void play_change_note();
|
||||
void stop_play();
|
||||
void update_current_note();
|
||||
uint32_t protected_sample_rate(audio::Rate r);
|
||||
void paint(Painter& painter) override;
|
||||
|
||||
uint16_t current_note_frequency{440};
|
||||
audio::Rate current_note_sample_rate{audio::Rate::Hz_12000};
|
||||
int8_t current_note_octave_shift{0};
|
||||
bool current_note_playing{false};
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 1 * 16}, "Instrument:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 2 * 16}, "Note:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 3 * 16}, "Note Frequency:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 4 * 16}, "Note Octave Shift:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 5 * 16}, "Volume:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
Text text_note_frequency{
|
||||
{(sizeof("Note Frequency:") + 1) * 8, 3 * 16, screen_width - (sizeof("Note Frequency:") + 1) * 8, 16},
|
||||
"",
|
||||
};
|
||||
|
||||
Text text_note_octave_shift{
|
||||
{(sizeof("Note Octave Shift:") + 1) * 8, 4 * 16, screen_width - (sizeof("Note Octave Shift:") + 1) * 8, 16},
|
||||
"",
|
||||
};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{(sizeof("Volume:") + 1) * 8, 5 * 16}};
|
||||
|
||||
// TODO: load list runtime
|
||||
OptionsField options_instrument{
|
||||
{(sizeof("Instrument:") + 1) * 8, 1 * 16},
|
||||
screen_width - (sizeof("Instrument:") + 1) * 8,
|
||||
{{"Guitar", 0},
|
||||
{"Violin", 1},
|
||||
{"Pitch Fork", 2}}};
|
||||
|
||||
OptionsField options_note{
|
||||
{(sizeof("Note:") + 1) * 8, 2 * 16},
|
||||
screen_width - (sizeof("Note:") + 1) * 8,
|
||||
{}};
|
||||
|
||||
NewButton button_play_stop{
|
||||
{0 * 8, 16 * 16, screen_width, screen_height - 16 * 16},
|
||||
{},
|
||||
&bitmap_icon_replay,
|
||||
Theme::getInstance()->fg_red->foreground};
|
||||
|
||||
// TODO: load from file DB
|
||||
const Instrument guitar = {
|
||||
.name = "Folk Guitar",
|
||||
.notes = {
|
||||
{"E2", {165, audio::Rate::Hz_12000, -1}}, // actual: E2, PP speaker: E3
|
||||
{"A2", {110, audio::Rate::Hz_12000, 0}},
|
||||
{"D3", {147, audio::Rate::Hz_12000, 0}},
|
||||
{"G3", {196, audio::Rate::Hz_24000, 0}},
|
||||
{"B3", {247, audio::Rate::Hz_24000, 0}},
|
||||
{"E4", {330, audio::Rate::Hz_24000, 0}}}};
|
||||
|
||||
const Instrument violin = {
|
||||
.name = "Violin 440 Standard, 12ET",
|
||||
.notes = {
|
||||
{"G3", {196, audio::Rate::Hz_12000, 0}},
|
||||
{"D4", {294, audio::Rate::Hz_24000, 0}},
|
||||
{"A4", {440, audio::Rate::Hz_48000, 0}},
|
||||
{"E5", {659, audio::Rate::Hz_48000, 0}}}};
|
||||
|
||||
const Instrument pitch_fork = {// freq copied from flipper app
|
||||
.name = "Pitch Fork",
|
||||
.notes = {
|
||||
{"12ET A4", {440, audio::Rate::Hz_48000, 0}},
|
||||
{"Sarti's A4", {436, audio::Rate::Hz_48000, 0}},
|
||||
{"1858 A4", {435, audio::Rate::Hz_48000, 0}},
|
||||
{"Verdi's A4", {432, audio::Rate::Hz_48000, 0}}}};
|
||||
|
||||
std::map<std::string, Instrument> instruments{
|
||||
{"Guitar", guitar},
|
||||
{"Violin", violin},
|
||||
{"Pitch Fork", pitch_fork}};
|
||||
};
|
||||
|
||||
} // namespace ui::external_app::tuner
|
||||
|
||||
#endif /*__UI_TUNER_H__*/
|
||||
@@ -330,6 +330,7 @@ SystemStatusView::SystemStatusView(
|
||||
|
||||
audio::output::stop();
|
||||
audio::output::update_audio_mute();
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
@@ -761,10 +762,10 @@ static void add_apps(NavigationView& nav, BtnGridView& grid, app_location_t loc)
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
void add_external_items(NavigationView& nav, app_location_t location, BtnGridView& grid, uint8_t notice_pos) {
|
||||
void add_external_items(NavigationView& nav, app_location_t location, BtnGridView& grid, uint8_t error_tile_pos) {
|
||||
auto externalItems = ExternalItemsMenuLoader::load_external_items(location, nav);
|
||||
if (externalItems.empty()) {
|
||||
grid.insert_item({"Notice!",
|
||||
grid.insert_item({"ExtAppErr",
|
||||
Theme::getInstance()->error_dark->foreground,
|
||||
nullptr,
|
||||
[&nav]() {
|
||||
@@ -774,7 +775,7 @@ void add_external_items(NavigationView& nav, app_location_t location, BtnGridVie
|
||||
"see Mayhem wiki and copy apps\n"
|
||||
"to " + apps_dir.string() + " folder of SD card.");
|
||||
}},
|
||||
notice_pos);
|
||||
error_tile_pos);
|
||||
} else {
|
||||
std::sort(externalItems.begin(), externalItems.end(), [](const auto &a, const auto &b)
|
||||
{
|
||||
@@ -795,6 +796,12 @@ void add_external_items(NavigationView& nav, app_location_t location, BtnGridVie
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
bool verify_sdcard_format() {
|
||||
FATFS* fs = &sd_card::fs;
|
||||
return (fs->fs_type == FS_FAT32 || fs->fs_type == FS_EXFAT) || !(sd_card::status() == sd_card::Status::Mounted);
|
||||
/* ^ to satisfy those users that not use an sd*/
|
||||
}
|
||||
|
||||
/* ReceiversMenuView *****************************************************/
|
||||
|
||||
ReceiversMenuView::ReceiversMenuView(NavigationView& nav)
|
||||
@@ -866,8 +873,13 @@ SystemMenuView::SystemMenuView(NavigationView& nav)
|
||||
}
|
||||
|
||||
void SystemMenuView::on_populate() {
|
||||
if (!verify_sdcard_format()) {
|
||||
add_item({"SDCard Error", Theme::getInstance()->error_dark->foreground, nullptr, [this]() {
|
||||
nav_.display_modal("Error", "SD Card is not exFAT/FAT32,\nformat to exFAT or FAT32 on PC");
|
||||
}});
|
||||
}
|
||||
add_apps(nav_, *this, HOME);
|
||||
add_external_items(nav_, app_location_t::HOME, *this, 2);
|
||||
add_external_items(nav_, app_location_t::HOME, *this, 0);
|
||||
add_item({"HackRF", Theme::getInstance()->fg_cyan->foreground, &bitmap_icon_hackrf, [this]() { hackrf_mode(nav_); }});
|
||||
}
|
||||
|
||||
|
||||
@@ -197,6 +197,7 @@ class SystemStatusView : public View {
|
||||
static constexpr auto default_title = "";
|
||||
bool batt_was_inited = false; // if the battery was off on tart, but later turned on.
|
||||
bool batt_info_up = false; // to prevent show multiple batt info dialog
|
||||
|
||||
NavigationView& nav_;
|
||||
|
||||
Rectangle backdrop{
|
||||
@@ -322,7 +323,7 @@ class InformationView : public View {
|
||||
|
||||
Rectangle backdrop{
|
||||
{0, 0 * 16, 240, 16},
|
||||
{33, 33, 33}};
|
||||
Theme::getInstance()->bg_darker->background};
|
||||
|
||||
Text version{
|
||||
{2, 0, 11 * 8, 16},
|
||||
|
||||
@@ -240,21 +240,16 @@ namespace ui {
|
||||
|
||||
SDCardDebugView::SDCardDebugView(NavigationView& nav) {
|
||||
add_children({
|
||||
&text_title,
|
||||
&text_csd_title,
|
||||
&labels,
|
||||
&text_format,
|
||||
&text_csd_value_3,
|
||||
&text_csd_value_2,
|
||||
&text_csd_value_1,
|
||||
&text_csd_value_0,
|
||||
&text_bus_width_title,
|
||||
&text_bus_width_value,
|
||||
&text_card_type_title,
|
||||
&text_card_type_value,
|
||||
&text_block_size_title,
|
||||
&text_block_size_value,
|
||||
&text_block_count_title,
|
||||
&text_block_count_value,
|
||||
&text_capacity_title,
|
||||
&text_capacity_value,
|
||||
&text_test_write_time_title,
|
||||
&text_test_write_time_value,
|
||||
@@ -374,6 +369,14 @@ void SDCardDebugView::on_status(const sd_card::Status) {
|
||||
text_csd_value_1.set(to_string_hex(csd[1], 8));
|
||||
text_csd_value_0.set(to_string_hex(csd[0], 8));
|
||||
|
||||
text_format.set(fetch_sdcard_format());
|
||||
if (fetch_sdcard_format().find("FAT32") != std::string::npos) {
|
||||
// to satisfy the intendent style in this app, the text contains padding space, thus can't use ==
|
||||
text_format.set_style(Theme::getInstance()->fg_green);
|
||||
} else {
|
||||
text_format.set_style(Theme::getInstance()->error_dark);
|
||||
}
|
||||
|
||||
BlockDeviceInfo block_device_info;
|
||||
if (sdcGetInfo(&SDCD1, &block_device_info) == CH_SUCCESS) {
|
||||
text_block_size_value.set(to_string_dec_uint(block_device_info.blk_size, 5));
|
||||
@@ -447,4 +450,38 @@ void SDCardDebugView::on_test() {
|
||||
}
|
||||
}
|
||||
|
||||
std::string SDCardDebugView::fetch_sdcard_format() {
|
||||
const size_t max_len = sizeof("Undefined: 255") + 1;
|
||||
|
||||
auto padding = [max_len](std::string s) {
|
||||
if (s.length() < max_len) {
|
||||
return std::string(max_len - s.length(), ' ') + s;
|
||||
}
|
||||
return s;
|
||||
};
|
||||
|
||||
FATFS* fs = &sd_card::fs;
|
||||
std::string resault;
|
||||
|
||||
switch (fs->fs_type) {
|
||||
case FS_FAT12:
|
||||
resault = "FAT12";
|
||||
break;
|
||||
case FS_FAT16:
|
||||
resault = "FAT16";
|
||||
break;
|
||||
case FS_FAT32:
|
||||
resault = "FAT32";
|
||||
break;
|
||||
case FS_EXFAT:
|
||||
resault = "ExFAT";
|
||||
break;
|
||||
default:
|
||||
resault = "Undefined: " + to_string_dec_uint(fs->fs_type, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
return padding(resault);
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
@@ -45,15 +45,23 @@ class SDCardDebugView : public View {
|
||||
|
||||
void on_status(const sd_card::Status status);
|
||||
void on_test();
|
||||
std::string fetch_sdcard_format();
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 1 * 16}, "Format", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 3 * 16}, "CSD", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 5 * 16}, "Bus width", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 6 * 16}, "Card type", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 8 * 16}, "Block size", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 9 * 16}, "Block count", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 10 * 16}, "Capacity", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 5 * 16}, "Bus width", Theme::getInstance()->fg_light->foreground},
|
||||
|
||||
Text text_title{
|
||||
{(240 - (7 * 8)) / 2, 1 * 16, (7 * 8), 16},
|
||||
"SD Card",
|
||||
};
|
||||
|
||||
Text text_csd_title{
|
||||
{0, 3 * 16, (8 * 8), 16},
|
||||
"CSD",
|
||||
Text text_format{
|
||||
{240 - ((sizeof("Undefined: 255") + 1) * 8), 1 * 16, (sizeof("Undefined: 255") + 1) * 8, 16},
|
||||
"Unknown",
|
||||
};
|
||||
|
||||
Text text_csd_value_3{
|
||||
@@ -78,11 +86,6 @@ class SDCardDebugView : public View {
|
||||
|
||||
static constexpr size_t bus_width_characters = 1;
|
||||
|
||||
Text text_bus_width_title{
|
||||
{0, 5 * 16, (9 * 8), 16},
|
||||
"Bus width",
|
||||
};
|
||||
|
||||
Text text_bus_width_value{
|
||||
{240 - (bus_width_characters * 8), 5 * 16, (bus_width_characters * 8), 16},
|
||||
"",
|
||||
@@ -90,11 +93,6 @@ class SDCardDebugView : public View {
|
||||
|
||||
static constexpr size_t card_type_characters = 13;
|
||||
|
||||
Text text_card_type_title{
|
||||
{0, 6 * 16, (9 * 8), 16},
|
||||
"Card type",
|
||||
};
|
||||
|
||||
Text text_card_type_value{
|
||||
{240 - (card_type_characters * 8), 6 * 16, (card_type_characters * 8), 16},
|
||||
"",
|
||||
@@ -102,11 +100,6 @@ class SDCardDebugView : public View {
|
||||
|
||||
static constexpr size_t block_size_characters = 5;
|
||||
|
||||
Text text_block_size_title{
|
||||
{0, 8 * 16, (10 * 8), 16},
|
||||
"Block size",
|
||||
};
|
||||
|
||||
Text text_block_size_value{
|
||||
{240 - (block_size_characters * 8), 8 * 16, (block_size_characters * 8), 16},
|
||||
"",
|
||||
@@ -114,11 +107,6 @@ class SDCardDebugView : public View {
|
||||
|
||||
static constexpr size_t block_count_characters = 9;
|
||||
|
||||
Text text_block_count_title{
|
||||
{0, 9 * 16, (11 * 8), 16},
|
||||
"Block count",
|
||||
};
|
||||
|
||||
Text text_block_count_value{
|
||||
{240 - (block_count_characters * 8), 9 * 16, (block_count_characters * 8), 16},
|
||||
"",
|
||||
@@ -126,11 +114,6 @@ class SDCardDebugView : public View {
|
||||
|
||||
static constexpr size_t capacity_characters = 10;
|
||||
|
||||
Text text_capacity_title{
|
||||
{0, 10 * 16, (8 * 8), 16},
|
||||
"Capacity",
|
||||
};
|
||||
|
||||
Text text_capacity_value{
|
||||
{240 - (capacity_characters * 8), 10 * 16, (capacity_characters * 8), 16},
|
||||
"",
|
||||
|
||||
@@ -271,6 +271,7 @@ macro(DeclareTargets chunk_tag name)
|
||||
project("baseband_${name}")
|
||||
|
||||
include(${RULESPATH}/rules.cmake)
|
||||
set_source_files_properties(${MODE_CPPSRC} PROPERTIES COMPILE_FLAGS "${MODE_FLAGS}")
|
||||
add_executable(${PROJECT_NAME}.elf $<TARGET_OBJECTS:baseband_shared> ${MODE_CPPSRC} ${HALSRC} ${PLATFORMSRC})
|
||||
set_target_properties(${PROJECT_NAME}.elf PROPERTIES LINK_DEPENDS ${LDSCRIPT})
|
||||
add_definitions(${DEFS})
|
||||
@@ -313,6 +314,7 @@ macro(DeclareTargets chunk_tag name)
|
||||
endmacro()
|
||||
|
||||
set(add_to_firmware TRUE)
|
||||
set(MODE_FLAGS "-O3")
|
||||
|
||||
|
||||
### ADS-B RX
|
||||
@@ -498,6 +500,7 @@ set(MODE_CPPSRC
|
||||
)
|
||||
DeclareTargets(PWTH weather)
|
||||
|
||||
set(MODE_FLAGS "-Os")
|
||||
|
||||
### Flash Utility
|
||||
|
||||
@@ -559,7 +562,7 @@ DeclareTargets(PUSB sd_over_usb)
|
||||
|
||||
### Place external app and disabled images below so they don't get added to the firmware
|
||||
set(add_to_firmware FALSE)
|
||||
|
||||
set(MODE_FLAGS "-O3")
|
||||
|
||||
### ACARS RX
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
/ 950 - Traditional Chinese (DBCS)
|
||||
*/
|
||||
|
||||
#define _USE_LFN 2
|
||||
#define _USE_LFN 3
|
||||
#define _MAX_LFN 255
|
||||
/* The _USE_LFN switches the support of long file name (LFN).
|
||||
/
|
||||
@@ -189,7 +189,7 @@
|
||||
/ Instead of private sector buffer eliminated from the file object, common sector
|
||||
/ buffer in the file system object (FATFS) is used for the file data transfer. */
|
||||
|
||||
#define _FS_EXFAT 0
|
||||
#define _FS_EXFAT 1
|
||||
/* This option switches support of exFAT file system. (0:Disable or 1:Enable)
|
||||
/ When enable exFAT, also LFN needs to be enabled. (_USE_LFN >= 1)
|
||||
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 886 B |
+1
-1
Submodule hackrf updated: 9bd91c6a85...65bf67f9b5
Reference in New Issue
Block a user