Beispiel #1
0
int cwiid_get_mesg(cwiid_wiimote_t *wiimote, int *mesg_count,
                   union cwiid_mesg *mesg[], struct timespec *timestamp)
{
	struct mesg_array ma;

	if (read_mesg_array(wiimote->mesg_pipe[0], &ma)) {
		if (errno == EAGAIN) {
			return -1;
		}
		else {
			cwiid_err(wiimote, "Pipe read error (mesg_pipe)");
			return -1;
		}
	}

	*mesg_count = ma.count;
	*timestamp = ma.timestamp;

	if ((*mesg = malloc(ma.count * sizeof ma.array[0])) == NULL) {
		cwiid_err(wiimote, "Memory allocation error (mesg array)");
		return -1;
	}

	memcpy(*mesg, &ma.array, ma.count * sizeof (*mesg)[0]);

	return 0;
}
Beispiel #2
0
int write_mesg_array(struct wiimote *wiimote, struct mesg_array *ma)
{
	ssize_t len = (void *)&ma->array[ma->count] - (void *)ma;
	int ret = 0;

	/* This must remain a single write operation to ensure atomicity,
	 * which is required to avoid mutexes and cancellation issues */
	if (write(wiimote->mesg_pipe[1], ma, len) != len) {
		if (errno == EAGAIN) {
			cwiid_err(wiimote, "Mesg pipe overflow");
			if (fcntl(wiimote->mesg_pipe[1], F_SETFL, 0)) {
				cwiid_err(wiimote, "File control error (mesg pipe)");
				ret = -1;
			}
			else {
				if (write(wiimote->mesg_pipe[1], ma, len) != len) {
					cwiid_err(wiimote, "Pipe write error (mesg pipe)");
					ret = -1;
				}
				if (fcntl(wiimote->mesg_pipe[1], F_SETFL, O_NONBLOCK)) {
					cwiid_err(wiimote, "File control error (mesg pipe");
				}
			}
		}
		else {
			cwiid_err(wiimote, "Pipe write error (mesg pipe)");
			ret = -1;
		}
	}

	return ret;
}
Beispiel #3
0
int cwiid_send_rpt(cwiid_wiimote_t *wiimote, uint8_t flags, uint8_t report,
                   size_t len, const void *data)
{
    unsigned char buf[32];

    if (len+2 > sizeof(buf)) {
        cwiid_err( wiimote, "cwiid_send_prt: %d bytes over maximum", len+2-sizeof(buf) );
        return -1;
    }

    buf[0] = BT_TRANS_SET_REPORT | BT_PARAM_OUTPUT;
    buf[1] = report;
    if (len > 0) {
        memcpy( &buf[2], data, len );
    }
    if (!(flags & CWIID_SEND_RPT_NO_RUMBLE)) {
        buf[2] |= wiimote->state.rumble;
    }

    if (write(wiimote->ctl_socket, buf, len+2) != (ssize_t)(len+2)) {
        cwiid_err(wiimote, "cwiid_send_rpt: write: %s", strerror(errno));
        return -1;
    }
    else if (verify_handshake(wiimote)) {
        return -1;
    }

    return 0;
}
Beispiel #4
0
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;
		}

		/* TODO: The callback can still be called once after disconnect,
		 * although it's very unlikely.  User must keep track and avoid
		 * accessing the wiimote struct after disconnect. */
		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;
}
Beispiel #5
0
int cwiid_beep(cwiid_wiimote_t *wiimote)
{
    /* 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}; */
    unsigned char buf[SOUND_BUF_LEN] = { 0xA0, 0xC3, 0xC3, 0xC3, 0xC3,
                                         0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3,
                                         0xC3, 0xC3, 0xC3, 0xC3
                                       };
    int i;
    int ret = 0;
    pthread_mutex_t timer_mutex = PTHREAD_MUTEX_INITIALIZER;
    pthread_cond_t timer_cond = PTHREAD_COND_INITIALIZER;
    struct timespec t;

    if (exec_write_seq(wiimote, SEQ_LEN(speaker_enable_seq),
                       speaker_enable_seq)) {
        cwiid_err(wiimote, "Speaker enable error");
        ret = -1;
    }

    pthread_mutex_lock(&timer_mutex);

    for (i=0; i<100; i++) {
        clock_gettime(CLOCK_REALTIME, &t);
        t.tv_nsec += 10204081;
        /* t.tv_nsec += 7000000; */
        if (cwiid_send_rpt(wiimote, 0, RPT_SPEAKER_DATA, SOUND_BUF_LEN, buf)) {
            printf("%d\n", i);
            cwiid_err(wiimote, "Report send error (speaker data)");
            ret = -1;
            break;
        }
        /* TODO: I should be shot for this, but hey, it works.
         * longterm - find a better wait */
        pthread_cond_timedwait(&timer_cond, &timer_mutex, &t);
    }

    pthread_mutex_unlock(&timer_mutex);

    if (exec_write_seq(wiimote, SEQ_LEN(speaker_disable_seq),
                       speaker_disable_seq)) {
        cwiid_err(wiimote, "Speaker disable error");
        ret = -1;
    }

    return ret;
}
Beispiel #6
0
int cwiid_find_wiimote(bdaddr_t *bdaddr, int timeout)
{
	struct cwiid_bdinfo *bdinfo;
	int bdinfo_count;

	if (timeout == -1) {
		while ((bdinfo_count = cwiid_get_bdinfo_array(-1, 2, 1, &bdinfo, 0))
		       == 0);
		if (bdinfo_count == -1) {
			return -1;
		}
	}
	else {
		bdinfo_count = cwiid_get_bdinfo_array(-1, timeout, 1, &bdinfo, 0);
		if (bdinfo_count == -1) {
			return -1;
		}
		else if (bdinfo_count == 0) {
			cwiid_err(NULL, "No wiimotes found");
			return -1;
		}
	}

	bacpy(bdaddr, &bdinfo[0].bdaddr);
	free(bdinfo);
	return 0;
}
Beispiel #7
0
int cancel_mesg_callback(struct wiimote *wiimote)
{
	int ret = 0;

	if (pthread_cancel(wiimote->mesg_callback_thread)) {
		cwiid_err(wiimote, "Thread cancel error (callback thread)");
		ret = -1;
	}

	if (pthread_detach(wiimote->mesg_callback_thread)) {
		cwiid_err(wiimote, "Thread detach error (callback thread)");
		ret = -1;
	}

	return ret;
}
Beispiel #8
0
int process_status(struct wiimote *wiimote, const unsigned char *data,
                   struct mesg_array *ma)
{
	struct cwiid_status_mesg status_mesg;

	(void)ma;

	status_mesg.type = CWIID_MESG_STATUS;
	status_mesg.battery = data[5];
	if (data[2] & 0x02) {
		/* status_thread will figure out what it is */
		status_mesg.ext_type = CWIID_EXT_UNKNOWN;
	}
	else {
		status_mesg.ext_type = CWIID_EXT_NONE;
	}

	if (write(wiimote->status_pipe[1], &status_mesg, sizeof status_mesg)
	  != sizeof status_mesg) {
		cwiid_err(wiimote, "Status pipe write error");
		return -1;
	}

	return 0;
}
Beispiel #9
0
int cwiid_get_state(cwiid_wiimote_t *wiimote, struct cwiid_state *state)
{
	if (pthread_mutex_lock(&wiimote->state_mutex)) {
		cwiid_err(wiimote, "Mutex lock error (state mutex)");
		return -1;
	}

	memcpy(state, &wiimote->state, sizeof *state);

	if (pthread_mutex_unlock(&wiimote->state_mutex)) {
		cwiid_err(wiimote, "Mutex unlock error (state mutex) - "
		                   "deadlock warning");
		return -1;
	}

	return 0;
}
Beispiel #10
0
int verify_handshake(struct wiimote *wiimote)
{
	unsigned char handshake;
	if (read(wiimote->ctl_socket, &handshake, 1) != 1) {
		cwiid_err(wiimote, "Socket read error (handshake)");
		return -1;
	}
	else if ((handshake & BT_TRANS_MASK) != BT_TRANS_HANDSHAKE) {
		cwiid_err(wiimote, "Handshake expected, non-handshake received");
		return -1;
	}
	else if ((handshake & BT_PARAM_MASK) != BT_PARAM_SUCCESSFUL) {
		cwiid_err(wiimote, "Non-successful handshake");
		return -1;
	}

	return 0;
}
Beispiel #11
0
int cwiid_request_status(cwiid_wiimote_t *wiimote)
{
	unsigned char data;

	data = 0;
	if (cwiid_send_rpt(wiimote, 0, RPT_STATUS_REQ, 1, &data)) {
		cwiid_err(wiimote, "Status request error");
		return -1;
	}

	return 0;
}
Beispiel #12
0
int cancel_mesg_callback(struct wiimote *wiimote)
{
	int err;

	err = pthread_cancel(wiimote->mesg_callback_thread);
	if (err) {
		cwiid_err(wiimote, "Thread cancel error (callback thread): %s", strerror(err));
		return -1;
	}

	return 0;
}
Beispiel #13
0
int cancel_rw(struct wiimote *wiimote)
{
	struct rw_mesg rw_mesg;

	rw_mesg.type = RW_CANCEL;

	if (write(wiimote->rw_pipe[1], &rw_mesg, sizeof rw_mesg) !=
	  sizeof rw_mesg) {
		cwiid_err(wiimote, "Pipe write error (rw)");
		return -1;
	}

	return 0;
}
Beispiel #14
0
int cwiid_set_rumble(cwiid_wiimote_t *wiimote, uint8_t rumble)
{
	unsigned char data;

	/* TODO: assumption: char assignments are atomic, no mutex lock needed */
	wiimote->state.rumble = rumble ? 1 : 0;
	data = wiimote->state.led << 4;
	if (cwiid_send_rpt(wiimote, 0, RPT_LED_RUMBLE, 1, &data)) {
		cwiid_err(wiimote, "Report send error (led)");
		return -1;
	}

	return 0;
}
Beispiel #15
0
int cwiid_get_acc_cal(cwiid_wiimote_t *wiimote, enum cwiid_ext_type ext_type,
                      struct acc_cal *acc_cal)
{
	uint8_t flags;
	uint32_t offset;
	unsigned char buf[7];
	char *err_str;

	switch (ext_type) {
	case CWIID_EXT_NONE:
		flags = CWIID_RW_EEPROM;
		offset = 0x16;
		err_str = "";
		break;
	case CWIID_EXT_NUNCHUK:
		flags = CWIID_RW_REG;
		offset = 0xA40020;
		err_str = "nunchuk ";
		break;
	default:
		cwiid_err(wiimote, "Unsupported calibration request");
		return -1;
	}
	if (cwiid_read(wiimote, flags, offset, 7, buf)) {
		cwiid_err(wiimote, "Read error (%scal)", err_str);
		return -1;
	}

	acc_cal->zero[CWIID_X] = buf[0];
	acc_cal->zero[CWIID_Y] = buf[1];
	acc_cal->zero[CWIID_Z] = buf[2];
	acc_cal->one[CWIID_X]  = buf[4];
	acc_cal->one[CWIID_Y]  = buf[5];
	acc_cal->one[CWIID_Z]  = buf[6];

	return 0;
}
Beispiel #16
0
int cwiid_enable(cwiid_wiimote_t *wiimote, int flags)
{
	unsigned char data;

	if ((flags & CWIID_FLAG_NONBLOCK) &&
	  !(wiimote->flags & CWIID_FLAG_NONBLOCK)) {
		if (fcntl(wiimote->mesg_pipe[0], F_SETFL, O_NONBLOCK)) {
			cwiid_err(wiimote, "File control error (mesg pipe)");
			return -1;
		}
	}
	if (flags & CWIID_FLAG_MOTIONPLUS) {
		data = 0x04;
		cwiid_write(wiimote, CWIID_RW_REG, 0xA600FE, 1, &data);
		cwiid_request_status(wiimote);
	}
	wiimote->flags |= flags;
	return 0;
}
Beispiel #17
0
int process_error(struct wiimote *wiimote, ssize_t len, struct mesg_array *ma)
{
	struct cwiid_error_mesg *error_mesg;

	error_mesg = &ma->array[ma->count++].error_mesg;
	error_mesg->type = CWIID_MESG_ERROR;
	if (len == 0) {
		error_mesg->error = CWIID_ERROR_DISCONNECT;
	}
	else {
		error_mesg->error = CWIID_ERROR_COMM;
	}

	if (cancel_rw(wiimote)) {
		cwiid_err(wiimote, "RW cancel error");
	}

	return 0;
}
Beispiel #18
0
/* TODO: fix error reporting - this is public now and
 * should report its own errors */
