git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@12415 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
funto66 2013-01-24 22:53:34 +00:00
parent 8e44df338c
commit 7935c687c7
33 changed files with 4814 additions and 1222 deletions

View File

@ -11,4 +11,7 @@ add_library(wiiuse
ir.c
nunchuk.c
wiiuse.c
wiiboard.c
motion_plus.c
util.c
)

View File

@ -31,19 +31,12 @@
* @brief Classic controller expansion device.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#ifdef WIN32
#include <Winsock2.h>
#endif
#include "definitions.h"
#include "wiiuse_internal.h"
#include "dynamics.h"
#include "events.h"
#include "classic.h"
#include "dynamics.h" /* for calc_joystick_state */
#include "events.h" /* for handshake_expansion */
#include <stdlib.h> /* for malloc */
#include <string.h> /* for memset */
static void classic_ctrl_pressed_buttons(struct classic_ctrl_t* cc, short now);
@ -56,9 +49,8 @@ static void classic_ctrl_pressed_buttons(struct classic_ctrl_t* cc, short now);
*
* @return Returns 1 if handshake was successful, 0 if not.
*/
#define HANDSHAKE_BYTES_USED 12
int classic_ctrl_handshake(struct wiimote_t* wm, struct classic_ctrl_t* cc, byte* data, unsigned short len) {
int i;
int offset = 0;
cc->btns = 0;
cc->btns_held = 0;
@ -66,11 +58,7 @@ int classic_ctrl_handshake(struct wiimote_t* wm, struct classic_ctrl_t* cc, byte
cc->r_shoulder = 0;
cc->l_shoulder = 0;
/* decrypt data */
for (i = 0; i < len; ++i)
data[i] = (data[i] ^ 0x17) + 0x17;
if (data[offset] == 0xFF) {
if (data[0] == 0xFF || len < HANDSHAKE_BYTES_USED) {
/*
* Sometimes the data returned here is not correct.
* This might happen because the wiimote is lagging
@ -81,40 +69,41 @@ int classic_ctrl_handshake(struct wiimote_t* wm, struct classic_ctrl_t* cc, byte
* but since the next 16 bytes are the same, just use
* those.
*/
if (data[offset + 16] == 0xFF) {
if (len < 17 || len < HANDSHAKE_BYTES_USED + 16 || data[16] == 0xFF) {
/* get the calibration data */
byte* handshake_buf = malloc(EXP_HANDSHAKE_LEN * sizeof(byte));
byte* handshake_buf = (byte *)malloc(EXP_HANDSHAKE_LEN * sizeof(byte));
WIIUSE_DEBUG("Classic controller handshake appears invalid, trying again.");
wiiuse_read_data_cb(wm, handshake_expansion, handshake_buf, WM_EXP_MEM_CALIBR, EXP_HANDSHAKE_LEN);
return 0;
} else
offset += 16;
} else {
data += 16;
}
}
/* joystick stuff */
cc->ljs.max.x = data[0 + offset] / 4;
cc->ljs.min.x = data[1 + offset] / 4;
cc->ljs.center.x = data[2 + offset] / 4;
cc->ljs.max.y = data[3 + offset] / 4;
cc->ljs.min.y = data[4 + offset] / 4;
cc->ljs.center.y = data[5 + offset] / 4;
cc->ljs.max.x = data[0] / 4;
cc->ljs.min.x = data[1] / 4;
cc->ljs.center.x = data[2] / 4;
cc->ljs.max.y = data[3] / 4;
cc->ljs.min.y = data[4] / 4;
cc->ljs.center.y = data[5] / 4;
cc->rjs.max.x = data[6 + offset] / 8;
cc->rjs.min.x = data[7 + offset] / 8;
cc->rjs.center.x = data[8 + offset] / 8;
cc->rjs.max.y = data[9 + offset] / 8;
cc->rjs.min.y = data[10 + offset] / 8;
cc->rjs.center.y = data[11 + offset] / 8;
cc->rjs.max.x = data[6] / 8;
cc->rjs.min.x = data[7] / 8;
cc->rjs.center.x = data[8] / 8;
cc->rjs.max.y = data[9] / 8;
cc->rjs.min.y = data[10] / 8;
cc->rjs.center.y = data[11] / 8;
/* handshake done */
wm->exp.type = EXP_CLASSIC;
#ifdef WIN32
#ifdef WIIUSE_WIN32
wm->timeout = WIIMOTE_DEFAULT_TIMEOUT;
#endif
#endif
return 1;
}
@ -138,14 +127,10 @@ void classic_ctrl_disconnected(struct classic_ctrl_t* cc) {
* @param msg The message specified in the event packet.
*/
void classic_ctrl_event(struct classic_ctrl_t* cc, byte* msg) {
int i, lx, ly, rx, ry;
int lx, ly, rx, ry;
byte l, r;
/* decrypt data */
for (i = 0; i < 6; ++i)
msg[i] = (msg[i] ^ 0x17) + 0x17;
classic_ctrl_pressed_buttons(cc, BIG_ENDIAN_SHORT(*(short*)(msg + 4)));
classic_ctrl_pressed_buttons(cc, from_big_endian_uint16_t(msg + 4));
/* left/right buttons */
l = (((msg[2] & 0x60) >> 2) | ((msg[3] & 0xE0) >> 5));
@ -164,8 +149,8 @@ void classic_ctrl_event(struct classic_ctrl_t* cc, byte* msg) {
rx = ((msg[0] & 0xC0) >> 3) | ((msg[1] & 0xC0) >> 5) | ((msg[2] & 0x80) >> 7);
ry = (msg[2] & 0x1F);
calc_joystick_state(&cc->ljs, lx, ly);
calc_joystick_state(&cc->rjs, rx, ry);
calc_joystick_state(&cc->ljs, (float)lx, (float)ly);
calc_joystick_state(&cc->rjs, (float)rx, (float)ry);
}

View File

@ -40,14 +40,17 @@
extern "C" {
#endif
int classic_ctrl_handshake(struct wiimote_t* wm, struct classic_ctrl_t* cc, byte* data, unsigned short len);
/** @defgroup internal_classic Internal: Classic Controller */
/** @{ */
int classic_ctrl_handshake(struct wiimote_t* wm, struct classic_ctrl_t* cc, byte* data, unsigned short len);
void classic_ctrl_disconnected(struct classic_ctrl_t* cc);
void classic_ctrl_disconnected(struct classic_ctrl_t* cc);
void classic_ctrl_event(struct classic_ctrl_t* cc, byte* msg);
void classic_ctrl_event(struct classic_ctrl_t* cc, byte* msg);
/** @} */
#ifdef __cplusplus
}
#endif
#endif // CLASSIC_H_INCLUDED
#endif /* CLASSIC_H_INCLUDED */

View File

@ -35,31 +35,43 @@
#define DEFINITIONS_H_INCLUDED
/* this is wiiuse - used to distinguish from third party programs using wiiuse.h */
#include "os.h"
#include <stdio.h>
#include "definitions_os.h"
/** @addtogroup internal_general */
/** @{ */
#define WIIMOTE_PI 3.14159265f
//#define WITH_WIIUSE_DEBUG
/* #define WITH_WIIUSE_DEBUG */
extern FILE* logtarget[];
#define OUTF_ERROR logtarget[0]
#define OUTF_WARNING logtarget[1]
#define OUTF_INFO logtarget[2]
#define OUTF_DEBUG logtarget[3]
/* Error output macros */
#define WIIUSE_ERROR(fmt, ...) fprintf(stderr, "[ERROR] " fmt "\n", ##__VA_ARGS__)
#define WIIUSE_ERROR(fmt, ...) do { if (OUTF_ERROR) fprintf(OUTF_ERROR, "[ERROR] " fmt "\n", ##__VA_ARGS__); } while(0)
/* Warning output macros */
#define WIIUSE_WARNING(fmt, ...) fprintf(stderr, "[WARNING] " fmt "\n", ##__VA_ARGS__)
#define WIIUSE_WARNING(fmt, ...) do { if (OUTF_WARNING) fprintf(OUTF_WARNING, "[WARNING] " fmt "\n", ##__VA_ARGS__); } while(0)
/* Information output macros */
#define WIIUSE_INFO(fmt, ...) fprintf(stderr, "[INFO] " fmt "\n", ##__VA_ARGS__)
#define WIIUSE_INFO(fmt, ...) do { if (OUTF_INFO) fprintf(OUTF_INFO, "[INFO] " fmt "\n", ##__VA_ARGS__); } while(0)
#ifdef WITH_WIIUSE_DEBUG
#ifdef WIN32
#define WIIUSE_DEBUG(fmt, ...) do { \
char* file = __FILE__; \
int i = strlen(file) - 1; \
for (; i && (file[i] != '\\'); --i); \
fprintf(stderr, "[DEBUG] %s:%i: " fmt "\n", file+i+1, __LINE__, ##__VA_ARGS__); \
#ifdef WIIUSE_WIN32
#define WIIUSE_DEBUG(fmt, ...) do { \
if (OUTF_DEBUG) { \
char* file = __FILE__; \
int i = strlen(file) - 1; \
for (; i && (file[i] != '\\'); --i); \
fprintf(OUTF_DEBUG, "[DEBUG] %s:%i: " fmt "\n", file+i+1, __LINE__, ##__VA_ARGS__); \
} \
} while (0)
#else
#define WIIUSE_DEBUG(fmt, ...) fprintf(stderr, "[DEBUG] " __FILE__ ":%i: " fmt "\n", __LINE__, ##__VA_ARGS__)
#define WIIUSE_DEBUG(fmt, ...) do { if (OUTF_DEBUG) fprintf(OUTF_DEBUG, "[DEBUG] " __FILE__ ":%i: " fmt "\n", __LINE__, ##__VA_ARGS__); } while (0)
#endif
#else
#define WIIUSE_DEBUG(fmt, ...)
@ -69,11 +81,12 @@
#define RAD_TO_DEGREE(r) ((r * 180.0f) / WIIMOTE_PI)
#define DEGREE_TO_RAD(d) (d * (WIIMOTE_PI / 180.0f))
/* Convert to big endian */
#define BIG_ENDIAN_LONG(i) (htonl(i))
#define BIG_ENDIAN_SHORT(i) (htons(i))
#define absf(x) ((x >= 0) ? (x) : (x * -1.0f))
#define diff_f(x, y) ((x >= y) ? (absf(x - y)) : (absf(y - x)))
#endif // DEFINITIONS_H_INCLUDED
#define WCONST
/** @} */
#endif /* DEFINITIONS_H_INCLUDED */

View File

@ -0,0 +1,51 @@
/*
* 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 Operating system related definitions.
*
* This file is an attempt to separate operating system
* dependent functions and choose what should be used
* at compile time.
*/
#ifndef DEFINITIONS_OS_H_INCLUDED
#define DEFINITIONS_OS_H_INCLUDED
#ifdef _MSC_VER
#include <float.h>
/* windows with visual c */
#define isnan(x) (_isnan(x))
#define isinf(x) (!_finite(x))
/* disable warnings I don't care about */
/*#pragma warning(disable:4273) */ /* inconsistent dll linkage */
#endif
#endif /* DEFINITIONS_OS_H_INCLUDED */

View File

@ -35,19 +35,12 @@
* motion sensing.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#ifdef WIN32
#include <float.h>
#endif
#include "definitions.h"
#include "wiiuse_internal.h"
#include "ir.h"
#include "dynamics.h"
#include <math.h> /* for atan2f, atanf, sqrt */
#include <stdlib.h> /* for abs */
/**
* @brief Calculate the roll, pitch, yaw.
*
@ -84,12 +77,21 @@ void calculate_orientation(struct accel_t* ac, struct vec3b_t* accel, struct ori
z = ((float)accel->z - (float)ac->cal_zero.z) / zg;
/* make sure x,y,z are between -1 and 1 for the tan functions */
if (x < -1.0f) x = -1.0f;
else if (x > 1.0f) x = 1.0f;
if (y < -1.0f) y = -1.0f;
else if (y > 1.0f) y = 1.0f;
if (z < -1.0f) z = -1.0f;
else if (z > 1.0f) z = 1.0f;
if (x < -1.0f) {
x = -1.0f;
} else if (x > 1.0f) {
x = 1.0f;
}
if (y < -1.0f) {
y = -1.0f;
} else if (y > 1.0f) {
y = 1.0f;
}
if (z < -1.0f) {
z = -1.0f;
} else if (z > 1.0f) {
z = 1.0f;
}
/* if it is over 1g then it is probably accelerating and not reliable */
if (abs(accel->x - ac->cal_zero.x) <= ac->cal_g.x) {
@ -137,6 +139,18 @@ void calculate_gforce(struct accel_t* ac, struct vec3b_t* accel, struct gforce_t
gforce->z = ((float)accel->z - (float)ac->cal_zero.z) / zg;
}
static float applyCalibration(float inval, float minval, float maxval, float centerval) {
float ret;
/* We don't use the exact ranges but the ranges + 1 in case we get bad calibration data - avoid div0 */
if (inval == centerval) {
ret = 0;
} else if (inval < centerval) {
ret = (inval - centerval) / (centerval - minval + 1);
} else {
ret = (inval - centerval) / (maxval - centerval + 1);
}
return ret;
}
/**
* @brief Calculate the angle and magnitude of a joystick.
@ -154,7 +168,7 @@ void calc_joystick_state(struct joystick_t* js, float x, float y) {
* Then the range from the min to the center and the center to the max
* may be different.
* Because of this, depending on if the current x or y value is greater
* or less than the assoicated axis center value, it needs to be interpolated
* or less than the associated axis center value, it needs to be interpolated
* between the center and the minimum or maxmimum rather than between
* the minimum and maximum.
*
@ -164,65 +178,50 @@ void calc_joystick_state(struct joystick_t* js, float x, float y) {
* The range is therefore -1 to 1, 0 being the exact center rather than
* the middle of min and max.
*/
if (x == js->center.x)
rx = 0;
else if (x >= js->center.x)
rx = ((float)(x - js->center.x) / (float)(js->max.x - js->center.x));
else
rx = ((float)(x - js->min.x) / (float)(js->center.x - js->min.x)) - 1.0f;
if (y == js->center.y)
ry = 0;
else if (y >= js->center.y)
ry = ((float)(y - js->center.y) / (float)(js->max.y - js->center.y));
else
ry = ((float)(y - js->min.y) / (float)(js->center.y - js->min.y)) - 1.0f;
rx = applyCalibration(x, js->min.x, js->max.x, js->center.x);
ry = applyCalibration(y, js->min.y, js->max.y, js->center.y);
/* calculate the joystick angle and magnitude */
ang = RAD_TO_DEGREE(atanf(ry / rx));
ang -= 90.0f;
if (rx < 0.0f)
ang -= 180.0f;
js->ang = absf(ang);
js->mag = (float) sqrt((rx * rx) + (ry * ry));
ang = RAD_TO_DEGREE(atan2f(ry, rx));
js->ang = ang + 180.0f;
js->mag = sqrtf((rx * rx) + (ry * ry));
}
void apply_smoothing(struct accel_t* ac, struct orient_t* orient, int type) {
switch (type) {
case SMOOTH_ROLL:
{
/* it's possible last iteration was nan or inf, so set it to 0 if that happened */
if (isnan(ac->st_roll) || isinf(ac->st_roll))
ac->st_roll = 0.0f;
case SMOOTH_ROLL: {
/* it's possible last iteration was nan or inf, so set it to 0 if that happened */
if (isnan(ac->st_roll) || isinf(ac->st_roll)) {
ac->st_roll = 0.0f;
}
/*
* If the sign changes (which will happen if going from -180 to 180)
* or from (-1 to 1) then don't smooth, just use the new angle.
*/
if (((ac->st_roll < 0) && (orient->roll > 0)) || ((ac->st_roll > 0) && (orient->roll < 0))) {
ac->st_roll = orient->roll;
} else {
orient->roll = ac->st_roll + (ac->st_alpha * (orient->a_roll - ac->st_roll));
ac->st_roll = orient->roll;
/*
* If the sign changes (which will happen if going from -180 to 180)
* or from (-1 to 1) then don't smooth, just use the new angle.
*/
if (((ac->st_roll < 0) && (orient->roll > 0)) || ((ac->st_roll > 0) && (orient->roll < 0))) {
ac->st_roll = orient->roll;
} else {
orient->roll = ac->st_roll + (ac->st_alpha * (orient->a_roll - ac->st_roll));
ac->st_roll = orient->roll;
}
return;
}
return;
}
case SMOOTH_PITCH: {
if (isnan(ac->st_pitch) || isinf(ac->st_pitch)) {
ac->st_pitch = 0.0f;
}
case SMOOTH_PITCH:
{
if (isnan(ac->st_pitch) || isinf(ac->st_pitch))
ac->st_pitch = 0.0f;
if (((ac->st_pitch < 0) && (orient->pitch > 0)) || ((ac->st_pitch > 0) && (orient->pitch < 0))) {
ac->st_pitch = orient->pitch;
} else {
orient->pitch = ac->st_pitch + (ac->st_alpha * (orient->a_pitch - ac->st_pitch));
ac->st_pitch = orient->pitch;
}
if (((ac->st_pitch < 0) && (orient->pitch > 0)) || ((ac->st_pitch > 0) && (orient->pitch < 0))) {
ac->st_pitch = orient->pitch;
} else {
orient->pitch = ac->st_pitch + (ac->st_alpha * (orient->a_pitch - ac->st_pitch));
ac->st_pitch = orient->pitch;
return;
}
return;
}
}
}

View File

@ -44,13 +44,17 @@
extern "C" {
#endif
void calculate_orientation(struct accel_t* ac, struct vec3b_t* accel, struct orient_t* orient, int smooth);
void calculate_gforce(struct accel_t* ac, struct vec3b_t* accel, struct gforce_t* gforce);
void calc_joystick_state(struct joystick_t* js, float x, float y);
void apply_smoothing(struct accel_t* ac, struct orient_t* orient, int type);
/** @defgroup internal_dynamics Internal: Dynamics Functions */
/** @{ */
void calculate_orientation(struct accel_t* ac, struct vec3b_t* accel, struct orient_t* orient, int smooth);
void calculate_gforce(struct accel_t* ac, struct vec3b_t* accel, struct gforce_t* gforce);
void calc_joystick_state(struct joystick_t* js, float x, float y);
void apply_smoothing(struct accel_t* ac, struct orient_t* orient, int type);
/** @} */
#ifdef __cplusplus
}
#endif
#endif // DYNAMICS_H_INCLUDED
#endif /* DYNAMICS_H_INCLUDED */

File diff suppressed because it is too large Load Diff

View File

@ -37,18 +37,28 @@
#ifndef EVENTS_H_INCLUDED
#define EVENTS_H_INCLUDED
#ifdef __cplusplus
extern "C" {
#if defined(_MSC_VER)
/* MS compilers of pre-VC2010 versions don't have stdint.h
* and I can't get VC2010's stdint.h to compile nicely in
* WiiUse
*/
#include "wiiuse_msvcstdint.h"
#else
#include <stdint.h>
#endif
/** @defgroup internal_events Internal: Event Utilities */
/** @{ */
void wiiuse_pressed_buttons(struct wiimote_t* wm, byte* msg);
void handshake_expansion(struct wiimote_t* wm, byte* data, unsigned short len);
void handshake_expansion(struct wiimote_t* wm, byte* data, uint16_t len);
void disable_expansion(struct wiimote_t* wm);
#ifdef __cplusplus
}
#endif
void propagate_event(struct wiimote_t* wm, byte event, byte* msg);
void idle_cycle(struct wiimote_t* wm);
void clear_dirty_reads(struct wiimote_t* wm);
/** @} */
#endif // EVENTS_H_INCLUDED
#endif /* EVENTS_H_INCLUDED */

View File

@ -31,20 +31,14 @@
* @brief Guitar Hero 3 expansion device.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#ifdef WIN32
#include <Winsock2.h>
#endif
#include "definitions.h"
#include "wiiuse_internal.h"
#include "dynamics.h"
#include "events.h"
#include "guitar_hero_3.h"
#include "dynamics.h" /* for calc_joystick_state */
#include "events.h" /* for handshake_expansion */
#include <stdlib.h> /* for malloc */
#include <string.h> /* for memset */
static void guitar_hero_3_pressed_buttons(struct guitar_hero_3_t* gh3, short now);
/**
@ -57,8 +51,6 @@ static void guitar_hero_3_pressed_buttons(struct guitar_hero_3_t* gh3, short now
* @return Returns 1 if handshake was successful, 0 if not.
*/
int guitar_hero_3_handshake(struct wiimote_t* wm, struct guitar_hero_3_t* gh3, byte* data, unsigned short len) {
int i;
int offset = 0;
/*
* The good fellows that made the Guitar Hero 3 controller
@ -71,11 +63,11 @@ int guitar_hero_3_handshake(struct wiimote_t* wm, struct guitar_hero_3_t* gh3, b
gh3->btns_released = 0;
gh3->whammy_bar = 0.0f;
/* decrypt data */
for (i = 0; i < len; ++i)
data[i] = (data[i] ^ 0x17) + 0x17;
if (data[offset] == 0xFF) {
/*
TODO: If we're not using anything from calibration data, why are we
even bothering here?
*/
if (data[0] == 0xFF) {
/*
* Sometimes the data returned here is not correct.
* This might happen because the wiimote is lagging
@ -86,7 +78,7 @@ int guitar_hero_3_handshake(struct wiimote_t* wm, struct guitar_hero_3_t* gh3, b
* but since the next 16 bytes are the same, just use
* those.
*/
if (data[offset + 16] == 0xFF) {
if (data[16] == 0xFF) {
/* get the calibration data */
byte* handshake_buf = malloc(EXP_HANDSHAKE_LEN * sizeof(byte));
@ -94,8 +86,9 @@ int guitar_hero_3_handshake(struct wiimote_t* wm, struct guitar_hero_3_t* gh3, b
wiiuse_read_data_cb(wm, handshake_expansion, handshake_buf, WM_EXP_MEM_CALIBR, EXP_HANDSHAKE_LEN);
return 0;
} else
offset += 16;
} else {
data += 16;
}
}
/* joystick stuff */
@ -109,9 +102,9 @@ int guitar_hero_3_handshake(struct wiimote_t* wm, struct guitar_hero_3_t* gh3, b
/* handshake done */
wm->exp.type = EXP_GUITAR_HERO_3;
#ifdef WIN32
#ifdef WIIUSE_WIN32
wm->timeout = WIIMOTE_DEFAULT_TIMEOUT;
#endif
#endif
return 1;
}
@ -135,13 +128,8 @@ void guitar_hero_3_disconnected(struct guitar_hero_3_t* gh3) {
* @param msg The message specified in the event packet.
*/
void guitar_hero_3_event(struct guitar_hero_3_t* gh3, byte* msg) {
int i;
/* decrypt data */
for (i = 0; i < 6; ++i)
msg[i] = (msg[i] ^ 0x17) + 0x17;
guitar_hero_3_pressed_buttons(gh3, BIG_ENDIAN_SHORT(*(short*)(msg + 4)));
guitar_hero_3_pressed_buttons(gh3, from_big_endian_uint16_t(msg + 4));
/* whammy bar */
gh3->whammy_bar = (msg[3] - GUITAR_HERO_3_WHAMMY_BAR_MIN) / (float)(GUITAR_HERO_3_WHAMMY_BAR_MAX - GUITAR_HERO_3_WHAMMY_BAR_MIN);

View File

@ -49,14 +49,18 @@
extern "C" {
#endif
int guitar_hero_3_handshake(struct wiimote_t* wm, struct guitar_hero_3_t* gh3, byte* data, unsigned short len);
void guitar_hero_3_disconnected(struct guitar_hero_3_t* gh3);
/** @defgroup internal_gh3 Internal: Guitar Hero 3 controller */
/** @{ */
int guitar_hero_3_handshake(struct wiimote_t* wm, struct guitar_hero_3_t* gh3, byte* data, unsigned short len);
void guitar_hero_3_event(struct guitar_hero_3_t* gh3, byte* msg);
void guitar_hero_3_disconnected(struct guitar_hero_3_t* gh3);
void guitar_hero_3_event(struct guitar_hero_3_t* gh3, byte* msg);
/** @} */
#ifdef __cplusplus
}
#endif
#endif // GUITAR_HERO_3_H_INCLUDED
#endif /* GUITAR_HERO_3_H_INCLUDED */

View File

@ -31,15 +31,162 @@
* @brief Handles device I/O (non-OS specific).
*/
#include <stdio.h>
#include <stdlib.h>
#include "definitions.h"
#include "wiiuse_internal.h"
#include "io.h"
#include "ir.h" /* for wiiuse_set_ir_mode */
#include "wiiuse_internal.h"
#include "os.h" /* for wiiuse_os_* */
/**
#include <stdlib.h> /* for free, malloc */
/**
* @brief Find a wiimote or wiimotes.
*
* @param wm An array of wiimote_t structures.
* @param max_wiimotes The number of wiimote structures in \a wm.
* @param timeout The number of seconds before the search times out.
*
* @return The number of wiimotes found.
*
* @see wiiuse_connect()
* @see wiiuse_os_find()
*
* This function will only look for wiimote devices. \n
* When a device is found the address in the structures will be set. \n
* You can then call wiiuse_connect() to connect to the found \n
* devices.
*
* This function only delegates to the platform-specific implementation
* wiiuse_os_find.
*
* This function is declared in wiiuse.h
*/
int wiiuse_find(struct wiimote_t** wm, int max_wiimotes, int timeout) {
return wiiuse_os_find(wm, max_wiimotes, timeout);
}
/**
* @brief Connect to a wiimote or wiimotes once an address is known.
*
* @param wm An array of wiimote_t structures.
* @param wiimotes The number of wiimote structures in \a wm.
*
* @return The number of wiimotes that successfully connected.
*
* @see wiiuse_find()
* @see wiiuse_disconnect()
* @see wiiuse_os_connect()
*
* Connect to a number of wiimotes when the address is already set
* in the wiimote_t structures. These addresses are normally set
* by the wiiuse_find() function, but can also be set manually.
*
* This function only delegates to the platform-specific implementation
* wiiuse_os_connect.
*
* This function is declared in wiiuse.h
*/
int wiiuse_connect(struct wiimote_t** wm, int wiimotes) {
return wiiuse_os_connect(wm, wiimotes);
}
/**
* @brief Disconnect a wiimote.
*
* @param wm Pointer to a wiimote_t structure.
*
* @see wiiuse_connect()
* @see wiiuse_os_disconnect()
*
* Note that this will not free the wiimote structure.
*
* This function only delegates to the platform-specific implementation
* wiiuse_os_disconnect.
*
* This function is declared in wiiuse.h
*/
void wiiuse_disconnect(struct wiimote_t* wm) {
wiiuse_os_disconnect(wm);
}
/**
* @brief Wait until specified report arrives and return it
*
* @param wm Pointer to a wiimote_t structure.
* @param buffer Pre-allocated memory to store the received data
* @param bufferLength size of buffer in bytes
*
* Synchronous/blocking, this function will not return until it receives the specified
* report from the Wiimote.
*
*/
void wiiuse_wait_report(struct wiimote_t *wm, int report, byte *buffer, int bufferLength) {
for (;;) {
if (wiiuse_os_read(wm, buffer, bufferLength) > 0) {
if (buffer[0] == report) {
break;
} else {
WIIUSE_DEBUG("(id %i) dropping report 0x%x, waiting for 0x%x", wm->unid, buffer[0], report);
}
}
}
}
/**
* @brief Read memory/register data synchronously
*
* @param wm Pointer to a wiimote_t structure.
* @param memory If set to non-zero, reads EEPROM, otherwise registers
* @param addr Address offset to read from
* @param size How many bytes to read
* @param data Pre-allocated memory to store the received data
*
* Synchronous/blocking read, this function will not return until it receives the specified
* amount of data from the Wiimote.
*
*/
void wiiuse_read_data_sync(struct wiimote_t *wm, byte memory, unsigned addr, unsigned short size, byte *data) {
byte pkt[6];
byte buf[MAX_PAYLOAD];
unsigned n_full_reports;
unsigned last_report;
byte *output;
unsigned int i;
/*
* address in big endian first, the leading byte will
* be overwritten (only 3 bytes are sent)
*/
to_big_endian_uint32_t(pkt, addr);
/* read from registers or memory */
pkt[0] = (memory != 0) ? 0x00 : 0x04;
/* length in big endian */
to_big_endian_uint16_t(pkt + 4, size);
/* send */
wiiuse_send(wm, WM_CMD_READ_DATA, pkt, sizeof(pkt));
/* calculate how many 16B packets we have to get back */
n_full_reports = size / 16;
last_report = size % 16;
output = data;
for (i = 0; i < n_full_reports; ++i) {
wiiuse_wait_report(wm, WM_RPT_READ, buf, MAX_PAYLOAD);
memmove(output, buf + 6, 16);
output += 16;
}
/* read the last incomplete packet */
if (last_report) {
wiiuse_wait_report(wm, WM_RPT_READ, buf, MAX_PAYLOAD);
memmove(output, buf + 6, last_report);
}
}
/**
* @brief Get initialization data from the wiimote.
*
* @param wm Pointer to a wiimote_t structure.
@ -52,68 +199,168 @@
* The handshake will be concluded when the wiimote responds
* with this data.
*/
void wiiuse_handshake(struct wiimote_t* wm, byte* data, unsigned short len) {
if (!wm) return;
switch (wm->handshake_state) {
case 0:
{
/* send request to wiimote for accelerometer calibration */
byte* buf;
#ifdef WIIUSE_SYNC_HANDSHAKE
WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE);
wiiuse_set_leds(wm, WIIMOTE_LED_NONE);
void wiiuse_handshake(struct wiimote_t* wm, byte* data, uint16_t len) {
/* send request to wiimote for accelerometer calibration */
byte buf[MAX_PAYLOAD];
buf = (byte*)malloc(sizeof(byte) * 8);
wiiuse_read_data_cb(wm, wiiuse_handshake, buf, WM_MEM_OFFSET_CALIBRATION, 7);
wm->handshake_state++;
/* step 0 - Reset wiimote */
{
//wiiuse_set_leds(wm, WIIMOTE_LED_NONE);
wiiuse_set_leds(wm, WIIMOTE_LED_NONE);
WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE);
WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_CONNECTED);
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_ACC);
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR);
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_RUMBLE);
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP);
WIIMOTE_DISABLE_FLAG(wm, WIIUSE_CONTINUOUS);
break;
wiiuse_set_report_type(wm);
wiiuse_millisleep(500);
WIIUSE_DEBUG("Wiimote reset!\n");
}
/* step 1 - calibration of accelerometers */
{
struct accel_t* accel = &wm->accel_calib;
wiiuse_read_data_sync(wm, 1, WM_MEM_OFFSET_CALIBRATION, 8, buf);
/* received read data */
accel->cal_zero.x = buf[0];
accel->cal_zero.y = buf[1];
accel->cal_zero.z = buf[2];
accel->cal_g.x = buf[4] - accel->cal_zero.x;
accel->cal_g.y = buf[5] - accel->cal_zero.y;
accel->cal_g.z = buf[6] - accel->cal_zero.z;
WIIUSE_DEBUG("Calibrated wiimote acc\n");
}
/* step 2 - re-enable IR and ask for status */
{
WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE_COMPLETE);
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE);
/* now enable IR if it was set before the handshake completed */
if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) {
WIIUSE_DEBUG("Handshake finished, enabling IR.");
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR);
wiiuse_set_ir(wm, 1);
}
case 1:
{
struct read_req_t* req = wm->read_req;
struct accel_t* accel = &wm->accel_calib;
/* received read data */
accel->cal_zero.x = req->buf[0];
accel->cal_zero.y = req->buf[1];
accel->cal_zero.z = req->buf[2];
accel->cal_g.x = req->buf[4] - accel->cal_zero.x;
accel->cal_g.y = req->buf[5] - accel->cal_zero.y;
accel->cal_g.z = req->buf[6] - accel->cal_zero.z;
/* done with the buffer */
free(req->buf);
/* handshake is done */
WIIUSE_DEBUG("Handshake finished. Calibration: Idle: X=%x Y=%x Z=%x\t+1g: X=%x Y=%x Z=%x",
accel->cal_zero.x, accel->cal_zero.y, accel->cal_zero.z,
accel->cal_g.x, accel->cal_g.y, accel->cal_g.z);
/* request the status of the wiimote to see if there is an expansion */
wiiuse_status(wm);
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE);
WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE_COMPLETE);
wm->handshake_state++;
/* now enable IR if it was set before the handshake completed */
if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) {
WIIUSE_DEBUG("Handshake finished, enabling IR.");
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR);
wiiuse_set_ir(wm, 1);
}
break;
}
default:
{
break;
}
WIIUSE_DEBUG("Asking for status ...\n");
wm->event = WIIUSE_CONNECT;
wiiuse_status(wm);
}
}
#else
static void wiiuse_disable_motion_plus1(struct wiimote_t *wm, byte *data, unsigned short len);
static void wiiuse_disable_motion_plus2(struct wiimote_t *wm, byte *data, unsigned short len);
void wiiuse_handshake(struct wiimote_t* wm, byte* data, uint16_t len) {
if (!wm) {
return;
}
switch (wm->handshake_state) {
case 0: {
byte* buf;
/* continuous reporting off, report to buttons only */
WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE);
wiiuse_set_leds(wm, WIIMOTE_LED_NONE);
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_ACC);
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR);
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_RUMBLE);
WIIMOTE_DISABLE_FLAG(wm, WIIUSE_CONTINUOUS);
wiiuse_set_report_type(wm);
/* send request to wiimote for accelerometer calibration */
buf = (byte*)malloc(sizeof(byte) * 8);
wiiuse_read_data_cb(wm, wiiuse_handshake, buf, WM_MEM_OFFSET_CALIBRATION, 7);
wm->handshake_state++;
wiiuse_set_leds(wm, WIIMOTE_LED_NONE);
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];
accel->cal_zero.y = req->buf[1];
accel->cal_zero.z = req->buf[2];
accel->cal_g.x = req->buf[4] - accel->cal_zero.x;
accel->cal_g.y = req->buf[5] - accel->cal_zero.y;
accel->cal_g.z = req->buf[6] - accel->cal_zero.z;
/* done with the buffer */
free(req->buf);
/* handshake is done */
WIIUSE_DEBUG("Handshake finished. Calibration: Idle: X=%x Y=%x Z=%x\t+1g: X=%x Y=%x Z=%x",
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);
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++;
/* now enable IR if it was set before the handshake completed */
if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) {
WIIUSE_DEBUG("Handshake finished, enabling IR.");
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR);
wiiuse_set_ir(wm, 1);
}
wm->event = WIIUSE_CONNECT;
wiiuse_status(wm);
break;
}
default: {
break;
}
}
}
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);
}
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);
}
#endif

