从Swift中的蓝牙读取中提取并转换NSData值

时间:2014-08-06 13:45:10

标签: ios bluetooth swift nsdata core-bluetooth

我正在尝试从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

2 个答案:

答案 0 :(得分:6)

看起来有两个问题。

  1. 如何将二进制数据从NSData提取为快速数据类型
  2. 如何从二进制字符串中提取有用数据
  3. 从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
    

    请注意,我做了以下假设:

    1. 您的二进制字符串是LSB
    2. 您的二进制字符串只有16位长。如果情况并非如此,那么你应该使用&运算符而不是>>提取标志。
    3. 更新 - 包含游乐场内容

      // 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)