int cwiid_send_rpt(cwiid_wiimote_t *wiimote, uint8_t flags, uint8_t report,
                   size_t len, const void *data)
{
	unsigned char *buf;

	if ((buf = malloc((len*2) * sizeof *buf)) == NULL) {
		cwiid_err(wiimote, "Memory allocation error (mesg array)");
		return -1;
	}

	if (wiimote->type == WIIMOTE_NEW)
		buf[0] = BT_TRANS_DATA | BT_PARAM_OUTPUT;
	else
		buf[0] = BT_TRANS_SET_REPORT | BT_PARAM_OUTPUT;
	buf[1] = report;
	memcpy(buf+2, data, len);
	if (!(flags & CWIID_SEND_RPT_NO_RUMBLE)) {
		buf[2] |= wiimote->state.rumble;
	}

	// if this is a new version of the wiimote
	if (wiimote->type == WIIMOTE_NEW)
	{
		if (write(wiimote->int_socket, buf, len+2) != (ssize_t)(len+2)) {
			free(buf);
			return -1;
		}
	}
	// otherwise it is WIIMOTE_OLD which also includes Wii Board
	else
	{
		if (write(wiimote->ctl_socket, buf, len+2) != (ssize_t)(len+2)) {
			free(buf);
			return -1;
		}
		else if (verify_handshake(wiimote)) {
			free(buf);
			return -1;
		}
	}

	return 0;
}
Beispiel #19
0
int cwiid_set_mesg_callback(cwiid_wiimote_t *wiimote,
                            cwiid_mesg_callback_t *callback)
{
	if (wiimote->mesg_callback) {
		if (cancel_mesg_callback(wiimote)) {
			/* prints it's own errors */
			return -1;
		}
	}

	wiimote->mesg_callback = callback;

	if (wiimote->mesg_callback) {
		if (pthread_create(&wiimote->mesg_callback_thread, NULL,
		                  (void *(*)(void *))&mesg_callback_thread, wiimote)) {
			cwiid_err(wiimote, "Thread creation error (callback thread)");
			return -1;
		}
	}

	return 0;
}
Beispiel #20
0
int cwiid_get_balance_cal(cwiid_wiimote_t *wiimote,
                          struct balance_cal *balance_cal)
{
	unsigned char buf[24];

	if (cwiid_read(wiimote, CWIID_RW_REG, 0xa40024, 24, buf)) {
		cwiid_err(wiimote, "Read error (balancecal)");
		return -1;
	}
	balance_cal->right_top[0]    = ((uint16_t)buf[0]<<8 | (uint16_t)buf[1]);
	balance_cal->right_bottom[0] = ((uint16_t)buf[2]<<8 | (uint16_t)buf[3]);
	balance_cal->left_top[0]     = ((uint16_t)buf[4]<<8 | (uint16_t)buf[5]);
	balance_cal->left_bottom[0]  = ((uint16_t)buf[6]<<8 | (uint16_t)buf[7]);
	balance_cal->right_top[1]    = ((uint16_t)buf[8]<<8 | (uint16_t)buf[9]);
	balance_cal->right_bottom[1] = ((uint16_t)buf[10]<<8 | (uint16_t)buf[11]);
	balance_cal->left_top[1]     = ((uint16_t)buf[12]<<8 | (uint16_t)buf[13]);
	balance_cal->left_bottom[1]  = ((uint16_t)buf[14]<<8 | (uint16_t)buf[15]);
	balance_cal->right_top[2]    = ((uint16_t)buf[16]<<8 | (uint16_t)buf[17]);
	balance_cal->right_bottom[2] = ((uint16_t)buf[18]<<8 | (uint16_t)buf[19]);
	balance_cal->left_top[2]     = ((uint16_t)buf[20]<<8 | (uint16_t)buf[21]);
	balance_cal->left_bottom[2]  = ((uint16_t)buf[22]<<8 | (uint16_t)buf[23]);

