Método para cálculo de CRC Java / C

Bom dia pessoal,

Estou desenvolvendo um sistema em que faz comunicação em DNP3, um protocolo de equipamentos microprocessados.

Peguei uma rotina para calculo de CRC em C e a reescrevi em java… a rotina funcionou mas o CRC não calcula corretamente…

segue codigo em C

static unsigned short crctable[256] = {
  0x0000,  0x365e,  0x6cbc,  0x5ae2,  0xd978,  0xef26,  0xb5c4,  0x839a,
  0xff89,  0xc9d7,  0x9335,  0xa56b,  0x26f1,  0x10af,  0x4a4d,  0x7c13,
  0xb26b,  0x8435,  0xded7,  0xe889,  0x6b13,  0x5d4d,  0x07af,  0x31f1,
  0x4de2,  0x7bbc,  0x215e,  0x1700,  0x949a,  0xa2c4,  0xf826,  0xce78,
  0x29af,  0x1ff1,  0x4513,  0x734d,  0xf0d7,  0xc689,  0x9c6b,  0xaa35,
  0xd626,  0xe078,  0xba9a,  0x8cc4,  0x0f5e,  0x3900,  0x63e2,  0x55bc,
  0x9bc4,  0xad9a,  0xf778,  0xc126,  0x42bc,  0x74e2,  0x2e00,  0x185e,
  0x644d,  0x5213,  0x08f1,  0x3eaf,  0xbd35,  0x8b6b,  0xd189,  0xe7d7,
  0x535e,  0x6500,  0x3fe2,  0x09bc,  0x8a26,  0xbc78,  0xe69a,  0xd0c4,
  0xacd7,  0x9a89,  0xc06b,  0xf635,  0x75af,  0x43f1,  0x1913,  0x2f4d,
  0xe135,  0xd76b,  0x8d89,  0xbbd7,  0x384d,  0x0e13,  0x54f1,  0x62af,
  0x1ebc,  0x28e2,  0x7200,  0x445e,  0xc7c4,  0xf19a,  0xab78,  0x9d26,
  0x7af1,  0x4caf,  0x164d,  0x2013,  0xa389,  0x95d7,  0xcf35,  0xf96b,
  0x8578,  0xb326,  0xe9c4,  0xdf9a,  0x5c00,  0x6a5e,  0x30bc,  0x06e2,
  0xc89a,  0xfec4,  0xa426,  0x9278,  0x11e2,  0x27bc,  0x7d5e,  0x4b00,
  0x3713,  0x014d,  0x5baf,  0x6df1,  0xee6b,  0xd835,  0x82d7,  0xb489,
  0xa6bc,  0x90e2,  0xca00,  0xfc5e,  0x7fc4,  0x499a,  0x1378,  0x2526,
  0x5935,  0x6f6b,  0x3589,  0x03d7,  0x804d,  0xb613,  0xecf1,  0xdaaf,
  0x14d7,  0x2289,  0x786b,  0x4e35,  0xcdaf,  0xfbf1,  0xa113,  0x974d,
  0xeb5e,  0xdd00,  0x87e2,  0xb1bc,  0x3226,  0x0478,  0x5e9a,  0x68c4,
  0x8f13,  0xb94d,  0xe3af,  0xd5f1,  0x566b,  0x6035,  0x3ad7,  0x0c89,
  0x709a,  0x46c4,  0x1c26,  0x2a78,  0xa9e2,  0x9fbc,  0xc55e,  0xf300,
  0x3d78,  0x0b26,  0x51c4,  0x679a,  0xe400,  0xd25e,  0x88bc,  0xbee2,
  0xc2f1,  0xf4af,  0xae4d,  0x9813,  0x1b89,  0x2dd7,  0x7735,  0x416b,
  0xf5e2,  0xc3bc,  0x995e,  0xaf00,  0x2c9a,  0x1ac4,  0x4026,  0x7678,
  0x0a6b,  0x3c35,  0x66d7,  0x5089,  0xd313,  0xe54d,  0xbfaf,  0x89f1,
  0x4789,  0x71d7,  0x2b35,  0x1d6b,  0x9ef1,  0xa8af,  0xf24d,  0xc413,
  0xb800,  0x8e5e,  0xd4bc,  0xe2e2,  0x6178,  0x5726,  0x0dc4,  0x3b9a,
  0xdc4d,  0xea13,  0xb0f1,  0x86af,  0x0535,  0x336b,  0x6989,  0x5fd7,
  0x23c4,  0x159a,  0x4f78,  0x7926,  0xfabc,  0xcce2,  0x9600,  0xa05e,
  0x6e26,  0x5878,  0x029a,  0x34c4,  0xb75e,  0x8100,  0xdbe2,  0xedbc,
  0x91af,  0xa7f1,  0xfd13,  0xcb4d,  0x48d7,  0x7e89,  0x246b,  0x1235
};

 

