Merge remote-tracking branch 'origin/motionplus'

This commit is contained in:
Ryan Pavlik
2011-09-27 17:28:52 -05:00
13 changed files with 801 additions and 78 deletions

View File

@@ -23,6 +23,9 @@ Added:
client app as well as choosing the appropriate option when building
WiiUse. The default is still a shared library (dll/so). Merged from
paulburton and added to build system.
- Initial MotionPlus support. Thanks to admiral0 for the initial pull
request merging from fwiine, and to Jan Ciger Reviatech SAS for building
on it with fwiine and WiiC code as well as additional code.
Fixed:
@@ -31,6 +34,9 @@ Fixed:
- Builds properly now on mingw (both cross-compile and native).
- Improved reliability on Windows when running an app twice without dis-connecting
the Wiimote (came as a part of the MotionPlus support.)
Changed:
- Improved header includes using feedback from (include-what-you-use)[iwyu]

View File

@@ -53,7 +53,9 @@ Additional Contributors:
- Karl Semich <https://github.com/xloem>
- Johannes Zarl <johannes.zarl@jku.at>
- hartsantler <http://code.google.com/p/rpythonic/>
- admiral0 and fwiine project <http://sourceforge.net/projects/fwiine/files/wiiuse/0.13/>
- Jeff Baker/Inv3rsion, LLC. <http://www.inv3rsion.com/>
- Jan Ciger - Reviatech SAS <jan.ciger@reviatech.com>
License
@@ -170,6 +172,12 @@ Known Issues
On Windows using more than one wiimote (usually more than two wiimotes)
may cause significant latency.
If you are going to use Motion+, make sure to call wiiuse_poll or wiiuse_update
in a loop for some 10-15 seconds before enabling it. Ideally you should be checking
the status of any expansion (nunchuk) you may have connected as well.
Otherwise the extra expansion may not initialize correctly - the initialization
and calibration takes some time.
Acknowledgements by Michael Laforest
------------------------------------
<http://wiibrew.org/>

View File

