1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2025-11-18 14:15:07 -05:00

LoRa: optimize non LoRa modes. Improve preamble detection. GUI updates

This commit is contained in:
f4exb 2020-03-05 07:12:41 +01:00
parent bedf682ef2
commit 22a668394e
13 changed files with 180 additions and 174 deletions

View File

@ -239,7 +239,7 @@ void ChirpChatDemodGUI::on_clear_clicked(bool checked)
{ {
(void) checked; (void) checked;
ui->messageText->clear(); ui->messageText->clear();
ui->hexText->clear(); ui->messageText->clear();
} }
void ChirpChatDemodGUI::on_eomSquelch_valueChanged(int value) void ChirpChatDemodGUI::on_eomSquelch_valueChanged(int value)
@ -410,8 +410,7 @@ ChirpChatDemodGUI::ChirpChatDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUI
ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999); ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999);
ui->messageText->setReadOnly(true); ui->messageText->setReadOnly(true);
ui->syncWord->setReadOnly(true); ui->messageText->setReadOnly(true);
ui->hexText->setReadOnly(true);
m_channelMarker.setMovable(true); m_channelMarker.setMovable(true);
m_channelMarker.setVisible(true); m_channelMarker.setVisible(true);
@ -602,7 +601,6 @@ void ChirpChatDemodGUI::showLoRaMessage(const Message& message)
QByteArray bytes = msg.getBytes(); QByteArray bytes = msg.getBytes();
QString syncWordStr((tr("%1").arg(msg.getSyncWord(), 2, 16, QChar('0')))); QString syncWordStr((tr("%1").arg(msg.getSyncWord(), 2, 16, QChar('0'))));
ui->syncWord->setText(tr("%1").arg(syncWordStr));
ui->sText->setText(tr("%1").arg(msg.getSingalDb(), 0, 'f', 1)); ui->sText->setText(tr("%1").arg(msg.getSingalDb(), 0, 'f', 1));
ui->snrText->setText(tr("%1").arg(msg.getSingalDb() - msg.getNoiseDb(), 0, 'f', 1)); ui->snrText->setText(tr("%1").arg(msg.getSingalDb() - msg.getNoiseDb(), 0, 'f', 1));
unsigned int packetLength; unsigned int packetLength;
@ -650,7 +648,8 @@ void ChirpChatDemodGUI::showLoRaMessage(const Message& message)
.arg(getParityStr(msg.getPayloadParityStatus())) .arg(getParityStr(msg.getPayloadParityStatus()))
.arg(msg.getPayloadCRCStatus() ? "ok" : "err"); .arg(msg.getPayloadCRCStatus() ? "ok" : "err");
displayBytes(loRaHeader, bytes); displayStatus(loRaHeader);
displayBytes(bytes);
QByteArray bytesCopy(bytes); QByteArray bytesCopy(bytes);
bytesCopy.truncate(packetLength); bytesCopy.truncate(packetLength);
@ -658,7 +657,7 @@ void ChirpChatDemodGUI::showLoRaMessage(const Message& message)
QString str = QString(bytesCopy.toStdString().c_str()); QString str = QString(bytesCopy.toStdString().c_str());
QString textHeader(tr("%1 (%2)").arg(dateStr).arg(syncWordStr)); QString textHeader(tr("%1 (%2)").arg(dateStr).arg(syncWordStr));
displayText(textHeader, str); displayText(str);
displayLoRaStatus(msg.getHeaderParityStatus(), msg.getHeaderCRCStatus(), msg.getPayloadParityStatus(), msg.getPayloadCRCStatus()); displayLoRaStatus(msg.getHeaderParityStatus(), msg.getHeaderCRCStatus(), msg.getPayloadParityStatus(), msg.getPayloadCRCStatus());
} }
@ -672,10 +671,6 @@ void ChirpChatDemodGUI::showTextMessage(const Message& message)
QDateTime dt = QDateTime::currentDateTime(); QDateTime dt = QDateTime::currentDateTime();
QString dateStr = dt.toString("HH:mm:ss"); QString dateStr = dt.toString("HH:mm:ss");
QString syncWordStr((tr("%1").arg(msg.getSyncWord(), 2, 16, QChar('0'))));
QString textHeader(tr("%1 (%2)").arg(dateStr).arg(syncWordStr));
displayText(textHeader, msg.getString());
ui->syncWord->setText(syncWordStr);
ui->sText->setText(tr("%1").arg(msg.getSingalDb(), 0, 'f', 1)); ui->sText->setText(tr("%1").arg(msg.getSingalDb(), 0, 'f', 1));
ui->snrText->setText(tr("%1").arg(msg.getSingalDb() - msg.getNoiseDb(), 0, 'f', 1)); ui->snrText->setText(tr("%1").arg(msg.getSingalDb() - msg.getNoiseDb(), 0, 'f', 1));
@ -683,30 +678,31 @@ void ChirpChatDemodGUI::showTextMessage(const Message& message)
.arg(dateStr) .arg(dateStr)
.arg(msg.getSingalDb(), 0, 'f', 1) .arg(msg.getSingalDb(), 0, 'f', 1)
.arg(msg.getSingalDb() - msg.getNoiseDb(), 0, 'f', 1); .arg(msg.getSingalDb() - msg.getNoiseDb(), 0, 'f', 1);
displayStatus(status); displayStatus(status);
displayText(msg.getString());
} }
void ChirpChatDemodGUI::displayText(const QString& header, const QString& text) void ChirpChatDemodGUI::displayText(const QString& text)
{ {
QTextCursor cursor = ui->messageText->textCursor(); QTextCursor cursor = ui->messageText->textCursor();
cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor); cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
if (!ui->messageText->document()->isEmpty()) { if (!ui->messageText->document()->isEmpty()) {
cursor.insertText("\n"); cursor.insertText("\n");
} }
cursor.insertText(tr("%1 %2").arg(header).arg(text)); cursor.insertText(tr("TXT|%1").arg(text));
ui->messageText->verticalScrollBar()->setValue(ui->messageText->verticalScrollBar()->maximum()); ui->messageText->verticalScrollBar()->setValue(ui->messageText->verticalScrollBar()->maximum());
} }
void ChirpChatDemodGUI::displayBytes(const QString& header, const QByteArray& bytes) void ChirpChatDemodGUI::displayBytes(const QByteArray& bytes)
{ {
QTextCursor cursor = ui->hexText->textCursor(); QTextCursor cursor = ui->messageText->textCursor();
cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor); cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
if (!ui->hexText->document()->isEmpty()) { if (!ui->messageText->document()->isEmpty()) {
cursor.insertText("\n"); cursor.insertText("\n");
} }
cursor.insertText(tr(">%1\n").arg(header));
QByteArray::const_iterator it = bytes.begin(); QByteArray::const_iterator it = bytes.begin();
unsigned int i = 0; unsigned int i = 0;
@ -729,20 +725,20 @@ void ChirpChatDemodGUI::displayBytes(const QString& header, const QByteArray& by
} }
} }
ui->hexText->verticalScrollBar()->setValue(ui->hexText->verticalScrollBar()->maximum()); ui->messageText->verticalScrollBar()->setValue(ui->messageText->verticalScrollBar()->maximum());
} }
void ChirpChatDemodGUI::displayStatus(const QString& status) void ChirpChatDemodGUI::displayStatus(const QString& status)
{ {
QTextCursor cursor = ui->hexText->textCursor(); QTextCursor cursor = ui->messageText->textCursor();
cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor); cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
if (!ui->hexText->document()->isEmpty()) { if (!ui->messageText->document()->isEmpty()) {
cursor.insertText("\n"); cursor.insertText("\n");
} }
cursor.insertText(tr(">%1").arg(status)); cursor.insertText(tr(">%1").arg(status));
ui->hexText->verticalScrollBar()->setValue(ui->hexText->verticalScrollBar()->maximum()); ui->messageText->verticalScrollBar()->setValue(ui->messageText->verticalScrollBar()->maximum());
} }
QString ChirpChatDemodGUI::getParityStr(int parityStatus) QString ChirpChatDemodGUI::getParityStr(int parityStatus)

