我试图将Objective C方法转换为Swift,但为了做到这一点,我需要一些帮助来理解正在发生的事情。
对于上下文,此方法的输入以NSString
开头,然后使用utf8编码转换为NSData
对象。然后将此数据对象的字节传递给方法(message
参数)。
然后,此方法的返回值通过writeData
发送到CBPeripheral
的某个特征。
这是我理解的内容(从Swift的角度来看)。
UInt8
字节数组:[UInt8]
UInt32
个值; crcVal
,byteVal
和mask
crcVal
设置为UInt32
类型UInt8
字节数组中的每个字节,并执行某种操作以生成并附加到最终用于发送的crcVal
值的最终结果CoreBluetooth对writeData
的{{1}}命令。我对按位运算符不是很扎实,或者为什么下面的方法正在做它正在做的事情,因为没有文档。有人可以帮助清理这部分的任何或所有部分吗?我希望写一个Swift等效版本的方法。谢谢。
CBPeripheral
答案 0 :(得分:4)
不是从头开始编写实现,为什么不使用crc32
的zlib实现?:
import zlib
func crc32(from data: Data) -> UInt {
return data.withUnsafeBytes { (buffer: UnsafePointer<Bytef>) -> UInt in
return zlib.crc32(0, buffer, uInt(data.count))
}
}
但是,为了帮助您理解按位操作:
func computeCRC(message: [UInt8]) -> UInt32 {
var crc: UInt32 = 0xFFFFFFFF
for byte in message {
crc ^= UInt32(byte)
for _ in 0 ..< 8 {
// negation using 2-complement: -x = ~x + 1
// use &+ addition with overflow
let mask = ~(crc & 1) &+ 1
crc = (crc >> 1) ^ (0xEDB88320 & mask)
}
}
return ~crc
}
请注意,我们不需要传递Swift中的字节数。实现具有不同的签名并返回稍微不同的类型,但它们都给出相同的结果。
答案 1 :(得分:1)
对于计算CRC16,您可以使用
import Foundation
extension Data {
enum CRCType {
case MODBUS
case ARC
}
static func crc16(_ data: [UInt8], type: CRCType) -> UInt16? {
if data.isEmpty {
return nil
}
let polynomial: UInt16 = 0xA001 // A001 is the bit reverse of 8005
var accumulator: UInt16
// set the accumulator initial value based on CRC type
if type == .ARC {
accumulator = 0
} else {
// default to MODBUS
accumulator = 0xFFFF
}
// main computation loop
for byte in data {
var tempByte = UInt16(byte)
for _ in 0 ..< 8 {
let temp1 = accumulator & 0x0001
accumulator = accumulator >> 1
let temp2 = tempByte & 0x0001
tempByte = tempByte >> 1
if (temp1 ^ temp2) == 1 {
accumulator = accumulator ^ polynomial
}
}
}
return accumulator
}
}
来源here