forked from flightaware/dump978
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
da67165
commit bca55d8
Showing
28 changed files
with
4,018 additions
and
340 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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])); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.