View File

@ -112,8 +112,8 @@ private:
void setBandwidths(); void setBandwidths();
void showLoRaMessage(const Message& message); void showLoRaMessage(const Message& message);
void showTextMessage(const Message& message); //!< For TTY and ASCII void showTextMessage(const Message& message); //!< For TTY and ASCII
void displayText(const QString& header, const QString& text); void displayText(const QString& text);
void displayBytes(const QString& header, const QByteArray& bytes); void displayBytes(const QByteArray& bytes);
void displayStatus(const QString& status); void displayStatus(const QString& status);
void displayLoRaStatus(int headerParityStatus, bool headerCRCStatus, int payloadParityStatus, bool payloadCRCStatus); void displayLoRaStatus(int headerParityStatus, bool headerCRCStatus, int payloadParityStatus, bool payloadCRCStatus);
QString getParityStr(int parityStatus); QString getParityStr(int parityStatus);

View File

@ -6,7 +6,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>552</width> <width>532</width>
<height>680</height> <height>680</height>
</rect> </rect>
</property> </property>
@ -562,28 +562,20 @@
<string>Msg</string> <string>Msg</string>
</property> </property>
</widget> </widget>
<widget class="QLabel" name="hexLabel">
<property name="geometry">
<rect>
<x>2</x>
<y>145</y>
<width>32</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>Hex</string>
</property>
</widget>
<widget class="QPlainTextEdit" name="messageText"> <widget class="QPlainTextEdit" name="messageText">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>30</x> <x>30</x>
<y>60</y> <y>60</y>
<width>490</width> <width>490</width>
<height>80</height> <height>161</height>
</rect> </rect>
</property> </property>
<property name="font">
<font>
<family>Liberation Mono</family>
</font>
</property>
</widget> </widget>
<widget class="QLabel" name="schemeLabel"> <widget class="QLabel" name="schemeLabel">
<property name="geometry"> <property name="geometry">
@ -784,28 +776,6 @@
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property> </property>
</widget> </widget>
<widget class="QLineEdit" name="syncWord">
<property name="geometry">
<rect>
<x>492</x>
<y>10</y>
<width>25</width>
<height>20</height>
</rect>
</property>
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="toolTip">
<string>Sync word (1 byte hex)</string>
</property>
<property name="inputMask">
<string>HH</string>
</property>
<property name="text">
<string>00</string>
</property>
</widget>
<widget class="QLabel" name="loraLabel"> <widget class="QLabel" name="loraLabel">
<property name="geometry"> <property name="geometry">
<rect> <rect>
@ -902,22 +872,6 @@
<string>FEC</string> <string>FEC</string>
</property> </property>
</widget> </widget>
<widget class="QPlainTextEdit" name="hexText">
<property name="geometry">
<rect>
<x>30</x>
<y>145</y>
<width>490</width>
<height>75</height>
</rect>
</property>
<property name="font">
<font>
<family>Liberation Mono</family>
<pointsize>9</pointsize>
</font>
</property>
</widget>
<widget class="QLabel" name="packetLengthLabel"> <widget class="QLabel" name="packetLengthLabel">
<property name="geometry"> <property name="geometry">
<rect> <rect>
@ -969,19 +923,6 @@
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property> </property>
</widget> </widget>
<widget class="QLabel" name="syncWordLabel">
<property name="geometry">
<rect>
<x>456</x>
<y>10</y>
<width>30</width>
<height>19</height>
</rect>
</property>
<property name="text">
<string>Sync</string>
</property>
</widget>
<widget class="QLabel" name="headerHammingStatus"> <widget class="QLabel" name="headerHammingStatus">
<property name="geometry"> <property name="geometry">
<rect> <rect>

