Compare commits

...

11 Commits

Author SHA1 Message Date
jLynx c2279e297c Stable v1.7.3 (#1224)
* Update past_version.txt

* Update version.txt
2023-06-30 20:45:20 +12:00
Mark Thompson cdd524b9f3 Use a common function for finding Tone Key index from received Tone Frequency (#1218)
* Common function for finding CTCSS tone index from freq
2023-06-30 07:37:43 +02:00
Kyle Reed 99809c7919 Consolidate anti_alias BW selection into function (#1217) 2023-06-30 07:35:35 +02:00
Kyle Reed 2390d79111 Fix up Waterfall control names (#1219) 2023-06-30 07:34:19 +02:00
Kyle Reed 3b41d73ddd Remove LTO, minor UI tweaks (#1216) 2023-06-30 07:33:33 +02:00
gullradriel 3d46c28911 fix build (#1215)
* fix build

* fixing build integrationg zoom

---------

Co-authored-by: GullCode <gullradriel@hotmail.com>
2023-06-29 13:58:10 -07:00
Kyle Reed ca7840557b Change how scrolling works, add home/end (#1212)
Conflicts fixed by gull
2023-06-29 22:17:31 +02:00
Mark Thompson ceaa115025 Revert color of "SD over USB" icon back to yellow (#1210) 2023-06-29 22:13:33 +02:00
Mark Thompson 8dbcefbc75 Move initializer from .hpp -> .cpp file (#1213) 2023-06-29 22:07:39 +02:00
Mark Thompson b28b96fb4a Notepad text zoom support 5x8 to 8x16 font (#1211)
* Zoom button 5/8 to 8/16 font

* Zoom button 5/8 to 8/16 font

* Clang & revert unintended change

* Suggested improvements

* Suggested code changes

* Added char_width function

* Added char_width function

* Oops copy-paste error

* Delete added blank line
2023-06-29 10:55:25 -07:00
Stupid retard noob attention king e15a8ed2d8 improve keyboard (#1209)
* init commit for raw input in keyboard

* clean up

* clean up - 1

* clean up - 2

* can input underline and < now

* format fix

* textual change

* textual change - 2

* textual change - 3

* textual change - 4

* edit for PR comment

* edit for PR comment - 2

* edit for PR comment - 3

* edit for PR comment - 4

* edit for PR comment - 5
2023-06-29 09:24:18 -07:00
29 changed files with 268 additions and 298 deletions
+1 -1
View File
@@ -1 +1 @@
v1.7.1
v1.7.2
+1 -1
View File
@@ -1 +1 @@
v1.7.2
v1.7.3
+1 -1
View File
@@ -44,7 +44,7 @@ if(cpp20_supported)
else()
set(USE_CPPOPT "-std=c++17")
endif()
set(USE_CPPOPT "${USE_CPPOPT} -flto -fno-rtti -fno-exceptions -Weffc++ -Wuninitialized -Wno-volatile")
set(USE_CPPOPT "${USE_CPPOPT} -fno-rtti -fno-exceptions -Weffc++ -Wuninitialized -Wno-volatile")
# Enable this if you want the linker to remove unused code and data
set(USE_LINK_GC yes)
+3 -16
View File
@@ -404,22 +404,9 @@ void AnalogAudioView::update_modulation(ReceiverModel::Mode modulation) {
}
void AnalogAudioView::handle_coded_squelch(uint32_t value) {
float diff, min_diff = value;
size_t min_idx{0};
size_t c;
// Find nearest match
for (c = 0; c < tone_keys.size(); c++) {
diff = abs(((float)value / 100.0) - tone_keys[c].second);
if (diff < min_diff) {
min_idx = c;
min_diff = diff;
}
}
// Arbitrary confidence threshold
if (min_diff < 40)
text_ctcss.set("CTCSS " + tone_keys[min_idx].first);
tone_index idx = tone_key_index_by_value(value);
if (idx >= 0)
text_ctcss.set("CTCSS " + tone_key_string(idx));
else
text_ctcss.set("???");
}
@@ -213,7 +213,7 @@ class AnalogAudioView : public View {
4096,
4};
spectrum::WaterfallWidget waterfall{true};
spectrum::WaterfallView waterfall{true};
void on_baseband_bandwidth_changed(uint32_t bandwidth_hz);
void on_modulation_changed(ReceiverModel::Mode modulation);
+2 -35
View File
@@ -60,41 +60,8 @@ CaptureAppView::CaptureAppView(NavigationView& nav)
/* ex. recording 500kHz BW to .C16 file, base_rate clock 500kHz x2(I,Q) x 2 bytes (int signed) =2MB/sec rate SD Card */
waterfall.on_hide();
/* Set up proper anti aliasing BPF bandwith in MAX2837 before ADC sampling according to the new added BW Options . */
switch (sampling_rate) { // we use the var fs (sampling_rate) , to set up BPF aprox < fs_max/2 by Nyquist theorem.
case 0 ... 2000000: // BW Captured range (0 <= 250kHz max ) fs = 8 x 250 kHz
anti_alias_baseband_bandwidth_filter = 1750000; // Minimum BPF MAX2837 for all those lower BW options.
break;
case 4000000 ... 6000000: // BW capture range (500k ... 750kHz max ) fs_max = 8 x 750kHz = 6Mhz
// BW 500k ... 750kHz , ex. 500kHz (fs = 8*BW = 4Mhz) , BW 600kHz (fs = 4,8Mhz) , BW 750 kHz (fs = 6Mhz)
anti_alias_baseband_bandwidth_filter = 2500000; // in some IC MAX2837 appear 2250000 , but both works similar.
break;
case 8800000: // BW capture 1,1Mhz fs = 8 x 1,1Mhz = 8,8Mhz . (1Mhz showed slightly higher noise background).
anti_alias_baseband_bandwidth_filter = 3500000;
break;
case 14000000: // BW capture 1,75Mhz , fs = 8 x 1,75Mhz = 14Mhz
// good BPF, good matching, but LCD making flicker , refresh rate should be < 20 Hz , but reasonable picture
anti_alias_baseband_bandwidth_filter = 5000000;
break;
case 16000000: // BW capture 2Mhz , fs = 8 x 2Mhz = 16Mhz
// good BPF, good matching, but LCD making flicker , refresh rate should be < 20 Hz , but reasonable picture
anti_alias_baseband_bandwidth_filter = 6000000;
break;
case 20000000: // BW capture 2,5Mhz , fs= 8 x 2,5 Mhz = 20Mhz
// good BPF, good matching, but LCD making flicker , refresh rate should be < 20 Hz , but reasonable picture
anti_alias_baseband_bandwidth_filter = 7000000;
break;
default: // BW capture 2,75Mhz, fs = 8 x 2,75Mhz= 22Mhz max ADC sampling) and others.
// We tested also 9Mhz FPB stightly too much noise floor, better 8Mhz
anti_alias_baseband_bandwidth_filter = 8000000;
}
/* Set up proper anti aliasing BPF bandwith in MAX2837 before ADC sampling according to the new added BW Options. */
auto anti_alias_baseband_bandwidth_filter = filter_bandwidth_for_sampling_rate(sampling_rate);
record_view.set_sampling_rate(sampling_rate);
receiver_model.set_sampling_rate(sampling_rate);
+1 -2
View File
@@ -56,7 +56,6 @@ class CaptureAppView : public View {
app_settings::Options::UseGlobalTargetFrequency};
uint32_t sampling_rate = 0;
uint32_t anti_alias_baseband_bandwidth_filter = 2500000;
Labels labels{
{{0 * 8, 1 * 16}, "Rate:", Color::light_grey()},
@@ -97,7 +96,7 @@ class CaptureAppView : public View {
16384,
3};
spectrum::WaterfallWidget waterfall{};
spectrum::WaterfallView waterfall{};
};
} /* namespace ui */
+1 -1
View File
@@ -124,7 +124,7 @@ class GpsSimAppView : public View {
Color::green(),
Color::black()};
spectrum::WaterfallWidget waterfall{};
spectrum::WaterfallView waterfall{};
MessageHandlerRegistration message_handler_replay_thread_error{
Message::ID::ReplayThreadDone,
+1 -1
View File
@@ -121,7 +121,7 @@ class ReplayAppView : public View {
Color::green(),
Color::black()};
spectrum::WaterfallWidget waterfall{};
spectrum::WaterfallView waterfall{};
MessageHandlerRegistration message_handler_replay_thread_error{
Message::ID::ReplayThreadDone,
@@ -32,7 +32,7 @@ class SpectrumAnalysisModel {
namespace ui {
class SpectrumAnalysisView : public spectrum::WaterfallWidget {
class SpectrumAnalysisView : public spectrum::WaterfallView {
public:
private:
SpectrumAnalysisModel model;
@@ -40,7 +40,7 @@ class FlashUtilityView : public View {
void focus() override;
std::string title() const override { return "FlashUtility"; }; // Removed the space because the title and speaker icon overlapped.
std::string title() const override { return "Flash Utility"; };
private:
NavigationView& nav_;
+13 -51
View File
@@ -205,34 +205,7 @@ size_t LevelView::change_mode(freqman_index_t new_mod) {
receiver_model.set_modulation(ReceiverModel::Mode::Capture);
field_bw.set_by_value(0);
field_bw.on_change = [this](size_t, OptionsField::value_t sampling_rate) {
uint32_t anti_alias_baseband_bandwidth_filter = 2500000;
switch (sampling_rate) { // we use the var fs (sampling_rate) , to set up BPF aprox < fs_max/2 by Nyquist theorem.
case 0 ... 2000000: // BW Captured range (0 <= 250kHz max ) fs = 8 x 250 kHz
anti_alias_baseband_bandwidth_filter = 1750000; // Minimum BPF MAX2837 for all those lower BW options.
break;
case 4000000 ... 6000000: // BW capture range (500k ... 750kHz max ) fs_max = 8 x 750kHz = 6Mhz
// BW 500k ... 750kHz , ex. 500kHz (fs = 8*BW = 4Mhz) , BW 600kHz (fs = 4,8Mhz) , BW 750 kHz (fs = 6Mhz)
anti_alias_baseband_bandwidth_filter = 2500000; // in some IC MAX2837 appear 2250000 , but both works similar.
break;
case 8800000: // BW capture 1,1Mhz fs = 8 x 1,1Mhz = 8,8Mhz . (1Mhz showed slightly higher noise background).
anti_alias_baseband_bandwidth_filter = 3500000;
break;
case 14000000: // BW capture 1,75Mhz , fs = 8 x 1,75Mhz = 14Mhz
// good BPF, good matching, but LCD making flicker , refresh rate should be < 20 Hz , but reasonable picture
anti_alias_baseband_bandwidth_filter = 5000000;
break;
case 16000000: // BW capture 2Mhz , fs = 8 x 2Mhz = 16Mhz
// good BPF, good matching, but LCD making flicker , refresh rate should be < 20 Hz , but reasonable picture
anti_alias_baseband_bandwidth_filter = 6000000;
break;
case 20000000: // BW capture 2,5Mhz , fs= 8 x 2,5 Mhz = 20Mhz
// good BPF, good matching, but LCD making flicker , refresh rate should be < 20 Hz , but reasonable picture
anti_alias_baseband_bandwidth_filter = 7000000;
break;
default: // BW capture 2,75Mhz, fs = 8 x 2,75Mhz= 22Mhz max ADC sampling) and others.
// We tested also 9Mhz FPB stightly too much noise floor, better 8Mhz
anti_alias_baseband_bandwidth_filter = 8000000;
}
auto anti_alias_baseband_bandwidth_filter = filter_bandwidth_for_sampling_rate(sampling_rate);
receiver_model.set_sampling_rate(sampling_rate);
receiver_model.set_baseband_bandwidth(anti_alias_baseband_bandwidth_filter);
};
@@ -243,34 +216,23 @@ size_t LevelView::change_mode(freqman_index_t new_mod) {
}
void LevelView::handle_coded_squelch(const uint32_t value) {
static int32_t last_idx = -1;
static tone_index last_squelch_index = -1;
float diff, min_diff = value;
size_t min_idx{0};
size_t c;
if (field_mode.selected_index() == NFM_MODULATION) {
tone_index idx = tone_key_index_by_value(value);
if (field_mode.selected_index() != NFM_MODULATION) {
text_ctcss.set(" ");
return;
}
// Find nearest match
for (c = 0; c < tone_keys.size(); c++) {
diff = abs(((float)value / 100.0) - tone_keys[c].second);
if (diff < min_diff) {
min_idx = c;
min_diff = diff;
if ((last_squelch_index < 0) || (last_squelch_index != idx)) {
last_squelch_index = idx;
if (idx >= 0) {
text_ctcss.set("T: " + tone_key_string(idx));
return;
}
} else {
return;
}
}
// Arbitrary confidence threshold
if (last_idx < 0 || (unsigned)last_idx != min_idx) {
last_idx = min_idx;
if (min_diff < 40)
text_ctcss.set("T: " + tone_keys[min_idx].first);
else
text_ctcss.set(" ");
}
text_ctcss.set(" ");
}
} /* namespace ui */
@@ -63,7 +63,7 @@ class GlassView : public View {
GlassView& operator=(const GlassView& nav);
~GlassView();
std::string title() const override { return "LookingGlass"; };
std::string title() const override { return "Looking Glass"; };
void on_show() override;
void on_hide() override;
+8 -3
View File
@@ -118,11 +118,16 @@ class PlaylistView : public View {
Text text_sample_rate{
{10 * 8, 1 * 16, 7 * 8, 16}};
/*v making there's 1px line (instead of two) between two progress bars,
* by letting 1px overlapped.
* So, since they overlapped 1px, they are visually same, and looks better.
*/
ProgressBar progressbar_track{
{18 * 8, 1 * 16, 12 * 8, 8}};
{18 * 8, 1 * 16, 12 * 8, 8 + 1}};
ProgressBar progressbar_transmit{
{18 * 8, 3 * 8, 12 * 8, 8}};
{18 * 8, 3 * 8 - 1, 12 * 8, 8}};
Text text_duration{
{0 * 8, 2 * 16, 5 * 8, 16}};
@@ -183,7 +188,7 @@ class PlaylistView : public View {
&bitmap_icon_save,
Color::dark_blue()};
spectrum::WaterfallWidget waterfall{};
spectrum::WaterfallView waterfall{};
MessageHandlerRegistration message_handler_replay_thread_error{
Message::ID::ReplayThreadDone,
+13 -52
View File
@@ -1399,34 +1399,7 @@ size_t ReconView::change_mode(freqman_index_t new_mod) {
receiver_model.set_modulation(ReceiverModel::Mode::Capture);
field_bw.set_by_value(0);
field_bw.on_change = [this](size_t, OptionsField::value_t sampling_rate) {
uint32_t anti_alias_baseband_bandwidth_filter = 2500000;
switch (sampling_rate) { // we use the var fs (sampling_rate) , to set up BPF aprox < fs_max/2 by Nyquist theorem.
case 0 ... 2000000: // BW Captured range (0 <= 250kHz max ) fs = 8 x 250 kHz
anti_alias_baseband_bandwidth_filter = 1750000; // Minimum BPF MAX2837 for all those lower BW options.
break;
case 4000000 ... 6000000: // BW capture range (500k ... 750kHz max ) fs_max = 8 x 750kHz = 6Mhz
// BW 500k ... 750kHz , ex. 500kHz (fs = 8*BW = 4Mhz) , BW 600kHz (fs = 4,8Mhz) , BW 750 kHz (fs = 6Mhz)
anti_alias_baseband_bandwidth_filter = 2500000; // in some IC MAX2837 appear 2250000 , but both works similar.
break;
case 8800000: // BW capture 1,1Mhz fs = 8 x 1,1Mhz = 8,8Mhz . (1Mhz showed slightly higher noise background).
anti_alias_baseband_bandwidth_filter = 3500000;
break;
case 14000000: // BW capture 1,75Mhz , fs = 8 x 1,75Mhz = 14Mhz
// good BPF, good matching, but LCD making flicker , refresh rate should be < 20 Hz , but reasonable picture
anti_alias_baseband_bandwidth_filter = 5000000;
break;
case 16000000: // BW capture 2Mhz , fs = 8 x 2Mhz = 16Mhz
// good BPF, good matching, but LCD making flicker , refresh rate should be < 20 Hz , but reasonable picture
anti_alias_baseband_bandwidth_filter = 6000000;
break;
case 20000000: // BW capture 2,5Mhz , fs= 8 x 2,5 Mhz = 20Mhz
// good BPF, good matching, but LCD making flicker , refresh rate should be < 20 Hz , but reasonable picture
anti_alias_baseband_bandwidth_filter = 7000000;
break;
default: // BW capture 2,75Mhz, fs = 8 x 2,75Mhz= 22Mhz max ADC sampling) and others.
// We tested also 9Mhz FPB stightly too much noise floor, better 8Mhz
anti_alias_baseband_bandwidth_filter = 8000000;
}
auto anti_alias_baseband_bandwidth_filter = filter_bandwidth_for_sampling_rate(sampling_rate);
record_view->set_sampling_rate(sampling_rate);
receiver_model.set_sampling_rate(sampling_rate);
receiver_model.set_baseband_bandwidth(anti_alias_baseband_bandwidth_filter);
@@ -1453,32 +1426,20 @@ size_t ReconView::change_mode(freqman_index_t new_mod) {
}
void ReconView::handle_coded_squelch(const uint32_t value) {
float diff{0.0};
float min_diff{(float)value};
size_t min_idx{0};
size_t c{0};
if (field_mode.selected_index() == NFM_MODULATION) {
tone_index idx = tone_key_index_by_value(value);
if (field_mode.selected_index() != NFM_MODULATION) {
text_ctcss.set(" ");
return;
}
// Find nearest match
for (c = 0; c < tone_keys.size(); c++) {
diff = abs(((float)value / 100.0) - tone_keys[c].second);
if (diff < min_diff) {
min_idx = c;
min_diff = diff;
if ((last_squelch_index < 0) || (last_squelch_index != idx)) {
last_squelch_index = idx;
if (idx >= 0) {
text_ctcss.set("T: " + tone_key_string(idx));
return;
}
} else {
return;
}
}
// Arbitrary confidence threshold
if (last_squelch_index < 0 || (unsigned)last_squelch_index != min_idx) {
last_squelch_index = min_idx;
if (min_diff < 40)
text_ctcss.set("T: " + tone_keys[min_idx].first);
else
text_ctcss.set(" ");
}
text_ctcss.set(" ");
}
} /* namespace ui */
+1 -1
View File
@@ -139,7 +139,7 @@ class ReconView : public View {
int8_t last_rssi_med{-127};
int8_t last_rssi_max{-127};
int32_t last_index{-1};
int32_t last_squelch_index{-1};
tone_index last_squelch_index{-1};
int64_t last_freq{0};
std::string freq_file_path{};
systime_t chrono_start{};
+43 -28
View File
@@ -42,10 +42,9 @@ namespace ui {
/* TextViewer *******************************************************/
TextViewer::TextViewer(Rect parent_rect)
: Widget(parent_rect),
max_line{static_cast<uint8_t>(parent_rect.height() / char_height)},
max_col{static_cast<uint8_t>(parent_rect.width() / char_width)} {
: Widget(parent_rect) {
set_focusable(true);
set_font_zoom(false);
}
void TextViewer::paint(Painter& painter) {
@@ -138,6 +137,16 @@ uint32_t TextViewer::offset() const {
return 0;
}
void TextViewer::cursor_home() {
cursor_.col = 0;
redraw();
}
void TextViewer::cursor_end() {
cursor_.col = line_length() - 1;
redraw();
}
uint16_t TextViewer::line_length() {
return file_->line_length(cursor_.line);
}
@@ -158,18 +167,14 @@ bool TextViewer::apply_scrolling_constraints(int16_t delta_line, int16_t delta_c
++new_line;
}
// Snap to first/last to make navigating easier.
if (new_line < 0 && new_col > 0) {
// Snap to first/last line to make navigating easier.
if (new_line < 0 && cursor_.line > 0) {
new_line = 0;
new_col = 0;
} else if (new_line >= (int32_t)file_->line_count()) {
auto last_line = file_->line_count() - 1;
int32_t last_col = file_->line_length(last_line) - 1;
if (new_col < last_col) {
if (cursor_.line < last_line)
new_line = last_line;
new_col = last_col;
}
}
if (new_line < 0 || (uint32_t)new_line >= file_->line_count())
@@ -177,7 +182,6 @@ bool TextViewer::apply_scrolling_constraints(int16_t delta_line, int16_t delta_c
new_line_length = file_->line_length(new_line);
// TODO: don't wrap with encoder?
// Wrap or clamp column.
if (new_line_length == 0)
new_col = 0;
@@ -207,7 +211,7 @@ void TextViewer::paint_text(Painter& painter, uint32_t line, uint16_t col) {
if (result && *result > 0)
painter.draw_string(
{0, r.top() + (int)i * char_height},
Styles::white_small, {buffer, *result});
style(), {buffer, *result});
// Clear empty line sections. This is less visually jarring than full clear.
int32_t clear_width = max_col - (result ? *result : 0);
@@ -216,7 +220,7 @@ void TextViewer::paint_text(Painter& painter, uint32_t line, uint16_t col) {
{(max_col - clear_width) * char_width,
r.top() + (int)i * char_height,
clear_width * char_width, char_height},
Styles::white_small.background);
style().background);
}
}
@@ -237,8 +241,8 @@ void TextViewer::paint_cursor(Painter& painter) {
};
// Clear old cursor. CONSIDER: XOR cursor?
draw_cursor(paint_state_.line, paint_state_.col, Styles::white_small.background);
draw_cursor(cursor_.line, cursor_.col, Styles::white_small.foreground);
draw_cursor(paint_state_.line, paint_state_.col, style().background);
draw_cursor(cursor_.line, cursor_.col, style().foreground);
paint_state_.line = cursor_.line;
paint_state_.col = cursor_.col;
}
@@ -252,6 +256,15 @@ void TextViewer::reset_file(FileWrapper* file) {
redraw(true);
}
void TextViewer::set_font_zoom(bool zoom) {
font_zoom = zoom;
font_style = font_zoom ? &Styles::white : &Styles::white_small;
char_height = style().font.line_height();
char_width = style().font.char_width();
max_line = (uint8_t)(parent_rect().height() / char_height);
max_col = (uint8_t)(parent_rect().width() / char_width);
}
/* TextEditorMenu ***************************************************/
TextEditorMenu::TextEditorMenu()
@@ -259,9 +272,9 @@ TextEditorMenu::TextEditorMenu()
add_children(
{
&rect_frame,
&button_cut,
&button_paste,
&button_copy,
&button_home,
&button_end,
&button_zoom,
&button_delline,
&button_edit,
&button_addline,
@@ -310,14 +323,20 @@ TextEditorView::TextEditorView(NavigationView& nav)
};
menu.hidden(true);
menu.on_cut() = [this]() {
show_nyi();
menu.on_home() = [this]() {
viewer.cursor_home();
hide_menu(true);
};
menu.on_paste() = [this]() {
show_nyi();
menu.on_end() = [this]() {
viewer.cursor_end();
hide_menu(true);
};
menu.on_copy() = [this]() {
show_nyi();
menu.on_zoom() = [this]() {
viewer.toggle_font_zoom();
refresh_ui();
hide_menu(true);
};
menu.on_delete_line() = [this]() {
@@ -490,10 +509,6 @@ void TextEditorView::show_edit_line() {
});
}
void TextEditorView::show_nyi() {
nav_.display_modal("Soon...", "Coming soon.");
}
void TextEditorView::show_save_prompt(std::function<void()> continuation) {
if (!file_dirty_) {
if (continuation)
+27 -22
View File
@@ -72,15 +72,23 @@ class TextViewer : public Widget {
uint32_t col() const { return cursor_.col; }
uint32_t offset() const;
void cursor_home();
void cursor_end();
// Gets the length of the current line.
uint16_t line_length();
private:
static constexpr int8_t char_width = 5;
static constexpr int8_t char_height = 8;
const Style& style() { return *font_style; }
void set_font_zoom(bool zoom);
void toggle_font_zoom() { set_font_zoom(!font_zoom); };
const uint8_t max_line = 32;
const uint8_t max_col = 48;
private:
bool font_zoom{};
const Style* font_style{};
int8_t char_width{};
int8_t char_height{};
uint8_t max_line{};
uint8_t max_col{};
/* Returns true if the cursor was updated. */
bool apply_scrolling_constraints(
@@ -120,14 +128,12 @@ class TextEditorMenu : public View {
void on_show() override;
void on_hide() override;
std::function<void()>& on_cut() { return button_cut.on_select; }
std::function<void()>& on_paste() { return button_paste.on_select; }
std::function<void()>& on_copy() { return button_copy.on_select; }
std::function<void()>& on_home() { return button_home.on_select; }
std::function<void()>& on_end() { return button_end.on_select; }
std::function<void()>& on_zoom() { return button_zoom.on_select; }
std::function<void()>& on_delete_line() { return button_delline.on_select; }
std::function<void()>& on_edit_line() { return button_edit.on_select; }
std::function<void()>& on_add_line() { return button_addline.on_select; }
std::function<void()>& on_open() { return button_open.on_select; }
std::function<void()>& on_save() { return button_save.on_select; }
std::function<void()>& on_exit() { return button_exit.on_select; }
@@ -139,23 +145,23 @@ class TextEditorMenu : public View {
{0 * 8, 0 * 8, 23 * 8, 23 * 8},
Color::dark_grey()};
NewButton button_cut{
NewButton button_home{
{1 * 8, 1 * 8, 7 * 8, 7 * 8},
"Cut",
&bitmap_icon_cut,
"Home",
&bitmap_arrow_left,
Color::dark_grey()};
NewButton button_paste{
NewButton button_end{
{8 * 8, 1 * 8, 7 * 8, 7 * 8},
"Paste",
&bitmap_icon_paste,
"End",
&bitmap_arrow_right,
Color::dark_grey()};
NewButton button_copy{
NewButton button_zoom{
{15 * 8, 1 * 8, 7 * 8, 7 * 8},
"Copy",
&bitmap_icon_copy,
Color::dark_grey()};
"Zoom",
&bitmap_icon_search,
Color::orange()};
NewButton button_delline{
{1 * 8, 8 * 8, 7 * 8, 7 * 8},
@@ -220,7 +226,6 @@ class TextEditorView : public View {
void hide_menu(bool hidden = true);
void show_file_picker(bool immediate = true);
void show_edit_line();
void show_nyi();
void show_save_prompt(std::function<void()> continuation);
void prepare_for_write();
@@ -258,4 +263,4 @@ class TextEditorView : public View {
} // namespace ui
#endif // __UI_TEXT_EDITOR_H__
#endif // __UI_TEXT_EDITOR_H__
+33 -8
View File
@@ -73,9 +73,9 @@ const tone_key_t tone_keys = {
{"34 M3", 218.100},
{"35 M4", 225.700},
{"49 9Z", 229.100},
{"36 --", 233.600},
{"37 --", 241.800},
{"38 --", 250.300},
{"36 M5", 233.600},
{"37 M6", 241.800},
{"38 M7", 250.300},
{"50 0Z", 254.100},
{"Axient 28kHz", 28000.0},
{"Senn. 32.768k", 32768.0},
@@ -113,6 +113,36 @@ std::string tone_key_string(tone_index index) {
return tone_keys[index].first;
}
std::string tone_key_string_by_value(uint32_t value) {
return tone_key_string(tone_key_index_by_value(value));
}
tone_index tone_key_index_by_value(uint32_t value) {
float diff;
float min_diff{(float)value};
float fvalue{(float)((min_diff + 50.0) / 100.0)};
tone_index min_idx{-1};
tone_index idx;
// Find nearest match
for (idx = 0; idx < (tone_index)tone_keys.size(); idx++) {
diff = abs(fvalue - tone_keys[idx].second);
if (diff < min_diff) {
min_idx = idx;
min_diff = diff;
} else {
// list is sorted in frequency order; if diff is getting larger than we've passed it
break;
}
}
// Arbitrary confidence threshold
if (min_diff < 40.0)
return min_idx;
else
return -1;
}
tone_index tone_key_index_by_string(char* str) {
if (!str)
return -1;
@@ -123,9 +153,4 @@ tone_index tone_key_index_by_string(char* str) {
return -1;
}
/* tone_index tone_key_index_by_value( int32_t freq )
{
return -1 ;
} */
} // namespace tonekey
+3 -3
View File
@@ -30,7 +30,7 @@ using namespace ui;
namespace tonekey {
typedef int16_t tone_index;
typedef int32_t tone_index;
using tone_key_t = std::vector<std::pair<std::string, float>>;
@@ -40,8 +40,8 @@ void tone_keys_populate(OptionsField& field);
float tone_key_frequency(const tone_index index);
std::string tone_key_string(const tone_index index);
tone_index tone_key_index_by_string(char* str);
// tone_index tone_key_index_by_value( int32_t freq );
std::string tone_key_string_by_value(uint32_t value);
tone_index tone_key_index_by_value(uint32_t value);
} // namespace tonekey
+17 -8
View File
@@ -37,9 +37,13 @@ AlphanumView::AlphanumView(
: TextEntryView(nav, str, max_length) {
size_t n;
add_children({&button_mode,
&text_raw,
&field_raw});
add_children({
&labels,
&field_raw,
&text_raw_to_char,
&button_delete,
&button_mode,
});
const auto button_fn = [this](Button& button) {
this->on_button(button);
@@ -65,10 +69,19 @@ AlphanumView::AlphanumView(
set_mode(mode + 1);
};
button_delete.on_select = [this](Button&) {
char_delete();
};
field_raw.set_value('0');
field_raw.on_select = [this](NumberField&) {
char_add(field_raw.value());
};
// make text_raw_to_char widget display the char value from field_raw
field_raw.on_change = [this](auto) {
text_raw_to_char.set(std::string{static_cast<char>(field_raw.value())});
};
}
void AlphanumView::set_mode(const uint32_t new_mode) {
@@ -96,11 +109,7 @@ void AlphanumView::set_mode(const uint32_t new_mode) {
void AlphanumView::on_button(Button& button) {
const auto c = button.text()[0];
if (c == '<')
char_delete();
else
char_add(c);
char_add(c);
}
bool AlphanumView::on_encoder(const EncoderEvent delta) {
+20 -15
View File
@@ -43,14 +43,14 @@ class AlphanumView : public TextEntryView {
bool on_encoder(const EncoderEvent delta) override;
private:
const char* const keys_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ, .<";
const char* const keys_lower = "abcdefghijklmnopqrstuvwxyz, .<";
const char* const keys_digit = "0123456789!\"#'()*+-/:;=>?@[\\]<";
const char* const keys_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ, ._";
const char* const keys_lower = "abcdefghijklmnopqrstuvwxyz, ._";
const char* const keys_digit = "0123456789!\"#'()*+-/:;=<>@[\\]?";
const std::pair<std::string, const char*> key_sets[3] = {
{"Upper", keys_upper},
{"Lower", keys_lower},
{"Digit", keys_digit}};
{"ABC", keys_upper},
{"abc", keys_lower},
{"123", keys_digit}};
int16_t focused_button = 0;
uint32_t mode = 0; // Uppercase
@@ -60,13 +60,10 @@ class AlphanumView : public TextEntryView {
std::array<Button, 30> buttons{};
Button button_mode{
{21 * 8, 33 * 8, 8 * 8, 32},
""};
Labels labels{
{{1 * 8, 33 * 8}, "Raw:", Color::light_grey()},
{{1 * 8, 35 * 8}, "AKA:", Color::light_grey()}};
Text text_raw{
{1 * 8, 33 * 8, 4 * 8, 16},
"Raw:"};
NumberField field_raw{
{5 * 8, 33 * 8},
3,
@@ -74,9 +71,17 @@ class AlphanumView : public TextEntryView {
1,
'0'};
Button button_ok{
{10 * 8, 33 * 8, 9 * 8, 32},
"OK"};
Text text_raw_to_char{
{5 * 8, 35 * 8, 4 * 8, 16},
"0"};
Button button_delete{
{9 * 8, 33 * 8, 6 * 8, 32},
"<DEL"};
Button button_mode{
{16 * 8, 33 * 8, 5 * 8, 32},
""};
};
} /* namespace ui */
+53 -30
View File
@@ -36,7 +36,7 @@ using namespace portapack;
namespace ui {
namespace spectrum {
/* AudioSpectrumView******************************************************/
/* AudioSpectrumView ******************************************************/
AudioSpectrumView::AudioSpectrumView(
const Rect parent_rect)
@@ -247,28 +247,25 @@ void FrequencyScale::on_tick_second() {
_blink = !_blink;
}
/* WaterfallView *********************************************************/
/* WaterfallWidget *********************************************************/
// TODO: buffer and use "paint" instead of immediate drawing would help with
// preventing flicker from drawing. Would use more RAM however.
void WaterfallView::on_show() {
void WaterfallWidget::on_show() {
clear();
const auto screen_r = screen_rect();
display.scroll_set_area(screen_r.top(), screen_r.bottom());
}
void WaterfallView::on_hide() {
void WaterfallWidget::on_hide() {
/* TODO: Clear region to eliminate brief flash of content at un-shifted
* position?
*/
display.scroll_disable();
}
void WaterfallView::paint(Painter& painter) {
// Do nothing.
(void)painter;
}
void WaterfallView::on_channel_spectrum(
void WaterfallWidget::on_channel_spectrum(
const ChannelSpectrum& spectrum) {
/* TODO: static_assert that message.spectrum.db.size() >= pixel_row.size() */
@@ -290,16 +287,16 @@ void WaterfallView::on_channel_spectrum(
pixel_row);
}
void WaterfallView::clear() {
void WaterfallWidget::clear() {
display.fill_rectangle(
screen_rect(),
Color::black());
}
/* WaterfallWidget *******************************************************/
/* WaterfallView *******************************************************/
WaterfallWidget::WaterfallWidget(const bool cursor) {
add_children({&waterfall_view,
WaterfallView::WaterfallView(const bool cursor) {
add_children({&waterfall_widget,
&frequency_scale});
frequency_scale.set_focusable(cursor);
@@ -310,17 +307,17 @@ WaterfallWidget::WaterfallWidget(const bool cursor) {
};
}
void WaterfallWidget::on_show() {
void WaterfallView::on_show() {
// TODO: Assert that baseband is not shutdown.
baseband::spectrum_streaming_start();
}
void WaterfallWidget::on_hide() {
void WaterfallView::on_hide() {
// TODO: Assert that baseband is not shutdown.
baseband::spectrum_streaming_stop();
}
void WaterfallWidget::show_audio_spectrum_view(const bool show) {
void WaterfallView::show_audio_spectrum_view(const bool show) {
if ((audio_spectrum_view && show) || (!audio_spectrum_view && !show)) return;
if (show) {
@@ -335,18 +332,18 @@ void WaterfallWidget::show_audio_spectrum_view(const bool show) {
}
}
void WaterfallWidget::update_widgets_rect() {
void WaterfallView::update_widgets_rect() {
if (audio_spectrum_view) {
frequency_scale.set_parent_rect({0, audio_spectrum_height, screen_rect().width(), scale_height});
waterfall_view.set_parent_rect(waterfall_reduced_rect);
waterfall_widget.set_parent_rect(waterfall_reduced_rect);
} else {
frequency_scale.set_parent_rect({0, 0, screen_rect().width(), scale_height});
waterfall_view.set_parent_rect(waterfall_normal_rect);
waterfall_widget.set_parent_rect(waterfall_normal_rect);
}
waterfall_view.on_show();
waterfall_widget.on_show();
}
void WaterfallWidget::set_parent_rect(const Rect new_parent_rect) {
void WaterfallView::set_parent_rect(const Rect new_parent_rect) {
View::set_parent_rect(new_parent_rect);
waterfall_normal_rect = {0, scale_height, new_parent_rect.width(), new_parent_rect.height() - scale_height};
@@ -355,13 +352,8 @@ void WaterfallWidget::set_parent_rect(const Rect new_parent_rect) {
update_widgets_rect();
}
void WaterfallWidget::paint(Painter& painter) {
// TODO:
(void)painter;
}
void WaterfallWidget::on_channel_spectrum(const ChannelSpectrum& spectrum) {
waterfall_view.on_channel_spectrum(spectrum);
void WaterfallView::on_channel_spectrum(const ChannelSpectrum& spectrum) {
waterfall_widget.on_channel_spectrum(spectrum);
sampling_rate = spectrum.sampling_rate;
frequency_scale.set_spectrum_sampling_rate(sampling_rate);
frequency_scale.set_channel_filter(
@@ -370,9 +362,40 @@ void WaterfallWidget::on_channel_spectrum(const ChannelSpectrum& spectrum) {
spectrum.channel_filter_transition);
}
void WaterfallWidget::on_audio_spectrum() {
void WaterfallView::on_audio_spectrum() {
audio_spectrum_view->on_audio_spectrum(audio_spectrum_data);
}
} /* namespace spectrum */
uint32_t filter_bandwidth_for_sampling_rate(int32_t sampling_rate) {
switch (sampling_rate) { // Use the var fs (sampling_rate) to set up BPF aprox < fs_max / 2 by Nyquist theorem.
case 0 ... 2000000: // BW Captured range (0 <= 250kHz max) fs = 8 x 250 kHz.
return 1750000; // Minimum BPF MAX2837 for all those lower BW options.
case 4000000 ... 6000000: // BW capture range (500k...750kHz max) fs_max = 8 x 750kHz = 6Mhz
// BW 500k...750kHz, ex. 500kHz (fs = 8 x BW = 4Mhz), BW 600kHz (fs = 4,8Mhz), BW 750 kHz (fs = 6Mhz).
return 2500000; // In some IC, MAX2837 appears as 2250000, but both work similarly.
case 8800000: // BW capture 1,1Mhz fs = 8 x 1,1Mhz = 8,8Mhz. (1Mhz showed slightly higher noise background).
return 3500000;
case 14000000: // BW capture 1,75Mhz, fs = 8 x 1,75Mhz = 14Mhz
// Good BPF, good matching, but LCD flickers, refresh rate should be < 20 Hz, reasonable picture.
return 5000000;
case 16000000: // BW capture 2Mhz, fs = 8 x 2Mhz = 16Mhz
// Good BPF, good matching, but LCD flickers, refresh rate should be < 20 Hz, reasonable picture.
return 6000000;
case 20000000: // BW capture 2,5Mhz, fs = 8 x 2,5 Mhz = 20Mhz
// Good BPF, good matching, but LCD flickers, refresh rate should be < 20 Hz, reasonable picture.
return 7000000;
default: // BW capture 2,75Mhz, fs = 8 x 2,75Mhz = 22Mhz max ADC sampling and others.
// We tested also 9Mhz FPB slightly too much noise floor, better at 8Mhz.
return 8000000;
}
}
} /* namespace ui */
+13 -12
View File
@@ -108,12 +108,11 @@ class FrequencyScale : public Widget {
* If the baseband is shutdown or otherwise not running when interacting
* with these, they will almost certainly hang the device. */
class WaterfallView : public Widget {
class WaterfallWidget : public Widget {
public:
void on_show() override;
void on_hide() override;
void paint(Painter& painter) override;
void paint(Painter&) override {}
void on_channel_spectrum(const ChannelSpectrum& spectrum);
@@ -121,16 +120,16 @@ class WaterfallView : public Widget {
void clear();
};
class WaterfallWidget : public View {
class WaterfallView : public View {
public:
std::function<void(int32_t offset)> on_select{};
WaterfallWidget(const bool cursor = false);
WaterfallView(const bool cursor = false);
WaterfallWidget(const WaterfallWidget&) = delete;
WaterfallWidget(WaterfallWidget&&) = delete;
WaterfallWidget& operator=(const WaterfallWidget&) = delete;
WaterfallWidget& operator=(WaterfallWidget&&) = delete;
WaterfallView(const WaterfallView&) = delete;
WaterfallView(WaterfallView&&) = delete;
WaterfallView& operator=(const WaterfallView&) = delete;
WaterfallView& operator=(WaterfallView&&) = delete;
void on_show() override;
void on_hide() override;
@@ -139,8 +138,6 @@ class WaterfallWidget : public View {
void show_audio_spectrum_view(const bool show);
void paint(Painter& painter) override;
private:
void update_widgets_rect();
@@ -148,7 +145,7 @@ class WaterfallWidget : public View {
static constexpr Dim audio_spectrum_height = 16 * 2 + 20;
static constexpr Dim scale_height = 20;
WaterfallView waterfall_view{};
WaterfallWidget waterfall_widget{};
FrequencyScale frequency_scale{};
ChannelSpectrumFIFO* channel_fifo{nullptr};
@@ -195,6 +192,10 @@ class WaterfallWidget : public View {
};
} /* namespace spectrum */
/* Calculates the best anti_alias_baseband_bandwidth_filter for the given sampling rate. */
uint32_t filter_bandwidth_for_sampling_rate(int32_t sampling_rate);
} /* namespace ui */
#endif /*__UI_SPECTRUM_H__*/
+1 -1
View File
@@ -50,7 +50,7 @@ class TextEntryView : public View {
TextField text_input;
Button button_ok{
{10 * 8, 33 * 8, 9 * 8, 32},
{22 * 8, 33 * 8, 7 * 8, 32},
"OK"};
};
+1 -1
View File
@@ -608,7 +608,7 @@ UtilitiesMenuView::UtilitiesMenuView(NavigationView& nav) {
{"Wipe SD card", Color::red(), &bitmap_icon_tools_wipesd, [&nav]() { nav.push<WipeSDView>(); }},
{"Flash Utility", Color::red(), &bitmap_icon_temperature, [&nav]() { nav.push<FlashUtilityView>(); }},
{"SD over USB", Color::green(), &bitmap_icon_hackrf, [&nav]() { nav.push<SdOverUsbView>(); }},
{"SD over USB", Color::yellow(), &bitmap_icon_hackrf, [&nav]() { nav.push<SdOverUsbView>(); }},
});
set_max_rows(2); // allow wider buttons
}
+1 -1
View File
@@ -44,7 +44,7 @@ if(cpp20_supported)
else()
set(USE_CPPOPT "-std=c++17")
endif()
set(USE_CPPOPT "${USE_CPPOPT} -flto -fno-rtti -fno-exceptions -Weffc++ -Wuninitialized -Wno-volatile")
set(USE_CPPOPT "${USE_CPPOPT} -fno-rtti -fno-exceptions -Weffc++ -Wuninitialized -Wno-volatile")
# Enable this if you want the linker to remove unused code and data
set(USE_LINK_GC yes)
+4
View File
@@ -39,6 +39,10 @@ Dim Font::line_height() const {
return h;
}
Dim Font::char_width() const {
return w;
}
Size Font::size_of(const std::string s) const {
Size size;
+2
View File
@@ -86,6 +86,8 @@ class Font {
Glyph glyph(const char c) const;
Dim line_height() const;
Dim char_width() const;
Size size_of(const std::string s) const;
private: