#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <time.h>
#include <unistd.h>
#include "cwiid_internal.h"
#define READ_BUF_LEN 23
void *router_thread(struct wiimote *wiimote)
{
unsigned char buf[READ_BUF_LEN];
ssize_t len;
struct mesg_array ma;
char err, print_clock_err = 1;
while (1) {
len = read(wiimote->int_socket, buf, READ_BUF_LEN);
ma.count = 0;
if (clock_gettime(CLOCK_REALTIME, &ma.timestamp)) {
if (print_clock_err) {
cwiid_err(wiimote, "clock_gettime error");
print_clock_err = 0;
}
}
err = 0;
if ((len == -1) || (len == 0)) {
process_error(wiimote, len, &ma);
write_mesg_array(wiimote, &ma);
break;
}
else {
if (buf[0] != (BT_TRANS_DATA | BT_PARAM_INPUT)) {
cwiid_err(wiimote, "Invalid packet type");
}
switch (buf[1]) {
case RPT_STATUS:
err = process_status(wiimote, &buf[2], &ma);
break;
case RPT_BTN:
err = process_btn(wiimote, &buf[2], &ma);
break;
case RPT_BTN_ACC:
err = process_btn(wiimote, &buf[2], &ma) ||
process_acc(wiimote, &buf[4], &ma);
break;
case RPT_BTN_EXT8:
err = process_btn(wiimote, &buf[2], &ma) ||
process_ext(wiimote, &buf[4], 8, &ma);
break;
case RPT_BTN_ACC_IR12:
err = process_btn(wiimote, &buf[2], &ma) ||
process_acc(wiimote, &buf[4], &ma) ||
process_ir12(wiimote, &buf[7], &ma);
break;
case RPT_BTN_EXT19:
err = process_btn(wiimote, &buf[2], &ma) ||
process_ext(wiimote, &buf[4], 19, &ma);
break;
case RPT_BTN_ACC_EXT16:
err = process_btn(wiimote, &buf[2], &ma) ||
process_acc(wiimote, &buf[4], &ma) ||
process_ext(wiimote, &buf[7], 16, &ma);
break;
case RPT_BTN_IR10_EXT9:
err = process_btn(wiimote, &buf[2], &ma) ||
process_ir10(wiimote, &buf[4], &ma) ||
process_ext(wiimote, &buf[14], 9, &ma);
break;
case RPT_BTN_ACC_IR10_EXT6:
err = process_btn(wiimote, &buf[2], &ma) ||
process_acc(wiimote, &buf[4], &ma) ||
process_ir10(wiimote, &buf[7], &ma) ||
process_ext(wiimote, &buf[17], 6, &ma);
break;
case RPT_EXT21:
err = process_ext(wiimote, &buf[2], 21, &ma);
break;
case RPT_BTN_ACC_IR36_1:
case RPT_BTN_ACC_IR36_2:
cwiid_err(wiimote, "Unsupported report type received "
"(interleaved data)");
err = 1;
break;
case RPT_READ_DATA:
err = process_read(wiimote, &buf[4]) ||
process_btn(wiimote, &buf[2], &ma);
break;
case RPT_WRITE_ACK:
err = process_write(wiimote, &buf[2]);
break;
default:
cwiid_err(wiimote, "Unknown message type");
err = 1;
break;
}
if (!err && (ma.count > 0)) {
if (update_state(wiimote, &ma)) {
cwiid_err(wiimote, "State update error");
}
if (wiimote->flags & CWIID_FLAG_MESG_IFC) {
write_mesg_array(wiimote, &ma);
}
}
}
}
return NULL;
}
void *status_thread(struct wiimote *wiimote)
{
struct mesg_array ma;
struct cwiid_status_mesg *status_mesg;
unsigned char buf[2];
ma.count = 1;
status_mesg = &ma.array[0].status_mesg;
while (1) {
if (full_read(wiimote->status_pipe[0], status_mesg,
sizeof *status_mesg)) {
cwiid_err(wiimote, "Pipe read error (status)");
break;
}
if (status_mesg->type != CWIID_MESG_STATUS) {
cwiid_err(wiimote, "Bad message on status pipe");
continue;
}
if (status_mesg->ext_type == CWIID_EXT_UNKNOWN) {
if (cwiid_read(wiimote, CWIID_RW_REG, 0xA400FE, 2, &buf)) {
cwiid_err(wiimote, "Read error (extension error)");
status_mesg->ext_type = CWIID_EXT_UNKNOWN;
}
switch ((buf[0] << 8) | buf[1]) {
case EXT_NONE:
status_mesg->ext_type = CWIID_EXT_NONE;
break;
case EXT_NUNCHUK:
status_mesg->ext_type = CWIID_EXT_NUNCHUK;
break;
case EXT_CLASSIC:
status_mesg->ext_type = CWIID_EXT_CLASSIC;
break;
case EXT_BALANCE:
status_mesg->ext_type = CWIID_EXT_BALANCE;
break;
case EXT_MOTIONPLUS:
status_mesg->ext_type = CWIID_EXT_MOTIONPLUS;
break;
case EXT_PARTIAL:
buf[0] = 0x55;
buf[1] = 0x00;
if (cwiid_write(wiimote, CWIID_RW_REG, 0xA400F0, 1, &buf[0])) {
cwiid_err(wiimote, "Extension initialization error");
status_mesg->ext_type = CWIID_EXT_UNKNOWN;
}
else if (cwiid_write(wiimote, CWIID_RW_REG, 0xA400FB, 1, &buf[1])) {
cwiid_err(wiimote, "Extension initialization error");
status_mesg->ext_type = CWIID_EXT_UNKNOWN;
}
else if (cwiid_read(wiimote, CWIID_RW_REG, 0xA400FE, 2, &buf)) {
cwiid_err(wiimote, "Read error (extension error)");
status_mesg->ext_type = CWIID_EXT_UNKNOWN;
}
else {
switch ((buf[0] << 8) | buf[1]) {
case EXT_NONE:
case EXT_PARTIAL:
status_mesg->ext_type = CWIID_EXT_NONE;
break;
case EXT_NUNCHUK:
status_mesg->ext_type = CWIID_EXT_NUNCHUK;
break;
case EXT_CLASSIC:
status_mesg->ext_type = CWIID_EXT_CLASSIC;
break;
case EXT_BALANCE:
status_mesg->ext_type = CWIID_EXT_BALANCE;
break;
default:
status_mesg->ext_type = CWIID_EXT_UNKNOWN;
break;
}
}
break;
}
}
if (update_state(wiimote, &ma)) {
cwiid_err(wiimote, "State update error");
}
if (update_rpt_mode(wiimote, -1)) {
cwiid_err(wiimote, "Error reseting report mode");
}
if ((wiimote->state.rpt_mode & CWIID_RPT_STATUS) &&
(wiimote->flags & CWIID_FLAG_MESG_IFC)) {
if (write_mesg_array(wiimote, &ma)) {
}
}
}
return NULL;
}
void *mesg_callback_thread(struct wiimote *wiimote)
{
int mesg_pipe = wiimote->mesg_pipe[0];
cwiid_mesg_callback_t *callback = wiimote->mesg_callback;
struct mesg_array ma;
int cancelstate;
while (1) {
if (read_mesg_array(mesg_pipe, &ma)) {
cwiid_err(wiimote, "Mesg pipe read error");
continue;
}
if (pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancelstate)) {
cwiid_err(wiimote, "Cancel state disable error (callback thread)");
}
callback(wiimote, ma.count, ma.array, &ma.timestamp);
if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &cancelstate)) {
cwiid_err(wiimote, "Cancel state restore error (callback thread)");
}
}
return NULL;
}