mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-14 09:37:36 -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();
|
mBufferATimeslot = cach.getTimeslot();
|
||||||
mBufferBTimeslot = (mBufferATimeslot == 1 ? 2 : 1);
|
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));
|
dispatch(DMRMessageFactory.create(mBufferAPattern, message, cach, getTimestamp(), mBufferATimeslot));
|
||||||
|
|
||||||
@@ -156,8 +165,8 @@ public class DMRMessageFramer implements Listener<Dibit>
|
|||||||
mBufferAPattern = DMRSyncPattern.getNextVoice(mBufferAPattern);
|
mBufferAPattern = DMRSyncPattern.getNextVoice(mBufferAPattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Automatically trigger buffer B burst collection if it is collecting a voice super frame.
|
//Automatically trigger buffer B burst collection if it is collecting a voice super frame or mobile direct.
|
||||||
if(mBufferBPattern.isVoicePattern())
|
if(mBufferBPattern.isVoicePattern() || mBufferBPattern == DMRSyncPattern.DIRECT_EMPTY_TIMESLOT)
|
||||||
{
|
{
|
||||||
mAssemblingBurst = true;
|
mAssemblingBurst = true;
|
||||||
mBufferAActive = false;
|
mBufferAActive = false;
|
||||||
@@ -205,6 +214,16 @@ public class DMRMessageFramer implements Listener<Dibit>
|
|||||||
mBufferBTimeslot = cach.getTimeslot();
|
mBufferBTimeslot = cach.getTimeslot();
|
||||||
mBufferATimeslot = (mBufferBTimeslot == 1 ? 2 : 1);
|
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));
|
dispatch(DMRMessageFactory.create(mBufferBPattern, burst, cach, getTimestamp(), mBufferBTimeslot));
|
||||||
|
|
||||||
@@ -215,8 +234,8 @@ public class DMRMessageFramer implements Listener<Dibit>
|
|||||||
mBufferBPattern = DMRSyncPattern.getNextVoice(mBufferBPattern);
|
mBufferBPattern = DMRSyncPattern.getNextVoice(mBufferBPattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Automatically trigger buffer A burst collection if it is collecting a voice super frame.
|
//Automatically trigger buffer A burst collection if it is collecting a voice super frame or mobile direct.
|
||||||
if(mBufferAPattern.isVoicePattern())
|
if(mBufferAPattern.isVoicePattern() || mBufferAPattern == DMRSyncPattern.DIRECT_EMPTY_TIMESLOT)
|
||||||
{
|
{
|
||||||
mAssemblingBurst = true;
|
mAssemblingBurst = true;
|
||||||
mBufferAActive = true;
|
mBufferAActive = true;
|
||||||
|
|||||||
@@ -49,6 +49,18 @@ public abstract class BPTCBase
|
|||||||
mRowCount = rowCount;
|
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.
|
* Performs error detection and correction.
|
||||||
* @param message to correct
|
* @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())
|
if(columns.isEmpty() && rows.isEmpty())
|
||||||
{
|
{
|
||||||
message.incrementCorrectedBitCount(correctedIndexes.size());
|
message.incrementCorrectedBitCount(correctedIndexes.size());
|
||||||
@@ -204,6 +238,90 @@ public abstract class BPTCBase
|
|||||||
return columns;
|
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.
|
* Corrects single bit errors in each row using only the Hamming error index.
|
||||||
* @param row to correct
|
* @param row to correct
|
||||||
@@ -313,7 +431,18 @@ public abstract class BPTCBase
|
|||||||
int offset = row * mColumnCount;
|
int offset = row * mColumnCount;
|
||||||
sb.append("Row ").append(row).append(": ");
|
sb.append("Row ").append(row).append(": ");
|
||||||
sb.append(message.getSubMessage(offset, offset + mColumnCount));
|
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);
|
System.out.println(sb);
|
||||||
|
|||||||
@@ -34,6 +34,15 @@ public class BPTC_128_77 extends BPTCBase
|
|||||||
super(new Hamming16(), 16, 8);
|
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.
|
* Performs error detection and correction and extracts the payload from the BPTC encoded message.
|
||||||
* @param message with BPTC encoding.
|
* @param message with BPTC encoding.
|
||||||
@@ -93,15 +102,15 @@ public class BPTC_128_77 extends BPTCBase
|
|||||||
public static void main(String[] args)
|
public static void main(String[] args)
|
||||||
{
|
{
|
||||||
BPTC_128_77 bptc = new BPTC_128_77();
|
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));
|
CorrectedBinaryMessage deinterleavedReferenceMessage = new CorrectedBinaryMessage(BinaryMessage.load(deinterleavedReference));
|
||||||
|
|
||||||
String interleaved = "00000000000000000000000000010010000100010000001000000010000100010000001100000110001101100000001100000101001000010010010100110011"; //Under test
|
// String interleaved = "00000000000000000000000000010010000100010000001000000010000100010000001100000110001101100000001100000101001000010010010100110011"; //Under test
|
||||||
CorrectedBinaryMessage interleavedMessage = new CorrectedBinaryMessage(BinaryMessage.load(interleaved));
|
// CorrectedBinaryMessage interleavedMessage = new CorrectedBinaryMessage(BinaryMessage.load(interleaved));
|
||||||
// CorrectedBinaryMessage deinterleaved = deinterleave(interleavedMessage);
|
// CorrectedBinaryMessage deinterleaved = deinterleave(interleavedMessage);
|
||||||
CorrectedBinaryMessage deinterleaved = new CorrectedBinaryMessage(BinaryMessage.load(deinterleavedRaw));
|
|
||||||
|
|
||||||
|
|
||||||
String deinterleavedUncorrected = deinterleaved.toString();
|
String deinterleavedUncorrected = deinterleaved.toString();
|
||||||
@@ -120,6 +129,7 @@ public class BPTC_128_77 extends BPTCBase
|
|||||||
System.out.println("--------------------------------");
|
System.out.println("--------------------------------");
|
||||||
System.out.println("Residual Error Map:");
|
System.out.println("Residual Error Map:");
|
||||||
bptc.logErrorMap(deinterleaved);
|
bptc.logErrorMap(deinterleaved);
|
||||||
|
System.out.println("Columns:" + bptc.getColumnErrors(deinterleaved) + " Rows:" + bptc.getRowErrors(deinterleaved));
|
||||||
System.out.println("--------------------------------");
|
System.out.println("--------------------------------");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -129,7 +129,12 @@ public class FLCAssembler
|
|||||||
{
|
{
|
||||||
CorrectedBinaryMessage extractedMessage = mBPTC.extract(message);
|
CorrectedBinaryMessage extractedMessage = mBPTC.extract(message);
|
||||||
FullLCMessage flco = LCMessageFactory.createFull(extractedMessage, timestamp, timeslot, false);
|
FullLCMessage flco = LCMessageFactory.createFull(extractedMessage, timestamp, timeslot, false);
|
||||||
flco.setValid(extractedMessage.getCorrectedBitCount() >= 0);
|
|
||||||
|
if(extractedMessage.getCorrectedBitCount() < 0)
|
||||||
|
{
|
||||||
|
flco.setValid(false);
|
||||||
|
}
|
||||||
|
|
||||||
return flco;
|
return flco;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user