POCSAG RX saves ignored address

Made AFSK code more generic (not tied to LCR)
Added modem presets and more options in AFSK setup
String-ized and simplified LCR UI code
Simplified AFSK baseband code, made to always work on 16bit words
This commit is contained in:
furrtek 2017-04-21 06:22:31 +01:00
parent eff96276c3
commit 90feadd9f5
28 changed files with 423 additions and 423 deletions

View File

@ -140,7 +140,7 @@ set(CPPSRC
protocols/dcs.cpp
protocols/lcr.cpp
protocols/rds.cpp
afsk.cpp
modems.cpp
audio.cpp
${COMMON}/bch_code.cpp
ctcss.cpp
@ -183,7 +183,7 @@ set(CPPSRC
ui_record_view.cpp
ui_replay_view.cpp
ui_rssi.cpp
ui_script.cpp
# ui_script.cpp
ui_sd_card_status_view.cpp
ui_sd_wipe.cpp
# ui_sd_card_debug.cpp

View File

@ -1,107 +0,0 @@
/*
* 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 "afsk.hpp"
#include "portapack_persistent_memory.hpp"
namespace afsk {
void generate_data(const std::string & in_message, char * out_data) {
const afsk_formats_t * format_def;
uint8_t pm, pp, bit, cp, cur_byte, new_byte;
uint16_t dp;
format_def = &afsk_formats[portapack::persistent_memory::afsk_format()];
if (format_def->parity == ODD)
pm = 1; // Odd parity
else
pm = 0; // Even parity
if (format_def->data_bits == 7) {
if (!format_def->use_LUT) {
for (dp = 0; dp < in_message.length(); dp++) {
pp = pm;
new_byte = 0;
cur_byte = in_message[dp];
for (cp = 0; cp < 7; cp++) {
bit = (cur_byte >> cp) & 1;
pp += bit;
new_byte |= (bit << (7 - cp));
}
if (format_def->parity != NONE) new_byte |= (pp & 1);
out_data[dp] = new_byte;
}
out_data[dp++] = 0;
out_data[dp] = 0;
} else {
for (dp = 0; dp < in_message.length(); dp++) {
pp = pm;
cur_byte = in_message[dp];
for (cp = 0; cp < 8; cp++)
if ((cur_byte >> cp) & 1) pp++;
out_data[dp * 2] = cur_byte;
out_data[(dp * 2) + 1] = 0xFE;
if (format_def->parity != NONE) out_data[(dp * 2) + 1] |= (pp & 1);
}
out_data[dp * 2] = 0;
out_data[(dp * 2) + 1] = 0;
}
} else {
/*
for (dp = 0; dp < strlen(in_message); dp++) {
pp = pm;
// Do not apply LUT on checksum (last byte) ?
if (dp != strlen(in_message) - 1)
cur_byte = alt_lookup[(uint8_t)in_message[dp] & 0x7F];
else
cur_byte = in_message[dp];
for (cp = 0; cp < 8; cp++)
if ((cur_byte >> cp) & 1) pp++;
out_data[dp * 2] = cur_byte;
out_data[(dp * 2) + 1] = 0xFE | (pp & 1);
}
out_data[dp * 2] = 0;
out_data[(dp * 2) + 1] = 0;
*/
}
/*
// MSB first
for (dp = 0; dp < strlen(lcr_message); dp++) {
pp = pm;
cur_byte = lcr_message[dp];
for (cp = 0; cp < 7; cp++)
if ((cur_byte >> cp) & 1) pp++;
lcr_message_data[dp] = (cur_byte << 1) | (pp & 1);
}
}*/
}
} /* namespace afsk */

View File

@ -116,14 +116,14 @@ void set_sstv_data(const uint8_t vis_code, const uint32_t pixel_duration) {
}
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 bool afsk_alt_format) {
const uint8_t afsk_repeat, const uint32_t afsk_bw, const uint8_t symbol_count) {
const AFSKConfigureMessage message {
afsk_samples_per_bit,
afsk_phase_inc_mark,
afsk_phase_inc_space,
afsk_repeat,
afsk_bw,
afsk_alt_format
symbol_count
};
send_message(&message);
}

View File

@ -65,7 +65,7 @@ void set_audiotx_data(const uint32_t divider, const uint32_t bw, const uint32_t
void set_fifo_data(const int8_t * data);
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 bool afsk_alt_format);
const uint8_t afsk_repeat, const uint32_t afsk_bw, const uint8_t symbol_count);
void kill_afsk();
void set_ook_data(const uint32_t stream_length, const uint32_t samples_per_bit, const uint8_t repeat,
const uint32_t pause_symbols);

View File

@ -0,0 +1,93 @@
/*
* 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 "modems.hpp"
#include "portapack_persistent_memory.hpp"
using namespace portapack;
namespace modems {
uint8_t symbol_count() {
serial_format_t serial_format;
uint8_t count;
serial_format = persistent_memory::serial_format();
count = 1 + serial_format.data_bits; // Start
if (serial_format.parity) count++;
count += serial_format.stop_bits;
return count;
};
void generate_data(const std::string& in_message, uint16_t * out_data) {
serial_format_t serial_format;
uint8_t parity_init, parity, data_bits, bits, bit, cur_byte;
uint16_t ordered_word, bytes;
serial_format = persistent_memory::serial_format();
if (serial_format.parity == ODD)
parity_init = 1;
else
parity_init = 0;
data_bits = serial_format.data_bits;
for (bytes = 0; bytes < in_message.length(); bytes++) {
parity = parity_init;
cur_byte = in_message[bytes];
if (serial_format.bit_order == MSB_FIRST) {
ordered_word = cur_byte;
for (bits = 0; bits < data_bits; bits++) {
bit = (cur_byte >> bits) & 1; // Get LSB
parity += bit;
}
} else {
ordered_word = 0;
for (bits = 0; bits < data_bits; bits++) {
bit = (cur_byte >> bits) & 1; // Get LSB
parity += bit;
ordered_word |= (bit << ((data_bits - 1) - bits)); // Set MSB
}
}
if (serial_format.parity) {
ordered_word <<= 1;
ordered_word |= (parity & 1);
}
for (bits = 0; bits < serial_format.stop_bits; bits++) {
ordered_word <<= 1;
ordered_word |= 1;
}
out_data[bytes] = ordered_word;
}
out_data[bytes] = 0; // End marker
}
} /* namespace modems */

