From 42439d18857650361ff642daac9801476298452f Mon Sep 17 00:00:00 2001 From: furrtek Date: Tue, 29 Aug 2017 09:42:04 +0100 Subject: [PATCH] Started writing (copying...) AFSK RX Encoders: removed bit duration setting (frame duration is more useful) --- firmware/application/CMakeLists.txt | 3 +- firmware/application/baseband_api.cpp | 11 +- firmware/application/baseband_api.hpp | 1 + firmware/application/de_bruijn.cpp | 27 +++- firmware/application/de_bruijn.hpp | 4 +- firmware/application/pocsag_app.hpp | 18 +-- firmware/application/ui_afsk_rx.cpp | 92 +++++++++++ firmware/application/ui_afsk_rx.hpp | 96 ++++++++++++ firmware/application/ui_afskrx.cpp | 140 ----------------- firmware/application/ui_afskrx.hpp | 74 --------- .../{ui_aprstx.cpp => ui_aprs_tx.cpp} | 2 +- .../{ui_aprstx.hpp => ui_aprs_tx.hpp} | 0 firmware/application/ui_encoders.cpp | 93 +++++------ firmware/application/ui_encoders.hpp | 38 ++--- firmware/application/ui_mictx.hpp | 4 +- firmware/application/ui_navigation.cpp | 7 +- firmware/baseband/CMakeLists.txt | 9 +- firmware/baseband/proc_afsk.cpp | 4 +- firmware/baseband/proc_afskrx.cpp | 148 +++++++++--------- firmware/baseband/proc_afskrx.hpp | 54 ++++--- firmware/baseband/proc_mictx.hpp | 2 +- firmware/common/message.hpp | 46 ++++-- firmware/common/spi_image.hpp | 3 +- 23 files changed, 453 insertions(+), 423 deletions(-) create mode 100644 firmware/application/ui_afsk_rx.cpp create mode 100644 firmware/application/ui_afsk_rx.hpp delete mode 100644 firmware/application/ui_afskrx.cpp delete mode 100644 firmware/application/ui_afskrx.hpp rename firmware/application/{ui_aprstx.cpp => ui_aprs_tx.cpp} (98%) rename firmware/application/{ui_aprstx.hpp => ui_aprs_tx.hpp} (100%) diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index 5e09f2f5..85da7d03 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -163,8 +163,9 @@ set(CPPSRC ui_about.cpp ui_adsb_rx.cpp ui_adsb_tx.cpp + ui_afsk_rx.cpp ui_alphanum.cpp - ui_aprstx.cpp + ui_aprs_tx.cpp ui_audio.cpp ui_baseband_stats_view.cpp ui_bht_tx.cpp diff --git a/firmware/application/baseband_api.cpp b/firmware/application/baseband_api.cpp index 6e8e2de6..463246fd 100644 --- a/firmware/application/baseband_api.cpp +++ b/firmware/application/baseband_api.cpp @@ -117,9 +117,16 @@ void set_sstv_data(const uint8_t vis_code, const uint32_t pixel_duration) { send_message(&message); } +void set_afsk(const uint32_t bitrate) { + const AFSKRxConfigureMessage message { + bitrate + }; + send_message(&message); +} + void set_afsk_data(const uint32_t afsk_samples_per_bit, const uint32_t afsk_phase_inc_mark, const uint32_t afsk_phase_inc_space, const uint8_t afsk_repeat, const uint32_t afsk_bw, const uint8_t symbol_count) { - const AFSKConfigureMessage message { + const AFSKTxConfigureMessage message { afsk_samples_per_bit, afsk_phase_inc_mark, afsk_phase_inc_space, @@ -131,7 +138,7 @@ void set_afsk_data(const uint32_t afsk_samples_per_bit, const uint32_t afsk_phas } void kill_afsk() { - const AFSKConfigureMessage message { + const AFSKTxConfigureMessage message { 0, 0, 0, diff --git a/firmware/application/baseband_api.hpp b/firmware/application/baseband_api.hpp index 5bd2cfc4..e10e2a1c 100644 --- a/firmware/application/baseband_api.hpp +++ b/firmware/application/baseband_api.hpp @@ -67,6 +67,7 @@ void set_pwmrssi(int32_t avg, bool enabled); void set_afsk_data(const uint32_t afsk_samples_per_bit, const uint32_t afsk_phase_inc_mark, const uint32_t afsk_phase_inc_space, const uint8_t afsk_repeat, const uint32_t afsk_bw, const uint8_t symbol_count); void kill_afsk(); +void set_afsk(const uint32_t bitrate); 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, diff --git a/firmware/application/de_bruijn.cpp b/firmware/application/de_bruijn.cpp index 1afb0d7d..ddd1ef79 100644 --- a/firmware/application/de_bruijn.cpp +++ b/firmware/application/de_bruijn.cpp @@ -26,10 +26,10 @@ * B(2,4) means: * Alphabet size = 2 (binary) * Code length = 4 - * The length of the bitstream is (2 ^ 4) - 1 = 15 + * The length of the bitstream is (2 ^ 4) + (4 - 1) = 19 bits * The primitive polynomials come from the de_bruijn_polys[] array (one for each code length) * The shift register is init with 1 and shifted left each step - * The polynomial is kept on the right, and ANDed with the corresponding shift register bits + * The polynomial is kept on the right, and used as a AND mask applied on the corresponding shift register bits * The resulting bits are XORed together to produce the new bit pushed in the shift register * * 0001 (init) @@ -52,9 +52,28 @@ * AND 1001 * 1000 XOR'd -> 1 * ... + * After 16 steps: (0+) 000111101011001000 + * Each of the 16 possible values appears in the sequence: + * -0000-111101011001000 0 + * 0-0001-11101011001000 1 + * 0000111101011-0010-00 2 + * 00-0011-1101011001000 3 + * 00001111010110-0100-0 4 + * 00001111-0101-1001000 5 + * 0000111101-0110-01000 6 + * 000-0111-101011001000 7 + * 000011110101100-1000- 8 + * 000011110101-1001-000 9 + * 0000111-1010-11001000 10 + * 000011110-1011-001000 11 + * 00001111010-1100-1000 12 + * 000011-1101-011001000 13 + * 00001-1110-1011001000 14 + * 0000-1111-01011001000 15 */ -void de_bruijn::init(const uint32_t n) { +size_t de_bruijn::init(const uint32_t n) { + // Cap if ((n < 3) || (n > 16)) length = 3; else @@ -62,6 +81,8 @@ void de_bruijn::init(const uint32_t n) { poly = de_bruijn_polys[length - 3]; shift_register = 1; + + return (1U << length) + (length - 1); } uint32_t de_bruijn::compute(const uint32_t steps) { diff --git a/firmware/application/de_bruijn.hpp b/firmware/application/de_bruijn.hpp index 6ab75b7e..937fb08e 100644 --- a/firmware/application/de_bruijn.hpp +++ b/firmware/application/de_bruijn.hpp @@ -25,7 +25,7 @@ #ifndef __DE_BRUIJN_H__ #define __DE_BRUIJN_H__ -// Starts at n = 3 +// n from 3 to 16 const uint32_t de_bruijn_polys[14] { 0b0000000000000101, 0b0000000000001001, @@ -45,7 +45,7 @@ const uint32_t de_bruijn_polys[14] { struct de_bruijn { public: - void init(const uint32_t n); + size_t init(const uint32_t n); uint32_t compute(const uint32_t steps); private: diff --git a/firmware/application/pocsag_app.hpp b/firmware/application/pocsag_app.hpp index 92488c2b..ace892d0 100644 --- a/firmware/application/pocsag_app.hpp +++ b/firmware/application/pocsag_app.hpp @@ -64,16 +64,6 @@ private: bool ignore { false }; uint32_t last_address = 0xFFFFFFFF; pocsag::POCSAGState pocsag_state { }; - - MessageHandlerRegistration message_handler_packet { - Message::ID::POCSAGPacket, - [this](Message* const p) { - const auto message = static_cast(p); - this->on_packet(message); - } - }; - - static constexpr ui::Dim header_height = 1 * 16; RFAmpField field_rf_amp { { 13 * 8, 0 * 16 } @@ -138,6 +128,14 @@ private: uint32_t target_frequency() const; void set_target_frequency(const uint32_t new_value); + + MessageHandlerRegistration message_handler_packet { + Message::ID::POCSAGPacket, + [this](Message* const p) { + const auto message = static_cast(p); + this->on_packet(message); + } + }; }; } /* namespace ui */ diff --git a/firmware/application/ui_afsk_rx.cpp b/firmware/application/ui_afsk_rx.cpp new file mode 100644 index 00000000..d8efec46 --- /dev/null +++ b/firmware/application/ui_afsk_rx.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2017 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_afsk_rx.hpp" +#include "baseband_api.hpp" + +//#include "string_format.hpp" + +using namespace portapack; + +namespace ui { + +void AFSKRxView::focus() { + field_frequency.focus(); +} + +void AFSKRxView::update_freq(rf::Frequency f) { + receiver_model.set_tuning_frequency(f); +} + +void AFSKRxView::on_bitrate_changed(const uint32_t new_bitrate) { + baseband::set_afsk(new_bitrate); +} + +AFSKRxView::AFSKRxView(NavigationView& nav) { + baseband::run_image(portapack::spi_flash::image_tag_afsk_rx); + + add_children({ + &rssi, + &channel, + &field_rf_amp, + &field_lna, + &field_vga, + &field_frequency, + &options_bitrate, + &console + }); + + //receiver_model.set_sampling_rate(3072000); + //receiver_model.set_baseband_bandwidth(1750000); + //receiver_model.enable(); + + field_frequency.set_value(receiver_model.tuning_frequency()); + field_frequency.set_step(receiver_model.frequency_step()); + field_frequency.on_change = [this](rf::Frequency f) { + update_freq(f); + }; + field_frequency.on_edit = [this, &nav]() { + // TODO: Provide separate modal method/scheme? + auto new_view = nav.push(receiver_model.tuning_frequency()); + new_view->on_changed = [this](rf::Frequency f) { + update_freq(f); + field_frequency.set_value(f); + }; + }; + + options_bitrate.on_change = [this](size_t, OptionsField::value_t v) { + on_bitrate_changed(v); + }; + options_bitrate.set_selected_index(1); // 1200bps +} + +void AFSKRxView::on_data(uint_fast8_t byte) { + std::string str_byte(1, byte); + console.write(str_byte); +} + +AFSKRxView::~AFSKRxView() { + receiver_model.disable(); + baseband::shutdown(); +} + +} /* namespace ui */ diff --git a/firmware/application/ui_afsk_rx.hpp b/firmware/application/ui_afsk_rx.hpp new file mode 100644 index 00000000..4b99f1c2 --- /dev/null +++ b/firmware/application/ui_afsk_rx.hpp @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2017 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_AFSK_RX_H__ +#define __UI_AFSK_RX_H__ + +#include "ui.hpp" +#include "ui_navigation.hpp" +#include "ui_receiver.hpp" +#include "ui_widget.hpp" +#include "utility.hpp" + +namespace ui { + +class AFSKRxView : public View { +public: + AFSKRxView(NavigationView& nav); + ~AFSKRxView(); + + void focus() override; + + std::string title() const override { return "AFSK RX (beta)"; }; + +private: + void on_data(uint_fast8_t byte); + + RFAmpField field_rf_amp { + { 13 * 8, 0 * 16 } + }; + LNAGainField field_lna { + { 15 * 8, 0 * 16 } + }; + VGAGainField field_vga { + { 18 * 8, 0 * 16 } + }; + RSSI rssi { + { 21 * 8, 0, 6 * 8, 4 }, + }; + Channel channel { + { 21 * 8, 5, 6 * 8, 4 }, + }; + + FrequencyField field_frequency { + { 0 * 8, 0 * 8 }, + }; + OptionsField options_bitrate { + { 12 * 8, 21 }, + 7, + { + { "600bps ", 600 }, + { "1200bps", 1200 }, + { "2400bps", 2400 } + } + }; + + Console console { + { 0, 4 * 16, 240, 240 } + }; + + void update_freq(rf::Frequency f); + + void on_bitrate_changed(const uint32_t new_bitrate); + + void on_data_afsk(const AFSKDataMessage& message); + + MessageHandlerRegistration message_handler_packet { + Message::ID::AFSKData, + [this](Message* const p) { + const auto message = static_cast(p); + this->on_data(message->byte); + } + }; +}; + +} /* namespace ui */ + +#endif/*__UI_AFSK_RX_H__*/ diff --git a/firmware/application/ui_afskrx.cpp b/firmware/application/ui_afskrx.cpp deleted file mode 100644 index 79b46886..00000000 --- a/firmware/application/ui_afskrx.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. - * - * 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_afskrx.hpp" - -#include "ui_spectrum.hpp" -#include "ui_console.hpp" - -#include "event_m0.hpp" -#include "ff.h" - -#include "portapack.hpp" -using namespace portapack; - -namespace ui { - -AFSKRXView::AFSKRXView( - NavigationView& nav -) -{ - add_children({ - &button_done, - &text_rx - }); - - button_done.on_select = [&nav](Button&){ - nav.pop(); - }; - - receiver_model.set_baseband_configuration({ - .mode = 6, - .sampling_rate = 3072000, - .decimation_factor = 4, - }); - receiver_model.set_baseband_bandwidth(1750000); -} - -AFSKRXView::~AFSKRXView() { - receiver_model.disable(); -} - -void AFSKRXView::on_show() { - EventDispatcher::message_map().register_handler(Message::ID::AFSKData, - [this](Message* const p) { - const auto message = static_cast(p); - this->on_data_afsk(*message); - } - ); - - receiver_model.enable(); -} - -void AFSKRXView::on_hide() { - EventDispatcher::message_map().unregister_handler(Message::ID::AFSKData); -} - -void AFSKRXView::on_data_afsk(const AFSKDataMessage& message) { - Coord oy,ny; - - //text_rx.set(to_string_dec_int(abs(message.data), 8, '0')); - - portapack::display.fill_rectangle({0,160-64,240,128},{32,32,32}); - - oy = 160; - for (int c=0;c<128;c++) { - ny = 160-(message.data[c]>>10); - portapack::display.draw_line({static_cast(c),oy},{static_cast(c+1),ny},{255,127,0}); - oy = ny; - } - - /*auto payload = message.packet.payload; - auto payload_length = message.packet.bits_received; - - std::string hex_data; - std::string hex_error; - uint8_t byte_data = 0; - uint8_t byte_error = 0; - for(size_t i=0; i> 1) & 7) == 7 ) { - hex_data += to_string_hex(byte_data, 2); - hex_error += to_string_hex(byte_error, 2); - } - } - - auto console = reinterpret_cast(widget_content.get()); - console->writeln(hex_data.substr(0, 240 / 8)); - - if( !f_error(&fil_tpms) ) { - rtc::RTC datetime; - rtcGetTime(&RTCD1, &datetime); - std::string timestamp = - to_string_dec_uint(datetime.year(), 4) + - to_string_dec_uint(datetime.month(), 2, '0') + - to_string_dec_uint(datetime.day(), 2, '0') + - to_string_dec_uint(datetime.hour(), 2, '0') + - to_string_dec_uint(datetime.minute(), 2, '0') + - to_string_dec_uint(datetime.second(), 2, '0'); - - const auto tuning_frequency = receiver_model.tuning_frequency(); - // TODO: function doesn't take uint64_t, so when >= 1<<32, weirdness will ensue! - const auto tuning_frequency_str = to_string_dec_uint(tuning_frequency, 10); - - std::string log = timestamp + " " + tuning_frequency_str + " FSK 38.4 19.2 " + hex_data + "/" + hex_error + "\r\n"; - f_puts(log.c_str(), &fil_tpms); - f_sync(&fil_tpms); - }*/ -} - -void AFSKRXView::focus() { - button_done.focus(); -} - -} /* namespace ui */ diff --git a/firmware/application/ui_afskrx.hpp b/firmware/application/ui_afskrx.hpp deleted file mode 100644 index ccd37a3b..00000000 --- a/firmware/application/ui_afskrx.hpp +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. - * - * 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_AFSKRX_H__ -#define __UI_AFSKRX_H__ - -#include "ui.hpp" -#include "ui_font_fixed_8x16.hpp" -#include "ui_navigation.hpp" -#include "ui_painter.hpp" -#include "ui_widget.hpp" -#include "ui_console.hpp" - -#include "utility.hpp" - -#include "receiver_model.hpp" - -#include -#include -#include -#include - -namespace ui { - -class AFSKRXView : public View { -public: - AFSKRXView(NavigationView& nav); - ~AFSKRXView(); - - void focus() override; - - void on_show() override; - void on_hide() override; - -private: - std::unique_ptr widget_content; - - Button button_done { - { 4 * 8, 0 * 16, 3 * 8, 16 }, - " < " - }; - - Text text_rx { - { 1 * 8, 2 * 16, 28 * 8, 16 }, - "Ready..." - }; - - void on_tuning_frequency_changed(rf::Frequency f); - void on_edit_frequency(); - - void on_data_afsk(const AFSKDataMessage& message); -}; - -} /* namespace ui */ - -#endif/*__UI_RECEIVER_H__*/ diff --git a/firmware/application/ui_aprstx.cpp b/firmware/application/ui_aprs_tx.cpp similarity index 98% rename from firmware/application/ui_aprstx.cpp rename to firmware/application/ui_aprs_tx.cpp index 07873b11..b4341531 100644 --- a/firmware/application/ui_aprstx.cpp +++ b/firmware/application/ui_aprs_tx.cpp @@ -20,7 +20,7 @@ * Boston, MA 02110-1301, USA. */ -#include "ui_aprstx.hpp" +#include "ui_aprs_tx.hpp" #include "ui_alphanum.hpp" #include "aprs.hpp" diff --git a/firmware/application/ui_aprstx.hpp b/firmware/application/ui_aprs_tx.hpp similarity index 100% rename from firmware/application/ui_aprstx.hpp rename to firmware/application/ui_aprs_tx.hpp diff --git a/firmware/application/ui_encoders.cpp b/firmware/application/ui_encoders.cpp index ef86bcf1..dd9f214f 100644 --- a/firmware/application/ui_encoders.cpp +++ b/firmware/application/ui_encoders.cpp @@ -32,9 +32,7 @@ namespace ui { EncodersConfigView::EncodersConfigView( NavigationView& nav, Rect parent_rect ) { - using name_t = std::string; - using value_t = int32_t; - using option_t = std::pair; + using option_t = std::pair; std::vector enc_options; size_t i; @@ -47,9 +45,8 @@ EncodersConfigView::EncodersConfigView( add_children({ &labels, &options_enctype, - &numberfield_clk, - &numberfield_bitduration, - &numberfield_wordduration, + &field_clk, + &field_frameduration, &symfield_word, &text_format, &waveform @@ -71,31 +68,19 @@ EncodersConfigView::EncodersConfigView( }; // Selecting input clock changes symbol and word duration - numberfield_clk.on_change = [this](int32_t value) { + field_clk.on_change = [this](int32_t value) { // value is in kHz, new_value is in us - int32_t new_value = 1000000 / ((value * 1000) / encoder_def->clk_per_symbol); - if (new_value != numberfield_bitduration.value()) { - numberfield_bitduration.set_value(new_value, false); - numberfield_wordduration.set_value(new_value * encoder_def->word_length, false); - } - }; - - // Selecting symbol duration changes input clock and word duration - numberfield_bitduration.on_change = [this](int32_t value) { - int32_t new_value = 1000000 / (((float)value * 1000) / encoder_def->clk_per_symbol); - if (new_value != numberfield_clk.value()) { - numberfield_clk.set_value(new_value, false); - numberfield_wordduration.set_value(value * encoder_def->word_length, false); - } + int32_t new_value = (encoder_def->clk_per_symbol * 1000000) / (value * 1000); + if (new_value != field_frameduration.value()) + field_frameduration.set_value(new_value * encoder_def->word_length, false); }; // Selecting word duration changes input clock and symbol duration - numberfield_wordduration.on_change = [this](int32_t value) { - int32_t new_value = value / encoder_def->word_length; - if (new_value != numberfield_bitduration.value()) { - numberfield_bitduration.set_value(new_value, false); - numberfield_clk.set_value(1000000 / (((float)new_value * 1000) / encoder_def->clk_per_symbol), false); - } + field_frameduration.on_change = [this](int32_t value) { + // value is in us, new_value is in kHz + int32_t new_value = (value * 1000) / (encoder_def->word_length * encoder_def->clk_per_symbol); + if (new_value != field_clk.value()) + field_clk.set_value(1000000 / new_value, false); }; } @@ -104,16 +89,13 @@ void EncodersConfigView::focus() { } void EncodersConfigView::on_type_change(size_t index) { - std::string word_format, format_string = ""; + std::string format_string = ""; size_t word_length; char symbol_type; - //size_t address_length; - - //enc_type = index; encoder_def = &encoder_defs[index]; - numberfield_clk.set_value(encoder_def->default_speed / 1000); + field_clk.set_value(encoder_def->default_speed / 1000); // SymField setup word_length = encoder_def->word_length; @@ -139,16 +121,14 @@ void EncodersConfigView::on_type_change(size_t index) { } void EncodersConfigView::on_show() { - // TODO: Remove ? - //options_enctype.set_selected_index(enc_type); - //on_type_change(enc_type); + options_enctype.set_selected_index(0); + on_type_change(0); } void EncodersConfigView::draw_waveform() { size_t length = frame_symbols.length(); - size_t n; - - for (n = 0; n < length; n++) { + + for (size_t n = 0; n < length; n++) { if (frame_symbols[n] == '0') waveform_buffer[n] = 0; else @@ -179,7 +159,7 @@ uint8_t EncodersConfigView::repeat_min() { } uint32_t EncodersConfigView::samples_per_bit() { - return OOK_SAMPLERATE / ((numberfield_clk.value() * 1000) / encoder_def->clk_per_fragment); + return OOK_SAMPLERATE / ((field_clk.value() * 1000) / encoder_def->clk_per_fragment); } uint32_t EncodersConfigView::pause_symbols() { @@ -199,20 +179,26 @@ EncodersScanView::EncodersScanView( add_children({ &labels, &field_debug, - &text_debug + &text_debug, + &text_length }); // DEBUG field_debug.on_change = [this](int32_t value) { uint32_t l; + size_t length; + de_bruijn debruijn_seq; - debruijn_seq.init(value); + length = debruijn_seq.init(value); + l = 1; l <<= value; l--; if (l > 25) l = 25; text_debug.set(to_string_bin(debruijn_seq.compute(l), 25)); + + text_length.set(to_string_dec_uint(length)); }; } @@ -256,7 +242,7 @@ void EncodersView::on_txdone(int n, const bool txdone) { if (!txdone) { // Repeating... - //repeat_index = n + 1; + repeat_index = n + 1; /*if (tx_mode == SCAN) { scan_progress++; @@ -299,8 +285,9 @@ void EncodersView::on_txdone(int n, const bool txdone) { void EncodersView::start_tx(const bool scan) { (void)scan; - uint8_t* ook_bitstream = shared_memory.bb_data.data; - uint32_t ook_bitstream_length; + uint8_t byte = 0; + size_t bitstream_length =0; + uint8_t * bitstream = shared_memory.bb_data.data; repeat_min = view_config.repeat_min(); @@ -324,17 +311,14 @@ void EncodersView::start_tx(const bool scan) { view_config.generate_frame(); - // Clear bitstream - memset(ook_bitstream, 0, 256); - - size_t n = 0; for (auto c : view_config.frame_symbols) { + byte <<= 1; if (c != '0') - ook_bitstream[n >> 3] |= (1 << (7 - (n & 7))); - n++; + byte |= 1; + if ((bitstream_length & 7) == 7) + bitstream[bitstream_length >> 3] = byte; + bitstream_length++; } - - ook_bitstream_length = n; transmitter_model.set_sampling_rate(OOK_SAMPLERATE); transmitter_model.set_rf_amp(true); @@ -342,10 +326,7 @@ void EncodersView::start_tx(const bool scan) { transmitter_model.enable(); baseband::set_ook_data( - ook_bitstream_length, - // 2280000/2 = 1140000Hz = 0,877192982us - // numberfield_clk.value() / encoder_def->clk_per_fragment - // 455000 / 12 = 37917Hz = 26,37339452us + bitstream_length, view_config.samples_per_bit(), repeat_min, view_config.pause_symbols() diff --git a/firmware/application/ui_encoders.hpp b/firmware/application/ui_encoders.hpp index 1ba48c36..e47f52b8 100644 --- a/firmware/application/ui_encoders.hpp +++ b/firmware/application/ui_encoders.hpp @@ -67,12 +67,10 @@ private: { { 1 * 8, 0 }, "Type:", Color::light_grey() }, { { 16 * 8, 0 }, "Clk:", Color::light_grey() }, { { 24 * 8, 0 }, "kHz", Color::light_grey() }, - { { 16 * 8, 2 * 8 }, "Bit:", Color::light_grey() }, - { { 25 * 8, 2 * 8 }, "us", Color::light_grey() }, - { { 15 * 8, 4 * 8 }, "Word:", Color::light_grey() }, - { { 26 * 8, 4 * 8 }, "us", Color::light_grey() }, - { { 2 * 8, 6 * 8 }, "Word:", Color::light_grey() }, - { { 1 * 8, 13 * 8 }, "Waveform:", Color::light_grey() } + { { 14 * 8, 2 * 8 }, "Frame:", Color::light_grey() }, + { { 26 * 8, 2 * 8 }, "us", Color::light_grey() }, + { { 2 * 8, 4 * 8 }, "Symbols:", Color::light_grey() }, + { { 1 * 8, 11 * 8 }, "Waveform:", Color::light_grey() } }; OptionsField options_enctype { // Options are loaded at runtime @@ -82,7 +80,7 @@ private: } }; - NumberField numberfield_clk { + NumberField field_clk { { 21 * 8, 0 }, 3, { 1, 500 }, @@ -90,16 +88,8 @@ private: ' ' }; - NumberField numberfield_bitduration { + NumberField field_frameduration { { 21 * 8, 2 * 8 }, - 4, - { 50, 9999 }, - 1, - ' ' - }; - - NumberField numberfield_wordduration { - { 21 * 8, 4 * 8 }, 5, { 300, 99999 }, 100, @@ -107,18 +97,18 @@ private: }; SymField symfield_word { - { 2 * 8, 8 * 8 }, + { 2 * 8, 6 * 8 }, 20, SymField::SYMFIELD_DEF }; Text text_format { - { 2 * 8, 10 * 8, 24 * 8, 16 }, + { 2 * 8, 8 * 8, 24 * 8, 16 }, "" }; Waveform waveform { - { 0, 16 * 8, 240, 32 }, + { 0, 14 * 8, 240, 32 }, waveform_buffer, 0, 0, @@ -136,7 +126,7 @@ public: private: Labels labels { - { { 1 * 8, 1 * 8 }, "Test", Color::light_grey() } + { { 1 * 8, 1 * 8 }, "Coming soon...", Color::light_grey() } }; // DEBUG @@ -153,6 +143,12 @@ private: { 1 * 8, 8 * 8, 24 * 8, 16 }, "" }; + + // DEBUG + Text text_length { + { 1 * 8, 10 * 8, 24 * 8, 16 }, + "" + }; }; class EncodersView : public View { @@ -192,7 +188,7 @@ private: .foreground = Color::blue(), }; - Rect view_rect = { 0, 5 * 8, 240, 168 }; + Rect view_rect = { 0, 4 * 8, 240, 168 }; EncodersConfigView view_config { nav_, view_rect }; EncodersScanView view_scan { nav_, view_rect }; diff --git a/firmware/application/ui_mictx.hpp b/firmware/application/ui_mictx.hpp index 63df9cbb..2d1d2a1d 100644 --- a/firmware/application/ui_mictx.hpp +++ b/firmware/application/ui_mictx.hpp @@ -177,9 +177,9 @@ private: }; MessageHandlerRegistration message_handler_audio_level { - Message::ID::AudioLevel, + Message::ID::AudioLevelReport, [this](const Message* const p) { - const auto message = static_cast(p); + const auto message = static_cast(p); this->audio_level = message->value; } }; diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 2b4666d2..43706c33 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -33,7 +33,8 @@ #include "ui_about.hpp" #include "ui_adsb_tx.hpp" #include "ui_adsb_rx.hpp" -#include "ui_aprstx.hpp" +#include "ui_aprs_tx.hpp" +#include "ui_afsk_rx.hpp" #include "ui_bht_tx.hpp" #include "ui_coasterp.hpp" #include "ui_siggen.hpp" @@ -282,9 +283,9 @@ void NavigationView::focus() { ReceiversMenuView::ReceiversMenuView(NavigationView& nav) { add_items({ - { "ADS-B: Planes", ui::Color::green(),&bitmap_icon_adsb, [&nav](){ nav.push(); }, }, + { "ADS-B: Planes", ui::Color::green(), &bitmap_icon_adsb, [&nav](){ nav.push(); }, }, { "AIS: Boats", ui::Color::green(), &bitmap_icon_ais, [&nav](){ nav.push(); } }, - { "APRS", ui::Color::grey(), &bitmap_icon_aprs, [&nav](){ nav.push(); } }, + { "APRS", ui::Color::orange(),&bitmap_icon_aprs, [&nav](){ nav.push(); } }, { "Audio", ui::Color::green(), &bitmap_icon_speaker, [&nav](){ nav.push(false); } }, { "ERT: Utility Meters", ui::Color::green(), &bitmap_icon_ert, [&nav](){ nav.push(); } }, { "POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav](){ nav.push(); } }, diff --git a/firmware/baseband/CMakeLists.txt b/firmware/baseband/CMakeLists.txt index 55fccf8a..e90973f0 100644 --- a/firmware/baseband/CMakeLists.txt +++ b/firmware/baseband/CMakeLists.txt @@ -294,7 +294,14 @@ DeclareTargets(PADT adsbtx) set(MODE_CPPSRC proc_afsk.cpp ) -DeclareTargets(PAFS afsk) +DeclareTargets(PAFT afsktx) + +### AFSK RX + +set(MODE_CPPSRC + proc_afskrx.cpp +) +DeclareTargets(PAFR afskrx) ### AIS diff --git a/firmware/baseband/proc_afsk.cpp b/firmware/baseband/proc_afsk.cpp index 0f33f73d..600058d0 100644 --- a/firmware/baseband/proc_afsk.cpp +++ b/firmware/baseband/proc_afsk.cpp @@ -93,9 +93,9 @@ void AFSKProcessor::execute(const buffer_c8_t& buffer) { } void AFSKProcessor::on_message(const Message* const msg) { - const auto message = *reinterpret_cast(msg); + const auto message = *reinterpret_cast(msg); - if (message.id == Message::ID::AFSKConfigure) { + if (message.id == Message::ID::AFSKTxConfigure) { if (message.samples_per_bit) { afsk_samples_per_bit = message.samples_per_bit; afsk_phase_inc_mark = message.phase_inc_mark * AFSK_DELTA_COEF; diff --git a/firmware/baseband/proc_afskrx.cpp b/firmware/baseband/proc_afskrx.cpp index ad3e3bbb..9820a55c 100644 --- a/firmware/baseband/proc_afskrx.cpp +++ b/firmware/baseband/proc_afskrx.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek * * This file is part of PortaPack. * @@ -20,90 +21,93 @@ */ #include "proc_afskrx.hpp" -#include "sine_table.hpp" #include "portapack_shared_memory.hpp" -using namespace lpc43xx; +#include "event_m4.hpp" -void AFSKRXProcessor::execute(const buffer_c8_t& buffer) { - if( !configured ) { - return; - } - /* Called every 2048/3072000 second -- 1500Hz. */ +#include +#include + +void AFSKRxProcessor::execute(const buffer_c8_t& buffer) { + // This is called at 1500Hz + + if (!configured) return; const auto decim_0_out = decim_0.execute(buffer, dst_buffer); const auto decim_1_out = decim_1.execute(decim_0_out, dst_buffer); const auto channel_out = channel_filter.execute(decim_1_out, dst_buffer); - auto audio = demod.execute(channel_out, work_audio_buffer); + feed_channel_stats(channel_out); + + auto audio = demod.execute(channel_out, audio_buffer); - /*static uint64_t audio_present_history = 0; - const auto audio_present_now = squelch.execute(audio); - audio_present_history = (audio_present_history << 1) | (audio_present_now ? 1 : 0); - const bool audio_present = (audio_present_history != 0); -*/ - //if( !audio_present ) { - // Zero audio buffer. - /*for(size_t i=0; i 1) - audio.p[i] = 4096; + for (size_t c = 0; c < audio.count; c++) { + + const int32_t sample_int = audio.p[c] * 32768.0f; + const int32_t audio_sample = __SSAT(sample_int, 16); + + /*slicer_sr <<= 1; + slicer_sr |= (audio_sample < 0); // Do we need hysteresis ? + + // Detect transitions to adjust clock + if ((slicer_sr ^ (slicer_sr >> 1)) & 1) { + if (sphase < (0x8000u - sphase_delta_half)) + sphase += sphase_delta_eighth; else - audio.p[i] = -4096; - }*/ - //} - - //audio_hpf.execute_in_place(audio); - - for(size_t i=0; i 10) { - if (audio.p[i] > 2000) - sign = 1; - if (audio.p[i] < -2000) - sign = 0; - spur = 0; - } else { - spur++; + sphase -= sphase_delta_eighth; } - if (sign != prev_sign) { - if (freq_timer < 15) // 48 - bit = 0; - else - bit++; - freq_timer = 0; - } - prev_sign = sign; - if (freq_timer < 1000) freq_timer++; // TODO: Limit in a more intelligent way + + sphase += sphase_delta;*/ + + // Symbol time elapsed + //if (sphase >= 0x10000u) { + // sphase &= 0xFFFFu; + + rx_data <<= 1; + rx_data |= 1; + + bit_count++; + if (bit_count == 8) { + data_message.byte = rx_data; + shared_memory.application_queue.push(data_message); + bit_count = 0; + } + //} } - - if (bit_timer >= 40) { - bit_timer = 0; - // Check bit state here ! - } else { - bit_timer++; - } - - if (sc >= 600) { - sc = 0; - //AFSKDataMessage message; - //memcpy(message.data,aud,128*2); - //shared_memory.application_queue.push(message); - audc = 0; - } else { - sc++; - } - - if (audc < 4) { - memcpy(aud+(audc*32),audio.p,32*2); - audc++; - } - - audio_output.write(audio); } -void AFSKRXProcessor::data_handler( - const double data -) { - /*AFSKDataMessage message; - message.data = 'T'; - shared_memory.application_queue.push(message);*/ +void AFSKRxProcessor::on_message(const Message* const message) { + if (message->id == Message::ID::AFSKRxConfigure) + configure(*reinterpret_cast(message)); +} + +void AFSKRxProcessor::configure(const AFSKRxConfigureMessage& message) { + constexpr size_t decim_0_input_fs = baseband_fs; + constexpr size_t decim_0_output_fs = decim_0_input_fs / decim_0.decimation_factor; + + constexpr size_t decim_1_input_fs = decim_0_output_fs; + constexpr size_t decim_1_output_fs = decim_1_input_fs / decim_1.decimation_factor; + + constexpr size_t channel_filter_input_fs = decim_1_output_fs; + const size_t channel_filter_output_fs = channel_filter_input_fs / 2; + + const size_t demod_input_fs = channel_filter_output_fs; + + decim_0.configure(taps_16k0_decim_0.taps, 33554432); + decim_1.configure(taps_16k0_decim_1.taps, 131072); + channel_filter.configure(taps_16k0_channel.taps, 2); + demod.configure(demod_input_fs, 5000); + + bitrate = message.bitrate; + sphase_delta = 0x10000u * bitrate / 24000; + sphase_delta_half = sphase_delta / 2; // Just for speed + sphase_delta_eighth = sphase_delta / 8; + + configured = true; +} + +int main() { + EventDispatcher event_dispatcher { std::make_unique() }; + event_dispatcher.run(); + return 0; } diff --git a/firmware/baseband/proc_afskrx.hpp b/firmware/baseband/proc_afskrx.hpp index 8a06743c..72868a0e 100644 --- a/firmware/baseband/proc_afskrx.hpp +++ b/firmware/baseband/proc_afskrx.hpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek * * This file is part of PortaPack. * @@ -23,46 +24,59 @@ #define __PROC_AFSKRX_H__ #include "baseband_processor.hpp" +#include "baseband_thread.hpp" +#include "rssi_thread.hpp" #include "dsp_decimate.hpp" #include "dsp_demodulate.hpp" -#include "audio_output.hpp" +#include "fifo.hpp" #include "message.hpp" -class AFSKRXProcessor : public BasebandProcessor { +class AFSKRxProcessor : public BasebandProcessor { public: void execute(const buffer_c8_t& buffer) override; + void on_message(const Message* const message) override; + private: - std::array dst; + static constexpr size_t baseband_fs = 3072000; + + BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Receive }; + RSSIThread rssi_thread { NORMALPRIO + 10 }; + + std::array dst { }; const buffer_c16_t dst_buffer { dst.data(), dst.size() }; - const buffer_f32_t work_audio_buffer { - (float*)dst.data(), - sizeof(dst) / sizeof(float) + std::array audio { }; + const buffer_f32_t audio_buffer { + audio.data(), + audio.size() }; - dsp::decimate::FIRAndDecimateComplex channel_filter; - dsp::demodulate::FM demod; // 48000 5000 + // Can't use FIFO class here since it only allows power-of-two sizes + std::array delay_line { 0 }; - dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0; - dsp::decimate::FIRC16xR16x32Decim8 decim_1; + dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0 { }; + dsp::decimate::FIRC16xR16x32Decim8 decim_1 { }; + dsp::decimate::FIRAndDecimateComplex channel_filter { }; + + dsp::demodulate::FM demod { }; - AudioOutput audio_output; - - uint16_t bit_timer = 0, freq_timer = 0; - uint16_t sc; - uint8_t audc, spur, sign, prev_sign, bit = 0; - - int16_t aud[128]; - - void data_handler(const double data); + uint32_t bitrate { }; + uint32_t sphase { 0 }; + uint32_t sphase_delta { 0 }; + uint32_t sphase_delta_half { 0 }; + uint32_t sphase_delta_eighth { 0 }; + uint32_t rx_data { 0 }; + uint32_t bit_count { 0 }; bool configured { false }; - void configure(const NBFMConfigureMessage& message); + void configure(const AFSKRxConfigureMessage& message); + + AFSKDataMessage data_message { 0 }; }; #endif/*__PROC_TPMS_H__*/ diff --git a/firmware/baseband/proc_mictx.hpp b/firmware/baseband/proc_mictx.hpp index a3208d3a..0590d15d 100644 --- a/firmware/baseband/proc_mictx.hpp +++ b/firmware/baseband/proc_mictx.hpp @@ -59,7 +59,7 @@ private: int8_t re { 0 }, im { 0 }; - AudioLevelMessage level_message { }; + AudioLevelReportMessage level_message { }; TXDoneMessage txdone_message { }; }; diff --git a/firmware/common/message.hpp b/firmware/common/message.hpp index 07c9fafd..d9686c7f 100644 --- a/firmware/common/message.hpp +++ b/firmware/common/message.hpp @@ -71,12 +71,13 @@ public: CaptureThreadDone = 18, ReplayConfig = 19, ReplayThreadDone = 20, + AFSKRxConfigure = 21, TXDone = 30, Retune = 31, TonesConfigure = 32, - AFSKConfigure = 33, + AFSKTxConfigure = 33, PWMRSSIConfigure = 34, OOKConfigure = 35, RDSConfigure = 36, @@ -93,11 +94,12 @@ public: POCSAGPacket = 50, ADSBFrame = 51, + AFSKData = 52, - RequestSignal = 52, - FIFOData = 53, + RequestSignal = 60, + FIFOData = 61, - AudioLevel = 54, + AudioLevelReport = 70, MAX }; @@ -331,6 +333,18 @@ public: adsb::ADSBFrame frame; }; +class AFSKDataMessage : public Message { +public: + constexpr AFSKDataMessage( + const uint_fast8_t byte + ) : Message { ID::AFSKData }, + byte { byte } + { + } + + uint_fast8_t byte; +}; + class ShutdownMessage : public Message { public: constexpr ShutdownMessage( @@ -598,7 +612,17 @@ public: bool done = false; }; - +class AFSKRxConfigureMessage : public Message { +public: + constexpr AFSKRxConfigureMessage( + const uint32_t bitrate + ) : Message { ID::AFSKRxConfigure }, + bitrate(bitrate) + { + } + + const uint32_t bitrate; +}; class PWMRSSIConfigureMessage : public Message { public: @@ -665,10 +689,10 @@ public: uint32_t range = 0; }; -class AudioLevelMessage : public Message { +class AudioLevelReportMessage : public Message { public: - constexpr AudioLevelMessage( - ) : Message { ID::AudioLevel } + constexpr AudioLevelReportMessage( + ) : Message { ID::AudioLevelReport } { } @@ -729,16 +753,16 @@ public: const uint32_t tone_delta; }; -class AFSKConfigureMessage : public Message { +class AFSKTxConfigureMessage : public Message { public: - constexpr AFSKConfigureMessage( + constexpr AFSKTxConfigureMessage( const uint32_t samples_per_bit, const uint32_t phase_inc_mark, const uint32_t phase_inc_space, const uint8_t repeat, const uint32_t fm_delta, const uint8_t symbol_count - ) : Message { ID::AFSKConfigure }, + ) : Message { ID::AFSKTxConfigure }, samples_per_bit(samples_per_bit), phase_inc_mark(phase_inc_mark), phase_inc_space(phase_inc_space), diff --git a/firmware/common/spi_image.hpp b/firmware/common/spi_image.hpp index b955f1ee..2c6282f1 100644 --- a/firmware/common/spi_image.hpp +++ b/firmware/common/spi_image.hpp @@ -64,6 +64,7 @@ private: }; constexpr image_tag_t image_tag_adsb_rx { 'P', 'A', 'D', 'R' }; +constexpr image_tag_t image_tag_afsk_rx { 'P', 'A', 'F', 'R' }; constexpr image_tag_t image_tag_ais { 'P', 'A', 'I', 'S' }; constexpr image_tag_t image_tag_am_audio { 'P', 'A', 'M', 'A' }; constexpr image_tag_t image_tag_capture { 'P', 'C', 'A', 'P' }; @@ -76,7 +77,7 @@ constexpr image_tag_t image_tag_wideband_spectrum { 'P', 'S', 'P', 'E' }; constexpr image_tag_t image_tag_jammer { 'P', 'J', 'A', 'M' }; constexpr image_tag_t image_tag_audio_tx { 'P', 'A', 'T', 'X' }; -constexpr image_tag_t image_tag_afsk { 'P', 'A', 'F', 'S' }; +constexpr image_tag_t image_tag_afsk { 'P', 'A', 'F', 'T' }; constexpr image_tag_t image_tag_tones { 'P', 'T', 'O', 'N' }; constexpr image_tag_t image_tag_rds { 'P', 'R', 'D', 'S' }; constexpr image_tag_t image_tag_ook { 'P', 'O', 'O', 'K' };