提取 4 位与 2 位蓝牙 HEX 数据,为什么相同的方法会导致错误
Extract 4 bits vs 2Bit of Bluetooth HEX Data, why same method results in error
这是来自这个 SO () which an answer has been accepted. I wanna understand more why the difference between what I was using; example below; (which works) when applied to the SO () 的后续问题。
要解码骑行功率数据,前 2 位是标志,用于确定功率计提供的功能。
guard let characteristicData = characteristic.value else { return -1 }
var byteArray = [UInt8](characteristicData)
// This is the output from the Sensor (In Decimal and Hex)
// DEC [35, 0, 25, 0, 96, 44, 0, 33, 229] Hex:{length = 9, bytes = 0x23001900602c0021e5} FirstByte:100011
/// First 2 Bits is Flags
let flags = byteArray[1]<<8 + byteArray[0]
这导致 flags
位与前 2 位连接。之后我使用 flags
位并将其屏蔽以获得相关位位置。
例如:为了获得权力平衡,我 (flags & 0x01 > 0)
这个方法有效,我是一个快乐的露营者。
但是,为什么当我在 SO 上使用同样的方法时它不起作用?这是解码蓝牙 FTMS 数据(与上面不同)
guard let characteristicData = characteristic.value else { return -1 }
let byteArray = [UInt8](characteristicData)
let nsdataStr = NSData.init(data: (characteristic.value)!)
print("pwrFTMS 2ACC Feature Array:[\(byteArray.count)]\(byteArray) Hex:\(nsdataStr)")
PwrFTMS 2ACC Feature Array:[8][2, 64, 0, 0, 8, 32, 0, 0] Hex:{length = 8, bytes = 0x0240000008200000}
根据规范,返回的数据有 2 个特征,每个特征长 4 个八位字节。
正在做
byteArray[3]<<24 + byteArray[2]<<16 + byteArray[1]<<8 + byteArray[0]
加入前 4 个字节会导致错误输出以开始解码。
编辑:添加了说明
您说有效的代码有问题...但它似乎“意外”有效:
let flags = byteArray[1]<<8 + byteArray[0]
这导致 UInt8
,但第一个 table 中的标志字段是 16 位。请注意,byteArray[1] << 8
始终计算为 0
,因为您正在将字节的所有位移出字节。它似乎有效,因为您唯一感兴趣的是 byteArray[0]
.
所以你需要先把它转换成16位(或更大),然后再移位:
let flags = (UInt16(byteArray[1]) << 8) + UInt16(byteArray[0])
现在 flags
是 UInt16
类似地,当你做 4 个字节时,你需要它们是 32 位值,然后再移位。所以
let flags = UInt32(byteArray[3]) << 24
+ UInt32(byteArray[2]) << 16
+ UInt32(byteArray[1]) << 8
+ UInt32(byteArray[0])
但由于这只是从小端字节顺序的字节序列中读取 32 位值,并且所有当前的 Apple 设备(以及绝大多数其他现代计算机)都是小端机器,这里是一种更简单的方法:
let flags = byteArray.withUnsafeBytes {
[=13=].bindMemory(to: UInt32.self)[0]
}
总而言之,在这两种情况下,您只在移位加法中保留了字节 0,因为由于将位完全移出字节,其他移位全部评估为 0。碰巧在第一种情况下 byte[0] 包含了你需要的信息。一般来说,需要先将值提升到结果需要的大小,然后再平移。
这是来自这个 SO (
要解码骑行功率数据,前 2 位是标志,用于确定功率计提供的功能。
guard let characteristicData = characteristic.value else { return -1 }
var byteArray = [UInt8](characteristicData)
// This is the output from the Sensor (In Decimal and Hex)
// DEC [35, 0, 25, 0, 96, 44, 0, 33, 229] Hex:{length = 9, bytes = 0x23001900602c0021e5} FirstByte:100011
/// First 2 Bits is Flags
let flags = byteArray[1]<<8 + byteArray[0]
这导致 flags
位与前 2 位连接。之后我使用 flags
位并将其屏蔽以获得相关位位置。
例如:为了获得权力平衡,我 (flags & 0x01 > 0)
这个方法有效,我是一个快乐的露营者。
但是,为什么当我在 SO
guard let characteristicData = characteristic.value else { return -1 }
let byteArray = [UInt8](characteristicData)
let nsdataStr = NSData.init(data: (characteristic.value)!)
print("pwrFTMS 2ACC Feature Array:[\(byteArray.count)]\(byteArray) Hex:\(nsdataStr)")
PwrFTMS 2ACC Feature Array:[8][2, 64, 0, 0, 8, 32, 0, 0] Hex:{length = 8, bytes = 0x0240000008200000}
根据规范,返回的数据有 2 个特征,每个特征长 4 个八位字节。
正在做
byteArray[3]<<24 + byteArray[2]<<16 + byteArray[1]<<8 + byteArray[0]
加入前 4 个字节会导致错误输出以开始解码。
编辑:添加了说明
您说有效的代码有问题...但它似乎“意外”有效:
let flags = byteArray[1]<<8 + byteArray[0]
这导致 UInt8
,但第一个 table 中的标志字段是 16 位。请注意,byteArray[1] << 8
始终计算为 0
,因为您正在将字节的所有位移出字节。它似乎有效,因为您唯一感兴趣的是 byteArray[0]
.
所以你需要先把它转换成16位(或更大),然后再移位:
let flags = (UInt16(byteArray[1]) << 8) + UInt16(byteArray[0])
现在 flags
是 UInt16
类似地,当你做 4 个字节时,你需要它们是 32 位值,然后再移位。所以
let flags = UInt32(byteArray[3]) << 24
+ UInt32(byteArray[2]) << 16
+ UInt32(byteArray[1]) << 8
+ UInt32(byteArray[0])
但由于这只是从小端字节顺序的字节序列中读取 32 位值,并且所有当前的 Apple 设备(以及绝大多数其他现代计算机)都是小端机器,这里是一种更简单的方法:
let flags = byteArray.withUnsafeBytes {
[=13=].bindMemory(to: UInt32.self)[0]
}
总而言之,在这两种情况下,您只在移位加法中保留了字节 0,因为由于将位完全移出字节,其他移位全部评估为 0。碰巧在第一种情况下 byte[0] 包含了你需要的信息。一般来说,需要先将值提升到结果需要的大小,然后再平移。