WORD CDNP32Driver::B013_dnpcrc(const CBuffer& buff, unsigned int count) const
{

  unsigned crc = 0;
  unsigned i = 0;
  while (count--)
    crc = (crc >> 8) ^ crctable[(crc ^ buff[i++]) & 0x00ff];
  return (WORD)(~crc);

}

e este é como ficou em java

private static int[] crctable = new int[]{
		  0x0000,  0x365e,  0x6cbc,  0x5ae2,  0xd978,  0xef26,  0xb5c4,  0x839a,
		  0xff89,  0xc9d7,  0x9335,  0xa56b,  0x26f1,  0x10af,  0x4a4d,  0x7c13,
		  0xb26b,  0x8435,  0xded7,  0xe889,  0x6b13,  0x5d4d,  0x07af,  0x31f1,
		  0x4de2,  0x7bbc,  0x215e,  0x1700,  0x949a,  0xa2c4,  0xf826,  0xce78,
		  0x29af,  0x1ff1,  0x4513,  0x734d,  0xf0d7,  0xc689,  0x9c6b,  0xaa35,
		  0xd626,  0xe078,  0xba9a,  0x8cc4,  0x0f5e,  0x3900,  0x63e2,  0x55bc,
		  0x9bc4,  0xad9a,  0xf778,  0xc126,  0x42bc,  0x74e2,  0x2e00,  0x185e,
		  0x644d,  0x5213,  0x08f1,  0x3eaf,  0xbd35,  0x8b6b,  0xd189,  0xe7d7,
		  0x535e,  0x6500,  0x3fe2,  0x09bc,  0x8a26,  0xbc78,  0xe69a,  0xd0c4,
		  0xacd7,  0x9a89,  0xc06b,  0xf635,  0x75af,  0x43f1,  0x1913,  0x2f4d,
		  0xe135,  0xd76b,  0x8d89,  0xbbd7,  0x384d,  0x0e13,  0x54f1,  0x62af,
		  0x1ebc,  0x28e2,  0x7200,  0x445e,  0xc7c4,  0xf19a,  0xab78,  0x9d26,
		  0x7af1,  0x4caf,  0x164d,  0x2013,  0xa389,  0x95d7,  0xcf35,  0xf96b,
		  0x8578,  0xb326,  0xe9c4,  0xdf9a,  0x5c00,  0x6a5e,  0x30bc,  0x06e2,
		  0xc89a,  0xfec4,  0xa426,  0x9278,  0x11e2,  0x27bc,  0x7d5e,  0x4b00,
		  0x3713,  0x014d,  0x5baf,  0x6df1,  0xee6b,  0xd835,  0x82d7,  0xb489,
		  0xa6bc,  0x90e2,  0xca00,  0xfc5e,  0x7fc4,  0x499a,  0x1378,  0x2526,
		  0x5935,  0x6f6b,  0x3589,  0x03d7,  0x804d,  0xb613,  0xecf1,  0xdaaf,
		  0x14d7,  0x2289,  0x786b,  0x4e35,  0xcdaf,  0xfbf1,  0xa113,  0x974d,
		  0xeb5e,  0xdd00,  0x87e2,  0xb1bc,  0x3226,  0x0478,  0x5e9a,  0x68c4,
		  0x8f13,  0xb94d,  0xe3af,  0xd5f1,  0x566b,  0x6035,  0x3ad7,  0x0c89,
		  0x709a,  0x46c4,  0x1c26,  0x2a78,  0xa9e2,  0x9fbc,  0xc55e,  0xf300,
		  0x3d78,  0x0b26,  0x51c4,  0x679a,  0xe400,  0xd25e,  0x88bc,  0xbee2,
		  0xc2f1,  0xf4af,  0xae4d,  0x9813,  0x1b89,  0x2dd7,  0x7735,  0x416b,
		  0xf5e2,  0xc3bc,  0x995e,  0xaf00,  0x2c9a,  0x1ac4,  0x4026,  0x7678,
		  0x0a6b,  0x3c35,  0x66d7,  0x5089,  0xd313,  0xe54d,  0xbfaf,  0x89f1,
		  0x4789,  0x71d7,  0x2b35,  0x1d6b,  0x9ef1,  0xa8af,  0xf24d,  0xc413,
		  0xb800,  0x8e5e,  0xd4bc,  0xe2e2,  0x6178,  0x5726,  0x0dc4,  0x3b9a,
		  0xdc4d,  0xea13,  0xb0f1,  0x86af,  0x0535,  0x336b,  0x6989,  0x5fd7,
		  0x23c4,  0x159a,  0x4f78,  0x7926,  0xfabc,  0xcce2,  0x9600,  0xa05e,
		  0x6e26,  0x5878,  0x029a,  0x34c4,  0xb75e,  0x8100,  0xdbe2,  0xedbc,
		  0x91af,  0xa7f1,  0xfd13,  0xcb4d,  0x48d7,  0x7e89,  0x246b,  0x1235
		};

