Exemplo n.º 1
0
PlayDeadView::PlayDeadView(NavigationView& nav, bool booting) {
	_booting = booting;
	persistent_memory::set_playing_dead(0x59);
	
	add_children({ {
		&text_playdead1,
		&text_playdead2,
		&button_done,
	} });
	
	button_done.on_dir = [this,&nav](Button&, KeyEvent key){
		sequence = (sequence<<3) | static_cast<std::underlying_type<KeyEvent>::type>(key);
	};
	
	button_done.on_select = [this,&nav](Button&){
		if (sequence == persistent_memory::playdead_sequence()) {
			persistent_memory::set_playing_dead(0);
			if (_booting) {
				nav.pop();
				nav.push(new SystemMenuView { nav });
			} else {
				nav.pop();
			}
		} else {
			sequence = 0;
		}
	};
}
Exemplo n.º 2
0
BMPView::BMPView(NavigationView& nav) {
	add_children({ {
		&text_info,
		&button_done
	} });
	
	button_done.on_select = [this,&nav](Button&){
		nav.pop();
		nav.push(new SystemMenuView { nav });
	};
}
Exemplo n.º 3
0
DebugMenuView::DebugMenuView(NavigationView& nav) {
	add_items<7>({ {
		{ "Memory",      [&nav](){ nav.push(new DebugMemoryView    { nav }); } },
		{ "Radio State", [&nav](){ nav.push(new NotImplementedView { nav }); } },
		{ "SD Card",     [&nav](){ nav.push(new NotImplementedView { nav }); } },
		{ "RFFC5072",    [&nav](){ nav.push(new DebugRFFC5072View  { nav }); } },
		{ "MAX2837",     [&nav](){ nav.push(new NotImplementedView { nav }); } },
		{ "Si5351C",     [&nav](){ nav.push(new NotImplementedView { nav }); } },
		{ "WM8731",      [&nav](){ nav.push(new NotImplementedView { nav }); } },
	} });
	on_left = [&nav](){ nav.pop(); };
}
Exemplo n.º 4
0
SetDateTimeView::SetDateTimeView(
    NavigationView& nav
) {
    button_ok.on_select = [&nav, this](Button&) {
        const auto model = this->form_collect();
        const rtc::RTC new_datetime {
            model.year, model.month, model.day,
            model.hour, model.minute, model.second
        };
        rtcSetTime(&RTCD1, &new_datetime);
        nav.pop();
    },

    button_cancel.on_select = [&nav](Button&) {
        nav.pop();
    },

    add_children({ {
            &text_title,
            &field_year,
            &text_slash1,
            &field_month,
            &text_slash2,
            &field_day,
            &field_hour,
            &text_colon1,
            &field_minute,
            &text_colon2,
            &field_second,
            &text_format,
            &button_ok,
            &button_cancel,
        }
    });

    rtc::RTC datetime;
    rtcGetTime(&RTCD1, &datetime);
    SetDateTimeModel model {
        datetime.year(),
        datetime.month(),
        datetime.day(),
        datetime.hour(),
        datetime.minute(),
        datetime.second()
    };

    form_init(model);
}
Exemplo n.º 5
0
LoadModuleView::LoadModuleView(
	NavigationView& nav,
	const char * hash,
	ViewID viewid
)
{

	add_children({ {
		&text_info,
		&text_infob,
		&button_ok
	} });
	
	_hash = hash;

	button_ok.on_select = [this, &nav, viewid](Button&){
		nav.pop();
		if (_mod_loaded == true) {
			if (viewid == AudioTX) nav.push<AudioTXView>();
			if (viewid == Xylos) nav.push<XylosView>();
			if (viewid == EPAR) nav.push<EPARView>();
			if (viewid == LCR) nav.push<LCRView>();
			if (viewid == SoundBoard) nav.push<SoundBoardView>();
			if (viewid == AnalogAudio) nav.push<AnalogAudioView>();
			if (viewid == RDS) nav.push<RDSView>();
			if (viewid == CloseCall) nav.push<CloseCallView>();
			if (viewid == Receiver) nav.push<ReceiverMenuView>();
		}
	};
}
Exemplo n.º 6
0
RegistersView::RegistersView(
	NavigationView& nav,
	const std::string& title,
	RegistersWidgetConfig&& config,
	std::function<uint32_t(const size_t register_number)>&& reader
) : registers_widget { std::move(config), std::move(reader) }
{
	add_children({ {
		&text_title,
		&registers_widget,
		&button_update,
		&button_done,
	} });

	button_update.on_select = [this](Button&){
		this->registers_widget.update();
	};
	button_done.on_select = [&nav](Button&){ nav.pop(); };

	registers_widget.set_parent_rect({ 0, 48, 240, 192 });

	text_title.set_parent_rect({
		(240 - static_cast<int>(title.size()) * 8) / 2, 16,
		static_cast<int>(title.size()) * 8, 16
	});
	text_title.set(title);
}
Exemplo n.º 7
0
NumbersStationView::NumbersStationView(
	NavigationView& nav,
	TransmitterModel& transmitter_model
) : transmitter_model(transmitter_model)
{
	uint8_t m, d, dayofweek;
	uint16_t y;
	
	add_children({ {
		&text_title,
		&button_exit
	} });
	
	rtc::RTC datetime;
	rtcGetTime(&RTCD1, &datetime);
	
	// Thanks, Sakamoto-sama !
	y = datetime.year();
	m = datetime.month();
	d = datetime.day();
	y -= m < 3;
	dayofweek = (y + y/4 - y/100 + y/400 + month_table[m-1] + d) % 7;
	
	text_title.set(day_of_week[dayofweek]);

	button_exit.on_select = [&nav](Button&){
		nav.pop();
	};
}
Exemplo n.º 8
0
FreqManView::FreqManView(
	NavigationView& nav
) {

	add_children({ {
		&button_exit
	} });

	size_t n = 0;
	for(auto& text : text_list) {
		add_child(&text);
		text.set_parent_rect({
			static_cast<Coord>(0),
			static_cast<Coord>(16 + (n * 16)),
			240, 16
		});
		const std::string label {
			(char)(n + 0x30)
		};
		text.set(label);
		n++;
	}
	
	button_exit.on_select = [this, &nav](Button&) {
		nav.pop();
	};

}
Exemplo n.º 9
0
SetupMenuView::SetupMenuView(NavigationView& nav) {
	add_items({
		{ "Date/Time", [&nav](){ nav.push<SetDateTimeView>(); } },
		{ "Frequency Correction", [&nav](){ nav.push<SetFrequencyCorrectionView>(); } },
		{ "Antenna Bias Voltage", [&nav](){ nav.push<AntennaBiasSetupView>(); } },
		{ "Touch",     [&nav](){ nav.push<TouchCalibrationView>(); } },
	});
	on_left = [&nav](){ nav.pop(); };
}
Exemplo n.º 10
0
TemperatureView::TemperatureView(NavigationView& nav) {
	add_children({ {
		&text_title,
		&temperature_widget,
		&button_done,
	} });

	button_done.on_select = [&nav](Button&){ nav.pop(); };
}
Exemplo n.º 11
0
DebugMenuView::DebugMenuView(NavigationView& nav) {
	add_items<8>({ {
		{ "Memory",      [&nav](){ nav.push<DebugMemoryView>(); } },
		{ "Radio State", [&nav](){ nav.push<NotImplementedView>(); } },
		{ "SD Card",     [&nav](){ nav.push<NotImplementedView>(); } },
		{ "Peripherals", [&nav](){ nav.push<DebugPeripheralsMenuView>(); } },
		{ "Temperature", [&nav](){ nav.push<TemperatureView>(); } },
	} });
	on_left = [&nav](){ nav.pop(); };
}
Exemplo n.º 12
0
NotImplementedView::NotImplementedView(NavigationView& nav) {
	button_done.on_select = [&nav](Button&){
		nav.pop();
	};

	add_children({ {
		&text_title,
		&button_done,
	} });
}
Exemplo n.º 13
0
SetupMenuView::SetupMenuView(NavigationView& nav) {
    add_items<3>({ {
            { "Date/Time", [&nav]() {
                    nav.push(new SetDateTimeView { nav });
                }
            },
            { "Frequency Correction", [&nav]() {
                    nav.push(new SetFrequencyCorrectionView { nav });
                }
            },
            { "Touch",     [&nav]() {
                    nav.push(new NotImplementedView { nav });
                }
            },
        }
    });
    on_left = [&nav]() {
        nav.pop();
    };
}
Exemplo n.º 14
0
FrequencySaveView::FrequencySaveView(
	NavigationView& nav,
	const rf::Frequency value
) {

	add_children({ {
		&button_exit
	} });
	
	button_exit.on_select = [this, &nav](Button&) {
		nav.pop();
	};
}
Exemplo n.º 15
0
DebugRFFC5072View::DebugRFFC5072View(NavigationView& nav) {
	add_children({ {
		&text_title,
		&widget_registers,
		&button_update,
		&button_done,
	} });

	button_update.on_select = [this](Button&){
		this->widget_registers.update();
	};
	button_done.on_select = [&nav](Button&){ nav.pop(); };
}
Exemplo n.º 16
0
CaptureAppView::CaptureAppView(NavigationView& nav) {
	baseband::run_image(portapack::spi_flash::image_tag_capture);

	add_children({ {
		&rssi,
		&channel,
		&field_frequency,
		&field_frequency_step,
		&field_rf_amp,
		&field_lna,
		&field_vga,
		&record_view,
		&waterfall,
	} });

	field_frequency.set_value(target_frequency());
	field_frequency.set_step(receiver_model.frequency_step());
	field_frequency.on_change = [this](rf::Frequency f) {
		this->on_target_frequency_changed(f);
	};
	field_frequency.on_edit = [this, &nav]() {
		// TODO: Provide separate modal method/scheme?
		auto new_view = nav.push<FrequencyKeypadView>(this->target_frequency());
		new_view->on_changed = [this](rf::Frequency f) {
			this->on_target_frequency_changed(f);
			this->field_frequency.set_value(f);
		};
	};

	field_frequency_step.set_by_value(receiver_model.frequency_step());
	field_frequency_step.on_change = [this](size_t, OptionsField::value_t v) {
		receiver_model.set_frequency_step(v);
		this->field_frequency.set_step(v);
	};

	radio::enable({
		tuning_frequency(),
		sampling_rate,
		baseband_bandwidth,
		rf::Direction::Receive,
		receiver_model.rf_amp(),
		static_cast<int8_t>(receiver_model.lna()),
		static_cast<int8_t>(receiver_model.vga()),
	});

	record_view.set_sampling_rate(sampling_rate / 8);
	record_view.on_error = [&nav](std::string message) {
		nav.display_modal("Error", message);
	};
}
Exemplo n.º 17
0
SystemMenuView::SystemMenuView(NavigationView& nav) {
	add_items<11>({ {
		{ "Play dead", ui::Color::red(),  		[&nav](){ nav.push(new PlayDeadView 	  { nav, false }); } },
		{ "Receiver", ui::Color::cyan(), 		[&nav](){ nav.push(new LoadModuleView { nav, md5_baseband, new ReceiverView { nav, receiver_model }}); } },
		//{ "Nordic/BTLE RX", ui::Color::cyan(),	[&nav](){ nav.push(new NotImplementedView { nav }); } },
		{ "Jammer", ui::Color::white(),   		[&nav](){ nav.push(new LoadModuleView { nav, md5_baseband, new JammerView { nav, transmitter_model }}); } },
		//{ "Audio file TX", ui::Color::white(),	[&nav](){ nav.push(new NotImplementedView { nav }); } },
		//{ "Encoder TX", ui::Color::green(),		[&nav](){ nav.push(new NotImplementedView { nav }); } },
		{ "Whistle", ui::Color::purple(),  		[&nav](){ nav.push(new LoadModuleView { nav, md5_baseband, new WhistleView { nav, transmitter_model }}); } },
		//{ "SIGFOX RX", ui::Color::orange(),  	[&nav](){ nav.push(new LoadModuleView { nav, md5_baseband, new SIGFRXView 		  { nav, receiver_model }}); } },
		{ "RDS TX", ui::Color::yellow(),  		[&nav](){ nav.push(new LoadModuleView { nav, md5_baseband_tx, new RDSView { nav, transmitter_model }}); } },
		{ "Xylos TX", ui::Color::orange(),  	[&nav](){ nav.push(new LoadModuleView { nav, md5_baseband_tx, new XylosView	{ nav, transmitter_model }}); } },
		//{ "AFSK RX", ui::Color::cyan(),  		[&nav](){ nav.push(new LoadModuleView { nav, md5_baseband, new AFSKRXView         { nav, receiver_model }}); } },
		{ "TEDI/LCR TX", ui::Color::yellow(),  	[&nav](){ nav.push(new LoadModuleView { nav, md5_baseband_tx, new LCRView { nav, transmitter_model }}); } },
		{ "Setup", ui::Color::white(),    		[&nav](){ nav.push(new SetupMenuView      { nav }); } },
		{ "About", ui::Color::white(),    		[&nav](){ nav.push(new AboutView          { nav }); } },
		{ "Debug", ui::Color::white(),    		[&nav](){ nav.push(new DebugMenuView      { nav }); } },
		{ "HackRF", ui::Color::white(),   		[&nav](){ nav.push(new HackRFFirmwareView { nav }); } },
	} });
}
Exemplo n.º 18
0
AboutView::AboutView(NavigationView& nav) {
	add_children({
		&text_title,
		&text_firmware,
		&text_cpld_hackrf,
		&text_cpld_hackrf_status,
		&button_ok,
	});

	button_ok.on_select = [&nav](Button&){ nav.pop(); };

	if( cpld_hackrf_verify_eeprom() ) {
		text_cpld_hackrf_status.set(" OK");
	} else {
		text_cpld_hackrf_status.set("BAD");
	}
}
Exemplo n.º 19
0
HackRFFirmwareView::HackRFFirmwareView(NavigationView& nav) {
	button_yes.on_select = [&nav](Button&){
		m4_request_shutdown();
	};

	button_no.on_select = [&nav](Button&){
		nav.pop();
	};

	add_children({ {
		&text_title,
		&text_description_1,
		&text_description_2,
		&text_description_3,
		&text_description_4,
		&button_yes,
		&button_no,
	} });
}
Exemplo n.º 20
0
DebugPeripheralsMenuView::DebugPeripheralsMenuView(NavigationView& nav) {
	add_items<4>({ {
		{ "RFFC5072",    [&nav](){ nav.push<RegistersView>(
			"RFFC5072", RegistersWidgetConfig { 31, 2, 4, 4 },
			[](const size_t register_number) { return radio::debug::first_if::register_read(register_number); }
		); } },
		{ "MAX2837",     [&nav](){ nav.push<RegistersView>(
			"MAX2837", RegistersWidgetConfig { 32, 2, 3, 4 },
			[](const size_t register_number) { return radio::debug::second_if::register_read(register_number); }
		); } },
		{ "Si5351C",     [&nav](){ nav.push<RegistersView>(
			"Si5351C", RegistersWidgetConfig { 96, 2, 2, 8 },
			[](const size_t register_number) { return portapack::clock_generator.read_register(register_number); }
		); } },
		{ "WM8731",      [&nav](){ nav.push<RegistersView>(
			"WM8731", RegistersWidgetConfig { audio::debug::reg_count(), 1, 3, 4 },
			[](const size_t register_number) { return audio::debug::reg_read(register_number); }
		); } },
	} });
	on_left = [&nav](){ nav.pop(); };
}
Exemplo n.º 21
0
DebugMemoryView::DebugMemoryView(NavigationView& nav) {
	add_children({ {
		&text_title,
		&text_label_m0_free,
		&text_label_m0_free_value,
		&text_label_m0_heap_fragmented_free,
		&text_label_m0_heap_fragmented_free_value,
		&text_label_m0_heap_fragments,
		&text_label_m0_heap_fragments_value,
		&button_done
	} });

	const auto m0_free = chCoreStatus();
	text_label_m0_free_value.set(to_string_dec_uint(m0_free, 5));

	size_t m0_fragmented_free_space = 0;
	const auto m0_fragments = chHeapStatus(NULL, &m0_fragmented_free_space);
	text_label_m0_heap_fragmented_free_value.set(to_string_dec_uint(m0_fragmented_free_space, 5));
	text_label_m0_heap_fragments_value.set(to_string_dec_uint(m0_fragments, 5));

	button_done.on_select = [&nav](Button&){ nav.pop(); };
}
Exemplo n.º 22
0
WhipCalcView::WhipCalcView(
	NavigationView& nav
) {

	add_children({ {
		&text_frequency,
		&field_frequency,
		&text_type,
		&options_type,
		&text_result_metric,
		&text_result_imperial,
		&text_result_ant500,
		&button_exit
	} });
	
	options_type.on_change = [this](size_t, OptionsField::value_t) {
		this->update_result();
	};
	options_type.set_selected_index(2);		// Quarter wave
	
	field_frequency.set_value(transmitter_model.tuning_frequency());
	field_frequency.set_step(500000);		// 500kHz step
	field_frequency.on_change = [this](rf::Frequency) {
		this->update_result();
	};
	field_frequency.on_edit = [this, &nav]() {
		// TODO: Provide separate modal method/scheme?
		auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.tuning_frequency());
		new_view->on_changed = [this](rf::Frequency f) {
			this->update_result();
			this->field_frequency.set_value(f);
		};
	};
	
	button_exit.on_select = [this, &nav](Button&) {
		nav.pop();
	};
}
Exemplo n.º 23
0
FrequencyKeypadView::FrequencyKeypadView(
	NavigationView& nav,
	const rf::Frequency value
) {
	add_child(&text_value);

	const auto button_fn = [this](Button& button) {
		this->on_button(button);
	};

	const char* const key_caps = "123456789<0.";

	size_t n = 0;
	for(auto& button : buttons) {
		add_child(&button);
		const std::string label {
			key_caps[n]
		};
		button.on_select = button_fn;
		button.set_parent_rect({
			static_cast<Coord>((n % 3) * button_w),
			static_cast<Coord>((n / 3) * button_h + button_h),
			button_w, button_h
		});
		button.set_text(label);
		n++;
	}

	add_child(&button_close);
	button_close.on_select = [this, &nav](Button&) {
		if( on_changed ) {
			on_changed(this->value());
		}
		nav.pop();
	};

	set_value(value);
}
Exemplo n.º 24
0
ReceiverView::ReceiverView(
	NavigationView& nav,
	ReceiverModel& receiver_model
) : receiver_model(receiver_model)
{
	add_children({ {
		&rssi,
		&channel,
		&audio,
		&button_done,
		&field_frequency,
		&field_lna,
		//&options_baseband_bandwidth,
		&field_vga,
		&options_modulation,
		//&options_baseband_oversampling,
		&field_volume,
		&view_frequency_options,
		&view_rf_gain_options,
		&waterfall,
	} });

	button_done.on_select = [&nav](Button&){
		nav.pop();
	};

	field_frequency.set_value(receiver_model.tuning_frequency());
	field_frequency.set_step(receiver_model.frequency_step());
	field_frequency.on_change = [this](rf::Frequency f) {
		this->on_tuning_frequency_changed(f);
	};
	field_frequency.on_edit = [this, &nav]() {
		// TODO: Provide separate modal method/scheme?
		auto new_view = new FrequencyKeypadView { nav, this->receiver_model.tuning_frequency() };
		new_view->on_changed = [this](rf::Frequency f) {
			this->on_tuning_frequency_changed(f);
			this->field_frequency.set_value(f);
		};
		nav.push(new_view);
	};
	field_frequency.on_show_options = [this]() {
		this->on_show_options_frequency();
	};

	field_lna.set_value(receiver_model.lna());
	field_lna.on_change = [this](int32_t v) {
		this->on_lna_changed(v);
	};
	field_lna.on_show_options = [this]() {
		this->on_show_options_rf_gain();
	};
	/*
	options_baseband_bandwidth.set_by_value(receiver_model.baseband_bandwidth());
	options_baseband_bandwidth.on_change = [this](size_t n, OptionsField::value_t v) {
		(void)n;
		this->on_baseband_bandwidth_changed(v);
	};
	*/
	field_vga.set_value(receiver_model.vga());
	field_vga.on_change = [this](int32_t v_db) {
		this->on_vga_changed(v_db);
	};

	options_modulation.set_by_value(receiver_model.modulation());
	options_modulation.on_change = [this](size_t n, OptionsField::value_t v) {
		(void)n;
		this->on_modulation_changed(v);
	};
/*
	options_baseband_oversampling.set_by_value(receiver_model.baseband_oversampling());
	options_baseband_oversampling.on_change = [this](size_t n, OptionsField::value_t v) {
		(void)n;
		this->on_baseband_oversampling_changed(v);
	};
*/
	field_volume.set_value((receiver_model.headphone_volume() - wolfson::wm8731::headphone_gain_range.max).decibel() + 99);
	field_volume.on_change = [this](int32_t v) {
		this->on_headphone_volume_changed(v);
	};

	view_frequency_options.hidden(true);
	view_frequency_options.set_step(receiver_model.frequency_step());
	view_frequency_options.on_change_step = [this](rf::Frequency f) {
		this->on_frequency_step_changed(f);
	};
	view_frequency_options.set_reference_ppm_correction(receiver_model.reference_ppm_correction());
	view_frequency_options.on_change_reference_ppm_correction = [this](int32_t v) {
		this->on_reference_ppm_correction_changed(v);
	};

	view_rf_gain_options.hidden(true);
	view_rf_gain_options.set_rf_amp(receiver_model.rf_amp());
	view_rf_gain_options.on_change_rf_amp = [this](bool enable) {
		this->on_rf_amp_changed(enable);
	};

	receiver_model.enable();
}
AnalogAudioView::AnalogAudioView(
	NavigationView& nav
) {
	add_children({ {
		&rssi,
		&channel,
		&audio,
		&field_frequency,
		&field_lna,
		&field_vga,
		&options_modulation,
		&field_volume,
		&record_view,
		&waterfall,
	} });

	field_frequency.set_value(receiver_model.tuning_frequency());
	field_frequency.set_step(receiver_model.frequency_step());
	field_frequency.on_change = [this](rf::Frequency f) {
		this->on_tuning_frequency_changed(f);
	};
	field_frequency.on_edit = [this, &nav]() {
		// TODO: Provide separate modal method/scheme?
		auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
		new_view->on_changed = [this](rf::Frequency f) {
			this->on_tuning_frequency_changed(f);
			this->field_frequency.set_value(f);
		};
	};

	field_frequency.on_show_options = [this]() {
		this->on_show_options_frequency();
	};

	field_lna.on_show_options = [this]() {
		this->on_show_options_rf_gain();
	};

	field_vga.on_show_options = [this]() {
		this->on_show_options_rf_gain();
	};

	const auto modulation = receiver_model.modulation();
	options_modulation.set_by_value(toUType(modulation));
	options_modulation.on_change = [this](size_t, OptionsField::value_t v) {
		this->on_modulation_changed(static_cast<ReceiverModel::Mode>(v));
	};
	options_modulation.on_show_options = [this]() {
		this->on_show_options_modulation();
	};

	field_volume.set_value((receiver_model.headphone_volume() - audio::headphone::volume_range().max).decibel() + 99);
	field_volume.on_change = [this](int32_t v) {
		this->on_headphone_volume_changed(v);
	};

	record_view.on_error = [&nav](std::string message) {
		nav.display_modal("Error", message);
	};

	audio::output::start();

	update_modulation(static_cast<ReceiverModel::Mode>(modulation));
}
Exemplo n.º 26
0
AFSKSetupView::AFSKSetupView(
	NavigationView& nav
)
{
	using name_t = std::string;
	using value_t = int32_t;
	using option_t = std::pair<name_t, value_t>;
	using options_t = std::vector<option_t>;
	options_t format_options;
	uint8_t rpt;
	size_t i;
	
	add_children({ {
		&text_setfreq,
		&button_setfreq,
		&text_bps,
		&options_bps,
		&text_mark,
		&field_mark,
		&text_space,
		&field_space,
		&text_bw,
		&field_bw,
		&text_repeat,
		&field_repeat,
		&text_format,
		&options_format,
		&button_save
	} });
	
	for (i = 0; i < AFSK_MODES_COUNT; i++)
		format_options.emplace_back(std::make_pair(afsk_formats[i].fullname, i));
	
	options_format.set_options(format_options);
	options_format.set_selected_index(portapack::persistent_memory::afsk_format());
	
	update_freq(portapack::persistent_memory::tuned_frequency());
	
	field_mark.set_value(portapack::persistent_memory::afsk_mark_freq() * 25);
	field_space.set_value(portapack::persistent_memory::afsk_space_freq() * 25);
	field_bw.set_value(portapack::persistent_memory::afsk_bw());
	rpt = portapack::persistent_memory::afsk_repeats();
	if ((rpt > 99) || (!rpt)) rpt = 5;
	field_repeat.set_value(rpt);
	
	button_setfreq.on_select = [this,&nav](Button&) {
		auto new_view = nav.push<FrequencyKeypadView>(portapack::persistent_memory::tuned_frequency());
		new_view->on_changed = [this](rf::Frequency f) {
			update_freq(f);
		};
	};
	
	options_bps.set_by_value(portapack::persistent_memory::afsk_bitrate());

	button_save.on_select = [this,&nav](Button&) {
		uint32_t afsk_config = 0;
		
		portapack::persistent_memory::set_afsk_bitrate(options_bps.selected_index_value());
		portapack::persistent_memory::set_afsk_mark(field_mark.value() / 25);
		portapack::persistent_memory::set_afsk_space(field_space.value() / 25);
		portapack::persistent_memory::set_afsk_bw(field_bw.value());
		
		afsk_config |= (options_format.selected_index() << 16);
		afsk_config |= (field_repeat.value() << 24);
		portapack::persistent_memory::set_afsk_config(afsk_config);
		
		nav.pop();
	};
}