WIP: checkpoint Wii native IMU and upstream IR bridge

Pause Wii pointing work with firmware 0.33-wii-trace installed. Preserve the pinned libogc IR pipeline, calibrated native IMU, software BOOTSEL, and standard camera sensitivity trial.

Tracking instability, tracking loss, and ineffective vertical movement remain unresolved. Level-2 camera filtering is not hardware-qualified. Nine targeted regression tests pass; firmware and persistent storage were verified after flashing.
This commit is contained in:
Joey Yakimowich-Payne 2026-09-11 17:05:54 -06:00
commit 9f6dddb790
41 changed files with 7990 additions and 150 deletions

View file

@ -0,0 +1,55 @@
#ifndef __DEFINITIONS_H__
#define __DEFINITIONS_H__
#include "os.h"
#define WIIMOTE_PI 3.14159265f
//#define WITH_WIIUSE_DEBUG
/* Error output macros */
#define WIIUSE_ERROR(fmt, ...) fprintf(stderr, "[ERROR] " fmt "\n", ##__VA_ARGS__)
/* Warning output macros */
#define WIIUSE_WARNING(fmt, ...) fprintf(stderr, "[WARNING] " fmt "\n", ##__VA_ARGS__)
/* Information output macros */
#define WIIUSE_INFO(fmt, ...) fprintf(stderr, "[INFO] " fmt "\n", ##__VA_ARGS__)
#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__); \
} while (0)
#else
#define WIIUSE_DEBUG(fmt, ...) fprintf(stderr, "[DEBUG] " __FILE__ ":%i: " fmt "\n", __LINE__, ##__VA_ARGS__)
#endif
#else
#define WIIUSE_DEBUG(fmt, ...)
#endif
#if 1
#define WII_DEBUG(fmt, ...) do { \
printf("[WDEBUG] " __FILE__ ":%i: " fmt "\n", __LINE__, ##__VA_ARGS__); \
usleep(3000000); \
} while (0)
#else
#define WII_DEBUG(fmt, ...)
#endif
/* Convert between radians and degrees */
#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

834
external/libogc_ir/upstream/ir.c vendored Normal file
View file

