mirror of
https://github.com/f4exb/sdrangel.git
synced 2026-09-15 15:35:32 -04:00
Fix Meshtastic soft FEC payload status
This commit is contained in:
@@ -432,6 +432,8 @@ void MeshtasticDemodDecoderLoRa::decodeBytesSoft(
|
||||
{
|
||||
payloadCRCStatus = false;
|
||||
payloadParityStatus = (int) MeshtasticDemodSettings::ParityUndefined;
|
||||
bool error = false; // set if any payload codeword requires soft FEC correction
|
||||
bool bad = false; // set if any payload codeword has a structural decode failure
|
||||
|
||||
if (inSymbols.size() < headerSymbols)
|
||||
{
|
||||
@@ -542,7 +544,18 @@ void MeshtasticDemodDecoderLoRa::decodeBytesSoft(
|
||||
}
|
||||
}
|
||||
|
||||
auto decodeSoftBlock = [&llrs, spreadFactor](unsigned int symOfs, unsigned int cwLen, unsigned int sfApp, unsigned int crApp, std::vector<uint8_t>& nibbles) {
|
||||
auto decodeSoftBlock = [
|
||||
&llrs,
|
||||
spreadFactor,
|
||||
&error, &bad // accumulated payload FEC status
|
||||
](
|
||||
unsigned int symOfs,
|
||||
unsigned int cwLen,
|
||||
unsigned int sfApp,
|
||||
unsigned int crApp,
|
||||
unsigned int payloadRowStart, // first row that contributes to payload FEC status
|
||||
std::vector<uint8_t>& nibbles) {
|
||||
|
||||
if (sfApp == 0U) {
|
||||
return false;
|
||||
}
|
||||
@@ -569,8 +582,22 @@ void MeshtasticDemodDecoderLoRa::decodeBytesSoft(
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int row = 0; row < sfApp; row++) {
|
||||
nibbles.push_back(decodeCodewordSoft(deinterBin[row], crApp));
|
||||
for (unsigned int row = 0; row < sfApp; row++)
|
||||
{
|
||||
if (row < payloadRowStart)
|
||||
{
|
||||
// Still in header, don't accumulate payload FEC
|
||||
bool ignoredError = false;
|
||||
bool ignoredBad = false;
|
||||
nibbles.push_back(
|
||||
decodeCodewordSoft(deinterBin[row], crApp, ignoredError, ignoredBad));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Payload row contributes to accumulated payload FEC status
|
||||
nibbles.push_back(
|
||||
decodeCodewordSoft(deinterBin[row], crApp, error, bad));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -587,7 +614,15 @@ void MeshtasticDemodDecoderLoRa::decodeBytesSoft(
|
||||
return;
|
||||
}
|
||||
|
||||
if (!decodeSoftBlock(symOfs, 8U, headerNbSymbolBits, 4U, nibbles)) {
|
||||
const unsigned int payloadRowStart = headerCodewords; // payload starts after the 5 header codewords
|
||||
|
||||
if (!decodeSoftBlock(
|
||||
symOfs,
|
||||
headerSymbols,
|
||||
headerNbSymbolBits,
|
||||
headerParityBits,
|
||||
payloadRowStart,
|
||||
nibbles)) {
|
||||
earlyEOM = true;
|
||||
return;
|
||||
}
|
||||
@@ -595,9 +630,17 @@ void MeshtasticDemodDecoderLoRa::decodeBytesSoft(
|
||||
symOfs += headerSymbols;
|
||||
}
|
||||
|
||||
const unsigned int payloadOnlyRowStart = 0U; // all rows in these blocks are payload
|
||||
|
||||
while (symOfs + payloadBlockSymbols <= numSymbols)
|
||||
{
|
||||
if (!decodeSoftBlock(symOfs, payloadBlockSymbols, payloadNbSymbolBits, nbParityBits, nibbles)) {
|
||||
if (!decodeSoftBlock(
|
||||
symOfs,
|
||||
payloadBlockSymbols,
|
||||
payloadNbSymbolBits,
|
||||
nbParityBits,
|
||||
payloadOnlyRowStart,
|
||||
nibbles)) {
|
||||
earlyEOM = true;
|
||||
return;
|
||||
}
|
||||
@@ -628,6 +671,15 @@ void MeshtasticDemodDecoderLoRa::decodeBytesSoft(
|
||||
dewhitenPayloadBytes(bytes.data(), packetLength);
|
||||
}
|
||||
|
||||
// Report accumulated payload FEC result independently of CRC
|
||||
if (bad) {
|
||||
payloadParityStatus = (int) MeshtasticDemodSettings::ParityError;
|
||||
} else if (error) {
|
||||
payloadParityStatus = (int) MeshtasticDemodSettings::ParityCorrected;
|
||||
} else {
|
||||
payloadParityStatus = (int) MeshtasticDemodSettings::ParityOK;
|
||||
}
|
||||
|
||||
if (hasCRC)
|
||||
{
|
||||
if ((packetLength >= 2U) && (dataByteLen >= packetLength + 2U))
|
||||
|
||||
@@ -274,7 +274,11 @@ private:
|
||||
return static_cast<unsigned char>((nibbleBits[0] << 3) | (nibbleBits[1] << 2) | (nibbleBits[2] << 1) | nibbleBits[3]);
|
||||
}
|
||||
|
||||
static inline unsigned char decodeCodewordSoft(const std::vector<float>& codewordLLR, unsigned int crApp)
|
||||
static inline unsigned char decodeCodewordSoft(
|
||||
const std::vector<float>& codewordLLR,
|
||||
unsigned int crApp,
|
||||
bool& error, // set if soft FEC changes a hard decision; caller may accumulate across codewords
|
||||
bool& bad) // set on structural decode failure; caller may accumulate across codewords
|
||||
{
|
||||
static const unsigned char cwLUT[16] = {
|
||||
0, 23, 45, 58, 78, 89, 99, 116,
|
||||
@@ -286,10 +290,17 @@ private:
|
||||
};
|
||||
|
||||
if ((crApp < 1U) || (crApp > 4U)) {
|
||||
bad = true; // invalid coding rate: structural decode failure
|
||||
return 0;
|
||||
}
|
||||
|
||||
const unsigned int cwLen = 4U + crApp;
|
||||
|
||||
if (codewordLLR.size() < cwLen) {
|
||||
bad = true; // insufficient LLR data: structural decode failure (later mapped to ParityError)
|
||||
return 0;
|
||||
}
|
||||
|
||||
const unsigned char *lut = (crApp == 1U) ? cwLUTCr5 : cwLUT;
|
||||
float bestScore = std::numeric_limits<float>::lowest();
|
||||
unsigned int bestIdx = 0U;
|
||||
@@ -312,6 +323,25 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
const unsigned char selectedCW =
|
||||
static_cast<unsigned char>(lut[bestIdx] >> (8U - cwLen));
|
||||
|
||||
for (unsigned int j = 0; j < cwLen; j++)
|
||||
{
|
||||
if (codewordLLR[j] == 0.0f) {
|
||||
continue; // no hard-decision preference for an exactly zero LLR
|
||||
}
|
||||
|
||||
const bool hardBit = codewordLLR[j] > 0.0f;
|
||||
const bool selectedBit =
|
||||
((selectedCW >> (cwLen - 1U - j)) & 0x1U) != 0U;
|
||||
|
||||
if (hardBit != selectedBit) {
|
||||
error = true; // soft FEC changed one or more raw hard-decision bits
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const unsigned char dataNibbleSoft = static_cast<unsigned char>(cwLUT[bestIdx] >> 4);
|
||||
return static_cast<unsigned char>(
|
||||
(((dataNibbleSoft & 0x1U) != 0U) << 3) |
|
||||
|
||||
Reference in New Issue
Block a user