private static int confereCRC(byte[] buff) {
  int crc=0x0;
  int i=0;
  for (int j = 0; j < buff.length; j++) {
     crc = (crc >> 8) ^ crctable[(crc ^ buff[i++]) & 0x00ff];
  }
  return crc;
}

se eu executar o metodo com o byte[]

byte[] by = new byte[] { 0x05, 0x64, 0x1A, 0x44, 0x01, 0x00, 0x01, 0x00 };

Ele me retorna 32111, ou seja em HEXA, o CRC 7D 6F, sendo que era para retornar 90 82

Receio ser algum atributo ou cast ou bitewise que no java se comporta de forma diferente do C.

Alguém tem alguma idéia?

Abraço

Em vez de

     crc = (crc >> 8) ^ crctable[(crc ^ buff[i++]) & 0x00ff];  

use

     crc = (crc >>> 8) ^ (crctable[(crc ^ buff[i++]) & 0x00ff] & 0xFFFF);  

Agora você sabe para que serve o “>>>”?

Leia com atenção:

http://www.darksleep.com/player/JavaAndUnsignedTypes.html

entanglement, testei sua sugestão e infelizmente o resultado foi o mesmo…

estive lendo aqui, o >>> serve para fazer a rotação a direita sem sinal, seria o unsigned (?!)…

juliocbq, vou ler esse material, parece muito interessante

encontrei um outro código exemplo em http://www.lammertbies.nl/comm/software/index.html onde o CRCTABLE é montado em tempo de execução, o resultado foi o mesmo 32111, o que leva a crer que é realmente relacionado ao unsigned

obrigado pelas respostas rápidas,

Abaixo uma classe teste que fiz com outro código C, que da o mesmo resultado que o primeiro post…
O comentado é o fonte em C

Onde era short em C coloquei int no java, deve ser isso o problema, na chamada do método update_crc_dnp originalmente era char…

e um if em C era if ( (crc ^ c) & 0x0001 )

fiz em java if (((crc ^ c) & 0x0001) > 0)

to bem perdido nesse negócio…

public class CRCDnp {
	static int[] crc_tabdnp = new int[256];
	static boolean crc_tabdnp_init = false;
	static int P_DNP = 0xA6BC;

	public static void main(String[] args) {
		CRCDnp crcc = new CRCDnp();
		byte[] by = new byte[] { 0x05, 0x64, 0x1A, 0x44, 0x01, 0x00, 0x01, 0x00 };
		int crc = 0;
		for (int i = 0; i < by.length; i++) {
			System.out.println(i);
			crc = crcc.update_crc_dnp(crc, by[i]);
		}
		System.out.println(crc);
	}

	public int update_crc_dnp(int crc, byte c) {

		int tmp, short_c;

		short_c = 0x00ff & c;

		if (!crc_tabdnp_init)
			init_crcdnp_tab();

		tmp = crc ^ short_c;
		crc = (crc >> 8) ^ crc_tabdnp[tmp & 0xff];

		return crc;

	}

	// unsigned short update_crc_dnp( unsigned short crc, char c ) {
	//
	// unsigned short tmp, short_c;
	//
	// short_c = 0x00ff & (unsigned short) c;
	//
	// if ( ! crc_tabdnp_init ) init_crcdnp_tab();
	//
	// tmp = crc ^ short_c;
	// crc = (crc >> 8) ^ crc_tabdnp[ tmp & 0xff ];
	//
	// return crc;
	//
	// }

