我正在开展bluetooth iOS
项目,并设法从bluetooth
设备获取一些数据。
但是,我正在努力将这些数据转换为有用的数据,例如NSString
。每当我尝试NSLog
从收到的NSString
转换的NSData
时,它就是一堆gibberish
。输出是:
ēဥ၆䄀
蓝牙设备是来自亚洲制造商的心脏监测器,他们提供了有关如何拨打设备的协议参考。他们在协议参考中提到了这一点:
The PC send 16-byte packets to the device, then the device sent back the 16-byte packets. Except for some special commands, all others can use this communication mode.
谁能告诉我我做错了什么?我尝试了所有我知道的内容,包括Apple文档中的每个编码以及initWithData
和initWithBytes
。谢谢!
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic
error:(NSError *)error {
if (error)
{
NSLog(@"erorr in read is %@", error.description);
return;
}
NSData *data= characteristic.value;
NSString *myString = [[NSString alloc] initWithBytes:[data bytes] length:[data length] encoding:NSUTF16StringEncoding];
NSLog(@"Value from device is %@", myString); //OUTPUT IS ēဥ၆䄀
}
答案 0 :(得分:3)
这里有一个原始数据的字符串,不能直接转换为人类可读的字符串 - 除非您认为十六进制表示是人类可读的:)
要了解这些数据,您需要手头有一个协议规范,或者准备数小时(有时)反向工程。
这个字节序列可以由标准格式(浮点IEEE 754,uint8_t
,uint16_t
...)甚至专有格式的多个值组成。
与外部世界通信时要考虑的一件重要事情也是endianness(即:多字节格式的“最大”字节是第一个还是最后一个)。
有很多方法可以操纵这些数据。要获得原始的字节数组,您可以这样做:
NSData *rxData = ...
uint8_t *bytes = (uint8_t *)[rxData bytes];
然后如果(例如)第一个字节告诉你字符串保持什么类型的有效负载,你可以切换如下:
switch (bytes[0])
{
case 0x00:
//first byte 0x00: do the parsing
break;
case 0x01:
//first byte 0x01: do the parsing
break;
// ...
default:
break;
}
以下是解析包含以下内容的数据的示例:
字节0:保存一些位编码标志的字节 字节1,2,3,4:32位浮点数 字节5,6:uint16_t
bool bitFlag0;
bool bitFlag1;
bool bitFlag2;
bool bitFlag3;
uint8_t firstByte;
float theFloat;
uint16_t theInteger;
NSData *rxData = ...
uint8_t *bytes = (uint8_t *)[rxData bytes];
// getting the flags
firstByte = bytes[0];
bitFlag0 = firstByte & 0x01;
bitFlag1 = firstByte & 0x02;
bitFlag2 = firstByte & 0x04;
bitFlag3 = firstByte & 0x08;
//getting the float
[[rxData subdataWithRange:NSMakeRange(1, 4)] getBytes:&theFloat length:sizeof(float)];
NSLog (@"the float is &.2f",theFloat);
//getting the unsigned integer
[[data subdataWithRange:NSMakeRange(6, 2)] getBytes:&theInteger length:sizeof(uint16_t)];
NSLog (@"the integer is %u",theInteger);
一个注意事项:根据字节顺序,您可能需要在转换它们之前反转4-float或2-uint16_t字节。转换此字节数组也可以使用联合。
union bytesToFloat
{
uint8_t b[4];
float f;
};
然后:
bytesToFloat conv;
//float would be written on bytes b1b2b3b4 in protocol
conv.b[0] = bytes[1]; //or bytes[4] .. endianness!
conv.b[1] = bytes[2]; //or bytes[3] .. endianness!
conv.b[2] = bytes[3]; //or bytes[2] .. endianness!
conv.b[3] = bytes[4]; //or bytes[1] .. endianness!
theFloat = conv.f,
例如,如果您知道byte6和byte7表示uint16_t
值,则可以从原始字节计算它:
value = uint16_t((bytes[6]<<8)+bytes[7]);
或(再次 - 字节顺序):
value = uint16_t((bytes[7]<<8)+bytes[6]);
还有一点需要注意:使用简单sizeof(float)
有点冒险,因为浮点数在一个平台上可以是32位而在另一个平台上可以是64位。