diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index 7daa3d5a..4c54abd9 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -175,6 +175,7 @@ set(CPPSRC ui_record_view.cpp ui_replay_view.cpp ui_rssi.cpp + ui_script.cpp ui_sd_card_status_view.cpp ui_sd_wipe.cpp # ui_sd_card_debug.cpp @@ -183,6 +184,7 @@ set(CPPSRC ui_spectrum.cpp ui_textentry.cpp ui_touch_calibration.cpp + ui_transmitter.cpp ui_whipcalc.cpp ui_whistle.cpp # ui_loadmodule.cpp diff --git a/firmware/application/Makefile b/firmware/application/Makefile index afc6ec3b..190677e2 100644 --- a/firmware/application/Makefile +++ b/firmware/application/Makefile @@ -5000,6 +5000,33 @@ ui_rssi.cpp.s: cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_rssi.cpp.s .PHONY : ui_rssi.cpp.s +ui_script.obj: ui_script.cpp.obj + +.PHONY : ui_script.obj + +# target to build an object file +ui_script.cpp.obj: + cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_script.cpp.obj +.PHONY : ui_script.cpp.obj + +ui_script.i: ui_script.cpp.i + +.PHONY : ui_script.i + +# target to preprocess a source file +ui_script.cpp.i: + cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_script.cpp.i +.PHONY : ui_script.cpp.i + +ui_script.s: ui_script.cpp.s + +.PHONY : ui_script.s + +# target to generate assembly for a file +ui_script.cpp.s: + cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_script.cpp.s +.PHONY : ui_script.cpp.s + ui_sd_card_status_view.obj: ui_sd_card_status_view.cpp.obj .PHONY : ui_sd_card_status_view.obj @@ -5189,6 +5216,33 @@ ui_touch_calibration.cpp.s: cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_touch_calibration.cpp.s .PHONY : ui_touch_calibration.cpp.s +ui_transmitter.obj: ui_transmitter.cpp.obj + +.PHONY : ui_transmitter.obj + +# target to build an object file +ui_transmitter.cpp.obj: + cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_transmitter.cpp.obj +.PHONY : ui_transmitter.cpp.obj + +ui_transmitter.i: ui_transmitter.cpp.i + +.PHONY : ui_transmitter.i + +# target to preprocess a source file +ui_transmitter.cpp.i: + cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_transmitter.cpp.i +.PHONY : ui_transmitter.cpp.i + +ui_transmitter.s: ui_transmitter.cpp.s + +.PHONY : ui_transmitter.s + +# target to generate assembly for a file +ui_transmitter.cpp.s: + cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_transmitter.cpp.s +.PHONY : ui_transmitter.cpp.s + ui_whipcalc.obj: ui_whipcalc.cpp.obj .PHONY : ui_whipcalc.obj @@ -5793,6 +5847,9 @@ help: @echo "... ui_rssi.obj" @echo "... ui_rssi.i" @echo "... ui_rssi.s" + @echo "... ui_script.obj" + @echo "... ui_script.i" + @echo "... ui_script.s" @echo "... ui_sd_card_status_view.obj" @echo "... ui_sd_card_status_view.i" @echo "... ui_sd_card_status_view.s" @@ -5814,6 +5871,9 @@ help: @echo "... ui_touch_calibration.obj" @echo "... ui_touch_calibration.i" @echo "... ui_touch_calibration.s" + @echo "... ui_transmitter.obj" + @echo "... ui_transmitter.i" + @echo "... ui_transmitter.s" @echo "... ui_whipcalc.obj" @echo "... ui_whipcalc.i" @echo "... ui_whipcalc.s" diff --git a/firmware/application/baseband_api.cpp b/firmware/application/baseband_api.cpp index ea819bfb..a1f7149c 100644 --- a/firmware/application/baseband_api.cpp +++ b/firmware/application/baseband_api.cpp @@ -79,7 +79,7 @@ void WFMConfig::apply() const { audio::set_rate(audio::Rate::Hz_48000); } -void set_tones_data(const uint64_t bw, const uint32_t pre_silence, const uint16_t tone_count, +void set_tones_data(const uint32_t bw, const uint32_t pre_silence, const uint16_t tone_count, const bool dual_tone, const bool audio_out) { const TonesConfigureMessage message { (uint32_t)(262144 * bw) / 1536000, diff --git a/firmware/application/baseband_api.hpp b/firmware/application/baseband_api.hpp index 145e7e76..e95add7c 100644 --- a/firmware/application/baseband_api.hpp +++ b/firmware/application/baseband_api.hpp @@ -54,7 +54,7 @@ struct WFMConfig { void apply() const; }; -void set_tones_data(const uint64_t bw, const uint32_t pre_silence, const uint16_t tone_count, +void set_tones_data(const uint32_t bw, const uint32_t pre_silence, const uint16_t tone_count, const bool dual_tone, const bool audio_out); void set_audiotx_data(const uint32_t divider, const uint32_t bw, const bool ctcss_enabled, const uint32_t ctcss_phase_inc); void set_fifo_data(const int8_t * data); diff --git a/firmware/application/bht.hpp b/firmware/application/bht.hpp index 17849b37..561590a0 100644 --- a/firmware/application/bht.hpp +++ b/firmware/application/bht.hpp @@ -24,14 +24,14 @@ #include "ui_widget.hpp" #include "ui_navigation.hpp" +#include "tonesets.hpp" #include "encoders.hpp" #include "portapack.hpp" using namespace encoders; -#define CCIR_TONE_LENGTH (153600-1) // 1536000*0.1 -#define CCIR_DELTA_COEF (43.691) // (65536*1024)/1536000 -#define CCIR_SILENCE (614400-1) // 400ms +#define XY_TONE_LENGTH ((TONES_SAMPLERATE * 0.1) - 1) // 100ms +#define XY_SILENCE (TONES_SAMPLERATE * 0.4) // 400ms struct bht_city { std::string name; @@ -39,25 +39,6 @@ struct bht_city { bool recent; }; -const uint32_t ccir_deltas[16] = { - (uint32_t)(1981 * CCIR_DELTA_COEF), - (uint32_t)(1124 * CCIR_DELTA_COEF), - (uint32_t)(1197 * CCIR_DELTA_COEF), - (uint32_t)(1275 * CCIR_DELTA_COEF), - (uint32_t)(1358 * CCIR_DELTA_COEF), - (uint32_t)(1446 * CCIR_DELTA_COEF), - (uint32_t)(1540 * CCIR_DELTA_COEF), - (uint32_t)(1640 * CCIR_DELTA_COEF), - (uint32_t)(1747 * CCIR_DELTA_COEF), - (uint32_t)(1860 * CCIR_DELTA_COEF), - (uint32_t)(2400 * CCIR_DELTA_COEF), - (uint32_t)(930 * CCIR_DELTA_COEF), - (uint32_t)(2247 * CCIR_DELTA_COEF), - (uint32_t)(991 * CCIR_DELTA_COEF), - (uint32_t)(2110 * CCIR_DELTA_COEF), - (uint32_t)(1055 * CCIR_DELTA_COEF) -}; - const rf::Frequency bht_freqs[7] = { 31325000, 31387500, 31437500, 31475000, 31687500, 31975000, 88000000 }; std::string gen_message_ep(uint8_t city_code, size_t family_code_ep, uint32_t relay_state_A, uint32_t relay_state_B); diff --git a/firmware/application/freqman.cpp b/firmware/application/freqman.cpp index c23cd065..fceb560f 100644 --- a/firmware/application/freqman.cpp +++ b/firmware/application/freqman.cpp @@ -104,7 +104,7 @@ std::string freqman_item_string(freqman_entry &entry) { to_string_dec_int((value / 100) % 10000, 4, '0'); if (entry.description.size() <= 19) { - item_string = entry.frequency_str + ":" + entry.description; + item_string = entry.frequency_str + "M: " + entry.description; } else { memcpy(temp_buffer, entry.description.c_str(), 16); temp_buffer[16] = (char)0; diff --git a/firmware/application/freqman.hpp b/firmware/application/freqman.hpp index f8cb4b64..2b218635 100644 --- a/firmware/application/freqman.hpp +++ b/firmware/application/freqman.hpp @@ -34,7 +34,8 @@ using namespace ui; enum freqman_error { NO_ERROR = 0, ERROR_ACCESS, - ERROR_EMPTY + ERROR_EMPTY, + ERROR_DUPLICATE }; struct freqman_entry { diff --git a/firmware/application/main.cpp b/firmware/application/main.cpp index bc7832e0..9f55f77f 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" +//BUG: Set description in frequency save makes everything go crazy //BUG: Distorted audio in WFM receiver //BUG: (fixed ?) Bad console scroll init //BUG: POCSAG misses alphanum messages, cuts them off sometimes @@ -33,8 +34,7 @@ //TEST: Numbers //TEST: Jammer -//TODO: Frequency manager auto-remove duplicates -//TODO: "TX box" view or composite widget with frequency and bw settings, simple and advanced setup TX buttons... +//TODO: Script engine ? //TODO: Morse coder for foxhunts //TODO: Finish EPAR tx //TODO: IQ replay diff --git a/firmware/application/pocsag_app.hpp b/firmware/application/pocsag_app.hpp index ad8e2901..c1a7dc2e 100644 --- a/firmware/application/pocsag_app.hpp +++ b/firmware/application/pocsag_app.hpp @@ -68,7 +68,7 @@ private: static constexpr uint32_t sampling_rate = 1536000; static constexpr uint32_t baseband_bandwidth = 1750000; - bool logging { true }; + bool logging { false }; uint32_t batch_cnt = 0; uint32_t address { 0 }; uint32_t function { 0 }; diff --git a/firmware/application/tonesets.hpp b/firmware/application/tonesets.hpp new file mode 100644 index 00000000..9a674345 --- /dev/null +++ b/firmware/application/tonesets.hpp @@ -0,0 +1,119 @@ +/* + * 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 __TONESETS_H__ +#define __TONESETS_H__ + +#include "portapack.hpp" + +#define TONES_SAMPLERATE 1536000 +#define TONES_DELTA_COEF ((1ULL << 32) / 1536000) + +#define TONES_F2D(f) (uint32_t)(f * TONES_DELTA_COEF) + +#define DTMF_C0 TONES_F2D(1209) +#define DTMF_C1 TONES_F2D(1336) +#define DTMF_C2 TONES_F2D(1477) +#define DTMF_C3 TONES_F2D(1633) +#define DTMF_R0 TONES_F2D(697) +#define DTMF_R1 TONES_F2D(770) +#define DTMF_R2 TONES_F2D(852) +#define DTMF_R3 TONES_F2D(941) + +const uint32_t ccir_deltas[16] = { + TONES_F2D(1981), + TONES_F2D(1124), + TONES_F2D(1197), + TONES_F2D(1275), + TONES_F2D(1358), + TONES_F2D(1446), + TONES_F2D(1540), + TONES_F2D(1640), + TONES_F2D(1747), + TONES_F2D(1860), + TONES_F2D(2400), + TONES_F2D(930), + TONES_F2D(2247), + TONES_F2D(991), + TONES_F2D(2110), + TONES_F2D(1055) +}; + +// 0123456789ABCD#* +const uint32_t dtmf_deltas[16][2] = { + { DTMF_C1, DTMF_R3 }, + { DTMF_C0, DTMF_R0 }, + { DTMF_C1, DTMF_R0 }, + { DTMF_C2, DTMF_R0 }, + { DTMF_C0, DTMF_R1 }, + { DTMF_C1, DTMF_R1 }, + { DTMF_C2, DTMF_R1 }, + { DTMF_C0, DTMF_R2 }, + { DTMF_C1, DTMF_R2 }, + { DTMF_C2, DTMF_R2 }, + { DTMF_C3, DTMF_R0 }, + { DTMF_C3, DTMF_R1 }, + { DTMF_C3, DTMF_R2 }, + { DTMF_C3, DTMF_R3 }, + { DTMF_C2, DTMF_R3 }, + { DTMF_C0, DTMF_R3 } +}; + +const uint32_t eia_deltas[16] = { + TONES_F2D(600), + TONES_F2D(741), + TONES_F2D(882), + TONES_F2D(1023), + TONES_F2D(1164), + TONES_F2D(1305), + TONES_F2D(1446), + TONES_F2D(1587), + TONES_F2D(1728), + TONES_F2D(1869), + TONES_F2D(2151), + TONES_F2D(2433), + TONES_F2D(2010), + TONES_F2D(2292), + TONES_F2D(459), + TONES_F2D(1091) +}; + +const uint32_t zvei_deltas[16] = { + TONES_F2D(2400), + TONES_F2D(1060), + TONES_F2D(1160), + TONES_F2D(1270), + TONES_F2D(1400), + TONES_F2D(1530), + TONES_F2D(1670), + TONES_F2D(1830), + TONES_F2D(2000), + TONES_F2D(2200), + TONES_F2D(2800), + TONES_F2D(810), + TONES_F2D(970), + TONES_F2D(885), + TONES_F2D(2600), + TONES_F2D(680) +}; + +#endif/*__TONESETS_H__*/ diff --git a/firmware/application/transmitter_model.cpp b/firmware/application/transmitter_model.cpp index b0fdf032..8fd0d022 100644 --- a/firmware/application/transmitter_model.cpp +++ b/firmware/application/transmitter_model.cpp @@ -79,6 +79,14 @@ void TransmitterModel::set_vga(int32_t v_db) { update_vga(); } +uint32_t TransmitterModel::bandwidth() const { + return bandwidth_; +} + +void TransmitterModel::set_bandwidth(uint32_t v) { + bandwidth_ = v; +} + uint32_t TransmitterModel::sampling_rate() const { return sampling_rate_; } @@ -88,6 +96,10 @@ void TransmitterModel::set_sampling_rate(uint32_t v) { update_sampling_rate(); } +int32_t TransmitterModel::tx_gain() const { + return tx_gain_db_; +} + void TransmitterModel::set_tx_gain(int32_t v_db) { tx_gain_db_ = v_db; update_tx_gain(); diff --git a/firmware/application/transmitter_model.hpp b/firmware/application/transmitter_model.hpp index add8584f..669c254f 100644 --- a/firmware/application/transmitter_model.hpp +++ b/firmware/application/transmitter_model.hpp @@ -52,6 +52,9 @@ public: int32_t tx_gain() const; void set_tx_gain(int32_t v_db); + + uint32_t bandwidth() const; + void set_bandwidth(uint32_t v); uint32_t sampling_rate() const; void set_sampling_rate(uint32_t v); @@ -63,6 +66,7 @@ private: bool enabled_ { false }; bool rf_amp_ { true }; int32_t lna_gain_db_ { 0 }; + uint32_t bandwidth_ { 1 }; uint32_t baseband_bandwidth_ { max2837::filter::bandwidth_minimum }; int32_t vga_gain_db_ { 8 }; int32_t tx_gain_db_ { 47 }; diff --git a/firmware/application/ui_bht_tx.cpp b/firmware/application/ui_bht_tx.cpp index 34e6534c..cfdf91a9 100644 --- a/firmware/application/ui_bht_tx.cpp +++ b/firmware/application/ui_bht_tx.cpp @@ -63,7 +63,7 @@ void BHTView::start_tx() { generate_message(); - transmitter_model.set_tuning_frequency(bht_freqs[options_freq.selected_index()]); + //transmitter_model.set_tuning_frequency(bht_freqs[options_freq.selected_index()]); transmitter_model.set_sampling_rate(1536000); transmitter_model.set_rf_amp(true); transmitter_model.set_lna(40); @@ -74,11 +74,11 @@ void BHTView::start_tx() { // Setup for Xy for (uint8_t c = 0; c < 16; c++) { shared_memory.bb_data.tones_data.tone_defs[c].delta = ccir_deltas[c]; - shared_memory.bb_data.tones_data.tone_defs[c].duration = CCIR_TONE_LENGTH; + shared_memory.bb_data.tones_data.tone_defs[c].duration = XY_TONE_LENGTH; } audio::set_rate(audio::Rate::Hz_24000); - baseband::set_tones_data(field_bw.value(), CCIR_SILENCE, 20, false, checkbox_speaker.value()); + baseband::set_tones_data(transmitter_model.bandwidth(), XY_SILENCE, 20, false, checkbox_speaker.value()); } void BHTView::on_tx_progress(const int progress, const bool done) { @@ -94,8 +94,7 @@ void BHTView::on_tx_progress(const int progress, const bool done) { if (!checkbox_cligno.value()) { tx_mode = IDLE; - button_transmit.set_style(&style_val); - button_transmit.set_text("START"); + tx_view.set_transmitting(false); } else { chThdSleepMilliseconds(tempo_cligno.value() * 1000); // Dirty :( @@ -115,12 +114,11 @@ void BHTView::on_tx_progress(const int progress, const bool done) { } BHTView::BHTView(NavigationView& nav) { - (void)nav; size_t n; baseband::run_image(portapack::spi_flash::image_tag_tones); //baseband::run_image(portapack::spi_flash::image_tag_encoders); - + add_children({ &options_mode, &text_header, @@ -138,16 +136,17 @@ BHTView::BHTView(NavigationView& nav) { &text_receiver, &receiver_code, &checkbox_wcid, - &text_freq, - &options_freq, - &field_bw, + //&text_freq, + //&options_freq, + //&field_bw, &text_relais, &progressbar, &text_message, - &button_transmit, + //&button_transmit, &checkbox_cligno, &tempo_cligno, - &text_cligno + &text_cligno, + &tx_view }); options_mode.set_selected_index(0); // Start up in Xy mode @@ -159,12 +158,12 @@ BHTView::BHTView(NavigationView& nav) { family_code_ep.set_selected_index(2); subfamily_code.set_value(1); receiver_code.set_value(1); - options_freq.set_selected_index(0); + //options_freq.set_selected_index(0); tempo_cligno.set_value(1); progressbar.set_max(20); relay_states[0].set_selected_index(1); // R1 OFF - field_bw.set_value(10); + //field_bw.set_value(20); options_mode.on_change = [this](size_t mode, OptionsField::value_t) { _mode = mode; @@ -281,8 +280,8 @@ BHTView::BHTView(NavigationView& nav) { for (auto& relay_state : relay_states) { relay_state.on_change = relay_state_fn; relay_state.set_parent_rect({ - static_cast(26 + (n * 53)), - 174, + static_cast(4 + (n * 36)), + 158, 24, 24 }); relay_state.set_options(relay_options); @@ -290,22 +289,33 @@ BHTView::BHTView(NavigationView& nav) { n++; } - button_transmit.set_style(&style_val); + //button_transmit.set_style(&style_val); generate_message(); - - button_transmit.on_select = [this, &nav](Button&) { + + tx_view.on_edit_frequency = [this, &nav]() { + auto new_view = nav.push(receiver_model.tuning_frequency()); + new_view->on_changed = [this](rf::Frequency f) { + receiver_model.set_tuning_frequency(f); + }; + }; + + tx_view.on_start = [this]() { if ((tx_mode == IDLE) && (!_mode)) { // DEBUG if (speaker_enabled) chThdSleepMilliseconds(40 * 1000); // DEBUG 40s //if (speaker_enabled && _mode) // audio::headphone::set_volume(volume_t::decibel(90 - 99) + audio::headphone::volume_range().max); tx_mode = SINGLE; - button_transmit.set_style(&style_cancel); - button_transmit.set_text("Wait"); + tx_view.set_transmitting(true); start_tx(); } }; + + tx_view.on_stop = [this]() { + tx_view.set_transmitting(false); + tx_mode = IDLE; + }; } } /* namespace ui */ diff --git a/firmware/application/ui_bht_tx.hpp b/firmware/application/ui_bht_tx.hpp index 19211750..8bee501c 100644 --- a/firmware/application/ui_bht_tx.hpp +++ b/firmware/application/ui_bht_tx.hpp @@ -23,6 +23,7 @@ #include "ui.hpp" #include "ui_widget.hpp" #include "ui_navigation.hpp" +#include "ui_transmitter.hpp" #include "ui_font_fixed_8x16.hpp" #include "bmp_bulb_on.hpp" @@ -196,7 +197,7 @@ private: "Tous" }; - Text text_freq { + /*Text text_freq { { 1 * 8, 8 * 16, 10 * 8, 16 }, "Frequence:" }; @@ -220,14 +221,14 @@ private: { 0, 99 }, 1, ' ' - }; + };*/ Text text_relais { - { 8, 19 * 8, 13 * 8, 16 }, - "Etats relais:" + { 1 * 8, 8 * 16 + 8, 7 * 8, 16 }, + "Relais:" }; - std::array relay_states; + std::array relay_states { }; ImageOptionsField::options_t relay_options = { { &bulb_ignore_bmp[0], 0 }, @@ -236,35 +237,41 @@ private: }; ProgressBar progressbar { - { 5 * 8, 27 * 8, 20 * 8, 16 }, + { 5 * 8, 13 * 16, 20 * 8, 16 }, }; Text text_message { - { 5 * 8, 29 * 8, 20 * 8, 16 }, + { 5 * 8, 14 * 16, 20 * 8, 16 }, "" }; - Button button_transmit { + /*Button button_transmit { { 2 * 8, 16 * 16, 12 * 8, 32 }, "START" - }; + };*/ Checkbox checkbox_cligno { - { 16 * 8, 16 * 16 + 4}, + { 18 * 8 + 4, 10 * 16}, 3, "J/N" }; NumberField tempo_cligno { - { 24 * 8, 16 * 16 + 8}, + { 25 * 8 + 4, 10 * 16 + 4}, 2, { 1, 99 }, 1, ' ' }; Text text_cligno { - { 26 * 8, 16 * 16 + 8, 2 * 8, 16 }, + { 27 * 8 + 4, 10 * 16 + 4, 2 * 8, 16 }, "s." }; + TransmitterView tx_view { + 16 * 16, + 10000, + 12 + }; + MessageHandlerRegistration message_handler_tx_done { Message::ID::TXDone, [this](const Message* const p) { diff --git a/firmware/application/ui_freqman.cpp b/firmware/application/ui_freqman.cpp index ea622c1f..31e4c5c4 100644 --- a/firmware/application/ui_freqman.cpp +++ b/firmware/application/ui_freqman.cpp @@ -43,10 +43,13 @@ void FrequencySaveView::on_save_timestamp(NavigationView& nav) { } void FrequencySaveView::focus() { - if (error == ERROR_ACCESS) + if (error == ERROR_ACCESS) { nav_.display_modal("Error", "File acces error", ABORT, nullptr); - else + } else { + if (error == ERROR_DUPLICATE) + nav_.display_modal("Error", "Frequency already saved", INFO, nullptr); button_save_timestamp.focus(); + } } void FrequencySaveView::on_tick_second() { @@ -68,6 +71,7 @@ FrequencySaveView::FrequencySaveView( value_ (value) { File freqs_file; + size_t n; if (!load_freqman_file(frequencies)) { if (!create_freqman_file(freqs_file)) { @@ -76,6 +80,13 @@ FrequencySaveView::FrequencySaveView( } } + for (n = 0; n < frequencies.size(); n++) { + if (frequencies[n].value == value_) { + error = ERROR_DUPLICATE; + break; + } + } + signal_token_tick_second = rtc_time::signal_tick_second += [this]() { this->on_tick_second(); }; @@ -223,6 +234,7 @@ FreqManView::FreqManView( add_children({ &menu_view, + &text_edit, &button_edit_freq, &button_edit_desc, &button_del, diff --git a/firmware/application/ui_freqman.hpp b/firmware/application/ui_freqman.hpp index e1d5c0f8..1f47ead3 100644 --- a/firmware/application/ui_freqman.hpp +++ b/firmware/application/ui_freqman.hpp @@ -136,21 +136,25 @@ private: MenuView menu_view { true }; + Text text_edit { + { 16, 194, 5 * 8, 16 }, + "Edit:" + }; Button button_edit_freq { - { 52, 194, 106, 30 }, - "Edit freq." + { 16, 194 + 16, 104, 32 }, + "Frequency" }; Button button_edit_desc { - { 52, 192 + 32, 106, 30 }, - "Edit desc." + { 16, 194 + 16 + 34, 104, 32 }, + "Description" }; Button button_del { - { 168, 192, 64, 64 }, - "Del" + { 160, 192, 72, 64 }, + "Delete" }; Button button_exit { - { 168, 264, 64, 32 }, + { 160, 264, 72, 32 }, "Exit" }; }; diff --git a/firmware/application/ui_menu.cpp b/firmware/application/ui_menu.cpp index 7713c8cb..e2c14ac0 100644 --- a/firmware/application/ui_menu.cpp +++ b/firmware/application/ui_menu.cpp @@ -44,6 +44,8 @@ void MenuItemView::unhighlight() { } void MenuItemView::paint(Painter& painter) { + Coord offset_x; + const auto r = screen_rect(); const auto paint_style = (highlighted() && (parent()->has_focus() || keep_highlight_)) ? style().invert() : style(); @@ -67,7 +69,9 @@ void MenuItemView::paint(Painter& painter) { final_item_color, final_bg_color ); - } + offset_x = 26; + } else + offset_x = 8; Style text_style { .font = paint_style.font, @@ -76,7 +80,7 @@ void MenuItemView::paint(Painter& painter) { }; painter.draw_string( - { r.location().x() + 26, r.location().y() + (r.size().height() - font_height) / 2 }, + { r.location().x() + offset_x, r.location().y() + (r.size().height() - font_height) / 2 }, text_style, item.text ); diff --git a/firmware/application/ui_menu.hpp b/firmware/application/ui_menu.hpp index 10e77176..e138c3c4 100644 --- a/firmware/application/ui_menu.hpp +++ b/firmware/application/ui_menu.hpp @@ -69,7 +69,7 @@ private: class MenuView : public View { public: - std::function on_left; + std::function on_left { }; MenuView(bool keep_highlight = false); @@ -102,9 +102,9 @@ private: void update_items(); void on_tick_second(); - bool keep_highlight_ = false; + bool keep_highlight_ { false }; - SignalToken signal_token_tick_second; + SignalToken signal_token_tick_second { }; Image arrow_more { { 228, 320 - 8, 8, 8 }, diff --git a/firmware/application/ui_navigation.hpp b/firmware/application/ui_navigation.hpp index cc3a8ca9..28bfecbf 100644 --- a/firmware/application/ui_navigation.hpp +++ b/firmware/application/ui_navigation.hpp @@ -71,7 +71,7 @@ private: }; ImageButton button_back { - { 0 * 8, 0 * 16, 16, 16 }, + { 2, 0 * 16, 16, 16 }, &bitmap_previous, Color::white(), Color::dark_grey() diff --git a/firmware/application/ui_nuoptix.cpp b/firmware/application/ui_nuoptix.cpp index e4d452f7..eecaa6a4 100644 --- a/firmware/application/ui_nuoptix.cpp +++ b/firmware/application/ui_nuoptix.cpp @@ -37,7 +37,7 @@ using namespace portapack; namespace ui { void NuoptixView::focus() { - button_tx.focus(); + number_timecode.focus(); } NuoptixView::~NuoptixView() { @@ -45,10 +45,6 @@ NuoptixView::~NuoptixView() { baseband::shutdown(); } -void NuoptixView::on_tuning_frequency_changed(rf::Frequency f) { - transmitter_model.set_tuning_frequency(f); -} - void NuoptixView::transmit(bool setup) { uint8_t mod, tone_code; uint8_t c; @@ -137,7 +133,7 @@ void NuoptixView::transmit(bool setup) { shared_memory.bb_data.tones_data.silence = NUOPTIX_TONE_LENGTH; // 49ms tone, 49ms space audio::set_rate(audio::Rate::Hz_24000); - baseband::set_tones_data(number_bw.value(), 0, 6 * 2, true, true); + baseband::set_tones_data(transmitter_model.bandwidth(), 0, 6 * 2, true, true); timecode++; } @@ -147,49 +143,37 @@ NuoptixView::NuoptixView( ) { baseband::run_image(portapack::spi_flash::image_tag_tones); - + add_children({ - &field_frequency, - &number_bw, - &text_kHz, + &tx_view, &number_timecode, &text_timecode, &text_mod, &pbar, - &button_tx, - &button_impro, &button_exit }); - number_bw.set_value(15); number_timecode.set_value(1); - field_frequency.set_value(transmitter_model.tuning_frequency()); - field_frequency.set_step(10000); - 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(transmitter_model.tuning_frequency()); + tx_view.on_edit_frequency = [this, &nav]() { + auto new_view = nav.push(receiver_model.tuning_frequency()); new_view->on_changed = [this](rf::Frequency f) { - this->on_tuning_frequency_changed(f); - this->field_frequency.set_value(f); + receiver_model.set_tuning_frequency(f); }; }; - button_tx.on_select = [this](Button&){ - if (tx_mode == NORMAL) { - tx_mode = IDLE; - button_tx.set_text("TX"); - } else if (tx_mode == IDLE) { - tx_mode = NORMAL; - button_tx.set_text("STOP"); - transmit(true); - } + tx_view.on_start = [this]() { + tx_view.set_transmitting(true); + tx_mode = NORMAL; + transmit(true); }; - button_impro.on_select = [this](Button&){ + tx_view.on_stop = [this]() { + tx_view.set_transmitting(false); + tx_mode = IDLE; + }; + + /*button_impro.on_select = [this](Button&){ if (tx_mode == IMPROVISE) { tx_mode = IDLE; button_impro.set_text("IMPROVISE"); @@ -198,7 +182,7 @@ NuoptixView::NuoptixView( button_impro.set_text("STOP"); transmit(true); } - }; + };*/ button_exit.on_select = [&nav](Button&){ nav.pop(); diff --git a/firmware/application/ui_nuoptix.hpp b/firmware/application/ui_nuoptix.hpp index 8e6fd962..61865948 100644 --- a/firmware/application/ui_nuoptix.hpp +++ b/firmware/application/ui_nuoptix.hpp @@ -28,23 +28,14 @@ #include "ui_font_fixed_8x16.hpp" #include "baseband_api.hpp" #include "ui_navigation.hpp" -#include "ui_receiver.hpp" +#include "ui_transmitter.hpp" #include "rtc_time.hpp" +#include "tonesets.hpp" #include "message.hpp" #include "volume.hpp" #include "audio.hpp" -#define DTMF_DELTA_COEF (43.691) // (65536*1024)/1536000 -#define DTMF_C0 (uint32_t)(1209 * DTMF_DELTA_COEF) -#define DTMF_C1 (uint32_t)(1336 * DTMF_DELTA_COEF) -#define DTMF_C2 (uint32_t)(1477 * DTMF_DELTA_COEF) -#define DTMF_C3 (uint32_t)(1633 * DTMF_DELTA_COEF) -#define DTMF_R0 (uint32_t)(697 * DTMF_DELTA_COEF) -#define DTMF_R1 (uint32_t)(770 * DTMF_DELTA_COEF) -#define DTMF_R2 (uint32_t)(852 * DTMF_DELTA_COEF) -#define DTMF_R3 (uint32_t)(941 * DTMF_DELTA_COEF) - -#define NUOPTIX_TONE_LENGTH 75264 // 1536000*0.049s +#define NUOPTIX_TONE_LENGTH ((TONES_SAMPLERATE * 0.049) - 1) // 49ms namespace ui { @@ -64,48 +55,17 @@ private: IMPROVISE }; - tx_modes tx_mode = IDLE; - - // 0123456789ABCD#* - const uint32_t dtmf_deltas[16][2] = { - { DTMF_C1, DTMF_R3 }, - { DTMF_C0, DTMF_R0 }, - { DTMF_C1, DTMF_R0 }, - { DTMF_C2, DTMF_R0 }, - { DTMF_C0, DTMF_R1 }, - { DTMF_C1, DTMF_R1 }, - { DTMF_C2, DTMF_R1 }, - { DTMF_C0, DTMF_R2 }, - { DTMF_C1, DTMF_R2 }, - { DTMF_C2, DTMF_R2 }, - { DTMF_C3, DTMF_R0 }, - { DTMF_C3, DTMF_R1 }, - { DTMF_C3, DTMF_R2 }, - { DTMF_C3, DTMF_R3 }, - { DTMF_C2, DTMF_R3 }, - { DTMF_C0, DTMF_R3 } - }; + tx_modes tx_mode { IDLE }; void on_tuning_frequency_changed(rf::Frequency f); void transmit(bool setup); uint32_t timecode { 0 }; - FrequencyField field_frequency { - { 1 * 8, 4 }, - }; - - NumberField number_bw { - { 13 * 8, 4 }, - 2, - {1, 99}, - 1, - ' ' - }; - - Text text_kHz { - { 15 * 8, 4, 3 * 8, 16 }, - "kHz" + TransmitterView tx_view { + 11 * 16, + 10000, + 15 }; Text text_timecode { @@ -130,15 +90,10 @@ private: { 16, 236, 208, 16 } }; - Button button_tx { - { 64, 128, 112, 40 }, - "TX" - }; - - Button button_impro { + /*Button button_impro { { 64, 184, 112, 40 }, "IMPROVISE" - }; + };*/ Button button_exit { { 88, 270, 64, 32 }, diff --git a/firmware/application/ui_receiver.cpp b/firmware/application/ui_receiver.cpp index 1142eeed..d41c0b4d 100644 --- a/firmware/application/ui_receiver.cpp +++ b/firmware/application/ui_receiver.cpp @@ -370,29 +370,4 @@ void VGAGainField::on_focus() { } } -/* TXGainField **********************************************************/ - -TXGainField::TXGainField( - Point parent_pos -) : NumberField { - parent_pos, 2, - { max2837::tx::gain_db_range.minimum, max2837::tx::gain_db_range.maximum }, - max2837::tx::gain_db_step, - ' ', - } -{ - set_value(receiver_model.tx_gain()); - - on_change = [](int32_t v) { - receiver_model.set_tx_gain(v); - }; -} - -void TXGainField::on_focus() { - //Widget::on_focus(); - if( on_show_options ) { - on_show_options(); - } -} - } /* namespace ui */ diff --git a/firmware/application/ui_receiver.hpp b/firmware/application/ui_receiver.hpp index af70e018..65523b59 100644 --- a/firmware/application/ui_receiver.hpp +++ b/firmware/application/ui_receiver.hpp @@ -338,15 +338,6 @@ public: void on_focus() override; }; -class TXGainField : public NumberField { -public: - std::function on_show_options { }; - - TXGainField(Point parent_pos); - - void on_focus() override; -}; - } /* namespace ui */ #endif/*__UI_RECEIVER_H__*/ diff --git a/firmware/application/ui_script.cpp b/firmware/application/ui_script.cpp new file mode 100644 index 00000000..bfd68a30 --- /dev/null +++ b/firmware/application/ui_script.cpp @@ -0,0 +1,110 @@ +/* + * 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_script.hpp" + +#include "portapack.hpp" +#include "event_m0.hpp" + +#include + +using namespace portapack; + +namespace ui { + +void ScriptView::on_frequency_select() { + //button_edit_freq.focus(); +} + +void ScriptView::on_edit_freq(rf::Frequency f) { + //frequencies[menu_view.highlighted()].value = f; + setup_list(); +} + +void ScriptView::on_edit_desc(NavigationView& nav) { + +} + +void ScriptView::on_delete() { + //frequencies.erase(frequencies.begin() + menu_view.highlighted()); + setup_list(); +} + +void ScriptView::setup_list() { + size_t n; + + menu_view.clear(); + + /*for (n = 0; n < frequencies.size(); n++) { + menu_view.add_item({ freqman_item_string(frequencies[n]), ui::Color::white(), nullptr, [this](){ on_frequency_select(); } }); + }*/ + + menu_view.set_parent_rect({ 0, 0, 240, 168 }); + menu_view.set_highlighted(menu_view.highlighted()); // Refresh +} + +void ScriptView::focus() { + menu_view.focus(); +} + +ScriptView::ScriptView( + NavigationView& nav +) { + + add_children({ + &menu_view, + &text_edit, + &button_edit_freq, + &button_edit_desc, + &button_del, + &button_exit + }); + + setup_list(); + + button_edit_freq.on_select = [this, &nav](Button&) { + /*auto new_view = nav.push(frequencies[menu_view.highlighted()].value); + new_view->on_changed = [this](rf::Frequency f) { + on_edit_freq(f); + };*/ + }; + + button_edit_desc.on_select = [this, &nav](Button&) { + on_edit_desc(nav); + }; + + button_del.on_select = [this, &nav](Button&) { + nav.push("Confirm", "Are you sure ?", YESNO, + [this](bool choice) { + if (choice) { + on_delete(); + } + } + ); + }; + + button_exit.on_select = [this, &nav](Button&) { + nav.pop(); + }; +} + +} diff --git a/firmware/application/ui_script.hpp b/firmware/application/ui_script.hpp new file mode 100644 index 00000000..24ef7283 --- /dev/null +++ b/firmware/application/ui_script.hpp @@ -0,0 +1,91 @@ +/* + * 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_receiver.hpp" +#include "ui_textentry.hpp" +#include "rtc_time.hpp" + +namespace ui { + +enum script_keyword { + STOP = 0, + WAIT_N, + WAIT_RTC, + IF, + LOOP, + END, + TX, + RX +}; + +struct script_line { + script_keyword keyword; +}; + +class ScriptView : public View { +public: + ScriptView(NavigationView& nav); + + void focus() override; + + std::string title() const override { return "Script editor"; }; + +private: + void on_frequency_select(); + void on_edit_freq(rf::Frequency f); + void on_edit_desc(NavigationView& nav); + void on_delete(); + void setup_list(); + + std::vector script { }; + + MenuView menu_view { true }; + + Text text_edit { + { 16, 194, 5 * 8, 16 }, + "Edit:" + }; + Button button_edit_freq { + { 16, 194 + 16, 88, 32 }, + "Frequency" + }; + Button button_edit_desc { + { 16, 194 + 16 + 34, 88, 32 }, + "Description" + }; + Button button_del { + { 160, 192, 72, 64 }, + "Delete" + }; + + Button button_exit { + { 160, 264, 72, 32 }, + "Exit" + }; +}; + +} /* namespace ui */ diff --git a/firmware/application/ui_transmitter.cpp b/firmware/application/ui_transmitter.cpp new file mode 100644 index 00000000..5070902b --- /dev/null +++ b/firmware/application/ui_transmitter.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2014 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_transmitter.hpp" + +#include "portapack.hpp" +using namespace portapack; + +#include "string_format.hpp" + +#include "max2837.hpp" + +namespace ui { + +/* TXGainField **********************************************************/ + +TXGainField::TXGainField( + Point parent_pos +) : NumberField { + parent_pos, 2, + { max2837::tx::gain_db_range.minimum, max2837::tx::gain_db_range.maximum }, + max2837::tx::gain_db_step, + ' ', + } +{ + set_value(transmitter_model.tx_gain()); + + on_change = [](int32_t v) { + transmitter_model.set_tx_gain(v); + }; +} + +/* TransmitterView *******************************************************/ + +void TransmitterView::on_tuning_frequency_changed(rf::Frequency f) { + receiver_model.set_tuning_frequency(f); +} + +void TransmitterView::on_bandwidth_changed(uint32_t bandwidth) { + transmitter_model.set_bandwidth(bandwidth); +} + +void TransmitterView::set_transmitting(const bool transmitting) { + if (transmitting) { + button_start.set_text("STOP"); + button_start.set_style(&style_stop); + } else { + button_start.set_text("START"); + button_start.set_style(&style_start); + } + + transmitting_ = transmitting; +} + +void TransmitterView::on_show() { + field_frequency.set_value(receiver_model.tuning_frequency()); +} + +TransmitterView::TransmitterView( + const Coord y, const uint32_t frequency_step, const uint32_t bandwidth +) { + set_parent_rect({ 0 * 8, y, 30 * 8, 2 * 16 }); + + add_children({ + &field_frequency, + &field_gain, + &field_bw, + &text_kHz, + &button_start + }); + + set_transmitting(false); + + field_frequency.set_value(receiver_model.tuning_frequency()); + field_frequency.set_step(frequency_step); + field_frequency.on_change = [this](rf::Frequency f) { + this->on_tuning_frequency_changed(f); + }; + field_frequency.on_edit = [this]() { + if (on_edit_frequency) + on_edit_frequency(); + }; + + field_bw.on_change = [this](int32_t bandwidth) { + transmitter_model.set_bandwidth(bandwidth); + }; + field_bw.set_value(bandwidth); + + button_start.on_select = [this](Button&){ + if (transmitting_) { + if (on_stop) + on_stop(); + } else { + if (on_start) + on_start(); + } + }; +} + +TransmitterView::~TransmitterView() { + /*audio::output::stop(); + + transmitter_model.disable(); + + baseband::shutdown();*/ +} + +} /* namespace ui */ diff --git a/firmware/application/ui_transmitter.hpp b/firmware/application/ui_transmitter.hpp new file mode 100644 index 00000000..73e8ccc5 --- /dev/null +++ b/firmware/application/ui_transmitter.hpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2014 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 __UI_TRANSMITTER_H__ +#define __UI_TRANSMITTER_H__ + +#include "ui.hpp" +#include "ui_navigation.hpp" +#include "ui_painter.hpp" +#include "ui_widget.hpp" +#include "ui_receiver.hpp" +#include "ui_font_fixed_8x16.hpp" + +#include "rf_path.hpp" + +#include +#include +#include +#include + +namespace ui { + +class TXGainField : public NumberField { +public: + std::function on_show_options { }; + + TXGainField(Point parent_pos); +}; + +class TransmitterView : public View { +public: + std::function on_edit_frequency { }; + std::function on_start { }; + std::function on_stop { }; + + TransmitterView(const Coord y, const uint32_t frequency_step, const uint32_t bandwidth); + ~TransmitterView(); + + void on_show() override; + + void set_transmitting(const bool transmitting); + +private: + const Style style_start { + .font = font::fixed_8x16, + .background = Color::black(), + .foreground = Color::green(), + }; + const Style style_stop { + .font = font::fixed_8x16, + .background = Color::black(), + .foreground = Color::red(), + }; + + bool transmitting_ { false }; + + FrequencyField field_frequency { + { 0 * 8, 0 * 16 } + }; + + TXGainField field_gain { + { 11 * 8, 0 * 16 } + }; + + NumberField field_bw { + { 14 * 8, 0 * 16 }, + 2, + { 1, 99 }, + 1, + ' ' + }; + Text text_kHz { + { 16 * 8, 0 * 16, 3 * 8, 1 * 16 }, + "kHz" + }; + + Button button_start { + { 20 * 8, 0 * 16, 9 * 8, 32 }, + "START" + }; + + void on_tuning_frequency_changed(rf::Frequency f); + void on_bandwidth_changed(uint32_t bandwidth); +}; + +} /* namespace ui */ + +#endif/*__UI_TRANSMITTER_H__*/ diff --git a/firmware/baseband/proc_tones.cpp b/firmware/baseband/proc_tones.cpp index 59ade4be..003d1607 100644 --- a/firmware/baseband/proc_tones.cpp +++ b/firmware/baseband/proc_tones.cpp @@ -82,11 +82,11 @@ void TonesProcessor::execute(const buffer_c8_t& buffer) { tone_sample = 0; } else { if (!dual_tone) { - tone_sample = (sine_table_i8[(tone_a_phase & 0x03FC0000U) >> 18]); + tone_sample = (sine_table_i8[(tone_a_phase & 0xFF000000U) >> 24]); tone_a_phase += tone_a_delta; } else { - tone_sample = sine_table_i8[(tone_a_phase & 0x03FC0000U) >> 18] >> 1; - tone_sample += sine_table_i8[(tone_b_phase & 0x03FC0000U) >> 18] >> 1; + tone_sample = sine_table_i8[(tone_a_phase & 0xFF000000U) >> 24] >> 1; + tone_sample += sine_table_i8[(tone_b_phase & 0xFF000000U) >> 24] >> 1; tone_a_phase += tone_a_delta; tone_b_phase += tone_b_delta; diff --git a/firmware/portapack-h1-havoc.bin b/firmware/portapack-h1-havoc.bin index 75a770ac..a5024266 100644 Binary files a/firmware/portapack-h1-havoc.bin and b/firmware/portapack-h1-havoc.bin differ