@@ -13,6 +13,8 @@ set(SOURCES
dynamics.h
events.h
guitar_hero_3.h
motion_plus.h
motion_plus.c
io.h
ir.h
nunchuk.h

View File

@@ -43,6 +43,7 @@
#include "ir.h" /* for calculate_basic_ir, etc */
#include "nunchuk.h" /* for nunchuk_disconnected, etc */
#include "wiiboard.h" /* for wii_board_disconnected, etc */
#include "motion_plus.h" /* for motion_plus_disconnected, etc */
#include "io.h" /* for wiiuse_io_read on Windows, etc */
#ifndef WIIUSE_WIN32
@@ -60,6 +61,7 @@ static void idle_cycle(struct wiimote_t* wm);
static void clear_dirty_reads(struct wiimote_t* wm);
static void propagate_event(struct wiimote_t* wm, byte event, byte* msg);
static void event_data_read(struct wiimote_t* wm, byte* msg);
static void event_data_write(struct wiimote_t *wm, byte *msg);
static void event_status(struct wiimote_t* wm, byte* msg);
static void handle_expansion(struct wiimote_t* wm, byte* msg);
@@ -396,7 +398,7 @@ static void propagate_event(struct wiimote_t* wm, byte event, byte* msg) {
}
case WM_RPT_WRITE:
{
/* write feedback - safe to skip */
event_data_write(wm,msg);
break;
}
default:
@@ -546,6 +548,52 @@ static void event_data_read(struct wiimote_t* wm, byte* msg) {
}
static void event_data_write(struct wiimote_t *wm, byte *msg)
{
struct data_req_t* req = wm->data_req;
wiiuse_pressed_buttons(wm,msg);
/* if we don't have a request out then we didn't ask for this packet */
if (!req) {
WIIUSE_WARNING("Transmitting data packet when no request was made.");
return;
}
if(!(req->state==REQ_SENT)) {
WIIUSE_WARNING("Transmission is not necessary");
/* delete this request */
wm->data_req = req->next;
free(req);
return;
}
req->state = REQ_DONE;
if(req->cb) {
/* this was a callback, so invoke it now */
req->cb(wm,NULL,0);
/* delete this request */
wm->data_req = req->next;
free(req);
} else {
/*
* This should generate an event.
* We need to leave the event in the array so the client
* can access it still. We'll flag is as being 'REQ_DONE'
* and give the client one cycle to use it. Next event
* we will remove it from the list.
*/
wm->event = WIIUSE_WRITE_DATA;
}
/* if another request exists send it to the wiimote */
if (wm->data_req) {
wiiuse_send_next_pending_write_request(wm);
}
}
/**
* @brief Read the controller status.
*
@@ -559,6 +607,11 @@ static void event_status(struct wiimote_t* wm, byte* msg) {
int attachment = 0;
int ir = 0;
int exp_changed = 0;
struct data_req_t* req = wm->data_req;
/* initial handshake is not finished yet, ignore this */
if(WIIMOTE_IS_SET(wm, WIIMOTE_STATE_HANDSHAKE))
return;
/*
* An event occured.
@@ -613,15 +666,27 @@ static void event_status(struct wiimote_t* wm, byte* msg) {
* We need to send a WIIMOTE_CMD_REPORT_TYPE packet to
* reenable other incoming reports.
*/
if (exp_changed && WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) {
if (exp_changed && WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR))
{
/*
* Since the expansion status changed IR needs to
* be reset for the new IR report mode.
* Since the expansion status changed IR needs to
* be reset for the new IR report mode.
*/
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR);
wiiuse_set_ir(wm, 1);
} else
} else {
wiiuse_set_report_type(wm);
return;
}
/* handling new Tx for changed exp */
if(!req) return;
if(!(req->state==REQ_SENT)) return;
wm->data_req = req->next;
req->state = REQ_DONE;
/* if(req->cb!=NULL) req->cb(wm,msg,6); */
free(req);
wiiuse_send_next_pending_write_request(wm);
}
@@ -645,6 +710,11 @@ static void handle_expansion(struct wiimote_t* wm, byte* msg) {
case EXP_WII_BOARD:
wii_board_event(&wm->exp.wb, msg);
break;
case EXP_MOTION_PLUS:
case EXP_MOTION_PLUS_CLASSIC:
case EXP_MOTION_PLUS_NUNCHUK:
motion_plus_event(&wm->exp.mp, wm->exp.type, msg);
break;
default:
break;
}
@@ -666,68 +736,76 @@ static void handle_expansion(struct wiimote_t* wm, byte* msg) {
*/
void handshake_expansion(struct wiimote_t* wm, byte* data, uint16_t len) {
int id;
byte val = 0;
byte buf = 0x00;
byte* handshake_buf;
if (!data) {
byte* handshake_buf;
byte buf = 0x00;
switch(wm->expansion_state) {
/* These two initialization writes disable the encryption */
case 0:
wm->expansion_state = 1;
/* increase the timeout until the handshake completes */
#ifdef WIIUSE_WIN32
WIIUSE_DEBUG("write 0x55 - Setting timeout to expansion %i ms.", wm->exp_timeout);
wm->timeout = wm->exp_timeout;
#endif
buf = 0x55;
wiiuse_write_data_cb(wm, WM_EXP_MEM_ENABLE1, &buf, 1, handshake_expansion);
break;
case 1:
wm->expansion_state = 2;
/* increase the timeout until the handshake completes */
#ifdef WIIUSE_WIN32
WIIUSE_DEBUG("write 0x00 - Setting timeout to expansion %i ms.", wm->exp_timeout);
wm->timeout = wm->exp_timeout;
#endif
val = 0x00;
wiiuse_write_data_cb(wm, WM_EXP_MEM_ENABLE2, &buf, 1, handshake_expansion);
break;
case 2:
wm->expansion_state = 3;
/* get the calibration data */
if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP))
disable_expansion(wm);
handshake_buf = malloc(EXP_HANDSHAKE_LEN * sizeof(byte));
wiiuse_read_data_cb(wm, handshake_expansion, handshake_buf, WM_EXP_MEM_CALIBR, EXP_HANDSHAKE_LEN);
if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP))
disable_expansion(wm);
/* increase the timeout until the handshake completes */
#ifdef WIIUSE_WIN32
WIIUSE_DEBUG("Setting timeout to expansion %i ms.", wm->exp_timeout);
wm->timeout = wm->exp_timeout;
#endif
wiiuse_write_data(wm, WM_EXP_MEM_ENABLE, &buf, 1);
/* get the calibration data */
handshake_buf = (byte *)malloc(EXP_HANDSHAKE_LEN * sizeof(byte));
wiiuse_read_data_cb(wm, handshake_expansion, handshake_buf, WM_EXP_MEM_CALIBR, EXP_HANDSHAKE_LEN);
/* tell the wiimote to send expansion data */
WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_EXP);
return;
/* tell the wiimote to send expansion data */
WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_EXP);
break;
case 3:
if(!data || !len) return;
id = from_big_endian_uint32_t(data + 220);
switch(id) {
case EXP_ID_CODE_NUNCHUK:
if (nunchuk_handshake(wm, &wm->exp.nunchuk, data, len))
wm->event = WIIUSE_NUNCHUK_INSERTED;
break;
case EXP_ID_CODE_CLASSIC_CONTROLLER:
if (classic_ctrl_handshake(wm, &wm->exp.classic, data, len))
wm->event = WIIUSE_CLASSIC_CTRL_INSERTED;
break;
case EXP_ID_CODE_GUITAR:
if (guitar_hero_3_handshake(wm, &wm->exp.gh3, data, len))
wm->event = WIIUSE_GUITAR_HERO_3_CTRL_INSERTED;
break;
case EXP_ID_CODE_MOTION_PLUS:
case EXP_ID_CODE_MOTION_PLUS_CLASSIC:
case EXP_ID_CODE_MOTION_PLUS_NUNCHUK:
/* wiiuse_motion_plus_handshake(wm, data, len); */
wm->event = WIIUSE_MOTION_PLUS_ACTIVATED;
break;
default:
WIIUSE_WARNING("Unknown expansion type. Code: 0x%x", id);
break;
}
free(data);
WIIMOTE_DISABLE_STATE(wm,WIIMOTE_STATE_EXP_HANDSHAKE);
WIIMOTE_ENABLE_STATE(wm,WIIMOTE_STATE_EXP);
wiiuse_set_ir_mode(wm);
wiiuse_status(wm);
break;
}
id = from_big_endian_uint32_t(data + 220);
/* call the corresponding handshake function for this expansion */
switch (id) {
case EXP_ID_CODE_NUNCHUK:
{
if (nunchuk_handshake(wm, &wm->exp.nunchuk, data, len))
wm->event = WIIUSE_NUNCHUK_INSERTED;
break;
}
case EXP_ID_CODE_CLASSIC_CONTROLLER:
{
if (classic_ctrl_handshake(wm, &wm->exp.classic, data, len))
wm->event = WIIUSE_CLASSIC_CTRL_INSERTED;
break;
}
case EXP_ID_CODE_GUITAR:
{
if (guitar_hero_3_handshake(wm, &wm->exp.gh3, data, len))
wm->event = WIIUSE_GUITAR_HERO_3_CTRL_INSERTED;
break;
}
case EXP_ID_CODE_WII_BOARD:
{
if (wii_board_handshake(wm, &wm->exp.wb, data, len))
wm->event = WIIUSE_WII_BOARD_CTRL_INSERTED;
break;
}
default:
{
WIIUSE_WARNING("Unknown expansion type. Code: 0x%x", id);
break;
}
}
free(data);
}
@@ -764,6 +842,12 @@ void disable_expansion(struct wiimote_t* wm) {
wii_board_disconnected(&wm->exp.wb);
wm->event = WIIUSE_WII_BOARD_CTRL_REMOVED;
break;
case EXP_MOTION_PLUS:
case EXP_MOTION_PLUS_CLASSIC:
case EXP_MOTION_PLUS_NUNCHUK:
motion_plus_disconnected(&wm->exp.mp);
wm->event = WIIUSE_MOTION_PLUS_REMOVED;
break;
default:
break;
}
@@ -822,6 +906,33 @@ static void save_state(struct wiimote_t* wm) {
wm->lstate.exp_wb_rbl = wm->exp.wb.rbl;
break;
case EXP_MOTION_PLUS:
case EXP_MOTION_PLUS_CLASSIC:
case EXP_MOTION_PLUS_NUNCHUK:
{
wm->lstate.drx = wm->exp.mp.raw_gyro.pitch;
wm->lstate.dry = wm->exp.mp.raw_gyro.roll;
wm->lstate.drz = wm->exp.mp.raw_gyro.yaw;
if(wm->exp.type == EXP_MOTION_PLUS_CLASSIC)
{
wm->lstate.exp_ljs_ang = wm->exp.classic.ljs.ang;
wm->lstate.exp_ljs_mag = wm->exp.classic.ljs.mag;
wm->lstate.exp_rjs_ang = wm->exp.classic.rjs.ang;
wm->lstate.exp_rjs_mag = wm->exp.classic.rjs.mag;
wm->lstate.exp_r_shoulder = wm->exp.classic.r_shoulder;
wm->lstate.exp_l_shoulder = wm->exp.classic.l_shoulder;
wm->lstate.exp_btns = wm->exp.classic.btns;
} else {
wm->lstate.exp_ljs_ang = wm->exp.nunchuk.js.ang;
wm->lstate.exp_ljs_mag = wm->exp.nunchuk.js.mag;
wm->lstate.exp_btns = wm->exp.nunchuk.btns;
wm->lstate.exp_accel = wm->exp.nunchuk.accel;
}
break;
}
case EXP_NONE:
break;
}
@@ -925,6 +1036,35 @@ static int state_changed(struct wiimote_t* wm) {
STATE_CHANGED(wm->lstate.exp_wb_rbl,wm->exp.wb.bl);
break;
}
case EXP_MOTION_PLUS:
case EXP_MOTION_PLUS_CLASSIC:
case EXP_MOTION_PLUS_NUNCHUK:
{
STATE_CHANGED(wm->lstate.drx, wm->exp.mp.raw_gyro.pitch);
STATE_CHANGED(wm->lstate.dry, wm->exp.mp.raw_gyro.roll);
STATE_CHANGED(wm->lstate.drz, wm->exp.mp.raw_gyro.yaw);
if(wm->exp.type == EXP_MOTION_PLUS_CLASSIC)
{
STATE_CHANGED(wm->lstate.exp_ljs_ang, wm->exp.classic.ljs.ang);
STATE_CHANGED(wm->lstate.exp_ljs_mag, wm->exp.classic.ljs.mag);
STATE_CHANGED(wm->lstate.exp_rjs_ang, wm->exp.classic.rjs.ang);
STATE_CHANGED(wm->lstate.exp_rjs_mag, wm->exp.classic.rjs.mag);
STATE_CHANGED(wm->lstate.exp_r_shoulder, wm->exp.classic.r_shoulder);
STATE_CHANGED(wm->lstate.exp_l_shoulder, wm->exp.classic.l_shoulder);
STATE_CHANGED(wm->lstate.exp_btns, wm->exp.classic.btns);
} else {
STATE_CHANGED(wm->lstate.exp_ljs_ang, wm->exp.nunchuk.js.ang);
STATE_CHANGED(wm->lstate.exp_ljs_mag, wm->exp.nunchuk.js.mag);
STATE_CHANGED(wm->lstate.exp_btns, wm->exp.nunchuk.btns);
CROSS_THRESH(wm->lstate.exp_orient, wm->exp.nunchuk.orient, wm->exp.nunchuk.orient_threshold);
CROSS_THRESH_XYZ(wm->lstate.exp_accel, wm->exp.nunchuk.accel, wm->exp.nunchuk.accel_threshold);
}
break;
}
case EXP_NONE:
{
break;

View File

@@ -31,10 +31,28 @@
* @brief Handles device I/O (non-OS specific).
*/
#include "io.h"
#include "ir.h" /* for wiiuse_set_ir_mode */
#include <stdlib.h> /* for free, malloc */
static void wiiuse_disable_motion_plus2(struct wiimote_t *wm,byte *data,unsigned short len)
{
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP_FAILED);
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP_HANDSHAKE);
wiiuse_set_ir_mode(wm);
wm->handshake_state++;
wiiuse_handshake(wm, NULL, 0);
}
static void wiiuse_disable_motion_plus1(struct wiimote_t *wm,byte *data,unsigned short len)
{
byte val = 0x00;
wiiuse_write_data_cb(wm, WM_EXP_MEM_ENABLE1, &val, 1, wiiuse_disable_motion_plus2);
}
/**
* @brief Get initialization data from the wiimote.
*
@@ -68,10 +86,12 @@ void wiiuse_handshake(struct wiimote_t* wm, byte* data, uint16_t len) {
break;
}
case 1:
{
struct read_req_t* req = wm->read_req;
struct accel_t* accel = &wm->accel_calib;
byte val;
/* received read data */
accel->cal_zero.x = req->buf[0];
@@ -90,10 +110,16 @@ void wiiuse_handshake(struct wiimote_t* wm, byte* data, uint16_t len) {
accel->cal_zero.x, accel->cal_zero.y, accel->cal_zero.z,
accel->cal_g.x, accel->cal_g.y, accel->cal_g.z);
/* M+ off */
val = 0x55;
wiiuse_write_data_cb(wm, WM_EXP_MEM_ENABLE1, &val, 1, wiiuse_disable_motion_plus1);
/* request the status of the wiimote to see if there is an expansion */
wiiuse_status(wm);
break;
}
case 2:
{
/* request the status of the wiimote to check for any expansion */
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE);
WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE_COMPLETE);
wm->handshake_state++;
@@ -105,8 +131,12 @@ void wiiuse_handshake(struct wiimote_t* wm, byte* data, uint16_t len) {
wiiuse_set_ir(wm, 1);
}
wm->event = WIIUSE_CONNECT;
wiiuse_status(wm);
break;
}
default:
{
break;

View File

@@ -57,6 +57,17 @@ static const byte WM_IR_BLOCK2_LEVEL4[] = "\x35\x03";
static const byte WM_IR_BLOCK1_LEVEL5[] = "\x07\x00\x00\x71\x01\x00\x72\x00\x20";
static const byte WM_IR_BLOCK2_LEVEL5[] = "\x1f\x03";
void wiiuse_set_ir_mode(struct wiimote_t *wm)
{
byte buf = 0x00;
if(!wm) return;
if(!WIIMOTE_IS_SET(wm,WIIMOTE_STATE_IR)) return;
if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP)) buf = WM_IR_TYPE_BASIC;
else buf = WM_IR_TYPE_EXTENDED;
wiiuse_write_data(wm,WM_REG_IR_MODENUM, &buf, 1);
}
/**
* @brief Set if the wiimote should track IR targets.
*

289
src/motion_plus.c Normal file
View File

@@ -0,0 +1,289 @@
/*
* wiiuse
*
* Written By:
* Michal Wiedenbauer < shagkur >
* Dave Murphy < WinterMute >
* Hector Martin < marcan >
* Radu Andries <admiral0>
*
* Copyright 2009
*
* This file is part of wiiuse and fWIIne.
*
* 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$
*
*/
#include "motion_plus.h"
#include "events.h" /* for disable_expansion */
#include "ir.h" /* for wiiuse_set_ir_mode */
#include "nunchuk.h" /* for nunchuk_pressed_buttons */
#include "dynamics.h" /* for calc_joystick_state, etc */
#include <string.h> /* for memset */
#include <math.h> /* for fabs */
static void wiiuse_calibrate_motion_plus(struct motion_plus_t *mp);
static void calculate_gyro_rates(struct motion_plus_t* mp);
void wiiuse_motion_plus_handshake(struct wiimote_t *wm,byte *data,unsigned short len)
{
uint32_t val;
if(data == NULL)
{
wiiuse_read_data_cb(wm, wiiuse_motion_plus_handshake, wm->motion_plus_id, WM_EXP_ID, 6);
}
else
{
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP_FAILED);
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP_HANDSHAKE);
WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_EXP); /* tell wiimote to include exp. data in reports */
val = from_big_endian_uint32_t(data + 2);
if(val == EXP_ID_CODE_MOTION_PLUS ||
val == EXP_ID_CODE_MOTION_PLUS_NUNCHUK ||
val == EXP_ID_CODE_MOTION_PLUS_CLASSIC)
{
/* handshake done */
wm->event = WIIUSE_MOTION_PLUS_ACTIVATED;
switch(val)
{
case EXP_ID_CODE_MOTION_PLUS:
wm->exp.type = EXP_MOTION_PLUS;
break;
case EXP_ID_CODE_MOTION_PLUS_NUNCHUK:
wm->exp.type = EXP_MOTION_PLUS_NUNCHUK;
break;
case EXP_ID_CODE_MOTION_PLUS_CLASSIC:
wm->exp.type = EXP_MOTION_PLUS_CLASSIC;
break;
default:
/* huh? */
WIIUSE_WARNING("Unknown ID returned in Motion+ handshake %d\n", val);
wm->exp.type = EXP_MOTION_PLUS;
break;
}
WIIUSE_DEBUG("Motion plus connected");
/* Init gyroscopes */
wm->exp.mp.cal_gyro.roll = 0;
wm->exp.mp.cal_gyro.pitch = 0;
wm->exp.mp.cal_gyro.yaw = 0;
wm->exp.mp.orient.roll = 0.0;
wm->exp.mp.orient.pitch = 0.0;
wm->exp.mp.orient.yaw = 0.0;
wm->exp.mp.raw_gyro_threshold = 10;
wm->exp.mp.nc = &(wm->exp.nunchuk);
wm->exp.mp.classic = &(wm->exp.classic);
wm->exp.nunchuk.flags = &wm->flags;
wm->exp.mp.ext = 0;
wiiuse_set_ir_mode(wm);
wiiuse_set_report_type(wm);
}
}
}
static void wiiuse_set_motion_plus_clear2(struct wiimote_t *wm,byte *data,unsigned short len)
{
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP_FAILED);
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP_HANDSHAKE);
wiiuse_set_ir_mode(wm);
wiiuse_status(wm);
}
static void wiiuse_set_motion_plus_clear1(struct wiimote_t *wm,byte *data,unsigned short len)
{
byte val = 0x00;
wiiuse_write_data_cb(wm, WM_EXP_MEM_ENABLE1, &val, 1, wiiuse_set_motion_plus_clear2);
}
/**
* @brief Enable/disable Motion+ expansion
*
* @param wm Pointer to the wiimote with Motion+
* @param status 0 - off, 1 - on, standalone, 2 - nunchuk pass-through
*
*/
void wiiuse_set_motion_plus(struct wiimote_t *wm, int status)
{
byte val;
if(status && !WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP_HANDSHAKE))
{
WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_EXP_HANDSHAKE);
val = (status == 1) ? 0x04 : 0x05;
wiiuse_write_data_cb(wm, WM_EXP_MOTION_PLUS_ENABLE, &val, 1, wiiuse_motion_plus_handshake);
}
else
{
disable_expansion(wm);
val = 0x55;
wiiuse_write_data_cb(wm, WM_EXP_MEM_ENABLE1, &val, 1, wiiuse_set_motion_plus_clear1);
}
}
void motion_plus_disconnected(struct motion_plus_t* mp)
{
WIIUSE_DEBUG("Motion plus disconnected");
memset(mp, 0, sizeof(struct motion_plus_t));
}
void motion_plus_event(struct motion_plus_t* mp, int exp_type, byte* msg)
{
/*
* Pass-through modes interleave data from the gyro
* with the expansion data. This extracts the tag
* determining which is which
*/
int isMPFrame = (1 << 1) & msg[5];
mp->ext = msg[4] & 0x1; /* extension attached to pass-through port? */
if (mp->ext == 0 || isMPFrame) /* reading gyro frame */
{
/* Check if the gyroscope is in fast or slow mode (0 if rotating fast, 1 if slow or still) */
mp->acc_mode = ((msg[4] & 0x2) << 1) | ((msg[3] & 0x1) << 1) | ((msg[3] & 0x2) >> 1);
mp->raw_gyro.roll = ((msg[4] & 0xFC) << 6) | msg[1];
mp->raw_gyro.pitch = ((msg[5] & 0xFC) << 6) | msg[2];
mp->raw_gyro.yaw = ((msg[3] & 0xFC) << 6) | msg[0];
/* First calibration */
if ((mp->raw_gyro.roll > 5000) &&
(mp->raw_gyro.pitch > 5000) &&
(mp->raw_gyro.yaw > 5000) &&
(mp->raw_gyro.roll < 0x3fff) &&
(mp->raw_gyro.pitch < 0x3fff) &&
(mp->raw_gyro.yaw < 0x3fff) &&
!(mp->cal_gyro.roll) &&
!(mp->cal_gyro.pitch) &&
!(mp->cal_gyro.yaw))
{
wiiuse_calibrate_motion_plus(mp);
}
/* Calculate angular rates in deg/sec and performs some simple filtering */
calculate_gyro_rates(mp);
}
else
{
/* expansion frame */
if (exp_type == EXP_MOTION_PLUS_NUNCHUK)
{
/* ok, this is nunchuck, re-encode it as regular nunchuck packet */
/* get button states */
nunchuk_pressed_buttons(mp->nc, (msg[5] >> 2));
/* calculate joystick state */
calc_joystick_state(&(mp->nc->js), msg[0], msg[1]);
/* calculate orientation */
mp->nc->accel.x = msg[2];
mp->nc->accel.y = msg[3];
mp->nc->accel.z = (msg[4] & 0xFE) | ((msg[5] >> 5) & 0x04);
calculate_orientation(&(mp->nc->accel_calib),
&(mp->nc->accel),
&(mp->nc->orient),
NUNCHUK_IS_FLAG_SET(mp->nc, WIIUSE_SMOOTHING));
calculate_gforce(&(mp->nc->accel_calib),
&(mp->nc->accel),
&(mp->nc->gforce));
}
else if (exp_type == EXP_MOTION_PLUS_CLASSIC)
{
WIIUSE_ERROR("Classic controller pass-through is not implemented!\n");
}
else
{
WIIUSE_ERROR("Unsupported mode passed to motion_plus_event() !\n");
}
}
}
/**
* @brief Calibrate the Motion Plus gyroscopes.
*
* @param mp Pointer to a motion_plus_t structure.
*
* This should be called only after receiving the first values
* from the Motion Plus.
*/
void wiiuse_calibrate_motion_plus(struct motion_plus_t *mp)
{
mp->cal_gyro.roll = mp->raw_gyro.roll;
mp->cal_gyro.pitch = mp->raw_gyro.pitch;
mp->cal_gyro.yaw = mp->raw_gyro.yaw;
mp->orient.roll = 0.0;
mp->orient.pitch = 0.0;
mp->orient.yaw = 0.0;
}
static void calculate_gyro_rates(struct motion_plus_t* mp)
{
short int tmp_r, tmp_p, tmp_y;
float tmp_roll, tmp_pitch, tmp_yaw;
/* We consider calibration data */
tmp_r = mp->raw_gyro.roll - mp->cal_gyro.roll;
tmp_p = mp->raw_gyro.pitch - mp->cal_gyro.pitch;
tmp_y = mp->raw_gyro.yaw - mp->cal_gyro.yaw;
/* We convert to degree/sec according to fast/slow mode */
if (mp->acc_mode & 0x04)
tmp_roll = tmp_r / 20.0;
else
tmp_roll = tmp_r / 4.0;
if (mp->acc_mode & 0x02)
tmp_pitch = tmp_p / 20.0;
else
tmp_pitch = tmp_p / 4.0;
if (mp->acc_mode & 0x01)
tmp_yaw = tmp_y / 20.0;
else
tmp_yaw = tmp_y / 4.0;
/* Simple filtering */
if (fabs(tmp_roll) < 0.5)
tmp_roll = 0.0;
if (fabs(tmp_pitch) < 0.5)
tmp_pitch = 0.0;
if (fabs(tmp_yaw) < 0.5)
tmp_yaw = 0.0;
mp->angle_rate_gyro.roll = tmp_roll;
mp->angle_rate_gyro.pitch = tmp_pitch;
mp->angle_rate_gyro.yaw = tmp_yaw;
}

