crc-16 cccitt 问题 - 计算不正确

crc-16 cccitt problem - incorrect calculation

尝试在我的蓝牙 ios 移动应用程序中实现此 CRC16 CITT 校验和:

extension Data {

typealias bit_order_16 = (_ value: UInt16) -> UInt16
typealias bit_order_8 = (_ value: UInt8) -> UInt8


func crc16Check() -> UInt16 {
 let data = self as! NSData
    let bytes = UnsafePointer<UInt8>(data.bytes.assumingMemoryBound(to: UInt8.self))
    let length = data.length
    return crc16ccitt(message: bytes, nBytes: length)
}


func straight_16(value: UInt16) -> UInt16 {
    return value
}

func reverse_16(value: UInt16) -> UInt16 {
    var value = value
    var reversed: UInt16 = 0
    for i in stride(from: 0, to: 16, by: 1) {
        reversed <<= 1
        reversed |= (value & 0x1)
        value >>= 1
    }
    return reversed
}

func straight_8(value: UInt8) -> UInt8 {
    return value
}

func reverse_8(value: UInt8) -> UInt8 {
    var value = value
    var reversed: UInt8 = 0
    for i in stride(from: 0, to: 8, by: 1) {
        reversed <<= 1
        reversed |= (value & 0x1)
        value >>= 1
    }
    return reversed
}


func crc16(message: UnsafePointer<UInt8>, nBytes: Int, data_order: bit_order_8, remainder_order: bit_order_16, remainder: UInt16, polynomial: UInt16) -> UInt16 {
    var remainder = remainder

    for byte in stride(from: 0, to: nBytes, by: 1) {

        remainder ^= UInt16(data_order(message[byte]) << 8)
        var bit = 8
        while bit > 0 {
            if (remainder & 0x8000) != 0 {
                remainder = (remainder << 1) ^ 0x1021
            } else {
                remainder = (remainder << 1)
            }
            bit -= 1
        }
    }

    return remainder_order(remainder)
}


func crc16ccitt(message: UnsafePointer<UInt8>, nBytes: Int) -> UInt16 {

    return crc16(message: message, nBytes: nBytes, data_order: straight_8, remainder_order: straight_16, remainder: 0xffff, polynomial: 0x1021)

}

func crc16ccitt_xmodem(message: UnsafeMutablePointer<UInt8>, nBytes: Int) -> UInt16 {
    return crc16(message: message, nBytes: nBytes, data_order: straight_8, remainder_order: straight_16, remainder: 0x0000, polynomial: 0x1021)
}

func crc16ccitt_kermit(message: UnsafeMutablePointer<UInt8>, nBytes: Int) -> UInt16 {
    let swap = crc16(message: message, nBytes: nBytes, data_order: reverse_8, remainder_order: reverse_16, remainder: 0x0000, polynomial: 0x1021)
    return swap << 8 | swap >> 8
}

func crc16ccitt_1d0f(message: UnsafeMutablePointer<UInt8>, nBytes: Int) -> UInt16 {
    return crc16(message: message, nBytes: nBytes, data_order: straight_8, remainder_order: straight_16, remainder: 0x1d0f, polynomial: 0x1021)
}

func crc16ibm(message: UnsafeMutablePointer<UInt8>, nBytes: Int) -> UInt16 {
    return crc16(message: message, nBytes: nBytes, data_order: reverse_8, remainder_order: reverse_16, remainder: 0x0000, polynomial: 0x8005)
}

}

我设置固定数据类型

 let tData = Data.init(bytes: [0x05, 0x02, 0x03] as [UInt8], count: 3)

    let crcString = String.init(format: "CRC error, calculated: %04X", tData.crc16Check())
    print(crcString)

//打印出CC9C

CC9C 不正确。

答案应该是:716D

似乎无法在 crc16 ccitt 计算中找到错误。有人可以帮助发现问题,因为我真的不确定哪里错了。花了太长时间试图弄清楚。感谢社区的任何帮助。谢谢。

错误是这里操作顺序错误:

remainder ^= UInt16(data_order(message[byte]) << 8)

