M17 mod: implement BERT

This commit is contained in:
f4exb 2022-07-04 22:45:16 +02:00
parent 71c486310a
commit 242a5843d8
9 changed files with 216 additions and 3 deletions

View File

@ -98,7 +98,7 @@ void M17Demodulator::dcd_off()
if (diagnostic_callback)
{
diagnostic_callback(
int(dcd_),
dcd_,
dev.error(),
dev.deviation(),
dev.offset(),
@ -482,7 +482,7 @@ void M17Demodulator::operator()(const float input)
if (diagnostic_callback)
{
diagnostic_callback(
int(dcd_),
dcd_,
dev.error(),
dev.deviation(),
dev.offset(),
@ -570,7 +570,7 @@ void M17Demodulator::operator()(const float input)
if (diagnostic_callback)
{
diagnostic_callback(
int(dcd_),
dcd_,
dev.error(),
dev.deviation(),
dev.offset(),

View File

@ -368,6 +368,82 @@ public:
return punctured;
}
static std::array<int8_t, 368> make_bert_frame(PRBS9& prbs)
{
std::array<uint8_t, 25> data; // 24.6125 bytes, 197 bits
// Generate the data.
for (size_t i = 0; i != data.size() - 1; ++i)
{
uint8_t byte = 0;
for (int i = 0; i != 8; ++i)
{
byte <<= 1;
byte |= prbs.generate();
}
data[i] = byte;
}
uint8_t byte = 0;
for (int i = 0; i != 5; ++i)
{
byte <<= 1;
byte |= prbs.generate();
}
byte <<= 3;
data[24] = byte;
std::array<uint8_t, 402> encoded;
size_t index = 0;
uint32_t memory = 0;
for (size_t i = 0; i != data.size() - 1; ++i)
{
auto b = data[i];
for (size_t j = 0; j != 8; ++j)
{
uint32_t x = (b & 0x80) >> 7;
b <<= 1;
memory = update_memory<4>(memory, x);
encoded[index++] = convolve_bit(031, memory);
encoded[index++] = convolve_bit(027, memory);
}
}
auto b = data[24];
for (size_t j = 0; j != 5; ++j)
{
uint32_t x = (b & 0x80) >> 7;
b <<= 1;
memory = update_memory<4>(memory, x);
encoded[index++] = convolve_bit(031, memory);
encoded[index++] = convolve_bit(027, memory);
}
// Flush the encoder.
for (size_t i = 0; i != 4; ++i)
{
memory = update_memory<4>(memory, 0);
encoded[index++] = convolve_bit(031, memory);
encoded[index++] = convolve_bit(027, memory);
}
std::array<int8_t, 368> punctured;
auto size = puncture(encoded, punctured, P2);
if (size != 368) {
std::cerr << "mobilinkd::M17Modulator::make_bert_frame: incorrect size (not 368)" << size;
}
return punctured;
}
static void interleave_and_randomize(std::array<int8_t, 368>& punctured)
{
M17Randomizer<368> randomizer;

View File

@ -292,6 +292,13 @@ void M17ModGUI::on_packetMode_toggled(bool checked)
applySettings();
}
void M17ModGUI::on_bertMode_toggled(bool checked)
{
m_settings.m_m17Mode = checked ? M17ModSettings::M17ModeM17BERT : M17ModSettings::M17ModeNone;
displayModes();
applySettings();
}
void M17ModGUI::on_sendPacket_clicked(bool)
{
m_m17Mod->sendPacket();
@ -602,6 +609,19 @@ void M17ModGUI::displayModes()
{
ui->packetMode->setChecked(true);
ui->packetMode->setEnabled(true);
ui->bertMode->setChecked(false);
ui->tone->setChecked(false);
ui->mic->setChecked(false);
ui->play->setChecked(false);
ui->bertMode->setEnabled(false);
ui->tone->setEnabled(false);
ui->mic->setEnabled(false);
ui->play->setEnabled(false);
}
if (m_settings.m_m17Mode == M17ModSettings::M17Mode::M17ModeM17BERT)
{
ui->bertMode->setChecked(true);
ui->bertMode->setEnabled(true);
ui->tone->setChecked(false);
ui->mic->setChecked(false);
ui->play->setChecked(false);
@ -614,9 +634,11 @@ void M17ModGUI::displayModes()
ui->tone->setChecked(true);
ui->tone->setEnabled(true);
ui->packetMode->setChecked(false);
ui->bertMode->setChecked(false);
ui->mic->setChecked(false);
ui->play->setChecked(false);
ui->packetMode->setEnabled(false);
ui->bertMode->setEnabled(true);
ui->mic->setEnabled(false);
ui->play->setEnabled(false);
}
@ -625,8 +647,10 @@ void M17ModGUI::displayModes()
{
ui->tone->setChecked(false);
ui->packetMode->setChecked(false);
ui->bertMode->setChecked(false);
ui->tone->setEnabled(false);
ui->packetMode->setEnabled(false);
ui->bertMode->setEnabled(true);
if (m_settings.m_audioType == M17ModSettings::AudioType::AudioInput)
{
@ -653,10 +677,12 @@ void M17ModGUI::displayModes()
else if (m_settings.m_m17Mode == M17ModSettings::M17Mode::M17ModeNone)
{
ui->packetMode->setChecked(false);
ui->bertMode->setChecked(false);
ui->tone->setChecked(false);
ui->mic->setChecked(false);
ui->play->setChecked(false);
ui->packetMode->setEnabled(true);
ui->bertMode->setEnabled(true);
ui->tone->setEnabled(true);
ui->mic->setEnabled(true);
ui->play->setEnabled(true);
@ -792,6 +818,7 @@ void M17ModGUI::makeUIConnections()
QObject::connect(ui->feedbackVolume, &QDial::valueChanged, this, &M17ModGUI::on_feedbackVolume_valueChanged);
QObject::connect(ui->fmAudio, &ButtonSwitch::toggled, this, &M17ModGUI::on_fmAudio_toggled);
QObject::connect(ui->packetMode, &ButtonSwitch::toggled, this, &M17ModGUI::on_packetMode_toggled);
QObject::connect(ui->bertMode, &ButtonSwitch::toggled, this, &M17ModGUI::on_bertMode_toggled);
QObject::connect(ui->sendPacket, &QPushButton::clicked, this, &M17ModGUI::on_sendPacket_clicked);
QObject::connect(ui->loopPacket, &ButtonSwitch::toggled, this, &M17ModGUI::on_loopPacket_toggled);
QObject::connect(ui->loopPacketInterval, &QDial::valueChanged, this, &M17ModGUI::on_loopPacketInterval_valueChanged);

View File

@ -134,6 +134,7 @@ private slots:
void on_feedbackVolume_valueChanged(int value);
void on_packetMode_toggled(bool checked);
void on_bertMode_toggled(bool checked);
void on_sendPacket_clicked(bool checked);
void on_loopPacket_toggled(bool checked);
void on_loopPacketInterval_valueChanged(int value);

View File

@ -858,6 +858,16 @@
</property>
</spacer>
</item>
<item>
<widget class="ButtonSwitch" name="bertMode">
<property name="toolTip">
<string>BERT mode</string>
</property>
<property name="text">
<string>BERT</string>
</property>
</widget>
</item>
</layout>
</item>
<item>

View File

@ -28,6 +28,9 @@ MESSAGE_CLASS_DEFINITION(M17ModProcessor::MsgSendAPRS, Message)
MESSAGE_CLASS_DEFINITION(M17ModProcessor::MsgSendAudioFrame, Message)
MESSAGE_CLASS_DEFINITION(M17ModProcessor::MsgStartAudio, Message)
MESSAGE_CLASS_DEFINITION(M17ModProcessor::MsgStopAudio, Message)
MESSAGE_CLASS_DEFINITION(M17ModProcessor::MsgStartBERT, Message)
MESSAGE_CLASS_DEFINITION(M17ModProcessor::MsgSendBERTFrame, Message)
MESSAGE_CLASS_DEFINITION(M17ModProcessor::MsgStopBERT, Message)
M17ModProcessor::M17ModProcessor() :
m_m17Modulator("MYCALL", ""),
@ -108,6 +111,24 @@ bool M17ModProcessor::handleMessage(const Message& cmd)
audioStop();
return true;
}
else if (MsgStartBERT::match(cmd))
{
qDebug("M17ModProcessor::handleMessage: MsgStartBERT");
m_prbs.reset();
send_preamble(); // preamble
return true;
}
else if (MsgSendBERTFrame::match(cmd))
{
processBERTFrame();
return true;
}
else if (MsgStopBERT::match(cmd))
{
qDebug("M17ModProcessor::handleMessage: MsgStopBERT");
send_eot(); // EOT
return true;
}
return false;
}
@ -243,6 +264,13 @@ void M17ModProcessor::processAudioFrame()
output_baseband(mobilinkd::M17Modulator::STREAM_SYNC_WORD, temp);
}
void M17ModProcessor::processBERTFrame()
{
std::array<int8_t, 368> temp = mobilinkd::M17Modulator::make_bert_frame(m_prbs);
mobilinkd::M17Modulator::interleave_and_randomize(temp);
output_baseband(mobilinkd::M17Modulator::BERT_SYNC_WORD, temp);
}
std::array<uint8_t, 16> M17ModProcessor::encodeAudio(std::array<int16_t, 320*6>& audioFrame)
{
std::array<int16_t, 320> audioFrame8k;

View File

@ -183,6 +183,51 @@ public:
{ }
};
class MsgStartBERT : public Message {
MESSAGE_CLASS_DECLARATION
public:
static MsgStartBERT* create() {
return new MsgStartBERT();
}
private:
MsgStartBERT() :
Message()
{ }
};
class MsgSendBERTFrame : public Message {
MESSAGE_CLASS_DECLARATION
public:
static MsgSendBERTFrame* create() {
return new MsgSendBERTFrame();
}
private:
MsgSendBERTFrame() :
Message()
{ }
};
class MsgStopBERT : public Message {
MESSAGE_CLASS_DECLARATION
public:
static MsgStopBERT* create() {
return new MsgStopBERT();
}
private:
MsgStopBERT() :
Message()
{ }
};
M17ModProcessor();
~M17ModProcessor();
@ -203,6 +248,7 @@ private:
int m_audioFrameIndex;
uint16_t m_audioFrameNumber;
struct CODEC2 *m_codec2;
mobilinkd::PRBS9 m_prbs;
bool m_insertPositionToggle;
bool handleMessage(const Message& cmd);
@ -211,6 +257,7 @@ private:
void audioStop();
void processAudioFrame();
std::array<uint8_t, 16> encodeAudio(std::array<int16_t, 320*6>& audioFrame);
void processBERTFrame();
void test(const QString& sourceCall, const QString& destCall);
void send_preamble();
void send_eot();

View File

@ -51,6 +51,7 @@ M17ModSource::M17ModSource() :
m_audioReadBufferIndex = 0;
m_m17PullAudio = false;
m_m17PullCount = 0;
m_m17PullBERT = false;
m_feedbackAudioBuffer.resize(1<<14);
m_feedbackAudioBufferFill = 0;
@ -358,6 +359,22 @@ void M17ModSource::pullM17(Real& sample, bool& carrier)
m_m17PullCount = 0;
}
}
else if (m_settings.m_m17Mode == M17ModSettings::M17ModeM17BERT)
{
if (!m_m17PullBERT)
{
M17ModProcessor::MsgStartBERT *msg = M17ModProcessor::MsgStartBERT::create();
m_processor->getInputMessageQueue()->push(msg);
m_m17PullBERT = true;
}
if ((m_processor->getBasebandFifo()->getFill() < 1920) && (m_m17PullCount > 192))
{
M17ModProcessor::MsgSendBERTFrame *msg = M17ModProcessor::MsgSendBERTFrame::create();
m_processor->getInputMessageQueue()->push(msg);
m_m17PullCount = 0;
}
}
else
{
if (m_m17PullAudio)
@ -366,6 +383,12 @@ void M17ModSource::pullM17(Real& sample, bool& carrier)
m_processor->getInputMessageQueue()->push(msg);
m_m17PullAudio = false;
}
else if (m_m17PullBERT)
{
M17ModProcessor::MsgStopBERT *msg = M17ModProcessor::MsgStopBERT::create();
m_processor->getInputMessageQueue()->push(msg);
m_m17PullBERT = false;
}
}
// get sample from processor FIFO

View File

@ -110,6 +110,7 @@ private:
AudioFifo m_audioFifo;
bool m_m17PullAudio;
int m_m17PullCount;
bool m_m17PullBERT;
int m_feedbackAudioSampleRate;
AudioVector m_feedbackAudioBuffer;