I am trying to read values from a Bluetooth 4.0 LE scale on iOS. How do I convert the Bluetooth Characteristics measurements received as NSData to dedicated Swift objects?
我试图在iOS上读取蓝牙4.0 LE规模的值。如何将作为NSData接收的蓝牙特性测量值转换为专用的Swift对象?
As a specification I know that …
作为一个规范我知道......
Bit 0 to Bit 12 → weight (0 to 5000 g)
位0到位12→重量(0到5000 g)
Bit 15 → positive/negative weight value
位15→正/负重量值
func peripheral(peripheral: CBPeripheral!, didUpdateValueForCharacteristic characteristic: CBCharacteristic!, error: NSError!) {
let value:NSData = characteristic.value
let weight:Double = … ?
let negative:Bool = … ?
one more piece of information – looking at
还有一条信息 - 看着
value.length
it looks like I am always getting 1 or 2 bytes (?) of data from the device. However I am still not sure how to extract the data/values I was looking for. I'd appreciate any advice.
看起来我总是从设备获得1或2个字节(?)的数据。但是我仍然不确定如何提取我想要的数据/值。我很感激任何建议。
Here's what works a little bit so far …
到目前为止,这是有效的...
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)")
– Doing this I manage to get some weight reading. It seems to work unless the value is bigger than 255 or negative. Here are some examples:
- 这样做我设法得到一些体重读数。它似乎工作,除非值大于255或负。这里有些例子:
75 grammes
Bytes 0x1655e458 Length 1 Value 75
字节数0x1655e458长度1值75
367 grammes
Bytes 0x1765cbc8 Length 2 Value 161
字节数0x1765cbc8长度2值161
-6 grammes
Bytes 0x17670f18 Length 2 Value 32
字节数0x17670f18长度2值32
Also this gets transmitted more often in between – it doesn't stand for 160 gramme in this case. Maybe some sort of error code?!
此外,这种情况在两者之间更频繁地传播 - 在这种情况下,它不代表160克。也许是某种错误代码?!
Bytes 0x146528b8 Length 2 Value 160
字节数0x146528b8长度2值160
2 个解决方案
#1
6
Looks like there are two questions.
看起来有两个问题。
- How to extract the binary data from NSData into a swift data type
- How to extract the useful data from the binary string
如何将NSData中的二进制数据提取为快速数据类型
如何从二进制字符串中提取有用的数据
Extracting Swift data types from NSData
从NSData中提取Swift数据类型
Looking at the question above your data is in a 16-bit binary string. Therefore, our first task is to extract the 16-bit binary string into a datatype. I think UInt16
is best for this.
查看上面的问题,您的数据采用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
Extracting data from the binary string
从二进制字符串中提取数据
At this point bin16
has a 16-bit binary string. Based on your description the weight data is stored in bites 0-12 and the sign bit is the 16th bit. Below is an example of how you would extract this data using bitwise operators & and >>. Check out the swift language guid for more on binary operators in Swift.
此时,bin16具有16位二进制字符串。根据您的描述,重量数据存储在0-12位,符号位是第16位。下面是如何使用按位运算符&和>>提取此数据的示例。在Swift中查看关于二元运算符的更多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
Please note that I made the following assumptions:
请注意,我做了以下假设:
- Your binary string is LSB
- Your binary string is only 16-bits long. If this is not the case then you should maybe use an & operator instead of the >> to extract the sign.
你的二进制字符串是LSB
您的二进制字符串只有16位长。如果不是这种情况,那么您应该使用&运算符而不是>>来提取符号。
Update - Include playground content
更新 - 包括游乐场内容
// 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)")
#2
2
More information is needed about the received data. Assuming that the two bytes are b0 and b1 and b0 the lead byte (first byte received). 1. Which byte has the sign bit. 2. Is the sign bit the left most bit (0x80) of the most right bit (0x01).
需要有关接收数据的更多信息。假设两个字节是b0,b1和b0是前导字节(接收的第一个字节)。 1.哪个字节有符号位。 2.符号位是最右位(0x01)的最左位(0x80)。
Here is a potential solution based on assumed byte, bit numbering order and endian-ness:
这是一个基于假设字节,位编号顺序和字节序的潜在解决方案:
// 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)
#1
6
Looks like there are two questions.
看起来有两个问题。
- How to extract the binary data from NSData into a swift data type
- How to extract the useful data from the binary string
如何将NSData中的二进制数据提取为快速数据类型
如何从二进制字符串中提取有用的数据
Extracting Swift data types from NSData
从NSData中提取Swift数据类型
Looking at the question above your data is in a 16-bit binary string. Therefore, our first task is to extract the 16-bit binary string into a datatype. I think UInt16
is best for this.
查看上面的问题,您的数据采用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
Extracting data from the binary string
从二进制字符串中提取数据
At this point bin16
has a 16-bit binary string. Based on your description the weight data is stored in bites 0-12 and the sign bit is the 16th bit. Below is an example of how you would extract this data using bitwise operators & and >>. Check out the swift language guid for more on binary operators in Swift.
此时,bin16具有16位二进制字符串。根据您的描述,重量数据存储在0-12位,符号位是第16位。下面是如何使用按位运算符&和>>提取此数据的示例。在Swift中查看关于二元运算符的更多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
Please note that I made the following assumptions:
请注意,我做了以下假设:
- Your binary string is LSB
- Your binary string is only 16-bits long. If this is not the case then you should maybe use an & operator instead of the >> to extract the sign.
你的二进制字符串是LSB
您的二进制字符串只有16位长。如果不是这种情况,那么您应该使用&运算符而不是>>来提取符号。
Update - Include playground content
更新 - 包括游乐场内容
// 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)")
#2
2
More information is needed about the received data. Assuming that the two bytes are b0 and b1 and b0 the lead byte (first byte received). 1. Which byte has the sign bit. 2. Is the sign bit the left most bit (0x80) of the most right bit (0x01).
需要有关接收数据的更多信息。假设两个字节是b0,b1和b0是前导字节(接收的第一个字节)。 1.哪个字节有符号位。 2.符号位是最右位(0x01)的最左位(0x80)。
Here is a potential solution based on assumed byte, bit numbering order and endian-ness:
这是一个基于假设字节,位编号顺序和字节序的潜在解决方案:
// 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)