Skip to content

Commit

Permalink
#2117 DMR simplex transmissions now frame correctly and added additio…
Browse files Browse the repository at this point in the history
…nal case for FLC BPTC error correction. (#2118)

Co-authored-by: Dennis Sheirer <[email protected]>
  • Loading branch information
DSheirer and Dennis Sheirer authored Dec 25, 2024
1 parent 9ffa02e commit 70fb74b
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,15 @@ private void dispatchBufferA()
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));

Expand All @@ -156,8 +165,8 @@ private void dispatchBufferA()
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;
Expand Down Expand Up @@ -205,6 +214,16 @@ private void dispatchBufferB()
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));

Expand All @@ -215,8 +234,8 @@ private void dispatchBufferB()
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;
Expand Down
131 changes: 130 additions & 1 deletion src/main/java/io/github/dsheirer/module/decode/dmr/bptc/BPTCBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,18 @@ public BPTCBase(IHamming hamming, int columnCount, int 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.
* @param message to correct
Expand Down Expand Up @@ -100,6 +112,28 @@ public boolean correct(CorrectedBinaryMessage message)
}
}

//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());
Expand Down Expand Up @@ -204,6 +238,90 @@ public BinaryMessage getColumnErrors(CorrectedBinaryMessage message)
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
Expand Down Expand Up @@ -313,7 +431,18 @@ public void logErrorMap(CorrectedBinaryMessage message)
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ public BPTC_128_77()
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.
Expand Down Expand Up @@ -93,15 +102,15 @@ public CorrectedBinaryMessage deinterleave(BinaryMessage interleaved)
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();
Expand All @@ -120,6 +129,7 @@ public static void main(String[] args)
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,12 @@ private FullLCMessage decode2(BinaryMessage message, long timestamp, int timeslo
{
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;
}

Expand Down

0 comments on commit 70fb74b

Please sign in to comment.