Compare commits

...

16 Commits

Author SHA1 Message Date
jLynx eb22af84ff Update version.txt 2024-12-20 20:05:01 +13:00
jLynx 6dc25813e2 Update past_version.txt 2024-12-20 20:04:46 +13:00
Bernd Herzog 4ee00c0031 Enable exFAT feature (#2437)
* enabled exFAT in ffconf
* added exFAT to sd card check
* solved todo
2024-12-20 07:55:39 +01:00
sommermorgentraum 55525ed4ad fix wrong cast in morse app (#2436)
* fix wrong cast

* sorry, forgot to use enum
2024-12-20 07:53:15 +01:00
Erwin Ried 84dcfe29a7 Update README.md link to h4m was broken again 2024-12-18 23:44:35 +01:00
Erwin Ried 1ebe956557 h4m photo was broken 2024-12-18 23:35:42 +01:00
gullradriel ae656f07bf Usb fix (#2433)
* revert custom compiler definition since we are now having correct hackrf m0 implementation

* update submodule

---------

Co-authored-by: gullradriel <gullradriel@no-mail.com>
2024-12-18 21:55:53 +01:00
sommermorgentraum d5c894b322 fix namingspace for an app, remove too old images and links (#2432) 2024-12-18 11:20:53 +01:00
sommermorgentraum 9cea76a9f3 add metronome app (merge tuner firstly to satisfy conflict) (#2431)
* _

* _
2024-12-18 09:25:02 +00:00
sommermorgentraum ead9449609 add tuner app (#2429)
* _

* icon
2024-12-18 10:06:25 +01:00
Totoo fff63e056a FM Radio ext app (#2428) 2024-12-17 18:53:26 +01:00
sommermorgentraum 42da7443b4 fix gray box & remove multiple line text support for NewButton (#2426) 2024-12-15 18:22:19 +01:00
gullradriel ee10081854 update submodule (#2424) 2024-12-14 18:21:13 +00:00
gullradriel b38d1012fa Fix usb.c and usb_queue.c warnings in our CMakeLists instead of in the files (#2423) 2024-12-14 19:14:39 +01:00
sommermorgentraum 5075349d2d sdcard format detect and warn user (#2420) 2024-12-14 09:39:39 +01:00
gullradriel 8497b62c13 updated submodule (#2422)
Co-authored-by: gullradriel <gullradriel@no-mail.com>
2024-12-14 09:38:45 +01:00
26 changed files with 1409 additions and 63 deletions
+1 -1
View File
@@ -1 +1 @@
v2.0.1
v2.0.2
+1 -1
View File
@@ -1 +1 @@
v2.0.2
v2.1.0
+2 -4
View File
@@ -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: ![Static Badge](https://img.shields.io/badge/NEW-yellow) 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: ![Static Badge](https://img.shields.io/badge/NEW-yellow) 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).
+2 -2
View File
@@ -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 */
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
};
}
+168
View File
@@ -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
+150
View File
@@ -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__*/
+84
View File
@@ -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
};
}
+177
View File
@@ -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
+126
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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__*/
+16 -4
View File
@@ -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_); }});
}
+2 -1
View File
@@ -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},
+44 -7
View File
@@ -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 */
+14 -31
View File
@@ -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},
"",
+4 -1
View File
@@ -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
+2 -2
View File
@@ -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