Skip to content

Commit

Permalink
Snapshot of v2 WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
mutability committed Feb 19, 2019
1 parent da67165 commit bca55d8
Show file tree
Hide file tree
Showing 28 changed files with 4,018 additions and 340 deletions.
364 changes: 24 additions & 340 deletions LICENSE

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
CC=gcc
CFLAGS+=-Wall -Werror -O2 -g -Ilibs

CXX=g++
CXXFLAGS+=-std=c++11 -Wall -Werror -O2 -g -Ilibs

LIBS=-lboost_system -lboost_program_options -lboost_regex -lSoapySDR -lpthread

all: dump978 faup978

dump978: dump978_main.o socket_output.o message_dispatch.o fec.o libs/fec/init_rs_char.o libs/fec/decode_rs_char.o sample_source.o soapy_source.o convert.o demodulator.o uat_message.o
$(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)

faup978: faup978_main.o socket_input.o uat_message.o track.o
$(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)

clean:
rm -f *.o fec/*.o dump978 faup978
24 changes: 24 additions & 0 deletions common.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// -*- c++ -*-

// Copyright (c) 2019, FlightAware LLC.
// All rights reserved.
// Licensed under the 2-clause BSD license; see the LICENSE file

#ifndef UAT_COMMON_H
#define UAT_COMMON_H

#include <vector>
#include <cstdint>
#include <cmath>

namespace uat {
typedef std::vector<std::uint8_t> Bytes;
typedef std::vector<std::uint16_t> PhaseBuffer;

inline static double RoundN(double value, unsigned dp) {
const double scale = std::pow(10, dp);
return std::round(value * scale) / scale;
}
};

#endif
158 changes: 158 additions & 0 deletions convert.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
// Copyright (c) 2019, FlightAware LLC.
// All rights reserved.
// Licensed under the 2-clause BSD license; see the LICENSE file

#include "convert.h"

#include <cmath>
#include <assert.h>

// TODO: This probably needs PhaseBuffer to use a POD-vector-like thing (not
// std::vector) to run at an acceptable speed. Profile it and check.

namespace dump978 {
static inline std::uint16_t scaled_atan2(double y, double x) {
double ang = std::atan2(y, x) + M_PI; // atan2 returns [-pi..pi], normalize to [0..2*pi]
double scaled_ang = std::round(32768 * ang / M_PI);
return scaled_ang < 0 ? 0 : scaled_ang > 65535 ? 65535 : (std::uint16_t)scaled_ang;
}

SampleConverter::Pointer SampleConverter::Create(SampleFormat format) {
switch (format) {
case SampleFormat::CU8:
return Pointer(new CU8Converter());
case SampleFormat::CS8:
return Pointer(new CS8Converter());
case SampleFormat::CS16H:
return Pointer(new CS16HConverter());
case SampleFormat::CF32H:
return Pointer(new CF32HConverter());
default:
throw std::runtime_error("format not implemented yet");
}
}

CU8Converter::CU8Converter() {
cu8_alias u;

unsigned i,q;
for (i = 0; i < 256; ++i) {
double d_i = (i - 127.5);
for (q = 0; q < 256; ++q) {
double d_q = (q - 127.5);
u.iq[0] = i;
u.iq[1] = q;
lookup_[u.iq16] = scaled_atan2(d_q, d_i);
}
}
}

void CU8Converter::Convert(const uat::Bytes &in, uat::PhaseBuffer &out) {
const cu8_alias *in_iq = reinterpret_cast<const cu8_alias*>(in.data());

// unroll the loop
const auto n = in.size() / 2;
const auto n8 = n / 8;
const auto n7 = n & 7;

out.reserve(out.size() + n);
for (unsigned i = 0; i < n8; ++i, in_iq += 8) {
out.push_back(lookup_[in_iq[0].iq16]);
out.push_back(lookup_[in_iq[1].iq16]);
out.push_back(lookup_[in_iq[2].iq16]);
out.push_back(lookup_[in_iq[3].iq16]);
out.push_back(lookup_[in_iq[4].iq16]);
out.push_back(lookup_[in_iq[5].iq16]);
out.push_back(lookup_[in_iq[6].iq16]);
out.push_back(lookup_[in_iq[7].iq16]);
}
for (unsigned i = 0; i < n7; ++i, ++in_iq) {
out.push_back(lookup_[in_iq[0].iq16]);
}
}

CS8Converter::CS8Converter() {
cs8_alias u;

int i,q;
for (i = -128; i <= 127; ++i) {
for (q = -128; q <= 127; ++q) {
u.iq[0] = i;
u.iq[1] = q;
lookup_[u.iq16] = scaled_atan2(q, i);
}
}
}

void CS8Converter::Convert(const uat::Bytes &in, uat::PhaseBuffer &out) {
const cs8_alias *in_iq = reinterpret_cast<const cs8_alias*>(in.data());

// unroll the loop
const auto n = in.size() / 2;
const auto n8 = n / 8;
const auto n7 = n & 7;

out.reserve(out.size() + n);
for (unsigned i = 0; i < n8; ++i, in_iq += 8) {
out.push_back(lookup_[in_iq[0].iq16]);
out.push_back(lookup_[in_iq[1].iq16]);
out.push_back(lookup_[in_iq[2].iq16]);
out.push_back(lookup_[in_iq[3].iq16]);
out.push_back(lookup_[in_iq[4].iq16]);
out.push_back(lookup_[in_iq[5].iq16]);
out.push_back(lookup_[in_iq[6].iq16]);
out.push_back(lookup_[in_iq[7].iq16]);
}
for (unsigned i = 0; i < n7; ++i, ++in_iq) {
out.push_back(lookup_[in_iq[0].iq16]);
}
}

void CS16HConverter::Convert(const uat::Bytes &in, uat::PhaseBuffer &out) {
const std::int16_t *in_iq = reinterpret_cast<const std::int16_t*>(in.data());

// unroll the loop
const auto n = in.size() / 4;
const auto n8 = n / 8;
const auto n7 = n & 7;

out.reserve(out.size() + n);
for (unsigned i = 0; i < n8; ++i, in_iq += 8) {
out.push_back(scaled_atan2(in_iq[1], in_iq[0]));
out.push_back(scaled_atan2(in_iq[3], in_iq[2]));
out.push_back(scaled_atan2(in_iq[5], in_iq[4]));
out.push_back(scaled_atan2(in_iq[7], in_iq[6]));
out.push_back(scaled_atan2(in_iq[9], in_iq[8]));
out.push_back(scaled_atan2(in_iq[11], in_iq[10]));
out.push_back(scaled_atan2(in_iq[13], in_iq[12]));
out.push_back(scaled_atan2(in_iq[15], in_iq[14]));
}
for (unsigned i = 0; i < n7; ++i, ++in_iq) {
out.push_back(scaled_atan2(in_iq[1], in_iq[0]));
}
}

void CF32HConverter::Convert(const uat::Bytes &in, uat::PhaseBuffer &out) {
const double *in_iq = reinterpret_cast<const double*>(in.data());

// unroll the loop
const auto n = in.size() / 8;
const auto n8 = n / 8;
const auto n7 = n & 7;

out.reserve(out.size() + n);
for (unsigned i = 0; i < n8; ++i, in_iq += 8) {
out.push_back(scaled_atan2(in_iq[1], in_iq[0]));
out.push_back(scaled_atan2(in_iq[3], in_iq[2]));
out.push_back(scaled_atan2(in_iq[5], in_iq[4]));
out.push_back(scaled_atan2(in_iq[7], in_iq[6]));
out.push_back(scaled_atan2(in_iq[9], in_iq[8]));
out.push_back(scaled_atan2(in_iq[11], in_iq[10]));
out.push_back(scaled_atan2(in_iq[13], in_iq[12]));
out.push_back(scaled_atan2(in_iq[15], in_iq[14]));
}
for (unsigned i = 0; i < n7; ++i, ++in_iq) {
out.push_back(scaled_atan2(in_iq[15], in_iq[14]));
}
}
}
91 changes: 91 additions & 0 deletions convert.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// -*- c++ -*-

// Copyright (c) 2019, FlightAware LLC.
// All rights reserved.
// Licensed under the 2-clause BSD license; see the LICENSE file

#ifndef DUMP978_CONVERT_H
#define DUMP978_CONVERT_H

#include <memory>

#include "common.h"

namespace dump978 {
// Describes a sample data layout:
// CU8 - interleaved I/Q data, 8 bit unsigned integers
// CS8 - interleaved I/Q data, 8 bit signed integers
// CS16H - interleaved I/Q data, 16 bit signed integers, host byte order
// CF32H - interleaved I/Q data, 32 bit signed floats, host byte order
enum class SampleFormat { CU8, CS8, CS16H, CF32H, UNKNOWN };

// Return the number of bytes for 1 sample in the given format
inline static unsigned BytesPerSample(SampleFormat f) {
switch (f) {
case SampleFormat::CU8: return 2;
case SampleFormat::CS8: return 2;
case SampleFormat::CS16H: return 4;
case SampleFormat::CF32H: return 8;
default: return 0;
}
}

// Base class for all sample converters.
// Use SampleConverter::Create to build converters.
class SampleConverter {
public:
typedef std::shared_ptr<SampleConverter> Pointer;

virtual ~SampleConverter() {};

// Read samples from `in` and append one phase value per sample to `out`.
// The input buffer should contain an integral number of samples (trailing
// partial samples are ignored, not buffered)
virtual void Convert(const uat::Bytes &in, uat::PhaseBuffer &out) = 0;

// Return a new SampleConverter that converts from the given format
static Pointer Create(SampleFormat format);
};

class CU8Converter : public SampleConverter {
public:
CU8Converter();

void Convert(const uat::Bytes &in, uat::PhaseBuffer &out) override;

private:
union cu8_alias {
std::uint8_t iq[2];
std::uint16_t iq16;
};

std::array<std::uint16_t,65536> lookup_;
};

class CS8Converter : public SampleConverter {
public:
CS8Converter();

void Convert(const uat::Bytes &in, uat::PhaseBuffer &out) override;

private:
union cs8_alias {
std::int8_t iq[2];
std::uint16_t iq16;
};

std::array<std::uint16_t,65536> lookup_;
};

class CS16HConverter : public SampleConverter {
public:
void Convert(const uat::Bytes &in, uat::PhaseBuffer &out) override;
};

class CF32HConverter : public SampleConverter {
public:
void Convert(const uat::Bytes &in, uat::PhaseBuffer &out) override;
};
};

#endif
Loading

0 comments on commit bca55d8

Please sign in to comment.