Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Input and Output of SYM, BIN, and RRC formats #21

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ stream from STDIN and writes out an M17 4-FSK baseband stream at 48k SPS,

This code requires the codec2-devel, boost-devel and gtest-devel packages be installed.

It also requires a modern C++17 compiler (GCC 8 minimum).
It also requires a modern C++20 compiler (GCC 8 minimum).

### Build Steps

Expand Down
80 changes: 76 additions & 4 deletions apps/m17-demod.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright 2020 Mobilinkd LLC.

#include "M17Demodulator.h"
#include "M17BitDemodulator.h"
#include "CRC16.h"
#include "ax25_frame.h"
#include "FirFilter.h"
Expand All @@ -27,6 +28,9 @@ bool quiet = false;
bool debug = false;
bool noise_blanker = false;

enum class InputType {SYM, BIN, RRC};
InputType inputType = InputType::RRC;

struct CODEC2 *codec2;

std::vector<uint8_t> current_packet;
Expand Down Expand Up @@ -377,6 +381,9 @@ struct Config
bool invert = false;
bool lsf = false;
bool noise_blanker = false;
bool bin = false;
bool sym = false;
bool rrc = true; // default is rrc

static std::optional<Config> parse(int argc, char* argv[])
{
Expand All @@ -393,6 +400,9 @@ struct Config
("invert,i", po::bool_switch(&result.invert), "invert the received baseband")
("noise-blanker,b", po::bool_switch(&result.noise_blanker), "noise blanker -- silence likely corrupt audio")
("lsf,l", po::bool_switch(&result.lsf), "display the decoded LSF")
("bin,x", po::bool_switch(&result.bin), "input packed dibits (default is rrc).")
("rrc,r", po::bool_switch(&result.rrc), "input rrc filtered and scaled symbols (default).")
("sym,s", po::bool_switch(&result.sym), "input symbols (default is rrc).")
("verbose,v", po::bool_switch(&result.verbose), "verbose output")
("debug,d", po::bool_switch(&result.debug), "debug-level output")
("quiet,q", po::bool_switch(&result.quiet), "silence all output -- no BERT output")
Expand Down Expand Up @@ -430,10 +440,17 @@ struct Config
return std::nullopt;
}

if (result.sym + result.bin + result.rrc > 1)
{
std::cerr << "Only one of sym, bin or rrc may be chosen." << std::endl;
return std::nullopt;
}

return result;
}
};


