AFSK RX works (only Bell202 for now)

AFSK RX always logs to file
Removed frequency and bw settings from modem setup view
Updated binary
Bugfix: Binary display shifted one bit
Bugfix: Frequency manager views freezing if SD card not present
Bugfix: Menuview blinking arrow not showing up at the right position
Bugfix: Freeze if console written to while it's hidden
Broken: LCR TX, needs UI update
This commit is contained in:
furrtek 2017-09-02 08:28:29 +01:00
parent 42439d1885
commit 950bc2b1d2
29 changed files with 428 additions and 206 deletions

View File

@ -117,9 +117,12 @@ void set_sstv_data(const uint8_t vis_code, const uint32_t pixel_duration) {
send_message(&message);
}
void set_afsk(const uint32_t bitrate) {
void set_afsk(const uint32_t baudrate, const uint32_t word_length, const uint32_t trigger_value, const bool trigger_word) {
const AFSKRxConfigureMessage message {
bitrate
baudrate,
word_length,
trigger_value,
trigger_word
};
send_message(&message);
}

View File

@ -67,7 +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_afsk(const uint32_t baudrate, const uint32_t word_length, const uint32_t trigger_value, const bool trigger_word);
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,

View File

@ -32,6 +32,8 @@
//BUG: SCANNER Lock on frequency, if frequency jump, still locked on first one
//BUG: SCANNER Multiple slices
//TODO: Frequency and bw settings were removed from modemsetup, put those back in LCR TX
//TODO: Use separate thread for scanning in LCR TX
//TODO: REPLAY Convert C16 to C8 on M0 core
//TODO: Use TabView
//TODO: De bruijn sequence scanner for encoders

View File

@ -79,4 +79,41 @@ void generate_data(const std::string& in_message, uint16_t * out_data) {
out_data[bytes] = 0; // End marker
}
// This accepts a word with start and stop bits removed !
uint32_t deframe_word(uint32_t raw_word) {
serial_format_t serial_format;
uint32_t parity, cur_bit, deframed_word { 0 };
size_t bit, bits;
serial_format = persistent_memory::serial_format();
/*if (serial_format.parity == ODD)
parity = 1;
else
parity = 0;*/
bits = serial_format.data_bits;
// Ignore parity for now
if (serial_format.parity)
raw_word >>= 1;
if (serial_format.bit_order == LSB_FIRST) {
// Reverse data bits
for (bit = 0; bit < bits; bit++) {
cur_bit = raw_word & 1;
deframed_word <<= 1;
deframed_word |= cur_bit;
//parity += cur_bit;
raw_word >>= 1;
}
return deframed_word;
} else
return raw_word;
}
} /* namespace modems */

View File