58
src/motion_plus.h Normal file
View File

@@ -0,0 +1,58 @@
/*
* wiiuse
*
* Written By:
* Michal Wiedenbauer < shagkur >
* Dave Murphy < WinterMute >
* Hector Martin < marcan >
* Radu Andries <admiral0>
*
* Copyright 2009
*
* This file is part of wiiuse and fWIIne.
*
* 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 Motion plus extension
*/
#ifndef MOTION_PLUS_H_INCLUDED
#define MOTION_PLUS_H_INCLUDED
#include "wiiuse_internal.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup internal_mp Internal: MotionPlus */
/** @{ */
void motion_plus_disconnected(struct motion_plus_t* mp);
void motion_plus_event(struct motion_plus_t* mp, int exp_type, byte* msg);
void wiiuse_motion_plus_handshake(struct wiimote_t *wm, byte *data,unsigned short len);
/** @} */
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -39,9 +39,6 @@
#include <stdlib.h> /* for malloc */
#include <string.h> /* for memset */
static void nunchuk_pressed_buttons(struct nunchuk_t* nc, byte now);
/**
* @brief Handle the handshake data from the nunchuk.
*
@@ -164,7 +161,7 @@ void nunchuk_event(struct nunchuk_t* nc, byte* msg) {
* @param nc Pointer to a nunchuk_t structure.
* @param msg The message byte specified in the event packet.
*/
static void nunchuk_pressed_buttons(struct nunchuk_t* nc, byte now) {
void nunchuk_pressed_buttons(struct nunchuk_t* nc, byte now) {
/* message is inverted (0 is active, 1 is inactive) */
now = ~now & NUNCHUK_BUTTON_ALL;

View File

@@ -48,6 +48,8 @@ int nunchuk_handshake(struct wiimote_t* wm, struct nunchuk_t* nc, byte* data, un
void nunchuk_disconnected(struct nunchuk_t* nc);
void nunchuk_event(struct nunchuk_t* nc, byte* msg);
void nunchuk_pressed_buttons(struct nunchuk_t* nc, byte now);
/** @} */
#ifdef __cplusplus

View File

@@ -147,6 +147,7 @@ struct wiimote_t** wiiuse_init(int wiimotes) {
wm[i]->event = WIIUSE_NONE;
wm[i]->exp.type = EXP_NONE;
wm[i]->expansion_state = 0;
wiiuse_set_aspect_ratio(wm[i], WIIUSE_ASPECT_4_3);
wiiuse_set_ir_position(wm[i], WIIUSE_IR_ABOVE);
@@ -567,6 +568,83 @@ int wiiuse_write_data(struct wiimote_t* wm, unsigned int addr, const byte* data,
return 1;
}
/**
* @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;
}
/**
* @brief Send a packet to the wiimote.

View File

@@ -197,6 +197,9 @@
#define EXP_CLASSIC 2
#define EXP_GUITAR_HERO_3 3
#define EXP_WII_BOARD 4
#define EXP_MOTION_PLUS 5
#define EXP_MOTION_PLUS_NUNCHUK 6 /* Motion+ in nunchuk pass-through mode */
#define EXP_MOTION_PLUS_CLASSIC 7 /* Motion+ in classic ctr. pass-through mode */
/** @} */
/** @brief IR correction types */
@@ -321,6 +324,21 @@ struct read_req_t {
struct read_req_t* next; /**< next read request in the queue */
};
/**
* @struct ang3s_t
* @brief Roll/Pitch/Yaw short angles.
*/
typedef struct ang3s_t {
int16_t roll, pitch, yaw;
} ang3s_t;
/**
* @struct ang3f_t
* @brief Roll/Pitch/Yaw float angles.
*/
typedef struct ang3f_t {
float roll, pitch, yaw;
} ang3f_t;
/**
* @brief Unsigned x,y byte vector.
@@ -510,6 +528,25 @@ typedef struct guitar_hero_3_t {
struct joystick_t js; /**< joystick calibration */
} guitar_hero_3_t;
/**
* @brief Motion Plus expansion device
*/
typedef struct motion_plus_t
{
byte ext; /**< is there a device on the pass-through port? */
struct ang3s_t raw_gyro; /**< current raw gyroscope data */
struct ang3s_t cal_gyro; /**< calibration raw gyroscope data */
struct ang3f_t angle_rate_gyro; /**< current gyro angle rate */
struct orient_t orient; /**< current orientation on each axis using Motion Plus gyroscopes */
byte acc_mode; /**< Fast/slow rotation mode for roll, pitch and yaw (0 if rotating fast, 1 if slow or still) */
int raw_gyro_threshold; /**< threshold for gyroscopes to generate an event */
struct nunchuk_t *nc; /**< pointers to nunchuk & classic in pass-through-mode */
struct classic_ctrl_t *classic;
} motion_plus_t;
/**
* @brief Wii Balance Board "expansion" device.
*
@@ -556,6 +593,8 @@ typedef struct wii_board_t {
typedef struct expansion_t {
int type; /**< type of expansion attached */
struct motion_plus_t mp;
union {
struct nunchuk_t nunchuk;
struct classic_ctrl_t classic;
@@ -590,6 +629,11 @@ typedef struct wiimote_state_t {
float exp_r_shoulder;
float exp_l_shoulder;
/* motion plus */
short drx;
short dry;
short drz;
/* wiiboard */
uint16_t exp_wb_rtr;
uint16_t exp_wb_rtl;
@@ -619,6 +663,7 @@ typedef enum WIIUSE_EVENT_TYPE {
WIIUSE_DISCONNECT,
WIIUSE_UNEXPECTED_DISCONNECT,
WIIUSE_READ_DATA,
WIIUSE_WRITE_DATA,
WIIUSE_NUNCHUK_INSERTED,
WIIUSE_NUNCHUK_REMOVED,
WIIUSE_CLASSIC_CTRL_INSERTED,
@@ -626,7 +671,9 @@ typedef enum WIIUSE_EVENT_TYPE {
WIIUSE_GUITAR_HERO_3_CTRL_INSERTED,
WIIUSE_GUITAR_HERO_3_CTRL_REMOVED,
WIIUSE_WII_BOARD_CTRL_INSERTED,
WIIUSE_WII_BOARD_CTRL_REMOVED
WIIUSE_WII_BOARD_CTRL_REMOVED,
WIIUSE_MOTION_PLUS_ACTIVATED,
WIIUSE_MOTION_PLUS_REMOVED
} WIIUSE_EVENT_TYPE;
/**
@@ -666,6 +713,8 @@ typedef struct wiimote_t {
WCONST int flags; /**< options flag */
WCONST byte handshake_state; /**< the state of the connection handshake */
WCONST byte expansion_state; /**< the state of the expansion handshake */
WCONST struct data_req_t* data_req; /**< list of data read requests */
WCONST struct read_req_t* read_req; /**< list of data read requests */
WCONST struct accel_t accel_calib; /**< wiimote accelerometer calibration */
@@ -688,6 +737,7 @@ typedef struct wiimote_t {
WCONST WIIUSE_EVENT_TYPE event; /**< type of event that occured */
WCONST byte event_buf[MAX_PAYLOAD]; /**< event buffer */
WCONST byte motion_plus_id[6];
} wiimote;
/** @brief Data passed to a callback during wiiuse_update() */
@@ -710,6 +760,42 @@ typedef struct wiimote_callback_data_t {
/** @brief Callback type */
typedef void (*wiiuse_update_cb)(struct wiimote_callback_data_t* wm);
/**
* @brief Callback that handles a write event.
*
* @param wm Pointer to a wiimote_t structure.
* @param data Pointer to the sent data block.
* @param len Length in bytes of the data block.
*
* @see wiiuse_init()
*
* A registered function of this type is called automatically by the wiiuse
* library when the wiimote has returned the full data requested by a previous
* call to wiiuse_write_data().
*/
typedef void (*wiiuse_write_cb)(struct wiimote_t* wm, unsigned char* data, unsigned short len);
typedef enum data_req_s
{
REQ_READY = 0,
REQ_SENT,
REQ_DONE
} data_req_s;
/**
* @struct data_req_t
* @brief Data write request structure.
*/
struct data_req_t {
byte data[21]; /**< buffer where read data is written */
byte len;
unsigned int addr;
data_req_s state; /**< set to 1 if not using callback and needs to be cleaned up */
wiiuse_write_cb cb; /**< read data callback */
struct data_req_t *next;
};
/**
* @brief Loglevels supported by wiiuse.
*/
@@ -811,6 +897,8 @@ WIIUSE_EXPORT extern void wiiuse_set_nunchuk_accel_threshold(struct wiimote_t* w
/* this function not currently implemented... */
WIIUSE_EXPORT extern void wiiuse_set_wii_board_calib(struct wiimote_t *wm);
WIIUSE_EXPORT extern void wiiuse_set_motion_plus(struct wiimote_t *wm, int status);
#ifdef __cplusplus
}
#endif

View File

@@ -129,10 +129,14 @@
/* offsets in wiimote memory */
#define WM_MEM_OFFSET_CALIBRATION 0x16
#define WM_EXP_MEM_BASE 0x04A40000
#define WM_EXP_ID 0x04A400FA
#define WM_EXP_MEM_ENABLE 0x04A40040
#define WM_EXP_MEM_ENABLE1 0x04A400F0
#define WM_EXP_MEM_ENABLE2 0x04A400FB
#define WM_EXP_MEM_CALIBR 0x04A40020
#define WM_REG_IR 0x04B00030
#define WM_EXP_MOTION_PLUS_ENABLE 0x04A600FE
#define WM_EXP_MOTION_PLUS_INIT 0x04A600F0
#define WM_REG_IR 0x04B00030
#define WM_REG_IR_BLOCK1 0x04B00000
#define WM_REG_IR_BLOCK2 0x04B0001A
#define WM_REG_IR_MODENUM 0x04B00033
@@ -162,11 +166,14 @@
* Expansion stuff
*/
/* encrypted expansion id codes (located at 0x04A400FC) */
#define EXP_ID_CODE_NUNCHUK 0x9A1EFEFE
#define EXP_ID_CODE_WII_BOARD 0xA4200402
#define EXP_ID_CODE_CLASSIC_CONTROLLER 0x9A1EFDFD
#define EXP_ID_CODE_GUITAR 0x9A1EFDFB
/* decrypted expansion id codes (located at 0x04A400FC) */
#define EXP_ID_CODE_NUNCHUK 0xA4200000
#define EXP_ID_CODE_WII_BOARD 0xA4200402
#define EXP_ID_CODE_CLASSIC_CONTROLLER 0xA4200101
#define EXP_ID_CODE_GUITAR 0xA4200103
#define EXP_ID_CODE_MOTION_PLUS 0xa4200405
#define EXP_ID_CODE_MOTION_PLUS_NUNCHUK 0xA4200505 /** Motion Plus ID in Nunchuck passthrough mode */
#define EXP_ID_CODE_MOTION_PLUS_CLASSIC 0xA4200705 /** Motion Plus ID in Classic control. passthrough */
#define EXP_HANDSHAKE_LEN 224
@@ -191,6 +198,11 @@
#define WIIMOTE_STATE_IR_SENS_LVL3 0x0800
#define WIIMOTE_STATE_IR_SENS_LVL4 0x1000
#define WIIMOTE_STATE_IR_SENS_LVL5 0x2000
#define WIIMOTE_STATE_EXP_HANDSHAKE 0x10000 /* actual M+ connection exists but no handshake yet */
#define WIIMOTE_STATE_EXP_EXTERN 0x20000 /* actual M+ connection exists but handshake failed */
#define WIIMOTE_STATE_EXP_FAILED 0x40000 /* actual M+ connection exists but handshake failed */
#define WIIMOTE_INIT_STATES (WIIMOTE_STATE_IR_SENS_LVL3)
@@ -254,8 +266,10 @@ void wiiuse_millisleep(int durationMilliseconds);
int wiiuse_set_report_type(struct wiimote_t* wm);
void wiiuse_send_next_pending_read_request(struct wiimote_t* wm);
void wiiuse_send_next_pending_write_request(struct wiimote_t* wm);
int wiiuse_send(struct wiimote_t* wm, byte report_type, byte* msg, int len);
int wiiuse_read_data_cb(struct wiimote_t* wm, wiiuse_read_cb read_cb, byte* buffer, unsigned int offset, uint16_t len);
int wiiuse_write_data_cb(struct wiimote_t *wm, unsigned int addr, byte* data, byte len, wiiuse_write_cb write_cb);
#ifdef WIIUSE_DOXYGEN_PARSING