View File

@ -24,38 +24,65 @@
#include <cstring>
#include <string>
#ifndef __AFSK_H__
#define __AFSK_H__
#ifndef __MODEMS_H__
#define __MODEMS_H__
namespace afsk {
namespace modems {
#define AFSK_MODES_COUNT 4
#define MODEM_DEF_COUNT 7
enum parity_enum {
enum parity_enum : uint8_t {
NONE = 0,
EVEN,
ODD
EVEN = 1,
ODD = 2
};
struct afsk_formats_t {
std::string fullname;
std::string shortname;
enum order_enum : uint8_t {
MSB_FIRST = 0,
LSB_FIRST = 1
};
struct serial_format_t {
uint8_t data_bits;
parity_enum parity;
uint8_t stop_bits;
bool MSB_first;
bool use_LUT;
order_enum bit_order;
};
const afsk_formats_t afsk_formats[4] = {
{ "7-Even-1 R", "7E1", 7, EVEN, 1, false, false },
uint8_t symbol_count();
enum modulation_enum {
AFSK = 0,
FSK,
PSK,
SSB
};
struct modem_def_t {
std::string name;
modulation_enum modulation;
uint16_t mark_freq;
uint16_t space_freq;
uint16_t baudrate;
};
const modem_def_t modem_defs[MODEM_DEF_COUNT] = {
{ "Bell202", AFSK, 1200, 2200, 1200 },
{ "Bell103", AFSK, 1270, 1070, 300 },
{ "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 }
/*{ "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 },
{ "8-Even-0 ", "8E0", 8, EVEN, 1, true, false }
{ "8-Even-0 ", "8E0", 8, EVEN, 1, true, false }*/
};
void generate_data(const std::string & in_message, char * out_data);
void generate_data(const std::string& in_message, uint16_t * out_data);
} /* namespace afsk */
} /* namespace modems */
#endif/*__AFSK_H__*/
#endif/*__MODEMS_H__*/

View File

@ -67,6 +67,7 @@ void POCSAGAppView::update_freq(rf::Frequency f) {
}
POCSAGAppView::POCSAGAppView(NavigationView& nav) {
uint32_t ignore_address;
baseband::run_image(portapack::spi_flash::image_tag_pocsag);
@ -109,8 +110,12 @@ POCSAGAppView::POCSAGAppView(NavigationView& nav) {
check_ignore.on_select = [this](Checkbox&, bool v) {
ignore = v;
};
for (size_t c = 0; c < 7; c++)
sym_ignore.set_sym(c, default_ignore[c]);
ignore_address = persistent_memory::pocsag_ignore_address();
for (size_t c = 0; c < 7; c++) {
sym_ignore.set_sym(6 - c, ignore_address % 10);
ignore_address /= 10;
}
button_setfreq.on_select = [this,&nav](Button&) {
auto new_view = nav.push<FrequencyKeypadView>(target_frequency_);
@ -126,6 +131,10 @@ POCSAGAppView::POCSAGAppView(NavigationView& nav) {
}
POCSAGAppView::~POCSAGAppView() {
// Save ignored address
persistent_memory::set_pocsag_ignore_address(sym_ignore.value_dec_u32());
receiver_model.disable();
baseband::shutdown();
}
@ -162,7 +171,7 @@ void POCSAGAppView::on_packet(const POCSAGPacketMessage * message) {
console_info += " F" + to_string_dec_uint(pocsag_state.function);
// Store last received address for POCSAG TX
portapack::persistent_memory::set_pocsag_address(pocsag_state.address);
persistent_memory::set_pocsag_last_address(pocsag_state.address);
if (pocsag_state.out_type == ADDRESS) {
// Address only

View File

@ -59,8 +59,6 @@ public:
private:
static constexpr uint32_t initial_target_frequency = 466175000;
static constexpr uint32_t sampling_rate = 3072000;
const uint8_t default_ignore[7] = { 1, 0, 0, 8, 8, 2, 4 };
bool logging { true };
bool ignore { false };

View File

@ -23,8 +23,6 @@
#include "lcr.hpp"
#include "string_format.hpp"
//#include "portapack_persistent_memory.hpp"
namespace lcr {
std::string generate_message(std::string rgsb, std::vector<std::string> litterals, size_t option_ec) {

View File

@ -67,13 +67,13 @@ ReplayThread::~ReplayThread() {
msg_t ReplayThread::static_fn(void* arg) {
auto obj = static_cast<ReplayThread*>(arg);
const auto error = obj->run();
/*if( error.is_valid() && obj->error_callback ) {
if( error.is_valid() && obj->error_callback ) {
obj->error_callback(error.value());
} else {
if( obj->success_callback ) {
obj->success_callback();
}
}*/
}
return 0;
}
@ -82,14 +82,13 @@ Optional<File::Error> ReplayThread::run() {
BufferExchange buffers { &config };
while( !chThdShouldTerminate() ) {
//auto buffer = buffers.get();
buffers.get();
auto buffer = buffers.get();
/*auto read_result = reader->read(buffer->data(), buffer->size());
if( read_result.is_error() ) {
return read_result.error();
}
buffers.put(buffer);*/
chThdSleep(50);
chThdSleep(50); // DEBUG
//led_tx.toggle();
}

View File

@ -33,7 +33,7 @@
#include <stdio.h>
using namespace portapack;
using namespace afsk;
using namespace modems;
namespace ui {
@ -42,18 +42,14 @@ void AFSKSetupView::focus() {
}
void AFSKSetupView::update_freq(rf::Frequency f) {
char finalstr[10] = {0};
std::string final_str;
portapack::persistent_memory::set_tuned_frequency(f);
persistent_memory::set_tuned_frequency(f);
auto mhz = to_string_dec_int(f / 1000000, 4);
auto hz100 = to_string_dec_int((f / 100) % 10000, 4, '0');
final_str = to_string_dec_int(f / 1000000, 4) + ".";
final_str += to_string_dec_int((f / 100) % 10000, 4, '0');
strcat(finalstr, mhz.c_str());
strcat(finalstr, ".");
strcat(finalstr, hz100.c_str());
this->button_setfreq.set_text(finalstr);
button_setfreq.set_text(final_str);
}
AFSKSetupView::AFSKSetupView(
@ -64,57 +60,81 @@ AFSKSetupView::AFSKSetupView(
using value_t = int32_t;
using option_t = std::pair<name_t, value_t>;
using options_t = std::vector<option_t>;
options_t format_options;
uint8_t rpt;
options_t modem_options;
size_t i;
add_children({
&labels,
&button_setfreq,
&options_bps,
&field_baudrate,
&field_mark,
&field_space,
&field_bw,
&field_repeat,
&options_format,
&options_modem,
&button_set_modem,
&sym_format,
&button_save
});
for (i = 0; i < AFSK_MODES_COUNT; i++)
format_options.emplace_back(std::make_pair(afsk_formats[i].fullname, i));
for (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_format.set_options(format_options);
options_format.set_selected_index(portapack::persistent_memory::afsk_format());
options_modem.set_options(modem_options);
options_modem.set_selected_index(0);
update_freq(portapack::persistent_memory::tuned_frequency());
sym_format.set_symbol_list(0, "6789"); // Data bits
sym_format.set_symbol_list(1, "NEo"); // Parity
sym_format.set_symbol_list(2, "012"); // Stop bits
sym_format.set_symbol_list(3, "ML"); // MSB/LSB first
field_mark.set_value(portapack::persistent_memory::afsk_mark_freq() * 25);
field_space.set_value(portapack::persistent_memory::afsk_space_freq() * 25);
field_bw.set_value(portapack::persistent_memory::afsk_bw());
rpt = portapack::persistent_memory::afsk_repeats();
if ((rpt > 99) || (!rpt)) rpt = 5;
field_repeat.set_value(rpt);
sym_format.set_sym(0, persistent_memory::serial_format().data_bits - 6);
sym_format.set_sym(1, persistent_memory::serial_format().parity);
sym_format.set_sym(2, persistent_memory::serial_format().stop_bits);
sym_format.set_sym(3, persistent_memory::serial_format().bit_order);
button_setfreq.on_select = [this,&nav](Button&) {
auto new_view = nav.push<FrequencyKeypadView>(portapack::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_repeat.set_value(persistent_memory::modem_repeat());
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);
};
};
options_bps.set_by_value(portapack::persistent_memory::afsk_bitrate());
field_baudrate.set_value(persistent_memory::modem_baudrate());
button_set_modem.on_select = [this, &nav](Button&) {
size_t modem_def_index = options_modem.selected_index();
field_mark.set_value(modem_defs[modem_def_index].mark_freq);
field_space.set_value(modem_defs[modem_def_index].space_freq);
field_baudrate.set_value(modem_defs[modem_def_index].baudrate);
};
button_save.on_select = [this,&nav](Button&) {
uint32_t afsk_config = 0;
serial_format_t serial_format;
portapack::persistent_memory::set_afsk_bitrate(options_bps.selected_index_value());
portapack::persistent_memory::set_afsk_mark(field_mark.value() / 25);
portapack::persistent_memory::set_afsk_space(field_space.value() / 25);
portapack::persistent_memory::set_afsk_bw(field_bw.value());
persistent_memory::set_afsk_mark(field_mark.value());
persistent_memory::set_afsk_space(field_space.value());
afsk_config |= (options_format.selected_index() << 16);
afsk_config |= (field_repeat.value() << 24);
portapack::persistent_memory::set_afsk_config(afsk_config);
persistent_memory::set_modem_baudrate(field_baudrate.value());
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;
serial_format.parity = (parity_enum)sym_format.get_sym(1);
serial_format.stop_bits = sym_format.get_sym(2);
serial_format.bit_order = (order_enum)sym_format.get_sym(3);
persistent_memory::set_serial_format(serial_format);
nav.pop();
};

View File

@ -20,7 +20,7 @@
* Boston, MA 02110-1301, USA.
*/
#include "afsk.hpp"
#include "modems.hpp"
#include "ui.hpp"
#include "ui_widget.hpp"
@ -40,30 +40,27 @@ private:
void update_freq(rf::Frequency f);
Labels labels {
{ { 1 * 8, 4 * 8 }, "Frequency:", Color::light_grey() },
{ { 16 * 8, 5 * 8 }, "Speed:", Color::light_grey() },
{ { 2 * 8, 4 * 8 }, "Frequency:", Color::light_grey() },
{ { 2 * 8, 11 * 8 }, "Speed: Bps", 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, 15 * 8 }, "Repeat:", Color::light_grey() },
{ { 2 * 8, 19 * 8 }, "Format:", Color::light_grey() }
{ { 2 * 8, 19 * 8 }, "Modem preset:", Color::light_grey() },
{ { 2 * 8, 22 * 8 }, "Serial format:", Color::light_grey() }
};
Button button_setfreq {
{ 8, 48, 104, 32 },
{ 13 * 8, 3 * 8, 12 * 8, 32 },
"----.----"
};
OptionsField options_bps {
{ 128, 60 },
7,
{
{ "600bps ", 600 },
{ "1200bps", 1200 },
{ "2400bps", 2400 },
{ "4800bps", 4800 },
{ "9600bps", 9600 }
}
NumberField field_baudrate {
{ 64, 88 },
5,
{ 50, 9600 },
25,
' '
};
NumberField field_mark {
@ -98,13 +95,24 @@ private:
' '
};
OptionsField options_format {
{ 80, 152 },
10,
OptionsField options_modem {
{ 16 * 8, 19 * 8 },
7,
{
}
};
SymField sym_format {
{ 16 * 8, 22 * 8 },
4,
SymField::SYMFIELD_DEF
};
Button button_set_modem {
{ 24 * 8, 19 * 8 - 4, 5 * 8, 24 },
"SET"
};
Button button_save {
{ 72, 250, 96, 40 },
"Save"

View File

@ -24,7 +24,7 @@
#include "ui_afsksetup.hpp"
#include "ui_debug.hpp"
#include "afsk.hpp"
#include "modems.hpp"
#include "lcr.hpp"
#include "baseband_api.hpp"
#include "string_format.hpp"
@ -35,7 +35,7 @@
#include <stdio.h>
using namespace portapack;
using namespace afsk;
using namespace modems;
namespace ui {
@ -49,7 +49,7 @@ LCRView::~LCRView() {
}
void LCRView::paint(Painter& painter) {
uint8_t i;
size_t i;
std::string final_str;
static constexpr Style style_orange {
@ -75,11 +75,11 @@ void LCRView::paint(Painter& painter) {
button_setrgsb.set_text(rgsb);
// Recap: freq @ bps
final_str = to_string_dec_int(portapack::persistent_memory::tuned_frequency() / 1000, 6);
final_str = to_string_dec_int(persistent_memory::tuned_frequency() / 1000, 6);
final_str += '@';
final_str += to_string_dec_int(portapack::persistent_memory::afsk_bitrate(), 4);
final_str += to_string_dec_int(persistent_memory::modem_baudrate(), 4);
final_str += "bps ";
final_str += afsk_formats[portapack::persistent_memory::afsk_format()].shortname;
//final_str += modem_defs[persistent_memory::modem_def_index()].name;
text_recap.set(final_str);
}
@ -95,25 +95,18 @@ std::vector<std::string> LCRView::parse_litterals() {
}
void LCRView::update_progress() {
char str[16];
std::string progress_str;
text_status.set(" ");
text_status.set(" "); // Clear
if (tx_mode == SINGLE) {
strcpy(str, to_string_dec_uint(repeat_index).c_str());
strcat(str, "/");
strcat(str, to_string_dec_uint(portapack::persistent_memory::afsk_repeats()).c_str());
text_status.set(str);
progress_str = to_string_dec_uint(repeat_index) + "/" + to_string_dec_uint(persistent_memory::modem_repeat());
text_status.set(progress_str);
progress.set_value(repeat_index);
} else if (tx_mode == SCAN) {
strcpy(str, to_string_dec_uint(repeat_index).c_str());
strcat(str, "/");
strcat(str, to_string_dec_uint(portapack::persistent_memory::afsk_repeats()).c_str());
strcat(str, " ");
strcat(str, to_string_dec_uint(scan_index + 1).c_str());
strcat(str, "/");
strcat(str, to_string_dec_uint(scan_count).c_str());
text_status.set(str);
progress_str = to_string_dec_uint(repeat_index) + "/" + to_string_dec_uint(persistent_memory::modem_repeat());
progress_str += " " + to_string_dec_uint(scan_index + 1) + "/" + to_string_dec_uint(scan_count);
text_status.set(progress_str);
progress.set_value(scan_progress);
} else {
text_status.set("Ready");
@ -153,10 +146,9 @@ void LCRView::on_txdone(int n) {
}
void LCRView::start_tx(const bool scan) {
uint8_t afsk_format;
uint8_t afsk_repeats;
uint8_t repeats;
afsk_repeats = portapack::persistent_memory::afsk_repeats();
repeats = persistent_memory::modem_repeat();
if (scan) {
if (tx_mode != SCAN) {
@ -166,35 +158,20 @@ void LCRView::start_tx(const bool scan) {
repeat_index = 1;
tx_mode = SCAN;
rgsb = scan_list[options_scanlist.selected_index()].addresses[0];
progress.set_max(scan_count * afsk_repeats);
progress.set_max(scan_count * repeats);
update_progress();
}
} else {
tx_mode = SINGLE;
repeat_index = 1;
progress.set_max(afsk_repeats);
progress.set_max(repeats);
update_progress();
}
button_setrgsb.set_text(rgsb);
afsk::generate_data(lcr::generate_message(rgsb, parse_litterals(), options_ec.selected_index()), lcr_message_data);
modems::generate_data(lcr::generate_message(rgsb, parse_litterals(), options_ec.selected_index()), lcr_message_data);
switch (portapack::persistent_memory::afsk_format()) {
case 0:
case 1:
case 2:
afsk_format = 0;
break;
case 3:
afsk_format = 1;
break;
default:
afsk_format = 0;
}
transmitter_model.set_tuning_frequency(portapack::persistent_memory::tuned_frequency());
transmitter_model.set_tuning_frequency(persistent_memory::tuned_frequency());
transmitter_model.set_sampling_rate(1536000U);
transmitter_model.set_rf_amp(true);
transmitter_model.set_baseband_bandwidth(1750000);
@ -203,12 +180,12 @@ void LCRView::start_tx(const bool scan) {
memcpy(shared_memory.bb_data.data, lcr_message_data, 300);
baseband::set_afsk_data(
(153600 * 5) / portapack::persistent_memory::afsk_bitrate(),
portapack::persistent_memory::afsk_mark_freq() * 437 * 5, // (0x40000 * 256) / (153600 / 25),
portapack::persistent_memory::afsk_space_freq() * 437 * 5, // (0x40000 * 256) / (153600 / 25),
afsk_repeats,
portapack::persistent_memory::afsk_bw() * 115, // See proc_afsk.cpp
afsk_format
1536000 / persistent_memory::modem_baudrate(),
persistent_memory::afsk_mark_freq(),
persistent_memory::afsk_space_freq(),
repeats,
persistent_memory::modem_bw(),
modems::symbol_count()
);
}

View File

@ -84,7 +84,7 @@ private:
std::string litteral[5] { " " };
std::string rgsb { " " };
char lcr_message[512];
char lcr_message_data[512];
uint16_t lcr_message_data[256];
rf::Frequency f { 0 };
uint8_t repeat_index { 0 };

View File

@ -361,7 +361,7 @@ SystemMenuView::SystemMenuView(NavigationView& nav) {
{ "Play dead", ui::Color::red(), &bitmap_icon_playdead, [&nav](){ nav.push<PlayDeadView>(); } },
{ "Receivers", ui::Color::cyan(), &bitmap_icon_receivers, [&nav](){ nav.push<ReceiverMenuView>(); } },
{ "Capture", ui::Color::blue(), &bitmap_icon_capture, [&nav](){ nav.push<CaptureAppView>(); } },
{ "Replay", ui::Color::blue(), &bitmap_icon_replay, [&nav](){ nav.push<ReplayAppView>(); } }, // ReplayAppView
{ "Replay", ui::Color::grey(), &bitmap_icon_replay, [&nav](){ nav.push<NotImplementedView>(); } }, // ReplayAppView
{ "Audio transmitters", ui::Color::green(), &bitmap_icon_audiotx, [&nav](){ nav.push<TransmitterAudioMenuView>(); } },
{ "Code transmitters", ui::Color::green(), &bitmap_icon_codetx, [&nav](){ nav.push<TransmitterCodedMenuView>(); } },
{ "SSTV transmitter", ui::Color::dark_green(), &bitmap_icon_sstv, [&nav](){ nav.push<SSTVTXView>(); } },

View File

@ -151,7 +151,7 @@ POCSAGTXView::POCSAGTXView(
options_type.set_selected_index(0); // Address only
// TODO: set_value for whole symfield
reload_address = portapack::persistent_memory::pocsag_address();
reload_address = persistent_memory::pocsag_last_address();
for (c = 0; c < 7; c++) {
field_address.set_sym(6 - c, reload_address % 10);
reload_address /= 10;

View File

@ -35,88 +35,60 @@ void AFSKProcessor::execute(const buffer_c8_t& buffer) {
for (size_t i = 0; i<buffer.count; i++) {
// Tone synthesis at 2.28M/10 = 228kHz
if (s >= (5 - 1)) {
s = 0;
if (sample_count >= afsk_samples_per_bit) {
if (configured) {
cur_word = *word_ptr;
if (sample_count >= afsk_samples_per_bit) {
if (configured) {
cur_byte = shared_memory.bb_data.data[byte_pos];
ext_byte = shared_memory.bb_data.data[byte_pos + 1];
if (!(cur_byte | ext_byte)) {
// End of data
if (repeat_counter < afsk_repeat) {
// Repeat
bit_pos = 0;
byte_pos = 0;
cur_byte = shared_memory.bb_data.data[0];
ext_byte = shared_memory.bb_data.data[1];
message.progress = repeat_counter + 1;
shared_memory.application_queue.push(message);
repeat_counter++;
} else {
// Stop
cur_byte = 0;
ext_byte = 0;
message.progress = 0;
shared_memory.application_queue.push(message);
configured = false;
}
if (!cur_word) {
// End of data
if (repeat_counter < afsk_repeat) {
// Repeat
bit_pos = 0;
word_ptr = (uint16_t*)shared_memory.bb_data.data;
cur_word = *word_ptr;
message.progress = repeat_counter + 1;
shared_memory.application_queue.push(message);
repeat_counter++;
} else {
// Stop
cur_word = 0;
message.progress = 0;
shared_memory.application_queue.push(message);
configured = false;
}
}
if (afsk_format == 0) {
// 0bbbbbbbp1
// Start, 7-bit data, parity, stop
gbyte = (cur_byte << 1) | 1;
} else if (afsk_format == 1) {
// 0bbbbbbbbp
// Start, 8-bit data, parity
gbyte = (cur_byte << 1) | (ext_byte & 1);
}
cur_bit = (gbyte >> (9 - bit_pos)) & 1;
if (bit_pos >= 9) {
bit_pos = 0;
if (afsk_format == 0)
byte_pos++;
else if (afsk_format == 1)
byte_pos += 2;
} else {
bit_pos++;
}
sample_count = 0;
} else {
sample_count++;
}
if (cur_bit)
tone_phase += afsk_phase_inc_mark;
else
tone_phase += afsk_phase_inc_space;
cur_bit = (cur_word >> (symbol_count - bit_pos)) & 1;
if (bit_pos >= symbol_count) {
bit_pos = 0;
word_ptr++;
} else {
bit_pos++;
}
sample_count = 0;
} else {
s--;
sample_count++;
}
//tone_phase += 432759; // 1981Hz
if (cur_bit)
tone_phase += afsk_phase_inc_mark;
else
tone_phase += afsk_phase_inc_space;
tone_sample = (sine_table_i8[(tone_phase & 0x03FC0000) >> 18]);
tone_sample = sine_table_i8[(tone_phase & 0xFF000000U) >> 24];
// FM
// 1<<18 = 262144
// m = (262144 * a) / 2280000
// a = 262144 / 2280000 (*1000 = 115, see ui_lcr afsk_bw setting)
frq = tone_sample * afsk_bw;
delta = tone_sample * fm_delta;
phase = (phase + frq);
sphase = phase + (64 << 18);
phase += delta;
sphase = phase + (64 << 24);
re = (sine_table_i8[(sphase & 0x03FC0000) >> 18]);
im = (sine_table_i8[(phase & 0x03FC0000) >> 18]);
re = (sine_table_i8[(sphase & 0xFF000000U) >> 24]);
im = (sine_table_i8[(phase & 0xFF000000U) >> 24]);
buffer.p[i] = {(int8_t)re, (int8_t)im};
buffer.p[i] = {re, im};
}
}
@ -126,19 +98,17 @@ void AFSKProcessor::on_message(const Message* const msg) {
if (message.id == Message::ID::AFSKConfigure) {
if (message.samples_per_bit) {
afsk_samples_per_bit = message.samples_per_bit;
afsk_phase_inc_mark = message.phase_inc_mark;
afsk_phase_inc_space = message.phase_inc_space;
afsk_phase_inc_mark = message.phase_inc_mark * AFSK_DELTA_COEF;
afsk_phase_inc_space = message.phase_inc_space * AFSK_DELTA_COEF;
afsk_repeat = message.repeat - 1;
afsk_bw = message.bw;
afsk_format = message.format;
fm_delta = message.fm_delta * (0xFFFFFFULL / 1536000);
symbol_count = message.symbol_count - 1;
s = 0;
sample_count = afsk_samples_per_bit;
repeat_counter = 0;
bit_pos = 0;
byte_pos = 0;
cur_byte = 0;
ext_byte = 0;
word_ptr = (uint16_t*)shared_memory.bb_data.data;
cur_word = 0;
cur_bit = 0;
configured = true;
} else

View File

@ -26,6 +26,9 @@
#include "baseband_processor.hpp"
#include "baseband_thread.hpp"
#define AFSK_SAMPLERATE 1536000
#define AFSK_DELTA_COEF ((1ULL << 32) / AFSK_SAMPLERATE)
class AFSKProcessor : public BasebandProcessor {
public:
void execute(const buffer_c8_t& buffer) override;
@ -41,21 +44,19 @@ private:
uint32_t afsk_phase_inc_mark { 0 };
uint32_t afsk_phase_inc_space { 0 };
uint8_t afsk_repeat { 0 };
uint32_t afsk_bw { 0 };
uint8_t afsk_format { 0 };
uint32_t fm_delta { 0 };
uint8_t symbol_count { 0 };
uint8_t repeat_counter { 0 };
int8_t re { 0 }, im { 0 };
uint8_t s { 0 };
uint8_t bit_pos { 0 };
uint16_t byte_pos { 0 };
char cur_byte { 0 };
char ext_byte { 0 };
uint16_t gbyte { 0 };
uint16_t * word_ptr { };
uint16_t cur_word { 0 };
uint8_t cur_bit { 0 };
uint32_t sample_count { 0 };
uint32_t tone_phase { 0 }, phase { 0 }, sphase { 0 };
int32_t tone_sample { 0 }, sig { 0 }, frq { 0 };
int32_t tone_sample { 0 }, delta { 0 };
int8_t re { 0 }, im { 0 };
TXDoneMessage message { };
};

View File

@ -22,8 +22,6 @@
#include "proc_replay.hpp"
//#include "dsp_fir_taps.hpp"
#include "event_m4.hpp"
#include "utility.hpp"
@ -34,16 +32,12 @@ ReplayProcessor::ReplayProcessor() {
void ReplayProcessor::execute(const buffer_c8_t& buffer) {
/* 2.4576MHz, 2048 samples */
//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& decimator_out = decim_1_out;
//const auto& channel = decimator_out;
size_t pos = 0;
for (size_t c = 0; c < 4; c++) {
if( stream ) {
const size_t bytes_to_read = sizeof(*buffer.p) * buffer.count / 4; // ?
const size_t bytes_to_read = sizeof(*buffer.p) * buffer.count / 4;
const auto result = stream->read(iq_buffer.p, bytes_to_read);
}
@ -52,7 +46,6 @@ void ReplayProcessor::execute(const buffer_c8_t& buffer) {
for (size_t i = 0; i < (buffer.count / 4); i++) {
buffer.p[pos] = { iq_buffer.p[i].real() >> 8, iq_buffer.p[i].imag() >> 8 };
pos++;
//buffer.p[i] = { iq_buffer.p[i].real(), iq_buffer.p[i].imag() };
}
}

View File

@ -25,11 +25,6 @@
#include "baseband_processor.hpp"
#include "baseband_thread.hpp"
//#include "rssi_thread.hpp"
//#include "dsp_decimate.hpp"
//#include "spectrum_collector.hpp"
#include "stream_output.hpp"
@ -52,7 +47,7 @@ private:
BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Transmit };
//RSSIThread rssi_thread { NORMALPRIO + 10 };
std::array<complex16_t, 512> iq { }; // 2048
std::array<complex16_t, 512> iq { }; // 2048 doesn't fit in allocated RAM
const buffer_c16_t iq_buffer {
iq.data(),
iq.size()

View File

@ -48,7 +48,7 @@ size_t StreamOutput::read(void* const data, const size_t length) {
if( !active_buffer ) {
// We need a full buffer...
if( !fifo_buffers_full.out(active_buffer) ) {
// ...but none are available. Samples were dropped.
// ...but none are available. Hole in transmission (inform app and stop ?)
break;
}
}
@ -59,11 +59,12 @@ size_t StreamOutput::read(void* const data, const size_t length) {
if( active_buffer->is_empty() ) {
if( !fifo_buffers_empty.in(active_buffer) ) {
// FIFO is completly empty.
// Bail out of the loop, and try retrieving the buffer in the
// next pass.
// Empty buffers FIFO is already full.
// This should never happen if the number of buffers is less
// than the capacity of the FIFO.
break;
}
// Tell M0 (IRQ) that a buffer has been consumed.
active_buffer = nullptr;
creg::m4txevent::assert();
}

View File

@ -32,7 +32,7 @@ BufferExchange::BufferExchange(
) // : config_capture { config }
{
obj = this;
direction = CAPTURE;
// In capture mode, baseband wants empty buffers, app waits for full buffers
fifo_buffers_for_baseband = config->fifo_buffers_empty;
fifo_buffers_for_application = config->fifo_buffers_full;
}
@ -42,7 +42,7 @@ BufferExchange::BufferExchange(
) // : config_replay { config }
{
obj = this;
direction = REPLAY;
// In replay mode, baseband wants full buffers, app waits for empty buffers
fifo_buffers_for_baseband = config->fifo_buffers_full;
fifo_buffers_for_application = config->fifo_buffers_empty;
}
@ -56,14 +56,15 @@ BufferExchange::~BufferExchange() {
StreamBuffer* BufferExchange::get(FIFO<StreamBuffer*>* fifo) {
while(true) {
StreamBuffer* p { nullptr };
fifo->out(p);
fifo->out(p); // This crashes replay
led_tx.on(); // DEBUG
//led_tx.on(); // DEBUG
if( p ) {
return p;
}
// Put thread to sleep, woken up by M4 IRQ
chSysLock();
thread = chThdSelf();
chSchGoSleepS(THD_STATE_SUSPENDED);

View File

@ -86,12 +86,8 @@ private:
} direction { };
void check_fifo_isr() {
//if (!empty() && (direction == CAPTURE)) {
if (!empty())
wakeup_isr();
//} else if (!empty() && (direction == REPLAY)) {
// wakeup_isr();
//}
}
void wakeup_isr() {

View File

@ -111,9 +111,9 @@ public:
return false;
}
val = _data[_out & mask()];
smp_wmb();
_out += 1;
val = _data[_out & mask()]; // Crashes
smp_wmb(); // Ok
_out += 1; // Crashes
return true;
}

View File

@ -683,15 +683,15 @@ public:
const uint32_t phase_inc_mark,
const uint32_t phase_inc_space,
const uint8_t repeat,
const uint32_t bw,
const uint8_t format
const uint32_t fm_delta,
const uint8_t symbol_count
) : Message { ID::AFSKConfigure },
samples_per_bit(samples_per_bit),
phase_inc_mark(phase_inc_mark),
phase_inc_space(phase_inc_space),
repeat(repeat),
bw(bw),
format(format)
fm_delta(fm_delta),
symbol_count(symbol_count)
{
}
@ -699,8 +699,8 @@ public:
const uint32_t phase_inc_mark;
const uint32_t phase_inc_space;
const uint8_t repeat;
const uint32_t bw;
const uint8_t format;
const uint32_t fm_delta;
const uint8_t symbol_count;
};
class OOKConfigureMessage : public Message {

View File

@ -44,17 +44,21 @@ constexpr ppb_range_t ppb_range { -99000, 99000 };
constexpr ppb_t ppb_reset_value { 0 };
using afsk_freq_range_t = range_t<int32_t>;
constexpr afsk_freq_range_t afsk_freq_range { 1, 400 };
constexpr int32_t afsk_mark_reset_value { 48 };
constexpr int32_t afsk_space_reset_value { 88 };
constexpr afsk_freq_range_t afsk_freq_range { 1, 4000 };
constexpr int32_t afsk_mark_reset_value { 1200 };
constexpr int32_t afsk_space_reset_value { 2200 };
using afsk_bitrate_range_t = range_t<int32_t>;
constexpr afsk_bitrate_range_t afsk_bitrate_range { 600, 9600 };
constexpr int32_t afsk_bitrate_reset_value { 1200 };
using modem_baudrate_range_t = range_t<int32_t>;
constexpr modem_baudrate_range_t modem_baudrate_range { 50, 9600 };
constexpr int32_t modem_baudrate_reset_value { 1200 };
using afsk_bw_range_t = range_t<int32_t>;
constexpr afsk_bw_range_t afsk_bw_range { 1, 50 };
constexpr int32_t afsk_bw_reset_value { 15 };
using modem_bw_range_t = range_t<int32_t>;
constexpr modem_bw_range_t modem_bw_range { 1000, 50000 };
constexpr int32_t modem_bw_reset_value { 15000 };
using modem_repeat_range_t = range_t<int32_t>;
constexpr modem_repeat_range_t modem_repeat_range { 1, 99 };
constexpr int32_t modem_repeat_reset_value { 5 };
/* struct must pack the same way on M4 and M0 cores. */
struct data_t {
@ -63,13 +67,14 @@ struct data_t {
uint32_t touch_calibration_magic;
touch::Calibration touch_calibration;
// AFSK modem
// Modem
uint32_t modem_def_index;
serial_format_t serial_format;
int32_t modem_bw;
int32_t afsk_mark_freq;
int32_t afsk_space_freq; // Todo: reduce size, only 256 bytes of NVRAM !
int32_t afsk_bitrate;
int32_t afsk_bw;
uint32_t afsk_config;
int32_t afsk_space_freq;
int32_t modem_baudrate;
int32_t modem_repeat;
// Play dead unlock
uint32_t playdead_magic;
@ -78,7 +83,8 @@ struct data_t {
uint32_t ui_config;
uint32_t pocsag_address;
uint32_t pocsag_last_address;
uint32_t pocsag_ignore_address;
};
static_assert(sizeof(data_t) <= backup_ram.size(), "Persistent memory structure too large for VBAT-maintained region");
@ -137,38 +143,39 @@ void set_afsk_space(const int32_t new_value) {
data->afsk_space_freq = afsk_freq_range.clip(new_value);
}
int32_t afsk_bitrate() {
afsk_bitrate_range.reset_if_outside(data->afsk_bitrate, afsk_bitrate_reset_value);
return data->afsk_bitrate;
int32_t modem_baudrate() {
modem_baudrate_range.reset_if_outside(data->modem_baudrate, modem_baudrate_reset_value);
return data->modem_baudrate;
}
void set_afsk_bitrate(const int32_t new_value) {
data->afsk_bitrate = afsk_bitrate_range.clip(new_value);
void set_modem_baudrate(const int32_t new_value) {
data->modem_baudrate = modem_baudrate_range.clip(new_value);
}
int32_t afsk_bw() {
afsk_bw_range.reset_if_outside(data->afsk_bw, afsk_bw_reset_value);
return data->afsk_bw;
int32_t modem_bw() {
modem_bw_range.reset_if_outside(data->modem_bw, modem_bw_reset_value);
return data->modem_bw;
}
void set_afsk_bw(const int32_t new_value) {
data->afsk_bw = afsk_bw_range.clip(new_value);
void set_modem_bw(const int32_t new_value) {
data->modem_bw = modem_bw_range.clip(new_value);
}
uint32_t afsk_config() {
return data->afsk_config;
uint8_t modem_repeat() {
modem_repeat_range.reset_if_outside(data->modem_repeat, modem_repeat_reset_value);
return data->modem_repeat;
}
uint8_t afsk_format() {
return ((data->afsk_config >> 16) & 3);
void set_modem_repeat(const uint32_t new_value) {
data->modem_repeat = modem_repeat_range.clip(new_value);
}
uint8_t afsk_repeats() {
return (data->afsk_config >> 24);
serial_format_t serial_format() {
return data->serial_format;
}
void set_afsk_config(const uint32_t new_value) {
data->afsk_config = new_value;
void set_serial_format(const serial_format_t new_value) {
data->serial_format = new_value;
}
static constexpr uint32_t playdead_magic = 0x88d3bb57;
@ -241,12 +248,20 @@ void set_ui_config(const uint32_t new_value) {
data->ui_config = new_value;
}
uint32_t pocsag_address() {
return data->pocsag_address;
uint32_t pocsag_last_address() {
return data->pocsag_last_address;
}
void set_pocsag_address(uint32_t address) {
data->pocsag_address = address;
void set_pocsag_last_address(uint32_t address) {
data->pocsag_last_address = address;
}
uint32_t pocsag_ignore_address() {
return data->pocsag_ignore_address;
}
void set_pocsag_ignore_address(uint32_t address) {
data->pocsag_ignore_address = address;
}
} /* namespace persistent_memory */

View File

@ -27,6 +27,9 @@
#include "rf_path.hpp"
#include "touch.hpp"
#include "modems.hpp"
using namespace modems;
namespace portapack {
namespace persistent_memory {
@ -42,22 +45,22 @@ void set_correction_ppb(const ppb_t new_value);
void set_touch_calibration(const touch::Calibration& new_value);
const touch::Calibration& touch_calibration();
serial_format_t serial_format();
void set_serial_format(const serial_format_t new_value);
int32_t afsk_mark_freq();
void set_afsk_mark(const int32_t new_value);
int32_t afsk_space_freq();
void set_afsk_space(const int32_t new_value);
int32_t afsk_bitrate();
void set_afsk_bitrate(const int32_t new_value);
int32_t modem_baudrate();
void set_modem_baudrate(const int32_t new_value);
uint32_t afsk_config();
uint8_t afsk_format();
uint8_t afsk_repeats();
void set_afsk_config(const uint32_t new_value);
int32_t afsk_bw();
void set_afsk_bw(const int32_t new_value);
uint8_t modem_repeat();
void set_modem_repeat(const uint32_t new_value);
int32_t modem_bw();
void set_modem_bw(const int32_t new_value);
uint32_t playing_dead();
void set_playing_dead(const uint32_t new_value);
@ -76,8 +79,11 @@ uint16_t ui_config_bloff();
uint8_t ui_config_textentry();
void set_config_textentry(uint8_t new_value);
uint32_t pocsag_address();
void set_pocsag_address(uint32_t address);
uint32_t pocsag_last_address();
void set_pocsag_last_address(uint32_t address);
uint32_t pocsag_ignore_address();
void set_pocsag_ignore_address(uint32_t address);
} /* namespace persistent_memory */
} /* namespace portapack */

Binary file not shown.