package edac; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import bits.BinaryMessage; /******************************************************************************* * SDR Trunk * Copyright (C) 2014 Dennis Sheirer * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/> * ----------------------------------------------------------------------- * Galois24 decoder based on Hank Wallace's tutorial/algorithm located at: * http://www.aqdi.com/golay.htm ******************************************************************************/ /** * Galois 24/12/7 decoder */ public class Golay24 { private final static Logger mLog = LoggerFactory.getLogger( Golay24.class ); /** * Galois 24/12 checksums generated by: * * CRCUtil.generate( 12, 11, 0xC75, 0x0, true ); */ public static final int[] CHECKSUMS = new int[] { 0x63A, 0x31D, 0x7B4, 0x3DA, 0x1ED, 0x6CC, 0x366, 0x1B3, 0x6E3, 0x54B, 0x49F, 0x475, 0x400, 0x200, 0x100, 0x080, 0x040, 0x020, 0x010, 0x008, 0x004, 0x002, 0x001 }; private static int calculateChecksum( BinaryMessage message, int startIndex ) { int calculated = 0; //Starting value /* Iterate the set bits and XOR running checksum with lookup value */ for (int i = message.nextSetBit( startIndex ); i >= startIndex && i < startIndex + 12; i = message.nextSetBit( i+1 ) ) { calculated ^= CHECKSUMS[ i - startIndex ]; } return calculated; } /** * Performs error detection and returns a corrected copy of the 24-bit * message that starts at the start index. * @param message - source message containing startIndex + 24 bits length * @param startIndex - start of the 24-bit galois 24 protected bit set * @return - corrected 24-bit galois value */ public static BinaryMessage checkAndCorrect( BinaryMessage message, int startIndex ) { boolean parityError = message.cardinality() % 2 != 0; int syndrome = getSyndrome( message, startIndex ); /* No errors */ if( syndrome == 0 ) { if( parityError ) { message.flip( startIndex + 23 ); } message.setCRC( CRC.PASSED ); return message; } /* Get original message value */ int original = message.getInt( 0, 22 ); int index = -1; int syndromeWeight = 3; int errors = 0; while( index < 23 ) { if( index != -1 ) { /* restore the previous flipped bit */ if( index > 0 ) { message.flip( index - 1 ); } message.flip( index ); syndromeWeight = 2; } syndrome = getSyndrome( message, startIndex ); if( syndrome > 0 ) { for( int i = 0; i < 23; i++ ) { errors = Integer.bitCount( syndrome ); if( errors <= syndromeWeight ) { message.xor( 12, 11, syndrome ); message.rotateRight( i, startIndex, startIndex + 22 ); if( index >= 0 ) { errors ++; } int corrected = message.getInt( 0, 22 ); if( Integer.bitCount( original ^ corrected ) > 3 ) { message.setCRC( CRC.FAILED_CRC ); return message; } message.setCRC( CRC.PASSED ); return message; } else { message.rotateLeft( startIndex, startIndex + 22 ); syndrome = getSyndrome( message, startIndex ); } } index++; } } message.setCRC( CRC.FAILED_CRC ); return message; } private static int getSyndrome( BinaryMessage message, int startIndex ) { int calculated = calculateChecksum( message, startIndex ); int checksum = message.getInt( startIndex + 12, startIndex + 22 ); return ( checksum ^ calculated ); } }