int main(int argc, char* argv[])
{
using namespace mobilinkd;
Expand All @@ -448,6 +465,16 @@ int main(int argc, char* argv[])
debug = config->debug;
noise_blanker = config->noise_blanker;

if (config->sym) {
inputType = InputType::SYM;
}
else if (config->bin) {
inputType = InputType::BIN;
}
else {
inputType = InputType::RRC;
}

codec2 = ::codec2_create(CODEC2_MODE_3200);

using FloatType = float;
Expand Down Expand Up @@ -483,10 +510,55 @@ int main(int argc, char* argv[])

while (std::cin)
{
int16_t sample;
std::cin.read(reinterpret_cast<char*>(&sample), 2);
if (invert_input) sample *= -1;
demod(sample / 44000.0);
switch(inputType)
{
case InputType::SYM:
{
char c;
std::array<int8_t, 1> symbol; // symbol to read in
std::array<int16_t, 10> samples; // array to hold 10 samples
//std::cin.read(reinterpret_cast<char*>(&symbol), 1);
std::cin.read(reinterpret_cast<char*>(&c), 1);
symbol[0] = (int8_t)c;
samples = symbols_to_baseband(symbol);
for (int i = 0; i < 10; i++)
{
int16_t s = samples[i];
if (invert_input) s *= -1;
demod(s / 44000.0);
}
}
break;
case InputType::BIN:
{
char c;
std::array<uint8_t, 1> packedSymbols; // dibit packed byte to read in
std::array<int8_t, 4> symbols; // converted to 4 symbols
std::array<int16_t, 40> samples; // array to hold 40 samples
//std::cin.read(reinterpret_cast<char*>(&packedSymbols), 1);
std::cin.read(reinterpret_cast<char*>(&c), 1);
packedSymbols[0] = (uint8_t)c;
symbols = bytes_to_symbols(packedSymbols);
samples = symbols_to_baseband(symbols);
for (int i = 0; i < 40; i++)
{
int16_t s = samples[i];
if (invert_input) s *= -1;
demod(s / 44000.0);
}
}
break;
default: // InputType::RRC
{
int16_t sample;
std::cin.read(reinterpret_cast<char*>(&sample), 2);
if (invert_input) sample *= -1;
demod(sample / 44000.0);
}
break;
}


}

std::cerr << std::endl;
Expand Down
136 changes: 103 additions & 33 deletions apps/m17-mod.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ struct Config
bool verbose = false;
bool debug = false;
bool quiet = false;
bool bitstream = false; // default is baseband audio

bool bin = false;
bool sym = false;
bool rrc = true; // default is rrc

bool bert = false; // Bit error rate testing.
bool invert = false;
int can = 10;
Expand Down Expand Up @@ -81,11 +85,12 @@ struct Config
"event device (default is C-Media Electronics Inc. USB Audio Device).")
("key,k", po::value<uint16_t>(&result.key)->default_value(385),
"Linux event code for PTT (default is RADIO).")
("bitstream,b", po::bool_switch(&result.bitstream),
"output bitstream (default is baseband).")
("bin,x", po::bool_switch(&result.bin), "output packed dibits (default is rrc).")
("rrc,r", po::bool_switch(&result.rrc), "output rrc filtered and scaled symbols (default).")
("sym,s", po::bool_switch(&result.sym), "output symbols (default is rrc).")
("bert,B", po::bool_switch(&result.bert),
"output a bit error rate test stream (default is read audio from STDIN).")
("invert,i", po::bool_switch(&result.invert), "invert the output baseband (ignored for bitstream)")
("invert,i", po::bool_switch(&result.invert), "invert the output baseband (only for rrc)")
("verbose,v", po::bool_switch(&result.verbose), "verbose output")
("debug,d", po::bool_switch(&result.debug), "debug-level output")
("quiet,q", po::bool_switch(&result.quiet), "silence all output")
Expand Down Expand Up @@ -140,6 +145,13 @@ struct Config
return std::nullopt;
}

if (result.sym + result.bin + result.rrc > 1)
{
std::cerr << "Only one of sym, bin or rrc may be chosen." << std::endl;
return std::nullopt;
}


return result;
}
};
Expand All @@ -150,7 +162,9 @@ using lsf_t = std::array<uint8_t, 30>;

std::atomic<bool> running{false};

bool bitstream = false;
enum class OutputType {SYM, BIN, RRC};

OutputType outputType = OutputType::RRC;
bool invert = false;
int8_t can = 10;

Expand Down Expand Up @@ -226,6 +240,7 @@ std::array<int16_t, N*10> symbols_to_baseband(std::array<int8_t, N> symbols)

using bitstream_t = std::array<int8_t, 368>;

// bin
void output_bitstream(std::array<uint8_t, 2> sync_word, const bitstream_t& frame)
{
for (auto c : sync_word) std::cout << c;
Expand All @@ -241,6 +256,20 @@ void output_bitstream(std::array<uint8_t, 2> sync_word, const bitstream_t& frame
}
}

// sym
void output_symbols(std::array<uint8_t, 2> sync_word, const bitstream_t& frame)
{
auto symbols = bits_to_symbols(frame);
auto sw = bytes_to_symbols(sync_word);

std::array<int8_t, 192> temp;
auto fit = std::copy(sw.begin(), sw.end(), temp.begin());
std::copy(symbols.begin(), symbols.end(), fit);
for (auto b : temp) std::cout << b;
}


