2

我正在使用 IOBluetooth Cocoa 框架与蓝牙设备进行通信。到目前为止,我已经完成了发现设备及其服务、与之配对、连接到它的整个过程,现在我想发送一些实际的命令,但我遇到了一些麻烦。下面是我正在尝试使用的 AVRCP 配置文件规范中的图形。您可以在此处查看 pdf

我相信我需要写一个 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 进行响应。

  1. 我什至不确定我是否正确地处理了这个问题!
  2. 根据图像中的示例,我发送的值是否正确?
  3. 对我在这里学习的任何帮助将不胜感激!
4

2 回答 2

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 中,文档集中的参考文档(而不是编程指南)有点古怪,因此您最好查看标题本身。

您需要查阅比目前更多的文档。您包含的图的 AV/C 命令帧实际上是AVCTP 帧的有效负载(承载在命令/响应消息信息字段中) ,这是您实际上必须通过 L2CAP 传输发送的内容。AVCTP规范在“附录 A,AVCTP 上接口”中勾画了一个基本的 API。

您需要找到或自己编写一个 AVCTP 库才能发送 AV/C 命令帧。您需要让 AVCTP 库包装 L2CAP 通道,以便您实际通过它发送命令帧并从中接收命令帧。祝你好运!与硬件交互会很有趣,而且您会学到很多东西。

于 2009-09-08T04:03:26.833 回答
1

仅仅填写一个字节数组就需要做大量的工作。此外,您正在尝试使用每个 -appendBytes:length: 消息将八个字节添加到 playData 上。

对于这种情况,我只需为您的 BT 命令框架声明一个结构。NSData 在这里并没有真正为您提供太多。

于 2009-09-06T20:42:28.027 回答