mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-08-21 06:59:02 +00:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fd7637187a | |||
| 674b865ec0 | |||
| 00c9c6b40e | |||
| 113cbc42c9 | |||
| 454b8776b6 | |||
| efdf043d62 | |||
| 0f9d9e589d | |||
| 3b57672dda | |||
| b739dd883c | |||
| bf18851b6b |
@@ -1 +1 @@
|
||||
v2.1.0
|
||||
v2.2.0
|
||||
|
||||
@@ -1 +1 @@
|
||||
v2.2.0
|
||||
v2.3.0
|
||||
|
||||
@@ -192,7 +192,6 @@ set(CPPSRC
|
||||
core_control.cpp
|
||||
database.cpp
|
||||
gradient.cpp
|
||||
rfm69.cpp
|
||||
event_m0.cpp
|
||||
file_reader.cpp
|
||||
file.cpp
|
||||
@@ -261,7 +260,6 @@ set(CPPSRC
|
||||
ui/ui_receiver.cpp
|
||||
ui/ui_rssi.cpp
|
||||
ui/ui_freqlist.cpp
|
||||
ui/ui_tv.cpp
|
||||
ui/ui_spectrum.cpp
|
||||
ui/ui_tabview.cpp
|
||||
ui/ui_textentry.cpp
|
||||
|
||||
@@ -171,7 +171,7 @@ void IQTrimView::update_range_controls(iq::TrimRange trim_range) {
|
||||
}
|
||||
|
||||
void IQTrimView::profile_capture() {
|
||||
power_buckets_ = {};
|
||||
power_buckets_.clear();
|
||||
iq::PowerBuckets buckets{
|
||||
.p = power_buckets_.data(),
|
||||
.size = power_buckets_.size()};
|
||||
|
||||
@@ -285,9 +285,9 @@ bool StandaloneView::on_encoder(const EncoderEvent event) {
|
||||
|
||||
bool StandaloneView::on_touch(const TouchEvent event) {
|
||||
if (get_application_information()->header_version > 1) {
|
||||
get_application_information()->OnTouchEvent(event.point.x(), event.point.y(), (uint32_t)event.type);
|
||||
return get_application_information()->OnTouchEvent(event.point.x(), event.point.y(), (uint32_t)event.type);
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StandaloneView::on_keyboard(const KeyboardEvent event) {
|
||||
|
||||
@@ -339,7 +339,7 @@ void SubGhzDRecentEntryDetailView::parseProtocol() {
|
||||
if (entry_.sensorType == FPS_CAMEATOMO) {
|
||||
entry_.data ^= 0xFFFFFFFFFFFFFFFF;
|
||||
entry_.data <<= 4;
|
||||
uint8_t pack[8] = {};
|
||||
uint8_t pack[8];
|
||||
pack[0] = (entry_.data >> 56);
|
||||
pack[1] = ((entry_.data >> 48) & 0xFF);
|
||||
pack[2] = ((entry_.data >> 40) & 0xFF);
|
||||
|
||||
@@ -612,7 +612,7 @@ void TextEditorView::open_file(const fs::path& path) {
|
||||
viewer.clear_file();
|
||||
delete_temp_file(path_);
|
||||
|
||||
path_ = {};
|
||||
path_ = "";
|
||||
file_dirty_ = false;
|
||||
has_temp_file_ = false;
|
||||
auto result = FileWrapper::open(
|
||||
|
||||
+2
-2
@@ -34,7 +34,7 @@ using namespace portapack;
|
||||
#include <cmath>
|
||||
#include <array>
|
||||
|
||||
namespace ui {
|
||||
namespace ui::external_app::analogtv {
|
||||
namespace tv {
|
||||
|
||||
/* TimeScopeView******************************************************/
|
||||
@@ -235,4 +235,4 @@ void TVWidget::on_audio_spectrum() {
|
||||
}
|
||||
|
||||
} /* namespace tv */
|
||||
} /* namespace ui */
|
||||
} // namespace ui::external_app::analogtv
|
||||
+2
-2
@@ -33,7 +33,7 @@
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
namespace ui {
|
||||
namespace ui::external_app::analogtv {
|
||||
namespace tv {
|
||||
|
||||
class TimeScopeView : public View {
|
||||
@@ -167,6 +167,6 @@ class TVWidget : public View {
|
||||
};
|
||||
|
||||
} /* namespace tv */
|
||||
} /* namespace ui */
|
||||
} // namespace ui::external_app::analogtv
|
||||
|
||||
#endif /*__UI_TV_H__*/
|
||||
@@ -21,7 +21,6 @@
|
||||
*/
|
||||
|
||||
#include "bht.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
|
||||
namespace ui::external_app::bht_tx {
|
||||
|
||||
|
||||
+1
-1
@@ -207,7 +207,7 @@ class BHTView : public View {
|
||||
"Scan"};
|
||||
|
||||
Checkbox checkbox_flashing{
|
||||
{16 * 8, 25 * 8},
|
||||
{UI_POS_X(16), 25 * 8},
|
||||
8,
|
||||
"Flashing"};
|
||||
NumberField field_speed{
|
||||
|
||||
+12
-12
@@ -20,13 +20,13 @@ void initialize_app(ui::NavigationView& nav) {
|
||||
extern "C" {
|
||||
|
||||
__attribute__((section(".external_app.app_breakout.application_information"), used)) application_information_t _application_information_breakout = {
|
||||
(uint8_t*)0x00000000,
|
||||
ui::external_app::breakout::initialize_app,
|
||||
CURRENT_HEADER_VERSION,
|
||||
VERSION_MD5,
|
||||
/*.memory_location = */ (uint8_t*)0x00000000,
|
||||
/*.externalAppEntry = */ ui::external_app::breakout::initialize_app,
|
||||
/*.header_version = */ CURRENT_HEADER_VERSION,
|
||||
/*.app_version = */ VERSION_MD5,
|
||||
|
||||
"Breakout",
|
||||
{
|
||||
/*.app_name = */ "Breakout",
|
||||
/*.bitmap_data = */ {
|
||||
0x00,
|
||||
0x00,
|
||||
0x7F,
|
||||
@@ -60,11 +60,11 @@ __attribute__((section(".external_app.app_breakout.application_information"), us
|
||||
0xF7,
|
||||
0xF7,
|
||||
},
|
||||
ui::Color::green().v,
|
||||
app_location_t::GAMES,
|
||||
-1,
|
||||
/*.icon_color = */ ui::Color::green().v,
|
||||
/*.menu_location = */ app_location_t::GAMES,
|
||||
/*.desired_menu_position = */ -1,
|
||||
|
||||
{0, 0, 0, 0},
|
||||
0x00000000,
|
||||
/*.m4_app_tag = */ {'P', 'A', 'B', 'P'}, // This is the audio beep baseband tag!
|
||||
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
|
||||
};
|
||||
} // namespace ui::external_app::breakout
|
||||
}
|
||||
+279
-10
@@ -7,6 +7,12 @@
|
||||
*/
|
||||
|
||||
#include "ui_breakout.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
#include "audio.hpp"
|
||||
#include "portapack.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui::external_app::breakout {
|
||||
|
||||
@@ -92,6 +98,37 @@ void BreakoutView::init_game() {
|
||||
game_state = STATE_MENU;
|
||||
menu_blink_state = true;
|
||||
menu_blink_counter = 0;
|
||||
|
||||
// Play startup sound
|
||||
if (sound_enabled) {
|
||||
baseband::request_audio_beep(262, 24000, 150); // C4 -
|
||||
chThdSleepMilliseconds(200);
|
||||
baseband::request_audio_beep(262, 24000, 150); // C4
|
||||
chThdSleepMilliseconds(200);
|
||||
baseband::request_audio_beep(392, 24000, 150); // G4
|
||||
chThdSleepMilliseconds(200);
|
||||
baseband::request_audio_beep(392, 24000, 150); // G4
|
||||
chThdSleepMilliseconds(200);
|
||||
baseband::request_audio_beep(440, 24000, 150); // A4
|
||||
chThdSleepMilliseconds(200);
|
||||
baseband::request_audio_beep(440, 24000, 150); // A4
|
||||
chThdSleepMilliseconds(200);
|
||||
baseband::request_audio_beep(392, 24000, 300); // G4
|
||||
chThdSleepMilliseconds(350);
|
||||
baseband::request_audio_beep(349, 24000, 150); // F4
|
||||
chThdSleepMilliseconds(200);
|
||||
baseband::request_audio_beep(349, 24000, 150); // F4
|
||||
chThdSleepMilliseconds(200);
|
||||
baseband::request_audio_beep(330, 24000, 150); // E4
|
||||
chThdSleepMilliseconds(200);
|
||||
baseband::request_audio_beep(330, 24000, 150); // E4
|
||||
chThdSleepMilliseconds(200);
|
||||
baseband::request_audio_beep(294, 24000, 150); // D4
|
||||
chThdSleepMilliseconds(200);
|
||||
baseband::request_audio_beep(294, 24000, 150); // D4
|
||||
chThdSleepMilliseconds(200);
|
||||
baseband::request_audio_beep(262, 24000, 400); // C4
|
||||
}
|
||||
}
|
||||
|
||||
void BreakoutView::init_level() {
|
||||
@@ -126,6 +163,34 @@ void BreakoutView::draw_screen() {
|
||||
draw_level();
|
||||
}
|
||||
|
||||
void BreakoutView::draw_menu_volume_bar() {
|
||||
// Clear the entire volume area first to handle bar shrinking
|
||||
painter.fill_rectangle({40, 259, 220, 40}, Color::black());
|
||||
|
||||
// Draw volume label
|
||||
auto style = *ui::Theme::getInstance()->fg_light;
|
||||
painter.draw_string({40, 260}, style, "Volume:");
|
||||
|
||||
// Draw volume bar background
|
||||
painter.draw_rectangle({100, 259, 102, 10}, Color::grey());
|
||||
|
||||
// Draw volume level
|
||||
int bar_width = (volume_level * 100) / 99;
|
||||
if (bar_width > 0) {
|
||||
painter.fill_rectangle({101, 260, bar_width, 8}, Color::green());
|
||||
}
|
||||
|
||||
// Draw percentage
|
||||
painter.draw_string({210, 260}, style, std::to_string(volume_level) + "%");
|
||||
|
||||
// Draw sound status
|
||||
if (sound_enabled) {
|
||||
painter.draw_string({UI_POS_X_CENTER(11), 280}, *ui::Theme::getInstance()->fg_green, "Sound: ON");
|
||||
} else {
|
||||
painter.draw_string({UI_POS_X_CENTER(11), 280}, *ui::Theme::getInstance()->fg_red, "Sound: OFF");
|
||||
}
|
||||
}
|
||||
|
||||
void BreakoutView::draw_borders() {
|
||||
rect(0, GAME_AREA_TOP - 1, SCREEN_WIDTH, GAME_AREA_TOP, COLOR_BORDER);
|
||||
}
|
||||
@@ -166,6 +231,22 @@ void BreakoutView::draw_level() {
|
||||
painter.draw_string({80, 30}, style, "Level: " + std::to_string(level));
|
||||
}
|
||||
|
||||
void BreakoutView::adjust_volume(int delta) {
|
||||
volume_level += delta;
|
||||
if (volume_level < 0) volume_level = 0;
|
||||
if (volume_level > 99) volume_level = 99;
|
||||
|
||||
// Update the actual audio volume using decibel conversion
|
||||
// Map 0-99 to roughly -60dB to 0dB range
|
||||
int db = (volume_level - 99) * 60 / 99; // Maps 0->-60dB, 99->0dB
|
||||
audio::headphone::set_volume(volume_t::decibel(db));
|
||||
|
||||
// If we're in the menu, redraw the volume bar
|
||||
if (game_state == STATE_MENU) {
|
||||
draw_menu_volume_bar();
|
||||
}
|
||||
}
|
||||
|
||||
void BreakoutView::move_paddle_left() {
|
||||
if (paddle_x > 0) {
|
||||
fillrect(paddle_x, PADDLE_Y, paddle_x + PADDLE_WIDTH, PADDLE_Y + PADDLE_HEIGHT, COLOR_BACKGROUND);
|
||||
@@ -231,19 +312,23 @@ void BreakoutView::update_game() {
|
||||
if (ball_x < 0) {
|
||||
ball_x = 0;
|
||||
ball_dx = -ball_dx;
|
||||
play_wall_hit();
|
||||
} else if (ball_x > SCREEN_WIDTH - BALL_SIZE) {
|
||||
ball_x = SCREEN_WIDTH - BALL_SIZE;
|
||||
ball_dx = -ball_dx;
|
||||
play_wall_hit();
|
||||
}
|
||||
|
||||
if (ball_y < GAME_AREA_TOP) {
|
||||
ball_y = GAME_AREA_TOP;
|
||||
ball_dy = -ball_dy;
|
||||
play_wall_hit();
|
||||
}
|
||||
|
||||
// Bottom edge - lose life
|
||||
if (ball_y > GAME_AREA_BOTTOM) {
|
||||
lives--;
|
||||
play_death_sound(); // Play death sound
|
||||
draw_lives();
|
||||
if (lives <= 0) {
|
||||
handle_game_over();
|
||||
@@ -262,6 +347,8 @@ void BreakoutView::update_game() {
|
||||
ball_y = PADDLE_Y - BALL_SIZE;
|
||||
ball_dy = -ball_dy;
|
||||
|
||||
play_paddle_hit();
|
||||
|
||||
// Add some angle based on hit position
|
||||
float hit_position = (ball_x + (BALL_SIZE / 2)) - paddle_x;
|
||||
float angle = (hit_position / PADDLE_WIDTH) - 0.5f;
|
||||
@@ -301,6 +388,8 @@ bool BreakoutView::check_brick_collision(int row, int col) {
|
||||
score += (5 - row) * 10;
|
||||
draw_score();
|
||||
|
||||
play_brick_hit();
|
||||
|
||||
ball_dy = -ball_dy;
|
||||
return true;
|
||||
}
|
||||
@@ -314,6 +403,8 @@ bool BreakoutView::check_level_complete() {
|
||||
|
||||
void BreakoutView::next_level() {
|
||||
level++;
|
||||
play_level_complete();
|
||||
chThdSleepMilliseconds(500); // Give time for sound to play
|
||||
init_level();
|
||||
draw_screen();
|
||||
}
|
||||
@@ -322,9 +413,11 @@ void BreakoutView::handle_game_over() {
|
||||
game_state = STATE_GAME_OVER;
|
||||
gameover_blink_state = true;
|
||||
gameover_blink_counter = 0;
|
||||
play_game_over();
|
||||
}
|
||||
|
||||
void BreakoutView::show_menu() {
|
||||
// Only draw the static parts once
|
||||
if (menu_blink_counter == 0) {
|
||||
cls();
|
||||
background(COLOR_BACKGROUND);
|
||||
@@ -338,23 +431,30 @@ void BreakoutView::show_menu() {
|
||||
painter.draw_string({UI_POS_X_CENTER(20), 130}, style_cyan, "ROTARY: MOVE PADDLE");
|
||||
painter.draw_string({UI_POS_X_CENTER(21), 160}, style_cyan, "SELECT: START/LAUNCH");
|
||||
painter.draw_string({UI_POS_X_CENTER(25), 190}, style_blue, "========================");
|
||||
|
||||
// Volume adjustment instructions
|
||||
painter.draw_string({UI_POS_X_CENTER(24), 220}, style_cyan, "Press UP/DOWN for Volume");
|
||||
|
||||
// Draw volume control at bottom
|
||||
draw_menu_volume_bar();
|
||||
}
|
||||
|
||||
auto style_red = *ui::Theme::getInstance()->fg_red;
|
||||
|
||||
// Only flash the "PRESS SELECT" text
|
||||
if (++menu_blink_counter >= 30) {
|
||||
menu_blink_counter = 0;
|
||||
menu_blink_counter = 1; // Keep it at 1 so we don't redraw everything
|
||||
menu_blink_state = !menu_blink_state;
|
||||
|
||||
painter.fill_rectangle({UI_POS_X_CENTER(17), 228, 128, 20}, Color::black());
|
||||
auto style_red = *ui::Theme::getInstance()->fg_red;
|
||||
painter.fill_rectangle({UI_POS_X_CENTER(17), 238, 128, 20}, Color::black());
|
||||
|
||||
if (menu_blink_state) {
|
||||
painter.draw_string({UI_POS_X_CENTER(17), 230}, style_red, "* PRESS SELECT *");
|
||||
painter.draw_string({UI_POS_X_CENTER(17), 240}, style_red, "* PRESS SELECT *");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BreakoutView::show_game_over() {
|
||||
// Only draw the static parts once
|
||||
if (gameover_blink_counter == 0) {
|
||||
cls();
|
||||
background(COLOR_BACKGROUND);
|
||||
@@ -366,12 +466,12 @@ void BreakoutView::show_game_over() {
|
||||
painter.draw_string({UI_POS_X_CENTER(11), 150}, style_yellow, "SCORE: " + std::to_string(score));
|
||||
}
|
||||
|
||||
auto style_green = *ui::Theme::getInstance()->fg_green;
|
||||
|
||||
// Only flash the "PRESS SELECT" text
|
||||
if (++gameover_blink_counter >= 30) {
|
||||
gameover_blink_counter = 0;
|
||||
gameover_blink_counter = 1; // Keep it at 1 so we don't redraw everything
|
||||
gameover_blink_state = !gameover_blink_state;
|
||||
|
||||
auto style_green = *ui::Theme::getInstance()->fg_green;
|
||||
painter.fill_rectangle({UI_POS_X_CENTER(13), 198, 96, 20}, Color::black());
|
||||
|
||||
if (gameover_blink_state) {
|
||||
@@ -385,17 +485,169 @@ void BreakoutView::reset_game() {
|
||||
score = 0;
|
||||
lives = 3;
|
||||
game_state = STATE_PLAYING;
|
||||
|
||||
dummy.focus();
|
||||
|
||||
init_level();
|
||||
draw_screen();
|
||||
}
|
||||
|
||||
// Sound effect implementations with timing control
|
||||
void BreakoutView::play_paddle_hit() {
|
||||
if (sound_enabled) {
|
||||
uint32_t current_time = chTimeNow();
|
||||
if (current_time - last_sound_time >= min_sound_interval) {
|
||||
baseband::request_beep_stop(); // Stop any previous sound
|
||||
chThdSleepMilliseconds(5); // Small delay
|
||||
baseband::request_audio_beep(440, 24000, 40); // 440Hz A4, 40ms
|
||||
last_sound_time = current_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BreakoutView::play_brick_hit() {
|
||||
if (sound_enabled) {
|
||||
uint32_t current_time = chTimeNow();
|
||||
if (current_time - last_sound_time >= min_sound_interval) {
|
||||
baseband::request_beep_stop(); // Stop any previous sound
|
||||
chThdSleepMilliseconds(5); // Small delay
|
||||
// Higher pitch that varies with remaining bricks
|
||||
uint32_t freq = 880 + ((25 - brick_count) * 20); // Gets higher as bricks are destroyed
|
||||
baseband::request_audio_beep(freq, 24000, 30);
|
||||
last_sound_time = current_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BreakoutView::play_wall_hit() {
|
||||
if (sound_enabled) {
|
||||
uint32_t current_time = chTimeNow();
|
||||
if (current_time - last_sound_time >= min_sound_interval) {
|
||||
baseband::request_beep_stop(); // Stop any previous sound
|
||||
chThdSleepMilliseconds(5); // Small delay
|
||||
baseband::request_audio_beep(220, 24000, 120); // 220Hz A3, 120ms
|
||||
last_sound_time = current_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BreakoutView::play_death_sound() {
|
||||
if (sound_enabled) {
|
||||
baseband::request_audio_beep(493, 24000, 150); // B4
|
||||
chThdSleepMilliseconds(180);
|
||||
baseband::request_audio_beep(466, 24000, 150); // Bb4
|
||||
chThdSleepMilliseconds(180);
|
||||
baseband::request_audio_beep(440, 24000, 150); // A4
|
||||
chThdSleepMilliseconds(180);
|
||||
baseband::request_audio_beep(415, 24000, 150); // Ab4
|
||||
chThdSleepMilliseconds(180);
|
||||
baseband::request_audio_beep(392, 24000, 150); // G4
|
||||
chThdSleepMilliseconds(180);
|
||||
baseband::request_audio_beep(369, 24000, 150); // Gb4
|
||||
chThdSleepMilliseconds(180);
|
||||
baseband::request_audio_beep(349, 24000, 150); // F4
|
||||
chThdSleepMilliseconds(180);
|
||||
baseband::request_audio_beep(329, 24000, 150); // E4
|
||||
chThdSleepMilliseconds(180);
|
||||
baseband::request_audio_beep(293, 24000, 150); // D4
|
||||
chThdSleepMilliseconds(180);
|
||||
baseband::request_audio_beep(261, 24000, 150); // C4
|
||||
chThdSleepMilliseconds(180);
|
||||
baseband::request_audio_beep(196, 24000, 200); // G3
|
||||
chThdSleepMilliseconds(230);
|
||||
baseband::request_audio_beep(130, 24000, 300); // C3
|
||||
}
|
||||
}
|
||||
|
||||
void BreakoutView::play_game_over() {
|
||||
if (sound_enabled) {
|
||||
// First phrase
|
||||
baseband::request_audio_beep(392, 24000, 300); // G4
|
||||
chThdSleepMilliseconds(350);
|
||||
baseband::request_audio_beep(392, 24000, 150); // G4
|
||||
chThdSleepMilliseconds(200);
|
||||
baseband::request_audio_beep(392, 24000, 150); // G4
|
||||
chThdSleepMilliseconds(200);
|
||||
baseband::request_audio_beep(311, 24000, 500); // Eb4 - long
|
||||
chThdSleepMilliseconds(600);
|
||||
|
||||
// Second phrase
|
||||
baseband::request_audio_beep(349, 24000, 300); // F4
|
||||
chThdSleepMilliseconds(350);
|
||||
baseband::request_audio_beep(349, 24000, 150); // F4
|
||||
chThdSleepMilliseconds(200);
|
||||
baseband::request_audio_beep(349, 24000, 150); // F4
|
||||
chThdSleepMilliseconds(200);
|
||||
baseband::request_audio_beep(294, 24000, 500); // D4 - long
|
||||
chThdSleepMilliseconds(600);
|
||||
|
||||
// Final phrase - slower and more dramatic
|
||||
baseband::request_audio_beep(262, 24000, 200); // C4
|
||||
chThdSleepMilliseconds(250);
|
||||
baseband::request_audio_beep(247, 24000, 200); // B3
|
||||
chThdSleepMilliseconds(250);
|
||||
baseband::request_audio_beep(233, 24000, 200); // Bb3
|
||||
chThdSleepMilliseconds(250);
|
||||
baseband::request_audio_beep(220, 24000, 200); // A3
|
||||
chThdSleepMilliseconds(250);
|
||||
baseband::request_audio_beep(196, 24000, 200); // G3
|
||||
chThdSleepMilliseconds(250);
|
||||
baseband::request_audio_beep(175, 24000, 200); // F3
|
||||
chThdSleepMilliseconds(250);
|
||||
baseband::request_audio_beep(131, 24000, 600); // C3
|
||||
}
|
||||
}
|
||||
|
||||
void BreakoutView::play_level_complete() {
|
||||
if (sound_enabled) {
|
||||
baseband::request_beep_stop(); // Stop any previous sound
|
||||
chThdSleepMilliseconds(10);
|
||||
baseband::request_audio_beep(1047, 24000, 300); // 1047Hz C6, 300ms
|
||||
}
|
||||
}
|
||||
|
||||
BreakoutView::BreakoutView(NavigationView& nav)
|
||||
: nav_{nav}, bricks{} { // Add bricks{} here
|
||||
: nav_{nav}, bricks{} {
|
||||
// Initialize audio system for beeps FIRST
|
||||
baseband::run_prepared_image(portapack::memory::map::m4_code.base()); // Load the audio beep baseband
|
||||
|
||||
add_children({&dummy});
|
||||
|
||||
// Initialize audio
|
||||
audio::set_rate(audio::Rate::Hz_24000);
|
||||
audio::output::start();
|
||||
|
||||
// Set initial volume to 80% and ensure sound is ON
|
||||
volume_level = 80;
|
||||
sound_enabled = true; // Make sure this is explicitly set to ON
|
||||
|
||||
// Set the actual volume
|
||||
int db = (volume_level - 99) * 60 / 99; // Maps to roughly -12dB for 80%
|
||||
audio::headphone::set_volume(volume_t::decibel(db));
|
||||
|
||||
attach(1.0 / 60.0);
|
||||
}
|
||||
|
||||
BreakoutView::~BreakoutView() {
|
||||
// Clean shutdown
|
||||
baseband::request_beep_stop();
|
||||
receiver_model.disable();
|
||||
baseband::shutdown();
|
||||
audio::output::stop();
|
||||
}
|
||||
|
||||
void BreakoutView::on_show() {
|
||||
// Nothing needed here, initialization done in constructor
|
||||
}
|
||||
|
||||
void BreakoutView::on_hide() {
|
||||
// Additional cleanup
|
||||
baseband::request_beep_stop();
|
||||
audio::output::stop();
|
||||
}
|
||||
|
||||
void BreakoutView::focus() {
|
||||
dummy.focus();
|
||||
}
|
||||
|
||||
void BreakoutView::paint(Painter& painter) {
|
||||
@@ -433,16 +685,33 @@ bool BreakoutView::on_key(const KeyEvent key) {
|
||||
} else if (game_state == STATE_PLAYING && ball_attached) {
|
||||
launch_ball();
|
||||
} else if (game_state == STATE_GAME_OVER) {
|
||||
reset_game();
|
||||
// Return to menu after game over
|
||||
game_state = STATE_MENU;
|
||||
menu_blink_counter = 0;
|
||||
init_game();
|
||||
}
|
||||
} else if (key == KeyEvent::Left && game_state == STATE_PLAYING) {
|
||||
move_paddle_left();
|
||||
} else if (key == KeyEvent::Right && game_state == STATE_PLAYING) {
|
||||
move_paddle_right();
|
||||
} else if (key == KeyEvent::Up && game_state == STATE_MENU) {
|
||||
// Only adjust volume in menu
|
||||
adjust_volume(5);
|
||||
if (!sound_enabled) sound_enabled = true;
|
||||
set_dirty();
|
||||
} else if (key == KeyEvent::Down && game_state == STATE_MENU) {
|
||||
// Only adjust volume in menu
|
||||
adjust_volume(-5);
|
||||
set_dirty();
|
||||
}
|
||||
|
||||
set_dirty();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BreakoutView::on_touch(const TouchEvent event) {
|
||||
(void)event; // Intentionally unused - touch disabled to avoid nav bar issues
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ui::external_app::breakout
|
||||
+21
-1
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_receiver.hpp"
|
||||
#include "event_m0.hpp"
|
||||
#include "message.hpp"
|
||||
#include "irq_controls.hpp"
|
||||
@@ -56,15 +57,18 @@ enum {
|
||||
class BreakoutView : public View {
|
||||
public:
|
||||
BreakoutView(NavigationView& nav);
|
||||
~BreakoutView();
|
||||
void on_show() override;
|
||||
void on_hide() override;
|
||||
|
||||
std::string title() const override { return "Breakout"; }
|
||||
|
||||
void focus() override { dummy.focus(); }
|
||||
void focus() override;
|
||||
void paint(Painter& painter) override;
|
||||
void frame_sync();
|
||||
bool on_encoder(const EncoderEvent event) override;
|
||||
bool on_key(KeyEvent key) override;
|
||||
bool on_touch(const TouchEvent event) override;
|
||||
|
||||
void cls();
|
||||
void background(int color);
|
||||
@@ -81,6 +85,7 @@ class BreakoutView : public View {
|
||||
void draw_lives();
|
||||
void draw_level();
|
||||
void draw_borders();
|
||||
void draw_menu_volume_bar();
|
||||
void move_paddle_left();
|
||||
void move_paddle_right();
|
||||
void launch_ball();
|
||||
@@ -96,6 +101,15 @@ class BreakoutView : public View {
|
||||
void check_game_timer();
|
||||
void attach(double delay_sec);
|
||||
void detach();
|
||||
void adjust_volume(int delta);
|
||||
|
||||
// Sound effect methods
|
||||
void play_paddle_hit();
|
||||
void play_brick_hit();
|
||||
void play_wall_hit();
|
||||
void play_death_sound();
|
||||
void play_game_over();
|
||||
void play_level_complete();
|
||||
|
||||
private:
|
||||
const Color pp_colors[9] = {
|
||||
@@ -147,6 +161,12 @@ class BreakoutView : public View {
|
||||
double game_update_timeout = 0;
|
||||
uint32_t game_update_counter = 0;
|
||||
|
||||
// Audio control
|
||||
bool sound_enabled = true;
|
||||
int volume_level = 80; // 0-99
|
||||
uint32_t last_sound_time = 0;
|
||||
uint32_t min_sound_interval = 20; // Minimum ms between sounds
|
||||
|
||||
Button dummy{
|
||||
{screen_width, 0, 0, 0},
|
||||
""};
|
||||
|
||||
+75
-73
@@ -1,265 +1,267 @@
|
||||
set(EXTCPPSRC
|
||||
|
||||
#afsk_rx
|
||||
#afsk_rx 16 byte
|
||||
external/afsk_rx/main.cpp
|
||||
external/afsk_rx/ui_afsk_rx.cpp
|
||||
|
||||
#calculator
|
||||
#calculator 632 bytes
|
||||
external/calculator/main.cpp
|
||||
external/calculator/ui_calculator.cpp
|
||||
|
||||
#font_viewer
|
||||
#font_viewer 8 byte?!
|
||||
external/font_viewer/main.cpp
|
||||
external/font_viewer/ui_font_viewer.cpp
|
||||
|
||||
#blespam
|
||||
#blespam 336 bytes - array initializers?
|
||||
external/blespam/main.cpp
|
||||
external/blespam/ui_blespam.cpp
|
||||
|
||||
#analogtv
|
||||
#analogtv 552 bytes
|
||||
external/analogtv/main.cpp
|
||||
external/analogtv/analog_tv_app.cpp
|
||||
external/analogtv/ui_tv.cpp
|
||||
|
||||
#nrf_rx
|
||||
#nrf_rx 40 byte
|
||||
external/nrf_rx/main.cpp
|
||||
external/nrf_rx/ui_nrf_rx.cpp
|
||||
|
||||
#coasterp
|
||||
#coasterp 0 byte
|
||||
external/coasterp/main.cpp
|
||||
external/coasterp/ui_coasterp.cpp
|
||||
|
||||
#lge
|
||||
#lge 120 byte
|
||||
external/lge/main.cpp
|
||||
external/lge/lge_app.cpp
|
||||
external/lge/rfm69.cpp
|
||||
|
||||
#lcr
|
||||
#lcr - 460 byte flash
|
||||
external/lcr/main.cpp
|
||||
external/lcr/ui_lcr.cpp
|
||||
|
||||
#jammer
|
||||
#jammer 144 byte
|
||||
external/jammer/main.cpp
|
||||
external/jammer/ui_jammer.cpp
|
||||
|
||||
#gpssim
|
||||
#gpssim 160 byte
|
||||
external/gpssim/main.cpp
|
||||
external/gpssim/gps_sim_app.cpp
|
||||
|
||||
#spainter
|
||||
#spainter 464 byte
|
||||
external/spainter/main.cpp
|
||||
external/spainter/ui_spectrum_painter.cpp
|
||||
external/spainter/ui_spectrum_painter_text.cpp
|
||||
external/spainter/ui_spectrum_painter_image.cpp
|
||||
|
||||
#keyfob
|
||||
#keyfob 216 byte
|
||||
external/keyfob/main.cpp
|
||||
external/keyfob/ui_keyfob.cpp
|
||||
external/keyfob/ui_keyfob.hpp
|
||||
|
||||
#tetris
|
||||
#tetris 88 byte
|
||||
external/tetris/main.cpp
|
||||
external/tetris/ui_tetris.cpp
|
||||
|
||||
#extsensors
|
||||
|
||||
#extsensors 192 byte
|
||||
external/extsensors/main.cpp
|
||||
external/extsensors/ui_extsensors.cpp
|
||||
external/extsensors/ui_extsensors.hpp
|
||||
|
||||
#foxhunt
|
||||
#foxhunt 0
|
||||
external/foxhunt/main.cpp
|
||||
external/foxhunt/ui_foxhunt_rx.cpp
|
||||
external/foxhunt/ui_foxhunt_rx.hpp
|
||||
|
||||
#audio_test
|
||||
#audio_test 192 byte
|
||||
external/audio_test/main.cpp
|
||||
external/audio_test/ui_audio_test.cpp
|
||||
|
||||
#wardrivemap
|
||||
#wardrivemap 64 byte
|
||||
external/wardrivemap/main.cpp
|
||||
external/wardrivemap/ui_wardrivemap.cpp
|
||||
|
||||
#tpmsrx
|
||||
#tpmsrx 920 byte- possible shared part with baseband
|
||||
external/tpmsrx/main.cpp
|
||||
external/tpmsrx/tpms_app.cpp
|
||||
|
||||
#protoview
|
||||
#protoview 8 byte
|
||||
external/protoview/main.cpp
|
||||
external/protoview/ui_protoview.cpp
|
||||
|
||||
#adsbtx
|
||||
#adsbtx 3544 byte - adsb shared part
|
||||
external/adsbtx/main.cpp
|
||||
external/adsbtx/ui_adsb_tx.cpp
|
||||
|
||||
#morse_tx
|
||||
#morse_tx 768 bytes
|
||||
external/morse_tx/main.cpp
|
||||
external/morse_tx/ui_morse.cpp
|
||||
|
||||
#sstvtx
|
||||
#sstvtx 456 bytes
|
||||
external/sstvtx/main.cpp
|
||||
external/sstvtx/ui_sstvtx.cpp
|
||||
|
||||
#random
|
||||
#random 464 bytes.
|
||||
external/random_password/main.cpp
|
||||
external/random_password/ui_random_password.cpp
|
||||
external/random_password/sha512.cpp
|
||||
external/random_password/sha512.h
|
||||
|
||||
#acars
|
||||
external/acars_rx/main.cpp
|
||||
external/acars_rx/acars_app.cpp
|
||||
#external/acars_rx/main.cpp
|
||||
#external/acars_rx/acars_app.cpp
|
||||
|
||||
#wefax_rx
|
||||
#wefax_rx 192 bytes
|
||||
external/wefax_rx/main.cpp
|
||||
external/wefax_rx/ui_wefax_rx.cpp
|
||||
|
||||
|
||||
#noaaapt_rx
|
||||
#noaaapt_rx 72 bytes
|
||||
external/noaaapt_rx/main.cpp
|
||||
external/noaaapt_rx/ui_noaaapt_rx.cpp
|
||||
|
||||
|
||||
|
||||
#shoppingcart_lock
|
||||
#shoppingcart_lock 272 bytes
|
||||
external/shoppingcart_lock/main.cpp
|
||||
external/shoppingcart_lock/shoppingcart_lock.cpp
|
||||
|
||||
#ookbrute
|
||||
|
||||
#ookbrute 80 byte
|
||||
external/ookbrute/main.cpp
|
||||
external/ookbrute/ui_ookbrute.cpp
|
||||
|
||||
#ook_editor
|
||||
#ook_editor 1808 bytes
|
||||
external/ook_editor/main.cpp
|
||||
external/ook_editor/ui_ook_editor.cpp
|
||||
|
||||
#cvs_spam
|
||||
#cvs_spam 24 byte
|
||||
external/cvs_spam/main.cpp
|
||||
external/cvs_spam/cvs_spam.cpp
|
||||
|
||||
#flippertx
|
||||
#flippertx 712 bytes
|
||||
external/flippertx/main.cpp
|
||||
external/flippertx/ui_flippertx.cpp
|
||||
|
||||
#remote
|
||||
#remote 1664 bytes
|
||||
external/remote/main.cpp
|
||||
external/remote/ui_remote.cpp
|
||||
|
||||
#mcu_temperature
|
||||
#mcu_temperature 112
|
||||
external/mcu_temperature/main.cpp
|
||||
external/mcu_temperature/mcu_temperature.cpp
|
||||
|
||||
#fmradio
|
||||
#fmradio 640
|
||||
external/fmradio/main.cpp
|
||||
external/fmradio/ui_fmradio.cpp
|
||||
|
||||
#tuner
|
||||
#tuner 384
|
||||
external/tuner/main.cpp
|
||||
external/tuner/ui_tuner.cpp
|
||||
|
||||
#metronome
|
||||
#metronome 696 bytes
|
||||
external/metronome/main.cpp
|
||||
external/metronome/ui_metronome.cpp
|
||||
|
||||
#app_manager
|
||||
#app_manager 40 bytes
|
||||
external/app_manager/main.cpp
|
||||
external/app_manager/ui_app_manager.cpp
|
||||
|
||||
#hopper
|
||||
#hopper 472 bytes
|
||||
external/hopper/main.cpp
|
||||
external/hopper/ui_hopper.cpp
|
||||
|
||||
# whip calculator
|
||||
# whip calculator 48 bytes
|
||||
external/antenna_length/main.cpp
|
||||
external/antenna_length/ui_whipcalc.cpp
|
||||
|
||||
# wav viewer
|
||||
# wav viewer 1232 bytes
|
||||
external/wav_view/main.cpp
|
||||
external/wav_view/ui_view_wav.cpp
|
||||
|
||||
# wipe sdcard
|
||||
|
||||
# wipe sdcard 16 byte
|
||||
external/sd_wipe/main.cpp
|
||||
external/sd_wipe/ui_sd_wipe.cpp
|
||||
|
||||
# playlist editor
|
||||
# playlist editor 232 bytes
|
||||
external/playlist_editor/main.cpp
|
||||
external/playlist_editor/ui_playlist_editor.cpp
|
||||
|
||||
#snake
|
||||
#snake 240 bytes
|
||||
external/snake/main.cpp
|
||||
external/snake/ui_snake.cpp
|
||||
|
||||
#stopwatch
|
||||
|
||||
#stopwatch 0
|
||||
external/stopwatch/main.cpp
|
||||
external/stopwatch/ui_stopwatch.cpp
|
||||
|
||||
#breakout
|
||||
#breakout 1144 bytes
|
||||
external/breakout/main.cpp
|
||||
external/breakout/ui_breakout.cpp
|
||||
|
||||
#dinogame
|
||||
#dinogame 0
|
||||
external/dinogame/main.cpp
|
||||
external/dinogame/ui_dinogame.cpp
|
||||
|
||||
#doom
|
||||
#doom 224
|
||||
external/doom/main.cpp
|
||||
external/doom/ui_doom.cpp
|
||||
|
||||
#debug_pmem
|
||||
#debug_pmem 944 byte
|
||||
external/debug_pmem/main.cpp
|
||||
external/debug_pmem/ui_debug_pmem.cpp
|
||||
|
||||
#scanner
|
||||
#scanner 520 byte
|
||||
external/scanner/main.cpp
|
||||
external/scanner/ui_scanner.cpp
|
||||
|
||||
#level
|
||||
#level 24 byte
|
||||
external/level/main.cpp
|
||||
external/level/ui_level.cpp
|
||||
|
||||
#gfxEQ
|
||||
#gfxEQ 80 byte
|
||||
external/gfxeq/main.cpp
|
||||
external/gfxeq/ui_gfxeq.cpp
|
||||
|
||||
#detector_rx
|
||||
#detector_rx 168 byte
|
||||
external/detector_rx/main.cpp
|
||||
external/detector_rx/ui_detector_rx.cpp
|
||||
|
||||
#space_invaders
|
||||
#space_invaders 0 byte
|
||||
external/spaceinv/main.cpp
|
||||
external/spaceinv/ui_spaceinv.cpp
|
||||
|
||||
#blackjack
|
||||
#blackjack 24 byte
|
||||
external/blackjack/main.cpp
|
||||
external/blackjack/ui_blackjack.cpp
|
||||
|
||||
#battleship
|
||||
#battleship 256 byte
|
||||
external/battleship/main.cpp
|
||||
external/battleship/ui_battleship.cpp
|
||||
|
||||
#ert
|
||||
#ert 3040 bytes - has common with baseband, could be renamed the namespace, so both could have it, but not kept in fw.
|
||||
external/ert/main.cpp
|
||||
external/ert/ert_app.cpp
|
||||
|
||||
#epirb_rx
|
||||
#epirb_rx 168 byte flash
|
||||
external/epirb_rx/main.cpp
|
||||
external/epirb_rx/ui_epirb_rx.cpp
|
||||
|
||||
#soundboard
|
||||
#soundboard 272byte - 1236 bytes
|
||||
external/soundboard/main.cpp
|
||||
external/soundboard/soundboard_app.cpp
|
||||
|
||||
#game2048
|
||||
#game2048 - 168 byte flash
|
||||
external/game2048/main.cpp
|
||||
external/game2048/ui_game2048.cpp
|
||||
|
||||
#bht_tx
|
||||
#bht_tx - 3920 byte flash, unknown
|
||||
external/bht_tx/main.cpp
|
||||
external/bht_tx/ui_bht_tx.cpp
|
||||
external/bht_tx/bht.cpp
|
||||
|
||||
#morse_practice
|
||||
#morse_practice - 80 byte flash - bc of array initializers
|
||||
external/morse_practice/main.cpp
|
||||
external/morse_practice/ui_morse_practice.cpp
|
||||
|
||||
#adult_toys_controller
|
||||
#adult_toys_controller 144 bytes
|
||||
external/adult_toys_controller/main.cpp
|
||||
external/adult_toys_controller/ui_adult_toys_controller.cpp
|
||||
)
|
||||
@@ -269,8 +271,8 @@ set(EXTAPPLIST
|
||||
calculator
|
||||
font_viewer
|
||||
blespam
|
||||
nrf_rx
|
||||
analogtv
|
||||
nrf_rx
|
||||
coasterp
|
||||
lge
|
||||
lcr
|
||||
@@ -283,19 +285,19 @@ set(EXTAPPLIST
|
||||
foxhunt_rx
|
||||
audio_test
|
||||
wardrivemap
|
||||
cvs_spam
|
||||
tpmsrx
|
||||
protoview
|
||||
adsbtx
|
||||
morse_tx
|
||||
sstvtx
|
||||
random_password
|
||||
# acars_rx
|
||||
ookbrute
|
||||
ook_editor
|
||||
# acars_rx --not working
|
||||
wefax_rx
|
||||
noaaapt_rx
|
||||
shoppingcart_lock
|
||||
ookbrute
|
||||
ook_editor
|
||||
cvs_spam
|
||||
flippertx
|
||||
remote
|
||||
mcu_temperature
|
||||
|
||||
@@ -79,7 +79,7 @@ class FlipperTxView : public View {
|
||||
void on_tx_progress(const bool done);
|
||||
bool on_file_changed(std::filesystem::path new_file_path);
|
||||
|
||||
std::filesystem::path filename = {};
|
||||
std::filesystem::path filename = "";
|
||||
FlipperProto proto = FLIPPER_PROTO_UNSUPPORTED;
|
||||
FlipperPreset preset = FLIPPER_PRESET_UNK;
|
||||
uint16_t te = 0; // for binraw
|
||||
|
||||
@@ -41,7 +41,6 @@ gfxEQView::gfxEQView(NavigationView& nav)
|
||||
audio::set_rate(audio::Rate::Hz_48000);
|
||||
audio::output::start();
|
||||
receiver_model.set_headphone_volume(receiver_model.headphone_volume()); // WM8731 hack
|
||||
//
|
||||
receiver_model.enable();
|
||||
|
||||
receiver_model.set_target_frequency(frequency_value); // Retune to actual freq
|
||||
|
||||
+9
-7
@@ -46,6 +46,7 @@ class gfxEQView : public View {
|
||||
NavigationView& nav_;
|
||||
|
||||
uint32_t current_theme{0};
|
||||
|
||||
const std::array<ColorTheme, 20> themes{
|
||||
ColorTheme{Color(255, 0, 255), Color(255, 255, 255)},
|
||||
ColorTheme{Color(0, 255, 0), Color(255, 0, 0)},
|
||||
@@ -68,13 +69,14 @@ class gfxEQView : public View {
|
||||
ColorTheme{Color(64, 64, 64), Color(255, 0, 0)},
|
||||
ColorTheme{Color(255, 192, 0), Color(0, 64, 128)}};
|
||||
|
||||
ButtonWithEncoder button_frequency{{UI_POS_X(0), UI_POS_Y(0) + 4, 11 * 8, 1 * 8}, ""};
|
||||
RFAmpField field_rf_amp{{13 * 8, UI_POS_Y(0)}};
|
||||
LNAGainField field_lna{{15 * 8, UI_POS_Y(0)}};
|
||||
VGAGainField field_vga{{18 * 8, UI_POS_Y(0)}};
|
||||
Button button_mood{{21 * 8, 0, 6 * 8, 16}, "MOOD"};
|
||||
AudioVolumeField field_volume{{screen_width - 2 * 8, UI_POS_Y(0)}};
|
||||
GraphEq gr{{2, UI_POS_DEFAULT_HEIGHT, UI_POS_MAXWIDTH - 4, UI_POS_HEIGHT_REMAINING(2)}, false};
|
||||
// Widgets with positions using UI_POS macros
|
||||
ButtonWithEncoder button_frequency{{UI_POS_X(0), UI_POS_Y(0) + 4, UI_POS_WIDTH(11), UI_POS_HEIGHT(1)}, ""};
|
||||
RFAmpField field_rf_amp{{UI_POS_X(12), UI_POS_Y(0) + 4}};
|
||||
LNAGainField field_lna{{UI_POS_X(14), UI_POS_Y(0) + 4}};
|
||||
VGAGainField field_vga{{UI_POS_X(17), UI_POS_Y(0) + 4}};
|
||||
Button button_mood{{UI_POS_X(21), UI_POS_Y(0) + 4, UI_POS_WIDTH(4), UI_POS_HEIGHT(1)}, "MOOD"};
|
||||
AudioVolumeField field_volume{{UI_POS_X_RIGHT(2), UI_POS_Y(0) + 4}};
|
||||
GraphEq gr{{2, UI_POS_Y(1) + 8, UI_POS_MAXWIDTH, UI_POS_Y_BOTTOM(1) - 28}, false};
|
||||
|
||||
rf::Frequency frequency_value{93100000};
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
#include "crc.hpp"
|
||||
#include "portapack_shared_memory.hpp"
|
||||
|
||||
namespace ui::external_app::lge {
|
||||
|
||||
uint32_t RFM69::gen_frame(std::vector<uint8_t>& payload) {
|
||||
CRC<16> crc{0x1021, 0x1D0F, 0xFFFF};
|
||||
std::vector<uint8_t> frame{};
|
||||
@@ -74,3 +76,5 @@ uint32_t RFM69::gen_frame(std::vector<uint8_t>& payload) {
|
||||
// Copy for baseband
|
||||
return frame.size();
|
||||
}
|
||||
|
||||
} /* namespace ui::external_app::lge */
|
||||
@@ -28,6 +28,8 @@
|
||||
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace ui::external_app::lge {
|
||||
|
||||
class RFM69 {
|
||||
public:
|
||||
RFM69(const uint8_t num_preamble, const uint16_t sync_word, const bool CRC, const bool manchester)
|
||||
@@ -54,4 +56,6 @@ class RFM69 {
|
||||
bool manchester_{false};
|
||||
};
|
||||
|
||||
} /* namespace ui::external_app::lge */
|
||||
|
||||
#endif /*__RFM69_H__*/
|
||||
+1
-1
@@ -110,7 +110,7 @@ class MorseView : public View {
|
||||
bool run{false};
|
||||
|
||||
Labels labels{
|
||||
{{4 * 8, 6 * 8}, "Speed: wps", Theme::getInstance()->fg_light->foreground},
|
||||
{{4 * 8, 6 * 8}, "Speed: wpm", Theme::getInstance()->fg_light->foreground},
|
||||
{{4 * 8, 8 * 8}, "Tone: Hz", Theme::getInstance()->fg_light->foreground},
|
||||
{{4 * 8, 10 * 8}, "Modulation:", Theme::getInstance()->fg_light->foreground},
|
||||
{{4 * 8, 12 * 8}, "Loop:", Theme::getInstance()->fg_light->foreground},
|
||||
|
||||
@@ -231,7 +231,7 @@ void RandomPasswordView::on_data(uint32_t value, bool is_data) {
|
||||
}
|
||||
|
||||
void RandomPasswordView::clean_buffer() {
|
||||
seeds_deque = {};
|
||||
seeds_deque.clear();
|
||||
}
|
||||
|
||||
void RandomPasswordView::on_freqchg(int64_t freq) {
|
||||
@@ -247,6 +247,18 @@ void RandomPasswordView::set_random_freq() {
|
||||
field_frequency.set_value(random_freq);
|
||||
}
|
||||
|
||||
bool RandomPasswordView::islower(char c) {
|
||||
return (c >= 'a' && c <= 'z');
|
||||
}
|
||||
|
||||
bool RandomPasswordView::isupper(char c) {
|
||||
return (c >= 'A' && c <= 'Z');
|
||||
}
|
||||
|
||||
bool RandomPasswordView::isdigit(char c) {
|
||||
return (c >= '0' && c <= '9');
|
||||
}
|
||||
|
||||
void RandomPasswordView::new_password() {
|
||||
if (seeds_deque.size() < MAX_DIGITS * 2) {
|
||||
seeds_buffer_not_full = true;
|
||||
@@ -261,21 +273,21 @@ void RandomPasswordView::new_password() {
|
||||
int password_length = field_digits.value();
|
||||
|
||||
/// charset worker
|
||||
if (check_digits.value())
|
||||
charset += "0123456789";
|
||||
if (check_latin_lower.value())
|
||||
charset += "abcdefghijklmnopqrstuvwxyz";
|
||||
if (check_latin_upper.value())
|
||||
charset += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
if (check_digits.value()) {
|
||||
charset += "23456789";
|
||||
if (check_allow_confusable_chars.value()) charset += "01";
|
||||
}
|
||||
if (check_latin_lower.value()) {
|
||||
charset += "abcdefghijkmnpqrstuvwxyz";
|
||||
if (check_allow_confusable_chars.value()) charset += "ol";
|
||||
}
|
||||
if (check_latin_upper.value()) {
|
||||
charset += "ABCDEFGHIJKLMNPQRSTUVWXYZ";
|
||||
if (check_allow_confusable_chars.value()) charset += "O";
|
||||
}
|
||||
if (check_punctuation.value())
|
||||
charset += ".,-!?";
|
||||
|
||||
if (!check_allow_confusable_chars.value()) {
|
||||
charset.erase(std::remove_if(charset.begin(), charset.end(),
|
||||
[](char c) { return c == '0' || c == 'O' || c == 'o' || c == '1' || c == 'l'; }),
|
||||
charset.end());
|
||||
}
|
||||
|
||||
if (charset.empty()) {
|
||||
text_generated_passwd.set("generate failed,");
|
||||
text_char_type_hints.set("select at least 1 type");
|
||||
@@ -306,11 +318,11 @@ void RandomPasswordView::new_password() {
|
||||
/// hint text worker
|
||||
for (char c : password_chars) {
|
||||
password += c;
|
||||
if (std::isdigit(c)) {
|
||||
if (isdigit(c)) {
|
||||
char_type_hints += "1";
|
||||
} else if (std::islower(c)) {
|
||||
} else if (islower(c)) {
|
||||
char_type_hints += "a";
|
||||
} else if (std::isupper(c)) {
|
||||
} else if (isupper(c)) {
|
||||
char_type_hints += "A";
|
||||
} else {
|
||||
char_type_hints += ",";
|
||||
@@ -360,11 +372,11 @@ void RandomPasswordView::paint_password_hints() {
|
||||
for (size_t i = 0; i < password.length(); i++) {
|
||||
char c = password[i];
|
||||
Color color;
|
||||
if (std::isdigit(c)) {
|
||||
if (isdigit(c)) {
|
||||
color = Color::red();
|
||||
} else if (std::islower(c)) {
|
||||
} else if (islower(c)) {
|
||||
color = Color::green();
|
||||
} else if (std::isupper(c)) {
|
||||
} else if (isupper(c)) {
|
||||
color = Color::blue();
|
||||
} else {
|
||||
color = Color::white();
|
||||
@@ -379,8 +391,8 @@ void RandomPasswordView::paint_password_hints() {
|
||||
|
||||
std::string RandomPasswordView::generate_log_line() {
|
||||
std::string seeds_set = "";
|
||||
for (auto seed : seeds_deque) {
|
||||
seeds_set += std::to_string(seed);
|
||||
for (unsigned int seed : seeds_deque) {
|
||||
seeds_set += to_string_dec_uint(seed);
|
||||
seeds_set += " ";
|
||||
}
|
||||
std::string line = "\npassword=" + password +
|
||||
|
||||
@@ -92,6 +92,10 @@ class RandomPasswordView : public View {
|
||||
std::string generate_log_line();
|
||||
void paint_password_hints();
|
||||
|
||||
bool islower(char c);
|
||||
bool isupper(char c);
|
||||
bool isdigit(char c);
|
||||
|
||||
NavigationView& nav_;
|
||||
RxRadioState radio_state_{};
|
||||
app_settings::SettingsManager settings_{
|
||||
|
||||
@@ -114,7 +114,7 @@ Optional<capture_metadata> read_metadata_file(const fs::path& path) {
|
||||
}
|
||||
|
||||
bool parse_float_meta(std::string_view str, float& out_val) {
|
||||
out_val = {};
|
||||
out_val = 0.0f;
|
||||
|
||||
if (str.size() > max_parse_int_length)
|
||||
return false;
|
||||
|
||||
@@ -81,7 +81,7 @@ class AlphanumView : public TextEntryView {
|
||||
std::array<Button, 29> buttons{};
|
||||
|
||||
NewButton button_shift{
|
||||
{192, 214, screen_width / 5, 38},
|
||||
{screen_width - screen_width / 5, 214, screen_width / 5, 38},
|
||||
{},
|
||||
&bitmap_icon_shift,
|
||||
Theme::getInstance()->bg_dark->background,
|
||||
|
||||
@@ -769,9 +769,9 @@ 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 error_tile_pos) {
|
||||
void add_external_items(NavigationView& nav, app_location_t location, BtnGridView& grid, uint8_t error_tile_pos, bool show_error_tile ) {
|
||||
auto externalItems = ExternalItemsMenuLoader::load_external_items(location, nav);
|
||||
if (externalItems.empty()) {
|
||||
if (externalItems.empty() && show_error_tile) {
|
||||
grid.insert_item({"ExtAppErr",
|
||||
Theme::getInstance()->error_dark->foreground,
|
||||
nullptr,
|
||||
@@ -848,8 +848,7 @@ void TranceiversMenuView::on_populate() {
|
||||
add_items({{"..", Theme::getInstance()->fg_light->foreground, &bitmap_icon_previous, [this]() { nav_.pop(); }}});
|
||||
}
|
||||
add_apps(nav_, *this, TRX);
|
||||
// add_external_items(nav_, app_location_t::TRX, *this, return_icon ? 1 : 0);
|
||||
// this folder doesn't have external apps, comment to prevent pop the err msg.
|
||||
add_external_items(nav_, app_location_t::TRX, *this, return_icon ? 1 : 0, false); // this folder doesn't have external apps, so don't show error for it.
|
||||
// NB: when has external app someday, uncomment this.
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ using namespace sd_card;
|
||||
namespace ui {
|
||||
|
||||
void add_apps(NavigationView& nav, BtnGridView& grid, app_location_t loc);
|
||||
void add_external_items(NavigationView& nav, app_location_t location, BtnGridView& grid, uint8_t error_tile_pos);
|
||||
void add_external_items(NavigationView& nav, app_location_t location, BtnGridView& grid, uint8_t error_tile_pos, bool show_error_tile = true);
|
||||
bool verify_sdcard_format();
|
||||
|
||||
enum modal_t {
|
||||
|
||||
@@ -175,7 +175,7 @@ void RecordView::start() {
|
||||
|
||||
text_record_filename.set("");
|
||||
text_record_dropped.set("");
|
||||
trim_path = {};
|
||||
trim_path = "";
|
||||
|
||||
if (sampling_rate == 0) {
|
||||
return;
|
||||
@@ -348,7 +348,7 @@ void RecordView::trim_capture() {
|
||||
trim_ui.clear();
|
||||
}
|
||||
|
||||
trim_path = {};
|
||||
trim_path = "";
|
||||
}
|
||||
|
||||
void RecordView::on_gps(const GPSPosDataMessage* msg) {
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace i2cdev {
|
||||
bool I2cDev_BH1750::init(uint8_t addr_) {
|
||||
if (addr_ != I2CDEV_BH1750_ADDR_1) return false;
|
||||
addr = addr_;
|
||||
model = I2CDECMDL_BH1750;
|
||||
model = I2CDEVMDL_BH1750;
|
||||
query_interval = 3;
|
||||
|
||||
// power up
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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 "i2cdev_sht4x.hpp"
|
||||
|
||||
namespace i2cdev {
|
||||
|
||||
bool I2cDev_SHT4x::init(uint8_t addr_) {
|
||||
if (addr_ != I2CDEV_SHT4X_ADDR_1 && addr_ != I2CDEV_SHT4X_ADDR_2) return false;
|
||||
addr = addr_; // store the addr
|
||||
model = I2C_DEVMDL::I2CDEVMDL_SHT4X; // set the device model!!!!!!!!!!!!!!!!!!
|
||||
query_interval = 10; // set update interval in sec
|
||||
chThdSleepMilliseconds(50);
|
||||
uint8_t tmp[1]; // command buffer
|
||||
uint8_t rx[6]; // response buffer
|
||||
tmp[0] = SHT4X_SERIAL_NUMBER_CMD_ID;
|
||||
if (!i2c_write(nullptr, 0, tmp, 1)) return false; // get serial number
|
||||
chThdSleepMilliseconds(10);
|
||||
if (!i2c_read(nullptr, 0, rx, 6)) return false; // read serial number
|
||||
return true;
|
||||
}
|
||||
|
||||
void I2cDev_SHT4x::update() {
|
||||
float temp = 0;
|
||||
float hum = 0;
|
||||
uint8_t cmd[1];
|
||||
cmd[0] = SHT4X_MEASURE_MEDIUM_PRECISION_TICKS_CMD_ID;
|
||||
uint8_t res[6];
|
||||
if (!i2c_write(nullptr, 0, cmd, 1)) return;
|
||||
chThdSleepMilliseconds(5); // wait for measurement, 10 for high precision, 5 for medium, 2 for low
|
||||
if (!i2c_read(nullptr, 0, res, 6)) return;
|
||||
uint16_t temptick = (uint16_t)res[0] << 8 | (uint16_t)res[1];
|
||||
uint16_t humtick = (uint16_t)res[3] << 8 | (uint16_t)res[4];
|
||||
|
||||
temp = -45 + (((float)temptick * 175.0) / 65535.0);
|
||||
hum = -6 + 125.0 * (float)humtick / 65535.0;
|
||||
if (hum < 0) hum = 0;
|
||||
if (hum > 100) hum = 100;
|
||||
EnvironmentDataMessage msg{temp, hum}; // create the system message
|
||||
EventDispatcher::send_message(msg); // and send it
|
||||
}
|
||||
|
||||
} // namespace i2cdev
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2025 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.
|
||||
*/
|
||||
|
||||
#ifndef __I2CDEV_SHT4X_H__
|
||||
#define __I2CDEV_SHT4X_H__
|
||||
|
||||
#include "i2cdevmanager.hpp"
|
||||
|
||||
namespace i2cdev {
|
||||
|
||||
class I2cDev_SHT4x : public I2cDev {
|
||||
public:
|
||||
typedef enum {
|
||||
SHT4X_MEASURE_HIGH_PRECISION_TICKS_CMD_ID = 0xfd,
|
||||
SHT4X_MEASURE_MEDIUM_PRECISION_TICKS_CMD_ID = 0xf6,
|
||||
SHT4X_MEASURE_LOWEST_PRECISION_TICKS_CMD_ID = 0xe0,
|
||||
SHT4X_ACTIVATE_HIGHEST_HEATER_POWER_LONG_TICKS_CMD_ID = 0x39,
|
||||
SHT4X_ACTIVATE_HIGHEST_HEATER_POWER_SHORT_TICKS_CMD_ID = 0x32,
|
||||
SHT4X_ACTIVATE_MEDIUM_HEATER_POWER_LONG_TICKS_CMD_ID = 0x2f,
|
||||
SHT4X_ACTIVATE_MEDIUM_HEATER_POWER_SHORT_TICKS_CMD_ID = 0x24,
|
||||
SHT4X_ACTIVATE_LOWEST_HEATER_POWER_LONG_TICKS_CMD_ID = 0x1e,
|
||||
SHT4X_ACTIVATE_LOWEST_HEATER_POWER_SHORT_TICKS_CMD_ID = 0x15,
|
||||
SHT4X_SERIAL_NUMBER_CMD_ID = 0x89,
|
||||
SHT4X_SOFT_RESET_CMD_ID = 0x94,
|
||||
} SHT4xCmdId;
|
||||
bool init(uint8_t addr_) override; // sets the addr to our local variable, set the model, try to init the module, and only return true if it is really that module, and inited ok
|
||||
void update() override; // query the module for recent data, and send it to the system via the corresponding Message
|
||||
|
||||
private:
|
||||
float read_temperature();
|
||||
float read_humidity();
|
||||
};
|
||||
} // namespace i2cdev
|
||||
|
||||
#endif
|
||||
@@ -34,14 +34,18 @@ enum I2C_DEVMDL {
|
||||
I2CDEVMDL_SHT3X,
|
||||
I2CDEVMDL_BMP280,
|
||||
I2CDEVMDL_BME280,
|
||||
I2CDECMDL_BH1750,
|
||||
I2CDEVMDL_BH1750,
|
||||
I2CDECMDL_PPMOD,
|
||||
I2CDEVMDL_SHT4X,
|
||||
};
|
||||
|
||||
#define I2CDEV_BMX280_ADDR_1 0x76
|
||||
#define I2CDEV_BMX280_ADDR_2 0x77
|
||||
#define I2CDEV_SHT3X_ADDR_1 0x44
|
||||
#define I2CDEV_SHT3X_ADDR_2 0x45
|
||||
// sadly sht4x uses the same addr as sht3x, but the init script can decide which is which
|
||||
#define I2CDEV_SHT4X_ADDR_1 0x44
|
||||
#define I2CDEV_SHT4X_ADDR_2 0x45
|
||||
|
||||
#define I2CDEV_MAX17055_ADDR_1 0x36
|
||||
#define I2CDEV_ADS1110_ADDR_1 0x48
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "i2cdev_ads1110.hpp"
|
||||
#include "i2cdev_bh1750.hpp"
|
||||
#include "i2cdev_ppmod.hpp"
|
||||
#include "i2cdev_sht4x.hpp"
|
||||
|
||||
namespace i2cdev {
|
||||
|
||||
@@ -73,6 +74,11 @@ bool I2CDevManager::found(uint8_t addr) {
|
||||
if (!item.dev->init(addr)) item.dev = nullptr;
|
||||
}
|
||||
|
||||
if (!item.dev && (addr == I2CDEV_SHT4X_ADDR_1 || addr == I2CDEV_SHT4X_ADDR_2)) {
|
||||
item.dev = std::make_unique<I2cDev_SHT4x>();
|
||||
if (!item.dev->init(addr)) item.dev = nullptr;
|
||||
}
|
||||
|
||||
if (!item.dev && (addr == I2CDEV_MAX17055_ADDR_1)) {
|
||||
item.dev = std::make_unique<I2cDev_MAX17055>();
|
||||
if (!item.dev->init(addr)) item.dev = nullptr;
|
||||
|
||||
@@ -148,7 +148,7 @@ struct standalone_application_information_t {
|
||||
void (*shutdown)();
|
||||
|
||||
void (*PaintViewMirror)();
|
||||
void (*OnTouchEvent)(int x, int y, uint32_t type);
|
||||
bool (*OnTouchEvent)(int x, int y, uint32_t type);
|
||||
void (*OnFocus)();
|
||||
bool (*OnKeyEvent)(uint8_t key);
|
||||
bool (*OnEncoder)(int32_t delta);
|
||||
|
||||
@@ -77,7 +77,7 @@ ui::Widget* touch_widget(ui::Widget* const w, ui::TouchEvent event) {
|
||||
|
||||
ui::Widget* captured_widget{nullptr};
|
||||
|
||||
void OnTouchEvent(int, int, uint32_t) {
|
||||
bool OnTouchEvent(int, int, uint32_t) {
|
||||
if (standaloneViewMirror) {
|
||||
_api->exit_app();
|
||||
/* //left here for example, but not used in digital rain
|
||||
@@ -96,6 +96,7 @@ void OnTouchEvent(int, int, uint32_t) {
|
||||
captured_widget->on_touch(event);
|
||||
*/
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void OnFocus() {
|
||||
|
||||
@@ -40,7 +40,7 @@ void shutdown();
|
||||
void OnFocus();
|
||||
bool OnKeyEvent(uint8_t);
|
||||
bool OnEncoder(int32_t);
|
||||
void OnTouchEvent(int, int, uint32_t);
|
||||
bool OnTouchEvent(int, int, uint32_t);
|
||||
bool OnKeyboad(uint8_t);
|
||||
void PaintViewMirror();
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "pacman.hpp"
|
||||
#include <memory>
|
||||
|
||||
void notouch(int, int, uint32_t) {
|
||||
bool notouch(int, int, uint32_t) {
|
||||
// do nothing
|
||||
}
|
||||
void nothing() {
|
||||
|
||||
Reference in New Issue
Block a user