问题
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)Pointer
s 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