@ -31,16 +31,16 @@ namespace modems {
#define MODEM_DEF_COUNT 7
enum modulation_enum {
enum ModemModulation {
AFSK = 0,
FSK,
PSK,
SSB
AM // SSB
};
struct modem_def_t {
std::string name;
modulation_enum modulation;
ModemModulation modulation;
uint16_t mark_freq;
uint16_t space_freq;
uint16_t baudrate;
@ -52,11 +52,12 @@ const modem_def_t modem_defs[MODEM_DEF_COUNT] = {
{ "V21", AFSK, 980, 1180, 300 },
{ "V23 M1", AFSK, 1300, 1700, 600 },
{ "V23 M2", AFSK, 1300, 2100, 1200 },
{ "RTTY US", SSB, 2295, 2125, 45 },
{ "RTTY EU", SSB, 2125, 1955, 45 }
{ "RTTY US", AM, 2295, 2125, 45 },
{ "RTTY EU", AM, 2125, 1955, 45 }
};
void generate_data(const std::string& in_message, uint16_t * out_data);
uint32_t deframe_word(uint32_t raw_word);
} /* namespace modems */

View File

@ -23,8 +23,6 @@
#include "pocsag_app.hpp"
#include "baseband_api.hpp"
#include "portapack.hpp"
#include "portapack_persistent_memory.hpp"
using namespace portapack;

View File

@ -39,11 +39,8 @@ namespace serializer {
* Diff M.: ...
*/
uint8_t symbol_count() {
serial_format_t serial_format;
uint8_t count;
serial_format = persistent_memory::serial_format();
size_t symbol_count(const serial_format_t& serial_format) {
size_t count;
count = 1 + serial_format.data_bits; // Start
if (serial_format.parity) count++;

View File

@ -21,16 +21,14 @@
*/
#include "ui.hpp"
#include <cstring>
#include <string>
#include "portapack_persistent_memory.hpp"
#ifndef __SERIALIZER_H__
#define __SERIALIZER_H__
namespace serializer {
uint8_t symbol_count();
enum parity_enum : uint8_t {
NONE = 0,
EVEN = 1,
@ -49,6 +47,8 @@ struct serial_format_t {
order_enum bit_order;
};
size_t symbol_count(const serial_format_t& serial_format);
/*{ "7-Even-1 R", "7E1", 7, EVEN, 1, false, false },
{ "7E1 LUT ", "7Ea", 7, EVEN, 1, true, true },
{ "7-Odd-1 ", "7o1", 7, ODD, 1, true, false },

View File

@ -61,7 +61,7 @@ std::string to_string_bin(
{
char p[33];
for (uint8_t c = 0; c < l; c++) {
if (n & (1 << (l - c)))
if (n & (1 << (l - 1 - c)))
p[c] = '1';
else
p[c] = '0';

View File

@ -25,13 +25,9 @@
#include "rtc_time.hpp"
#include "string_format.hpp"
#include "portapack.hpp"
#include "baseband_api.hpp"
#include "portapack_persistent_memory.hpp"
#include <cstring>
#include <stdio.h>
using namespace portapack;
namespace ui {

View File

@ -21,11 +21,24 @@
*/
#include "ui_afsk_rx.hpp"
#include "baseband_api.hpp"
#include "ui_modemsetup.hpp"
//#include "string_format.hpp"
#include "modems.hpp"
#include "audio.hpp"
#include "rtc_time.hpp"
#include "baseband_api.hpp"
#include "string_format.hpp"
#include "portapack_persistent_memory.hpp"
using namespace portapack;
using namespace modems;
void AFSKLogger::log_raw_data(const std::string& data) {
rtc::RTC datetime;
rtcGetTime(&RTCD1, &datetime);
log_file.write_entry(datetime, data);
}
namespace ui {
@ -37,10 +50,6 @@ 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);
@ -51,16 +60,24 @@ AFSKRxView::AFSKRxView(NavigationView& nav) {
&field_lna,
&field_vga,
&field_frequency,
&options_bitrate,
&text_debug,
&button_modem_setup,
&console
});
//receiver_model.set_sampling_rate(3072000);
//receiver_model.set_baseband_bandwidth(1750000);
//receiver_model.enable();
// Auto-configure modem for LCR RX (will be removed later)
update_freq(462713300); // 162950000
auto def_bell202 = &modem_defs[0];
persistent_memory::set_modem_baudrate(def_bell202->baudrate);
serial_format_t serial_format;
serial_format.data_bits = 7;
serial_format.parity = EVEN;
serial_format.stop_bits = 1;
serial_format.bit_order = LSB_FIRST;
persistent_memory::set_serial_format(serial_format);
field_frequency.set_value(receiver_model.tuning_frequency());
field_frequency.set_step(receiver_model.frequency_step());
field_frequency.set_step(100);
field_frequency.on_change = [this](rf::Frequency f) {
update_freq(f);
};
@ -72,19 +89,69 @@ AFSKRxView::AFSKRxView(NavigationView& nav) {
field_frequency.set_value(f);
};
};
options_bitrate.on_change = [this](size_t, OptionsField::value_t v) {
on_bitrate_changed(v);
button_modem_setup.on_select = [&nav](Button&) {
nav.push<ModemSetupView>();
};
options_bitrate.set_selected_index(1); // 1200bps
logger = std::make_unique<AFSKLogger>();
if (logger)
logger->append("AFSK_LOG.TXT");
// Auto-configure modem for LCR RX (will be removed later)
baseband::set_afsk(persistent_memory::modem_baudrate(), 8, 0, false);
audio::set_rate(audio::Rate::Hz_24000);
audio::output::start();
receiver_model.set_sampling_rate(3072000);
receiver_model.set_baseband_bandwidth(1750000);
receiver_model.enable();
}
void AFSKRxView::on_data(uint_fast8_t byte) {
std::string str_byte(1, byte);
console.write(str_byte);
void AFSKRxView::on_data(uint32_t value, bool is_data) {
std::string str_byte = "\x1B";
str_byte += (char)((console_color & 3) + 9);
if (is_data) {
//value = deframe_word(value);
value &= 0xFF; // ABCDEFGH
value = ((value & 0xF0) >> 4) | ((value & 0x0F) << 4); // EFGHABCD
value = ((value & 0xCC) >> 2) | ((value & 0x33) << 2); // GHEFCDAB
value = ((value & 0xAA) >> 1) | ((value & 0x55) << 1); // HGFEDCBA
value &= 0x7F;
if ((value >= 32) && (value < 127))
str_byte += (char)value ; // Printable
else
str_byte += "[" + to_string_hex(value, 2) + "]"; // Not printable
//str_byte = to_string_bin(value & 0xFF, 8) + " ";
console.write(str_byte);
if (logger) str_log += str_byte;
if ((value != 0x7F) && (prev_value == 0x7F)) {
console.writeln("");
console_color++;
if (logger) {
logger->log_raw_data(str_log);
str_log = "";
}
}
prev_value = value;
} else {
// Baudrate estimation
text_debug.set("~" + to_string_dec_uint(value));
}
}
AFSKRxView::~AFSKRxView() {
audio::output::stop();
receiver_model.disable();
baseband::shutdown();
}

View File

@ -26,9 +26,22 @@
#include "ui.hpp"
#include "ui_navigation.hpp"
#include "ui_receiver.hpp"
#include "ui_widget.hpp"
#include "log_file.hpp"
#include "utility.hpp"
class AFSKLogger {
public:
Optional<File::Error> append(const std::string& filename) {
return log_file.append(filename);
}
void log_raw_data(const std::string& data);
private:
LogFile log_file { };
};
namespace ui {
class AFSKRxView : public View {
@ -41,7 +54,11 @@ public:
std::string title() const override { return "AFSK RX (beta)"; };
private:
void on_data(uint_fast8_t byte);
void on_data(uint32_t value, bool is_data);
uint8_t console_color { 0 };
uint32_t prev_value { 0 };
std::string str_log { "" };
RFAmpField field_rf_amp {
{ 13 * 8, 0 * 16 }
@ -60,33 +77,34 @@ private:
};
FrequencyField field_frequency {
{ 0 * 8, 0 * 8 },
{ 0 * 8, 0 * 16 },
};
OptionsField options_bitrate {
{ 12 * 8, 21 },
7,
{
{ "600bps ", 600 },
{ "1200bps", 1200 },
{ "2400bps", 2400 }
}
Text text_debug {
{ 0 * 8, 1 * 16, 10 * 8, 16 },
"DEBUG"
};
Button button_modem_setup {
{ 12 * 8, 1 * 16, 96, 24 },
"Modem setup"
};
Console console {
{ 0, 4 * 16, 240, 240 }
{ 0, 3 * 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);
std::unique_ptr<AFSKLogger> logger { };
MessageHandlerRegistration message_handler_packet {
Message::ID::AFSKData,
[this](Message* const p) {
const auto message = static_cast<const AFSKDataMessage*>(p);
this->on_data(message->byte);
this->on_data(message->value, message->is_data);
}
};
};

View File

@ -177,7 +177,7 @@ private:
void start_tx(const bool scan);
void on_txdone(int n, const bool txdone);
const Style style_address {
/*const Style style_address {
.font = font::fixed_8x16,
.background = Color::black(),
.foreground = Color::red(),
@ -186,7 +186,7 @@ private:
.font = font::fixed_8x16,
.background = Color::black(),
.foreground = Color::blue(),
};
};*/
Rect view_rect = { 0, 4 * 8, 240, 168 };

View File

@ -30,31 +30,28 @@ using namespace portapack;
namespace ui {
FreqManBaseView::FreqManBaseView(
NavigationView& nav,
Widget& default_focus_widget
) : nav_ (nav),
default_focus_widget_ (default_focus_widget)
NavigationView& nav
) : nav_ (nav)
{
file_list = get_freqman_files();
if (!file_list.size()) {
if (!file_list.size())
error_ = ERROR_NOFILES;
return;
}
add_children({
&label_category,
&options_category,
&button_exit
});
// Populate categories OptionsField
populate_categories();
if (file_list.size()) {
add_child(&options_category);
populate_categories();
}
// Default function
on_change_category = [this](int32_t category_id) {
change_category(category_id);
};
//change_category(0);
button_exit.on_select = [this, &nav](Button&) {
nav.pop();
@ -62,26 +59,21 @@ FreqManBaseView::FreqManBaseView(
};
void FreqManBaseView::focus() {
/*if (error_ == ERROR_ACCESS) {
nav_.display_modal("Error", "File acces error", ABORT, nullptr);
} else if (error_ == ERROR_DUPLICATE) {
nav_.display_modal("Error", "Frequency already saved", INFO, nullptr);
error_ = NO_ERROR;
}*/
button_exit.focus();
if (error_ == ERROR_NOFILES) {
if (error_ == ERROR_ACCESS) {
nav_.display_modal("Error", "File acces error", ABORT, nullptr);
} else if (error_ == ERROR_NOFILES) {
nav_.display_modal("Error", "No database files", ABORT, nullptr);
} else {
default_focus_widget_.focus();
options_category.focus();
}
}
bool FreqManBaseView::populate_categories() {
size_t n;
categories.clear();
for (n = 0; n < file_list.size(); n++)
for (size_t n = 0; n < file_list.size(); n++)
categories.emplace_back(std::make_pair(file_list[n], n));
options_category.set_options(categories);
@ -96,10 +88,13 @@ bool FreqManBaseView::populate_categories() {
}
void FreqManBaseView::change_category(int32_t category_id) {
if (!file_list.size()) return;
current_category_id = category_id;
if (!load_freqman_file(file_list[current_category_id], database))
error_ = ERROR_ACCESS; // Todo
error_ = ERROR_ACCESS;
else
refresh_list();
}
@ -158,7 +153,7 @@ FrequencySaveView::~FrequencySaveView() {
FrequencySaveView::FrequencySaveView(
NavigationView& nav,
const rf::Frequency value
) : FreqManBaseView(nav, options_category),
) : FreqManBaseView(nav),
value_ (value)
{
desc_buffer.reserve(28);
@ -204,7 +199,7 @@ void FrequencyLoadView::refresh_widgets(const bool v) {
FrequencyLoadView::FrequencyLoadView(
NavigationView& nav
) : FreqManBaseView(nav, options_category)
) : FreqManBaseView(nav)
{
on_refresh_widgets = [this](bool v) {
refresh_widgets(v);
@ -278,7 +273,7 @@ FrequencyManagerView::~FrequencyManagerView() {
FrequencyManagerView::FrequencyManagerView(
NavigationView& nav
) : FreqManBaseView(nav, options_category)
) : FreqManBaseView(nav)
{
on_refresh_widgets = [this](bool v) {
refresh_widgets(v);

View File

@ -35,7 +35,7 @@ namespace ui {
class FreqManBaseView : public View {
public:
FreqManBaseView(
NavigationView& nav, Widget& default_focus_widget
NavigationView& nav
);
void focus() override;
@ -48,7 +48,6 @@ protected:
NavigationView& nav_;
freqman_error error_ { NO_ERROR };
Widget& default_focus_widget_;
options_t categories { };
std::function<void(int32_t category_id)> on_change_category { nullptr };
std::function<void(void)> on_select_frequency { nullptr };

View File

@ -23,15 +23,12 @@
#include "ui_lcr.hpp"
#include "ui_modemsetup.hpp"
#include "modems.hpp"
#include "lcr.hpp"
#include "modems.hpp"
#include "baseband_api.hpp"
#include "string_format.hpp"
#include "portapack_persistent_memory.hpp"
#include <cstring>
#include <stdio.h>
#include "serializer.hpp"
using namespace portapack;
@ -47,7 +44,6 @@ LCRView::~LCRView() {
}
void LCRView::paint(Painter& painter) {
size_t i;
std::string final_str;
static constexpr Style style_orange {
@ -61,7 +57,7 @@ void LCRView::paint(Painter& painter) {
static_cast<Coord>(68)
};
for (i = 0; i < 5; i++) {
for (size_t i = 0; i < 5; i++) {
painter.draw_string(
screen_pos() + offset,
style_orange,
@ -181,7 +177,7 @@ void LCRView::start_tx(const bool scan) {
persistent_memory::afsk_space_freq(),
repeats,
persistent_memory::modem_bw(),
serializer::symbol_count()
serializer::symbol_count(persistent_memory::serial_format())
);
}
@ -201,7 +197,7 @@ LCRView::LCRView(NavigationView& nav) {
&text_recap,
&options_ec,
&button_setrgsb,
&button_txsetup,
&button_modem_setup,
&text_status,
&progress,
&button_transmit,
@ -266,7 +262,7 @@ LCRView::LCRView(NavigationView& nav) {
text_prompt(nav, &rgsb, 4);
};
button_txsetup.on_select = [&nav](Button&) {
button_modem_setup.on_select = [&nav](Button&) {
nav.push<ModemSetupView>();
};
@ -294,11 +290,9 @@ LCRView::LCRView(NavigationView& nav) {
};
button_clear.on_select = [this, &nav](Button&) {
size_t n;
if (tx_mode == IDLE) {
options_ec.set_selected_index(0); // Auto
for (n = 0; n < 5; n++) {
for (size_t n = 0; n < 5; n++) {
litteral[n] = " ";
checkboxes[n].set_value(true);
}

View File

@ -134,7 +134,7 @@ private:
{ 8, 24, 80, 32 },
"RGSB"
};
Button button_txsetup {
Button button_modem_setup {
{ 13 * 8, 24, 128, 32 },
"Modem setup"
};

View File

@ -93,10 +93,7 @@ MenuView::MenuView(
bool keep_highlight
) : keep_highlight_ { keep_highlight }
{
View::set_parent_rect(new_parent_rect);
displayed_max_ = (parent_rect().size().height() / 24);
arrow_more.set_parent_rect( { 228, (Coord)(displayed_max_ * item_height), 8, 8 } );
set_parent_rect(new_parent_rect);
set_focusable(true);
@ -116,6 +113,14 @@ MenuView::~MenuView() {
}
}
void MenuView::set_parent_rect(const Rect new_parent_rect) {
View::set_parent_rect(new_parent_rect);
displayed_max_ = (parent_rect().size().height() / 24);
arrow_more.set_parent_rect( { 228, (Coord)(displayed_max_ * item_height), 8, 8 } );
}
void MenuView::on_tick_second() {
if (more_ && blink_)
arrow_more.set_foreground(Color::white());

View File

@ -84,11 +84,11 @@ public:
size_t highlighted() const;
bool set_highlighted(int32_t new_value);
void set_parent_rect(const Rect new_parent_rect) override;
void on_focus() override;
void on_blur() override;
bool on_key(const KeyEvent event) override;
bool on_encoder(const EncoderEvent event) override;
private:
void update_items();

View File

@ -29,42 +29,36 @@
#include "portapack_shared_memory.hpp"
#include "portapack_persistent_memory.hpp"
#include <cstring>
#include <stdio.h>
using namespace portapack;
using namespace modems;
namespace ui {
void ModemSetupView::focus() {
button_setfreq.focus();
field_baudrate.focus();
}
void ModemSetupView::update_freq(rf::Frequency f) {
/*void ModemSetupView::update_freq(rf::Frequency f) {
persistent_memory::set_tuned_frequency(f);
button_setfreq.set_text(to_string_short_freq(f));
}
}*/
ModemSetupView::ModemSetupView(
NavigationView& nav
)
{
using name_t = std::string;
using value_t = int32_t;
using option_t = std::pair<name_t, value_t>;
using option_t = std::pair<std::string, int32_t>;
using options_t = std::vector<option_t>;
options_t modem_options;
size_t i;
add_children({
&labels,
&button_setfreq,
//&button_setfreq,
&field_baudrate,
&field_mark,
&field_space,
&field_bw,
//&field_bw,
&field_repeat,
&options_modem,
&button_set_modem,
@ -72,11 +66,10 @@ ModemSetupView::ModemSetupView(
&button_save
});
for (i = 0; i < MODEM_DEF_COUNT; i++) {
for (size_t i = 0; i < MODEM_DEF_COUNT; i++) {
if (modem_defs[i].modulation == AFSK)
modem_options.emplace_back(std::make_pair(modem_defs[i].name, i));
}
options_modem.set_options(modem_options);
options_modem.set_selected_index(0);
@ -90,19 +83,19 @@ ModemSetupView::ModemSetupView(
sym_format.set_sym(2, persistent_memory::serial_format().stop_bits);
sym_format.set_sym(3, persistent_memory::serial_format().bit_order);
update_freq(persistent_memory::tuned_frequency());
//update_freq(persistent_memory::tuned_frequency());
field_mark.set_value(persistent_memory::afsk_mark_freq());
field_space.set_value(persistent_memory::afsk_space_freq());
field_bw.set_value(persistent_memory::modem_bw() / 1000);
//field_bw.set_value(persistent_memory::modem_bw() / 1000);
field_repeat.set_value(persistent_memory::modem_repeat());
button_setfreq.on_select = [this, &nav](Button&) {
/*button_setfreq.on_select = [this, &nav](Button&) {
auto new_view = nav.push<FrequencyKeypadView>(persistent_memory::tuned_frequency());
new_view->on_changed = [this](rf::Frequency f) {
update_freq(f);
};
};
};*/
field_baudrate.set_value(persistent_memory::modem_baudrate());
@ -121,7 +114,7 @@ ModemSetupView::ModemSetupView(
persistent_memory::set_afsk_space(field_space.value());
persistent_memory::set_modem_baudrate(field_baudrate.value());
persistent_memory::set_modem_bw(field_bw.value() * 1000);
//persistent_memory::set_modem_bw(field_bw.value() * 1000);
persistent_memory::set_modem_repeat(field_repeat.value());
serial_format.data_bits = sym_format.get_sym(0) + 6;

View File

@ -41,23 +41,23 @@ private:
void update_freq(rf::Frequency f);
Labels labels {
{ { 2 * 8, 4 * 8 }, "Frequency:", Color::light_grey() },
{ { 2 * 8, 11 * 8 }, "Speed: Bps", Color::light_grey() },
//{ { 2 * 8, 4 * 8 }, "Frequency:", Color::light_grey() },
{ { 2 * 8, 11 * 8 }, "Baudrate:", Color::light_grey() },
{ { 2 * 8, 13 * 8 }, "Mark: Hz", Color::light_grey() },
{ { 2 * 8, 15 * 8 }, "Space: Hz", Color::light_grey() },
{ { 140, 13 * 8 }, "BW: kHz", Color::light_grey() },
//{ { 140, 13 * 8 }, "BW: kHz", Color::light_grey() },
{ { 140, 15 * 8 }, "Repeat:", Color::light_grey() },
{ { 2 * 8, 19 * 8 }, "Modem preset:", Color::light_grey() },
{ { 1 * 8, 6 * 8 }, "Modem preset:", Color::light_grey() },
{ { 2 * 8, 22 * 8 }, "Serial format:", Color::light_grey() }
};
Button button_setfreq {
/*Button button_setfreq {
{ 13 * 8, 3 * 8, 12 * 8, 32 },
"----.----"
};
};*/
NumberField field_baudrate {
{ 64, 88 },
{ 11 * 8, 11 * 8 },
5,
{ 50, 9600 },
25,
@ -65,7 +65,7 @@ private:
};
NumberField field_mark {
{ 64, 104 },
{ 8 * 8, 13 * 8 },
5,
{ 100, 15000 },
25,
@ -73,23 +73,23 @@ private:
};
NumberField field_space {
{ 64, 120 },
{ 8 * 8, 15 * 8 },
5,
{ 100, 15000 },
25,
' '
};
NumberField field_bw {
/*NumberField field_bw {
{ 172, 104 },
2,
{ 1, 50 },
1,
' '
};
};*/
NumberField field_repeat {
{ 204, 120 },
{ 204, 15 * 8 },
2,
{ 1, 99 },
1,
@ -97,7 +97,7 @@ private:
};
OptionsField options_modem {
{ 16 * 8, 19 * 8 },
{ 15 * 8, 6 * 8 },
7,
{
}
@ -110,12 +110,12 @@ private:
};
Button button_set_modem {
{ 24 * 8, 19 * 8 - 4, 5 * 8, 24 },
{ 23 * 8, 6 * 8 - 4, 6 * 8, 24 },
"SET"
};
Button button_save {
{ 72, 250, 96, 40 },
{ 9 * 8, 250, 96, 40 },
"Save"
};
};

View File

@ -285,7 +285,8 @@ ReceiversMenuView::ReceiversMenuView(NavigationView& nav) {
add_items({
{ "ADS-B: Planes", ui::Color::green(), &bitmap_icon_adsb, [&nav](){ nav.push<ADSBRxView>(); }, },
{ "AIS: Boats", ui::Color::green(), &bitmap_icon_ais, [&nav](){ nav.push<AISAppView>(); } },
{ "APRS", ui::Color::orange(),&bitmap_icon_aprs, [&nav](){ nav.push<AFSKRxView>(); } },
{ "AFSK", ui::Color::yellow(),&bitmap_icon_receivers, [&nav](){ nav.push<AFSKRxView>(); } },
{ "APRS", ui::Color::grey(), &bitmap_icon_aprs, [&nav](){ nav.push<NotImplementedView>(); } },
{ "Audio", ui::Color::green(), &bitmap_icon_speaker, [&nav](){ nav.push<AnalogAudioView>(false); } },
{ "ERT: Utility Meters", ui::Color::green(), &bitmap_icon_ert, [&nav](){ nav.push<ERTAppView>(); } },
{ "POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav](){ nav.push<POCSAGAppView>(); } },
@ -295,7 +296,7 @@ ReceiversMenuView::ReceiversMenuView(NavigationView& nav) {
{ "TPMS: Cars", ui::Color::green(), &bitmap_icon_tpms, [&nav](){ nav.push<TPMSAppView>(); } },
});
on_left = [&nav](){ nav.pop(); };
//set_highlighted(3); // Default selection is "Audio"
//set_highlighted(4); // Default selection is "Audio"
}
/* TransmittersMenuView **************************************************/

View File

@ -25,54 +25,119 @@
#include "event_m4.hpp"
#include <cstdint>
#include <cstddef>
void AFSKRxProcessor::execute(const buffer_c8_t& buffer) {
// This is called at 1500Hz
// This is called at 3072000 / 2048 = 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);
// FM demodulation
const auto decim_0_out = decim_0.execute(buffer, dst_buffer); // 2048 / 8 = 256 (512 I/Q samples)
const auto decim_1_out = decim_1.execute(decim_0_out, dst_buffer); // 256 / 8 = 32 (64 I/Q samples)
const auto channel_out = channel_filter.execute(decim_1_out, dst_buffer); // 32 / 2 = 16 (32 I/Q samples)
feed_channel_stats(channel_out);
auto audio = demod.execute(channel_out, audio_buffer);
audio_output.write(audio);
// Audio signal processing
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);
int32_t current_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;
current_sample /= 128;
// Delay line put
delay_line[delay_line_index & 0x3F] = current_sample;
// Delay line get, and LPF
sample_mixed = (delay_line[(delay_line_index - (samples_per_bit/2)) & 0x3F] * current_sample) / 4;
sample_filtered = prev_mixed + sample_mixed + (prev_filtered / 2);
delay_line_index++;
prev_filtered = sample_filtered;
prev_mixed = sample_mixed;
// Slice
sample_bits <<= 1;
sample_bits |= (sample_filtered < -20) ? 1 : 0;
// Check for "clean" transition: either 0011 or 1100
if ((((sample_bits >> 2) ^ sample_bits) & 3) == 3) {
// Adjust phase
if (phase < 0x8000)
phase += 0x800; // Is this a proper value ?
else
sphase -= sphase_delta_eighth;
phase -= 0x800;
}
sphase += sphase_delta;*/
phase += phase_inc;
// Symbol time elapsed
//if (sphase >= 0x10000u) {
// sphase &= 0xFFFFu;
if (phase >= 0x10000) {
phase &= 0xFFFF;
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 (trigger_word) {
// Continuous-stream value-triggered mode (AX.25) - UNTESTED
word_bits <<= 1;
word_bits |= (sample_bits & 1);
bit_counter++;
if (triggered) {
if (bit_counter == word_length) {
bit_counter = 0;
data_message.is_data = true;
data_message.value = word_bits & word_mask;
shared_memory.application_queue.push(data_message);
}
} else {
if ((word_bits & word_mask) == trigger_value) {
triggered = !triggered;
bit_counter = 0;
data_message.is_data = true;
data_message.value = trigger_value;
shared_memory.application_queue.push(data_message);
}
}
} else {
// RS232-like modem mode
if (state == WAIT_START) {
if (!(sample_bits & 1)) {
// Got start bit
state = RECEIVE;
bit_counter = 0;
}
} else if (state == WAIT_STOP) {
if (sample_bits & 1) {
// Got stop bit
state = WAIT_START;
}
} else {
word_bits <<= 1;
word_bits |= (sample_bits & 1);
bit_counter++;
}
if (bit_counter == word_length) {
bit_counter = 0;
state = WAIT_STOP;
data_message.is_data = true;
data_message.value = word_bits;
shared_memory.application_queue.push(data_message);
}
}
//}
}
}
}
@ -82,26 +147,39 @@ void AFSKRxProcessor::on_message(const Message* const message) {
}
void AFSKRxProcessor::configure(const AFSKRxConfigureMessage& message) {
constexpr size_t decim_0_input_fs = baseband_fs;
/*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);
const size_t demod_input_fs = channel_filter_output_fs;*/
bitrate = message.bitrate;
sphase_delta = 0x10000u * bitrate / 24000;
sphase_delta_half = sphase_delta / 2; // Just for speed
sphase_delta_eighth = sphase_delta / 8;
decim_0.configure(taps_11k0_decim_0.taps, 33554432);
decim_1.configure(taps_11k0_decim_1.taps, 131072);
channel_filter.configure(taps_11k0_channel.taps, 2);
demod.configure(audio_fs, 5000);
audio_output.configure(audio_24k_hpf_300hz_config, audio_24k_deemph_300_6_config, 0);
samples_per_bit = audio_fs / message.baudrate;
phase_inc = (0x10000 * message.baudrate) / audio_fs;
phase = 0;
trigger_word = message.trigger_word;
word_length = message.word_length;
trigger_value = message.trigger_value;
word_mask = (1 << word_length) - 1;
// Delay line
delay_line_index = 0;
triggered = false;
state = WAIT_START;
configured = true;
}

View File

@ -30,6 +30,8 @@
#include "dsp_decimate.hpp"
#include "dsp_demodulate.hpp"
#include "audio_output.hpp"
#include "fifo.hpp"
#include "message.hpp"
@ -41,6 +43,15 @@ public:
private:
static constexpr size_t baseband_fs = 3072000;
static constexpr size_t audio_fs = baseband_fs / 8 / 8 / 2;
size_t samples_per_bit { };
enum State {
WAIT_START = 0,
WAIT_STOP,
RECEIVE
};
BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Receive };
RSSIThread rssi_thread { NORMALPRIO + 10 };
@ -56,27 +67,37 @@ private:
audio.size()
};
// Can't use FIFO class here since it only allows power-of-two sizes
std::array<int32_t, 24000/1200> delay_line { 0 };
// Array size ok down to 375 bauds (24000 / 375)
std::array<int32_t, 64> delay_line { 0 };
dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0 { };
dsp::decimate::FIRC16xR16x32Decim8 decim_1 { };
dsp::decimate::FIRAndDecimateComplex channel_filter { };
dsp::demodulate::FM demod { };
AudioOutput audio_output { };
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 };
State state { };
size_t delay_line_index { };
uint32_t bit_counter { 0 };
uint32_t word_bits { 0 };
uint32_t sample_bits { 0 };
uint32_t phase { }, phase_inc { };
int32_t sample_mixed { }, prev_mixed { }, sample_filtered { }, prev_filtered { };
uint32_t word_length { };
uint32_t word_mask { };
uint32_t trigger_value { };
bool configured { false };
bool wait_start { };
bool bit_value { };
bool trigger_word { };
bool triggered { };
void configure(const AFSKRxConfigureMessage& message);
AFSKDataMessage data_message { 0 };
AFSKDataMessage data_message { false, 0 };
};
#endif/*__PROC_TPMS_H__*/

View File

@ -336,13 +336,16 @@ public:
class AFSKDataMessage : public Message {
public:
constexpr AFSKDataMessage(
const uint_fast8_t byte
const bool is_data,
const uint32_t value
) : Message { ID::AFSKData },
byte { byte }
is_data { is_data },
value { value }
{
}
uint_fast8_t byte;
bool is_data;
uint32_t value;
};
class ShutdownMessage : public Message {
@ -615,13 +618,22 @@ public:
class AFSKRxConfigureMessage : public Message {
public:
constexpr AFSKRxConfigureMessage(
const uint32_t bitrate
const uint32_t baudrate,
const uint32_t word_length,
const uint32_t trigger_value,
const bool trigger_word
) : Message { ID::AFSKRxConfigure },
bitrate(bitrate)
baudrate(baudrate),
word_length(word_length),
trigger_value(trigger_value),
trigger_word(trigger_word)
{
}
const uint32_t bitrate;
const uint32_t baudrate;
const uint32_t word_length;
const uint32_t trigger_value;
const bool trigger_word;
};
class PWMRSSIConfigureMessage : public Message {

View File

@ -26,7 +26,6 @@
#include <cstdint>
#include <cstddef>
#include "portapack_shared_memory.hpp"
#include "message_queue.hpp"
struct JammerChannel {

View File

@ -538,7 +538,7 @@ void Console::clear() {
void Console::write(std::string message) {
bool escape = false;
if (visible) {
if (!hidden() && visible()) {
const Style& s = style();
const Font& font = s.font;
const auto rect = screen_rect();
@ -546,7 +546,10 @@ void Console::write(std::string message) {
for (const auto c : message) {
if (escape) {
pen_color = term_colors[c & 7];
if (c <= 15)
pen_color = term_colors[c & 15];
else
pen_color = s.foreground;
escape = false;
} else {
if (c == '\n') {
@ -570,7 +573,7 @@ void Console::write(std::string message) {
}
buffer = message;
} else {
buffer += message;
if (buffer.size() < 256) buffer += message;
}
}
@ -588,7 +591,7 @@ void Console::on_show() {
display.scroll_set_area(screen_r.top(), screen_r.bottom());
display.scroll_set_position(0);
clear();
visible = true;
//visible = true;
}
void Console::on_hide() {
@ -596,9 +599,12 @@ void Console::on_hide() {
* position?
*/
display.scroll_disable();
//visible = false;
}
void Console::crlf() {
if (hidden() || !visible()) return;
const Style& s = style();
const auto sr = screen_rect();
const auto line_height = s.font.line_height();

View File

@ -289,7 +289,7 @@ public:
void on_hide() override;
private:
bool visible = false;
//bool visible = false;
Point pos { 0, 0 };
std::string buffer { };

Binary file not shown.