mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-09-07 07:19:07 +00:00
Morserx added ssb modes (#2934)
* USB receive good * LSB receive good * all mode receive good, log is dead * frequency measurement good, decode dead * total killed * szutyok, gerjed * frequenty meas only. * ui ok * Add frequency measurement handling and update Morse processing logic * fix ssb speed
This commit is contained in:
+61
-53
@@ -16,6 +16,8 @@ MorseRadioView::MorseRadioView(ui::NavigationView& nav)
|
||||
&field_frequency,
|
||||
&txt_last,
|
||||
&txt_speed,
|
||||
&txt_freq,
|
||||
&options_mode,
|
||||
&btn_clear,
|
||||
&console_text,
|
||||
&labels,
|
||||
@@ -31,28 +33,43 @@ MorseRadioView::MorseRadioView(ui::NavigationView& nav)
|
||||
logger->init_daily_log(logs_dir);
|
||||
};
|
||||
|
||||
audio::set_rate(audio::Rate::Hz_24000);
|
||||
audio::output::start();
|
||||
|
||||
receiver_model.set_sampling_rate(3072000);
|
||||
receiver_model.set_baseband_bandwidth(1750000);
|
||||
receiver_model.set_hidden_offset(0);
|
||||
baseband::set_moreserx_config();
|
||||
receiver_model.set_am_configuration(4);
|
||||
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
|
||||
receiver_model.enable();
|
||||
|
||||
options_mode.on_change = [this](size_t, int32_t value) {
|
||||
current_mode = (uint8_t)value;
|
||||
morse_decoder_.resetLearning();
|
||||
if (current_mode == 0) {
|
||||
receiver_model.set_am_configuration(4);
|
||||
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
|
||||
field_squelch.set_style(Theme::getInstance()->option_active);
|
||||
field_squelch.set_focusable(true);
|
||||
receiver_model.set_squelch_level(field_squelch.value());
|
||||
audio::set_rate(audio::Rate::Hz_24000);
|
||||
} else {
|
||||
receiver_model.set_modulation(ReceiverModel::Mode::AMAudio);
|
||||
receiver_model.set_am_configuration(current_mode + 7);
|
||||
receiver_model.set_squelch_level(0);
|
||||
field_squelch.set_style(Theme::getInstance()->fg_dark);
|
||||
field_squelch.set_focusable(false);
|
||||
audio::set_rate(audio::Rate::Hz_12000);
|
||||
}
|
||||
baseband::set_moreserx_config(current_mode);
|
||||
};
|
||||
field_squelch.set_value(receiver_model.squelch_level(), false); // will be sent later, no need to send 2x
|
||||
field_squelch.on_change = [this](int32_t v) {
|
||||
if (current_mode == 0)
|
||||
receiver_model.set_squelch_level(v);
|
||||
};
|
||||
options_mode.set_selected_index(current_mode, true);
|
||||
|
||||
auto vol = field_volume.value(); // audio volume fix
|
||||
field_volume.set_value(0);
|
||||
field_volume.set_value(vol);
|
||||
|
||||
field_squelch.set_value(receiver_model.squelch_level());
|
||||
field_squelch.on_change = [this](int32_t v) {
|
||||
receiver_model.set_squelch_level(v);
|
||||
};
|
||||
|
||||
logger = std::make_unique<MorseLogger>();
|
||||
|
||||
chk_log.on_select = [this](Checkbox&, bool save) {
|
||||
save_log = save;
|
||||
if (logger && save_log)
|
||||
@@ -86,35 +103,29 @@ void MorseLogger::init_daily_log(const std::filesystem::path& log_dir) {
|
||||
}
|
||||
}
|
||||
|
||||
void MorseLogger::radio_set_log() {
|
||||
void MorseLogger::radio_set_log(uint8_t current_mode) {
|
||||
int64_t freq = receiver_model.target_frequency();
|
||||
std::string header = "Freq:" + to_string_dec_int(freq / 1000000) + "." + to_string_dec_int((freq % 1000000) / 1000, 3);
|
||||
header += "MHz SQ:" + to_string_dec_uint(receiver_model.squelch_level());
|
||||
header += " LNA:" + to_string_dec_uint(receiver_model.lna());
|
||||
header += " VGA:" + to_string_dec_uint(receiver_model.vga());
|
||||
header += " AMP:" + std::string(receiver_model.rf_amp() ? "ON" : "OFF");
|
||||
header += "\r\nMessage:\r\n";
|
||||
|
||||
std::string header = "Freq:" + to_string_rounded_freq(freq, 4);
|
||||
header += "MHz, ";
|
||||
header += "RX MODE:" + std::string(current_mode == 0 ? "CW/FM" : (current_mode == 1 ? "USB" : "LSB"));
|
||||
header += "\r\nMessage:";
|
||||
log_file.write_raw(header);
|
||||
}
|
||||
|
||||
bool MorseLogger::on_packet(const std::string& content, bool time) {
|
||||
bool MorseLogger::on_packet(const std::string& content, bool time, uint8_t current_mode) {
|
||||
if (!time) {
|
||||
log_file.write_raw_no_newline("\r\n\r\n");
|
||||
auto timestamp = to_string_datetime(rtc_time::now(), YMDHMS);
|
||||
log_file.write_raw("[" + timestamp + "] ");
|
||||
|
||||
radio_set_log();
|
||||
|
||||
radio_set_log(current_mode);
|
||||
char_count = 0;
|
||||
time = true;
|
||||
}
|
||||
|
||||
if (content.empty()) return time;
|
||||
|
||||
std::string s;
|
||||
for (char c : content) {
|
||||
std::string s(1, c);
|
||||
|
||||
s = c;
|
||||
if ((char_count >= 35 && c == ' ') || (char_count >= 47)) {
|
||||
log_file.write_raw_no_newline("\r\n");
|
||||
|
||||
@@ -145,14 +156,11 @@ void MorseRadioView::focus() {
|
||||
|
||||
void MorseRadioView::check_for_timeout() {
|
||||
uint64_t now = chTimeNow();
|
||||
|
||||
if (last_activity_time == 0) {
|
||||
last_activity_time = now;
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t quiet_duration = now - last_activity_time;
|
||||
|
||||
if (quiet_duration >= 60000) {
|
||||
morse_decoder_.resetLearning();
|
||||
time_stamp = false;
|
||||
@@ -170,13 +178,11 @@ int32_t MorseRadioView::ProcessSignal(int32_t sig_time_us) {
|
||||
long_pause_sent_ = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sign == last_sign_) {
|
||||
accumulator_us_ += sig_time_us;
|
||||
|
||||
if (sign < 0) {
|
||||
int32_t threshold_us = morse_decoder_.getInterWordThreshold() * 1000;
|
||||
|
||||
if (!long_pause_sent_ && accumulator_us_ <= -threshold_us) {
|
||||
result = accumulator_us_ / 1000;
|
||||
long_pause_sent_ = true;
|
||||
@@ -189,53 +195,55 @@ int32_t MorseRadioView::ProcessSignal(int32_t sig_time_us) {
|
||||
} else {
|
||||
result = 0;
|
||||
}
|
||||
|
||||
accumulator_us_ = sig_time_us;
|
||||
last_sign_ = sign;
|
||||
long_pause_sent_ = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void MorseRadioView::on_data(const MorseRXDataMessage* message) {
|
||||
uint16_t start = 0;
|
||||
uint16_t stop = 0;
|
||||
bool has_valid = false;
|
||||
int32_t r;
|
||||
|
||||
for (uint16_t i = 0; i <= message->maxptr; ++i) {
|
||||
if (message->state_durations[i] >= 30000 || message->state_durations[i] <= -30000) {
|
||||
if (!has_valid) {
|
||||
start = i;
|
||||
}
|
||||
} else {
|
||||
has_valid = true;
|
||||
stop = i;
|
||||
}
|
||||
}
|
||||
if (!has_valid) return; // no valid data arrived
|
||||
|
||||
for (uint16_t i = start; i <= stop; i++) {
|
||||
for (uint8_t i = 0; i <= message->state_cnt; ++i) {
|
||||
r = ProcessSignal(message->state_durations[i]);
|
||||
auto result = morse_decoder_.handleInput((r != 0) ? r : 0);
|
||||
if (result.isValid()) {
|
||||
last_activity_time = chTimeNow(); // start reset timer on valid input
|
||||
writeCharToConsole(result.text, result.confidence);
|
||||
if (logger && save_log) {
|
||||
time_stamp = logger->on_packet(result.text, time_stamp);
|
||||
time_stamp = logger->on_packet(result.text, time_stamp, current_mode);
|
||||
}
|
||||
float dah_time = morse_decoder_.getCurrentTimeUnit() * 3.0f;
|
||||
|
||||
if (dah_time > 0) {
|
||||
uint16_t wpm = (uint16_t)(3600.0f / (dah_time + 18.0f) + 0.5f);
|
||||
|
||||
txt_speed.set(to_string_dec_uint(wpm));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MorseRadioView::on_freq(const MorseRXfreqMessage* message) {
|
||||
std::string ret = " ";
|
||||
uint32_t freq = message->measured_frequency;
|
||||
if (freq < 301) {
|
||||
ret = "<";
|
||||
freq = 300;
|
||||
}
|
||||
if (freq > 2299) {
|
||||
freq = 2300;
|
||||
ret = ">";
|
||||
}
|
||||
if (freq < 400 || freq > 1400)
|
||||
txt_freq.set_style(Theme::getInstance()->fg_red);
|
||||
else if (freq <= 580 || freq >= 1220)
|
||||
txt_freq.set_style(Theme::getInstance()->fg_yellow);
|
||||
else
|
||||
txt_freq.set_style(Theme::getInstance()->fg_green);
|
||||
ret += to_string_dec_uint(freq);
|
||||
txt_freq.set(ret);
|
||||
}
|
||||
|
||||
void MorseRadioView::writeCharToConsole(const std::string& ch, double confidence) {
|
||||
if (ch.empty()) {
|
||||
return;
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "file.hpp"
|
||||
#include "rtc_time.hpp"
|
||||
#include "morsedecoder.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace ui::external_app::morse_radio {
|
||||
@@ -53,8 +54,8 @@ class MorseLogger {
|
||||
}
|
||||
|
||||
void init_daily_log(const std::filesystem::path& log_dir);
|
||||
bool on_packet(const std::string& content, bool time);
|
||||
void radio_set_log();
|
||||
bool on_packet(const std::string& content, bool time, uint8_t current_mode);
|
||||
void radio_set_log(uint8_t current_mode);
|
||||
|
||||
private:
|
||||
LogFile log_file{};
|
||||
@@ -73,6 +74,7 @@ class MorseRadioView : public ui::View {
|
||||
private:
|
||||
void writeCharToConsole(const std::string& ch, double confidence);
|
||||
void on_data(const MorseRXDataMessage* message);
|
||||
void on_freq(const MorseRXfreqMessage* message);
|
||||
void on_message(const Message* const p);
|
||||
void check_for_timeout();
|
||||
int32_t ProcessSignal(int32_t sig_time_us);
|
||||
@@ -80,8 +82,13 @@ class MorseRadioView : public ui::View {
|
||||
MorseDecoder morse_decoder_{};
|
||||
RxRadioState radio_state_{};
|
||||
std::unique_ptr<MorseLogger> logger{};
|
||||
|
||||
uint8_t current_mode{0}; // 0=CW/FM, 1=USB, 2=LSB
|
||||
|
||||
app_settings::SettingsManager settings_{
|
||||
"trx_morese_radio", app_settings::Mode::RX_TX};
|
||||
"rx_morese_radio",
|
||||
app_settings::Mode::RX,
|
||||
{{"cwmode"sv, ¤t_mode}}};
|
||||
|
||||
RxFrequencyField field_frequency{
|
||||
{UI_POS_X(0), UI_POS_Y(0)},
|
||||
@@ -107,27 +114,35 @@ class MorseRadioView : public ui::View {
|
||||
};
|
||||
ui::Text txt_speed{{UI_POS_X(23), UI_POS_Y(1), UI_POS_WIDTH(3), UI_POS_HEIGHT(1)}, "??"};
|
||||
ui::Text txt_last{{UI_POS_X(12), UI_POS_Y(4), UI_POS_WIDTH_REMAINING(12), UI_POS_HEIGHT(1)}, ""};
|
||||
ui::Text txt_freq{{UI_POS_X(21), UI_POS_Y(2), UI_POS_WIDTH(5), UI_POS_HEIGHT(1)}, "??"};
|
||||
ui::Console console_text{{UI_POS_X(0), UI_POS_Y(5), UI_POS_MAXWIDTH, UI_POS_HEIGHT_REMAINING(7)}};
|
||||
ui::Labels labels{
|
||||
{{UI_POS_X(0), UI_POS_Y(1)}, "Squelch:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(15), UI_POS_Y(1)}, "Speed:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(26), UI_POS_Y(1)}, "wpm", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), UI_POS_Y(4)}, "Last seq.:", Theme::getInstance()->fg_light->foreground},
|
||||
};
|
||||
{{UI_POS_X(15), UI_POS_Y(2)}, "Tone:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(27), UI_POS_Y(2)}, "Hz", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
ui::OptionsField options_mode{
|
||||
{UI_POS_X(9), UI_POS_Y(2)},
|
||||
5,
|
||||
{{"CW/FM", 0}, {"USB", 1}, {"LSB", 2}}};
|
||||
|
||||
Checkbox chk_log{{UI_POS_X(0), UI_POS_Y(2)}, 12, "Log", false};
|
||||
ui::Button btn_clear{{UI_POS_X(0), UI_POS_Y_BOTTOM(2), UI_POS_WIDTH(6), UI_POS_HEIGHT(1)}, "CLR"};
|
||||
|
||||
uint8_t last_color_id{255};
|
||||
uint8_t color_id{255};
|
||||
std::string arr_color[4] = {STR_COLOR_WHITE, STR_COLOR_RED, STR_COLOR_YELLOW, STR_COLOR_GREEN};
|
||||
|
||||
int32_t accumulator_us_{0};
|
||||
int8_t last_sign_{0};
|
||||
uint8_t space_timer{0};
|
||||
bool long_pause_sent_{false};
|
||||
bool save_log{false};
|
||||
bool reset_triggered_{false};
|
||||
bool time_stamp{false};
|
||||
uint8_t last_color_id{255};
|
||||
uint8_t color_id{255};
|
||||
int8_t last_sign_{0};
|
||||
uint8_t space_timer{0};
|
||||
int32_t accumulator_us_{0};
|
||||
uint64_t last_activity_time{0};
|
||||
|
||||
MessageHandlerRegistration message_handler_packet{
|
||||
@@ -137,6 +152,13 @@ class MorseRadioView : public ui::View {
|
||||
this->on_data(message);
|
||||
}};
|
||||
|
||||
MessageHandlerRegistration message_handler_freq{
|
||||
Message::ID::MorseRXfreq,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const MorseRXfreqMessage*>(p);
|
||||
this->on_freq(message);
|
||||
}};
|
||||
|
||||
MessageHandlerRegistration message_handler_framesync{
|
||||
Message::ID::DisplayFrameSync,
|
||||
[this](const Message* const p) {
|
||||
|
||||
Reference in New Issue
Block a user