1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-25 09:18:54 -05:00

M17 demod: fixed BERT

This commit is contained in:
f4exb 2022-07-06 07:01:42 +02:00
parent 1fa3adb669
commit c3f55af6a6
14 changed files with 125 additions and 45 deletions

View File

@ -49,6 +49,8 @@ add_library(modems SHARED
${modems_SOURCES} ${modems_SOURCES}
) )
target_link_libraries(modems) target_link_libraries(modems
Qt5::Core
)
install(TARGETS modems DESTINATION ${INSTALL_LIB_DIR}) install(TARGETS modems DESTINATION ${INSTALL_LIB_DIR})

View File

@ -1,3 +1,6 @@
#include <QDebug>
#include <QString>
#include "M17Demodulator.h" #include "M17Demodulator.h"
namespace modemm17 { namespace modemm17 {
@ -103,6 +106,7 @@ void M17Demodulator::dcd_off()
dev.deviation(), dev.deviation(),
dev.offset(), dev.offset(),
(int) demodState, (int) demodState,
(int) sync_word_type,
clock_recovery.clock_estimate(), clock_recovery.clock_estimate(),
sample_index, sample_index,
sync_sample_index, sync_sample_index,
@ -210,7 +214,7 @@ void M17Demodulator::do_lsf_sync()
if (sync_triggered > 0.1) if (sync_triggered > 0.1)
{ {
std::cerr << "M17Demodulator::do_lsf_sync: preamble:" << sync_triggered << std::endl; qDebug() << "modemm17::M17Demodulator::do_lsf_sync: preamble:" << sync_triggered;
return; return;
} }
@ -218,11 +222,11 @@ void M17Demodulator::do_lsf_sync()
bert_triggered = packet_sync.triggered(correlator); bert_triggered = packet_sync.triggered(correlator);
if (sync_triggered != 0) { if (sync_triggered != 0) {
std::cerr << "M17Demodulator::do_lsf_sync: sync_triggered:" << sync_triggered << std::endl; qDebug() << "modemm17::M17Demodulator::do_lsf_sync: sync_triggered:" << sync_triggered;
} }
if (bert_triggered != 0) { if (bert_triggered != 0) {
std::cerr << "M17Demodulator::do_lsf_sync: bert_triggered:" << bert_triggered << std::endl; qDebug() << "modemm17::M17Demodulator::do_lsf_sync: bert_triggered:" << bert_triggered;
} }
if (bert_triggered < 0) if (bert_triggered < 0)
@ -232,7 +236,7 @@ void M17Demodulator::do_lsf_sync()
update_values(sample_index); update_values(sample_index);
demodState = DemodState::FRAME; demodState = DemodState::FRAME;
sync_word_type = M17FrameDecoder::SyncWordType::BERT; sync_word_type = M17FrameDecoder::SyncWordType::BERT;
std::cerr << "M17Demodulator::do_lsf_sync: BERT:" << (int) sync_word_type << std::endl; qDebug() << "modemm17::M17Demodulator::do_lsf_sync: BERT:" << (int) sync_word_type;
} }
else if (bert_triggered > 0) else if (bert_triggered > 0)
{ {
@ -241,7 +245,7 @@ void M17Demodulator::do_lsf_sync()
update_values(sample_index); update_values(sample_index);
demodState = DemodState::FRAME; demodState = DemodState::FRAME;
sync_word_type = M17FrameDecoder::SyncWordType::PACKET; sync_word_type = M17FrameDecoder::SyncWordType::PACKET;
std::cerr << "M17Demodulator::do_lsf_sync: PACKET:" << (int) sync_word_type << std::endl; qDebug() << "modemm17::M17Demodulator::do_lsf_sync: PACKET:" << (int) sync_word_type;
} }
else if (std::abs(sync_triggered) > 0.1) else if (std::abs(sync_triggered) > 0.1)
{ {
@ -253,13 +257,13 @@ void M17Demodulator::do_lsf_sync()
{ {
demodState = DemodState::FRAME; demodState = DemodState::FRAME;
sync_word_type = M17FrameDecoder::SyncWordType::LSF; sync_word_type = M17FrameDecoder::SyncWordType::LSF;
std::cerr << "M17Demodulator::do_lsf_sync: LSF:" << (int) sync_word_type << std::endl; qDebug() << "modemm17::M17Demodulator::do_lsf_sync: LSF:" << (int) sync_word_type;
} }
else else
{ {
demodState = DemodState::FRAME; demodState = DemodState::FRAME;
sync_word_type = M17FrameDecoder::SyncWordType::STREAM; sync_word_type = M17FrameDecoder::SyncWordType::STREAM;
std::cerr << "M17Demodulator::do_lsf_sync: STREAM:" << (int) sync_word_type << std::endl; qDebug() << "modemm17::M17Demodulator::do_lsf_sync: STREAM:" << (int) sync_word_type;
} }
} }
else if (++missing_sync_count > 192) else if (++missing_sync_count > 192)
@ -267,7 +271,7 @@ void M17Demodulator::do_lsf_sync()
demodState = DemodState::UNLOCKED; demodState = DemodState::UNLOCKED;
decoder.reset(); decoder.reset();
missing_sync_count = 0; missing_sync_count = 0;
std::cerr << "M17Demodulator::do_lsf_sync: UNLOCKED:" << (int) sync_word_type << std::endl; qDebug() << "modemm17::M17Demodulator::do_lsf_sync: UNLOCKED:" << (int) sync_word_type;
} }
else else
{ {
@ -403,7 +407,6 @@ void M17Demodulator::do_frame(float filtered_sample)
if (len != 0) if (len != 0)
{ {
// std::cerr << "M17Demodulator::do_frame: sync_word_type:" << (int) sync_word_type << " len:" << len << std::endl;
need_clock_update_ = true; need_clock_update_ = true;
M17FrameDecoder::input_buffer_t buffer; M17FrameDecoder::input_buffer_t buffer;
std::copy(tmp, tmp + len, buffer.begin()); std::copy(tmp, tmp + len, buffer.begin());
@ -411,6 +414,11 @@ void M17Demodulator::do_frame(float filtered_sample)
cost_count = viterbi_cost > 90 ? cost_count + 1 : 0; cost_count = viterbi_cost > 90 ? cost_count + 1 : 0;
cost_count = viterbi_cost > 100 ? cost_count + 1 : cost_count; cost_count = viterbi_cost > 100 ? cost_count + 1 : cost_count;
cost_count = viterbi_cost > 110 ? cost_count + 1 : cost_count; cost_count = viterbi_cost > 110 ? cost_count + 1 : cost_count;
// qDebug() << "modemm17::M17Demodulator::do_frame: "
// << "sync_word_type:" << (int) sync_word_type
// << " len:" << len
// << " viterbi_cost: " << viterbi_cost
// << " cost_count" << cost_count;
if (cost_count > 75) if (cost_count > 75)
{ {
@ -487,6 +495,7 @@ void M17Demodulator::operator()(const float input)
dev.deviation(), dev.deviation(),
dev.offset(), dev.offset(),
(int) demodState, (int) demodState,
(int) sync_word_type,
clock_recovery.clock_estimate(), clock_recovery.clock_estimate(),
sample_index, sample_index,
sync_sample_index, sync_sample_index,
@ -575,6 +584,7 @@ void M17Demodulator::operator()(const float input)
dev.deviation(), dev.deviation(),
dev.offset(), dev.offset(),
(int) demodState, (int) demodState,
(int) sync_word_type,
clock_recovery.clock_estimate(), clock_recovery.clock_estimate(),
sample_index, sample_index,
sync_sample_index, sync_sample_index,

View File

@ -37,7 +37,7 @@ struct M17_API M17Demodulator
using collelator_t = Correlator; using collelator_t = Correlator;
using sync_word_t = SyncWord<collelator_t>; using sync_word_t = SyncWord<collelator_t>;
using callback_t = M17FrameDecoder::callback_t; using callback_t = M17FrameDecoder::callback_t;
using diagnostic_callback_t = std::function<void(bool, float, float, float, int, float, int, int, int, int)>; using diagnostic_callback_t = std::function<void(bool, float, float, float, int, int, float, int, int, int, int)>;
enum class DemodState { enum class DemodState {
UNLOCKED, UNLOCKED,

View File

@ -2,6 +2,9 @@
#pragma once #pragma once
#include <QDebug>
#include <QString>
#include "M17Randomizer.h" #include "M17Randomizer.h"
#include "PolynomialInterleaver.h" #include "PolynomialInterleaver.h"
#include "Trellis.h" #include "Trellis.h"
@ -22,15 +25,16 @@ namespace modemm17
template <typename C, size_t N> template <typename C, size_t N>
void dump(const std::array<C,N>& data, char header = 'D') QString dump(const std::array<C,N>& data, char header = 'D')
{ {
std::cerr << header << " = "; QString s(header);
s += "=";
for (auto c : data) { for (auto c : data) {
std::cerr << std::hex << std::setw(2) << std::setfill('0') << (int) c << " "; s += QString("%1 ").arg((int) c, 2, 16, QChar('0'));
} }
std::cerr << std::dec << std::endl; return s;
} }
struct M17FrameDecoder struct M17FrameDecoder
@ -153,8 +157,7 @@ struct M17FrameDecoder
viterbi_cost = viterbi_.decode(depuncture_buffer.lsf, decode_buffer.lsf); viterbi_cost = viterbi_.decode(depuncture_buffer.lsf, decode_buffer.lsf);
to_byte_array(decode_buffer.lsf, output_buffer.lsf); to_byte_array(decode_buffer.lsf, output_buffer.lsf);
// std::cerr << "M17FrameDecoder::decode_lsf: vierbi:" << viterbi_cost << std::endl; // qDebug() << "modemm17::M17FrameDecoder::decode_lsf: vierbi:" << viterbi_cost <<dump(output_buffer.lsf);
// dump(output_buffer.lsf);
crc_.reset(); crc_.reset();
for (auto c : output_buffer.lsf) crc_(c); for (auto c : output_buffer.lsf) crc_(c);
@ -169,8 +172,7 @@ struct M17FrameDecoder
} }
else else
{ {
std::cerr << "M17FrameDecoder::decode_lsf: bad CRC:" << std::endl; qDebug() << "modemm17::M17FrameDecoder::decode_lsf: bad CRC:" << dump(output_buffer.lsf);
dump(output_buffer.lsf);
} }
lich_segments = 0; lich_segments = 0;
@ -262,9 +264,10 @@ struct M17FrameDecoder
return DecodeResult::INCOMPLETE; return DecodeResult::INCOMPLETE;
} }
DecodeResult decode_bert(input_buffer_t&, int& viterbi_cost) DecodeResult decode_bert(input_buffer_t& buffer, int& viterbi_cost)
{ {
depunctured_buffer_t depuncture_buffer; depunctured_buffer_t depuncture_buffer;
depuncture(buffer, depuncture_buffer.bert, P2);
viterbi_cost = viterbi_.decode(depuncture_buffer.bert, decode_buffer.bert); viterbi_cost = viterbi_.decode(depuncture_buffer.bert, decode_buffer.bert);
to_byte_array(decode_buffer.bert, output_buffer.bert); to_byte_array(decode_buffer.bert, output_buffer.bert);

View File

@ -1,5 +1,8 @@
#pragma once #pragma once
#include <QDebug>
#include <QString>
#include "FirFilter.h" #include "FirFilter.h"
#include "LinkSetupFrame.h" #include "LinkSetupFrame.h"
#include "CRC16.h" #include "CRC16.h"
@ -177,7 +180,7 @@ public:
auto size = puncture(encoded, punctured, P1); auto size = puncture(encoded, punctured, P1);
if (size != 368) { if (size != 368) {
std::cerr << "modemm17::M17Modulator::make_lsf: incorrect size (not 368)" << size; qWarning() << "modemm17::M17Modulator::make_lsf: incorrect size (not 368)" << size;
} }
interleaver.interleave(punctured); interleaver.interleave(punctured);
@ -277,7 +280,7 @@ public:
auto size = modemm17::puncture(encoded, punctured, modemm17::P2); auto size = modemm17::puncture(encoded, punctured, modemm17::P2);
if (size != 272) { if (size != 272) {
std::cerr << "modemm17::M17Modulator::make_stream_data_frame: incorrect size (not 272)" << size; qWarning() << "modemm17::M17Modulator::make_stream_data_frame: incorrect size (not 272)" << size;
} }
return punctured; return punctured;
@ -310,7 +313,9 @@ public:
packet_assembly[25] = 0x80 | ((packet_size+2)<<2); // sent packet size includes CRC packet_assembly[25] = 0x80 | ((packet_size+2)<<2); // sent packet size includes CRC
packet_assembly[packet_size] = crc_.get_bytes()[1]; packet_assembly[packet_size] = crc_.get_bytes()[1];
packet_assembly[packet_size+1] = crc_.get_bytes()[0]; packet_assembly[packet_size+1] = crc_.get_bytes()[0];
std::cerr << "M17Modulator::make_packet_frame:" << std::hex << (int) crc_.get_bytes()[1] << ":" << (int) crc_.get_bytes()[0] << std::endl; qDebug() << QString("modemm17::M17Modulator::make_packet_frame: %1:%2")
.arg((int) crc_.get_bytes()[1], 2, 16, QChar('0'))
.arg((int) crc_.get_bytes()[0], 2, 16, QChar('0'));
} }
else else
{ {
@ -359,7 +364,7 @@ public:
auto size = puncture(encoded, punctured, P3); auto size = puncture(encoded, punctured, P3);
if (size != 368) { if (size != 368) {
std::cerr << "modemm17::M17Modulator::make_packet_frame: incorrect size (not 368)" << size; qWarning() << "modemm17::M17Modulator::make_packet_frame: incorrect size (not 368)" << size;
} }
interleaver.interleave(punctured); interleaver.interleave(punctured);
@ -372,7 +377,7 @@ public:
{ {
std::array<uint8_t, 25> data; // 24.6125 bytes, 197 bits std::array<uint8_t, 25> data; // 24.6125 bytes, 197 bits
// Generate the data. // Generate the data (24*8 = 192 bits).
for (size_t i = 0; i != data.size() - 1; ++i) for (size_t i = 0; i != data.size() - 1; ++i)
{ {
uint8_t byte = 0; uint8_t byte = 0;
@ -386,8 +391,8 @@ public:
data[i] = byte; data[i] = byte;
} }
// Generate the data (last 5 bits).
uint8_t byte = 0; uint8_t byte = 0;
for (int i = 0; i != 5; ++i) for (int i = 0; i != 5; ++i)
{ {
byte <<= 1; byte <<= 1;
@ -397,10 +402,12 @@ public:
byte <<= 3; byte <<= 3;
data[24] = byte; data[24] = byte;
// Convolutional encode
std::array<uint8_t, 402> encoded; std::array<uint8_t, 402> encoded;
size_t index = 0; size_t index = 0;
uint32_t memory = 0; uint32_t memory = 0;
// 24*8 = 192 first bits
for (size_t i = 0; i != data.size() - 1; ++i) for (size_t i = 0; i != data.size() - 1; ++i)
{ {
auto b = data[i]; auto b = data[i];
@ -415,8 +422,8 @@ public:
} }
} }
// last 5 bits
auto b = data[24]; auto b = data[24];
for (size_t j = 0; j != 5; ++j) for (size_t j = 0; j != 5; ++j)
{ {
uint32_t x = (b & 0x80) >> 7; uint32_t x = (b & 0x80) >> 7;
@ -438,7 +445,7 @@ public:
auto size = puncture(encoded, punctured, P2); auto size = puncture(encoded, punctured, P2);
if (size != 368) { if (size != 368) {
std::cerr << "modemm17::M17Modulator::make_bert_frame: incorrect size (not 368)" << size; qWarning() << "modemm17::M17Modulator::make_bert_frame: incorrect size (not 368)" << size;
} }
return punctured; return punctured;

View File

@ -47,7 +47,7 @@ constexpr auto P1 = std::array<int8_t, 61>{
1, 0, 1, 1 // M15 1, 0, 1, 1 // M15
}; };
/// Puncture matrix for audio frames. Rate 6/11. /// Puncture matrix for audio and BERT frames. Rate 11/12.
constexpr auto P2 = std::array<int8_t, 12>{ constexpr auto P2 = std::array<int8_t, 12>{
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 0}; 1, 1, 1, 1, 1, 0};

View File

@ -219,6 +219,7 @@ public:
float& deviation, float& deviation,
float& offset, float& offset,
int& status, int& status,
int& sync_word_type,
float& clock, float& clock,
int& sampleIndex, int& sampleIndex,
int& syncIndex, int& syncIndex,
@ -226,7 +227,19 @@ public:
int& viterbiCost int& viterbiCost
) const ) const
{ {
m_basebandSink->getDiagnostics(dcd, evm, deviation, offset, status, clock, sampleIndex, syncIndex, clockIndex, viterbiCost); m_basebandSink->getDiagnostics(
dcd,
evm,
deviation,
offset,
status,
sync_word_type,
clock,
sampleIndex,
syncIndex,
clockIndex,
viterbiCost
);
} }
uint32_t getLSFCount() const { return m_basebandSink->getLSFCount(); } uint32_t getLSFCount() const { return m_basebandSink->getLSFCount(); }

View File

@ -80,6 +80,7 @@ public:
float& deviation, float& deviation,
float& offset, float& offset,
int& status, int& status,
int& sync_word_type,
float& clock, float& clock,
int& sampleIndex, int& sampleIndex,
int& syncIndex, int& syncIndex,
@ -87,7 +88,19 @@ public:
int& viterbiCost int& viterbiCost
) const ) const
{ {
m_sink.getDiagnostics(dcd, evm, deviation, offset, status, clock, sampleIndex, syncIndex, clockIndex, viterbiCost); m_sink.getDiagnostics(
dcd,
evm,
deviation,
offset,
status,
sync_word_type,
clock,
sampleIndex,
syncIndex,
clockIndex,
viterbiCost
);
} }
uint32_t getLSFCount() const { return m_sink.getLSFCount(); } uint32_t getLSFCount() const { return m_sink.getLSFCount(); }

View File

@ -604,13 +604,26 @@ void M17DemodGUI::tick()
float deviation; float deviation;
float offset; float offset;
int status; int status;
int sync_word_type;
float clock; float clock;
int sampleIndex; int sampleIndex;
int syncIndex; int syncIndex;
int clockIndex; int clockIndex;
int viterbiCost; int viterbiCost;
m_m17Demod->getDiagnostics(dcd, evm, deviation, offset, status, clock, sampleIndex, syncIndex, clockIndex, viterbiCost); m_m17Demod->getDiagnostics(
dcd,
evm,
deviation,
offset,
status,
sync_word_type,
clock,
sampleIndex,
syncIndex,
clockIndex,
viterbiCost
);
if (dcd) { if (dcd) {
ui->dcdLabel->setStyleSheet("QLabel { background-color : green; }"); ui->dcdLabel->setStyleSheet("QLabel { background-color : green; }");
@ -624,7 +637,7 @@ void M17DemodGUI::tick()
ui->lockLabel->setStyleSheet("QLabel { background-color : green; }"); ui->lockLabel->setStyleSheet("QLabel { background-color : green; }");
} }
ui->syncText->setText(getStatus(status, m_m17Demod->getStreamElsePacket(), m_m17Demod->getStdPacketProtocol())); ui->syncText->setText(getStatus(status, sync_word_type, m_m17Demod->getStreamElsePacket(), m_m17Demod->getStdPacketProtocol()));
ui->evmText->setText(tr("%1").arg(evm*100.0f, 3, 'f', 1)); ui->evmText->setText(tr("%1").arg(evm*100.0f, 3, 'f', 1));
ui->deviationText->setText(tr("%1").arg(deviation/1.5f, 3, 'f', 2)); ui->deviationText->setText(tr("%1").arg(deviation/1.5f, 3, 'f', 2));
ui->offsetText->setText(tr("%1").arg(offset/1.5f, 3, 'f', 2)); ui->offsetText->setText(tr("%1").arg(offset/1.5f, 3, 'f', 2));
@ -657,11 +670,11 @@ void M17DemodGUI::tick()
m_tickCount++; m_tickCount++;
} }
QString M17DemodGUI::getStatus(int status, bool streamElsePacket, int packetProtocol) QString M17DemodGUI::getStatus(int status, int sync_word_type, bool streamElsePacket, int packetProtocol)
{ {
if (status == 0) { if (status == 0) {
return "Unlocked"; return "Unlocked";
} else if (status == 4) { } else if ((status == 5) && (sync_word_type == 3)) {
return "BERT"; return "BERT";
} else if (streamElsePacket) { } else if (streamElsePacket) {
return "Stream"; return "Stream";

View File

@ -110,7 +110,7 @@ private:
bool handleMessage(const Message& message); bool handleMessage(const Message& message);
void makeUIConnections(); void makeUIConnections();
void updateAbsoluteCenterFrequency(); void updateAbsoluteCenterFrequency();
QString getStatus(int status, bool streamElsePacket, int packetProtocol); QString getStatus(int status, int sync_word_type, bool streamElsePacket, int packetProtocol);
void packetReceived(QByteArray packet); void packetReceived(QByteArray packet);
void leaveEvent(QEvent*); void leaveEvent(QEvent*);

View File

@ -1370,13 +1370,13 @@
<rect> <rect>
<x>203</x> <x>203</x>
<y>65</y> <y>65</y>
<width>25</width> <width>30</width>
<height>28</height> <height>28</height>
</rect> </rect>
</property> </property>
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>25</width> <width>30</width>
<height>0</height> <height>0</height>
</size> </size>
</property> </property>

View File

@ -102,6 +102,7 @@ void M17DemodProcessor::diagnostic_callback(
float deviation, float deviation,
float offset, float offset,
int status, int status,
int sync_word_type,
float clock, float clock,
int sample_index, int sample_index,
int sync_index, int sync_index,
@ -116,6 +117,7 @@ void M17DemodProcessor::diagnostic_callback(
m_this->m_deviation = deviation; m_this->m_deviation = deviation;
m_this->m_offset = offset; m_this->m_offset = offset;
m_this->m_status = status; m_this->m_status = status;
m_this->m_syncWordType = sync_word_type;
m_this->m_clock = clock; m_this->m_clock = clock;
m_this->m_sampleIndex = sample_index; m_this->m_sampleIndex = sample_index;
m_this->m_syncIndex = sync_index; m_this->m_syncIndex = sync_index;

View File

@ -71,6 +71,7 @@ public:
float& deviation, float& deviation,
float& offset, float& offset,
int& status, int& status,
int& sync_word_type,
float& clock, float& clock,
int& sampleIndex, int& sampleIndex,
int& syncIndex, int& syncIndex,
@ -83,6 +84,7 @@ public:
deviation = m_deviation; deviation = m_deviation;
offset = m_offset; offset = m_offset;
status = m_status; status = m_status;
sync_word_type = m_syncWordType;
clock = m_clock; clock = m_clock;
sampleIndex = m_sampleIndex; sampleIndex = m_sampleIndex;
syncIndex = m_syncIndex; syncIndex = m_syncIndex;
@ -117,6 +119,7 @@ private:
float m_deviation; //!< Estimated deviation. Ideal = 1.0 float m_deviation; //!< Estimated deviation. Ideal = 1.0
float m_offset; //!< Estimated frequency offset. Ideal = 0.0 practically limited to ~[-0.18, 0.18] float m_offset; //!< Estimated frequency offset. Ideal = 0.0 practically limited to ~[-0.18, 0.18]
int m_status; //!< Status int m_status; //!< Status
int m_syncWordType; //!< Sync word type
float m_clock; float m_clock;
int m_sampleIndex; int m_sampleIndex;
int m_syncIndex; int m_syncIndex;
@ -141,6 +144,7 @@ private:
float deviation, float deviation,
float offset, float offset,
int status, int status,
int sync_word_type,
float clock, float clock,
int sample_index, int sample_index,
int sync_index, int sync_index,

View File

@ -82,6 +82,7 @@ public:
float& deviation, float& deviation,
float& offset, float& offset,
int& status, int& status,
int& sync_word_type,
float& clock, float& clock,
int& sampleIndex, int& sampleIndex,
int& syncIndex, int& syncIndex,
@ -89,7 +90,19 @@ public:
int& viterbiCost int& viterbiCost
) const ) const
{ {
m_m17DemodProcessor.getDiagnostics(dcd, evm, deviation, offset, status, clock, sampleIndex, syncIndex, clockIndex, viterbiCost); m_m17DemodProcessor.getDiagnostics(
dcd,
evm,
deviation,
offset,
status,
sync_word_type,
clock,
sampleIndex,
syncIndex,
clockIndex,
viterbiCost
);
} }
uint32_t getLSFCount() const { return m_m17DemodProcessor.getLSFCount(); } uint32_t getLSFCount() const { return m_m17DemodProcessor.getLSFCount(); }