diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index 6d9251f5..41428aaf 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -238,6 +238,7 @@ set(CPPSRC apps/ui_soundboard.cpp apps/ui_sstvtx.cpp apps/ui_test.cpp + apps/ui_tone_search.cpp apps/ui_touch_calibration.cpp apps/ui_touchtunes.cpp apps/ui_view_wav.cpp diff --git a/firmware/application/apps/ui_aprs_tx.cpp b/firmware/application/apps/ui_aprs_tx.cpp index 257e892e..63aa1cf9 100644 --- a/firmware/application/apps/ui_aprs_tx.cpp +++ b/firmware/application/apps/ui_aprs_tx.cpp @@ -27,6 +27,7 @@ #include "string_format.hpp" #include "portapack.hpp" #include "baseband_api.hpp" +#include "portapack_shared_memory.hpp" #include "portapack_persistent_memory.hpp" #include @@ -46,21 +47,29 @@ APRSTXView::~APRSTXView() { baseband::shutdown(); } -void APRSTXView::paint(Painter& painter) { - (void)painter; -} - -void APRSTXView::generate_frame() { - -} - void APRSTXView::start_tx() { - //generate_frame(); + make_aprs_frame( + sym_source.value_string().c_str(), num_ssid_source.value(), + sym_dest.value_string().c_str(), num_ssid_dest.value(), + payload); - /*transmitter_model.set_tuning_frequency(144800000); + //uint8_t * bb_data_ptr = shared_memory.bb_data.data; + //text_payload.set(to_string_hex_array(bb_data_ptr + 56, 15)); + + transmitter_model.set_tuning_frequency(persistent_memory::tuned_frequency()); + transmitter_model.set_sampling_rate(AFSK_TX_SAMPLERATE); transmitter_model.set_rf_amp(true); - transmitter_model.set_baseband_bandwidth(2500000); - transmitter_model.enable();*/ + transmitter_model.set_baseband_bandwidth(1750000); + transmitter_model.enable(); + + baseband::set_afsk_data( + AFSK_TX_SAMPLERATE / 1200, + 1200, + 2200, + 1, + 10000, //transmitter_model.channel_bandwidth(), + 8 + ); } void APRSTXView::on_tx_progress(const uint32_t progress, const bool done) { @@ -69,9 +78,6 @@ void APRSTXView::on_tx_progress(const uint32_t progress, const bool done) { if (done) { transmitter_model.disable(); tx_view.set_transmitting(false); - //progress.set_value(0); - } else { - //progress.set_value(n); } } @@ -81,10 +87,26 @@ APRSTXView::APRSTXView(NavigationView& nav) { add_children({ &labels, - &text_frame_a, + &sym_source, + &num_ssid_source, + &sym_dest, + &num_ssid_dest, + &text_payload, + &button_set, &tx_view }); + button_set.on_select = [this, &nav](Button&) { + text_prompt( + nav, + &payload, + 30, + [this](std::string* s) { + text_payload.set(*s); + } + ); + }; + tx_view.on_edit_frequency = [this, &nav]() { return; }; diff --git a/firmware/application/apps/ui_aprs_tx.hpp b/firmware/application/apps/ui_aprs_tx.hpp index d920684b..173d9fd7 100644 --- a/firmware/application/apps/ui_aprs_tx.hpp +++ b/firmware/application/apps/ui_aprs_tx.hpp @@ -38,8 +38,6 @@ public: APRSTXView(NavigationView& nav); ~APRSTXView(); - void paint(Painter& painter) override; - void focus() override; std::string title() const override { return "APRS TX (beta)"; }; @@ -53,25 +51,58 @@ private: tx_modes tx_mode = IDLE;*/ + std::string payload { "" }; + void start_tx(); void generate_frame(); void generate_frame_pos(); void on_tx_progress(const uint32_t progress, const bool done); Labels labels { - { { 2 * 8, 2 * 8 }, "Work in progress...", Color::light_grey() } + { { 0 * 8, 1 * 16 }, "Source: SSID:", Color::light_grey() }, // 6 alphanum + SSID + { { 0 * 8, 2 * 16 }, " Dest.: SSID:", Color::light_grey() }, + { { 0 * 8, 4 * 16 }, "Info field:", Color::light_grey() }, }; - Text text_frame_a { - { 2 * 8, 13 * 16, 14 * 8, 16 }, + SymField sym_source { + { 7 * 8, 1 * 16 }, + 6, + SymField::SYMFIELD_ALPHANUM + }; + NumberField num_ssid_source { + { 19 * 8, 1 * 16 }, + 2, + { 0, 15 }, + 1, + ' ' + }; + + SymField sym_dest { + { 7 * 8, 2 * 16 }, + 6, + SymField::SYMFIELD_ALPHANUM + }; + NumberField num_ssid_dest { + { 19 * 8, 2 * 16 }, + 2, + { 0, 15 }, + 1, + ' ' + }; + + Text text_payload { + { 0 * 8, 5 * 16, 30 * 8, 16 }, "-" }; + Button button_set { + { 0 * 8, 6 * 16, 80, 32 }, + "Set" + }; TransmitterView tx_view { 16 * 16, - 144800000, - 2000000, - true + 5000, + 10 }; MessageHandlerRegistration message_handler_tx_progress { diff --git a/firmware/application/apps/ui_tone_search.cpp b/firmware/application/apps/ui_tone_search.cpp new file mode 100644 index 00000000..c7c2e0fc --- /dev/null +++ b/firmware/application/apps/ui_tone_search.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2018 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_tone_search.hpp" + +#include "baseband_api.hpp" +#include "string_format.hpp" + +using namespace portapack; + +namespace ui { + +void ToneSearchView::focus() { + //field_frequency_min.focus(); +} + +ToneSearchView::~ToneSearchView() { + receiver_model.disable(); + baseband::shutdown(); +} + +ToneSearchView::ToneSearchView( + NavigationView& nav +) : nav_ (nav) +{ + //baseband::run_image(portapack::spi_flash::image_tag_wideband_spectrum); + + add_children({ + &labels + }); +} + +} /* namespace ui */ diff --git a/firmware/application/apps/ui_tone_search.hpp b/firmware/application/apps/ui_tone_search.hpp new file mode 100644 index 00000000..b32c9bff --- /dev/null +++ b/firmware/application/apps/ui_tone_search.hpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2018 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 "receiver_model.hpp" + +#include "ui_receiver.hpp" +#include "ui_font_fixed_8x16.hpp" + +namespace ui { + +class ToneSearchView : public View { +public: + ToneSearchView(NavigationView& nav); + ~ToneSearchView(); + + void focus() override; + + std::string title() const override { return "Tone search"; }; + +private: + NavigationView& nav_; + + Labels labels { + { { 1 * 8, 0 }, "Min: Max: LNA VGA", Color::light_grey() } + }; + + /* + MessageHandlerRegistration message_handler_frame_sync { + Message::ID::DisplayFrameSync, + [this](const Message* const) { + if( this->fifo ) { + ChannelSpectrum channel_spectrum; + while( fifo->out(channel_spectrum) ) { + this->on_channel_spectrum(channel_spectrum); + } + } + this->do_timers(); + } + };*/ +}; + +} /* namespace ui */ diff --git a/firmware/application/main.cpp b/firmware/application/main.cpp index ac6244da..6d15d483 100755 --- a/firmware/application/main.cpp +++ b/firmware/application/main.cpp @@ -23,6 +23,7 @@ // Color bitmaps generated with: // Gimp image > indexed colors (16), then "xxd -i *.bmp" +//TEST: Goertzel //TEST: Menuview refresh, seems to blink a lot //TEST: Check AFSK transmit end, skips last bits ? //TEST: Imperial in whipcalc @@ -44,7 +45,6 @@ //TODO: De bruijn sequence scanner for encoders //TODO: FILEMAN Move files //TODO: Use separate thread for scanning in EPAR TX -//TODO: Use separate thread for scanning in LCR TX //TODO: Make freqman refresh simpler (use previous black rectangle method) //TODO: Merge AFSK and TONES procs ? //TODO: NFM RX mode: nav.pop on squelch diff --git a/firmware/application/protocols/aprs.cpp b/firmware/application/protocols/aprs.cpp index d0d32636..96cf8df6 100644 --- a/firmware/application/protocols/aprs.cpp +++ b/firmware/application/protocols/aprs.cpp @@ -29,17 +29,20 @@ using namespace ax25; namespace aprs { -void make_aprs_frame(char * address_dest, char * address_src) { +void make_aprs_frame(const char * src_address, const uint32_t src_ssid, + const char * dest_address, const uint32_t dest_ssid, + const std::string& payload) { + AX25Frame frame; char address[14] = { 0 }; - uint8_t info[7] = { 0 }; //{ 'F','U','R','R','T','E','K' }; - // Both SSIDs are 0 - memcpy(&address[0], address_dest, 6); - memcpy(&address[7], address_src, 6); + memcpy(&address[0], dest_address, 6); + address[6] = (dest_ssid & 15) << 1; + memcpy(&address[7], src_address, 6); + address[13] = (src_ssid & 15) << 1; - frame.make_ui_frame(address, 0x03, protocol_id_t::NO_LAYER3, info, sizeof(info)); + frame.make_ui_frame(address, 0x03, protocol_id_t::NO_LAYER3, payload); } } /* namespace aprs */ diff --git a/firmware/application/protocols/aprs.hpp b/firmware/application/protocols/aprs.hpp index 79b3a6a6..4229b9e5 100644 --- a/firmware/application/protocols/aprs.hpp +++ b/firmware/application/protocols/aprs.hpp @@ -28,7 +28,10 @@ namespace aprs { - void make_aprs_frame(); + void make_aprs_frame( + const char * src_address, const uint32_t src_ssid, + const char * dest_address, const uint32_t dest_ssid, + const std::string& payload); } /* namespace aprs */ diff --git a/firmware/application/protocols/ax25.cpp b/firmware/application/protocols/ax25.cpp index e784e7dd..ea1744f6 100644 --- a/firmware/application/protocols/ax25.cpp +++ b/firmware/application/protocols/ax25.cpp @@ -35,39 +35,42 @@ void AX25Frame::make_extended_field(char * const data, size_t length) { add_data((data[i] << 1) | 1); } -void AX25Frame::add_byte(uint8_t byte, bool is_flag, bool is_data) { - size_t i; +void AX25Frame::NRZI_add_bit(const uint32_t bit) { + if (!bit) + current_bit ^= 1; // Zero: flip - for (i = 0; i < 8; ) { + current_byte <<= 1; + current_byte |= current_bit; + + bit_counter++; + + if (bit_counter == 8) { + bit_counter = 0; + *bb_data_ptr = current_byte; + bb_data_ptr++; + } +} + +void AX25Frame::add_byte(uint8_t byte, bool is_flag, bool is_data) { + uint32_t bit; + + if (is_data) + crc_ccitt.process_byte(byte); + + for (uint32_t i = 0; i < 8; i++) { + bit = (byte >> i) & 1; - if (!(byte & 1)) { - current_bit ^= 1; // Zero: flip - ones_counter = 0; - byte >>= 1; - i++; - } else { + if (bit) ones_counter++; - if ((ones_counter == 5) && (!is_flag)) { - current_bit ^= 1; // Stuff zero: flip - ones_counter = 0; - } else { - byte >>= 1; - i++; - } + else + ones_counter = 0; + + if ((ones_counter == 6) && (!is_flag)) { + NRZI_add_bit(0); + ones_counter = 0; } - if (is_data) - crc_ccitt.process_bit(current_bit); - current_byte <<= 1; - current_byte |= current_bit; - - if (bit_counter == 7) { - bit_counter = 0; - *bb_data_ptr = current_byte; - bb_data_ptr++; - } else { - bit_counter++; - } + NRZI_add_bit(bit); } } @@ -86,32 +89,38 @@ void AX25Frame::add_data(uint8_t byte) { void AX25Frame::add_checksum() { auto checksum = crc_ccitt.checksum(); - add_byte(checksum >> 8, false, false); add_byte(checksum, false, false); + add_byte(checksum >> 8, false, false); } void AX25Frame::make_ui_frame(char * const address, const uint8_t control, - const uint8_t protocol, uint8_t * const info, size_t length) { + const uint8_t protocol, const std::string& info) { size_t i; - bb_data_ptr = shared_memory.bb_data.data; + bb_data_ptr = (uint16_t*)shared_memory.bb_data.data; + memset(bb_data_ptr, 0, sizeof(shared_memory.bb_data.data)); bit_counter = 0; current_bit = 0; current_byte = 0; ones_counter = 0; crc_ccitt.reset(); + add_flag(); + add_flag(); + add_flag(); add_flag(); make_extended_field(address, 14); add_data(control); add_data(protocol); - for (i = 0; i < length; i++) + for (i = 0; i < info.size(); i++) add_data(info[i]); add_checksum(); + + add_flag(); add_flag(); flush(); diff --git a/firmware/application/protocols/ax25.hpp b/firmware/application/protocols/ax25.hpp index badf51e2..8819cf5a 100644 --- a/firmware/application/protocols/ax25.hpp +++ b/firmware/application/protocols/ax25.hpp @@ -44,9 +44,10 @@ enum protocol_id_t { class AX25Frame { public: void make_ui_frame(char * const address, const uint8_t control, const uint8_t protocol, - uint8_t * const info, size_t length); + const std::string& info); private: + void NRZI_add_bit(const uint32_t bit); void make_extended_field(char * const data, size_t length); void add_byte(uint8_t byte, bool is_flag, bool is_data); void add_data(uint8_t byte); @@ -54,13 +55,13 @@ private: void add_flag(); void flush(); - uint8_t * bb_data_ptr { nullptr }; + uint16_t * bb_data_ptr { nullptr }; uint8_t current_bit { 0 }; uint8_t current_byte { 0 }; size_t bit_counter { 0 }; uint8_t ones_counter { 0 }; - CRC<16> crc_ccitt { 0x1021, 0xFFFF }; + CRC<16, true, true> crc_ccitt { 0x1021, 0xFFFF, 0xFFFF }; }; } /* namespace ax25 */ diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index a166558f..37aca0b8 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -59,6 +59,7 @@ #include "ui_soundboard.hpp" #include "ui_sstvtx.hpp" #include "ui_test.hpp" +#include "ui_tone_search.hpp" #include "ui_touchtunes.hpp" #include "ui_view_wav.hpp" #include "ui_whipcalc.hpp" @@ -349,7 +350,7 @@ ReceiversMenuView::ReceiversMenuView(NavigationView& nav) { TransmittersMenuView::TransmittersMenuView(NavigationView& nav) { add_items({ { "ADS-B Mode S", ui::Color::yellow(), &bitmap_icon_adsb, [&nav](){ nav.push(); } }, - { "APRS", ui::Color::grey(), &bitmap_icon_aprs, [&nav](){ nav.push(); } }, + { "APRS", ui::Color::orange(), &bitmap_icon_aprs, [&nav](){ nav.push(); } }, { "BHT Xy/EP", ui::Color::green(), &bitmap_icon_bht, [&nav](){ nav.push(); } }, { "Jammer", ui::Color::yellow(), &bitmap_icon_jammer, [&nav](){ nav.push(); } }, { "Key fob", ui::Color::orange(), &bitmap_icon_keyfob, [&nav](){ nav.push(); } }, @@ -360,11 +361,10 @@ TransmittersMenuView::TransmittersMenuView(NavigationView& nav) { { "Generic OOK remotes", ui::Color::yellow(), &bitmap_icon_remote, [&nav](){ nav.push(); } }, { "POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav](){ nav.push(); } }, { "RDS", ui::Color::green(), &bitmap_icon_rds, [&nav](){ nav.push(); } }, - { "Signal generator", ui::Color::green(), &bitmap_icon_cwgen, [&nav](){ nav.push(); } }, { "Soundboard", ui::Color::green(), &bitmap_icon_soundboard, [&nav](){ nav.push(); } }, { "SSTV", ui::Color::green(), &bitmap_icon_sstv, [&nav](){ nav.push(); } }, { "TEDI/LCR AFSK", ui::Color::yellow(), &bitmap_icon_lcr, [&nav](){ nav.push(); } }, - { "TouchTunes remote", ui::Color::orange(), nullptr, [&nav](){ nav.push(); } }, + { "TouchTunes remote", ui::Color::yellow(), nullptr, [&nav](){ nav.push(); } }, }); on_left = [&nav](){ nav.pop(); }; } @@ -376,8 +376,10 @@ UtilitiesMenuView::UtilitiesMenuView(NavigationView& nav) { { "Test app", ui::Color::grey(), nullptr, [&nav](){ nav.push(); } }, { "Frequency manager", ui::Color::green(), &bitmap_icon_freqman, [&nav](){ nav.push(); } }, { "File manager", ui::Color::yellow(), &bitmap_icon_file, [&nav](){ nav.push(); } }, - { "Whip antenna length", ui::Color::yellow(), nullptr, [&nav](){ nav.push(); } }, { "Notepad", ui::Color::grey(), &bitmap_icon_notepad, [&nav](){ nav.push(); } }, + { "Signal generator", ui::Color::green(), &bitmap_icon_cwgen, [&nav](){ nav.push(); } }, + { "Tone search", ui::Color::grey(), nullptr, [&nav](){ nav.push(); } }, // ToneSearchView + { "Whip antenna length", ui::Color::yellow(), nullptr, [&nav](){ nav.push(); } }, { "Wipe SD card", ui::Color::red(), nullptr, [&nav](){ nav.push(); } }, }); on_left = [&nav](){ nav.pop(); }; diff --git a/firmware/baseband/CMakeLists.txt b/firmware/baseband/CMakeLists.txt index 9ca339fd..13f0a62f 100644 --- a/firmware/baseband/CMakeLists.txt +++ b/firmware/baseband/CMakeLists.txt @@ -113,6 +113,7 @@ set(CPPSRC baseband_stats_collector.cpp dsp_decimate.cpp dsp_demodulate.cpp + dsp_goertzel.cpp matched_filter.cpp spectrum_collector.cpp stream_input.cpp diff --git a/firmware/baseband/dsp_goertzel.cpp b/firmware/baseband/dsp_goertzel.cpp new file mode 100644 index 00000000..eaa374d0 --- /dev/null +++ b/firmware/baseband/dsp_goertzel.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2018 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 "dsp_goertzel.hpp" + +#include "complex.hpp" +#include "sine_table.hpp" + +namespace dsp { + +GoertzelDetector::GoertzelDetector( + const float frequency, + const uint32_t sample_rate +) { + coefficient = 2.0 * sin_f32((2.0 * pi * frequency / sample_rate) - pi / 2.0); +} + +float GoertzelDetector::execute( + const buffer_s16_t& src +) { + + const size_t count = src.count; + + for (size_t i = 0; i < count; i++) { + s[2] = s[1]; + s[1] = s[0]; + s[0] = src.p[i] + coefficient * s[1] - s[2]; + } + + const uint32_t sq0 = s[0] * s[0]; + const uint32_t sq1 = s[1] * s[1]; + float magnitude = __builtin_sqrtf(sq0 + sq1 - s[0] * s[1] * coefficient); + + return magnitude; +} + +} /* namespace dsp */ diff --git a/firmware/baseband/dsp_goertzel.hpp b/firmware/baseband/dsp_goertzel.hpp new file mode 100644 index 00000000..7b733a0e --- /dev/null +++ b/firmware/baseband/dsp_goertzel.hpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2018 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 __DSP_GOERTZEL_H__ +#define __DSP_GOERTZEL_H__ + +#include "dsp_types.hpp" + +namespace dsp { + +class GoertzelDetector { +public: + GoertzelDetector(const float frequency, const uint32_t sample_rate); + + float execute(const buffer_s16_t& src); + +private: + float coefficient { }; + int16_t s[2] { 0 }; +}; + +} /* namespace dsp */ + +#endif/*__DSP_GOERTZEL_H__*/ diff --git a/firmware/common/ui_widget.cpp b/firmware/common/ui_widget.cpp index d1e8044f..756ac513 100644 --- a/firmware/common/ui_widget.cpp +++ b/firmware/common/ui_widget.cpp @@ -1309,17 +1309,19 @@ SymField::SymField( } else if (type == SYMFIELD_HEX) { for (c = 0; c < length; c++) set_symbol_list(c, "0123456789ABCDEF"); + } else if (type == SYMFIELD_ALPHANUM) { + for (c = 0; c < length; c++) + set_symbol_list(c, " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"); } set_focusable(true); } uint32_t SymField::value_dec_u32() { - uint32_t c, mul = 1; - uint32_t v = 0; + uint32_t mul = 1, v = 0; if (type_ == SYMFIELD_DEC) { - for (c = 0; c < length_; c++) { + for (uint32_t c = 0; c < length_; c++) { v += values_[(length_ - 1 - c)] * mul; mul *= 10; } @@ -1329,16 +1331,27 @@ uint32_t SymField::value_dec_u32() { } uint64_t SymField::value_hex_u64() { - uint32_t c; uint64_t v = 0; if (type_ != SYMFIELD_DEF) { - for (c = 0; c < length_; c++) + for (uint32_t c = 0; c < length_; c++) v += (uint64_t)(values_[c]) << (4 * (length_ - 1 - c)); return v; } else return 0; } + +std::string SymField::value_string() { + std::string return_string { "" }; + + if (type_ == SYMFIELD_ALPHANUM) { + for (uint32_t c = 0; c < length_; c++) { + return_string += symbol_list_[0][values_[c]]; + } + } + + return return_string; +} uint32_t SymField::get_sym(const uint32_t index) { if (index >= length_) return 0; diff --git a/firmware/common/ui_widget.hpp b/firmware/common/ui_widget.hpp index 7874d448..49b40bd1 100644 --- a/firmware/common/ui_widget.hpp +++ b/firmware/common/ui_widget.hpp @@ -563,6 +563,7 @@ public: SYMFIELD_OCT, SYMFIELD_DEC, SYMFIELD_HEX, + SYMFIELD_ALPHANUM, SYMFIELD_DEF // User DEFined }; @@ -577,6 +578,7 @@ public: void set_symbol_list(const uint32_t index, const std::string symbol_list); uint32_t value_dec_u32(); uint64_t value_hex_u64(); + std::string value_string(); void paint(Painter& painter) override; diff --git a/firmware/portapack-h1-havoc.bin b/firmware/portapack-h1-havoc.bin index 8b44f7ca..64300e57 100644 Binary files a/firmware/portapack-h1-havoc.bin and b/firmware/portapack-h1-havoc.bin differ