Updated to wiiuse fork from https://github.com/rpavlik/wiiuse
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:
parent
8e44df338c
commit
7935c687c7
@ -11,4 +11,7 @@ add_library(wiiuse
|
||||
ir.c
|
||||
nunchuk.c
|
||||
wiiuse.c
|
||||
wiiboard.c
|
||||
motion_plus.c
|
||||
util.c
|
||||
)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
51
lib/wiiuse/definitions_os.h
Normal file
51
lib/wiiuse/definitions_os.h
Normal 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 */
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
371
lib/wiiuse/io.c
371
lib/wiiuse/io.c
@ -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
|
||||
|
@ -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 */
|
||||
|
455
lib/wiiuse/ir.c
455
lib/wiiuse/ir.c
@ -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));
|
||||
}
|
||||
|
@ -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
338
lib/wiiuse/motion_plus.c
Normal 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
60
lib/wiiuse/motion_plus.h
Normal 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
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
92
lib/wiiuse/os_mac/os_mac.h
Normal file
92
lib/wiiuse/os_mac/os_mac.h
Normal 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
351
lib/wiiuse/os_mac/os_mac.m
Normal 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__
|
240
lib/wiiuse/os_mac/os_mac_find.m
Normal file
240
lib/wiiuse/os_mac/os_mac_find.m
Normal 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__
|
222
lib/wiiuse/os_mac/os_mac_interface.m
Normal file
222
lib/wiiuse/os_mac/os_mac_interface.m
Normal 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
387
lib/wiiuse/os_nix.c
Normal 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
326
lib/wiiuse/os_win.c
Normal 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
49
lib/wiiuse/util.c
Normal 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
146
lib/wiiuse/wiiboard.c
Normal 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
55
lib/wiiuse/wiiboard.h
Normal 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
|
@ -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
|
||||
}
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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 */
|
||||
|
247
lib/wiiuse/wiiuse_msvcstdint.h
Normal file
247
lib/wiiuse/wiiuse_msvcstdint.h
Normal 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_ ]
|
Loading…
x
Reference in New Issue
Block a user