crc-16 cccitt问题-计算错误

时间:2019-02-13 20:53:28

标签: swift crc16

尝试在我的蓝牙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计算中找到错误。有人可以帮忙找出问题,因为我真的不确定哪里出问题了。花了太长时间试图弄清楚。随时感谢社区的帮助。谢谢。

1 个答案:

答案 0 :(得分:1)

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

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

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

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

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

在类似的C程序中可能不会发生该问题,在该程序中,所有整数操作数在进行计算之前都被提升为int –此类隐式类型转换未在Swift中完成。

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

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

func crc16Check() -> UInt16 {
    return self.withUnsafeBytes { [length = self.count] in
        crc16ccitt(message: $0, 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)
    }
}

用法示例:

let tData = Data(bytes: [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的结果相符。