1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-12-23 10:05:46 -05:00

M17 demod: various adjustments

This commit is contained in:
f4exb 2022-06-09 04:49:41 +02:00
parent 278a94f29e
commit f326860f64
15 changed files with 953 additions and 2008 deletions

View File

@ -274,6 +274,7 @@ struct M17FrameDecoder
std::array<int8_t, 272> tmp;
std::copy(buffer.begin() + 96, buffer.end(), tmp.begin());
depuncture(tmp, depuncture_buffer.stream, P2);
viterbi_cost = viterbi_.decode(depuncture_buffer.stream, decode_buffer.stream);
to_byte_array(decode_buffer.stream, output_buffer.stream);

View File

@ -14,6 +14,19 @@
namespace mobilinkd
{
inline constexpr std::array<int8_t, 61> make_p1() {
std::array<int8_t, 61> result{};
for (size_t i = 0, j = 2; i != 61; ++i) {
if (i == j) {
result[i] = 0;
j += 4;
} else {
result[i] = 1;
}
}
return result;
};
/// Puncture matrix for LSF
constexpr auto P1 = std::array<int8_t, 61>{
1,
@ -42,8 +55,7 @@ constexpr auto P2 = std::array<int8_t, 12>{
/// Puncture matrix for packet frames (7/8).
constexpr auto P3 = std::array<int8_t, 8>{
1, 1, 1, 1,
1, 1, 1, 0};
1, 1, 1, 1, 1, 1, 1, 0};
/**
* Convert an integer value to an array of bits, with the

View File

@ -148,7 +148,9 @@ public:
const QString& getSrcCall() const { return m_basebandSink->getSrcCall(); }
const QString& getDestcCall() const { return m_basebandSink->getDestcCall(); }
const QString& getTypeInfo() const { return m_basebandSink->getTypeInfo(); }
bool getStreamElsePacket() const { return m_basebandSink->getStreamElsePacket(); }
uint16_t getCRC() const { return m_basebandSink->getCRC(); }
int getStdPacketProtocol() const { return m_basebandSink->getStdPacketProtocol(); }
static const char* const m_channelIdURI;
static const char* const m_channelId;

File diff suppressed because it is too large Load Diff

View File

@ -94,7 +94,9 @@ public:
const QString& getSrcCall() const { return m_sink.getSrcCall(); }
const QString& getDestcCall() const { return m_sink.getDestcCall(); }
const QString& getTypeInfo() const { return m_sink.getTypeInfo(); }
bool getStreamElsePacket() const { return m_sink.getStreamElsePacket(); }
uint16_t getCRC() const { return m_sink.getCRC(); }
int getStdPacketProtocol() const { return m_sink.getStdPacketProtocol(); }
private:
SampleSinkFifo m_sampleFifo;

View File

@ -157,8 +157,8 @@ void M17DemodGUI::on_fmDeviation_valueChanged(int value)
void M17DemodGUI::on_volume_valueChanged(int value)
{
m_settings.m_volume= value / 10.0;
ui->volumeText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1));
m_settings.m_volume= value / 100.0;
ui->volumeText->setText(QString("%1").arg(value / 100.0, 0, 'f', 2));
applySettings();
}
@ -419,8 +419,8 @@ void M17DemodGUI::displaySettings()
ui->squelchGate->setValue(m_settings.m_squelchGate);
ui->squelchGateText->setText(QString("%1").arg(ui->squelchGate->value() * 10.0, 0, 'f', 0));
ui->volume->setValue(m_settings.m_volume * 10.0);
ui->volumeText->setText(QString("%1").arg(ui->volume->value() / 10.0, 0, 'f', 1));
ui->volume->setValue(m_settings.m_volume * 100.0);
ui->volumeText->setText(QString("%1").arg(ui->volume->value() / 100.0, 0, 'f', 2));
ui->syncOrConstellation->setChecked(m_settings.m_syncOrConstellation);
ui->audioMute->setChecked(m_settings.m_audioMute);
@ -561,10 +561,10 @@ void M17DemodGUI::tick()
ui->lockLabel->setStyleSheet("QLabel { background-color : green; }");
}
ui->syncText->setText(getStatus(status));
ui->syncText->setText(getStatus(status, m_m17Demod->getStreamElsePacket(), m_m17Demod->getStdPacketProtocol()));
ui->evmText->setText(tr("%1").arg(evm*100.0f, 3, 'f', 1));
ui->deviationText->setText(tr("%1").arg(deviation, 2, 'f', 1));
ui->offsetText->setText(tr("%1").arg(offset, 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->viterbiText->setText(tr("%1").arg(viterbiCost));
ui->clockText->setText(tr("%1").arg(clock, 2, 'f', 1));
ui->sampleText->setText(tr("%1, %2, %3").arg(sampleIndex).arg(syncIndex).arg(clockIndex));
@ -575,27 +575,47 @@ void M17DemodGUI::tick()
ui->destText->setText(m_m17Demod->getDestcCall());
ui->typeText->setText(m_m17Demod->getTypeInfo());
ui->crcText->setText(tr("%1").arg(m_m17Demod->getCRC(), 4, 16, QChar('0')));
if (ui->activateStatusLog->isChecked() && (m_m17Demod->getLSFCount() != 0))
{
QString s = tr("Src: %1 Dst: %2 Typ: %3 CRC: %4")
.arg(m_m17Demod->getSrcCall())
.arg(m_m17Demod->getDestcCall())
.arg(m_m17Demod->getTypeInfo())
.arg(m_m17Demod->getCRC(), 4, 16, QChar('0'));
m_m17StatusTextDialog.addLine(s);
}
m_lsfCount = m_m17Demod->getLSFCount();
}
}
m_tickCount++;
}
QString M17DemodGUI::getStatus(int status)
QString M17DemodGUI::getStatus(int status, bool streamElsePacket, int packetProtocol)
{
if (status == 0) {
return "Unlocked";
} else if (status == 1) {
return "LSF";
} else if (status == 2) {
return "Stream";
} else if (status == 3) {
return "Packet";
} else if (status == 4) {
return "BERT";
} else if (status == 5) {
return "Frame";
} else if (streamElsePacket) {
return "Stream";
} else if (packetProtocol == 0) {
return "Raw";
} else if (packetProtocol == 1) {
return "AX.25";
} else if (packetProtocol == 2) {
return "APRS";
} else if (packetProtocol == 3) {
return "6LoWPAN";
} else if (packetProtocol == 4) {
return "IPv4";
} else if (packetProtocol == 5) {
return "SMS";
} else if (packetProtocol == 6) {
return "Winlink";
} else {
return "Unknown";
}

View File

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

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>482</width>
<height>392</height>
<height>400</height>
</rect>
</property>
<property name="sizePolicy">
@ -19,13 +19,13 @@
<property name="minimumSize">
<size>
<width>482</width>
<height>392</height>
<height>400</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>750</width>
<height>392</height>
<width>560</width>
<height>400</height>
</size>
</property>
<property name="font">
@ -43,7 +43,7 @@
<x>0</x>
<y>0</y>
<width>480</width>
<height>172</height>
<height>136</height>
</rect>
</property>
<property name="sizePolicy">
@ -341,13 +341,13 @@
<string>Sound volume</string>
</property>
<property name="maximum">
<number>100</number>
<number>200</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
<property name="value">
<number>20</number>
<number>100</number>
</property>
</widget>
</item>
@ -369,7 +369,7 @@
<string>Sound volume</string>
</property>
<property name="text">
<string>10.0</string>
<string>1.00</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
@ -518,17 +518,44 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="formatStatusLayout">
</layout>
</widget>
<widget class="QWidget" name="digitalWidget" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>136</y>
<width>480</width>
<height>249</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>480</width>
<height>248</height>
</size>
</property>
<property name="windowTitle">
<string>Digital</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<layout class="QHBoxLayout" name="formatStatusLayout">
<item>
<widget class="QLabel" name="sourceLabel">
<property name="text">
@ -544,6 +571,12 @@
<height>0</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Mono</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="toolTip">
<string>Source callsign</string>
</property>
@ -573,6 +606,12 @@
<height>0</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Mono</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="toolTip">
<string>Destination callsign</string>
</property>
@ -602,6 +641,12 @@
<height>0</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Mono</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="toolTip">
<string>Data stream type information</string>
</property>
@ -618,6 +663,12 @@
</item>
<item>
<widget class="QLabel" name="crcLabel">
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="text">
<string>CRC</string>
</property>
@ -631,6 +682,12 @@
<height>0</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Mono</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="toolTip">
<string>CRC for the LSF data</string>
</property>
@ -660,39 +717,8 @@
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="scopeWidget" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>180</y>
<width>480</width>
<height>210</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>480</width>
<height>210</height>
</size>
</property>
<property name="windowTitle">
<string>Digital</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<layout class="QHBoxLayout" name="scopeLayout">
<item>
<widget class="TVScreen" name="screenTV" native="true">
<property name="sizePolicy">
@ -711,6 +737,12 @@
</item>
<item>
<widget class="QFrame" name="frame">
<property name="minimumSize">
<size>
<width>0</width>
<height>210</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
@ -869,7 +901,7 @@
<rect>
<x>110</x>
<y>40</y>
<width>25</width>
<width>31</width>
<height>28</height>
</rect>
</property>
@ -880,10 +912,10 @@
</size>
</property>
<property name="toolTip">
<string>Carrier input level (%) when synchronized</string>
<string>Detected FM deviation relative to nominal deviation</string>
</property>
<property name="text">
<string>0.0</string>
<string>0.00</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
@ -1222,7 +1254,7 @@
<widget class="QLabel" name="offsetLabel">
<property name="geometry">
<rect>
<x>142</x>
<x>148</x>
<y>40</y>
<width>25</width>
<height>28</height>
@ -1247,9 +1279,9 @@
<widget class="QLabel" name="offsetText">
<property name="geometry">
<rect>
<x>170</x>
<x>172</x>
<y>40</y>
<width>35</width>
<width>31</width>
<height>28</height>
</rect>
</property>
@ -1260,7 +1292,7 @@
</size>
</property>
<property name="toolTip">
<string>Carrier input level (%) when synchronized</string>
<string>Detected carrier deviation relative to nominal deviation</string>
</property>
<property name="text">
<string>0.00</string>
@ -1310,7 +1342,7 @@
</size>
</property>
<property name="toolTip">
<string>Carrier input level (%) when synchronized</string>
<string>Viterbi cost. -1 if not available.</string>
</property>
<property name="text">
<string>128</string>
@ -1360,10 +1392,10 @@
</size>
</property>
<property name="toolTip">
<string>Carrier input level (%) when synchronized</string>
<string>Difference between Tx and Rx clock normalized</string>
</property>
<property name="text">
<string>0</string>
<string>0.0</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
@ -1410,7 +1442,7 @@
</size>
</property>
<property name="toolTip">
<string>Carrier input level (%) when synchronized</string>
<string>Estimated sample point: sample, sync, clock. Clock wins </string>
</property>
<property name="text">
<string>0, 0, 0</string>
@ -1422,6 +1454,8 @@
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<customwidgets>

View File

@ -40,7 +40,7 @@ M17DemodProcessor::M17DemodProcessor() :
{
m_this = this;
m_codec2 = ::codec2_create(CODEC2_MODE_3200);
m_audioBuffer.resize(48000);
m_audioBuffer.resize(12000);
m_audioBufferFill = 0;
m_srcCall = "";
m_destCall = "";
@ -212,14 +212,16 @@ bool M17DemodProcessor::decode_lsf(mobilinkd::M17FrameDecoder::lsf_buffer_t cons
}
}
qDebug() << "M17DemodProcessor::decode_lsf: " << oss.str().c_str();
m_lsfCount++;
qDebug() << "M17DemodProcessor::decode_lsf: " << m_lsfCount << ":" << oss.str().c_str();
return true;
}
void M17DemodProcessor::decode_type(uint16_t type)
{
if (type & 1) // bit 0
m_streamElsePacket = type & 1; // bit 0
if (m_streamElsePacket)
{
m_typeInfo = "STR:"; // Stream mode
@ -268,6 +270,7 @@ void M17DemodProcessor::resetInfo()
m_srcCall = "";
m_destCall = "";
m_typeInfo = "";
m_streamElsePacket = true;
m_metadata.fill(0);
m_crc = 0;
m_lsfCount = 0;
@ -301,17 +304,30 @@ bool M17DemodProcessor::decode_packet(mobilinkd::M17FrameDecoder::packet_buffer_
if (packet_segment[25] & 0x80) // last frame of packet.
{
size_t packet_size = (packet_segment[25] & 0x7F) >> 2;
packet_size = std::min(packet_size, size_t(25));
packet_size = std::min(packet_size, size_t(25)); // on last frame this is the remainder byte count
m_packetFrameCounter = 0;
for (size_t i = 0; i != packet_size; ++i) {
m_currentPacket.push_back(packet_segment[i]);
}
if (m_currentPacket.size() < 3) {
qDebug() << "M17DemodProcessor::decode_packet: too small:" << m_currentPacket.size();
return false;
}
boost::crc_optimal<16, 0x1021, 0xFFFF, 0xFFFF, true, true> crc;
crc.process_bytes(&m_currentPacket.front(), m_currentPacket.size());
uint16_t checksum = crc.checksum();
uint16_t calcChecksum = crc.checksum();
uint16_t xmitChecksum = m_currentPacket.back() + (1<<8) * m_currentPacket.end()[-2];
if (checksum == 0x0f47)
if (calcChecksum == xmitChecksum) // (checksum == 0x0f47)
{
uint8_t protocol = m_currentPacket.front();
m_stdPacketProtocol = protocol < (int) StdPacketUnknown ? (StdPacketProtocol) protocol : StdPacketUnknown;
qDebug() << "M17DemodProcessor::decode_packet: protocol: " << m_stdPacketProtocol;
if (m_stdPacketProtocol == StdPacketAX25)
{
std::string ax25;
ax25.reserve(m_currentPacket.size());
@ -323,11 +339,23 @@ bool M17DemodProcessor::decode_packet(mobilinkd::M17FrameDecoder::packet_buffer_
mobilinkd::ax25_frame frame(ax25);
std::ostringstream oss;
mobilinkd::write(oss, frame); // TODO: get details
qDebug() << "M17DemodProcessor::decode_packet: " << oss.str().c_str();
qDebug() << "M17DemodProcessor::decode_packet: AX25:" << oss.str().c_str();
}
else if (m_stdPacketProtocol == StdPacketSMS)
{
std::ostringstream oss;
for (std::vector<uint8_t>::const_iterator it = m_currentPacket.begin()+1; it < m_currentPacket.end()-2; ++it) {
oss << *it;
}
qDebug() << "M17DemodProcessor::decode_packet: SMS:" << oss.str().c_str();
}
return true;
}
qWarning() << "M17DemodProcessor::decode_packet: Packet checksum error: " << std::hex << checksum << std::dec;
qWarning() << "M17DemodProcessor::decode_packet: Packet checksum error: " << std::hex << calcChecksum << "vs" << xmitChecksum << std::dec;
return false;
}
@ -450,8 +478,8 @@ void M17DemodProcessor::upsample(int upsampling, const int16_t *in, int nbSample
for (int j = 1; j <= upsampling; j++)
{
upsample = (qint16) m_upsamplingFilter.runLP(cur*m_upsamplingFactors[j] + prev*m_upsamplingFactors[upsampling-j]);
m_audioBuffer[m_audioBufferFill].l = upsample; //m_compressor.compress(upsample);
m_audioBuffer[m_audioBufferFill].r = upsample; //m_compressor.compress(upsample);
m_audioBuffer[m_audioBufferFill].l = m_compressor.compress(upsample);
m_audioBuffer[m_audioBufferFill].r = m_compressor.compress(upsample);
if (m_audioBufferFill < m_audioBuffer.size() - 1) {
++m_audioBufferFill;
@ -492,3 +520,12 @@ void M17DemodProcessor::setVolumeFactors()
m_upsamplingFactors[i] = (i*m_volume) / (float) m_upsampling;
}
}
M17DemodProcessor::StdPacketProtocol M17DemodProcessor::getStdPacketProtocol() const
{
if (m_streamElsePacket) {
return StdPacketUnknown;
} else {
return m_stdPacketProtocol;
}
}

View File

@ -30,6 +30,18 @@ class M17DemodProcessor : public QObject
{
Q_OBJECT
public:
enum StdPacketProtocol
{
StdPacketRaw,
StdPacketAX25,
StdPacketAPRS,
StdPacket6LoWPAN,
StdPacketIPv4,
StdPacketSMS,
StdPacketWinlink,
StdPacketUnknown
};
M17DemodProcessor();
~M17DemodProcessor();
@ -47,7 +59,9 @@ public:
const QString& getSrcCall() const { return m_srcCall; }
const QString& getDestcCall() const { return m_destCall; }
const QString& getTypeInfo() const { return m_typeInfo; }
bool getStreamElsePacket() const { return m_streamElsePacket; }
uint16_t getCRC() const { return m_crc; }
StdPacketProtocol getStdPacketProtocol() const;
void getDiagnostics(
bool& dcd,
@ -110,9 +124,11 @@ private:
QString m_srcCall;
QString m_destCall;
QString m_typeInfo;
bool m_streamElsePacket;
std::array<uint8_t, 14> m_metadata;
uint16_t m_crc;
uint32_t m_lsfCount; // Incremented each time a new LSF is decoded. Reset when lock is lost.
StdPacketProtocol m_stdPacketProtocol;
static bool handle_frame(mobilinkd::M17FrameDecoder::output_buffer_t const& frame, int viterbi_cost);
static void diagnostic_callback(

View File

@ -96,7 +96,9 @@ public:
const QString& getSrcCall() const { return m_m17DemodProcessor.getSrcCall(); }
const QString& getDestcCall() const { return m_m17DemodProcessor.getDestcCall(); }
const QString& getTypeInfo() const { return m_m17DemodProcessor.getTypeInfo(); }
bool getStreamElsePacket() const { return m_m17DemodProcessor.getStreamElsePacket(); }
uint16_t getCRC() const { return m_m17DemodProcessor.getCRC(); }
int getStdPacketProtocol() const { return (int) m_m17DemodProcessor.getStdPacketProtocol(); }
private:
struct MagSqLevelsStore

View File

@ -39,17 +39,17 @@ M17StatusTextDialog::~M17StatusTextDialog()
void M17StatusTextDialog::addLine(const QString& line)
{
if ((line.size() > 0) && (line != m_lastLine))
if (line.size() > 0)
{
QDateTime dt = QDateTime::currentDateTime();
QString dateStr = dt.toString("HH:mm:ss");
QTextCursor cursor = ui->logEdit->textCursor();
cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
cursor.insertText(tr("%1 %2\n").arg(dateStr).arg(line));
if (ui->pinToLastLine->isChecked()) {
ui->logEdit->verticalScrollBar()->setValue(ui->logEdit->verticalScrollBar()->maximum());
}
m_lastLine = line;
}
}

View File

@ -36,7 +36,6 @@ public:
private:
Ui::M17StatusTextDialog* ui;
QString m_lastLine;
private slots:
void on_clear_clicked();

View File

@ -109,6 +109,7 @@
<property name="font">
<font>
<family>Liberation Mono</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="toolTip">
@ -148,32 +149,32 @@
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>DSDStatusTextDialog</receiver>
<receiver>M17StatusTextDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>257</x>
<y>194</y>
<x>369</x>
<y>357</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>203</y>
<x>369</x>
<y>189</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DSDStatusTextDialog</receiver>
<receiver>M17StatusTextDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>314</x>
<y>194</y>
<x>369</x>
<y>357</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>203</y>
<x>369</x>
<y>189</y>
</hint>
</hints>
</connection>