我正在尝试从iOS上的蓝牙4.0 LE刻度读取值。如何将作为 NSData 接收的蓝牙特性测量值转换为专用的Swift对象?
作为一个规范,我知道......
位0到位12 →重量(0到5000 g)
位15 →正/负重量值
func peripheral(peripheral: CBPeripheral!, didUpdateValueForCharacteristic characteristic: CBCharacteristic!, error: NSError!) {
let value:NSData = characteristic.value
let weight:Double = … ?
let negative:Bool = … ?
另一条信息 - 查看
value.length
看起来我总是从设备获得1或2个字节(?)的数据。但是我仍然不确定如何提取我想要的数据/值。我很感激任何建议。
到目前为止,这是有点的作用......
var bin16:UInt16 = 0
characteristic.value.getBytes(&bin16, range: NSRange(location: 0,length: 1))
println("Bytes \(characteristic.value.bytes) Length \(characteristic.value.length)")
println("Value \(bin16)")
- 这样做我设法得到一些体重读数。除非值大于255或负值,否则它似乎有效。以下是一些例子:
75克
字节0x1655e458长度1 价值75
367克
字节0x1765cbc8长度2 价值161
-6克
字节0x17670f18长度2 价值32
此间更频繁地传播 - 在这种情况下,它不代表160克。可能是某种错误代码?!
字节0x146528b8长度2 价值160
答案 0 :(得分:6)
看起来有两个问题。
从NSData中提取Swift数据类型
查看上面的问题,您的数据是16位二进制字符串。因此,我们的第一个任务是将16位二进制字符串提取为数据类型。我认为UInt16
是最好的。
func peripheral(peripheral: CBPeripheral!, didUpdateValueForCharacteristic characteristic: CBCharacteristic!, error: NSError!) {
var bin16:UInt16 = 0
var wrapin: NSNumber = NSNumber(unsignedShort: 0)
characteristic.value.getBytes(&wrapin, range: NSRange(location: 0,length: 2))
bin16 = wrapin.unsignedShortValue
从二进制字符串中提取数据
此时bin16
有一个16位二进制字符串。根据您的描述,重量数据存储在0-12位,符号位是第16位。下面是一个如何使用按位运算符&提取数据的示例。和>>。在Swift中查看有关二元运算符的更多语言指南。
// The actual data
let value : UInt16 = 0b0010_1010_0000_0000 // 2560g & positive sign
let weight : uint16 = value & 0b0001_1111_1111_1111 // Extract weight
let sign : UInt16 = value >> 15 // Posative or negative
请注意,我做了以下假设:
更新 - 包含游乐场内容
// Important Note: Reading & Writing to NSData using the native UInt16 does
// not work correctly. Something happens and it mangles the data. To get
// around this in xcode beta 5 you must wrap your data in an NSNumber.
import UIKit
// Build an NSData type
// Bit 0 through 12 --> Weight in g
// Bit 13 & 14 --> not read or used in example (discarded)
// Bit 15 --> Sign-bit
// The value below:
// Weight: (bit 0-12) : 2560G
// Sign: Positive
let rawvalue : UInt16 = 0b0010_1010_0000_0000
// Build NSData payload
var wrapout : NSNumber = NSNumber(unsignedShort: rawvalue)
var payload : NSData = NSData(bytes: &wrapout, length: 2)
// Extracting data
var finalWeight = 0
if payload.length >= 2 {
var wrapin : NSNumber = NSNumber(unsignedShort: 0)
var bstring : UInt16 = 0
payload.getBytes(&wrapin, range: NSRange(location: 0, length: 2))
bstring = wrapin.unsignedShortValue
let weight : UInt16 = bstring & 0b0001_1111_1111_1111
let valsign: UInt16 = (bstring & 0b1000_0000_0000_0000) >> 15
if valsign == 0 {
finalWeight = Int(weight)
} else {
finalWeight = -1 * Int(weight)
}
}
println("\(finalWeight)")
答案 1 :(得分:2)
需要有关收到的数据的更多信息。假设两个字节是b0,b1和b0是前导字节(接收到第一个字节)。 1.哪个字节有符号位。 2.符号位是最右位(0x01)的最左位(0x80)。
这是一个基于假定字节,位编号顺序和字节序的潜在解决方案:
// let value:NSData = characteristic.value
// println("value: \(value)")
let value16 = UnsafePointer<UInt16>(value.bytes)[0]
//value16 = value16.bigEndian // if value is bigendian uncomment, change let to var
println("value16: 0x\(String(value16, radix:16))")
let negative:Bool = (value16 & 0x0001) == 0 // Possibly the sign is a different bit
let weightInt = (value16 >> 4) & 0x0fff // Possibly a different shift is needed
let weight:Double = Double(weightInt)