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

我相信我需要写入一个 5 字节值,如图所示:

alt text

这是我现在写入数据的方法:

- (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. 在我努力学习这里的任何帮助都将不胜感激!
有帮助吗?

解决方案

如果您要经常使用 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 通道,以便您实际上通过它发送命令帧并从中接收命令帧。祝你好运!与硬件交互会很有趣,而且您会学到很多东西。

其他提示

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

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top