	return 0;
}
Beispiel #21
0
int process_ext(struct wiimote *wiimote, unsigned char *data,
                unsigned char len, struct mesg_array *ma)
{
	struct cwiid_nunchuk_mesg *nunchuk_mesg;
	struct cwiid_classic_mesg *classic_mesg;
	struct cwiid_balance_mesg *balance_mesg;
	struct cwiid_motionplus_mesg *motionplus_mesg;
	int i;

	switch (wiimote->state.ext_type) {
	case CWIID_EXT_NONE:
		cwiid_err(wiimote, "Received unexpected extension report");
		break;
	case CWIID_EXT_UNKNOWN:
		break;
	case CWIID_EXT_NUNCHUK:
		if (wiimote->state.rpt_mode & CWIID_RPT_NUNCHUK) {
			nunchuk_mesg = &ma->array[ma->count++].nunchuk_mesg;
			nunchuk_mesg->type = CWIID_MESG_NUNCHUK;
			nunchuk_mesg->stick[CWIID_X] = data[0];
			nunchuk_mesg->stick[CWIID_Y] = data[1];
			nunchuk_mesg->acc[CWIID_X] = data[2];
			nunchuk_mesg->acc[CWIID_Y] = data[3];
			nunchuk_mesg->acc[CWIID_Z] = data[4];
			nunchuk_mesg->buttons = ~data[5] & NUNCHUK_BTN_MASK;
		}
		break;
	case CWIID_EXT_CLASSIC:
		if (wiimote->state.rpt_mode & CWIID_RPT_CLASSIC) {
			classic_mesg = &ma->array[ma->count++].classic_mesg;
			classic_mesg->type = CWIID_MESG_CLASSIC;

			for (i=0; i < 6; i++) {
				data[i] = data[i];
			}

			classic_mesg->l_stick[CWIID_X] = data[0] & 0x3F;
			classic_mesg->l_stick[CWIID_Y] = data[1] & 0x3F;
			classic_mesg->r_stick[CWIID_X] = (data[0] & 0xC0)>>3 |
			                                 (data[1] & 0xC0)>>5 |
			                                 (data[2] & 0x80)>>7;
			classic_mesg->r_stick[CWIID_Y] = data[2] & 0x1F;
			classic_mesg->l = (data[2] & 0x60)>>2 |
			                  (data[3] & 0xE0)>>5;
			classic_mesg->r = data[3] & 0x1F;
			classic_mesg->buttons = ~((uint16_t)data[4]<<8 |
			                          (uint16_t)data[5]);
		}
		break;
	case CWIID_EXT_BALANCE:
		if (wiimote->state.rpt_mode & CWIID_RPT_BALANCE) {
			balance_mesg = &ma->array[ma->count++].balance_mesg;
			balance_mesg->type = CWIID_MESG_BALANCE;
			balance_mesg->right_top = ((uint16_t)data[0]<<8 |
			                           (uint16_t)data[1]);
			balance_mesg->right_bottom = ((uint16_t)data[2]<<8 |
			                              (uint16_t)data[3]);
			balance_mesg->left_top = ((uint16_t)data[4]<<8 |
			                          (uint16_t)data[5]);
			balance_mesg->left_bottom = ((uint16_t)data[6]<<8 |
			                             (uint16_t)data[7]);
		}
	case CWIID_EXT_MOTIONPLUS:
		if (wiimote->state.rpt_mode & CWIID_RPT_MOTIONPLUS) {
			motionplus_mesg = &ma->array[ma->count++].motionplus_mesg;
			motionplus_mesg->type = CWIID_MESG_MOTIONPLUS;
			motionplus_mesg->angle_rate[CWIID_PHI]   = ((uint16_t)data[5] & 0xFC)<<6 |
			                                            (uint16_t)data[2];
			motionplus_mesg->angle_rate[CWIID_THETA] = ((uint16_t)data[4] & 0xFC)<<6 |
			                                            (uint16_t)data[1];
			motionplus_mesg->angle_rate[CWIID_PSI]   = ((uint16_t)data[3] & 0xFC)<<6 |
			                                            (uint16_t)data[0];
			motionplus_mesg->low_speed[CWIID_PHI]    = ((uint8_t)data[3] & 0x01);
			motionplus_mesg->low_speed[CWIID_THETA]  = ((uint8_t)data[4] & 0x02)>>1;
			motionplus_mesg->low_speed[CWIID_PSI]    = ((uint8_t)data[3] & 0x02)>>1;
		}
Beispiel #22
0
cwiid_wiimote_t *cwiid_open_timeout(bdaddr_t *bdaddr, int flags, int timeout)
{
	struct sockaddr_l2 remote_addr;
	int ctl_socket = -1, int_socket = -1;
	struct wiimote *wiimote = NULL;
	bdaddr_t any_bdaddr;

	/* Treat a null bdaddr as BDADDR_ANY */
	if (bdaddr == NULL) {
		any_bdaddr = *BDADDR_ANY;
		bdaddr = &any_bdaddr;
	}

	/* If BDADDR_ANY is given, find available wiimote */
	if (bacmp(bdaddr, BDADDR_ANY) == 0) {
		if (cwiid_find_wiimote(bdaddr, timeout)) {
			goto ERR_HND;
		}
		sleep(1);
	}

	/* Connect to Wiimote */
	/* Control Channel */
	memset(&remote_addr, 0, sizeof remote_addr);
	remote_addr.l2_family = AF_BLUETOOTH;
	bacpy( &remote_addr.l2_bdaddr, bdaddr );
	remote_addr.l2_psm = htobs(CTL_PSM);
	if ((ctl_socket =
	  socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1) {
		cwiid_err(NULL, "Socket creation error (control socket): %s", strerror(errno));
		goto ERR_HND;
	}
	if (connect(ctl_socket, (struct sockaddr *)&remote_addr,
		        sizeof remote_addr)) {
		cwiid_err(NULL, "Socket connect error (control socket): %s", strerror(errno));
		goto ERR_HND;
	}

	/* Interrupt Channel */
	remote_addr.l2_psm = htobs(INT_PSM);
	if ((int_socket =
	  socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1) {
		cwiid_err(NULL, "Socket creation error (interrupt socket): %s", strerror(errno));
		goto ERR_HND;
	}
	if (connect(int_socket, (struct sockaddr *)&remote_addr,
		        sizeof remote_addr)) {
		cwiid_err(NULL, "Socket connect error (interrupt socket): %s", strerror(errno));
		goto ERR_HND;
	}

	if ((wiimote = cwiid_new(ctl_socket, int_socket, flags)) == NULL) {
		/* Raises its own error */
		goto ERR_HND;
	}

	return wiimote;

ERR_HND:
	/* Close Sockets */
	if (ctl_socket != -1) {
		if (close(ctl_socket)) {
			cwiid_err(NULL, "Socket close error (control socket): %s", strerror(errno));
		}
	}
	if (int_socket != -1) {
		if (close(int_socket)) {
			cwiid_err(NULL, "Socket close error (interrupt socket): %s", strerror(errno));
		}
	}
	return NULL;
}
Beispiel #23
0
int cwiid_close(cwiid_wiimote_t *wiimote)
{
	void *pthread_ret;
	int err;

	/* Stop rumbling, otherwise wiimote continues to rumble for
	   few seconds after closing the connection! There should be no
	   need to check if stopping fails: we are closing the connection
	   in any case. */
	if (wiimote->state.rumble) {
		cwiid_set_rumble(wiimote, 0);
	}

	/* Cancel and join router_thread and status_thread */
	if (pthread_cancel(wiimote->router_thread)) {
		/* if thread quit abnormally, would have printed it's own error */
	}
	err = pthread_join(wiimote->router_thread, &pthread_ret);
	if (err) {
		cwiid_err(wiimote, "Thread join error (router thread): %s", strerror(err));
	}
	else if (!((pthread_ret == PTHREAD_CANCELED) || (pthread_ret == NULL))) {
		cwiid_err(wiimote, "Bad return value from router thread");
	}

	if (pthread_cancel(wiimote->status_thread)) {
		/* if thread quit abnormally, would have printed it's own error */
	}
	err = pthread_join(wiimote->status_thread, &pthread_ret);
	if (err) {
		cwiid_err(wiimote, "Thread join error (status thread): %s", strerror(err));
	}
	else if (!((pthread_ret == PTHREAD_CANCELED) || (pthread_ret == NULL))) {
		cwiid_err(wiimote, "Bad return value from status thread");
	}

	if (wiimote->mesg_callback) {
		if (cancel_mesg_callback(wiimote)) {
			/* prints it's own errors */
		}
	}

	if (cancel_rw(wiimote)) {
		/* prints it's own errors */
	}

	/* Close sockets */
	if (close(wiimote->int_socket)) {
		cwiid_err(wiimote, "Socket close error (interrupt socket): %s", strerror(errno));
	}
	if (close(wiimote->ctl_socket)) {
		cwiid_err(wiimote, "Socket close error (control socket): %s", strerror(errno));
	}
	/* Close Pipes */
	if (close(wiimote->mesg_pipe[0]) || close(wiimote->mesg_pipe[1])) {
		cwiid_err(wiimote, "Pipe close error (mesg pipe): %s", strerror(errno));
	}
	if (close(wiimote->status_pipe[0]) || close(wiimote->status_pipe[1])) {
		cwiid_err(wiimote, "Pipe close error (status pipe): %s", strerror(errno));
	}
	if (close(wiimote->rw_pipe[0]) || close(wiimote->rw_pipe[1])) {
		cwiid_err(wiimote, "Pipe close error (rw pipe): %s", strerror(errno));
	}
	/* Destroy mutexes */
	err = pthread_mutex_destroy(&wiimote->state_mutex);
	if (err) {
		cwiid_err(wiimote, "Mutex destroy error (state): %s", strerror(err));
	}
	err = pthread_mutex_destroy(&wiimote->rw_mutex);
	if (err) {
		cwiid_err(wiimote, "Mutex destroy error (rw): %s", strerror(err));
	}
	err = pthread_mutex_destroy(&wiimote->rpt_mutex);
	if (err) {
		cwiid_err(wiimote, "Mutex destroy error (rpt): %s", strerror(err));
	}

	free(wiimote);

	return 0;
}
Beispiel #24
0
cwiid_wiimote_t *cwiid_new(int ctl_socket, int int_socket, int flags)
{
	struct wiimote *wiimote = NULL;
	char mesg_pipe_init = 0, status_pipe_init = 0, rw_pipe_init = 0,
	     state_mutex_init = 0, rw_mutex_init = 0, rpt_mutex_init = 0,
	     router_thread_init = 0, status_thread_init = 0;
	void *pthread_ret;
	int err;

	/* Allocate wiimote */
	if ((wiimote = malloc(sizeof *wiimote)) == NULL) {
		cwiid_err(NULL, "Memory allocation error (cwiid_wiimote_t)");
		goto ERR_HND;
	}

	/* set sockets and flags */
	wiimote->ctl_socket = ctl_socket;
	wiimote->int_socket = int_socket;
	wiimote->flags = flags;

	/* Global Lock, Store and Increment wiimote_id */
	err = pthread_mutex_lock(&global_mutex);
	if (err) {
		cwiid_err(NULL, "Mutex lock error (global mutex): %s", strerror(err));
		goto ERR_HND;
	}
	wiimote->id = wiimote_id++;
	err = pthread_mutex_unlock(&global_mutex);
	if (err) {
		cwiid_err(wiimote, "Mutex unlock error (global mutex) - "
		                   "deadlock warning: %s", strerror(err));
		goto ERR_HND;
	}

	/* Create pipes */
	if (pipe(wiimote->mesg_pipe)) {
		cwiid_err(wiimote, "Pipe creation error (mesg pipe): %s", strerror(errno));
		goto ERR_HND;
	}
	mesg_pipe_init = 1;
	if (pipe(wiimote->status_pipe)) {
		cwiid_err(wiimote, "Pipe creation error (status pipe): %s", strerror(errno));
		goto ERR_HND;
	}
	status_pipe_init = 1;
	if (pipe(wiimote->rw_pipe)) {
		cwiid_err(wiimote, "Pipe creation error (rw pipe): %s", strerror(errno));
		goto ERR_HND;
	}
	rw_pipe_init = 1;

	/* Setup blocking */
	if (fcntl(wiimote->mesg_pipe[1], F_SETFL, O_NONBLOCK)) {
		cwiid_err(wiimote, "File control error (mesg write pipe): %s", strerror(errno));
		goto ERR_HND;
	}
	if (wiimote->flags & CWIID_FLAG_NONBLOCK) {
		if (fcntl(wiimote->mesg_pipe[0], F_SETFL, O_NONBLOCK)) {
			cwiid_err(wiimote, "File control error (mesg read pipe): %s", strerror(errno));
			goto ERR_HND;
		}
	}

	/* Init mutexes */
	err = pthread_mutex_init(&wiimote->state_mutex, NULL);
	if (err) {
		cwiid_err(wiimote, "Mutex initialization error (state mutex): %s", strerror(err));
		goto ERR_HND;
	}
	state_mutex_init = 1;
	err = pthread_mutex_init(&wiimote->rw_mutex, NULL);
	if (err) {
		cwiid_err(wiimote, "Mutex initialization error (rw mutex): %s", strerror(err));
		goto ERR_HND;
	}
	rw_mutex_init = 1;
	err = pthread_mutex_init(&wiimote->rpt_mutex, NULL);
	if (err) {
		cwiid_err(wiimote, "Mutex initialization error (rpt mutex): %s", strerror(err));
		goto ERR_HND;
	}
	rpt_mutex_init = 1;

	/* Set rw_status before starting router thread */
	wiimote->rw_status = RW_IDLE;

	/* Launch interrupt socket listener and dispatch threads */
	err = pthread_create(&wiimote->router_thread, NULL,
	                   (void *(*)(void *))&router_thread, wiimote);
	if (err) {
		cwiid_err(wiimote, "Thread creation error (router thread): %s", strerror(err));
		goto ERR_HND;
	}
	router_thread_init = 1;
	err = pthread_create(&wiimote->status_thread, NULL,
	                   (void *(*)(void *))&status_thread, wiimote);
	if (err) {
		cwiid_err(wiimote, "Thread creation error (status thread): %s", strerror(err));
		goto ERR_HND;
	}
	status_thread_init = 1;

	/* Success!  Update state */
	memset(&wiimote->state, 0, sizeof wiimote->state);
	wiimote->mesg_callback = NULL;
	cwiid_set_led(wiimote, 0);
	cwiid_request_status(wiimote);

	return wiimote;

ERR_HND:
	if (wiimote) {
		/* Close threads */
		if (router_thread_init) {
			pthread_cancel(wiimote->router_thread);
			err = pthread_join(wiimote->router_thread, &pthread_ret);
			if (err) {
				cwiid_err(wiimote, "Thread join error (router thread): %s", strerror(err));
			}
			else if (!((pthread_ret == PTHREAD_CANCELED) &&
			         (pthread_ret == NULL))) {
				cwiid_err(wiimote, "Bad return value from router thread");
			}
		}

		if (status_thread_init) {
			pthread_cancel(wiimote->status_thread);
			err = pthread_join(wiimote->status_thread, &pthread_ret);
			if (err) {
				cwiid_err(wiimote, "Thread join error (status thread): %s", strerror(err));
			}
			else if (!((pthread_ret == PTHREAD_CANCELED) && (pthread_ret == NULL))) {
				cwiid_err(wiimote, "Bad return value from status thread");
			}
		}

		/* Close Pipes */
		if (mesg_pipe_init) {
			if (close(wiimote->mesg_pipe[0]) || close(wiimote->mesg_pipe[1])) {
				cwiid_err(wiimote, "Pipe close error (mesg pipe): %s", strerror(errno));
			}
		}
		if (status_pipe_init) {
			if (close(wiimote->status_pipe[0]) ||
			  close(wiimote->status_pipe[1])) {
				cwiid_err(wiimote, "Pipe close error (status pipe): %s", strerror(errno));
			}
		}
		if (rw_pipe_init) {
			if (close(wiimote->rw_pipe[0]) || close(wiimote->rw_pipe[1])) {
				cwiid_err(wiimote, "Pipe close error (rw pipe): %s", strerror(errno));
			}
		}
		/* Destroy Mutexes */
		if (state_mutex_init) {
			err = pthread_mutex_destroy(&wiimote->state_mutex);
			if (err) {
				cwiid_err(wiimote, "Mutex destroy error (state mutex): %s", strerror(err));
			}
		}
		if (rw_mutex_init) {
			err = pthread_mutex_destroy(&wiimote->rw_mutex);
			if (err) {
				cwiid_err(wiimote, "Mutex destroy error (rw mutex): %s", strerror(err));
			}
		}
		if (rpt_mutex_init) {
			err = pthread_mutex_destroy(&wiimote->rpt_mutex);
			if (err) {
				cwiid_err(wiimote, "Mutex destroy error (rpt mutex): %s", strerror(err));
			}
		}
		free(wiimote);
	}
	return NULL;
}
Beispiel #25
0
/* timeout in 2 second units */
int cwiid_get_bdinfo_array(int dev_id, unsigned int timeout, int max_bdinfo,
                           struct cwiid_bdinfo **bdinfo, uint8_t flags)
{
	inquiry_info *dev_list = NULL;
	int max_inquiry;
	int dev_count;
	int sock = -1;
	int bdinfo_count;
	int i, j;
	int err = 0;
	int ret;

	/* NULLify for the benefit of error handling */
	*bdinfo = NULL;

	/* If not given (=-1), get the first available Bluetooth interface */
	if (dev_id == -1) {
		if ((dev_id = hci_get_route(NULL)) == -1) {
			cwiid_err(NULL, "No Bluetooth interface found");
			return -1;
		}
	}

	/* Get Bluetooth Device List */
	if ((flags & BT_NO_WIIMOTE_FILTER) && (max_bdinfo != -1)) {
		max_inquiry = max_bdinfo;
	}
	else {
		max_inquiry = BT_MAX_INQUIRY;
	}
	if ((dev_count = hci_inquiry(dev_id, timeout, max_inquiry, NULL,
	                             &dev_list, IREQ_CACHE_FLUSH)) == -1) {
		cwiid_err(NULL, "Bluetooth device inquiry error");
		err = 1;
		goto CODA;
	}

	if (dev_count == 0) {
		bdinfo_count = 0;
		goto CODA;
	}

	/* Open connection to Bluetooth Interface */
	if ((sock = hci_open_dev(dev_id)) == -1) {
		cwiid_err(NULL, "Bluetooth interface open error");
		err = 1;
		goto CODA;
	}

	/* Allocate info list */
	if (max_bdinfo == -1) {
		max_bdinfo = dev_count;
	}
	if ((*bdinfo = malloc(max_bdinfo * sizeof **bdinfo)) == NULL) {
		cwiid_err(NULL, "Memory allocation error (bdinfo array)");
		err = 1;
		goto CODA;
	}

	/* Copy dev_list to bdinfo */
	for (bdinfo_count=i=0; (i < dev_count) && (bdinfo_count < max_bdinfo);
	     i++) {
		/* Filter by class */
		if (!(flags & BT_NO_WIIMOTE_FILTER) &&
		  ((dev_list[i].dev_class[0] != WIIMOTE_CLASS_0) ||
		   (dev_list[i].dev_class[1] != WIIMOTE_CLASS_1) ||
		   (dev_list[i].dev_class[2] != WIIMOTE_CLASS_2))) {
			continue;
		}

		/* timeout (10000) in milliseconds */
		if (hci_read_remote_name(sock, &dev_list[i].bdaddr, BT_NAME_LEN,
		                         (*bdinfo)[bdinfo_count].name, 10000)) {
			cwiid_err(NULL, "Bluetooth name read error");
			err = 1;
			goto CODA;
		}

		/* Filter by name */
		if (!(flags & BT_NO_WIIMOTE_FILTER) &&
		  strncmp((*bdinfo)[bdinfo_count].name, WIIMOTE_NAME, BT_NAME_LEN) &&
		  strncmp((*bdinfo)[bdinfo_count].name, WIIBALANCE_NAME, BT_NAME_LEN)) {
			continue;
		}

		/* Passed filter, add to bdinfo */
		bacpy(&(*bdinfo)[bdinfo_count].bdaddr, &dev_list[i].bdaddr);
		for (j=0; j<3; j++) {
			(*bdinfo)[bdinfo_count].btclass[j] =
			            dev_list[i].dev_class[j];
		}
		bdinfo_count++;
	}

	if (bdinfo_count == 0) {
		free(*bdinfo);
	}
	else if (bdinfo_count < max_bdinfo) {
		if ((*bdinfo = realloc(*bdinfo, bdinfo_count * sizeof **bdinfo))
		  == NULL) {
			cwiid_err(NULL, "Memory reallocation error (bdinfo array)");
			err = 1;
			goto CODA;
		}
	}

CODA:
	if (dev_list) free(dev_list);
	if (sock != -1) hci_close_dev(sock);
	if (err) {
		if (*bdinfo) free(*bdinfo);
		ret = -1;
	}
	else {
		ret = bdinfo_count;
	}
	return ret;
}
Beispiel #26
0
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) {
		/* Read packet */
		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);
			/* Quit! */
			break;
		}
		else {
			/* Verify first byte (DATA/INPUT) */
			if (buf[0] != (BT_TRANS_DATA | BT_PARAM_INPUT)) {
				cwiid_err(wiimote, "Invalid packet type");
			}

			/* Main switch */
			/* printf("%.2X %.2X %.2X %.2X  %.2X %.2X %.2X %.2X\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
			printf("%.2X %.2X %.2X %.2X  %.2X %.2X %.2X %.2X\n", buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
			printf("%.2X %.2X %.2X %.2X  %.2X %.2X %.2X %.2X\n", buf[16], buf[17], buf[18], buf[19], buf[20], buf[21], buf[22], buf[23]);
			printf("\n"); */
			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) {
					/* prints its own errors */
					write_mesg_array(wiimote, &ma);
				}
			}
		}
	}

	return NULL;
}
Beispiel #27
0
int update_state(struct wiimote *wiimote, struct mesg_array *ma)
{
	int i;
	union cwiid_mesg *mesg;

	if (pthread_mutex_lock(&wiimote->state_mutex)) {
		cwiid_err(wiimote, "Mutex lock error (state mutex)");
		return -1;
	}

	for (i=0; i < ma->count; i++) {
		mesg = &ma->array[i];

		switch (mesg->type) {
		case CWIID_MESG_STATUS:
			wiimote->state.battery = mesg->status_mesg.battery;
			if (wiimote->state.ext_type != mesg->status_mesg.ext_type) {
				memset(&wiimote->state.ext, 0, sizeof wiimote->state.ext);
				wiimote->state.ext_type = mesg->status_mesg.ext_type;
			}
			break;
		case CWIID_MESG_BTN:
			wiimote->state.buttons = mesg->btn_mesg.buttons;
			break;
		case CWIID_MESG_ACC:
			memcpy(wiimote->state.acc, mesg->acc_mesg.acc,
			       sizeof wiimote->state.acc);
			break;
		case CWIID_MESG_IR:
			memcpy(wiimote->state.ir_src, mesg->ir_mesg.src,
			       sizeof wiimote->state.ir_src);
			break;
		case CWIID_MESG_NUNCHUK:
			memcpy(wiimote->state.ext.nunchuk.stick,
			       mesg->nunchuk_mesg.stick,
			       sizeof wiimote->state.ext.nunchuk.stick);
			memcpy(wiimote->state.ext.nunchuk.acc,
			       mesg->nunchuk_mesg.acc,
			       sizeof wiimote->state.ext.nunchuk.acc);
			wiimote->state.ext.nunchuk.buttons = mesg->nunchuk_mesg.buttons;
			break;
		case CWIID_MESG_CLASSIC:
			memcpy(wiimote->state.ext.classic.l_stick,
			       mesg->classic_mesg.l_stick,
			       sizeof wiimote->state.ext.classic.l_stick);
			memcpy(wiimote->state.ext.classic.r_stick,
			       mesg->classic_mesg.r_stick,
			       sizeof wiimote->state.ext.classic.r_stick);
			wiimote->state.ext.classic.l = mesg->classic_mesg.l;
			wiimote->state.ext.classic.r = mesg->classic_mesg.r;
			wiimote->state.ext.classic.buttons = mesg->classic_mesg.buttons;
			break;
		case CWIID_MESG_BALANCE:
			wiimote->state.ext.balance.right_top = mesg->balance_mesg.right_top;
			wiimote->state.ext.balance.right_bottom = mesg->balance_mesg.right_bottom;
			wiimote->state.ext.balance.left_top = mesg->balance_mesg.left_top;
			wiimote->state.ext.balance.left_bottom = mesg->balance_mesg.left_bottom;
			break;
		case CWIID_MESG_ERROR:
			wiimote->state.error = mesg->error_mesg.error;
			break;
		case CWIID_MESG_UNKNOWN:
			/* do nothing, error has already been printed */
			break;
		}
	}

	if (pthread_mutex_unlock(&wiimote->state_mutex)) {
		cwiid_err(wiimote, "Mutex unlock error (state mutex) - "
		                   "deadlock warning");
		return -1;
	}

	return 0;
}
Beispiel #28
0
void *status_thread(struct wiimote *wiimote)
{
	struct mesg_array ma;
	struct cwiid_status_mesg *status_mesg;
	unsigned char buf[2];
	unsigned char data[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)");
			/* Quit! */
			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) {
			/* Read extension ID */
			if (cwiid_read(wiimote, CWIID_RW_REG, 0xA400FE, 2, &buf)) {
				cwiid_err(wiimote, "Read error (extension error)");
				status_mesg->ext_type = CWIID_EXT_UNKNOWN;
			}

			/* If we have just disabled passthrough override passthrough with just plain motionplus */
			/*if ((!wiimote->passthrough_activate_flag && ((buf[0] << 8) | buf[1]) == EXT_NUNCHUK_MOTIONPLUS) || 
				(!wiimote->passthrough_activate_flag && ((buf[0] << 8) | buf[1]) == EXT_CLASSIC_MOTIONPLUS)) {
				fprintf(stderr, "status_thread: reverting to motionplus\n");
				buf[0] = EXT_MOTIONPLUS;
			}*/

			/* If the extension didn't change, or if the extension is a
			 * MotionPlus, no init necessary */
			switch ((buf[0] << 8) | buf[1]) {
			case EXT_NONE:
				status_mesg->ext_type = CWIID_EXT_NONE;
				break;
			case EXT_NUNCHUK:
				if (wiimote->ext == MOTIONPLUS_PRESENT && wiimote->passthrough_activate_flag){		
					data[0] = 0x05;
					cwiid_write(wiimote, CWIID_RW_REG, 0xA600FE, 1, &data[0]);
					cwiid_read(wiimote, CWIID_RW_REG, 0xA400FE, 1, &data[1]);
					if (data[1] == 0x05) {
						status_mesg->ext_type = CWIID_EXT_NUNCHUK_MPLUS_PASSTHROUGH;
						wiimote->ext = NUNCHUK_MOTIONPLUS_PRESENT;
						break;
					}
				}else{
					status_mesg->ext_type = CWIID_EXT_NUNCHUK;
					wiimote->ext = EXT_PRESENT_NOT_MOTIONPLUS;
					break;
				}
			case EXT_NUNCHUK_MOTIONPLUS:
				status_mesg->ext_type = CWIID_EXT_NUNCHUK_MPLUS_PASSTHROUGH;
				wiimote->ext = NUNCHUK_MOTIONPLUS_PRESENT;
				break;
			case EXT_CLASSIC:
				if (wiimote->ext == MOTIONPLUS_PRESENT && wiimote->passthrough_activate_flag){		
					data[0] = 0x07;
					cwiid_write(wiimote, CWIID_RW_REG, 0xA600FE, 1, &data[0]);
					cwiid_read(wiimote, CWIID_RW_REG, 0xA400FE, 1, &data[1]);
					if (data[1] == 0x07) {
						status_mesg->ext_type = CWIID_EXT_CLASSIC_MPLUS_PASSTHROUGH;
						wiimote->ext = CLASSIC_MOTIONPLUS_PRESENT;
						break;
					}
				}else{
					status_mesg->ext_type = CWIID_EXT_CLASSIC;
					wiimote->ext = EXT_PRESENT_NOT_MOTIONPLUS;
					break;
				}
			case EXT_CLASSIC_MOTIONPLUS:
				status_mesg->ext_type = CWIID_EXT_CLASSIC_MPLUS_PASSTHROUGH;
				wiimote->ext = CLASSIC_MOTIONPLUS_PRESENT;
				break;
			case EXT_BALANCE:
				status_mesg->ext_type = CWIID_EXT_BALANCE;
				wiimote->ext = EXT_PRESENT_NOT_MOTIONPLUS;
				break;
			case EXT_MOTIONPLUS:
				status_mesg->ext_type = CWIID_EXT_MOTIONPLUS;
				wiimote->ext = MOTIONPLUS_PRESENT;
				break;
			case EXT_PARTIAL:
				/* Everything (but MotionPlus) shows up as partial until initialized */
				buf[0] = 0x55;
				buf[1] = 0x00;
				/* Initialize extension register space */
				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;
				}
				/* Read extension ID */
				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;
					case EXT_NUNCHUK_MOTIONPLUS:
						status_mesg->ext_type = CWIID_EXT_NUNCHUK_MPLUS_PASSTHROUGH;
						break;
					case EXT_CLASSIC_MOTIONPLUS:
						status_mesg->ext_type = CWIID_EXT_CLASSIC_MPLUS_PASSTHROUGH;
						break;
					default:
						status_mesg->ext_type = CWIID_EXT_UNKNOWN;
						break;
					}
				}
				break;
			}
		}
		else {
			//fprintf(stderr,"ext_type=%d ext=%d\n", status_mesg->ext_type, wiimote->ext);
			if (!(wiimote->passthrough_activate_flag && wiimote->ext == MOTIONPLUS_PRESENT) ||
					!wiimote->passthrough_activate_flag) {
				//fprintf(stderr,"NO EXTENSION\n");
				wiimote->ext = NO_EXTENSION;
			}

			pthread_cond_signal(&wiimote->condition_var);
		}				

		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)) {
				/* prints its own errors */
			}
		}
	}

	return NULL;
}
Beispiel #29
0
cwiid_wiimote_t *cwiid_listen(int flags)
{
	struct sockaddr_l2 local_addr;
	struct sockaddr_l2 remote_addr;
	socklen_t socklen;
	int ctl_server_socket = -1, int_server_socket = -1,
	    ctl_socket = -1, int_socket = -1;
	struct wiimote *wiimote = NULL;

	/* Connect to Wiimote */
	/* Control Channel */
	memset(&local_addr, 0, sizeof local_addr);
	local_addr.l2_family = AF_BLUETOOTH;
	local_addr.l2_bdaddr = *BDADDR_ANY;
	local_addr.l2_psm = htobs(CTL_PSM);
	if ((ctl_server_socket =
	  socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1) {
		cwiid_err(NULL, "Socket creation error (control socket): %s", strerror(errno));
		goto ERR_HND;
	}
	if (bind(ctl_server_socket, (struct sockaddr *)&local_addr,
	         sizeof local_addr)) {
		cwiid_err(NULL, "Socket bind error (control socket): %s", strerror(errno));
		goto ERR_HND;
	}
	if (listen(ctl_server_socket, 1)) {
		cwiid_err(NULL, "Socket listen error (control socket): %s", strerror(errno));
		goto ERR_HND;
	}

	/* Interrupt Channel */
	local_addr.l2_psm = htobs(INT_PSM);
	if ((int_server_socket =
	  socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1) {
		cwiid_err(NULL, "Socket creation error (interrupt socket): %s", strerror(errno));
		goto ERR_HND;
	}
	if (bind(int_server_socket, (struct sockaddr *)&local_addr,
	         sizeof local_addr)) {
		cwiid_err(NULL, "Socket bind error (interrupt socket): %s", strerror(errno));
		goto ERR_HND;
	}
	if (listen(int_server_socket, 1)) {
		cwiid_err(NULL, "Socket listen error (interrupt socket): %s", strerror(errno));
		goto ERR_HND;
	}

	/* Block for Connections */
	if ((ctl_socket = accept(ctl_server_socket, (struct sockaddr *)&remote_addr, &socklen)) < 0) {
		cwiid_err(NULL, "Socket accept error (control socket): %s", strerror(errno));
		goto ERR_HND;
	}
	if ((int_socket = accept(int_server_socket, (struct sockaddr *)&remote_addr, &socklen)) < 0) {
		cwiid_err(NULL, "Socket accept error (interrupt socket): %s", strerror(errno));
		goto ERR_HND;
	}

	/* Close server sockets */
	if (close(ctl_server_socket)) {
		cwiid_err(NULL, "Socket close error (control socket): %s", strerror(errno));
	}
	if (close(int_server_socket)) {
		cwiid_err(NULL, "Socket close error (interrupt socket): %s", strerror(errno));
	}

	if ((wiimote = cwiid_new(ctl_socket, int_socket, flags)) == NULL) {
		/* Raises its own error */
		goto ERR_HND;
	}

	return wiimote;

ERR_HND:
	/* Close Sockets */
	if (ctl_server_socket != -1) {
		if (close(ctl_server_socket)) {
			cwiid_err(NULL, "Socket close error (control server socket): %s", strerror(errno));
		}
	}
	if (int_server_socket != -1) {
		if (close(int_server_socket)) {
			cwiid_err(NULL, "Socket close error (interrupt server socket): %s", strerror(errno));
		}
	}
	if (ctl_socket != -1) {
		if (close(ctl_socket)) {
			cwiid_err(NULL, "Socket close error (control socket): %s", strerror(errno));
		}
	}
	if (int_socket != -1) {
		if (close(int_socket)) {
			cwiid_err(NULL, "Socket close error (interrupt socket): %s", strerror(errno));
		}
	}

	return NULL;
}
Beispiel #30
0
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)");
			/* Quit! */
			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) {
			/* Read extension ID */
			if (cwiid_read(wiimote, CWIID_RW_REG, 0xA400FE, 1, &buf[0])) {
				cwiid_err(wiimote, "Read error (extension error)");
				status_mesg->ext_type = CWIID_EXT_UNKNOWN;
			}
			/* If the extension didn't change, or if the extension is a
			 * MotionPlus, no init necessary */
			switch (buf[0]) {
			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:
				/* Everything (but MotionPlus) shows up as partial until initialized */
				buf[0] = 0x55;
				buf[1] = 0x00;
				/* Initialize extension register space */
				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;
				}
				/* Read extension ID */
				else if (cwiid_read(wiimote, CWIID_RW_REG, 0xA400FE, 1, &buf[0])) {
					cwiid_err(wiimote, "Read error (extension error)");
					status_mesg->ext_type = CWIID_EXT_UNKNOWN;
				}
				else {
					switch (buf[0]) {
					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)) {
				/* prints its own errors */
			}
		}
	}

	return NULL;
}