View File

@ -202,3 +202,19 @@ bool ChirpChatDemodSettings::deserialize(const QByteArray& data)
return false; return false;
} }
} }
unsigned int ChirpChatDemodSettings::getNbSFDFourths() const
{
switch (m_codingScheme)
{
case CodingLoRa:
return 9;
default:
return 8;
}
}
bool ChirpChatDemodSettings::hasSyncWord() const
{
return m_codingScheme == CodingLoRa;
}

View File

@ -72,6 +72,8 @@ struct ChirpChatDemodSettings
void resetToDefaults(); void resetToDefaults();
void setChannelMarker(Serializable *channelMarker) { m_channelMarker = channelMarker; } void setChannelMarker(Serializable *channelMarker) { m_channelMarker = channelMarker; }
void setSpectrumGUI(Serializable *spectrumGUI) { m_spectrumGUI = spectrumGUI; } void setSpectrumGUI(Serializable *spectrumGUI) { m_spectrumGUI = spectrumGUI; }
unsigned int getNbSFDFourths() const; //!< Get the number of SFD period fourths (depends on coding scheme)
bool hasSyncWord() const; //!< Only LoRa has a syncword (for the moment)
QByteArray serialize() const; QByteArray serialize() const;
bool deserialize(const QByteArray& data); bool deserialize(const QByteArray& data);
}; };

View File

