From 242a5843d8ff2e38fe4caa4fffb726ed5e952833 Mon Sep 17 00:00:00 2001 From: f4exb Date: Mon, 4 Jul 2022 22:45:16 +0200 Subject: [PATCH] M17 mod: implement BERT --- modems/m17/M17Demodulator.cpp | 6 +- modems/m17/M17Modulator.h | 76 ++++++++++++++++++++ plugins/channeltx/modm17/m17modgui.cpp | 27 +++++++ plugins/channeltx/modm17/m17modgui.h | 1 + plugins/channeltx/modm17/m17modgui.ui | 10 +++ plugins/channeltx/modm17/m17modprocessor.cpp | 28 ++++++++ plugins/channeltx/modm17/m17modprocessor.h | 47 ++++++++++++ plugins/channeltx/modm17/m17modsource.cpp | 23 ++++++ plugins/channeltx/modm17/m17modsource.h | 1 + 9 files changed, 216 insertions(+), 3 deletions(-) diff --git a/modems/m17/M17Demodulator.cpp b/modems/m17/M17Demodulator.cpp index fce8046ec..2cb50ff3b 100644 --- a/modems/m17/M17Demodulator.cpp +++ b/modems/m17/M17Demodulator.cpp @@ -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(), diff --git a/modems/m17/M17Modulator.h b/modems/m17/M17Modulator.h index c55287aeb..6083482aa 100644 --- a/modems/m17/M17Modulator.h +++ b/modems/m17/M17Modulator.h @@ -368,6 +368,82 @@ public: return punctured; } + static std::array make_bert_frame(PRBS9& prbs) + { + std::array 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 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 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& punctured) { M17Randomizer<368> randomizer; diff --git a/plugins/channeltx/modm17/m17modgui.cpp b/plugins/channeltx/modm17/m17modgui.cpp index 13d0edbad..60e155a9c 100644 --- a/plugins/channeltx/modm17/m17modgui.cpp +++ b/plugins/channeltx/modm17/m17modgui.cpp @@ -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); diff --git a/plugins/channeltx/modm17/m17modgui.h b/plugins/channeltx/modm17/m17modgui.h index b16fe0933..1c4f7e475 100644 --- a/plugins/channeltx/modm17/m17modgui.h +++ b/plugins/channeltx/modm17/m17modgui.h @@ -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); diff --git a/plugins/channeltx/modm17/m17modgui.ui b/plugins/channeltx/modm17/m17modgui.ui index 6f10a3830..d18244515 100644 --- a/plugins/channeltx/modm17/m17modgui.ui +++ b/plugins/channeltx/modm17/m17modgui.ui @@ -858,6 +858,16 @@ + + + + BERT mode + + + BERT + + + diff --git a/plugins/channeltx/modm17/m17modprocessor.cpp b/plugins/channeltx/modm17/m17modprocessor.cpp index 5b9d87103..8f3f9110b 100644 --- a/plugins/channeltx/modm17/m17modprocessor.cpp +++ b/plugins/channeltx/modm17/m17modprocessor.cpp @@ -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 temp = mobilinkd::M17Modulator::make_bert_frame(m_prbs); + mobilinkd::M17Modulator::interleave_and_randomize(temp); + output_baseband(mobilinkd::M17Modulator::BERT_SYNC_WORD, temp); +} + std::array M17ModProcessor::encodeAudio(std::array& audioFrame) { std::array audioFrame8k; diff --git a/plugins/channeltx/modm17/m17modprocessor.h b/plugins/channeltx/modm17/m17modprocessor.h index 5f45ee087..e0e153366 100644 --- a/plugins/channeltx/modm17/m17modprocessor.h +++ b/plugins/channeltx/modm17/m17modprocessor.h @@ -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 encodeAudio(std::array& audioFrame); + void processBERTFrame(); void test(const QString& sourceCall, const QString& destCall); void send_preamble(); void send_eot(); diff --git a/plugins/channeltx/modm17/m17modsource.cpp b/plugins/channeltx/modm17/m17modsource.cpp index f513381f7..efee628f8 100644 --- a/plugins/channeltx/modm17/m17modsource.cpp +++ b/plugins/channeltx/modm17/m17modsource.cpp @@ -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 diff --git a/plugins/channeltx/modm17/m17modsource.h b/plugins/channeltx/modm17/m17modsource.h index c87399362..b86ca65ae 100644 --- a/plugins/channeltx/modm17/m17modsource.h +++ b/plugins/channeltx/modm17/m17modsource.h @@ -110,6 +110,7 @@ private: AudioFifo m_audioFifo; bool m_m17PullAudio; int m_m17PullCount; + bool m_m17PullBERT; int m_feedbackAudioSampleRate; AudioVector m_feedbackAudioBuffer;