diff --git a/plugins/channelrx/demodlora/lorademod.cpp b/plugins/channelrx/demodlora/lorademod.cpp index 3211bca2e..38da6b579 100644 --- a/plugins/channelrx/demodlora/lorademod.cpp +++ b/plugins/channelrx/demodlora/lorademod.cpp @@ -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); diff --git a/plugins/channelrx/demodlora/lorademod.h b/plugins/channelrx/demodlora/lorademod.h index a31cb2c38..7ce297567 100644 --- a/plugins/channelrx/demodlora/lorademod.h +++ b/plugins/channelrx/demodlora/lorademod.h @@ -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), diff --git a/plugins/channelrx/demodlora/lorademoddecoder.cpp b/plugins/channelrx/demodlora/lorademoddecoder.cpp index b6e0bdd14..e9d46cb38 100644 --- a/plugins/channelrx/demodlora/lorademoddecoder.cpp +++ b/plugins/channelrx/demodlora/lorademoddecoder.cpp @@ -78,12 +78,21 @@ void LoRaDemodDecoder::decodeSymbols(const std::vector& 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; } diff --git a/plugins/channelrx/demodlora/lorademoddecoder.h b/plugins/channelrx/demodlora/lorademoddecoder.h index 4fac56de6..ffe79a88e 100644 --- a/plugins/channelrx/demodlora/lorademoddecoder.h +++ b/plugins/channelrx/demodlora/lorademoddecoder.h @@ -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& symbols, QString& str); //!< For ASCII and TTY void decodeSymbols(const std::vector& 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; }; diff --git a/plugins/channelrx/demodlora/lorademoddecoderlora.cpp b/plugins/channelrx/demodlora/lorademoddecoderlora.cpp index 3659d2626..530ba599a 100644 --- a/plugins/channelrx/demodlora/lorademoddecoderlora.cpp +++ b/plugins/channelrx/demodlora/lorademoddecoderlora.cpp @@ -19,6 +19,83 @@ #include "lorademoddecoderlora.h" +void LoRaDemodDecoderLoRa::decodeHeader( + const std::vector& 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 symbols(headerSymbols); + std::copy(inSymbols.begin(), inSymbols.begin() + headerSymbols, symbols.begin()); + + //gray encode + for (auto &sym : symbols) { + sym = binaryToGray16(sym); + } + + std::vector 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& 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 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) +} \ No newline at end of file diff --git a/plugins/channelrx/demodlora/lorademoddecoderlora.h b/plugins/channelrx/demodlora/lorademoddecoderlora.h index bf7121a0f..3f1bf4d84 100644 --- a/plugins/channelrx/demodlora/lorademoddecoderlora.h +++ b/plugins/channelrx/demodlora/lorademoddecoderlora.h @@ -26,6 +26,14 @@ class LoRaDemodDecoderLoRa { public: + enum ParityStatus + { + ParityUndefined, + ParityError, + ParityCorrected, + ParityOK + }; + static void decodeBytes( QByteArray& bytes, const std::vector& 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& 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; diff --git a/plugins/channelrx/demodlora/lorademodgui.cpp b/plugins/channelrx/demodlora/lorademodgui.cpp index a39ccc11e..496441f21 100644 --- a/plugins/channelrx/demodlora/lorademodgui.cpp +++ b/plugins/channelrx/demodlora/lorademodgui.cpp @@ -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) diff --git a/plugins/channelrx/demodlora/lorademodgui.h b/plugins/channelrx/demodlora/lorademodgui.h index 71efb5ad7..95baada85 100644 --- a/plugins/channelrx/demodlora/lorademodgui.h +++ b/plugins/channelrx/demodlora/lorademodgui.h @@ -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(); }; diff --git a/plugins/channelrx/demodlora/lorademodgui.ui b/plugins/channelrx/demodlora/lorademodgui.ui index a9ec43f02..25f1b980d 100644 --- a/plugins/channelrx/demodlora/lorademodgui.ui +++ b/plugins/channelrx/demodlora/lorademodgui.ui @@ -6,13 +6,13 @@ 0 0 - 500 + 512 660 - 500 + 512 660 @@ -28,9 +28,9 @@ - 5 + 1 20 - 490 + 510 90 @@ -74,7 +74,7 @@ 30 50 - 361 + 381 16 @@ -102,7 +102,7 @@ 30 70 - 80 + 101 16 @@ -131,7 +131,7 @@ - 120 + 140 70 20 16 @@ -153,7 +153,7 @@ - 400 + 420 50 80 16 @@ -175,7 +175,7 @@ - 170 + 190 70 22 16 @@ -188,7 +188,7 @@ - 290 + 320 70 15 16 @@ -210,9 +210,9 @@ - 200 + 220 70 - 80 + 91 16 @@ -243,7 +243,7 @@ 10 10 - 471 + 491 26 @@ -392,7 +392,7 @@ - 450 + 480 70 20 16 @@ -414,7 +414,7 @@ - 340 + 350 70 32 16 @@ -427,9 +427,9 @@ - 370 + 380 70 - 81 + 91 16 @@ -459,9 +459,9 @@ - 5 + 1 120 - 490 + 510 230 @@ -505,7 +505,7 @@ 30 60 - 455 + 471 80 @@ -712,7 +712,7 @@ - 455 + 480 10 25 20 @@ -827,28 +827,12 @@ FEC - - - - 230 - 35 - 50 - 16 - - - - Check to disable display of payloads with errors - - - ERR - - 30 145 - 455 + 471 75 @@ -862,7 +846,7 @@ - 290 + 240 35 20 16 @@ -875,7 +859,7 @@ - 310 + 260 30 24 24 @@ -897,7 +881,7 @@ - 330 + 280 35 25 16 @@ -913,7 +897,7 @@ - 420 + 440 10 30 19 @@ -926,7 +910,7 @@ - 370 + 380 35 20 16 @@ -942,7 +926,7 @@ - 395 + 410 35 20 16 @@ -958,7 +942,7 @@ - 420 + 440 35 25 16 @@ -974,7 +958,7 @@ - 455 + 475 35 28 16 @@ -987,13 +971,67 @@ CRC + + + + 310 + 35 + 25 + 16 + + + + Number of symbols in the payload with header and CRC + + + --- + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 340 + 35 + 25 + 16 + + + + Number of codewords in the payload with header and CRC + + + --- + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + 328 + 35 + 12 + 16 + + + + / + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + - 5 + 1 360 - 490 + 510 260 diff --git a/plugins/channelrx/demodlora/lorademodsettings.cpp b/plugins/channelrx/demodlora/lorademodsettings.cpp index 260ee4a1a..2abe5508e 100644 --- a/plugins/channelrx/demodlora/lorademodsettings.cpp +++ b/plugins/channelrx/demodlora/lorademodsettings.cpp @@ -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; diff --git a/plugins/channelrx/demodlora/lorademodsettings.h b/plugins/channelrx/demodlora/lorademodsettings.h index fd1c9b47a..fdb866a77 100644 --- a/plugins/channelrx/demodlora/lorademodsettings.h +++ b/plugins/channelrx/demodlora/lorademodsettings.h @@ -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; diff --git a/plugins/channeltx/modlora/loramod.cpp b/plugins/channeltx/modlora/loramod.cpp index 90d851696..d671cbda1 100644 --- a/plugins/channeltx/modlora/loramod.cpp +++ b/plugins/channeltx/modlora/loramod.cpp @@ -262,7 +262,7 @@ void LoRaMod::applySettings(const LoRaModSettings& settings, bool force) if (getMessageQueueToGUI()) { MsgReportPayloadTime *rpt = MsgReportPayloadTime::create( - (symbols.size()*(1<push(rpt); } diff --git a/plugins/channeltx/modlora/loramod.h b/plugins/channeltx/modlora/loramod.h index b36ec2783..8ecaad207 100644 --- a/plugins/channeltx/modlora/loramod.h +++ b/plugins/channeltx/modlora/loramod.h @@ -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) {} - }; //================================================================= diff --git a/plugins/channeltx/modlora/loramodencoderlora.cpp b/plugins/channeltx/modlora/loramodencoderlora.cpp index 976c5d611..f89627c6b 100644 --- a/plugins/channeltx/modlora/loramodencoderlora.cpp +++ b/plugins/channeltx/modlora/loramodencoderlora.cpp @@ -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 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(); diff --git a/plugins/channeltx/modlora/loramodgui.cpp b/plugins/channeltx/modlora/loramodgui.cpp index f14778887..3a71e7860 100644 --- a/plugins/channeltx/modlora/loramodgui.cpp +++ b/plugins/channeltx/modlora/loramodgui.cpp @@ -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<msgTimeText->setText(tr("%1 ms").arg(rpt.getPayloadTimeMs())); - ui->msgTotalTimeText->setText(tr("%1 ms").arg(rpt.getPayloadTimeMs()+controlMs)); + float fourthsMs = ((1<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)) diff --git a/plugins/channeltx/modlora/loramodgui.ui b/plugins/channeltx/modlora/loramodgui.ui index dd1d9f442..1a1963aea 100644 --- a/plugins/channeltx/modlora/loramodgui.ui +++ b/plugins/channeltx/modlora/loramodgui.ui @@ -6,13 +6,13 @@ 0 0 - 380 - 376 + 392 + 373 - 380 + 392 180 @@ -28,9 +28,9 @@ - 10 + 1 20 - 370 + 390 125 @@ -74,7 +74,7 @@ 40 50 - 221 + 251 16 @@ -102,7 +102,7 @@ 40 70 - 61 + 81 16 @@ -131,7 +131,7 @@ - 110 + 130 70 30 16 @@ -153,7 +153,7 @@ - 280 + 300 50 80 16 @@ -175,7 +175,7 @@ - 160 + 180 70 32 16 @@ -188,7 +188,7 @@ - 250 + 280 70 10 16 @@ -210,9 +210,9 @@ - 200 + 210 70 - 41 + 61 16 @@ -243,7 +243,7 @@ 10 10 - 351 + 371 26 @@ -496,7 +496,7 @@ - 280 + 310 70 32 16 @@ -509,7 +509,7 @@ - 320 + 350 68 30 20 @@ -532,9 +532,9 @@ - 10 + 1 150 - 370 + 390 221 @@ -576,7 +576,7 @@ - 200 + 210 40 50 16 @@ -591,7 +591,7 @@ 90 40 - 90 + 110 16 @@ -611,9 +611,9 @@ - 260 + 269 40 - 90 + 110 16 @@ -648,7 +648,7 @@ 90 60 - 90 + 110 16 @@ -668,7 +668,7 @@ - 200 + 210 60 50 16 @@ -681,9 +681,9 @@ - 260 + 270 60 - 90 + 110 16 @@ -703,7 +703,7 @@ - 310 + 340 80 40 20 @@ -807,7 +807,7 @@ 40 110 - 311 + 341 60 @@ -830,7 +830,7 @@ 40 175 - 311 + 341 20 @@ -881,7 +881,7 @@ - 200 + 210 82 51 16 @@ -894,7 +894,7 @@ - 250 + 260 78 24 24 @@ -916,7 +916,7 @@ - 280 + 290 82 22 16 @@ -929,7 +929,7 @@ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - + 2 @@ -942,12 +942,12 @@ Time - + - 40 + 200 200 - 65 + 60 16 @@ -961,28 +961,28 @@ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - + - 119 + 290 200 - 35 + 25 16 - Total + Ttot - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - + - 150 + 320 200 - 65 + 60 16 @@ -1037,7 +1037,7 @@ - 300 + 290 10 50 16 @@ -1053,7 +1053,7 @@ - 240 + 230 10 50 16 @@ -1069,7 +1069,7 @@ - 160 + 150 10 32 16 @@ -1082,7 +1082,7 @@ - 190 + 180 5 24 24 @@ -1104,7 +1104,7 @@ - 220 + 205 10 12 16 @@ -1117,6 +1117,57 @@ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + 160 + 200 + 35 + 16 + + + + Tpay + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 70 + 200 + 70 + 16 + + + + Payload time in milliseconds + + + 0000.0 ms + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 40 + 200 + 30 + 16 + + + + Tsym + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + +