diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index 37f158be..6a1dff41 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -171,6 +171,7 @@ set(CPPSRC ui_navigation.cpp ui_numbers.cpp ui_nuoptix.cpp + ui_pocsag_tx.cpp ui_rds.cpp ui_receiver.cpp ui_record_view.cpp diff --git a/firmware/application/Makefile b/firmware/application/Makefile index 75488f89..6e65b14f 100644 --- a/firmware/application/Makefile +++ b/firmware/application/Makefile @@ -4919,6 +4919,33 @@ 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_pocsag_tx.obj: ui_pocsag_tx.cpp.obj + +.PHONY : ui_pocsag_tx.obj + +# target to build an object file +ui_pocsag_tx.cpp.obj: + cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_pocsag_tx.cpp.obj +.PHONY : ui_pocsag_tx.cpp.obj + +ui_pocsag_tx.i: ui_pocsag_tx.cpp.i + +.PHONY : ui_pocsag_tx.i + +# target to preprocess a source file +ui_pocsag_tx.cpp.i: + cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_pocsag_tx.cpp.i +.PHONY : ui_pocsag_tx.cpp.i + +ui_pocsag_tx.s: ui_pocsag_tx.cpp.s + +.PHONY : ui_pocsag_tx.s + +# target to generate assembly for a file +ui_pocsag_tx.cpp.s: + cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_pocsag_tx.cpp.s +.PHONY : ui_pocsag_tx.cpp.s + ui_rds.obj: ui_rds.cpp.obj .PHONY : ui_rds.obj @@ -5892,6 +5919,9 @@ help: @echo "... ui_nuoptix.obj" @echo "... ui_nuoptix.i" @echo "... ui_nuoptix.s" + @echo "... ui_pocsag_tx.obj" + @echo "... ui_pocsag_tx.i" + @echo "... ui_pocsag_tx.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 db815fd9..bf91a5fe 100644 --- a/firmware/application/baseband_api.cpp +++ b/firmware/application/baseband_api.cpp @@ -141,6 +141,17 @@ void set_ook_data(const uint32_t stream_length, const uint32_t samples_per_bit, send_message(&message); } +void set_fsk_data(const uint32_t stream_length, const uint32_t samples_per_bit, const uint32_t shift, + const uint32_t progress_notice) { + const FSKConfigureMessage message { + stream_length, + samples_per_bit, + shift, + progress_notice + }; + send_message(&message); +} + void set_pocsag(const pocsag::BitRate bitrate) { const POCSAGConfigureMessage message { bitrate diff --git a/firmware/application/baseband_api.hpp b/firmware/application/baseband_api.hpp index 1dcc75b5..695d7913 100644 --- a/firmware/application/baseband_api.hpp +++ b/firmware/application/baseband_api.hpp @@ -63,6 +63,8 @@ void set_afsk_data(const uint32_t afsk_samples_per_bit, const uint32_t afsk_phas const uint8_t afsk_repeat, const uint32_t afsk_bw, const bool afsk_alt_format); 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_fsk_data(const uint32_t stream_length, const uint32_t samples_per_bit, const uint32_t shift, + const uint32_t progress_notice); void set_pocsag(const pocsag::BitRate bitrate); void set_adsb(); void set_jammer(const bool run, const uint32_t type, const uint32_t speed); diff --git a/firmware/application/main.cpp b/firmware/application/main.cpp index bc9d58bd..c29a619c 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: POCSAG TX: Chops off the few last chars on long messages ? //BUG: (fixed ?) POCSAG: Bad console scroll init //BUG: (fixed ?) POCSAG misses alphanum messages, cuts them off sometimes //BUG: Check AFSK transmit end, skips last bits ? @@ -31,6 +32,7 @@ //TEST: Imperial in whipcalc //TEST: Numbers +//TODO: Use TransmitterView everywhere possible //TODO: FreqMan: Add and rename categories //TODO: FreqMan: Sort by category in edit screen //TODO: FreqMan: Cap entry count per category (only done for total entries right now) diff --git a/firmware/application/pocsag_app.hpp b/firmware/application/pocsag_app.hpp index a49ad8e6..80d1665d 100644 --- a/firmware/application/pocsag_app.hpp +++ b/firmware/application/pocsag_app.hpp @@ -33,7 +33,6 @@ #include "log_file.hpp" -#include "bch_code.hpp" #include "pocsag.hpp" #include "pocsag_packet.hpp" @@ -70,11 +69,6 @@ private: static constexpr uint32_t sampling_rate = 3072000; //static constexpr uint32_t baseband_bandwidth = 1750000; - BCHCode BCH_code { - { 1, 0, 1, 0, 0, 1 }, - 5, 31, 21, 2 - }; - bool logging { true }; uint32_t last_address = 0xFFFFFFFF; pocsag::POCSAGState pocsag_state { }; diff --git a/firmware/application/ui_bht_tx.cpp b/firmware/application/ui_bht_tx.cpp index cfdf91a9..ba312798 100644 --- a/firmware/application/ui_bht_tx.cpp +++ b/firmware/application/ui_bht_tx.cpp @@ -63,7 +63,6 @@ void BHTView::start_tx() { generate_message(); - //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); @@ -136,13 +135,9 @@ BHTView::BHTView(NavigationView& nav) { &text_receiver, &receiver_code, &checkbox_wcid, - //&text_freq, - //&options_freq, - //&field_bw, &text_relais, &progressbar, &text_message, - //&button_transmit, &checkbox_cligno, &tempo_cligno, &text_cligno, @@ -158,13 +153,10 @@ 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); tempo_cligno.set_value(1); progressbar.set_max(20); relay_states[0].set_selected_index(1); // R1 OFF - //field_bw.set_value(20); - options_mode.on_change = [this](size_t mode, OptionsField::value_t) { _mode = mode; @@ -289,8 +281,6 @@ BHTView::BHTView(NavigationView& nav) { n++; } - //button_transmit.set_style(&style_val); - generate_message(); tx_view.on_edit_frequency = [this, &nav]() { @@ -301,11 +291,9 @@ BHTView::BHTView(NavigationView& nav) { }; 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); + if ((tx_mode == IDLE) && (!_mode)) { + if (speaker_enabled && _mode) + audio::headphone::set_volume(volume_t::decibel(90 - 99) + audio::headphone::volume_range().max); tx_mode = SINGLE; tx_view.set_transmitting(true); start_tx(); diff --git a/firmware/application/ui_bht_tx.hpp b/firmware/application/ui_bht_tx.hpp index 93509e45..330b6e88 100644 --- a/firmware/application/ui_bht_tx.hpp +++ b/firmware/application/ui_bht_tx.hpp @@ -197,32 +197,6 @@ private: "Tous" }; - /*Text text_freq { - { 1 * 8, 8 * 16, 10 * 8, 16 }, - "Frequence:" - }; - OptionsField options_freq { - { 12 * 8, 8 * 16}, - 7, - { - { "31.3250", 0 }, - { "31.3875", 1 }, - { "31.4375", 2 }, - { "31.4750", 3 }, - { "31.6875", 4 }, - { "31.9750", 5 }, - { "TEST 88", 6 } - } - }; - - NumberField field_bw { - { 20 * 8, 8 * 16 }, - 2, - { 0, 99 }, - 1, - ' ' - };*/ - Text text_relais { { 1 * 8, 8 * 16 + 8, 7 * 8, 16 }, "Relais:" @@ -244,11 +218,6 @@ private: "" }; - /*Button button_transmit { - { 2 * 8, 16 * 16, 12 * 8, 32 }, - "START" - };*/ - Checkbox checkbox_cligno { { 18 * 8 + 4, 10 * 16}, 3, diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 3d1e7ce4..a4c8b1f1 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -43,6 +43,7 @@ #include "ui_morse.hpp" #include "ui_numbers.hpp" #include "ui_nuoptix.hpp" +#include "ui_pocsag_tx.hpp" #include "ui_rds.hpp" #include "ui_sd_wipe.hpp" #include "ui_setup.hpp" @@ -301,12 +302,13 @@ ReceiverMenuView::ReceiverMenuView(NavigationView& nav) { /* TransmitterCodedMenuView ******************************************************/ TransmitterCodedMenuView::TransmitterCodedMenuView(NavigationView& nav) { - add_items<7>({ { + add_items<8>({ { { "ADS-B Mode S", ui::Color::orange(),&bitmap_icon_adsb, [&nav](){ nav.push(); } }, { "BHT Xy/EP", ui::Color::yellow(),&bitmap_icon_bht, [&nav](){ nav.push(); } }, { "Morse beacon", ui::Color::yellow(),&bitmap_icon_morse, [&nav](){ nav.push(); } }, { "Nuoptix DTMF timecode", ui::Color::green(), &bitmap_icon_nuoptix, [&nav](){ nav.push(); } }, { "OOK remote encoders", ui::Color::green(), &bitmap_icon_remote, [&nav](){ nav.push(); } }, + { "POCSAG", ui::Color::cyan(), &bitmap_icon_pocsag, [&nav](){ nav.push(); } }, { "RDS", ui::Color::green(), &bitmap_icon_rds, [&nav](){ nav.push(); } }, { "TEDI/LCR AFSK", ui::Color::green(), &bitmap_icon_lcr, [&nav](){ nav.push(); } }, } }); diff --git a/firmware/application/ui_pocsag_tx.cpp b/firmware/application/ui_pocsag_tx.cpp new file mode 100644 index 00000000..10ba66a2 --- /dev/null +++ b/firmware/application/ui_pocsag_tx.cpp @@ -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_pocsag_tx.hpp" + +#include "pocsag.hpp" +#include "baseband_api.hpp" +#include "string_format.hpp" + +#include "portapack_persistent_memory.hpp" + +#include +#include +#include + +using namespace portapack; +using namespace pocsag; + +namespace ui { + +void POCSAGTXView::focus() { + tx_view.focus(); +} + +POCSAGTXView::~POCSAGTXView() { + transmitter_model.disable(); + baseband::shutdown(); +} + +void POCSAGTXView::on_tx_progress(const int progress, const bool done) { + if (done) { + transmitter_model.disable(); + progressbar.set_value(0); + tx_view.set_transmitting(false); + } else + progressbar.set_value(progress); +} + +void POCSAGTXView::start_tx() { + uint32_t total_frames, i, codeword, b, bi, address; + std::string test_string = "PORTAPACK !"; + std::vector codewords; + uint8_t byte = 0; + + address = address_field.value_dec_u32(); + if (address > 0x7FFFFFU) + address = 0; // Todo: Error screen + + pocsag_encode(BCH_code, test_string, address, codewords); + + total_frames = codewords.size() / 2; + + progressbar.set_max(total_frames); + + transmitter_model.set_sampling_rate(2280000); + 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(); + + uint8_t * data_ptr = shared_memory.bb_data.data; + + bi = 0; + for (i = 0; i < codewords.size(); i++) { + /*for (b = 0; b < 32; b++) { + byte |= ((((codewords[i] << b) & 0x80000000U) ? 1 : 0) << (7 - (b & 7))); + if ((b & 7) == 7) { + data_ptr[bi++] = byte; + byte = 0; + } + }*/ + codeword = codewords[i]; + data_ptr[bi++] = (codeword >> 24) & 0xFF; + data_ptr[bi++] = (codeword >> 16) & 0xFF; + data_ptr[bi++] = (codeword >> 8) & 0xFF; + data_ptr[bi++] = codeword & 0xFF; + } + + text_debug_a.set("Codewords: " + to_string_dec_uint(codewords.size())); + + baseband::set_fsk_data( + codewords.size() * 32, + 228000 / 1200, + 4500, + 64 + //228000 / ((numberfield_clk.value() * 1000) / encoder_def->clk_per_fragment), + ); +} + +POCSAGTXView::POCSAGTXView(NavigationView& nav) { + //size_t i; + + baseband::run_image(portapack::spi_flash::image_tag_fsktx); + + add_children({ + &text_debug_a, + &text_debug_b, + &text_debug_c, + &address_field, + &progressbar, + &tx_view + }); + + 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]() { + tx_view.set_transmitting(true); + start_tx(); + }; + + tx_view.on_stop = [this]() { + tx_view.set_transmitting(false); + }; + +} + +} /* namespace ui */ diff --git a/firmware/application/ui_pocsag_tx.hpp b/firmware/application/ui_pocsag_tx.hpp new file mode 100644 index 00000000..389d5832 --- /dev/null +++ b/firmware/application/ui_pocsag_tx.hpp @@ -0,0 +1,102 @@ +/* + * 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 __POCSAG_TX_H__ +#define __POCSAG_TX_H__ + +#include "ui.hpp" +#include "ui_widget.hpp" +#include "ui_navigation.hpp" +#include "ui_font_fixed_8x16.hpp" +#include "ui_receiver.hpp" +#include "ui_transmitter.hpp" +#include "bch_code.hpp" +#include "message.hpp" +#include "transmitter_model.hpp" + +namespace ui { + +class POCSAGTXView : public View { +public: + POCSAGTXView(NavigationView& nav); + ~POCSAGTXView(); + + /*POCSAGTXView(const EncodersView&) = delete; + POCSAGTXView(EncodersView&&) = delete; + POCSAGTXView& operator=(const EncodersView&) = delete; + POCSAGTXView& operator=(EncodersView&&) = delete;*/ + + void focus() override; + + std::string title() const override { return "POCSAG TX"; }; + +private: + + BCHCode BCH_code { + { 1, 0, 1, 0, 0, 1 }, + 5, 31, 21, 2 + }; + + void on_tx_progress(const int progress, const bool done); + void start_tx(); + + Text text_debug_a { + { 1 * 8, 4 * 8, 20 * 8, 16 }, + "-" + }; + Text text_debug_b { + { 1 * 8, 6 * 8, 20 * 8, 16 }, + "-" + }; + Text text_debug_c { + { 1 * 8, 12 * 8, 20 * 8, 16 }, + "Address:" + }; + + SymField address_field { + { 9 * 8, 12 * 8 }, + 7, + SymField::SYMFIELD_DEC + }; + + ProgressBar progressbar { + { 16, 200, 208, 16 } + }; + + TransmitterView tx_view { + 16 * 16, + 10000, + 9 + }; + + MessageHandlerRegistration message_handler_tx_done { + Message::ID::TXDone, + [this](const Message* const p) { + const auto message = *reinterpret_cast(p); + this->on_tx_progress(message.progress, message.done); + } + }; +}; + +} /* namespace ui */ + +#endif/*__POCSAG_TX_H__*/ diff --git a/firmware/application/ui_transmitter.cpp b/firmware/application/ui_transmitter.cpp index 5070902b..eebacc6d 100644 --- a/firmware/application/ui_transmitter.cpp +++ b/firmware/application/ui_transmitter.cpp @@ -75,6 +75,10 @@ void TransmitterView::on_show() { field_frequency.set_value(receiver_model.tuning_frequency()); } +void TransmitterView::focus() { + button_start.focus(); +} + TransmitterView::TransmitterView( const Coord y, const uint32_t frequency_step, const uint32_t bandwidth ) { diff --git a/firmware/application/ui_transmitter.hpp b/firmware/application/ui_transmitter.hpp index ea1f516b..156d8a9f 100644 --- a/firmware/application/ui_transmitter.hpp +++ b/firmware/application/ui_transmitter.hpp @@ -56,6 +56,7 @@ public: ~TransmitterView(); void on_show() override; + void focus() override; void set_transmitting(const bool transmitting); @@ -78,11 +79,11 @@ private: }; TXGainField field_gain { - { 11 * 8, 0 * 16 } + { 10 * 8, 0 * 16 } }; NumberField field_bw { - { 14 * 8, 0 * 16 }, + { 13 * 8, 0 * 16 }, 3, { 1, 150 }, 1, diff --git a/firmware/baseband/CMakeLists.txt b/firmware/baseband/CMakeLists.txt index 78e70eec..5c5fe4fb 100644 --- a/firmware/baseband/CMakeLists.txt +++ b/firmware/baseband/CMakeLists.txt @@ -301,6 +301,13 @@ set(MODE_CPPSRC ) DeclareTargets(PERT ert) +### FSK TX + +set(MODE_CPPSRC + proc_fsk.cpp +) +DeclareTargets(PFSK fsktx) + ### POCSAG RX set(MODE_CPPSRC diff --git a/firmware/baseband/proc_fsk.cpp b/firmware/baseband/proc_fsk.cpp new file mode 100644 index 00000000..5f194bf6 --- /dev/null +++ b/firmware/baseband/proc_fsk.cpp @@ -0,0 +1,115 @@ +/* + * 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 "proc_fsk.hpp" +#include "portapack_shared_memory.hpp" +#include "sine_table_int8.hpp" +#include "event_m4.hpp" + +#include + +void FSKProcessor::execute(const buffer_c8_t& buffer) { + int8_t re, im; + + // This is called at 2.28M/2048 = 1113Hz + + if (!configured) return; + + for (size_t i = 0; i < buffer.count; i++) { + + // Synthesis at 2.28M/10 = 228kHz + if (!s) { + s = 10 - 1; + if (sample_count >= samples_per_bit) { + if (bit_pos >= length) { + // End of data + cur_bit = 0; + txdone_message.done = true; + shared_memory.application_queue.push(txdone_message); + configured = false; + } else { + cur_bit = (shared_memory.bb_data.data[bit_pos >> 3] << (bit_pos & 7)) & 0x80; + bit_pos++; + if (progress_count >= progress_notice) { + progress_count = 0; + txdone_message.progress++; + shared_memory.application_queue.push(txdone_message); + } else { + progress_count++; + } + } + sample_count = 0; + } else { + sample_count++; + } + } else { + s--; + } + + if (configured) { + if (cur_bit) + phase += shift_one; + else + phase += shift_zero; + + sphase = phase + (64 << 24); + + re = (sine_table_i8[(sphase & 0xFF000000) >> 24]); + im = (sine_table_i8[(phase & 0xFF000000) >> 24]); + } else { + re = 0; + im = 0; + } + + buffer.p[i] = {re, im}; + } +} + +void FSKProcessor::on_message(const Message* const p) { + const auto message = *reinterpret_cast(p); + + if (message.id == Message::ID::FSKConfigure) { + samples_per_bit = message.samples_per_bit; + length = message.stream_length - 1; + + shift_zero = message.shift * (0xFFFFFFFFULL / 2280000); + shift_one = -shift_zero; + + progress_notice = message.progress_notice; + + s = 0; + sample_count = samples_per_bit; + progress_count = 0; + bit_pos = 0; + cur_bit = 0; + + txdone_message.progress = 0; + txdone_message.done = false; + configured = true; + } +} + +int main() { + EventDispatcher event_dispatcher { std::make_unique() }; + event_dispatcher.run(); + return 0; +} diff --git a/firmware/baseband/proc_fsk.hpp b/firmware/baseband/proc_fsk.hpp new file mode 100644 index 00000000..3475b55b --- /dev/null +++ b/firmware/baseband/proc_fsk.hpp @@ -0,0 +1,54 @@ +/* + * 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 __PROC_FSK_H__ +#define __PROC_FSK_H__ + +#include "baseband_processor.hpp" +#include "baseband_thread.hpp" + +class FSKProcessor : public BasebandProcessor { +public: + void execute(const buffer_c8_t& buffer) override; + + void on_message(const Message* const p) override; + +private: + bool configured = false; + + BasebandThread baseband_thread { 2280000, this, NORMALPRIO + 20, baseband::Direction::Transmit }; + + uint32_t samples_per_bit { 0 }; + uint32_t length { 0 }; + + uint8_t s { 0 }; + uint32_t shift_zero { }, shift_one { }; + uint32_t bit_pos { 0 }; + uint32_t progress_notice { }, progress_count { 0 }; + uint8_t cur_bit { 0 }; + uint32_t sample_count { 0 }; + uint32_t phase { 0 }, sphase { 0 }; + + TXDoneMessage txdone_message { }; +}; + +#endif diff --git a/firmware/common/message.hpp b/firmware/common/message.hpp index 4552b115..31868356 100644 --- a/firmware/common/message.hpp +++ b/firmware/common/message.hpp @@ -84,6 +84,7 @@ public: ADSBConfigure = 40, JammerConfigure = 41, WidebandSpectrumConfig = 42, + FSKConfigure = 43, POCSAGPacket = 50, @@ -695,6 +696,27 @@ public: const uint32_t pause_symbols; }; +class FSKConfigureMessage : public Message { +public: + constexpr FSKConfigureMessage( + const uint32_t stream_length, + const uint32_t samples_per_bit, + const uint32_t shift, + const uint32_t progress_notice + ) : Message { ID::FSKConfigure }, + stream_length(stream_length), + samples_per_bit(samples_per_bit), + shift(shift), + progress_notice(progress_notice) + { + } + + const uint32_t stream_length; + const uint32_t samples_per_bit; + const uint32_t shift; + const uint32_t progress_notice; +}; + class POCSAGConfigureMessage : public Message { public: constexpr POCSAGConfigureMessage( diff --git a/firmware/common/pocsag.cpp b/firmware/common/pocsag.cpp index 14a19578..460e466d 100644 --- a/firmware/common/pocsag.cpp +++ b/firmware/common/pocsag.cpp @@ -94,19 +94,20 @@ void pocsag_encode( } // Address - codeword = (address & 0x1FFFF8U) << 13; + codeword = (address & 0x1FFFF8U) << 10; address_slot = (address & 7) * 2; // Function - codeword = 3 << 11; + codeword |= (3 << 11); insert_BCH(BCH_code, &codeword); // Address batch codewords.push_back(POCSAG_SYNCWORD); for (c = 0; c < 16; c++) { - if (c == address_slot) + if (c == address_slot) { codewords.push_back(codeword); - else + break; + } else codewords.push_back(POCSAG_IDLEWORD); } @@ -115,44 +116,52 @@ void pocsag_encode( // Messages batch(es) do { - codewords.push_back(POCSAG_SYNCWORD); + if (c == 0) codewords.push_back(POCSAG_SYNCWORD); - for (c = 0; c < 16; c++) { - // Fill up 20 bits - do { - bit_idx -= 7; - - if (char_idx < text_size) - ascii_char = text[char_idx] & 0x7F; - else - ascii_char = 0; // Padding - - // Bottom's up - ascii_char = (ascii_char & 0xF0) >> 4 | (ascii_char & 0x0F) << 4; // *6543210 -> 3210*654 - ascii_char = (ascii_char & 0xCC) >> 2 | (ascii_char & 0x33) << 2; // 3210*654 -> 103254*6 - ascii_char = (ascii_char & 0xAA) >> 2 | (ascii_char & 0x55); // 103254*6 -> *0123456 - - codeword |= (ascii_char << bit_idx); - - char_idx++; - - } while (bit_idx > 11); + for ( ; c < 16; c++) { - codeword &= 0x7FFFF800; // Trim data - codeword |= 0x80000000; // Message type - insert_BCH(BCH_code, &codeword); - - codewords.push_back(codeword); - - if (bit_idx != 11) { - bit_idx = 20 + bit_idx; - codeword = ascii_char << bit_idx; + if (char_idx < text_size) { + + // Fill up 20 bits + do { + bit_idx -= 7; + + if (char_idx < text_size) + ascii_char = text[char_idx] & 0x7F; + else + ascii_char = 0; // Codeword padding + + // Bottom's up + ascii_char = (ascii_char & 0xF0) >> 4 | (ascii_char & 0x0F) << 4; // *6543210 -> 3210*654 + ascii_char = (ascii_char & 0xCC) >> 2 | (ascii_char & 0x33) << 2; // 3210*654 -> 103254*6 + ascii_char = (ascii_char & 0xAA) >> 2 | (ascii_char & 0x55); // 103254*6 -> *0123456 + + codeword |= (ascii_char << bit_idx); + + char_idx++; + + } while (bit_idx > 11); + + codeword &= 0x7FFFF800; // Trim data + codeword |= 0x80000000; // Message type + insert_BCH(BCH_code, &codeword); + + codewords.push_back(codeword); + + if (bit_idx != 11) { + bit_idx = 20 + bit_idx; + codeword = ascii_char << bit_idx; + } else { + bit_idx = 20 + 11; + codeword = 0; + } } else { - bit_idx = 20 + 11; - codeword = 0; + codewords.push_back(POCSAG_IDLEWORD); // Batch padding } } + c = 0; + } while (char_idx < text_size); } diff --git a/firmware/common/spi_image.hpp b/firmware/common/spi_image.hpp index 7c3079b9..353cd4f7 100644 --- a/firmware/common/spi_image.hpp +++ b/firmware/common/spi_image.hpp @@ -82,6 +82,7 @@ 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_adsb_tx { 'P', 'A', 'D', 'S' }; constexpr image_tag_t image_tag_replay { 'P', 'R', 'E', 'P' }; +constexpr image_tag_t image_tag_fsktx { 'P', 'F', 'S', 'K' }; constexpr image_tag_t image_tag_hackrf { 'H', 'R', 'F', '1' }; diff --git a/firmware/common/ui_widget.cpp b/firmware/common/ui_widget.cpp index 17ea133d..80f1def2 100644 --- a/firmware/common/ui_widget.cpp +++ b/firmware/common/ui_widget.cpp @@ -1185,6 +1185,20 @@ SymField::SymField( set_focusable(true); } +uint32_t SymField::value_dec_u32() { + uint32_t c, mul = 1; + uint32_t v = 0; + + if (type_ == SYMFIELD_DEC) { + for (c = 0; c < length_; c++) { + v += values_[(length_ - 1 - c)] * mul; + mul *= 10; + } + return v; + } else + return 0; +} + uint64_t SymField::value_hex_u64() { uint32_t c; uint64_t v = 0; diff --git a/firmware/common/ui_widget.hpp b/firmware/common/ui_widget.hpp index fea00dc3..bbacd7be 100644 --- a/firmware/common/ui_widget.hpp +++ b/firmware/common/ui_widget.hpp @@ -491,6 +491,7 @@ public: void set_value(const uint32_t index, const uint32_t new_value); void set_length(const uint32_t new_length); void set_symbol_list(const uint32_t index, const std::string symbol_list); + uint32_t value_dec_u32(); uint64_t value_hex_u64(); void paint(Painter& painter) override; diff --git a/firmware/portapack-h1-havoc.bin b/firmware/portapack-h1-havoc.bin index 8b9c9ac1..c5d3046a 100644 Binary files a/firmware/portapack-h1-havoc.bin and b/firmware/portapack-h1-havoc.bin differ