Implementación

Implementación

La generación de sonido hace uso de una serie de definiciones y tipos que no están disponibles públicamente en la librería CWIID por lo que habrá que copiarlos al código fuente del programa que se escriba:

#define SEQ_LEN(seq) (sizeof(seq)/sizeof(struct write_seq))
#define RPT_SPEAKER_ENABLE 0x14
#define RPT_SPEAKER_DATA 0x18
#define RPT_SPEAKER_MUTE 0x19
#define SOUND_BUF_LEN 21

enum write_seq_type {
     WRITE_SEQ_RPT,
      WRITE_SEQ_MEM
};

struct write_seq {
enum write_seq_type type;
uint32_t report_offset;
const void *data;
uint16_t len;
uint8_t flags;
};

La inicialización del altavoz se realiza mediante el siguiente proceso:

  1. Habilitar el altavoz mediante envío de 0x04 al report 0x14.
  2. Silenciar el altavoz mediante envío de 0x04 al report 0x19.
  3. Escribir 0x01 en el registro 0xa20009.
  4. Escribir 0x08 en el registro 0xa20001.
  5. Escribir la configuración en los registros 0xa20001 a 0xa20008.
  6. Escribir 0x01 en el registro 0xa20008.
  7. Deshacer el 2º paso mediante envío de 0x00 al report 0x19.

Es posible que los pasos 3 y 4 deban omitirse para que el altavoz se inicialice correctamente.

Los 7 bytes de configuración son los siguientes: 00 FF RR RR VV 00 00.

  • FF es el formato de codificación usado, 0x40 para PCM de 8 bits y 0x00 para ADPCM de 4 bits.
  • RR RR indican la frecuencia de muestreo, su valor será 12000000/frecuencia_muestreo para PCM y 6000000/frecuencia_muestreo para ADPCM.
    El primer byte contiene el menos significativo y el segundo el más significativo.
  • VV es el volumen. Su rango va de 0x00 a 0xFF para PCM de 8 bits y de 0x00 a 0x40 para ADPCM de 4 bits.

Una posible secuencia de inicialización sería:

struct write_seq speaker_enable_seq[] = {
{WRITE_SEQ_RPT, RPT_SPEAKER_ENABLE, (const void *)"\x04", 1, 0},
{WRITE_SEQ_RPT, RPT_SPEAKER_MUTE, (const void *)"\x04", 1, 0},
{WRITE_SEQ_MEM, 0xA20009, (const void *)"\x01", 1, CWIID_RW_REG},
{WRITE_SEQ_MEM, 0xA20001, (const void *)"\x08", 1, CWIID_RW_REG},
{WRITE_SEQ_MEM, 0xA20001, (const void *)"\x00\x00\x00\x0e\x10\x00\x00", 7, CWIID_RW_REG},
{WRITE_SEQ_MEM, 0xA20008, (const void *)"\x01", 1, CWIID_RW_REG},
{WRITE_SEQ_RPT, RPT_SPEAKER_MUTE, (const void *)"\x00", 1, 0}
};

Y se enviaría mediante:

if (exec_write_seq(wiimote, SEQ_LEN(speaker_enable_seq), speaker_enable_seq)) {printf("Error al habilitar el altavoz\n");}

Una vez inicializado el altavoz se deben enviar las muestras de sonido al ritmo adecuado mediante:

if (cwiid_send_rpt(wiimote, 0, RPT_SPEAKER_DATA, SOUND_BUF_LEN, buf)) {printf("Error\n");}

Siendo buf el paquete de datos a enviar. Debe ser un array de unsigned char con una longitud mínima de 21 elementos, el primero indicará el número de bits sin tenerse en cuenta a sí mismo, el resto contienen las muestras del sonido a reproducir.

Un ejemplo de paquete de datos:

unsigned char buf[SOUND_BUF_LEN] = { 0xA0, 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33};

Finalizado su uso, el altavoz debe deshabilitarse mediante la siguiente secuencia:

  1. Silenciar el altavoz mediante envío de 0x04 al report 0x19.
  2. Escribir 0x00 en el registro 0xa20009.
  3. Escribir 0x00 en el registro 0xa20001.
  4. Deshabilitar el altavoz mediante envío de 0x00 al report 0x14.

Esta secuencia se traduce en:

struct write_seq speaker_disable_seq[] = {
{WRITE_SEQ_RPT, RPT_SPEAKER_MUTE, (const void *)"\x04", 1, 0},
{WRITE_SEQ_MEM, 0xA20009, (const void *)"\x00", 1, CWIID_RW_REG},
{WRITE_SEQ_MEM, 0xA20001, (const void *)"\x00", 1, CWIID_RW_REG},
{WRITE_SEQ_RPT, RPT_SPEAKER_ENABLE, (const void *)"\x00", 1, 0}
};

Y se envía mediante:

if (exec_write_seq(wiimote, SEQ_LEN(speaker_disable_seq), speaker_disable_seq)) {printf("Error al deshabilitar el altavoz\n");}

 

Obra publicada con Licencia Creative Commons Reconocimiento 3.0