SymField rewrite (#1444)

* First WIP symfield

* Cleanup widget code

* Rebase and format

* Fix 'to_integer' bug, fix siggen UI.

* to_string_hex fix, unit tests for string code

* Pass instance in callback

* Fix on_change callbacks

* Fix keyfob (not active)

* to_byte_array, coaster tx cleanup

* Add to_byte_array tests

* Changes in ui_numbers

* Fix ui_encoders

* Format

* Fix modemsetup view's symfields

* Remove header

* Format
This commit is contained in:
Kyle Reed
2023-09-12 12:38:19 -07:00
committed by GitHub
parent 70e0f2913f
commit af424aa5f8
30 changed files with 607 additions and 371 deletions

View File

@@ -71,6 +71,7 @@ POCSAGSettingsView::POCSAGSettingsView(
check_hide_bad.set_value(settings_.hide_bad_data);
check_hide_addr_only.set_value(settings_.hide_addr_only);
check_ignore.set_value(settings_.enable_ignore);
field_ignore.set_value(settings_.address_to_ignore);
button_save.on_select = [this, &nav](Button&) {
@@ -81,7 +82,7 @@ POCSAGSettingsView::POCSAGSettingsView(
settings_.hide_bad_data = check_hide_bad.value();
settings_.hide_addr_only = check_hide_addr_only.value();
settings_.enable_ignore = check_ignore.value();
settings_.address_to_ignore = field_ignore.value();
settings_.address_to_ignore = field_ignore.to_integer();
nav.pop();
};
@@ -155,7 +156,7 @@ POCSAGAppView::~POCSAGAppView() {
// Save pmem settings.
pmem::set_pocsag_ignore_address(settings_.address_to_ignore);
pmem::set_pocsag_last_address(pocsag_state.address); // For POCSAG TX.
pmem::set_pocsag_last_address(last_address); // For POCSAG TX.
}
void POCSAGAppView::refresh_ui() {

View File

@@ -171,12 +171,11 @@ class POCSAGSettingsView : public View {
22,
"Enable Ignored Address"};
NumberField field_ignore{
SymField field_ignore{
{7 * 8, 13 * 16 + 8},
7,
{0, 9999999},
1,
'0'};
SymField::Type::Dec,
true /*explicit_edit*/};
Button button_save{
{11 * 8, 16 * 16, 10 * 8, 2 * 16},
@@ -223,7 +222,7 @@ class POCSAGAppView : public View {
void on_packet(const POCSAGPacketMessage* message);
void on_stats(const POCSAGStatsMessage* stats);
uint32_t last_address = 0xFFFFFFFF;
uint32_t last_address = 0;
pocsag::EccContainer ecc{};
pocsag::POCSAGState pocsag_state{&ecc};
POCSAGLogger logger{};

View File

@@ -186,13 +186,12 @@ ADSBSquawkView::ADSBSquawkView(
&field_squawk});
}
void ADSBSquawkView::collect_frames(const uint32_t ICAO_address, std::vector<ADSBFrame>& frame_list) {
void ADSBSquawkView::collect_frames(const uint32_t /*ICAO_address*/, std::vector<ADSBFrame>& frame_list) {
if (!enabled) return;
ADSBFrame temp_frame;
(void)ICAO_address;
encode_frame_squawk(temp_frame, field_squawk.concatenate_4_octal_u16());
encode_frame_squawk(temp_frame, field_squawk.to_integer());
frame_list.emplace_back(temp_frame);
}
@@ -277,7 +276,7 @@ ADSBTxView::~ADSBTxView() {
}
void ADSBTxView::generate_frames() {
const uint32_t ICAO_address = sym_icao.value_hex_u64();
const uint32_t ICAO_address = sym_icao.to_integer();
frames.clear();

View File

@@ -135,7 +135,7 @@ class ADSBSquawkView : public OptionTabView {
SymField field_squawk{
{10 * 8, 2 * 16},
4,
SymField::SYMFIELD_OCT};
SymField::Type::Oct};
};
class ADSBTXThread {
@@ -235,7 +235,7 @@ class ADSBTxView : public View {
SymField sym_icao{
{10 * 8, 4 * 8},
6,
SymField::SYMFIELD_HEX};
SymField::Type::Hex};
Text text_frame{
{1 * 8, 29 * 8, 14 * 8, 16},

View File

@@ -48,9 +48,10 @@ APRSTXView::~APRSTXView() {
}
void APRSTXView::start_tx() {
// TODO: Clean up this API to take string_views to avoid allocations.
make_aprs_frame(
sym_source.value_string().c_str(), num_ssid_source.value(),
sym_dest.value_string().c_str(), num_ssid_dest.value(),
sym_source.to_string().c_str(), num_ssid_source.value(),
sym_dest.to_string().c_str(), num_ssid_dest.value(),
payload);
// uint8_t * bb_data_ptr = shared_memory.bb_data.data;

View File

@@ -68,7 +68,8 @@ class APRSTXView : public View {
SymField sym_source{
{7 * 8, 1 * 16},
6,
SymField::SYMFIELD_ALPHANUM};
SymField::Type::Alpha};
NumberField num_ssid_source{
{19 * 8, 1 * 16},
2,
@@ -79,7 +80,7 @@ class APRSTXView : public View {
SymField sym_dest{
{7 * 8, 2 * 16},
6,
SymField::SYMFIELD_ALPHANUM};
SymField::Type::Alpha};
NumberField num_ssid_dest{
{19 * 8, 2 * 16},

View File

@@ -42,12 +42,12 @@ CoasterPagerView::~CoasterPagerView() {
}
void CoasterPagerView::generate_frame() {
uint8_t frame[19];
uint32_t c;
constexpr uint8_t frame_bytes = 19;
uint8_t frame[frame_bytes];
// Preamble (8 bytes)
for (c = 0; c < 8; c++)
frame[c] = 0x55; // Isn't this 0xAA ?
for (uint8_t c = 0; c < 8; c++)
frame[c] = 0x55;
// Sync word
frame[8] = 0x2D;
@@ -57,11 +57,11 @@ void CoasterPagerView::generate_frame() {
frame[10] = 8;
// Data
for (c = 0; c < 8; c++)
frame[c + 11] = (sym_data.get_sym(c * 2) << 4) | sym_data.get_sym(c * 2 + 1);
auto data_bytes = to_byte_array(sym_data.to_integer());
memcpy(&frame[11], data_bytes.data(), data_bytes.size());
// Copy for baseband
memcpy(shared_memory.bb_data.data, frame, 19);
memcpy(shared_memory.bb_data.data, frame, frame_bytes);
}
void CoasterPagerView::start_tx() {
@@ -72,12 +72,7 @@ void CoasterPagerView::start_tx() {
baseband::set_fsk_data(19 * 8, 2280000 / 1000, 5000, 32);
}
void CoasterPagerView::on_tx_progress(const uint32_t progress, const bool done) {
(void)progress;
uint16_t address = 0;
uint32_t c;
void CoasterPagerView::on_tx_progress(const uint32_t /*progress*/, const bool done) {
if (done) {
if (tx_mode == SINGLE) {
transmitter_model.disable();
@@ -85,18 +80,12 @@ void CoasterPagerView::on_tx_progress(const uint32_t progress, const bool done)
tx_view.set_transmitting(false);
} else if (tx_mode == SCAN) {
// Increment address
for (c = 0; c < 4; c++) {
address <<= 4;
address |= sym_data.get_sym(12 + c);
}
uint64_t data = sym_data.to_integer();
uint16_t address = data & 0xFFFF;
address++;
for (c = 0; c < 4; c++) {
sym_data.set_sym(15 - c, address & 0x0F);
address >>= 4;
}
data = (data & 0xFFFFFFFFFFFF0000) + address;
sym_data.set_value(data);
start_tx();
}
@@ -104,9 +93,6 @@ void CoasterPagerView::on_tx_progress(const uint32_t progress, const bool done)
}
CoasterPagerView::CoasterPagerView(NavigationView& nav) {
const uint8_t data_init[8] = {0x44, 0x01, 0x3B, 0x30, 0x30, 0x30, 0x34, 0xBC};
uint32_t c;
baseband::run_image(portapack::spi_flash::image_tag_fsktx);
add_children({&labels,
@@ -115,9 +101,7 @@ CoasterPagerView::CoasterPagerView(NavigationView& nav) {
&text_message,
&tx_view});
// Bytes to nibbles
for (c = 0; c < 16; c++)
sym_data.set_sym(c, (data_init[c >> 1] >> ((c & 1) ? 0 : 4)) & 0x0F);
sym_data.set_value(0x44013B30303034BC);
checkbox_scan.set_value(false);

View File

@@ -68,17 +68,19 @@ class CoasterPagerView : public View {
SymField sym_data{
{7 * 8, 8 * 8},
16, // 14 ? 12 ?
SymField::SYMFIELD_HEX};
16,
SymField::Type::Hex};
Checkbox checkbox_scan{
{10 * 8, 14 * 8},
4,
"Scan"};
/*ProgressBar progressbar {
{ 5 * 8, 12 * 16, 20 * 8, 16 },
};*/
/*
ProgressBar progressbar {
{ 5 * 8, 12 * 16, 20 * 8, 16 }};
*/
Text text_message{
{5 * 8, 13 * 16, 20 * 8, 16},
""};

View File

@@ -49,7 +49,6 @@ EncodersConfigView::EncodersConfigView(
&field_clk_step,
&field_frameduration,
&field_frameduration_step,
&symfield_word,
&text_format,
&waveform});
@@ -64,10 +63,6 @@ EncodersConfigView::EncodersConfigView(
options_enctype.set_options(enc_options);
options_enctype.set_selected_index(0);
symfield_word.on_change = [this]() {
generate_frame();
};
// Selecting input clock changes symbol and word duration
field_clk.on_change = [this](int32_t value) {
// value is in kHz, new_value is in us
@@ -98,33 +93,46 @@ void EncodersConfigView::focus() {
}
void EncodersConfigView::on_type_change(size_t index) {
std::string format_string = "";
size_t word_length;
char symbol_type;
// Remove existing SymField controls.
for (auto& symfield : symfields_word)
remove_child(symfield.get());
symfields_word.clear();
encoder_def = &encoder_defs[index];
field_clk.set_value(encoder_def->default_speed / 1000);
field_repeat_min.set_value(encoder_def->repeat_min);
// SymField setup
word_length = encoder_def->word_length;
symfield_word.set_length(word_length);
size_t n = 0, i = 0;
while (n < word_length) {
symbol_type = encoder_def->word_format[i++];
if (symbol_type == 'A') {
symfield_word.set_symbol_list(n++, encoder_def->address_symbols);
format_string += 'A';
} else if (symbol_type == 'D') {
symfield_word.set_symbol_list(n++, encoder_def->data_symbols);
format_string += 'D';
// Add new SymFields.
Point pos{2 * 8, 9 * 8};
std::string format_string;
uint8_t word_length = encoder_def->word_length;
auto on_change_handler = [this](SymField&) {
generate_frame();
};
for (uint8_t i = 0; i < word_length; i++) {
auto symbol_type = encoder_def->word_format[i];
symfields_word.push_back(std::make_unique<SymField>(pos, 1));
auto& symfield = symfields_word.back();
symfield->on_change = on_change_handler;
switch (symbol_type) {
case 'A':
symfield->set_symbol_list(encoder_def->address_symbols);
format_string += 'A';
break;
case 'D':
symfield->set_symbol_list(encoder_def->data_symbols);
format_string += 'D';
break;
}
add_child(symfield.get());
pos += Point{8, 0};
}
// Ugly :( Pad to erase
format_string.append(24 - format_string.size(), ' ');
text_format.set(format_string);
generate_frame();
@@ -146,17 +154,18 @@ void EncodersConfigView::draw_waveform() {
}
void EncodersConfigView::generate_frame() {
size_t i = 0;
frame_fragments.clear();
size_t i = 0;
for (auto c : encoder_def->word_format) {
if (c == 'S')
frame_fragments += encoder_def->sync;
else if (!c)
else if (c == '\0')
break;
else
frame_fragments += encoder_def->bit_format[symfield_word.get_sym(i++)];
else {
auto offset = symfields_word[i++]->get_offset(0);
frame_fragments += encoder_def->bit_format[offset];
}
}
draw_waveform();

View File

@@ -29,6 +29,9 @@
#include "app_settings.hpp"
#include "radio_state.hpp"
#include <memory>
#include <vector>
using namespace encoders;
namespace ui {
@@ -113,10 +116,7 @@ class EncodersConfigView : public View {
{"100", 100},
{"1000", 1000}}};
SymField symfield_word{
{2 * 8, 9 * 8},
20,
SymField::SYMFIELD_DEF};
std::vector<std::unique_ptr<SymField>> symfields_word{};
Text text_format{
{2 * 8, 11 * 8, 24 * 8, 16},

View File

@@ -97,12 +97,12 @@ size_t KeyfobView::generate_frame() {
uint64_t payload;
// Symfield word to frame
payload = field_payload_a.value_hex_u64();
payload = field_payload_a.to_integer();
for (size_t i = 0; i < 5; i++) {
frame[4 - i] = payload & 0xFF;
payload >>= 8;
}
payload = field_payload_b.value_hex_u64();
payload = field_payload_b.to_integer();
for (size_t i = 0; i < 5; i++) {
frame[9 - i] = payload & 0xFF;
payload >>= 8;
@@ -136,9 +136,6 @@ void KeyfobView::focus() {
}
KeyfobView::~KeyfobView() {
// save app settings
settings.save("tx_keyfob", &app_settings);
transmitter_model.disable();
baseband::shutdown();
}
@@ -167,12 +164,12 @@ void KeyfobView::on_make_change(size_t index) {
// DEBUG
void KeyfobView::update_symfields() {
for (size_t i = 0; i < 5; i++) {
field_payload_a.set_sym(i << 1, frame[i] >> 4);
field_payload_a.set_sym((i << 1) + 1, frame[i] & 0x0F);
field_payload_a.set_offset(i << 1, frame[i] >> 4);
field_payload_a.set_offset((i << 1) + 1, frame[i] & 0x0F);
}
for (size_t i = 0; i < 5; i++) {
field_payload_b.set_sym(i << 1, frame[5 + i] >> 4);
field_payload_b.set_sym((i << 1) + 1, frame[5 + i] & 0x0F);
field_payload_b.set_offset(i << 1, frame[5 + i] >> 4);
field_payload_b.set_offset((i << 1) + 1, frame[5 + i] & 0x0F);
}
}
@@ -212,13 +209,6 @@ KeyfobView::KeyfobView(
&progressbar,
&tx_view});
// load app settings
auto rc = settings.load("tx_keyfob", &app_settings);
if (rc == SETTINGS_OK) {
transmitter_model.set_rf_amp(app_settings.tx_amp);
transmitter_model.set_tx_gain(app_settings.tx_gain);
}
frame[0] = 0x55;
update_symfields();

View File

@@ -48,7 +48,7 @@ class KeyfobView : public View {
OOK_SAMPLERATE /* sampling rate */
};
app_settings::SettingsManager settings_{
"tx_keyfob", , app_settings::Mode::TX};
"tx_keyfob", app_settings::Mode::TX};
// 1013210ns / bit
static constexpr uint32_t subaru_samples_per_bit = (OOK_SAMPLERATE * 0.00101321);
@@ -98,11 +98,11 @@ class KeyfobView : public View {
SymField field_payload_a{
{2 * 8, 5 * 16},
10,
SymField::SYMFIELD_HEX};
SymField::Type::Hex};
SymField field_payload_b{
{13 * 8, 5 * 16},
10,
SymField::SYMFIELD_HEX};
SymField::Type::Hex};
Text text_status{
{2 * 8, 13 * 16, 128, 16},

View File

@@ -23,7 +23,6 @@
#include "ui_modemsetup.hpp"
#include "portapack.hpp"
#include "portapack_persistent_memory.hpp"
using namespace portapack;
@@ -41,15 +40,20 @@ ModemSetupView::ModemSetupView(
using options_t = std::vector<option_t>;
options_t modem_options;
add_children({&labels,
&field_baudrate,
&field_mark,
&field_space,
&field_repeat,
&options_modem,
&button_set_modem,
&sym_format,
&button_save});
add_children({
&labels,
&field_baudrate,
&field_mark,
&field_space,
&field_repeat,
&options_modem,
&button_set_modem,
&sym_format_data,
&sym_format_parity,
&sym_format_stop,
&sym_format_msb,
&button_save,
});
// Only list AFSK modems for now
for (size_t i = 0; i < MODEM_DEF_COUNT; i++) {
@@ -59,15 +63,10 @@ ModemSetupView::ModemSetupView(
options_modem.set_options(modem_options);
options_modem.set_selected_index(0);
sym_format.set_symbol_list(0, "6789"); // Data bits
sym_format.set_symbol_list(1, "NEo"); // Parity
sym_format.set_symbol_list(2, "012"); // Stop bits
sym_format.set_symbol_list(3, "ML"); // MSB/LSB first
sym_format.set_sym(0, persistent_memory::serial_format().data_bits - 6);
sym_format.set_sym(1, persistent_memory::serial_format().parity);
sym_format.set_sym(2, persistent_memory::serial_format().stop_bits);
sym_format.set_sym(3, persistent_memory::serial_format().bit_order);
sym_format_data.set_offset(0, persistent_memory::serial_format().data_bits - 6);
sym_format_parity.set_offset(0, persistent_memory::serial_format().parity);
sym_format_stop.set_offset(0, persistent_memory::serial_format().stop_bits);
sym_format_msb.set_offset(0, persistent_memory::serial_format().bit_order);
field_mark.set_value(persistent_memory::afsk_mark_freq());
field_space.set_value(persistent_memory::afsk_space_freq());
@@ -84,18 +83,17 @@ ModemSetupView::ModemSetupView(
};
button_save.on_select = [this, &nav](Button&) {
serial_format_t serial_format;
persistent_memory::set_afsk_mark(field_mark.value());
persistent_memory::set_afsk_space(field_space.value());
persistent_memory::set_modem_baudrate(field_baudrate.value());
persistent_memory::set_modem_repeat(field_repeat.value());
serial_format.data_bits = sym_format.get_sym(0) + 6;
serial_format.parity = (parity_enum)sym_format.get_sym(1);
serial_format.stop_bits = sym_format.get_sym(2);
serial_format.bit_order = (order_enum)sym_format.get_sym(3);
serial_format_t serial_format{};
serial_format.data_bits = sym_format_data.get_offset(0) + 6;
serial_format.parity = (parity_enum)sym_format_parity.get_offset(0);
serial_format.stop_bits = sym_format_stop.get_offset(0);
serial_format.bit_order = (order_enum)sym_format_msb.get_offset(0);
persistent_memory::set_serial_format(serial_format);

View File

@@ -79,10 +79,25 @@ class ModemSetupView : public View {
7,
{}};
SymField sym_format{
SymField sym_format_data{
{16 * 8, 22 * 8},
4,
SymField::SYMFIELD_DEF};
1,
"6789"};
SymField sym_format_parity{
{17 * 8, 22 * 8},
1,
"NEo"};
SymField sym_format_stop{
{18 * 8, 22 * 8},
1,
"012"};
SymField sym_format_msb{
{19 * 8, 22 * 8},
1,
"ML"};
Button button_set_modem{
{23 * 8, 6 * 8 - 4, 6 * 8, 24},

View File

@@ -21,6 +21,7 @@
*/
#include "ui_numbers.hpp"
#include "ui_styles.hpp"
#include "string_format.hpp"
#include "portapack.hpp"
@@ -75,7 +76,7 @@ void NumbersStationView::prepare_audio() {
return;
}
code = symfield_code.get_sym(code_index);
code = symfield_code.get_offset(code_index);
if (code >= 10) {
memset(audio_buffer, 0, 1024);
@@ -144,7 +145,7 @@ void NumbersStationView::on_tick_second() {
armed_blink = not armed_blink;
if (armed_blink)
check_armed.set_style(&style_red);
check_armed.set_style(&Styles::red);
else
check_armed.set_style(&style());
@@ -152,14 +153,12 @@ void NumbersStationView::on_tick_second() {
}
void NumbersStationView::on_voice_changed(size_t index) {
std::string code_list = "";
std::string code_list;
for (const auto& wavs : voices[index].available_wavs)
code_list += wavs.code;
for (uint32_t c = 0; c < 25; c++)
symfield_code.set_symbol_list(c, code_list);
symfield_code.set_symbol_list(code_list);
current_voice = &voices[index];
}
@@ -265,17 +264,17 @@ NumbersStationView::NumbersStationView(
};
// DEBUG
symfield_code.set_sym(0, 10);
symfield_code.set_sym(1, 3);
symfield_code.set_sym(2, 4);
symfield_code.set_sym(3, 11);
symfield_code.set_sym(4, 6);
symfield_code.set_sym(5, 1);
symfield_code.set_sym(6, 9);
symfield_code.set_sym(7, 7);
symfield_code.set_sym(8, 8);
symfield_code.set_sym(9, 0);
symfield_code.set_sym(10, 12); // End
symfield_code.set_offset(0, 10);
symfield_code.set_offset(1, 3);
symfield_code.set_offset(2, 4);
symfield_code.set_offset(3, 11);
symfield_code.set_offset(4, 6);
symfield_code.set_offset(5, 1);
symfield_code.set_offset(6, 9);
symfield_code.set_offset(7, 7);
symfield_code.set_offset(8, 8);
symfield_code.set_offset(9, 0);
symfield_code.set_offset(10, 12); // End
/*
rtc::RTC datetime;

View File

@@ -142,16 +142,19 @@ class NumbersStationView : public View {
SymField symfield_code{
{1 * 8, 10 * 8},
25,
SymField::SYMFIELD_DEF};
SymField::Type::Custom};
Checkbox check_armed{
{2 * 8, 13 * 16},
5,
"Armed"};
/*Button button_tx_now {
{ 18 * 8, 13 * 16, 10 * 8, 32 },
"TX now"
};*/
/*
Button button_tx_now {
{ 18 * 8, 13 * 16, 10 * 8, 32 },
"TX now"};
*/
Button button_exit{
{21 * 8, 16 * 16, 64, 32},
"Exit"};

View File

@@ -56,7 +56,7 @@ bool POCSAGTXView::start_tx() {
pocsag::BitRate bitrate;
std::vector<uint32_t> codewords;
address = field_address.value_dec_u32();
address = field_address.to_integer();
if (address > 0x1FFFFFU) {
nav_.display_modal("Bad address", "Address must be less\nthan 2097152.");
return false;
@@ -137,12 +137,7 @@ POCSAGTXView::POCSAGTXView(
options_bitrate.set_selected_index(1); // 1200bps
options_type.set_selected_index(0); // Address only
// TODO: set_value for whole symfield
uint32_t reload_address = persistent_memory::pocsag_last_address();
for (uint32_t c = 0; c < 7; c++) {
field_address.set_sym(6 - c, reload_address % 10);
reload_address /= 10;
}
field_address.set_value(persistent_memory::pocsag_last_address());
options_type.on_change = [this](size_t, int32_t i) {
if (i == 2)

View File

@@ -94,8 +94,7 @@ class POCSAGTXView : public View {
SymField field_address{
{11 * 8, 6 * 8},
7,
SymField::SYMFIELD_DEC};
7};
OptionsField options_type{
{11 * 8, 8 * 8},

View File

@@ -164,7 +164,7 @@ RDSView::~RDSView() {
}
void RDSView::start_tx() {
rds_flags.PI_code = sym_pi_code.value_hex_u64();
rds_flags.PI_code = sym_pi_code.to_integer();
rds_flags.PTY = options_pty.selected_index_value();
rds_flags.DI = view_PSN.mono_stereo ? 1 : 0;
rds_flags.TP = check_TP.value();
@@ -212,12 +212,9 @@ RDSView::RDSView(
check_TP.set_value(true);
sym_pi_code.set_sym(0, 0xF);
sym_pi_code.set_sym(1, 0x3);
sym_pi_code.set_sym(2, 0xE);
sym_pi_code.set_sym(3, 0x0);
sym_pi_code.on_change = [this]() {
rds_flags.PI_code = sym_pi_code.value_hex_u64();
sym_pi_code.set_value(0xF3E0);
sym_pi_code.on_change = [this](SymField&) {
rds_flags.PI_code = sym_pi_code.to_integer();
};
options_pty.set_selected_index(0); // None

View File

@@ -287,7 +287,7 @@ class RDSView : public View {
SymField sym_pi_code{
{13 * 8, 28 + 16},
4,
SymField::SYMFIELD_HEX};
SymField::Type::Hex};
/*OptionsField options_coverage {
{ 17 * 8, 32 + 8 },

View File

@@ -50,7 +50,7 @@ void SigGenView::update_config() {
}
void SigGenView::update_tone() {
baseband::set_siggen_tone(symfield_tone.value_dec_u32());
baseband::set_siggen_tone(symfield_tone.to_integer());
}
void SigGenView::start_tx() {
@@ -97,8 +97,8 @@ SigGenView::SigGenView(
field_stop.set_value(1);
symfield_tone.set_sym(1, 1); // Default: 1000 Hz
symfield_tone.on_change = [this]() {
symfield_tone.set_value(1000); // Default: 1000 Hz
symfield_tone.on_change = [this](SymField&) {
if (auto_update)
update_tone();
};

View File

@@ -92,9 +92,8 @@ class SigGenView : public View {
""};
SymField symfield_tone{
{13 * 8, 7 * 8},
5,
SymField::SYMFIELD_DEC};
{12 * 8, 7 * 8},
5};
Button button_update{
{5 * 8, 10 * 8, 8 * 8, 3 * 8},