2012-01-01 18:50:36 -05:00
|
|
|
/*
|
|
|
|
* 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 "wiiuse_internal.h"
|
2013-01-24 17:53:34 -05:00
|
|
|
#include "io.h" /* for wiiuse_handshake, etc */
|
|
|
|
#include "os.h" /* for wiiuse_os_* */
|
|
|
|
|
|
|
|
#include <stdio.h> /* for printf, FILE */
|
|
|
|
#include <stdlib.h> /* for malloc, free */
|
|
|
|
#include <string.h> /* for memcpy, memset */
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
static int g_banner = 0;
|
2013-01-24 17:53:34 -05:00
|
|
|
static const char g_wiiuse_version_string[] = WIIUSE_VERSION;
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
/**
|
2013-01-24 17:53:34 -05:00
|
|
|
* @brief Returns the version of the library.
|
2012-01-01 18:50:36 -05:00
|
|
|
*/
|
|
|
|
const char* wiiuse_version() {
|
2013-01-24 17:53:34 -05:00
|
|
|
return g_wiiuse_version_string;
|
2012-01-01 18:50:36 -05:00
|
|
|
}
|
|
|
|
|
2013-01-24 17:53:34 -05:00
|
|
|
/**
|
|
|
|
* @brief Output FILE stream for each wiiuse_loglevel.
|
|
|
|
*/
|
|
|
|
FILE* logtarget[4];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Specify an alternate FILE stream for a log level.
|
|
|
|
*
|
|
|
|
* @param loglevel The loglevel, for which the output should be set.
|
|
|
|
*
|
|
|
|
* @param logfile A valid, writeable <code>FILE*</code>, or 0, if output should be disabled.
|
|
|
|
*
|
|
|
|
* The default <code>FILE*</code> for all loglevels is <code>stderr</code>
|
|
|
|
*/
|
|
|
|
void wiiuse_set_output(enum wiiuse_loglevel loglevel, FILE *logfile) {
|
|
|
|
logtarget[(int)loglevel] = logfile;
|
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Clean up wiimote_t array created by wiiuse_init()
|
|
|
|
*/
|
|
|
|
void wiiuse_cleanup(struct wiimote_t** wm, int wiimotes) {
|
|
|
|
int i = 0;
|
|
|
|
|
2013-01-24 17:53:34 -05:00
|
|
|
if (!wm) {
|
2012-01-01 18:50:36 -05:00
|
|
|
return;
|
2013-01-24 17:53:34 -05:00
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
WIIUSE_INFO("wiiuse clean up...");
|
|
|
|
|
|
|
|
for (; i < wiimotes; ++i) {
|
|
|
|
wiiuse_disconnect(wm[i]);
|
2013-01-24 17:53:34 -05:00
|
|
|
wiiuse_cleanup_platform_fields(wm[i]);
|
2012-01-01 18:50:36 -05:00
|
|
|
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) {
|
2013-01-24 17:53:34 -05:00
|
|
|
printf("wiiuse v" WIIUSE_VERSION " loaded.\n"
|
|
|
|
" Fork at http://github.com/rpavlik/wiiuse\n"
|
|
|
|
" Original By: Michael Laforest <thepara[at]gmail{dot}com> http://wiiuse.net\n");
|
2012-01-01 18:50:36 -05:00
|
|
|
g_banner = 1;
|
|
|
|
}
|
|
|
|
|
2013-01-24 17:53:34 -05:00
|
|
|
logtarget[0] = stderr;
|
|
|
|
logtarget[1] = stderr;
|
|
|
|
logtarget[2] = stderr;
|
|
|
|
logtarget[3] = stderr;
|
|
|
|
|
|
|
|
if (!wiimotes) {
|
2012-01-01 18:50:36 -05:00
|
|
|
return NULL;
|
2013-01-24 17:53:34 -05:00
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
wm = malloc(sizeof(struct wiimote_t*) * wiimotes);
|
|
|
|
|
|
|
|
for (i = 0; i < wiimotes; ++i) {
|
|
|
|
wm[i] = malloc(sizeof(struct wiimote_t));
|
|
|
|
memset(wm[i], 0, sizeof(struct wiimote_t));
|
|
|
|
|
2013-01-24 17:53:34 -05:00
|
|
|
wm[i]->unid = i + 1;
|
|
|
|
wiiuse_init_platform_fields(wm[i]);
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
wm[i]->state = WIIMOTE_INIT_STATES;
|
|
|
|
wm[i]->flags = WIIUSE_INIT_FLAGS;
|
|
|
|
|
|
|
|
wm[i]->event = WIIUSE_NONE;
|
|
|
|
|
|
|
|
wm[i]->exp.type = EXP_NONE;
|
2013-01-24 17:53:34 -05:00
|
|
|
wm[i]->expansion_state = 0;
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
wiiuse_set_aspect_ratio(wm[i], WIIUSE_ASPECT_4_3);
|
|
|
|
wiiuse_set_ir_position(wm[i], WIIUSE_IR_ABOVE);
|
|
|
|
|
|
|
|
wm[i]->orient_threshold = 0.5f;
|
|
|
|
wm[i]->accel_threshold = 5;
|
|
|
|
|
|
|
|
wm[i]->accel_calib.st_alpha = WIIUSE_DEFAULT_SMOOTH_ALPHA;
|
2013-06-05 03:24:42 -04:00
|
|
|
|
|
|
|
wm[i]->type = WIIUSE_WIIMOTE_REGULAR;
|
2012-01-01 18:50:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return wm;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief The wiimote disconnected.
|
|
|
|
*
|
|
|
|
* @param wm Pointer to a wiimote_t structure.
|
|
|
|
*/
|
|
|
|
void wiiuse_disconnected(struct wiimote_t* wm) {
|
2013-01-24 17:53:34 -05:00
|
|
|
if (!wm) {
|
|
|
|
return;
|
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
WIIUSE_INFO("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;
|
|
|
|
wm->read_req = NULL;
|
2013-01-24 17:53:34 -05:00
|
|
|
#ifndef WIIUSE_SYNC_HANDSHAKE
|
2012-01-01 18:50:36 -05:00
|
|
|
wm->handshake_state = 0;
|
2013-01-24 17:53:34 -05:00
|
|
|
#endif
|
2012-01-01 18:50:36 -05:00
|
|
|
wm->btns = 0;
|
|
|
|
wm->btns_held = 0;
|
|
|
|
wm->btns_released = 0;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2013-01-24 17:53:34 -05:00
|
|
|
if (!wm || !WIIMOTE_IS_CONNECTED(wm)) {
|
2012-01-01 18:50:36 -05:00
|
|
|
return;
|
2013-01-24 17:53:34 -05:00
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
/* make sure to keep the current lit leds */
|
|
|
|
buf = wm->leds;
|
|
|
|
|
|
|
|
if (status) {
|
|
|
|
WIIUSE_DEBUG("Starting rumble...");
|
|
|
|
WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_RUMBLE);
|
|
|
|
buf |= 0x01;
|
|
|
|
} else {
|
|
|
|
WIIUSE_DEBUG("Stopping rumble...");
|
|
|
|
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_RUMBLE);
|
2013-01-24 17:53:34 -05:00
|
|
|
buf &= ~(0x01);
|
2012-01-01 18:50:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* preserve IR state */
|
2013-01-24 17:53:34 -05:00
|
|
|
if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) {
|
2012-01-01 18:50:36 -05:00
|
|
|
buf |= 0x04;
|
2013-01-24 17:53:34 -05:00
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
wiiuse_send(wm, WM_CMD_RUMBLE, &buf, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Toggle the state of the rumble.
|
|
|
|
*
|
|
|
|
* @param wm Pointer to a wiimote_t structure.
|
|
|
|
*/
|
|
|
|
void wiiuse_toggle_rumble(struct wiimote_t* wm) {
|
2013-01-24 17:53:34 -05:00
|
|
|
if (!wm) {
|
|
|
|
return;
|
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
wiiuse_rumble(wm, !WIIMOTE_IS_SET(wm, WIIMOTE_STATE_RUMBLE));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @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;
|
|
|
|
|
2013-01-24 17:53:34 -05:00
|
|
|
if (!wm || !WIIMOTE_IS_CONNECTED(wm)) {
|
2012-01-01 18:50:36 -05:00
|
|
|
return;
|
2013-01-24 17:53:34 -05:00
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
/* remove the lower 4 bits because they control rumble */
|
|
|
|
wm->leds = (leds & 0xF0);
|
|
|
|
|
|
|
|
/* make sure if the rumble is on that we keep it on */
|
2013-01-24 17:53:34 -05:00
|
|
|
if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_RUMBLE)) {
|
2012-01-01 18:50:36 -05:00
|
|
|
wm->leds |= 0x01;
|
2013-01-24 17:53:34 -05:00
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
buf = wm->leds;
|
|
|
|
|
|
|
|
wiiuse_send(wm, WM_CMD_LED, &buf, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set if the wiimote should report motion sensing.
|
|
|
|
*
|
|
|
|
* @param wm Pointer to a wiimote_t structure.
|
|
|
|
* @param status 1 to enable, 0 to disable.
|
|
|
|
*
|
|
|
|
* Since reporting motion sensing sends a lot of data,
|
|
|
|
* the wiimote saves power by not transmitting it
|
|
|
|
* by default.
|
|
|
|
*/
|
|
|
|
void wiiuse_motion_sensing(struct wiimote_t* wm, int status) {
|
2013-01-24 17:53:34 -05:00
|
|
|
if (status) {
|
2012-01-01 18:50:36 -05:00
|
|
|
WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_ACC);
|
2013-01-24 17:53:34 -05:00
|
|
|
} else {
|
2012-01-01 18:50:36 -05:00
|
|
|
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_ACC);
|
2013-01-24 17:53:34 -05:00
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
wiiuse_set_report_type(wm);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @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, exp, ir;
|
|
|
|
|
2013-01-24 17:53:34 -05:00
|
|
|
if (!wm || !WIIMOTE_IS_CONNECTED(wm)) {
|
2012-01-01 18:50:36 -05:00
|
|
|
return 0;
|
2013-01-24 17:53:34 -05:00
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
buf[0] = (WIIMOTE_IS_FLAG_SET(wm, WIIUSE_CONTINUOUS) ? 0x04 : 0x00); /* set to 0x04 for continuous reporting */
|
|
|
|
buf[1] = 0x00;
|
|
|
|
|
|
|
|
/* if rumble is enabled, make sure we keep it */
|
2013-01-24 17:53:34 -05:00
|
|
|
if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_RUMBLE)) {
|
2012-01-01 18:50:36 -05:00
|
|
|
buf[0] |= 0x01;
|
2013-01-24 17:53:34 -05:00
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
motion = WIIMOTE_IS_SET(wm, WIIMOTE_STATE_ACC);
|
|
|
|
exp = WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP);
|
|
|
|
ir = WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR);
|
|
|
|
|
2013-01-24 17:53:34 -05:00
|
|
|
if (motion && ir && exp) {
|
|
|
|
buf[1] = WM_RPT_BTN_ACC_IR_EXP;
|
|
|
|
} else if (motion && exp) {
|
|
|
|
buf[1] = WM_RPT_BTN_ACC_EXP;
|
|
|
|
} else if (motion && ir) {
|
|
|
|
buf[1] = WM_RPT_BTN_ACC_IR;
|
|
|
|
} else if (ir && exp) {
|
|
|
|
buf[1] = WM_RPT_BTN_IR_EXP;
|
|
|
|
} else if (ir) {
|
|
|
|
buf[1] = WM_RPT_BTN_ACC_IR;
|
|
|
|
} else if (exp) {
|
|
|
|
buf[1] = WM_RPT_BTN_EXP;
|
|
|
|
} else if (motion) {
|
|
|
|
buf[1] = WM_RPT_BTN_ACC;
|
|
|
|
} else {
|
|
|
|
buf[1] = WM_RPT_BTN;
|
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
WIIUSE_DEBUG("Setting report type: 0x%x", buf[1]);
|
|
|
|
|
|
|
|
exp = wiiuse_send(wm, WM_CMD_REPORT_TYPE, buf, 2);
|
2013-01-24 17:53:34 -05:00
|
|
|
if (exp <= 0) {
|
2012-01-01 18:50:36 -05:00
|
|
|
return exp;
|
2013-01-24 17:53:34 -05:00
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
return buf[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Read data from the wiimote (callback version).
|
|
|
|
*
|
|
|
|
* @param wm Pointer to a wiimote_t structure.
|
|
|
|
* @param read_cb Function pointer to call when the data arrives from the wiimote.
|
|
|
|
* @param buffer An allocated buffer to store the data as it arrives from the wiimote.
|
|
|
|
* Must be persistent in memory and large enough to hold the data.
|
|
|
|
* @param addr The address of wiimote memory to read from.
|
|
|
|
* @param len The length of the block to be read.
|
|
|
|
*
|
|
|
|
* The library can only handle one data read request at a time
|
|
|
|
* because it must keep track of the buffer and other
|
|
|
|
* events that are specific to that request. So if a request
|
|
|
|
* has already been made, subsequent requests will be added
|
|
|
|
* to a pending list and be sent out when the previous
|
|
|
|
* finishes.
|
|
|
|
*/
|
2013-01-24 17:53:34 -05:00
|
|
|
int wiiuse_read_data_cb(struct wiimote_t* wm, wiiuse_read_cb read_cb, byte* buffer, unsigned int addr, uint16_t len) {
|
2012-01-01 18:50:36 -05:00
|
|
|
struct read_req_t* req;
|
|
|
|
|
2013-01-24 17:53:34 -05:00
|
|
|
if (!wm || !WIIMOTE_IS_CONNECTED(wm)) {
|
2012-01-01 18:50:36 -05:00
|
|
|
return 0;
|
2013-01-24 17:53:34 -05:00
|
|
|
}
|
|
|
|
if (!buffer || !len) {
|
2012-01-01 18:50:36 -05:00
|
|
|
return 0;
|
2013-01-24 17:53:34 -05:00
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
/* make this request structure */
|
|
|
|
req = (struct read_req_t*)malloc(sizeof(struct read_req_t));
|
2013-01-24 17:53:34 -05:00
|
|
|
if (req == NULL) {
|
|
|
|
return 0;
|
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
req->cb = read_cb;
|
|
|
|
req->buf = buffer;
|
|
|
|
req->addr = addr;
|
|
|
|
req->size = len;
|
2012-01-01 16:19:13 -05:00
|
|
|
req->wait = len;
|
2012-01-01 18:50:36 -05:00
|
|
|
req->dirty = 0;
|
|
|
|
req->next = NULL;
|
|
|
|
|
|
|
|
/* add this to the request list */
|
|
|
|
if (!wm->read_req) {
|
|
|
|
/* root node */
|
|
|
|
wm->read_req = req;
|
|
|
|
|
|
|
|
WIIUSE_DEBUG("Data read request can be sent out immediately.");
|
|
|
|
|
|
|
|
/* send the request out immediately */
|
|
|
|
wiiuse_send_next_pending_read_request(wm);
|
|
|
|
} else {
|
|
|
|
struct read_req_t* nptr = wm->read_req;
|
2013-01-24 17:53:34 -05:00
|
|
|
for (; nptr->next; nptr = nptr->next) {
|
|
|
|
;
|
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
nptr->next = req;
|
|
|
|
|
|
|
|
WIIUSE_DEBUG("Added pending data read request.");
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-01-01 16:19:13 -05:00
|
|
|
/**
|
|
|
|
* @brief Read data from the wiimote (event version).
|
|
|
|
*
|
|
|
|
* @param wm Pointer to a wiimote_t structure.
|
|
|
|
* @param buffer An allocated buffer to store the data as it arrives from the wiimote.
|
|
|
|
* Must be persistent in memory and large enough to hold the data.
|
|
|
|
* @param addr The address of wiimote memory to read from.
|
|
|
|
* @param len The length of the block to be read.
|
|
|
|
*
|
|
|
|
* The library can only handle one data read request at a time
|
|
|
|
* because it must keep track of the buffer and other
|
|
|
|
* events that are specific to that request. So if a request
|
|
|
|
* has already been made, subsequent requests will be added
|
|
|
|
* to a pending list and be sent out when the previous
|
|
|
|
* finishes.
|
|
|
|
*/
|
2013-01-24 17:53:34 -05:00
|
|
|
int wiiuse_read_data(struct wiimote_t* wm, byte* buffer, unsigned int addr, uint16_t len) {
|
|
|
|
return wiiuse_read_data_cb(wm, NULL, buffer, addr, len);
|
2012-01-01 16:19:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-01-01 18:50:36 -05:00
|
|
|
/**
|
|
|
|
* @brief Send the next pending data read request to the wiimote.
|
|
|
|
*
|
|
|
|
* @param wm Pointer to a wiimote_t structure.
|
|
|
|
*
|
|
|
|
* @see wiiuse_read_data()
|
|
|
|
*
|
|
|
|
* This function is not part of the wiiuse API.
|
|
|
|
*/
|
|
|
|
void wiiuse_send_next_pending_read_request(struct wiimote_t* wm) {
|
|
|
|
byte buf[6];
|
|
|
|
struct read_req_t* req;
|
|
|
|
|
2013-01-24 17:53:34 -05:00
|
|
|
if (!wm || !WIIMOTE_IS_CONNECTED(wm)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!wm->read_req) {
|
2012-01-01 18:50:36 -05:00
|
|
|
return;
|
2013-01-24 17:53:34 -05:00
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
|
2012-01-01 16:19:13 -05:00
|
|
|
/* skip over dirty ones since they have already been read */
|
|
|
|
req = wm->read_req;
|
2013-01-24 17:53:34 -05:00
|
|
|
while (req && req->dirty) {
|
2012-01-01 16:19:13 -05:00
|
|
|
req = req->next;
|
2013-01-24 17:53:34 -05:00
|
|
|
}
|
|
|
|
if (!req) {
|
2012-01-01 18:50:36 -05:00
|
|
|
return;
|
2013-01-24 17:53:34 -05:00
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
/* the offset is in big endian */
|
2013-01-24 17:53:34 -05:00
|
|
|
to_big_endian_uint32_t(buf, req->addr);
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
/* the length is in big endian */
|
2013-01-24 17:53:34 -05:00
|
|
|
to_big_endian_uint16_t(buf + 4, req->size);
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
WIIUSE_DEBUG("Request read at address: 0x%x length: %i", req->addr, req->size);
|
|
|
|
wiiuse_send(wm, WM_CMD_READ_DATA, buf, 6);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Request the wiimote controller status.
|
|
|
|
*
|
|
|
|
* @param wm Pointer to a wiimote_t structure.
|
|
|
|
*
|
|
|
|
* Controller status includes: battery level, LED status, expansions
|
|
|
|
*/
|
|
|
|
void wiiuse_status(struct wiimote_t* wm) {
|
|
|
|
byte buf = 0;
|
|
|
|
|
2013-01-24 17:53:34 -05:00
|
|
|
if (!wm || !WIIMOTE_IS_CONNECTED(wm)) {
|
2012-01-01 18:50:36 -05:00
|
|
|
return;
|
2013-01-24 17:53:34 -05:00
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
WIIUSE_DEBUG("Requested wiimote status.");
|
|
|
|
|
|
|
|
wiiuse_send(wm, WM_CMD_CTRL_STATUS, &buf, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Find a wiimote_t structure by its unique identifier.
|
|
|
|
*
|
|
|
|
* @param wm Pointer to a wiimote_t structure.
|
|
|
|
* @param wiimotes The number of wiimote_t structures in \a wm.
|
|
|
|
* @param unid The unique identifier to search for.
|
|
|
|
*
|
|
|
|
* @return Pointer to a wiimote_t structure, or NULL if not found.
|
|
|
|
*/
|
|
|
|
struct wiimote_t* wiiuse_get_by_id(struct wiimote_t** wm, int wiimotes, int unid) {
|
|
|
|
int i = 0;
|
2013-01-24 17:53:34 -05:00
|
|
|
if (!wm) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
for (; i < wiimotes; ++i) {
|
2013-01-24 17:53:34 -05:00
|
|
|
if (!wm[i]) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (wm[i]->unid == unid) {
|
2012-01-01 18:50:36 -05:00
|
|
|
return wm[i];
|
2013-01-24 17:53:34 -05:00
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @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.
|
|
|
|
*/
|
2013-01-24 17:53:34 -05:00
|
|
|
int wiiuse_write_data(struct wiimote_t* wm, unsigned int addr, const byte* data, byte len) {
|
2012-01-01 18:50:36 -05:00
|
|
|
byte buf[21] = {0}; /* the payload is always 23 */
|
|
|
|
|
2013-01-24 17:53:34 -05:00
|
|
|
byte * bufPtr = buf;
|
|
|
|
if (!wm || !WIIMOTE_IS_CONNECTED(wm)) {
|
2012-01-01 18:50:36 -05:00
|
|
|
return 0;
|
2013-01-24 17:53:34 -05:00
|
|
|
}
|
|
|
|
if (!data || !len) {
|
2012-01-01 18:50:36 -05:00
|
|
|
return 0;
|
2013-01-24 17:53:34 -05:00
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
WIIUSE_DEBUG("Writing %i bytes to memory location 0x%x...", len, addr);
|
|
|
|
|
2013-01-24 17:53:34 -05:00
|
|
|
#ifdef WITH_WIIUSE_DEBUG
|
2012-01-01 18:50:36 -05:00
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
printf("Write data is: ");
|
2013-01-24 17:53:34 -05:00
|
|
|
for (; i < len; ++i) {
|
2012-01-01 18:50:36 -05:00
|
|
|
printf("%x ", data[i]);
|
2013-01-24 17:53:34 -05:00
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
printf("\n");
|
|
|
|
}
|
2013-01-24 17:53:34 -05:00
|
|
|
#endif
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
/* the offset is in big endian */
|
2013-01-24 17:53:34 -05:00
|
|
|
buffer_big_endian_uint32_t(&bufPtr, (uint32_t)addr);
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
/* length */
|
2013-01-24 17:53:34 -05:00
|
|
|
buffer_big_endian_uint8_t(&bufPtr, len);
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
/* data */
|
2013-01-24 17:53:34 -05:00
|
|
|
memcpy(bufPtr, data, len);
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
wiiuse_send(wm, WM_CMD_WRITE_DATA, buf, 21);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-01-24 17:53:34 -05:00
|
|
|
/**
|
|
|
|
* @brief Write data to the wiimote (callback version).
|
|
|
|
*
|
|
|
|
* @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.
|
|
|
|
* @param cb Function pointer to call when the data arrives from the wiimote.
|
|
|
|
*
|
|
|
|
* The library can only handle one data read request at a time
|
|
|
|
* because it must keep track of the buffer and other
|
|
|
|
* events that are specific to that request. So if a request
|
|
|
|
* has already been made, subsequent requests will be added
|
|
|
|
* to a pending list and be sent out when the previous
|
|
|
|
* finishes.
|
|
|
|
*/
|
|
|
|
int wiiuse_write_data_cb(struct wiimote_t *wm, unsigned int addr, byte *data, byte len, wiiuse_write_cb write_cb) {
|
|
|
|
struct data_req_t* req;
|
|
|
|
|
|
|
|
if (!wm || !WIIMOTE_IS_CONNECTED(wm)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (!data || !len) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
req = (struct data_req_t*)malloc(sizeof(struct data_req_t));
|
|
|
|
req->cb = write_cb;
|
|
|
|
req->len = len;
|
|
|
|
memcpy(req->data, data, req->len);
|
|
|
|
req->state = REQ_READY;
|
|
|
|
req->addr = addr;/* BIG_ENDIAN_LONG(addr); */
|
|
|
|
req->next = NULL;
|
|
|
|
/* add this to the request list */
|
|
|
|
if (!wm->data_req) {
|
|
|
|
/* root node */
|
|
|
|
wm->data_req = req;
|
|
|
|
|
|
|
|
WIIUSE_DEBUG("Data write request can be sent out immediately.");
|
|
|
|
|
|
|
|
/* send the request out immediately */
|
|
|
|
wiiuse_send_next_pending_write_request(wm);
|
|
|
|
} else {
|
|
|
|
struct data_req_t* nptr = wm->data_req;
|
|
|
|
WIIUSE_DEBUG("chaud2fois");
|
|
|
|
for (; nptr->next; nptr = nptr->next) {
|
|
|
|
;
|
|
|
|
}
|
|
|
|
nptr->next = req;
|
|
|
|
|
|
|
|
WIIUSE_DEBUG("Added pending data write request.");
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Send the next pending data write request to the wiimote.
|
|
|
|
*
|
|
|
|
* @param wm Pointer to a wiimote_t structure.
|
|
|
|
*
|
|
|
|
* @see wiiuse_write_data()
|
|
|
|
*
|
|
|
|
* This function is not part of the wiiuse API.
|
|
|
|
*/
|
|
|
|
void wiiuse_send_next_pending_write_request(struct wiimote_t* wm) {
|
|
|
|
struct data_req_t* req;
|
|
|
|
|
|
|
|
if (!wm || !WIIMOTE_IS_CONNECTED(wm)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
req = wm->data_req;
|
|
|
|
if (!req) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!req->data || !req->len) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (req->state != REQ_READY) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
wiiuse_write_data(wm, req->addr, req->data, req->len);
|
|
|
|
|
|
|
|
req->state = REQ_SENT;
|
|
|
|
return;
|
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @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
|
2013-01-24 17:53:34 -05:00
|
|
|
* @param msg The payload. Might be changed by the callee.
|
2012-01-01 18:50:36 -05:00
|
|
|
* @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) {
|
|
|
|
switch (report_type) {
|
|
|
|
case WM_CMD_LED:
|
|
|
|
case WM_CMD_RUMBLE:
|
2013-01-24 17:53:34 -05:00
|
|
|
case WM_CMD_CTRL_STATUS: {
|
|
|
|
/* Rumble flag for: 0x11, 0x13, 0x14, 0x15, 0x19 or 0x1a */
|
|
|
|
if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_RUMBLE)) {
|
|
|
|
msg[0] |= 0x01;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-01-24 17:53:34 -05:00
|
|
|
#ifdef WITH_WIIUSE_DEBUG
|
2012-01-01 18:50:36 -05:00
|
|
|
{
|
2013-01-24 17:53:34 -05:00
|
|
|
int x;
|
|
|
|
printf("[DEBUG] (id %i) SEND: (%.2x) %.2x ", wm->unid, report_type, msg[0]);
|
|
|
|
for (x = 1; x < len; ++x) {
|
|
|
|
printf("%.2x ", msg[x]);
|
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
printf("\n");
|
|
|
|
}
|
2013-01-24 17:53:34 -05:00
|
|
|
#endif
|
2012-01-01 18:50:36 -05:00
|
|
|
|
2013-01-24 17:53:34 -05:00
|
|
|
return wiiuse_os_write(wm, report_type, msg, len);
|
2012-01-01 18:50:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set flags for the specified wiimote.
|
|
|
|
*
|
|
|
|
* @param wm Pointer to a wiimote_t structure.
|
|
|
|
* @param enable Flags to enable.
|
|
|
|
* @param disable Flags to disable.
|
|
|
|
*
|
|
|
|
* @return The flags set after 'enable' and 'disable' have been applied.
|
|
|
|
*
|
|
|
|
* The values 'enable' and 'disable' may be any flags OR'ed together.
|
|
|
|
* Flags are defined in wiiuse.h.
|
|
|
|
*/
|
|
|
|
int wiiuse_set_flags(struct wiimote_t* wm, int enable, int disable) {
|
2013-01-24 17:53:34 -05:00
|
|
|
if (!wm) {
|
|
|
|
return 0;
|
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
/* remove mutually exclusive flags */
|
|
|
|
enable &= ~disable;
|
|
|
|
disable &= ~enable;
|
|
|
|
|
|
|
|
wm->flags |= enable;
|
|
|
|
wm->flags &= ~disable;
|
|
|
|
|
|
|
|
return wm->flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set the wiimote smoothing alpha value.
|
|
|
|
*
|
|
|
|
* @param wm Pointer to a wiimote_t structure.
|
|
|
|
* @param alpha The alpha value to set. Between 0 and 1.
|
|
|
|
*
|
|
|
|
* @return Returns the old alpha value.
|
|
|
|
*
|
|
|
|
* The alpha value is between 0 and 1 and is used in an exponential
|
|
|
|
* smoothing algorithm.
|
|
|
|
*
|
|
|
|
* Smoothing is only performed if the WIIMOTE_USE_SMOOTHING is set.
|
|
|
|
*/
|
|
|
|
float wiiuse_set_smooth_alpha(struct wiimote_t* wm, float alpha) {
|
|
|
|
float old;
|
|
|
|
|
2013-01-24 17:53:34 -05:00
|
|
|
if (!wm) {
|
|
|
|
return 0.0f;
|
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
old = wm->accel_calib.st_alpha;
|
|
|
|
|
|
|
|
wm->accel_calib.st_alpha = alpha;
|
|
|
|
|
|
|
|
/* if there is a nunchuk set that too */
|
2013-01-24 17:53:34 -05:00
|
|
|
if (wm->exp.type == EXP_NUNCHUK) {
|
2012-01-01 18:50:36 -05:00
|
|
|
wm->exp.nunchuk.accel_calib.st_alpha = alpha;
|
2013-01-24 17:53:34 -05:00
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
return old;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set the bluetooth stack type to use.
|
|
|
|
*
|
|
|
|
* @param wm Array of wiimote_t structures.
|
|
|
|
* @param wiimotes Number of objects in the wm array.
|
|
|
|
* @param type The type of bluetooth stack to use.
|
|
|
|
*/
|
|
|
|
void wiiuse_set_bluetooth_stack(struct wiimote_t** wm, int wiimotes, enum win_bt_stack_t type) {
|
2013-01-24 17:53:34 -05:00
|
|
|
#ifdef WIIUSE_WIN32
|
2012-01-01 18:50:36 -05:00
|
|
|
int i;
|
|
|
|
|
2013-01-24 17:53:34 -05:00
|
|
|
if (!wm) {
|
|
|
|
return;
|
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
|
2013-01-24 17:53:34 -05:00
|
|
|
for (i = 0; i < wiimotes; ++i) {
|
2012-01-01 18:50:36 -05:00
|
|
|
wm[i]->stack = type;
|
2013-01-24 17:53:34 -05:00
|
|
|
}
|
|
|
|
#endif
|
2012-01-01 18:50:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set the orientation event threshold.
|
|
|
|
*
|
|
|
|
* @param wm Pointer to a wiimote_t structure.
|
|
|
|
* @param threshold The decimal place that should be considered a significant change.
|
|
|
|
*
|
|
|
|
* If threshold is 0.01, and any angle changes by 0.01 then a significant change
|
2013-01-24 17:53:34 -05:00
|
|
|
* has occurred and the event callback will be invoked. If threshold is 1 then
|
2012-01-01 18:50:36 -05:00
|
|
|
* the angle has to change by a full degree to generate an event.
|
|
|
|
*/
|
|
|
|
void wiiuse_set_orient_threshold(struct wiimote_t* wm, float threshold) {
|
2013-01-24 17:53:34 -05:00
|
|
|
if (!wm) {
|
|
|
|
return;
|
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
wm->orient_threshold = threshold;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set the accelerometer event threshold.
|
|
|
|
*
|
|
|
|
* @param wm Pointer to a wiimote_t structure.
|
|
|
|
* @param threshold The decimal place that should be considered a significant change.
|
|
|
|
*/
|
|
|
|
void wiiuse_set_accel_threshold(struct wiimote_t* wm, int threshold) {
|
2013-01-24 17:53:34 -05:00
|
|
|
if (!wm) {
|
|
|
|
return;
|
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
wm->accel_threshold = threshold;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Try to resync with the wiimote by starting a new handshake.
|
|
|
|
*
|
|
|
|
* @param wm Pointer to a wiimote_t structure.
|
|
|
|
*/
|
|
|
|
void wiiuse_resync(struct wiimote_t* wm) {
|
2013-01-24 17:53:34 -05:00
|
|
|
if (!wm) {
|
|
|
|
return;
|
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
|
2013-01-24 17:53:34 -05:00
|
|
|
#ifndef WIIUSE_SYNC_HANDSHAKE
|
2012-01-01 18:50:36 -05:00
|
|
|
wm->handshake_state = 0;
|
2013-01-24 17:53:34 -05:00
|
|
|
#endif
|
2012-01-01 18:50:36 -05:00
|
|
|
wiiuse_handshake(wm, NULL, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @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 normal_timeout, byte exp_timeout) {
|
2013-01-24 17:53:34 -05:00
|
|
|
#ifdef WIIUSE_WIN32
|
2012-01-01 18:50:36 -05:00
|
|
|
int i;
|
|
|
|
|
2013-01-24 17:53:34 -05:00
|
|
|
if (!wm) {
|
|
|
|
return;
|
|
|
|
}
|
2012-01-01 18:50:36 -05:00
|
|
|
|
|
|
|
for (i = 0; i < wiimotes; ++i) {
|
|
|
|
wm[i]->normal_timeout = normal_timeout;
|
|
|
|
wm[i]->exp_timeout = exp_timeout;
|
|
|
|
}
|
2013-01-24 17:53:34 -05:00
|
|
|
#endif
|
2012-01-01 18:50:36 -05:00
|
|
|
}
|