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