【问题标题】:Calculate 16 bit CRC in java and append it at the end of the byte array在java中计算16位CRC并将其附加到字节数组的末尾
【发布时间】:2014-01-02 07:27:30
【问题描述】:

我有以下缓冲区

byte pingBuff[] ={0x01, 0x01,0x00,0x01,0x00,0x20}

我需要计算这 6 个字节的 16 位 CRC 并将其附加在末尾​​p>

pingBuff[]

我已经使用 C++ 完成了它,并尝试在 java 中更改该代码,如下所示,但它不起作用。

    package org.totalbeginner.tutorial;

    public class CRCLikeC
    {
      /* Table of CRC values for high–order byte */
      char auchCRCHi[] = {
      0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
      0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
      0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
      0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
      0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81,
      0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
      0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
      0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
      0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
      0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
      0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
      0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
      0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
      0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
      0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
      0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
      0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
      0x40
      } ;

      /* Table of CRC values for low–order byte */
      char auchCRCLo[] = {
      0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,
      0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
      0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD,
      0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
      0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7,
      0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
      0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE,
      0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
      0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2,
      0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
      0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB,
      0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
      0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91,
      0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
      0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88,
      0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
      0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80,
      0x40
      } ;

      int CRC16(char puchMsg, int usDataLen)
      {
         char uchCRCHi = 0xFF ; /* high byte of CRC initialized */
         char uchCRCLo = 0xFF ; /* low byte of CRC initialized */
         int uIndex ; /* will index into CRC lookup table */

         while (usDataLen--) /* pass through message buffer */
         {
          uIndex = uchCRCHi ^ puchMsg++ ; /* calculate the CRC */
          uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ;
          uchCRCLo = auchCRCLo[uIndex] ;
         }

        return (uchCRCHi << 8 | uchCRCLo) ;
        }

    }

排队

while (usDataLen--)

看到的错误是“无法从 int 转换为 boolean”

并在行中

uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ;

看到的错误是“无法从 int 转换为 char”

实际上 c 中的代码使用 unsigned char ,我将它们转换为 char 。我在这个 java 实现中将 unsinged short 转换为 int 。

请建议我如何改进这种 crc 计算方法。 或者有没有其他方法从十六进制字节计算 crc 。我已经搜索了其他方法,但它不适用于 pingBuff[] 中的十六进制字节。

【问题讨论】:

    标签: java byte crc16


    【解决方案1】:

    关于第一个问题:在(或)中,0int 被评估为false,任何其他值被评估为true。 Java 不执行这些隐式转换,因此您需要手动检查您的int 是否大于0(请参阅下面代码中的“更正1”)。

    关于第二个问题:在 Java 中,^ 运算符仅在 ints 之间定义。因此,当您在两个chars 上执行时,它们都被提升为ints,然后才进行异或。结果当然是一个int,它不能被分配给char——你必须显式地将它转换回一个字符。请注意,由于两个 ints 的 MSB 都已知为零(因为它们是从 chars 升级而来的),因此这是非常安全的,不会有任何数据丢失的风险。

      int CRC16(char puchMsg, int usDataLen)
      {
         char uchCRCHi = 0xFF ; /* high byte of CRC initialized */
         char uchCRCLo = 0xFF ; /* low byte of CRC initialized */
         int uIndex ; /* will index into CRC lookup table */
    
         // Correction 1: compare the int to 0
         while (usDataLen-- > 0) /* pass through message buffer */
         {
          uIndex = uchCRCHi ^ puchMsg++ ; /* calculate the CRC */
          uchCRCHi = (char) (uchCRCLo ^ auchCRCHi[uIndex]); // Correction 2: explicit ca
          uchCRCLo = auchCRCLo[uIndex] ;
         }
    
        return (uchCRCHi << 8 | uchCRCLo) ;
        }
    

    【讨论】:

      【解决方案2】:

      与 C 不同,java while() 语句中的条件必须是 boolean,因此将其更改为 while(usDataLen-- &gt; 0)

      第二个应该是uchCRCHi = (char) (uchCRCLo ^ auchCRCHi[uIndex]); 可以看this discussion

      【讨论】:

        【解决方案3】:
        public int calcCRC(byte[] bitPlane) {
        
                    crc = 0;
        
                    for (int i = 0; i < bitPlane.length; i++) {
                        byte element = bitPlane[i];
                        crc ^= (element << 8);
                        for (int j = 0; j < 8; j++) {
                            boolean carry = ((crc & 0x8000) != 0);
                            crc <<= 1;
                            if (carry) {
                                crc ^= 0x1021;
                            }
                        }
        
                    }
        
        
                    return crc;
        
                }
        

        【讨论】:

          【解决方案4】:

          我知道这已经很老了,但如果周围的人仍然需要它,我制作了一个适用于我的 Java 版本。 它接收并返回一个String,因此您可以将您的数据转换为String 并按原样使用它,或者将其作为线索来制作与字节一起使用的版本(我认为它非常简单)。

          希望对你有帮助!

          我是here

          编辑:

          你可以这样使用: 假设您有一些数据并且需要它的 crc。您首先将其转换为字符串,然后像这样使用 process() 函数:

          String crc = CRCITU.process(data);
          // for example
          CRCITU.process("0d0103588990501766460026"); // will return "7bf9"
          

          然后在您的情况下,您将其转换回字节并将其附加到原始数据的末尾。

          如果您有任何问题,请在 GitHub 存储库中发布问题,我会尽力帮助您。

          【讨论】:

            猜你喜欢
            • 2023-03-15
            • 1970-01-01
            • 2013-07-02
            • 2021-08-09
            • 2015-07-02
            • 1970-01-01
            • 2014-10-04
            • 1970-01-01
            • 2018-02-18
            相关资源
            最近更新 更多