@ -0,0 +1,834 @@
#include <stdio.h>
#include <math.h>
#include <time.h>
#ifndef WIN32
#include <unistd.h>
#endif
#ifdef GEKKO
#include <ogcsys.h>
#endif
#include "definitions.h"
#include "wiiuse_internal.h"
#include "ir.h"
static int ir_correct_for_bounds(float* x, float* y, enum aspect_t aspect, int offset_x, int offset_y);
static void ir_convert_to_vres(float* x, float* y, enum aspect_t aspect, unsigned int vx, unsigned int vy);
/**
* @brief Get the IR sensitivity settings.
*
* @param wm Pointer to a wiimote_t structure.
* @param block1 [out] Pointer to where block1 will be set.
* @param block2 [out] Pointer to where block2 will be set.
*
* @return Returns the sensitivity level.
*/
static int get_ir_sens(struct wiimote_t* wm, char** block1, char** block2) {
if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR_SENS_LVL1)) {
*block1 = WM_IR_BLOCK1_LEVEL1;
*block2 = WM_IR_BLOCK2_LEVEL1;
return 1;
} else if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR_SENS_LVL2)) {
*block1 = WM_IR_BLOCK1_LEVEL2;
*block2 = WM_IR_BLOCK2_LEVEL2;
return 2;
} else if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR_SENS_LVL3)) {
*block1 = WM_IR_BLOCK1_LEVEL3;
*block2 = WM_IR_BLOCK2_LEVEL3;
return 3;
} else if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR_SENS_LVL4)) {
*block1 = WM_IR_BLOCK1_LEVEL4;
*block2 = WM_IR_BLOCK2_LEVEL4;
return 4;
} else if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR_SENS_LVL5)) {
*block1 = WM_IR_BLOCK1_LEVEL5;
*block2 = WM_IR_BLOCK2_LEVEL5;
return 5;
}
*block1 = NULL;
*block2 = NULL;
return 0;
}
static void rotate_dots(struct fdot_t* in, struct fdot_t *out, int count, float ang) {
float s, c;
int i;
if (ang == 0) {
for (i = 0; i < count; ++i) {
out[i].x = in[i].x;
out[i].y = in[i].y;
}
return;
}
s = sin(DEGREE_TO_RAD(ang));
c = cos(DEGREE_TO_RAD(ang));
/*
* [ cos(theta) -sin(theta) ][ ir->rx ]
* [ sin(theta) cos(theta) ][ ir->ry ]
*/
for (i = 0; i < count; ++i) {
out[i].x = (c * in[i].x) + (-s * in[i].y);
out[i].y = (s * in[i].x) + (c * in[i].y);
}
}
/**
* @brief Correct for the IR bounding box.
*
* @param x [out] The current X, it will be updated if valid.
* @param y [out] The current Y, it will be updated if valid.
* @param aspect Aspect ratio of the screen.
* @param offset_x The X offset of the bounding box.
* @param offset_y The Y offset of the bounding box.
*
* @return Returns 1 if the point is valid and was updated.
*
* Nintendo was smart with this bit. They sacrifice a little
* precision for a big increase in usability.
*/
static int ir_correct_for_bounds(float* x, float* y, enum aspect_t aspect, int offset_x, int offset_y) {
float x0, y0;
int xs, ys;
if (aspect == WIIUSE_ASPECT_16_9) {
xs = WM_ASPECT_16_9_X;
ys = WM_ASPECT_16_9_Y;
} else {
xs = WM_ASPECT_4_3_X;
ys = WM_ASPECT_4_3_Y;
}
x0 = ((1024 - xs) / 2) + offset_x;
y0 = ((768 - ys) / 2) + offset_y;
if ((*x >= x0)
&& (*x <= (x0 + xs))
&& (*y >= y0)
&& (*y <= (y0 + ys)))
{
*x -= offset_x;
*y -= offset_y;
return 1;
}
return 0;
}
/**
* @brief Interpolate the point to the user defined virtual screen resolution.
*/
static void ir_convert_to_vres(float* x, float* y, enum aspect_t aspect, unsigned int vx, unsigned int vy) {
int xs, ys;
if (aspect == WIIUSE_ASPECT_16_9) {
xs = WM_ASPECT_16_9_X;
ys = WM_ASPECT_16_9_Y;
} else {
xs = WM_ASPECT_4_3_X;
ys = WM_ASPECT_4_3_Y;
}
*x -= ((1024-xs)/2);
*y -= ((768-ys)/2);
*x = (*x / (float)xs) * vx;
*y = (*y / (float)ys) * vy;
}
void wiiuse_set_ir_mode(struct wiimote_t *wm)
{
ubyte 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, NULL);
}
void wiiuse_set_ir(struct wiimote_t *wm,int status)
{
ubyte buf = 0x00;
int ir_level = 0;
char* block1 = NULL;
char* block2 = NULL;
if(!wm) return;
/*
* Wait for the handshake to finish first.
* When it handshake finishes and sees that
* IR is enabled, it will call this function
* 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.\n");
if(status)
WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_INIT);
else
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR_INIT);
return;
}
/*
* Check to make sure a sensitivity setting is selected.
*/
ir_level = get_ir_sens(wm, &block1, &block2);
if (!ir_level) {
WIIUSE_ERROR("No IR sensitivity setting selected.");
return;
}
if (status) {
/* if already enabled then stop */
if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR) || WIIMOTE_IS_SET(wm, WIIMOTE_STATE_WIIU_PRO)) {
wiiuse_status(wm,NULL);
return;
}
} else {
/* if already disabled then stop */
if (!WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) {
wiiuse_status(wm,NULL);
return;
}
}
buf = (status ? 0x04 : 0x00);
wiiuse_sendcmd(wm,WM_CMD_IR,&buf,1,NULL);
wiiuse_sendcmd(wm,WM_CMD_IR_2,&buf,1,NULL);
if (!status) {
WIIUSE_DEBUG("Disabled IR cameras for wiimote id %i.", wm->unid);
wiiuse_status(wm,NULL);
return;
}
/* enable IR, set sensitivity */
buf = 0x08;
wiiuse_write_data(wm,WM_REG_IR,&buf,1,NULL);
wiiuse_write_data(wm, WM_REG_IR_BLOCK1, (ubyte*)block1, 9, NULL);
wiiuse_write_data(wm, WM_REG_IR_BLOCK2, (ubyte*)block2, 2, NULL);
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, NULL);
wiiuse_status(wm,NULL);
return;
}
/**
* @brief Set the virtual screen resolution for IR tracking.
*
* @param wm Pointer to a wiimote_t structure.
* @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;
wm->ir.vres[0] = (x-1);
wm->ir.vres[1] = (y-1);
}
/**
* @brief Set the XY position for the IR cursor.
*
* @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;
wm->ir.pos = pos;
switch (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;
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 + 70;
else if (wm->ir.aspect == WIIUSE_ASPECT_4_3)
wm->ir.offset[1] = -WM_ASPECT_4_3_Y/2 + 100;
return;
default:
return;
};
}
/**
* @brief Set the aspect ratio of the TV/monitor.
*
* @param wm Pointer to a wiimote_t structure.
* @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;
wm->ir.aspect = aspect;
if (aspect == WIIUSE_ASPECT_4_3) {
wm->ir.vres[0] = WM_ASPECT_4_3_X;
wm->ir.vres[1] = WM_ASPECT_4_3_Y;
} else {
wm->ir.vres[0] = WM_ASPECT_16_9_X;
wm->ir.vres[1] = WM_ASPECT_16_9_Y;
}
/* reset the position offsets */
wiiuse_set_ir_position(wm, wm->ir.pos);
}
/**
* @brief Set the IR sensitivity.
*
* @param wm Pointer to a wiimote_t structure.
* @param level 1-5, same as Wii system sensitivity setting.
*
* If the level is < 1, then level will be set to 1.
* 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;
if (!wm) return;
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));
switch (level) {
case 1:
WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL1);
break;
case 2:
WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL2);
break;
case 3:
WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL3);
break;
case 4:
WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL4);
break;
case 5:
WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL5);
break;
default:
return;
}
if(!WIIMOTE_IS_SET(wm,WIIMOTE_STATE_IR)) return;
/* set the new sensitivity */
get_ir_sens(wm, &block1, &block2);
wiiuse_write_data(wm, WM_REG_IR_BLOCK1, (ubyte*)block1, 9,NULL);
wiiuse_write_data(wm, WM_REG_IR_BLOCK2, (ubyte*)block2, 2,NULL);
WIIUSE_DEBUG("Set IR sensitivity to level %i (unid %i)", level, wm->unid);
}
/**
* @brief Calculate the data from the IR spots. Basic IR mode.
*
* @param wm Pointer to a wiimote_t structure.
* @param data Data returned by the wiimote for the IR spots.
*/
void calculate_basic_ir(struct wiimote_t* wm, ubyte* data) {
struct ir_dot_t* dot = wm->ir.dot;
int i;
dot[0].rx = 1023 - (data[0] | ((data[2] & 0x30) << 4));
dot[0].ry = data[1] | ((data[2] & 0xC0) << 2);
dot[1].rx = 1023 - (data[3] | ((data[2] & 0x03) << 8));
dot[1].ry = data[4] | ((data[2] & 0x0C) << 6);
dot[2].rx = 1023 - (data[5] | ((data[7] & 0x30) << 4));
dot[2].ry = data[6] | ((data[7] & 0xC0) << 2);
dot[3].rx = 1023 - (data[8] | ((data[7] & 0x03) << 8));
dot[3].ry = data[9] | ((data[7] & 0x0C) << 6);
/* set each IR spot to visible if spot is in range */
for (i = 0; i < 4; ++i) {
dot[i].rx = BIG_ENDIAN_SHORT(dot[i].rx);
dot[i].ry = BIG_ENDIAN_SHORT(dot[i].ry);
if (dot[i].ry == 1023)
dot[i].visible = 0;
else {
dot[i].visible = 1;
dot[i].size = 0; /* since we don't know the size, set it as 0 */
}
}
#ifndef GEKKO
interpret_ir_data(&wm->ir,&wm->orient,WIIMOTE_IS_SET(wm, WIIMOTE_STATE_ACC));
#endif
}
/**
* @brief Calculate the data from the IR spots. Extended IR mode.
*
* @param wm Pointer to a wiimote_t structure.
* @param data Data returned by the wiimote for the IR spots.
*/
void calculate_extended_ir(struct wiimote_t* wm, ubyte* data) {
struct ir_dot_t* dot = wm->ir.dot;
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].size = data[(3*i)+2];
dot[i].rx = BIG_ENDIAN_SHORT(dot[i].rx);
dot[i].ry = BIG_ENDIAN_SHORT(dot[i].ry);
dot[i].size = dot[i].size&0x0f;
/* if in range set to visible */
if (dot[i].ry == 1023)
dot[i].visible = 0;
else
dot[i].visible = 1;
}
#ifndef GEKKO
interpret_ir_data(&wm->ir,&wm->orient,WIIMOTE_IS_SET(wm, WIIMOTE_STATE_ACC));
#endif
}
enum {
IR_STATE_DEAD = 0,
IR_STATE_GOOD,
IR_STATE_SINGLE,
IR_STATE_LOST,
};
// half-height of the IR sensor if half-width is 1
#define HEIGHT (384.0f / 512.0f)
// maximum sensor bar slope (tan(35 degrees))
#define MAX_SB_SLOPE 0.7f
// minimum sensor bar width in view, relative to half of the IR sensor area
#define MIN_SB_WIDTH 0.1f
// reject "sensor bars" that happen to have a dot towards the middle
#define SB_MIDDOT_REJECT 0.05f
// physical dimensions
// cm center to center of emitters
#define SB_WIDTH 19.5f
// half-width in cm of emitters
#define SB_DOT_WIDTH 2.25f
// half-height in cm of emitters (with some tolerance)
#define SB_DOT_HEIGHT 1.0f
#define SB_DOT_WIDTH_RATIO (SB_DOT_WIDTH / SB_WIDTH)
#define SB_DOT_HEIGHT_RATIO (SB_DOT_HEIGHT / SB_WIDTH)
// dots further out than these coords are allowed to not be picked up
// otherwise assume something's wrong
//#define SB_OFF_SCREEN_X 0.8f
//#define SB_OFF_SCREEN_Y (0.8f * HEIGHT)
// disable, may be doing more harm than good due to sensor pickup glitches
#define SB_OFF_SCREEN_X 0.0f
#define SB_OFF_SCREEN_Y 0.0f
// if a point is closer than this to one of the previous SB points
// when it reappears, consider it the same instead of trying to guess
// which one of the two it is
#define SB_SINGLE_NOGUESS_DISTANCE (100.0 * 100.0)
// width of the sensor bar in pixels at one meter from the Wiimote
#define SB_Z_COEFFICIENT 256.0f
// distance in meters from the center of the FOV to the left or right edge,
// when the wiimote is at one meter
#define WIIMOTE_FOV_COEFFICIENT 0.39f
#define SQUARED(x) ((x)*(x))
#define WMAX(x,y) ((x>y)?(x):(y))
#define WMIN(x,y) ((x<y)?(x):(y))
/**
* @brief Interpret IR data into more user friendly variables.
*
* @param wm Pointer to a wiimote_t structure.
*/
void find_sensorbar(struct ir_t* ir, struct orient_t *orient) {
struct fdot_t dots[4];
struct fdot_t acc_dots[4];
struct sb_t cand;
struct sb_t candidates[6];
struct sb_t sb;
fdot_t difference;
int num_candidates = 0;
int i;
int j;
int first, second;
WIIUSE_DEBUG("IR: orient angle: %.02f\n",orient->roll);
/* count visible dots and populate dots structure */
/* dots[] is in -1..1 units for width */
ir->num_dots = 0;
for (i = 0; i < 4; i++) {
if (ir->dot[i].visible) {
dots[ir->num_dots].x = (ir->dot[i].rx - 512.0f) / 512.0f;
dots[ir->num_dots].y = (ir->dot[i].ry - 384.0f) / 512.0f;
WIIUSE_DEBUG("IR: dot %d at (%d,%d) (%.03f,%.03f)\n",ir->num_dots,ir->dot[i].rx,ir->dot[i].ry,dots[ir->num_dots].x,dots[ir->num_dots].y);
ir->num_dots++;
}
}
WIIUSE_DEBUG("IR: found %d dots\n",ir->num_dots);
// nothing to track
if(ir->num_dots == 0) {
if(ir->state != IR_STATE_DEAD)
ir->state = IR_STATE_LOST;
ir->ax = 0;
ir->ay = 0;
ir->distance = 0.0f;
ir->raw_valid = 0;
return;
}
/* ==== Find the Sensor Bar ==== */
// first rotate according to accelerometer orientation
rotate_dots(dots, acc_dots, ir->num_dots, orient->roll);
if(ir->num_dots > 1) {
WIIUSE_DEBUG("IR: locating sensor bar candidates\n");
// iterate through all dot pairs
for(first=0; first < (ir->num_dots-1); first++) {
for(second=(first+1); second < ir->num_dots; second++) {
WIIUSE_DEBUG("IR: trying dots %d and %d\n",first,second);
// order the dots leftmost first into cand
// storing both the raw dots and the accel-rotated dots
if(acc_dots[first].x > acc_dots[second].x) {
cand.dots[0] = dots[second];
cand.dots[1] = dots[first];
cand.acc_dots[0] = acc_dots[second];
cand.acc_dots[1] = acc_dots[first];
} else {
cand.dots[0] = dots[first];
cand.dots[1] = dots[second];
cand.acc_dots[0] = acc_dots[first];
cand.acc_dots[1] = acc_dots[second];
}
difference.x = cand.acc_dots[1].x - cand.acc_dots[0].x;
difference.y = cand.acc_dots[1].y - cand.acc_dots[0].y;
// check angle
if(fabsf(difference.y / difference.x) > MAX_SB_SLOPE)
continue;
WIIUSE_DEBUG("IR: passed angle check\n");
// rotate to the true sensor bar angle
cand.off_angle = -RAD_TO_DEGREE(atan2(difference.y, difference.x));
cand.angle = cand.off_angle + orient->roll;
rotate_dots(cand.dots, cand.rot_dots, 2, cand.angle);
WIIUSE_DEBUG("IR: off_angle: %.02f, angle: %.02f\n", cand.off_angle, cand.angle);
// recalculate x distance - y should be zero now, so ignore it
difference.x = cand.rot_dots[1].x - cand.rot_dots[0].x;
// check distance
if(difference.x < MIN_SB_WIDTH)
continue;
// middle dot check. If there's another source somewhere in the
// middle of this candidate, then this can't be a sensor bar
for(i=0; i<ir->num_dots; i++) {
float wadj, hadj;
struct fdot_t tdot;
if(i==first || i==second) continue;
hadj = SB_DOT_HEIGHT_RATIO * difference.x;
wadj = SB_DOT_WIDTH_RATIO * difference.x;
rotate_dots(&dots[i], &tdot, 1, cand.angle);
if( ((cand.rot_dots[0].x + wadj) < tdot.x) &&
((cand.rot_dots[1].x - wadj) > tdot.x) &&
((cand.rot_dots[0].y + hadj) > tdot.y) &&
((cand.rot_dots[0].y - hadj) < tdot.y))
break;
}
// failed middle dot check
if(i < ir->num_dots) continue;
WIIUSE_DEBUG("IR: passed middle dot check\n");
cand.score = 1 / (cand.rot_dots[1].x - cand.rot_dots[0].x);
// we have a candidate, store it
WIIUSE_DEBUG("IR: new candidate %d\n",num_candidates);
candidates[num_candidates++] = cand;
}
}
}
if(num_candidates == 0) {
int closest = -1;
int closest_to = 0;
float best = 999.0f;
float d;
float dx[2];
struct sb_t sbx[2];
// no sensor bar candidates, try to work with a lone dot
WIIUSE_DEBUG("IR: no candidates\n");
switch(ir->state) {
case IR_STATE_DEAD:
WIIUSE_DEBUG("IR: we're dead\n");
// we've never seen a sensor bar before, so we're screwed
ir->ax = 0.0f;
ir->ay = 0.0f;
ir->distance = 0.0f;
ir->raw_valid = 0;
return;
case IR_STATE_GOOD:
case IR_STATE_SINGLE:
case IR_STATE_LOST:
WIIUSE_DEBUG("IR: trying to keep track of single dot\n");
// try to find the dot closest to the previous sensor bar position
for(i=0; i<ir->num_dots; i++) {
WIIUSE_DEBUG("IR: checking dot %d (%.02f, %.02f)\n",i, acc_dots[i].x,acc_dots[i].y);
for(j=0; j<2; j++) {
WIIUSE_DEBUG(" to dot %d (%.02f, %.02f)\n",j, ir->sensorbar.acc_dots[j].x,ir->sensorbar.acc_dots[j].y);
d = SQUARED(acc_dots[i].x - ir->sensorbar.acc_dots[j].x);
d += SQUARED(acc_dots[i].y - ir->sensorbar.acc_dots[j].y);
if(d < best) {
best = d;
closest_to = j;
closest = i;
}
}
}
WIIUSE_DEBUG("IR: closest dot is %d to %d\n",closest,closest_to);
if(ir->state != IR_STATE_LOST || best < SB_SINGLE_NOGUESS_DISTANCE) {
// now work out where the other dot would be, in the acc frame
sb.acc_dots[closest_to] = acc_dots[closest];
sb.acc_dots[closest_to^1].x = ir->sensorbar.acc_dots[closest_to^1].x - ir->sensorbar.acc_dots[closest_to].x + acc_dots[closest].x;
sb.acc_dots[closest_to^1].y = ir->sensorbar.acc_dots[closest_to^1].y - ir->sensorbar.acc_dots[closest_to].y + acc_dots[closest].y;
// get the raw frame
rotate_dots(sb.acc_dots, sb.dots, 2, -orient->roll);
if((fabsf(sb.dots[closest_to^1].x) < SB_OFF_SCREEN_X) && (fabsf(sb.dots[closest_to^1].y) < SB_OFF_SCREEN_Y)) {
// this dot should be visible but isn't, since the candidate section failed.
// fall through and try to pick out the sensor bar without previous information
WIIUSE_DEBUG("IR: dot falls on screen, falling through\n");
} else {
// calculate the rotated dots frame
// angle tends to drift, so recalculate
sb.off_angle = -RAD_TO_DEGREE(atan2(sb.acc_dots[1].y - sb.acc_dots[0].y, sb.acc_dots[1].x - sb.acc_dots[0].x));
sb.angle = ir->sensorbar.off_angle + orient->roll;
rotate_dots(sb.acc_dots, sb.rot_dots, 2, ir->sensorbar.off_angle);
WIIUSE_DEBUG("IR: kept track of single dot\n");
break;
}
} else {
WIIUSE_DEBUG("IR: lost the dot and new one is too far away\n");
}
// try to find the dot closest to the sensor edge
WIIUSE_DEBUG("IR: trying to find best dot\n");
for(i=0; i<ir->num_dots; i++) {
d = WMIN(1.0f - fabsf(dots[i].x), HEIGHT - fabsf(dots[i].y));
if(d < best) {
best = d;
closest = i;
}
}
WIIUSE_DEBUG("IR: best dot: %d\n",closest);
// now try it as both places in the sensor bar
// and pick the one that places the other dot furthest off-screen
for(i=0; i<2; i++) {
sbx[i].acc_dots[i] = acc_dots[closest];
sbx[i].acc_dots[i^1].x = ir->sensorbar.acc_dots[i^1].x - ir->sensorbar.acc_dots[i].x + acc_dots[closest].x;
sbx[i].acc_dots[i^1].y = ir->sensorbar.acc_dots[i^1].y - ir->sensorbar.acc_dots[i].y + acc_dots[closest].y;
rotate_dots(sbx[i].acc_dots, sbx[i].dots, 2, -orient->roll);
dx[i] = WMAX(fabsf(sbx[i].dots[i^1].x),fabsf(sbx[i].dots[i^1].y / HEIGHT));
}
if(dx[0] > dx[1]) {
WIIUSE_DEBUG("IR: dot is LEFT: %.02f > %.02f\n",dx[0],dx[1]);
sb = sbx[0];
} else {
WIIUSE_DEBUG("IR: dot is RIGHT: %.02f < %.02f\n",dx[0],dx[1]);
sb = sbx[1];
}
// angle tends to drift, so recalculate
sb.off_angle = -RAD_TO_DEGREE(atan2(sb.acc_dots[1].y - sb.acc_dots[0].y, sb.acc_dots[1].x - sb.acc_dots[0].x));
sb.angle = ir->sensorbar.off_angle + orient->roll;
rotate_dots(sb.acc_dots, sb.rot_dots, 2, ir->sensorbar.off_angle);
WIIUSE_DEBUG("IR: found new dot to track\n");
break;
}
sb.score = 0;
ir->state = IR_STATE_SINGLE;
} else {
int bestidx = 0;
float best = 0.0f;
WIIUSE_DEBUG("IR: finding best candidate\n");
// look for the best candidate
// for now, the formula is simple: pick the one with the smallest distance
for(i=0; i<num_candidates; i++) {
if(candidates[i].score > best) {
bestidx = i;
best = candidates[i].score;
}
}
WIIUSE_DEBUG("IR: best candidate: %d\n",bestidx);
sb = candidates[bestidx];
ir->state = IR_STATE_GOOD;
}
ir->raw_valid = 1;
ir->ax = ((sb.rot_dots[0].x + sb.rot_dots[1].x) / 2) * 512.0 + 512.0;
ir->ay = ((sb.rot_dots[0].y + sb.rot_dots[1].y) / 2) * 512.0 + 384.0;
ir->sensorbar = sb;
ir->distance = (sb.rot_dots[1].x - sb.rot_dots[0].x) * 512.0;
}
#define SMOOTH_IR_RADIUS 8.0f
#define SMOOTH_IR_SPEED 0.25f
#define SMOOTH_IR_DEADZONE 2.5f
/**
* @brief Smooth the IR pointer position
*
* @param ir Pointer to an ir_t structure.
*/
void apply_ir_smoothing(struct ir_t *ir) {
f32 dx, dy, d, theta;
WIIUSE_DEBUG("Smooth: OK (%.02f, %.02f) LAST (%.02f, %.02f) ", ir->ax, ir->ay, ir->sx, ir->sy);
dx = ir->ax - ir->sx;
dy = ir->ay - ir->sy;
d = sqrtf(dx*dx + dy*dy);
if (d > SMOOTH_IR_DEADZONE) {
if (d < SMOOTH_IR_RADIUS) {
WIIUSE_DEBUG("INSIDE\n");
ir->sx += dx * SMOOTH_IR_SPEED;
ir->sy += dy * SMOOTH_IR_SPEED;
} else {
WIIUSE_DEBUG("OUTSIDE\n");
theta = atan2f(dy, dx);
ir->sx = ir->ax - cosf(theta) * SMOOTH_IR_RADIUS;
ir->sy = ir->ay - sinf(theta) * SMOOTH_IR_RADIUS;
}
} else {
WIIUSE_DEBUG("DEADZONE\n");
}
}
// max number of errors before cooked data drops out
#define ERROR_MAX_COUNT 8
// max number of glitches before cooked data updates
#define GLITCH_MAX_COUNT 5
// squared delta over which we consider something a glitch
#define GLITCH_DIST (150.0f * 150.0f)
/**
* @brief Interpret IR data into more user friendly variables.
*
* @param ir Pointer to an ir_t structure.
* @param orient Pointer to an orient_t structure.
*/
void interpret_ir_data(struct ir_t* ir, struct orient_t *orient) {
float x,y;
float d;
find_sensorbar(ir, orient);
if(ir->raw_valid) {
ir->angle = ir->sensorbar.angle;
ir->z = SB_Z_COEFFICIENT / ir->distance;
orient->yaw = calc_yaw(ir);
if(ir->error_cnt >= ERROR_MAX_COUNT) {
ir->sx = ir->ax;
ir->sy = ir->ay;
ir->glitch_cnt = 0;
} else {
d = SQUARED(ir->ax - ir->sx) + SQUARED(ir->ay - ir->sy);
if(d > GLITCH_DIST) {
if(ir->glitch_cnt > GLITCH_MAX_COUNT) {
apply_ir_smoothing(ir);
ir->glitch_cnt = 0;
} else {
ir->glitch_cnt++;
}
} else {
ir->glitch_cnt = 0;
apply_ir_smoothing(ir);
}
}
ir->smooth_valid = 1;
ir->error_cnt = 0;
} else {
if(ir->error_cnt >= ERROR_MAX_COUNT) {
ir->smooth_valid = 0;
} else {
ir->smooth_valid = 1;
ir->error_cnt++;
}
}
if(ir->smooth_valid) {
x = ir->sx;
y = ir->sy;
if (ir_correct_for_bounds(&x, &y, ir->aspect, ir->offset[0], ir->offset[1])) {
ir_convert_to_vres(&x, &y, ir->aspect, ir->vres[0], ir->vres[1]);
ir->x = x;
ir->y = y;
ir->valid = 1;
} else {
ir->valid = 0;
}
} else {
ir->valid = 0;
}
}
/**
* @brief Calculate yaw given the IR data.
*
* @param ir IR data structure.
*/
float calc_yaw(struct ir_t* ir) {
float x;
x = ir->ax - 512;
x *= WIIMOTE_FOV_COEFFICIENT / 512.0;
return RAD_TO_DEGREE( atanf(x) );
}