@ -82,9 +82,12 @@ void ChirpChatDemodSink::initSF(unsigned int sf, unsigned int deBits)
m_nbSymbols = 1 << sf; m_nbSymbols = 1 << sf;
m_nbSymbolsEff = 1 << (sf - deBits); m_nbSymbolsEff = 1 << (sf - deBits);
m_deLength = 1 << deBits;
m_fftLength = m_nbSymbols; m_fftLength = m_nbSymbols;
m_fft->configure(m_fftInterpolation*m_fftLength, false); m_interpolatedFFTLength = m_fftInterpolation*m_fftLength;
m_fftSFD->configure(m_fftInterpolation*m_fftLength, false); m_preambleTolerance = (m_deLength*m_fftInterpolation)/2;
m_fft->configure(m_interpolatedFFTLength, false);
m_fftSFD->configure(m_interpolatedFFTLength, false);
m_state = ChirpChatStateReset; m_state = ChirpChatStateReset;
m_sfdSkip = m_fftLength / 4; m_sfdSkip = m_fftLength / 4;
m_fftWindow.create(FFTWindow::Function::Kaiser, m_fftLength); m_fftWindow.create(FFTWindow::Function::Kaiser, m_fftLength);
@ -146,7 +149,7 @@ void ChirpChatDemodSink::processSample(const Complex& ci)
if (m_fftCounter == m_fftLength) if (m_fftCounter == m_fftLength)
{ {
m_fftWindow.apply(m_fft->in()); m_fftWindow.apply(m_fft->in());
std::fill(m_fft->in()+m_fftLength, m_fft->in()+m_fftInterpolation*m_fftLength, Complex{0.0, 0.0}); std::fill(m_fft->in()+m_fftLength, m_fft->in()+m_interpolatedFFTLength, Complex{0.0, 0.0});
m_fft->transform(); m_fft->transform();
m_fftCounter = 0; m_fftCounter = 0;
double magsq, magsqTotal; double magsq, magsqTotal;
@ -176,11 +179,20 @@ void ChirpChatDemodSink::processSample(const Complex& ci)
for (int i = 1; i < m_requiredPreambleChirps; i++) for (int i = 1; i < m_requiredPreambleChirps; i++)
{ {
if (m_argMaxHistory[0] != m_argMaxHistory[i]) int delta = m_argMaxHistory[i] - m_argMaxHistory[i-1];
// qDebug("ChirpChatDemodSink::processSample: search: delta: %d / %d", delta, m_deLength);
if ((delta < -m_preambleTolerance) || (delta > m_preambleTolerance))
{ {
preambleFound = false; preambleFound = false;
break; break;
} }
// if (m_argMaxHistory[0] != m_argMaxHistory[i])
// {
// preambleFound = false;
// break;
// }
} }
if ((preambleFound) && (magsq > 1e-9)) if ((preambleFound) && (magsq > 1e-9))
@ -227,11 +239,11 @@ void ChirpChatDemodSink::processSample(const Complex& ci)
if (m_fftCounter == m_fftLength) if (m_fftCounter == m_fftLength)
{ {
m_fftWindow.apply(m_fft->in()); m_fftWindow.apply(m_fft->in());
std::fill(m_fft->in()+m_fftLength, m_fft->in()+m_fftInterpolation*m_fftLength, Complex{0.0, 0.0}); std::fill(m_fft->in()+m_fftLength, m_fft->in()+m_interpolatedFFTLength, Complex{0.0, 0.0});
m_fft->transform(); m_fft->transform();
m_fftWindow.apply(m_fftSFD->in()); m_fftWindow.apply(m_fftSFD->in());
std::fill(m_fftSFD->in()+m_fftLength, m_fftSFD->in()+m_fftInterpolation*m_fftLength, Complex{0.0, 0.0}); std::fill(m_fftSFD->in()+m_fftLength, m_fftSFD->in()+m_interpolatedFFTLength, Complex{0.0, 0.0});
m_fftSFD->transform(); m_fftSFD->transform();
m_fftCounter = 0; m_fftCounter = 0;
@ -265,23 +277,30 @@ void ChirpChatDemodSink::processSample(const Complex& ci)
{ {
m_magsqTotalAvg(magsqSFDTotal); m_magsqTotalAvg(magsqSFDTotal);
if (m_chirpCount < 3) // too early if (m_chirpCount < 1 + (m_settings.hasSyncWord() ? 2 : 0)) // too early
{ {
m_state = ChirpChatStateReset; m_state = ChirpChatStateReset;
qDebug("ChirpChatDemodSink::processSample: SFD search: signal drop is too early"); qDebug("ChirpChatDemodSink::processSample: SFD search: signal drop is too early");
} }
else else
{ {
m_syncWord = round(m_preambleHistory[m_chirpCount-2] / 8.0); if (m_settings.hasSyncWord())
m_syncWord += 16 * round(m_preambleHistory[m_chirpCount-3] / 8.0); {
qDebug("ChirpChatDemodSink::processSample: SFD found: up: %4u|%11.6f - down: %4u|%11.6f sync: %x", imax, magsq, imaxSFD, magsqSFD, m_syncWord); m_syncWord = round(m_preambleHistory[m_chirpCount-2] / 8.0);
m_syncWord += 16 * round(m_preambleHistory[m_chirpCount-3] / 8.0);
qDebug("ChirpChatDemodSink::processSample: SFD found: up: %4u|%11.6f - down: %4u|%11.6f sync: %x", imax, magsq, imaxSFD, magsqSFD, m_syncWord);
}
else
{
qDebug("ChirpChatDemodSink::processSample: SFD found: up: %4u|%11.6f - down: %4u|%11.6f", imax, magsq, imaxSFD, magsqSFD);
}
int sadj = 0; int sadj = 0;
int nadj = 0; int nadj = 0;
int zadj; int zadj;
int sfdSkip = m_sfdSkip; int sfdSkip = m_sfdSkip;
for (int i = 0; i < m_chirpCount-3; i++) for (int i = 0; i < m_chirpCount - 1 - (m_settings.hasSyncWord() ? 2 : 0); i++)
{ {
sadj += m_preambleHistory[i] > m_nbSymbols/2 ? m_preambleHistory[i] - m_nbSymbols : m_preambleHistory[i]; sadj += m_preambleHistory[i] > m_nbSymbols/2 ? m_preambleHistory[i] - m_nbSymbols : m_preambleHistory[i];
nadj++; nadj++;
@ -315,7 +334,7 @@ void ChirpChatDemodSink::processSample(const Complex& ci)
} }
} }
} }
else if (m_state == ChirpChatStateSkipSFD) // Just skip SFD else if (m_state == ChirpChatStateSkipSFD) // Just skip the rest of SFD
{ {
m_fftCounter++; m_fftCounter++;
@ -324,13 +343,12 @@ void ChirpChatDemodSink::processSample(const Complex& ci)
m_fftCounter = m_fftLength - m_sfdSkip; m_fftCounter = m_fftLength - m_sfdSkip;
m_sfdSkipCounter++; m_sfdSkipCounter++;
if (m_sfdSkipCounter == m_sfdFourths) // 1.25 SFD chips left if (m_sfdSkipCounter == m_settings.getNbSFDFourths() - 4U) // SFD chips fourths less one full period
{ {
qDebug("ChirpChatDemodSink::processSample: SFD skipped"); qDebug("ChirpChatDemodSink::processSample: SFD skipped");
m_chirp = m_chirp0; m_chirp = m_chirp0;
m_fftCounter = 0; m_fftCounter = 0;
m_chirpCount = 0; m_chirpCount = 0;
int correction = 0;
m_magsqMax = 0.0; m_magsqMax = 0.0;
m_decodeMsg = ChirpChatDemodMsg::MsgDecodeSymbols::create(); m_decodeMsg = ChirpChatDemodMsg::MsgDecodeSymbols::create();
m_decodeMsg->setSyncWord(m_syncWord); m_decodeMsg->setSyncWord(m_syncWord);
@ -346,7 +364,7 @@ void ChirpChatDemodSink::processSample(const Complex& ci)
if (m_fftCounter == m_fftLength) if (m_fftCounter == m_fftLength)
{ {
m_fftWindow.apply(m_fft->in()); m_fftWindow.apply(m_fft->in());
std::fill(m_fft->in()+m_fftLength, m_fft->in()+m_fftInterpolation*m_fftLength, Complex{0.0, 0.0}); std::fill(m_fft->in()+m_fftLength, m_fft->in()+m_interpolatedFFTLength, Complex{0.0, 0.0});
m_fft->transform(); m_fft->transform();
m_fftCounter = 0; m_fftCounter = 0;
double magsq, magsqTotal; double magsq, magsqTotal;

View File

@ -77,7 +77,6 @@ private:
static const unsigned int m_requiredPreambleChirps = 4; //!< Number of chirps required to estimate preamble static const unsigned int m_requiredPreambleChirps = 4; //!< Number of chirps required to estimate preamble
static const unsigned int m_maxSFDSearchChirps = 8; //!< Maximum number of chirps when looking for SFD after preamble detection static const unsigned int m_maxSFDSearchChirps = 8; //!< Maximum number of chirps when looking for SFD after preamble detection
static const unsigned int m_sfdFourths = 5; //!< Number of SFD chip period fourths to skip until payload
static const unsigned int m_fftInterpolation = 2; //!< FFT interpolation factor (usually a power of 2) static const unsigned int m_fftInterpolation = 2; //!< FFT interpolation factor (usually a power of 2)
FFTEngine *m_fft; FFTEngine *m_fft;
@ -87,7 +86,7 @@ private:
Complex *m_upChirps; Complex *m_upChirps;
Complex *m_spectrumLine; Complex *m_spectrumLine;
unsigned int m_fftCounter; unsigned int m_fftCounter;
unsigned int m_argMaxHistory[m_requiredPreambleChirps]; int m_argMaxHistory[m_requiredPreambleChirps];
unsigned int m_argMaxHistoryCounter; unsigned int m_argMaxHistoryCounter;
unsigned int m_preambleHistory[m_maxSFDSearchChirps]; unsigned int m_preambleHistory[m_maxSFDSearchChirps];
unsigned int m_syncWord; unsigned int m_syncWord;
@ -108,9 +107,12 @@ private:
BasebandSampleSink* m_spectrumSink; BasebandSampleSink* m_spectrumSink;
Complex *m_spectrumBuffer; Complex *m_spectrumBuffer;
unsigned int m_nbSymbols; unsigned int m_nbSymbols; //!< Number of symbols = length of base FFT
unsigned int m_nbSymbolsEff; //!< effective symbols considering DE bits unsigned int m_nbSymbolsEff; //!< effective symbols considering DE bits
unsigned int m_fftLength; unsigned int m_fftLength; //!< Length of base FFT
unsigned int m_interpolatedFFTLength; //!< Length of interpolated FFT
int m_deLength; //!< Number of FFT bins collated to represent one symbol
int m_preambleTolerance; //!< Number of FFT bins to collate when looking for preamble
void processSample(const Complex& ci); void processSample(const Complex& ci);
void initSF(unsigned int sf, unsigned int deBits); //!< Init tables, FFTs, depending on spread factor void initSF(unsigned int sf, unsigned int deBits); //!< Init tables, FFTs, depending on spread factor

View File

@ -109,7 +109,10 @@ bool ChirpChatModGUI::handleMessage(const Message& message)
{ {
const ChirpChatMod::MsgReportPayloadTime& rpt = (ChirpChatMod::MsgReportPayloadTime&) message; const ChirpChatMod::MsgReportPayloadTime& rpt = (ChirpChatMod::MsgReportPayloadTime&) message;
float fourthsMs = ((1<<m_settings.m_spreadFactor) * 250.0) / ChirpChatModSettings::bandwidths[m_settings.m_bandwidthIndex]; float fourthsMs = ((1<<m_settings.m_spreadFactor) * 250.0) / ChirpChatModSettings::bandwidths[m_settings.m_bandwidthIndex];
float controlMs = (4*m_settings.m_preambleChirps + 8 + 9) * fourthsMs; // preamble + sync word + SFD int fourthsChirps = 4*m_settings.m_preambleChirps;
fourthsChirps += m_settings.hasSyncWord() ? 8 : 0;
fourthsChirps += m_settings.getNbSFDFourths();
float controlMs = fourthsChirps * fourthsMs; // preamble + sync word + SFD
ui->timePayloadText->setText(tr("%1 ms").arg(QString::number(rpt.getPayloadTimeMs(), 'f', 0))); ui->timePayloadText->setText(tr("%1 ms").arg(QString::number(rpt.getPayloadTimeMs(), 'f', 0)));
ui->timeTotalText->setText(tr("%1 ms").arg(QString::number(rpt.getPayloadTimeMs() + controlMs, 'f', 0))); ui->timeTotalText->setText(tr("%1 ms").arg(QString::number(rpt.getPayloadTimeMs() + controlMs, 'f', 0)));
ui->timeSymbolText->setText(tr("%1 ms").arg(QString::number(4.0*fourthsMs, 'f', 1))); ui->timeSymbolText->setText(tr("%1 ms").arg(QString::number(4.0*fourthsMs, 'f', 1)));

View File

@ -6,7 +6,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>392</width> <width>402</width>
<height>373</height> <height>373</height>
</rect> </rect>
</property> </property>
@ -30,7 +30,7 @@
<rect> <rect>
<x>1</x> <x>1</x>
<y>20</y> <y>20</y>
<width>390</width> <width>400</width>
<height>125</height> <height>125</height>
</rect> </rect>
</property> </property>
@ -74,7 +74,7 @@
<rect> <rect>
<x>40</x> <x>40</x>
<y>50</y> <y>50</y>
<width>251</width> <width>261</width>
<height>16</height> <height>16</height>
</rect> </rect>
</property> </property>
@ -102,7 +102,7 @@
<rect> <rect>
<x>40</x> <x>40</x>
<y>70</y> <y>70</y>
<width>81</width> <width>101</width>
<height>16</height> <height>16</height>
</rect> </rect>
</property> </property>
@ -131,7 +131,7 @@
<widget class="QLabel" name="spreadText"> <widget class="QLabel" name="spreadText">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>130</x> <x>150</x>
<y>70</y> <y>70</y>
<width>30</width> <width>30</width>
<height>16</height> <height>16</height>
@ -153,7 +153,7 @@
<widget class="QLabel" name="bwText"> <widget class="QLabel" name="bwText">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>300</x> <x>310</x>
<y>50</y> <y>50</y>
<width>80</width> <width>80</width>
<height>16</height> <height>16</height>
@ -175,7 +175,7 @@
<widget class="QLabel" name="deBitsLabel"> <widget class="QLabel" name="deBitsLabel">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>180</x> <x>200</x>
<y>70</y> <y>70</y>
<width>32</width> <width>32</width>
<height>16</height> <height>16</height>
@ -188,7 +188,7 @@
<widget class="QLabel" name="deBitsText"> <widget class="QLabel" name="deBitsText">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>280</x> <x>370</x>
<y>70</y> <y>70</y>
<width>10</width> <width>10</width>
<height>16</height> <height>16</height>
@ -210,9 +210,9 @@
<widget class="QSlider" name="deBits"> <widget class="QSlider" name="deBits">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>210</x> <x>240</x>
<y>70</y> <y>70</y>
<width>61</width> <width>91</width>
<height>16</height> <height>16</height>
</rect> </rect>
</property> </property>
@ -243,7 +243,7 @@
<rect> <rect>
<x>10</x> <x>10</x>
<y>10</y> <y>10</y>
<width>371</width> <width>381</width>
<height>26</height> <height>26</height>
</rect> </rect>
</property> </property>
@ -366,7 +366,7 @@
<rect> <rect>
<x>40</x> <x>40</x>
<y>90</y> <y>90</y>
<width>81</width> <width>101</width>
<height>16</height> <height>16</height>
</rect> </rect>
</property> </property>
@ -408,7 +408,7 @@
<widget class="QLabel" name="preambleChirpsText"> <widget class="QLabel" name="preambleChirpsText">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>130</x> <x>150</x>
<y>90</y> <y>90</y>
<width>30</width> <width>30</width>
<height>16</height> <height>16</height>
@ -430,7 +430,7 @@
<widget class="QLabel" name="idleTimeLabel"> <widget class="QLabel" name="idleTimeLabel">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>180</x> <x>200</x>
<y>90</y> <y>90</y>
<width>32</width> <width>32</width>
<height>16</height> <height>16</height>
@ -443,9 +443,9 @@
<widget class="QSlider" name="idleTime"> <widget class="QSlider" name="idleTime">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>220</x> <x>240</x>
<y>90</y> <y>90</y>
<width>81</width> <width>91</width>
<height>16</height> <height>16</height>
</rect> </rect>
</property> </property>
@ -474,7 +474,7 @@
<widget class="QLabel" name="idleTimeText"> <widget class="QLabel" name="idleTimeText">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>320</x> <x>350</x>
<y>90</y> <y>90</y>
<width>30</width> <width>30</width>
<height>16</height> <height>16</height>
@ -493,48 +493,13 @@
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property> </property>
</widget> </widget>
<widget class="QLabel" name="syncLabel">
<property name="geometry">
<rect>
<x>310</x>
<y>70</y>
<width>32</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>Sync</string>
</property>
</widget>
<widget class="QLineEdit" name="syncWord">
<property name="geometry">
<rect>
<x>350</x>
<y>68</y>
<width>30</width>
<height>20</height>
</rect>
</property>
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="toolTip">
<string>Sync word (1 byte hex)</string>
</property>
<property name="inputMask">
<string>HH</string>
</property>
<property name="text">
<string>00</string>
</property>
</widget>
</widget> </widget>
<widget class="QWidget" name="messageContainer" native="true"> <widget class="QWidget" name="messageContainer" native="true">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>1</x> <x>1</x>
<y>150</y> <y>150</y>
<width>390</width> <width>400</width>
<height>221</height> <height>221</height>
</rect> </rect>
</property> </property>
@ -807,7 +772,7 @@
<rect> <rect>
<x>40</x> <x>40</x>
<y>110</y> <y>110</y>
<width>341</width> <width>355</width>
<height>60</height> <height>60</height>
</rect> </rect>
</property> </property>
@ -830,7 +795,7 @@
<rect> <rect>
<x>40</x> <x>40</x>
<y>175</y> <y>175</y>
<width>341</width> <width>355</width>
<height>20</height> <height>20</height>
</rect> </rect>
</property> </property>
@ -964,7 +929,7 @@
<widget class="QLabel" name="timeTotalLabel"> <widget class="QLabel" name="timeTotalLabel">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>290</x> <x>300</x>
<y>200</y> <y>200</y>
<width>25</width> <width>25</width>
<height>16</height> <height>16</height>
@ -980,7 +945,7 @@
<widget class="QLabel" name="timeTotalText"> <widget class="QLabel" name="timeTotalText">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>320</x> <x>330</x>
<y>200</y> <y>200</y>
<width>60</width> <width>60</width>
<height>16</height> <height>16</height>
@ -1037,7 +1002,7 @@
<widget class="QCheckBox" name="header"> <widget class="QCheckBox" name="header">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>290</x> <x>285</x>
<y>10</y> <y>10</y>
<width>50</width> <width>50</width>
<height>16</height> <height>16</height>
@ -1053,7 +1018,7 @@
<widget class="QCheckBox" name="crc"> <widget class="QCheckBox" name="crc">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>230</x> <x>226</x>
<y>10</y> <y>10</y>
<width>50</width> <width>50</width>
<height>16</height> <height>16</height>
@ -1168,6 +1133,41 @@
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property> </property>
</widget> </widget>
<widget class="QLineEdit" name="syncWord">
<property name="geometry">
<rect>
<x>377</x>
<y>8</y>
<width>22</width>
<height>20</height>
</rect>
</property>
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="toolTip">
<string>Sync word (1 byte hex)</string>
</property>
<property name="inputMask">
<string>HH</string>
</property>
<property name="text">
<string>00</string>
</property>
</widget>
<widget class="QLabel" name="syncLabel">
<property name="geometry">
<rect>
<x>342</x>
<y>10</y>
<width>32</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>Sync</string>
</property>
</widget>
</widget> </widget>
</widget> </widget>
<customwidgets> <customwidgets>

View File

@ -122,6 +122,22 @@ void ChirpChatModSettings::generateMessages()
.arg(m_urCall).arg(m_myCall).arg(m_textMessage); .arg(m_urCall).arg(m_myCall).arg(m_textMessage);
} }
unsigned int ChirpChatModSettings::getNbSFDFourths() const
{
switch (m_codingScheme)
{
case CodingLoRa:
return 9;
default:
return 8;
}
}
bool ChirpChatModSettings::hasSyncWord() const
{
return m_codingScheme == CodingLoRa;
}
QByteArray ChirpChatModSettings::serialize() const QByteArray ChirpChatModSettings::serialize() const
{ {
SimpleSerializer s(1); SimpleSerializer s(1);

View File

@ -96,6 +96,8 @@ struct ChirpChatModSettings
void resetToDefaults(); void resetToDefaults();
void setDefaultTemplates(); void setDefaultTemplates();
void generateMessages(); void generateMessages();
unsigned int getNbSFDFourths() const; //!< Get the number of SFD period fourths (depends on coding scheme)
bool hasSyncWord() const; //!< Only LoRa has a syncword (for the moment)
void setChannelMarker(Serializable *channelMarker) { m_channelMarker = channelMarker; } void setChannelMarker(Serializable *channelMarker) { m_channelMarker = channelMarker; }
QByteArray serialize() const; QByteArray serialize() const;
bool deserialize(const QByteArray& data); bool deserialize(const QByteArray& data);

View File

@ -233,10 +233,20 @@ void ChirpChatModSource::modulateSample()
if (m_chirpCount == m_settings.m_preambleChirps) if (m_chirpCount == m_settings.m_preambleChirps)
{ {
m_chirpCount = 0; m_chirpCount = 0;
m_chirp0 = ((m_settings.m_syncWord >> ((1-m_chirpCount)*4)) & 0xf)*8;
m_chirp = (m_chirp0 + m_fftLength)*ChirpChatModSettings::oversampling - 1; if (m_settings.hasSyncWord())
m_fftCounter = 0; {
m_state = ChirpChatStateSyncWord; m_chirp0 = ((m_settings.m_syncWord >> ((1-m_chirpCount)*4)) & 0xf)*8;
m_chirp = (m_chirp0 + m_fftLength)*ChirpChatModSettings::oversampling - 1;
m_state = ChirpChatStateSyncWord;
}
else
{
m_sampleCounter = 0;
m_chirp0 = 0;
m_chirp = m_fftLength*ChirpChatModSettings::oversampling - 1;
m_state = ChirpChatStateSFD;
}
} }
} }
} }
@ -286,7 +296,7 @@ void ChirpChatModSource::modulateSample()
m_sampleCounter = 0; m_sampleCounter = 0;
} }
if (m_chirpCount == 9) if (m_chirpCount == m_settings.getNbSFDFourths())
{ {
m_fftCounter = 0; m_fftCounter = 0;
m_chirpCount = 0; m_chirpCount = 0;

View File

@ -82,7 +82,7 @@ In practice it is difficult on the Rx side to make correct decodes if only one F
<h3>7: Sync word</h3> <h3>7: Sync word</h3>
This is the sync word (byte) to transmit entered as a 2 nibble hexadecimal number. This is a LoRa specific feature and is the sync word (byte) to transmit entered as a 2 nibble hexadecimal number.
<h3>8: Number of preamble chirps</h3> <h3>8: Number of preamble chirps</h3>