Files
mayhem-firmware/firmware/application/apps/ui_debug.hpp
T
stafur 6b663894b0 Addresses comments from PR #3057 (#3058)
* Addressed clock inversion and fractiona/interger states. Created ui_debug display that checks expected clock frequencies for expected 3.072 MHz sampling frequency commonly utilizaed in portapack apps.

* Ran format-code.sh

* Addressed comments from PR. Ran format-code.sh. Updated definition of a, b, and c in comments and introduced x, y, and z for debug display. Changed default color for P2/P3 conditional debub display for MS_DIV. Removed implied recalibration since this did not address crackling sound.
2026-03-01 21:51:28 +01:00

1303 lines
38 KiB
C++

/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2024 Mark Thompson
* Copyright (C) 2024 u-foka
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __UI_DEBUG_H__
#define __UI_DEBUG_H__
#include "ui.hpp"
#include "ui_widget.hpp"
#include "ui_painter.hpp"
#include "ui_menu.hpp"
#include "ui_navigation.hpp"
#include "rffc507x.hpp"
#include "portapack.hpp"
#include "memory_map.hpp"
#include "irq_controls.hpp"
#include <functional>
#include <utility>
namespace ui {
class DebugMemoryView : public View {
public:
DebugMemoryView(NavigationView& nav);
void focus() override;
std::string title() const override { return "Memory"; };
private:
Text text_title{
{72, 96, 96, 16},
"Memory Usage",
};
Text text_label_m0_core_free{
{0, 128, 144, 16},
"M0 Core Free Bytes",
};
Text text_label_m0_core_free_value{
{200, 128, 40, 16},
};
Text text_label_m0_heap_fragmented_free{
{0, 144, 184, 16},
"M0 Heap Fragmented Free",
};
Text text_label_m0_heap_fragmented_free_value{
{200, 144, 40, 16},
};
Text text_label_m0_heap_fragments{
{0, 160, 136, 16},
"M0 Heap Fragments",
};
Text text_label_m0_heap_fragments_value{
{200, 160, 40, 16},
};
Button button_done{
{72, 192, 96, 24},
"Done"};
};
typedef enum {
CT_PMEM,
CT_RFFC5072,
CT_MAX283X,
CT_SI5351,
CT_AUDIO,
CT_MAX17055,
#ifdef PRALINE
CT_FPGA,
#endif
CT_SGPIO,
} chip_type_t;
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 {
return (registers_count >= 0x10) ? 2 : 1;
}
constexpr size_t legend_width() const {
return legend_length() * 8;
}
constexpr size_t value_length() const {
return (register_bits + 3) / 4;
}
constexpr size_t value_width() const {
return value_length() * 8;
}
constexpr size_t registers_per_row() const {
return (value_length() >= 3) ? 4 : 8;
}
constexpr size_t registers_row_length() const {
return (registers_per_row() * (value_length() + 1)) - 1;
}
constexpr size_t registers_row_width() const {
return registers_row_length() * 8;
}
constexpr size_t row_width() const {
return legend_width() + 8 + registers_row_width();
}
constexpr size_t rows() const {
return registers_count / registers_per_row();
}
};
class RegistersWidget : public Widget {
public:
RegistersWidget(RegistersWidgetConfig&& config);
void update();
void paint(Painter& painter) override;
uint32_t reg_read(const uint32_t register_number);
void reg_write(const uint32_t register_number, const uint32_t value);
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;
uint32_t page_number;
static constexpr size_t row_height = 16;
void draw_legend(const Coord left, Painter& painter);
void draw_values(const Coord left, Painter& painter);
};
class RegistersView : public View {
public:
RegistersView(NavigationView& nav, const std::string& title, RegistersWidgetConfig&& config);
void focus() override;
bool on_encoder(const EncoderEvent delta) override;
private:
Text text_title{};
RegistersWidget registers_widget;
Button button_update{
{16, 280, 96, 24},
"Update"};
Button button_done{
{128, 280, 96, 24},
"Done"};
Button button_write{
{144, 248, 80, 20},
"Write"};
Labels labels{
{{1 * 8, 248}, "Reg:", Theme::getInstance()->fg_light->foreground},
{{8 * 8, 248}, "Data:", Theme::getInstance()->fg_light->foreground}};
SymField field_write_reg_num{
{5 * 8, 248},
2,
SymField::Type::Hex};
SymField field_write_data_val{
{13 * 8, 248},
4,
SymField::Type::Hex};
};
class ControlsSwitchesWidget : public Widget {
public:
ControlsSwitchesWidget(
Rect parent_rect)
: Widget{parent_rect},
key_event_mask(0),
long_press_key_event_mask{0},
last_delta{0} {
set_focusable(true);
}
void on_show() override;
bool on_key(const KeyEvent key) override;
bool on_encoder(const EncoderEvent delta) override;
void paint(Painter& painter) override;
private:
uint8_t key_event_mask;
uint8_t long_press_key_event_mask;
EncoderEvent last_delta;
MessageHandlerRegistration message_handler_frame_sync{
Message::ID::DisplayFrameSync,
[this](const Message* const) {
this->on_frame_sync();
}};
void on_frame_sync();
};
class DebugControlsView : public View {
public:
explicit DebugControlsView(NavigationView& nav);
void focus() override;
std::string title() const override { return "Buttons Test"; };
private:
Labels labels{
{{UI_POS_X_CENTER(14), 1 * 16}, "Controls State", Theme::getInstance()->bg_darkest->foreground},
{{UI_POS_X(0), 11 * 16}, "Dial:", Theme::getInstance()->fg_medium->foreground},
{{UI_POS_X(0), 14 * 16}, "Long-Press Mode:", Theme::getInstance()->fg_medium->foreground}};
ControlsSwitchesWidget switches_widget{
{80, 80, 80, 112},
};
OptionsField options_switches_mode{
{17 * 8, 14 * 16},
8,
{
{"Disabled", 0},
{"Enabled", 0xFF}, // all KeyEvent bits to long-press mode
}};
Button button_done{
{UI_POS_X_CENTER(12), 264, 96, 24},
"Done"};
};
class DebugMemoryDumpView : public View {
public:
DebugMemoryDumpView(NavigationView& nav);
void focus() override;
std::string title() const override { return "Memory Dump"; };
private:
Button button_dump{
{UI_POS_X_CENTER(12), 4 * 16, 96, 24},
"Dump"};
Button button_read{
{UI_POS_X_CENTER(12) - UI_POS_WIDTH(10), 11 * 16, 96, 24},
"Read"};
Button button_write{
{UI_POS_X_CENTER(12) + UI_POS_WIDTH(10), 11 * 16, 96, 24},
"Write"};
Button button_done{
{UI_POS_X_RIGHT(12), UI_POS_Y_BOTTOM(3), 96, 24},
"Done"};
Labels labels{
{{5 * 8, 1 * 16}, "Dump Range to File", Theme::getInstance()->fg_yellow->foreground},
{{UI_POS_X(0), 2 * 16}, "Starting Address: 0x", Theme::getInstance()->fg_light->foreground},
{{UI_POS_X(0), 3 * 16}, "Byte Count: 0x", Theme::getInstance()->fg_light->foreground},
{{3 * 8, 8 * 16}, "Read/Write Single Word", Theme::getInstance()->fg_yellow->foreground},
{{UI_POS_X(0), 9 * 16}, "Memory Address: 0x", Theme::getInstance()->fg_light->foreground},
{{UI_POS_X(0), 10 * 16}, "Data Value: 0x", Theme::getInstance()->fg_light->foreground}};
SymField field_starting_address{
{20 * 8, 2 * 16},
8,
SymField::Type::Hex};
SymField field_byte_count{
{20 * 8, 3 * 16},
8,
SymField::Type::Hex};
SymField field_rw_address{
{20 * 8, 9 * 16},
8,
SymField::Type::Hex};
SymField field_data_value{
{20 * 8, 10 * 16},
8,
SymField::Type::Hex};
};
class DebugPmemView : public View {
public:
DebugPmemView(NavigationView& nav);
void focus() override;
bool on_encoder(const EncoderEvent delta) override;
std::string title() const override { return "P.Mem Debug"; }
private:
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};
RegistersWidget registers_widget;
Text text_checksum{{16, 232, 208, 16}};
Text text_checksum2{{16, 248, 208, 16}};
Button button_ok{
{screen_width / 3, 270, screen_width / 3, 24},
"OK",
};
void update();
};
class DebugScreenTest : public View {
public:
DebugScreenTest(NavigationView& nav);
bool on_key(KeyEvent key) override;
bool on_encoder(EncoderEvent delta) override;
bool on_touch(TouchEvent event) override;
void paint(Painter& painter) override;
private:
NavigationView& nav_;
Point pen_pos{};
Color pen_color{0};
int16_t pen_size{10};
};
/*class DebugLCRView : public View {
public:
DebugLCRView(NavigationView& nav, std::string lcrstring);
void focus() override;
std::string title() const override { return "LCR debug"; };
private:
Console console {
{ 8, 16, 224, screen_height-80 }
};
Button button_exit {
{ 72, 264, 96, 32 },
"Exit"
};
};*/
/* Radio Signal Path Diagnostics View
* Shows status of each component in the RX/TX signal chain:
* Antenna -> RF Path -> RFFC5072 -> MAX283x -> MAX5864 -> FPGA -> SGPIO -> MCU
*/
class RadioDiagnosticsView : public View {
public:
RadioDiagnosticsView(NavigationView& nav);
void focus() override;
std::string title() const override { return "Radio Diag"; };
private:
NavigationView& nav_;
void update_status();
Text text_title{{0, 0, 240, 16}, "=== Signal Path Status ==="};
Text text_lbl_rffc{{0, 20, 140, 16}, "RFFC5072 (1st IF):"};
Text text_rffc_status{{144, 20, 96, 16}, "---"};
Text text_lbl_max{{0, 36, 140, 16}, "MAX283x (2nd IF):"};
Text text_max_status{{144, 36, 96, 16}, "---"};
Text text_lbl_adc{{0, 52, 140, 16}, "MAX5864 (ADC):"};
Text text_adc_status{{144, 52, 96, 16}, "---"};
Text text_lbl_fpga{{0, 68, 140, 16}, "FPGA/CPLD:"};
Text text_fpga_status{{144, 68, 96, 16}, "---"};
Text text_lbl_sgpio{{0, 84, 140, 16}, "SGPIO:"};
Text text_sgpio_status{{144, 84, 96, 16}, "---"};
Text text_lbl_clock{{0, 100, 140, 16}, "Si5351 Clocks:"};
Text text_clock_status{{144, 100, 96, 16}, "---"};
Text text_regs_title{{0, 124, 240, 16}, "=== Key Registers ==="};
Text text_lbl_rffc_reg{{0, 144, 80, 16}, "RFFC R0:"};
Text text_rffc_reg{{80, 144, 160, 16}, "---"};
Text text_lbl_max_reg{{0, 160, 80, 16}, "MAX R0:"};
Text text_max_reg{{80, 160, 160, 16}, "---"};
Text text_lbl_fpga_reg{{0, 176, 80, 16}, "FPGA:"};
Text text_fpga_reg{{80, 176, 160, 16}, "---"};
Text text_lbl_sgpio_reg{{0, 192, 80, 16}, "SGPIO:"};
Text text_sgpio_reg{{80, 192, 160, 16}, "---"};
Text text_test_result{{0, 220, 240, 32}, ""};
Button button_refresh{
{8, 280, 72, 24},
"Refresh"};
Button button_done{
{168, 280, 64, 24},
"Done"};
};
#ifdef PRALINE
/* Praline-Specific Radio Debug View
* Monitors Mixer Lock, SPI Bit Depth, and toggles Si5351 CLK5
*/
class PralineRadioDebugView : public View {
public:
PralineRadioDebugView(NavigationView& nav);
void focus() override;
std::string title() const override { return "Pro Radio Debug"; };
private:
void refresh();
void toggle_clk5();
Text text_title{{0, 0, 240, 16}, "=== Pro Radio Debug ==="};
// Mixer Lock (PD_11 / GPIO6[25])
Text text_lbl_lock{{0, 24, 124, 16}, "Mix Lock (LD):"};
Text text_lock_status{{126, 24, 114, 16}, "---"};
// Si5351 CLK5 (Mixer Reference)
Text text_lbl_clk5{{0, 40, 124, 16}, "Si5351 CLK5(Mix):"};
Text text_clk5_status{{126, 40, 114, 16}, "---"};
// SPI Bus configuration check
Text text_lbl_spi{{0, 56, 124, 16}, "SPI Bit Mode:"};
Text text_spi_status{{126, 56, 118, 16}, "---"};
// FPGA DC Block (Reg 1)
Text text_lbl_fpga_ctrl{{0, 72, 124, 16}, "FPGA Reg 1:"};
Text text_fpga_ctrl{{126, 72, 118, 16}, "---"};
// VAA Power Rail (P8_1 / GPIO4[1])
Text text_lbl_vaa{{0, 88, 124, 16}, "VAA RF Power:"};
Text text_vaa_status{{126, 88, 118, 16}, "---"};
Text text_status_msg{{0, 110, 240, 48}, ""};
Button button_refresh{{8, 240, 72, 24}, "Refresh"};
Button button_toggle_clk5{{88, 240, 72, 24}, "CLK5_T"};
Button button_done{{168, 240, 64, 24}, "Done"};
};
#endif
/* WFMAudioDebugView ***************************************************/
#ifdef PRALINE
class WFMAudioDebugView : public View {
public:
WFMAudioDebugView(NavigationView& nav);
void focus() override;
std::string title() const override { return "WFM Audio Debug"; }
private:
void refresh();
NavigationView& nav_;
Text text_title{{0, 0, 240, 16}, "=== WFM Audio Debug ==="};
// Sample rates section
Text text_lbl_clk0{{0, 20, 140, 16}, "Si5351 CLK0 Rate:"};
Text text_clk0{{150, 20, 90, 16}, "---"};
Text text_lbl_fpga_dec{{0, 36, 140, 16}, "FPGA Decimation:"};
Text text_fpga_dec{{150, 36, 90, 16}, "---"};
Text text_lbl_post_fpga{{0, 52, 140, 16}, "Post-FPGA Rate:"};
Text text_post_fpga{{150, 52, 90, 16}, "---"};
// MAX2831 section
Text text_section1{{0, 72, 240, 16}, "--- MAX2831 LPF ---"};
Text text_lbl_reg8{{0, 88, 140, 16}, "Reg8 (LPF RX):"};
Text text_reg8{{150, 88, 90, 16}, "---"};
Text text_lbl_lpf_bw{{0, 104, 140, 16}, "LPF Bandwidth:"};
Text text_lpf_bw{{150, 104, 90, 16}, "---"};
// FPGA section
Text text_section2{{0, 124, 240, 16}, "--- FPGA Control ---"};
Text text_lbl_fpga_r1{{0, 140, 140, 16}, "Reg1 (Ctrl):"};
Text text_fpga_r1{{150, 140, 90, 16}, "---"};
Text text_lbl_dc_q{{0, 156, 70, 16}, "DC/Q/QS:"};
Text text_dc_q{{72, 156, 168, 16}, "---"};
// Audio section
Text text_section3{{0, 176, 240, 16}, "--- Audio Path ---"};
Text text_lbl_expected{{0, 192, 96, 16}, "Expctd Aud:"};
Text text_expected{{98, 192, 142, 16}, "---"};
Text text_lbl_deemph{{0, 208, 96, 16}, "D-emph Cfg:"};
Text text_deemph{{98, 208, 132, 16}, "---"};
// Status
Text text_status{{0, 228, 240, 16}, "---"};
Text text_status2{{0, 244, 240, 16}, "---"};
Button button_refresh{{10, 268, 70, 24}, "Refresh"};
Button button_toggle_q{{90, 268, 70, 24}, "Toggle Q"};
Button button_done{{170, 268, 60, 24}, "Done"};
};
#endif
/* BasebandStatusView ***************************************************/
class BasebandStatusView : public View {
public:
BasebandStatusView(NavigationView& nav);
void focus() override;
std::string title() const override { return "Baseband Status"; };
private:
NavigationView& nav_;
void update();
Text text_title{{0, 0, 240, 16}, "=== Baseband Counters ==="};
Text text_lbl_marker{{0, 20, 140, 16}, "Streaming Marker:"};
Text text_marker{{144, 20, 96, 16}, "---"};
Text text_lbl_loops{{0, 36, 140, 16}, "Baseband Loops:"};
Text text_loops{{144, 36, 96, 16}, "---"};
Text text_lbl_wait{{0, 52, 140, 16}, "DMA Wait Count:"};
Text text_wait{{144, 52, 96, 16}, "---"};
Text text_lbl_xfr{{0, 68, 140, 16}, "DMA Xfr Count:"};
Text text_xfr{{144, 68, 96, 16}, "---"};
Text text_lbl_missed{{0, 84, 140, 16}, "Buffer Missed:"};
Text text_missed{{144, 84, 96, 16}, "---"};
Text text_status_line1{{0, 110, 240, 16}, ""};
Text text_status_line2{{0, 126, 240, 16}, ""};
Text text_status_line3{{0, 142, 240, 16}, ""};
Button button_refresh{
{8, 280, 72, 24},
"Refresh"};
Button button_done{
{168, 280, 64, 24},
"Done"};
MessageHandlerRegistration message_handler_frame_sync{
Message::ID::DisplayFrameSync,
[this](const Message* const) { this->update(); }};
};
/* SGPIOLiveMonitorView ***************************************************/
class SGPIOLiveMonitorView : public View {
public:
SGPIOLiveMonitorView(NavigationView& nav);
void focus() override;
std::string title() const override { return "SGPIO Live"; };
private:
NavigationView& nav_;
void update();
Text text_title{{0, 0, 240, 16}, "=== SGPIO Registers ==="};
Text text_lbl_ctrl{{0, 20, 140, 16}, "CTRL_ENABLE:"};
Text text_ctrl{{144, 20, 96, 16}, "---"};
Text text_lbl_in{{0, 36, 140, 16}, "GPIO_INREG:"};
Text text_in{{144, 36, 96, 16}, "---"};
Text text_lbl_ss{{0, 52, 140, 16}, "REG_SS[0]:"};
Text text_ss{{144, 52, 96, 16}, "---"};
Text text_lbl_status{{0, 68, 140, 16}, "STATUS_1:"};
Text text_status{{144, 68, 96, 16}, "---"};
Text text_lbl_out{{0, 84, 140, 16}, "GPIO_OUTREG:"};
Text text_out{{144, 84, 96, 16}, "---"};
Text text_lbl_oen{{0, 100, 140, 16}, "GPIO_OENREG:"};
Text text_oen{{144, 100, 96, 16}, "---"};
Text text_diag_line1{{0, 126, 240, 16}, ""};
Text text_diag_line2{{0, 142, 240, 16}, ""};
Text text_diag_line3{{0, 158, 240, 16}, ""};
Text text_diag_line4{{0, 174, 240, 16}, ""};
Button button_refresh{
{8, 280, 72, 24},
"Refresh"};
Button button_done{
{168, 280, 64, 24},
"Done"};
MessageHandlerRegistration message_handler_frame_sync{
Message::ID::DisplayFrameSync,
[this](const Message* const) { this->update(); }};
};
/* Radio RX Step-by-Step Test View
* Tests radio hardware directly without M0 baseband involvement.
* Logs each step to help isolate where the signal chain breaks.
*/
class RadioRxTestView : public View {
public:
RadioRxTestView(NavigationView& nav);
void focus() override;
std::string title() const override { return "RX Test"; };
private:
NavigationView& nav_;
bool radio_initialized_{false};
uint32_t test_frequency_{433000000}; // 433 MHz default
void log(const std::string& msg);
void log_registers(const std::string& label);
void run_init_test();
void run_rx_mode_test();
void run_freq_test();
void run_sgpio_test();
void run_full_test();
void run_step_test();
bool check_gpio_changing();
Labels labels{
{{0, 0}, "=== Radio RX Test ===", Theme::getInstance()->fg_yellow->foreground}};
Console console{
{0, 20, 240, 200}};
Button button_init{
{0, 224, 56, 24},
"Init"};
Button button_rx{
{60, 224, 56, 24},
"RX"};
Button button_freq{
{120, 224, 56, 24},
"Freq"};
Button button_sgpio{
{180, 224, 56, 24},
"SGPIO"};
Button button_full{
{0, 252, 56, 24},
"Full"};
Button button_step{
{60, 252, 56, 24},
"Step"};
Button button_done{
{120, 252, 112, 24},
"Done"};
};
/* SGPIO8 Clock Detector View
* Samples SGPIO8 pin to verify external clock is present.
* Shows toggle count and estimated frequency.
*/
class SGPIO8ClockDetectorView : public View {
public:
SGPIO8ClockDetectorView(NavigationView& nav);
void focus() override;
std::string title() const override { return "SGPIO8 Clock"; };
private:
NavigationView& nav_;
Text text_title{{8, 16, 224, 16}, "SGPIO8 Clock Detector"};
Text text_lbl_samples{{8, 48, 160, 16}, "Samples (first 20):"};
Text text_samples{{8, 64, 224, 16}, " "};
Text text_lbl_toggles{{8, 96, 160, 16}, "Toggle count:"};
Text text_toggles{{8, 112, 224, 16}, " "};
Text text_status{{8, 144, 224, 32}, " "};
Button button_sample{{8, 200, 96, 24}, "Sample"};
Button button_done{{128, 200, 96, 24}, "Done"};
void sample_sgpio8();
};
/* Slice Status View
* Shows SGPIO slice status: which slices are enabled vs active,
* counter values, and data capture status.
*/
/* Si5351 Debug View
* Dedicated diagnostic tool for Si5351 clock generator.
* Shows PLL lock status, clock configurations, and allows testing.
*/
class Si5351DebugView : public View {
public:
Si5351DebugView(NavigationView& nav);
void focus() override;
std::string title() const override { return "Si5351 Clocks"; };
private:
NavigationView& nav_;
Text text_title{{0, 0, 200, 16}, "Si5351 Clock Generator"};
Text text_status_label{{0, 16, 80, 16}, "Status Reg:"};
Text text_status_value{{96, 16, 144, 16}, ""};
Text text_pll_a_label{{0, 32, 80, 16}, "PLL A:"};
Text text_pll_a_status{{96, 32, 144, 16}, ""};
Text text_pll_b_label{{0, 48, 80, 16}, "PLL B:"};
Text text_pll_b_status{{96, 48, 144, 16}, ""};
Text text_sys_init_label{{0, 64, 80, 16}, "SYS_INIT:"};
Text text_sys_init_status{{96, 64, 144, 16}, ""};
Text text_xtal_cap_label{{0, 80, 80, 16}, "XTAL Cap:"};
Text text_xtal_cap_value{{96, 80, 144, 16}, ""};
Text text_clk0_label{{0, 96, 48, 16}, "CLK0:"};
Text text_clk0_status{{50, 96, 28, 16}, ""};
Text text_clk0_freq_value{{80, 96, 160, 16}, ""};
Text text_clk0_div_value{{50, 112, 190, 16}, ""};
Text text_clk1_label{{0, 128, 96, 16}, "CLK1 (SCT):"};
Text text_clk1_status{{112, 128, 128, 16}, ""};
Text text_clk4_label{{0, 144, 96, 16}, "CLK4 (MAX):"};
Text text_clk4_status{{112, 144, 128, 16}, ""};
Text text_clk5_label{{0, 160, 96, 16}, "CLK5 (RFFC):"};
Text text_clk5_status{{112, 160, 128, 16}, ""};
Button button_refresh{{8, 240, 72, 24}, "Refresh"};
Button button_reset_pll{{88, 240, 72, 24}, "Reset PLL"};
Button button_done{{168, 240, 64, 24}, "Done"};
void refresh_status();
void reset_pll();
};
#ifdef PRALINE
/* SignalPathStatusView *************************************************/
class SignalPathStatusView : public View {
public:
SignalPathStatusView(NavigationView& nav);
void focus() override;
std::string title() const override { return "Signal Path"; };
private:
NavigationView& nav_;
void refresh_status();
Text text_title{{0, 0, 240, 16}, "=== Signal Path Status ==="};
Text text_lbl_max_enable{{0, 20, 114, 16}, "MAX2831:"};
Text text_max_enable{{116, 20, 124, 16}, "---"};
Text text_lbl_max_mode{{0, 36, 114, 16}, "RX Mode:"};
Text text_max_mode{{116, 36, 124, 16}, "---"};
Text text_lbl_rf_path{{0, 52, 114, 16}, "RF Path:"};
Text text_rf_path{{116, 52, 124, 16}, "---"};
Text text_lbl_filter{{0, 68, 114, 16}, "Filter Band:"};
Text text_filter{{116, 68, 124, 16}, "---"};
Text text_lbl_mixer{{0, 84, 114, 16}, "Mixer Enable:"};
Text text_mixer{{116, 84, 124, 16}, "---"};
Text text_lbl_rf_amp{{0, 100, 114, 16}, "RF Amp:"};
Text text_rf_amp{{116, 100, 124, 16}, "---"};
Text text_lbl_lna{{0, 116, 114, 16}, "LNA Gain:"};
Text text_lna{{116, 116, 124, 16}, "---"};
Text text_lbl_vga{{0, 132, 114, 16}, "VGA Gain:"};
Text text_vga{{116, 132, 124, 16}, "---"};
Text text_lbl_fpga_decim{{0, 148, 114, 16}, "FPGA Decim:"};
Text text_fpga_decim{{116, 148, 124, 16}, "---"};
Text text_lbl_fpga_ctrl_dc_q{{0, 164, 114, 16}, "FPGA Ctrl:"};
Text text_fpga_ctrl_dc_q{{116, 164, 124, 16}, "---"};
Text text_lbl_fpga_ctrl_qs{{0, 180, 114, 16}, ""};
Text text_fpga_ctrl_qs{{116, 180, 124, 16}, "---"};
Text text_status{{0, 200, 240, 32}, ""};
Button button_refresh{{0, 280, 72, 24}, "Refresh"};
Button button_toggle_q{{88, 280, 72, 24}, "Q Inv"};
Button button_done{{176, 280, 64, 24}, "Done"};
};
#endif
#ifdef PRALINE
class GPIODebugView : public View {
public:
GPIODebugView(NavigationView& nav);
void focus() override;
std::string title() const override { return "GPIO Debug"; };
private:
void refresh();
// GPIO4 (LPF and RF Amp)
Text text_lbl_gpio4{{0, 0, 240, 16}, "Pin Diag: GPIO4 (LPF|Amp|Mix)"};
Text text_lbl_mixr1{{0, 18, 56, 16}, "MixR1:"};
Text text_mixr1{{58, 18, 180, 16}, "---"};
Text text_lbl_pin4{{0, 36, 114, 16}, "PIN[4] (read):"};
Text text_pin4{{116, 36, 124, 16}, "---"};
Text text_lbl_set4{{0, 54, 114, 16}, "SET[4] (write):"};
Text text_set4{{116, 54, 124, 16}, "---"};
// Bit 8 (LPF)
Text text_lbl_lpf_bit{{0, 78, 240, 16}, "Bit 8 (LPF - GPIO4[8]):"};
Text text_lpf_dir{{0, 96, 80, 16}, "DIR: ?"};
Text text_lpf_pin{{82, 96, 78, 16}, "PIN: ?"};
Text text_lpf_set{{162, 96, 78, 16}, "SET: ?"};
Button button_lpf_toggle{{8, 114, 110, 24}, "Toggle LPF"};
Button button_lpf_on{{122, 114, 50, 24}, "ON"};
Button button_lpf_off{{176, 114, 50, 24}, "OFF"};
// Bit 9 (RF Amp)
Text text_lbl_amp_bit{{0, 146, 240, 16}, "Bit 9 (Amp - GPIO4[9]):"};
Text text_amp_dir{{0, 164, 80, 16}, "DIR: ?"};
Text text_amp_pin{{82, 164, 78, 16}, "PIN: ?"};
Text text_amp_set{{162, 164, 78, 16}, "SET: ?"};
Button button_amp_toggle{{8, 182, 110, 24}, "Toggle Amp"};
Button button_amp_on{{122, 182, 50, 24}, "ON"};
Button button_amp_off{{176, 182, 50, 24}, "OFF"};
// GPIO3 (Mixer)
Text text_lbl_gpio3{{0, 214, 240, 16}, "--- GPIO3 (Mixer) ---"};
Text text_lbl_mix_bit{{0, 232, 240, 16}, "Bit 2 (MIX - GPIO3[2]):"};
Text text_mix_dir{{0, 250, 80, 16}, "DIR: ?"};
Text text_mix_pin{{82, 250, 78, 16}, "PIN: ?"};
Text text_mix_set{{162, 250, 78, 16}, "SET: ?"};
// Controls
Button button_refresh{{8, 280, 72, 24}, "Refresh"};
Button button_done{{168, 280, 64, 24}, "Done"};
};
#endif
#ifdef PRALINE
/* RFFC5072StatusView *************************************************/
class RFFC5072StatusView : public View {
public:
RFFC5072StatusView(NavigationView& nav);
void focus() override;
std::string title() const override { return "RFFC5072 Status"; };
private:
NavigationView& nav_;
void refresh_status();
Text text_status{{0, 0, 240, 16}, "---"};
Text text_gpio4{{0, 16, 240, 16}, "---"};
Text text_ctrl{{0, 32, 240, 16}, "---"};
Text text_lbl_enabled{{0, 48, 114, 16}, "Status:"};
Text text_enabled{{116, 48, 124, 16}, "---"};
Text text_lbl_freq{{0, 64, 114, 16}, "LO Freq:"};
Text text_freq{{116, 64, 124, 16}, "---"};
Text text_lbl_path{{0, 80, 114, 16}, "Path:"};
Text text_path{{116, 80, 124, 16}, "---"};
Text text_lbl_mixer{{0, 96, 114, 16}, "Mixer:"};
Text text_mixer{{116, 96, 124, 16}, "---"};
Text text_lbl_r0{{0, 112, 114, 16}, "Reg 0:"};
Text text_r0{{116, 112, 124, 16}, "---"};
Text text_lbl_r1{{0, 128, 114, 16}, "Reg 1 (N):"};
Text text_r1{{116, 128, 124, 16}, "---"};
Text text_lbl_r2{{0, 144, 114, 16}, "Reg 2:"};
Text text_r2{{116, 144, 124, 16}, "---"};
Text text_lbl_n{{0, 160, 114, 16}, "N divider:"};
Text text_n{{116, 160, 124, 16}, "---"};
Text text_lbl_lodiv{{0, 176, 114, 16}, "LO divider:"};
Text text_lodiv{{116, 176, 124, 16}, "---"};
Text text_lbl_calc{{0, 192, 114, 16}, "Calc freq:"};
Text text_calc{{116, 192, 124, 16}, "---"};
Text text_regs_status{{0, 208, 240, 16}, "---"};
Text text_status2{{0, 224, 240, 16}, ""};
Text text_status3{{0, 240, 240, 16}, ""};
Button button_refresh{{2, 280, 72, 24}, "Refresh"};
Button button_force{{98, 280, 60, 24}, "SPI"};
Button button_done{{182, 280, 56, 24}, "Done"};
};
#ifdef PRALINE
/* RFFCTuningDebugView *************************************************/
class RFFCTuningDebugView : public View {
public:
RFFCTuningDebugView(NavigationView& nav);
void focus() override;
std::string title() const override { return "RFFC Tuning Debug"; };
private:
void refresh();
Text text_title{{0, 0, 240, 16}, "RFFC5072 Tuning Debug"};
Text text_lbl_called{{0, 18, 120, 16}, "Freq Set:"};
Text text_called{{122, 18, 118, 16}, "NO"};
Text text_lbl_req{{0, 38, 120, 16}, "Requested:"};
Text text_req{{122, 38, 118, 16}, "---"};
Text text_lbl_exp_n{{0, 56, 120, 16}, "Expected N:"};
Text text_exp_n{{122, 56, 118, 16}, "---"};
Text text_lbl_act_n{{0, 74, 120, 16}, "Actual N:"};
Text text_act_n{{122, 74, 118, 16}, "---"};
Text text_lbl_exp_div{{0, 92, 120, 16}, "Exp LO/Pres:"};
Text text_exp_div{{122, 92, 118, 16}, "---"};
Text text_lbl_act_div{{0, 110, 120, 16}, "Act LO/Pres:"};
Text text_act_div{{122, 110, 118, 16}, "---"};
Text text_lbl_calc{{0, 128, 120, 16}, "Calc LO freq:"};
Text text_calc{{122, 128, 118, 16}, "---"};
Text text_lbl_calc_lo{{0, 146, 120, 16}, "Calc input:"};
Text text_calc_lo{{122, 146, 118, 16}, "---"};
Text text_lbl_calc_vco{{0, 164, 120, 16}, "In Calc VCO:"};
Text text_calc_vco{{122, 164, 118, 16}, "---"};
Text text_lbl_vco{{0, 182, 120, 16}, "Calc VCO:"};
Text text_vco{{122, 182, 118, 16}, "---"};
Text text_lbl_n_q24{{0, 200, 120, 16}, "N (Q24):"};
Text text_n_q24{{122, 200, 118, 16}, "---"};
Text text_status{{0, 224, 240, 48}, ""};
Button button_refresh{{8, 280, 72, 24}, "Refresh"};
Button button_done{{168, 280, 64, 24}, "Done"};
};
#endif
#ifdef PRALINE
/* MAX2831DebugView *************************************************/
class MAX2831DebugView : public View {
public:
MAX2831DebugView(NavigationView& nav);
void focus() override;
std::string title() const override { return "MAX2831 Debug"; };
private:
void refresh();
Text text_title{{0, 0, 240, 16}, "MAX2831 (2nd IF) Debug"};
Text text_lbl_called{{0, 24, 120, 16}, "Freq Set:"};
Text text_called{{122, 24, 118, 16}, "NO"};
Text text_lbl_valid{{0, 42, 120, 16}, "In Range:"};
Text text_valid{{122, 42, 118, 16}, "---"};
Text text_lbl_req{{0, 60, 120, 16}, "Requested:"};
Text text_req{{122, 60, 118, 16}, "---"};
Text text_lbl_calc_n{{0, 78, 120, 16}, "Calc N:"};
Text text_calc_n{{122, 78, 118, 16}, "---"};
Text text_lbl_calc_frac{{0, 96, 120, 16}, "Calc Frac:"};
Text text_calc_frac{{122, 96, 118, 16}, "---"};
Text text_spacer{{0, 114, 240, 16}, "--- Hardware Regs ---"};
Text text_lbl_r3{{0, 132, 120, 16}, "Reg 3:"};
Text text_r3{{122, 132, 118, 16}, "---"};
Text text_lbl_r4{{0, 150, 120, 16}, "Reg 4:"};
Text text_r4{{122, 150, 118, 16}, "---"};
Text text_lbl_act_n{{0, 168, 120, 16}, "Actual N:"};
Text text_act_n{{122, 168, 118, 16}, "---"};
Text text_lbl_act_frac{{0, 186, 120, 16}, "Actual Frac:"};
Text text_act_frac{{122, 186, 118, 16}, "---"};
Text text_lbl_calc_freq{{0, 204, 120, 16}, "Calc Freq:"};
Text text_calc_freq{{122, 204, 118, 16}, "---"};
Text text_status{{0, 228, 240, 44}, ""};
Button button_refresh{{8, 280, 72, 24}, "Refresh"};
Button button_done{{168, 280, 64, 24}, "Done"};
};
#endif
#ifdef PRALINE
class SystemDiagnosticsView : public View {
public:
SystemDiagnosticsView(NavigationView& nav);
void focus() override;
std::string title() const override { return "System Diagnostics"; };
private:
void refresh();
void read_gpio_states();
void set_sample_rate(uint32_t rate);
Text text_title{{0, 0, 240, 16}, "System Diagnostics"};
// Sample Rate Section
Text text_lbl_sample{{0, 24, 42, 16}, "Rate:"};
Text text_sample_rate{{44, 24, 50, 16}, "---"};
Text text_lbl_fpga_decode{{96, 24, 144, 16}, "DC:? Q:? QS:?"};
Button button_sample_2m{{2, 44, 56, 24}, "2 MSPS"};
Button button_sample_4m{{62, 44, 56, 24}, "4 MSPS"};
Button button_sample_8m{{122, 44, 56, 24}, "8 MSPS"};
Button button_sample_20m{{182, 44, 56, 24}, "20 MSPS"};
// Baseband Filter Section
Text text_lbl_bb_filter{{0, 76, 114, 16}, "BB Filter BW:"};
Text text_bb_filter{{116, 76, 124, 16}, "---"};
Text text_lbl_reg8{{0, 94, 114, 16}, "MAX2831 R8:"};
Text text_reg8{{116, 94, 124, 16}, "---"};
// GPIO States Section
Text text_lbl_gpio{{0, 118, 240, 16}, "--- GPIO Pin States ---"};
Text text_lbl_lpf{{0, 136, 56, 16}, "LPF:"};
Text text_gpio_lpf{{58, 136, 181, 16}, "---"};
Text text_lbl_mix{{0, 154, 56, 16}, "Mixer:"};
Text text_gpio_mix{{58, 154, 181, 16}, "---"};
Text text_lbl_amp{{0, 172, 56, 16}, "RF Amp:"};
Text text_gpio_amp{{58, 172, 181, 16}, "---"};
// FPGA Control Section
Text text_lbl_fpga{{0, 196, 240, 16}, "--- FPGA Control ---"};
Text text_lbl_fpga_ctrl{{0, 214, 114, 16}, "FPGA Reg 1:"};
Text text_fpga_ctrl{{116, 214, 124, 16}, "---"};
Text text_lbl_band{{0, 232, 48, 16}, "Band:"};
Text text_band{{50, 232, 190, 16}, "---"};
Button button_toggle_q{{2, 252, 110, 24}, "Toggle Q Inv"};
Button button_toggle_dc{{122, 252, 110, 24}, "Toggle DC Blk"};
// Control Buttons
Button button_refresh{{2, 280, 72, 24}, "Refresh"};
Button button_done{{168, 280, 64, 24}, "Done"};
};
#endif
#ifdef PRALINE
/* Si5351MultiSynthDebugView - Debug fractional register values for MS0 */
class Si5351MultiSynthDebugView : public View {
public:
Si5351MultiSynthDebugView(NavigationView& nav);
void focus() override;
std::string title() const override { return "Si5351 MS0 Debug"; };
private:
NavigationView& nav_;
void refresh();
void force_pll_reset();
void force_fractional_mode();
Text text_title{{0, 0, 240, 16}, "===MS0 Fractional Debug==="};
// Clock Control Register 16 (CLK0)
Text text_lbl_clk_ctrl{{0, 18, 100, 16}, "CLK0 Ctrl:"};
Text text_clk_ctrl{{102, 18, 138, 16}, "---"};
Text text_lbl_ms_int{{0, 34, 100, 16}, "MS_INT bit:"};
Text text_ms_int{{102, 34, 138, 16}, "---"};
// Raw register values
Text text_lbl_raw{{0, 54, 240, 16}, "---Raw Registers (42-49)---"};
Text text_lbl_r42_43{{0, 70, 80, 16}, "R42-43:"};
Text text_r42_43{{82, 70, 158, 16}, "---"};
Text text_lbl_r44_46{{0, 86, 80, 16}, "R44-46:"};
Text text_r44_46{{82, 86, 158, 16}, "---"};
Text text_lbl_r47_49{{0, 102, 80, 16}, "R47-49:"};
Text text_r47_49{{82, 102, 158, 16}, "---"};
// Decoded values
Text text_lbl_decoded{{0, 122, 240, 16}, "---Decoded Values---"};
Text text_lbl_p1{{0, 138, 48, 16}, "P1:"};
Text text_p1{{50, 138, 190, 16}, "---"};
Text text_lbl_p2{{0, 154, 48, 16}, "P2:"};
Text text_p2{{50, 154, 190, 16}, "---"};
Text text_lbl_p3{{0, 170, 48, 16}, "P3:"};
Text text_p3{{50, 170, 190, 16}, "---"};
Text text_lbl_rdiv{{0, 186, 48, 16}, "R_DIV:"};
Text text_rdiv{{50, 186, 190, 16}, "---"};
// Calculated frequency
Text text_lbl_calc{{0, 206, 240, 16}, "---Calculated Output---"};
Text text_lbl_div{{0, 222, 80, 16}, "MS Div:"};
Text text_div{{82, 222, 158, 16}, "---"};
Text text_lbl_freq{{0, 238, 80, 16}, "CLK0 Out:"};
Text text_freq{{82, 238, 158, 16}, "---"};
// Status
Text text_status{{0, 258, 240, 16}, ""};
Button button_refresh{{2, 280, 56, 24}, "Refresh"};
Button button_reset{{62, 280, 56, 24}, "PLL Rst"};
Button button_frac{{122, 280, 56, 24}, "Frac"};
Button button_done{{182, 280, 56, 24}, "Done"};
};
#endif
#ifdef PRALINE
class PralineClockDebugView : public View {
public:
PralineClockDebugView(NavigationView& nav);
void focus() override;
std::string title() const override { return "Pro Clock Status"; };
private:
void refresh();
Text text_title{{0, 0, 240, 16}, "=== Pro Clock Dashboard ==="};
// System Status
Text text_lbl_pll{{0, 20, 80, 16}, "PLL Lock:"};
Text text_pll_status{{88, 20, 152, 16}, "---"};
Text text_lbl_afe{{0, 36, 80, 16}, "AFE Rate:"};
Text text_afe_rate{{88, 36, 152, 16}, "---"};
Text text_lbl_n{{0, 52, 80, 16}, "Decim (n):"};
Text text_n_val{{88, 52, 152, 16}, "-"};
// Table Header
Text text_header{{0, 72, 240, 16}, "ID mA Mode Phase Stat"};
// Helper structure to group row widgets for CLK0-CLK5
struct ClockRow {
Text* id;
Text* ma;
Text* mode;
Text* phase;
Text* stat;
};
std::vector<ClockRow> rows;
// We define the actual widgets for 6 clocks
// Note: Layout uses 16px vertical spacing per row
Text t0_id{{0, 88, 24, 16}, "C0:"};
Text t0_ma{{32, 88, 24, 16}, "-"};
Text t0_mode{{64, 88, 48, 16}, "-"};
Text t0_ph{{128, 88, 56, 16}, "-"};
Text t0_st{{192, 88, 48, 16}, "-"};
Text t1_id{{0, 104, 24, 16}, "C1:"};
Text t1_ma{{32, 104, 24, 16}, "-"};
Text t1_mode{{64, 104, 48, 16}, "-"};
Text t1_ph{{128, 104, 56, 16}, "-"};
Text t1_st{{192, 104, 48, 16}, "-"};
Text t2_id{{0, 120, 24, 16}, "C2:"};
Text t2_ma{{32, 120, 24, 16}, "-"};
Text t2_mode{{64, 120, 48, 16}, "-"};
Text t2_ph{{128, 120, 56, 16}, "-"};
Text t2_st{{192, 120, 48, 16}, "-"};
Text t3_id{{0, 136, 24, 16}, "C3:"};
Text t3_ma{{32, 136, 24, 16}, "-"};
Text t3_mode{{64, 136, 48, 16}, "-"};
Text t3_ph{{128, 136, 56, 16}, "-"};
Text t3_st{{192, 136, 48, 16}, "-"};
Text t4_id{{0, 152, 24, 16}, "C4:"};
Text t4_ma{{32, 152, 24, 16}, "-"};
Text t4_mode{{64, 152, 48, 16}, "-"};
Text t4_ph{{128, 152, 56, 16}, "-"};
Text t4_st{{192, 152, 48, 16}, "-"};
Text t5_id{{0, 168, 24, 16}, "C5:"};
Text t5_ma{{32, 168, 24, 16}, "-"};
Text t5_mode{{64, 168, 48, 16}, "-"};
Text t5_ph{{128, 168, 56, 16}, "-"};
Text t5_st{{192, 168, 48, 16}, "-"};
Button button_refresh{{8, 260, 100, 24}, "Refresh"};
Button button_done{{132, 260, 100, 24}, "Done"};
};
#endif
#endif
class DebugPeripheralsMenuView : public BtnGridView {
public:
DebugPeripheralsMenuView(NavigationView& nav);
std::string title() const override { return "Peripherals"; };
private:
NavigationView& nav_;
void on_populate() override;
};
class DebugReboot : public BtnGridView {
public:
DebugReboot(NavigationView& nav);
private:
void on_populate() override;
};
class DebugMenuView : public BtnGridView {
public:
DebugMenuView(NavigationView& nav);
std::string title() const override { return "Debug"; };
private:
NavigationView& nav_;
void on_populate() override;
};
} /* namespace ui */
#endif /*__UI_DEBUG_H__*/