	// static void init_crcdnp_tab( void ) {
	// int i, j;
	// unsigned short crc, c;
	//
	// for (i=0; i<256; i++) {
	// crc = 0;
	// c = (unsigned short) i;
	//
	// for (j=0; j<8; j++) {
	//
	// if ( (crc ^ c) & 0x0001 ) crc = ( crc >> 1 ) ^ P_DNP;
	// else crc = crc >> 1;
	//
	// c = c >> 1;
	// }
	//
	// crc_tabdnp[i] = crc;
	// }
	// crc_tabdnp_init = TRUE;
	//
	// } /* init_crcdnp_tab */

	static void init_crcdnp_tab() {

		int i, j;
		int crc, c;

		for (i = 0; i < 256; i++) {
			crc = 0;
			c = i;

			for (j = 0; j < 8; j++) {

				if (((crc ^ c) & 0x0001) > 0)
					crc = (crc >> 1) ^ P_DNP;
				else
					crc = crc >> 1;

				c = c >> 1;
			}

			crc_tabdnp[i] = crc;
		}
		crc_tabdnp_init = true;

	} /* init_crcdnp_tab */

}
class CRC {
	private static short crctable[] = {  
		(short)0x0000,  (short)0x365e,  (short)0x6cbc,  (short)0x5ae2,  (short)0xd978,  (short)0xef26,  (short)0xb5c4,  (short)0x839a,  
		(short)0xff89,  (short)0xc9d7,  (short)0x9335,  (short)0xa56b,  (short)0x26f1,  (short)0x10af,  (short)0x4a4d,  (short)0x7c13,  
		(short)0xb26b,  (short)0x8435,  (short)0xded7,  (short)0xe889,  (short)0x6b13,  (short)0x5d4d,  (short)0x07af,  (short)0x31f1,  
		(short)0x4de2,  (short)0x7bbc,  (short)0x215e,  (short)0x1700,  (short)0x949a,  (short)0xa2c4,  (short)0xf826,  (short)0xce78,  
		(short)0x29af,  (short)0x1ff1,  (short)0x4513,  (short)0x734d,  (short)0xf0d7,  (short)0xc689,  (short)0x9c6b,  (short)0xaa35,  
		(short)0xd626,  (short)0xe078,  (short)0xba9a,  (short)0x8cc4,  (short)0x0f5e,  (short)0x3900,  (short)0x63e2,  (short)0x55bc,  
		(short)0x9bc4,  (short)0xad9a,  (short)0xf778,  (short)0xc126,  (short)0x42bc,  (short)0x74e2,  (short)0x2e00,  (short)0x185e,  
		(short)0x644d,  (short)0x5213,  (short)0x08f1,  (short)0x3eaf,  (short)0xbd35,  (short)0x8b6b,  (short)0xd189,  (short)0xe7d7,  
		(short)0x535e,  (short)0x6500,  (short)0x3fe2,  (short)0x09bc,  (short)0x8a26,  (short)0xbc78,  (short)0xe69a,  (short)0xd0c4,  
		(short)0xacd7,  (short)0x9a89,  (short)0xc06b,  (short)0xf635,  (short)0x75af,  (short)0x43f1,  (short)0x1913,  (short)0x2f4d,  
		(short)0xe135,  (short)0xd76b,  (short)0x8d89,  (short)0xbbd7,  (short)0x384d,  (short)0x0e13,  (short)0x54f1,  (short)0x62af,  
		(short)0x1ebc,  (short)0x28e2,  (short)0x7200,  (short)0x445e,  (short)0xc7c4,  (short)0xf19a,  (short)0xab78,  (short)0x9d26,  
		(short)0x7af1,  (short)0x4caf,  (short)0x164d,  (short)0x2013,  (short)0xa389,  (short)0x95d7,  (short)0xcf35,  (short)0xf96b,  
		(short)0x8578,  (short)0xb326,  (short)0xe9c4,  (short)0xdf9a,  (short)0x5c00,  (short)0x6a5e,  (short)0x30bc,  (short)0x06e2,  
		(short)0xc89a,  (short)0xfec4,  (short)0xa426,  (short)0x9278,  (short)0x11e2,  (short)0x27bc,  (short)0x7d5e,  (short)0x4b00,  
		(short)0x3713,  (short)0x014d,  (short)0x5baf,  (short)0x6df1,  (short)0xee6b,  (short)0xd835,  (short)0x82d7,  (short)0xb489,  
		(short)0xa6bc,  (short)0x90e2,  (short)0xca00,  (short)0xfc5e,  (short)0x7fc4,  (short)0x499a,  (short)0x1378,  (short)0x2526,  
		(short)0x5935,  (short)0x6f6b,  (short)0x3589,  (short)0x03d7,  (short)0x804d,  (short)0xb613,  (short)0xecf1,  (short)0xdaaf,  
		(short)0x14d7,  (short)0x2289,  (short)0x786b,  (short)0x4e35,  (short)0xcdaf,  (short)0xfbf1,  (short)0xa113,  (short)0x974d,  
		(short)0xeb5e,  (short)0xdd00,  (short)0x87e2,  (short)0xb1bc,  (short)0x3226,  (short)0x0478,  (short)0x5e9a,  (short)0x68c4,  
		(short)0x8f13,  (short)0xb94d,  (short)0xe3af,  (short)0xd5f1,  (short)0x566b,  (short)0x6035,  (short)0x3ad7,  (short)0x0c89,  
		(short)0x709a,  (short)0x46c4,  (short)0x1c26,  (short)0x2a78,  (short)0xa9e2,  (short)0x9fbc,  (short)0xc55e,  (short)0xf300,  
		(short)0x3d78,  (short)0x0b26,  (short)0x51c4,  (short)0x679a,  (short)0xe400,  (short)0xd25e,  (short)0x88bc,  (short)0xbee2,  
		(short)0xc2f1,  (short)0xf4af,  (short)0xae4d,  (short)0x9813,  (short)0x1b89,  (short)0x2dd7,  (short)0x7735,  (short)0x416b,  
		(short)0xf5e2,  (short)0xc3bc,  (short)0x995e,  (short)0xaf00,  (short)0x2c9a,  (short)0x1ac4,  (short)0x4026,  (short)0x7678,  
		(short)0x0a6b,  (short)0x3c35,  (short)0x66d7,  (short)0x5089,  (short)0xd313,  (short)0xe54d,  (short)0xbfaf,  (short)0x89f1,  
		(short)0x4789,  (short)0x71d7,  (short)0x2b35,  (short)0x1d6b,  (short)0x9ef1,  (short)0xa8af,  (short)0xf24d,  (short)0xc413,  
		(short)0xb800,  (short)0x8e5e,  (short)0xd4bc,  (short)0xe2e2,  (short)0x6178,  (short)0x5726,  (short)0x0dc4,  (short)0x3b9a,  
		(short)0xdc4d,  (short)0xea13,  (short)0xb0f1,  (short)0x86af,  (short)0x0535,  (short)0x336b,  (short)0x6989,  (short)0x5fd7,  
		(short)0x23c4,  (short)0x159a,  (short)0x4f78,  (short)0x7926,  (short)0xfabc,  (short)0xcce2,  (short)0x9600,  (short)0xa05e,  
		(short)0x6e26,  (short)0x5878,  (short)0x029a,  (short)0x34c4,  (short)0xb75e,  (short)0x8100,  (short)0xdbe2,  (short)0xedbc,  
		(short)0x91af,  (short)0xa7f1,  (short)0xfd13,  (short)0xcb4d,  (short)0x48d7,  (short)0x7e89,  (short)0x246b,  (short)0x1235  
	};  



	public short B013_dnpcrc(byte buff[], int count) 
	{  
		int crc = 0;
		for (int i = 0; i < count; ++i) {
			crc = (crc >>> 8) ^ (crctable[(crc ^ buff[i]) & 0xFF] & 0xFFFF);
		}
		return (short) ~crc;
	}  

	public static void main (String[] args) {
		byte buff[] = {
			0x05, 0x64, 0x1A, 0x44, 0x01, 0x00, 0x01, 0x00
		};
		CRC crc = new CRC();
		System.out.printf ("CRC = %04X%n", crc.B013_dnpcrc(buff, buff.length)  & 0xFFFF);
	}
}

resultado:

CRC = 8290

entanglement, muito obrigado pela ajuda! Salvou meu dia!

Percebi meu erro no return faltava o “~” que muda o 32111 para -32112 passando isso pra hexa da 8290, falei anteriormente em 9082 por causa do LSB e MSB.

VALEUUUUUUUU