2022-07-04 17:03:07 -04:00
|
|
|
// Copyright 2020-2021 Rob Riggs <rob@modemm17.com>
|
2022-06-06 21:22:18 -04:00
|
|
|
// All rights reserved.
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "ClockRecovery.h"
|
|
|
|
#include "Correlator.h"
|
|
|
|
#include "DataCarrierDetect.h"
|
|
|
|
#include "FirFilter.h"
|
|
|
|
#include "FreqDevEstimator.h"
|
|
|
|
#include "M17FrameDecoder.h"
|
|
|
|
#include "M17Framer.h"
|
|
|
|
#include "Util.h"
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <array>
|
|
|
|
#include <functional>
|
|
|
|
#include <optional>
|
|
|
|
#include <tuple>
|
|
|
|
|
2022-06-10 13:17:56 -04:00
|
|
|
#include "export.h"
|
2022-06-06 21:22:18 -04:00
|
|
|
|
2022-07-04 17:03:07 -04:00
|
|
|
namespace modemm17 {
|
2022-06-06 21:22:18 -04:00
|
|
|
|
2022-06-10 13:17:56 -04:00
|
|
|
struct M17_API M17Demodulator
|
2022-06-06 21:22:18 -04:00
|
|
|
{
|
|
|
|
static const uint16_t SAMPLE_RATE = 48000;
|
|
|
|
static const uint16_t SYMBOL_RATE = 4800;
|
|
|
|
static const uint16_t SAMPLES_PER_SYMBOL = SAMPLE_RATE / SYMBOL_RATE;
|
|
|
|
static const uint16_t BLOCK_SIZE = 192;
|
|
|
|
|
2022-06-09 14:12:35 -04:00
|
|
|
static constexpr float sample_rate = SAMPLE_RATE;
|
|
|
|
static constexpr float symbol_rate = SYMBOL_RATE;
|
2022-06-06 21:22:18 -04:00
|
|
|
|
|
|
|
static const uint8_t MAX_MISSING_SYNC = 8;
|
|
|
|
|
2022-06-09 14:12:35 -04:00
|
|
|
using collelator_t = Correlator;
|
2022-06-06 21:22:18 -04:00
|
|
|
using sync_word_t = SyncWord<collelator_t>;
|
|
|
|
using callback_t = M17FrameDecoder::callback_t;
|
2022-07-06 01:01:42 -04:00
|
|
|
using diagnostic_callback_t = std::function<void(bool, float, float, float, int, int, float, int, int, int, int)>;
|
2022-06-06 21:22:18 -04:00
|
|
|
|
|
|
|
enum class DemodState {
|
|
|
|
UNLOCKED,
|
|
|
|
LSF_SYNC,
|
|
|
|
STREAM_SYNC,
|
|
|
|
PACKET_SYNC,
|
|
|
|
BERT_SYNC,
|
|
|
|
FRAME
|
|
|
|
};
|
|
|
|
|
2022-06-09 14:12:35 -04:00
|
|
|
DataCarrierDetect<SAMPLE_RATE, 500> dcd{2500, 4000, 1.0, 4.0};
|
|
|
|
ClockRecovery<SAMPLE_RATE, SYMBOL_RATE> clock_recovery;
|
2022-06-06 21:22:18 -04:00
|
|
|
|
2022-06-16 20:25:34 -04:00
|
|
|
sync_word_t preamble_sync{{+3, -3, +3, -3, +3, -3, +3, -3}, 29.f};
|
|
|
|
sync_word_t lsf_sync{ {+3, +3, +3, +3, -3, -3, +3, -3}, 32.f, -31.f}; // LSF or STREAM (inverted)
|
|
|
|
sync_word_t packet_sync{ {+3, -3, +3, +3, -3, -3, -3, -3}, 31.f, -31.f}; // PACKET or BERT (inverted)
|
2022-06-06 21:22:18 -04:00
|
|
|
|
2022-06-09 14:12:35 -04:00
|
|
|
FreqDevEstimator dev;
|
|
|
|
float idev;
|
2022-06-06 21:22:18 -04:00
|
|
|
size_t count_ = 0;
|
|
|
|
|
|
|
|
int8_t polarity = 1;
|
|
|
|
M17Framer<368> framer;
|
|
|
|
M17FrameDecoder decoder;
|
|
|
|
DemodState demodState = DemodState::UNLOCKED;
|
|
|
|
M17FrameDecoder::SyncWordType sync_word_type = M17FrameDecoder::SyncWordType::LSF;
|
|
|
|
uint8_t sample_index = 0;
|
|
|
|
|
|
|
|
bool dcd_ = false;
|
|
|
|
bool need_clock_reset_ = false;
|
|
|
|
bool need_clock_update_ = false;
|
|
|
|
|
|
|
|
bool passall_ = false;
|
|
|
|
int viterbi_cost = 0;
|
|
|
|
int sync_count = 0;
|
|
|
|
int missing_sync_count = 0;
|
|
|
|
uint8_t sync_sample_index = 0;
|
|
|
|
diagnostic_callback_t diagnostic_callback;
|
|
|
|
|
|
|
|
M17Demodulator(callback_t callback) :
|
2022-06-16 20:25:34 -04:00
|
|
|
decoder(callback),
|
|
|
|
initializing_count_(1920)
|
|
|
|
{
|
|
|
|
demodState = DemodState::UNLOCKED;
|
|
|
|
}
|
2022-06-06 21:22:18 -04:00
|
|
|
|
|
|
|
virtual ~M17Demodulator() {}
|
|
|
|
|
|
|
|
void dcd_on();
|
|
|
|
void dcd_off();
|
2022-06-09 14:12:35 -04:00
|
|
|
void initialize(const float input);
|
2022-06-06 21:22:18 -04:00
|
|
|
void update_dcd();
|
|
|
|
void do_unlocked();
|
|
|
|
void do_lsf_sync();
|
|
|
|
void do_packet_sync();
|
|
|
|
void do_stream_sync();
|
|
|
|
void do_bert_sync();
|
2022-06-09 14:12:35 -04:00
|
|
|
void do_frame(float filtered_sample);
|
2022-06-06 21:22:18 -04:00
|
|
|
|
2022-06-16 20:25:34 -04:00
|
|
|
bool locked() const {
|
2022-06-06 21:22:18 -04:00
|
|
|
return dcd_;
|
|
|
|
}
|
|
|
|
|
2022-06-16 20:25:34 -04:00
|
|
|
void passall(bool enabled) {
|
|
|
|
passall_ = enabled;
|
2022-06-06 21:22:18 -04:00
|
|
|
// decoder.passall(enabled);
|
|
|
|
}
|
|
|
|
|
|
|
|
void diagnostics(diagnostic_callback_t callback)
|
|
|
|
{
|
|
|
|
diagnostic_callback = callback;
|
|
|
|
}
|
|
|
|
|
|
|
|
void update_values(uint8_t index);
|
2022-06-09 14:12:35 -04:00
|
|
|
void operator()(const float input);
|
2022-06-06 21:22:18 -04:00
|
|
|
|
|
|
|
private:
|
2022-06-09 14:12:35 -04:00
|
|
|
static const std::array<float, 150> rrc_taps;
|
|
|
|
BaseFirFilter<rrc_taps.size()> demod_filter{rrc_taps};
|
2022-06-16 20:25:34 -04:00
|
|
|
collelator_t correlator;
|
|
|
|
int16_t initializing_count_;
|
2022-06-06 21:22:18 -04:00
|
|
|
};
|
|
|
|
|
2022-07-04 17:03:07 -04:00
|
|
|
} // modemm17
|