8 位值 data_order(message[byte]) 向左移动 8 位 - 结果始终为零。应该是

remainder ^= UInt16(data_order(message[byte])) << 8

以便将数字转换为 16 位值然后将其左移。

在类似的 C 程序中可能不会出现该问题,其中所有整数操作数在进行计算之前都被提升为 int – 这种隐式类型转换不会在 Swift.[=26 中完成=]

另一个错误是您的 func crc16() 使用固定多项式 0x1021 而不是 polynomial 参数。这会导致 crc16ibm 校验和的错误结果。

另请注意,不需要在 crc16Check() 中转换为 NSData。该方法可以简化为

func crc16Check() -> UInt16 {
    return self.withUnsafeBytes { [length = self.count] in
        crc16ccitt(message: [=12=], nBytes: length)
    }
}

甚至更好:让所有方法都在 self 上进行运算,而不是传递 Unsafe(Mutable)Pointer 和周围的长度:

extension Data {
    
    typealias bit_order_16 = (_ value: UInt16) -> UInt16
    typealias bit_order_8 = (_ value: UInt8) -> UInt8
    
    func straight_16(value: UInt16) -> UInt16 {
        return value
    }
    
    func reverse_16(value: UInt16) -> UInt16 {
        var value = value
        var reversed: UInt16 = 0
        for _ in 0..<16 {
            reversed <<= 1
            reversed |= (value & 0x1)
            value >>= 1
        }
        return reversed
    }
    
    func straight_8(value: UInt8) -> UInt8 {
        return value
    }
    
    func reverse_8(value: UInt8) -> UInt8 {
        var value = value
        var reversed: UInt8 = 0
        for _ in 0..<8 {
            reversed <<= 1
            reversed |= (value & 0x1)
            value >>= 1
        }
        return reversed
    }
    
    func crc16(data_order: bit_order_8, remainder_order: bit_order_16, remainder: UInt16, polynomial: UInt16) -> UInt16 {
        var remainder = remainder
        
        for byte in self {
            remainder ^= UInt16(data_order(byte)) << 8
            for _ in 0..<8 {
                if (remainder & 0x8000) != 0 {
                    remainder = (remainder << 1) ^ polynomial
                } else {
                    remainder = (remainder << 1)
                }
            }
        }
        return remainder_order(remainder)
    }
    
    func crc16ccitt() -> UInt16 {
        return crc16(data_order: straight_8, remainder_order: straight_16, remainder: 0xffff, polynomial: 0x1021)
    }
    
    func crc16ccitt_xmodem() -> UInt16 {
        return crc16(data_order: straight_8, remainder_order: straight_16, remainder: 0x0000, polynomial: 0x1021)
    }
    
    func crc16ccitt_kermit() -> UInt16 {
        let swap = crc16(data_order: reverse_8, remainder_order: reverse_16, remainder: 0x0000, polynomial: 0x1021)
        return swap.byteSwapped
    }
    
    func crc16ccitt_1d0f() -> UInt16 {
        return crc16(data_order: straight_8, remainder_order: straight_16, remainder: 0x1d0f, polynomial: 0x1021)
    }
    
    func crc16ibm() -> UInt16 {
        return crc16(data_order: reverse_8, remainder_order: reverse_16, remainder: 0x0000, polynomial: 0x8005)
    }
}

用法示例(针对 Swift 4+ 更新了代码):

let tData = Data([0x05, 0x02, 0x03])
print(String(format: "crc16ccitt:        %04X", tData.crc16ccitt()))        // 716D
print(String(format: "crc16ccitt_xmodem: %04X", tData.crc16ccitt_xmodem())) // BDF1
print(String(format: "crc16ccitt_kermit: %04X", tData.crc16ccitt_kermit())) // 9638
print(String(format: "crc16ccitt_1d0f:   %04X", tData.crc16ccitt_1d0f()))   // ACFD
print(String(format: "crc16ibm:          %04X", tData.crc16ibm()))          // 6051

这些数字与 Online CRC calculator.

的结果一致