mirror of
https://github.com/f4exb/sdrangel.git
synced 2026-01-05 15:58:50 -05:00
LoRa mod: fixed packet length. LoRa demod: enhancements
This commit is contained in:
parent
9277813f23
commit
118840db0c
@ -119,6 +119,9 @@ bool LoRaDemod::handleMessage(const Message& cmd)
|
||||
msgToGUI->setPacketSize(m_decoder.getPacketLength());
|
||||
msgToGUI->setNbParityBits(m_decoder.getNbParityBits());
|
||||
msgToGUI->setHasCRC(m_decoder.getHasCRC());
|
||||
msgToGUI->setNbSymbols(m_decoder.getNbSymbols());
|
||||
msgToGUI->setNbCodewords(m_decoder.getNbCodewords());
|
||||
msgToGUI->setEarlyEOM(m_decoder.getEarlyEOM());
|
||||
msgToGUI->setHeaderParityStatus(m_decoder.getHeaderParityStatus());
|
||||
msgToGUI->setHeaderCRCStatus(m_decoder.getHeaderCRCStatus());
|
||||
msgToGUI->setPayloadParityStatus(m_decoder.getPayloadParityStatus());
|
||||
@ -200,7 +203,6 @@ void LoRaDemod::applySettings(const LoRaDemodSettings& settings, bool force)
|
||||
<< " m_hasCRC: " << settings.m_hasCRC
|
||||
<< " m_nbParityBits: " << settings.m_nbParityBits
|
||||
<< " m_packetLength: " << settings.m_packetLength
|
||||
<< " m_errorCheck: " << settings.m_errorCheck
|
||||
<< " m_rgbColor: " << settings.m_rgbColor
|
||||
<< " m_title: " << settings.m_title
|
||||
<< " force: " << force;
|
||||
@ -230,10 +232,6 @@ void LoRaDemod::applySettings(const LoRaDemodSettings& settings, bool force)
|
||||
m_decoder.setLoRaPacketLength(settings.m_packetLength);
|
||||
}
|
||||
|
||||
if ((settings.m_errorCheck != m_settings.m_errorCheck) || force) {
|
||||
m_decoder.setErrorCheck(settings.m_errorCheck);
|
||||
}
|
||||
|
||||
LoRaDemodBaseband::MsgConfigureLoRaDemodBaseband *msg = LoRaDemodBaseband::MsgConfigureLoRaDemodBaseband::create(settings, force);
|
||||
m_basebandSink->getInputMessageQueue()->push(msg);
|
||||
|
||||
|
||||
@ -67,10 +67,13 @@ public:
|
||||
float getNoiseDb() const { return m_noiseDb; }
|
||||
unsigned int getPacketSize() const { return m_packetSize; }
|
||||
unsigned int getNbParityBits() const { return m_nbParityBits; }
|
||||
unsigned int getNbSymbols() const { return m_nbSymbols; }
|
||||
unsigned int getNbCodewords() const { return m_nbCodewords; }
|
||||
bool getHasCRC() const { return m_hasCRC; }
|
||||
bool getHeaderParityStatus() const { return m_headerParityStatus; }
|
||||
bool getEarlyEOM() const { return m_earlyEOM; }
|
||||
int getHeaderParityStatus() const { return m_headerParityStatus; }
|
||||
bool getHeaderCRCStatus() const { return m_headerCRCStatus; }
|
||||
bool getPayloadParityStatus() const { return m_payloadParityStatus; }
|
||||
int getPayloadParityStatus() const { return m_payloadParityStatus; }
|
||||
bool getPayloadCRCStatus() const { return m_payloadCRCStatus; }
|
||||
|
||||
static MsgReportDecodeBytes* create(const QByteArray& bytes) {
|
||||
@ -91,16 +94,25 @@ public:
|
||||
void setNbParityBits(unsigned int nbParityBits) {
|
||||
m_nbParityBits = nbParityBits;
|
||||
}
|
||||
void setNbSymbols(unsigned int nbSymbols) {
|
||||
m_nbSymbols = nbSymbols;
|
||||
}
|
||||
void setNbCodewords(unsigned int nbCodewords) {
|
||||
m_nbCodewords = nbCodewords;
|
||||
}
|
||||
void setHasCRC(bool hasCRC) {
|
||||
m_hasCRC = hasCRC;
|
||||
}
|
||||
void setHeaderParityStatus(bool headerParityStatus) {
|
||||
void setEarlyEOM(bool earlyEOM) {
|
||||
m_earlyEOM = earlyEOM;
|
||||
}
|
||||
void setHeaderParityStatus(int headerParityStatus) {
|
||||
m_headerParityStatus = headerParityStatus;
|
||||
}
|
||||
void setHeaderCRCStatus(bool headerCRCStatus) {
|
||||
m_headerCRCStatus = headerCRCStatus;
|
||||
}
|
||||
void setPayloadParityStatus(bool payloadParityStatus) {
|
||||
void setPayloadParityStatus(int payloadParityStatus) {
|
||||
m_payloadParityStatus = payloadParityStatus;
|
||||
}
|
||||
void setPayloadCRCStatus(bool payloadCRCStatus) {
|
||||
@ -114,10 +126,13 @@ public:
|
||||
float m_noiseDb;
|
||||
unsigned int m_packetSize;
|
||||
unsigned int m_nbParityBits;
|
||||
unsigned int m_nbSymbols;
|
||||
unsigned int m_nbCodewords;
|
||||
bool m_hasCRC;
|
||||
bool m_headerParityStatus;
|
||||
bool m_earlyEOM;
|
||||
int m_headerParityStatus;
|
||||
bool m_headerCRCStatus;
|
||||
bool m_payloadParityStatus;
|
||||
int m_payloadParityStatus;
|
||||
bool m_payloadCRCStatus;
|
||||
|
||||
MsgReportDecodeBytes(const QByteArray& bytes) :
|
||||
@ -128,7 +143,10 @@ public:
|
||||
m_noiseDb(0.0),
|
||||
m_packetSize(0),
|
||||
m_nbParityBits(0),
|
||||
m_nbSymbols(0),
|
||||
m_nbCodewords(0),
|
||||
m_hasCRC(false),
|
||||
m_earlyEOM(false),
|
||||
m_headerParityStatus(false),
|
||||
m_headerCRCStatus(false),
|
||||
m_payloadParityStatus(false),
|
||||
|
||||
@ -78,12 +78,21 @@ void LoRaDemodDecoder::decodeSymbols(const std::vector<unsigned short>& symbols,
|
||||
m_hasCRC,
|
||||
m_nbParityBits,
|
||||
m_packetLength,
|
||||
m_errorCheck,
|
||||
m_earlyEOM,
|
||||
m_headerParityStatus,
|
||||
m_headerCRCStatus,
|
||||
m_payloadParityStatus,
|
||||
m_payloadCRCStatus
|
||||
);
|
||||
LoRaDemodDecoderLoRa::getCodingMetrics(
|
||||
m_nbSymbolBits,
|
||||
m_nbParityBits,
|
||||
m_packetLength,
|
||||
m_hasHeader,
|
||||
m_hasCRC,
|
||||
m_nbSymbols,
|
||||
m_nbCodewords
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -33,15 +33,17 @@ public:
|
||||
void setLoRaHasHeader(bool hasHeader) { m_hasHeader = hasHeader; }
|
||||
void setLoRaHasCRC(bool hasCRC) { m_hasCRC = hasCRC; }
|
||||
void setLoRaPacketLength(unsigned int packetLength) { m_packetLength = packetLength; }
|
||||
void setErrorCheck(bool errorCheck) { m_errorCheck = errorCheck; }
|
||||
void decodeSymbols(const std::vector<unsigned short>& symbols, QString& str); //!< For ASCII and TTY
|
||||
void decodeSymbols(const std::vector<unsigned short>& symbols, QByteArray& bytes); //!< For raw bytes (original LoRa)
|
||||
unsigned int getNbParityBits() const { return m_nbParityBits; }
|
||||
unsigned int getPacketLength() const { return m_packetLength; }
|
||||
bool getHasCRC() const { return m_hasCRC; }
|
||||
bool getHeaderParityStatus() const { return m_headerParityStatus; }
|
||||
unsigned int getNbSymbols() const { return m_nbSymbols; }
|
||||
unsigned int getNbCodewords() const { return m_nbCodewords; }
|
||||
bool getEarlyEOM() const { return m_earlyEOM; }
|
||||
int getHeaderParityStatus() const { return m_headerParityStatus; }
|
||||
bool getHeaderCRCStatus() const { return m_headerCRCStatus; }
|
||||
bool getPayloadParityStatus() const { return m_payloadParityStatus; }
|
||||
int getPayloadParityStatus() const { return m_payloadParityStatus; }
|
||||
bool getPayloadCRCStatus() const { return m_payloadCRCStatus; }
|
||||
|
||||
private:
|
||||
@ -54,10 +56,12 @@ private:
|
||||
bool m_hasCRC;
|
||||
bool m_hasHeader;
|
||||
unsigned int m_packetLength;
|
||||
bool m_errorCheck;
|
||||
bool m_headerParityStatus;
|
||||
unsigned int m_nbSymbols; //!< Number of encoded symbols: this is only dependent of nbSymbolBits, nbParityBits, packetLength, hasHeader and hasCRC
|
||||
unsigned int m_nbCodewords; //!< Number of encoded codewords: this is only dependent of nbSymbolBits, nbParityBits, packetLength, hasHeader and hasCRC
|
||||
bool m_earlyEOM;
|
||||
int m_headerParityStatus;
|
||||
bool m_headerCRCStatus;
|
||||
bool m_payloadParityStatus;
|
||||
int m_payloadParityStatus;
|
||||
bool m_payloadCRCStatus;
|
||||
};
|
||||
|
||||
|
||||
@ -19,6 +19,83 @@
|
||||
|
||||
#include "lorademoddecoderlora.h"
|
||||
|
||||
void LoRaDemodDecoderLoRa::decodeHeader(
|
||||
const std::vector<unsigned short>& inSymbols,
|
||||
unsigned int nbSymbolBits,
|
||||
bool& hasCRC,
|
||||
unsigned int& nbParityBits,
|
||||
unsigned int& packetLength,
|
||||
int& headerParityStatus,
|
||||
bool& headerCRCStatus
|
||||
)
|
||||
{
|
||||
// with header (H: header 8-bit codeword P: payload-8 bit codeword):
|
||||
// nbSymbolBits = 5 |H|H|H|H|H| codewords => 8 symbols (always) : static headerSymbols = 8
|
||||
// nbSymbolBits = 7 |H|H|H|H|H|P|P|
|
||||
// without header (P: payload 8-bit codeword):
|
||||
// nbSymbolBits = 5 |P|P|P|P|P| codewords => 8 symbols (always)
|
||||
// nbSymbolBits = 7 |P|P|P|P|P|P|P|
|
||||
// Actual header is always represented with 5 8-bit codewords : static headerCodewords = 5
|
||||
// These 8-bit codewords are encoded with Hamming(4,8) FEC : static headerParityBits = 4
|
||||
|
||||
const unsigned int numSymbols = roundUp(inSymbols.size(), 4 + nbParityBits);
|
||||
const unsigned int numCodewords = (numSymbols / (4 + nbParityBits))*nbSymbolBits;
|
||||
|
||||
std::vector<uint16_t> symbols(headerSymbols);
|
||||
std::copy(inSymbols.begin(), inSymbols.begin() + headerSymbols, symbols.begin());
|
||||
|
||||
//gray encode
|
||||
for (auto &sym : symbols) {
|
||||
sym = binaryToGray16(sym);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> codewords(nbSymbolBits);
|
||||
|
||||
// Header symbols de-interleave thus headerSymbols (8) symbols into nbSymbolBits (5..12) codewords using header FEC (4/8)
|
||||
diagonalDeinterleaveSx(symbols.data(), headerSymbols, codewords.data(), nbSymbolBits, headerParityBits);
|
||||
|
||||
// whitening does not apply to the header codewords
|
||||
Sx1272ComputeWhiteningLfsr(codewords.data() + headerCodewords, nbSymbolBits - headerCodewords, 0, headerParityBits);
|
||||
|
||||
bool error = false;
|
||||
bool bad = false;
|
||||
uint8_t bytes[3];
|
||||
|
||||
// decode actual header inside 8-bit codewords header with 4/8 FEC (5 first codewords)
|
||||
bytes[0] = decodeHamming84sx(codewords[1], error, bad) & 0xf;
|
||||
bytes[0] |= decodeHamming84sx(codewords[0], error, bad) << 4; // length
|
||||
|
||||
bytes[1] = decodeHamming84sx(codewords[2], error, bad) & 0xf; // coding rate and crc enable
|
||||
|
||||
bytes[2] = decodeHamming84sx(codewords[4], error, bad) & 0xf;
|
||||
bytes[2] |= decodeHamming84sx(codewords[3], error, bad) << 4; // checksum
|
||||
|
||||
bytes[2] ^= headerChecksum(bytes);
|
||||
|
||||
if (bad)
|
||||
{
|
||||
headerParityStatus = (int) ParityError;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (error) {
|
||||
headerParityStatus = (int) ParityCorrected;
|
||||
} else {
|
||||
headerParityStatus = (int) ParityOK;
|
||||
}
|
||||
|
||||
if (bytes[2] != 0) {
|
||||
headerCRCStatus = false;
|
||||
} else {
|
||||
headerCRCStatus = true;
|
||||
}
|
||||
}
|
||||
|
||||
hasCRC = (bytes[1] & 1) != 0;
|
||||
nbParityBits = (bytes[1] >> 1) & 0x7;
|
||||
packetLength = bytes[0];
|
||||
}
|
||||
|
||||
void LoRaDemodDecoderLoRa::decodeBytes(
|
||||
QByteArray& inBytes,
|
||||
const std::vector<unsigned short>& inSymbols,
|
||||
@ -27,14 +104,44 @@ void LoRaDemodDecoderLoRa::decodeBytes(
|
||||
bool& hasCRC,
|
||||
unsigned int& nbParityBits,
|
||||
unsigned int& packetLength,
|
||||
bool errorCheck,
|
||||
bool& headerParityStatus,
|
||||
bool& earlyEOM,
|
||||
int& headerParityStatus,
|
||||
bool& headerCRCStatus,
|
||||
bool& payloadParityStatus,
|
||||
int& payloadParityStatus,
|
||||
bool& payloadCRCStatus
|
||||
)
|
||||
{
|
||||
if (inSymbols.size() < 8) { // need at least a header
|
||||
// need at least a header (8 symbols of 8 bit codewords) whether an actual header is sent or not
|
||||
if (inSymbols.size() < headerSymbols)
|
||||
{
|
||||
qDebug("LoRaDemodDecoderLoRa::decodeBytes: need at least %u symbols for header", headerSymbols);
|
||||
earlyEOM = true;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
earlyEOM = false;
|
||||
}
|
||||
|
||||
if (hasHeader)
|
||||
{
|
||||
decodeHeader(
|
||||
inSymbols,
|
||||
nbSymbolBits,
|
||||
hasCRC,
|
||||
nbParityBits,
|
||||
packetLength,
|
||||
headerParityStatus,
|
||||
headerCRCStatus
|
||||
);
|
||||
}
|
||||
|
||||
qDebug("LoRaDemodDecoderLoRa::decodeBytes: crc: %s nbParityBits: %u packetLength: %u",
|
||||
hasCRC ? "on": "off", nbParityBits, packetLength);
|
||||
|
||||
if (nbParityBits > 4)
|
||||
{
|
||||
qDebug("LoRaDemodDecoderLoRa::decodeBytes: invalid parity bits in header: %u", nbParityBits);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -54,20 +161,24 @@ void LoRaDemodDecoderLoRa::decodeBytes(
|
||||
unsigned int sOfs = 0;
|
||||
unsigned int cOfs = 0;
|
||||
|
||||
if (nbParityBits != 4)
|
||||
{
|
||||
diagonalDeinterleaveSx(symbols.data(), 8, codewords.data(), nbSymbolBits, 4);
|
||||
// the first headerSymbols (8 symbols) are coded with 4/8 FEC (thus 8 bit codewords) whether an actual header is present or not
|
||||
// this corresponds to nbSymbolBits codewords (therefore LoRa imposes nbSymbolBits >= headerCodewords (5 codewords) this is controlled externally)
|
||||
|
||||
if (hasHeader) {
|
||||
if (nbParityBits != 4) // different FEC between header symbols and the rest of the packet
|
||||
{
|
||||
// Header symbols de-interleave thus headerSymbols (8) symbols into nbSymbolBits (5..12) codewords using header FEC (4/8)
|
||||
diagonalDeinterleaveSx(symbols.data(), headerSymbols, codewords.data(), nbSymbolBits, headerParityBits);
|
||||
|
||||
if (hasHeader) { // whitening does not apply to the header codewords
|
||||
Sx1272ComputeWhiteningLfsr(codewords.data() + headerCodewords, nbSymbolBits - headerCodewords, 0, headerParityBits);
|
||||
} else {
|
||||
Sx1272ComputeWhiteningLfsr(codewords.data(), nbSymbolBits, 0, headerParityBits);
|
||||
}
|
||||
|
||||
cOfs += nbSymbolBits;
|
||||
sOfs += headerSymbols;
|
||||
cOfs += nbSymbolBits; // nbSymbolBits codewords in header
|
||||
sOfs += headerSymbols; // headerSymbols symbols in header
|
||||
|
||||
if (numSymbols - sOfs > 0)
|
||||
if (numSymbols - sOfs > 0) // remaining payload symbols after header symbols using their own FEC (4/5..4/7)
|
||||
{
|
||||
diagonalDeinterleaveSx(symbols.data() + sOfs, numSymbols - sOfs, codewords.data() + cOfs, nbSymbolBits, nbParityBits);
|
||||
|
||||
@ -78,101 +189,48 @@ void LoRaDemodDecoderLoRa::decodeBytes(
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
else // uniform 4/8 FEC for all the packet
|
||||
{
|
||||
// De-interleave the whole packet thus numSymbols into nbSymbolBits (5..12) codewords using packet FEC (4/8)
|
||||
diagonalDeinterleaveSx(symbols.data(), numSymbols, codewords.data(), nbSymbolBits, nbParityBits);
|
||||
|
||||
if (hasHeader) {
|
||||
if (hasHeader) { // whitening does not apply to the header codewords
|
||||
Sx1272ComputeWhiteningLfsr(codewords.data() + headerCodewords, numCodewords - headerCodewords, 0, nbParityBits);
|
||||
} else {
|
||||
Sx1272ComputeWhiteningLfsr(codewords.data(), numCodewords, 0, nbParityBits);
|
||||
}
|
||||
}
|
||||
|
||||
bool error = false;
|
||||
bool bad = false;
|
||||
// Now we have nbSymbolBits 8-bit codewords (4/8 FEC) possibly containing the actual header followed by the rest of payload codewords with their own FEC (4/5..4/8)
|
||||
|
||||
std::vector<uint8_t> bytes((codewords.size()+1) / 2);
|
||||
unsigned int dOfs = 0;
|
||||
cOfs = 0;
|
||||
|
||||
unsigned int dataLength = 0;
|
||||
bool hasCRCInt; // payload has CRC indicator internal (explicit or implicit)
|
||||
unsigned int nbParityBitsInt; // number of parity bits internal (explicit or implicit)
|
||||
unsigned int packetLengthInt; // packet length internal (explicit or implicit)
|
||||
unsigned int dataLength = packetLength + 3 + (hasCRC ? 2 : 0); // include header and CRC
|
||||
|
||||
if (hasHeader)
|
||||
{
|
||||
bytes[0] = decodeHamming84sx(codewords[1], error, bad) & 0xf;
|
||||
bytes[0] |= decodeHamming84sx(codewords[0], error, bad) << 4; // length
|
||||
|
||||
bytes[1] = decodeHamming84sx(codewords[2], error, bad) & 0xf; // coding rate and crc enable
|
||||
|
||||
bytes[2] = decodeHamming84sx(codewords[4], error, bad) & 0xf;
|
||||
bytes[2] |= decodeHamming84sx(codewords[3], error, bad) << 4; // checksum
|
||||
|
||||
bytes[2] ^= headerChecksum(bytes.data());
|
||||
|
||||
if (error)
|
||||
{
|
||||
qDebug("LoRaDemodDecoderLoRa::decodeBytes: header Hamming error");
|
||||
headerParityStatus = false;
|
||||
|
||||
if (errorCheck) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
headerParityStatus = true;
|
||||
|
||||
if (bytes[2] != 0)
|
||||
{
|
||||
headerCRCStatus = false;
|
||||
qDebug("LoRaDemodDecoderLoRa::decodeBytes: header CRC error");
|
||||
|
||||
if (errorCheck) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
headerCRCStatus = true;
|
||||
}
|
||||
}
|
||||
|
||||
hasCRCInt = (bytes[1] & 1) != 0;
|
||||
nbParityBitsInt = (bytes[1] >> 1) & 0x7;
|
||||
|
||||
if (nbParityBitsInt > 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
packetLengthInt = bytes[0];
|
||||
//dataLength = packetLengthInt + 3 + (hasCRCInt ? 2 : 0); // include header and crc
|
||||
dataLength = packetLengthInt + 5;
|
||||
|
||||
cOfs = headerCodewords;
|
||||
dOfs = 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
hasCRCInt = hasCRC;
|
||||
nbParityBitsInt = nbParityBits;
|
||||
packetLengthInt = packetLength;
|
||||
cOfs = 0;
|
||||
dOfs = 0;
|
||||
|
||||
if (hasCRCInt) {
|
||||
dataLength = packetLengthInt + 2;
|
||||
} else {
|
||||
dataLength = packetLengthInt;
|
||||
}
|
||||
}
|
||||
|
||||
if (dataLength > bytes.size()) {
|
||||
if (dataLength > bytes.size())
|
||||
{
|
||||
qDebug("LoRaDemodDecoderLoRa::decodeBytes: not enough data %lu vs %u", bytes.size(), dataLength);
|
||||
earlyEOM = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// decode the rest of the payload inside 8-bit codewords header with 4/8 FEC
|
||||
bool error = false;
|
||||
bool bad = false;
|
||||
|
||||
for (; cOfs < nbSymbolBits; cOfs++, dOfs++)
|
||||
{
|
||||
if (dOfs % 2 == 1) {
|
||||
@ -182,15 +240,15 @@ void LoRaDemodDecoderLoRa::decodeBytes(
|
||||
}
|
||||
}
|
||||
|
||||
if (dOfs % 2 == 1)
|
||||
if (dOfs % 2 == 1) // decode the start of the payload codewords with their own FEC when not on an even boundary
|
||||
{
|
||||
if (nbParityBitsInt == 1) {
|
||||
if (nbParityBits == 1) {
|
||||
bytes[dOfs/2] |= checkParity54(codewords[cOfs++], error) << 4;
|
||||
} else if (nbParityBitsInt == 2) {
|
||||
} else if (nbParityBits == 2) {
|
||||
bytes[dOfs/2] |= checkParity64(codewords[cOfs++], error) << 4;
|
||||
} else if (nbParityBitsInt == 3){
|
||||
} else if (nbParityBits == 3){
|
||||
bytes[dOfs/2] |= decodeHamming74sx(codewords[cOfs++], error) << 4;
|
||||
} else if (nbParityBitsInt == 4){
|
||||
} else if (nbParityBits == 4){
|
||||
bytes[dOfs/2] |= decodeHamming84sx(codewords[cOfs++], error, bad) << 4;
|
||||
} else {
|
||||
bytes[dOfs/2] |= codewords[cOfs++] << 4;
|
||||
@ -201,23 +259,9 @@ void LoRaDemodDecoderLoRa::decodeBytes(
|
||||
|
||||
dOfs /= 2;
|
||||
|
||||
if (error)
|
||||
{
|
||||
qDebug("LoRaDemodDecoderLoRa::decodeBytes: Hamming decode (1) error");
|
||||
payloadParityStatus = false;
|
||||
// decode the rest of the payload codewords with their own FEC
|
||||
|
||||
if (errorCheck) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
payloadParityStatus = true;
|
||||
}
|
||||
|
||||
//decode each codeword as 2 bytes with correction
|
||||
|
||||
if (nbParityBitsInt == 1)
|
||||
if (nbParityBits == 1)
|
||||
{
|
||||
for (unsigned int i = dOfs; i < dataLength; i++)
|
||||
{
|
||||
@ -225,7 +269,7 @@ void LoRaDemodDecoderLoRa::decodeBytes(
|
||||
bytes[i] |= checkParity54(codewords[cOfs++], error) << 4;
|
||||
}
|
||||
}
|
||||
else if (nbParityBitsInt == 2)
|
||||
else if (nbParityBits == 2)
|
||||
{
|
||||
for (unsigned int i = dOfs; i < dataLength; i++)
|
||||
{
|
||||
@ -233,7 +277,7 @@ void LoRaDemodDecoderLoRa::decodeBytes(
|
||||
bytes[i] |= checkParity64(codewords[cOfs++],error) << 4;
|
||||
}
|
||||
}
|
||||
else if (nbParityBitsInt == 3)
|
||||
else if (nbParityBits == 3)
|
||||
{
|
||||
for (unsigned int i = dOfs; i < dataLength; i++)
|
||||
{
|
||||
@ -241,7 +285,7 @@ void LoRaDemodDecoderLoRa::decodeBytes(
|
||||
bytes[i] |= decodeHamming74sx(codewords[cOfs++], error) << 4;
|
||||
}
|
||||
}
|
||||
else if (nbParityBitsInt == 4)
|
||||
else if (nbParityBits == 4)
|
||||
{
|
||||
for (unsigned int i = dOfs; i < dataLength; i++)
|
||||
{
|
||||
@ -258,73 +302,66 @@ void LoRaDemodDecoderLoRa::decodeBytes(
|
||||
}
|
||||
}
|
||||
|
||||
if (error)
|
||||
{
|
||||
qDebug("LoRaDemodDecoderLoRa::decodeBytes: Hamming decode (2) error");
|
||||
payloadParityStatus = false;
|
||||
|
||||
if (errorCheck) {
|
||||
return;
|
||||
}
|
||||
if (bad) {
|
||||
payloadParityStatus = (int) ParityError;
|
||||
} else if (error) {
|
||||
payloadParityStatus = (int) ParityCorrected;
|
||||
} else {
|
||||
payloadParityStatus = (int) ParityOK;
|
||||
}
|
||||
|
||||
// finalization:
|
||||
// adjust offsets dpending on header and CRC presence
|
||||
// compute and verify payload CRC if present
|
||||
|
||||
if (hasHeader)
|
||||
{
|
||||
dOfs = 3;
|
||||
dataLength -= 5;
|
||||
dOfs = 3; // skip header
|
||||
dataLength -= 3; // remove header
|
||||
|
||||
if (hasCRCInt) // always compute crc if present
|
||||
if (hasCRC) // always compute crc if present skipping the header
|
||||
{
|
||||
uint16_t crc = sx1272DataChecksum(bytes.data() + dOfs, packetLengthInt - 2);
|
||||
uint16_t packetCRC = bytes[dOfs + packetLengthInt - 2] | (bytes[dOfs + packetLengthInt - 1] << 8);
|
||||
uint16_t crc = sx1272DataChecksum(bytes.data() + dOfs, packetLength);
|
||||
uint16_t packetCRC = bytes[dOfs + packetLength] | (bytes[dOfs + packetLength + 1] << 8);
|
||||
|
||||
if (crc != packetCRC)
|
||||
{
|
||||
qDebug("LoRaDemodDecoderLoRa::decodeBytes: packet CRC error: calc: %x found: %x", crc, packetCRC);
|
||||
if (crc != packetCRC) {
|
||||
payloadCRCStatus = false;
|
||||
|
||||
if (errorCheck) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
payloadCRCStatus = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
hasCRC = hasCRCInt;
|
||||
nbParityBits = nbParityBitsInt;
|
||||
packetLength = packetLengthInt;
|
||||
}
|
||||
else
|
||||
{
|
||||
dOfs = 0;
|
||||
dOfs = 0; // no header to skip
|
||||
|
||||
if (hasCRCInt)
|
||||
if (hasCRC)
|
||||
{
|
||||
uint16_t crc = sx1272DataChecksum(bytes.data(), packetLengthInt - 2);
|
||||
uint16_t packetCRC = bytes[packetLengthInt - 2] | (bytes[packetLengthInt - 1] << 8);
|
||||
uint16_t crc = sx1272DataChecksum(bytes.data(), packetLength);
|
||||
uint16_t packetCRC = bytes[packetLength] | (bytes[packetLength + 1] << 8);
|
||||
|
||||
if (crc != packetCRC)
|
||||
{
|
||||
qDebug("LoRaDemodDecoderLoRa::decodeBytes: packet CRC error: calc: %x found: %x", crc, packetCRC);
|
||||
if (crc != packetCRC) {
|
||||
payloadCRCStatus = false;
|
||||
|
||||
if (errorCheck) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
payloadCRCStatus = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
qDebug("LoRaDemodDecoderLoRa::decodeBytes: dataLength: %u packetLengthInt: %u", dataLength, packetLengthInt);
|
||||
inBytes.resize(dataLength);
|
||||
std::copy(bytes.data() + dOfs, bytes.data() + dOfs + dataLength, inBytes.data());
|
||||
}
|
||||
|
||||
void LoRaDemodDecoderLoRa::getCodingMetrics(
|
||||
unsigned int nbSymbolBits,
|
||||
unsigned int nbParityBits,
|
||||
unsigned int packetLength,
|
||||
bool hasHeader,
|
||||
bool hasCRC,
|
||||
unsigned int& numSymbols,
|
||||
unsigned int& numCodewords
|
||||
)
|
||||
{
|
||||
numCodewords = roundUp((packetLength + (hasCRC ? 2 : 0))*2 + (hasHeader ? headerCodewords : 0), nbSymbolBits); // uses payload + CRC for encoding size
|
||||
numSymbols = headerSymbols + (numCodewords / nbSymbolBits - 1) * (4 + nbParityBits); // header is always coded with 8 bits and yields exactly 8 symbols (headerSymbols)
|
||||
}
|
||||
@ -26,6 +26,14 @@
|
||||
class LoRaDemodDecoderLoRa
|
||||
{
|
||||
public:
|
||||
enum ParityStatus
|
||||
{
|
||||
ParityUndefined,
|
||||
ParityError,
|
||||
ParityCorrected,
|
||||
ParityOK
|
||||
};
|
||||
|
||||
static void decodeBytes(
|
||||
QByteArray& bytes,
|
||||
const std::vector<unsigned short>& inSymbols,
|
||||
@ -34,14 +42,34 @@ public:
|
||||
bool& hasCRC,
|
||||
unsigned int& nbParityBits,
|
||||
unsigned int& packetLength,
|
||||
bool errorCheck,
|
||||
bool& headerParityStatus,
|
||||
bool& earlyEOM,
|
||||
int& headerParityStatus,
|
||||
bool& headerCRCStatus,
|
||||
bool& payloadParityStatus,
|
||||
int& payloadParityStatus,
|
||||
bool& payloadCRCStatus
|
||||
);
|
||||
|
||||
static void getCodingMetrics(
|
||||
unsigned int nbSymbolBits,
|
||||
unsigned int nbParityBits,
|
||||
unsigned int packetLength,
|
||||
bool hasHeader,
|
||||
bool hasCRC,
|
||||
unsigned int& numSymbols,
|
||||
unsigned int& numCodewords
|
||||
);
|
||||
|
||||
private:
|
||||
static void decodeHeader(
|
||||
const std::vector<unsigned short>& inSymbols,
|
||||
unsigned int nbSymbolBits,
|
||||
bool& hasCRC,
|
||||
unsigned int& nbParityBits,
|
||||
unsigned int& packetLength,
|
||||
int& headerParityStatus,
|
||||
bool& headerCRCStatus
|
||||
);
|
||||
|
||||
static const unsigned int headerParityBits = 4;
|
||||
static const unsigned int headerSymbols = 8;
|
||||
static const unsigned int headerCodewords = 5;
|
||||
@ -240,6 +268,8 @@ private:
|
||||
* Decode 7 bits into a 4 bit word with single bit correction.
|
||||
* Non standard version used in sx1272.
|
||||
* Set error to true when a parity error was detected
|
||||
* Non correctable errors are indistinguishable from single or no errors
|
||||
* therefore no 'bad' variable is proposed
|
||||
**********************************************************************/
|
||||
static inline unsigned char decodeHamming74sx(const unsigned char b, bool &error)
|
||||
{
|
||||
@ -270,7 +300,7 @@ private:
|
||||
case 0x0:
|
||||
case 0x1:
|
||||
case 0x2:
|
||||
case 0x4: return b & 0xF;
|
||||
case 0x4: break;
|
||||
}
|
||||
|
||||
return b & 0xf;
|
||||
|
||||
@ -110,39 +110,18 @@ bool LoRaDemodGUI::handleMessage(const Message& message)
|
||||
}
|
||||
else if (LoRaDemod::MsgReportDecodeBytes::match(message))
|
||||
{
|
||||
const LoRaDemod::MsgReportDecodeBytes& msg = (LoRaDemod::MsgReportDecodeBytes&) message;
|
||||
QByteArray bytes = msg.getBytes();
|
||||
ui->syncWord->setText((tr("%1").arg(msg.getSyncWord(), 2, 16)));
|
||||
ui->sText->setText(tr("%1").arg(msg.getSingalDb(), 0, 'f', 1));
|
||||
ui->snrText->setText(tr("%1").arg(msg.getSingalDb() - msg.getNoiseDb(), 0, 'f', 1));
|
||||
|
||||
if (m_settings.m_hasHeader)
|
||||
{
|
||||
ui->fecParity->setValue(msg.getNbParityBits());
|
||||
ui->fecParityText->setText(tr("%1").arg(msg.getNbParityBits()));
|
||||
ui->crc->setChecked(msg.getHasCRC());
|
||||
ui->packetLength->setValue(msg.getPacketSize());
|
||||
ui->packetLengthText->setText(tr("%1").arg(msg.getPacketSize()));
|
||||
displayBytes(bytes, msg.getPacketSize(), msg.getHasCRC());
|
||||
}
|
||||
else
|
||||
{
|
||||
displayBytes(bytes, m_settings.m_packetLength, m_settings.m_hasCRC);
|
||||
}
|
||||
|
||||
if (m_settings.m_codingScheme == LoRaDemodSettings::CodingLoRa) {
|
||||
displayLoRaStatus(msg.getHeaderParityStatus(), msg.getHeaderCRCStatus(), msg.getPayloadParityStatus(), msg.getPayloadCRCStatus());
|
||||
showLoRaMessage(message);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (LoRaDemod::MsgReportDecodeString::match(message))
|
||||
{
|
||||
const LoRaDemod::MsgReportDecodeString& msg = (LoRaDemod::MsgReportDecodeString&) message;
|
||||
addText(msg.getString());
|
||||
ui->syncWord->setText((tr("%1").arg(msg.getSyncWord(), 2, 16)));
|
||||
ui->sText->setText(tr("%1").arg(msg.getSingalDb(), 0, 'f', 1));
|
||||
ui->snrText->setText(tr("%1").arg(msg.getSingalDb() - msg.getNoiseDb(), 0, 'f', 1));
|
||||
if ((m_settings.m_codingScheme == LoRaDemodSettings::CodingASCII)
|
||||
|| (m_settings.m_codingScheme == LoRaDemodSettings::CodingTTY)) {
|
||||
showTextMessage(message);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -246,6 +225,7 @@ void LoRaDemodGUI::on_clear_clicked(bool checked)
|
||||
{
|
||||
(void) checked;
|
||||
ui->messageText->clear();
|
||||
ui->hexText->clear();
|
||||
}
|
||||
|
||||
void LoRaDemodGUI::on_eomSquelch_valueChanged(int value)
|
||||
@ -296,12 +276,6 @@ void LoRaDemodGUI::on_crc_stateChanged(int state)
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void LoRaDemodGUI::on_errorCheck_stateChanged(int state)
|
||||
{
|
||||
m_settings.m_errorCheck = (state == Qt::Checked);
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void LoRaDemodGUI::on_packetLength_valueChanged(int value)
|
||||
{
|
||||
m_settings.m_packetLength = value;
|
||||
@ -426,7 +400,6 @@ void LoRaDemodGUI::displaySettings()
|
||||
ui->messageLengthText->setText(tr("%1").arg(m_settings.m_nbSymbolsMax));
|
||||
ui->messageLength->setValue(m_settings.m_nbSymbolsMax);
|
||||
ui->header->setChecked(m_settings.m_hasHeader);
|
||||
ui->errorCheck->setChecked(m_settings.m_errorCheck);
|
||||
|
||||
if (!m_settings.m_hasHeader)
|
||||
{
|
||||
@ -453,12 +426,14 @@ void LoRaDemodGUI::displaySquelch()
|
||||
}
|
||||
}
|
||||
|
||||
void LoRaDemodGUI::displayLoRaStatus(bool headerParityStatus, bool headerCRCStatus, bool payloadParityStatus, bool payloadCRCStatus)
|
||||
void LoRaDemodGUI::displayLoRaStatus(int headerParityStatus, bool headerCRCStatus, int payloadParityStatus, bool payloadCRCStatus)
|
||||
{
|
||||
if (m_settings.m_hasHeader && headerParityStatus) {
|
||||
if (m_settings.m_hasHeader && (headerParityStatus == (int) ParityOK)) {
|
||||
ui->headerHammingStatus->setStyleSheet("QLabel { background-color : green; }");
|
||||
} else if (m_settings.m_hasHeader && !headerParityStatus) {
|
||||
} else if (m_settings.m_hasHeader && (headerParityStatus == (int) ParityError)) {
|
||||
ui->headerHammingStatus->setStyleSheet("QLabel { background-color : red; }");
|
||||
} else if (m_settings.m_hasHeader && (headerParityStatus == (int) ParityCorrected)) {
|
||||
ui->headerHammingStatus->setStyleSheet("QLabel { background-color : blue; }");
|
||||
} else {
|
||||
ui->headerHammingStatus->setStyleSheet("QLabel { background:rgb(79,79,79); }");
|
||||
}
|
||||
@ -471,10 +446,14 @@ void LoRaDemodGUI::displayLoRaStatus(bool headerParityStatus, bool headerCRCStat
|
||||
ui->headerCRCStatus->setStyleSheet("QLabel { background:rgb(79,79,79); }");
|
||||
}
|
||||
|
||||
if (payloadParityStatus) {
|
||||
if (payloadParityStatus == (int) ParityOK) {
|
||||
ui->payloadFECStatus->setStyleSheet("QLabel { background-color : green; }");
|
||||
} else {
|
||||
} else if (payloadParityStatus == (int) ParityError) {
|
||||
ui->payloadFECStatus->setStyleSheet("QLabel { background-color : red; }");
|
||||
} else if (payloadParityStatus == (int) ParityCorrected) {
|
||||
ui->payloadFECStatus->setStyleSheet("QLabel { background-color : blue; }");
|
||||
} else {
|
||||
ui->payloadFECStatus->setStyleSheet("QLabel { background:rgb(79,79,79); }");
|
||||
}
|
||||
|
||||
if (payloadCRCStatus) {
|
||||
@ -490,6 +469,8 @@ void LoRaDemodGUI::resetLoRaStatus()
|
||||
ui->headerCRCStatus->setStyleSheet("QLabel { background:rgb(79,79,79); }");
|
||||
ui->payloadFECStatus->setStyleSheet("QLabel { background:rgb(79,79,79); }");
|
||||
ui->payloadCRCStatus->setStyleSheet("QLabel { background:rgb(79,79,79); }");
|
||||
ui->nbSymbolsText->setText("---");
|
||||
ui->nbCodewordsText->setText("---");
|
||||
}
|
||||
|
||||
void LoRaDemodGUI::setBandwidths()
|
||||
@ -509,30 +490,105 @@ void LoRaDemodGUI::setBandwidths()
|
||||
}
|
||||
}
|
||||
|
||||
void LoRaDemodGUI::addText(const QString& text)
|
||||
void LoRaDemodGUI::showLoRaMessage(const Message& message)
|
||||
{
|
||||
const LoRaDemod::MsgReportDecodeBytes& msg = (LoRaDemod::MsgReportDecodeBytes&) message;
|
||||
QByteArray bytes = msg.getBytes();
|
||||
|
||||
ui->syncWord->setText((tr("%1").arg(msg.getSyncWord(), 2, 16)));
|
||||
ui->sText->setText(tr("%1").arg(msg.getSingalDb(), 0, 'f', 1));
|
||||
ui->snrText->setText(tr("%1").arg(msg.getSingalDb() - msg.getNoiseDb(), 0, 'f', 1));
|
||||
unsigned int packetLength;
|
||||
|
||||
if (m_settings.m_hasHeader)
|
||||
{
|
||||
ui->fecParity->setValue(msg.getNbParityBits());
|
||||
ui->fecParityText->setText(tr("%1").arg(msg.getNbParityBits()));
|
||||
ui->crc->setChecked(msg.getHasCRC());
|
||||
ui->packetLength->setValue(msg.getPacketSize());
|
||||
ui->packetLengthText->setText(tr("%1").arg(msg.getPacketSize()));
|
||||
packetLength = msg.getPacketSize();
|
||||
}
|
||||
else
|
||||
{
|
||||
packetLength = m_settings.m_packetLength;
|
||||
}
|
||||
|
||||
QDateTime dt = QDateTime::currentDateTime();
|
||||
QString dateStr = dt.toString("HH:mm:ss");
|
||||
|
||||
if (msg.getEarlyEOM())
|
||||
{
|
||||
QString loRaStatus = tr("%1 %2 S:%3 SN:%4 HF:%5 HC:%6 EOM:too early")
|
||||
.arg(dateStr)
|
||||
.arg(msg.getSyncWord(), 2, 16)
|
||||
.arg(msg.getSingalDb(), 0, 'f', 1)
|
||||
.arg(msg.getSingalDb() - msg.getNoiseDb(), 0, 'f', 1)
|
||||
.arg(getParityStr(msg.getHeaderParityStatus()))
|
||||
.arg(msg.getHeaderCRCStatus() ? "ok" : "err");
|
||||
|
||||
displayStatus(loRaStatus);
|
||||
displayLoRaStatus(msg.getHeaderParityStatus(), msg.getHeaderCRCStatus(), (int) ParityUndefined, true);
|
||||
ui->payloadCRCStatus->setStyleSheet("QLabel { background:rgb(79,79,79); }"); // reset payload CRC
|
||||
}
|
||||
else
|
||||
{
|
||||
QString loRaHeader = tr("%1 %2 S:%3 SN:%4 HF:%5 HC:%6 FEC:%7 CRC:%8")
|
||||
.arg(dateStr)
|
||||
.arg(msg.getSyncWord(), 2, 16)
|
||||
.arg(msg.getSingalDb(), 0, 'f', 1)
|
||||
.arg(msg.getSingalDb() - msg.getNoiseDb(), 0, 'f', 1)
|
||||
.arg(getParityStr(msg.getHeaderParityStatus()))
|
||||
.arg(msg.getHeaderCRCStatus() ? "ok" : "err")
|
||||
.arg(getParityStr(msg.getPayloadParityStatus()))
|
||||
.arg(msg.getPayloadCRCStatus() ? "ok" : "err");
|
||||
|
||||
displayBytes(loRaHeader, bytes);
|
||||
|
||||
QByteArray bytesCopy(bytes);
|
||||
bytesCopy.truncate(packetLength);
|
||||
bytesCopy.replace('\0', " ");
|
||||
QString str = QString(bytesCopy.toStdString().c_str());
|
||||
displayText(dateStr, str);
|
||||
|
||||
displayLoRaStatus(msg.getHeaderParityStatus(), msg.getHeaderCRCStatus(), msg.getPayloadParityStatus(), msg.getPayloadCRCStatus());
|
||||
}
|
||||
|
||||
ui->nbSymbolsText->setText(tr("%1").arg(msg.getNbSymbols()));
|
||||
ui->nbCodewordsText->setText(tr("%1").arg(msg.getNbCodewords()));
|
||||
}
|
||||
|
||||
void LoRaDemodGUI::showTextMessage(const Message& message)
|
||||
{
|
||||
const LoRaDemod::MsgReportDecodeString& msg = (LoRaDemod::MsgReportDecodeString&) message;
|
||||
|
||||
QDateTime dt = QDateTime::currentDateTime();
|
||||
QString dateStr = dt.toString("HH:mm:ss");
|
||||
displayText(dateStr, msg.getString());
|
||||
ui->syncWord->setText((tr("%1").arg(msg.getSyncWord(), 2, 16)));
|
||||
ui->sText->setText(tr("%1").arg(msg.getSingalDb(), 0, 'f', 1));
|
||||
ui->snrText->setText(tr("%1").arg(msg.getSingalDb() - msg.getNoiseDb(), 0, 'f', 1));
|
||||
|
||||
QString status = tr("%1 S:%2 SN:%3")
|
||||
.arg(dateStr)
|
||||
.arg(msg.getSingalDb(), 0, 'f', 1)
|
||||
.arg(msg.getSingalDb() - msg.getNoiseDb(), 0, 'f', 1);
|
||||
displayStatus(status);
|
||||
}
|
||||
|
||||
void LoRaDemodGUI::displayText(const QString& header, const QString& text)
|
||||
{
|
||||
QTextCursor cursor = ui->messageText->textCursor();
|
||||
cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
|
||||
if (!ui->messageText->document()->isEmpty()) {
|
||||
cursor.insertText("\n");
|
||||
}
|
||||
cursor.insertText(tr("%1 %2").arg(dateStr).arg(text));
|
||||
cursor.insertText(tr("%1 %2").arg(header).arg(text));
|
||||
ui->messageText->verticalScrollBar()->setValue(ui->messageText->verticalScrollBar()->maximum());
|
||||
}
|
||||
|
||||
void LoRaDemodGUI::displayBytes(const QByteArray& bytes, unsigned int packetLength, bool hasCRC)
|
||||
void LoRaDemodGUI::displayBytes(const QString& header, const QByteArray& bytes)
|
||||
{
|
||||
QByteArray bytesCopy(bytes);
|
||||
bytesCopy.truncate(packetLength);
|
||||
bytesCopy.replace('\0', " ");
|
||||
QString str = QString(bytesCopy.toStdString().c_str());
|
||||
str.chop(hasCRC ? 2 : 0);
|
||||
addText(str);
|
||||
|
||||
QDateTime dt = QDateTime::currentDateTime();
|
||||
QString dateStr = dt.toString("=== HH:mm:ss ===");
|
||||
QTextCursor cursor = ui->hexText->textCursor();
|
||||
cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
|
||||
|
||||
@ -540,7 +596,7 @@ void LoRaDemodGUI::displayBytes(const QByteArray& bytes, unsigned int packetLeng
|
||||
cursor.insertText("\n");
|
||||
}
|
||||
|
||||
cursor.insertText(tr("%1\n").arg(dateStr));
|
||||
cursor.insertText(tr(">%1\n").arg(header));
|
||||
QByteArray::const_iterator it = bytes.begin();
|
||||
unsigned int i = 0;
|
||||
|
||||
@ -566,6 +622,32 @@ void LoRaDemodGUI::displayBytes(const QByteArray& bytes, unsigned int packetLeng
|
||||
ui->hexText->verticalScrollBar()->setValue(ui->hexText->verticalScrollBar()->maximum());
|
||||
}
|
||||
|
||||
void LoRaDemodGUI::displayStatus(const QString& status)
|
||||
{
|
||||
QTextCursor cursor = ui->hexText->textCursor();
|
||||
cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
|
||||
|
||||
if (!ui->hexText->document()->isEmpty()) {
|
||||
cursor.insertText("\n");
|
||||
}
|
||||
|
||||
cursor.insertText(tr(">%1").arg(status));
|
||||
ui->hexText->verticalScrollBar()->setValue(ui->hexText->verticalScrollBar()->maximum());
|
||||
}
|
||||
|
||||
QString LoRaDemodGUI::getParityStr(int parityStatus)
|
||||
{
|
||||
if (parityStatus == (int) ParityError) {
|
||||
return "err";
|
||||
} else if (parityStatus == (int) ParityCorrected) {
|
||||
return "fix";
|
||||
} else if (parityStatus == (int) ParityOK) {
|
||||
return "ok";
|
||||
} else {
|
||||
return "n/a";
|
||||
}
|
||||
}
|
||||
|
||||
void LoRaDemodGUI::tick()
|
||||
{
|
||||
if (m_tickCount < 10)
|
||||
|
||||
@ -68,7 +68,6 @@ private slots:
|
||||
void on_header_stateChanged(int state);
|
||||
void on_fecParity_valueChanged(int value);
|
||||
void on_crc_stateChanged(int state);
|
||||
void on_errorCheck_stateChanged(int state);
|
||||
void on_packetLength_valueChanged(int value);
|
||||
void onWidgetRolled(QWidget* widget, bool rollDown);
|
||||
void channelMarkerHighlightedByCursor();
|
||||
@ -76,6 +75,14 @@ private slots:
|
||||
void tick();
|
||||
|
||||
private:
|
||||
enum ParityStatus // matches LoRa decoder status
|
||||
{
|
||||
ParityUndefined,
|
||||
ParityError,
|
||||
ParityCorrected,
|
||||
ParityOK
|
||||
};
|
||||
|
||||
Ui::LoRaDemodGUI* ui;
|
||||
PluginAPI* m_pluginAPI;
|
||||
DeviceUISet* m_deviceUISet;
|
||||
@ -97,9 +104,13 @@ private:
|
||||
void displaySettings();
|
||||
void displaySquelch();
|
||||
void setBandwidths();
|
||||
void addText(const QString& text);
|
||||
void displayBytes(const QByteArray& bytes, unsigned int packetLength, bool hasCRC);
|
||||
void displayLoRaStatus(bool headerParityStatus, bool headerCRCStatus, bool payloadParityStatus, bool payloadCRCStatus);
|
||||
void showLoRaMessage(const Message& message);
|
||||
void showTextMessage(const Message& message); //!< For TTY and ASCII
|
||||
void displayText(const QString& header, const QString& text);
|
||||
void displayBytes(const QString& header, const QByteArray& bytes);
|
||||
void displayStatus(const QString& status);
|
||||
void displayLoRaStatus(int headerParityStatus, bool headerCRCStatus, int payloadParityStatus, bool payloadCRCStatus);
|
||||
QString getParityStr(int parityStatus);
|
||||
void resetLoRaStatus();
|
||||
};
|
||||
|
||||
|
||||
@ -6,13 +6,13 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>500</width>
|
||||
<width>512</width>
|
||||
<height>660</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>500</width>
|
||||
<width>512</width>
|
||||
<height>660</height>
|
||||
</size>
|
||||
</property>
|
||||
@ -28,9 +28,9 @@
|
||||
<widget class="QWidget" name="settingsContainer" native="true">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>5</x>
|
||||
<x>1</x>
|
||||
<y>20</y>
|
||||
<width>490</width>
|
||||
<width>510</width>
|
||||
<height>90</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -74,7 +74,7 @@
|
||||
<rect>
|
||||
<x>30</x>
|
||||
<y>50</y>
|
||||
<width>361</width>
|
||||
<width>381</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -102,7 +102,7 @@
|
||||
<rect>
|
||||
<x>30</x>
|
||||
<y>70</y>
|
||||
<width>80</width>
|
||||
<width>101</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -131,7 +131,7 @@
|
||||
<widget class="QLabel" name="SpreadText">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>120</x>
|
||||
<x>140</x>
|
||||
<y>70</y>
|
||||
<width>20</width>
|
||||
<height>16</height>
|
||||
@ -153,7 +153,7 @@
|
||||
<widget class="QLabel" name="BWText">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>400</x>
|
||||
<x>420</x>
|
||||
<y>50</y>
|
||||
<width>80</width>
|
||||
<height>16</height>
|
||||
@ -175,7 +175,7 @@
|
||||
<widget class="QLabel" name="deBitsLabel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>170</x>
|
||||
<x>190</x>
|
||||
<y>70</y>
|
||||
<width>22</width>
|
||||
<height>16</height>
|
||||
@ -188,7 +188,7 @@
|
||||
<widget class="QLabel" name="deBitsText">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>290</x>
|
||||
<x>320</x>
|
||||
<y>70</y>
|
||||
<width>15</width>
|
||||
<height>16</height>
|
||||
@ -210,9 +210,9 @@
|
||||
<widget class="QSlider" name="deBits">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>200</x>
|
||||
<x>220</x>
|
||||
<y>70</y>
|
||||
<width>80</width>
|
||||
<width>91</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -243,7 +243,7 @@
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>10</y>
|
||||
<width>471</width>
|
||||
<width>491</width>
|
||||
<height>26</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -392,7 +392,7 @@
|
||||
<widget class="QLabel" name="preambleChirpsText">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>450</x>
|
||||
<x>480</x>
|
||||
<y>70</y>
|
||||
<width>20</width>
|
||||
<height>16</height>
|
||||
@ -414,7 +414,7 @@
|
||||
<widget class="QLabel" name="preambleChirpsLabel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>340</x>
|
||||
<x>350</x>
|
||||
<y>70</y>
|
||||
<width>32</width>
|
||||
<height>16</height>
|
||||
@ -427,9 +427,9 @@
|
||||
<widget class="QSlider" name="preambleChirps">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>370</x>
|
||||
<x>380</x>
|
||||
<y>70</y>
|
||||
<width>81</width>
|
||||
<width>91</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -459,9 +459,9 @@
|
||||
<widget class="QWidget" name="payloadContainer" native="true">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>5</x>
|
||||
<x>1</x>
|
||||
<y>120</y>
|
||||
<width>490</width>
|
||||
<width>510</width>
|
||||
<height>230</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -505,7 +505,7 @@
|
||||
<rect>
|
||||
<x>30</x>
|
||||
<y>60</y>
|
||||
<width>455</width>
|
||||
<width>471</width>
|
||||
<height>80</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -712,7 +712,7 @@
|
||||
<widget class="QLineEdit" name="syncWord">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>455</x>
|
||||
<x>480</x>
|
||||
<y>10</y>
|
||||
<width>25</width>
|
||||
<height>20</height>
|
||||
@ -827,28 +827,12 @@
|
||||
<string>FEC</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QCheckBox" name="errorCheck">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>230</x>
|
||||
<y>35</y>
|
||||
<width>50</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Check to disable display of payloads with errors</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>ERR</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPlainTextEdit" name="hexText">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>30</x>
|
||||
<y>145</y>
|
||||
<width>455</width>
|
||||
<width>471</width>
|
||||
<height>75</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -862,7 +846,7 @@
|
||||
<widget class="QLabel" name="packetLengthLabel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>290</x>
|
||||
<x>240</x>
|
||||
<y>35</y>
|
||||
<width>20</width>
|
||||
<height>16</height>
|
||||
@ -875,7 +859,7 @@
|
||||
<widget class="QDial" name="packetLength">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>310</x>
|
||||
<x>260</x>
|
||||
<y>30</y>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
@ -897,7 +881,7 @@
|
||||
<widget class="QLabel" name="packetLengthText">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>330</x>
|
||||
<x>280</x>
|
||||
<y>35</y>
|
||||
<width>25</width>
|
||||
<height>16</height>
|
||||
@ -913,7 +897,7 @@
|
||||
<widget class="QLabel" name="syncWordLabel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>420</x>
|
||||
<x>440</x>
|
||||
<y>10</y>
|
||||
<width>30</width>
|
||||
<height>19</height>
|
||||
@ -926,7 +910,7 @@
|
||||
<widget class="QLabel" name="headerHammingStatus">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>370</x>
|
||||
<x>380</x>
|
||||
<y>35</y>
|
||||
<width>20</width>
|
||||
<height>16</height>
|
||||
@ -942,7 +926,7 @@
|
||||
<widget class="QLabel" name="headerCRCStatus">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>395</x>
|
||||
<x>410</x>
|
||||
<y>35</y>
|
||||
<width>20</width>
|
||||
<height>16</height>
|
||||
@ -958,7 +942,7 @@
|
||||
<widget class="QLabel" name="payloadFECStatus">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>420</x>
|
||||
<x>440</x>
|
||||
<y>35</y>
|
||||
<width>25</width>
|
||||
<height>16</height>
|
||||
@ -974,7 +958,7 @@
|
||||
<widget class="QLabel" name="payloadCRCStatus">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>455</x>
|
||||
<x>475</x>
|
||||
<y>35</y>
|
||||
<width>28</width>
|
||||
<height>16</height>
|
||||
@ -987,13 +971,67 @@
|
||||
<string>CRC</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="nbSymbolsText">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>310</x>
|
||||
<y>35</y>
|
||||
<width>25</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Number of symbols in the payload with header and CRC</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>---</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="nbCodewordsText">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>340</x>
|
||||
<y>35</y>
|
||||
<width>25</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Number of codewords in the payload with header and CRC</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>---</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="fecParityText_2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>328</x>
|
||||
<y>35</y>
|
||||
<width>12</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>/</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QWidget" name="spectrumContainer" native="true">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>5</x>
|
||||
<x>1</x>
|
||||
<y>360</y>
|
||||
<width>490</width>
|
||||
<width>510</width>
|
||||
<height>260</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
||||
@ -50,7 +50,6 @@ void LoRaDemodSettings::resetToDefaults()
|
||||
m_nbParityBits = 1;
|
||||
m_hasCRC = true;
|
||||
m_hasHeader = true;
|
||||
m_errorCheck = false;
|
||||
m_rgbColor = QColor(255, 0, 255).rgb();
|
||||
m_title = "LoRa Demodulator";
|
||||
}
|
||||
@ -80,7 +79,6 @@ QByteArray LoRaDemodSettings::serialize() const
|
||||
s.writeS32(13, m_nbParityBits);
|
||||
s.writeBool(14, m_hasCRC);
|
||||
s.writeBool(15, m_hasHeader);
|
||||
s.writeBool(16, m_errorCheck);
|
||||
s.writeS32(17, m_preambleChirps);
|
||||
|
||||
return s.final();
|
||||
@ -126,7 +124,6 @@ bool LoRaDemodSettings::deserialize(const QByteArray& data)
|
||||
d.readS32(13, &m_nbParityBits, 1);
|
||||
d.readBool(14, &m_hasCRC, true);
|
||||
d.readBool(15, &m_hasHeader, true);
|
||||
d.readBool(16, &m_errorCheck, false);
|
||||
d.readS32(17, &m_preambleChirps, 8);
|
||||
|
||||
return true;
|
||||
|
||||
@ -48,7 +48,6 @@ struct LoRaDemodSettings
|
||||
int m_packetLength; //!< Payload packet length in bytes or characters (LoRa)
|
||||
bool m_hasCRC; //!< Payload has CRC (LoRa)
|
||||
bool m_hasHeader; //!< Header present before actual payload (LoRa)
|
||||
bool m_errorCheck; //!< Error check failure cancels decoding (LoRa)
|
||||
uint32_t m_rgbColor;
|
||||
QString m_title;
|
||||
|
||||
|
||||
@ -262,7 +262,7 @@ void LoRaMod::applySettings(const LoRaModSettings& settings, bool force)
|
||||
if (getMessageQueueToGUI())
|
||||
{
|
||||
MsgReportPayloadTime *rpt = MsgReportPayloadTime::create(
|
||||
(symbols.size()*(1<<settings.m_spreadFactor)*1000) / LoRaModSettings::bandwidths[settings.m_bandwidthIndex]
|
||||
(symbols.size()*(1<<settings.m_spreadFactor)*1000.0) / LoRaModSettings::bandwidths[settings.m_bandwidthIndex]
|
||||
);
|
||||
getMessageQueueToGUI()->push(rpt);
|
||||
}
|
||||
|
||||
@ -70,19 +70,18 @@ public:
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
|
||||
public:
|
||||
unsigned int getPayloadTimeMs() const { return m_timeMs; }
|
||||
static MsgReportPayloadTime* create(unsigned int timeMs) {
|
||||
float getPayloadTimeMs() const { return m_timeMs; }
|
||||
static MsgReportPayloadTime* create(float timeMs) {
|
||||
return new MsgReportPayloadTime(timeMs);
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned int m_timeMs; //!< time in milliseconds
|
||||
float m_timeMs; //!< time in milliseconds
|
||||
|
||||
MsgReportPayloadTime(unsigned int timeMs) :
|
||||
MsgReportPayloadTime(float timeMs) :
|
||||
Message(),
|
||||
m_timeMs(timeMs)
|
||||
{}
|
||||
|
||||
};
|
||||
|
||||
//=================================================================
|
||||
|
||||
@ -39,8 +39,7 @@ void LoRaModEncoderLoRa::encodeBytes(
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int payloadSize = bytes.size();
|
||||
const unsigned int numCodewords = roundUp(bytes.size()*2 + (hasHeader ? headerCodewords : 0), nbSymbolBits);
|
||||
const unsigned int numCodewords = roundUp(bytes.size()*2 + (hasHeader ? headerCodewords : 0), nbSymbolBits); // uses payload + CRC for encoding size
|
||||
unsigned int cOfs = 0;
|
||||
unsigned int dOfs = 0;
|
||||
|
||||
@ -49,6 +48,7 @@ void LoRaModEncoderLoRa::encodeBytes(
|
||||
if (hasHeader)
|
||||
{
|
||||
std::vector<uint8_t> hdr(3);
|
||||
unsigned int payloadSize = bytes.size() - (hasCRC ? 2 : 0); // actual payload size is without CRC
|
||||
hdr[0] = payloadSize % 256;
|
||||
hdr[1] = (hasCRC ? 1 : 0) | (nbParityBits << 1);
|
||||
hdr[2] = headerChecksum(hdr.data());
|
||||
@ -75,7 +75,8 @@ void LoRaModEncoderLoRa::encodeBytes(
|
||||
Sx1272ComputeWhitening(codewords.data() + cOfs2, numCodewords - nbSymbolBits, nbSymbolBits - headerSize, nbParityBits);
|
||||
}
|
||||
|
||||
const unsigned int numSymbols = headerSymbols + (numCodewords / nbSymbolBits - 1) * (4 + nbParityBits); // header is always coded with 8 bits
|
||||
// header is always coded with 8 bits and yields exactly 8 symbols (headerSymbols)
|
||||
const unsigned int numSymbols = headerSymbols + (numCodewords / nbSymbolBits - 1) * (4 + nbParityBits);
|
||||
|
||||
// interleave the codewords into symbols
|
||||
symbols.clear();
|
||||
|
||||
@ -108,10 +108,11 @@ bool LoRaModGUI::handleMessage(const Message& message)
|
||||
else if (LoRaMod::MsgReportPayloadTime::match(message))
|
||||
{
|
||||
const LoRaMod::MsgReportPayloadTime& rpt = (LoRaMod::MsgReportPayloadTime&) message;
|
||||
unsigned int fourthsMs = ((1<<m_settings.m_spreadFactor)*250) / LoRaModSettings::bandwidths[m_settings.m_bandwidthIndex];
|
||||
unsigned int controlMs = (4*(m_settings.m_preambleChirps)+8+9)*fourthsMs; // preamble + sync word + SFD
|
||||
ui->msgTimeText->setText(tr("%1 ms").arg(rpt.getPayloadTimeMs()));
|
||||
ui->msgTotalTimeText->setText(tr("%1 ms").arg(rpt.getPayloadTimeMs()+controlMs));
|
||||
float fourthsMs = ((1<<m_settings.m_spreadFactor) * 250.0) / LoRaModSettings::bandwidths[m_settings.m_bandwidthIndex];
|
||||
float controlMs = (4*m_settings.m_preambleChirps + 8 + 9) * fourthsMs; // preamble + sync word + SFD
|
||||
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->timeSymbolText->setText(tr("%1 ms").arg(QString::number(4.0*fourthsMs, 'f', 1)));
|
||||
return true;
|
||||
}
|
||||
else if (DSPSignalNotification::match(message))
|
||||
|
||||
@ -6,13 +6,13 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>380</width>
|
||||
<height>376</height>
|
||||
<width>392</width>
|
||||
<height>373</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>380</width>
|
||||
<width>392</width>
|
||||
<height>180</height>
|
||||
</size>
|
||||
</property>
|
||||
@ -28,9 +28,9 @@
|
||||
<widget class="QWidget" name="settingsContainer" native="true">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<x>1</x>
|
||||
<y>20</y>
|
||||
<width>370</width>
|
||||
<width>390</width>
|
||||
<height>125</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -74,7 +74,7 @@
|
||||
<rect>
|
||||
<x>40</x>
|
||||
<y>50</y>
|
||||
<width>221</width>
|
||||
<width>251</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -102,7 +102,7 @@
|
||||
<rect>
|
||||
<x>40</x>
|
||||
<y>70</y>
|
||||
<width>61</width>
|
||||
<width>81</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -131,7 +131,7 @@
|
||||
<widget class="QLabel" name="spreadText">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>110</x>
|
||||
<x>130</x>
|
||||
<y>70</y>
|
||||
<width>30</width>
|
||||
<height>16</height>
|
||||
@ -153,7 +153,7 @@
|
||||
<widget class="QLabel" name="bwText">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>280</x>
|
||||
<x>300</x>
|
||||
<y>50</y>
|
||||
<width>80</width>
|
||||
<height>16</height>
|
||||
@ -175,7 +175,7 @@
|
||||
<widget class="QLabel" name="deBitsLabel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>160</x>
|
||||
<x>180</x>
|
||||
<y>70</y>
|
||||
<width>32</width>
|
||||
<height>16</height>
|
||||
@ -188,7 +188,7 @@
|
||||
<widget class="QLabel" name="deBitsText">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>250</x>
|
||||
<x>280</x>
|
||||
<y>70</y>
|
||||
<width>10</width>
|
||||
<height>16</height>
|
||||
@ -210,9 +210,9 @@
|
||||
<widget class="QSlider" name="deBits">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>200</x>
|
||||
<x>210</x>
|
||||
<y>70</y>
|
||||
<width>41</width>
|
||||
<width>61</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -243,7 +243,7 @@
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>10</y>
|
||||
<width>351</width>
|
||||
<width>371</width>
|
||||
<height>26</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -496,7 +496,7 @@
|
||||
<widget class="QLabel" name="syncLabel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>280</x>
|
||||
<x>310</x>
|
||||
<y>70</y>
|
||||
<width>32</width>
|
||||
<height>16</height>
|
||||
@ -509,7 +509,7 @@
|
||||
<widget class="QLineEdit" name="syncWord">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>320</x>
|
||||
<x>350</x>
|
||||
<y>68</y>
|
||||
<width>30</width>
|
||||
<height>20</height>
|
||||
@ -532,9 +532,9 @@
|
||||
<widget class="QWidget" name="messageContainer" native="true">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<x>1</x>
|
||||
<y>150</y>
|
||||
<width>370</width>
|
||||
<width>390</width>
|
||||
<height>221</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -576,7 +576,7 @@
|
||||
<widget class="QLabel" name="urCallLabel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>200</x>
|
||||
<x>210</x>
|
||||
<y>40</y>
|
||||
<width>50</width>
|
||||
<height>16</height>
|
||||
@ -591,7 +591,7 @@
|
||||
<rect>
|
||||
<x>90</x>
|
||||
<y>40</y>
|
||||
<width>90</width>
|
||||
<width>110</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -611,9 +611,9 @@
|
||||
<widget class="QLineEdit" name="urCall">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>260</x>
|
||||
<x>269</x>
|
||||
<y>40</y>
|
||||
<width>90</width>
|
||||
<width>110</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -648,7 +648,7 @@
|
||||
<rect>
|
||||
<x>90</x>
|
||||
<y>60</y>
|
||||
<width>90</width>
|
||||
<width>110</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -668,7 +668,7 @@
|
||||
<widget class="QLabel" name="reportLabel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>200</x>
|
||||
<x>210</x>
|
||||
<y>60</y>
|
||||
<width>50</width>
|
||||
<height>16</height>
|
||||
@ -681,9 +681,9 @@
|
||||
<widget class="QLineEdit" name="report">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>260</x>
|
||||
<x>270</x>
|
||||
<y>60</y>
|
||||
<width>90</width>
|
||||
<width>110</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -703,7 +703,7 @@
|
||||
<widget class="QPushButton" name="generateMessages">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>310</x>
|
||||
<x>340</x>
|
||||
<y>80</y>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
@ -807,7 +807,7 @@
|
||||
<rect>
|
||||
<x>40</x>
|
||||
<y>110</y>
|
||||
<width>311</width>
|
||||
<width>341</width>
|
||||
<height>60</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -830,7 +830,7 @@
|
||||
<rect>
|
||||
<x>40</x>
|
||||
<y>175</y>
|
||||
<width>311</width>
|
||||
<width>341</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -881,7 +881,7 @@
|
||||
<widget class="QLabel" name="repeatLabel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>200</x>
|
||||
<x>210</x>
|
||||
<y>82</y>
|
||||
<width>51</width>
|
||||
<height>16</height>
|
||||
@ -894,7 +894,7 @@
|
||||
<widget class="QDial" name="repeatMessage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>250</x>
|
||||
<x>260</x>
|
||||
<y>78</y>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
@ -916,7 +916,7 @@
|
||||
<widget class="QLabel" name="repeatText">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>280</x>
|
||||
<x>290</x>
|
||||
<y>82</y>
|
||||
<width>22</width>
|
||||
<height>16</height>
|
||||
@ -929,7 +929,7 @@
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="msgTimeLabel">
|
||||
<widget class="QLabel" name="timesLabel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>2</x>
|
||||
@ -942,12 +942,12 @@
|
||||
<string>Time</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="msgTimeText">
|
||||
<widget class="QLabel" name="timePayloadText">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>40</x>
|
||||
<x>200</x>
|
||||
<y>200</y>
|
||||
<width>65</width>
|
||||
<width>60</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -961,28 +961,28 @@
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="msgTotalTimeLabel">
|
||||
<widget class="QLabel" name="timeTotalLabel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>119</x>
|
||||
<x>290</x>
|
||||
<y>200</y>
|
||||
<width>35</width>
|
||||
<width>25</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Total</string>
|
||||
<string>Ttot</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="msgTotalTimeText">
|
||||
<widget class="QLabel" name="timeTotalText">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>150</x>
|
||||
<x>320</x>
|
||||
<y>200</y>
|
||||
<width>65</width>
|
||||
<width>60</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -1037,7 +1037,7 @@
|
||||
<widget class="QCheckBox" name="header">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>300</x>
|
||||
<x>290</x>
|
||||
<y>10</y>
|
||||
<width>50</width>
|
||||
<height>16</height>
|
||||
@ -1053,7 +1053,7 @@
|
||||
<widget class="QCheckBox" name="crc">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>240</x>
|
||||
<x>230</x>
|
||||
<y>10</y>
|
||||
<width>50</width>
|
||||
<height>16</height>
|
||||
@ -1069,7 +1069,7 @@
|
||||
<widget class="QLabel" name="fecParityLabel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>160</x>
|
||||
<x>150</x>
|
||||
<y>10</y>
|
||||
<width>32</width>
|
||||
<height>16</height>
|
||||
@ -1082,7 +1082,7 @@
|
||||
<widget class="QDial" name="fecParity">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>190</x>
|
||||
<x>180</x>
|
||||
<y>5</y>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
@ -1104,7 +1104,7 @@
|
||||
<widget class="QLabel" name="fecParityText">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>220</x>
|
||||
<x>205</x>
|
||||
<y>10</y>
|
||||
<width>12</width>
|
||||
<height>16</height>
|
||||
@ -1117,6 +1117,57 @@
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="timePayloadLabel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>160</x>
|
||||
<y>200</y>
|
||||
<width>35</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Tpay</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="timeSymbolText">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>70</x>
|
||||
<y>200</y>
|
||||
<width>70</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Payload time in milliseconds</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>0000.0 ms</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="timeSymbolLabel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>40</x>
|
||||
<y>200</y>
|
||||
<width>30</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Tsym</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user