From 337e3f4449d49ca1b6deb7d4e2f9da760344133e Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Fri, 22 Dec 2023 01:45:05 -0600 Subject: [PATCH 01/13] Enhance Debug->Peripherals to view all registers of SI5351 chip (#1663) --- firmware/application/apps/ui_debug.cpp | 39 ++++++++++++------- firmware/application/apps/ui_debug.hpp | 8 ++-- .../common/portapack_persistent_memory.cpp | 8 ++-- .../common/portapack_persistent_memory.hpp | 3 ++ 4 files changed, 36 insertions(+), 22 deletions(-) diff --git a/firmware/application/apps/ui_debug.cpp b/firmware/application/apps/ui_debug.cpp index 9e6897837..29fe8e5fa 100644 --- a/firmware/application/apps/ui_debug.cpp +++ b/firmware/application/apps/ui_debug.cpp @@ -176,12 +176,15 @@ void RegistersWidget::paint(Painter& painter) { void RegistersWidget::draw_legend(const Coord left, Painter& painter) { const auto pos = screen_pos(); + const std::string spaces(config.legend_length(), ' '); + + for (uint32_t i = 0; i < config.registers_per_page; i += config.registers_per_row()) { + uint32_t r = page_number * config.registers_per_page + i; - for (uint32_t i = 0; i < config.registers_count; i += config.registers_per_row()) { const Point offset{ left, static_cast((i / config.registers_per_row()) * row_height)}; - const auto text = to_string_hex(i, config.legend_length()); + const auto text = (r >= config.registers_count) ? spaces : to_string_hex(r, config.legend_length()); painter.draw_string( pos + offset, style().invert(), @@ -193,15 +196,16 @@ void RegistersWidget::draw_values( const Coord left, Painter& painter) { const auto pos = screen_pos(); + const std::string spaces(config.value_length(), ' '); + + for (uint32_t i = 0; i < config.registers_per_page; i++) { + uint32_t r = page_number * config.registers_per_page + i; - for (uint32_t i = 0; i < config.registers_count; i++) { const Point offset = { static_cast(left + config.legend_width() + 8 + (i % config.registers_per_row()) * (config.value_width() + 8)), static_cast((i / config.registers_per_row()) * row_height)}; - const auto value = reg_read(i); - - const auto text = to_string_hex(value, config.value_length()); + const auto text = (r >= config.registers_count) ? spaces : to_string_hex(reg_read(r), config.value_length()); painter.draw_string( pos + offset, style(), @@ -213,7 +217,7 @@ uint32_t RegistersWidget::reg_read(const uint32_t register_number) { if (register_number < config.registers_count) { switch (config.chip_type) { case CT_PMEM: - return portapack::persistent_memory::pmem_data_word((page_number * config.registers_count + register_number) / 4) >> (register_number % 4 * 8); + return portapack::persistent_memory::pmem_data_word(register_number / 4) >> (register_number % 4 * 8); case CT_RFFC5072: return radio::debug::first_if::register_read(register_number); case CT_MAX283X: @@ -272,6 +276,7 @@ RegistersView::RegistersView( button_done.on_select = [&nav](Button&) { nav.pop(); }; registers_widget.set_parent_rect({0, 48, 240, 192}); + registers_widget.set_page(0); text_title.set_parent_rect({(240 - static_cast(title.size()) * 8) / 2, 16, static_cast(title.size()) * 8, 16}); @@ -296,6 +301,13 @@ void RegistersView::focus() { button_done.focus(); } +bool RegistersView::on_encoder(const EncoderEvent delta) { + registers_widget.set_page(std::max(0ul, std::min(registers_widget.page_count() - 1, registers_widget.page() + delta))); + registers_widget.update(); + + return true; +} + /* ControlsSwitchesWidget ************************************************/ void ControlsSwitchesWidget::on_show() { @@ -429,10 +441,10 @@ DebugPeripheralsMenuView::DebugPeripheralsMenuView(NavigationView& nav) { const char* max283x = hackrf_r9 ? "MAX2839" : "MAX2837"; const char* si5351x = hackrf_r9 ? "Si5351A" : "Si5351C"; add_items({ - {"RFFC5072", ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [&nav]() { nav.push("RFFC5072", RegistersWidgetConfig{CT_RFFC5072, 31, 16}); }}, - {max283x, ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [&nav, max283x]() { nav.push(max283x, RegistersWidgetConfig{CT_MAX283X, 32, 10}); }}, - {si5351x, ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [&nav, si5351x]() { nav.push(si5351x, RegistersWidgetConfig{CT_SI5351, 96, 8}); }}, - {audio::debug::codec_name(), ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [&nav]() { nav.push(audio::debug::codec_name(), RegistersWidgetConfig{CT_AUDIO, audio::debug::reg_count(), audio::debug::reg_bits()}); }}, + {"RFFC5072", ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [&nav]() { nav.push("RFFC5072", RegistersWidgetConfig{CT_RFFC5072, 31, 31, 16}); }}, + {max283x, ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [&nav, max283x]() { nav.push(max283x, RegistersWidgetConfig{CT_MAX283X, 32, 32, 10}); }}, + {si5351x, ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [&nav, si5351x]() { nav.push(si5351x, RegistersWidgetConfig{CT_SI5351, 188, 96, 8}); }}, + {audio::debug::codec_name(), ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [&nav]() { nav.push(audio::debug::codec_name(), RegistersWidgetConfig{CT_AUDIO, audio::debug::reg_count(), audio::debug::reg_count(), audio::debug::reg_bits()}); }}, }); set_max_rows(2); // allow wider buttons } @@ -504,8 +516,8 @@ void DebugMemoryDumpView::focus() { /* DebugPmemView *********************************************************/ DebugPmemView::DebugPmemView(NavigationView& nav) - : registers_widget(RegistersWidgetConfig{CT_PMEM, page_size, 8}) { - add_children({&text_page, ®isters_widget, &text_checksum, &text_checksum2, &button_ok}); + : registers_widget(RegistersWidgetConfig{CT_PMEM, PMEM_SIZE_BYTES, page_size, 8}) { + add_children({®isters_widget, &text_checksum, &text_checksum2, &button_ok}); registers_widget.set_parent_rect({0, 32, 240, 192}); @@ -532,7 +544,6 @@ void DebugPmemView::focus() { } void DebugPmemView::update() { - text_page.set(to_string_hex(registers_widget.page() * page_size, 2) + "+"); registers_widget.update(); } diff --git a/firmware/application/apps/ui_debug.hpp b/firmware/application/apps/ui_debug.hpp index 8328a9973..583819980 100644 --- a/firmware/application/apps/ui_debug.hpp +++ b/firmware/application/apps/ui_debug.hpp @@ -142,6 +142,7 @@ typedef enum { struct RegistersWidgetConfig { chip_type_t chip_type; uint32_t registers_count; + uint32_t registers_per_page; uint32_t register_bits; constexpr size_t legend_length() const { @@ -194,6 +195,7 @@ class RegistersWidget : public Widget { void set_page(int32_t value) { page_number = value; } uint32_t page(void) { return page_number; } + uint32_t page_count(void) { return (config.registers_count + config.registers_per_page - 1) / config.registers_per_page; } private: const RegistersWidgetConfig config; @@ -208,8 +210,8 @@ class RegistersWidget : public Widget { class RegistersView : public View { public: RegistersView(NavigationView& nav, const std::string& title, RegistersWidgetConfig&& config); - - void focus(); + void focus() override; + bool on_encoder(const EncoderEvent delta) override; private: Text text_title{}; @@ -364,8 +366,6 @@ class DebugPmemView : public View { static constexpr uint8_t page_size{96}; // Must be multiply of 4 otherwise bit shifting for register view wont work properly static constexpr uint8_t page_count{(portapack::memory::map::backup_ram.size() + page_size - 1) / page_size}; - Text text_page{{16, 16, 208, 16}}; - RegistersWidget registers_widget; Text text_checksum{{16, 232, 208, 16}}; diff --git a/firmware/common/portapack_persistent_memory.cpp b/firmware/common/portapack_persistent_memory.cpp index 55294cab2..8f83282f6 100644 --- a/firmware/common/portapack_persistent_memory.cpp +++ b/firmware/common/portapack_persistent_memory.cpp @@ -284,11 +284,11 @@ struct data_t { struct backup_ram_t { private: - volatile uint32_t regfile[63]; + volatile uint32_t regfile[PMEM_SIZE_WORDS - 1]; volatile uint32_t check_value; static void copy(const backup_ram_t& src, backup_ram_t& dst) { - for (size_t i = 0; i < 63; i++) { + for (size_t i = 0; i < PMEM_SIZE_WORDS - 1; i++) { dst.regfile[i] = src.regfile[i]; } dst.check_value = src.check_value; @@ -297,7 +297,7 @@ struct backup_ram_t { static void copy_from_data_t(const data_t& src, backup_ram_t& dst) { const uint32_t* const src_words = (uint32_t*)&src; const size_t word_count = (sizeof(data_t) + 3) / 4; - for (size_t i = 0; i < 63; i++) { + for (size_t i = 0; i < PMEM_SIZE_WORDS - 1; i++) { if (i < word_count) { dst.regfile[i] = src_words[i]; } else { @@ -308,7 +308,7 @@ struct backup_ram_t { uint32_t compute_check_value() { CRC<32> crc{0x04c11db7, 0xffffffff, 0xffffffff}; - for (size_t i = 0; i < 63; i++) { + for (size_t i = 0; i < PMEM_SIZE_WORDS - 1; i++) { const auto word = regfile[i]; crc.process_byte((word >> 0) & 0xff); crc.process_byte((word >> 8) & 0xff); diff --git a/firmware/common/portapack_persistent_memory.hpp b/firmware/common/portapack_persistent_memory.hpp index 4c5e50eee..2760322b3 100644 --- a/firmware/common/portapack_persistent_memory.hpp +++ b/firmware/common/portapack_persistent_memory.hpp @@ -39,6 +39,9 @@ // persistant memory from/to sdcard flag file #define PMEM_SETTING_FILE u"/SETTINGS/pmem_settings" +#define PMEM_SIZE_BYTES 256 // total amount of pmem space in bytes, including checksum +#define PMEM_SIZE_WORDS (PMEM_SIZE_BYTES / 4) + using namespace modems; using namespace serializer; From d0bd8e50be948b142e453c0b12e3fa3df2e72a13 Mon Sep 17 00:00:00 2001 From: gullradriel <3157857+gullradriel@users.noreply.github.com> Date: Fri, 22 Dec 2023 11:00:27 +0100 Subject: [PATCH 02/13] Added USB serial checkbox (#1664) --- firmware/application/apps/ble_rx_app.cpp | 20 +++++++++++++++----- firmware/application/apps/ble_rx_app.hpp | 9 +++++++++ 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/firmware/application/apps/ble_rx_app.cpp b/firmware/application/apps/ble_rx_app.cpp index b5a27faf8..88cdb19ff 100644 --- a/firmware/application/apps/ble_rx_app.cpp +++ b/firmware/application/apps/ble_rx_app.cpp @@ -426,6 +426,7 @@ BLERxView::BLERxView(NavigationView& nav) &options_sort, &label_found, &text_found_count, + &check_serial_log, &button_filter, &button_save_list, &button_clear_list, @@ -436,7 +437,15 @@ BLERxView::BLERxView(NavigationView& nav) nav_.push(entry); }; - usb_serial_thread = std::make_unique(); + check_serial_log.on_select = [this](Checkbox&, bool v) { + serial_logging = v; + if (v) { + usb_serial_thread = std::make_unique(); + } else { + usb_serial_thread.reset(); + } + }; + check_serial_log.set_value(serial_logging); ensure_directory(find_packet_path); ensure_directory(log_packets_path); @@ -456,8 +465,6 @@ BLERxView::BLERxView(NavigationView& nav) logger = std::make_unique(); - check_log.set_value(logging); - check_log.on_select = [this](Checkbox&, bool v) { str_log = ""; logging = v; @@ -468,6 +475,7 @@ BLERxView::BLERxView(NavigationView& nav) "/BLELOG_" + to_string_timestamp(rtc_time::now()) + ".TXT"); }; + check_log.set_value(logging); button_save_list.on_select = [this, &nav](const ui::Button&) { listFileBuffer = ""; @@ -723,8 +731,10 @@ void BLERxView::on_data(BlePacketData* packet) { logger->log_raw_data(str_console + "\r\n"); } - usb_serial_thread->serial_str = str_console + "\r\n"; - usb_serial_thread->str_ready = true; + if (serial_logging) { + usb_serial_thread->serial_str = str_console + "\r\n"; + usb_serial_thread->str_ready = true; + } str_console = ""; if (!searchList.empty()) { diff --git a/firmware/application/apps/ble_rx_app.hpp b/firmware/application/apps/ble_rx_app.hpp index 8735c545e..f3e81444d 100644 --- a/firmware/application/apps/ble_rx_app.hpp +++ b/firmware/application/apps/ble_rx_app.hpp @@ -215,6 +215,7 @@ class BLERxView : public View { uint8_t sort_index{0}; std::string filter{}; bool logging{false}; + bool serial_logging{false}; bool name_enable{true}; app_settings::SettingsManager settings_{ @@ -225,6 +226,8 @@ class BLERxView : public View { {"sort_index"sv, &sort_index}, {"filter"sv, &filter}, {"log"sv, &logging}, + // disabled to always start without USB serial activated until we can make it non blocking if not connected + // {"serial_log"sv, &serial_logging}, {"name"sv, &name_enable}, }}; @@ -320,6 +323,12 @@ class BLERxView : public View { {11 * 8, 3 * 16, 20 * 8, 16}, "0/0"}; + Checkbox check_serial_log{ + {17 * 8, 3 * 16 - 2}, + 7, + "USB Log", + true}; + Console console{ {0, 4 * 16, 240, 240}}; From f42ad5ffc6e3443a48d2bfc6358feed51f8d3857 Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Sun, 24 Dec 2023 01:54:56 -0600 Subject: [PATCH 03/13] Configure CLKOUT at power-up per PMEM setting (#1669) --- firmware/application/ui_navigation.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 8bd21b757..38650477f 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -173,6 +173,9 @@ SystemStatusView::SystemStatusView( pmem::load_persistent_settings_from_file(); } + // configure CLKOUT per pmem setting + portapack::clock_manager.enable_clock_output(pmem::clkout_enabled()); + // force apply of selected sdcard speed override at UI startup pmem::set_config_sdcard_high_speed_io(pmem::config_sdcard_high_speed_io(), false); From 4eb5c4603e8c761f16dbf5b0964c2f465c0370c0 Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Sun, 24 Dec 2023 01:55:15 -0600 Subject: [PATCH 04/13] Simplify CLKOUT frequency entry (#1668) --- firmware/application/apps/ui_settings.cpp | 30 +++++------------------ firmware/application/apps/ui_settings.hpp | 10 ++------ 2 files changed, 8 insertions(+), 32 deletions(-) diff --git a/firmware/application/apps/ui_settings.cpp b/firmware/application/apps/ui_settings.cpp index c57f32201..c2642b047 100644 --- a/firmware/application/apps/ui_settings.cpp +++ b/firmware/application/apps/ui_settings.cpp @@ -133,7 +133,6 @@ SetRadioView::SetRadioView( &check_clkout, &field_clkout_freq, &labels_clkout_khz, - &value_freq_step, &labels_bias, &check_bias, &disable_external_tcxo, // TODO: always show? @@ -186,28 +185,11 @@ SetRadioView::SetRadioView( }; field_clkout_freq.set_value(pmem::clkout_freq()); - value_freq_step.set_style(&Styles::light_grey); - - field_clkout_freq.on_select = [this](NumberField&) { - freq_step_khz++; - if (freq_step_khz > 3) { - freq_step_khz = 0; - } - switch (freq_step_khz) { - case 0: - value_freq_step.set(" |"); - break; - case 1: - value_freq_step.set(" | "); - break; - case 2: - value_freq_step.set(" | "); - break; - case 3: - value_freq_step.set("| "); - break; - } - field_clkout_freq.set_step(pow(10, freq_step_khz)); + field_clkout_freq.on_change = [this](SymField&) { + if (field_clkout_freq.to_integer() < 10) + field_clkout_freq.set_value(10); + if (field_clkout_freq.to_integer() > 60000) + field_clkout_freq.set_value(60000); }; check_bias.set_value(get_antenna_bias()); @@ -248,7 +230,7 @@ void SetRadioView::form_init(const SetFrequencyCorrectionModel& model) { SetFrequencyCorrectionModel SetRadioView::form_collect() { return { .ppm = static_cast(field_ppm.value()), - .freq = static_cast(field_clkout_freq.value()), + .freq = static_cast(field_clkout_freq.to_integer()), }; } diff --git a/firmware/application/apps/ui_settings.hpp b/firmware/application/apps/ui_settings.hpp index 3473d2195..be9ce5328 100644 --- a/firmware/application/apps/ui_settings.hpp +++ b/firmware/application/apps/ui_settings.hpp @@ -163,20 +163,14 @@ class SetRadioView : public View { 13, "Enable CLKOUT"}; - NumberField field_clkout_freq{ + SymField field_clkout_freq{ {20 * 8, 6 * 16}, 5, - {10, 60000}, - 1000, - ' '}; + SymField::Type::Dec}; Labels labels_clkout_khz{ {{26 * 8, 6 * 16}, "kHz", Color::light_grey()}}; - Text value_freq_step{ - {21 * 8, (7 * 16), 4 * 8, 16}, - "| "}; - Labels labels_bias{ {{4 * 8 + 4, 8 * 16}, "CAUTION: Ensure that all", Color::red()}, {{5 * 8 + 0, 9 * 16}, "devices attached to the", Color::red()}, From 93585d846a3d4e139f1432346526a738746b85c1 Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Sun, 24 Dec 2023 04:06:11 -0600 Subject: [PATCH 05/13] CLKOUT workaround for r9 boards (#1671) --- firmware/application/clock_manager.cpp | 44 +++++++++++++++----------- firmware/common/hackrf_hal.hpp | 1 + 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/firmware/application/clock_manager.cpp b/firmware/application/clock_manager.cpp index 32b92ce59..c89247810 100644 --- a/firmware/application/clock_manager.cpp +++ b/firmware/application/clock_manager.cpp @@ -561,26 +561,32 @@ void ClockManager::stop_audio_pll() { } void ClockManager::enable_clock_output(bool enable) { - if (enable) { - clock_generator.enable_output(clock_generator_output_og_clkout); - if (portapack::persistent_memory::clkout_freq() < 1000) { - clock_generator.set_ms_frequency(clock_generator_output_og_clkout, portapack::persistent_memory::clkout_freq() * 128000, si5351_vco_f, 7); - } else { - clock_generator.set_ms_frequency(clock_generator_output_og_clkout, portapack::persistent_memory::clkout_freq() * 1000, si5351_vco_f, 0); - } - } else { - clock_generator.disable_output(clock_generator_output_og_clkout); + if (hackrf_r9) { + gpio_r9_clkout_en.output(); + gpio_r9_clkout_en.write(enable); + + // NOTE: RETURNING HERE IF HACKRF_R9 TO PREVENT CLK2 FROM BEING DISABLED OR FREQ MODIFIED SINCE CLK2 ON R9 IS + // USED FOR BOTH CLKOUT AND FOR THE MCU_CLOCK (== GP_CLKIN) WHICH OTHER LP43XX CLOCKS CURRENTLY RELY ON. + // FUTURE TBD: REMOVE OTHER LP43XX CLOCK DEPENDENCIES ON GP_CLKIN, THEN DELETE THE return LINE BELOW TO ALLOW + // CLKOUT FREQ CHANGES ON R9 BOARDS. + return; } - auto si5351_clock_control_common = hackrf_r9 - ? si5351a_clock_control_common - : si5351c_clock_control_common; - const auto ref_pll = hackrf_r9 - ? ClockControl::MultiSynthSource::PLLA - : get_si5351c_reference_clock_generator_pll(reference.source); + auto clkout_select = hackrf_r9 ? clock_generator_output_r9_clkout : clock_generator_output_og_clkout; - if (enable) - clock_generator.set_clock_control(clock_generator_output_og_clkout, si5351_clock_control_common[clock_generator_output_og_clkout].ms_src(ref_pll).clk_pdn(ClockControl::ClockPowerDown::Power_On)); - else - clock_generator.set_clock_control(clock_generator_output_og_clkout, ClockControl::power_off()); + if (enable) { + clock_generator.enable_output(clkout_select); + if (portapack::persistent_memory::clkout_freq() < 1000) { + clock_generator.set_ms_frequency(clkout_select, portapack::persistent_memory::clkout_freq() * 128000, si5351_vco_f, 7); + } else { + clock_generator.set_ms_frequency(clkout_select, portapack::persistent_memory::clkout_freq() * 1000, si5351_vco_f, 0); + } + + auto si5351_clock_control_common = hackrf_r9 ? si5351a_clock_control_common : si5351c_clock_control_common; + const auto ref_pll = hackrf_r9 ? ClockControl::MultiSynthSource::PLLA : get_si5351c_reference_clock_generator_pll(reference.source); + clock_generator.set_clock_control(clkout_select, si5351_clock_control_common[clkout_select].ms_src(ref_pll).clk_pdn(ClockControl::ClockPowerDown::Power_On)); + } else { + clock_generator.disable_output(clkout_select); + clock_generator.set_clock_control(clkout_select, ClockControl::power_off()); + } } diff --git a/firmware/common/hackrf_hal.hpp b/firmware/common/hackrf_hal.hpp index 9e5e2695b..2798a4ad1 100644 --- a/firmware/common/hackrf_hal.hpp +++ b/firmware/common/hackrf_hal.hpp @@ -68,6 +68,7 @@ constexpr size_t clock_generator_output_og_mcu_clkin = 7; constexpr size_t clock_generator_output_r9_if = 0; constexpr size_t clock_generator_output_r9_sgpio = 1; +constexpr size_t clock_generator_output_r9_clkout = 2; constexpr size_t clock_generator_output_r9_mcu_clkin = 2; /* ADC0 */ From 459e8d0b24a3bdea1ea5c4ffb4e65891355a7ae8 Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Sun, 24 Dec 2023 10:28:22 -0600 Subject: [PATCH 06/13] Disallow CLKOUT freq changes on r9 (#1672) --- firmware/application/apps/ui_settings.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/firmware/application/apps/ui_settings.cpp b/firmware/application/apps/ui_settings.cpp index c2642b047..58ce5a126 100644 --- a/firmware/application/apps/ui_settings.cpp +++ b/firmware/application/apps/ui_settings.cpp @@ -184,6 +184,14 @@ SetRadioView::SetRadioView( send_system_refresh(); }; + // Disallow CLKOUT freq change on hackrf_r9 due to dependencies on GP_CLKIN (same Si5351A clock); + // see comments in ClockManager::enable_clock_output() + if (hackrf_r9) { + if (pmem::clkout_freq() != 10000) + pmem::set_clkout_freq(10000); + field_clkout_freq.set_focusable(false); + } + field_clkout_freq.set_value(pmem::clkout_freq()); field_clkout_freq.on_change = [this](SymField&) { if (field_clkout_freq.to_integer() < 10) From 7bf3e02f6c2b66568afb0b45b8a1a6576030b524 Mon Sep 17 00:00:00 2001 From: Totoo Date: Mon, 25 Dec 2023 17:25:16 +0100 Subject: [PATCH 07/13] Faster usb serial file download (#1674) * Made file read much faster via USB serial * Remove old code --- firmware/application/usb_serial_shell.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/firmware/application/usb_serial_shell.cpp b/firmware/application/usb_serial_shell.cpp index 4a37ae7eb..c7a3516a5 100644 --- a/firmware/application/usb_serial_shell.cpp +++ b/firmware/application/usb_serial_shell.cpp @@ -418,21 +418,18 @@ static void cmd_sd_read(BaseSequentialStream* chp, int argc, char* argv[]) { int size = (int)strtol(argv[0], NULL, 10); - uint8_t buffer[16]; + uint8_t buffer[62]; do { - File::Size bytes_to_read = size > 16 ? 16 : size; + File::Size bytes_to_read = size > 62 ? 62 : size; auto bytes_read = shell_file->read(buffer, bytes_to_read); if (bytes_read.is_error()) { chprintf(chp, "error %d\r\n", bytes_read.error()); return; } - - for (size_t i = 0; i < bytes_read.value(); i++) - chprintf(chp, "%02X", buffer[i]); - - chprintf(chp, "\r\n"); - + std::string res = to_string_hex_array(buffer, bytes_read.value()); + res += "\r\n"; + fillOBuffer(&((SerialUSBDriver*)chp)->oqueue, (const uint8_t*)res.c_str(), res.size()); if (bytes_to_read != bytes_read.value()) return; From a85357a8af17246fd63ce09e8be906099a6e2791 Mon Sep 17 00:00:00 2001 From: Brumi-2021 <86470699+Brumi-2021@users.noreply.github.com> Date: Tue, 26 Dec 2023 07:11:14 +0100 Subject: [PATCH 08/13] Minor Improvement (Extending_min_CLK_out_from_10khz_to_4khz) (#1675) --- firmware/application/apps/ui_settings.cpp | 4 ++-- firmware/common/portapack_persistent_memory.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/firmware/application/apps/ui_settings.cpp b/firmware/application/apps/ui_settings.cpp index 58ce5a126..66a89d63d 100644 --- a/firmware/application/apps/ui_settings.cpp +++ b/firmware/application/apps/ui_settings.cpp @@ -194,8 +194,8 @@ SetRadioView::SetRadioView( field_clkout_freq.set_value(pmem::clkout_freq()); field_clkout_freq.on_change = [this](SymField&) { - if (field_clkout_freq.to_integer() < 10) - field_clkout_freq.set_value(10); + if (field_clkout_freq.to_integer() < 4) // Min. CLK out of Si5351A/B/C-B is 2.5khz , but in our application -intermediate freq 800Mhz-,Min working CLK=4khz. + field_clkout_freq.set_value(4); if (field_clkout_freq.to_integer() > 60000) field_clkout_freq.set_value(60000); }; diff --git a/firmware/common/portapack_persistent_memory.cpp b/firmware/common/portapack_persistent_memory.cpp index 8f83282f6..6afafea7d 100644 --- a/firmware/common/portapack_persistent_memory.cpp +++ b/firmware/common/portapack_persistent_memory.cpp @@ -77,7 +77,7 @@ constexpr modem_repeat_range_t modem_repeat_range{1, 99}; constexpr int32_t modem_repeat_reset_value{5}; using clkout_freq_range_t = range_t; -constexpr clkout_freq_range_t clkout_freq_range{10, 60000}; +constexpr clkout_freq_range_t clkout_freq_range{4, 60000}; // Min. CLK out of Si5351A/B/C-B is 2.5khz , but in our application -intermediate freq 800Mhz-,Min working CLK=4khz. constexpr uint16_t clkout_freq_reset_value{10000}; enum data_structure_version_enum : uint32_t { From 1bf95e85a037c544caee719134a31bca7ac3f2c5 Mon Sep 17 00:00:00 2001 From: Totoo Date: Tue, 26 Dec 2023 07:16:54 +0100 Subject: [PATCH 09/13] Fixed #1670 (#1676) --- .../external/blespam/ui_blespam.cpp | 1058 ++++++++--------- .../external/blespam/ui_blespam.hpp | 11 +- .../application/external/jammer/ui_jammer.hpp | 7 +- 3 files changed, 540 insertions(+), 536 deletions(-) diff --git a/firmware/application/external/blespam/ui_blespam.cpp b/firmware/application/external/blespam/ui_blespam.cpp index 818b45ad5..7131ecd2b 100644 --- a/firmware/application/external/blespam/ui_blespam.cpp +++ b/firmware/application/external/blespam/ui_blespam.cpp @@ -78,8 +78,12 @@ BLESpamView::BLESpamView(NavigationView& nav) &field_frequency, &tx_view, &chk_randdev, - &options_atkmode, - &console}); + &options_atkmode +#ifdef BLESPMUSECONSOLE + , + &console +#endif + }); button_startstop.on_select = [this](Button&) { if (is_running) { @@ -101,10 +105,12 @@ BLESpamView::BLESpamView(NavigationView& nav) attackType = (ATK_TYPE)i; changePacket(true); }; +#ifdef BLESPMUSECONSOLE console.writeln("Based on work of:"); console.writeln("@Willy-JL, @ECTO-1A,"); console.writeln("@Spooks4576, @iNetro"); console.writeln(""); +#endif changePacket(true); // init } @@ -167,7 +173,6 @@ void BLESpamView::createSamsungPacket() { type = types[rand() % COUNT_OF(types)]; uint8_t size = packet_SamsungSizes[type]; - uint8_t* packet = (uint8_t*)malloc(size); uint8_t i = 0; switch (type) { @@ -254,7 +259,6 @@ void BLESpamView::createSamsungPacket() { std::string res = to_string_hex_array(packet, size); memset(advertisementData, 0, sizeof(advertisementData)); std::copy(res.begin(), res.end(), advertisementData); - free(packet); } void BLESpamView::createWindowsPacket() { @@ -267,12 +271,11 @@ void BLESpamView::createWindowsPacket() { "🔵🦷", }; //not worky using fix, for testing. */ - const char* name = "PortaPack"; + const char* name = "PortaHack"; // name = names[rand() % 6]; uint8_t name_len = strlen(name); uint8_t size = 7 + name_len; - uint8_t* packet = (uint8_t*)malloc(size); uint8_t i = 0; packet[i++] = size - 1; // Size @@ -288,7 +291,6 @@ void BLESpamView::createWindowsPacket() { std::string res = to_string_hex_array(packet, size); memset(advertisementData, 0, sizeof(advertisementData)); std::copy(res.begin(), res.end(), advertisementData); - free(packet); } void BLESpamView::createIosPacket(bool crash = false) { @@ -302,7 +304,6 @@ void BLESpamView::createIosPacket(bool crash = false) { if (crash) type = ContinuityTypeCustomCrash; uint8_t size = ios_packet_sizes[type]; - uint8_t* packet = (uint8_t*)malloc(size); uint8_t i = 0; packet[i++] = size - 1; // Size @@ -478,13 +479,11 @@ void BLESpamView::createIosPacket(bool crash = false) { std::string res = to_string_hex_array(packet, size); memset(advertisementData, 0, sizeof(advertisementData)); std::copy(res.begin(), res.end(), advertisementData); - free(packet); } void BLESpamView::createFastPairPacket() { uint32_t model = fastpairModels[rand() % fastpairModels_count].value; uint8_t size = 14; - uint8_t* packet = (uint8_t*)malloc(size); uint8_t i = 0; packet[i++] = 3; // Size @@ -508,7 +507,6 @@ void BLESpamView::createFastPairPacket() { std::string res = to_string_hex_array(packet, size); memset(advertisementData, 0, sizeof(advertisementData)); std::copy(res.begin(), res.end(), advertisementData); - free(packet); } void BLESpamView::changePacket(bool forced = false) { @@ -538,12 +536,14 @@ void BLESpamView::changePacket(bool forced = false) { break; } } - // rate limit console display +// rate limit console display +#ifdef BLESPMUSECONSOLE displayCounter++; if (displayCounter > 25) { displayCounter = 0; console.writeln(advertisementData); } +#endif } } @@ -727,526 +727,524 @@ const uint8_t BLESpamView::na_actions_count = COUNT_OF(na_actions); const BLESpamView::fpUi32 BLESpamView::fastpairModels[] = { // Genuine non-production/forgotten (good job Google) - {0x0001F0, "Bisto CSR8670 Dev Board"}, - {0x000047, "Arduino 101"}, - {0x470000, "Arduino 101 2"}, - {0x00000A, "Anti-Spoof Test"}, - {0x0A0000, "Anti-Spoof Test 2"}, - {0x00000B, "Google Gphones"}, - {0x0B0000, "Google Gphones 2"}, - {0x0C0000, "Google Gphones 3"}, - {0x00000D, "Test 00000D"}, - {0x000007, "Android Auto"}, - {0x070000, "Android Auto 2"}, - {0x000008, "Foocorp Foophones"}, - {0x080000, "Foocorp Foophones 2"}, - {0x000009, "Test Android TV"}, - {0x090000, "Test Android TV 2"}, - {0x000035, "Test 000035"}, - {0x350000, "Test 000035 2"}, - {0x000048, "Fast Pair Headphones"}, - {0x480000, "Fast Pair Headphones 2"}, - {0x000049, "Fast Pair Headphones 3"}, - {0x490000, "Fast Pair Headphones 4"}, - {0x001000, "LG HBS1110"}, - {0x00B727, "Smart Controller 1"}, - {0x01E5CE, "BLE-Phone"}, - {0x0200F0, "Goodyear"}, - {0x00F7D4, "Smart Setup"}, - {0xF00002, "Goodyear"}, - {0xF00400, "T10"}, - {0x1E89A7, "ATS2833_EVB"}, + {0x0001F0}, + {0x000047}, + {0x470000}, + {0x00000A}, + {0x0A0000}, + {0x00000B}, + {0x0B0000}, + {0x0C0000}, + {0x00000D}, + {0x000007}, + {0x070000}, + {0x000008}, + {0x080000}, + {0x000009}, + {0x090000}, + {0x000035}, + {0x350000}, + {0x000048}, + {0x480000}, + {0x000049}, + {0x490000}, + {0x001000}, + {0x00B727}, + {0x01E5CE}, + {0x0200F0}, + {0x00F7D4}, + {0xF00002}, + {0xF00400}, + {0x1E89A7}, - // Phone setup - {0x00000C, "Google Gphones Transfer"}, - {0x0577B1, "Galaxy S23 Ultra"}, - {0x05A9BC, "Galaxy S20+"}, + {0x00000C}, + {0x0577B1}, + {0x05A9BC}, - // Genuine devices - {0xCD8256, "Bose NC 700"}, - {0x0000F0, "Bose QuietComfort 35 II"}, - {0xF00000, "Bose QuietComfort 35 II 2"}, - {0x821F66, "JBL Flip 6"}, - {0xF52494, "JBL Buds Pro"}, - {0x718FA4, "JBL Live 300TWS"}, - {0x0002F0, "JBL Everest 110GA"}, - {0x92BBBD, "Pixel Buds"}, - {0x000006, "Google Pixel buds"}, - {0x060000, "Google Pixel buds 2"}, - {0xD446A7, "Sony XM5"}, - {0x2D7A23, "Sony WF-1000XM4"}, - {0x0E30C3, "Razer Hammerhead TWS"}, - {0x72EF8D, "Razer Hammerhead TWS X"}, - {0x72FB00, "Soundcore Spirit Pro GVA"}, - {0x0003F0, "LG HBS-835S"}, - {0x002000, "AIAIAI TMA-2 (H60)"}, - {0x003000, "Libratone Q Adapt On-Ear"}, - {0x003001, "Libratone Q Adapt On-Ear 2"}, - {0x00A168, "boAt Airdopes 621"}, - {0x00AA48, "Jabra Elite 2"}, - {0x00AA91, "Beoplay E8 2.0"}, - {0x00C95C, "Sony WF-1000X"}, - {0x01EEB4, "WH-1000XM4"}, - {0x02AA91, "B&O Earset"}, - {0x01C95C, "Sony WF-1000X"}, - {0x02D815, "ATH-CK1TW"}, - {0x035764, "PLT V8200 Series"}, - {0x038CC7, "JBL TUNE760NC"}, - {0x02DD4F, "JBL TUNE770NC"}, - {0x02E2A9, "TCL MOVEAUDIO S200"}, - {0x035754, "Plantronics PLT_K2"}, - {0x02C95C, "Sony WH-1000XM2"}, - {0x038B91, "DENON AH-C830NCW"}, - {0x02F637, "JBL LIVE FLEX"}, - {0x02D886, "JBL REFLECT MINI NC"}, - {0xF00000, "Bose QuietComfort 35 II"}, - {0xF00001, "Bose QuietComfort 35 II"}, - {0xF00201, "JBL Everest 110GA"}, - {0xF00204, "JBL Everest 310GA"}, - {0xF00209, "JBL LIVE400BT"}, - {0xF00205, "JBL Everest 310GA"}, - {0xF00200, "JBL Everest 110GA"}, - {0xF00208, "JBL Everest 710GA"}, - {0xF00207, "JBL Everest 710GA"}, - {0xF00206, "JBL Everest 310GA"}, - {0xF0020A, "JBL LIVE400BT"}, - {0xF0020B, "JBL LIVE400BT"}, - {0xF0020C, "JBL LIVE400BT"}, - {0xF00203, "JBL Everest 310GA"}, - {0xF00202, "JBL Everest 110GA"}, - {0xF00213, "JBL LIVE650BTNC"}, - {0xF0020F, "JBL LIVE500BT"}, - {0xF0020E, "JBL LIVE500BT"}, - {0xF00214, "JBL LIVE650BTNC"}, - {0xF00212, "JBL LIVE500BT"}, - {0xF0020D, "JBL LIVE400BT"}, - {0xF00211, "JBL LIVE500BT"}, - {0xF00215, "JBL LIVE650BTNC"}, - {0xF00210, "JBL LIVE500BT"}, - {0xF00305, "LG HBS-1500"}, - {0xF00304, "LG HBS-1010"}, - {0xF00308, "LG HBS-1125"}, - {0xF00303, "LG HBS-930"}, - {0xF00306, "LG HBS-1700"}, - {0xF00300, "LG HBS-835S"}, - {0xF00309, "LG HBS-2000"}, - {0xF00302, "LG HBS-830"}, - {0xF00307, "LG HBS-1120"}, - {0xF00301, "LG HBS-835"}, - {0xF00E97, "JBL VIBE BEAM"}, - {0x04ACFC, "JBL WAVE BEAM"}, - {0x04AA91, "Beoplay H4"}, - {0x04AFB8, "JBL TUNE 720BT"}, - {0x05A963, "WONDERBOOM 3"}, - {0x05AA91, "B&O Beoplay E6"}, - {0x05C452, "JBL LIVE220BT"}, - {0x05C95C, "Sony WI-1000X"}, - {0x0602F0, "JBL Everest 310GA"}, - {0x0603F0, "LG HBS-1700"}, - {0x1E8B18, "SRS-XB43"}, - {0x1E955B, "WI-1000XM2"}, - {0x1EC95C, "Sony WF-SP700N"}, - {0x1ED9F9, "JBL WAVE FLEX"}, - {0x1EE890, "ATH-CKS30TW WH"}, - {0x1EEDF5, "Teufel REAL BLUE TWS 3"}, - {0x1F1101, "TAG Heuer Calibre E4 45mm"}, - {0x1F181A, "LinkBuds S"}, - {0x1F2E13, "Jabra Elite 2"}, - {0x1F4589, "Jabra Elite 2"}, - {0x1F4627, "SRS-XG300"}, - {0x1F5865, "boAt Airdopes 441"}, - {0x1FBB50, "WF-C700N"}, - {0x1FC95C, "Sony WF-SP700N"}, - {0x1FE765, "TONE-TF7Q"}, - {0x1FF8FA, "JBL REFLECT MINI NC"}, - {0x201C7C, "SUMMIT"}, - {0x202B3D, "Amazfit PowerBuds"}, - {0x20330C, "SRS-XB33"}, - {0x003B41, "M&D MW65"}, - {0x003D8A, "Cleer FLOW II"}, - {0x005BC3, "Panasonic RP-HD610N"}, - {0x008F7D, "soundcore Glow Mini"}, - {0x00FA72, "Pioneer SE-MS9BN"}, - {0x0100F0, "Bose QuietComfort 35 II"}, - {0x011242, "Nirvana Ion"}, - {0x013D8A, "Cleer EDGE Voice"}, - {0x01AA91, "Beoplay H9 3rd Generation"}, - {0x038F16, "Beats Studio Buds"}, - {0x039F8F, "Michael Kors Darci 5e"}, - {0x03AA91, "B&O Beoplay H8i"}, - {0x03B716, "YY2963"}, - {0x03C95C, "Sony WH-1000XM2"}, - {0x03C99C, "MOTO BUDS 135"}, - {0x03F5D4, "Writing Account Key"}, - {0x045754, "Plantronics PLT_K2"}, - {0x045764, "PLT V8200 Series"}, - {0x04C95C, "Sony WI-1000X"}, - {0x050F0C, "Major III Voice"}, - {0x052CC7, "MINOR III"}, - {0x057802, "TicWatch Pro 5"}, - {0x0582FD, "Pixel Buds"}, - {0x058D08, "WH-1000XM4"}, - {0x06AE20, "Galaxy S21 5G"}, - {0x06C197, "OPPO Enco Air3 Pro"}, - {0x06C95C, "Sony WH-1000XM2"}, - {0x06D8FC, "soundcore Liberty 4 NC"}, - {0x0744B6, "Technics EAH-AZ60M2"}, - {0x07A41C, "WF-C700N"}, - {0x07C95C, "Sony WH-1000XM2"}, - {0x07F426, "Nest Hub Max"}, - {0x0102F0, "JBL Everest 110GA - Gun Metal"}, - {0x0202F0, "JBL Everest 110GA - Silver"}, - {0x0302F0, "JBL Everest 310GA - Brown"}, - {0x0402F0, "JBL Everest 310GA - Gun Metal"}, - {0x0502F0, "JBL Everest 310GA - Silver"}, - {0x0702F0, "JBL Everest 710GA - Gun Metal"}, - {0x0802F0, "JBL Everest 710GA - Silver"}, - {0x054B2D, "JBL TUNE125TWS"}, - {0x0660D7, "JBL LIVE770NC"}, - {0x0103F0, "LG HBS-835"}, - {0x0203F0, "LG HBS-830"}, - {0x0303F0, "LG HBS-930"}, - {0x0403F0, "LG HBS-1010"}, - {0x0503F0, "LG HBS-1500"}, - {0x0703F0, "LG HBS-1120"}, - {0x0803F0, "LG HBS-1125"}, - {0x0903F0, "LG HBS-2000"}, - {0x0102F0, "JBL Everest 110GA"}, - {0x0202F0, "JBL Everest 110GA"}, - {0x0302F0, "JBL Everest 310GA"}, - {0x0402F0, "JBL Everest 310GA"}, - {0x0502F0, "JBL Everest 310GA"}, - {0x060000, "Google Pixel Buds"}, - {0x070000, "Android Auto"}, - {0x0702F0, "JBL Everest 710GA"}, - {0x071C74, "JBL Flip 6"}, - {0x080000, "Foocorp Foophones"}, - {0x0802F0, "JBL Everest 710GA"}, - {0x090000, "Test Android TV"}, - {0x0A0000, "Test 00000a - Anti-Spoofing"}, - {0x0B0000, "Google Gphones"}, - {0x0C0000, "Google Gphones"}, - {0x0DC6BF, "My Awesome Device II"}, - {0x0DC95C, "Sony WH-1000XM3"}, - {0x0DEC2B, "Emporio Armani EA Connected"}, - {0x0E138D, "WF-SP800N"}, - {0x0EC95C, "Sony WI-C600N"}, - {0x0ECE95, "Philips TAT3508"}, - {0x0F0993, "COUMI TWS-834A"}, - {0x0F1B8D, "JBL VIBE BEAM"}, - {0x0F232A, "JBL TUNE BUDS"}, - {0x0F2D16, "WH-CH520"}, - {0x20A19B, "WF-SP800N"}, - {0x20C95C, "Sony WF-SP700N"}, - {0x20CC2C, "SRS-XB43"}, - {0x213C8C, "DIZO Wireless Power"}, - {0x21521D, "boAt Rockerz 355 (Green)"}, - {0x21A04E, "oraimo FreePods Pro"}, - {0x2D7A23, "WF-1000XM4"}, - {0x350000, "Test 000035"}, - {0x470000, "Arduino 101"}, - {0x480000, "Fast Pair Headphones"}, - {0x490000, "Fast Pair Headphones"}, - {0x5BA9B5, "WF-SP800N"}, - {0x5BACD6, "Bose QC Ultra Earbuds"}, - {0x5BD6C9, "JBL TUNE225TWS"}, - {0x5BE3D4, "JBL Flip 6"}, - {0x5C0206, "UA | JBL TWS STREAK"}, - {0x5C0C84, "JBL TUNE225TWS"}, - {0x5C4833, "WH-CH720N"}, - {0x5C4A7E, "LG HBS-XL7"}, - {0x5C55E7, "TCL MOVEAUDIO S200"}, - {0x5C7CDC, "WH-1000XM5"}, - {0x5C8AA5, "JBL LIVE220BT"}, - {0x5CC900, "Sony WF-1000X"}, - {0x5CC901, "Sony WF-1000X"}, - {0x5CC902, "Sony WH-1000XM2"}, - {0x5CC903, "Sony WH-1000XM2"}, - {0x5CC904, "Sony WI-1000X"}, - {0x5CC905, "Sony WI-1000X"}, - {0x5CC906, "Sony WH-1000XM2"}, - {0x5CC907, "Sony WH-1000XM2"}, - {0x5CC908, "Sony WI-1000X"}, - {0x5CC909, "Sony WI-1000X"}, - {0x5CC90A, "Sony WH-1000XM3"}, - {0x5CC90B, "Sony WH-1000XM3"}, - {0x5CC90C, "Sony WH-1000XM3"}, - {0x5CC90D, "Sony WH-1000XM3"}, - {0x5CC90E, "Sony WI-C600N"}, - {0x5CC90F, "Sony WI-C600N"}, - {0x5CC910, "Sony WI-C600N"}, - {0x5CC911, "Sony WI-C600N"}, - {0x5CC912, "Sony WI-C600N"}, - {0x5CC913, "Sony WI-C600N"}, - {0x5CC914, "Sony WI-SP600N"}, - {0x5CC915, "Sony WI-SP600N"}, - {0x5CC916, "Sony WI-SP600N"}, - {0x5CC917, "Sony WI-SP600N"}, - {0x5CC918, "Sony WI-SP600N"}, - {0x5CC919, "Sony WI-SP600N"}, - {0x5CC91A, "Sony WI-SP600N"}, - {0x5CC91B, "Sony WI-SP600N"}, - {0x5CC91C, "Sony WI-SP600N"}, - {0x5CC91D, "Sony WI-SP600N"}, - {0x5CC91E, "Sony WF-SP700N"}, - {0x5CC91F, "Sony WF-SP700N"}, - {0x5CC920, "Sony WF-SP700N"}, - {0x5CC921, "Sony WF-SP700N"}, - {0x5CC922, "Sony WF-SP700N"}, - {0x5CC923, "Sony WF-SP700N"}, - {0x5CC924, "Sony WF-SP700N"}, - {0x5CC925, "Sony WF-SP700N"}, - {0x5CC926, "Sony WF-SP700N"}, - {0x5CC927, "Sony WF-SP700N"}, - {0x5CC928, "Sony WH-H900N"}, - {0x5CC929, "Sony WH-H900N"}, - {0x5CC92A, "Sony WH-H900N"}, - {0x5CC92B, "Sony WH-H900N"}, - {0x5CC92C, "Sony WH-H900N"}, - {0x5CC92D, "Sony WH-H900N"}, - {0x5CC92E, "Sony WH-H900N"}, - {0x5CC92F, "Sony WH-H900N"}, - {0x5CC930, "Sony WH-H900N"}, - {0x5CC931, "Sony WH-H900N"}, - {0x5CC932, "Sony WH-CH700N"}, - {0x5CC933, "Sony WH-CH700N"}, - {0x5CC934, "Sony WH-CH700N"}, - {0x5CC935, "Sony WH-CH700N"}, - {0x5CC936, "Sony WH-CH700N"}, - {0x5CC937, "Sony WH-CH700N"}, - {0x5CC938, "Sony WF-1000XM3"}, - {0x5CC939, "Sony WF-1000XM3"}, - {0x5CC93A, "Sony WF-1000XM3"}, - {0x5CC93B, "Sony WF-1000XM3"}, - {0x5CC93C, "Sony WH-XB700"}, - {0x5CC93D, "Sony WH-XB700"}, - {0x5CC93E, "Sony WH-XB700"}, - {0x5CC93F, "Sony WH-XB700"}, - {0x5CC940, "Sony WH-XB900N"}, - {0x5CC941, "Sony WH-XB900N"}, - {0x5CC942, "Sony WH-XB900N"}, - {0x5CC943, "Sony WH-XB900N"}, - {0x5CC944, "Sony WH-XB900N"}, - {0x5CC945, "Sony WH-XB900N"}, - {0x5CEE3C, "Fitbit Charge 4"}, - {0x6AD226, "TicWatch Pro 3"}, - {0x6B1C64, "Pixel Buds"}, - {0x6B8C65, "oraimo FreePods 4"}, - {0x6B9304, "Nokia SB-101"}, - {0x6BA5C3, "Jabra Elite 4"}, - {0x6C42C0, "TWS05"}, - {0x6C4DE5, "JBL LIVE PRO 2 TWS"}, - {0x718FA4, "JBL LIVE300TWS"}, - {0x89BAD5, "Galaxy A23 5G"}, - {0x8A31B7, "Bose QC Ultra Headphones"}, - {0x8A3D00, "Cleer FLOW â…¡"}, - {0x8A3D01, "Cleer EDGE Voice"}, - {0x8A8F23, "WF-1000XM5"}, - {0x8AADAE, "JLab GO Work 2"}, - {0x8B0A91, "Jabra Elite 5"}, - {0x8B5A7B, "TicWatch Pro 3 GPS"}, - {0x8B66AB, "Pixel Buds A-Series"}, - {0x8BB0A0, "Nokia Solo Bud+"}, - {0x8BF79A, "Oladance Whisper E1"}, - {0x8C07D2, "Jabra Elite 4 Active"}, - {0x8C1706, "YY7861E"}, - {0x8C4236, "GLIDiC mameBuds"}, - {0x8C6B6A, "realme Buds Air 3S"}, - {0x8CAD81, "KENWOOD WS-A1"}, - {0x8CB05C, "JBL LIVE PRO+ TWS"}, - {0x8CD10F, "realme Buds Air Pro"}, - {0x8D13B9, "BLE-TWS"}, - {0x8D16EA, "Galaxy M14 5G"}, - {0x8D5B67, "Pixel 90c"}, - {0x8E14D7, "LG-TONE-TFP8"}, - {0x8E1996, "Galaxy A24 5g"}, - {0x8E4666, "Oladance Wearable Stereo"}, - {0x8E5550, "boAt Airdopes 511v2"}, - {0x9101F0, "Jabra Elite 2"}, - {0x9128CB, "TCL MOVEAUDIO Neo"}, - {0x913B0C, "YH-E700B"}, - {0x915CFA, "Galaxy A14"}, - {0x9171BE, "Jabra Evolve2 65 Flex"}, - {0x917E46, "LinkBuds"}, - {0x91AA00, "Beoplay E8 2.0"}, - {0x91AA01, "Beoplay H9 3rd Generation"}, - {0x91AA02, "B&O Earset"}, - {0x91AA03, "B&O Beoplay H8i"}, - {0x91AA04, "Beoplay H4"}, - {0x91AA05, "B&O Beoplay E6"}, - {0x91BD38, "LG HBS-FL7"}, - {0x91C813, "JBL TUNE770NC"}, - {0x91DABC, "SRS-XB33"}, - {0x92255E, "LG-TONE-FP6"}, - {0x989D0A, "Set up your new Pixel 2"}, - {0x9939BC, "ATH-SQ1TW"}, - {0x994374, "EDIFIER W320TN"}, - {0x997B4A, "UA | JBL True Wireless Flash X"}, - {0x99C87B, "WH-H810 (h.ear)"}, - {0x99D7EA, "oraimo OpenCirclet"}, - {0x99F098, "Galaxy S22 Ultra"}, - {0x9A408A, "MOTO BUDS 065"}, - {0x9A9BDD, "WH-XB910N"}, - {0x9ADB11, "Pixel Buds Pro"}, - {0x9AEEA4, "LG HBS-FN4"}, - {0x9B7339, "AKG N9 Hybrid"}, - {0x9B735A, "JBL RFL FLOW PRO"}, - {0x9B9872, "Hyundai"}, - {0x9BC64D, "JBL TUNE225TWS"}, - {0x9BE931, "WI-C100"}, - {0x9C0AF7, "JBL VIBE BUDS"}, - {0x9C3997, "ATH-M50xBT2"}, - {0x9C4058, "JBL WAVE FLEX"}, - {0x9C6BC0, "LinkBuds S"}, - {0x9C888B, "WH-H910N (h.ear)"}, - {0x9C98DB, "JBL TUNE225TWS"}, - {0x9CA277, "YY2963"}, - {0x9CB5F3, "WH-1000XM5"}, - {0x9CB881, "soundcore Motion 300"}, - {0x9CD0F3, "LG HBS-TFN7"}, - {0x9CE3C7, "EDIFIER NeoBuds Pro 2"}, - {0x9CEFD1, "SRS-XG500"}, - {0x9CF08F, "JLab Epic Air ANC"}, - {0x9D00A6, "Urbanears Juno"}, - {0x9D7D42, "Galaxy S20"}, - {0x9DB896, "Your BMW"}, - {0xA7E52B, "Bose NC 700 Headphones"}, - {0xA7EF76, "JBL CLUB PRO+ TWS"}, - {0xA8001A, "JBL CLUB ONE"}, - {0xA83C10, "adidas Z.N.E. 01"}, - {0xA8658F, "ROCKSTER GO"}, - {0xA8845A, "oraimo FreePods 4"}, - {0xA88B69, "WF-SP800N"}, - {0xA8A00E, "Nokia CB-201"}, - {0xA8A72A, "JBL LIVE670NC"}, - {0xA8C636, "JBL TUNE660NC"}, - {0xA8CAAD, "Galaxy F04"}, - {0xA8E353, "JBL TUNE BEAM"}, - {0xA8F96D, "JBL ENDURANCE RUN 2 WIRELESS"}, - {0xA90358, "JBL LIVE220BT"}, - {0xA92498, "JBL WAVE BUDS"}, - {0xA9394A, "JBL TUNE230NC TWS"}, - {0xC6936A, "JBL LIVE PRO+ TWS"}, - {0xC69AFD, "WF-H800 (h.ear)"}, - {0xC6ABEA, "UA | JBL True Wireless Flash X"}, - {0xC6EC5F, "SRS-XE300"}, - {0xC7736C, "Philips PH805"}, - {0xC79B91, "Jabra Evolve2 75"}, - {0xC7A267, "Fake Test Mouse"}, - {0xC7D620, "JBL Pulse 5"}, - {0xC7FBCC, "JBL VIBE FLEX"}, - {0xC8162A, "LinkBuds S"}, - {0xC85D7A, "JBL ENDURANCE PEAK II"}, - {0xC8777E, "Jaybird Vista 2"}, - {0xC878AA, "SRS-XV800"}, - {0xC8C641, "Redmi Buds 4 Lite"}, - {0xC8D335, "WF-1000XM4"}, - {0xC8E228, "Pixel Buds Pro"}, - {0xC9186B, "WF-1000XM4"}, - {0xC9836A, "JBL Xtreme 4"}, - {0xCA7030, "ATH-TWX7"}, - {0xCAB6B8, "ATH-M20xBT"}, - {0xCAF511, "Jaybird Vista 2"}, - {0xCB093B, "Urbanears Juno"}, - {0xCB529D, "soundcore Glow"}, - {0xCC438E, "WH-1000XM4"}, - {0xCC5F29, "JBL TUNE660NC"}, - {0xCC754F, "YY2963"}, - {0xCC93A5, "Sync"}, - {0xCCBB7E, "MIDDLETON"}, - {0xCD8256, "Bose NC 700 Headphones"}, - {0xD446A7, "WH-1000XM5"}, - {0xD5A59E, "Jabra Elite Speaker"}, - {0xD5B5F7, "MOTO BUDS 600 ANC"}, - {0xD5C6CE, "realme TechLife Buds T100"}, - {0xD654CD, "JBL Xtreme 4"}, - {0xD65F4E, "Philips Fidelio T2"}, - {0xD69B2B, "TONE-T80S"}, - {0xD6C195, "LG HBS-SL5"}, - {0xD6E870, "Beoplay EX"}, - {0xD6EE84, "Rockerz 255 Max"}, - {0xD7102F, "ATH-SQ1TW SVN"}, - {0xD7E3EB, "Cleer HALO"}, - {0xD8058C, "MOTIF II A.N.C."}, - {0xD820EA, "WH-XB910N"}, - {0xD87A3E, "Pixel Buds Pro"}, - {0xD8F3BA, "WH-1000XM5"}, - {0xD8F4E8, "realme Buds T100"}, - {0xD90617, "Redmi Buds 4 Active"}, - {0xD933A7, "JBL ENDURANCE PEAK 3"}, - {0xD9414F, "JBL SOUNDGEAR SENSE"}, - {0xD97EBA, "JBL TUNE125TWS"}, - {0xD9964B, "JBL TUNE670NC"}, - {0xDA0F83, "SPACE"}, - {0xDA4577, "Jabra Elite 4 Active"}, - {0xDA5200, "blackbox TRIP II"}, - {0xDAD3A6, "Jabra Elite 10"}, - {0xDADE43, "Chromebox"}, - {0xDAE096, "adidas RPT-02 SOL"}, - {0xDB8AC7, "LG TONE-FREE"}, - {0xDBE5B1, "WF-1000XM4"}, - {0xDC5249, "WH-H810 (h.ear)"}, - {0xDCF33C, "JBL REFLECT MINI NC"}, - {0xDD4EC0, "OPPO Enco Air3 Pro"}, - {0xDE215D, "WF-C500"}, - {0xDE577F, "Teufel AIRY TWS 2"}, - {0xDEC04C, "SUMMIT"}, - {0xDEDD6F, "soundcore Space One"}, - {0xDEE8C0, "Ear (2)"}, - {0xDEEA86, "Xiaomi Buds 4 Pro"}, - {0xDEF234, "WH-H810 (h.ear)"}, - {0xDF01E3, "Sync"}, - {0xDF271C, "Big Bang e Gen 3"}, - {0xDF42DE, "TAG Heuer Calibre E4 42mm"}, - {0xDF4B02, "SRS-XB13"}, - {0xDF9BA4, "Bose NC 700 Headphones"}, - {0xDFD433, "JBL REFLECT AERO"}, - {0xE020C1, "soundcore Motion 300"}, - {0xE06116, "LinkBuds S"}, - {0xE07634, "OnePlus Buds Z"}, - {0xE09172, "JBL TUNE BEAM"}, - {0xE4E457, "Galaxy S20 5G"}, - {0xE5440B, "TAG Heuer Calibre E4 45mm"}, - {0xE57363, "Oladance Wearable Stereo"}, - {0xE57B57, "Super Device"}, - {0xE5B4B0, "WF-1000XM5"}, - {0xE5B91B, "SRS-XB33"}, - {0xE5E2E9, "Zone Wireless 2"}, - {0xE64613, "JBL WAVE BEAM"}, - {0xE64CC6, "Set up your new Pixel 3 XL"}, - {0xE69877, "JBL REFLECT AERO"}, - {0xE6E37E, "realme Buds Air 5 Pro"}, - {0xE6E771, "ATH-CKS50TW"}, - {0xE6E8B8, "POCO Pods"}, - {0xE750CE, "Jabra Evolve2 75"}, - {0xF52494, "JBL LIVE PRO+ TWS"}, - {0x000006, "Google Pixel Buds"}, - {0x00000A, "Test 00000a - Anti-Spoofing"}, - {0x00000C, "Google Gphones"}, - {0x000049, "Fast Pair Headphones"}, - {0x003001, "Libratone Q Adapt On-Ear"}, - {0x003D8A, "Cleer FLOW â…¡"}, - {0x0052DA, "blackbox TRIP II"}, - {0x109201, "Beoplay H9 3rd Generation"}, - {0x124366, "BLE-Phone"}, - {0x126644, "WH-1000XM4"}, - {0x284500, "Plantronics PLT_K2"}, - {0x532011, "Big Bang e Gen 3"}, - {0x549547, "JBL WAVE BUDS"}, - {0x567679, "Pixel Buds Pro"}, - {0x575836, "Sony WI-1000X"}, - {0x596007, "MOTIF II A.N.C."}, - {0x612907, "Redmi Buds 4 Lite"}, - {0x614199, "Oraimo FreePods Pro"}, - {0x625740, "LG-TONE-NP3"}, - {0x641372, "Sony WI-1000X"}, - {0x641630, "boAt Airdopes 452"}, - {0x664454, "JBL TUNE 520BT"}, - {0x706908, "Sony WH-1000XM3"}, - {0x837980, "Sony WH-1000XM3"}, - {0x855347, "NIRVANA NEBULA"}, - {0x861698, "LinkBuds"}, - {0xCB2FE7, "soundcore Motion X500"}, + {0xCD8256}, + {0x0000F0}, + {0xF00000}, + {0x821F66}, + {0xF52494}, + {0x718FA4}, + {0x0002F0}, + {0x92BBBD}, + {0x000006}, + {0x060000}, + {0xD446A7}, + {0x2D7A23}, + {0x0E30C3}, + {0x72EF8D}, + {0x72FB00}, + {0x0003F0}, + {0x002000}, + {0x003000}, + {0x003001}, + {0x00A168}, + {0x00AA48}, + {0x00AA91}, + {0x00C95C}, + {0x01EEB4}, + {0x02AA91}, + {0x01C95C}, + {0x02D815}, + {0x035764}, + {0x038CC7}, + {0x02DD4F}, + {0x02E2A9}, + {0x035754}, + {0x02C95C}, + {0x038B91}, + {0x02F637}, + {0x02D886}, + {0xF00000}, + {0xF00001}, + {0xF00201}, + {0xF00204}, + {0xF00209}, + {0xF00205}, + {0xF00200}, + {0xF00208}, + {0xF00207}, + {0xF00206}, + {0xF0020A}, + {0xF0020B}, + {0xF0020C}, + {0xF00203}, + {0xF00202}, + {0xF00213}, + {0xF0020F}, + {0xF0020E}, + {0xF00214}, + {0xF00212}, + {0xF0020D}, + {0xF00211}, + {0xF00215}, + {0xF00210}, + {0xF00305}, + {0xF00304}, + {0xF00308}, + {0xF00303}, + {0xF00306}, + {0xF00300}, + {0xF00309}, + {0xF00302}, + {0xF00307}, + {0xF00301}, + {0xF00E97}, + {0x04ACFC}, + {0x04AA91}, + {0x04AFB8}, + {0x05A963}, + {0x05AA91}, + {0x05C452}, + {0x05C95C}, + {0x0602F0}, + {0x0603F0}, + {0x1E8B18}, + {0x1E955B}, + {0x1EC95C}, + {0x1ED9F9}, + {0x1EE890}, + {0x1EEDF5}, + {0x1F1101}, + {0x1F181A}, + {0x1F2E13}, + {0x1F4589}, + {0x1F4627}, + {0x1F5865}, + {0x1FBB50}, + {0x1FC95C}, + {0x1FE765}, + {0x1FF8FA}, + {0x201C7C}, + {0x202B3D}, + {0x20330C}, + {0x003B41}, + {0x003D8A}, + {0x005BC3}, + {0x008F7D}, + {0x00FA72}, + {0x0100F0}, + {0x011242}, + {0x013D8A}, + {0x01AA91}, + {0x038F16}, + {0x039F8F}, + {0x03AA91}, + {0x03B716}, + {0x03C95C}, + {0x03C99C}, + {0x03F5D4}, + {0x045754}, + {0x045764}, + {0x04C95C}, + {0x050F0C}, + {0x052CC7}, + {0x057802}, + {0x0582FD}, + {0x058D08}, + {0x06AE20}, + {0x06C197}, + {0x06C95C}, + {0x06D8FC}, + {0x0744B6}, + {0x07A41C}, + {0x07C95C}, + {0x07F426}, + {0x0102F0}, + {0x0202F0}, + {0x0302F0}, + {0x0402F0}, + {0x0502F0}, + {0x0702F0}, + {0x0802F0}, + {0x054B2D}, + {0x0660D7}, + {0x0103F0}, + {0x0203F0}, + {0x0303F0}, + {0x0403F0}, + {0x0503F0}, + {0x0703F0}, + {0x0803F0}, + {0x0903F0}, + {0x0102F0}, + {0x0202F0}, + {0x0302F0}, + {0x0402F0}, + {0x0502F0}, + {0x060000}, + {0x070000}, + {0x0702F0}, + {0x071C74}, + {0x080000}, + {0x0802F0}, + {0x090000}, + {0x0A0000}, + {0x0B0000}, + {0x0C0000}, + {0x0DC6BF}, + {0x0DC95C}, + {0x0DEC2B}, + {0x0E138D}, + {0x0EC95C}, + {0x0ECE95}, + {0x0F0993}, + {0x0F1B8D}, + {0x0F232A}, + {0x0F2D16}, + {0x20A19B}, + {0x20C95C}, + {0x20CC2C}, + {0x213C8C}, + {0x21521D}, + {0x21A04E}, + {0x2D7A23}, + {0x350000}, + {0x470000}, + {0x480000}, + {0x490000}, + {0x5BA9B5}, + {0x5BACD6}, + {0x5BD6C9}, + {0x5BE3D4}, + {0x5C0206}, + {0x5C0C84}, + {0x5C4833}, + {0x5C4A7E}, + {0x5C55E7}, + {0x5C7CDC}, + {0x5C8AA5}, + {0x5CC900}, + {0x5CC901}, + {0x5CC902}, + {0x5CC903}, + {0x5CC904}, + {0x5CC905}, + {0x5CC906}, + {0x5CC907}, + {0x5CC908}, + {0x5CC909}, + {0x5CC90A}, + {0x5CC90B}, + {0x5CC90C}, + {0x5CC90D}, + {0x5CC90E}, + {0x5CC90F}, + {0x5CC910}, + {0x5CC911}, + {0x5CC912}, + {0x5CC913}, + {0x5CC914}, + {0x5CC915}, + {0x5CC916}, + {0x5CC917}, + {0x5CC918}, + {0x5CC919}, + {0x5CC91A}, + {0x5CC91B}, + {0x5CC91C}, + {0x5CC91D}, + {0x5CC91E}, + {0x5CC91F}, + {0x5CC920}, + {0x5CC921}, + {0x5CC922}, + {0x5CC923}, + {0x5CC924}, + {0x5CC925}, + {0x5CC926}, + {0x5CC927}, + {0x5CC928}, + {0x5CC929}, + {0x5CC92A}, + {0x5CC92B}, + {0x5CC92C}, + {0x5CC92D}, + {0x5CC92E}, + {0x5CC92F}, + {0x5CC930}, + {0x5CC931}, + {0x5CC932}, + {0x5CC933}, + {0x5CC934}, + {0x5CC935}, + {0x5CC936}, + {0x5CC937}, + {0x5CC938}, + {0x5CC939}, + {0x5CC93A}, + {0x5CC93B}, + {0x5CC93C}, + {0x5CC93D}, + {0x5CC93E}, + {0x5CC93F}, + {0x5CC940}, + {0x5CC941}, + {0x5CC942}, + {0x5CC943}, + {0x5CC944}, + {0x5CC945}, + {0x5CEE3C}, + {0x6AD226}, + {0x6B1C64}, + {0x6B8C65}, + {0x6B9304}, + {0x6BA5C3}, + {0x6C42C0}, + {0x6C4DE5}, + {0x718FA4}, + {0x89BAD5}, + {0x8A31B7}, + {0x8A3D00}, + {0x8A3D01}, + {0x8A8F23}, + {0x8AADAE}, + {0x8B0A91}, + {0x8B5A7B}, + {0x8B66AB}, + {0x8BB0A0}, + {0x8BF79A}, + {0x8C07D2}, + {0x8C1706}, + {0x8C4236}, + {0x8C6B6A}, + {0x8CAD81}, + {0x8CB05C}, + {0x8CD10F}, + {0x8D13B9}, + {0x8D16EA}, + {0x8D5B67}, + {0x8E14D7}, + {0x8E1996}, + {0x8E4666}, + {0x8E5550}, + {0x9101F0}, + {0x9128CB}, + {0x913B0C}, + {0x915CFA}, + {0x9171BE}, + {0x917E46}, + {0x91AA00}, + {0x91AA01}, + {0x91AA02}, + {0x91AA03}, + {0x91AA04}, + {0x91AA05}, + {0x91BD38}, + {0x91C813}, + {0x91DABC}, + {0x92255E}, + {0x989D0A}, + {0x9939BC}, + {0x994374}, + {0x997B4A}, + {0x99C87B}, + {0x99D7EA}, + {0x99F098}, + {0x9A408A}, + {0x9A9BDD}, + {0x9ADB11}, + {0x9AEEA4}, + {0x9B7339}, + {0x9B735A}, + {0x9B9872}, + {0x9BC64D}, + {0x9BE931}, + {0x9C0AF7}, + {0x9C3997}, + {0x9C4058}, + {0x9C6BC0}, + {0x9C888B}, + {0x9C98DB}, + {0x9CA277}, + {0x9CB5F3}, + {0x9CB881}, + {0x9CD0F3}, + {0x9CE3C7}, + {0x9CEFD1}, + {0x9CF08F}, + {0x9D00A6}, + {0x9D7D42}, + {0x9DB896}, + {0xA7E52B}, + {0xA7EF76}, + {0xA8001A}, + {0xA83C10}, + {0xA8658F}, + {0xA8845A}, + {0xA88B69}, + {0xA8A00E}, + {0xA8A72A}, + {0xA8C636}, + {0xA8CAAD}, + {0xA8E353}, + {0xA8F96D}, + {0xA90358}, + {0xA92498}, + {0xA9394A}, + {0xC6936A}, + {0xC69AFD}, + {0xC6ABEA}, + {0xC6EC5F}, + {0xC7736C}, + {0xC79B91}, + {0xC7A267}, + {0xC7D620}, + {0xC7FBCC}, + {0xC8162A}, + {0xC85D7A}, + {0xC8777E}, + {0xC878AA}, + {0xC8C641}, + {0xC8D335}, + {0xC8E228}, + {0xC9186B}, + {0xC9836A}, + {0xCA7030}, + {0xCAB6B8}, + {0xCAF511}, + {0xCB093B}, + {0xCB529D}, + {0xCC438E}, + {0xCC5F29}, + {0xCC754F}, + {0xCC93A5}, + {0xCCBB7E}, + {0xCD8256}, + {0xD446A7}, + {0xD5A59E}, + {0xD5B5F7}, + {0xD5C6CE}, + {0xD654CD}, + {0xD65F4E}, + {0xD69B2B}, + {0xD6C195}, + {0xD6E870}, + {0xD6EE84}, + {0xD7102F}, + {0xD7E3EB}, + {0xD8058C}, + {0xD820EA}, + {0xD87A3E}, + {0xD8F3BA}, + {0xD8F4E8}, + {0xD90617}, + {0xD933A7}, + {0xD9414F}, + {0xD97EBA}, + {0xD9964B}, + {0xDA0F83}, + {0xDA4577}, + {0xDA5200}, + {0xDAD3A6}, + {0xDADE43}, + {0xDAE096}, + {0xDB8AC7}, + {0xDBE5B1}, + {0xDC5249}, + {0xDCF33C}, + {0xDD4EC0}, + {0xDE215D}, + {0xDE577F}, + {0xDEC04C}, + {0xDEDD6F}, + {0xDEE8C0}, + {0xDEEA86}, + {0xDEF234}, + {0xDF01E3}, + {0xDF271C}, + {0xDF42DE}, + {0xDF4B02}, + {0xDF9BA4}, + {0xDFD433}, + {0xE020C1}, + {0xE06116}, + {0xE07634}, + {0xE09172}, + {0xE4E457}, + {0xE5440B}, + {0xE57363}, + {0xE57B57}, + {0xE5B4B0}, + {0xE5B91B}, + {0xE5E2E9}, + {0xE64613}, + {0xE64CC6}, + {0xE69877}, + {0xE6E37E}, + {0xE6E771}, + {0xE6E8B8}, + {0xE750CE}, + {0xF52494}, + {0x000006}, + {0x00000A}, + {0x00000C}, + {0x000049}, + {0x003001}, + {0x003D8A}, + {0x0052DA}, + {0x109201}, + {0x124366}, + {0x126644}, + {0x284500}, + {0x532011}, + {0x549547}, + {0x567679}, + {0x575836}, + {0x596007}, + {0x612907}, + {0x614199}, + {0x625740}, + {0x641372}, + {0x641630}, + {0x664454}, + {0x706908}, + {0x837980}, + {0x855347}, + {0x861698}, + {0xCB2FE7}, }; const uint16_t BLESpamView::fastpairModels_count = COUNT_OF(fastpairModels); diff --git a/firmware/application/external/blespam/ui_blespam.hpp b/firmware/application/external/blespam/ui_blespam.hpp index ab33bffcc..f1b4f93f8 100644 --- a/firmware/application/external/blespam/ui_blespam.hpp +++ b/firmware/application/external/blespam/ui_blespam.hpp @@ -27,6 +27,8 @@ #ifndef __UI_BLESPAM_H__ #define __UI_BLESPAM_H__ +#define BLESPMUSECONSOLE 1 + #include "ui.hpp" #include "ui_language.hpp" #include "ui_navigation.hpp" @@ -111,9 +113,10 @@ class BLESpamView : public View { LanguageHelper::currentMessages[LANG_START]}; Checkbox chk_randdev{{100, 16}, 10, "Rnd device", true}; +#ifdef BLESPMUSECONSOLE Console console{ {0, 70, 240, 220}}; - +#endif OptionsField options_atkmode{ {0 * 8, 2 * 8}, 10, @@ -134,7 +137,7 @@ class BLESpamView : public View { bool randomDev{true}; uint8_t channel_number = 37; - char mac[13] = "010203040507"; + char mac[13] = "010203040407"; char advertisementData[63] = {"03032CFE06162CFED5A59E020AB4\0"}; PKT_TYPE pduType = {PKT_TYPE_DISCOVERY}; @@ -161,6 +164,8 @@ class BLESpamView : public View { this->on_tx_progress(message.done); }}; + uint8_t packet[80]; + // continuity typedef enum { @@ -227,7 +232,7 @@ class BLESpamView : public View { static const uint16_t fastpairModels_count; typedef struct { uint32_t value; - const char* name; // could be moved too + // const char* name; // could be moved too } fpUi32; static const fpUi32 fastpairModels[]; diff --git a/firmware/application/external/jammer/ui_jammer.hpp b/firmware/application/external/jammer/ui_jammer.hpp index b3e2550e1..d39d48b8d 100644 --- a/firmware/application/external/jammer/ui_jammer.hpp +++ b/firmware/application/external/jammer/ui_jammer.hpp @@ -21,6 +21,7 @@ */ #include "ui.hpp" +#include "ui_language.hpp" #include "ui_widget.hpp" #include "ui_styles.hpp" #include "ui_navigation.hpp" @@ -56,8 +57,8 @@ class RangeView : public View { const Style& style_info = Styles::grey; Labels labels{ - {{2 * 8, 8 * 8 + 4}, "Start", Color::light_grey()}, - {{23 * 8, 8 * 8 + 4}, "Stop", Color::light_grey()}, + {{2 * 8, 8 * 8 + 4}, LanguageHelper::currentMessages[LANG_START], Color::light_grey()}, + {{23 * 8, 8 * 8 + 4}, LanguageHelper::currentMessages[LANG_STOP], Color::light_grey()}, {{12 * 8, 5 * 8 - 4}, "Center", Color::light_grey()}, {{12 * 8 + 4, 13 * 8}, "Width", Color::light_grey()}}; @@ -226,7 +227,7 @@ class JammerView : public View { Button button_transmit{ {148, 216, 80, 80}, - "START"}; + LanguageHelper::currentMessages[LANG_START]}; MessageHandlerRegistration message_handler_retune{ Message::ID::Retune, From 794fece8cc81f32c5edeb8625136be9bf8901ada Mon Sep 17 00:00:00 2001 From: gullradriel <3157857+gullradriel@users.noreply.github.com> Date: Thu, 28 Dec 2023 11:25:53 +0100 Subject: [PATCH 10/13] Recon raw repeat (#1658) * UI for Recon Repeater config * persistent recon repeat settings * record_view: added possibility to force keep the provided record filename * working auto record to same file * Recon TX * added Repeater type * adding yellow coloring on Repeater config+a modal, comments in the code * default repeater values --- firmware/application/apps/ui_freqman.cpp | 3 +- firmware/application/apps/ui_freqman.hpp | 3 +- firmware/application/apps/ui_recon.cpp | 283 +++++++++++++++--- firmware/application/apps/ui_recon.hpp | 77 ++++- .../application/apps/ui_recon_settings.cpp | 41 ++- .../application/apps/ui_recon_settings.hpp | 51 +++- firmware/application/apps/ui_scanner.cpp | 1 + firmware/application/freqman_db.cpp | 25 +- firmware/application/freqman_db.hpp | 4 +- firmware/application/ui_record_view.cpp | 15 +- firmware/application/ui_record_view.hpp | 2 + .../common/portapack_persistent_memory.cpp | 40 +++ .../common/portapack_persistent_memory.hpp | 10 + firmware/test/application/test_freqman_db.cpp | 21 ++ 14 files changed, 514 insertions(+), 62 deletions(-) diff --git a/firmware/application/apps/ui_freqman.cpp b/firmware/application/apps/ui_freqman.cpp index 453cda2b4..47f971c0e 100644 --- a/firmware/application/apps/ui_freqman.cpp +++ b/firmware/application/apps/ui_freqman.cpp @@ -412,7 +412,8 @@ void FrequencyEditView::refresh_ui() { auto is_range = entry_.type == freqman_type::Range; auto is_ham = entry_.type == freqman_type::HamRadio; - auto has_freq_b = is_range || is_ham; + auto is_repeater = entry_.type == freqman_type::Repeater; + auto has_freq_b = is_range || is_ham || is_repeater; field_freq_b.set_style(has_freq_b ? &Styles::white : &Styles::grey); field_step.set_style(is_range ? &Styles::white : &Styles::grey); diff --git a/firmware/application/apps/ui_freqman.hpp b/firmware/application/apps/ui_freqman.hpp index 03a7f021b..0ece16a37 100644 --- a/firmware/application/apps/ui_freqman.hpp +++ b/firmware/application/apps/ui_freqman.hpp @@ -220,7 +220,8 @@ class FrequencyEditView : public View { {"Single", 0}, {"Range", 1}, {"HamRadio", 2}, - {"Raw", 3}, + {"Repeater", 3}, + {"Raw", 4}, }}; FrequencyField field_freq_a{{13 * 8, 4 * 16}}; diff --git a/firmware/application/apps/ui_recon.cpp b/firmware/application/apps/ui_recon.cpp index cdfc63d74..1dafadf0e 100644 --- a/firmware/application/apps/ui_recon.cpp +++ b/firmware/application/apps/ui_recon.cpp @@ -22,13 +22,24 @@ */ #include "ui_recon.hpp" -#include "ui_fileman.hpp" #include "ui_freqman.hpp" #include "capture_app.hpp" #include "convert.hpp" #include "file.hpp" #include "file_reader.hpp" #include "tone_key.hpp" +#include "replay_app.hpp" +#include "string_format.hpp" +#include "ui_fileman.hpp" +#include "io_file.hpp" +#include "io_convert.hpp" +#include "oversample.hpp" +#include "baseband_api.hpp" +#include "metadata_file.hpp" +#include "portapack.hpp" +#include "portapack_persistent_memory.hpp" +#include "utility.hpp" +#include "replay_thread.hpp" using namespace portapack; using namespace tonekey; @@ -37,6 +48,30 @@ namespace fs = std::filesystem; namespace ui { +void ReconView::reload_restart_recon() { + frequency_file_load(); + if (frequency_list.size() > 0) { + if (fwd) { + button_dir.set_text("FW>"); + } else { + button_dir.set_text(" FREQMAN_MAX_PER_FILE) { + file_name.set_style(&Styles::yellow); + } +} + void ReconView::check_update_ranges_from_current() { if (frequency_list.size() && current_is_valid() && current_entry().type == freqman_type::Range) { if (update_ranges && !manual_mode) { @@ -75,8 +110,12 @@ void ReconView::recon_stop_recording() { button_audio_app.set_text("AUDIO"); button_audio_app.set_style(&Styles::white); record_view->stop(); - button_config.set_style(&Styles::white); // disable config while recording as it's causing an IO error pop up at exit + button_config.set_style(&Styles::white); is_recording = false; + // repeater mode + if (persistent_memory::recon_repeat_recorded()) { + start_repeat(); + } } } @@ -111,6 +150,9 @@ void ReconView::update_description() { case freqman_type::HamRadio: description = "H: "; break; + case freqman_type::Repeater: + description = "L: "; + break; default: description = "S: "; } @@ -182,6 +224,7 @@ void ReconView::load_persisted_settings() { load_freqs = persistent_memory::recon_load_freqs(); load_ranges = persistent_memory::recon_load_ranges(); load_hamradios = persistent_memory::recon_load_hamradios(); + load_repeaters = persistent_memory::recon_load_repeaters(); update_ranges = persistent_memory::recon_update_ranges_when_recon(); auto_record_locked = persistent_memory::recon_auto_record_locked(); } @@ -275,9 +318,20 @@ ReconView::~ReconView() { ReconView::ReconView(NavigationView& nav) : nav_{nav} { chrono_start = chTimeNow(); + + tx_view.hidden(true); + + // set record View record_view = std::make_unique(Rect{0, 0, 30 * 8, 1 * 16}, - u"AUTO_AUDIO_", u"AUDIO", + u"AUTO_AUDIO", u"AUDIO", RecordView::FileType::WAV, 4096, 4); + record_view->set_filename_date_frequency(true); + record_view->set_auto_trim(false); + record_view->hidden(true); + record_view->on_error = [&nav](std::string message) { + nav.display_modal("Error", message); + }; + add_children({&labels, &field_lna, &field_vga, @@ -314,13 +368,9 @@ ReconView::ReconView(NavigationView& nav) &button_restart, &button_mic_app, &button_remove, - record_view.get()}); - - record_view->hidden(true); - record_view->set_filename_date_frequency(true); - record_view->on_error = [&nav](std::string message) { - nav.display_modal("Error", message); - }; + record_view.get(), + &progressbar, + &tx_view}); def_step = 0; load_persisted_settings(); @@ -566,27 +616,7 @@ ReconView::ReconView(NavigationView& nav) }; button_restart.on_select = [this](Button&) { - frequency_file_load(); - if (frequency_list.size() > 0) { - if (fwd) { - button_dir.set_text("FW>"); - } else { - button_dir.set_text(" FREQMAN_MAX_PER_FILE) { - file_name.set_style(&Styles::yellow); - } + reload_restart_recon(); }; button_add.on_select = [this](ButtonWithEncoder&) { @@ -704,6 +734,9 @@ ReconView::ReconView(NavigationView& nav) change_mode(AM_MODULATION); // start on AM. field_mode.set_by_value(AM_MODULATION); // reflect the mode into the manual selector + // tx progress bar + progressbar.hidden(true); + if (filedelete) { delete_file(freq_file_path); } @@ -741,7 +774,8 @@ void ReconView::frequency_file_load() { freqman_load_options options{ .load_freqs = load_freqs, .load_ranges = load_ranges, - .load_hamradios = load_hamradios}; + .load_hamradios = load_hamradios, + .load_repeaters = load_repeaters}; if (!load_freqman_file(file_input, frequency_list, options) || frequency_list.empty()) { file_name.set_style(&Styles::red); desc_cycle.set("...empty file..."); @@ -776,6 +810,12 @@ void ReconView::frequency_file_load() { } void ReconView::on_statistics_update(const ChannelStatistics& statistics) { + if (recon_tx) + return; + + if (is_repeat_active()) + return; + chrono_end = chTimeNow(); systime_t time_interval = chrono_end - chrono_start; chrono_start = chrono_end; @@ -835,9 +875,9 @@ void ReconView::on_statistics_update(const ChannelStatistics& statistics) { // contents of a possible recon_start_recording(), but not yet since it's only called once if (auto_record_locked && !is_recording) { button_audio_app.set_style(&Styles::red); - if (field_mode.selected_index_value() == SPEC_MODULATION) + if (field_mode.selected_index_value() == SPEC_MODULATION) { button_audio_app.set_text("RAW REC"); - else + } else button_audio_app.set_text("WAV REC"); record_view->start(); button_config.set_style(&Styles::light_grey); // disable config while recording as it's causing an IO error pop up at exit @@ -956,6 +996,26 @@ void ReconView::on_statistics_update(const ChannelStatistics& statistics) { } } } + } else if (current_entry().type == freqman_type::Repeater) { + // repeater is like single, we only listen on frequency_a and then jump to next entry + if ((fwd && stepper == 0) || stepper > 0) { // forward + current_index++; + entry_has_changed = true; + // looping + if ((uint32_t)current_index >= frequency_list.size()) { + has_looped = true; + current_index = 0; + } + } else if ((!fwd && stepper == 0) || stepper < 0) { + // reverse + current_index--; + entry_has_changed = true; + // if previous if under the list => go back from end + if (current_index < 0) { + has_looped = true; + current_index = frequency_list.size() - 1; + } + } } // set index to boundary if !continuous if (has_looped && !continuous) { @@ -984,6 +1044,7 @@ void ReconView::on_statistics_update(const ChannelStatistics& statistics) { if (entry_has_changed) { timer = 0; switch (current_entry().type) { + case freqman_type::Repeater: case freqman_type::Single: freq = current_entry().frequency_a; break; @@ -1017,7 +1078,7 @@ void ReconView::on_statistics_update(const ChannelStatistics& statistics) { if (stepper > 0) stepper--; } // if( recon || stepper != 0 || index_stepper != 0 ) } // if (frequency_list.size() > 0 ) - } /* on_statistic_updates */ + } /* on_statistics_updates */ } handle_retune(); recon_redraw(); @@ -1080,28 +1141,39 @@ void ReconView::on_stepper_delta(int32_t v) { } size_t ReconView::change_mode(freqman_index_t new_mod) { + if (recon_tx || is_repeat_active()) + return 0; field_mode.on_change = [this](size_t, OptionsField::value_t) {}; field_bw.on_change = [this](size_t, OptionsField::value_t) {}; recon_stop_recording(); - remove_child(record_view.get()); - record_view.reset(); - if (new_mod == SPEC_MODULATION) { + if (record_view != nullptr) { + remove_child(record_view.get()); + record_view.reset(); + } + if (persistent_memory::recon_repeat_recorded()) { + record_view = std::make_unique(Rect{0, 0, 30 * 8, 1 * 16}, + u"RECON_REPEAT.C16", u"CAPTURES", + RecordView::FileType::RawS16, 16384, 3); + record_view->set_filename_as_is(true); + } else if (new_mod == SPEC_MODULATION) { audio::output::stop(); record_view = std::make_unique(Rect{0, 0, 30 * 8, 1 * 16}, - u"AUTO_RAW_", u"CAPTURES", + u"AUTO_RAW", u"CAPTURES", RecordView::FileType::RawS16, 16384, 3); } else { record_view = std::make_unique(Rect{0, 0, 30 * 8, 1 * 16}, - u"AUTO_AUDIO_", u"AUDIO", + u"AUTO_AUDIO", u"AUDIO", RecordView::FileType::WAV, 4096, 4); + record_view->set_filename_date_frequency(true); } + record_view->set_auto_trim(false); add_child(record_view.get()); record_view->hidden(true); - record_view->set_filename_date_frequency(true); record_view->on_error = [this](std::string message) { nav_.display_modal("Error", message); }; receiver_model.disable(); + transmitter_model.disable(); baseband::shutdown(); size_t recording_sampling_rate = 0; switch (new_mod) { @@ -1144,7 +1216,6 @@ size_t ReconView::change_mode(freqman_index_t new_mod) { field_bw.on_change = [this](size_t, OptionsField::value_t sampling_rate) { // record_view determines the correct oversampling to apply and returns the actual sample rate. auto actual_sampling_rate = record_view->set_sampling_rate(sampling_rate); - // The radio needs to know the effective sampling rate. receiver_model.set_sampling_rate(actual_sampling_rate); receiver_model.set_baseband_bandwidth(filter_bandwidth_for_sampling_rate(actual_sampling_rate)); @@ -1222,4 +1293,132 @@ void ReconView::handle_remove_current_item() { update_description(); } +void ReconView::on_repeat_tx_progress(const uint32_t progress) { + progressbar.set_value(progress); +} + +void ReconView::repeat_file_error(const std::filesystem::path& path, const std::string& message) { + nav_.display_modal("Error", "Error opening file \n" + path.string() + "\n" + message); +} + +bool ReconView::is_repeat_active() const { + return replay_thread != nullptr; +} + +void ReconView::start_repeat() { + // Prepare to send a file. + std::filesystem::path rawfile = u"/" + repeat_rec_path + u"/" + repeat_rec_file; + std::filesystem::path rawmeta = u"/" + repeat_rec_path + u"/" + repeat_rec_meta; + + if (recon_tx == false) { + recon_tx = true; + + if (record_view != nullptr) { + record_view->stop(); + remove_child(record_view.get()); + record_view.reset(); + } + + receiver_model.disable(); + transmitter_model.disable(); + baseband::shutdown(); + + baseband::run_image(portapack::spi_flash::image_tag_replay); + + size_t rawsize = 0; + { + File capture_file; + auto error = capture_file.open(rawfile); + if (error) { + repeat_file_error(rawfile, "Can't open file to send for size"); + return; + } + rawsize = capture_file.size(); + } + + // Reset the transmit progress bar. + uint8_t sample_size = std::filesystem::capture_file_sample_size(rawfile); + progressbar.set_value(0); + progressbar.set_max(rawsize * sizeof(complex16_t) / sample_size); + progressbar.hidden(false); + + auto metadata = read_metadata_file(rawmeta); + // If no metadata found, fallback to the TX frequency. + if (!metadata) { + metadata = {freq, 500'000}; + repeat_file_error(rawmeta, "Can't open file to read meta, using default rx_freq,500'000"); + } + + // Update the sample rate in proc_replay baseband. + baseband::set_sample_rate(metadata->sample_rate, + get_oversample_rate(metadata->sample_rate)); + + transmitter_model.set_sampling_rate(get_actual_sample_rate(metadata->sample_rate)); + transmitter_model.set_baseband_bandwidth(metadata->sample_rate <= 500'000 ? 1'750'000 : 2'500'000); // TX LPF min 1M75 for SR <=500K, and 2M5 (by experimental test) for SR >500K + + // set TX to repeater TX freq if entry is Repeater, else use recorded one + if (current_entry().type == freqman_type::Repeater) { + transmitter_model.set_target_frequency(current_entry().frequency_b); + } else { + transmitter_model.set_target_frequency(metadata->center_frequency); + } + + // set TX powers and enable transmitter + transmitter_model.set_tx_gain(persistent_memory::recon_repeat_gain()); + transmitter_model.set_rf_amp(persistent_memory::recon_repeat_amp()); + transmitter_model.enable(); + } + + // clear replay thread and set reader + replay_thread.reset(); + auto reader = std::make_unique(); + auto error = reader->open(rawfile); + if (error) { + repeat_file_error(rawfile, "Can't open file to send to thread"); + return; + } + repeat_ready_signal = true; + repeat_cur_rep++; + + // ReplayThread starts immediately on construction; must be set before creating. + replay_thread = std::make_unique( + std::move(reader), + /* read_size */ repeat_read_size, + /* buffer_count */ repeat_buffer_count, + &repeat_ready_signal, + [](uint32_t return_code) { + ReplayThreadDoneMessage message{return_code}; + EventDispatcher::send_message(message); + }); +} + +void ReconView::stop_repeat(const bool do_loop) { + repeat_ready_signal = false; + + if (is_repeat_active()) { + replay_thread.reset(); + transmitter_model.disable(); + } + + // repeat transmit if current number of repetitions (repeat_cur_rep) is < recon configured number of repetitions (recon_repeat_nb) + if (do_loop && repeat_cur_rep < persistent_memory::recon_repeat_nb()) { + start_repeat(); + } else { + repeat_cur_rep = 0; + recon_tx = false; + reload_restart_recon(); + progressbar.hidden(true); + set_dirty(); // fix progressbar no hiding + } +} + +void ReconView::handle_repeat_thread_done(const uint32_t return_code) { + if (return_code == ReplayThread::END_OF_FILE) { + stop_repeat(true); + } else if (return_code == ReplayThread::READ_ERROR) { + stop_repeat(false); + repeat_file_error(u"/" + repeat_rec_path + u"/" + repeat_rec_file, "Can't open file to send."); + } +} + } /* namespace ui */ diff --git a/firmware/application/apps/ui_recon.hpp b/firmware/application/apps/ui_recon.hpp index 477524c41..141db39fc 100644 --- a/firmware/application/apps/ui_recon.hpp +++ b/firmware/application/apps/ui_recon.hpp @@ -41,10 +41,20 @@ #include "app_settings.hpp" #include "radio_state.hpp" #include "ui_recon_settings.hpp" +#include "ui_transmitter.hpp" +#include "replay_thread.hpp" +#include "metadata_file.hpp" +#include "ui_widget.hpp" +#include "ui_navigation.hpp" +#include "ui_freq_field.hpp" +#include "ui_spectrum.hpp" + +#include +#include namespace ui { -#define RECON_CFG_FILE "SETTINGS/recon.cfg" +#define RECON_CFG_FILE u"SETTINGS/recon.cfg" enum class recon_mode : uint8_t { Recon, @@ -66,10 +76,17 @@ class ReconView : public View { private: NavigationView& nav_; - RxRadioState radio_state_{}; + RxRadioState rx_radio_state_{}; + TxRadioState tx_radio_state_{ + 0 /* frequency */, + 1750000 /* bandwidth */, + 500000 /* sampling rate */ + }; app_settings::SettingsManager settings_{ - "rx_recon"sv, app_settings::Mode::RX}; + "rx_tx_recon"sv, app_settings::Mode::RX_TX}; + ; + void reload_restart_recon(); void check_update_ranges_from_current(); void set_loop_config(bool v); void clear_freqlist_for_ui_action(); @@ -125,6 +142,7 @@ class ReconView : public View { bool load_freqs{true}; bool load_ranges{true}; bool load_hamradios{true}; + bool load_repeaters{true}; bool update_ranges{true}; bool fwd{true}; bool recon{true}; @@ -163,6 +181,25 @@ class ReconView : public View { systime_t chrono_start{}; systime_t chrono_end{}; + const std::filesystem::path repeat_rec_file = u"RECON_REPEAT.C16"; + const std::filesystem::path repeat_rec_meta = u"RECON_REPEAT.TXT"; + const std::filesystem::path repeat_rec_path = u"CAPTURES"; + const size_t repeat_read_size{16384}; + const size_t repeat_buffer_count{3}; + int8_t repeat_cur_rep = 0; + int64_t repeat_sample_rate = 0; + static constexpr uint32_t repeat_bandwidth = 2500000; + void on_repeat_tx_progress(const uint32_t progress); + void start_repeat(); + void stop_repeat(const bool do_loop); + bool is_repeat_active() const; + void handle_repeat_thread_done(const uint32_t return_code); + void repeat_file_error(const std::filesystem::path& path, const std::string& message); + std::filesystem::path repeat_file_path{}; + std::unique_ptr replay_thread{}; + bool repeat_ready_signal{false}; + bool recon_tx{false}; + // Persisted settings. SettingsStore ui_settings{ "recon"sv, @@ -354,17 +391,47 @@ class ReconView : public View { {168, (35 * 8) - 4, 72, 28}, ""}; + ProgressBar progressbar{ + {0 * 8, SCREEN_H / 2 - 16, SCREEN_W, 32}}; + + TransmitterView2 tx_view{ + {11 * 8, 2 * 16}, + /*short_ui*/ true}; + MessageHandlerRegistration message_handler_coded_squelch{ Message::ID::CodedSquelch, [this](const Message* const p) { const auto message = *reinterpret_cast(p); - this->handle_coded_squelch(message.value); + handle_coded_squelch(message.value); }}; MessageHandlerRegistration message_handler_stats{ Message::ID::ChannelStatistics, [this](const Message* const p) { - this->on_statistics_update(static_cast(p)->statistics); + on_statistics_update(static_cast(p)->statistics); + }}; + + MessageHandlerRegistration message_handler_replay_thread_error{ + Message::ID::ReplayThreadDone, + [this](const Message* p) { + auto message = *reinterpret_cast(p); + handle_repeat_thread_done(message.return_code); + }}; + + MessageHandlerRegistration message_handler_fifo_signal{ + Message::ID::RequestSignal, + [this](const Message* p) { + auto message = static_cast(p); + if (message->signal == RequestSignalMessage::Signal::FillRequest) { + repeat_ready_signal = true; + } + }}; + + MessageHandlerRegistration message_handler_tx_progress{ + Message::ID::TXProgress, + [this](const Message* p) { + auto message = *reinterpret_cast(p); + on_repeat_tx_progress(message.progress); }}; }; diff --git a/firmware/application/apps/ui_recon_settings.cpp b/firmware/application/apps/ui_recon_settings.cpp index 00a449984..d400a8da8 100644 --- a/firmware/application/apps/ui_recon_settings.cpp +++ b/firmware/application/apps/ui_recon_settings.cpp @@ -99,8 +99,13 @@ void ReconSetupViewMore::save() { persistent_memory::set_recon_load_freqs(checkbox_load_freqs.value()); persistent_memory::set_recon_load_ranges(checkbox_load_ranges.value()); persistent_memory::set_recon_load_hamradios(checkbox_load_hamradios.value()); + persistent_memory::set_recon_load_repeaters(checkbox_load_repeaters.value()); persistent_memory::set_recon_update_ranges_when_recon(checkbox_update_ranges_when_recon.value()); persistent_memory::set_recon_auto_record_locked(checkbox_auto_record_locked.value()); + persistent_memory::set_recon_repeat_recorded(checkbox_repeat_recorded.value()); + persistent_memory::set_recon_repeat_nb(field_repeat_nb.value()); + persistent_memory::set_recon_repeat_amp(checkbox_repeat_amp.value()); + persistent_memory::set_recon_repeat_gain(field_repeat_gain.value()); }; void ReconSetupViewMain::focus() { @@ -113,16 +118,50 @@ ReconSetupViewMore::ReconSetupViewMore(NavigationView& nav, Rect parent_rect) hidden(true); add_children({&checkbox_load_freqs, + &checkbox_load_repeaters, &checkbox_load_ranges, &checkbox_load_hamradios, &checkbox_update_ranges_when_recon, - &checkbox_auto_record_locked}); + &checkbox_auto_record_locked, + &checkbox_repeat_recorded, + &text_repeat_nb, + &field_repeat_nb, + &checkbox_repeat_amp, + &text_repeat_gain, + &field_repeat_gain}); + + // tx options have to be in yellow to inform the users that activating them will make the device transmit + checkbox_repeat_recorded.set_style(&Styles::yellow); + text_repeat_nb.set_style(&Styles::yellow); + field_repeat_nb.set_style(&Styles::yellow); + checkbox_repeat_amp.set_style(&Styles::yellow); + text_repeat_gain.set_style(&Styles::yellow); + field_repeat_gain.set_style(&Styles::yellow); checkbox_load_freqs.set_value(persistent_memory::recon_load_freqs()); + checkbox_load_repeaters.set_value(persistent_memory::recon_load_repeaters()); checkbox_load_ranges.set_value(persistent_memory::recon_load_ranges()); checkbox_load_hamradios.set_value(persistent_memory::recon_load_hamradios()); checkbox_update_ranges_when_recon.set_value(persistent_memory::recon_update_ranges_when_recon()); checkbox_auto_record_locked.set_value(persistent_memory::recon_auto_record_locked()); + checkbox_repeat_recorded.set_value(persistent_memory::recon_repeat_recorded()); + checkbox_repeat_amp.set_value(persistent_memory::recon_repeat_amp()); + field_repeat_nb.set_value(persistent_memory::recon_repeat_nb()); + field_repeat_gain.set_value(persistent_memory::recon_repeat_gain()); + + // tx warning modal + checkbox_repeat_recorded.on_select = [this, &nav](Checkbox&, bool v) { + if (v) { + nav.display_modal( + "TX WARNING", + "This activate TX ability\nin Recon !", + YESNO, + [this, &nav](bool choice) { + if (!choice) + checkbox_repeat_recorded.set_value(choice); + }); + } + }; }; void ReconSetupViewMore::focus() { diff --git a/firmware/application/apps/ui_recon_settings.hpp b/firmware/application/apps/ui_recon_settings.hpp index 27bd7ab47..01ae43310 100644 --- a/firmware/application/apps/ui_recon_settings.hpp +++ b/firmware/application/apps/ui_recon_settings.hpp @@ -30,6 +30,7 @@ #include "ui_tabview.hpp" #include "ui_navigation.hpp" #include "string_format.hpp" +#include "ui_styles.hpp" // 1Mhz helper #ifdef OneMHz @@ -116,26 +117,70 @@ class ReconSetupViewMore : public View { Checkbox checkbox_load_freqs{ {1 * 8, 12}, 3, - "input: load freqs"}; + "load freq", + true}; + + Checkbox checkbox_load_repeaters{ + {14 * 8, 12}, + 3, + "load repeater", + true}; Checkbox checkbox_load_ranges{ {1 * 8, 42}, 3, - "input: load ranges"}; + "load range", + true}; Checkbox checkbox_load_hamradios{ {1 * 8, 72}, 3, - "input: load hamradios"}; + "load hamradio", + true}; Checkbox checkbox_update_ranges_when_recon{ {1 * 8, 102}, 3, "auto update m-ranges"}; + Checkbox checkbox_auto_record_locked{ {1 * 8, 132}, 3, "record locked periods"}; + + Checkbox checkbox_repeat_recorded{ + {1 * 8, 162}, + 3, + "repeater,"}; + + Text text_repeat_nb{ + {14 * 8, 165, 3 * 8, 22}, + "nb:"}; + + NumberField field_repeat_nb{ + {18 * 8, 165}, + 2, + {1, 99}, + 1, + ' ', + }; + + Checkbox checkbox_repeat_amp{ + {1 * 8, 192}, + 3, + "AMP,"}; + + Text text_repeat_gain{ + {10 * 8, 196, 5 * 8, 22}, + "GAIN:"}; + + NumberField field_repeat_gain{ + {16 * 8, 196}, + 2, + {0, 47}, + 1, + ' ', + }; }; class ReconSetupView : public View { diff --git a/firmware/application/apps/ui_scanner.cpp b/firmware/application/apps/ui_scanner.cpp index 2f0718ba8..902f697d2 100644 --- a/firmware/application/apps/ui_scanner.cpp +++ b/firmware/application/apps/ui_scanner.cpp @@ -564,6 +564,7 @@ void ScannerView::frequency_file_load(const fs::path& path) { def_step_index = entry.step; switch (entry.type) { + case freqman_type::Repeater: case freqman_type::Single: entries.push_back({entry.frequency_a, entry.description}); break; diff --git a/firmware/application/freqman_db.cpp b/firmware/application/freqman_db.cpp index b3ef011f7..6bbc3d776 100644 --- a/firmware/application/freqman_db.cpp +++ b/firmware/application/freqman_db.cpp @@ -185,6 +185,8 @@ bool operator==(const freqman_entry& lhs, const freqman_entry& rhs) { } else if (lhs.type == freqman_type::HamRadio) { equal = lhs.frequency_b == rhs.frequency_b && lhs.tone == rhs.tone; + } else if (lhs.type == freqman_type::Repeater) { + equal = lhs.frequency_b == rhs.frequency_b; } return equal; @@ -248,6 +250,10 @@ std::string pretty_string(const freqman_entry& entry, size_t max_length) { str = "R:" + to_string_rounded_freq(entry.frequency_a, 1) + "M,T:" + to_string_rounded_freq(entry.frequency_b, 1) + "M: " + entry.description; break; + case freqman_type::Repeater: + str = "L:" + to_string_rounded_freq(entry.frequency_a, 1) + "M,T:" + + to_string_rounded_freq(entry.frequency_b, 1) + "M: " + entry.description; + break; case freqman_type::Raw: str = entry.description; break; @@ -292,6 +298,10 @@ std::string to_freqman_string(const freqman_entry& entry) { if (is_valid(entry.tone)) append_field("c", tonekey::tone_key_value_string(entry.tone)); break; + case freqman_type::Repeater: + append_field("l", to_string_dec_uint(entry.frequency_a)); + append_field("t", to_string_dec_uint(entry.frequency_b)); + break; case freqman_type::Raw: return entry.description; default: @@ -372,16 +382,18 @@ bool parse_freqman_entry(std::string_view str, freqman_entry& entry) { parse_int(value, entry.frequency_a); } else if (key == "m") { entry.modulation = find_by_name(freqman_modulations, value); - } else if (key == "r") { + } else if (key == "r") { // HamRadio relay receive freq entry.type = freqman_type::HamRadio; parse_int(value, entry.frequency_a); + } else if (key == "l") { // Portapack Repeater mode listen freq. Used as a single freq if Repeater mode isn't active + entry.type = freqman_type::Repeater; + parse_int(value, entry.frequency_a); } else if (key == "s") { entry.step = find_by_name(freqman_steps_short, value); - } else if (key == "t") { + } else if (key == "t") { // Tx freq: scanned as a single freq in HamRadio mode, used as TX freq in Repeater mode and ignored by the scanner parse_int(value, entry.frequency_b); } } - return is_valid(entry); } @@ -400,7 +412,8 @@ bool parse_freqman_file(const fs::path& path, freqman_db& db, freqman_load_optio if (entry.type == freqman_type::Unknown || (entry.type == freqman_type::Single && !options.load_freqs) || (entry.type == freqman_type::Range && !options.load_ranges) || - (entry.type == freqman_type::HamRadio && !options.load_hamradios)) { + (entry.type == freqman_type::HamRadio && !options.load_hamradios) || + (entry.type == freqman_type::Repeater && !options.load_repeaters)) { continue; } @@ -433,8 +446,8 @@ bool is_valid(const freqman_entry& entry) { if (entry.frequency_a == 0) return false; - // Frequency B must be set for type Range or Ham Radio - if (entry.type == freqman_type::Range || entry.type == freqman_type::HamRadio) { + // Frequency B must be set for type Range or HamRadio or Repeater + if (entry.type == freqman_type::Range || entry.type == freqman_type::HamRadio || entry.type == freqman_type::Repeater) { if (entry.frequency_b == 0) return false; } diff --git a/firmware/application/freqman_db.hpp b/firmware/application/freqman_db.hpp index a93bd6f66..4f31ea043 100644 --- a/firmware/application/freqman_db.hpp +++ b/firmware/application/freqman_db.hpp @@ -56,6 +56,7 @@ enum class freqman_type : uint8_t { Single, // f= Range, // a=,b= HamRadio, // r=,t= + Repeater, // l=,t= Raw, // line content in description Unknown, }; @@ -167,6 +168,7 @@ struct freqman_load_options { bool load_freqs{true}; bool load_ranges{true}; bool load_hamradios{true}; + bool load_repeaters{true}; }; using freqman_entry_ptr = std::unique_ptr; @@ -277,4 +279,4 @@ class FreqmanDB { bool read_raw_{true}; }; -#endif /* __FREQMAN_DB_H__ */ \ No newline at end of file +#endif /* __FREQMAN_DB_H__ */ diff --git a/firmware/application/ui_record_view.cpp b/firmware/application/ui_record_view.cpp index 0478d97f2..3c0a37b99 100644 --- a/firmware/application/ui_record_view.cpp +++ b/firmware/application/ui_record_view.cpp @@ -145,6 +145,15 @@ OversampleRate RecordView::get_oversample_rate(uint32_t sample_rate) { // Setter for datetime and frequency filename void RecordView::set_filename_date_frequency(bool set) { filename_date_frequency = set; + if (set) + filename_as_is = false; +} + +// Setter for leaving the filename untouched +void RecordView::set_filename_as_is(bool set) { + filename_as_is = set; + if (set) + filename_date_frequency = false; } bool RecordView::is_active() const { @@ -186,9 +195,11 @@ void RecordView::start() { base_path = filename_stem_pattern.string() + "_" + date_time + "_" + trim(to_string_freq(receiver_model.target_frequency())) + "Hz"; base_path = folder / base_path; - } else { + } else if (filename_as_is) { + base_path = filename_stem_pattern.string(); + base_path = folder / base_path; + } else base_path = next_filename_matching_pattern(folder / filename_stem_pattern); - } if (base_path.empty()) { return; diff --git a/firmware/application/ui_record_view.hpp b/firmware/application/ui_record_view.hpp index c062a4544..785f14281 100644 --- a/firmware/application/ui_record_view.hpp +++ b/firmware/application/ui_record_view.hpp @@ -73,6 +73,7 @@ class RecordView : public View { bool is_active() const; void set_filename_date_frequency(bool set); + void set_filename_as_is(bool set); private: void toggle(); @@ -91,6 +92,7 @@ class RecordView : public View { // Time Stamp bool filename_date_frequency = false; + bool filename_as_is = false; rtc::RTC datetime{}; const std::filesystem::path filename_stem_pattern; diff --git a/firmware/common/portapack_persistent_memory.cpp b/firmware/common/portapack_persistent_memory.cpp index 6afafea7d..9e4db7aae 100644 --- a/firmware/common/portapack_persistent_memory.cpp +++ b/firmware/common/portapack_persistent_memory.cpp @@ -195,6 +195,8 @@ struct data_t { // Recon App uint64_t recon_config; + int8_t recon_repeat_nb; + int8_t recon_repeat_gain; // enable or disable converter bool converter; @@ -257,7 +259,10 @@ struct data_t { tone_mix(tone_mix_reset_value), hardware_config(0), + recon_config(0), + recon_repeat_nb(0), + recon_repeat_gain(0), converter(false), updown_converter(false), @@ -391,10 +396,15 @@ void defaults() { set_recon_continuous(true); set_recon_clear_output(false); set_recon_load_freqs(true); + set_recon_load_repeaters(true); set_recon_load_ranges(true); set_recon_update_ranges_when_recon(true); set_recon_load_hamradios(true); set_recon_match_mode(0); + set_recon_repeat_recorded(false); + set_recon_repeat_amp(false); + set_recon_repeat_gain(35); + set_recon_repeat_nb(3); set_config_sdcard_high_speed_io(false, true); } @@ -747,6 +757,21 @@ bool recon_match_mode() { bool recon_auto_record_locked() { return (data->recon_config & 0x00400000UL) ? true : false; } +bool recon_repeat_recorded() { + return (data->recon_config & 0x00200000UL) ? true : false; +} +int8_t recon_repeat_nb() { + return data->recon_repeat_nb; +} +int8_t recon_repeat_gain() { + return data->recon_repeat_gain; +} +bool recon_repeat_amp() { + return (data->recon_config & 0x00100000UL) ? true : false; +} +bool recon_load_repeaters() { + return (data->recon_config & 0x00080000UL) ? true : false; +} void set_recon_autosave_freqs(const bool v) { data->recon_config = (data->recon_config & ~0x80000000UL) | (v << 31); @@ -778,6 +803,21 @@ void set_recon_match_mode(const bool v) { void set_recon_auto_record_locked(const bool v) { data->recon_config = (data->recon_config & ~0x00400000UL) | (v << 22); } +void set_recon_repeat_recorded(const bool v) { + data->recon_config = (data->recon_config & ~0x00200000UL) | (v << 21); +} +void set_recon_repeat_nb(const int8_t v) { + data->recon_repeat_nb = v; +} +void set_recon_repeat_gain(const int8_t v) { + data->recon_repeat_gain = v; +} +void set_recon_repeat_amp(const bool v) { + data->recon_config = (data->recon_config & ~0x00100000UL) | (v << 20); +} +void set_recon_load_repeaters(const bool v) { + data->recon_config = (data->recon_config & ~0x00080000UL) | (v << 19); +} /* UI Config 2 */ bool ui_hide_speaker() { diff --git a/firmware/common/portapack_persistent_memory.hpp b/firmware/common/portapack_persistent_memory.hpp index 2760322b3..3c77ba7fb 100644 --- a/firmware/common/portapack_persistent_memory.hpp +++ b/firmware/common/portapack_persistent_memory.hpp @@ -245,9 +245,14 @@ bool recon_autostart_recon(); bool recon_continuous(); bool recon_clear_output(); bool recon_load_freqs(); +bool recon_load_repeaters(); bool recon_load_ranges(); bool recon_update_ranges_when_recon(); bool recon_auto_record_locked(); +bool recon_repeat_recorded(); +int8_t recon_repeat_nb(); +int8_t recon_repeat_gain(); +bool recon_repeat_amp(); bool recon_load_hamradios(); bool recon_match_mode(); void set_recon_autosave_freqs(const bool v); @@ -258,7 +263,12 @@ void set_recon_load_freqs(const bool v); void set_recon_load_ranges(const bool v); void set_recon_update_ranges_when_recon(const bool v); void set_recon_auto_record_locked(const bool v); +void set_recon_repeat_recorded(const bool v); +void set_recon_repeat_nb(const int8_t v); +void set_recon_repeat_gain(const int8_t v); +void set_recon_repeat_amp(const bool v); void set_recon_load_hamradios(const bool v); +void set_recon_load_repeaters(const bool v); void set_recon_match_mode(const bool v); /* UI Config 2 */ diff --git a/firmware/test/application/test_freqman_db.cpp b/firmware/test/application/test_freqman_db.cpp index 5d3b308b9..d2348021d 100644 --- a/firmware/test/application/test_freqman_db.cpp +++ b/firmware/test/application/test_freqman_db.cpp @@ -59,6 +59,17 @@ TEST_CASE("It can parse basic ham radio freq entry.") { CHECK_EQ(e.type, freqman_type::HamRadio); } +TEST_CASE("It can parse repeater entry.") { + freqman_entry e; + REQUIRE( + parse_freqman_entry( + "l=123000000,t=123000500,d=This is the description.", e)); + CHECK_EQ(e.frequency_a, 123'000'000); + CHECK_EQ(e.frequency_b, 123'000'500); + CHECK_EQ(e.description, "This is the description."); + CHECK_EQ(e.type, freqman_type::Repeater); +} + TEST_CASE("It can parse modulation") { freqman_entry e; REQUIRE( @@ -195,6 +206,16 @@ TEST_CASE("It can serialize basic HamRadio entry") { CHECK(str == "r=123456000,t=423456000,d=Foobar"); } +TEST_CASE("It can serialize basic Repeater entry") { + auto str = to_freqman_string(freqman_entry{ + .frequency_a = 123'456'000, + .frequency_b = 423'456'000, + .description = "Foobar", + .type = freqman_type::Repeater, + }); + CHECK(str == "l=123456000,t=423456000,d=Foobar"); +} + // New tables for a future PR. /* TEST_CASE("It can parse modulation") { From a7393c349203e20bd4abf9e983dc674cfc85abba Mon Sep 17 00:00:00 2001 From: gullradriel <3157857+gullradriel@users.noreply.github.com> Date: Thu, 28 Dec 2023 20:10:38 +0100 Subject: [PATCH 11/13] fix for freq_b equal zero in repeater entries (#1686) --- firmware/application/apps/ui_recon.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/application/apps/ui_recon.cpp b/firmware/application/apps/ui_recon.cpp index 1dafadf0e..fac19f270 100644 --- a/firmware/application/apps/ui_recon.cpp +++ b/firmware/application/apps/ui_recon.cpp @@ -1356,8 +1356,8 @@ void ReconView::start_repeat() { transmitter_model.set_sampling_rate(get_actual_sample_rate(metadata->sample_rate)); transmitter_model.set_baseband_bandwidth(metadata->sample_rate <= 500'000 ? 1'750'000 : 2'500'000); // TX LPF min 1M75 for SR <=500K, and 2M5 (by experimental test) for SR >500K - // set TX to repeater TX freq if entry is Repeater, else use recorded one - if (current_entry().type == freqman_type::Repeater) { + // set TX to repeater TX freq if entry is Repeater and have a valid freq, else use recorded one + if (current_entry().type == freqman_type::Repeater && current_entry().frequency_b != 0) { transmitter_model.set_target_frequency(current_entry().frequency_b); } else { transmitter_model.set_target_frequency(metadata->center_frequency); From 2153c2dd1099e90fd6b64087b02cd59f4b2c6614 Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Fri, 29 Dec 2023 00:28:42 -0600 Subject: [PATCH 12/13] ERT app - Fix freq field overlapping amp setting (#1689) --- firmware/application/apps/ert_app.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/application/apps/ert_app.hpp b/firmware/application/apps/ert_app.hpp index cc306008f..d8cbe098a 100644 --- a/firmware/application/apps/ert_app.hpp +++ b/firmware/application/apps/ert_app.hpp @@ -146,7 +146,7 @@ class ERTAppView : public View { static constexpr auto header_height = 1 * 16; RxFrequencyField field_frequency{ - {5 * 8, 0 * 16}, + {0 * 8, 0 * 16}, nav_}; RFAmpField field_rf_amp{ From 84d4066986c2f02f2d8e073f224855c7b974d6dd Mon Sep 17 00:00:00 2001 From: jLynx Date: Fri, 29 Dec 2023 22:07:43 +1300 Subject: [PATCH 13/13] V1.9.1 (#1691) * Update past_version.txt * Update version.txt --- .github/workflows/past_version.txt | 2 +- .github/workflows/version.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/past_version.txt b/.github/workflows/past_version.txt index 804a616da..295e37c0e 100644 --- a/.github/workflows/past_version.txt +++ b/.github/workflows/past_version.txt @@ -1 +1 @@ -v1.8.0 +v1.9.0 diff --git a/.github/workflows/version.txt b/.github/workflows/version.txt index 295e37c0e..ba1e8bf0b 100644 --- a/.github/workflows/version.txt +++ b/.github/workflows/version.txt @@ -1 +1 @@ -v1.9.0 +v1.9.1