View File

@ -31,12 +31,8 @@
* @brief Handles device I/O.
*/
#ifndef CONNECT_H_INCLUDED
#define CONNECT_H_INCLUDED
#ifndef WIN32
#include <bluetooth/bluetooth.h>
#endif
#ifndef IO_H_INCLUDED
#define IO_H_INCLUDED
#include "wiiuse_internal.h"
@ -44,13 +40,16 @@
extern "C" {
#endif
void wiiuse_handshake(struct wiimote_t* wm, byte* data, unsigned short len);
/** @defgroup internal_io Internal: Device I/O */
/** @{ */
void wiiuse_handshake(struct wiimote_t* wm, byte* data, uint16_t len);
int wiiuse_io_read(struct wiimote_t* wm);
int wiiuse_io_write(struct wiimote_t* wm, byte* buf, int len);
void wiiuse_wait_report(struct wiimote_t *wm, int report, byte *buffer, int bufferLength);
void wiiuse_read_data_sync(struct wiimote_t *wm, byte memory, unsigned addr, unsigned short size, byte *data);
/** @} */
#ifdef __cplusplus
}
#endif
#endif // CONNECT_H_INCLUDED
#endif /* IO_H_INCLUDED */

View File

@ -31,18 +31,11 @@
* @brief Handles IR data.
*/
#include <stdio.h>
#include <math.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include "definitions.h"
#include "wiiuse_internal.h"
#include "ir.h"
static int get_ir_sens(struct wiimote_t* wm, char** block1, char** block2);
#include <math.h> /* for atanf, cos, sin, sqrt */
static int get_ir_sens(struct wiimote_t* wm, const byte** block1, const byte** block2);
static void interpret_ir_data(struct wiimote_t* wm);
static void fix_rotated_ir_dots(struct ir_dot_t* dot, float ang);
static void get_ir_dot_avg(struct ir_dot_t* dot, int* x, int* y);
@ -52,6 +45,35 @@ static int ir_correct_for_bounds(int* x, int* y, enum aspect_t aspect, int offse
static void ir_convert_to_vres(int* x, int* y, enum aspect_t aspect, int vx, int vy);
/* ir block data */
static const byte WM_IR_BLOCK1_LEVEL1[] = "\x02\x00\x00\x71\x01\x00\x64\x00\xfe";
static const byte WM_IR_BLOCK2_LEVEL1[] = "\xfd\x05";
static const byte WM_IR_BLOCK1_LEVEL2[] = "\x02\x00\x00\x71\x01\x00\x96\x00\xb4";
static const byte WM_IR_BLOCK2_LEVEL2[] = "\xb3\x04";
static const byte WM_IR_BLOCK1_LEVEL3[] = "\x02\x00\x00\x71\x01\x00\xaa\x00\x64";
static const byte WM_IR_BLOCK2_LEVEL3[] = "\x63\x03";
static const byte WM_IR_BLOCK1_LEVEL4[] = "\x02\x00\x00\x71\x01\x00\xc8\x00\x36";
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.
*
@ -60,12 +82,13 @@ static void ir_convert_to_vres(int* x, int* y, enum aspect_t aspect, int vx, int
*/
void wiiuse_set_ir(struct wiimote_t* wm, int status) {
byte buf;
char* block1 = NULL;
char* block2 = NULL;
const byte* block1 = NULL;
const byte* block2 = NULL;
int ir_level;
if (!wm)
if (!wm) {
return;
}
/*
* Wait for the handshake to finish first.
@ -74,8 +97,10 @@ void wiiuse_set_ir(struct wiimote_t* wm, int status) {
* again to actually enable IR.
*/
if (!WIIMOTE_IS_SET(wm, WIIMOTE_STATE_HANDSHAKE_COMPLETE)) {
WIIUSE_DEBUG("Tried to enable IR, will wait until handshake finishes.");
WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR);
if (status) {
WIIUSE_DEBUG("Tried to enable IR, will wait until handshake finishes.");
WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR);
} /* else ignoring request to turn off, since it's turned off by default */
return;
}
@ -90,13 +115,15 @@ void wiiuse_set_ir(struct wiimote_t* wm, int status) {
if (status) {
/* if already enabled then stop */
if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR))
if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) {
return;
}
WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR);
} else {
/* if already disabled then stop */
if (!WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR))
if (!WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) {
return;
}
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR);
}
@ -116,28 +143,21 @@ void wiiuse_set_ir(struct wiimote_t* wm, int status) {
wiiuse_write_data(wm, WM_REG_IR, &buf, 1);
/* wait for the wiimote to catch up */
#ifndef WIN32
usleep(50000);
#else
Sleep(50);
#endif
wiiuse_millisleep(50);
/* write sensitivity blocks */
wiiuse_write_data(wm, WM_REG_IR_BLOCK1, (byte*)block1, 9);
wiiuse_write_data(wm, WM_REG_IR_BLOCK2, (byte*)block2, 2);
/* set the IR mode */
if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP))
if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP)) {
buf = WM_IR_TYPE_BASIC;
else
} else {
buf = WM_IR_TYPE_EXTENDED;
}
wiiuse_write_data(wm, WM_REG_IR_MODENUM, &buf, 1);
#ifndef WIN32
usleep(50000);
#else
Sleep(50);
#endif
wiiuse_millisleep(50);
/* set the wiimote report type */
wiiuse_set_report_type(wm);
@ -155,7 +175,7 @@ void wiiuse_set_ir(struct wiimote_t* wm, int status) {
*
* @return Returns the sensitivity level.
*/
static int get_ir_sens(struct wiimote_t* wm, char** block1, char** block2) {
static int get_ir_sens(struct wiimote_t* wm, const byte** block1, const byte** block2) {
if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR_SENS_LVL1)) {
*block1 = WM_IR_BLOCK1_LEVEL1;
*block2 = WM_IR_BLOCK2_LEVEL1;
@ -191,10 +211,12 @@ static int get_ir_sens(struct wiimote_t* wm, char** block1, char** block2) {
* @param status 1 to enable, 0 to disable.
*/
void wiiuse_set_ir_vres(struct wiimote_t* wm, unsigned int x, unsigned int y) {
if (!wm) return;
if (!wm) {
return;
}
wm->ir.vres[0] = (x-1);
wm->ir.vres[1] = (y-1);
wm->ir.vres[0] = (x - 1);
wm->ir.vres[1] = (y - 1);
}
@ -204,7 +226,9 @@ void wiiuse_set_ir_vres(struct wiimote_t* wm, unsigned int x, unsigned int y) {
* @param wm Pointer to a wiimote_t structure.
*/
void wiiuse_set_ir_position(struct wiimote_t* wm, enum ir_position_t pos) {
if (!wm) return;
if (!wm) {
return;
}
wm->ir.pos = pos;
@ -213,20 +237,22 @@ void wiiuse_set_ir_position(struct wiimote_t* wm, enum ir_position_t pos) {
case WIIUSE_IR_ABOVE:
wm->ir.offset[0] = 0;
if (wm->ir.aspect == WIIUSE_ASPECT_16_9)
wm->ir.offset[1] = WM_ASPECT_16_9_Y/2 - 70;
else if (wm->ir.aspect == WIIUSE_ASPECT_4_3)
wm->ir.offset[1] = WM_ASPECT_4_3_Y/2 - 100;
if (wm->ir.aspect == WIIUSE_ASPECT_16_9) {
wm->ir.offset[1] = WM_ASPECT_16_9_Y / 2 - 70;
} else if (wm->ir.aspect == WIIUSE_ASPECT_4_3) {
wm->ir.offset[1] = WM_ASPECT_4_3_Y / 2 - 100;
}
return;
case WIIUSE_IR_BELOW:
wm->ir.offset[0] = 0;
if (wm->ir.aspect == WIIUSE_ASPECT_16_9)
wm->ir.offset[1] = -WM_ASPECT_16_9_Y/2 + 100;
else if (wm->ir.aspect == WIIUSE_ASPECT_4_3)
wm->ir.offset[1] = -WM_ASPECT_4_3_Y/2 + 70;
if (wm->ir.aspect == WIIUSE_ASPECT_16_9) {
wm->ir.offset[1] = -WM_ASPECT_16_9_Y / 2 + 100;
} else if (wm->ir.aspect == WIIUSE_ASPECT_4_3) {
wm->ir.offset[1] = -WM_ASPECT_4_3_Y / 2 + 70;
}
return;
@ -243,7 +269,9 @@ void wiiuse_set_ir_position(struct wiimote_t* wm, enum ir_position_t pos) {
* @param aspect Either WIIUSE_ASPECT_16_9 or WIIUSE_ASPECT_4_3
*/
void wiiuse_set_aspect_ratio(struct wiimote_t* wm, enum aspect_t aspect) {
if (!wm) return;
if (!wm) {
return;
}
wm->ir.aspect = aspect;
@ -270,19 +298,25 @@ void wiiuse_set_aspect_ratio(struct wiimote_t* wm, enum aspect_t aspect) {
* If the level is > 5, then level will be set to 5.
*/
void wiiuse_set_ir_sensitivity(struct wiimote_t* wm, int level) {
char* block1 = NULL;
char* block2 = NULL;
const byte* block1 = NULL;
const byte* block2 = NULL;
if (!wm) return;
if (!wm) {
return;
}
if (level > 5) level = 5;
if (level < 1) level = 1;
if (level > 5) {
level = 5;
}
if (level < 1) {
level = 1;
}
WIIMOTE_DISABLE_STATE(wm, (WIIMOTE_STATE_IR_SENS_LVL1 |
WIIMOTE_STATE_IR_SENS_LVL2 |
WIIMOTE_STATE_IR_SENS_LVL3 |
WIIMOTE_STATE_IR_SENS_LVL4 |
WIIMOTE_STATE_IR_SENS_LVL5));
WIIMOTE_STATE_IR_SENS_LVL2 |
WIIMOTE_STATE_IR_SENS_LVL3 |
WIIMOTE_STATE_IR_SENS_LVL4 |
WIIMOTE_STATE_IR_SENS_LVL5));
switch (level) {
case 1:
@ -307,8 +341,8 @@ void wiiuse_set_ir_sensitivity(struct wiimote_t* wm, int level) {
/* set the new sensitivity */
get_ir_sens(wm, &block1, &block2);
wiiuse_write_data(wm, WM_REG_IR_BLOCK1, (byte*)block1, 9);
wiiuse_write_data(wm, WM_REG_IR_BLOCK2, (byte*)block2, 2);
wiiuse_write_data(wm, WM_REG_IR_BLOCK1, block1, 9);
wiiuse_write_data(wm, WM_REG_IR_BLOCK2, block2, 2);
WIIUSE_DEBUG("Set IR sensitivity to level %i (unid %i)", level, wm->unid);
}
@ -338,9 +372,9 @@ void calculate_basic_ir(struct wiimote_t* wm, byte* data) {
/* set each IR spot to visible if spot is in range */
for (i = 0; i < 4; ++i) {
if (dot[i].ry == 1023)
if (dot[i].ry == 1023) {
dot[i].visible = 0;
else {
} else {
dot[i].visible = 1;
dot[i].size = 0; /* since we don't know the size, set it as 0 */
}
@ -361,16 +395,17 @@ void calculate_extended_ir(struct wiimote_t* wm, byte* data) {
int i;
for (i = 0; i < 4; ++i) {
dot[i].rx = 1023 - (data[3*i] | ((data[(3*i)+2] & 0x30) << 4));
dot[i].ry = data[(3*i)+1] | ((data[(3*i)+2] & 0xC0) << 2);
dot[i].rx = 1023 - (data[3 * i] | ((data[(3 * i) + 2] & 0x30) << 4));
dot[i].ry = data[(3 * i) + 1] | ((data[(3 * i) + 2] & 0xC0) << 2);
dot[i].size = data[(3*i)+2] & 0x0F;
dot[i].size = data[(3 * i) + 2] & 0x0F;
/* if in range set to visible */
if (dot[i].ry == 1023)
if (dot[i].ry == 1023) {
dot[i].visible = 0;
else
} else {
dot[i].visible = 1;
}
}
interpret_ir_data(wm);
@ -388,147 +423,150 @@ static void interpret_ir_data(struct wiimote_t* wm) {
float roll = 0.0f;
int last_num_dots = wm->ir.num_dots;
if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_ACC))
if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_ACC)) {
roll = wm->orient.roll;
}
/* count visible dots */
wm->ir.num_dots = 0;
for (i = 0; i < 4; ++i) {
if (dot[i].visible)
if (dot[i].visible) {
wm->ir.num_dots++;
}
}
switch (wm->ir.num_dots) {
case 0:
{
wm->ir.state = 0;
case 0: {
wm->ir.state = 0;
/* reset the dot ordering */
for (i = 0; i < 4; ++i)
dot[i].order = 0;
wm->ir.x = 0;
wm->ir.y = 0;
wm->ir.z = 0.0f;
return;
}
case 1:
{
fix_rotated_ir_dots(wm->ir.dot, roll);
if (wm->ir.state < 2) {
/*
* Only 1 known dot, so use just that.
*/
/* reset the dot ordering */
for (i = 0; i < 4; ++i) {
if (dot[i].visible) {
wm->ir.x = dot[i].x;
wm->ir.y = dot[i].y;
wm->ir.ax = wm->ir.x;
wm->ir.ay = wm->ir.y;
/* can't calculate yaw because we don't have the distance */
//wm->orient.yaw = calc_yaw(&wm->ir);
ir_convert_to_vres(&wm->ir.x, &wm->ir.y, wm->ir.aspect, wm->ir.vres[0], wm->ir.vres[1]);
break;
}
dot[i].order = 0;
}
} else {
/*
* Only see 1 dot but know theres 2.
* Try to estimate where the other one
* should be and use that.
*/
for (i = 0; i < 4; ++i) {
if (dot[i].visible) {
int ox = 0;
int x, y;
if (dot[i].order == 1)
/* visible is the left dot - estimate where the right is */
ox = dot[i].x + wm->ir.distance;
else if (dot[i].order == 2)
/* visible is the right dot - estimate where the left is */
ox = dot[i].x - wm->ir.distance;
x = ((signed int)dot[i].x + ox) / 2;
y = dot[i].y;
wm->ir.ax = x;
wm->ir.ay = y;
wm->orient.yaw = calc_yaw(&wm->ir);
if (ir_correct_for_bounds(&x, &y, wm->ir.aspect, wm->ir.offset[0], wm->ir.offset[1])) {
ir_convert_to_vres(&x, &y, wm->ir.aspect, wm->ir.vres[0], wm->ir.vres[1]);
wm->ir.x = x;
wm->ir.y = y;
}
break;
}
}
}
break;
}
case 2:
case 3:
case 4:
{
/*
* Two (or more) dots known and seen.
* Average them together to estimate the true location.
*/
int x, y;
wm->ir.state = 2;
fix_rotated_ir_dots(wm->ir.dot, roll);
/* if there is at least 1 new dot, reorder them all */
if (wm->ir.num_dots > last_num_dots) {
reorder_ir_dots(dot);
wm->ir.x = 0;
wm->ir.y = 0;
wm->ir.z = 0.0f;
return;
}
case 1: {
fix_rotated_ir_dots(wm->ir.dot, roll);
wm->ir.distance = ir_distance(dot);
wm->ir.z = 1023 - wm->ir.distance;
if (wm->ir.state < 2) {
/*
* Only 1 known dot, so use just that.
*/
for (i = 0; i < 4; ++i) {
if (dot[i].visible) {
wm->ir.x = dot[i].x;
wm->ir.y = dot[i].y;
get_ir_dot_avg(wm->ir.dot, &x, &y);
wm->ir.ax = wm->ir.x;
wm->ir.ay = wm->ir.y;
wm->ir.ax = x;
wm->ir.ay = y;
wm->orient.yaw = calc_yaw(&wm->ir);
/* can't calculate yaw because we don't have the distance */
/* wm->orient.yaw = calc_yaw(&wm->ir); */
if (ir_correct_for_bounds(&x, &y, wm->ir.aspect, wm->ir.offset[0], wm->ir.offset[1])) {
ir_convert_to_vres(&x, &y, wm->ir.aspect, wm->ir.vres[0], wm->ir.vres[1]);
wm->ir.x = x;
wm->ir.y = y;
ir_convert_to_vres(&wm->ir.x, &wm->ir.y, wm->ir.aspect, wm->ir.vres[0], wm->ir.vres[1]);
break;
}
}
} else {
/*
* Only see 1 dot but know theres 2.
* Try to estimate where the other one
* should be and use that.
*/
for (i = 0; i < 4; ++i) {
if (dot[i].visible) {
int ox = 0;
int x, y;
if (dot[i].order == 1)
/* visible is the left dot - estimate where the right is */
{
ox = (int32_t)(dot[i].x + wm->ir.distance);
} else if (dot[i].order == 2)
/* visible is the right dot - estimate where the left is */
{
ox = (int32_t)(dot[i].x - wm->ir.distance);
}
x = ((signed int)dot[i].x + ox) / 2;
y = dot[i].y;
wm->ir.ax = x;
wm->ir.ay = y;
wm->orient.yaw = calc_yaw(&wm->ir);
if (ir_correct_for_bounds(&x, &y, wm->ir.aspect, wm->ir.offset[0], wm->ir.offset[1])) {
ir_convert_to_vres(&x, &y, wm->ir.aspect, wm->ir.vres[0], wm->ir.vres[1]);
wm->ir.x = x;
wm->ir.y = y;
}
break;
}
}
}
break;
}
case 2:
case 3:
case 4: {
/*
* Two (or more) dots known and seen.
* Average them together to estimate the true location.
*/
int x, y;
wm->ir.state = 2;
break;
}
default:
{
break;
}
fix_rotated_ir_dots(wm->ir.dot, roll);
/* if there is at least 1 new dot, reorder them all */
if (wm->ir.num_dots > last_num_dots) {
reorder_ir_dots(dot);
wm->ir.x = 0;
wm->ir.y = 0;
}
wm->ir.distance = ir_distance(dot);
wm->ir.z = 1023 - wm->ir.distance;
get_ir_dot_avg(wm->ir.dot, &x, &y);
wm->ir.ax = x;
wm->ir.ay = y;
wm->orient.yaw = calc_yaw(&wm->ir);
if (ir_correct_for_bounds(&x, &y, wm->ir.aspect, wm->ir.offset[0], wm->ir.offset[1])) {
ir_convert_to_vres(&x, &y, wm->ir.aspect, wm->ir.vres[0], wm->ir.vres[1]);
wm->ir.x = x;
wm->ir.y = y;
}
break;
}
default: {
break;
}
}
#ifdef WITH_WIIUSE_DEBUG
#ifdef WITH_WIIUSE_DEBUG
{
int ir_level;
WIIUSE_GET_IR_SENSITIVITY(wm, &ir_level);
WIIUSE_DEBUG("IR sensitivity: %i", ir_level);
WIIUSE_DEBUG("IR visible dots: %i", wm->ir.num_dots);
for (i = 0; i < 4; ++i)
if (dot[i].visible)
WIIUSE_DEBUG("IR[%i][order %i] (%.3i, %.3i) -> (%.3i, %.3i)", i, dot[i].order, dot[i].rx, dot[i].ry, dot[i].x, dot[i].y);
WIIUSE_DEBUG("IR[absolute]: (%i, %i)", wm->ir.x, wm->ir.y);
int ir_level;
WIIUSE_GET_IR_SENSITIVITY(wm, &ir_level);
WIIUSE_DEBUG("IR sensitivity: %i", ir_level);
WIIUSE_DEBUG("IR visible dots: %i", wm->ir.num_dots);
for (i = 0; i < 4; ++i)
if (dot[i].visible) {
WIIUSE_DEBUG("IR[%i][order %i] (%.3i, %.3i) -> (%.3i, %.3i)", i, dot[i].order, dot[i].rx, dot[i].ry, dot[i].x, dot[i].y);
}
WIIUSE_DEBUG("IR[absolute]: (%i, %i)", wm->ir.x, wm->ir.y);
}
#endif
#endif
}
@ -560,8 +598,8 @@ static void fix_rotated_ir_dots(struct ir_dot_t* dot, float ang) {
return;
}
s = sin(DEGREE_TO_RAD(ang));
c = cos(DEGREE_TO_RAD(ang));
s = sinf(DEGREE_TO_RAD(ang));
c = cosf(DEGREE_TO_RAD(ang));
/*
* [ cos(theta) -sin(theta) ][ ir->rx ]
@ -569,17 +607,18 @@ static void fix_rotated_ir_dots(struct ir_dot_t* dot, float ang) {
*/
for (i = 0; i < 4; ++i) {
if (!dot[i].visible)
if (!dot[i].visible) {
continue;
}
x = dot[i].rx - (1024/2);
y = dot[i].ry - (768/2);
x = dot[i].rx - (1024 / 2);
y = dot[i].ry - (768 / 2);
dot[i].x = (c * x) + (-s * y);
dot[i].y = (s * x) + (c * y);
dot[i].x = (uint32_t)((c * x) + (-s * y));
dot[i].y = (uint32_t)((s * x) + (c * y));
dot[i].x += (1024/2);
dot[i].y += (768/2);
dot[i].x += (1024 / 2);
dot[i].y += (768 / 2);
}
}
@ -619,19 +658,22 @@ static void reorder_ir_dots(struct ir_dot_t* dot) {
int i, j, order;
/* reset the dot ordering */
for (i = 0; i < 4; ++i)
for (i = 0; i < 4; ++i) {
dot[i].order = 0;
}
for (order = 1; order < 5; ++order) {
i = 0;
for (; !dot[i].visible || dot[i].order; ++i)
if (i > 4)
return;
if (i >= 3) {
return;
}
for (j = 0; j < 4; ++j) {
if (dot[j].visible && !dot[j].order && (dot[j].x < dot[i].x))
if (dot[j].visible && !dot[j].order && (dot[j].x < dot[i].x)) {
i = j;
}
}
dot[i].order = order;
@ -649,21 +691,25 @@ static float ir_distance(struct ir_dot_t* dot) {
int xd, yd;
for (i1 = 0; i1 < 4; ++i1)
if (dot[i1].visible)
if (dot[i1].visible) {
break;
if (i1 == 4)
}
if (i1 == 4) {
return 0.0f;
}
for (i2 = i1+1; i2 < 4; ++i2)
if (dot[i2].visible)
for (i2 = i1 + 1; i2 < 4; ++i2)
if (dot[i2].visible) {
break;
if (i2 == 4)
}
if (i2 == 4) {
return 0.0f;
}
xd = dot[i2].x - dot[i1].x;
yd = dot[i2].y - dot[i1].y;
return sqrt(xd*xd + yd*yd);
return sqrtf(xd * xd + yd * yd);
}
@ -697,10 +743,9 @@ static int ir_correct_for_bounds(int* x, int* y, enum aspect_t aspect, int offse
y0 = ((768 - ys) / 2) + offset_y;
if ((*x >= x0)
&& (*x <= (x0 + xs))
&& (*y >= y0)
&& (*y <= (y0 + ys)))
{
&& (*x <= (x0 + xs))
&& (*y >= y0)
&& (*y <= (y0 + ys))) {
*x -= offset_x;
*y -= offset_y;
@ -725,11 +770,11 @@ static void ir_convert_to_vres(int* x, int* y, enum aspect_t aspect, int vx, int
ys = WM_ASPECT_4_3_Y;
}
*x -= ((1024-xs)/2);
*y -= ((768-ys)/2);
*x -= ((1024 - xs) / 2);
*y -= ((768 - ys) / 2);
*x = (*x / (float)xs) * vx;
*y = (*y / (float)ys) * vy;
*x = (int)((*x / (float)xs) * vx);
*y = (int)((*y / (float)ys) * vy);
}
@ -741,8 +786,8 @@ static void ir_convert_to_vres(int* x, int* y, enum aspect_t aspect, int vx, int
float calc_yaw(struct ir_t* ir) {
float x;
x = ir->ax - 512;
x = (float)(ir->ax - 512);
x = x * (ir->z / 1024.0f);
return RAD_TO_DEGREE( atanf(x / ir->z) );
return RAD_TO_DEGREE(atanf(x / ir->z));
}

View File

@ -43,14 +43,19 @@
extern "C" {
#endif
void calculate_basic_ir(struct wiimote_t* wm, byte* data);
void calculate_extended_ir(struct wiimote_t* wm, byte* data);
float calc_yaw(struct ir_t* ir);
/** @defgroup internal_ir Internal: IR Sensor */
/** @{ */
void wiiuse_set_ir_mode(struct wiimote_t *wm);
void calculate_basic_ir(struct wiimote_t* wm, byte* data);
void calculate_extended_ir(struct wiimote_t* wm, byte* data);
float calc_yaw(struct ir_t* ir);
/** @} */
#ifdef __cplusplus
}
#endif
#endif // IR_H_INCLUDED
#endif /* IR_H_INCLUDED */

338
lib/wiiuse/motion_plus.c Normal file
View File

@ -0,0 +1,338 @@
/*
* 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 "io.h" /* for wiiuse_read */
#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_probe_motion_plus(struct wiimote_t *wm) {
byte buf[MAX_PAYLOAD];
unsigned id;
wiiuse_read_data_sync(wm, 0, WM_EXP_MOTION_PLUS_IDENT, 6, buf);
/* check error code */
if (buf[4] & 0x0f) {
WIIUSE_DEBUG("No Motion+ available, stopping probe.");
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_MPLUS_PRESENT);
return;
}
/* decode the id */
id = from_big_endian_uint32_t(buf + 2);
if (id != EXP_ID_CODE_INACTIVE_MOTION_PLUS &&
id != EXP_ID_CODE_NLA_MOTION_PLUS &&
id != EXP_ID_CODE_NLA_MOTION_PLUS_NUNCHUK &&
id != EXP_ID_CODE_NLA_MOTION_PLUS_CLASSIC) {
/* we have read something weird */
WIIUSE_DEBUG("Motion+ ID doesn't match, probably not connected.");
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_MPLUS_PRESENT);
return;
}
WIIUSE_DEBUG("Detected inactive Motion+!");
WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_MPLUS_PRESENT);
/* init M+ */
buf[0] = 0x55;
wiiuse_write_data(wm, WM_EXP_MOTION_PLUS_INIT, buf, 1);
/* Init whatever is hanging on the pass-through port */
buf[0] = 0x55;
wiiuse_write_data(wm, WM_EXP_MEM_ENABLE1, buf, 1);
buf[0] = 0x00;
wiiuse_write_data(wm, WM_EXP_MEM_ENABLE2, buf, 1);
/* Init gyroscope data */
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);
}
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 (!WIIMOTE_IS_SET(wm, WIIMOTE_STATE_MPLUS_PRESENT) ||
WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP_HANDSHAKE)) {
return;
}
if (status) {
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 = (float)tmp_r / 20.0f;
} else {
tmp_roll = (float)tmp_r / 4.0f;
}
if (mp->acc_mode & 0x02) {
tmp_pitch = (float)tmp_p / 20.0f;
} else {
tmp_pitch = (float)tmp_p / 4.0f;
}
if (mp->acc_mode & 0x01) {
tmp_yaw = (float)tmp_y / 20.0f;
} else {
tmp_yaw = (float)tmp_y / 4.0f;
}
/* Simple filtering */
if (fabs(tmp_roll) < 0.5f) {
tmp_roll = 0.0f;
}
if (fabs(tmp_pitch) < 0.5f) {
tmp_pitch = 0.0f;
}
if (fabs(tmp_yaw) < 0.5f) {
tmp_yaw = 0.0f;
}
mp->angle_rate_gyro.roll = tmp_roll;
mp->angle_rate_gyro.pitch = tmp_pitch;
mp->angle_rate_gyro.yaw = tmp_yaw;
}

60
lib/wiiuse/motion_plus.h Normal file
View File

@ -0,0 +1,60 @@
/*
* 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);
void wiiuse_probe_motion_plus(struct wiimote_t *wm);
/** @} */
#ifdef __cplusplus
}
#endif
#endif

View File

@ -31,17 +31,13 @@
* @brief Nunchuk expansion device.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "definitions.h"
#include "wiiuse_internal.h"
#include "dynamics.h"
#include "events.h"
#include "nunchuk.h"
#include "dynamics.h" /* for calc_joystick_state, etc */
#include "events.h" /* for handshake_expansion */
static void nunchuk_pressed_buttons(struct nunchuk_t* nc, byte now);
#include <stdlib.h> /* for malloc */
#include <string.h> /* for memset */
/**
* @brief Handle the handshake data from the nunchuk.
@ -52,10 +48,8 @@ static void nunchuk_pressed_buttons(struct nunchuk_t* nc, byte now);
*
* @return Returns 1 if handshake was successful, 0 if not.
*/
#define HANDSHAKE_BYTES_USED 14
int nunchuk_handshake(struct wiimote_t* wm, struct nunchuk_t* nc, byte* data, unsigned short len) {
int i;
int offset = 0;
nc->btns = 0;
nc->btns_held = 0;
nc->btns_released = 0;
@ -64,11 +58,7 @@ int nunchuk_handshake(struct wiimote_t* wm, struct nunchuk_t* nc, byte* data, un
nc->flags = &wm->flags;
nc->accel_calib.st_alpha = wm->accel_calib.st_alpha;
/* decrypt data */
for (i = 0; i < len; ++i)
data[i] = (data[i] ^ 0x17) + 0x17;
if (data[offset] == 0xFF) {
if (data[0] == 0xFF || len < HANDSHAKE_BYTES_USED) {
/*
* Sometimes the data returned here is not correct.
* This might happen because the wiimote is lagging
@ -79,30 +69,34 @@ int nunchuk_handshake(struct wiimote_t* wm, struct nunchuk_t* nc, byte* data, un
* but since the next 16 bytes are the same, just use
* those.
*/
if (data[offset + 16] == 0xFF) {
if (len < 17 || len < HANDSHAKE_BYTES_USED + 16 || data[16] == 0xFF) {
/* get the calibration data */
byte* handshake_buf = malloc(EXP_HANDSHAKE_LEN * sizeof(byte));
byte* handshake_buf = (byte *)malloc(EXP_HANDSHAKE_LEN * sizeof(byte));
WIIUSE_DEBUG("Nunchuk handshake appears invalid, trying again.");
wiiuse_read_data_cb(wm, handshake_expansion, handshake_buf, WM_EXP_MEM_CALIBR, EXP_HANDSHAKE_LEN);
return 0;
} else
offset += 16;
} else {
data += 16;
}
}
nc->accel_calib.cal_zero.x = data[offset + 0];
nc->accel_calib.cal_zero.y = data[offset + 1];
nc->accel_calib.cal_zero.z = data[offset + 2];
nc->accel_calib.cal_g.x = data[offset + 4];
nc->accel_calib.cal_g.y = data[offset + 5];
nc->accel_calib.cal_g.z = data[offset + 6];
nc->js.max.x = data[offset + 8];
nc->js.min.x = data[offset + 9];
nc->js.center.x = data[offset + 10];
nc->js.max.y = data[offset + 11];
nc->js.min.y = data[offset + 12];
nc->js.center.y = data[offset + 13];
nc->accel_calib.cal_zero.x = data[0];
nc->accel_calib.cal_zero.y = data[1];
nc->accel_calib.cal_zero.z = data[2];
nc->accel_calib.cal_g.x = data[4];
nc->accel_calib.cal_g.y = data[5];
nc->accel_calib.cal_g.z = data[6];
nc->js.max.x = data[8];
nc->js.min.x = data[9];
nc->js.center.x = data[10];
nc->js.max.y = data[11];
nc->js.min.y = data[12];
nc->js.center.y = data[13];
WIIUSE_DEBUG("Nunchuk calibration X: min %x, max %x, center %x Y: min %x, max %x, center %x",
nc->js.min.x, nc->js.max.x, nc->js.center.x,
nc->js.min.y, nc->js.max.y, nc->js.center.y);
/* default the thresholds to the same as the wiimote */
nc->orient_threshold = wm->orient_threshold;
@ -111,9 +105,9 @@ int nunchuk_handshake(struct wiimote_t* wm, struct nunchuk_t* nc, byte* data, un
/* handshake done */
wm->exp.type = EXP_NUNCHUK;
#ifdef WIN32
#ifdef WIIUSE_WIN32
wm->timeout = WIIMOTE_DEFAULT_TIMEOUT;
#endif
#endif
return 1;
}
@ -137,11 +131,6 @@ void nunchuk_disconnected(struct nunchuk_t* nc) {
* @param msg The message specified in the event packet.
*/
void nunchuk_event(struct nunchuk_t* nc, byte* msg) {
int i;
/* decrypt data */
for (i = 0; i < 6; ++i)
msg[i] = (msg[i] ^ 0x17) + 0x17;
/* get button states */
nunchuk_pressed_buttons(nc, msg[5]);
@ -165,7 +154,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;
@ -189,7 +178,9 @@ static void nunchuk_pressed_buttons(struct nunchuk_t* nc, byte now) {
* See wiiuse_set_orient_threshold() for details.
*/
void wiiuse_set_nunchuk_orient_threshold(struct wiimote_t* wm, float threshold) {
if (!wm) return;
if (!wm) {
return;
}
wm->exp.nunchuk.orient_threshold = threshold;
}
@ -204,7 +195,9 @@ void wiiuse_set_nunchuk_orient_threshold(struct wiimote_t* wm, float threshold)
* See wiiuse_set_orient_threshold() for details.
*/
void wiiuse_set_nunchuk_accel_threshold(struct wiimote_t* wm, int threshold) {
if (!wm) return;
if (!wm) {
return;
}
wm->exp.nunchuk.accel_threshold = threshold;
}

View File

@ -40,14 +40,20 @@
extern "C" {
#endif
int nunchuk_handshake(struct wiimote_t* wm, struct nunchuk_t* nc, byte* data, unsigned short len);
void nunchuk_disconnected(struct nunchuk_t* nc);
/** @defgroup internal_nunchuk Internal: Nunchuk */
/** @{ */
int nunchuk_handshake(struct wiimote_t* wm, struct nunchuk_t* nc, byte* data, unsigned short len);
void nunchuk_event(struct nunchuk_t* nc, byte* msg);
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
}
#endif
#endif // NUNCHUK_H_INCLUDED
#endif /* NUNCHUK_H_INCLUDED */

View File

@ -26,31 +26,39 @@
*
*/
/**
* @file
* @brief Operating system related definitions.
*
* This file is an attempt to separate operating system
* dependent functions and choose what should be used
* at compile time.
* @brief Handles device I/O.
*/
#ifndef OS_H_INCLUDED
#define OS_H_INCLUDED
#ifndef PLATFORM_H_INCLUDED
#define PLATFORM_H_INCLUDED
#ifdef WIN32
/* windows */
#define isnan(x) _isnan(x)
#define isinf(x) !_finite(x)
#include "wiiuse_internal.h"
/* disable warnings I don't care about */
#pragma warning(disable:4244) /* possible loss of data conversion */
#pragma warning(disable:4273) /* inconsistent dll linkage */
#pragma warning(disable:4217)
#else
/* nix */
#ifdef __cplusplus
extern "C" {
#endif
#endif // OS_H_INCLUDED
/** @defgroup internal_io Internal: Platform-specific Device I/O */
/** @{ */
void wiiuse_init_platform_fields(struct wiimote_t* wm);
void wiiuse_cleanup_platform_fields(struct wiimote_t* wm);
int wiiuse_os_find(struct wiimote_t** wm, int max_wiimotes, int timeout);
int wiiuse_os_connect(struct wiimote_t** wm, int wiimotes);
void wiiuse_os_disconnect(struct wiimote_t* wm);
int wiiuse_os_poll(struct wiimote_t** wm, int wiimotes);
/* buf[0] will be the report type, buf+1 the rest of the report */
int wiiuse_os_read(struct wiimote_t* wm, byte* buf, int len);
int wiiuse_os_write(struct wiimote_t* wm, byte report_type, byte* buf, int len);
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* PLATFORM_H_INCLUDED */

View File

@ -0,0 +1,92 @@
/*
* 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 Handles device I/O for Mac OS X.
*/
#ifdef __APPLE__
#define BLUETOOTH_VERSION_USE_CURRENT
#import <IOBluetooth/objc/IOBluetoothDevice.h>
#import <IOBluetooth/objc/IOBluetoothL2CAPChannel.h>
#import "../wiiuse_internal.h"
#if defined(MAC_OS_X_VERSION_10_7) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7
#define WIIUSE_MAC_OS_X_VERSION_10_7_OR_ABOVE 1
#else
#define WIIUSE_MAC_OS_X_VERSION_10_7_OR_ABOVE 0
#endif
@interface WiiuseWiimote : NSObject<IOBluetoothL2CAPChannelDelegate> {
wiimote* wm; // reference to the C wiimote struct
IOBluetoothDevice* device;
IOBluetoothL2CAPChannel* controlChannel;
IOBluetoothL2CAPChannel* interruptChannel;
IOBluetoothUserNotification* disconnectNotification;
NSMutableArray* receivedData; // a queue of NSObject<WiiuseReceivedMessage>*
NSLock* receivedDataLock;
}
- (id) initWithPtr: (wiimote*) wm device: (IOBluetoothDevice*) device;
- (IOReturn) connect;
- (void) disconnect;
- (int) readBuffer: (byte*) buffer length: (NSUInteger) bufferLength;
- (int) writeReport: (byte) report_type buffer: (byte*) buffer length: (NSUInteger) length;
@end
@protocol WiiuseReceivedMessage <NSObject>
- (int) applyToStruct: (wiimote*) wm buffer: (byte*) buffer length: (NSUInteger) bufferLength; // <0: not copied, 0: copied empty, >0: copied
@end
@interface WiiuseReceivedData : NSObject<WiiuseReceivedMessage> {
NSData* data;
}
- (id) initWithBytes: (void*) bytes length: (NSUInteger) length;
- (id) initWithData: (NSData*) data;
@end
@interface WiiuseDisconnectionMessage : NSObject<WiiuseReceivedMessage> {
}
@end
#endif // __APPLE__

351
lib/wiiuse/os_mac/os_mac.m Normal file
View File

@ -0,0 +1,351 @@
/*
* 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 Handles device I/O for Mac OS X.
*/
#ifdef __APPLE__
#import "os_mac.h"
#import "../events.h"
#import <IOBluetooth/IOBluetoothUtilities.h>
#import <IOBluetooth/objc/IOBluetoothDevice.h>
#import <IOBluetooth/objc/IOBluetoothHostController.h>
#import <IOBluetooth/objc/IOBluetoothDeviceInquiry.h>
#import <IOBluetooth/objc/IOBluetoothL2CAPChannel.h>
@implementation WiiuseWiimote
#pragma mark init, dealloc
- (id) initWithPtr: (wiimote*) wm_ device:(IOBluetoothDevice *)device_ {
self = [super init];
if(self) {
wm = wm_;
device = [device_ retain];
controlChannel = nil;
interruptChannel = nil;
disconnectNotification = nil;
receivedData = [[NSMutableArray alloc] initWithCapacity: 2];
receivedDataLock = [[NSLock alloc] init];
}
return self;
}
- (void) dealloc {
wm = NULL;
[interruptChannel release];
[controlChannel release];
[device release];
[disconnectNotification unregister];
[disconnectNotification release];
[receivedData release];
[super dealloc];
}
#pragma mark connect, disconnect
- (BOOL) connectChannel: (IOBluetoothL2CAPChannel**) pChannel PSM: (BluetoothL2CAPPSM) psm {
if ([device openL2CAPChannelSync:pChannel withPSM:psm delegate:self] != kIOReturnSuccess) {
WIIUSE_ERROR("Unable to open L2CAP channel [id %i].", wm->unid);
*pChannel = nil;
return NO;
} else {
[*pChannel retain];
return YES;
}
}
- (IOReturn) connect {
if(!device) {
WIIUSE_ERROR("Missing device.");
return kIOReturnBadArgument;
}
// open channels
if(![self connectChannel:&controlChannel PSM:kBluetoothL2CAPPSMHIDControl]) {
[self disconnect];
return kIOReturnNotOpen;
} else if(![self connectChannel:&interruptChannel PSM:kBluetoothL2CAPPSMHIDInterrupt]) {
[self disconnect];
return kIOReturnNotOpen;
}
// register for device disconnection
disconnectNotification = [device registerForDisconnectNotification:self selector:@selector(disconnected:fromDevice:)];
if(!disconnectNotification) {
WIIUSE_ERROR("Unable to register disconnection handler [id %i].", wm->unid);
[self disconnect];
return kIOReturnNotOpen;
}
return kIOReturnSuccess;
}
- (void) disconnectChannel: (IOBluetoothL2CAPChannel**) pChannel {
if(!pChannel) return;
if([*pChannel closeChannel] != kIOReturnSuccess)
WIIUSE_ERROR("Unable to close channel [id %i].", wm ? wm->unid : -1);
[*pChannel release];
*pChannel = nil;
}
- (void) disconnect {
// channels
[self disconnectChannel:&interruptChannel];
[self disconnectChannel:&controlChannel];
// device
if([device closeConnection] != kIOReturnSuccess)
WIIUSE_ERROR("Unable to close the device connection [id %i].", wm ? wm->unid : -1);
[device release];
device = nil;
}
- (void) disconnected:(IOBluetoothUserNotification*) notification fromDevice:(IOBluetoothDevice*) device {
WiiuseDisconnectionMessage* message = [[WiiuseDisconnectionMessage alloc] init];
[receivedDataLock lock];
[receivedData addObject:message];
[receivedDataLock unlock];
[message release];
}
#pragma mark read, write
// <0: nothing received, else: length of data received (can be 0 in case of disconnection message)
- (int) checkForAvailableDataForBuffer: (byte*) buffer length: (NSUInteger) bufferLength {
int result = -1;
[receivedDataLock lock];
if([receivedData count]) {
// look at first item in queue
NSObject<WiiuseReceivedMessage>* firstMessage = [receivedData objectAtIndex:0];
result = [firstMessage applyToStruct:wm buffer: buffer length: bufferLength];
if(result >= 0)
[receivedData removeObjectAtIndex:0];
}
[receivedDataLock unlock];
return result;
}
- (void) waitForIncomingData: (NSTimeInterval) duration {
NSDate* timeoutDate = [NSDate dateWithTimeIntervalSinceNow: duration];
NSRunLoop *theRL = [NSRunLoop currentRunLoop];
while (true) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // This is used for fast release of NSDate, otherwise it leaks
if(![theRL runMode:NSDefaultRunLoopMode beforeDate:timeoutDate]) {
WIIUSE_ERROR("Could not start run loop while waiting for read [id %i].", wm->unid);
break;
}
[pool drain];
[receivedDataLock lock];
NSUInteger count = [receivedData count];
[receivedDataLock unlock];
if(count) {
// received some data, stop waiting
break;
}
if([timeoutDate isLessThanOrEqualTo:[NSDate date]]) {
// timeout
break;
}
}
}
// result = length of data copied to event buffer
- (int) readBuffer:(byte *)buffer length:(NSUInteger)bufferLength {
// is there already some data to read?
int result = [self checkForAvailableDataForBuffer: buffer length: bufferLength];
if(result < 0) {
// wait a short amount of time, until data becomes available or a timeout is reached
[self waitForIncomingData:1];
// check again
result = [self checkForAvailableDataForBuffer: buffer length: bufferLength];
}
return result >= 0 ? result : 0;
}
- (int) writeReport: (byte) report_type buffer: (byte*) buffer length: (NSUInteger) length {
if(interruptChannel == nil) {
WIIUSE_ERROR("Attempted to write to nil interrupt channel [id %i].", wm->unid);
return 0;
}
byte write_buffer[MAX_PAYLOAD];
write_buffer[0] = WM_SET_DATA | WM_BT_OUTPUT;
write_buffer[1] = report_type;
memcpy(write_buffer+2, buffer, length);
IOReturn error = [interruptChannel writeSync:write_buffer length:length+2];
if (error != kIOReturnSuccess) {
WIIUSE_ERROR("Error writing to interrupt channel [id %i].", wm->unid);
WIIUSE_DEBUG("Attempting to reopen the interrupt channel [id %i].", wm->unid);
[self disconnectChannel:&interruptChannel];
[self connectChannel:&interruptChannel PSM:kBluetoothL2CAPPSMHIDInterrupt];
if(!interruptChannel) {
WIIUSE_ERROR("Error reopening the interrupt channel [id %i].", wm->unid);
[self disconnect];
} else {
WIIUSE_DEBUG("Attempting to write again to the interrupt channel [id %i].", wm->unid);
error = [interruptChannel writeSync:write_buffer length:length+2];
if (error != kIOReturnSuccess)
WIIUSE_ERROR("Unable to write again to the interrupt channel [id %i].", wm->unid);
}
}
return (error == kIOReturnSuccess) ? length : 0;
}
#pragma mark IOBluetoothL2CAPChannelDelegate
- (void) l2capChannelData:(IOBluetoothL2CAPChannel*)channel data:(void*)data_ length:(NSUInteger)length {
byte* data = (byte*) data_;
// This is done in case the control channel woke up this handler
#if WIIUSE_MAC_OS_X_VERSION_10_7_OR_ABOVE
BluetoothL2CAPPSM psm = channel.PSM;
#else
BluetoothL2CAPPSM psm = [channel getPSM];
#endif
if(!data || (psm == kBluetoothL2CAPPSMHIDControl)) {
return;
}
// copy the data into the buffer
// on Mac, we ignore the first byte
WiiuseReceivedData* newData = [[WiiuseReceivedData alloc] initWithBytes: data+1 length: length-1];
[receivedDataLock lock];
[receivedData addObject: newData];
[receivedDataLock unlock];
[newData release];
}
#if !WIIUSE_MAC_OS_X_VERSION_10_7_OR_ABOVE
// the following delegate methods were required on 10.6. They are here to get rid of 10.6 compiler warnings.
- (void)l2capChannelOpenComplete:(IOBluetoothL2CAPChannel*)l2capChannel status:(IOReturn)error {
/* no-op */
}
- (void)l2capChannelClosed:(IOBluetoothL2CAPChannel*)l2capChannel {
/* no-op */
}
- (void)l2capChannelReconfigured:(IOBluetoothL2CAPChannel*)l2capChannel {
/* no-op */
}
- (void)l2capChannelWriteComplete:(IOBluetoothL2CAPChannel*)l2capChannel refcon:(void*)refcon status:(IOReturn)error {
/* no-op */
}
- (void)l2capChannelQueueSpaceAvailable:(IOBluetoothL2CAPChannel*)l2capChannel {
/* no-op */
}
#endif
@end
#pragma mark -
#pragma mark WiiuseReceivedMessage
@implementation WiiuseReceivedData
- (id) initWithData:(NSData *)data_ {
self = [super init];
if (self) {
data = [data_ retain];
}
return self;
}
- (id) initWithBytes: (void*) bytes length: (NSUInteger) length {
NSData* data_ = [[NSData alloc] initWithBytes:bytes length:length];
id result = [self initWithData: data_];
[data_ release];
return result;
}
- (void) dealloc {
[data release];
[super dealloc];
}
- (int) applyToStruct:(wiimote *)wm buffer:(byte *)buffer length:(NSUInteger)bufferLength {
byte* bytes = (byte*) [data bytes];
NSUInteger length = [data length];
if(length > bufferLength) {
WIIUSE_WARNING("Received data was longer than event buffer. Dropping excess bytes.");
length = bufferLength;
}
// log the received data
#ifdef WITH_WIIUSE_DEBUG
{
printf("[DEBUG] (id %i) RECV: (%.2x) ", wm->unid, bytes[0]);
int x;
for (x = 1; x < length; ++x)
printf("%.2x ", bytes[x]);
printf("\n");
}
#endif
// copy to struct
memcpy(buffer, bytes, length);
return length;
}
@end
@implementation WiiuseDisconnectionMessage
- (int) applyToStruct:(wiimote *)wm buffer:(byte *)buffer length:(NSUInteger)bufferLength {
wiiuse_disconnected(wm);
return 0;
}
@end
#endif // __APPLE__

View File

@ -0,0 +1,240 @@
/*
* 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 Handles device I/O for Mac OS X.
*/
#ifdef __APPLE__
#import "os_mac.h"
#import "../io.h"
#import "../events.h"
#import "../os.h"
#import <IOBluetooth/IOBluetoothUtilities.h>
#import <IOBluetooth/objc/IOBluetoothDevice.h>
#import <IOBluetooth/objc/IOBluetoothHostController.h>
#import <IOBluetooth/objc/IOBluetoothDeviceInquiry.h>
#if !WIIUSE_MAC_OS_X_VERSION_10_7_OR_ABOVE
#import <IOBluetooth/IOBluetoothUserLib.h> // IOBluetoothLocalDeviceGetPowerState
#endif
#pragma mark -
#pragma mark WiiuseDeviceInquiry
#if WIIUSE_MAC_OS_X_VERSION_10_7_OR_ABOVE
@interface WiiuseDeviceInquiry : NSObject<IOBluetoothDeviceInquiryDelegate> {
#else
@interface WiiuseDeviceInquiry : NSObject {
#endif
wiimote** wiimotes;
NSUInteger maxDevices;
int timeout;
BOOL _running;
NSUInteger _foundDevices;
BOOL _inquiryComplete;
}
- (id) initWithMemory:(wiimote**)wiimotes maxDevices:(int)maxDevices timeout:(int)timeout;
- (int) run;
@end
@implementation WiiuseDeviceInquiry
- (id) initWithMemory:(wiimote**)wiimotes_ maxDevices:(int)maxDevices_ timeout:(int)timeout_ {
self = [super init];
if(self) {
BluetoothHCIPowerState powerState = kBluetoothHCIPowerStateUnintialized;
#if WIIUSE_MAC_OS_X_VERSION_10_7_OR_ABOVE
if([IOBluetoothHostController defaultController])
powerState = [IOBluetoothHostController defaultController].powerState;
#else
// yes it is deprecated. no, there is no alternative (on 10.6).
IOBluetoothLocalDeviceGetPowerState(&powerState);
#endif
if (![IOBluetoothHostController defaultController] ||
powerState != kBluetoothHCIPowerStateON)
{
WIIUSE_DEBUG("Bluetooth hardware not available.");
[self release];
self = nil;
} else {
wiimotes = wiimotes_;
maxDevices = maxDevices_;
timeout = timeout_;
_running = NO;
}
}
return self;
}
// creates and starts inquiry. the returned object is in the current autorelease pool.
- (IOBluetoothDeviceInquiry*) start {
// reset state variables
_foundDevices = 0;
_inquiryComplete = NO;
// create inquiry
IOBluetoothDeviceInquiry* inquiry = [IOBluetoothDeviceInquiry inquiryWithDelegate: self];
// refine search & set timeout
[inquiry setSearchCriteria:kBluetoothServiceClassMajorAny
majorDeviceClass:WM_DEV_MAJOR_CLASS
minorDeviceClass:WM_DEV_MINOR_CLASS];
[inquiry setUpdateNewDeviceNames: NO];
if(timeout > 0)
[inquiry setInquiryLength:timeout];
// start inquiry
IOReturn status = [inquiry start];
if (status != kIOReturnSuccess) {
WIIUSE_ERROR("Unable to start bluetooth device inquiry.");
if(![inquiry stop]) {
WIIUSE_ERROR("Unable to stop bluetooth device inquiry.");
} else {
WIIUSE_DEBUG("Bluetooth device inquiry stopped.");
}
return nil;
}
return inquiry;
}
- (void) wait {
// wait for the inquiry to complete
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
while(!_inquiryComplete &&
[runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]) {
// no-op
}
}
- (NSUInteger) collectResultsOf: (IOBluetoothDeviceInquiry*) inquiry {
// stop the inquiry
if(![inquiry stop])
WIIUSE_ERROR("Unable to stop bluetooth device inquiry.");
// read found device information
NSArray* devices = [inquiry foundDevices];
NSUInteger i;
for(i = 0; i < [devices count]; i++) {
IOBluetoothDevice* device = [devices objectAtIndex:i];
// save the device in the wiimote structure
wiimotes[i]->objc_wm = (void*) [[WiiuseWiimote alloc] initWithPtr:wiimotes[i] device: device];
// mark as found
WIIMOTE_ENABLE_STATE(wiimotes[i], WIIMOTE_STATE_DEV_FOUND);
NSString* address = IOBluetoothNSStringFromDeviceAddress([device getAddress]);
const char* address_str = [address cStringUsingEncoding:NSMacOSRomanStringEncoding];
WIIUSE_INFO("Found Wiimote (%s) [id %i]", address_str, wiimotes[i]->unid);
}
return [devices count];
}
- (int) run {
int result = -1;
if(maxDevices == 0) {
result = 0;
} else if(!_running) {
_running = YES;
if (![IOBluetoothHostController defaultController]) {
WIIUSE_ERROR("Unable to find any bluetooth receiver on your host.");
} else {
IOBluetoothDeviceInquiry* inquiry = [self start];
if(inquiry) {
[self wait];
result = [self collectResultsOf: inquiry];
WIIUSE_INFO("Found %i Wiimote device(s).", result);
}
}
_running = NO;
} else { // if(_running)
WIIUSE_ERROR("Device inquiry already running - won't start it again.");
}
return result;
}
#pragma mark IOBluetoothDeviceInquiryDelegate
- (void) deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry *) inquiry device:(IOBluetoothDevice *) device {
WIIUSE_DEBUG("Found a wiimote");
_foundDevices++;
if(_foundDevices >= maxDevices) {
// reached maximum number of devices
_inquiryComplete = YES;
}
}
- (void) deviceInquiryComplete:(IOBluetoothDeviceInquiry*) inquiry error:(IOReturn) error aborted:(BOOL) aborted
{
WIIUSE_DEBUG("Inquiry complete, error=%i, aborted=%s", error, aborted ? "YES" : "NO");
// mark completion
_inquiryComplete = YES;
// print error message if we stop due to an error
if ((error != kIOReturnSuccess) && !aborted) {
WIIUSE_ERROR("Bluetooth device inquiry not completed due to unexpected errors. Try increasing the timeout.");
}
}
@end
#pragma mark -
#pragma mark public interface
int wiiuse_os_find(struct wiimote_t** wm, int max_wiimotes, int timeout) {
int result;
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
WiiuseDeviceInquiry* inquiry = [[WiiuseDeviceInquiry alloc] initWithMemory:wm maxDevices:max_wiimotes timeout:timeout];
result = [inquiry run];
[inquiry release];
[pool drain];
return result;
}
#endif // __APPLE__

View File

@ -0,0 +1,222 @@
/*
* 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 C function interface to os_mac.
*/
#ifdef __APPLE__
#import "os_mac.h"
#import "../io.h"
#import "../events.h"
#import "../os.h"
#import <IOBluetooth/IOBluetoothUtilities.h>
#import <IOBluetooth/objc/IOBluetoothDevice.h>
#import <IOBluetooth/objc/IOBluetoothHostController.h>
#import <IOBluetooth/objc/IOBluetoothDeviceInquiry.h>
#import <IOBluetooth/objc/IOBluetoothL2CAPChannel.h>
#pragma mark -
#pragma mark find
// See os_mac_find.m
#pragma mark -
#pragma mark connect, disconnect
/**
* @brief Connect to a wiimote with a known address.
*
* @param wm Pointer to a wiimote_t structure.
*
* @see wiimote_os_connect()
* @see wiimote_os_find()
*
* @return 1 on success, 0 on failure
*/
static short wiiuse_os_connect_single(struct wiimote_t* wm) {
// Skip if already connected or device not found
if(!wm) {
WIIUSE_ERROR("No Wiimote given.");
return 0;
} else if(wm && (!WIIMOTE_IS_SET(wm, WIIMOTE_STATE_DEV_FOUND) || wm->objc_wm == NULL)) {
WIIUSE_ERROR("Tried to connect Wiimote without an address.");
return 0;
} else if(WIIMOTE_IS_CONNECTED(wm)) {
WIIUSE_WARNING("Wiimote [id %i] is already connected.", wm->unid);
return 1;
}
WIIUSE_DEBUG("Connecting to Wiimote [id %i].", wm->unid);
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
short result = 0;
// connect
WiiuseWiimote* objc_wm = (WiiuseWiimote*) wm->objc_wm;
if([objc_wm connect] == kIOReturnSuccess) {
WIIUSE_INFO("Connected to Wiimote [id %i].", wm->unid);
// save the connect structure to retrieve data later on
wm->objc_wm = (void*)objc_wm;
// save the connection status
WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_CONNECTED);
// Do the handshake
wiiuse_handshake(wm, NULL, 0);
wiiuse_set_report_type(wm);
result = 1;
}
[pool drain];
return result;
}
int wiiuse_os_connect(struct wiimote_t** wm, int wiimotes) {
int connected = 0;
int i;
for (i = 0; i < wiimotes; ++i) {
if(wm[i] == NULL) {
WIIUSE_ERROR("Trying to connect to non-initialized Wiimote.");
break;
}
if (!WIIMOTE_IS_SET(wm[i], WIIMOTE_STATE_DEV_FOUND) || !wm[i]->objc_wm) {
// If the device is not found, skip it
continue;
}
if (wiiuse_os_connect_single(wm[i]))
++connected;
}
return connected;
}
void wiiuse_os_disconnect(struct wiimote_t* wm) {
if (!wm || !WIIMOTE_IS_CONNECTED(wm) || !wm->objc_wm)
return;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[((WiiuseWiimote*)wm->objc_wm) disconnect];
[pool drain];
}
#pragma mark -
#pragma mark poll, read, write
int wiiuse_os_poll(struct wiimote_t** wm, int wiimotes) {
int i;
byte read_buffer[MAX_PAYLOAD];
int evnt = 0;
if (!wm) return 0;
for (i = 0; i < wiimotes; ++i) {
wm[i]->event = WIIUSE_NONE;
/* clear out the buffer */
memset(read_buffer, 0, sizeof(read_buffer));
/* read */
if (wiiuse_os_read(wm[i], read_buffer, sizeof(read_buffer))) {
/* propagate the event */
propagate_event(wm[i], read_buffer[0], read_buffer+1);
} else {
/* send out any waiting writes */
wiiuse_send_next_pending_write_request(wm[i]);
idle_cycle(wm[i]);
}
evnt += (wm[i]->event != WIIUSE_NONE);
}
return evnt;
}
int wiiuse_os_read(struct wiimote_t* wm, byte* buf, int len) {
if(!wm || !wm->objc_wm) return 0;
if(!WIIMOTE_IS_CONNECTED(wm)) {
WIIUSE_ERROR("Attempting to read from unconnected Wiimote");
return 0;
}
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
WiiuseWiimote* objc_wm = (WiiuseWiimote*) wm->objc_wm;
int result = [objc_wm readBuffer: buf length: len];
[pool drain];
return result;
}
int wiiuse_os_write(struct wiimote_t* wm, byte report_type, byte* buf, int len) {
if(!wm || !wm->objc_wm) return 0;
if(!WIIMOTE_IS_CONNECTED(wm)) {
WIIUSE_ERROR("Attempting to write to unconnected Wiimote");
return 0;
}
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
WiiuseWiimote* objc_wm = (WiiuseWiimote*) wm->objc_wm;
int result = [objc_wm writeReport: report_type buffer: buf length: (NSUInteger)len];
[pool drain];
return result;
}
#pragma mark -
#pragma mark platform fields
void wiiuse_init_platform_fields(struct wiimote_t* wm) {
wm->objc_wm = NULL;
}
void wiiuse_cleanup_platform_fields(struct wiimote_t* wm) {
if(!wm) return;
WiiuseWiimote* objc_wm = (WiiuseWiimote*) wm->objc_wm;
// disconnect
// Note: this should already have happened, because this function
// is called once the device is disconnected. This is just paranoia.
[objc_wm disconnect];
// release WiiuseWiimote object
[objc_wm release];
wm->objc_wm = NULL;
}
#endif // __APPLE__

387
lib/wiiuse/os_nix.c Normal file
View File

@ -0,0 +1,387 @@
/*
* 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 Handles device I/O for *nix.
*/
#include "io.h"
#include "events.h"
#include "os.h"
#ifdef WIIUSE_BLUEZ
#include <bluetooth/bluetooth.h> /* for ba2str, str2ba */
#include <bluetooth/hci.h> /* for inquiry_info */
#include <bluetooth/hci_lib.h> /* for hci_get_route, hci_inquiry, etc */
#include <bluetooth/l2cap.h> /* for sockaddr_l2 */
#include <stdio.h> /* for perror */
#include <string.h> /* for memset */
#include <sys/socket.h> /* for connect, socket */
#include <sys/time.h> /* for struct timeval */
#include <unistd.h> /* for close, write */
#include <errno.h>
static int wiiuse_os_connect_single(struct wiimote_t* wm, char* address);
int wiiuse_os_find(struct wiimote_t** wm, int max_wiimotes, int timeout) {
int device_id;
int device_sock;
inquiry_info scan_info_arr[128];
inquiry_info* scan_info = scan_info_arr;
int found_devices;
int found_wiimotes;
int i = 0;
/* reset all wiimote bluetooth device addresses */
for (found_wiimotes = 0; found_wiimotes < max_wiimotes; ++found_wiimotes) {
/* bacpy(&(wm[found_wiimotes]->bdaddr), BDADDR_ANY); */
memset(&(wm[found_wiimotes]->bdaddr), 0, sizeof(bdaddr_t));
}
found_wiimotes = 0;
/* get the id of the first bluetooth device. */
device_id = hci_get_route(NULL);
if (device_id < 0) {
if (errno == ENODEV) {
WIIUSE_ERROR("Could not detect a Bluetooth adapter!");
} else {
perror("hci_get_route");
}
return 0;
}
/* create a socket to the device */
device_sock = hci_open_dev(device_id);
if (device_sock < 0) {
perror("hci_open_dev");
return 0;
}
memset(&scan_info_arr, 0, sizeof(scan_info_arr));
/* scan for bluetooth devices for 'timeout' seconds */
found_devices = hci_inquiry(device_id, timeout, 128, NULL, &scan_info, IREQ_CACHE_FLUSH);
if (found_devices < 0) {
perror("hci_inquiry");
return 0;
}
WIIUSE_INFO("Found %i bluetooth device(s).", found_devices);
/* display discovered devices */
for (i = 0; (i < found_devices) && (found_wiimotes < max_wiimotes); ++i) {
if ((scan_info[i].dev_class[0] == WM_DEV_CLASS_0) &&
(scan_info[i].dev_class[1] == WM_DEV_CLASS_1) &&
(scan_info[i].dev_class[2] == WM_DEV_CLASS_2)) {
/* found a device */
ba2str(&scan_info[i].bdaddr, wm[found_wiimotes]->bdaddr_str);
WIIUSE_INFO("Found wiimote (%s) [id %i].", wm[found_wiimotes]->bdaddr_str, wm[found_wiimotes]->unid);
wm[found_wiimotes]->bdaddr = scan_info[i].bdaddr;
WIIMOTE_ENABLE_STATE(wm[found_wiimotes], WIIMOTE_STATE_DEV_FOUND);
++found_wiimotes;
}
}
close(device_sock);
return found_wiimotes;
}
/**
* @see wiiuse_connect()
* @see wiiuse_os_connect_single()
*/
int wiiuse_os_connect(struct wiimote_t** wm, int wiimotes) {
int connected = 0;
int i = 0;
for (; i < wiimotes; ++i) {
if (!WIIMOTE_IS_SET(wm[i], WIIMOTE_STATE_DEV_FOUND))
/* if the device address is not set, skip it */
{
continue;
}
if (wiiuse_os_connect_single(wm[i], NULL)) {
++connected;
}
}
return connected;
}
/**
* @brief Connect to a wiimote with a known address.
*
* @param wm Pointer to a wiimote_t structure.
* @param address The address of the device to connect to.
* If NULL, use the address in the struct set by wiiuse_os_find().
*
* @return 1 on success, 0 on failure
*/
static int wiiuse_os_connect_single(struct wiimote_t* wm, char* address) {
struct sockaddr_l2 addr;
memset(&addr, 0, sizeof(addr));
if (!wm || WIIMOTE_IS_CONNECTED(wm)) {
return 0;
}
addr.l2_family = AF_BLUETOOTH;
bdaddr_t *bdaddr = &wm->bdaddr;
if (address)
/* use provided address */
{
str2ba(address, &addr.l2_bdaddr);
} else {
/** @todo this line doesn't make sense
bacmp(bdaddr, BDADDR_ANY);*/
/* use address of device discovered */
addr.l2_bdaddr = *bdaddr;
}
/*
* OUTPUT CHANNEL
*/
wm->out_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
if (wm->out_sock == -1) {
return 0;
}
addr.l2_psm = htobs(WM_OUTPUT_CHANNEL);
/* connect to wiimote */
if (connect(wm->out_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
perror("connect() output sock");
return 0;
}
/*
* INPUT CHANNEL
*/
wm->in_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
if (wm->in_sock == -1) {
close(wm->out_sock);
wm->out_sock = -1;
return 0;
}
addr.l2_psm = htobs(WM_INPUT_CHANNEL);
/* connect to wiimote */
if (connect(wm->in_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
perror("connect() interrupt sock");
close(wm->out_sock);
wm->out_sock = -1;
return 0;
}
WIIUSE_INFO("Connected to wiimote [id %i].", wm->unid);
/* do the handshake */
WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_CONNECTED);
wiiuse_handshake(wm, NULL, 0);
wiiuse_set_report_type(wm);
return 1;
}
void wiiuse_os_disconnect(struct wiimote_t* wm) {
if (!wm || WIIMOTE_IS_CONNECTED(wm)) {
return;
}
close(wm->out_sock);
close(wm->in_sock);
wm->out_sock = -1;
wm->in_sock = -1;
wm->event = WIIUSE_NONE;
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_CONNECTED);
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE);
}
int wiiuse_os_poll(struct wiimote_t** wm, int wiimotes) {
int evnt;
struct timeval tv;
fd_set fds;
int r;
int i;
byte read_buffer[MAX_PAYLOAD];
int highest_fd = -1;
evnt = 0;
if (!wm) {
return 0;
}
/* block select() for 1/2000th of a second */
tv.tv_sec = 0;
tv.tv_usec = 500;
FD_ZERO(&fds);
for (i = 0; i < wiimotes; ++i) {
/* only poll it if it is connected */
if (WIIMOTE_IS_SET(wm[i], WIIMOTE_STATE_CONNECTED)) {
FD_SET(wm[i]->in_sock, &fds);
/* find the highest fd of the connected wiimotes */
if (wm[i]->in_sock > highest_fd) {
highest_fd = wm[i]->in_sock;
}
}
wm[i]->event = WIIUSE_NONE;
}
if (highest_fd == -1)
/* nothing to poll */
{
return 0;
}
if (select(highest_fd + 1, &fds, NULL, NULL, &tv) == -1) {
WIIUSE_ERROR("Unable to select() the wiimote interrupt socket(s).");
perror("Error Details");
return 0;
}
/* check each socket for an event */
for (i = 0; i < wiimotes; ++i) {
/* if this wiimote is not connected, skip it */
if (!WIIMOTE_IS_CONNECTED(wm[i])) {
continue;
}
if (FD_ISSET(wm[i]->in_sock, &fds)) {
/* clear out the event buffer */
memset(read_buffer, 0, sizeof(read_buffer));
/* clear out any old read data */
clear_dirty_reads(wm[i]);
/* read the pending message into the buffer */
r = wiiuse_os_read(wm[i], read_buffer, sizeof(read_buffer));
if (r > 0) {
/* propagate the event */
propagate_event(wm[i], read_buffer[0], read_buffer + 1);
evnt += (wm[i]->event != WIIUSE_NONE);
}
} else {
/* send out any waiting writes */
wiiuse_send_next_pending_write_request(wm[i]);
idle_cycle(wm[i]);
}
}
return evnt;
}
int wiiuse_os_read(struct wiimote_t* wm, byte* buf, int len) {
int rc;
int i;
rc = read(wm->in_sock, buf, len);
if (rc == -1) {
/* error reading data */
WIIUSE_ERROR("Receiving wiimote data (id %i).", wm->unid);
perror("Error Details");
if (errno == ENOTCONN) {
/* this can happen if the bluetooth dongle is disconnected */
WIIUSE_ERROR("Bluetooth appears to be disconnected. Wiimote unid %i will be disconnected.", wm->unid);
wiiuse_os_disconnect(wm);
wiiuse_disconnected(wm);
}
} else if (rc == 0) {
/* remote disconnect */
wiiuse_disconnected(wm);
} else {
/* read successful */
/* on *nix we ignore the first byte */
memmove(buf, buf + 1, len - 1);
/* log the received data */
#ifdef WITH_WIIUSE_DEBUG
{
int i;
printf("[DEBUG] (id %i) RECV: (%.2x) ", wm->unid, buf[0]);
for (i = 1; i < rc; i++) {
printf("%.2x ", buf[i]);
}
printf("\n");
}
#endif
}
return rc;
}
int wiiuse_os_write(struct wiimote_t* wm, byte report_type, byte* buf, int len) {
int rc;
byte write_buffer[MAX_PAYLOAD];
write_buffer[0] = WM_SET_REPORT | WM_BT_OUTPUT;
write_buffer[1] = report_type;
memcpy(write_buffer + 2, buf, len);
rc = write(wm->out_sock, write_buffer, len + 2);
if (rc < 0) {
wiiuse_disconnected(wm);
}
return rc;
}
void wiiuse_init_platform_fields(struct wiimote_t* wm) {
memset(&(wm->bdaddr), 0, sizeof(bdaddr_t)); /* = *BDADDR_ANY;*/
wm->out_sock = -1;
wm->in_sock = -1;
}
void wiiuse_cleanup_platform_fields(struct wiimote_t* wm) {
wm->out_sock = -1;
wm->in_sock = -1;
}
#endif /* ifdef WIIUSE_BLUEZ */

326
lib/wiiuse/os_win.c Normal file
View File

@ -0,0 +1,326 @@
/*
* 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 Handles device I/O for Windows.
*/
#include "io.h"
#include "events.h"
#include "os.h"
#ifdef WIIUSE_WIN32
#include <stdlib.h>
#include <hidsdi.h>
#include <setupapi.h>
#ifdef __MINGW32__
/* this prototype is missing from the mingw headers so we must add it
or suffer linker errors. */
# ifdef __cplusplus
extern "C" {
# endif
WINHIDSDI BOOL WINAPI HidD_SetOutputReport(HANDLE, PVOID, ULONG);
# ifdef __cplusplus
}
# endif
#endif
int wiiuse_os_find(struct wiimote_t** wm, int max_wiimotes, int timeout) {
GUID device_id;
HANDLE dev;
HDEVINFO device_info;
int i, index;
DWORD len;
SP_DEVICE_INTERFACE_DATA device_data;
PSP_DEVICE_INTERFACE_DETAIL_DATA detail_data = NULL;
HIDD_ATTRIBUTES attr;
int found = 0;
(void) timeout; /* unused */
device_data.cbSize = sizeof(device_data);
index = 0;
/* get the device id */
HidD_GetHidGuid(&device_id);
/* get all hid devices connected */
device_info = SetupDiGetClassDevs(&device_id, NULL, NULL, (DIGCF_DEVICEINTERFACE | DIGCF_PRESENT));
for (;; ++index) {
if (detail_data) {
free(detail_data);
detail_data = NULL;
}
/* query the next hid device info */
if (!SetupDiEnumDeviceInterfaces(device_info, NULL, &device_id, index, &device_data)) {
break;
}
/* get the size of the data block required */
i = SetupDiGetDeviceInterfaceDetail(device_info, &device_data, NULL, 0, &len, NULL);
detail_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_A*)malloc(len);
detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
/* query the data for this device */
if (!SetupDiGetDeviceInterfaceDetail(device_info, &device_data, detail_data, len, NULL, NULL)) {
continue;
}
/* open the device */
dev = CreateFile(detail_data->DevicePath,
(GENERIC_READ | GENERIC_WRITE),
(FILE_SHARE_READ | FILE_SHARE_WRITE),
NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (dev == INVALID_HANDLE_VALUE) {
continue;
}
/* get device attributes */
attr.Size = sizeof(attr);
i = HidD_GetAttributes(dev, &attr);
if ((attr.VendorID == WM_VENDOR_ID) && (attr.ProductID == WM_PRODUCT_ID)) {
/* this is a wiimote */
wm[found]->dev_handle = dev;
wm[found]->hid_overlap.hEvent = CreateEvent(NULL, 1, 1, "");
wm[found]->hid_overlap.Offset = 0;
wm[found]->hid_overlap.OffsetHigh = 0;
WIIMOTE_ENABLE_STATE(wm[found], WIIMOTE_STATE_DEV_FOUND);
WIIMOTE_ENABLE_STATE(wm[found], WIIMOTE_STATE_CONNECTED);
/* try to set the output report to see if the device is actually connected */
if (!wiiuse_set_report_type(wm[found])) {
WIIMOTE_DISABLE_STATE(wm[found], WIIMOTE_STATE_CONNECTED);
continue;
}
/* do the handshake */
wiiuse_handshake(wm[found], NULL, 0);
WIIUSE_INFO("Connected to wiimote [id %i].", wm[found]->unid);
++found;
if (found >= max_wiimotes) {
break;
}
} else {
/* not a wiimote */
CloseHandle(dev);
}
}
if (detail_data) {
free(detail_data);
}
SetupDiDestroyDeviceInfoList(device_info);
return found;
}
int wiiuse_os_connect(struct wiimote_t** wm, int wiimotes) {
int connected = 0;
int i = 0;
for (; i < wiimotes; ++i) {
if (!wm[i]) {
continue;
}
if (WIIMOTE_IS_SET(wm[i], WIIMOTE_STATE_CONNECTED)) {
++connected;
}
}
return connected;
}
void wiiuse_os_disconnect(struct wiimote_t* wm) {
if (!wm || WIIMOTE_IS_CONNECTED(wm)) {
return;
}
CloseHandle(wm->dev_handle);
wm->dev_handle = 0;
ResetEvent(&wm->hid_overlap);
wm->event = WIIUSE_NONE;
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_CONNECTED);
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE);
}
int wiiuse_os_poll(struct wiimote_t** wm, int wiimotes) {
int i;
byte read_buffer[MAX_PAYLOAD];
int evnt = 0;
if (!wm) {
return 0;
}
for (i = 0; i < wiimotes; ++i) {
wm[i]->event = WIIUSE_NONE;
/* clear out the buffer */
memset(read_buffer, 0, sizeof(read_buffer));
/* read */
if (wiiuse_os_read(wm[i], read_buffer, sizeof(read_buffer))) {
/* propagate the event */
propagate_event(wm[i], read_buffer[0], read_buffer + 1);
evnt += (wm[i]->event != WIIUSE_NONE);
} else {
/* send out any waiting writes */
wiiuse_send_next_pending_write_request(wm[i]);
idle_cycle(wm[i]);
}
}
return evnt;
}
int wiiuse_os_read(struct wiimote_t* wm, byte* buf, int len) {
DWORD b, r;
if (!wm || !WIIMOTE_IS_CONNECTED(wm)) {
return 0;
}
if (!ReadFile(wm->dev_handle, buf, len, &b, &wm->hid_overlap)) {
/* partial read */
b = GetLastError();
if ((b == ERROR_HANDLE_EOF) || (b == ERROR_DEVICE_NOT_CONNECTED)) {
/* remote disconnect */
wiiuse_disconnected(wm);
return 0;
}
r = WaitForSingleObject(wm->hid_overlap.hEvent, wm->timeout);
if (r == WAIT_TIMEOUT) {
/* timeout - cancel and continue */
if (*buf) {
WIIUSE_WARNING("Packet ignored. This may indicate a problem (timeout is %i ms).", wm->timeout);
}
CancelIo(wm->dev_handle);
ResetEvent(wm->hid_overlap.hEvent);
return 0;
} else if (r == WAIT_FAILED) {
WIIUSE_WARNING("A wait error occurred on reading from wiimote %i.", wm->unid);
return 0;
}
if (!GetOverlappedResult(wm->dev_handle, &wm->hid_overlap, &b, 0)) {
return 0;
}
/* log the received data */
#ifdef WITH_WIIUSE_DEBUG
{
DWORD i;
printf("[DEBUG] (id %i) RECV: (%.2x) ", wm->unid, buf[0]);
for (i = 1; i < b; i++) {
printf("%.2x ", buf[i]);
}
printf("\n");
}
#endif
}
ResetEvent(wm->hid_overlap.hEvent);
return 1;
}
int wiiuse_os_write(struct wiimote_t* wm, byte report_type, byte* buf, int len) {
DWORD bytes;
int i;
byte write_buffer[MAX_PAYLOAD];
if (!wm || !WIIMOTE_IS_CONNECTED(wm)) {
return 0;
}
write_buffer[0] = report_type;
memcpy(write_buffer + 1, buf, len);
switch (wm->stack) {
case WIIUSE_STACK_UNKNOWN: {
/* try to auto-detect the stack type */
if (i = WriteFile(wm->dev_handle, write_buffer, 22, &bytes, &wm->hid_overlap)) {
/* bluesoleil will always return 1 here, even if it's not connected */
wm->stack = WIIUSE_STACK_BLUESOLEIL;
return i;
}
if (i = HidD_SetOutputReport(wm->dev_handle, write_buffer, len + 1)) {
wm->stack = WIIUSE_STACK_MS;
return i;
}
WIIUSE_ERROR("Unable to determine bluetooth stack type.");
return 0;
}
case WIIUSE_STACK_MS:
return HidD_SetOutputReport(wm->dev_handle, write_buffer, len + 1);
case WIIUSE_STACK_BLUESOLEIL:
return WriteFile(wm->dev_handle, write_buffer, 22, &bytes, &wm->hid_overlap);
}
return 0;
}
void wiiuse_init_platform_fields(struct wiimote_t* wm) {
wm->dev_handle = 0;
wm->stack = WIIUSE_STACK_UNKNOWN;
wm->normal_timeout = WIIMOTE_DEFAULT_TIMEOUT;
wm->exp_timeout = WIIMOTE_EXP_TIMEOUT;
wm->timeout = wm->normal_timeout;
}
void wiiuse_cleanup_platform_fields(struct wiimote_t* wm) {
wm->dev_handle = 0;
}
#endif /* ifdef WIIUSE_WIN32 */

49
lib/wiiuse/util.c Normal file
View File

@ -0,0 +1,49 @@
/*
* wiiuse
*
* Copyright 2011 Iowa State University Virtual Reality Applications Center
*
* 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 Provides platform-specific utility functions.
*/
#include "wiiuse_internal.h"
#ifdef WIIUSE_WIN32
#include <windows.h>
void wiiuse_millisleep(int durationMilliseconds) {
Sleep(durationMilliseconds);
}
#else /* not win32 - assuming posix */
#include <unistd.h> /* for usleep */
void wiiuse_millisleep(int durationMilliseconds) {
usleep(durationMilliseconds * 1000);
}
#endif /* ifdef WIIUSE_WIN32 */

146
lib/wiiuse/wiiboard.c Normal file
View File

@ -0,0 +1,146 @@
/*
* 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 Wii Fit Balance Board device.
*/
#include "wiiboard.h"
#include <stdio.h> /* for printf */
#include <string.h> /* for memset */
/**
* @brief Handle the handshake data from the wiiboard.
*
* @param wb A pointer to a wii_board_t structure.
* @param data The data read in from the device.
* @param len The length of the data block, in bytes.
*
* @return Returns 1 if handshake was successful, 0 if not.
*/
int wii_board_handshake(struct wiimote_t* wm, struct wii_board_t* wb, byte* data, uint16_t len) {
byte * bufptr;
/* decrypt data */
#ifdef WITH_WIIUSE_DEBUG
int i;
printf("DECRYPTED DATA WIIBOARD\n");
for (i = 0; i < len; ++i) {
if (i % 16 == 0) {
if (i != 0) {
printf("\n");
}
printf("%X: ", 0x4a40000 + 32 + i);
}
printf("%02X ", data[i]);
}
printf("\n");
#endif
bufptr = data + 4;
wb->ctr[0] = unbuffer_big_endian_uint16_t(&bufptr);
wb->cbr[0] = unbuffer_big_endian_uint16_t(&bufptr);
wb->ctl[0] = unbuffer_big_endian_uint16_t(&bufptr);
wb->cbl[0] = unbuffer_big_endian_uint16_t(&bufptr);
wb->ctr[1] = unbuffer_big_endian_uint16_t(&bufptr);
wb->cbr[1] = unbuffer_big_endian_uint16_t(&bufptr);
wb->ctl[1] = unbuffer_big_endian_uint16_t(&bufptr);
wb->cbl[1] = unbuffer_big_endian_uint16_t(&bufptr);
wb->ctr[2] = unbuffer_big_endian_uint16_t(&bufptr);
wb->cbr[2] = unbuffer_big_endian_uint16_t(&bufptr);
wb->ctl[2] = unbuffer_big_endian_uint16_t(&bufptr);
wb->cbl[2] = unbuffer_big_endian_uint16_t(&bufptr);
/* handshake done */
wm->event = WIIUSE_WII_BOARD_CTRL_INSERTED;
wm->exp.type = EXP_WII_BOARD;
#ifdef WIIUSE_WIN32
wm->timeout = WIIMOTE_DEFAULT_TIMEOUT;
#endif
return 1;
}
/**
* @brief The wii board disconnected.
*
* @param cc A pointer to a wii_board_t structure.
*/
void wii_board_disconnected(struct wii_board_t* wb) {
memset(wb, 0, sizeof(struct wii_board_t));
}
static float do_interpolate(uint16_t raw, uint16_t cal[3]) {
#define WIIBOARD_MIDDLE_CALIB 17.0f
if (raw < cal[0]) {
return 0.0f;
} else if (raw < cal[1]) {
return ((float)(raw - cal[0]) * WIIBOARD_MIDDLE_CALIB) / (float)(cal[1] - cal[0]);
} else if (raw < cal[2]) {
return ((float)(raw - cal[1]) * WIIBOARD_MIDDLE_CALIB) / (float)(cal[2] - cal[1]) + WIIBOARD_MIDDLE_CALIB;
} else {
return WIIBOARD_MIDDLE_CALIB * 2.0f;
}
}
/**
* @brief Handle wii board event.
*
* @param wb A pointer to a wii_board_t structure.
* @param msg The message specified in the event packet.
*/
void wii_board_event(struct wii_board_t* wb, byte* msg) {
byte * bufPtr = msg;
wb->rtr = unbuffer_big_endian_uint16_t(&bufPtr);
wb->rbr = unbuffer_big_endian_uint16_t(&bufPtr);
wb->rtl = unbuffer_big_endian_uint16_t(&bufPtr);
wb->rbl = unbuffer_big_endian_uint16_t(&bufPtr);
/*
Interpolate values
Calculations borrowed from wiili.org - No names to mention sadly :( http://www.wiili.org/index.php/Wii_Balance_Board_PC_Drivers page however!
*/
wb->tr = do_interpolate(wb->rtr, wb->ctr);
wb->tl = do_interpolate(wb->rtl, wb->ctl);
wb->br = do_interpolate(wb->rbr, wb->cbr);
wb->bl = do_interpolate(wb->rbl, wb->cbl);
}
/**
@todo not implemented!
*/
void wiiuse_set_wii_board_calib(struct wiimote_t *wm) {
}

55
lib/wiiuse/wiiboard.h Normal file
View File

@ -0,0 +1,55 @@
/*
* 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 Wii balance board expansion device.
*/
#ifndef WII_BOARD_H_INCLUDED
#define WII_BOARD_H_INCLUDED
#include "wiiuse_internal.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup internal_wiiboard Internal: Wii Balance Board */
/** @{ */
int wii_board_handshake(struct wiimote_t* wm, struct wii_board_t* wb, byte* data, uint16_t len);
void wii_board_disconnected(struct wii_board_t* wb);
void wii_board_event(struct wii_board_t* wb, byte* msg);
/** @} */
#ifdef __cplusplus
}
#endif
#endif

View File

@ -35,29 +35,41 @@
* of the API.
*/
#include <stdio.h>
#include <stdlib.h>
#ifndef WIN32
#include <unistd.h>
#else
#include <Winsock2.h>
#endif
#include "definitions.h"
#include "wiiuse_internal.h"
#include "events.h"
#include "io.h"
#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 */
static int g_banner = 0;
static const char g_wiiuse_version_string[] = WIIUSE_VERSION;
/**
* @breif Returns the version of the library.
* @brief Returns the version of the library.
*/
const char* wiiuse_version() {
return WIIUSE_VERSION;
return g_wiiuse_version_string;
}
/**
* @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;
}
/**
* @brief Clean up wiimote_t array created by wiiuse_init()
@ -65,13 +77,15 @@ const char* wiiuse_version() {
void wiiuse_cleanup(struct wiimote_t** wm, int wiimotes) {
int i = 0;
if (!wm)
if (!wm) {
return;
}
WIIUSE_INFO("wiiuse clean up...");
for (; i < wiimotes; ++i) {
wiiuse_disconnect(wm[i]);
wiiuse_cleanup_platform_fields(wm[i]);
free(wm[i]);
}
@ -106,14 +120,20 @@ struct wiimote_t** wiiuse_init(int wiimotes) {
* 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");
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");
g_banner = 1;
}
if (!wiimotes)
logtarget[0] = stderr;
logtarget[1] = stderr;
logtarget[2] = stderr;
logtarget[3] = stderr;
if (!wiimotes) {
return NULL;
}
wm = malloc(sizeof(struct wiimote_t*) * wiimotes);
@ -121,19 +141,8 @@ struct wiimote_t** wiiuse_init(int wiimotes) {
wm[i] = malloc(sizeof(struct wiimote_t));
memset(wm[i], 0, sizeof(struct wiimote_t));
wm[i]->unid = i+1;
#ifndef WIN32
wm[i]->bdaddr = *BDADDR_ANY;
wm[i]->out_sock = -1;
wm[i]->in_sock = -1;
#else
wm[i]->dev_handle = 0;
wm[i]->stack = WIIUSE_STACK_UNKNOWN;
wm[i]->normal_timeout = WIIMOTE_DEFAULT_TIMEOUT;
wm[i]->exp_timeout = WIIMOTE_EXP_TIMEOUT;
wm[i]->timeout = wm[i]->normal_timeout;
#endif
wm[i]->unid = i + 1;
wiiuse_init_platform_fields(wm[i]);
wm[i]->state = WIIMOTE_INIT_STATES;
wm[i]->flags = WIIUSE_INIT_FLAGS;
@ -141,6 +150,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);
@ -161,7 +171,9 @@ struct wiimote_t** wiiuse_init(int wiimotes) {
* @param wm Pointer to a wiimote_t structure.
*/
void wiiuse_disconnected(struct wiimote_t* wm) {
if (!wm) return;
if (!wm) {
return;
}
WIIUSE_INFO("Wiimote disconnected [id %i].", wm->unid);
@ -169,21 +181,15 @@ void wiiuse_disconnected(struct wiimote_t* wm) {
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_CONNECTED);
/* reset a bunch of stuff */
#ifndef WIN32
wm->out_sock = -1;
wm->in_sock = -1;
#else
wm->dev_handle = 0;
#endif
wm->leds = 0;
wm->state = WIIMOTE_INIT_STATES;
wm->read_req = NULL;
#ifndef WIIUSE_SYNC_HANDSHAKE
wm->handshake_state = 0;
#endif
wm->btns = 0;
wm->btns_held = 0;
wm->btns_released = 0;
memset(wm->event_buf, 0, sizeof(wm->event_buf));
wm->event = WIIUSE_DISCONNECT;
}
@ -198,8 +204,9 @@ void wiiuse_disconnected(struct wiimote_t* wm) {
void wiiuse_rumble(struct wiimote_t* wm, int status) {
byte buf;
if (!wm || !WIIMOTE_IS_CONNECTED(wm))
if (!wm || !WIIMOTE_IS_CONNECTED(wm)) {
return;
}
/* make sure to keep the current lit leds */
buf = wm->leds;
@ -211,11 +218,13 @@ void wiiuse_rumble(struct wiimote_t* wm, int status) {
} else {
WIIUSE_DEBUG("Stopping rumble...");
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_RUMBLE);
buf &= ~(0x01);
}
/* preserve IR state */
if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR))
if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) {
buf |= 0x04;
}
wiiuse_send(wm, WM_CMD_RUMBLE, &buf, 1);
}
@ -227,7 +236,9 @@ void wiiuse_rumble(struct wiimote_t* wm, int status) {
* @param wm Pointer to a wiimote_t structure.
*/
void wiiuse_toggle_rumble(struct wiimote_t* wm) {
if (!wm) return;
if (!wm) {
return;
}
wiiuse_rumble(wm, !WIIMOTE_IS_SET(wm, WIIMOTE_STATE_RUMBLE));
}
@ -244,15 +255,17 @@ void wiiuse_toggle_rumble(struct wiimote_t* wm) {
void wiiuse_set_leds(struct wiimote_t* wm, int leds) {
byte buf;
if (!wm || !WIIMOTE_IS_CONNECTED(wm))
if (!wm || !WIIMOTE_IS_CONNECTED(wm)) {
return;
}
/* 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 */
if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_RUMBLE))
if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_RUMBLE)) {
wm->leds |= 0x01;
}
buf = wm->leds;
@ -271,10 +284,11 @@ void wiiuse_set_leds(struct wiimote_t* wm, int leds) {
* by default.
*/
void wiiuse_motion_sensing(struct wiimote_t* wm, int status) {
if (status)
if (status) {
WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_ACC);
else
} else {
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_ACC);
}
wiiuse_set_report_type(wm);
}
@ -296,34 +310,46 @@ int wiiuse_set_report_type(struct wiimote_t* wm) {
byte buf[2];
int motion, exp, ir;
if (!wm || !WIIMOTE_IS_CONNECTED(wm))
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 */
buf[1] = 0x00;
/* if rumble is enabled, make sure we keep it */
if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_RUMBLE))
if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_RUMBLE)) {
buf[0] |= 0x01;
}
motion = WIIMOTE_IS_SET(wm, WIIMOTE_STATE_ACC);
exp = WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP);
ir = WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR);
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;
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;
}
WIIUSE_DEBUG("Setting report type: 0x%x", buf[1]);
exp = wiiuse_send(wm, WM_CMD_REPORT_TYPE, buf, 2);
if (exp <= 0)
if (exp <= 0) {
return exp;
}
return buf[1];
}
@ -346,16 +372,21 @@ int wiiuse_set_report_type(struct wiimote_t* wm) {
* to a pending list and be sent out when the previous
* finishes.
*/
int wiiuse_read_data_cb(struct wiimote_t* wm, wiiuse_read_cb read_cb, byte* buffer, unsigned int addr, unsigned short len) {
int wiiuse_read_data_cb(struct wiimote_t* wm, wiiuse_read_cb read_cb, byte* buffer, unsigned int addr, uint16_t len) {
struct read_req_t* req;
if (!wm || !WIIMOTE_IS_CONNECTED(wm))
if (!wm || !WIIMOTE_IS_CONNECTED(wm)) {
return 0;
if (!buffer || !len || !read_cb)
}
if (!buffer || !len) {
return 0;
}
/* make this request structure */
req = (struct read_req_t*)malloc(sizeof(struct read_req_t));
if (req == NULL) {
return 0;
}
req->cb = read_cb;
req->buf = buffer;
req->addr = addr;
@ -375,7 +406,9 @@ int wiiuse_read_data_cb(struct wiimote_t* wm, wiiuse_read_cb read_cb, byte* buff
wiiuse_send_next_pending_read_request(wm);
} else {
struct read_req_t* nptr = wm->read_req;
for (; nptr->next; nptr = nptr->next);
for (; nptr->next; nptr = nptr->next) {
;
}
nptr->next = req;
WIIUSE_DEBUG("Added pending data read request.");
@ -401,42 +434,8 @@ int wiiuse_read_data_cb(struct wiimote_t* wm, wiiuse_read_cb read_cb, byte* buff
* to a pending list and be sent out when the previous
* finishes.
*/
int wiiuse_read_data(struct wiimote_t* wm, byte* buffer, unsigned int addr, unsigned short len) {
struct read_req_t* req;
if (!wm || !WIIMOTE_IS_CONNECTED(wm))
return 0;
if (!buffer || !len)
return 0;
/* make this request structure */
req = (struct read_req_t*)malloc(sizeof(struct read_req_t));
req->cb = NULL;
req->buf = buffer;
req->addr = addr;
req->size = len;
req->wait = len;
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;
for (; nptr->next; nptr = nptr->next);
nptr->next = req;
WIIUSE_DEBUG("Added pending data read request.");
}
return 1;
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);
}
@ -453,22 +452,27 @@ void wiiuse_send_next_pending_read_request(struct wiimote_t* wm) {
byte buf[6];
struct read_req_t* req;
if (!wm || !WIIMOTE_IS_CONNECTED(wm))
if (!wm || !WIIMOTE_IS_CONNECTED(wm)) {
return;
if (!wm->read_req) return;
}
if (!wm->read_req) {
return;
}
/* skip over dirty ones since they have already been read */
req = wm->read_req;
while (req && req->dirty)
while (req && req->dirty) {
req = req->next;
if (!req)
}
if (!req) {
return;
}
/* the offset is in big endian */
*(int*)(buf) = BIG_ENDIAN_LONG(req->addr);
to_big_endian_uint32_t(buf, req->addr);
/* the length is in big endian */
*(short*)(buf + 4) = BIG_ENDIAN_SHORT(req->size);
to_big_endian_uint16_t(buf + 4, req->size);
WIIUSE_DEBUG("Request read at address: 0x%x length: %i", req->addr, req->size);
wiiuse_send(wm, WM_CMD_READ_DATA, buf, 6);
@ -485,8 +489,9 @@ void wiiuse_send_next_pending_read_request(struct wiimote_t* wm) {
void wiiuse_status(struct wiimote_t* wm) {
byte buf = 0;
if (!wm || !WIIMOTE_IS_CONNECTED(wm))
if (!wm || !WIIMOTE_IS_CONNECTED(wm)) {
return;
}
WIIUSE_DEBUG("Requested wiimote status.");
@ -505,10 +510,17 @@ void wiiuse_status(struct wiimote_t* wm) {
*/
struct wiimote_t* wiiuse_get_by_id(struct wiimote_t** wm, int wiimotes, int unid) {
int i = 0;
if (!wm) {
return NULL;
}
for (; i < wiimotes; ++i) {
if (wm[i]->unid == unid)
if (!wm[i]) {
continue;
}
if (wm[i]->unid == unid) {
return wm[i];
}
}
return NULL;
@ -523,104 +535,168 @@ struct wiimote_t* wiiuse_get_by_id(struct wiimote_t** wm, int wiimotes, int unid
* @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) {
int wiiuse_write_data(struct wiimote_t* wm, unsigned int addr, const byte* data, byte len) {
byte buf[21] = {0}; /* the payload is always 23 */
if (!wm || !WIIMOTE_IS_CONNECTED(wm))
byte * bufPtr = buf;
if (!wm || !WIIMOTE_IS_CONNECTED(wm)) {
return 0;
if (!data || !len)
}
if (!data || !len) {
return 0;
}
WIIUSE_DEBUG("Writing %i bytes to memory location 0x%x...", len, addr);
#ifdef WITH_WIIUSE_DEBUG
#ifdef WITH_WIIUSE_DEBUG
{
int i = 0;
printf("Write data is: ");
for (; i < len; ++i)
for (; i < len; ++i) {
printf("%x ", data[i]);
}
printf("\n");
}
#endif
#endif
/* the offset is in big endian */
*(int*)(buf) = BIG_ENDIAN_LONG(addr);
buffer_big_endian_uint32_t(&bufPtr, (uint32_t)addr);
/* length */
*(byte*)(buf + 4) = len;
buffer_big_endian_uint8_t(&bufPtr, len);
/* data */
memcpy(buf + 5, data, len);
memcpy(bufPtr, data, len);
wiiuse_send(wm, WM_CMD_WRITE_DATA, buf, 21);
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.
*
* @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 msg The payload. Might be changed by the callee.
* @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;
#ifndef WIN32
buf[0] = WM_SET_REPORT | WM_BT_OUTPUT;
buf[1] = report_type;
#else
buf[0] = report_type;
#endif
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;
}
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;
}
default:
break;
}
#ifndef WIN32
memcpy(buf+2, msg, len);
if (rumble)
buf[2] |= 0x01;
#else
memcpy(buf+1, msg, len);
if (rumble)
buf[1] |= 0x01;
#endif
#ifdef WITH_WIIUSE_DEBUG
#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]);
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]);
}
printf("\n");
}
#endif
#endif
#ifndef WIN32
return wiiuse_io_write(wm, buf, len+2);
#else
return wiiuse_io_write(wm, buf, len+1);
#endif
return wiiuse_os_write(wm, report_type, msg, len);
}
@ -637,7 +713,9 @@ int wiiuse_send(struct wiimote_t* wm, byte report_type, byte* msg, int len) {
* Flags are defined in wiiuse.h.
*/
int wiiuse_set_flags(struct wiimote_t* wm, int enable, int disable) {
if (!wm) return 0;
if (!wm) {
return 0;
}
/* remove mutually exclusive flags */
enable &= ~disable;
@ -666,15 +744,18 @@ int wiiuse_set_flags(struct wiimote_t* wm, int enable, int disable) {
float wiiuse_set_smooth_alpha(struct wiimote_t* wm, float alpha) {
float old;
if (!wm) return 0.0f;
if (!wm) {
return 0.0f;
}
old = wm->accel_calib.st_alpha;
wm->accel_calib.st_alpha = alpha;
/* if there is a nunchuk set that too */
if (wm->exp.type == EXP_NUNCHUK)
if (wm->exp.type == EXP_NUNCHUK) {
wm->exp.nunchuk.accel_calib.st_alpha = alpha;
}
return old;
}
@ -688,14 +769,17 @@ float wiiuse_set_smooth_alpha(struct wiimote_t* wm, float alpha) {
* @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) {
#ifdef WIN32
#ifdef WIIUSE_WIN32
int i;
if (!wm) return;
if (!wm) {
return;
}
for (i = 0; i < wiimotes; ++i)
for (i = 0; i < wiimotes; ++i) {
wm[i]->stack = type;
#endif
}
#endif
}
@ -706,11 +790,13 @@ void wiiuse_set_bluetooth_stack(struct wiimote_t** wm, int wiimotes, enum win_bt
* @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
* has occured and the event callback will be invoked. If threshold is 1 then
* has occurred and the event callback will be invoked. If threshold is 1 then
* the angle has to change by a full degree to generate an event.
*/
void wiiuse_set_orient_threshold(struct wiimote_t* wm, float threshold) {
if (!wm) return;
if (!wm) {
return;
}
wm->orient_threshold = threshold;
}
@ -723,7 +809,9 @@ void wiiuse_set_orient_threshold(struct wiimote_t* wm, float threshold) {
* @param threshold The decimal place that should be considered a significant change.
*/
void wiiuse_set_accel_threshold(struct wiimote_t* wm, int threshold) {
if (!wm) return;
if (!wm) {
return;
}
wm->accel_threshold = threshold;
}
@ -735,9 +823,13 @@ void wiiuse_set_accel_threshold(struct wiimote_t* wm, int threshold) {
* @param wm Pointer to a wiimote_t structure.
*/
void wiiuse_resync(struct wiimote_t* wm) {
if (!wm) return;
if (!wm) {
return;
}
#ifndef WIIUSE_SYNC_HANDSHAKE
wm->handshake_state = 0;
#endif
wiiuse_handshake(wm, NULL, 0);
}
@ -751,14 +843,16 @@ void wiiuse_resync(struct wiimote_t* wm) {
* @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) {
#ifdef WIN32
#ifdef WIIUSE_WIN32
int i;
if (!wm) return;
if (!wm) {
return;
}
for (i = 0; i < wiimotes; ++i) {
wm[i]->normal_timeout = normal_timeout;
wm[i]->exp_timeout = exp_timeout;
}
#endif
#endif
}

View File

@ -7,6 +7,12 @@
*
* Copyright 2006-2007
*
* Mac fields based on wiic_structs.h from WiiC, written By:
* Gabriele Randelli
* Email: < randelli (--AT--) dis [--DOT--] uniroma1 [--DOT--] it >
*
* Copyright 2010
*
* This file is part of wiiuse.
*
* This program is free software; you can redistribute it and/or modify
@ -36,31 +42,121 @@
* is also included which extends this file.
*/
/**
* @mainpage
*
* @section intro Introduction
*
* WiiUse is a cross-platform C library for accessing the Nintendo Wii
* Remote and its related expansions and variations.
*
* @section project Project
*
* This is a friendly fork of the original WiiUse project, which seems
* to have gone defunct. This updated version incorporates improvements
* from a number of internal forks found across the Internet, and is
* intended to be the new "upstream" of the project. The new homepage is
* on GitHub, where the source is maintained:
*
* - http://github.com/rpavlik/wiiuse
*
* Contributions (under the GPL 3+) are welcome and encouraged!
*
* @section publicapisec Public API
*
* - @ref publicapi "Public API" - entirely within @ref wiiuse.h
* - @ref wiimote "Wiimote device structure"
*
*/
#ifndef WIIUSE_H_INCLUDED
#define WIIUSE_H_INCLUDED
#ifdef _WIN32
#define WIIUSE_MAJOR 0
#define WIIUSE_MINOR 14
#define WIIUSE_MICRO 0
#ifndef WIIUSE_PLATFORM
#if defined(_WIN32)
#define WIIUSE_PLATFORM
#define WIIUSE_WIN32
#elif defined(__linux)
#define WIIUSE_PLATFORM
#define WIIUSE_BLUEZ
#elif defined(__APPLE__)
#define WIIUSE_PLATFORM
#define WIIUSE_MAC
#else
#error "Platform not yet supported!"
#endif
#endif
#ifdef WIIUSE_WIN32
/* windows */
#define WIN32_LEAN_AND_MEAN 1
#include <windows.h>
#else
#endif
#ifdef WIIUSE_BLUEZ
/* nix */
#include <bluetooth/bluetooth.h>
#endif
#ifdef WIIUSE_INTERNAL_H_INCLUDED
#define WCONST
#else
#ifndef WCONST
#define WCONST const
#endif
/* led bit masks */
#if defined(_MSC_VER)
/* MS compilers of pre-VC2010 versions don't have stdint.h
* and I can't get VC2010's stdint.h to compile nicely in
* WiiUse
*/
#include "wiiuse_msvcstdint.h"
#else
#include <stdint.h>
#endif
#include <stdio.h> /* for FILE */
/** @defgroup publicapi External API */
/** @{ */
/** @name Wiimote state flags and macros */
/** @{ */
#define WIIMOTE_STATE_DEV_FOUND 0x0001
#define WIIMOTE_STATE_HANDSHAKE 0x0002 /* actual connection exists but no handshake yet */
#define WIIMOTE_STATE_HANDSHAKE_COMPLETE 0x0004 /* actual connection exists but no handshake yet */
#define WIIMOTE_STATE_CONNECTED 0x0008
#define WIIMOTE_STATE_RUMBLE 0x0010
#define WIIMOTE_STATE_ACC 0x0020
#define WIIMOTE_STATE_EXP 0x0040
#define WIIMOTE_STATE_IR 0x0080
#define WIIMOTE_STATE_SPEAKER 0x0100
#define WIIMOTE_STATE_IR_SENS_LVL1 0x0200
#define WIIMOTE_STATE_IR_SENS_LVL2 0x0400
#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_STATE_MPLUS_PRESENT 0x80000 /* Motion+ is connected */
#define WIIMOTE_ID(wm) (wm->unid)
#define WIIMOTE_IS_SET(wm, s) ((wm->state & (s)) == (s))
#define WIIMOTE_IS_CONNECTED(wm) (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_CONNECTED))
/** @} */
/** @name LED bit masks */
/** @{ */
#define WIIMOTE_LED_NONE 0x00
#define WIIMOTE_LED_1 0x10
#define WIIMOTE_LED_2 0x20
#define WIIMOTE_LED_3 0x40
#define WIIMOTE_LED_4 0x80
/** @} */
/* button codes */
/** @name Button codes */
/** @{ */
#define WIIMOTE_BUTTON_TWO 0x0001
#define WIIMOTE_BUTTON_ONE 0x0002
#define WIIMOTE_BUTTON_B 0x0004
@ -78,13 +174,17 @@
#define WIIMOTE_BUTTON_ZACCEL_BIT5 0x4000
#define WIIMOTE_BUTTON_UNKNOWN 0x8000
#define WIIMOTE_BUTTON_ALL 0x1F9F
/** @} */
/* nunchul button codes */
/** @name Nunchuk button codes */
/** @{ */
#define NUNCHUK_BUTTON_Z 0x01
#define NUNCHUK_BUTTON_C 0x02
#define NUNCHUK_BUTTON_ALL 0x03
/** @} */
/* classic controller button codes */
/** @name Classic controller button codes */
/** @{ */
#define CLASSIC_CTRL_BUTTON_UP 0x0001
#define CLASSIC_CTRL_BUTTON_LEFT 0x0002
#define CLASSIC_CTRL_BUTTON_ZR 0x0004
@ -101,8 +201,10 @@
#define CLASSIC_CTRL_BUTTON_DOWN 0x4000
#define CLASSIC_CTRL_BUTTON_RIGHT 0x8000
#define CLASSIC_CTRL_BUTTON_ALL 0xFEFF
/** @} */
/* guitar hero 3 button codes */
/** @name Guitar Hero 3 button codes */
/** @{ */
#define GUITAR_HERO_3_BUTTON_STRUM_UP 0x0001
#define GUITAR_HERO_3_BUTTON_YELLOW 0x0008
#define GUITAR_HERO_3_BUTTON_GREEN 0x0010
@ -113,28 +215,39 @@
#define GUITAR_HERO_3_BUTTON_MINUS 0x1000
#define GUITAR_HERO_3_BUTTON_STRUM_DOWN 0x4000
#define GUITAR_HERO_3_BUTTON_ALL 0xFEFF
/** @} */
/* wiimote option flags */
/** @name Wiimote option flags */
/** @{ */
#define WIIUSE_SMOOTHING 0x01
#define WIIUSE_CONTINUOUS 0x02
#define WIIUSE_ORIENT_THRESH 0x04
#define WIIUSE_INIT_FLAGS (WIIUSE_SMOOTHING | WIIUSE_ORIENT_THRESH)
#define WIIUSE_ORIENT_PRECISION 100.0f
/** @} */
/* expansion codes */
/** @name Expansion codes */
/** @{ */
#define EXP_NONE 0
#define EXP_NUNCHUK 1
#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 */
/** @} */
/* IR correction types */
/** @brief IR correction types */
typedef enum ir_position_t {
WIIUSE_IR_ABOVE,
WIIUSE_IR_BELOW
} ir_position_t;
/** @name Device Inquiry Macros */
/** @{ */
/**
* @brief Check if a button is pressed.
* @param dev Pointer to a wiimote_t or expansion structure.
@ -192,22 +305,20 @@ typedef enum ir_position_t {
#define WIIUSE_USING_SPEAKER(wm) ((wm->state & 0x100) == 0x100)
#define WIIUSE_IS_LED_SET(wm, num) ((wm->leds & WIIMOTE_LED_##num) == WIIMOTE_LED_##num)
/*
* Largest known payload is 21 bytes.
* Add 2 for the prefix and round up to a power of 2.
*/
#define MAX_PAYLOAD 32
/** @} */
/*
* This is left over from an old hack, but it may actually
* be a useful feature to keep so it wasn't removed.
*/
#ifdef WIN32
#ifdef WIIUSE_WIN32
#define WIIMOTE_DEFAULT_TIMEOUT 10
#define WIIMOTE_EXP_TIMEOUT 10
#endif
#define WIIUSE_SYNC_HANDSHAKE
typedef unsigned char byte;
typedef char sbyte;
@ -230,27 +341,40 @@ struct gforce_t;
* library when the wiimote has returned the full data requested by a previous
* call to wiiuse_read_data().
*/
typedef void (*wiiuse_read_cb)(struct wiimote_t* wm, byte* data, unsigned short len);
typedef void (*wiiuse_read_cb)(struct wiimote_t* wm, byte* data, uint16_t len);
/**
* @struct read_req_t
* @brief Data read request structure.
*/
struct read_req_t {
wiiuse_read_cb cb; /**< read data callback */
byte* buf; /**< buffer where read data is written */
unsigned int addr; /**< the offset that the read started at */
unsigned short size; /**< the length of the data read */
unsigned short wait; /**< num bytes still needed to finish read */
uint32_t addr; /**< the offset that the read started at */
uint16_t size; /**< the length of the data read */
uint16_t wait; /**< num bytes still needed to finish read */
byte dirty; /**< set to 1 if not using callback and needs to be cleaned up */
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;
/**
* @struct vec2b_t
* @brief Unsigned x,y byte vector.
*/
typedef struct vec2b_t {
@ -259,7 +383,6 @@ typedef struct vec2b_t {
/**
* @struct vec3b_t
* @brief Unsigned x,y,z byte vector.
*/
typedef struct vec3b_t {
@ -268,7 +391,6 @@ typedef struct vec3b_t {
/**
* @struct vec3f_t
* @brief Signed x,y,z float struct.
*/
typedef struct vec3f_t {
@ -277,7 +399,6 @@ typedef struct vec3f_t {
/**
* @struct orient_t
* @brief Orientation struct.
*
* Yaw, pitch, and roll range from -180 to 180 degrees.
@ -293,7 +414,6 @@ typedef struct orient_t {
/**
* @struct gforce_t
* @brief Gravity force struct.
*/
typedef struct gforce_t {
@ -302,7 +422,6 @@ typedef struct gforce_t {
/**
* @struct accel_t
* @brief Accelerometer struct. For any device with an accelerometer.
*/
typedef struct accel_t {
@ -316,7 +435,6 @@ typedef struct accel_t {
/**
* @struct ir_dot_t
* @brief A single IR source.
*/
typedef struct ir_dot_t {
@ -325,8 +443,8 @@ typedef struct ir_dot_t {
unsigned int x; /**< interpolated X coordinate */
unsigned int y; /**< interpolated Y coordinate */
short rx; /**< raw X coordinate (0-1023) */
short ry; /**< raw Y coordinate (0-767) */
int16_t rx; /**< raw X coordinate (0-1023) */
int16_t ry; /**< raw Y coordinate (0-767) */
byte order; /**< increasing order by x-axis value */
@ -335,7 +453,6 @@ typedef struct ir_dot_t {
/**
* @enum aspect_t
* @brief Screen aspect ratio.
*/
typedef enum aspect_t {
@ -345,7 +462,6 @@ typedef enum aspect_t {
/**
* @struct ir_t
* @brief IR struct. Hold all data related to the IR tracking.
*/
typedef struct ir_t {
@ -372,7 +488,6 @@ typedef struct ir_t {
/**
* @struct joystick_t
* @brief Joystick calibration structure.
*
* The angle \a ang is relative to the positive y-axis into quadrant I
@ -397,7 +512,6 @@ typedef struct joystick_t {
/**
* @struct nunchuk_t
* @brief Nunchuk expansion device.
*/
typedef struct nunchuk_t {
@ -420,13 +534,12 @@ typedef struct nunchuk_t {
/**
* @struct classic_ctrl_t
* @brief Classic controller expansion device.
*/
typedef struct classic_ctrl_t {
short btns; /**< what buttons have just been pressed */
short btns_held; /**< what buttons are being held down */
short btns_released; /**< what buttons were just released this */
int16_t btns; /**< what buttons have just been pressed */
int16_t btns_held; /**< what buttons are being held down */
int16_t btns_released; /**< what buttons were just released this */
float r_shoulder; /**< right shoulder button (range 0-1) */
float l_shoulder; /**< left shoulder button (range 0-1) */
@ -437,13 +550,12 @@ typedef struct classic_ctrl_t {
/**
* @struct guitar_hero_3_t
* @brief Guitar Hero 3 expansion device.
*/
typedef struct guitar_hero_3_t {
short btns; /**< what buttons have just been pressed */
short btns_held; /**< what buttons are being held down */
short btns_released; /**< what buttons were just released this */
int16_t btns; /**< what buttons have just been pressed */
int16_t btns_held; /**< what buttons are being held down */
int16_t btns_released; /**< what buttons were just released this */
float whammy_bar; /**< whammy bar (range 0-1) */
@ -452,22 +564,80 @@ typedef struct guitar_hero_3_t {
/**
* @struct expansion_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.
*
* A Balance Board presents itself as a Wiimote with a permanently-attached
* Balance Board expansion device.
*/
typedef struct wii_board_t {
/** @name Interpolated weight per sensor (kg)
*
* These are the values you're most likely to use.
*
* See example.c for how to compute total weight and center of gravity
* from these values.
*/
/** @{ */
float tl;
float tr;
float bl;
float br;
/** @} */
/** @name Raw sensor values */
/** @{ */
uint16_t rtl;
uint16_t rtr;
uint16_t rbl;
uint16_t rbr;
/** @} */
/** @name Sensor calibration values */
/** @{ */
uint16_t ctl[3]; /* Calibration */
uint16_t ctr[3];
uint16_t cbl[3];
uint16_t cbr[3]; /* /Calibration */
/** @} */
uint8_t update_calib;
} wii_board_t;
/**
* @brief Generic expansion device plugged into wiimote.
*/
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;
struct guitar_hero_3_t gh3;
struct wii_board_t wb;
};
} expansion_t;
/**
* @enum win32_bt_stack_t
* @brief Available bluetooth stacks for Windows.
*/
typedef enum win_bt_stack_t {
@ -478,7 +648,6 @@ typedef enum win_bt_stack_t {
/**
* @struct wiimote_state_t
* @brief Significant data from the previous event.
*/
typedef struct wiimote_state_t {
@ -487,26 +656,36 @@ typedef struct wiimote_state_t {
float exp_rjs_ang;
float exp_ljs_mag;
float exp_rjs_mag;
unsigned short exp_btns;
uint16_t exp_btns;
struct orient_t exp_orient;
struct vec3b_t exp_accel;
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;
uint16_t exp_wb_rbr;
uint16_t exp_wb_rbl;
/* ir_t */
int ir_ax;
int ir_ay;
float ir_distance;
struct orient_t orient;
unsigned short btns;
uint16_t btns;
struct vec3b_t accel;
} wiimote_state_t;
/**
* @enum WIIUSE_EVENT_TYPE
* @brief Events that wiiuse can generate from a poll.
*/
typedef enum WIIUSE_EVENT_TYPE {
@ -517,34 +696,55 @@ 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,
WIIUSE_CLASSIC_CTRL_REMOVED,
WIIUSE_GUITAR_HERO_3_CTRL_INSERTED,
WIIUSE_GUITAR_HERO_3_CTRL_REMOVED
WIIUSE_GUITAR_HERO_3_CTRL_REMOVED,
WIIUSE_WII_BOARD_CTRL_INSERTED,
WIIUSE_WII_BOARD_CTRL_REMOVED,
WIIUSE_MOTION_PLUS_ACTIVATED,
WIIUSE_MOTION_PLUS_REMOVED
} WIIUSE_EVENT_TYPE;
/**
* @struct wiimote_t
* @brief Wiimote structure.
* @brief Main Wiimote device structure.
*
* You need one of these to do pretty much anything with this library.
*/
typedef struct wiimote_t {
WCONST int unid; /**< user specified id */
#ifndef WIN32
WCONST bdaddr_t bdaddr; /**< bt address */
WCONST char bdaddr_str[18]; /**< readable bt address */
WCONST int out_sock; /**< output socket */
WCONST int in_sock; /**< input socket */
#else
WCONST HANDLE dev_handle; /**< HID handle */
WCONST OVERLAPPED hid_overlap; /**< overlap handle */
WCONST enum win_bt_stack_t stack; /**< type of bluetooth stack to use */
WCONST int timeout; /**< read timeout */
WCONST byte normal_timeout; /**< normal timeout */
WCONST byte exp_timeout; /**< timeout for expansion handshake */
#endif
#ifdef WIIUSE_BLUEZ
/** @name Linux-specific (BlueZ) members */
/** @{ */
WCONST char bdaddr_str[18]; /**< readable bt address */
WCONST bdaddr_t bdaddr; /**< bt address */
WCONST int out_sock; /**< output socket */
WCONST int in_sock; /**< input socket */
/** @} */
#endif
#ifdef WIIUSE_WIN32
/** @name Windows-specific members */
/** @{ */
WCONST HANDLE dev_handle; /**< HID handle */
WCONST OVERLAPPED hid_overlap; /**< overlap handle */
WCONST enum win_bt_stack_t stack; /**< type of bluetooth stack to use */
WCONST int timeout; /**< read timeout */
WCONST byte normal_timeout; /**< normal timeout */
WCONST byte exp_timeout; /**< timeout for expansion handshake */
/** @} */
#endif
#ifdef WIIUSE_MAC
/** @name Mac OS X-specific members */
/** @{ */
WCONST void* objc_wm; /** WiiuseWiimote* as opaque pointer */
/** @} */
#endif
WCONST int state; /**< various state flags */
WCONST byte leds; /**< currently lit leds */
@ -552,7 +752,11 @@ typedef struct wiimote_t {
WCONST int flags; /**< options flag */
#ifndef WIIUSE_SYNC_HANDSHAKE
WCONST byte handshake_state; /**< the state of the connection handshake */
#endif
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 */
@ -564,19 +768,83 @@ typedef struct wiimote_t {
WCONST struct ir_t ir; /**< IR data */
WCONST unsigned short btns; /**< what buttons have just been pressed */
WCONST unsigned short btns_held; /**< what buttons are being held down */
WCONST unsigned short btns_released; /**< what buttons were just released this */
WCONST uint16_t btns; /**< what buttons have just been pressed */
WCONST uint16_t btns_held; /**< what buttons are being held down */
WCONST uint16_t btns_released; /**< what buttons were just released this */
WCONST float orient_threshold; /**< threshold for orient to generate an event */
WCONST int accel_threshold; /**< threshold for accel to generate an event */
WCONST int32_t accel_threshold; /**< threshold for accel to generate an event */
WCONST struct wiimote_state_t lstate; /**< last saved state */
WCONST WIIUSE_EVENT_TYPE event; /**< type of event that occured */
WCONST byte event_buf[MAX_PAYLOAD]; /**< event buffer */
WCONST WIIUSE_EVENT_TYPE event; /**< type of event that occurred */
WCONST byte motion_plus_id[6];
} wiimote;
/** @brief Data passed to a callback during wiiuse_update() */
typedef struct wiimote_callback_data_t {
WCONST int uid;
WCONST byte leds;
WCONST float battery_level;
WCONST struct vec3b_t accel;
WCONST struct orient_t orient;
WCONST struct gforce_t gforce;
WCONST struct ir_t ir;
WCONST uint16_t buttons;
WCONST uint16_t buttons_held;
WCONST uint16_t buttons_released;
WCONST WIIUSE_EVENT_TYPE event;
WCONST int state;
WCONST struct expansion_t expansion;
} 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.
*/
typedef enum wiiuse_loglevel {
LOGLEVEL_ERROR = 0,
LOGLEVEL_WARNING = 1,
LOGLEVEL_INFO = 2,
LOGLEVEL_DEBUG = 3
} wiiuse_loglevel;
/*****************************************
*
@ -584,9 +852,14 @@ typedef struct wiimote_t {
*
*****************************************/
#ifdef _WIN32
#define WIIUSE_EXPORT_DECL __declspec(dllexport)
#define WIIUSE_IMPORT_DECL __declspec(dllimport)
#ifdef WIIUSE_WIN32
#ifdef WIIUSE_STATIC
#define WIIUSE_EXPORT_DECL
#define WIIUSE_IMPORT_DECL
#else
#define WIIUSE_EXPORT_DECL __declspec(dllexport)
#define WIIUSE_IMPORT_DECL __declspec(dllimport)
#endif
#else
#define WIIUSE_EXPORT_DECL
#define WIIUSE_IMPORT_DECL
@ -602,52 +875,75 @@ typedef struct wiimote_t {
extern "C" {
#endif
/* wiiuse.c */
WIIUSE_EXPORT extern const char* wiiuse_version();
/* wiiuse.c */
WIIUSE_EXPORT extern const char* wiiuse_version();
WIIUSE_EXPORT extern struct wiimote_t** wiiuse_init(int wiimotes);
WIIUSE_EXPORT extern void wiiuse_disconnected(struct wiimote_t* wm);
WIIUSE_EXPORT extern void wiiuse_cleanup(struct wiimote_t** wm, int wiimotes);
WIIUSE_EXPORT extern void wiiuse_rumble(struct wiimote_t* wm, int status);
WIIUSE_EXPORT extern void wiiuse_toggle_rumble(struct wiimote_t* wm);
WIIUSE_EXPORT extern void wiiuse_set_leds(struct wiimote_t* wm, int leds);
WIIUSE_EXPORT extern void wiiuse_motion_sensing(struct wiimote_t* wm, int status);
WIIUSE_EXPORT extern int wiiuse_read_data(struct wiimote_t* wm, byte* buffer, unsigned int offset, unsigned short len);
WIIUSE_EXPORT extern int wiiuse_write_data(struct wiimote_t* wm, unsigned int addr, byte* data, byte len);
WIIUSE_EXPORT extern void wiiuse_status(struct wiimote_t* wm);
WIIUSE_EXPORT extern struct wiimote_t* wiiuse_get_by_id(struct wiimote_t** wm, int wiimotes, int unid);
WIIUSE_EXPORT extern int wiiuse_set_flags(struct wiimote_t* wm, int enable, int disable);
WIIUSE_EXPORT extern float wiiuse_set_smooth_alpha(struct wiimote_t* wm, float alpha);
WIIUSE_EXPORT extern void wiiuse_set_bluetooth_stack(struct wiimote_t** wm, int wiimotes, enum win_bt_stack_t type);
WIIUSE_EXPORT extern void wiiuse_set_orient_threshold(struct wiimote_t* wm, float threshold);
WIIUSE_EXPORT extern void wiiuse_resync(struct wiimote_t* wm);
WIIUSE_EXPORT extern void wiiuse_set_timeout(struct wiimote_t** wm, int wiimotes, byte normal_timeout, byte exp_timeout);
WIIUSE_EXPORT extern void wiiuse_set_accel_threshold(struct wiimote_t* wm, int threshold);
/** @brief Define indicating the presence of the feature allowing you to
* redirect output for one or more logging levels within the library.
*/
#define WIIUSE_HAS_OUTPUT_REDIRECTION
WIIUSE_EXPORT extern void wiiuse_set_output(enum wiiuse_loglevel loglevel, FILE *logtarget);
/* connect.c */
WIIUSE_EXPORT extern int wiiuse_find(struct wiimote_t** wm, int max_wiimotes, int timeout);
WIIUSE_EXPORT extern int wiiuse_connect(struct wiimote_t** wm, int wiimotes);
WIIUSE_EXPORT extern void wiiuse_disconnect(struct wiimote_t* wm);
WIIUSE_EXPORT extern struct wiimote_t** wiiuse_init(int wiimotes);
WIIUSE_EXPORT extern void wiiuse_disconnected(struct wiimote_t* wm);
WIIUSE_EXPORT extern void wiiuse_cleanup(struct wiimote_t** wm, int wiimotes);
WIIUSE_EXPORT extern void wiiuse_rumble(struct wiimote_t* wm, int status);
WIIUSE_EXPORT extern void wiiuse_toggle_rumble(struct wiimote_t* wm);
WIIUSE_EXPORT extern void wiiuse_set_leds(struct wiimote_t* wm, int leds);
WIIUSE_EXPORT extern void wiiuse_motion_sensing(struct wiimote_t* wm, int status);
WIIUSE_EXPORT extern int wiiuse_read_data(struct wiimote_t* wm, byte* buffer, unsigned int offset, uint16_t len);
WIIUSE_EXPORT extern int wiiuse_write_data(struct wiimote_t* wm, unsigned int addr, const byte* data, byte len);
WIIUSE_EXPORT extern void wiiuse_status(struct wiimote_t* wm);
WIIUSE_EXPORT extern struct wiimote_t* wiiuse_get_by_id(struct wiimote_t** wm, int wiimotes, int unid);
WIIUSE_EXPORT extern int wiiuse_set_flags(struct wiimote_t* wm, int enable, int disable);
WIIUSE_EXPORT extern float wiiuse_set_smooth_alpha(struct wiimote_t* wm, float alpha);
WIIUSE_EXPORT extern void wiiuse_set_bluetooth_stack(struct wiimote_t** wm, int wiimotes, enum win_bt_stack_t type);
WIIUSE_EXPORT extern void wiiuse_set_orient_threshold(struct wiimote_t* wm, float threshold);
WIIUSE_EXPORT extern void wiiuse_resync(struct wiimote_t* wm);
WIIUSE_EXPORT extern void wiiuse_set_timeout(struct wiimote_t** wm, int wiimotes, byte normal_timeout, byte exp_timeout);
WIIUSE_EXPORT extern void wiiuse_set_accel_threshold(struct wiimote_t* wm, int threshold);
/* events.c */
WIIUSE_EXPORT extern int wiiuse_poll(struct wiimote_t** wm, int wiimotes);
/* io.c */
WIIUSE_EXPORT extern int wiiuse_find(struct wiimote_t** wm, int max_wiimotes, int timeout);
WIIUSE_EXPORT extern int wiiuse_connect(struct wiimote_t** wm, int wiimotes);
WIIUSE_EXPORT extern void wiiuse_disconnect(struct wiimote_t* wm);
/* ir.c */
WIIUSE_EXPORT extern void wiiuse_set_ir(struct wiimote_t* wm, int status);
WIIUSE_EXPORT extern void wiiuse_set_ir_vres(struct wiimote_t* wm, unsigned int x, unsigned int y);
WIIUSE_EXPORT extern void wiiuse_set_ir_position(struct wiimote_t* wm, enum ir_position_t pos);
WIIUSE_EXPORT extern void wiiuse_set_aspect_ratio(struct wiimote_t* wm, enum aspect_t aspect);
WIIUSE_EXPORT extern void wiiuse_set_ir_sensitivity(struct wiimote_t* wm, int level);
/* events.c */
WIIUSE_EXPORT extern int wiiuse_poll(struct wiimote_t** wm, int wiimotes);
/* nunchuk.c */
WIIUSE_EXPORT extern void wiiuse_set_nunchuk_orient_threshold(struct wiimote_t* wm, float threshold);
WIIUSE_EXPORT extern void wiiuse_set_nunchuk_accel_threshold(struct wiimote_t* wm, int threshold);
/**
* @brief Poll Wiimotes, and call the provided callback with information
* on each Wiimote that had an event.
*
* Alternative to calling wiiuse_poll yourself, and provides the same
* information struct on all platforms.
*
* @return Number of wiimotes that had an event.
*/
WIIUSE_EXPORT extern int wiiuse_update(struct wiimote_t** wm, int wiimotes, wiiuse_update_cb callback);
/* ir.c */
WIIUSE_EXPORT extern void wiiuse_set_ir(struct wiimote_t* wm, int status);
WIIUSE_EXPORT extern void wiiuse_set_ir_vres(struct wiimote_t* wm, unsigned int x, unsigned int y);
WIIUSE_EXPORT extern void wiiuse_set_ir_position(struct wiimote_t* wm, enum ir_position_t pos);
WIIUSE_EXPORT extern void wiiuse_set_aspect_ratio(struct wiimote_t* wm, enum aspect_t aspect);
WIIUSE_EXPORT extern void wiiuse_set_ir_sensitivity(struct wiimote_t* wm, int level);
/* nunchuk.c */
WIIUSE_EXPORT extern void wiiuse_set_nunchuk_orient_threshold(struct wiimote_t* wm, float threshold);
WIIUSE_EXPORT extern void wiiuse_set_nunchuk_accel_threshold(struct wiimote_t* wm, int threshold);
/* wiiboard.c */
/* 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
/** @} */
#endif /* WIIUSE_H_INCLUDED */

View File

@ -9,6 +9,12 @@
*
* This file is part of wiiuse.
*
* Mac device classes based on wiic_internal.h from WiiC, written By:
* Gabriele Randelli
* Email: < randelli (--AT--) dis [--DOT--] uniroma1 [--DOT--] it >
*
* Copyright 2010
*
* 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
@ -44,15 +50,45 @@
#ifndef WIIUSE_INTERNAL_H_INCLUDED
#define WIIUSE_INTERNAL_H_INCLUDED
#ifndef WIN32
#ifndef WIIUSE_PLATFORM
#if defined(_WIN32)
#define WIIUSE_PLATFORM
#define WIIUSE_WIN32
#elif defined(__linux)
#define WIIUSE_PLATFORM
#define WIIUSE_BLUEZ
#elif defined(__APPLE__)
#define WIIUSE_PLATFORM
#define WIIUSE_MAC
#else
#error "Platform not yet supported!"
#endif
#endif
#ifdef WIIUSE_WIN32
#include <winsock2.h>
#endif
#ifdef WIIUSE_BLUEZ
#include <arpa/inet.h> /* htons() */
#include <bluetooth/bluetooth.h>
#endif
#ifdef WIIUSE_MAC
/* mac */
#include <CoreFoundation/CoreFoundation.h> /*CFRunLoops and CFNumberRef in Bluetooth classes*/
#include <IOBluetooth/IOBluetoothUserLib.h> /*IOBluetoothDeviceRef and IOBluetoothL2CAPChannelRef*/
#endif
#include "definitions.h"
/* wiiuse version */
#define WIIUSE_VERSION "0.12"
#if defined(_MSC_VER)
/* MS compilers of pre-VC2010 versions don't have stdint.h
* and I can't get VC2010's stdint.h to compile nicely in
* WiiUse
*/
#include "wiiuse_msvcstdint.h"
#else
#include <stdint.h>
#endif
/********************
*
@ -60,11 +96,15 @@
*
********************/
/** @addtogroup internal_general Internal: API for General Internal Use */
/** @{ */
/* Communication channels */
#define WM_OUTPUT_CHANNEL 0x11
#define WM_INPUT_CHANNEL 0x13
#define WM_SET_REPORT 0x50
#define WM_SET_DATA 0xA0
/* commands */
#define WM_CMD_LED 0x11
@ -92,9 +132,33 @@
#define WM_BT_OUTPUT 0x02
/* Identify the wiimote device by its class */
#define WM_DEV_CLASS_0 0x04
#define WM_DEV_CLASS_1 0x25
#define WM_DEV_CLASS_2 0x00
/* (Explanation and mac classes taken from WiiC)
* The different codes wrt. to Linux
* is a bit hard to explain.
* Looking at Bluetooth CoD format, we have 24 bits.
* In wiic Linux they are stored in three fields,
* each one 8bit long. The result number is
* 0x002504. However, MacOS Bluetooth does
* not store them in such a way, rather it uses
* the concept of major service, major class,
* and minor class, that are respectivelly
* 11bit, 5bit, and 6bit long. Hence, the
* numbers are different.
* The Wiimote CoD Bluetooth division is the following:
* 00000000001 00101 000001 00 (major service - major class - minor class - format type)
* This can also be seen in the WiiC Linux way:
* 00000000 00100101 00000100
*/
#ifdef WIIUSE_MAC
#define WM_DEV_MINOR_CLASS 0x01
#define WM_DEV_MAJOR_CLASS 0x05
#define WM_DEV_MAJOR_SERVICE 0x01
#else
#define WM_DEV_CLASS_0 0x04
#define WM_DEV_CLASS_1 0x25
#define WM_DEV_CLASS_2 0x00
#endif
#define WM_VENDOR_ID 0x057E
#define WM_PRODUCT_ID 0x0306
@ -104,25 +168,19 @@
/* 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_IDENT 0x04A600FA
#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
/* ir block data */
#define WM_IR_BLOCK1_LEVEL1 "\x02\x00\x00\x71\x01\x00\x64\x00\xfe"
#define WM_IR_BLOCK2_LEVEL1 "\xfd\x05"
#define WM_IR_BLOCK1_LEVEL2 "\x02\x00\x00\x71\x01\x00\x96\x00\xb4"
#define WM_IR_BLOCK2_LEVEL2 "\xb3\x04"
#define WM_IR_BLOCK1_LEVEL3 "\x02\x00\x00\x71\x01\x00\xaa\x00\x64"
#define WM_IR_BLOCK2_LEVEL3 "\x63\x03"
#define WM_IR_BLOCK1_LEVEL4 "\x02\x00\x00\x71\x01\x00\xc8\x00\x36"
#define WM_IR_BLOCK2_LEVEL4 "\x35\x03"
#define WM_IR_BLOCK1_LEVEL5 "\x07\x00\x00\x71\x01\x00\x72\x00\x20"
#define WM_IR_BLOCK2_LEVEL5 "\x1f\x03"
#define WM_IR_TYPE_BASIC 0x01
#define WM_IR_TYPE_EXTENDED 0x03
@ -148,10 +206,20 @@
* Expansion stuff
*/
/* encrypted expansion id codes (located at 0x04A400FC) */
#define EXP_ID_CODE_NUNCHUK 0x9A1EFEFE
#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 */
/* decrypted M+ codes at 0x04A600FA */
#define EXP_ID_CODE_INACTIVE_MOTION_PLUS 0xA6200005 /** Inactive Motion Plus ID */
#define EXP_ID_CODE_NLA_MOTION_PLUS 0xA6200405 /** No longer active Motion Plus ID */
#define EXP_ID_CODE_NLA_MOTION_PLUS_NUNCHUK 0xA6200505 /** No longer active Motion Plus ID in Nunchuck passthrough mode */
#define EXP_ID_CODE_NLA_MOTION_PLUS_CLASSIC 0xA6200705 /** No longer active Motion Plus ID in Classic control. passthrough */
#define EXP_HANDSHAKE_LEN 224
@ -161,26 +229,9 @@
*
********************/
/* wiimote state flags - (some duplicated in wiiuse.h)*/
#define WIIMOTE_STATE_DEV_FOUND 0x0001
#define WIIMOTE_STATE_HANDSHAKE 0x0002 /* actual connection exists but no handshake yet */
#define WIIMOTE_STATE_HANDSHAKE_COMPLETE 0x0004 /* actual connection exists but no handshake yet */
#define WIIMOTE_STATE_CONNECTED 0x0008
#define WIIMOTE_STATE_RUMBLE 0x0010
#define WIIMOTE_STATE_ACC 0x0020
#define WIIMOTE_STATE_EXP 0x0040
#define WIIMOTE_STATE_IR 0x0080
#define WIIMOTE_STATE_SPEAKER 0x0100
#define WIIMOTE_STATE_IR_SENS_LVL1 0x0200
#define WIIMOTE_STATE_IR_SENS_LVL2 0x0400
#define WIIMOTE_STATE_IR_SENS_LVL3 0x0800
#define WIIMOTE_STATE_IR_SENS_LVL4 0x1000
#define WIIMOTE_STATE_IR_SENS_LVL5 0x2000
#define WIIMOTE_INIT_STATES (WIIMOTE_STATE_IR_SENS_LVL3)
/* macro to manage states */
#define WIIMOTE_IS_SET(wm, s) ((wm->state & (s)) == (s))
#define WIIMOTE_ENABLE_STATE(wm, s) (wm->state |= (s))
#define WIIMOTE_DISABLE_STATE(wm, s) (wm->state &= ~(s))
#define WIIMOTE_TOGGLE_STATE(wm, s) ((wm->state & (s)) ? WIIMOTE_DISABLE_STATE(wm, s) : WIIMOTE_ENABLE_STATE(wm, s))
@ -192,9 +243,11 @@
#define NUNCHUK_IS_FLAG_SET(wm, s) ((*(wm->flags) & (s)) == (s))
/* misc macros */
#define WIIMOTE_ID(wm) (wm->unid)
#define WIIMOTE_IS_CONNECTED(wm) (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_CONNECTED))
/*
* Largest known payload is 21 bytes.
* Add 1 (Win32) or 2 (Mac, *nix) for the prefix and round up to a power of 2.
*/
#define MAX_PAYLOAD 32
/*
* Smooth tilt calculations are computed with the
@ -207,20 +260,180 @@
#define SMOOTH_ROLL 0x01
#define SMOOTH_PITCH 0x02
/** @} */
#include "wiiuse.h"
/** @addtogroup internal_general */
/** @{ */
#define _STRINGIFY(s) _STRINGIFY_IMPL(s)
#define _STRINGIFY_IMPL(s) #s
/* wiiuse version, from public per-component version defines */
#define WIIUSE_VERSION _STRINGIFY(WIIUSE_MAJOR) "." _STRINGIFY(WIIUSE_MINOR) "." _STRINGIFY(WIIUSE_MICRO)
#ifdef _MSC_VER
# define INLINE_UTIL __inline
#else
# define INLINE_UTIL static inline
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* not part of the api */
int wiiuse_set_report_type(struct wiimote_t* wm);
void wiiuse_send_next_pending_read_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, unsigned short len);
/* not part of the api */
/** @brief Cross-platform call to sleep for at least the specified number
* of milliseconds.
*
* Use instead of Sleep(), usleep(), or similar functions.
* Defined in util.c
*/
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
/** @addtogroup betosystem Big-endian buffer to system-byte-order value
@{ */
/** @brief Given a buffer buf, copy and return a value of type uint8_t.
*/
uint8_t from_big_endian_uint8_t(byte * buf);
/** @brief Given a buffer buf, copy out a uint16_t, convert it from big-endian
to system byte order, and return it.
@note Requires that at least 2 bytes be available in buf, but does not
check this - it is your responsibility.
*/
uint16_t from_big_endian_uint16_t(byte * buf);
/** @brief Given a buffer buf, copy out a uint32_t, convert it from big-endian
to system byte order, and return it.
@note Requires that at least 4 bytes be available in buf, but does not
check this - it is your responsibility.
*/
uint32_t from_big_endian_uint32_t(byte * buf);
/** @} */
/** @addtogroup systemtobe System-byte-order value to big-endian buffer
@{
*/
/** @brief Copies the value val into the buffer buf.
@note Requires that at least 1 byte is available in buf, but does not
check this - it is your responsibility.
*/
void to_big_endian_uint8_t(byte * buf, uint8_t val);
/** @brief Converts the value val from system byte order to big endian,
and copies it into the given buffer starting at buf.
@note Requires that at least 2 bytes be available in buf, but does not
check this - it is your responsibility.
*/
void to_big_endian_uint16_t(byte * buf, uint16_t val);
/** @brief Converts the value val from system byte order to big endian,
and copies it into the given buffer starting at buf.
@note Requires that at least 4 bytes be available in buf, but does not
check this - it is your responsibility.
*/
void to_big_endian_uint32_t(byte * buf, uint32_t val);
/** @}
*/
/** @addtogroup bufferfunc Buffering functions
@brief These wrap around from/to_big_endian_TYPE, but take a byte** so that
they can advance the input/output pointer appropriately.
@{
*/
/** @brief Converts the value val from system byte order to big endian,
copies it into the given buffer starting at *buf, and advances buf by
sizeof(uint16_t).
*/
void buffer_big_endian_uint16_t(byte ** buf, uint16_t val);
/** @brief Given the address of a buffer pointer buf, copy out a uint16_t
from *buf, convert it from big-endian to system byte order, advance
buf by sizeof(uint16_t), and return the value retrieved.
*/
uint16_t unbuffer_big_endian_uint16_t(byte ** buf);
/** @sa buffer_big_endian_uint16_t()
*/
void buffer_big_endian_uint8_t(byte ** buf, uint8_t val);
/** @sa unbuffer_big_endian_uint8_t
*/
uint8_t unbuffer_big_endian_uint8_t(byte ** buf);
/** @sa buffer_big_endian_uint16_t
*/
void buffer_big_endian_uint32_t(byte ** buf, uint32_t val);
/** @sa unbuffer_big_endian_uint32_t
*/
uint8_t unbuffer_big_endian_uint32_t(byte ** buf)
/** @} */
#else /* this else is true when not in doxygen */
INLINE_UTIL void to_big_endian_uint8_t(byte * buf, uint8_t val) {
memcpy(buf, &val, 1);
}
INLINE_UTIL uint8_t from_big_endian_uint8_t(byte * buf) {
uint8_t beVal;
memcpy(&beVal, buf, 1);
return beVal;
}
#define WIIUSE_DECLARE_ENDIAN_CONVERSION_OPS(_TYPE, _TOBE, _FROMBE) \
INLINE_UTIL void to_big_endian_##_TYPE(byte * buf, _TYPE val) { \
_TYPE beVal = _TOBE(val); \
memcpy(buf, &beVal, sizeof(_TYPE)); \
} \
INLINE_UTIL _TYPE from_big_endian_##_TYPE(byte * buf) { \
_TYPE beVal; \
memcpy(&beVal, buf, sizeof(_TYPE)); \
return _FROMBE(beVal); \
}
WIIUSE_DECLARE_ENDIAN_CONVERSION_OPS(uint16_t, htons, ntohs)
WIIUSE_DECLARE_ENDIAN_CONVERSION_OPS(uint32_t, htonl, ntohl)
#undef WIIUSE_DECLARE_ENDIAN_CONVERSION_OPS
#define WIIUSE_DECLARE_BUFFERING_OPS(_TYPE) \
INLINE_UTIL void buffer_big_endian_##_TYPE (byte ** buf, _TYPE val) { \
to_big_endian_##_TYPE(*buf, val); \
*buf += sizeof(_TYPE); \
} \
INLINE_UTIL _TYPE unbuffer_big_endian_##_TYPE (byte ** buf) { \
byte * current = *buf; \
*buf += sizeof(_TYPE); \
return from_big_endian_##_TYPE(current); \
}
WIIUSE_DECLARE_BUFFERING_OPS(uint8_t)
WIIUSE_DECLARE_BUFFERING_OPS(uint16_t)
WIIUSE_DECLARE_BUFFERING_OPS(uint32_t)
#undef WIIUSE_DECLARE_BUFFERING_OPS
#endif /* not in doxygen */
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* WIIUSE_INTERNAL_H_INCLUDED */

View File

@ -0,0 +1,247 @@
// ISO C9x compliant stdint.h for Microsoft Visual Studio
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
//
// Copyright (c) 2006-2008 Alexander Chemeris
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. The name of the author may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef _MSC_VER // [
#error "Use this header only with Microsoft Visual C++ compilers!"
#endif // _MSC_VER ]
#ifndef _MSC_STDINT_H_ // [
#define _MSC_STDINT_H_
#if _MSC_VER > 1000
#pragma once
#endif
#include <limits.h>
// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
// or compiler give many errors like this:
// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
#ifdef __cplusplus
extern "C" {
#endif
# include <wchar.h>
#ifdef __cplusplus
}
#endif
// Define _W64 macros to mark types changing their size, like intptr_t.
#ifndef _W64
# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
# define _W64 __w64
# else
# define _W64
# endif
#endif
// 7.18.1 Integer types
// 7.18.1.1 Exact-width integer types
// Visual Studio 6 and Embedded Visual C++ 4 doesn't
// realize that, e.g. char has the same size as __int8
// so we give up on __intX for them.
#if (_MSC_VER < 1300)
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
#else
typedef signed __int8 int8_t;
typedef signed __int16 int16_t;
typedef signed __int32 int32_t;
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
#endif
typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;
// 7.18.1.2 Minimum-width integer types
typedef int8_t int_least8_t;
typedef int16_t int_least16_t;
typedef int32_t int_least32_t;
typedef int64_t int_least64_t;
typedef uint8_t uint_least8_t;
typedef uint16_t uint_least16_t;
typedef uint32_t uint_least32_t;
typedef uint64_t uint_least64_t;
// 7.18.1.3 Fastest minimum-width integer types
typedef int8_t int_fast8_t;
typedef int16_t int_fast16_t;
typedef int32_t int_fast32_t;
typedef int64_t int_fast64_t;
typedef uint8_t uint_fast8_t;
typedef uint16_t uint_fast16_t;
typedef uint32_t uint_fast32_t;
typedef uint64_t uint_fast64_t;
// 7.18.1.4 Integer types capable of holding object pointers
#ifdef _WIN64 // [
typedef signed __int64 intptr_t;
typedef unsigned __int64 uintptr_t;
#else // _WIN64 ][
typedef _W64 signed int intptr_t;
typedef _W64 unsigned int uintptr_t;
#endif // _WIN64 ]
// 7.18.1.5 Greatest-width integer types
typedef int64_t intmax_t;
typedef uint64_t uintmax_t;
// 7.18.2 Limits of specified-width integer types
#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
// 7.18.2.1 Limits of exact-width integer types
#define INT8_MIN ((int8_t)_I8_MIN)
#define INT8_MAX _I8_MAX
#define INT16_MIN ((int16_t)_I16_MIN)
#define INT16_MAX _I16_MAX
#define INT32_MIN ((int32_t)_I32_MIN)
#define INT32_MAX _I32_MAX
#define INT64_MIN ((int64_t)_I64_MIN)
#define INT64_MAX _I64_MAX
#define UINT8_MAX _UI8_MAX
#define UINT16_MAX _UI16_MAX
#define UINT32_MAX _UI32_MAX
#define UINT64_MAX _UI64_MAX
// 7.18.2.2 Limits of minimum-width integer types
#define INT_LEAST8_MIN INT8_MIN
#define INT_LEAST8_MAX INT8_MAX
#define INT_LEAST16_MIN INT16_MIN
#define INT_LEAST16_MAX INT16_MAX
#define INT_LEAST32_MIN INT32_MIN
#define INT_LEAST32_MAX INT32_MAX
#define INT_LEAST64_MIN INT64_MIN
#define INT_LEAST64_MAX INT64_MAX
#define UINT_LEAST8_MAX UINT8_MAX
#define UINT_LEAST16_MAX UINT16_MAX
#define UINT_LEAST32_MAX UINT32_MAX
#define UINT_LEAST64_MAX UINT64_MAX
// 7.18.2.3 Limits of fastest minimum-width integer types
#define INT_FAST8_MIN INT8_MIN
#define INT_FAST8_MAX INT8_MAX
#define INT_FAST16_MIN INT16_MIN
#define INT_FAST16_MAX INT16_MAX
#define INT_FAST32_MIN INT32_MIN
#define INT_FAST32_MAX INT32_MAX
#define INT_FAST64_MIN INT64_MIN
#define INT_FAST64_MAX INT64_MAX
#define UINT_FAST8_MAX UINT8_MAX
#define UINT_FAST16_MAX UINT16_MAX
#define UINT_FAST32_MAX UINT32_MAX
#define UINT_FAST64_MAX UINT64_MAX
// 7.18.2.4 Limits of integer types capable of holding object pointers
#ifdef _WIN64 // [
# define INTPTR_MIN INT64_MIN
# define INTPTR_MAX INT64_MAX
# define UINTPTR_MAX UINT64_MAX
#else // _WIN64 ][
# define INTPTR_MIN INT32_MIN
# define INTPTR_MAX INT32_MAX
# define UINTPTR_MAX UINT32_MAX
#endif // _WIN64 ]
// 7.18.2.5 Limits of greatest-width integer types
#define INTMAX_MIN INT64_MIN
#define INTMAX_MAX INT64_MAX
#define UINTMAX_MAX UINT64_MAX
// 7.18.3 Limits of other integer types
#ifdef _WIN64 // [
# define PTRDIFF_MIN _I64_MIN
# define PTRDIFF_MAX _I64_MAX
#else // _WIN64 ][
# define PTRDIFF_MIN _I32_MIN
# define PTRDIFF_MAX _I32_MAX
#endif // _WIN64 ]
#define SIG_ATOMIC_MIN INT_MIN
#define SIG_ATOMIC_MAX INT_MAX
#ifndef SIZE_MAX // [
# ifdef _WIN64 // [
# define SIZE_MAX _UI64_MAX
# else // _WIN64 ][
# define SIZE_MAX _UI32_MAX
# endif // _WIN64 ]
#endif // SIZE_MAX ]
// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
#ifndef WCHAR_MIN // [
# define WCHAR_MIN 0
#endif // WCHAR_MIN ]
#ifndef WCHAR_MAX // [
# define WCHAR_MAX _UI16_MAX
#endif // WCHAR_MAX ]
#define WINT_MIN 0
#define WINT_MAX _UI16_MAX
#endif // __STDC_LIMIT_MACROS ]
// 7.18.4 Limits of other integer types
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
// 7.18.4.1 Macros for minimum-width integer constants
#define INT8_C(val) val##i8
#define INT16_C(val) val##i16
#define INT32_C(val) val##i32
#define INT64_C(val) val##i64
#define UINT8_C(val) val##ui8
#define UINT16_C(val) val##ui16
#define UINT32_C(val) val##ui32
#define UINT64_C(val) val##ui64
// 7.18.4.2 Macros for greatest-width integer constants
#define INTMAX_C INT64_C
#define UINTMAX_C UINT64_C
#endif // __STDC_CONSTANT_MACROS ]
#endif // _MSC_STDINT_H_ ]