mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-08-21 15:09:03 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b19ed5fec5 | |||
| 419bc75d2f | |||
| b3a0ad018c | |||
| a21e9ca1af | |||
| 20f45e88f3 | |||
| 967506fb97 | |||
| 24ab2f29fa |
+20
-7
@@ -23,6 +23,8 @@ cmake_policy(SET CMP0005 NEW)
|
||||
|
||||
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/firmware/toolchain-arm-cortex-m.cmake)
|
||||
|
||||
option(USE_CCACHE "Enable ccache, please keep an eye on this because sometimes it's not quite stable and generated unusable binary" OFF)
|
||||
|
||||
project(portapack-h1)
|
||||
|
||||
set(EXPECTED_GCC_VERSION "9.2.1")
|
||||
@@ -72,13 +74,24 @@ set(HACKRF_CPLD_XSVF_PATH ${HACKRF_PATH}/firmware/cpld/sgpio_if/${HACKRF_CPLD_XS
|
||||
set(HACKRF_FIRMWARE_DFU_IMAGE ${hackrf_usb_BINARY_DIR}/${HACKRF_FIRMWARE_DFU_FILENAME})
|
||||
set(HACKRF_FIRMWARE_BIN_IMAGE ${hackrf_usb_BINARY_DIR}/${HACKRF_FIRMWARE_BIN_FILENAME})
|
||||
|
||||
# this seems causing some issues (ref. in discord discussions), so temporarily disabled, until figure out the pros and cons and bugs of this tool.
|
||||
#find_program(CCACHE "ccache")
|
||||
#if(CCACHE)
|
||||
# set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE})
|
||||
# set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE})
|
||||
# set(ENV{CCACHE_SLOPPINESS} pch_defines,time_macros)
|
||||
#endif(CCACHE)
|
||||
# this seems causing some issues (ref. in discord discussions), but it sometimes do helps, so you have your choice to use. it's default disabled, unless you use such command:
|
||||
# cmake -DUSE_CCACHE=ON ..
|
||||
# `make` or `make -j` or `make -j10` etc
|
||||
# the default behavior `cmake ..` isn't changed (aka don't use ccache)
|
||||
message(STATUS "-------v ccache info--------")
|
||||
if(USE_CCACHE)
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
if(CCACHE_FOUND)
|
||||
set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_FOUND})
|
||||
set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_FOUND})
|
||||
message(STATUS "Using ccache, please keep an eye on this because sometimes it's not quite stable and generated unusable binary.\n-- use `cmake -DUSE_CCACHE=OFF ..` to turn off ccache")
|
||||
else()
|
||||
message(WARNING "ccache is enabled but not found on the system.")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Not using ccache, use `cmake -DUSE_CCACHE=ON ..` to turn on ccache")
|
||||
endif()
|
||||
message(STATUS "-------^ ccache info--------")
|
||||
|
||||
enable_testing()
|
||||
add_subdirectory(firmware)
|
||||
|
||||
@@ -35,6 +35,8 @@ using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
|
||||
#define FILE_PER_PAGE 50
|
||||
|
||||
bool SoundBoardView::is_active() const {
|
||||
return (bool)replay_thread;
|
||||
}
|
||||
@@ -178,9 +180,9 @@ void SoundBoardView::refresh_list() {
|
||||
if ((reader->channels() == 1) && ((reader->bits_per_sample() == 8) || (reader->bits_per_sample() == 16))) {
|
||||
// sounds[c].ms_duration = reader->ms_duration();
|
||||
// sounds[c].path = u"WAV/" + entry.path().native();
|
||||
if (count >= (page - 1) * 100 && count < page * 100) {
|
||||
if (count >= (page - 1) * FILE_PER_PAGE && count < page * FILE_PER_PAGE) {
|
||||
file_list.push_back(entry.path());
|
||||
if (file_list.size() == 100) {
|
||||
if (file_list.size() == FILE_PER_PAGE) {
|
||||
page++;
|
||||
break;
|
||||
}
|
||||
@@ -225,7 +227,7 @@ void SoundBoardView::refresh_list() {
|
||||
menu_view.set_highlighted(0); // Refresh
|
||||
}
|
||||
|
||||
if (file_list.size() < 100) {
|
||||
if (file_list.size() < FILE_PER_PAGE) {
|
||||
page = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,6 @@ rf::Frequency GlassView::get_freq_from_bin_pos(uint8_t pos) {
|
||||
freq_at_pos = f_center_ini + ((pos - 120) * ((looking_glass_range - ((16 * looking_glass_range) / SPEC_NB_BINS)) / 2)) / (SCREEN_W / 2);
|
||||
} else
|
||||
freq_at_pos = f_min + (2 * offset * each_bin_size) + (pos * looking_glass_range) / SCREEN_W;
|
||||
|
||||
return freq_at_pos;
|
||||
}
|
||||
|
||||
@@ -257,7 +256,7 @@ void GlassView::on_range_changed() {
|
||||
bin_length = SCREEN_W;
|
||||
ignore_dc = 0;
|
||||
looking_glass_bandwidth = looking_glass_range;
|
||||
looking_glass_sampling_rate = looking_glass_bandwidth;
|
||||
looking_glass_sampling_rate = looking_glass_range;
|
||||
each_bin_size = looking_glass_bandwidth / SCREEN_W;
|
||||
looking_glass_step = looking_glass_bandwidth;
|
||||
f_center_ini = f_min + (looking_glass_bandwidth / 2); // Initial center frequency for sweep
|
||||
@@ -265,7 +264,7 @@ void GlassView::on_range_changed() {
|
||||
// view is made in multiple pass, use original bin picking
|
||||
mode = scan_type.selected_index_value();
|
||||
looking_glass_bandwidth = LOOKING_GLASS_SLICE_WIDTH_MAX;
|
||||
looking_glass_sampling_rate = LOOKING_GLASS_SLICE_WIDTH_MAX;
|
||||
looking_glass_sampling_rate = LOOKING_GLASS_MAX_SAMPLERATE;
|
||||
each_bin_size = LOOKING_GLASS_SLICE_WIDTH_MAX / SPEC_NB_BINS;
|
||||
if (mode == LOOKING_GLASS_FASTSCAN) {
|
||||
offset = 2;
|
||||
@@ -315,8 +314,8 @@ void GlassView::update_min(int32_t v) {
|
||||
int32_t min_size = steps;
|
||||
if (locked_range)
|
||||
min_size = search_span;
|
||||
if (min_size < 2)
|
||||
min_size = 2;
|
||||
if (min_size < 1)
|
||||
min_size = 1;
|
||||
if (v > 7200 - min_size) {
|
||||
v = 7200 - min_size;
|
||||
}
|
||||
@@ -332,8 +331,8 @@ void GlassView::update_max(int32_t v) {
|
||||
int32_t min_size = steps;
|
||||
if (locked_range)
|
||||
min_size = search_span;
|
||||
if (min_size < 2)
|
||||
min_size = 2;
|
||||
if (min_size < 1)
|
||||
min_size = 1;
|
||||
if (v < min_size) {
|
||||
v = min_size;
|
||||
}
|
||||
@@ -487,7 +486,12 @@ GlassView::GlassView(
|
||||
range_presets.set_selected_index(preset_index);
|
||||
|
||||
field_marker.on_encoder_change = [this](TextField&, EncoderEvent delta) {
|
||||
marker_pixel_index = clip<uint8_t>(marker_pixel_index + delta, 0, SCREEN_W);
|
||||
if ((marker_pixel_index + delta) < 0)
|
||||
marker_pixel_index = marker_pixel_index + delta + SCREEN_W;
|
||||
else if ((marker_pixel_index + delta) > SCREEN_W)
|
||||
marker_pixel_index = marker_pixel_index + delta - SCREEN_W;
|
||||
else
|
||||
marker_pixel_index = marker_pixel_index + delta;
|
||||
on_marker_change();
|
||||
};
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
namespace ui {
|
||||
|
||||
#define LOOKING_GLASS_SLICE_WIDTH_MAX 20000000
|
||||
#define LOOKING_GLASS_MAX_SAMPLERATE 20000000
|
||||
#define MHZ_DIV 1000000
|
||||
|
||||
// blanked DC (16 centered bins ignored ) and top left and right (2 bins ignored on each side )
|
||||
|
||||
+41
-15
@@ -1,6 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2017 Furrtek
|
||||
* Copyright (C) 2024 HTotoo, zxkmm
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
@@ -49,10 +48,12 @@ ProtoView::ProtoView(NavigationView& nav)
|
||||
&field_vga,
|
||||
&field_volume,
|
||||
&field_frequency,
|
||||
&labels,
|
||||
&label_zoom,
|
||||
&label_shift,
|
||||
&options_zoom,
|
||||
&number_shift,
|
||||
&button_reset,
|
||||
&button_pause,
|
||||
&waveform,
|
||||
&waveform2,
|
||||
&waveform3,
|
||||
@@ -72,6 +73,10 @@ ProtoView::ProtoView(NavigationView& nav)
|
||||
button_reset.on_select = [this](Button&) {
|
||||
reset();
|
||||
};
|
||||
button_pause.on_select = [this](Button&) {
|
||||
set_pause(!paused);
|
||||
};
|
||||
set_pause(false); // need to use this to default hide shift functionality
|
||||
baseband::set_subghzd_config(0, receiver_model.sampling_rate());
|
||||
audio::set_rate(audio::Rate::Hz_24000);
|
||||
audio::output::start();
|
||||
@@ -80,6 +85,7 @@ ProtoView::ProtoView(NavigationView& nav)
|
||||
|
||||
void ProtoView::reset() {
|
||||
cnt = 0;
|
||||
set_pause(false);
|
||||
number_shift.set_value(0);
|
||||
waveform_shift = 0;
|
||||
for (uint16_t i = 0; i < MAXSIGNALBUFFER; i++) time_buffer[i] = 0;
|
||||
@@ -134,19 +140,20 @@ void ProtoView::draw() {
|
||||
drawcnt = 0;
|
||||
for (uint16_t i = 0; i < MAXDRAWCNT; i++) waveform_buffer[i] = 0; // reset
|
||||
|
||||
// add empty data for padding (so you can shift left/nagetive)
|
||||
for (int32_t i = 0;
|
||||
i < ((waveform_shift > 0) ? 0 : -waveform_shift) && drawcnt < MAXDRAWCNT; // this is for shift nagetive (left side)
|
||||
++i) {
|
||||
waveform_buffer[drawcnt++] = 0;
|
||||
// add empty data for padding (so you can shift left/negative)
|
||||
if (waveform_shift < 0) {
|
||||
for (int32_t i = 0; (i < -1 * waveform_shift) && drawcnt < MAXDRAWCNT; // this is for shift negative (move to right)
|
||||
++i) {
|
||||
waveform_buffer[drawcnt++] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint16_t i = ((waveform_shift < 0) ? -waveform_shift : 0); // this is for shift positive aka right side
|
||||
i < MAXSIGNALBUFFER && drawcnt < MAXDRAWCNT; // prevent out of ranging
|
||||
uint16_t skipped = 0;
|
||||
uint16_t to_skip = ((waveform_shift > 0) ? waveform_shift : 0); // when >0 it'll skip some to move left
|
||||
for (uint16_t i = 0;
|
||||
i < MAXSIGNALBUFFER && drawcnt < MAXDRAWCNT; // prevent out of ranging
|
||||
++i) {
|
||||
uint16_t buffer_index = (i + waveform_shift + MAXSIGNALBUFFER) % MAXSIGNALBUFFER;
|
||||
state = time_buffer[buffer_index] >= 0;
|
||||
int32_t timeabs = state ? time_buffer[buffer_index] : -1 * time_buffer[buffer_index];
|
||||
state = time_buffer[i] >= 0;
|
||||
int32_t timeabs = state ? time_buffer[i] : -1 * time_buffer[i];
|
||||
int32_t timesize = timeabs / zoom;
|
||||
if (timesize == 0) {
|
||||
remain += timeabs;
|
||||
@@ -164,7 +171,11 @@ void ProtoView::draw() {
|
||||
remain = 0;
|
||||
lmax = 0;
|
||||
for (int32_t ii = 0; ii < timesize && drawcnt < MAXDRAWCNT; ++ii) {
|
||||
waveform_buffer[drawcnt++] = state;
|
||||
if (skipped < to_skip) {
|
||||
skipped++;
|
||||
} else {
|
||||
waveform_buffer[drawcnt++] = state;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -175,6 +186,7 @@ void ProtoView::add_time(int32_t time) {
|
||||
}
|
||||
|
||||
void ProtoView::on_data(const ProtoViewDataMessage* message) {
|
||||
if (paused) return;
|
||||
// filter out invalid ones.
|
||||
uint16_t start = 0;
|
||||
uint16_t stop = 0;
|
||||
@@ -207,6 +219,20 @@ void ProtoView::on_freqchg(int64_t freq) {
|
||||
field_frequency.set_value(freq);
|
||||
}
|
||||
|
||||
void ProtoView::set_pause(bool pause) {
|
||||
paused = pause;
|
||||
if (pause) {
|
||||
label_shift.hidden(false);
|
||||
number_shift.hidden(false);
|
||||
button_pause.set_text(LanguageHelper::currentMessages[LANG_RESUME]);
|
||||
} else {
|
||||
label_shift.hidden(true);
|
||||
number_shift.hidden(true);
|
||||
button_pause.set_text(LanguageHelper::currentMessages[LANG_PAUSE]);
|
||||
}
|
||||
set_dirty();
|
||||
}
|
||||
|
||||
ProtoView::~ProtoView() {
|
||||
audio::output::stop();
|
||||
receiver_model.disable();
|
||||
|
||||
+12
-3
@@ -74,8 +74,11 @@ class ProtoView : public View {
|
||||
RxFrequencyField field_frequency{
|
||||
{0 * 8, 0 * 16},
|
||||
nav_};
|
||||
Labels labels{
|
||||
{{0 * 8, 1 * 16}, "Zoom: ", Theme::getInstance()->fg_light->foreground},
|
||||
|
||||
// need to seperate because label shift need to hide independently
|
||||
Labels label_zoom{
|
||||
{{0 * 8, 1 * 16}, "Zoom: ", Theme::getInstance()->fg_light->foreground}};
|
||||
Labels label_shift{
|
||||
{{0 * 8, 2 * 16}, "Shift: ", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
OptionsField options_zoom{
|
||||
@@ -103,6 +106,10 @@ class ProtoView : public View {
|
||||
{screen_width - 12 * 8, 1 * 16, 96, 24},
|
||||
LanguageHelper::currentMessages[LANG_RESET]};
|
||||
|
||||
Button button_pause{
|
||||
{screen_width - 12 * 8, 1 * 16 + 24, 96, 24},
|
||||
LanguageHelper::currentMessages[LANG_PAUSE]};
|
||||
|
||||
Waveform waveform{
|
||||
{0, 8 * 8, 240, 50},
|
||||
waveform_buffer,
|
||||
@@ -136,6 +143,7 @@ class ProtoView : public View {
|
||||
Theme::getInstance()->fg_yellow->foreground};
|
||||
|
||||
bool needCntReset = false;
|
||||
bool paused = false;
|
||||
|
||||
int16_t zoom = 1; // one value in ms
|
||||
int16_t waveform_shift = 0;
|
||||
@@ -151,6 +159,7 @@ class ProtoView : public View {
|
||||
void on_data(const ProtoViewDataMessage* message);
|
||||
void draw();
|
||||
void draw2();
|
||||
void set_pause(bool pause);
|
||||
void reset();
|
||||
|
||||
MessageHandlerRegistration message_handler_packet{
|
||||
@@ -178,4 +187,4 @@ class ProtoView : public View {
|
||||
|
||||
} // namespace ui::external_app::protoview
|
||||
|
||||
#endif /*__UI_PROTOVIEW_H__*/
|
||||
#endif /*__UI_PROTOVIEW_H__*/
|
||||
|
||||
@@ -722,8 +722,8 @@ void NavigationView::update_view() {
|
||||
auto top_view = top.view.get();
|
||||
|
||||
add_child(top_view);
|
||||
top_view->set_parent_rect({{0, 0}, size()});
|
||||
|
||||
auto newSize = (is_top()) ? Size{size().width(), size().height() - 16} : size(); // if top(), then there is the info bar at the bottom, so leave space for it
|
||||
top_view->set_parent_rect({{0, 0}, newSize});
|
||||
focus();
|
||||
set_dirty();
|
||||
|
||||
@@ -996,17 +996,48 @@ void BMPView::focus() {
|
||||
button_done.focus();
|
||||
}
|
||||
|
||||
BMPView::BMPView(NavigationView& nav) {
|
||||
BMPView::BMPView(NavigationView& nav)
|
||||
: nav_(nav) {
|
||||
add_children({&button_done});
|
||||
|
||||
button_done.on_select = [this, &nav](Button&) {
|
||||
nav.pop();
|
||||
button_done.on_select = [this](Button&) {
|
||||
handle_pop();
|
||||
};
|
||||
}
|
||||
|
||||
void BMPView::paint(Painter&) {
|
||||
if (!portapack::display.drawBMP2({0, 0}, splash_dot_bmp))
|
||||
portapack::display.drawBMP({(240 - 230) / 2, (320 - 50) / 2 - 10}, splash_bmp, true);
|
||||
portapack::display.drawBMP({(240 - 230) / 2, (320 - 50) / 2 - 10}, splash_bmp, (const uint8_t[]){0x29, 0x18, 0x16});
|
||||
}
|
||||
|
||||
bool BMPView::on_touch(const TouchEvent event) {
|
||||
/* the event thing were resolved by HTotoo, talked here https://discord.com/channels/719669764804444213/956561375155589192/1287756910950486027
|
||||
* the touch screen policy can be better, talked here https://discord.com/channels/719669764804444213/956561375155589192/1198926225897443328
|
||||
*/
|
||||
|
||||
if (!nav_.is_valid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (event.type) {
|
||||
case TouchEvent::Type::Start:
|
||||
return true;
|
||||
|
||||
case TouchEvent::Type::End:
|
||||
handle_pop();
|
||||
return true;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void BMPView::handle_pop() {
|
||||
if (nav_.is_valid()) {
|
||||
nav_.pop();
|
||||
}
|
||||
}
|
||||
|
||||
/* NotImplementedView ****************************************************/
|
||||
@@ -1072,7 +1103,7 @@ ModalMessageView::ModalMessageView(
|
||||
}
|
||||
|
||||
void ModalMessageView::paint(Painter& painter) {
|
||||
if (!compact) portapack::display.drawBMP({100, 48}, modal_warning_bmp, true);
|
||||
if (!compact) portapack::display.drawBMP({100, 48}, modal_warning_bmp, (const uint8_t[]){0, 0, 0});
|
||||
|
||||
// Break lines.
|
||||
auto lines = split_string(message_, '\n');
|
||||
|
||||
@@ -343,7 +343,11 @@ class BMPView : public View {
|
||||
void paint(Painter&) override;
|
||||
void focus() override;
|
||||
|
||||
bool on_touch(const TouchEvent event) override;
|
||||
void handle_pop();
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
Button button_done{
|
||||
{240, 0, 1, 1},
|
||||
""};
|
||||
|
||||
@@ -344,7 +344,20 @@ void ILI9341::render_box(const ui::Point p, const ui::Size s, const ui::Color* l
|
||||
}
|
||||
|
||||
// RLE_4 BMP loader (delta not implemented)
|
||||
void ILI9341::drawBMP(const ui::Point p, const uint8_t* bitmap, const bool transparency) {
|
||||
/* draw transparent, pass transparent color as arg, usage inline anonymous obj
|
||||
* portapack::display.drawBMP({100, 100}, foo_bmp, (const uint8_t[]){41, 24, 22}); // dec, out of {255, 255, 255}
|
||||
* portapack::display.drawBMP({100, 100}, foo_bmp, (const uint8_t[]){0x29, 0x18, 0x16}); //hex out of {0xFF, 0xFF, 0xFF}
|
||||
*
|
||||
* draw transparent, pass transparent color as arg, usage pass uint8_t[] obj
|
||||
* const uint8_t c[] = {41, 24, 22}; or const uint8_t c[3] = {0x29, 0x18, 0x16};
|
||||
* portapack::display.drawBMP({100, 100}, foo_bmp, c);
|
||||
*
|
||||
* don't draw transparent, pass nullptr as arg, usage
|
||||
* portapack::display.drawBMP({100, 100}, foo_bmp, nullptr);
|
||||
*
|
||||
* if your image use RLE compress as transparency methods, pass any valid color as arg, it doesn't matter (like the modal bmp. TODO: write RLE transparency generator)
|
||||
* */
|
||||
void ILI9341::drawBMP(const ui::Point p, const uint8_t* bitmap, const uint8_t* transparency_color) {
|
||||
const bmp_header_t* bmp_header = (const bmp_header_t*)bitmap;
|
||||
uint32_t data_idx;
|
||||
uint8_t by, c, count, transp_idx = 0;
|
||||
@@ -362,12 +375,13 @@ void ILI9341::drawBMP(const ui::Point p, const uint8_t* bitmap, const bool trans
|
||||
// Convert palette and find pure magenta index (alpha color key) rgb dec(41,24,22)
|
||||
for (c = 0; c < 16; c++) {
|
||||
palette[c] = ui::Color(bmp_palette->color[c].R, bmp_palette->color[c].G, bmp_palette->color[c].B);
|
||||
if ((bmp_palette->color[c].R == 0x29) &&
|
||||
(bmp_palette->color[c].G == 0x18) &&
|
||||
(bmp_palette->color[c].B == 0x16)) transp_idx = c;
|
||||
if (transparency_color &&
|
||||
(bmp_palette->color[c].R == transparency_color[0]) &&
|
||||
(bmp_palette->color[c].G == transparency_color[1]) &&
|
||||
(bmp_palette->color[c].B == transparency_color[2])) transp_idx = c;
|
||||
}
|
||||
|
||||
if (!transparency) {
|
||||
if (!transparency_color) {
|
||||
py = bmp_header->height + 16;
|
||||
do {
|
||||
by = bitmap[data_idx++];
|
||||
|
||||
@@ -62,7 +62,7 @@ class ILI9341 {
|
||||
const ui::Color background);
|
||||
|
||||
void draw_pixel(const ui::Point p, const ui::Color color);
|
||||
void drawBMP(const ui::Point p, const uint8_t* bitmap, const bool transparency);
|
||||
void drawBMP(const ui::Point p, const uint8_t* bitmap, const uint8_t* transparency_color);
|
||||
bool drawBMP2(const ui::Point p, const std::filesystem::path& file);
|
||||
void render_line(const ui::Point p, const uint8_t count, const ui::Color* line_buffer);
|
||||
void render_box(const ui::Point p, const ui::Size s, const ui::Color* line_buffer);
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#include "ui_language.hpp"
|
||||
|
||||
const char* LanguageHelper::englishMessages[] = {"OK", "Cancel", "Error", "Modem setup", "Debug", "Log", "Done", "Start", "Stop", "Scan", "Clear", "Ready", "Data:", "Loop", "Reset"};
|
||||
// use the exact position in this array! the enum's value is the identifier. Best to add to the end
|
||||
const char* LanguageHelper::englishMessages[] = {"OK", "Cancel", "Error", "Modem setup", "Debug", "Log", "Done", "Start", "Stop", "Scan", "Clear", "Ready", "Data:", "Loop", "Reset", "Pause", "Resume"};
|
||||
|
||||
// multi language support will changes (not in use for now)
|
||||
const char** LanguageHelper::currentMessages = englishMessages;
|
||||
|
||||
void LanguageHelper::setLanguage(LanguageList lang) {
|
||||
|
||||
@@ -1,10 +1,43 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
The purpose of this: when creating an ext app it's address will be changed. But the compiler doesn't know this, so when it optimizes literals it can remove something from one ext app, that is included in the other, to save space.
|
||||
But when we want to run this app, it won't find the literal at the fake address, so the best case we'll get just garbage or nothing instead of the string.
|
||||
So we must use this Language helper that stores the literals in the fw instead of any ext app, so it'll be always available.
|
||||
In the first run we must move those string literal here what are not so unique, like "OK".
|
||||
*/
|
||||
|
||||
#ifndef __UI_LANGUAGE_H__
|
||||
#define __UI_LANGUAGE_H__
|
||||
|
||||
// For future multi language support
|
||||
enum LanguageList {
|
||||
ENGLISH,
|
||||
};
|
||||
|
||||
// Add an element to this enum when you fill a new value.
|
||||
// Then add the string literal to the LanguageHelper::englishMessages at the exact position where the enum points to (usualy to the end)
|
||||
|
||||
enum LangConsts {
|
||||
LANG_OK,
|
||||
LANG_CANCEL,
|
||||
@@ -20,12 +53,14 @@ enum LangConsts {
|
||||
LANG_READY,
|
||||
LANG_DATADP,
|
||||
LANG_LOOP,
|
||||
LANG_RESET
|
||||
LANG_RESET,
|
||||
LANG_PAUSE,
|
||||
LANG_RESUME
|
||||
};
|
||||
|
||||
class LanguageHelper {
|
||||
public:
|
||||
static void setLanguage(LanguageList lang);
|
||||
static void setLanguage(LanguageList lang); // changes the pointer to the currently used language literal container. not used yet.
|
||||
static const char* getMessage(LangConsts msg);
|
||||
static const char** currentMessages; // expose, so can link directly too
|
||||
|
||||
|
||||
Reference in New Issue
Block a user