/*---------------------------------------------------------------------------*\ FILE........: golay23.c AUTHOR......: Tomas Härdin & David Rowe DATE CREATED: 3 March 2013 To test: src$ gcc golay23.c -o golay23 -Wall -O3 -DGOLAY23_UNITTEST && ./golay23 src$ gcc golay23.c -o golay23 -Wall -O3 -DGOLAY23_UNITTEST -DRUN_TIME_TABLES && ./golay23 src$ gcc golay23.c -o golay23 -Wall -O3 -DGOLAY23_UNITTEST -DNO_TABLES && ./golay23 To generate tables: src$ gcc golay23.c -o golay23 -Wall -O3 -DGOLAY23_MAKETABLES && ./golay23 \*---------------------------------------------------------------------------*/ /* Copyright (C) 2016 Tomas Härdin & David Rowe All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 2.1, as published by the Free Software Foundation. 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 Lesser General Public License along with this program; if not,see . */ #include #ifdef GOLAY23_MAKETABLES #define RUN_TIME_TABLES #endif #ifndef NO_TABLES #ifdef RUN_TIME_TABLES int static encoding_table[4096]; int static decoding_table[2048]; static int inited = 0; #else //default is to use precomputed tables #include "golayenctable.h" #include "golaydectable.h" #endif #endif //since we want to avoid bit-reversing inside syndrome() we bit-reverse the polynomial instead #define GOLAY_POLYNOMIAL 0xC75 //AE3 reversed int golay23_syndrome(int c) { //could probably be done slightly smarter, but works int x; for (x = 11; x >= 0; x--) { if (c & ((1<<11) << x)) { c ^= GOLAY_POLYNOMIAL << x; } } return c; } #ifdef __GNUC__ #define popcount __builtin_popcount #elif defined(__MSC_VER) #include #define popcount __popcnt #else static int popcount(unsigned int c) { int ret = 0; while (c) { if (c & 1) { ret++; } c >>= 1; } return ret; } #endif #if defined(NO_TABLES) || defined(RUN_TIME_TABLES) static int golay23_encode_no_tables(int c) { c <<= 11; return golay23_syndrome(c) | c; } #endif #ifdef NO_TABLES static int unrotate(unsigned int c, int x) { return ((c << x) & 0x7FFFFF) | (c >> (23 - x)); } static int golay23_decode_no_tables(int c) { //TODO: optimize? int x; c = unrotate(c, 12); for (x = 0; x < 23; x++) { int t; int s = golay23_syndrome(c); if (popcount(s) <= 3) { return unrotate(c ^ s, x) & 0xFFF; } for (t = 0; t < 23; t++) { int c2 = c ^ (1 << t); int s = golay23_syndrome(c2); if (popcount(s) <= 2) { return unrotate(c2 ^ s, x) & 0xFFF; } } //rotate c = (c >> 1) | ((c & 1) << 22); } //shouldn't reach here.. assert("Something is wrong with golay23_decode_no_tables().."); return c & 0xFFF; } #endif void golay23_init(void) { #ifdef RUN_TIME_TABLES int x, y, z; inited = 1; for (x = 0; x < 4096; x++) { encoding_table[x] = golay23_encode_no_tables(x); } decoding_table[0] = 0; //1-bit errors for (x = 0; x < 23; x++) { int d = 1<= 0 && c <= 0xFFF); #ifdef RUN_TIME_TABLES assert(inited); #endif #ifdef NO_TABLES return golay23_encode_no_tables(c); #else return encoding_table[c]; #endif } int golay23_decode(int c) { assert(c >= 0 && c <= 0x7FFFFF); #ifdef RUN_TIME_TABLES assert(inited); #endif #ifdef NO_TABLES //duplicate old golay23_decode()'s shift return unrotate(golay23_decode_no_tables(c), 11); #else //message is shifted 11 places left in the return value return c ^ decoding_table[golay23_syndrome(c)]; #endif } int golay23_count_errors(int recd_codeword, int corrected_codeword) { return popcount(recd_codeword ^ corrected_codeword); } /** * Table generation and testing code below */ #ifdef GOLAY23_MAKETABLES #include int main(void) { int x; //generate and dump golay23_init(); FILE *enc = fopen("golayenctable.h", "w"); FILE *dec = fopen("golaydectable.h", "w"); fprintf(enc, "/* Generated by golay23.c -DGOLAY23_MAKETABLE */\n\ \n\ const int static encoding_table[]={\n"); for (x = 0; x < 4096; x++) { fprintf(enc, x < 4095 ? " 0x%x,\n" : " 0x%x\n", encoding_table[x]); } fprintf(enc, "};\n"); fprintf(dec, "/* Generated by golay23.c -DGOLAY23_MAKETABLE */\n\ \n\ const int static decoding_table[]={\n"); for (x = 0; x < 2048; x++) { fprintf(dec, x < 2047 ? " 0x%x,\n" : " 0x%x\n", decoding_table[x]); } fprintf(dec, "};\n"); fclose(enc); fclose(dec); return 0; } #elif defined(GOLAY23_UNITTEST) #include #include #include int main(void) { int c; golay23_init(); //keep track of whether every single codeword has been checked char *checkmask = malloc(1<<23); memset(checkmask, 0, 1<<23); //step through all possible messages for (c = 0; c < (1<<12); c++) { int g23 = golay23_encode(c); int x,y,z; checkmask[g23] = 1; int c2 = golay23_decode(g23) >> 11; printf("%03x -> %06x %03x\n", c, g23, c2); if (c != c2) { printf("Bad!\n"); exit(1); } //test the code by flipping every combination of one, two and three bits for (x = 0; x < 23; x++) { int flipped = g23 ^ (1<> 11; if (c != c2) { printf("Bad!\n"); exit(1); } } for (x = 0; x < 22; x++) { for (y = x+1; y < 23; y++) { int flipped = g23 ^ (1<> 11; if (c != c2) { printf("Bad!\n"); exit(1); } } } for (x = 0; x < 21; x++) { for (y = x+1; y < 22; y++) { for (z = y+1; z < 23; z++) { int flipped = g23 ^ (1<> 11; if (c != c2) { printf("Bad!\n"); exit(1); } } } } } //did we check every codeword? for (c = 0; c < (1<<23); c++) { if (checkmask[c] != 1) { printf("%06x unchecked!\n", c); exit(1); } } printf("Everything checks out\n"); free(checkmask); return 0; } #endif