From c208b1bc60573add9635a2d05df906fd476a1019 Mon Sep 17 00:00:00 2001 From: "fires.gc" Date: Wed, 5 Nov 2008 16:46:30 +0000 Subject: [PATCH] added special wiiuse version git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@1072 8ced0084-cf51-0410-be5f-012b33b47a6e --- Externals/WiiUse/Inc/wiiuse.h | 657 ++++++++++++++++ Externals/WiiUse/Win32/wiiuse.dll | Bin 0 -> 104960 bytes Externals/WiiUse/Win32/wiiuse.lib | Bin 0 -> 8610 bytes Externals/WiiUse/X64/wiiuse.dll | Bin 0 -> 103424 bytes Externals/WiiUse/X64/wiiuse.lib | Bin 0 -> 8462 bytes Externals/WiiUseSrc/Src/Makefile | 91 +++ Externals/WiiUseSrc/Src/classic.c | 190 +++++ Externals/WiiUseSrc/Src/classic.h | 53 ++ Externals/WiiUseSrc/Src/definitions.h | 79 ++ Externals/WiiUseSrc/Src/dynamics.c | 228 ++++++ Externals/WiiUseSrc/Src/dynamics.h | 56 ++ Externals/WiiUseSrc/Src/events.c | 878 ++++++++++++++++++++++ Externals/WiiUseSrc/Src/events.h | 54 ++ Externals/WiiUseSrc/Src/guitar_hero_3.c | 172 +++++ Externals/WiiUseSrc/Src/guitar_hero_3.h | 62 ++ Externals/WiiUseSrc/Src/io.c | 119 +++ Externals/WiiUseSrc/Src/io.h | 56 ++ Externals/WiiUseSrc/Src/io_nix.c | 270 +++++++ Externals/WiiUseSrc/Src/io_win.c | 247 ++++++ Externals/WiiUseSrc/Src/ir.c | 748 ++++++++++++++++++ Externals/WiiUseSrc/Src/ir.h | 56 ++ Externals/WiiUseSrc/Src/nunchuk.c | 210 ++++++ Externals/WiiUseSrc/Src/nunchuk.h | 53 ++ Externals/WiiUseSrc/Src/os.h | 56 ++ Externals/WiiUseSrc/Src/wiiuse.c | 764 +++++++++++++++++++ Externals/WiiUseSrc/Src/wiiuse.h | 657 ++++++++++++++++ Externals/WiiUseSrc/Src/wiiuse_internal.h | 226 ++++++ Externals/WiiUseSrc/wiiuse.sln | 26 + Externals/WiiUseSrc/wiiuse.suo | Bin 0 -> 32768 bytes Externals/WiiUseSrc/wiiuse.vcproj | 508 +++++++++++++ 30 files changed, 6516 insertions(+) create mode 100644 Externals/WiiUse/Inc/wiiuse.h create mode 100644 Externals/WiiUse/Win32/wiiuse.dll create mode 100644 Externals/WiiUse/Win32/wiiuse.lib create mode 100644 Externals/WiiUse/X64/wiiuse.dll create mode 100644 Externals/WiiUse/X64/wiiuse.lib create mode 100644 Externals/WiiUseSrc/Src/Makefile create mode 100644 Externals/WiiUseSrc/Src/classic.c create mode 100644 Externals/WiiUseSrc/Src/classic.h create mode 100644 Externals/WiiUseSrc/Src/definitions.h create mode 100644 Externals/WiiUseSrc/Src/dynamics.c create mode 100644 Externals/WiiUseSrc/Src/dynamics.h create mode 100644 Externals/WiiUseSrc/Src/events.c create mode 100644 Externals/WiiUseSrc/Src/events.h create mode 100644 Externals/WiiUseSrc/Src/guitar_hero_3.c create mode 100644 Externals/WiiUseSrc/Src/guitar_hero_3.h create mode 100644 Externals/WiiUseSrc/Src/io.c create mode 100644 Externals/WiiUseSrc/Src/io.h create mode 100644 Externals/WiiUseSrc/Src/io_nix.c create mode 100644 Externals/WiiUseSrc/Src/io_win.c create mode 100644 Externals/WiiUseSrc/Src/ir.c create mode 100644 Externals/WiiUseSrc/Src/ir.h create mode 100644 Externals/WiiUseSrc/Src/nunchuk.c create mode 100644 Externals/WiiUseSrc/Src/nunchuk.h create mode 100644 Externals/WiiUseSrc/Src/os.h create mode 100644 Externals/WiiUseSrc/Src/wiiuse.c create mode 100644 Externals/WiiUseSrc/Src/wiiuse.h create mode 100644 Externals/WiiUseSrc/Src/wiiuse_internal.h create mode 100644 Externals/WiiUseSrc/wiiuse.sln create mode 100644 Externals/WiiUseSrc/wiiuse.suo create mode 100644 Externals/WiiUseSrc/wiiuse.vcproj diff --git a/Externals/WiiUse/Inc/wiiuse.h b/Externals/WiiUse/Inc/wiiuse.h new file mode 100644 index 0000000000..a70dc9e344 --- /dev/null +++ b/Externals/WiiUse/Inc/wiiuse.h @@ -0,0 +1,657 @@ +/* + * 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 . + * + * $Header$ + * + */ + +/** + * @file + * + * @brief API header file. + * + * If this file is included from inside the wiiuse source + * and not from a third party program, then wiimote_internal.h + * is also included which extends this file. + */ + +#ifndef WIIUSE_H_INCLUDED +#define WIIUSE_H_INCLUDED + +#ifdef _WIN32 + /* windows */ + #include +#else + /* nix */ + #include +#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 + + +/* 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 */ +#define EXP_NONE 0 +#define EXP_NUNCHUK 1 +#define EXP_CLASSIC 2 +#define EXP_GUITAR_HERO_3 3 + +/* 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 & 0x0200) == 0x0200) *lvl = 1; \ + else if ((wm->state & 0x0400) == 0x0400) *lvl = 2; \ + else if ((wm->state & 0x0800) == 0x0800) *lvl = 3; \ + else if ((wm->state & 0x1000) == 0x1000) *lvl = 4; \ + else if ((wm->state & 0x2000) == 0x2000) *lvl = 5; \ + else *lvl = 0; \ + } while (0) + +#define WIIUSE_USING_ACC(wm) ((wm->state & 0x020) == 0x020) +#define WIIUSE_USING_EXP(wm) ((wm->state & 0x040) == 0x040) +#define WIIUSE_USING_IR(wm) ((wm->state & 0x080) == 0x080) +#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 + #define WIIMOTE_DEFAULT_TIMEOUT 10 + #define WIIMOTE_EXP_TIMEOUT 10 +#endif + +typedef unsigned char byte; +typedef char sbyte; + +struct wiimote_t; +struct vec3b_t; +struct orient_t; +struct gforce_t; + + +/** + * @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_read_cb)(struct wiimote_t* wm, byte* data, unsigned short 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 */ + 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 vec2b_t + * @brief Unsigned x,y byte vector. + */ +typedef struct vec2b_t { + byte x, y; +} vec2b_t; + + +/** + * @struct vec3b_t + * @brief Unsigned x,y,z byte vector. + */ +typedef struct vec3b_t { + byte x, y, z; +} vec3b_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 vec3b_t cal_zero; /**< zero calibration */ + struct vec3b_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 { + byte visible; /**< if the IR source is visible */ + + 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) */ + + byte order; /**< increasing order by x-axis value */ + + byte size; /**< size of the IR dot (0-15) */ +} ir_dot_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 */ + byte num_dots; /**< number of dots at this time */ + + 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 */ + int state; /**< keeps track of the IR state */ + + int ax; /**< absolute X coordinate */ + int ay; /**< absolute Y coordinate */ + + int x; /**< calculated X coordinate */ + int y; /**< calculated Y coordinate */ + + float distance; /**< pixel distance between first 2 dots*/ + float z; /**< calculated distance */ +} 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 */ + + 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) */ + + byte btns; /**< what buttons have just been pressed */ + byte btns_held; /**< what buttons are being held down */ + byte btns_released; /**< what buttons were just released this */ + + float orient_threshold; /**< threshold for orient to generate an event */ + int accel_threshold; /**< threshold for accel to generate an event */ + + struct vec3b_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_held; /**< what buttons are being held down */ + short 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) */ + + struct joystick_t ljs; /**< left joystick calibration */ + struct joystick_t rjs; /**< right joystick calibration */ +} 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 */ + + float whammy_bar; /**< whammy bar (range 0-1) */ + + struct joystick_t js; /**< joystick calibration */ +} guitar_hero_3_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; + }; +} 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 { + /* expansion_t */ + float exp_ljs_ang; + float exp_rjs_ang; + float exp_ljs_mag; + float exp_rjs_mag; + unsigned short exp_btns; + struct orient_t exp_orient; + struct vec3b_t exp_accel; + float exp_r_shoulder; + float exp_l_shoulder; + + /* ir_t */ + int ir_ax; + int ir_ay; + float ir_distance; + + struct orient_t orient; + unsigned short 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 { + WIIUSE_NONE = 0, + WIIUSE_EVENT, + WIIUSE_STATUS, + WIIUSE_CONNECT, + WIIUSE_DISCONNECT, + WIIUSE_UNEXPECTED_DISCONNECT, + WIIUSE_READ_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_EVENT_TYPE; + +/** + * @struct wiimote_t + * @brief Wiimote structure. + */ +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 + + WCONST int state; /**< various state flags */ + WCONST byte leds; /**< currently lit leds */ + WCONST float battery_level; /**< battery level */ + + WCONST int flags; /**< options flag */ + + WCONST byte handshake_state; /**< the state of the connection handshake */ + + WCONST struct read_req_t* read_req; /**< list of data read requests */ + WCONST struct accel_t accel_calib; /**< wiimote accelerometer calibration */ + WCONST struct expansion_t exp; /**< wiimote expansion device */ + + WCONST struct vec3b_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 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 float orient_threshold; /**< threshold for orient to generate an event */ + WCONST int 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 */ +} wiimote; + + +/***************************************** + * + * 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(); + +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); + +/* 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(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); + +/* io.c */ +WIIUSE_EXPORT extern int wiiuse_io_read(struct wiimote_t* wm); +WIIUSE_EXPORT extern int wiiuse_io_write(struct wiimote_t* wm, byte* buf, int len); + + +#ifdef __cplusplus +} +#endif + + +#endif /* WIIUSE_H_INCLUDED */ + diff --git a/Externals/WiiUse/Win32/wiiuse.dll b/Externals/WiiUse/Win32/wiiuse.dll new file mode 100644 index 0000000000000000000000000000000000000000..6b52becf21dc232f1bd08bda98d382445e6e0504 GIT binary patch literal 104960 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¨lv$8*lDJl-y_pz#WOA|NBpUAz@HH(d- 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�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 literal 0 HcmV?d00001 diff --git a/Externals/WiiUse/X64/wiiuse.lib b/Externals/WiiUse/X64/wiiuse.lib new file mode 100644 index 0000000000000000000000000000000000000000..f0013849ea22c7b9b07dc7e8c9f2cbd4772153dc GIT binary patch literal 8462 zcmcIpOK%iM5H8jR;suP2-|yv-kZ>@t>>68&qU8|@i>HjaAr0%@!8>BSv)Y~Ib&15m zx#X4$M}+bdIONEQOE}~ZAr3kC7jWRf5mG(fJ>4}gn})1Z>gnq0{<^xWtEzhs|5$C; z8b9Sv7U=JEu~=R@Ra{y;L;0sf_4L`r692rD2Y?Fz{f_|#o&gNL0T`=u8r}k6H1w3y za1QH8qtk*mu|%3a!D;F|0HcW~oTgr29cl6{ry1l2)QcrjVS&@oJdTevg0hT;TbxEN zVI67Gj z^?q$x%U5q)Us<&-{(SSo%JPlX>nqj+$LV%#u&ishu3U+?!!KNbH?Lm0b?vfs@!aY; z?BHy)L~pC*xh@F7;G4AGb((eA8hn%1n%8XFHD3zIDv_x>9my9c8izjug~cNwO`k)@rt! zJy=wPjCJ2`ceHhtRU%V!?P{~zk_yTyk#U+%XlTJVX;n65hx!s8kzU8uT6<(Up{QaI zIksYV-Re5ABF>1(bv8WDZ&+2g)u>8ESbxHg^;&bgwjXrt_|@7yy<@Z~);DXPV{NhC z(M=PFlTA6=MEaspJ!;nEL`98AupxYB!}hx2hUqLK+wN|xx#4LRH6r1A>+7ytxG3b2WE0wd-5DS#&v057n7JBi;j0KG^H z1%P>!e=!2k!akRs3TSZj)<7HGR#vu?GNot{EQQ{HGKltvc~@!I%OBxZG* zOjaAQMXistLdhZ#m|C6?kv1o)nzg0fY`Eln-F0~!-R{O&T9S9qJNf!%5B&Pq;BtN! zV2t9w`MSNY#xj-)(2mhC}31(JOzR?sCgSLoNC|0-{I3Iy$6Z{n_CW~#ub2IwhhS%bmKTe zro?2h6NEBl#bJC*8^RwO9kYwD&aiG^%_M??se9S4Rv-K|`WUX4p*(%G0 zVrP?`E&W%4iac8-$!Bu^$ciYL+}B>+ovbV-$EmL|>g4TgT}unX7;#-8IG^=R=C?3O z$6v3EAT$y)m#CfbFGt#?A(0?&h9nPIL?>pEIfbOM1x**-LGDbi^6BIiWPYe82`$V` z0_8sYB$UGUPP$`wMMAW2$F#i15N9!2FJ^ta6;3p#GTX5Xo%Sd!EnPFzDZ|?LYB(en zG}Gv8^6KFQ8S{Z~m%Gc&A|Rb}>hh+>5|KSQe#Z-9kJ{5*n4Ls2C4 z7NTvR`rKg*P4SlBBI0liF@9k+)Kgy9B6{LOB)%<%CtkeyXqREL{Y%l2MTAj`rrop6 zG+RiCbNB}&zJ(Ia?0&O#5<5{&yVlCn)~c#Z5V(%QzjR#sx&0QAkNIJ!YDvoEUZwnpJr8 W5y=cG#X8yTWKJPz?^DW~LjFIn3qR)o literal 0 HcmV?d00001 diff --git a/Externals/WiiUseSrc/Src/Makefile b/Externals/WiiUseSrc/Src/Makefile new file mode 100644 index 0000000000..bab5b140f4 --- /dev/null +++ b/Externals/WiiUseSrc/Src/Makefile @@ -0,0 +1,91 @@ +# +# wiiuse Makefile +# + +# +# Change this to your GCC version. +# +CC = gcc + +#################################################### +# +# You should not need to edit below this line. +# +#################################################### + +# +# Universal cflags +# +CFLAGS = -Wall -pipe -fPIC -funroll-loops + +ifeq ($(debug),1) + OBJ_PREFIX = debug + CFLAGS += -g -pg -DWITH_WIIUSE_DEBUG + +else + OBJ_PREFIX = release + CFLAGS += -O2 +endif + +OBJ_DIR = $(OBJ_PREFIX)-$(shell $(CC) -v 2>&1|grep ^Target:|cut -d' ' -f2) + +# +# Linking flags +# +LDFLAGS = -shared -lm -lbluetooth + +# +# Target binaries (always created as BIN) +# +BIN = ./$(OBJ_DIR)/libwiiuse.so + +# +# Inclusion paths. +# +INCLUDES = -I. + +# +# Generate a list of object files +# +OBJS = \ + $(OBJ_DIR)/classic.o \ + $(OBJ_DIR)/dynamics.o \ + $(OBJ_DIR)/events.o \ + $(OBJ_DIR)/io.o \ + $(OBJ_DIR)/io_nix.o \ + $(OBJ_DIR)/ir.o \ + $(OBJ_DIR)/nunchuk.o \ + $(OBJ_DIR)/guitar_hero_3.o \ + $(OBJ_DIR)/wiiuse.o + +############################### +# +# Build targets. +# +############################### + +all: $(BIN) + +clean: + @-rm $(OBJS) 2> /dev/null + +distclean: + @-rm -r debug-* release-* 2> /dev/null + +install: + @if [ -e $(BIN) ]; then \ + cp -v $(BIN) /usr/lib ; \ + fi + @cp -v wiiuse.h /usr/include + +$(BIN): mkdir $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $(BIN) + +$(OBJ_DIR)/%.o: %.c + $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ + +mkdir: + @if [ ! -d $(OBJ_DIR) ]; then \ + mkdir $(OBJ_DIR); \ + fi + diff --git a/Externals/WiiUseSrc/Src/classic.c b/Externals/WiiUseSrc/Src/classic.c new file mode 100644 index 0000000000..1d2c3ab275 --- /dev/null +++ b/Externals/WiiUseSrc/Src/classic.c @@ -0,0 +1,190 @@ +/* + * 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 . + * + * $Header$ + * + */ + +/** + * @file + * @brief Classic controller expansion device. + */ + +#include +#include +#include + +#ifdef WIN32 + #include +#endif + +#include "definitions.h" +#include "wiiuse_internal.h" +#include "dynamics.h" +#include "events.h" +#include "classic.h" + +static void classic_ctrl_pressed_buttons(struct classic_ctrl_t* cc, short now); + +/** + * @brief Handle the handshake data from the classic controller. + * + * @param cc A pointer to a classic_ctrl_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 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; + cc->btns_released = 0; + 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) { + /* + * Sometimes the data returned here is not correct. + * This might happen because the wiimote is lagging + * behind our initialization sequence. + * To fix this just request the handshake again. + * + * Other times it's just the first 16 bytes are 0xFF, + * but since the next 16 bytes are the same, just use + * those. + */ + if (data[offset + 16] == 0xFF) { + /* get the calibration data */ + byte* handshake_buf = 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; + } + + + /* 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->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; + + /* handshake done */ + wm->exp.type = EXP_CLASSIC; + + #ifdef WIN32 + wm->timeout = WIIMOTE_DEFAULT_TIMEOUT; + #endif + + return 1; +} + + +/** + * @brief The classic controller disconnected. + * + * @param cc A pointer to a classic_ctrl_t structure. + */ +void classic_ctrl_disconnected(struct classic_ctrl_t* cc) { + memset(cc, 0, sizeof(struct classic_ctrl_t)); +} + + + +/** + * @brief Handle classic controller event. + * + * @param cc A pointer to a classic_ctrl_t structure. + * @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; + 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))); + + /* left/right buttons */ + l = (((msg[2] & 0x60) >> 2) | ((msg[3] & 0xE0) >> 5)); + r = (msg[3] & 0x1F); + + /* + * TODO - LR range hardcoded from 0x00 to 0x1F. + * This is probably in the calibration somewhere. + */ + cc->r_shoulder = ((float)r / 0x1F); + cc->l_shoulder = ((float)l / 0x1F); + + /* calculate joystick orientation */ + lx = (msg[0] & 0x3F); + ly = (msg[1] & 0x3F); + 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); +} + + +/** + * @brief Find what buttons are pressed. + * + * @param cc A pointer to a classic_ctrl_t structure. + * @param msg The message byte specified in the event packet. + */ +static void classic_ctrl_pressed_buttons(struct classic_ctrl_t* cc, short now) { + /* message is inverted (0 is active, 1 is inactive) */ + now = ~now & CLASSIC_CTRL_BUTTON_ALL; + + /* pressed now & were pressed, then held */ + cc->btns_held = (now & cc->btns); + + /* were pressed or were held & not pressed now, then released */ + cc->btns_released = ((cc->btns | cc->btns_held) & ~now); + + /* buttons pressed now */ + cc->btns = now; +} diff --git a/Externals/WiiUseSrc/Src/classic.h b/Externals/WiiUseSrc/Src/classic.h new file mode 100644 index 0000000000..356f6a458b --- /dev/null +++ b/Externals/WiiUseSrc/Src/classic.h @@ -0,0 +1,53 @@ +/* + * 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 . + * + * $Header$ + * + */ + +/** + * @file + * @brief Classic controller expansion device. + */ + +#ifndef CLASSIC_H_INCLUDED +#define CLASSIC_H_INCLUDED + +#include "wiiuse_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +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_event(struct classic_ctrl_t* cc, byte* msg); + +#ifdef __cplusplus +} +#endif + +#endif // CLASSIC_H_INCLUDED diff --git a/Externals/WiiUseSrc/Src/definitions.h b/Externals/WiiUseSrc/Src/definitions.h new file mode 100644 index 0000000000..5a8da85def --- /dev/null +++ b/Externals/WiiUseSrc/Src/definitions.h @@ -0,0 +1,79 @@ +/* + * 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 . + * + * $Header$ + * + */ + +/** + * @file + * @brief General definitions. + */ + +#ifndef DEFINITIONS_H_INCLUDED +#define DEFINITIONS_H_INCLUDED + +/* this is wiiuse - used to distinguish from third party programs using wiiuse.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 + +/* 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 // DEFINITIONS_H_INCLUDED diff --git a/Externals/WiiUseSrc/Src/dynamics.c b/Externals/WiiUseSrc/Src/dynamics.c new file mode 100644 index 0000000000..53612a6b90 --- /dev/null +++ b/Externals/WiiUseSrc/Src/dynamics.c @@ -0,0 +1,228 @@ +/* + * 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 . + * + * $Header$ + * + */ + +/** + * @file + * @brief Handles the dynamics of the wiimote. + * + * The file includes functions that handle the dynamics + * of the wiimote. Such dynamics include orientation and + * motion sensing. + */ + +#include +#include +#include + +#ifdef WIN32 + #include +#endif + +#include "definitions.h" +#include "wiiuse_internal.h" +#include "ir.h" +#include "dynamics.h" + +/** + * @brief Calculate the roll, pitch, yaw. + * + * @param ac An accelerometer (accel_t) structure. + * @param accel [in] Pointer to a vec3b_t structure that holds the raw acceleration data. + * @param orient [out] Pointer to a orient_t structure that will hold the orientation data. + * @param rorient [out] Pointer to a orient_t structure that will hold the non-smoothed orientation data. + * @param smooth If smoothing should be performed on the angles calculated. 1 to enable, 0 to disable. + * + * Given the raw acceleration data from the accelerometer struct, calculate + * the orientation of the device and set it in the \a orient parameter. + */ +void calculate_orientation(struct accel_t* ac, struct vec3b_t* accel, struct orient_t* orient, int smooth) { + float xg, yg, zg; + float x, y, z; + + /* + * roll - use atan(z / x) [ ranges from -180 to 180 ] + * pitch - use atan(z / y) [ ranges from -180 to 180 ] + * yaw - impossible to tell without IR + */ + + /* yaw - set to 0, IR will take care of it if it's enabled */ + orient->yaw = 0.0f; + + /* find out how much it has to move to be 1g */ + xg = (float)ac->cal_g.x; + yg = (float)ac->cal_g.y; + zg = (float)ac->cal_g.z; + + /* find out how much it actually moved and normalize to +/- 1g */ + x = ((float)accel->x - (float)ac->cal_zero.x) / xg; + y = ((float)accel->y - (float)ac->cal_zero.y) / yg; + 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 it is over 1g then it is probably accelerating and not reliable */ + if (abs(accel->x - ac->cal_zero.x) <= ac->cal_g.x) { + /* roll */ + x = RAD_TO_DEGREE(atan2f(x, z)); + + orient->roll = x; + orient->a_roll = x; + } + + if (abs(accel->y - ac->cal_zero.y) <= ac->cal_g.y) { + /* pitch */ + y = RAD_TO_DEGREE(atan2f(y, z)); + + orient->pitch = y; + orient->a_pitch = y; + } + + /* smooth the angles if enabled */ + if (smooth) { + apply_smoothing(ac, orient, SMOOTH_ROLL); + apply_smoothing(ac, orient, SMOOTH_PITCH); + } +} + + +/** + * @brief Calculate the gravity forces on each axis. + * + * @param ac An accelerometer (accel_t) structure. + * @param accel [in] Pointer to a vec3b_t structure that holds the raw acceleration data. + * @param gforce [out] Pointer to a gforce_t structure that will hold the gravity force data. + */ +void calculate_gforce(struct accel_t* ac, struct vec3b_t* accel, struct gforce_t* gforce) { + float xg, yg, zg; + + /* find out how much it has to move to be 1g */ + xg = (float)ac->cal_g.x; + yg = (float)ac->cal_g.y; + zg = (float)ac->cal_g.z; + + /* find out how much it actually moved and normalize to +/- 1g */ + gforce->x = ((float)accel->x - (float)ac->cal_zero.x) / xg; + gforce->y = ((float)accel->y - (float)ac->cal_zero.y) / yg; + gforce->z = ((float)accel->z - (float)ac->cal_zero.z) / zg; +} + + +/** + * @brief Calculate the angle and magnitude of a joystick. + * + * @param js [out] Pointer to a joystick_t structure. + * @param x The raw x-axis value. + * @param y The raw y-axis value. + */ +void calc_joystick_state(struct joystick_t* js, float x, float y) { + float rx, ry, ang; + + /* + * Since the joystick center may not be exactly: + * (min + max) / 2 + * 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 + * between the center and the minimum or maxmimum rather than between + * the minimum and maximum. + * + * So we have something like this: + * (x min) [-1] ---------*------ [0] (x center) [0] -------- [1] (x max) + * Where the * is the current x value. + * 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; + + /* 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)); +} + + +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; + + /* + * 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; + } + + 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; + } + + return; + } + } +} diff --git a/Externals/WiiUseSrc/Src/dynamics.h b/Externals/WiiUseSrc/Src/dynamics.h new file mode 100644 index 0000000000..2a8f96500b --- /dev/null +++ b/Externals/WiiUseSrc/Src/dynamics.h @@ -0,0 +1,56 @@ +/* + * 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 . + * + * $Header$ + * + */ + +/** + * @file + * @brief Handles the dynamics of the wiimote. + * + * The file includes functions that handle the dynamics + * of the wiimote. Such dynamics include orientation and + * motion sensing. + */ + +#ifndef DYNAMICS_H_INCLUDED +#define DYNAMICS_H_INCLUDED + +#include "wiiuse_internal.h" + +#ifdef __cplusplus +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); + +#ifdef __cplusplus +} +#endif + +#endif // DYNAMICS_H_INCLUDED diff --git a/Externals/WiiUseSrc/Src/events.c b/Externals/WiiUseSrc/Src/events.c new file mode 100644 index 0000000000..6668eda5c8 --- /dev/null +++ b/Externals/WiiUseSrc/Src/events.c @@ -0,0 +1,878 @@ +/* + * 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 . + * + * $Header$ + * + */ + +/** + * @file + * @brief Handles wiimote events. + * + * The file includes functions that handle the events + * that are sent from the wiimote to us. + */ + +#include + +#ifndef WIN32 + #include + #include + #include +#else + #include +#endif + +#include +#include +#include + +#include "definitions.h" +#include "io.h" +#include "wiiuse_internal.h" +#include "dynamics.h" +#include "ir.h" +#include "nunchuk.h" +#include "classic.h" +#include "guitar_hero_3.h" +#include "events.h" + +static void idle_cycle(struct wiimote_t* wm); +static void clear_dirty_reads(struct wiimote_t* wm); +static void propagate_event(struct wiimote_t* wm, byte event, byte* msg); +static void event_data_read(struct wiimote_t* wm, byte* msg); +static void event_status(struct wiimote_t* wm, byte* msg); +static void handle_expansion(struct wiimote_t* wm, byte* msg); + +static void save_state(struct wiimote_t* wm); +static int state_changed(struct wiimote_t* wm); + +/** + * @brief Poll the wiimotes for any events. + * + * @param wm An array of pointers to wiimote_t structures. + * @param wiimotes The number of wiimote_t structures in the \a wm array. + * + * @return Returns number of wiimotes that an event has occured on. + * + * It is necessary to poll the wiimote devices for events + * that occur. If an event occurs on a particular wiimote, + * the event variable will be set. + */ +int wiiuse_poll(struct wiimote_t** wm, int wiimotes) { + int evnt = 0; + + #ifndef WIN32 + /* + * *nix + */ + struct timeval tv; + fd_set fds; + int r; + int i; + int highest_fd = -1; + + 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(wm[i]->event_buf, 0, sizeof(wm[i]->event_buf)); + + /* clear out any old read requests */ + clear_dirty_reads(wm[i]); + + /* read the pending message into the buffer */ + r = read(wm[i]->in_sock, wm[i]->event_buf, sizeof(wm[i]->event_buf)); + if (r == -1) { + /* error reading data */ + WIIUSE_ERROR("Receiving wiimote data (id %i).", wm[i]->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[i]->unid); + wiiuse_disconnect(wm[i]); + wm[i]->event = WIIUSE_UNEXPECTED_DISCONNECT; + } + + continue; + } + if (!r) { + /* remote disconnect */ + wiiuse_disconnected(wm[i]); + evnt = 1; + continue; + } + + /* propagate the event */ + propagate_event(wm[i], wm[i]->event_buf[1], wm[i]->event_buf+2); + evnt += (wm[i]->event != WIIUSE_NONE); + } else { + idle_cycle(wm[i]); + } + } + #else + /* + * Windows + */ + int i; + + if (!wm) return 0; + + for (i = 0; i < wiimotes; ++i) { + wm[i]->event = WIIUSE_NONE; + + if (wiiuse_io_read(wm[i])) { + /* propagate the event */ + propagate_event(wm[i], wm[i]->event_buf[0], wm[i]->event_buf+1); + evnt += (wm[i]->event != WIIUSE_NONE); + + /* clear out the event buffer */ + memset(wm[i]->event_buf, 0, sizeof(wm[i]->event_buf)); + } else { + idle_cycle(wm[i]); + } + } + #endif + + return evnt; +} + + +/** + * @brief Called on a cycle where no significant change occurs. + * + * @param wm Pointer to a wiimote_t structure. + */ +static void idle_cycle(struct wiimote_t* wm) { + /* + * Smooth the angles. + * + * This is done to make sure that on every cycle the orientation + * angles are smoothed. Normally when an event occurs the angles + * are updated and smoothed, but if no packet comes in then the + * angles remain the same. This means the angle wiiuse reports + * is still an old value. Smoothing needs to be applied in this + * case in order for the angle it reports to converge to the true + * angle of the device. + */ + if (WIIUSE_USING_ACC(wm) && WIIMOTE_IS_FLAG_SET(wm, WIIUSE_SMOOTHING)) { + apply_smoothing(&wm->accel_calib, &wm->orient, SMOOTH_ROLL); + apply_smoothing(&wm->accel_calib, &wm->orient, SMOOTH_PITCH); + } + + /* clear out any old read requests */ + clear_dirty_reads(wm); +} + + +/** + * @brief Clear out all old 'dirty' read requests. + * + * @param wm Pointer to a wiimote_t structure. + */ +static void clear_dirty_reads(struct wiimote_t* wm) { + struct read_req_t* req = wm->read_req; + + while (req && req->dirty) { + WIIUSE_DEBUG("Cleared old read request for address: %x", req->addr); + + wm->read_req = req->next; + free(req); + req = wm->read_req; + } +} + + +/** + * @brief Analyze the event that occured on a wiimote. + * + * @param wm An array of pointers to wiimote_t structures. + * @param event The event that occured. + * @param msg The message specified in the event packet. + * + * Pass the event to the registered event callback. + */ +static void propagate_event(struct wiimote_t* wm, byte event, byte* msg) { + save_state(wm); + + switch (event) { + case WM_RPT_BTN: + { + /* button */ + wiiuse_pressed_buttons(wm, msg); + break; + } + case WM_RPT_BTN_ACC: + { + /* button - motion */ + wiiuse_pressed_buttons(wm, msg); + + wm->accel.x = msg[2]; + wm->accel.y = msg[3]; + wm->accel.z = msg[4]; + + /* calculate the remote orientation */ + calculate_orientation(&wm->accel_calib, &wm->accel, &wm->orient, WIIMOTE_IS_FLAG_SET(wm, WIIUSE_SMOOTHING)); + + /* calculate the gforces on each axis */ + calculate_gforce(&wm->accel_calib, &wm->accel, &wm->gforce); + + break; + } + case WM_RPT_READ: + { + /* data read */ + event_data_read(wm, msg); + + /* yeah buttons may be pressed, but this wasn't an "event" */ + return; + } + case WM_RPT_CTRL_STATUS: + { + /* controller status */ + event_status(wm, msg); + + /* don't execute the event callback */ + return; + } + case WM_RPT_BTN_EXP: + { + /* button - expansion */ + wiiuse_pressed_buttons(wm, msg); + handle_expansion(wm, msg+2); + + break; + } + case WM_RPT_BTN_ACC_EXP: + { + /* button - motion - expansion */ + wiiuse_pressed_buttons(wm, msg); + + wm->accel.x = msg[2]; + wm->accel.y = msg[3]; + wm->accel.z = msg[4]; + + calculate_orientation(&wm->accel_calib, &wm->accel, &wm->orient, WIIMOTE_IS_FLAG_SET(wm, WIIUSE_SMOOTHING)); + calculate_gforce(&wm->accel_calib, &wm->accel, &wm->gforce); + + handle_expansion(wm, msg+5); + + break; + } + case WM_RPT_BTN_ACC_IR: + { + /* button - motion - ir */ + wiiuse_pressed_buttons(wm, msg); + + wm->accel.x = msg[2]; + wm->accel.y = msg[3]; + wm->accel.z = msg[4]; + + calculate_orientation(&wm->accel_calib, &wm->accel, &wm->orient, WIIMOTE_IS_FLAG_SET(wm, WIIUSE_SMOOTHING)); + calculate_gforce(&wm->accel_calib, &wm->accel, &wm->gforce); + + /* ir */ + calculate_extended_ir(wm, msg+5); + + break; + } + case WM_RPT_BTN_IR_EXP: + { + /* button - ir - expansion */ + wiiuse_pressed_buttons(wm, msg); + handle_expansion(wm, msg+12); + + /* ir */ + calculate_basic_ir(wm, msg+2); + + break; + } + case WM_RPT_BTN_ACC_IR_EXP: + { + /* button - motion - ir - expansion */ + wiiuse_pressed_buttons(wm, msg); + + wm->accel.x = msg[2]; + wm->accel.y = msg[3]; + wm->accel.z = msg[4]; + + calculate_orientation(&wm->accel_calib, &wm->accel, &wm->orient, WIIMOTE_IS_FLAG_SET(wm, WIIUSE_SMOOTHING)); + calculate_gforce(&wm->accel_calib, &wm->accel, &wm->gforce); + + handle_expansion(wm, msg+15); + + /* ir */ + calculate_basic_ir(wm, msg+5); + + break; + } + case WM_RPT_WRITE: + { + /* write feedback - safe to skip */ + break; + } + default: + { + WIIUSE_WARNING("Unknown event, can not handle it [Code 0x%x].", event); + return; + } + } + + /* was there an event? */ + if (state_changed(wm)) + wm->event = WIIUSE_EVENT; +} + + +/** + * @brief Find what buttons are pressed. + * + * @param wm Pointer to a wiimote_t structure. + * @param msg The message specified in the event packet. + */ +void wiiuse_pressed_buttons(struct wiimote_t* wm, byte* msg) { + short now; + + /* convert to big endian */ + now = BIG_ENDIAN_SHORT(*(short*)msg) & WIIMOTE_BUTTON_ALL; + + /* pressed now & were pressed, then held */ + wm->btns_held = (now & wm->btns); + + /* were pressed or were held & not pressed now, then released */ + wm->btns_released = ((wm->btns | wm->btns_held) & ~now); + + /* buttons pressed now */ + wm->btns = now; +} + + +/** + * @brief Received a data packet from a read request. + * + * @param wm Pointer to a wiimote_t structure. + * @param msg The message specified in the event packet. + * + * Data from the wiimote comes in packets. If the requested + * data segment size is bigger than one packet can hold then + * several packets will be received. These packets are first + * reassembled into one, then the registered callback function + * that handles data reads is invoked. + */ +static void event_data_read(struct wiimote_t* wm, byte* msg) { + /* we must always assume the packet received is from the most recent request */ + byte err; + byte len; + unsigned short offset; + struct read_req_t* req = wm->read_req; + + wiiuse_pressed_buttons(wm, msg); + + /* find the next non-dirty request */ + while (req && req->dirty) + req = req->next; + + /* if we don't have a request out then we didn't ask for this packet */ + if (!req) { + WIIUSE_WARNING("Received data packet when no request was made."); + return; + } + + err = msg[2] & 0x0F; + + if (err == 0x08) + WIIUSE_WARNING("Unable to read data - address does not exist."); + else if (err == 0x07) + WIIUSE_WARNING("Unable to read data - address is for write-only registers."); + else if (err) + WIIUSE_WARNING("Unable to read data - unknown error code %x.", err); + + if (err) { + /* this request errored out, so skip it and go to the next one */ + + /* delete this request */ + wm->read_req = req->next; + free(req); + + /* if another request exists send it to the wiimote */ + if (wm->read_req) + wiiuse_send_next_pending_read_request(wm); + + return; + } + + len = ((msg[2] & 0xF0) >> 4) + 1; + offset = BIG_ENDIAN_SHORT(*(unsigned short*)(msg + 3)); + req->addr = (req->addr & 0xFFFF); + + req->wait -= len; + if (req->wait >= req->size) + /* this should never happen */ + req->wait = 0; + + WIIUSE_DEBUG("Received read packet:"); + WIIUSE_DEBUG(" Packet read offset: %i bytes", offset); + WIIUSE_DEBUG(" Request read offset: %i bytes", req->addr); + WIIUSE_DEBUG(" Read offset into buf: %i bytes", offset - req->addr); + WIIUSE_DEBUG(" Read data size: %i bytes", len); + WIIUSE_DEBUG(" Still need: %i bytes", req->wait); + + /* reconstruct this part of the data */ + memcpy((req->buf + offset - req->addr), (msg + 5), len); + + #ifdef WITH_WIIUSE_DEBUG + { + int i = 0; + printf("Read: "); + for (; i < req->size - req->wait; ++i) + printf("%x ", req->buf[i]); + printf("\n"); + } + #endif + + /* if all data has been received, execute the read event callback or generate event */ + if (!req->wait) { + if (req->cb) { + /* this was a callback, so invoke it now */ + req->cb(wm, req->buf, req->size); + + /* delete this request */ + wm->read_req = req->next; + free(req); + } else { + /* + * This should generate an event. + * We need to leave the event in the array so the client + * can access it still. We'll flag is as being 'dirty' + * and give the client one cycle to use it. Next event + * we will remove it from the list. + */ + wm->event = WIIUSE_READ_DATA; + req->dirty = 1; + } + + /* if another request exists send it to the wiimote */ + if (wm->read_req) + wiiuse_send_next_pending_read_request(wm); + } +} + + +/** + * @brief Read the controller status. + * + * @param wm Pointer to a wiimote_t structure. + * @param msg The message specified in the event packet. + * + * Read the controller status and execute the registered status callback. + */ +static void event_status(struct wiimote_t* wm, byte* msg) { + int led[4] = {0}; + int attachment = 0; + int ir = 0; + int exp_changed = 0; + + /* + * An event occured. + * This event can be overwritten by a more specific + * event type during a handshake or expansion removal. + */ + wm->event = WIIUSE_STATUS; + + wiiuse_pressed_buttons(wm, msg); + + /* find what LEDs are lit */ + if (msg[2] & WM_CTRL_STATUS_BYTE1_LED_1) led[0] = 1; + if (msg[2] & WM_CTRL_STATUS_BYTE1_LED_2) led[1] = 1; + if (msg[2] & WM_CTRL_STATUS_BYTE1_LED_3) led[2] = 1; + if (msg[2] & WM_CTRL_STATUS_BYTE1_LED_4) led[3] = 1; + + /* is an attachment connected to the expansion port? */ + if ((msg[2] & WM_CTRL_STATUS_BYTE1_ATTACHMENT) == WM_CTRL_STATUS_BYTE1_ATTACHMENT) + attachment = 1; + + /* is the speaker enabled? */ + if ((msg[2] & WM_CTRL_STATUS_BYTE1_SPEAKER_ENABLED) == WM_CTRL_STATUS_BYTE1_SPEAKER_ENABLED) + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_SPEAKER); + + /* is IR sensing enabled? */ + if ((msg[2] & WM_CTRL_STATUS_BYTE1_IR_ENABLED) == WM_CTRL_STATUS_BYTE1_IR_ENABLED) + ir = 1; + + /* find the battery level and normalize between 0 and 1 */ + wm->battery_level = (msg[5] / (float)WM_MAX_BATTERY_CODE); + + /* expansion port */ + if (attachment && !WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP)) { + /* send the initialization code for the attachment */ + handshake_expansion(wm, NULL, 0); + exp_changed = 1; + } else if (!attachment && WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP)) { + /* attachment removed */ + disable_expansion(wm); + exp_changed = 1; + } + + #ifdef WIN32 + if (!attachment) { + WIIUSE_DEBUG("Setting timeout to normal %i ms.", wm->normal_timeout); + wm->timeout = wm->normal_timeout; + } + #endif + + /* + * From now on the remote will only send status packets. + * We need to send a WIIMOTE_CMD_REPORT_TYPE packet to + * reenable other incoming reports. + */ + if (exp_changed && WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) { + /* + * Since the expansion status changed IR needs to + * be reset for the new IR report mode. + */ + WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR); + wiiuse_set_ir(wm, 1); + } else + wiiuse_set_report_type(wm); +} + + +/** + * @brief Handle data from the expansion. + * + * @param wm A pointer to a wiimote_t structure. + * @param msg The message specified in the event packet for the expansion. + */ +static void handle_expansion(struct wiimote_t* wm, byte* msg) { + switch (wm->exp.type) { + case EXP_NUNCHUK: + nunchuk_event(&wm->exp.nunchuk, msg); + break; + case EXP_CLASSIC: + classic_ctrl_event(&wm->exp.classic, msg); + break; + case EXP_GUITAR_HERO_3: + guitar_hero_3_event(&wm->exp.gh3, msg); + break; + default: + break; + } +} + + +/** + * @brief Handle the handshake data from the expansion device. + * + * @param wm A pointer to a wiimote_t structure. + * @param data The data read in from the device. + * @param len The length of the data block, in bytes. + * + * Tries to determine what kind of expansion was attached + * and invoke the correct handshake function. + * + * If the data is NULL then this function will try to start + * a handshake with the expansion. + */ +void handshake_expansion(struct wiimote_t* wm, byte* data, unsigned short len) { + int id; + + if (!data) { + byte* handshake_buf; + byte buf = 0x00; + + if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP)) + disable_expansion(wm); + + /* increase the timeout until the handshake completes */ + #ifdef WIN32 + WIIUSE_DEBUG("Setting timeout to expansion %i ms.", wm->exp_timeout); + wm->timeout = wm->exp_timeout; + #endif + + wiiuse_write_data(wm, WM_EXP_MEM_ENABLE, &buf, 1); + + /* get the calibration data */ + handshake_buf = malloc(EXP_HANDSHAKE_LEN * sizeof(byte)); + wiiuse_read_data_cb(wm, handshake_expansion, handshake_buf, WM_EXP_MEM_CALIBR, EXP_HANDSHAKE_LEN); + + /* tell the wiimote to send expansion data */ + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_EXP); + + return; + } + + id = BIG_ENDIAN_LONG(*(int*)(data + 220)); + + /* call the corresponding handshake function for this expansion */ + switch (id) { + case EXP_ID_CODE_NUNCHUK: + { + if (nunchuk_handshake(wm, &wm->exp.nunchuk, data, len)) + wm->event = WIIUSE_NUNCHUK_INSERTED; + break; + } + case EXP_ID_CODE_CLASSIC_CONTROLLER: + { + if (classic_ctrl_handshake(wm, &wm->exp.classic, data, len)) + wm->event = WIIUSE_CLASSIC_CTRL_INSERTED; + break; + } + case EXP_ID_CODE_GUITAR: + { + if (guitar_hero_3_handshake(wm, &wm->exp.gh3, data, len)) + wm->event = WIIUSE_GUITAR_HERO_3_CTRL_INSERTED; + break; + } + default: + { + WIIUSE_WARNING("Unknown expansion type. Code: 0x%x", id); + break; + } + } + + free(data); +} + + + +/** + * @brief Disable the expansion device if it was enabled. + * + * @param wm A pointer to a wiimote_t structure. + * @param data The data read in from the device. + * @param len The length of the data block, in bytes. + * + * If the data is NULL then this function will try to start + * a handshake with the expansion. + */ +void disable_expansion(struct wiimote_t* wm) { + if (!WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP)) + return; + + /* tell the assoicated module the expansion was removed */ + switch (wm->exp.type) { + case EXP_NUNCHUK: + nunchuk_disconnected(&wm->exp.nunchuk); + wm->event = WIIUSE_NUNCHUK_REMOVED; + break; + case EXP_CLASSIC: + classic_ctrl_disconnected(&wm->exp.classic); + wm->event = WIIUSE_CLASSIC_CTRL_REMOVED; + break; + case EXP_GUITAR_HERO_3: + guitar_hero_3_disconnected(&wm->exp.gh3); + wm->event = WIIUSE_GUITAR_HERO_3_CTRL_REMOVED; + break; + default: + break; + } + + WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP); + wm->exp.type = EXP_NONE; +} + + +/** + * @brief Save important state data. + * @param wm A pointer to a wiimote_t structure. + */ +static void save_state(struct wiimote_t* wm) { + /* wiimote */ + wm->lstate.btns = wm->btns; + wm->lstate.accel = wm->accel; + + /* ir */ + if (WIIUSE_USING_IR(wm)) { + wm->lstate.ir_ax = wm->ir.ax; + wm->lstate.ir_ay = wm->ir.ay; + wm->lstate.ir_distance = wm->ir.distance; + } + + /* expansion */ + switch (wm->exp.type) { + case EXP_NUNCHUK: + wm->lstate.exp_ljs_ang = wm->exp.nunchuk.js.ang; + wm->lstate.exp_ljs_mag = wm->exp.nunchuk.js.mag; + wm->lstate.exp_btns = wm->exp.nunchuk.btns; + wm->lstate.exp_accel = wm->exp.nunchuk.accel; + break; + + case EXP_CLASSIC: + wm->lstate.exp_ljs_ang = wm->exp.classic.ljs.ang; + wm->lstate.exp_ljs_mag = wm->exp.classic.ljs.mag; + wm->lstate.exp_rjs_ang = wm->exp.classic.rjs.ang; + wm->lstate.exp_rjs_mag = wm->exp.classic.rjs.mag; + wm->lstate.exp_r_shoulder = wm->exp.classic.r_shoulder; + wm->lstate.exp_l_shoulder = wm->exp.classic.l_shoulder; + wm->lstate.exp_btns = wm->exp.classic.btns; + break; + + case EXP_GUITAR_HERO_3: + wm->lstate.exp_ljs_ang = wm->exp.gh3.js.ang; + wm->lstate.exp_ljs_mag = wm->exp.gh3.js.mag; + wm->lstate.exp_r_shoulder = wm->exp.gh3.whammy_bar; + wm->lstate.exp_btns = wm->exp.gh3.btns; + break; + + case EXP_NONE: + break; + } +} + + +/** + * @brief Determine if the current state differs significantly from the previous. + * @param wm A pointer to a wiimote_t structure. + * @return 1 if a significant change occured, 0 if not. + */ +static int state_changed(struct wiimote_t* wm) { + #define STATE_CHANGED(a, b) if (a != b) return 1 + + #define CROSS_THRESH(last, now, thresh) \ + do { \ + if (WIIMOTE_IS_FLAG_SET(wm, WIIUSE_ORIENT_THRESH)) { \ + if ((diff_f(last.roll, now.roll) >= thresh) || \ + (diff_f(last.pitch, now.pitch) >= thresh) || \ + (diff_f(last.yaw, now.yaw) >= thresh)) \ + { \ + last = now; \ + return 1; \ + } \ + } else { \ + if (last.roll != now.roll) return 1; \ + if (last.pitch != now.pitch) return 1; \ + if (last.yaw != now.yaw) return 1; \ + } \ + } while (0) + + #define CROSS_THRESH_XYZ(last, now, thresh) \ + do { \ + if (WIIMOTE_IS_FLAG_SET(wm, WIIUSE_ORIENT_THRESH)) { \ + if ((diff_f(last.x, now.x) >= thresh) || \ + (diff_f(last.y, now.y) >= thresh) || \ + (diff_f(last.z, now.z) >= thresh)) \ + { \ + last = now; \ + return 1; \ + } \ + } else { \ + if (last.x != now.x) return 1; \ + if (last.y != now.y) return 1; \ + if (last.z != now.z) return 1; \ + } \ + } while (0) + + /* ir */ + if (WIIUSE_USING_IR(wm)) { + STATE_CHANGED(wm->lstate.ir_ax, wm->ir.ax); + STATE_CHANGED(wm->lstate.ir_ay, wm->ir.ay); + STATE_CHANGED(wm->lstate.ir_distance, wm->ir.distance); + } + + /* accelerometer */ + if (WIIUSE_USING_ACC(wm)) { + /* raw accelerometer */ + CROSS_THRESH_XYZ(wm->lstate.accel, wm->accel, wm->accel_threshold); + + /* orientation */ + CROSS_THRESH(wm->lstate.orient, wm->orient, wm->orient_threshold); + } + + /* expansion */ + switch (wm->exp.type) { + case EXP_NUNCHUK: + { + STATE_CHANGED(wm->lstate.exp_ljs_ang, wm->exp.nunchuk.js.ang); + STATE_CHANGED(wm->lstate.exp_ljs_mag, wm->exp.nunchuk.js.mag); + STATE_CHANGED(wm->lstate.exp_btns, wm->exp.nunchuk.btns); + + CROSS_THRESH(wm->lstate.exp_orient, wm->exp.nunchuk.orient, wm->exp.nunchuk.orient_threshold); + CROSS_THRESH_XYZ(wm->lstate.exp_accel, wm->exp.nunchuk.accel, wm->exp.nunchuk.accel_threshold); + break; + } + case EXP_CLASSIC: + { + STATE_CHANGED(wm->lstate.exp_ljs_ang, wm->exp.classic.ljs.ang); + STATE_CHANGED(wm->lstate.exp_ljs_mag, wm->exp.classic.ljs.mag); + STATE_CHANGED(wm->lstate.exp_rjs_ang, wm->exp.classic.rjs.ang); + STATE_CHANGED(wm->lstate.exp_rjs_mag, wm->exp.classic.rjs.mag); + STATE_CHANGED(wm->lstate.exp_r_shoulder, wm->exp.classic.r_shoulder); + STATE_CHANGED(wm->lstate.exp_l_shoulder, wm->exp.classic.l_shoulder); + STATE_CHANGED(wm->lstate.exp_btns, wm->exp.classic.btns); + break; + } + case EXP_GUITAR_HERO_3: + { + STATE_CHANGED(wm->lstate.exp_ljs_ang, wm->exp.gh3.js.ang); + STATE_CHANGED(wm->lstate.exp_ljs_mag, wm->exp.gh3.js.mag); + STATE_CHANGED(wm->lstate.exp_r_shoulder, wm->exp.gh3.whammy_bar); + STATE_CHANGED(wm->lstate.exp_btns, wm->exp.gh3.btns); + break; + } + case EXP_NONE: + { + break; + } + } + + STATE_CHANGED(wm->lstate.btns, wm->btns); + + return 0; +} diff --git a/Externals/WiiUseSrc/Src/events.h b/Externals/WiiUseSrc/Src/events.h new file mode 100644 index 0000000000..5e9b955c55 --- /dev/null +++ b/Externals/WiiUseSrc/Src/events.h @@ -0,0 +1,54 @@ +/* + * 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 . + * + * $Header$ + * + */ + +/** + * @file + * @brief Handles wiimote events. + * + * The file includes functions that handle the events + * that are sent from the wiimote to us. + */ + +#ifndef EVENTS_H_INCLUDED +#define EVENTS_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +void wiiuse_pressed_buttons(struct wiimote_t* wm, byte* msg); + +void handshake_expansion(struct wiimote_t* wm, byte* data, unsigned short len); +void disable_expansion(struct wiimote_t* wm); + +#ifdef __cplusplus +} +#endif + + +#endif // EVENTS_H_INCLUDED diff --git a/Externals/WiiUseSrc/Src/guitar_hero_3.c b/Externals/WiiUseSrc/Src/guitar_hero_3.c new file mode 100644 index 0000000000..5837dc016f --- /dev/null +++ b/Externals/WiiUseSrc/Src/guitar_hero_3.c @@ -0,0 +1,172 @@ +/* + * 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 . + * + * $Header$ + * + */ + +/** + * @file + * @brief Guitar Hero 3 expansion device. + */ + +#include +#include +#include + +#ifdef WIN32 + #include +#endif + +#include "definitions.h" +#include "wiiuse_internal.h" +#include "dynamics.h" +#include "events.h" +#include "guitar_hero_3.h" + +static void guitar_hero_3_pressed_buttons(struct guitar_hero_3_t* gh3, short now); + +/** + * @brief Handle the handshake data from the guitar. + * + * @param cc A pointer to a classic_ctrl_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 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 + * failed to factory calibrate the devices. There is no + * calibration data on the device. + */ + + gh3->btns = 0; + gh3->btns_held = 0; + 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) { + /* + * Sometimes the data returned here is not correct. + * This might happen because the wiimote is lagging + * behind our initialization sequence. + * To fix this just request the handshake again. + * + * Other times it's just the first 16 bytes are 0xFF, + * but since the next 16 bytes are the same, just use + * those. + */ + if (data[offset + 16] == 0xFF) { + /* get the calibration data */ + byte* handshake_buf = malloc(EXP_HANDSHAKE_LEN * sizeof(byte)); + + WIIUSE_DEBUG("Guitar Hero 3 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; + } + + /* joystick stuff */ + gh3->js.max.x = GUITAR_HERO_3_JS_MAX_X; + gh3->js.min.x = GUITAR_HERO_3_JS_MIN_X; + gh3->js.center.x = GUITAR_HERO_3_JS_CENTER_X; + gh3->js.max.y = GUITAR_HERO_3_JS_MAX_Y; + gh3->js.min.y = GUITAR_HERO_3_JS_MIN_Y; + gh3->js.center.y = GUITAR_HERO_3_JS_CENTER_Y; + + /* handshake done */ + wm->exp.type = EXP_GUITAR_HERO_3; + + #ifdef WIN32 + wm->timeout = WIIMOTE_DEFAULT_TIMEOUT; + #endif + + return 1; +} + + +/** + * @brief The guitar disconnected. + * + * @param cc A pointer to a classic_ctrl_t structure. + */ +void guitar_hero_3_disconnected(struct guitar_hero_3_t* gh3) { + memset(gh3, 0, sizeof(struct guitar_hero_3_t)); +} + + + +/** + * @brief Handle guitar event. + * + * @param cc A pointer to a classic_ctrl_t structure. + * @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))); + + /* 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); + + /* joy stick */ + calc_joystick_state(&gh3->js, msg[0], msg[1]); +} + + +/** + * @brief Find what buttons are pressed. + * + * @param cc A pointer to a classic_ctrl_t structure. + * @param msg The message byte specified in the event packet. + */ +static void guitar_hero_3_pressed_buttons(struct guitar_hero_3_t* gh3, short now) { + /* message is inverted (0 is active, 1 is inactive) */ + now = ~now & GUITAR_HERO_3_BUTTON_ALL; + + /* pressed now & were pressed, then held */ + gh3->btns_held = (now & gh3->btns); + + /* were pressed or were held & not pressed now, then released */ + gh3->btns_released = ((gh3->btns | gh3->btns_held) & ~now); + + /* buttons pressed now */ + gh3->btns = now; +} diff --git a/Externals/WiiUseSrc/Src/guitar_hero_3.h b/Externals/WiiUseSrc/Src/guitar_hero_3.h new file mode 100644 index 0000000000..024d603177 --- /dev/null +++ b/Externals/WiiUseSrc/Src/guitar_hero_3.h @@ -0,0 +1,62 @@ +/* + * 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 . + * + * $Header$ + * + */ + +/** + * @file + * @brief Guitar Hero 3 expansion device. + */ + +#ifndef GUITAR_HERO_3_H_INCLUDED +#define GUITAR_HERO_3_H_INCLUDED + +#include "wiiuse_internal.h" + +#define GUITAR_HERO_3_JS_MIN_X 0xC5 +#define GUITAR_HERO_3_JS_MAX_X 0xFC +#define GUITAR_HERO_3_JS_CENTER_X 0xE0 +#define GUITAR_HERO_3_JS_MIN_Y 0xC5 +#define GUITAR_HERO_3_JS_MAX_Y 0xFA +#define GUITAR_HERO_3_JS_CENTER_Y 0xE0 +#define GUITAR_HERO_3_WHAMMY_BAR_MIN 0xEF +#define GUITAR_HERO_3_WHAMMY_BAR_MAX 0xFA + +#ifdef __cplusplus +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); + +void guitar_hero_3_event(struct guitar_hero_3_t* gh3, byte* msg); + +#ifdef __cplusplus +} +#endif + +#endif // GUITAR_HERO_3_H_INCLUDED diff --git a/Externals/WiiUseSrc/Src/io.c b/Externals/WiiUseSrc/Src/io.c new file mode 100644 index 0000000000..ae420b9ef3 --- /dev/null +++ b/Externals/WiiUseSrc/Src/io.c @@ -0,0 +1,119 @@ +/* + * 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 . + * + * $Header$ + * + */ + +/** + * @file + * @brief Handles device I/O (non-OS specific). + */ + +#include +#include + +#include "definitions.h" +#include "wiiuse_internal.h" +#include "io.h" + + + /** + * @brief Get initialization data from the wiimote. + * + * @param wm Pointer to a wiimote_t structure. + * @param data unused + * @param len unused + * + * When first called for a wiimote_t structure, a request + * is sent to the wiimote for initialization information. + * This includes factory set accelerometer data. + * 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; + + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE); + wiiuse_set_leds(wm, WIIMOTE_LED_NONE); + + 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; + + /* 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; + } + } +} diff --git a/Externals/WiiUseSrc/Src/io.h b/Externals/WiiUseSrc/Src/io.h new file mode 100644 index 0000000000..7a683e4ee5 --- /dev/null +++ b/Externals/WiiUseSrc/Src/io.h @@ -0,0 +1,56 @@ +/* + * 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 . + * + * $Header$ + * + */ + +/** + * @file + * @brief Handles device I/O. + */ + +#ifndef CONNECT_H_INCLUDED +#define CONNECT_H_INCLUDED + +#ifndef WIN32 + #include +#endif + +#include "wiiuse_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void wiiuse_handshake(struct wiimote_t* wm, byte* data, unsigned short len); + +int wiiuse_io_read(struct wiimote_t* wm); +int wiiuse_io_write(struct wiimote_t* wm, byte* buf, int len); + +#ifdef __cplusplus +} +#endif + +#endif // CONNECT_H_INCLUDED diff --git a/Externals/WiiUseSrc/Src/io_nix.c b/Externals/WiiUseSrc/Src/io_nix.c new file mode 100644 index 0000000000..ec4e0e1780 --- /dev/null +++ b/Externals/WiiUseSrc/Src/io_nix.c @@ -0,0 +1,270 @@ +/* + * 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 . + * + * $Header$ + * + */ + +/** + * @file + * @brief Handles device I/O for *nix. + */ + +#ifndef WIN32 + +#include +#include +#include + +#include +#include +#include +#include + +#include "definitions.h" +#include "wiiuse_internal.h" +#include "io.h" + +static int wiiuse_connect_single(struct wiimote_t* wm, char* address); + +/** + * @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 wiimote_connect() + * + * 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 wiimote_connect() to connect to the found \n + * devices. + */ +int wiiuse_find(struct wiimote_t** wm, int max_wiimotes, int timeout) { + int device_id; + int device_sock; + int found_devices; + int found_wiimotes; + + /* reset all wiimote bluetooth device addresses */ + for (found_wiimotes = 0; found_wiimotes < max_wiimotes; ++found_wiimotes) + wm[found_wiimotes]->bdaddr = *BDADDR_ANY; + found_wiimotes = 0; + + /* get the id of the first bluetooth device. */ + device_id = hci_get_route(NULL); + if (device_id < 0) { + 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; + } + + inquiry_info scan_info_arr[128]; + inquiry_info* scan_info = scan_info_arr; + 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); + + int i = 0; + + /* display discovered devices */ + for (; (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; +} + + +/** + * @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_connect_single() + * @see wiiuse_disconnect() + * + * 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. + */ +int wiiuse_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_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_find(). + * + * @return 1 on success, 0 on failure + */ +static int wiiuse_connect_single(struct wiimote_t* wm, char* address) { + struct sockaddr_l2 addr; + + if (!wm || WIIMOTE_IS_CONNECTED(wm)) + return 0; + + addr.l2_family = AF_BLUETOOTH; + + if (address) + /* use provided address */ + str2ba(address, &addr.l2_bdaddr); + else + /* use address of device discovered */ + addr.l2_bdaddr = wm->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; +} + + +/** + * @brief Disconnect a wiimote. + * + * @param wm Pointer to a wiimote_t structure. + * + * @see wiiuse_connect() + * + * Note that this will not free the wiimote structure. + */ +void wiiuse_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_io_read(struct wiimote_t* wm) { + /* not used */ + return 0; +} + + +int wiiuse_io_write(struct wiimote_t* wm, byte* buf, int len) { + return write(wm->out_sock, buf, len); +} + + + +#endif /* ifndef WIN32 */ diff --git a/Externals/WiiUseSrc/Src/io_win.c b/Externals/WiiUseSrc/Src/io_win.c new file mode 100644 index 0000000000..17fac360d3 --- /dev/null +++ b/Externals/WiiUseSrc/Src/io_win.c @@ -0,0 +1,247 @@ +/* + * 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 . + * + * $Header$ + * + */ + +/** + * @file + * @brief Handles device I/O for Windows. + */ + +#ifdef WIN32 + +#include +#include + +#include +#include +#include + +#include "definitions.h" +#include "wiiuse_internal.h" +#include "io.h" + + +int wiiuse_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 = 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_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_CONNECTED)) + ++connected; + } + + return connected; +} + + +void wiiuse_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_io_read(struct wiimote_t* wm) { + DWORD b, r; + + if (!wm || !WIIMOTE_IS_CONNECTED(wm)) + return 0; + + if (!ReadFile(wm->dev_handle, wm->event_buf, sizeof(wm->event_buf), &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 (*wm->event_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 occured on reading from wiimote %i.", wm->unid); + return 0; + } + + if (!GetOverlappedResult(wm->dev_handle, &wm->hid_overlap, &b, 0)) + return 0; + } + + ResetEvent(wm->hid_overlap.hEvent); + return 1; +} + + +int wiiuse_io_write(struct wiimote_t* wm, byte* buf, int len) { + DWORD bytes; + int i; + + if (!wm || !WIIMOTE_IS_CONNECTED(wm)) + return 0; + + switch (wm->stack) { + case WIIUSE_STACK_UNKNOWN: + { + /* try to auto-detect the stack type */ + if (i = WriteFile(wm->dev_handle, buf, 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, buf, len)) { + 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, buf, len); + + case WIIUSE_STACK_BLUESOLEIL: + return WriteFile(wm->dev_handle, buf, 22, &bytes, &wm->hid_overlap); + } + + return 0; +} + +#endif /* ifdef WIN32 */ diff --git a/Externals/WiiUseSrc/Src/ir.c b/Externals/WiiUseSrc/Src/ir.c new file mode 100644 index 0000000000..7a9bb68289 --- /dev/null +++ b/Externals/WiiUseSrc/Src/ir.c @@ -0,0 +1,748 @@ +/* + * 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 . + * + * $Header$ + * + */ + +/** + * @file + * @brief Handles IR data. + */ + +#include +#include + +#ifndef WIN32 + #include +#endif + +#include "definitions.h" +#include "wiiuse_internal.h" +#include "ir.h" + +static int get_ir_sens(struct wiimote_t* wm, char** block1, char** 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); +static void reorder_ir_dots(struct ir_dot_t* dot); +static float ir_distance(struct ir_dot_t* dot); +static int ir_correct_for_bounds(int* x, int* y, enum aspect_t aspect, int offset_x, int offset_y); +static void ir_convert_to_vres(int* x, int* y, enum aspect_t aspect, int vx, int vy); + + +/** + * @brief Set if the wiimote should track IR targets. + * + * @param wm Pointer to a wiimote_t structure. + * @param status 1 to enable, 0 to disable. + */ +void wiiuse_set_ir(struct wiimote_t* wm, int status) { + byte buf; + char* block1 = NULL; + char* block2 = NULL; + int ir_level; + + 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."); + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR); + 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)) + return; + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR); + } else { + /* if already disabled then stop */ + if (!WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) + return; + WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR); + } + + /* set camera 1 and 2 */ + buf = (status ? 0x04 : 0x00); + wiiuse_send(wm, WM_CMD_IR, &buf, 1); + wiiuse_send(wm, WM_CMD_IR_2, &buf, 1); + + if (!status) { + WIIUSE_DEBUG("Disabled IR cameras for wiimote id %i.", wm->unid); + wiiuse_set_report_type(wm); + return; + } + + /* enable IR, set sensitivity */ + buf = 0x08; + wiiuse_write_data(wm, WM_REG_IR, &buf, 1); + + /* wait for the wiimote to catch up */ + #ifndef WIN32 + usleep(50000); + #else + Sleep(50); + #endif + + /* 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)) + buf = WM_IR_TYPE_BASIC; + else + buf = WM_IR_TYPE_EXTENDED; + wiiuse_write_data(wm, WM_REG_IR_MODENUM, &buf, 1); + + #ifndef WIN32 + usleep(50000); + #else + Sleep(50); + #endif + + /* set the wiimote report type */ + wiiuse_set_report_type(wm); + + WIIUSE_DEBUG("Enabled IR camera for wiimote id %i (sensitivity level %i).", wm->unid, ir_level); +} + + +/** + * @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; +} + + +/** + * @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 + 100; + else if (wm->ir.aspect == WIIUSE_ASPECT_4_3) + wm->ir.offset[1] = -WM_ASPECT_4_3_Y/2 + 70; + + 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; + } + + /* 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_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, byte* 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) { + 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 */ + } + } + + interpret_ir_data(wm); +} + + +/** + * @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, byte* 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] & 0x0F; + + /* if in range set to visible */ + if (dot[i].ry == 1023) + dot[i].visible = 0; + else + dot[i].visible = 1; + } + + interpret_ir_data(wm); +} + + +/** + * @brief Interpret IR data into more user friendly variables. + * + * @param wm Pointer to a wiimote_t structure. + */ +static void interpret_ir_data(struct wiimote_t* wm) { + struct ir_dot_t* dot = wm->ir.dot; + int i; + float roll = 0.0f; + int last_num_dots = wm->ir.num_dots; + + 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) + wm->ir.num_dots++; + } + + switch (wm->ir.num_dots) { + 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. + */ + 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; + } + } + } 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.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 + { + 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 +} + + + +/** + * @brief Fix the rotation of the IR dots. + * + * @param dot An array of 4 ir_dot_t objects. + * @param ang The roll angle to correct by (-180, 180) + * + * If there is roll then the dots are rotated + * around the origin and give a false cursor + * position. Correct for the roll. + * + * If the accelerometer is off then obviously + * this will not do anything and the cursor + * position may be inaccurate. + */ +static void fix_rotated_ir_dots(struct ir_dot_t* dot, float ang) { + float s, c; + int x, y; + int i; + + if (!ang) { + for (i = 0; i < 4; ++i) { + dot[i].x = dot[i].rx; + dot[i].y = dot[i].ry; + } + 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 < 4; ++i) { + if (!dot[i].visible) + continue; + + 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 += (1024/2); + dot[i].y += (768/2); + } +} + + +/** + * @brief Average IR dots. + * + * @param dot An array of 4 ir_dot_t objects. + * @param x [out] Average X + * @param y [out] Average Y + */ +static void get_ir_dot_avg(struct ir_dot_t* dot, int* x, int* y) { + int vis = 0, i = 0; + + *x = 0; + *y = 0; + + for (; i < 4; ++i) { + if (dot[i].visible) { + *x += dot[i].x; + *y += dot[i].y; + ++vis; + } + } + + *x /= vis; + *y /= vis; +} + + +/** + * @brief Reorder the IR dots. + * + * @param dot An array of 4 ir_dot_t objects. + */ +static void reorder_ir_dots(struct ir_dot_t* dot) { + int i, j, order; + + /* reset the dot ordering */ + 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; + + for (j = 0; j < 4; ++j) { + if (dot[j].visible && !dot[j].order && (dot[j].x < dot[i].x)) + i = j; + } + + dot[i].order = order; + } +} + + +/** + * @brief Calculate the distance between the first 2 visible IR dots. + * + * @param dot An array of 4 ir_dot_t objects. + */ +static float ir_distance(struct ir_dot_t* dot) { + int i1, i2; + int xd, yd; + + for (i1 = 0; i1 < 4; ++i1) + if (dot[i1].visible) + break; + if (i1 == 4) + return 0.0f; + + for (i2 = i1+1; i2 < 4; ++i2) + if (dot[i2].visible) + break; + 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); +} + + +/** + * @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(int* x, int* y, enum aspect_t aspect, int offset_x, int offset_y) { + int 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(int* x, int* y, enum aspect_t aspect, int vx, 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; +} + + +/** + * @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 = x * (ir->z / 1024.0f); + + return RAD_TO_DEGREE( atanf(x / ir->z) ); +} diff --git a/Externals/WiiUseSrc/Src/ir.h b/Externals/WiiUseSrc/Src/ir.h new file mode 100644 index 0000000000..9082492987 --- /dev/null +++ b/Externals/WiiUseSrc/Src/ir.h @@ -0,0 +1,56 @@ +/* + * 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 . + * + * $Header$ + * + */ + +/** + * @file + * @brief Handles IR data. + */ + +#ifndef IR_H_INCLUDED +#define IR_H_INCLUDED + +#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, 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 + + diff --git a/Externals/WiiUseSrc/Src/nunchuk.c b/Externals/WiiUseSrc/Src/nunchuk.c new file mode 100644 index 0000000000..48dbe6a089 --- /dev/null +++ b/Externals/WiiUseSrc/Src/nunchuk.c @@ -0,0 +1,210 @@ +/* + * 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 . + * + * $Header$ + * + */ + +/** + * @file + * @brief Nunchuk expansion device. + */ + +#include +#include +#include + +#include "definitions.h" +#include "wiiuse_internal.h" +#include "dynamics.h" +#include "events.h" +#include "nunchuk.h" + +static void nunchuk_pressed_buttons(struct nunchuk_t* nc, byte now); + +/** + * @brief Handle the handshake data from the nunchuk. + * + * @param nc A pointer to a nunchuk_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 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; + + /* set the smoothing to the same as the wiimote */ + 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) { + /* + * Sometimes the data returned here is not correct. + * This might happen because the wiimote is lagging + * behind our initialization sequence. + * To fix this just request the handshake again. + * + * Other times it's just the first 16 bytes are 0xFF, + * but since the next 16 bytes are the same, just use + * those. + */ + if (data[offset + 16] == 0xFF) { + /* get the calibration data */ + byte* handshake_buf = 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; + } + + 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]; + + /* default the thresholds to the same as the wiimote */ + nc->orient_threshold = wm->orient_threshold; + nc->accel_threshold = wm->accel_threshold; + + /* handshake done */ + wm->exp.type = EXP_NUNCHUK; + + #ifdef WIN32 + wm->timeout = WIIMOTE_DEFAULT_TIMEOUT; + #endif + + return 1; +} + + +/** + * @brief The nunchuk disconnected. + * + * @param nc A pointer to a nunchuk_t structure. + */ +void nunchuk_disconnected(struct nunchuk_t* nc) { + memset(nc, 0, sizeof(struct nunchuk_t)); +} + + + +/** + * @brief Handle nunchuk event. + * + * @param nc A pointer to a nunchuk_t structure. + * @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]); + + /* calculate joystick state */ + calc_joystick_state(&nc->js, msg[0], msg[1]); + + /* calculate orientation */ + nc->accel.x = msg[2]; + nc->accel.y = msg[3]; + nc->accel.z = msg[4]; + + calculate_orientation(&nc->accel_calib, &nc->accel, &nc->orient, NUNCHUK_IS_FLAG_SET(nc, WIIUSE_SMOOTHING)); + calculate_gforce(&nc->accel_calib, &nc->accel, &nc->gforce); +} + + +/** + * @brief Find what buttons are pressed. + * + * @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) { + /* message is inverted (0 is active, 1 is inactive) */ + now = ~now & NUNCHUK_BUTTON_ALL; + + /* pressed now & were pressed, then held */ + nc->btns_held = (now & nc->btns); + + /* were pressed or were held & not pressed now, then released */ + nc->btns_released = ((nc->btns | nc->btns_held) & ~now); + + /* buttons pressed now */ + nc->btns = now; +} + + +/** + * @brief Set the orientation event threshold for the nunchuk. + * + * @param wm Pointer to a wiimote_t structure with a nunchuk attached. + * @param threshold The decimal place that should be considered a significant change. + * + * See wiiuse_set_orient_threshold() for details. + */ +void wiiuse_set_nunchuk_orient_threshold(struct wiimote_t* wm, float threshold) { + if (!wm) return; + + wm->exp.nunchuk.orient_threshold = threshold; +} + + +/** + * @brief Set the accelerometer event threshold for the nunchuk. + * + * @param wm Pointer to a wiimote_t structure with a nunchuk attached. + * @param threshold The decimal place that should be considered a significant change. + * + * See wiiuse_set_orient_threshold() for details. + */ +void wiiuse_set_nunchuk_accel_threshold(struct wiimote_t* wm, int threshold) { + if (!wm) return; + + wm->exp.nunchuk.accel_threshold = threshold; +} diff --git a/Externals/WiiUseSrc/Src/nunchuk.h b/Externals/WiiUseSrc/Src/nunchuk.h new file mode 100644 index 0000000000..f036073d64 --- /dev/null +++ b/Externals/WiiUseSrc/Src/nunchuk.h @@ -0,0 +1,53 @@ +/* + * 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 . + * + * $Header$ + * + */ + +/** + * @file + * @brief Nunchuk expansion device. + */ + +#ifndef NUNCHUK_H_INCLUDED +#define NUNCHUK_H_INCLUDED + +#include "wiiuse_internal.h" + +#ifdef __cplusplus +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); + +void nunchuk_event(struct nunchuk_t* nc, byte* msg); + +#ifdef __cplusplus +} +#endif + +#endif // NUNCHUK_H_INCLUDED diff --git a/Externals/WiiUseSrc/Src/os.h b/Externals/WiiUseSrc/Src/os.h new file mode 100644 index 0000000000..53b80f557c --- /dev/null +++ b/Externals/WiiUseSrc/Src/os.h @@ -0,0 +1,56 @@ +/* + * 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 . + * + * $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 OS_H_INCLUDED +#define OS_H_INCLUDED + +#ifdef WIN32 + /* windows */ + #define isnan(x) _isnan(x) + #define isinf(x) !_finite(x) + + /* 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 */ +#endif + + +#endif // OS_H_INCLUDED diff --git a/Externals/WiiUseSrc/Src/wiiuse.c b/Externals/WiiUseSrc/Src/wiiuse.c new file mode 100644 index 0000000000..8d4b763864 --- /dev/null +++ b/Externals/WiiUseSrc/Src/wiiuse.c @@ -0,0 +1,764 @@ +/* + * 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 . + * + * $Header$ + * + */ + +/** + * @file + * @brief General wiimote operations. + * + * The file includes functions that handle general + * tasks. Most of these are functions that are part + * of the API. + */ + +#include +#include + +#ifndef WIN32 + #include +#else + #include +#endif + +#include "definitions.h" +#include "wiiuse_internal.h" +#include "events.h" +#include "io.h" + +static int g_banner = 0; + +/** + * @breif Returns the version of the library. + */ +const char* wiiuse_version() { + return WIIUSE_VERSION; +} + + +/** + * @brief Clean up wiimote_t array created by wiiuse_init() + */ +void wiiuse_cleanup(struct wiimote_t** wm, int wiimotes) { + int i = 0; + + if (!wm) + return; + + WIIUSE_INFO("wiiuse clean up..."); + + for (; i < wiimotes; ++i) { + wiiuse_disconnect(wm[i]); + free(wm[i]); + } + + free(wm); + + return; +} + + +/** + * @brief Initialize an array of wiimote structures. + * + * @param wiimotes Number of wiimote_t structures to create. + * + * @return An array of initialized wiimote_t structures. + * + * @see wiiuse_connect() + * + * The array returned by this function can be passed to various + * functions, including wiiuse_connect(). + */ +struct wiimote_t** wiiuse_init(int wiimotes) { + int i = 0; + struct wiimote_t** wm = NULL; + + /* + * Please do not remove this banner. + * GPL asks that you please leave output credits intact. + * Thank you. + * + * This banner is only displayed once so that if you need + * to call this function again it won't be intrusive. + */ + if (!g_banner) { + printf( "wiiuse v" WIIUSE_VERSION " loaded.\n" + " By: Michael Laforest \n" + " http://wiiuse.net http://wiiuse.sf.net\n"); + g_banner = 1; + } + + if (!wiimotes) + return NULL; + + wm = malloc(sizeof(struct wiimote_t*) * wiimotes); + + for (i = 0; i < wiimotes; ++i) { + wm[i] = malloc(sizeof(struct wiimote_t)); + memset(wm[i], 0, sizeof(struct wiimote_t)); + + 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]->state = WIIMOTE_INIT_STATES; + wm[i]->flags = WIIUSE_INIT_FLAGS; + + wm[i]->event = WIIUSE_NONE; + + wm[i]->exp.type = EXP_NONE; + + wiiuse_set_aspect_ratio(wm[i], WIIUSE_ASPECT_4_3); + wiiuse_set_ir_position(wm[i], WIIUSE_IR_ABOVE); + + wm[i]->orient_threshold = 0.5f; + wm[i]->accel_threshold = 5; + + wm[i]->accel_calib.st_alpha = WIIUSE_DEFAULT_SMOOTH_ALPHA; + } + + return wm; +} + + +/** + * @brief The wiimote disconnected. + * + * @param wm Pointer to a wiimote_t structure. + */ +void wiiuse_disconnected(struct wiimote_t* wm) { + if (!wm) return; + + WIIUSE_INFO("Wiimote disconnected [id %i].", wm->unid); + + /* disable the connected flag */ + 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; + wm->handshake_state = 0; + wm->btns = 0; + wm->btns_held = 0; + wm->btns_released = 0; + memset(wm->event_buf, 0, sizeof(wm->event_buf)); + + wm->event = WIIUSE_DISCONNECT; +} + + +/** + * @brief Enable or disable the rumble. + * + * @param wm Pointer to a wiimote_t structure. + * @param status 1 to enable, 0 to disable. + */ +void wiiuse_rumble(struct wiimote_t* wm, int status) { + byte buf; + + if (!wm || !WIIMOTE_IS_CONNECTED(wm)) + return; + + /* make sure to keep the current lit leds */ + buf = wm->leds; + + if (status) { + WIIUSE_DEBUG("Starting rumble..."); + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_RUMBLE); + buf |= 0x01; + } else { + WIIUSE_DEBUG("Stopping rumble..."); + WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_RUMBLE); + } + + /* preserve IR state */ + if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) + buf |= 0x04; + + wiiuse_send(wm, WM_CMD_RUMBLE, &buf, 1); +} + + +/** + * @brief Toggle the state of the rumble. + * + * @param wm Pointer to a wiimote_t structure. + */ +void wiiuse_toggle_rumble(struct wiimote_t* wm) { + if (!wm) return; + + wiiuse_rumble(wm, !WIIMOTE_IS_SET(wm, WIIMOTE_STATE_RUMBLE)); +} + + +/** + * @brief Set the enabled LEDs. + * + * @param wm Pointer to a wiimote_t structure. + * @param leds What LEDs to enable. + * + * \a leds is a bitwise or of WIIMOTE_LED_1, WIIMOTE_LED_2, WIIMOTE_LED_3, or WIIMOTE_LED_4. + */ +void wiiuse_set_leds(struct wiimote_t* wm, int leds) { + byte buf; + + 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)) + wm->leds |= 0x01; + + buf = wm->leds; + + wiiuse_send(wm, WM_CMD_LED, &buf, 1); +} + + +/** + * @brief Set if the wiimote should report motion sensing. + * + * @param wm Pointer to a wiimote_t structure. + * @param status 1 to enable, 0 to disable. + * + * Since reporting motion sensing sends a lot of data, + * the wiimote saves power by not transmitting it + * by default. + */ +void wiiuse_motion_sensing(struct wiimote_t* wm, int status) { + if (status) + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_ACC); + else + WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_ACC); + + wiiuse_set_report_type(wm); +} + + +/** + * @brief Set the report type based on the current wiimote state. + * + * @param wm Pointer to a wiimote_t structure. + * + * @return The report type sent. + * + * The wiimote reports formatted packets depending on the + * report type that was last requested. This function will + * update the type of report that should be sent based on + * the current state of the device. + */ +int wiiuse_set_report_type(struct wiimote_t* wm) { + byte buf[2]; + int motion, exp, ir; + + 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)) + 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; + + WIIUSE_DEBUG("Setting report type: 0x%x", buf[1]); + + exp = wiiuse_send(wm, WM_CMD_REPORT_TYPE, buf, 2); + if (exp <= 0) + return exp; + + return buf[1]; +} + + +/** + * @brief Read data from the wiimote (callback version). + * + * @param wm Pointer to a wiimote_t structure. + * @param read_cb Function pointer to call when the data arrives from the wiimote. + * @param buffer An allocated buffer to store the data as it arrives from the wiimote. + * Must be persistent in memory and large enough to hold the data. + * @param addr The address of wiimote memory to read from. + * @param len The length of the block to be read. + * + * The library can only handle one data read request at a time + * because it must keep track of the buffer and other + * events that are specific to that request. So if a request + * has already been made, subsequent requests will be added + * to a pending list and be sent out when the previous + * finishes. + */ +int wiiuse_read_data_cb(struct wiimote_t* wm, wiiuse_read_cb read_cb, byte* buffer, unsigned int addr, unsigned short len) { + struct read_req_t* req; + + if (!wm || !WIIMOTE_IS_CONNECTED(wm)) + return 0; + if (!buffer || !len || !read_cb) + return 0; + + /* make this request structure */ + req = (struct read_req_t*)malloc(sizeof(struct read_req_t)); + req->cb = read_cb; + 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; +} + + +/** + * @brief Read data from the wiimote (event version). + * + * @param wm Pointer to a wiimote_t structure. + * @param buffer An allocated buffer to store the data as it arrives from the wiimote. + * Must be persistent in memory and large enough to hold the data. + * @param addr The address of wiimote memory to read from. + * @param len The length of the block to be read. + * + * The library can only handle one data read request at a time + * because it must keep track of the buffer and other + * events that are specific to that request. So if a request + * has already been made, subsequent requests will be added + * to a pending list and be sent out when the previous + * finishes. + */ +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; +} + + +/** + * @brief Send the next pending data read request to the wiimote. + * + * @param wm Pointer to a wiimote_t structure. + * + * @see wiiuse_read_data() + * + * This function is not part of the wiiuse API. + */ +void wiiuse_send_next_pending_read_request(struct wiimote_t* wm) { + byte buf[6]; + struct read_req_t* req; + + if (!wm || !WIIMOTE_IS_CONNECTED(wm)) + return; + if (!wm->read_req) return; + + /* skip over dirty ones since they have already been read */ + req = wm->read_req; + while (req && req->dirty) + req = req->next; + if (!req) + return; + + /* the offset is in big endian */ + *(int*)(buf) = BIG_ENDIAN_LONG(req->addr); + + /* the length is in big endian */ + *(short*)(buf + 4) = BIG_ENDIAN_SHORT(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); +} + + +/** + * @brief Request the wiimote controller status. + * + * @param wm Pointer to a wiimote_t structure. + * + * Controller status includes: battery level, LED status, expansions + */ +void wiiuse_status(struct wiimote_t* wm) { + byte buf = 0; + + if (!wm || !WIIMOTE_IS_CONNECTED(wm)) + return; + + WIIUSE_DEBUG("Requested wiimote status."); + + wiiuse_send(wm, WM_CMD_CTRL_STATUS, &buf, 1); +} + + +/** + * @brief Find a wiimote_t structure by its unique identifier. + * + * @param wm Pointer to a wiimote_t structure. + * @param wiimotes The number of wiimote_t structures in \a wm. + * @param unid The unique identifier to search for. + * + * @return Pointer to a wiimote_t structure, or NULL if not found. + */ +struct wiimote_t* wiiuse_get_by_id(struct wiimote_t** wm, int wiimotes, int unid) { + int i = 0; + + for (; i < wiimotes; ++i) { + if (wm[i]->unid == unid) + return wm[i]; + } + + return NULL; +} + + +/** + * @brief Write data to the wiimote. + * + * @param wm Pointer to a wiimote_t structure. + * @param addr The address to write to. + * @param data The data to be written to the memory location. + * @param len The length of the block to be written. + */ +int wiiuse_write_data(struct wiimote_t* wm, unsigned int addr, byte* data, byte len) { + byte buf[21] = {0}; /* the payload is always 23 */ + + if (!wm || !WIIMOTE_IS_CONNECTED(wm)) + return 0; + if (!data || !len) + return 0; + + WIIUSE_DEBUG("Writing %i bytes to memory location 0x%x...", len, addr); + + #ifdef WITH_WIIUSE_DEBUG + { + int i = 0; + printf("Write data is: "); + for (; i < len; ++i) + printf("%x ", data[i]); + printf("\n"); + } + #endif + + /* the offset is in big endian */ + *(int*)(buf) = BIG_ENDIAN_LONG(addr); + + /* length */ + *(byte*)(buf + 4) = len; + + /* data */ + memcpy(buf + 5, data, len); + + wiiuse_send(wm, WM_CMD_WRITE_DATA, buf, 21); + return 1; +} + + +/** + * @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 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; + } + 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 + { + 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]); + printf("\n"); + } + #endif + + #ifndef WIN32 + return wiiuse_io_write(wm, buf, len+2); + #else + return wiiuse_io_write(wm, buf, len+1); + #endif +} + + +/** + * @brief Set flags for the specified wiimote. + * + * @param wm Pointer to a wiimote_t structure. + * @param enable Flags to enable. + * @param disable Flags to disable. + * + * @return The flags set after 'enable' and 'disable' have been applied. + * + * The values 'enable' and 'disable' may be any flags OR'ed together. + * Flags are defined in wiiuse.h. + */ +int wiiuse_set_flags(struct wiimote_t* wm, int enable, int disable) { + if (!wm) return 0; + + /* remove mutually exclusive flags */ + enable &= ~disable; + disable &= ~enable; + + wm->flags |= enable; + wm->flags &= ~disable; + + return wm->flags; +} + + +/** + * @brief Set the wiimote smoothing alpha value. + * + * @param wm Pointer to a wiimote_t structure. + * @param alpha The alpha value to set. Between 0 and 1. + * + * @return Returns the old alpha value. + * + * The alpha value is between 0 and 1 and is used in an exponential + * smoothing algorithm. + * + * Smoothing is only performed if the WIIMOTE_USE_SMOOTHING is set. + */ +float wiiuse_set_smooth_alpha(struct wiimote_t* wm, float alpha) { + float old; + + 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) + wm->exp.nunchuk.accel_calib.st_alpha = alpha; + + return old; +} + + +/** + * @brief Set the bluetooth stack type to use. + * + * @param wm Array of wiimote_t structures. + * @param wiimotes Number of objects in the wm array. + * @param type The type of bluetooth stack to use. + */ +void wiiuse_set_bluetooth_stack(struct wiimote_t** wm, int wiimotes, enum win_bt_stack_t type) { + #ifdef WIN32 + int i; + + if (!wm) return; + + for (i = 0; i < wiimotes; ++i) + wm[i]->stack = type; + #endif +} + + +/** + * @brief Set the orientation event threshold. + * + * @param wm Pointer to a wiimote_t structure. + * @param threshold The decimal place that should be considered a significant change. + * + * If threshold is 0.01, and any angle changes by 0.01 then a significant change + * has occured 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; + + wm->orient_threshold = threshold; +} + + +/** + * @brief Set the accelerometer event threshold. + * + * @param wm Pointer to a wiimote_t structure. + * @param threshold The decimal place that should be considered a significant change. + */ +void wiiuse_set_accel_threshold(struct wiimote_t* wm, int threshold) { + if (!wm) return; + + wm->accel_threshold = threshold; +} + + +/** + * @brief Try to resync with the wiimote by starting a new handshake. + * + * @param wm Pointer to a wiimote_t structure. + */ +void wiiuse_resync(struct wiimote_t* wm) { + if (!wm) return; + + wm->handshake_state = 0; + wiiuse_handshake(wm, NULL, 0); +} + + +/** + * @brief Set the normal and expansion handshake timeouts. + * + * @param wm Array of wiimote_t structures. + * @param wiimotes Number of objects in the wm array. + * @param normal_timeout The timeout in milliseconds for a normal read. + * @param exp_timeout The timeout in millisecondsd to wait for an expansion handshake. + */ +void wiiuse_set_timeout(struct wiimote_t** wm, int wiimotes, byte normal_timeout, byte exp_timeout) { + #ifdef WIN32 + int i; + + if (!wm) return; + + for (i = 0; i < wiimotes; ++i) { + wm[i]->normal_timeout = normal_timeout; + wm[i]->exp_timeout = exp_timeout; + } + #endif +} diff --git a/Externals/WiiUseSrc/Src/wiiuse.h b/Externals/WiiUseSrc/Src/wiiuse.h new file mode 100644 index 0000000000..a70dc9e344 --- /dev/null +++ b/Externals/WiiUseSrc/Src/wiiuse.h @@ -0,0 +1,657 @@ +/* + * 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 . + * + * $Header$ + * + */ + +/** + * @file + * + * @brief API header file. + * + * If this file is included from inside the wiiuse source + * and not from a third party program, then wiimote_internal.h + * is also included which extends this file. + */ + +#ifndef WIIUSE_H_INCLUDED +#define WIIUSE_H_INCLUDED + +#ifdef _WIN32 + /* windows */ + #include +#else + /* nix */ + #include +#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 + + +/* 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 */ +#define EXP_NONE 0 +#define EXP_NUNCHUK 1 +#define EXP_CLASSIC 2 +#define EXP_GUITAR_HERO_3 3 + +/* 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 & 0x0200) == 0x0200) *lvl = 1; \ + else if ((wm->state & 0x0400) == 0x0400) *lvl = 2; \ + else if ((wm->state & 0x0800) == 0x0800) *lvl = 3; \ + else if ((wm->state & 0x1000) == 0x1000) *lvl = 4; \ + else if ((wm->state & 0x2000) == 0x2000) *lvl = 5; \ + else *lvl = 0; \ + } while (0) + +#define WIIUSE_USING_ACC(wm) ((wm->state & 0x020) == 0x020) +#define WIIUSE_USING_EXP(wm) ((wm->state & 0x040) == 0x040) +#define WIIUSE_USING_IR(wm) ((wm->state & 0x080) == 0x080) +#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 + #define WIIMOTE_DEFAULT_TIMEOUT 10 + #define WIIMOTE_EXP_TIMEOUT 10 +#endif + +typedef unsigned char byte; +typedef char sbyte; + +struct wiimote_t; +struct vec3b_t; +struct orient_t; +struct gforce_t; + + +/** + * @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_read_cb)(struct wiimote_t* wm, byte* data, unsigned short 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 */ + 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 vec2b_t + * @brief Unsigned x,y byte vector. + */ +typedef struct vec2b_t { + byte x, y; +} vec2b_t; + + +/** + * @struct vec3b_t + * @brief Unsigned x,y,z byte vector. + */ +typedef struct vec3b_t { + byte x, y, z; +} vec3b_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 vec3b_t cal_zero; /**< zero calibration */ + struct vec3b_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 { + byte visible; /**< if the IR source is visible */ + + 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) */ + + byte order; /**< increasing order by x-axis value */ + + byte size; /**< size of the IR dot (0-15) */ +} ir_dot_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 */ + byte num_dots; /**< number of dots at this time */ + + 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 */ + int state; /**< keeps track of the IR state */ + + int ax; /**< absolute X coordinate */ + int ay; /**< absolute Y coordinate */ + + int x; /**< calculated X coordinate */ + int y; /**< calculated Y coordinate */ + + float distance; /**< pixel distance between first 2 dots*/ + float z; /**< calculated distance */ +} 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 */ + + 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) */ + + byte btns; /**< what buttons have just been pressed */ + byte btns_held; /**< what buttons are being held down */ + byte btns_released; /**< what buttons were just released this */ + + float orient_threshold; /**< threshold for orient to generate an event */ + int accel_threshold; /**< threshold for accel to generate an event */ + + struct vec3b_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_held; /**< what buttons are being held down */ + short 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) */ + + struct joystick_t ljs; /**< left joystick calibration */ + struct joystick_t rjs; /**< right joystick calibration */ +} 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 */ + + float whammy_bar; /**< whammy bar (range 0-1) */ + + struct joystick_t js; /**< joystick calibration */ +} guitar_hero_3_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; + }; +} 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 { + /* expansion_t */ + float exp_ljs_ang; + float exp_rjs_ang; + float exp_ljs_mag; + float exp_rjs_mag; + unsigned short exp_btns; + struct orient_t exp_orient; + struct vec3b_t exp_accel; + float exp_r_shoulder; + float exp_l_shoulder; + + /* ir_t */ + int ir_ax; + int ir_ay; + float ir_distance; + + struct orient_t orient; + unsigned short 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 { + WIIUSE_NONE = 0, + WIIUSE_EVENT, + WIIUSE_STATUS, + WIIUSE_CONNECT, + WIIUSE_DISCONNECT, + WIIUSE_UNEXPECTED_DISCONNECT, + WIIUSE_READ_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_EVENT_TYPE; + +/** + * @struct wiimote_t + * @brief Wiimote structure. + */ +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 + + WCONST int state; /**< various state flags */ + WCONST byte leds; /**< currently lit leds */ + WCONST float battery_level; /**< battery level */ + + WCONST int flags; /**< options flag */ + + WCONST byte handshake_state; /**< the state of the connection handshake */ + + WCONST struct read_req_t* read_req; /**< list of data read requests */ + WCONST struct accel_t accel_calib; /**< wiimote accelerometer calibration */ + WCONST struct expansion_t exp; /**< wiimote expansion device */ + + WCONST struct vec3b_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 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 float orient_threshold; /**< threshold for orient to generate an event */ + WCONST int 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 */ +} wiimote; + + +/***************************************** + * + * 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(); + +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); + +/* 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(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); + +/* io.c */ +WIIUSE_EXPORT extern int wiiuse_io_read(struct wiimote_t* wm); +WIIUSE_EXPORT extern int wiiuse_io_write(struct wiimote_t* wm, byte* buf, int len); + + +#ifdef __cplusplus +} +#endif + + +#endif /* WIIUSE_H_INCLUDED */ + diff --git a/Externals/WiiUseSrc/Src/wiiuse_internal.h b/Externals/WiiUseSrc/Src/wiiuse_internal.h new file mode 100644 index 0000000000..1b2f423862 --- /dev/null +++ b/Externals/WiiUseSrc/Src/wiiuse_internal.h @@ -0,0 +1,226 @@ +/* + * 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 . + * + * $Header$ + * + */ + +/** + * @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 + +#ifndef WIN32 + #include /* htons() */ + #include +#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 + +/* commands */ +#define WM_CMD_LED 0x11 +#define WM_CMD_REPORT_TYPE 0x12 +#define WM_CMD_RUMBLE 0x13 +#define WM_CMD_IR 0x13 +#define WM_CMD_CTRL_STATUS 0x15 +#define WM_CMD_WRITE_DATA 0x16 +#define WM_CMD_READ_DATA 0x17 +#define WM_CMD_IR_2 0x1A + +/* input report ids */ +#define WM_RPT_CTRL_STATUS 0x20 +#define WM_RPT_READ 0x21 +#define WM_RPT_WRITE 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_ENABLE 0x04A40040 +#define WM_EXP_MEM_CALIBR 0x04A40020 + +#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 + +/* 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 0x9A1EFEFE +#define EXP_ID_CODE_CLASSIC_CONTROLLER 0x9A1EFDFD +#define EXP_ID_CODE_GUITAR 0x9A1EFDFB + +#define EXP_HANDSHAKE_LEN 224 + +/******************** + * + * End Wiimote internal codes + * + ********************/ + +/* 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)) + +#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.07f + +#define SMOOTH_ROLL 0x01 +#define SMOOTH_PITCH 0x02 + +#include "wiiuse.h" + +#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); + +#ifdef __cplusplus +} +#endif + +#endif /* WIIUSE_INTERNAL_H_INCLUDED */ diff --git a/Externals/WiiUseSrc/wiiuse.sln b/Externals/WiiUseSrc/wiiuse.sln new file mode 100644 index 0000000000..beece4e143 --- /dev/null +++ b/Externals/WiiUseSrc/wiiuse.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wiiuse", "wiiuse.vcproj", "{944EF6DE-471D-447E-A2FD-D37D58805169}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {944EF6DE-471D-447E-A2FD-D37D58805169}.Debug|Win32.ActiveCfg = Debug|Win32 + {944EF6DE-471D-447E-A2FD-D37D58805169}.Debug|Win32.Build.0 = Debug|Win32 + {944EF6DE-471D-447E-A2FD-D37D58805169}.Debug|x64.ActiveCfg = Debug|x64 + {944EF6DE-471D-447E-A2FD-D37D58805169}.Debug|x64.Build.0 = Debug|x64 + {944EF6DE-471D-447E-A2FD-D37D58805169}.Release|Win32.ActiveCfg = Release|Win32 + {944EF6DE-471D-447E-A2FD-D37D58805169}.Release|Win32.Build.0 = Release|Win32 + {944EF6DE-471D-447E-A2FD-D37D58805169}.Release|x64.ActiveCfg = Release|x64 + {944EF6DE-471D-447E-A2FD-D37D58805169}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Externals/WiiUseSrc/wiiuse.suo b/Externals/WiiUseSrc/wiiuse.suo new file mode 100644 index 0000000000000000000000000000000000000000..3dfa0ede367a79e83c3a920cbf205a15e9c3fcd3 GIT binary patch literal 32768 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 aKrKu + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +