diff --git a/firmware/application/Makefile b/firmware/application/Makefile index cbbdabd5..0d2b97d4 100755 --- a/firmware/application/Makefile +++ b/firmware/application/Makefile @@ -161,6 +161,7 @@ CPPSRC = main.cpp \ ui_closecall.cpp \ ui_console.cpp \ ui_debug.cpp \ + ui_epar.cpp \ ui_focus.cpp \ ui_font_fixed_8x16.cpp \ ui_handwrite.cpp \ diff --git a/firmware/application/ui_epar.cpp b/firmware/application/ui_epar.cpp new file mode 100644 index 00000000..70ea8f8e --- /dev/null +++ b/firmware/application/ui_epar.cpp @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek + * + * 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. + */ + +#include "ui_epar.hpp" + +#include "ch.h" +#include "hackrf_hal.hpp" + +#include "event_m0.hpp" +#include "ff.h" +#include "hackrf_gpio.hpp" +#include "portapack.hpp" +#include "radio.hpp" + +#include "hackrf_hal.hpp" +#include "portapack_shared_memory.hpp" +#include "portapack_persistent_memory.hpp" + +#include +#include + +using namespace portapack; + +namespace ui { + +void EPARView::focus() { + city_code.focus(); +} + +EPARView::~EPARView() { + transmitter_model.disable(); +} + +void EPARView::update_message() { + uint8_t c; + + // Start bit + epar_bits[0] = 1; + + // To binary + for (c = 0; c < 8; c++) + epar_bits[c + 1] = ((city_code.value() >> c) & 1); + + epar_bits[9] = options_group.selected_index_value() & 1; + epar_bits[10] = (options_group.selected_index_value() >> 1) & 1; + + if (checkbox_ra.value()) + epar_bits[11] = 1; // Bit 11 is relay 1 state + else + epar_bits[11] = 0; + + if (checkbox_rb.value()) + epar_bits[12] = 1; // Bit 12 is relay 2 state + else + epar_bits[12] = 0; + + // DEBUG + char debug_binary[14]; + for (c = 0; c < 13; c++) + debug_binary[c] = 0x30 + epar_bits[c]; + debug_binary[13] = 0; + + text_debug.set(debug_binary); +} + +void EPARView::journuit() { + chThdSleepMilliseconds(1000); + + // Invert relay states + checkbox_ra.set_value(~checkbox_ra.value()); + checkbox_rb.set_value(~checkbox_rb.value()); + + update_message(); + + shared_memory.transmit_done = false; + memcpy(shared_memory.epardata, epar_bits, 13); + transmitter_model.enable(); +} + +EPARView::EPARView( + NavigationView& nav +) +{ + static constexpr Style style_val { + .font = font::fixed_8x16, + .background = Color::green(), + .foreground = Color::black(), + }; + + static constexpr Style style_cancel { + .font = font::fixed_8x16, + .background = Color::red(), + .foreground = Color::black(), + }; + + transmitter_model.set_baseband_configuration({ + .mode = 4, + .sampling_rate = 1536000, + .decimation_factor = 1, + }); + + add_children({ { + &text_city, + &city_code, + &text_group, + &options_group, + &checkbox_ra, + &checkbox_rb, + &text_freq, + &options_freq, + &progressbar, + &text_debug, + &button_transmit, + &checkbox_cligno, + &button_exit + } }); + + city_code.set_value(220); + options_group.set_selected_index(3); // TP + options_freq.set_selected_index(6); // 5 ! DEBUG + + checkbox_ra.set_value(true); + checkbox_rb.set_value(true); + + city_code.on_change = [this](int32_t v) { + (void)v; + EPARView::update_message(); + }; + options_group.on_change = [this](size_t n, OptionsField::value_t v) { + (void)n; + (void)v; + EPARView::update_message(); + }; + checkbox_ra.on_select = [this](Checkbox&) { + EPARView::update_message(); + }; + checkbox_rb.on_select = [this](Checkbox&) { + EPARView::update_message(); + }; + + button_transmit.set_style(&style_val); + + EPARView::update_message(); + + button_transmit.on_select = [this](Button&) { + if (txing == false) { + update_message(); + + EventDispatcher::message_map().unregister_handler(Message::ID::TXDone); + + EventDispatcher::message_map().register_handler(Message::ID::TXDone, + [this](Message* const p) { + const auto message = static_cast(p); + if (message->n == 100) { + transmitter_model.disable(); + progressbar.set_value(0); + if (checkbox_cligno.value() == false) { + txing = false; + button_transmit.set_style(&style_val); + button_transmit.set_text("START"); + } else { + journuit(); + } + } else { + progressbar.set_value(message->n * 2); // 100/52 + } + } + ); + + shared_memory.transmit_done = false; + memcpy(shared_memory.epardata, epar_bits, 13); + + transmitter_model.set_tuning_frequency(epar_freqs[options_freq.selected_index()]); + + txing = true; + button_transmit.set_style(&style_cancel); + button_transmit.set_text("Wait"); + transmitter_model.enable(); + } + }; + + button_exit.on_select = [&nav](Button&){ + nav.pop(); + }; + +} + +} /* namespace ui */ diff --git a/firmware/application/ui_epar.hpp b/firmware/application/ui_epar.hpp new file mode 100644 index 00000000..d9d5762f --- /dev/null +++ b/firmware/application/ui_epar.hpp @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek + * + * 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. + */ + +#include "ui.hpp" +#include "ui_widget.hpp" +#include "ui_painter.hpp" +#include "ui_menu.hpp" +#include "ui_navigation.hpp" +#include "ui_font_fixed_8x16.hpp" +#include "clock_manager.hpp" +#include "message.hpp" +#include "rf_path.hpp" +#include "max2837.hpp" +#include "volume.hpp" +#include "transmitter_model.hpp" +#include "receiver_model.hpp" + +namespace ui { + +class EPARView : public View { +public: + EPARView(NavigationView& nav); + ~EPARView(); + std::string title() const override { return "EPAR transmit"; }; + void journuit(); + + void talk(); + void update_message(); + void focus() override; + +private: + bool txing = false; + const rf::Frequency epar_freqs[7] = { 31325000, 31387500, 31437500, 31475000, 31687500, 31975000, 88000000 }; + char epar_bits[13]; + + /* |012345678901234567890123456789| + * | Code ville: 000 | + * | Groupe: 00 | + * */ + + Text text_city { + { 6 * 8, 1 * 16, 11 * 8, 16 }, + "Code ville:" + }; + NumberField city_code { + { 18 * 8, 1 * 16 }, + 3, + { 0, 255 }, + 0, + ' ' + }; + + Text text_group { + { 10 * 8, 2 * 16, 7 * 8, 16 }, + "Groupe:" + }; + OptionsField options_group { + { 18 * 8, 2 * 16 }, + 4, + { + { "A ", 2 }, // See receiver PCB + { "B ", 1 }, + { "C ", 0 }, + { "TP", 3 } + } + }; + + Text text_freq { + { 5 * 8, 4 * 16, 10 * 8, 16 }, + "Frequence:" + }; + OptionsField options_freq { + { 16 * 8, 4 * 16}, + 7, + { + { "31.3250", 0 }, + { "31.3875", 1 }, + { "31.4375", 2 }, + { "31.4750", 3 }, + { "31.6875", 4 }, + { "31.9750", 5 }, + { "TEST 88", 6 } + } + }; + + Checkbox checkbox_ra { + { 7 * 8, 6 * 16 }, + 8, + "Relais 1" + }; + Checkbox checkbox_rb { + { 7 * 8, 8 * 16 }, + 8, + "Relais 2" + }; + + ProgressBar progressbar { + { 2 * 8, 12 * 16, 26 * 8, 20 }, + }; + + Text text_debug { + { 5 * 8, 14 * 16, 13 * 8, 16 }, + "-------------" + }; + + Button button_transmit { + { 2 * 8, 16 * 16, 64, 32 }, + "START" + }; + + Checkbox checkbox_cligno { + { 96, 16 * 16 + 4}, + 3, + "J/N" + }; + + Button button_exit { + { 21 * 8, 16 * 16, 64, 32 }, + "Exit" + }; +}; + +} /* namespace ui */ diff --git a/firmware/application/ui_loadmodule.cpp b/firmware/application/ui_loadmodule.cpp index 4d782fce..63eed8ef 100644 --- a/firmware/application/ui_loadmodule.cpp +++ b/firmware/application/ui_loadmodule.cpp @@ -34,6 +34,7 @@ #include "ui_rds.hpp" #include "ui_xylos.hpp" +#include "ui_epar.hpp" #include "ui_lcr.hpp" #include "analog_audio_app.hpp" #include "ui_soundboard.hpp" @@ -166,6 +167,7 @@ LoadModuleView::LoadModuleView( if (_mod_loaded == true) { if (viewid == AudioTX) nav.push(); if (viewid == Xylos) nav.push(); + if (viewid == EPAR) nav.push(); if (viewid == LCR) nav.push(); if (viewid == SoundBoard) nav.push(); if (viewid == AnalogAudio) nav.push(); diff --git a/firmware/application/ui_loadmodule.hpp b/firmware/application/ui_loadmodule.hpp index d2d35e99..e142d070 100644 --- a/firmware/application/ui_loadmodule.hpp +++ b/firmware/application/ui_loadmodule.hpp @@ -35,6 +35,7 @@ enum ViewID { AudioTX, CloseCall, Xylos, + EPAR, LCR, SoundBoard, AnalogAudio, diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index f4130c68..5ea4446b 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -187,7 +187,8 @@ SystemMenuView::SystemMenuView(NavigationView& nav) { { "Receiver RX", ui::Color::cyan(), [&nav](){ nav.push(md5_baseband, Receiver); } }, { "Close Call RX", ui::Color::cyan(), [&nav](){ nav.push(md5_baseband, CloseCall); } }, { "Soundboard TX", ui::Color::yellow(), [&nav](){ nav.push(md5_baseband_tx, SoundBoard); } }, - { "Audio TX", ui::Color::yellow(), [&nav](){ nav.push(md5_baseband_tx, AudioTX); } }, + //{ "Audio TX", ui::Color::yellow(), [&nav](){ nav.push(md5_baseband_tx, AudioTX); } }, + { "EPAR TX", ui::Color::green(), [&nav](){ nav.push(md5_baseband_tx, EPAR); } }, { "Xylos TX", ui::Color::orange(), [&nav](){ nav.push(md5_baseband_tx, Xylos); } }, { "TEDI/LCR TX", ui::Color::orange(), [&nav](){ nav.push(md5_baseband_tx, LCR); } }, { "RDS TX", ui::Color::yellow(), [&nav](){ nav.push(md5_baseband_tx, RDS); } }, diff --git a/firmware/application/ui_xylos.cpp b/firmware/application/ui_xylos.cpp index f1c1d14a..deed06de 100644 --- a/firmware/application/ui_xylos.cpp +++ b/firmware/application/ui_xylos.cpp @@ -206,7 +206,7 @@ void XylosView::journuit() { upd_message(); audio::headphone::set_volume(volume_t::decibel(90 - 99) + audio::headphone::volume_range().max); - shared_memory.xylos_transmit_done = false; + shared_memory.transmit_done = false; memcpy(shared_memory.xylosdata, ccirmessage, 21); transmitter_model.enable(); } @@ -270,7 +270,7 @@ XylosView::XylosView( receiver_code.set_value(1); header_code_a.set_value(0); header_code_b.set_value(0); - options_freq.set_selected_index(6); // 5 ! DEBUG + options_freq.set_selected_index(5); checkbox_wcsubfamily.set_value(true); checkbox_wcid.set_value(true); @@ -352,7 +352,7 @@ XylosView::XylosView( ); memcpy(ccirmessage, ccirtest, 21); - shared_memory.xylos_transmit_done = false; + shared_memory.transmit_done = false; memcpy(shared_memory.xylosdata, ccirmessage, 21); transmitter_model.set_tuning_frequency(xylos_freqs[options_freq.selected_index()]); @@ -401,7 +401,7 @@ XylosView::XylosView( } ); - shared_memory.xylos_transmit_done = false; + shared_memory.transmit_done = false; memcpy(shared_memory.xylosdata, ccirmessage, 21); transmitter_model.set_tuning_frequency(xylos_freqs[options_freq.selected_index()]); diff --git a/firmware/application/ui_xylos.hpp b/firmware/application/ui_xylos.hpp index 0d8d79c6..96d88977 100644 --- a/firmware/application/ui_xylos.hpp +++ b/firmware/application/ui_xylos.hpp @@ -151,7 +151,6 @@ private: bool txing = false; const rf::Frequency xylos_freqs[7] = { 31325000, 31387500, 31437500, 31475000, 31687500, 31975000, 88000000 }; char ccirmessage[21]; - char ccir_received[21]; Text text_title { { 8, 8, 11, 16 }, diff --git a/firmware/baseband-tx.bin b/firmware/baseband-tx.bin index 002a8983..b8c8e5b9 100644 Binary files a/firmware/baseband-tx.bin and b/firmware/baseband-tx.bin differ diff --git a/firmware/baseband-tx/Makefile b/firmware/baseband-tx/Makefile index cfe010f9..db9f9a07 100755 --- a/firmware/baseband-tx/Makefile +++ b/firmware/baseband-tx/Makefile @@ -140,6 +140,7 @@ CPPSRC = main.cpp \ matched_filter.cpp \ proc_audiotx.cpp \ proc_fsk_lcr.cpp \ + proc_epar.cpp \ proc_playaudio.cpp \ proc_xylos.cpp \ dsp_squelch.cpp \ diff --git a/firmware/baseband-tx/baseband_thread.cpp b/firmware/baseband-tx/baseband_thread.cpp index 51c62caf..eeb1fdea 100644 --- a/firmware/baseband-tx/baseband_thread.cpp +++ b/firmware/baseband-tx/baseband_thread.cpp @@ -31,6 +31,7 @@ #include "proc_playaudio.hpp" #include "proc_audiotx.hpp" #include "proc_xylos.hpp" +#include "proc_epar.hpp" #include "proc_fsk_lcr.hpp" #include "rssi.hpp" @@ -124,6 +125,7 @@ BasebandProcessor* BasebandThread::create_processor(const int32_t mode) { case 1: return new AudioTXProcessor(); case 2: return new XylosProcessor(); case 3: return new LCRFSKProcessor(); + case 4: return new EPARProcessor(); default: return nullptr; } } diff --git a/firmware/baseband-tx/proc_epar.cpp b/firmware/baseband-tx/proc_epar.cpp new file mode 100644 index 00000000..d186228f --- /dev/null +++ b/firmware/baseband-tx/proc_epar.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek + * + * 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. + */ + +#include "proc_epar.hpp" + +#include "dsp_iir_config.hpp" +#include "audio_output.hpp" + +#include "portapack_shared_memory.hpp" +#include "sine_table.hpp" + +#include + +void EPARProcessor::execute(const buffer_c8_t& buffer) { + + // This is called at 1536000/2048 = 750Hz + + for (size_t i = 0; i= 9) { + s = 0; + + if (sample_count >= EPAR_TU) { + + if (state) { + // Send code + if (current_tu == 2) { + current_bit = shared_memory.epardata[bit_pos]; + if (bit_pos == 12) { + bit_pos = 0; + current_tu = 0; + state = 0; + } else { + bit_pos++; + } + + current_tu = 0; + } else { + current_tu++; + } + + sample = bitdef[current_bit][current_tu]; + } else { + // Pause + if (current_tu == EPAR_SPACE) { + if (repeat_count == EPAR_REPEAT) { + message.n = 100; // End of transmission code + shared_memory.transmit_done = true; + shared_memory.application_queue.push(message); + } + if (shared_memory.transmit_done == false) { + message.n = repeat_count; // Inform UI about progress (just as eye candy) + shared_memory.application_queue.push(message); + state = 1; + } + repeat_count++; + current_tu = 0; + } else { + current_tu++; + } + sample = 0; + } + + sample_count = 0; + } else { + sample_count++; + } + + } else { + s++; + } + + //FM + frq = sample * 1000; // ~25kHz wide + + phase = (phase + frq); + sphase = phase + (256<<16); + + re = (sine_table_f32[(sphase & 0x03FF0000)>>18]*127); + im = (sine_table_f32[(phase & 0x03FF0000)>>18]*127); + + buffer.p[i] = {(int8_t)re,(int8_t)im}; + } +} diff --git a/firmware/baseband-tx/proc_epar.hpp b/firmware/baseband-tx/proc_epar.hpp new file mode 100644 index 00000000..d1b060d0 --- /dev/null +++ b/firmware/baseband-tx/proc_epar.hpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek + * + * 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 __PROC_EPAR_H__ +#define __PROC_EPAR_H__ + +#include "baseband_processor.hpp" + +#include "dsp_decimate.hpp" +#include "dsp_demodulate.hpp" + +#include "audio_output.hpp" +#include "baseband_processor.hpp" + +// One bit is 0.005119048s (~200bps ?) +// Time unit is 0.001706349s (586Hz) + +#define EPAR_TU 262-1 // 1536000/10/586 +#define EPAR_SPACE 33-1 +#define EPAR_REPEAT 26*2 // DEBUG + +// 0: 011 +// 1: 001 + +// Good: 1001110111111 +// Bad: 1100111011111 + +class EPARProcessor : public BasebandProcessor { +public: + void execute(const buffer_c8_t& buffer) override; + +private: + const uint8_t bitdef[2][3] = { + {0, 255, 255}, + {0, 0, 255} + }; + int8_t re, im; + uint8_t s; + uint8_t state_length = 0; + uint8_t current_bit = 0; + uint8_t current_tu = 0; + uint8_t bit_pos = 0; + uint8_t repeat_count = 0; + uint32_t sample_count = 0; + uint32_t aphase, phase, sphase; + int32_t sample, frq; + uint8_t state = 1; + TXDoneMessage message; +}; + +#endif diff --git a/firmware/baseband-tx/proc_xylos.cpp b/firmware/baseband-tx/proc_xylos.cpp index 9caf1d19..8d6de4d9 100644 --- a/firmware/baseband-tx/proc_xylos.cpp +++ b/firmware/baseband-tx/proc_xylos.cpp @@ -43,7 +43,7 @@ void XylosProcessor::execute(const buffer_c8_t& buffer) { s = 0; if (sample_count >= CCIR_TONELENGTH) { - if (shared_memory.xylos_transmit_done == false) { + if (shared_memory.transmit_done == false) { message.n = byte_pos; // Inform UI about progress (just as eye candy) shared_memory.application_queue.push(message); digit = shared_memory.xylosdata[byte_pos++]; @@ -51,7 +51,7 @@ void XylosProcessor::execute(const buffer_c8_t& buffer) { if (digit == 0xFF) { message.n = 25; // End of message code - shared_memory.xylos_transmit_done = true; + shared_memory.transmit_done = true; shared_memory.application_queue.push(message); } @@ -60,7 +60,7 @@ void XylosProcessor::execute(const buffer_c8_t& buffer) { sample_count++; } - aphase += ccir_phases[digit]; // DEBUG + aphase += ccir_phases[digit]; } else { s++; } @@ -76,7 +76,7 @@ void XylosProcessor::execute(const buffer_c8_t& buffer) { }*/ //FM - frq = sample * 1000; // ~10kHz wide + frq = sample * 1000; // ~25kHz wide phase = (phase + frq); sphase = phase + (256<<16); diff --git a/firmware/common/modules.h b/firmware/common/modules.h index 3f5e744c..dfb335a0 100644 --- a/firmware/common/modules.h +++ b/firmware/common/modules.h @@ -1,2 +1,2 @@ const char md5_baseband[16] = {0x07,0xff,0xf6,0x7f,0x06,0x02,0xd1,0xd7,0x67,0x8f,0x67,0xdc,0xe8,0x36,0xa9,0xc0,}; -const char md5_baseband_tx[16] = {0xe9,0xeb,0x30,0xea,0x3f,0xf5,0xea,0x93,0xf9,0x62,0x1e,0x9c,0x5f,0x29,0xa7,0x95,}; +const char md5_baseband_tx[16] = {0xac,0xaf,0x2a,0x20,0x45,0x35,0x18,0x9c,0xdf,0x02,0x5c,0x2c,0x8f,0x76,0xd3,0xdc,}; diff --git a/firmware/common/portapack_shared_memory.hpp b/firmware/common/portapack_shared_memory.hpp index 8fbd689c..26492d7c 100644 --- a/firmware/common/portapack_shared_memory.hpp +++ b/firmware/common/portapack_shared_memory.hpp @@ -67,7 +67,8 @@ struct SharedMemory { JammerRange jammer_ranges[16]; char xylosdata[21]; - bool xylos_transmit_done; + char epardata[13]; + bool transmit_done; }; extern SharedMemory& shared_memory; diff --git a/firmware/common/ui_widget.cpp b/firmware/common/ui_widget.cpp index 77e36887..51d08d1e 100644 --- a/firmware/common/ui_widget.cpp +++ b/firmware/common/ui_widget.cpp @@ -729,6 +729,10 @@ size_t OptionsField::selected_index() const { return selected_index_; } +size_t OptionsField::selected_index_value() const { + return options[selected_index_].second; +} + void OptionsField::set_selected_index(const size_t new_index) { if( new_index < options.size() ) { if( new_index != selected_index() ) { diff --git a/firmware/common/ui_widget.hpp b/firmware/common/ui_widget.hpp index 42306d98..0ba7185d 100644 --- a/firmware/common/ui_widget.hpp +++ b/firmware/common/ui_widget.hpp @@ -322,6 +322,7 @@ public: void set_options(options_t new_options); size_t selected_index() const; + size_t selected_index_value() const; void set_selected_index(const size_t new_index); void set_by_value(value_t v); diff --git a/firmware/portapack-h1-firmware.bin b/firmware/portapack-h1-firmware.bin index f852f729..b3d7bdad 100644 Binary files a/firmware/portapack-h1-firmware.bin and b/firmware/portapack-h1-firmware.bin differ diff --git a/sdcard/baseband-tx.bin b/sdcard/baseband-tx.bin index 002a8983..b8c8e5b9 100644 Binary files a/sdcard/baseband-tx.bin and b/sdcard/baseband-tx.bin differ