mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-09 15:17:24 -05:00
#2117 DMR simplex transmissions now frame correctly and added additional case for FLC BPTC error correction. (#2118)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
This commit is contained in:
@@ -146,6 +146,15 @@ public class DMRMessageFramer implements Listener<Dibit>
|
||||
mBufferATimeslot = cach.getTimeslot();
|
||||
mBufferBTimeslot = (mBufferATimeslot == 1 ? 2 : 1);
|
||||
}
|
||||
else if(mBufferAPattern.isMobileStationSyncPattern())
|
||||
{
|
||||
mBufferATimeslot = 1;
|
||||
mBufferBTimeslot = 2;
|
||||
if(mBufferBPattern == DMRSyncPattern.UNKNOWN)
|
||||
{
|
||||
mBufferBPattern = DMRSyncPattern.DIRECT_EMPTY_TIMESLOT;
|
||||
}
|
||||
}
|
||||
|
||||
dispatch(DMRMessageFactory.create(mBufferAPattern, message, cach, getTimestamp(), mBufferATimeslot));
|
||||
|
||||
@@ -156,8 +165,8 @@ public class DMRMessageFramer implements Listener<Dibit>
|
||||
mBufferAPattern = DMRSyncPattern.getNextVoice(mBufferAPattern);
|
||||
}
|
||||
|
||||
//Automatically trigger buffer B burst collection if it is collecting a voice super frame.
|
||||
if(mBufferBPattern.isVoicePattern())
|
||||
//Automatically trigger buffer B burst collection if it is collecting a voice super frame or mobile direct.
|
||||
if(mBufferBPattern.isVoicePattern() || mBufferBPattern == DMRSyncPattern.DIRECT_EMPTY_TIMESLOT)
|
||||
{
|
||||
mAssemblingBurst = true;
|
||||
mBufferAActive = false;
|
||||
@@ -205,6 +214,16 @@ public class DMRMessageFramer implements Listener<Dibit>
|
||||
mBufferBTimeslot = cach.getTimeslot();
|
||||
mBufferATimeslot = (mBufferBTimeslot == 1 ? 2 : 1);
|
||||
}
|
||||
else if(mBufferBPattern.isMobileStationSyncPattern())
|
||||
{
|
||||
mBufferBTimeslot = 1;
|
||||
mBufferATimeslot = 2;
|
||||
|
||||
if(mBufferAPattern == DMRSyncPattern.UNKNOWN)
|
||||
{
|
||||
mBufferAPattern = DMRSyncPattern.DIRECT_EMPTY_TIMESLOT;
|
||||
}
|
||||
}
|
||||
|
||||
dispatch(DMRMessageFactory.create(mBufferBPattern, burst, cach, getTimestamp(), mBufferBTimeslot));
|
||||
|
||||
@@ -215,8 +234,8 @@ public class DMRMessageFramer implements Listener<Dibit>
|
||||
mBufferBPattern = DMRSyncPattern.getNextVoice(mBufferBPattern);
|
||||
}
|
||||
|
||||
//Automatically trigger buffer A burst collection if it is collecting a voice super frame.
|
||||
if(mBufferAPattern.isVoicePattern())
|
||||
//Automatically trigger buffer A burst collection if it is collecting a voice super frame or mobile direct.
|
||||
if(mBufferAPattern.isVoicePattern() || mBufferAPattern == DMRSyncPattern.DIRECT_EMPTY_TIMESLOT)
|
||||
{
|
||||
mAssemblingBurst = true;
|
||||
mBufferAActive = true;
|
||||
|
||||
@@ -49,6 +49,18 @@ public abstract class BPTCBase
|
||||
mRowCount = rowCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by the correct() method to employ an optional attempt to correct multiple row, two-bit errors where each
|
||||
* set of row errors don't shadow each other based on a test where the column cardinality is twice the row
|
||||
* cardinality. This is probably not mathematically correct and should only be enabled when the decoded message
|
||||
* payload has a good CRC check after the extraction (ie. only use for FLC).
|
||||
* @return true if enabled, false (default) otherwise
|
||||
*/
|
||||
protected boolean canCorrectMultiRow2BitErrors()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs error detection and correction.
|
||||
* @param message to correct
|
||||
@@ -100,6 +112,28 @@ public abstract class BPTCBase
|
||||
}
|
||||
}
|
||||
|
||||
//3: fix single row, multi-column errors
|
||||
if(rows.cardinality() == 1 && !columns.isEmpty())
|
||||
{
|
||||
List<Integer> solution = correctMultiBitErrors(rows.nextSetBit(0), message, columns, rows);
|
||||
|
||||
if(!solution.isEmpty())
|
||||
{
|
||||
correctedIndexes.addAll(solution);
|
||||
}
|
||||
}
|
||||
|
||||
//4: fix one or more rows that each have 2 bit errors, not shadowing each other.
|
||||
if(canCorrectMultiRow2BitErrors() && rows.cardinality() > 0 && columns.cardinality() / rows.cardinality() == 2)
|
||||
{
|
||||
List<Integer> solution = correctMultipleRowTwoBitErrorsNotShadowing(columns, rows, message);
|
||||
|
||||
if(!solution.isEmpty())
|
||||
{
|
||||
correctedIndexes.addAll(solution);
|
||||
}
|
||||
}
|
||||
|
||||
if(columns.isEmpty() && rows.isEmpty())
|
||||
{
|
||||
message.incrementCorrectedBitCount(correctedIndexes.size());
|
||||
@@ -204,6 +238,90 @@ public abstract class BPTCBase
|
||||
return columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the indices that make up the intersections of the row and column errors.
|
||||
* @param rows bitmap indicating rows with errors
|
||||
* @param columns bitmap indicating columns with errors
|
||||
* @return set of intersection indices.
|
||||
*/
|
||||
public List<Integer> getIntersectionIndices(BinaryMessage columns, BinaryMessage rows)
|
||||
{
|
||||
List<Integer> intersections = new ArrayList<>();
|
||||
|
||||
for(int row = rows.nextSetBit(0); row >= 0 && row < mRowCount; row = rows.nextSetBit(row + 1))
|
||||
{
|
||||
for(int column = columns.nextSetBit(0); column >= 0 && column < mColumnCount; column = columns.nextSetBit(column + 1))
|
||||
{
|
||||
intersections.add(getIndex(column, row));
|
||||
}
|
||||
}
|
||||
|
||||
return intersections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the indices that make up the intersections of the row and column errors.
|
||||
* @param rows bitmap indicating rows with errors
|
||||
* @param columns bitmap indicating columns with errors
|
||||
* @return set of intersection indices.
|
||||
*/
|
||||
public List<Integer> getIntersectionIndices(BinaryMessage columns, int row)
|
||||
{
|
||||
List<Integer> intersections = new ArrayList<>();
|
||||
|
||||
for(int column = columns.nextSetBit(0); column >= 0 && column < mColumnCount; column = columns.nextSetBit(column + 1))
|
||||
{
|
||||
intersections.add(getIndex(column, row));
|
||||
}
|
||||
|
||||
return intersections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct multiple rows with two-bit errors each where the error columns are not shadowing each other.
|
||||
* @param columns error map
|
||||
* @param rows error map
|
||||
* @param message to correct
|
||||
* @return corrected indices
|
||||
*/
|
||||
public List<Integer> correctMultipleRowTwoBitErrorsNotShadowing(BinaryMessage columns, BinaryMessage rows,
|
||||
CorrectedBinaryMessage message)
|
||||
{
|
||||
List<Integer> solution = new ArrayList<>();
|
||||
|
||||
for(int row = rows.nextSetBit(0); row >= 0 && row < mRowCount; row = rows.nextSetBit(row + 1))
|
||||
{
|
||||
for(int column1 = columns.nextSetBit(0); column1 >= 0; column1 = columns.nextSetBit(column1 + 1))
|
||||
{
|
||||
for(int column2 = columns.nextSetBit(column1 + 1); column2 >= 0; column2 = columns.nextSetBit(column2 + 1))
|
||||
{
|
||||
int index1 = getIndex(column1, row);
|
||||
int index2 = getIndex(column2, row);
|
||||
message.flip(index1);
|
||||
message.flip(index2);
|
||||
|
||||
if(isRowCorrect(row, message))
|
||||
{
|
||||
solution.add(index1);
|
||||
solution.add(index2);
|
||||
columns.clear(column1);
|
||||
columns.clear(column2);
|
||||
rows.clear(row);
|
||||
column1 = mColumnCount;
|
||||
column2 = mColumnCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
message.flip(index1);
|
||||
message.flip(index2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return solution;
|
||||
}
|
||||
|
||||
/**
|
||||
* Corrects single bit errors in each row using only the Hamming error index.
|
||||
* @param row to correct
|
||||
@@ -313,7 +431,18 @@ public abstract class BPTCBase
|
||||
int offset = row * mColumnCount;
|
||||
sb.append("Row ").append(row).append(": ");
|
||||
sb.append(message.getSubMessage(offset, offset + mColumnCount));
|
||||
sb.append(" ").append(offset).append(":").append(offset + mColumnCount).append("\n");
|
||||
sb.append(" (").append(offset).append(":").append(offset + mColumnCount).append(")");
|
||||
|
||||
for(int error = offset; error < offset + mColumnCount; error++)
|
||||
{
|
||||
if(message.get(error))
|
||||
{
|
||||
sb.append(" ").append(error);
|
||||
}
|
||||
}
|
||||
|
||||
sb.append("\n");
|
||||
|
||||
}
|
||||
|
||||
System.out.println(sb);
|
||||
|
||||
@@ -34,6 +34,15 @@ public class BPTC_128_77 extends BPTCBase
|
||||
super(new Hamming16(), 16, 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow the base class to attempt to correct multiple rows of 2-bit errors each
|
||||
*/
|
||||
@Override
|
||||
protected boolean canCorrectMultiRow2BitErrors()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs error detection and correction and extracts the payload from the BPTC encoded message.
|
||||
* @param message with BPTC encoding.
|
||||
@@ -93,15 +102,15 @@ public class BPTC_128_77 extends BPTCBase
|
||||
public static void main(String[] args)
|
||||
{
|
||||
BPTC_128_77 bptc = new BPTC_128_77();
|
||||
String deinterleavedRaw = "00000000000000000000000000000000001000000010010101011001001000010000000000000000000000000110101000010110111100010000111110011111";
|
||||
String deinterleavedRaw = "00000100000101010000001000111000100000000001001101000010001001000000000010101000111100000000001000011000100010110010100100100000";
|
||||
CorrectedBinaryMessage deinterleaved = new CorrectedBinaryMessage(BinaryMessage.load(deinterleavedRaw));
|
||||
|
||||
String deinterleavedReference = "00000000000000000000000000000000000000000010011100011001001000110000000000000000000000000110101000010110111100010000111110011111"; //No errors
|
||||
String deinterleavedReference = "00000100000101010000011000111001100000000001001101000010001101100000000110101000111100000000101000011000100010110010100100100000"; //No errors
|
||||
CorrectedBinaryMessage deinterleavedReferenceMessage = new CorrectedBinaryMessage(BinaryMessage.load(deinterleavedReference));
|
||||
|
||||
String interleaved = "00000000000000000000000000010010000100010000001000000010000100010000001100000110001101100000001100000101001000010010010100110011"; //Under test
|
||||
CorrectedBinaryMessage interleavedMessage = new CorrectedBinaryMessage(BinaryMessage.load(interleaved));
|
||||
// String interleaved = "00000000000000000000000000010010000100010000001000000010000100010000001100000110001101100000001100000101001000010010010100110011"; //Under test
|
||||
// CorrectedBinaryMessage interleavedMessage = new CorrectedBinaryMessage(BinaryMessage.load(interleaved));
|
||||
// CorrectedBinaryMessage deinterleaved = deinterleave(interleavedMessage);
|
||||
CorrectedBinaryMessage deinterleaved = new CorrectedBinaryMessage(BinaryMessage.load(deinterleavedRaw));
|
||||
|
||||
|
||||
String deinterleavedUncorrected = deinterleaved.toString();
|
||||
@@ -120,6 +129,7 @@ public class BPTC_128_77 extends BPTCBase
|
||||
System.out.println("--------------------------------");
|
||||
System.out.println("Residual Error Map:");
|
||||
bptc.logErrorMap(deinterleaved);
|
||||
System.out.println("Columns:" + bptc.getColumnErrors(deinterleaved) + " Rows:" + bptc.getRowErrors(deinterleaved));
|
||||
System.out.println("--------------------------------");
|
||||
}
|
||||
else
|
||||
|
||||
@@ -129,7 +129,12 @@ public class FLCAssembler
|
||||
{
|
||||
CorrectedBinaryMessage extractedMessage = mBPTC.extract(message);
|
||||
FullLCMessage flco = LCMessageFactory.createFull(extractedMessage, timestamp, timeslot, false);
|
||||
flco.setValid(extractedMessage.getCorrectedBitCount() >= 0);
|
||||
|
||||
if(extractedMessage.getCorrectedBitCount() < 0)
|
||||
{
|
||||
flco.setValid(false);
|
||||
}
|
||||
|
||||
return flco;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user