// Copyright (C) 2004, Rodrigo Balerdi // http://www.balerdi.com.ar/dakota package ar.com.balerdi.smartmedia; public final class ECC { private ECC() {} public static final int NO_ERROR = 0; public static final int EXTRA_ECC_BIT_ERROR = 1; public static final int CORRECTABLE_DATA_ERROR = 2; public static final int CORRECTABLE_ECC_ERROR = 4; public static final int UNCORRECTABLE_ERROR = 8; private static final int[] addressMask = new int[0x100]; private static final int[] dataMask = new int[0x100]; static { int[] dmm = new int[] { 0xFFFF54, 0xFFFF58, 0xFFFF64, 0xFFFF68, 0xFFFF94, 0xFFFF98, 0xFFFFA4, 0xFFFFA8 } ; initMasks ( 0, 0x100, 0x5555FF, 0x3000000, 0, dmm, 8 ) ; } private static void initMasks(int o, int l, int am, int amm, int dm, int[] dmm, int dmmi) { if (l == 1) { addressMask[o] = am; dataMask[o] = dm; } else { l >>= 1; amm >>= 2; dmmi--; initMasks(o, l, am, amm, dm, dmm, dmmi); initMasks(o + l, l, am ^ amm, amm, dm ^ dmm[dmmi], dmm, dmmi); } } public static int create() { return 0xFFFFFF; } public static int create(byte[] data) { return create(data, 0); } public static int create(byte[] data, int offset) { int ecc = 0xFFFFFF; for (int a = 0; a < 0x100; a++) ecc ^= addressMask[a] & dataMask[data[offset++] & 0xFF]; return ecc; } public static int update(int ecc, int address, int data) { return ecc ^ (addressMask[address] & dataMask[data]); } public static int update(int ecc, int address, byte[] data, int offset, int length) { while (length-- > 0) ecc ^= (addressMask[address++] & dataMask[data[offset++] & 0xFF]); return ecc; } public static int read(byte[] data, int offset) { return ((data[offset] & 0xFF) << 8) + ((data[offset + 1] & 0xFF) << 16) + (data[offset + 2] & 0xFF); } public static void write(byte[] data, int offset, int ecc) { data[offset] = (byte) (ecc >> 8); data[offset + 1] = (byte) (ecc >> 16); data[offset + 2] = (byte) ecc; } public static int check(int eccXor) { if (eccXor == 0) return NO_ERROR; int x = eccXor & 0xFFFFFC; if (x == 0) return EXTRA_ECC_BIT_ERROR; if (((x ^ (x >> 1)) & 0x555554) == 0x555554) return eccXor == x ? CORRECTABLE_DATA_ERROR : (CORRECTABLE_DATA_ERROR | EXTRA_ECC_BIT_ERROR); if ((x & -x) == x) return eccXor == x ? CORRECTABLE_ECC_ERROR : (CORRECTABLE_ECC_ERROR | EXTRA_ECC_BIT_ERROR); return eccXor == x ? UNCORRECTABLE_ERROR : (UNCORRECTABLE_ERROR | EXTRA_ECC_BIT_ERROR); } public static int getCorrectableDataLine(int eccXor) { return ((eccXor >> 9) & 0x01) | ((eccXor >> 10) & 0x02) | ((eccXor >> 11) & 0x04) | ((eccXor >> 12) & 0x08) | ((eccXor >> 13) & 0x10) | ((eccXor >> 14) & 0x20) | ((eccXor >> 15) & 0x40) | ((eccXor >> 16) & 0x80); } public static int getCorrectableDataColumn(int eccXor) { return ((eccXor >> 3) & 0x1) | ((eccXor >> 4) & 0x2) | ((eccXor >> 5) & 0x4); } public static int checkAndCorrect(int eccXor, byte[] data) { return checkAndCorrect(eccXor, data, 0); } public static int checkAndCorrect(int eccXor, byte[] data, int offset) { int e = check(eccXor); if ((e & CORRECTABLE_DATA_ERROR) != 0) { data[offset + getCorrectableDataLine(eccXor)] ^= 1 << getCorrectableDataColumn(eccXor); } return e; } public static int checkAndCorrect(byte[] data, int ecc) { return checkAndCorrect(data, 0, ecc); } public static int checkAndCorrect(byte[] data, int offset, int ecc) { int cecc = create(data, offset); return checkAndCorrect(cecc ^ ecc, data, offset); } public static int checkAndCorrect(byte[] data, int offset, byte[] eccData, int eccOffset) { int cecc = create(data, offset); int ecc = read(eccData, eccOffset); return checkAndCorrect(cecc ^ ecc, data, offset); } public static int checkAndCorrectDataAndECC(byte[] data, int offset, byte[] eccData, int eccOffset) { int cecc = create(data, offset); int ecc = read(eccData, eccOffset); int e = checkAndCorrect(cecc ^ ecc, data, offset); if (e != NO_ERROR && (e & UNCORRECTABLE_ERROR) == 0) { if ((e & (CORRECTABLE_ECC_ERROR | EXTRA_ECC_BIT_ERROR)) != 0) { write(eccData, eccOffset, (e & CORRECTABLE_DATA_ERROR) != 0 ? ecc | 3 : cecc); } } return e; } }