diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index 87a16948..f754a6f4 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -161,6 +161,7 @@ set(CPPSRC ui_alphanum.cpp ui_spectrum.cpp ui_about.cpp + ui_nuoptix.cpp # ui_jammer.cpp ui_handwrite.cpp ui_afsksetup.cpp diff --git a/firmware/application/Makefile b/firmware/application/Makefile index e2d0e61b..7ad789f1 100644 --- a/firmware/application/Makefile +++ b/firmware/application/Makefile @@ -3894,6 +3894,30 @@ ui_navigation.cpp.s: cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_navigation.cpp.s .PHONY : ui_navigation.cpp.s +ui_nuoptix.obj: ui_nuoptix.cpp.obj +.PHONY : ui_nuoptix.obj + +# target to build an object file +ui_nuoptix.cpp.obj: + cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_nuoptix.cpp.obj +.PHONY : ui_nuoptix.cpp.obj + +ui_nuoptix.i: ui_nuoptix.cpp.i +.PHONY : ui_nuoptix.i + +# target to preprocess a source file +ui_nuoptix.cpp.i: + cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_nuoptix.cpp.i +.PHONY : ui_nuoptix.cpp.i + +ui_nuoptix.s: ui_nuoptix.cpp.s +.PHONY : ui_nuoptix.s + +# target to generate assembly for a file +ui_nuoptix.cpp.s: + cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_nuoptix.cpp.s +.PHONY : ui_nuoptix.cpp.s + ui_rds.obj: ui_rds.cpp.obj .PHONY : ui_rds.obj @@ -4663,6 +4687,9 @@ help: @echo "... ui_navigation.obj" @echo "... ui_navigation.i" @echo "... ui_navigation.s" + @echo "... ui_nuoptix.obj" + @echo "... ui_nuoptix.i" + @echo "... ui_nuoptix.s" @echo "... ui_rds.obj" @echo "... ui_rds.i" @echo "... ui_rds.s" diff --git a/firmware/application/baseband_api.cpp b/firmware/application/baseband_api.cpp index e30e1392..a117285e 100644 --- a/firmware/application/baseband_api.cpp +++ b/firmware/application/baseband_api.cpp @@ -141,6 +141,15 @@ void set_pocsag() { send_message(&message); } +void set_dtmf_data(const uint32_t bw, const uint32_t tone_length, const uint32_t pause_length) { + const DTMFTXConfigMessage message { + bw, + tone_length, + pause_length + }; + send_message(&message); +} + static bool baseband_image_running = false; void run_image(const portapack::spi_flash::image_tag_t image_tag) { diff --git a/firmware/application/baseband_api.hpp b/firmware/application/baseband_api.hpp index c4d959c7..d1c18502 100644 --- a/firmware/application/baseband_api.hpp +++ b/firmware/application/baseband_api.hpp @@ -61,6 +61,7 @@ void set_afsk_data(const uint32_t afsk_samples_per_bit, const uint32_t afsk_phas void set_ook_data(const uint32_t stream_length, const uint32_t samples_per_bit, const uint8_t repeat, const uint32_t pause_symbols); void set_pocsag(); +void set_dtmf_data(const uint32_t bw, const uint32_t tone_length, const uint32_t pause_length); void run_image(const portapack::spi_flash::image_tag_t image_tag); void shutdown(); diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index ce4b6977..b394fa05 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -37,6 +37,7 @@ //#include "ui_closecall.hpp" // DEBUG //#include "ui_freqman.hpp" // DEBUG +#include "ui_nuoptix.hpp" #include "ui_soundboard.hpp" #include "ui_encoders.hpp" @@ -241,7 +242,7 @@ ReceiverMenuView::ReceiverMenuView(NavigationView& nav) { /* SystemMenuView ********************************************************/ SystemMenuView::SystemMenuView(NavigationView& nav) { - add_items<12>({ { + add_items<13>({ { { "Play dead", ui::Color::red(), [&nav](){ nav.push(false); } }, { "Receiver RX", ui::Color::cyan(), [&nav](){ nav.push(); } }, { "Capture RX", ui::Color::cyan(), [&nav](){ nav.push(); } }, @@ -255,6 +256,7 @@ SystemMenuView::SystemMenuView(NavigationView& nav) { { "Xylos TX", ui::Color::green(), [&nav](){ nav.push(); } }, { "TEDI/LCR TX", ui::Color::yellow(), [&nav](){ nav.push(); } }, { "OOK encoders TX", ui::Color::orange(), [&nav](){ nav.push(); } }, + { "Nuoptix DTMF sync TX", ui::Color::purple(), [&nav](){ nav.push(); } }, { "RDS TX", ui::Color::red(), [&nav](){ nav.push(); } }, //{ "Analyze", ui::Color::white(), [&nav](){ nav.push(); } }, { "Setup", ui::Color::white(), [&nav](){ nav.push(); } }, diff --git a/firmware/application/ui_nuoptix.cpp b/firmware/application/ui_nuoptix.cpp new file mode 100644 index 00000000..e2aa27f4 --- /dev/null +++ b/firmware/application/ui_nuoptix.cpp @@ -0,0 +1,164 @@ +/* + * 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_nuoptix.hpp" + +#include "ch.h" + +//#include "lfsr_random.hpp" +#include "ui_alphanum.hpp" +#include "portapack.hpp" +#include "string_format.hpp" + +#include "portapack_shared_memory.hpp" + +#include +#include + +using namespace portapack; + +namespace ui { + +void NuoptixView::focus() { + number_timecode.focus(); +} + +void NuoptixView::on_tuning_frequency_changed(rf::Frequency f) { + transmitter_model.set_tuning_frequency(f); +} + +void NuoptixView::transmit(bool setup) { + uint8_t mod; + uint8_t c; + + if (!txing) { + transmitter_model.disable(); + return; + } + + if (setup) { + pbar.set_max(4); + + timecode = number_timecode.value(); + + transmitter_model.set_baseband_configuration({ + .mode = 0, + .sampling_rate = 1536000, + .decimation_factor = 1, + }); + transmitter_model.set_rf_amp(true); + transmitter_model.set_lna(40); + transmitter_model.set_vga(40); + transmitter_model.set_baseband_bandwidth(1750000); + transmitter_model.enable(); + + shared_memory.tx_data[0] = '*'; // "Pre-tone for restart" method #1 + shared_memory.tx_data[1] = 'A'; // "Restart" method #1 + } else { + shared_memory.tx_data[0] = '#'; + shared_memory.tx_data[1] = (timecode / 1000) % 10; + chThdSleepMilliseconds(92); // 141-49ms + number_timecode.set_value(timecode); + } + + pbar.set_value(0); + + //strcpy("#00028", shared_memory.tx_data); + shared_memory.tx_data[2] = (timecode / 100) % 10; + shared_memory.tx_data[3] = (timecode / 10) % 10; + shared_memory.tx_data[4] = timecode % 10; + + mod = 0; + for (c = 1; c < 5; c++) + if (shared_memory.tx_data[c] <= 9) + mod += shared_memory.tx_data[c]; + + mod = 10 - (mod % 10); + if (mod == 10) mod = 0; // Is this right ? + text_mod.set("Mod: " + to_string_dec_uint(mod)); + + shared_memory.tx_data[5] = mod; + + shared_memory.tx_data[6] = 0xFF; + + baseband::set_dtmf_data(number_bw.value(), 49, 49); // 49ms tone, 49ms space + + timecode++; +} + +NuoptixView::NuoptixView( + NavigationView& nav +) +{ + + baseband::run_image(portapack::spi_flash::image_tag_dtmf_tx); + + add_children({ { + &field_frequency, + &number_bw, + &text_kHz, + &number_timecode, + &text_timecode, + &text_mod, + &pbar, + &button_tx, + &button_exit + } }); + + //check_loop.set_value(false); + 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()); + new_view->on_changed = [this](rf::Frequency f) { + this->on_tuning_frequency_changed(f); + this->field_frequency.set_value(f); + }; + }; + + button_tx.on_select = [this](Button&){ + if (txing) { + txing = false; + } else { + txing = true; + transmit(true); + } + }; + + button_exit.on_select = [&nav](Button&){ + nav.pop(); + }; +} + +NuoptixView::~NuoptixView() { + transmitter_model.disable(); + baseband::shutdown(); +} + +} diff --git a/firmware/application/ui_nuoptix.hpp b/firmware/application/ui_nuoptix.hpp new file mode 100644 index 00000000..514daeea --- /dev/null +++ b/firmware/application/ui_nuoptix.hpp @@ -0,0 +1,128 @@ +/* + * 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 __UI_NUOPTIX_H__ +#define __UI_NUOPTIX_H__ + +#include "ui.hpp" +#include "ui_widget.hpp" +#include "ui_font_fixed_8x16.hpp" +#include "baseband_api.hpp" +#include "ui_navigation.hpp" +#include "ui_receiver.hpp" +#include "message.hpp" + +namespace ui { + +class NuoptixView : public View { +public: + NuoptixView(NavigationView& nav); + ~NuoptixView(); + + void focus() override; + + std::string title() const override { return "Nuoptix sync"; }; + +private: + /*enum tx_modes { + NORMAL = 0, + RANDOM + }; + + tx_modes tx_mode = NORMAL;*/ + + void on_tuning_frequency_changed(rf::Frequency f); + void transmit(bool setup); + + bool txing = false; + uint32_t timecode; + + FrequencyField field_frequency { + { 1 * 8, 4 }, + }; + + NumberField number_bw { + { 13 * 8, 4 }, + 3, + {1, 150}, + 1, + ' ' + }; + + Text text_kHz { + { 16 * 8, 4, 3 * 8, 16 }, + "kHz" + }; + + Text text_timecode { + { 10 * 8, 32, 9 * 8, 16 }, + "Timecode:" + }; + + NumberField number_timecode { + { 13 * 8, 48 }, + 4, + { 1, 9999 }, + 1, + '0' + }; + + Text text_mod { + { 10 * 8, 80, 6 * 8, 16 }, + "Mod: " + }; + + ProgressBar pbar { + { 16, 236, 208, 16 } + }; + + /*Checkbox check_loop { + { 16, 274 }, + 4, + "Loop" + };*/ + + Button button_tx { + { 32, 270, 64, 32 }, + "TX" + }; + + Button button_exit { + { 160, 270, 64, 32 }, + "Exit" + }; + + MessageHandlerRegistration message_handler_tx_done { + Message::ID::TXDone, + [this](const Message* const p) { + const auto message = *reinterpret_cast(p); + if (message.n == 64) + transmit(false); + else + pbar.set_value(message.n); + } + }; +}; + +} /* namespace ui */ + +#endif/*__UI_NUOPTIX_H__*/ diff --git a/firmware/application/ui_soundboard.cpp b/firmware/application/ui_soundboard.cpp index a0d32c57..e78e87a1 100644 --- a/firmware/application/ui_soundboard.cpp +++ b/firmware/application/ui_soundboard.cpp @@ -29,14 +29,9 @@ #include "lfsr_random.hpp" #include "ui_alphanum.hpp" -//#include "ff.h" -//#include "hackrf_gpio.hpp" #include "portapack.hpp" -//#include "radio.hpp" -//#include "event_m0.hpp" #include "string_format.hpp" -//#include "hackrf_hal.hpp" #include "portapack_shared_memory.hpp" #include @@ -206,43 +201,44 @@ SoundBoardView::SoundBoardView( auto error = file.open("/wav/" + file_name); - file.seek(40); - file.read(file_buffer, 4); - size = fb_to_uint32(file_buffer); - sounds[c].size = size; - - file.seek(22); - file.read(file_buffer, 2); - if (fb_to_uint16(file_buffer) > 1) { - sounds[c].stereo = true; - size /= 2; - } else - sounds[c].stereo = false; - - file.seek(24); - file.read(file_buffer, 4); - sounds[c].sample_rate = fb_to_uint32(file_buffer); - - file.seek(34); - file.read(file_buffer, 2); - if (fb_to_uint16(file_buffer) > 8) { - sounds[c].sixteenbit = true; - size /= 2; - } else - sounds[c].sixteenbit = false; - - sounds[c].ms_duration = (size * 1000) / sounds[c].sample_rate; - sounds[c].sample_duration = size; - - sounds[c].filename = file_name; - sounds[c].shortname = remove_filename_extension(file_name); - - c++; - if (c == 100) break; + if (!error.is_valid()) { + + file.seek(22); + file.read(file_buffer, 2); + + // Is file mono ? + if (fb_to_uint16(file_buffer) == 1) { + file.seek(40); + file.read(file_buffer, 4); + size = fb_to_uint32(file_buffer); + sounds[c].size = size; + + file.seek(24); + file.read(file_buffer, 4); + sounds[c].sample_rate = fb_to_uint32(file_buffer); + + file.seek(34); + file.read(file_buffer, 2); + if (fb_to_uint16(file_buffer) > 8) { + sounds[c].sixteenbit = true; + size /= 2; + } else + sounds[c].sixteenbit = false; + + sounds[c].ms_duration = (size * 1000) / sounds[c].sample_rate; + sounds[c].sample_duration = size; + + sounds[c].filename = file_name; + sounds[c].shortname = remove_filename_extension(file_name); + + c++; + if (c == 100) break; // Limit to 100 files + } + } } max_sound = c; - max_page = max_sound / 21; + max_page = max_sound / 21; // 21 buttons per page add_children({ { &field_frequency, diff --git a/firmware/application/ui_soundboard.hpp b/firmware/application/ui_soundboard.hpp index c4934c11..9f07c2f9 100644 --- a/firmware/application/ui_soundboard.hpp +++ b/firmware/application/ui_soundboard.hpp @@ -54,7 +54,6 @@ private: struct sound { std::string filename = ""; std::string shortname = ""; - bool stereo = false; bool sixteenbit = false; uint32_t sample_rate = 0; uint32_t size = 0; @@ -120,9 +119,9 @@ private: }; NumberField number_bw { - { 14 * 8, 4 }, - 2, - {1, 50}, + { 13 * 8, 4 }, + 3, + {1, 150}, 1, ' ' }; diff --git a/firmware/baseband/CMakeLists.txt b/firmware/baseband/CMakeLists.txt index 548a2831..4b7dc088 100644 --- a/firmware/baseband/CMakeLists.txt +++ b/firmware/baseband/CMakeLists.txt @@ -375,6 +375,13 @@ set(MODE_CPPSRC ) DeclareTargets(PXYL xylos) +### DTMF TX + +set(MODE_CPPSRC + proc_dtmf_tx.cpp +) +DeclareTargets(PDTX dtmf_tx) + ### RDS set(MODE_CPPSRC diff --git a/firmware/baseband/proc_dtmf_tx.cpp b/firmware/baseband/proc_dtmf_tx.cpp new file mode 100644 index 00000000..0bcb64e5 --- /dev/null +++ b/firmware/baseband/proc_dtmf_tx.cpp @@ -0,0 +1,136 @@ +/* + * 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_dtmf_tx.hpp" +#include "portapack_shared_memory.hpp" +#include "sine_table_int8.hpp" +//#include "audio_output.hpp" +#include "event_m4.hpp" + +#include + +// 153600 = 1000ms +// + +void DTMFTXProcessor::execute(const buffer_c8_t& buffer){ + + // This is called at 1536000/2048 = 750Hz + // DTMF samplerate = 153600Hz + + if (!configured) return; + + //ai = 0; + for (size_t i = 0; i> 18] >> 1; + sample += sine_table_i8[(tone_b_phase & 0x03FC0000) >> 18] >> 1; + + tone_a_phase += DTMF_LUT[tone_code][0]; + tone_b_phase += DTMF_LUT[tone_code][1]; + } else { + sample = 0; + } + } else { + as--; + } + + // FM + frq = sample * bw; + + phase = (phase + frq); + sphase = phase + (64 << 18); + + re = (sine_table_i8[(sphase & 0x03FC0000) >> 18]); + im = (sine_table_i8[(phase & 0x03FC0000) >> 18]); + + buffer.p[i] = {(int8_t)re, (int8_t)im}; + } + + //AudioOutput::fill_audio_buffer(preview_audio_buffer, true); +} + +void DTMFTXProcessor::on_message(const Message* const msg) { + const auto message = *reinterpret_cast(msg); + + if (message.id == Message::ID::DTMFTXConfig) { + // 1<<18 = 262144 + // m = (262144 * a) / 1536000 + // a = 262144 / 1536000 (*1000 = 171) + bw = 171 * (message.bw); + tone_length = message.tone_length; + pause_length = message.pause_length; + as = 0; + //memcpy(tone_list, shared_memory.tx_data, 32); + //tone_list[31] = 0; + tone = false; + timer = 0; + tone_idx = 0; + + configured = true; + } +} + +int main() { + EventDispatcher event_dispatcher { std::make_unique() }; + event_dispatcher.run(); + return 0; +} diff --git a/firmware/baseband/proc_dtmf_tx.hpp b/firmware/baseband/proc_dtmf_tx.hpp new file mode 100644 index 00000000..8389f205 --- /dev/null +++ b/firmware/baseband/proc_dtmf_tx.hpp @@ -0,0 +1,86 @@ +/* + * 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_DTMFTX_H__ +#define __PROC_DTMFTX_H__ + +#include "baseband_processor.hpp" +#include "baseband_thread.hpp" + +#define DTMF_PHASEINC (436.91) // (65536*1024)/1536000*10 + +class DTMFTXProcessor : public BasebandProcessor { +public: + void execute(const buffer_c8_t& buffer) override; + + void on_message(const Message* const msg) override; + +private: + bool configured = false; + + BasebandThread baseband_thread { 1536000, this, NORMALPRIO + 20, baseband::Direction::Transmit }; + + // 0123456789ABCD#* + const uint32_t DTMF_LUT[16][2] = { + { (uint32_t)(1336*DTMF_PHASEINC), (uint32_t)(941*DTMF_PHASEINC) }, + { (uint32_t)(1209*DTMF_PHASEINC), (uint32_t)(697*DTMF_PHASEINC) }, + { (uint32_t)(1336*DTMF_PHASEINC), (uint32_t)(697*DTMF_PHASEINC) }, + { (uint32_t)(1477*DTMF_PHASEINC), (uint32_t)(697*DTMF_PHASEINC) }, + { (uint32_t)(1209*DTMF_PHASEINC), (uint32_t)(770*DTMF_PHASEINC) }, + { (uint32_t)(1336*DTMF_PHASEINC), (uint32_t)(770*DTMF_PHASEINC) }, + { (uint32_t)(1477*DTMF_PHASEINC), (uint32_t)(770*DTMF_PHASEINC) }, + { (uint32_t)(1209*DTMF_PHASEINC), (uint32_t)(852*DTMF_PHASEINC) }, + { (uint32_t)(1336*DTMF_PHASEINC), (uint32_t)(852*DTMF_PHASEINC) }, + { (uint32_t)(1477*DTMF_PHASEINC), (uint32_t)(852*DTMF_PHASEINC) }, + { (uint32_t)(1633*DTMF_PHASEINC), (uint32_t)(697*DTMF_PHASEINC) }, + { (uint32_t)(1633*DTMF_PHASEINC), (uint32_t)(770*DTMF_PHASEINC) }, + { (uint32_t)(1633*DTMF_PHASEINC), (uint32_t)(852*DTMF_PHASEINC) }, + { (uint32_t)(1633*DTMF_PHASEINC), (uint32_t)(941*DTMF_PHASEINC) }, + { (uint32_t)(1477*DTMF_PHASEINC), (uint32_t)(941*DTMF_PHASEINC) }, + { (uint32_t)(1209*DTMF_PHASEINC), (uint32_t)(941*DTMF_PHASEINC) } + }; + + uint32_t tone_length, pause_length; + uint32_t as, bw; + uint8_t tone_list[32]; + uint8_t tone_idx = 0, tone_code = 0; + + uint32_t timer = 0; + + bool tone = false; + + int8_t re, im; + int8_t sample; + + //int16_t audio_data[64]; + /*const buffer_s16_t preview_audio_buffer { + audio_data, + sizeof(int16_t)*64 + };*/ + + TXDoneMessage txdone_message; + + uint32_t tone_a_phase, tone_b_phase, phase, sphase; + int32_t frq; +}; + +#endif diff --git a/firmware/common/message.hpp b/firmware/common/message.hpp index 0f0c438a..fc85fa82 100644 --- a/firmware/common/message.hpp +++ b/firmware/common/message.hpp @@ -75,6 +75,7 @@ public: RDSConfigure = 26, AudioTXConfig = 27, POCSAGConfigure = 28, + DTMFTXConfig = 29, POCSAGPacket = 30, @@ -633,6 +634,24 @@ public: const uint32_t rate; }; +class DTMFTXConfigMessage : public Message { +public: + constexpr DTMFTXConfigMessage( + const uint32_t bw, + const uint32_t tone_length, + const uint32_t pause_length + ) : Message { ID::DTMFTXConfig }, + bw(bw), + tone_length(tone_length), + pause_length(pause_length) + { + } + + const uint32_t bw; + const uint32_t tone_length; + const uint32_t pause_length; +}; + // TODO: use streaming buffer instead class FIFOSignalMessage : public Message { public: diff --git a/firmware/common/spi_image.hpp b/firmware/common/spi_image.hpp index 90ccd452..a7473206 100644 --- a/firmware/common/spi_image.hpp +++ b/firmware/common/spi_image.hpp @@ -79,6 +79,7 @@ constexpr image_tag_t image_tag_epar { 'P', 'E', 'P', 'R' }; constexpr image_tag_t image_tag_xylos { 'P', 'X', 'Y', 'L' }; constexpr image_tag_t image_tag_rds { 'P', 'R', 'D', 'S' }; constexpr image_tag_t image_tag_ook { 'P', 'O', 'O', 'K' }; +constexpr image_tag_t image_tag_dtmf_tx { 'P', 'D', 'T', 'X' }; constexpr image_tag_t image_tag_hackrf { 'H', 'R', 'F', '1' }; diff --git a/firmware/portapack-h1-havoc.bin b/firmware/portapack-h1-havoc.bin index adef30c2..55c13bcb 100644 Binary files a/firmware/portapack-h1-havoc.bin and b/firmware/portapack-h1-havoc.bin differ