我正在使用IOBluetooth Cocoa框架与蓝牙设备进行通信。到目前为止,我已经完成了发现设备及其服务的整个过程,与它配对,连接到它,现在我想发送一些实际的命令,但我遇到了一些麻烦。下面是我正在尝试使用的AVRCP配置文件规范的图形。你可以view the pdf here。
我相信我需要写一个5字节的值,如图所示:
以下是我现在编写数据的方法:
- (void)l2capChannelOpenComplete:(IOBluetoothL2CAPChannel*)l2capChannel status:(IOReturn)error {
NSLog(@"Open Complete");
NSMutableData *playData = [[NSMutableData alloc] initWithCapacity:5];
unsigned char ctype = 0x0;
unsigned char subunit = 0x90;
unsigned char opcode = 0x7C;
unsigned char opid = 0x44;
unsigned char opdata = 0x0;
[playData appendBytes:&ctype length:8];
[playData appendBytes:&subunit length:8];
[playData appendBytes:&opcode length:8];
[playData appendBytes:&opid length:8];
[playData appendBytes:&opdata length:8];
usleep(1000);
[l2capChannel writeAsync:[playData mutableBytes] length:40 refcon:nil];
}
当该函数运行时,设备将使用以下十六进制值0x400010进行响应。
答案 0 :(得分:3)
如果您要使用AV / C帧很多,而不是创建一个结构(这对于部分字节打包不会有帮助),您应该创建一个AVCFrame
类,可以轻松设置这些框架,完整性检查您提供的值,具有调试说明,并将为您处理所有蹩脚的细节。
您的代码可能如下所示:
AVCFrame *frame = [AVCFrame frameWithCommandType:AVCCommandTypePlay
subunitType:mySubunitType
subunitID:mySubunitID];
// You likely won't actually be writing to the L2CAPChannel. See below.
[l2capChannel writeAsync:[frame mutableBytes] length:[frame length] refcon:nil];
这不是最好的界面。您需要阅读 AV / C数字接口命令集通用规范。
就字节打包而言(最终必须发生),你会想要使用类似的东西:
// Returns |subunitType| shifted and masked appropriately for bit_oring
// with subunit ID to create an address octet.
inline UInt8
AVRCAddressSubunitType(UInt8 subunitType) {
const UInt8 kLeastThreeBytes = 0x07;
UInt8 shiftedType = (subunitType << 3) & ~kLeastThreeBytes;
return shiftedType;
}
// Returns |subunitID| masked appropriately for bit_oring with subunit type
// to create an address octet.
inline UInt8
AVRCAddressSubunitID(UInt8 subunitID) {
const UInt8 kLeastThreeBytes = 0x07;
UInt8 maskedID = subunitID & kLeastThreeBytes;
if (subunitID & ~kLeastThreeBytes) {
NSLog(@"*** %s: subunit ID %#hhx > 0x07 cannot be represented "
"in the 3 bits allotted. Truncating to %#hhx.",
__PRETTY_FUNCTION__, subunitID, maskedID);
}
return maskedID;
}
- (void)l2capChannelOpenComplete:(IOBluetoothL2CAPChannel *)l2capChannel
status:(IOReturn)error {
/* might be worth looking at the error... */
NSLog(@"%s: open complete - "
"error: (system: %#x; subsystem: %#x; code: %#x)",
__PRETTY_FUNCTION__,
err_get_system(error), err_get_sub(error), err_get_code(error));
/* to send, first pack your data into byte-sized variables */
// some variables...
// address byte layout is [3:7] = 9 = PANEL; [0:2] = 0 = subunit ID
UInt8 address = (AVRCAddressSubunitType(0x09) | AVRCAddressSubunitID(0x00));
// some more variables...
/* create a mutable data and append the bytes in sequence */
// some appending...
[playData appendBytes:&address length:sizeof(address)];
// more appending...
/* finally, send all the bytes */
[l2capChannel writeAsync:[playData mutableBytes]
length:[playData length]
refcon:NULL];
}
有关IOWhatever
的更多详细信息,请查看详尽的IOKit文档。至少在10.5中,docset中的参考文档(与编程指南相对)有点棘手,所以你最好自己查看标题。
到目前为止,您需要查阅的文档比您查看过的文档多。您所包含的AV / C命令帧实际上是 AVCTP帧的有效负载(在命令/响应消息信息字段中承载),这是您实际必须通过L2CAP发送的内容运输。 AVCTP spec在“附录A,AVCTP上界面”中草拟了一个基本的API。
您需要找到或自己编写AVCTP库才能发送AV / C命令帧。您需要让AVCTP库包装L2CAP通道,以便您实际通过它发送命令帧并从中接收命令帧。祝好运!与硬件接口可以带来很多乐趣,您将学到很多东西。
答案 1 :(得分:1)
为了填充一个字节数组,这是一项非常多的工作。另外,你试图用每个-appendBytes:length:messages来将8个字节写入playData。
对于这样的情况,我只是为你的BT命令框声明一个结构。 NSData在这里并不能为你提供太多帮助。