390 lines
8.7 KiB
C++
390 lines
8.7 KiB
C++
/*
|
|
* wiiuse
|
|
*
|
|
* Written By:
|
|
* Michael Laforest < para >
|
|
* Email: < thepara (--AT--) g m a i l [--DOT--] com >
|
|
*
|
|
* Copyright 2006-2007
|
|
*
|
|
* This file is part of wiiuse.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* $Header$
|
|
*
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
* @brief General wiimote operations.
|
|
*
|
|
* The file includes functions that handle general
|
|
* tasks. Most of these are functions that are part
|
|
* of the API.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#ifndef _WIN32
|
|
#include <unistd.h>
|
|
#else
|
|
#include <Winsock2.h>
|
|
#endif
|
|
|
|
#include "Common.h"
|
|
#include "wiiuse_internal.h"
|
|
|
|
static int g_banner = 1;
|
|
|
|
/**
|
|
* @breif Returns the version of the library.
|
|
*/
|
|
const char* wiiuse_version() {
|
|
return WIIUSE_VERSION;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Clean up wiimote_t array created by wiiuse_init()
|
|
*/
|
|
void wiiuse_cleanup(struct wiimote_t** wm, int wiimotes) {
|
|
int i = 0;
|
|
|
|
if (!wm)
|
|
return;
|
|
|
|
NOTICE_LOG(WIIMOTE, "wiiuse clean up...");
|
|
|
|
for (; i < wiimotes; ++i) {
|
|
wiiuse_disconnect(wm[i]);
|
|
free(wm[i]);
|
|
}
|
|
|
|
free(wm);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Initialize an array of wiimote structures.
|
|
*
|
|
* @param wiimotes Number of wiimote_t structures to create.
|
|
*
|
|
* @return An array of initialized wiimote_t structures.
|
|
*
|
|
* @see wiiuse_connect()
|
|
*
|
|
* The array returned by this function can be passed to various
|
|
* functions, including wiiuse_connect().
|
|
*/
|
|
struct wiimote_t** wiiuse_init(int wiimotes) {
|
|
int i = 0;
|
|
struct wiimote_t** wm = NULL;
|
|
|
|
/*
|
|
* Please do not remove this banner.
|
|
* GPL asks that you please leave output credits intact.
|
|
* Thank you.
|
|
*
|
|
* This banner is only displayed once so that if you need
|
|
* to call this function again it won't be intrusive.
|
|
*/
|
|
if (!g_banner) {
|
|
printf( "wiiuse v" WIIUSE_VERSION " loaded.\n"
|
|
" By: Michael Laforest <thepara[at]gmail{dot}com>\n"
|
|
" http://wiiuse.net http://wiiuse.sf.net\n");
|
|
g_banner = 1;
|
|
}
|
|
|
|
if (!wiimotes)
|
|
return NULL;
|
|
|
|
wm = (struct wiimote_t **)malloc(sizeof(struct wiimote_t*) * wiimotes);
|
|
|
|
for (i = 0; i < wiimotes; ++i) {
|
|
wm[i] = (struct wiimote_t *)malloc(sizeof(struct wiimote_t));
|
|
memset(wm[i], 0, sizeof(struct wiimote_t));
|
|
|
|
wm[i]->unid = i+1;
|
|
|
|
#if defined __linux__ && HAVE_BLUEZ
|
|
wm[i]->bdaddr = (bdaddr_t){{0, 0, 0, 0, 0, 0}};
|
|
wm[i]->out_sock = -1;
|
|
wm[i]->in_sock = -1;
|
|
#elif defined(_WIN32)
|
|
wm[i]->dev_handle = 0;
|
|
wm[i]->stack = WIIUSE_STACK_UNKNOWN;
|
|
#endif
|
|
|
|
wm[i]->timeout = WIIMOTE_DEFAULT_TIMEOUT;
|
|
wm[i]->state = WIIMOTE_INIT_STATES;
|
|
wm[i]->flags = WIIUSE_INIT_FLAGS;
|
|
wm[i]->event = WIIUSE_NONE;
|
|
}
|
|
|
|
return wm;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief The wiimote disconnected.
|
|
*
|
|
* @param wm Pointer to a wiimote_t structure.
|
|
*/
|
|
void wiiuse_disconnected(struct wiimote_t* wm) {
|
|
if (!wm) return;
|
|
|
|
NOTICE_LOG(WIIMOTE, "Wiimote disconnected [id %i].", wm->unid);
|
|
|
|
/* disable the connected flag */
|
|
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_CONNECTED);
|
|
|
|
/* reset a bunch of stuff */
|
|
wm->leds = 0;
|
|
wm->state = WIIMOTE_INIT_STATES;
|
|
memset(wm->event_buf, 0, sizeof(wm->event_buf));
|
|
|
|
#if defined __linux__ && HAVE_BLUEZ
|
|
wm->out_sock = -1;
|
|
wm->in_sock = -1;
|
|
#elif defined(_WIN32)
|
|
CloseHandle(wm->dev_handle);
|
|
wm->dev_handle = 0;
|
|
#endif
|
|
|
|
wm->event = WIIUSE_DISCONNECT;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Enable or disable the rumble.
|
|
*
|
|
* @param wm Pointer to a wiimote_t structure.
|
|
* @param status 1 to enable, 0 to disable.
|
|
*/
|
|
void wiiuse_rumble(struct wiimote_t* wm, int status) {
|
|
byte buf;
|
|
|
|
if (!wm || !WIIMOTE_IS_CONNECTED(wm))
|
|
return;
|
|
|
|
/* make sure to keep the current lit leds */
|
|
buf = wm->leds;
|
|
|
|
if (status) {
|
|
DEBUG_LOG(WIIMOTE, "Starting rumble...");
|
|
WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_RUMBLE);
|
|
buf |= 0x01;
|
|
} else {
|
|
DEBUG_LOG(WIIMOTE, "Stopping rumble...");
|
|
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_RUMBLE);
|
|
}
|
|
|
|
/* preserve IR state */
|
|
if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR))
|
|
buf |= 0x04;
|
|
|
|
wiiuse_send(wm, WM_CMD_RUMBLE, &buf, 1);
|
|
}
|
|
|
|
/**
|
|
* @brief Set the enabled LEDs.
|
|
*
|
|
* @param wm Pointer to a wiimote_t structure.
|
|
* @param leds What LEDs to enable.
|
|
*
|
|
* \a leds is a bitwise or of WIIMOTE_LED_1, WIIMOTE_LED_2, WIIMOTE_LED_3, or WIIMOTE_LED_4.
|
|
*/
|
|
void wiiuse_set_leds(struct wiimote_t* wm, int leds) {
|
|
byte buf;
|
|
|
|
if (!wm || !WIIMOTE_IS_CONNECTED(wm))
|
|
return;
|
|
|
|
/* remove the lower 4 bits because they control rumble */
|
|
wm->leds = (leds & 0xF0);
|
|
buf = wm->leds;
|
|
|
|
/* make sure if the rumble is on that we keep it on */
|
|
if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_RUMBLE))
|
|
buf |= 0x01;
|
|
|
|
wiiuse_send(wm, WM_CMD_LED, &buf, 1);
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Set the report type based on the current wiimote state.
|
|
*
|
|
* @param wm Pointer to a wiimote_t structure.
|
|
*
|
|
* @return The report type sent.
|
|
*
|
|
* The wiimote reports formatted packets depending on the
|
|
* report type that was last requested. This function will
|
|
* update the type of report that should be sent based on
|
|
* the current state of the device.
|
|
*/
|
|
int wiiuse_set_report_type(struct wiimote_t* wm) {
|
|
byte buf[2];
|
|
int motion, expansion, ir;
|
|
|
|
if (!wm || !WIIMOTE_IS_CONNECTED(wm))
|
|
return 0;
|
|
|
|
buf[0] = (WIIMOTE_IS_FLAG_SET(wm, WIIUSE_CONTINUOUS) ? 0x04 : 0x00); /* set to 0x04 for continuous reporting */
|
|
|
|
/* if rumble is enabled, make sure we keep it */
|
|
if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_RUMBLE))
|
|
buf[0] |= 0x01;
|
|
|
|
motion = WIIMOTE_IS_SET(wm, WIIMOTE_STATE_ACC);
|
|
expansion = WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP);
|
|
ir = WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR);
|
|
|
|
buf[1] = 0x30;
|
|
|
|
|
|
DEBUG_LOG(WIIMOTE, "Setting report type: 0x%x", buf[1]);
|
|
|
|
expansion = wiiuse_send(wm, WM_CMD_REPORT_TYPE, buf, 2);
|
|
if (expansion <= 0)
|
|
return expansion;
|
|
|
|
return buf[1];
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* @brief Write data to the wiimote.
|
|
*
|
|
* @param wm Pointer to a wiimote_t structure.
|
|
* @param addr The address to write to.
|
|
* @param data The data to be written to the memory location.
|
|
* @param len The length of the block to be written.
|
|
*/
|
|
int wiiuse_write_data(struct wiimote_t* wm, unsigned int addr, byte* data, byte len) {
|
|
byte buf[21] = {0}; /* the payload is always 23 */
|
|
|
|
if (!wm || !WIIMOTE_IS_CONNECTED(wm))
|
|
return 0;
|
|
if (!data || !len)
|
|
return 0;
|
|
|
|
DEBUG_LOG(WIIMOTE, "Writing %i bytes to memory location 0x%x...", len, addr);
|
|
|
|
#ifdef WITH_WIIUSE_DEBUG
|
|
{
|
|
int i = 0;
|
|
printf("Write data is: ");
|
|
for (; i < len; ++i)
|
|
printf("%x ", data[i]);
|
|
printf("\n");
|
|
}
|
|
#endif
|
|
|
|
/* the offset is in big endian */
|
|
#ifdef __BIG_ENDIAN__
|
|
*(int*)(buf) = addr;
|
|
#else
|
|
*(int*)(buf) = Common::swap32(addr);
|
|
#endif
|
|
|
|
/* length */
|
|
*(byte*)(buf + 4) = len;
|
|
|
|
/* data */
|
|
memcpy(buf + 5, data, len);
|
|
|
|
wiiuse_send(wm, WM_CMD_WRITE_DATA, buf, 21);
|
|
return 1;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Send a packet to the wiimote.
|
|
*
|
|
* @param wm Pointer to a wiimote_t structure.
|
|
* @param report_type The report type to send (WIIMOTE_CMD_LED, WIIMOTE_CMD_RUMBLE, etc). Found in wiiuse.h
|
|
* @param msg The payload.
|
|
* @param len Length of the payload in bytes.
|
|
*
|
|
* This function should replace any write()s directly to the wiimote device.
|
|
*/
|
|
int wiiuse_send(struct wiimote_t* wm, byte report_type, byte* msg, int len) {
|
|
byte buf[32]; /* no payload is better than this */
|
|
int rumble = 0;
|
|
|
|
buf[0] = WM_SET_REPORT | WM_BT_OUTPUT;
|
|
buf[1] = report_type;
|
|
|
|
switch (report_type) {
|
|
case WM_CMD_LED:
|
|
case WM_CMD_RUMBLE:
|
|
case WM_CMD_CTRL_STATUS:
|
|
{
|
|
/* Rumble flag for: 0x11, 0x13, 0x14, 0x15, 0x19 or 0x1a */
|
|
if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_RUMBLE))
|
|
rumble = 1;
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
memcpy(buf+2, msg, len);
|
|
if (rumble)
|
|
buf[2] |= 0x01;
|
|
|
|
#ifdef WITH_WIIUSE_DEBUG
|
|
{
|
|
int x = 2;
|
|
printf("[DEBUG] (id %i) SEND: (%x) %.2x ", wm->unid, buf[0], buf[1]);
|
|
#ifndef _WIN32
|
|
for (; x < len+2; ++x)
|
|
#else
|
|
for (; x < len+1; ++x)
|
|
#endif
|
|
printf("%.2x ", buf[x]);
|
|
printf("\n");
|
|
}
|
|
#endif
|
|
|
|
return wiiuse_io_write(wm, buf, len+2);
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Set the normal and expansion handshake timeouts.
|
|
*
|
|
* @param wm Array of wiimote_t structures.
|
|
* @param wiimotes Number of objects in the wm array.
|
|
* @param normal_timeout The timeout in milliseconds for a normal read.
|
|
* @param exp_timeout The timeout in millisecondsd to wait for an expansion handshake.
|
|
*/
|
|
void wiiuse_set_timeout(struct wiimote_t** wm, int wiimotes, byte timeout) {
|
|
int i;
|
|
|
|
if (!wm) return;
|
|
|
|
for (i = 0; i < wiimotes; ++i) {
|
|
wm[i]->timeout = timeout;
|
|
}
|
|
}
|