Pregunta

Estoy usando el marco IOBluetooth cacao para comunicarse con un dispositivo Bluetooth. Hasta ahora he conseguido abajo todo el proceso de descubrir el dispositivo y sus servicios, el vínculo con ella, conectando a ella y ahora quieren enviar algunos comandos reales, pero estoy teniendo algunos problemas con él. A continuación se muestra un gráfico de la especificación para el perfil AVRCP que estoy tratando de usar. Puede ver el pdf aquí .

Creo que necesito para escribir un valor de 5 bytes, como se muestra por la imagen:

text alt

Este es el método que tengo ahora que escribe los datos:

- (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];
}

Cuando esa función ejecuta las responde dispositivos con el siguiente valor hexadecimal 0x400010.

  1. Ni siquiera estoy seguro de que estoy acercarse esto correctamente!
  2. ¿Los valores que soy envío correcta según el ejemplo, en la imagen?
  3. Cualquier ayuda en mi esforzarse por aprender aquí sería mucho apreciado!
¿Fue útil?

Solución

Si usted va a estar trabajando con AV / C enmarca una gran cantidad, en lugar de crear una estructura (que en realidad no ayuda con el embalaje bytes parcial), se debe crear una clase AVCFrame que hace que sea fácil establecer estos marcos, comprobaciones de validez de los valores que asigne a él, tiene una descripción de depuración, y se encargará de todos los detalles sucios para usted.

Su código puede entonces tener este aspecto:

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];

Esto no es la mejor interfaz. Usted querrá leer a través de la AV / C Digital Interface conjunto de especificaciones generales .

En cuanto al embalaje de bytes va (y que tendrá que pasar con el tiempo), usted querrá usar algo como:

// 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];
}

Para más detalles sobre IOWhatever, vistazo a la extensa documentación IOKit. Por lo menos en 10.5, los documentos de referencia (en contraposición a las guías de programación) en la docset eran un poco chiflado, por lo que va a hacer bien en mirar a los propios encabezados.

Usted necesitará consultar más documentación que usted ha visto hasta ahora. El / trama de instrucción AV C cuyo diagrama que ha incluido es en realidad la carga útil (transmitidas en el campo Comando / Información Mensaje de respuesta) de un marco AVCTP , que es lo que realmente tiene que enviar a través de la L2CAP transporte. El AVCTP especificación bocetos una API rudimentaria en el "Anexo a, AVCTP superior Interface".

Usted tendrá que localizar ya sea a sí mismo o escribir una biblioteca AVCTP el fin de enviar las tramas de instrucción AV / C. Usted querrá tener la biblioteca AVCTP envolver el canal L2CAP, por lo que en realidad se envía sus tramas de instrucción a través de ella y recibe sus tramas de instrucción de ella. ¡Buena suerte! Interfaz con el hardware puede ser un montón de diversión, y que va a aprender mucho.

Otros consejos

Eso es un montón de trabajo sólo para llenar una matriz de bytes. Además, usted está tratando de tachuela ocho bytes en playData con cada uno de sus -appendBytes: longitud:. Mensajes

En una situación como esta, que acababa de declarar una estructura para su trama de instrucción BT. NSData en realidad no le ofrece mucho aquí.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top