// rrc
void output_baseband(std::array<uint8_t, 2> sync_word, const bitstream_t& frame)
{
auto symbols = bits_to_symbols(frame);
Expand All @@ -257,8 +286,18 @@ void output_baseband(std::array<uint8_t, 2> sync_word, const bitstream_t& frame)

void output_frame(std::array<uint8_t, 2> sync_word, const bitstream_t& frame)
{
if (bitstream) output_bitstream(sync_word, frame);
else output_baseband(sync_word, frame);
switch(outputType)
{
case OutputType::SYM:
output_symbols(sync_word, frame);
break;
case OutputType::BIN:
output_bitstream(sync_word, frame);
break;
default: // OutputType::RRC
output_baseband(sync_word, frame);
break;
}
}

void send_preamble()
Expand All @@ -267,15 +306,23 @@ void send_preamble()
std::cerr << "Sending preamble." << std::endl;
std::array<uint8_t, 48> preamble_bytes;
preamble_bytes.fill(0x77);
if (bitstream)
{
for (auto c : preamble_bytes) std::cout << c;
}
else // baseband
{
auto preamble_symbols = bytes_to_symbols(preamble_bytes);
auto preamble_baseband = symbols_to_baseband(preamble_symbols);
for (auto b : preamble_baseband) std::cout << uint8_t(b & 0xFF) << uint8_t(b >> 8);
switch(outputType) {
case OutputType::SYM:
{
auto preamble_symbols = bytes_to_symbols(preamble_bytes);
for (auto b : preamble_symbols) std::cout << b;
}
break;
case OutputType::BIN:
for (auto c : preamble_bytes) std::cout << c;
break;
default:
{ // OutputType::RRC
auto preamble_symbols = bytes_to_symbols(preamble_bytes);
auto preamble_baseband = symbols_to_baseband(preamble_symbols);
for (auto b : preamble_baseband) std::cout << uint8_t(b & 0xFF) << uint8_t(b >> 8);
}
break;
}
}

Expand All @@ -288,22 +335,36 @@ constexpr std::array<uint8_t, 2> EOT_SYNC = { 0x55, 0x5D };

void output_eot()
{
if (bitstream)
{
for (auto c : EOT_SYNC) std::cout << c;
for (size_t i = 0; i !=10; ++i) std::cout << '\0'; // Flush RRC FIR Filter.
}
else
{
std::array<int8_t, 48> out_symbols; // EOT symbols + FIR flush.
out_symbols.fill(0);
auto symbols = bytes_to_symbols(EOT_SYNC);
for (size_t i = 0; i != symbols.size(); ++i)
{
out_symbols[i] = symbols[i];
}
auto baseband = symbols_to_baseband(out_symbols);
for (auto b : baseband) std::cout << uint8_t(b & 0xFF) << uint8_t(b >> 8);
switch(outputType) {
case OutputType::SYM:
{
std::array<int8_t, 48> out_symbols; // EOT symbols + FIR flush.
out_symbols.fill(0);
auto symbols = bytes_to_symbols(EOT_SYNC);
for (size_t i = 0; i != symbols.size(); ++i)
{
out_symbols[i] = symbols[i];
}
for (auto b : out_symbols) std::cout << b;
}
break;
case OutputType::BIN:
for (auto c : EOT_SYNC) std::cout << c;
for (size_t i = 0; i !=10; ++i) std::cout << '\0'; // Flush RRC FIR Filter.
break;
default:
{ // OutputType::RRC
std::array<int8_t, 48> out_symbols; // EOT symbols + FIR flush.
out_symbols.fill(0);
auto symbols = bytes_to_symbols(EOT_SYNC);
for (size_t i = 0; i != symbols.size(); ++i)
{
out_symbols[i] = symbols[i];
}
auto baseband = symbols_to_baseband(out_symbols);
for (auto b : baseband) std::cout << uint8_t(b & 0xFF) << uint8_t(b >> 8);
}
break;
}
}

Expand Down Expand Up @@ -632,7 +693,16 @@ int main(int argc, char* argv[])
auto config = Config::parse(argc, argv);
if (!config) return 0;

bitstream = config->bitstream;
if (config->sym) {
outputType = OutputType::SYM;
}
else if (config->bin) {
outputType = OutputType::BIN;
}
else {
outputType = OutputType::RRC;
}

invert = config->invert;
can = config->can;

Expand Down