22
external/libogc_ir/upstream/ir.h vendored Normal file
View file

@ -0,0 +1,22 @@
#ifndef __IR_H__
#define __IR_H__
#include "wiiuse_internal.h"
#define WII_VRES_X 560
#define WII_VRES_Y 340
#ifdef __cplusplus
extern "C" {
#endif
void calculate_basic_ir(struct wiimote_t* wm, ubyte* data);
void calculate_extended_ir(struct wiimote_t* wm, ubyte* data);
float calc_yaw(struct ir_t* ir);
void interpret_ir_data(struct ir_t* ir, struct orient_t *orient);
#ifdef __cplusplus
}
#endif
#endif

748
external/libogc_ir/upstream/wiiuse.h vendored Normal file
View file

@ -0,0 +1,748 @@
#ifndef __WIIUSE_H__
#define __WIIUSE_H__
#if defined(_WIN32)
/* windows */
#include <windows.h>
#elif defined(GEKKO)
/* wii */
#include <bte/bte.h>
#elif defined(__linux__)
/* nix */
#include <bluetooth/bluetooth.h>
#endif
#ifdef WIIUSE_INTERNAL_H_INCLUDED
#define WCONST
#else
#define WCONST const
#endif
/* 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 */
#define WIIMOTE_BUTTON_TWO 0x0001
#define WIIMOTE_BUTTON_ONE 0x0002
#define WIIMOTE_BUTTON_B 0x0004
#define WIIMOTE_BUTTON_A 0x0008
#define WIIMOTE_BUTTON_MINUS 0x0010
#define WIIMOTE_BUTTON_ZACCEL_BIT6 0x0020
#define WIIMOTE_BUTTON_ZACCEL_BIT7 0x0040
#define WIIMOTE_BUTTON_HOME 0x0080
#define WIIMOTE_BUTTON_LEFT 0x0100
#define WIIMOTE_BUTTON_RIGHT 0x0200
#define WIIMOTE_BUTTON_DOWN 0x0400
#define WIIMOTE_BUTTON_UP 0x0800
#define WIIMOTE_BUTTON_PLUS 0x1000
#define WIIMOTE_BUTTON_ZACCEL_BIT4 0x2000
#define WIIMOTE_BUTTON_ZACCEL_BIT5 0x4000
#define WIIMOTE_BUTTON_UNKNOWN 0x8000
#define WIIMOTE_BUTTON_ALL 0x1F9F
/* nunchul button codes */
#define NUNCHUK_BUTTON_Z 0x01
#define NUNCHUK_BUTTON_C 0x02
#define NUNCHUK_BUTTON_ALL 0x03
/* classic controller button codes */
#define CLASSIC_CTRL_BUTTON_UP 0x0001
#define CLASSIC_CTRL_BUTTON_LEFT 0x0002
#define CLASSIC_CTRL_BUTTON_ZR 0x0004
#define CLASSIC_CTRL_BUTTON_X 0x0008
#define CLASSIC_CTRL_BUTTON_A 0x0010
#define CLASSIC_CTRL_BUTTON_Y 0x0020
#define CLASSIC_CTRL_BUTTON_B 0x0040
#define CLASSIC_CTRL_BUTTON_ZL 0x0080
#define CLASSIC_CTRL_BUTTON_FULL_R 0x0200
#define CLASSIC_CTRL_BUTTON_PLUS 0x0400
#define CLASSIC_CTRL_BUTTON_HOME 0x0800
#define CLASSIC_CTRL_BUTTON_MINUS 0x1000
#define CLASSIC_CTRL_BUTTON_FULL_L 0x2000
#define CLASSIC_CTRL_BUTTON_DOWN 0x4000
#define CLASSIC_CTRL_BUTTON_RIGHT 0x8000
#define CLASSIC_CTRL_BUTTON_ALL 0xFEFF
/* 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
#define GUITAR_HERO_3_BUTTON_BLUE 0x0020
#define GUITAR_HERO_3_BUTTON_RED 0x0040
#define GUITAR_HERO_3_BUTTON_ORANGE 0x0080
#define GUITAR_HERO_3_BUTTON_PLUS 0x0400
#define GUITAR_HERO_3_BUTTON_MINUS 0x1000
#define GUITAR_HERO_3_BUTTON_STRUM_DOWN 0x4000
#define GUITAR_HERO_3_BUTTON_ALL 0xFEFF
/* guitar hero world tour touch bar codes */
#define GUITAR_HERO_3_TOUCH_AVAILABLE 0x1000
#define GUITAR_HERO_3_TOUCH_GREEN 0x1001
#define GUITAR_HERO_3_TOUCH_RED 0x1002
#define GUITAR_HERO_3_TOUCH_YELLOW 0x1004
#define GUITAR_HERO_3_TOUCH_BLUE 0x1008
#define GUITAR_HERO_3_TOUCH_ORANGE 0x1010
/* wiimote option flags */
#define WIIUSE_SMOOTHING 0x01
#define WIIUSE_CONTINUOUS 0x02
#define WIIUSE_ACCEL_THRESH 0x04
#define WIIUSE_IR_THRESH 0x08
#define WIIUSE_JS_THRESH 0x10
#define WIIUSE_INIT_FLAGS WIIUSE_SMOOTHING
#define WIIUSE_ORIENT_PRECISION 100.0f
/* 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
/* IR correction types */
typedef enum ir_position_t {
WIIUSE_IR_ABOVE,
WIIUSE_IR_BELOW
} ir_position_t;
/**
* @brief Check if a button is pressed.
* @param dev Pointer to a wiimote_t or expansion structure.
* @param button The button you are interested in.
* @return 1 if the button is pressed, 0 if not.
*/
#define IS_PRESSED(dev, button) ((dev->btns & button) == button)
/**
* @brief Check if a button is being held.
* @param dev Pointer to a wiimote_t or expansion structure.
* @param button The button you are interested in.
* @return 1 if the button is held, 0 if not.
*/
#define IS_HELD(dev, button) ((dev->btns_held & button) == button)
/**
* @brief Check if a button is released on this event. \n\n
* This does not mean the button is not pressed, it means \n
* this button was just now released.
* @param dev Pointer to a wiimote_t or expansion structure.
* @param button The button you are interested in.
* @return 1 if the button is released, 0 if not.
*
*/
#define IS_RELEASED(dev, button) ((dev->btns_released & button) == button)
/**
* @brief Check if a button has just been pressed this event.
* @param dev Pointer to a wiimote_t or expansion structure.
* @param button The button you are interested in.
* @return 1 if the button is pressed, 0 if not.
*/
#define IS_JUST_PRESSED(dev, button) (IS_PRESSED(dev, button) && !IS_HELD(dev, button))
/**
* @brief Return the IR sensitivity level.
* @param wm Pointer to a wiimote_t structure.
* @param lvl [out] Pointer to an int that will hold the level setting.
* If no level is set 'lvl' will be set to 0.
*/
#define WIIUSE_GET_IR_SENSITIVITY(dev, lvl) \
do { \
if ((wm->state & 0x01000) == 0x01000) *lvl = 1; \
else if ((wm->state & 0x02000) == 0x02000) *lvl = 2; \
else if ((wm->state & 0x04000) == 0x04000) *lvl = 3; \
else if ((wm->state & 0x08000) == 0x08000) *lvl = 4; \
else if ((wm->state & 0x10000) == 0x10000) *lvl = 5; \
else *lvl = 0; \
} while (0)
#define WIIUSE_USING_ACC(wm) ((wm->state & 0x00100) == 0x00100)
#define WIIUSE_USING_EXP(wm) ((wm->state & 0x00200) == 0x00200)
#define WIIUSE_USING_IR(wm) ((wm->state & 0x00400) == 0x00400)
#define WIIUSE_USING_SPEAKER(wm) ((wm->state & 0x00800) == 0x00800)
#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
#define WIIMOTE_DEFAULT_TIMEOUT 100
#define WIIMOTE_EXP_TIMEOUT 100
#endif
typedef unsigned char ubyte;
typedef char sbyte;
typedef unsigned short uword;
typedef short sword;
typedef unsigned int uint;
typedef char sint;
struct wiimote_t;
struct vec3b_t;
struct orient_t;
struct gforce_t;
#ifdef GEKKO
typedef void (*wii_event_cb)(struct wiimote_t*, s32 event);
#endif
/**
* @brief Callback that handles a read event.
*
* @param wm Pointer to a wiimote_t structure.
* @param data Pointer to the filled 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_read_data().
*/
typedef void (*wiiuse_data_cb)(struct wiimote_t* wm, ubyte* 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 read request structure.
*/
struct data_req_t {
lwp_node node;
ubyte data[48]; /**< buffer where read data is written */
unsigned int len;
data_req_s state; /**< set to 1 if not using callback and needs to be cleaned up */
wiiuse_data_cb cb; /**< read data callback */
struct data_req_t *next;
};
typedef void (*cmd_blk_cb)(struct wiimote_t *wm,ubyte *data,uword len);
typedef enum cmd_blk_s
{
CMD_READY = 0,
CMD_SENT,
CMD_DONE
} cmd_blk_s;
struct cmd_blk_t
{
lwp_node node;
ubyte data[48];
uint len;
cmd_blk_s state;
cmd_blk_cb cb;
struct cmd_blk_t *next;
};
/**
* @struct vec2b_t
* @brief Unsigned x,y byte vector.
*/
typedef struct vec2b_t {
ubyte x, y;
} vec2b_t;
/**
* @struct vec3b_t
* @brief Unsigned x,y,z byte vector.
*/
typedef struct vec3b_t {
ubyte x, y, z;
} vec3b_t;
/**
* @struct vec3b_t
* @brief Unsigned x,y,z byte vector.
*/
typedef struct vec3w_t {
uword x, y, z;
} vec3w_t;
/**
* @struct vec3f_t
* @brief Signed x,y,z float struct.
*/
typedef struct vec3f_t {
float x, y, z;
} vec3f_t;
/**
* @struct orient_t
* @brief Orientation struct.
*
* Yaw, pitch, and roll range from -180 to 180 degrees.
*/
typedef struct orient_t {
float roll; /**< roll, this may be smoothed if enabled */
float pitch; /**< pitch, this may be smoothed if enabled */
float yaw;
float a_roll; /**< absolute roll, unsmoothed */
float a_pitch; /**< absolute pitch, unsmoothed */
} orient_t;
/**
* @struct gforce_t
* @brief Gravity force struct.
*/
typedef struct gforce_t {
float x, y, z;
} gforce_t;
/**
* @struct accel_t
* @brief Accelerometer struct. For any device with an accelerometer.
*/
typedef struct accel_t {
struct vec3w_t cal_zero; /**< zero calibration */
struct vec3w_t cal_g; /**< 1g difference around 0cal */
float st_roll; /**< last smoothed roll value */
float st_pitch; /**< last smoothed roll pitch */
float st_alpha; /**< alpha value for smoothing [0-1] */
} accel_t;
/**
* @struct ir_dot_t
* @brief A single IR source.
*/
typedef struct ir_dot_t {
ubyte visible; /**< if the IR source is visible */
short rx; /**< raw X coordinate (0-1023) */
short ry; /**< raw Y coordinate (0-767) */
ubyte size; /**< size of the IR dot (0-15) */
} ir_dot_t;
typedef struct fdot_t {
float x,y;
} fdot_t;
typedef struct sb_t {
fdot_t dots[2];
fdot_t acc_dots[2];
fdot_t rot_dots[2];
float angle;
float off_angle;
float score;
} sb_t;
/**
* @enum aspect_t
* @brief Screen aspect ratio.
*/
typedef enum aspect_t {
WIIUSE_ASPECT_4_3,
WIIUSE_ASPECT_16_9
} aspect_t;
/**
* @struct ir_t
* @brief IR struct. Hold all data related to the IR tracking.
*/
typedef struct ir_t {
struct ir_dot_t dot[4]; /**< IR dots */
ubyte num_dots; /**< number of dots at this time */
int state; /**< keeps track of the IR state */
int raw_valid; /**< is the raw position valid? */
sb_t sensorbar; /**< sensor bar, detected or guessed */
float ax; /**< raw X coordinate */
float ay; /**< raw Y coordinate */
float distance; /**< pixel width of the sensor bar */
float z; /**< calculated distance in meters */
float angle; /**< angle of the wiimote to the sensor bar*/
int smooth_valid; /**< is the smoothed position valid? */
float sx; /**< smoothed X coordinate */
float sy; /**< smoothed Y coordinate */
float error_cnt; /**< error count, for smoothing algorithm*/
float glitch_cnt; /**< glitch count, same */
int valid; /**< is the bounded position valid? */
float x; /**< bounded X coordinate */
float y; /**< bounded Y coordinate */
enum aspect_t aspect; /**< aspect ratio of the screen */
enum ir_position_t pos; /**< IR sensor bar position */
unsigned int vres[2]; /**< IR virtual screen resolution */
int offset[2]; /**< IR XY correction offset */
} ir_t;
/**
* @struct joystick_t
* @brief Joystick calibration structure.
*
* The angle \a ang is relative to the positive y-axis into quadrant I
* and ranges from 0 to 360 degrees. So if the joystick is held straight
* upwards then angle is 0 degrees. If it is held to the right it is 90,
* down is 180, and left is 270.
*
* The magnitude \a mag is the distance from the center to where the
* joystick is being held. The magnitude ranges from 0 to 1.
* If the joystick is only slightly tilted from the center the magnitude
* will be low, but if it is closer to the outter edge the value will
* be higher.
*/
typedef struct joystick_t {
struct vec2b_t max; /**< maximum joystick values */
struct vec2b_t min; /**< minimum joystick values */
struct vec2b_t center; /**< center joystick values */
struct vec2b_t pos; /**< raw position values */
float ang; /**< angle the joystick is being held */
float mag; /**< magnitude of the joystick (range 0-1) */
} joystick_t;
/**
* @struct nunchuk_t
* @brief Nunchuk expansion device.
*/
typedef struct nunchuk_t {
struct accel_t accel_calib; /**< nunchuk accelerometer calibration */
struct joystick_t js; /**< joystick calibration */
int* flags; /**< options flag (points to wiimote_t.flags) */
ubyte btns; /**< what buttons have just been pressed */
ubyte btns_last; /**< what buttons have just been pressed */
ubyte btns_held; /**< what buttons are being held down */
ubyte btns_released; /**< what buttons were just released this */
struct vec3w_t accel; /**< current raw acceleration data */
struct orient_t orient; /**< current orientation on each axis */
struct gforce_t gforce; /**< current gravity forces on each axis */
} 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_last; /**< what buttons have just been pressed */
short btns_held; /**< what buttons are being held down */
short btns_released; /**< what buttons were just released this */
ubyte rs_raw;
ubyte ls_raw;
float r_shoulder; /**< right shoulder button (range 0-1) */
float l_shoulder; /**< left shoulder button (range 0-1) */
struct joystick_t ljs; /**< left joystick calibration */
struct joystick_t rjs; /**< right joystick calibration */
ubyte type; /**< original, pro, wiiu pro */
} 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_last; /**< what buttons have just been pressed */
short btns_held; /**< what buttons are being held down */
short btns_released; /**< what buttons were just released this */
ubyte wb_raw;
float whammy_bar; /**< whammy bar (range 0-1) */
ubyte tb_raw;
int touch_bar; /**< touch bar */
struct joystick_t js; /**< joystick calibration */
} guitar_hero_3_t;
/**
* @struct wii_board_t
* @brief Wii Balance Board expansion device.
*/
typedef struct wii_board_t {
float tl; /* Interpolated */
float tr;
float bl;
float br; /* End interp */
short rtl; /* RAW */
short rtr;
short rbl;
short rbr; /* /RAW */
short ctl[3]; /* Calibration */
short ctr[3];
short cbl[3];
short cbr[3]; /* /Calibration */
float x;
float y;
} wii_board_t;
typedef struct motion_plus_t
{
short rx, ry, rz;
ubyte status;
ubyte ext;
} motion_plus_t;
/**
* @struct expansion_t
* @brief Generic expansion device plugged into wiimote.
*/
typedef struct expansion_t {
int type; /**< type of expansion attached */
union {
struct nunchuk_t nunchuk;
struct classic_ctrl_t classic;
struct guitar_hero_3_t gh3;
struct wii_board_t wb;
struct motion_plus_t mp;
};
} expansion_t;
/**
* @enum win32_bt_stack_t
* @brief Available bluetooth stacks for Windows.
*/
typedef enum win_bt_stack_t {
WIIUSE_STACK_UNKNOWN,
WIIUSE_STACK_MS,
WIIUSE_STACK_BLUESOLEIL
} win_bt_stack_t;
/**
* @struct wiimote_state_t
* @brief Significant data from the previous event.
*/
typedef struct wiimote_state_t {
unsigned short btns;
struct ir_t ir;
struct vec3w_t accel;
struct expansion_t exp;
} wiimote_state_t;
/**
* @enum WIIUSE_EVENT_TYPE
* @brief Events that wiiuse can generate from a poll.
*/
typedef enum WIIUSE_EVENT_TYPE {
WIIUSE_NONE = 0,
WIIUSE_EVENT,
WIIUSE_STATUS,
WIIUSE_CONNECT,
WIIUSE_DISCONNECT,
WIIUSE_UNEXPECTED_DISCONNECT,
WIIUSE_READ_DATA,
WIIUSE_ACK,
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_WII_BOARD_INSERTED,
WIIUSE_WII_BOARD_REMOVED,
WIIUSE_MOTION_PLUS_ACTIVATED,
WIIUSE_MOTION_PLUS_REMOVED
} WIIUSE_EVENT_TYPE;
/**
* @struct wiimote_t
* @brief Wiimote structure.
*/
typedef struct wiimote_t {
WCONST int unid; /**< user specified id */
#if defined(_WIN32)
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 ubyte normal_timeout; /**< normal timeout */
WCONST ubyte exp_timeout; /**< timeout for expansion handshake */
#elif defined(GEKKO)
WCONST lwp_queue cmdq;
WCONST struct bd_addr bdaddr; /**< bt address */
WCONST char bdaddr_str[18]; /**< readable bt address */
WCONST struct bte_pcb *sock; /**< output socket */
WCONST wii_event_cb event_cb; /**< event callback */
#elif defined(unix)
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 */
#endif
WCONST int state; /**< various state flags */
WCONST ubyte leds; /**< currently lit leds */
#ifdef GEKKO
WCONST ubyte battery_level; /**< battery level */
#else
WCONST float battery_level; /**< battery level */
#endif
WCONST int flags; /**< options flag */
WCONST ubyte handshake_state; /**< the state of the connection handshake */
WCONST ubyte expansion_state; /**< the state of the expansion handshake */
WCONST struct data_req_t* data_req; /**< list of data read requests */
WCONST struct cmd_blk_t *cmd_head;
WCONST struct cmd_blk_t *cmd_tail;
WCONST struct accel_t accel_calib; /**< wiimote accelerometer calibration */
WCONST struct expansion_t exp; /**< wiimote expansion device */
WCONST struct vec3w_t accel; /**< current raw acceleration data */
WCONST struct orient_t orient; /**< current orientation on each axis */
WCONST struct gforce_t gforce; /**< current gravity forces on each axis */
WCONST struct ir_t ir; /**< IR data */
WCONST unsigned short btns; /**< what buttons are down */
WCONST unsigned short btns_last; /**< what buttons were down before */
WCONST unsigned short btns_held; /**< what buttons are and were held down */
WCONST unsigned short btns_released; /**< what buttons were just released */
WCONST struct wiimote_state_t lstate; /**< last saved state */
WCONST WIIUSE_EVENT_TYPE event; /**< type of event that occured */
WCONST ubyte event_buf[MAX_PAYLOAD]; /**< event buffer */
WCONST ubyte motion_plus_id[6];
} wiimote;
#if defined(GEKKO)
/**
* @struct wiimote_listen_t
* @brief Wiimote listen structure.
*/
typedef struct wiimote_listen_t {
WCONST struct bd_addr bdaddr;
WCONST struct bte_pcb *sock;
WCONST struct wiimote_t *(*assign_cb)(struct bd_addr *bdaddr);
WCONST struct wiimote_t *wm;
} wiimote_listen;
#endif
/*****************************************
*
* Include API specific stuff
*
*****************************************/
#ifdef _WIN32
#define WIIUSE_EXPORT_DECL __declspec(dllexport)
#define WIIUSE_IMPORT_DECL __declspec(dllimport)
#else
#define WIIUSE_EXPORT_DECL
#define WIIUSE_IMPORT_DECL
#endif
#ifdef WIIUSE_COMPILE_LIB
#define WIIUSE_EXPORT WIIUSE_EXPORT_DECL
#else
#define WIIUSE_EXPORT WIIUSE_IMPORT_DECL
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* wiiuse.c */
WIIUSE_EXPORT extern const char* wiiuse_version();
#ifndef GEKKO
WIIUSE_EXPORT extern struct wiimote_t** wiiuse_init(int wiimotes);
#else
WIIUSE_EXPORT extern int wiiuse_register(struct wiimote_listen_t *wml, struct bd_addr *bdaddr, struct wiimote_t *(*assign_cb)(struct bd_addr *bdaddr));
WIIUSE_EXPORT extern struct wiimote_t** wiiuse_init(int wiimotes, wii_event_cb event_cb);
WIIUSE_EXPORT extern void wiiuse_sensorbar_enable(int enable);
#endif
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,cmd_blk_cb cb);
WIIUSE_EXPORT extern void wiiuse_motion_sensing(struct wiimote_t* wm, int status);
WIIUSE_EXPORT extern int wiiuse_read_data(struct wiimote_t* wm, ubyte* buffer, unsigned int offset, unsigned short len, cmd_blk_cb cb);
WIIUSE_EXPORT extern int wiiuse_write_data(struct wiimote_t *wm,unsigned int addr,ubyte *data,ubyte len,cmd_blk_cb cb);
WIIUSE_EXPORT extern void wiiuse_status(struct wiimote_t *wm,cmd_blk_cb cb);
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_resync(struct wiimote_t* wm);
WIIUSE_EXPORT extern void wiiuse_set_timeout(struct wiimote_t** wm, int wiimotes, ubyte normal_timeout, ubyte exp_timeout);
WIIUSE_EXPORT extern int wiiuse_write_streamdata(struct wiimote_t *wm,ubyte *data,ubyte len,cmd_blk_cb cb);
/* 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);
/* events.c */
WIIUSE_EXPORT extern int wiiuse_poll(struct wiimote_t** wm, int wiimotes);
/* ir.c */
WIIUSE_EXPORT extern void wiiuse_set_ir_mode(struct wiimote_t *wm);
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);
/* motion_plus.c */
WIIUSE_EXPORT extern void wiiuse_set_motion_plus(struct wiimote_t *wm, int status);
/* speaker.c */
WIIUSE_EXPORT extern void wiiuse_set_speaker(struct wiimote_t *wm, int status);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,277 @@
/*
* 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: /lvm/shared/ds/ds/cvs/devkitpro-cvsbackup/libogc/wiiuse/wiiuse_internal.h,v 1.8 2008-12-10 16:16:40 shagkur Exp $
*
*/
/**
* @file
* @brief General internal wiiuse stuff.
*
* Since Wiiuse is a library, wiiuse.h is a duplicate
* of the API header.
*
* The code that would normally go in that file, but
* which is not needed by third party developers,
* is put here.
*
* So wiiuse_internal.h is included by other files
* internally, wiiuse.h is included only here.
*/
#ifndef WIIUSE_INTERNAL_H_INCLUDED
#define WIIUSE_INTERNAL_H_INCLUDED
#if defined(__linux__)
#include <arpa/inet.h> /* htons() */
#include <bluetooth/bluetooth.h>
#endif
#include "definitions.h"
/* wiiuse version */
#define WIIUSE_VERSION "0.12"
/********************
*
* Wiimote internal codes
*
********************/
/* Communication channels */
#define WM_OUTPUT_CHANNEL 0x11
#define WM_INPUT_CHANNEL 0x13
#define WM_SET_REPORT 0x50
#define WM_DATA 0xA0
/* commands */
#define WM_CMD_RUMBLE 0x10
#define WM_CMD_LED 0x11
#define WM_CMD_REPORT_TYPE 0x12
#define WM_CMD_IR 0x13
#define WM_CMD_SPEAKER_ENABLE 0x14
#define WM_CMD_CTRL_STATUS 0x15
#define WM_CMD_WRITE_DATA 0x16
#define WM_CMD_READ_DATA 0x17
#define WM_CMD_STREAM_DATA 0x18
#define WM_CMD_SPEAKER_MUTE 0x19
#define WM_CMD_IR_2 0x1A
/* input report ids */
#define WM_RPT_CTRL_STATUS 0x20
#define WM_RPT_READ 0x21
#define WM_RPT_ACK 0x22
#define WM_RPT_BTN 0x30
#define WM_RPT_BTN_ACC 0x31
#define WM_RPT_BTN_ACC_IR 0x33
#define WM_RPT_BTN_EXP 0x34
#define WM_RPT_BTN_ACC_EXP 0x35
#define WM_RPT_BTN_IR_EXP 0x36
#define WM_RPT_BTN_ACC_IR_EXP 0x37
#define WM_BT_INPUT 0x01
#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
#define WM_VENDOR_ID 0x057E
#define WM_PRODUCT_ID 0x0306
/* controller status stuff */
#define WM_MAX_BATTERY_CODE 0xC8
/* offsets in wiimote memory */
#define WM_MEM_OFFSET_CALIBRATION 0x16
#define WM_EXP_MEM_BASE 0x04A40000
#define WM_EXP_MEM_ENABLE1 0x04A400F0
#define WM_EXP_MEM_ENABLE2 0x04A400FB
#define WM_EXP_MEM_KEY 0x04A40040
#define WM_EXP_MEM_CALIBR 0x04A40020
#define WM_EXP_MOTION_PLUS_ENABLE 0x04A600FE
#define WM_EXP_ID 0x04A400FA
#define WM_REG_IR 0x04B00030
#define WM_REG_IR_BLOCK1 0x04B00000
#define WM_REG_IR_BLOCK2 0x04B0001A
#define WM_REG_IR_MODENUM 0x04B00033
#define WM_REG_SPEAKER_REG1 0x04A20001
#define WM_REG_SPEAKER_REG2 0x04A20008
#define WM_REG_SPEAKER_REG3 0x04A20009
#define WM_REG_SPEAKER_BLOCK 0x04A20001
/* 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
#define WM_IR_TYPE_FULL 0x05
/* controller status flags for the first message byte */
/* bit 1 is unknown */
#define WM_CTRL_STATUS_BYTE1_ATTACHMENT 0x02
#define WM_CTRL_STATUS_BYTE1_SPEAKER_ENABLED 0x04
#define WM_CTRL_STATUS_BYTE1_IR_ENABLED 0x08
#define WM_CTRL_STATUS_BYTE1_LED_1 0x10
#define WM_CTRL_STATUS_BYTE1_LED_2 0x20
#define WM_CTRL_STATUS_BYTE1_LED_3 0x40
#define WM_CTRL_STATUS_BYTE1_LED_4 0x80
/* aspect ratio */
#define WM_ASPECT_16_9_X 660
#define WM_ASPECT_16_9_Y 370
#define WM_ASPECT_4_3_X 560
#define WM_ASPECT_4_3_Y 420
/**
* Expansion stuff
*/
/* encrypted expansion id codes (located at 0x04A400FC) */
#define EXP_ID_CODE_NUNCHUK 0xa4200000
#define EXP_ID_CODE_CLASSIC_CONTROLLER 0xa4200101
#define EXP_ID_CODE_CLASSIC_CONTROLLER_NYKOWING 0x90908f00
#define EXP_ID_CODE_CLASSIC_CONTROLLER_NYKOWING2 0x9e9f9c00
#define EXP_ID_CODE_CLASSIC_CONTROLLER_NYKOWING3 0x908f8f00
#define EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC 0xa5a2a300
#define EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC2 0x98999900
#define EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC3 0xa0a1a000
#define EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC4 0x8d8d8e00
#define EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC5 0x93949400
#define EXP_ID_CODE_CLASSIC_WIIU_PRO 0xa4200120
#define EXP_ID_CODE_GUITAR 0xa4200103
#define EXP_ID_CODE_WIIBOARD 0xa4200402
#define EXP_ID_CODE_MOTION_PLUS 0xa4200405
#define EXP_HANDSHAKE_LEN 224
/********************
*
* End Wiimote internal codes
*
********************/
/* wiimote state flags - (some duplicated in wiiuse.h)*/
#define WIIMOTE_STATE_DEV_FOUND 0x00001
//#define WIIMOTE_STATE_DEV_REGISTER 0x00002
#define WIIMOTE_STATE_HANDSHAKE 0x00004 /* actual connection exists but no handshake yet */
#define WIIMOTE_STATE_HANDSHAKE_COMPLETE 0x00008 /* actual connection exists but no handshake yet */
#define WIIMOTE_STATE_CONNECTED 0x00010
#define WIIMOTE_STATE_EXP_HANDSHAKE 0x00020 /* actual connection exists but no handshake yet */
#define WIIMOTE_STATE_EXP_FAILED 0x00040 /* actual connection exists but no handshake yet */
#define WIIMOTE_STATE_RUMBLE 0x00080
#define WIIMOTE_STATE_ACC 0x00100
#define WIIMOTE_STATE_EXP 0x00200
#define WIIMOTE_STATE_IR 0x00400
#define WIIMOTE_STATE_SPEAKER 0x00800
#define WIIMOTE_STATE_IR_SENS_LVL1 0x01000
#define WIIMOTE_STATE_IR_SENS_LVL2 0x02000
#define WIIMOTE_STATE_IR_SENS_LVL3 0x04000
#define WIIMOTE_STATE_IR_SENS_LVL4 0x08000
#define WIIMOTE_STATE_IR_SENS_LVL5 0x10000
#define WIIMOTE_STATE_IR_INIT 0x20000
#define WIIMOTE_STATE_SPEAKER_INIT 0x40000
#define WIIMOTE_STATE_WIIU_PRO 0x80000
#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))
#define WIIMOTE_IS_FLAG_SET(wm, s) ((wm->flags & (s)) == (s))
#define WIIMOTE_ENABLE_FLAG(wm, s) (wm->flags |= (s))
#define WIIMOTE_DISABLE_FLAG(wm, s) (wm->flags &= ~(s))
#define WIIMOTE_TOGGLE_FLAG(wm, s) ((wm->flags & (s)) ? WIIMOTE_DISABLE_FLAG(wm, s) : WIIMOTE_ENABLE_FLAG(wm, s))
#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))
/*
* Smooth tilt calculations are computed with the
* exponential moving average formula:
* St = St_last + (alpha * (tilt - St_last))
* alpha is between 0 and 1
*/
#define WIIUSE_DEFAULT_SMOOTH_ALPHA 0.3f
#define SMOOTH_ROLL 0x01
#define SMOOTH_PITCH 0x02
#include <wiiuse/wiiuse.h>
#ifdef __cplusplus
extern "C" {
#endif
struct op_t
{
ubyte cmd;
union {
struct {
uint addr;
uword size;
} readdata;
struct {
uint addr;
ubyte size;
ubyte data[16];
} writedata;
ubyte __data[MAX_PAYLOAD];
};
void *buffer;
int wait;
} __attribute__((packed));
/* not part of the api */
void wiiuse_init_cmd_queue(struct wiimote_t *wm);
void wiiuse_send_next_command(struct wiimote_t *wm);
int wiiuse_set_report_type(struct wiimote_t* wm,cmd_blk_cb cb);
int wiiuse_sendcmd(struct wiimote_t *wm,ubyte report_type,ubyte *msg,int len,cmd_blk_cb cb);
#ifdef __cplusplus
}
#endif
#endif /* WIIUSE_INTERNAL_H_INCLUDED */