From 78d3480b68d64c033692f106170ccdd75036583a Mon Sep 17 00:00:00 2001 From: Pezsma <159525557+Pezsma@users.noreply.github.com> Date: Fri, 27 Mar 2026 18:29:20 +0100 Subject: [PATCH] Morse tx update (#3112) * loop message, progress bar --- .../morseradiotx/ui_morse_radiotx.cpp | 117 +++++++++++------- .../morseradiotx/ui_morse_radiotx.hpp | 24 ++-- 2 files changed, 90 insertions(+), 51 deletions(-) diff --git a/firmware/application/external/morseradiotx/ui_morse_radiotx.cpp b/firmware/application/external/morseradiotx/ui_morse_radiotx.cpp index 5ef99e5c7..36f67064b 100644 --- a/firmware/application/external/morseradiotx/ui_morse_radiotx.cpp +++ b/firmware/application/external/morseradiotx/ui_morse_radiotx.cpp @@ -27,6 +27,9 @@ MorseRadiotxView::MorseRadiotxView(ui::NavigationView& nav) &chk_trans, &bandwidth, &chk_callsgn, + &chk_loop, + &wait_time, + &progressbar, &txt_last, &console_text, &btn_clear, @@ -69,6 +72,7 @@ MorseRadiotxView::MorseRadiotxView(ui::NavigationView& nav) options_mode.set_selected_index(current_mode, true); tone_.set_value(tone, true); wpm_.set_value(wpm, true); + wait_time.set_value(1, true); bandwidth.set_value(band, true); btn_ptt.on_select = [this](Button&) { @@ -156,6 +160,14 @@ MorseRadiotxView::MorseRadiotxView(ui::NavigationView& nav) transmitter_model.set_target_frequency(f); }; }; + + chk_trans.on_select = [this](Checkbox&, bool v) { + if (v) chk_loop.set_value(false); + }; + + chk_loop.on_select = [this](Checkbox&, bool v) { + if (v) chk_trans.set_value(false); + }; } MorseRadiotxView::~MorseRadiotxView() { @@ -197,19 +209,15 @@ MorseRadiotxView::MorseTimings MorseRadiotxView::calculate_morse_timings(uint32_ void MorseRadiotxView::transmit_morse_message() { std::string full_message = ""; - // cal sign - if (chk_callsgn.value() && !call_sign.empty()) { - full_message = call_sign; - if (!chk_trans.value() && !msg_buffer.empty()) { - full_message += " " + msg_buffer; - } - } else { - if (!chk_trans.value()) full_message = msg_buffer; - } - if (full_message.empty() && !chk_trans.value()) { + if (chk_trans.value()) { ptt_button_visibility(false); return; + } else { + full_message = msg_buffer; + if (chk_callsgn.value() && !call_sign.empty()) { // call sign + full_message += " " + call_sign; + } } // enable transmit @@ -219,46 +227,63 @@ void MorseRadiotxView::transmit_morse_message() { ui_toggle(); } - for (size_t i = 0; i < full_message.length(); i++) { - if (chThdShouldTerminate()) break; + uint8_t loop_seconds = static_cast(wait_time.value()); + progressbar.set_max(loop_seconds * 2); - char c = full_message[i]; + do { + for (size_t i = 0; i < full_message.length(); i++) { + if (chThdShouldTerminate()) break; - std::string s_char(1, c); - // space - if (c == ' ') { - console_text.write(" "); - chThdSleepMilliseconds(current_timings.word_gap); - continue; - } + char c = full_message[i]; - const char* pattern = morse_decoder_.get_morse_pattern(c); + std::string s_char(1, c); + // space + if (c == ' ') { + console_text.write(" "); + chThdSleepMilliseconds(current_timings.word_gap); + continue; + } - if (pattern != nullptr) { - txt_last.set(pattern); + const char* pattern = morse_decoder_.get_morse_pattern(c); - // write blue char to console - console_text.write(STR_COLOR_BLUE + s_char); + if (pattern != nullptr) { + txt_last.set(pattern); - // Morze (dih/dah) send - for (int j = 0; pattern[j] != '\0'; j++) { - baseband::set_morsetx_key(true); - if (pattern[j] == '.') { - chThdSleepMilliseconds(current_timings.dot_ms); - } else if (pattern[j] == '-') { - chThdSleepMilliseconds(current_timings.dash_ms); + // write blue char to console + console_text.write(STR_COLOR_BLUE + s_char); + + // Morze (dih/dah) send + for (int j = 0; pattern[j] != '\0'; j++) { + baseband::set_morsetx_key(true); + if (pattern[j] == '.') { + chThdSleepMilliseconds(current_timings.dot_ms); + } else if (pattern[j] == '-') { + chThdSleepMilliseconds(current_timings.dash_ms); + } + if (chThdShouldTerminate()) break; + // pause between signs + baseband::set_morsetx_key(false); + chThdSleepMilliseconds(current_timings.symbol_gap); } if (chThdShouldTerminate()) break; - // pause between signs - baseband::set_morsetx_key(false); - chThdSleepMilliseconds(current_timings.symbol_gap); - } - if (chThdShouldTerminate()) break; - if (current_timings.char_gap > current_timings.symbol_gap) { - chThdSleepMilliseconds(current_timings.char_gap - current_timings.symbol_gap); + if (current_timings.char_gap > current_timings.symbol_gap) { + chThdSleepMilliseconds(current_timings.char_gap - current_timings.symbol_gap); + } } } - } + if (chThdShouldTerminate()) break; + if (chk_loop.value()) { + console_text.write(" "); + for (uint8_t s = 0; s < (loop_seconds * 2); s++) { + if (chThdShouldTerminate()) break; + progressbar.set_value(s + 1); + if (!chk_loop.value()) break; + chThdSleepMilliseconds(500); + } + progressbar.set_value(0); + } + if (!chk_loop.value()) break; + } while (chk_loop.value() && !chThdShouldTerminate()); if (chk_trans.value()) ptt_button_visibility(false); baseband::set_morsetx_key(false); @@ -356,13 +381,17 @@ void MorseRadiotxView::ui_toggle() { wpm_.set_style(Theme::getInstance()->fg_dark); wpm_.set_focusable(false); btn_message.set_style(Theme::getInstance()->fg_dark); + btn_message.set_focusable(false); btn_calls.set_style(Theme::getInstance()->fg_dark); + btn_calls.set_focusable(false); chk_trans.set_style(Theme::getInstance()->fg_dark); chk_trans.set_focusable(false); - bandwidth.set_style(Theme::getInstance()->fg_dark); - bandwidth.set_focusable(false); chk_callsgn.set_style(Theme::getInstance()->fg_dark); chk_callsgn.set_focusable(false); + wait_time.set_style(Theme::getInstance()->fg_dark); + wait_time.set_focusable(false); + bandwidth.set_style(Theme::getInstance()->fg_dark); + bandwidth.set_focusable(false); } else { options_mode.set_style(Theme::getInstance()->bg_darker); @@ -370,11 +399,15 @@ void MorseRadiotxView::ui_toggle() { wpm_.set_style(Theme::getInstance()->bg_darker); wpm_.set_focusable(true); btn_message.set_style(Theme::getInstance()->bg_darker); + btn_message.set_focusable(true); btn_calls.set_style(Theme::getInstance()->bg_darker); + btn_calls.set_focusable(true); chk_trans.set_style(Theme::getInstance()->bg_darker); chk_trans.set_focusable(true); chk_callsgn.set_style(Theme::getInstance()->bg_darker); chk_callsgn.set_focusable(true); + wait_time.set_style(Theme::getInstance()->bg_darker); + wait_time.set_focusable(true); ptt_button_visibility(true); tone_.set_style(Theme::getInstance()->bg_darker); tone_.set_focusable(true); diff --git a/firmware/application/external/morseradiotx/ui_morse_radiotx.hpp b/firmware/application/external/morseradiotx/ui_morse_radiotx.hpp index c74bb576a..155cd8c82 100644 --- a/firmware/application/external/morseradiotx/ui_morse_radiotx.hpp +++ b/firmware/application/external/morseradiotx/ui_morse_radiotx.hpp @@ -118,15 +118,20 @@ class MorseRadiotxView : public ui::View { {{"AM", 0}, {"FM", 1}, {"DSB", 2}, {"USB", 3}, {"LSB", 4}}}; NumberField tone_{{UI_POS_X(14), UI_POS_Y(0)}, 4, {400, 1400}, 10, ' ', true}; NumberField wpm_{{UI_POS_X(25), UI_POS_Y(0)}, 2, {10, 45}, 1, ' ', true}; - FloatField bandwidth{{UI_POS_X(20), UI_POS_Y(3)}, 4, {1.0, 16.0}, 0.1, ' ', true, 1}; + NumberField wait_time{{UI_POS_X(10), UI_POS_Y(4)}, 3, {1, 99}, 1, ' ', true}; // wait between tx-es in loop mode (sec) + FloatField bandwidth{{UI_POS_X(6), UI_POS_Y(5)}, 4, {1.0, 16.0}, 0.1, ' ', true, 1}; + + ProgressBar progressbar{ + {UI_POS_X(0), UI_POS_Y(6), screen_width, 16}}; ui::Text txt_msg{{UI_POS_X(0), UI_POS_Y(1), UI_POS_MAXWIDTH, UI_POS_HEIGHT(1)}, "[" + msg_buffer + "] "}; ui::Button btn_message{{UI_POS_X(0), UI_POS_Y(2), UI_POS_WIDTH(11), UI_POS_HEIGHT(1)}, "Message"}; - ui::Button btn_calls{{UI_POS_X(0), UI_POS_Y(4), UI_POS_WIDTH(11), UI_POS_HEIGHT(1)}, (call_sign.empty()) ? "call sign?" : call_sign}; + ui::Button btn_calls{{UI_POS_X(0), UI_POS_Y(3), UI_POS_WIDTH(11), UI_POS_HEIGHT(1)}, (call_sign.empty()) ? "call sign?" : call_sign}; Checkbox chk_trans{{UI_POS_X(14), UI_POS_Y(2)}, 13, "Manual trans.", true}; - Checkbox chk_callsgn{{UI_POS_X(14), UI_POS_Y(4)}, 13, "Call sign", true}; - ui::Text txt_last{{UI_POS_X(10), UI_POS_Y(5), UI_POS_WIDTH_REMAINING(10), UI_POS_HEIGHT(1)}, ""}; - ui::Console console_text{{UI_POS_X(0), UI_POS_Y(7), UI_POS_MAXWIDTH, UI_POS_HEIGHT_REMAINING(14)}}; + Checkbox chk_callsgn{{UI_POS_X(14), UI_POS_Y(3)}, 9, "Call sign", true}; + Checkbox chk_loop{{UI_POS_X(14), UI_POS_Y(4)}, 4, "loop", true}; + ui::Text txt_last{{UI_POS_X(10), UI_POS_Y(7), UI_POS_WIDTH_REMAINING(10), UI_POS_HEIGHT(1)}, ""}; + ui::Console console_text{{UI_POS_X(0), UI_POS_Y(9), UI_POS_MAXWIDTH, UI_POS_HEIGHT_REMAINING(14)}}; ui::Button btn_clear{{UI_POS_X(0), UI_POS_Y_BOTTOM(5), UI_POS_WIDTH(5), UI_POS_HEIGHT(1)}, "CLR"}; ui::Button btn_ptt{{UI_POS_X_CENTER(12), UI_POS_Y_BOTTOM(7), UI_POS_WIDTH(12), UI_POS_HEIGHT(3)}, "PTT"}; @@ -135,10 +140,11 @@ class MorseRadiotxView : public ui::View { {{UI_POS_X(9), UI_POS_Y(0)}, "Tone:", Theme::getInstance()->fg_light->foreground}, {{UI_POS_X(18), UI_POS_Y(0)}, "Hz", Theme::getInstance()->fg_light->foreground}, {{UI_POS_X(21), UI_POS_Y(0)}, "WPM:", Theme::getInstance()->fg_light->foreground}, - {{UI_POS_X(14), UI_POS_Y(3)}, "BandW:", Theme::getInstance()->fg_light->foreground}, - {{UI_POS_X(24), UI_POS_Y(3)}, "kHz", Theme::getInstance()->fg_light->foreground}, - {{UI_POS_X(0), UI_POS_Y(5)}, "Last seq:", Theme::getInstance()->fg_light->foreground}, - {{UI_POS_X(0), UI_POS_Y(6)}, "Sent Message:", Theme::getInstance()->fg_light->foreground}, + {{UI_POS_X(0), UI_POS_Y(5)}, "BandW:", Theme::getInstance()->fg_light->foreground}, + {{UI_POS_X(10), UI_POS_Y(5)}, "kHz", Theme::getInstance()->fg_light->foreground}, + {{UI_POS_X(0), UI_POS_Y(4)}, "Wait time: ", Theme::getInstance()->fg_light->foreground}, + {{UI_POS_X(0), UI_POS_Y(7)}, "Last seq:", Theme::getInstance()->fg_light->foreground}, + {{UI_POS_X(0), UI_POS_Y(8)}, "Sent Message:", Theme::getInstance()->fg_light->foreground}, {{UI_POS_X_RIGHT(7), UI_POS_Y_BOTTOM(5)}, "Vol.:", Theme::getInstance()->fg_light->foreground}, };