crc-16 cccitt problem - incorrect calculation

北城以北 提交于 2020-07-09 14:31:50

问题


Trying to implement this CRC16 CITT checksum within my bluetooth ios mobile application:

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)
}

}

I set up a fixed data type of

 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)

//Prints out CC9C

CC9C is incorrect.

The answer should be: 716D

Can't seem to find the error within the crc16 ccitt calculation. Can someone help to please spot the issue, as I'm really not sure where it's wrong. Been spending too long trying to figure it out. Would appreciate any time of help from the community. Thank you.


回答1:


The error is the wrong order of operations here:

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

The 8-bit value data_order(message[byte]) is shifted by 8 bits to the left – the result will always be zero. It should be

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

so that the number is converted to a 16-bit value before shifting it to the left.

That problem might not occur in a similar C program, where all integral operands are promoted to int before doing the calculation – such implicit type conversions are not done in Swift.

Another error is that your func crc16() uses the fixed polynomial 0x1021 instead of the polynomial argument. That causes a wrong result for the crc16ibm checksum.

Note also that the conversion to NSData in crc16Check() is not needed. That method can be simplified to

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

Even better: Make all methods operator on self instead of passing Unsafe(Mutable)Pointers and lengths around:

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)
    }
}

Example usage (code updated for 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

These numbers coincide with the results from this Online CRC calculator.



来源:https://stackoverflow.com/questions/54679243/crc-16-cccitt-problem-incorrect-calculation

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!