From fa8b1658af843f86bb588b70c4cbfcf39fa1d0ed Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 1 Mar 2010 15:49:13 +0000 Subject: [PATCH] Initial commit - wiiuse 0.12 --- CHANGELOG | 208 ++++++++ LICENSE | 620 +++++++++++++++++++++++ LICENSE_noncommercial | 170 +++++++ Makefile | 23 + README | 155 ++++++ example-sdl/Makefile | 83 ++++ example-sdl/msvc/wiiusesdl.dsp | 111 +++++ example-sdl/msvc/wiiusesdl.dsw | 29 ++ example-sdl/msvc/wiiusesdl.ncb | Bin 0 -> 58368 bytes example-sdl/msvc/wiiusesdl.opt | Bin 0 -> 48640 bytes example-sdl/sdl.c | 439 +++++++++++++++++ example/Makefile | 84 ++++ example/example.c | 437 ++++++++++++++++ example/msvc/wiiuseexample.dsp | 106 ++++ example/msvc/wiiuseexample.dsw | 29 ++ example/msvc/wiiuseexample.ncb | Bin 0 -> 58368 bytes example/msvc/wiiuseexample.opt | Bin 0 -> 48640 bytes src/Makefile | 91 ++++ src/classic.c | 190 +++++++ src/classic.h | 53 ++ src/definitions.h | 79 +++ src/dynamics.c | 228 +++++++++ src/dynamics.h | 56 +++ src/events.c | 878 +++++++++++++++++++++++++++++++++ src/events.h | 54 ++ src/guitar_hero_3.c | 172 +++++++ src/guitar_hero_3.h | 62 +++ src/io.c | 119 +++++ src/io.h | 56 +++ src/io_nix.c | 270 ++++++++++ src/io_win.c | 247 ++++++++++ src/ir.c | 748 ++++++++++++++++++++++++++++ src/ir.h | 56 +++ src/msvc/wiiuse.dsp | 191 +++++++ src/msvc/wiiuse.dsw | 29 ++ src/msvc/wiiuse.ncb | Bin 0 -> 115712 bytes src/msvc/wiiuse.opt | Bin 0 -> 52736 bytes src/nunchuk.c | 210 ++++++++ src/nunchuk.h | 53 ++ src/os.h | 56 +++ src/wiiuse.c | 764 ++++++++++++++++++++++++++++ src/wiiuse.h | 653 ++++++++++++++++++++++++ src/wiiuse_internal.h | 226 +++++++++ wiiuse.cbp | 86 ++++ wiiuse.layout | 61 +++ 45 files changed, 8182 insertions(+) create mode 100644 CHANGELOG create mode 100644 LICENSE create mode 100644 LICENSE_noncommercial create mode 100644 Makefile create mode 100644 README create mode 100644 example-sdl/Makefile create mode 100644 example-sdl/msvc/wiiusesdl.dsp create mode 100644 example-sdl/msvc/wiiusesdl.dsw create mode 100644 example-sdl/msvc/wiiusesdl.ncb create mode 100644 example-sdl/msvc/wiiusesdl.opt create mode 100644 example-sdl/sdl.c create mode 100644 example/Makefile create mode 100644 example/example.c create mode 100644 example/msvc/wiiuseexample.dsp create mode 100644 example/msvc/wiiuseexample.dsw create mode 100644 example/msvc/wiiuseexample.ncb create mode 100644 example/msvc/wiiuseexample.opt create mode 100644 src/Makefile create mode 100644 src/classic.c create mode 100644 src/classic.h create mode 100644 src/definitions.h create mode 100644 src/dynamics.c create mode 100644 src/dynamics.h create mode 100644 src/events.c create mode 100644 src/events.h create mode 100644 src/guitar_hero_3.c create mode 100644 src/guitar_hero_3.h create mode 100644 src/io.c create mode 100644 src/io.h create mode 100644 src/io_nix.c create mode 100644 src/io_win.c create mode 100644 src/ir.c create mode 100644 src/ir.h create mode 100644 src/msvc/wiiuse.dsp create mode 100644 src/msvc/wiiuse.dsw create mode 100644 src/msvc/wiiuse.ncb create mode 100644 src/msvc/wiiuse.opt create mode 100644 src/nunchuk.c create mode 100644 src/nunchuk.h create mode 100644 src/os.h create mode 100644 src/wiiuse.c create mode 100644 src/wiiuse.h create mode 100644 src/wiiuse_internal.h create mode 100644 wiiuse.cbp create mode 100644 wiiuse.layout diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..ccb831a --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,208 @@ +--------------------------- +- +- CHANGE LOG - Wiiuse +- +--------------------------- + +http://wiiuse.net/ +http://wiiuse.sourceforge.net/ +http://sourceforge.net/projects/wiiuse/ + +--------------------------- +v0.12 -- 2 Apr 2008 +--------------------------- + + Added: + - API function wiiuse_set_ir_sensitivity() + - Macro WIIUSE_GET_IR_SENSITIVITY() + - Event type WIIUSE_READ_DATA + - Event type WIIUSE_UNEXPECTED_DISCONNECT + + Fixed: + - [Linux] Ability to try to select() nothing + - [Linux] Changed Makefile to include debug output when compiling in debug mode + + Changed: + - wiiuse_set_nunchuk_orient_threshold() now takes a wiimote_t pointer + - wiiuse_set_nunchuk_accel_threshold() now takes a wiimote_t pointer + - wiiuse_read_data() generates an event WIIUSE_READ_DATA rather than executing a callback + +--------------------------- +v0.11 -- 25 Feb 2008 +--------------------------- + + Added: + - API function wiiuse_set_nunchuk_orient_threshold() + - API function wiiuse_set_nunchuk_accel_threshold() + - Event type WIIUSE_NUNCHUK_INSERTED + - Event type WIIUSE_NUNCHUK_REMOVED + - Event type WIIUSE_CLASSIC_CTRL_INSERTED + - Event type WIIUSE_CLASSIC_CTRL_REMOVED + - Event type WIIUSE_GUITAR_HERO_3_CTRL_INSERTED + - Event type WIIUSE_GUITAR_HERO_3_CTRL_REMOVED + + Fixed: + - Added some missing function prototypes to wiiuse.h + - [Linux] Fixed Makefile to link libmath and libbluetooth + - Status event is set when a status report comes in + - Orientation threshold not being saved in lstate + +--------------------------- +v0.10 -- 11 Feb 2008 +--------------------------- + + Added: + - Real dynamic linking (by noisehole) + - Changed from callback to SDL style + - Guitar Hero 3 controller support + - API function wiiuse_set_accel_threshold() + - API function wiiuse_version() + - Macro WIIUSE_USING_SPEAKER() + - Macro WIIUSE_IS_LED_SET(wm, num) + - wiiuse_init() now autogenerates unids + - orient_t::a_roll/a_pitch + - wiiuse_resync() + - wiiuse_cleanup() + - wiiuse_set_timeout() + + Fixed: + - [Windows] Fixed bug where it did not detect expansions on startup + - Renamed INFO/WARNING/DEBUG macros to WIIUSE_* (by noisehole) + - Updated Makefiles (by noisehole) + - Fixed incorrect roll/pitch when smoothing was enabled + - Fixed nunchuk and classic controller flooding events when significant changes occured + - Fixed bug where IR was not correct on roll if IR was enabled before handshake + + Removed: + - wiiuse_startup(), no longer needed + +--------------------------- +v0.9 -- 3 Nov 2007 +--------------------------- + + Fixed: + - Can now use include/wiiuse.h in C++ projects. + - HOME button works again. + - IR now functions after expansion is connected or removed. + +--------------------------- +v0.8 -- 27 Oct 2007 +--------------------------- + + - Bumped API version to 8 + - Exported all API functions for usage with non-C/C++ languages. + - Changed event callback to only trigger if a significant state change occurs. + + Added: + - wiimote_t::lstate structure + + Fixed: + - Bug 1820140 - Buffer overflow in io_nix.c. Thanks proppy. + +--------------------------- +v0.7 -- 19 Oct 2007 +--------------------------- + + - Bumped API version to 7 + - Renamed Linux build from wii.so to wiiuse.so + - Changed version representation from float to const char*. + + Added: + - [Windows] BlueSoleil support. + - [Windows] Bluetooth stack auto-detection (WinXP SP2, Bluesoleil, Widdcomm tested). + - [Windows] API function wiiuse_set_bluetooth_stack(). + - Calculates yaw if IR tracking is enabled. + + Fixed: + - [Windows] Problem where a connection is made to a wiimote that does not exist. + - [Windows] Issue that occured while using multiple wiimotes. + +--------------------------- +v0.6 -- 16 Oct 2007 +--------------------------- + + - Bumped API version to 0.6. + - Ported to Microsoft Windows. + - Improved IR tracking. + - Default IR virtual screen resolutions changed depending on 16:9 or 4:3. + + Added: + - src/msvc/ and api/msvc/ - Microsoft Visual C++ 6.0 project files. + +--------------------------- +v0.5 -- 13 Oct 2007 +--------------------------- + + - Bumped API version to 0.5. + - Greatly improved IR tracking. + - Renamed function wiiuse_set_ir_correction() to wiiuse_set_ir_position(). + + Added: + - API function wiiuse_set_aspect_ratio() + + Fixed: + - When rolling around 180 degree rotation smoothing would not be seemless. + +--------------------------- +v0.4 -- 08 Oct 2007 +--------------------------- + + - Bumped API version to 0.4. + - Greatly improved classic controller joystick functionality. + - Changed all functions named wiimote_*() to wiiuse_*() + - Renamed many macros from WIIMOTE_* to WIIUSE_* + + Added: + - IR support + - New WIIMOTE_CONTINUOUS flag to set continuous reporting + - Macro IS_JUST_PRESSED() + - Macro WIIUSE_USING_ACC() + - Macro WIIUSE_USING_EXP() + - Macro WIIUSE_USING_IR() + - API function wiiuse_set_ir() + - API function wiiuse_set_ir_vres() + - API function wiiuse_set_ir_correction() + + - gfx/ - A small OpenGL example that renders IR data + + Fixed: + - Sometimes classic controller would only report infinite angle and magnitude for joysticks. + +--------------------------- +v0.3 -- 10 Sept 2007 +--------------------------- + + - Moved license to GPLv3. + - Bumped API version to 0.3. + + Added: + - Support for Classic Controller + - Smoothing for roll and pitch values of the wiimote and nunchuk. + + - API: wiimote_set_flags() to set or disable wiimote options. + - API: wiimote_set_smooth_alpha() to set smoothing alpha value. + + Fixed: + - When the wiimote accelerates the roll or pitch is unreliable and was set to 0. + It now remains at previous tilt value. + - If no event callback was specified then no events would be processed internally. + +--------------------------- +v0.2 -- 25 Aug 2007 +--------------------------- + + - Bumped API version to 0.2. + + Added: + - Nunchuk support. + - Ability to write to flash memory. + + Fixed: + - Roll and pitch rotation now ranges from -180 to 180 degrees (previously -90 to 90). + - Bug when reading data from flash memory would read wrong address. + +--------------------------- +v0.1 -- 23 Feb 2007 +--------------------------- + + - Initial release diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..85b8e59 --- /dev/null +++ b/LICENSE @@ -0,0 +1,620 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + diff --git a/LICENSE_noncommercial b/LICENSE_noncommercial new file mode 100644 index 0000000..b556a22 --- /dev/null +++ b/LICENSE_noncommercial @@ -0,0 +1,170 @@ +This license can be used for any works that this license defines +as "derived" or "combined" works that are strictly NON-COMMERCIAL. +This license prohibits the use of any source or object code +in works that are PROPRIETARY. + + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f63da69 --- /dev/null +++ b/Makefile @@ -0,0 +1,23 @@ +# +# wiiuse Makefile +# + +all clean install: + @$(MAKE) -C src $@ + @$(MAKE) -C example $@ + @$(MAKE) -C example-sdl $@ + +wiiuse: + @$(MAKE) -C src + +ex: + @$(MAKE) -C example + +sdl-ex: + @$(MAKE) -C example-sdl + +distclean: + @$(MAKE) -C src $@ + @$(MAKE) -C example $@ + @$(MAKE) -C example-sdl $@ + @find . -type f \( -name "*.save" -or -name "*~" -or -name gmon.out \) -delete &> /dev/null diff --git a/README b/README new file mode 100644 index 0000000..12d9f71 --- /dev/null +++ b/README @@ -0,0 +1,155 @@ +--------------------------- +- +- README - Wiiuse +- +--------------------------- + +http://wiiuse.net/ +http://wiiuse.sourceforge.net/ +http://sourceforge.net/projects/wiiuse/ + +--------------------------- + +ABOUT + + Wiiuse is a library written in C that connects with several Nintendo Wii remotes. + Supports motion sensing, IR tracking, nunchuk, classic controller, and the Guitar Hero 3 controller. + Single threaded and nonblocking makes a light weight and clean API. + + Distributed under the GPL and LGPL. + + +AUTHORS + + Michael Laforest < para > + Email: < thepara (--AT--) g m a i l [--DOT--] com > + + The following people have contributed patches to wiiuse: + - dhewg + + +LICENSE + + There are two licenses for wiiuse. Please read them carefully before choosing which one + you use. You may of course at any time switch the license you are currently using to + the other. + + Briefly, the license options are: + + a) GNU LGPL (modified for non-commercial usage only) + b) GNU GPL + + PLEASE READ THE LICENSES! + + +ACKNOWLEDGEMENTS + + http://wiibrew.org/ + This site and their users have contributed an immense amount of information + about the wiimote and its technical details. I could not have written this program + without the vast amounts of reverse engineered information that was researched by them. + + Nintendo + Of course Nintendo for designing and manufacturing the Wii and Wii remote. + + BlueZ + Easy and intuitive bluetooth stack for Linux. + + Thanks to Brent for letting me borrow his Guitar Hero 3 controller. + + +DISCLAIMER AND WARNINGS + + I am in no way responsible for any damages or effects, intended or not, caused by this program. + + *** WARNING *** WARNING *** WARNING *** + + Be aware that writing to memory may damage or destroy your wiimote or expansions. + + *** WARNING *** WARNING *** WARNING *** + + This program was written using reverse engineered specifications available from wiibrew.org. + Therefore the operation of this program may not be entirely correct. + Results obtained by using this program may vary. + + +AUDIENCE + + This project is intended for developers who wish to include support for the Nintendo Wii remote + with their third party application. Please be aware that by using this software you are bound + to the terms of the GNU GPL. + + +PLATFORMS AND DEPENDENCIES + + Wiiuse currently operates on both Linux and Windows. + You will need: + + For Linux: + - The kernel must support bluetooth + - The BlueZ bluetooth drivers must be installed + + For Windows: + - Bluetooth driver (tested with Microsoft's stack with Windows XP SP2) + - If compiling, Microsoft Windows Driver Development Kit (DDK) + + +COMPILING + + Linux: + You need SDL and OpenGL installed to compile the SDL example. + + # make [target] + + If 'target' is omitted then everything is compiled. + + Where 'target' can be any of the following: + + - wiiuse + Compiles libwiiuse.so + + - ex + Compiles wiiuse-example + + - sdl-ex + Compiles wiiuse-sdl + + Become root. + + # make install + + The above command will only install the binaries that you + selected to compile. + + wiiuse.so is installed to /usr/lib + wiiuse-example and wiiuse-sdl are installed to /usr/bin + + Windows: + A Microsoft Visual C++ 6.0 project file has been included. + + You need the install the Windows DDK (driver development kit) + to compile wiiuse. Make sure you include the inc/ and lib/ + directories from the DDK in your IDE include and library paths. + You can download this from here: + http://www.microsoft.com/whdc/devtools/ddk/default.mspx + + You need to link the following libraries (already set in the + included project file): + - Ws2_32.lib + - hid.lib + - setupapi.lib + + +USING THE LIBRARY IN A THIRD PARTY APPLICATION + + To use the library in your own program you must first compile wiiuse as a module. + Include include/wiiuse.h in any file that uses wiiuse. + + For Linux you must link wiiuse.so ( -lwiiuse ). + For Windows you must link wiiuse.lib. When your program runs it will need wiiuse.dll. + + +BUGS + + On Windows using more than one wiimote (usually more than two wiimotes) may cause + significant latency. diff --git a/example-sdl/Makefile b/example-sdl/Makefile new file mode 100644 index 0000000..c206354 --- /dev/null +++ b/example-sdl/Makefile @@ -0,0 +1,83 @@ +# +# 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 = -L../src/$(OBJ_DIR) -lm -lGL -lGLU -lglut -lSDL -lbluetooth -lwiiuse + +# +# Target binaries (always created as BIN) +# +BIN = ./$(OBJ_DIR)/wiiuse-sdl + +# +# Inclusion paths. +# +INCLUDES = -I../src/ -I/usr/include/SDL + +# +# Generate a list of object files +# +OBJS = $(OBJ_DIR)/sdl.o + +############################### +# +# Build targets. +# +############################### + +all: $(BIN) + +clean: + @-rm $(OBJS) 2> /dev/null + +distclean: clean + @-rm -r debug-* release-* 2> /dev/null + +install: + @if [ -e $(BIN) ]; then \ + cp -v $(BIN) /usr/bin ;\ + fi + +$(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 + +run: all + LD_LIBRARY_PATH=`pwd`/../src/$(OBJ_DIR):$(LD_LIBRARY_PATH) $(BIN) + diff --git a/example-sdl/msvc/wiiusesdl.dsp b/example-sdl/msvc/wiiusesdl.dsp new file mode 100644 index 0000000..23c4a24 --- /dev/null +++ b/example-sdl/msvc/wiiusesdl.dsp @@ -0,0 +1,111 @@ +# Microsoft Developer Studio Project File - Name="wiiusesdl" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=wiiusesdl - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "wiiusesdl.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "wiiusesdl.mak" CFG="wiiusesdl - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "wiiusesdl - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "wiiusesdl - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "wiiusesdl - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\..\src" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib sdl.lib opengl32.lib glu32.lib wiiuse.lib /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "wiiusesdl - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\src" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib sdl.lib opengl32.lib glu32.lib wiiuse.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "wiiusesdl - Win32 Release" +# Name "wiiusesdl - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\sdl.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\src\wiiuse.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/example-sdl/msvc/wiiusesdl.dsw b/example-sdl/msvc/wiiusesdl.dsw new file mode 100644 index 0000000..630b942 --- /dev/null +++ b/example-sdl/msvc/wiiusesdl.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "wiiusesdl"=".\wiiusesdl.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/example-sdl/msvc/wiiusesdl.ncb b/example-sdl/msvc/wiiusesdl.ncb new file mode 100644 index 0000000000000000000000000000000000000000..e44ea287ff5726783066802f16b3cdb555ac9c1c GIT binary patch literal 58368 zcmeHQ378y5b$+iTSu0t`u4J9Y(r9&9=j!qyjg6)Ct}N?b-IBHTXm)0Hccj^w)y%9e zz?Nj=6N4?nWk3OQJ8?qDM*t@f?0|7dzzG;*e+DcdALhgPYy}c<0=Dx1)jd7ct6hiq z2zJ~(Usb(VRb5^ErmDK?^{c%Iqk$Hm19>`E03NOro6D=1ggCxzOEuAe-$eWm+=_lU?1p%)C-M*9zB=a;xxC z3(e+Jxt?^!zeYo+dzRBM1|t(S&zwP&U~+z+ZqIM-Yw&-;MA? zNZ5_==ZK$)@D$qec!bPfFH_}0bcHE0O(w~7nIUuJJamDX zGD~L5WQoaKiTZ!k|Iuio<5iQupQF!?%tUg zGHw^>y?%OyW}b0~V>xuu5lNsg32Z}S9f|hJX=T06(g*R-CeP{Ud-RXB%TMP3@p=8S z{;khrN+1*T+zMYy{vrGx#)&+ibAwOnpXrU5x00U>et}-9kMjH#5}ONtohJ1u%zv4_ z5PV4w>lb}K4*saVQ$OxsZyETrbyS6~CI1clwqkzF^EpL+Ql65hFh?f868tlAN^bSe zuO8`E(xy!Si>4eOQ00c6{6-wdB8!pXD(=?FavBoo15g zTO8lW&%y6|xIS*#^1sk$wGQ>GljY!5rs*_2jYN+(GF7K)Q;IiV-?PK@u~^+w2jdY}G9z>k!_*1y($ z0bh%;{!5w&_&WJ3{VN@Vb&PlZD4D1ebxOdGw*0(+KgaS&1F1 z;LpR;>Joidz)zBex==qF@RMb+F4p@3J|-7n=KPnaFQV{&#pDLLNovsE>%PPGF-11& zM!k;w1LW&vr|#67$$yvpRJls8(vOn2?P;1MG@(C6d#xMI^y#u**Xw_he>eFVvOzcK z)y#hr`SWF)Zqupc*N~qnn{~66$PXt!OSbEFT~0nhezt7Yt$HW@qk|-hxCwc2>69k*0Lr7ev$NOk5Vz= zU2n16rnl(>!Syb{T;!MzVfp~p??SmrZ_)`t{)^;hy;&Oq{$jaBZ_!@{=P!}B>)Ult zkiJxI*W2~+AU!VE>-D;W>B{mik$31j^u8efrHHT7&jkFNrB-Y8wt&A(hU;*BYrrp) zVLD7d81TzwgpSbn1pT{FeuCe%0e`vt7{A>C-y|pTdnn+WLpPx1Rgz+WN% zg5TYcCoYNluav*T@7dt`SIV>a{a3)RvizVx{;TCV{AvS!jpfe`__daA2>5lPIF<(d zddoKl{07V43*M_wi%c`q%!h*hyHS3kKhYZlev_QklX`E^|2NC`^m{rWNZ%rl>0`Py zNZ%^|tpBW~fZrzH)$i&z0)D$Zs*mbV1Ad2mU%#*00)D4_N57+Y1pHOZ*cvbj4@-( zfZ+Tt8E%G~napqdOJ2l?c_>IPU_Ls|{5{i8v%GGpF*PO;)Nh}}Ow1e$u3wY^W`H>! zoL`c2%sFOekiRVFne)t~AiYOMnvrI8aD6;+jhZh8C$B^D z8~u$I(0{!4c~~C9?>o5Oke>Ji2e zPJx?>yywHsK-@I&(?QRKn+1Nhn3_2V=fcfH+I+YMlyd>nFGSo$;1?oXgm3}eV$hc& z?ac_6h&jDXOhY5$FN0eSw-hc8cRBJjiTUa!pqs@Eyb^8|&bb2o3WO`+*1&Cq+koq> zMLFw`wjORZ+$OjdF@v_jZAG5#xYicr*$nzBxSeo2kf#;yYPemOspg(T^3X95i>N4xK8B11MY2bZ$~|EM;+dU z_*>wP!o3sjCb&Z=`xx%`2GH+-I{_uaM#1#C}!VbXzWfV}R~5&2&Q~kpgGl3imvh$pF%M*X#Z}H>SUHDtwMsl`x_dDh zpc~_tQ7PwXv^%EnLHs;FZB4H{ycXxXm5?;=fphvw`3wgjp7VCrgY#+T@9kKJccSgH z{VzhEr+xQn)ZZf)*NkY zu049>BUhetYkGOjz+<&Ku(ola9=&7B#>P?2HJ9Je+&pvjrq#FB)D5Yx9XRl4?a;snbZEcNFZLF<1R(o@-w&sS~S}Htx9amoE)vH%@#6}W$-AVvm42Kcw zm8g5?Gn6`a&TXh`=X00OTh4Q+TfZA|)ag-=!Dlb$6x5+pZ_arTpTE?}QBTgbXJt-8 zJsWl9T>tS|O+6ZQ<WO;>7@ODWwm7?w!)8#So`f0R44*m&(yQQ8 zUqBkGSK-=)^o{T-7t(KHJSs(c7kuiINY97QwG-*1@F^S8gW*%hLwX5(u3t&-g-=}( z=?mdgPeS?%_+0amJ`A6-CCzG67eab9e7&>AV{M)p{|njO!!~oKgKJ5clvdn z2AcX%#?OY&wKwS-;8U+mdK`S}m`HDj&;CjpI&G^PCVd`as5c=^8PX@c96t3IqbFUcg-_ij>80@Pdp*#&4dEJ{@$Z1o=Q-)=@TuD*9fwc7 z8tKjOV}6+vK~sOt_(|}o8zP;BPrVK4ZurzulD-^1^$DbJhR?M<={w+4Z%MidKF2!J z=fbDHo%96w)UA@f1U~grq&wkrydqr(pW_wjG4QF&A$100^xNR`{U>P@ zE!0hs?t)LfKk4!CsY4~*44?WM($~W0*hzXge2%T8hrs99OZsB?TZ-vkIC8Vdo=er2fbKz4jN;(anI$qK{;8Pz-IuD=EI?`j|`1~V%96oha zq~8Uf`c%>x_V`?T!l&Mj^!4zmlO^2_pWy_! zOF{YXw$aCNpMJZYhj{AbnC}+&)UT6X2mh!3y%a!GkI(ok;oEoipmBMtk7oSUi08b4 z^jYvZryxB5KHs5`z5qU|k7tfj2NxZY1R@E%$`U}=mVxMe?6Z6piA;2^_=j2lA9?n( zoH_>Uf2Tr!Q1W-rAF=~x3bJ}F=_M-i`hyB5y7=o-0-V>6yu&Upt$iHVVxzhw#+wQ3 z|9pGB!2Zv-4-D-8ph9E*!2ZwA->?0jc=-eSKSTaS?Eh?j$NtZj@7VuY`^6Wr|10#e z|4Z|Fj{Tpt&vWem?DbxT{hzI$WB+H%bL{_;y#D{K{ons)&CmH?WzBzT>&IU5njh0) ziPrpoxHUf>Q+=-abD~1KA4R&S|6k?n{}%=N|1XZ*z+`y{A?^PkLx?H9oI*(Zf2rMo zH{S>l(*8e&koNxz5YqmCIYQ=d@x$E+G3A$TgrlH=sM`OJ!?ap|Bu0{ zh`P3D&HwsY^HWFJ*P5R?#Awa$t@&T6b^h7XrlECX)0+s&%y1t31@{t503A`i;@L5j%KlOjo-xl~Y<15?VvAe&eSm-Dw zyJA;lbD2`>x@@XgC>7evv2EE>Pcj$VT<%F{3$0CsuC7A9b=~IX%>JcIS})J$u?ruY z>>Ki_HhDRvq>AO2T}D@XDp}4|ig{(=3N8f}LN43Z(0Q3$+LbJKS^~G6E*vOXdga>r z9l0viW690UYZ=yi5^w0Nmvpw&ol72){e^5=Iy2dh&a$jro6VQ`Z*>*QnM7FtSFkRb z%?o3%T(y4lmd5o>D`K6ifX9%`r!sC_OEI%Qh+o^XdCR6)uDhu#jS@3FKb8lxxwCMf zQhcdG#AeTywq$B=Qz2I7FDksu~a>-VLrS4jEH7?D}oq&zVWfGbFz>uiaCQ**fKG4OM^HTn< zGk_ohS;pf%c?jC!)0zDVuLg2u_aZuEgQD2*tE8>rDa94n*)DA zYOiGSJzX)#BGFb(*ckk4&Na%}u1ujP6qPR&yOOy?C8h09Ipdy@IoKVfIR&BYaK2n7 z9sGlday;IaESEFILx~)unR5$l&m}uTIeE{e&g9+} zCYMMh(E-GxL-&Tt3tTc!w2ZJMY;M_~NiA**ClrcV{{3DMPU>hc6w%7PAe@vfO12n| zYAfeU(t}HPaJXcmSN3GWJ0bYT&TKvCT#MMb{4gFrSS9hC@w%QL%U&3dJF$mt zhIa4t#Rw}IE$L;nh)~ejW<7wscDfI13F%*@|cZB$^WQUaOFqrC07AvET z06(ZFRgMK?prr69DP>cMRJn-Zvloj2klo+w_2HaelGpY7ObPzr-l@d|%InFcaRa@R zaxapErr0}s5pihMwrd7NJib3$%C_b3eD;$l^I!x+lXVhoC$Z#2MJLngVkpAa+dc6>GFuMi$Y&0srDN_Co0&+Y(wS5)HhcQ4 znY~+0Z1!9`e$Jj7$kn!yS;138LVCR=;IXZD+D8+V_l`2)`xX>gRc)Wb5I}?scBzp1$UrWd1{^OzFbbr|BH@%~Cv0RG38r_Sl ziRSGwyLxEezF||dOWH|yF#}LGn;x(j8*ErVZ#Iur!3Ta(>`rgAjR?tKt4g$GTAX%5R*-h3U(?O`PeGUnvv2}lF%(Q@1@x%%}Hq%$Ac!Pg6>63FNY!rnodEeq>8*4$#ZZ8{QZ zLmJutNA~~!ll}j}PdAvz{{R1%{l9AqupDppBK!Zy{y(z+f8*Hy^Vv_lE6g8cl1>ld zf87Z@DDLxMI&C}t0{Bg|+aI}2Vzdz(qvJgOF0uGuUz4v{`w!-)ZP49%PYC~Ot}gNL zzmPr`>8pSr#7WA?(;og;0r)^J{@2^|)(YNNjCfyzftSNQ5Gdc`e-Y1yds}$D6-a*q z_&1znj)XnoO7Opsf3^ELn4kOu_z`b_`B#JgmHbBt|Lb@1f>``7)Q5Oq{{Z|JYafa8 z$={Ek&jSxcC++nub9R{_+OKCatQy6_+T#n7xBS3@vSq&OBn=w zw)znM*D}34g#Yyw`AP`?>$n~d;eWkb-yOpL`Xl`#5C5yo@`qY{FpK|XuXnb5KtJH& ze+^~&FpDQ<@xSgOKiuMh-HAzO-9hprES?u9vmTzxNcn<(!NdQu`D=k6_xTY1*XQ(e z9{!ibgBc}bb!-U#i#!(vbp@7xj!k#*zdoiP3*mo#Tt6Pd|N4Y}!o&Ys!SlykJTMpk zi}+#O_vhi!z#daC4B>w*(nTTsFXDN*_+P{Wv-n@lEPs;B(|IBMulYJZg#Wcb7xaz) zB|Lu$_H?fE@V_iyZ}GP*{+E^CREyumg@`BLX|hXqdH7#8|8!Zct3CWL%g>NCy2iu* zvi$k7NjG`;UzVR~@xd(qm&NOuW%0ncNb<^`ZSlw~{+GS}94u&dc=%sQ)_1POC$sop zA0j``;)8Mjsds*Z#q)CUzlvJ)@V{(%3oO2u#s9MZ|3c~3?hyXhKHV3>|02GZi~n`4 zUhCn1WqJJzEnb(!|FY#>Bsb^{A^b1meYyBwNA+k3|BLuwF8LNc zF8&vJ7ys*ddEV|<^W?K0-1By?S)DC!gXLZPub7E>_+K`Cqx?vJ5&t8T0Ry zZ|k>1_+S5|{}jUiB3_t_|3&;U7ys*VecZ$UdVu9!WAVZ){+De(35!ofg@bqf-7?G! z^YFjy{UTg5%U&I%) z_+PgCPMK^bd-z|L&szL0?qT=pw}+cMJ^ZgByq~=mKa0v3FFj}R!YuxmJ-^H1m0A2R z%je~H`a8AwUzRUe{4oQwaZy_+?azc-JdgyflmdW$&+S@z5;( zmo2}?;*(kYFU#+j=k_Doo&x^Yz6k$|^XKJIAog|<{ud_n(Gf}D4JLuU_6TroAMO8t zgEfTccHfW^fO-i>KW{4EkP?Y*I+DN}M*`9Nf8*f)0f8IJGLD8^4Oj91jD!D&cnq4% z1LSK5|Iax1f5yT8GYw1QJP!UJ5Xb#8p;2-0|A3$leLM40i_%iVn#s5PagC3XnNX=Ol z|Iax1f5yT8LwA52*fr`OxAy_(lT&?^3)k?Q&%&lJBt;q^bpK)*iJyjJo5 zjD!DY9Q;2#clk1;z_-O&+I;qzV;Sw!=wF`+FN)PrwKTIuf2s>;#0Lk^%FlM zQBkM!(;EDQ1=S7w1O?SrJS+r}M_QkseCd5qUBQFf1lIK<1AbzGpN`?D6KUQ}6J>t> zgK9#mrU}8wPbu<~i-bF-dXK6kyR`r`O_Glxo}WacIV9CdkD{JbtanRn&yqq&jSv|DRAL$Ac#M{Djbp9aQu3;AfDiV&$hv`a7s*?(d-bjwaLm z6eCSnsb2p#=YOGUXD-(c{y`Pcaa@yT{FUQIKb@bEq`A2LL^{e{j0_KgALZX4^Ye2> zd~HJ25LJYH6+n|`e%g_r)_e@t=Rq@LehQtR!r`$C`KfMRj*zM+ewK)z@S!fy@O25*Wc-v=?_(U&sCuM&oUc8ouIuZdDJl=D z!l|C83jOpDVqQP9{3;q&Hp1@kZA56&E2E9`ztkf=fwE6I(L8c)tj}y zawX5bZ-H)Yy@yy#*zb*nEg`5%2vTkHfo|22DQENT1&{A4q2(4#MsBM*AUZH2ezB;!#-_tL-FFCxIA1|J#@*>3M0uU?_O{)@mdDRVR zy|_TaTg(pAyh()H1LMAS-&xd2qCE&R*z6%ZuQ5Xk$AG>54 z7qF|4&h_6ja4(_=Kx%aSKa&9M0#Cr59I-(sKmqa9og3J~>A!N)e* z@A=#T{vVNY1R*g#x)JjGKf4j~`#&=g^87FUO^eN61D;LuIq+<%KS#*#19d*rg6{xb vjBi2LW0&kAD0|Mu_kP9$MW6xS(jINU2ebeUp5FmtvyP5P0+9q>c?tYCK?sbO literal 0 HcmV?d00001 diff --git a/example-sdl/msvc/wiiusesdl.opt b/example-sdl/msvc/wiiusesdl.opt new file mode 100644 index 0000000000000000000000000000000000000000..fa46687ca8ba0f6b26f90b80a5827429b8b86bfd GIT binary patch literal 48640 zcmeHQL37*26$a&4l^Ms06E|txwB0goXg3xqO0pueu4VRGEf4_z!Go;xC&eYs2<@4(p6v?SOHdno4~JtHJ}Di zz1xW22iAc*zz4vGz(+tG_!yvi-Um#ca1n7hdI-4k&MYiNMFov%`BuZ;-lm?n6~pf1bXbn$xYLWQyt6kTdr$|H4L|D+M98SZr;^fs+zwgZFL>jmT?uN z^mY&*wA+>$Ud1&VhN^(1(TWd9In)lfC7n%mu}!-j7e|^6Yvdi*b~jy-_uCEsz7L%g z(N5Ft_#$sPh9_ybbi3%FO3Q2%Giwqp@nya{t~q39M82sTTTpVbGBZCX@@_lmRaM@T z8IjK9>hV?T)KItaNhbYqx;rjVO*m#YE+;bh+|J=Vap^$g6OR6BJ7~27u^x6P8hsF9 z8-t(A<G9o=(qGLAs8mM6ine8V;GQ@j;4 z?S*tS{4^{)7PwbR;l0vtEO2wSER1hB8ip;3Lfx+6(8t;qTv?;_7~gf2GPLEEFekh$r>lI9=@x39=9UGt4B zE`WPNH-)4q`VPvB7+Ug%6= z_WW72S*f}-J3TvF6xofoW0115D8n=EuJn9T{f6f@Mb>hHtO#7_qq@d%0V|8Ml%V>Wtd1@C&8RVynuFjyPVyB$5V zM0Mpxp)g;-2r5>RxEcNDKfUvIbZK&#eZI?EFWEe(U3HlkIzVbexR8vQ8_bO)C)6=>W3;%z_CLjZj#&ev zr-2E0{w`OqlWQy6|01t2_WvV4KKB13$4s{W!9kb(|H#8t`QE|J@e%%m?Ee?K--@BU z6xsie{r?g_yZ9Y+wBAA0@bkFyxGOFsW99~PBgqMM%-ncgctPRRb){LGNe+YX=-i{|D~>FL%j5g8AP& zbH9(3Y~Ax9#Bsx{`nV8s>LOFFJ@s50^EJ zV;uonAK^Kji_iX_?ElIBpR{JgL5$Ws|9kJxA$|{k{P%FBN!B6jP;ns{GdGwUNlvI^ z<_2>^aUmHG;s)D)liK2A*1+g!;5T1Kj-PMtnBFF7A-0oK|1dO1E@xQw9|* zir8N;35ieIV^&OIdE2lcpxy~AO}NWYIiO~A-RP6t3u)RU zum8Bf>pyFtif4u)o@2#}rl@)pam#4RB4e$TbZ<{Q(|Isf%en;nbbmBp; zz}#SN^x_5OF*leS-*#@W{jc8$aXxF{`PYEj|M}s=(37rY`&VqUX1k4@Nx`H9w*L+A z>f2}X?CVj;{(s5+x%=%oylcw@-v9Zjuf@s!f9(Iq{(tQM$Nqo4e(~{pJio{H;sxa~ zH<%mDjr|(n`{LQSFWCOKpSzsH8W$tFRzwvFE4#ss4te6D=QTw zs;i~NY7L27ve~My)ovEbxuDs~u>IGO#mWr(f3p84`+rJP485izJ!M?ui5RWf|C9Yc z$HwlfpEUbowq-mUwhT3JJYGCriVMk@xxw5>azY)CA~)Fnt45z=*1+g#U>vTUDebfI z(=hw}eoyyH`O>@LPC0vWX^J;t%KArWs#VrQRf&#OnaZPh{ttiD&Oj1{Ugcpy-;Zlg z>TU0x-_Fd=&&^$!FHg>1Sh_q}D3q>DUcNFrH#s%6xHvU6TPjR1P5(~Q&Y>;TPwJ1d zul^f}e*&tRAENL}RAT>6DcJsJx*cESEywU=Q#yfe7adpRTV|t}iC0q1ch@-0Av+`T zP2JeS*3xYMgV{&uVxt|jJt;hCOWl`g!xlw>y~mrnV+xp;_iVvEGlxQK$Rn~#*L)+3 z3-|%{hZ63F$X>mZ9ena5_U~S<9`1bJ|C{&!wq4&RGMajzr*}ECS1T(wz}yXF+d_Jt z>j~cfTYaI%@hHBBDHU+v**>ATkc^od%#9=`)G>2|xuLj_j0bUp?SDya@iA*)bTsfk D?Hm`n literal 0 HcmV?d00001 diff --git a/example-sdl/sdl.c b/example-sdl/sdl.c new file mode 100644 index 0000000..0c0cdfb --- /dev/null +++ b/example-sdl/sdl.c @@ -0,0 +1,439 @@ +/* + * Written By: + * Michael Laforest < para > + * Email: < thepara (--AT--) g m a i l [--DOT--] com > + * + * Copyright 2006-2007 + * + * 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$ + */ + +#include +#include + +#ifndef WIN32 + #include + #include + #include +#else + #include +#endif + +#include +#include +#include +#include + +#include + +#define PI 3.14159265358979323846 +#define PI_DIV_180 0.017453292519943296 +#define deg PI_DIV_180 + +#define MAX_WIIMOTES 2 + +GLint width = 1024, height = 768; +GLfloat backColor[4] = {1.0,1.0,1.0,1.0}; + +wiimote** wiimotes = NULL; + +int last_dots[4][2] = {{0}}; +int xcoord = 0; +int ycoord = 0; + +#ifdef WIN32 + DWORD last_render; +#else + struct timeval last_render; + int last_sec = 0; + int fps = 0; +#endif + +enum render_mode_t { + IR = 1, + TEAPOT +}; +enum render_mode_t render_mode = IR; + +/* light information */ +struct light_t { + GLfloat position[4]; + GLfloat spotDirection[3]; + GLfloat ambient[4]; + GLfloat diffuse[4]; + GLfloat specular[4]; + GLfloat spotCutoff; + GLfloat spotExponent; + GLfloat spotAttenuation[3]; /* [0] = constant, [1] = linear, [2] = quadratic */ +}; +struct light_t light = { + { 1.0, 1.0, -2.0, 1.0 }, + { -1.0, -1.0, 2.0 }, + { 0.0, 0.0, 0.0, 1.0 }, + { 1.0, 1.0, 1.0, 1.0 }, + { 1.0, 1.0, 1.0, 1.0 }, + 180.0, 0.0, + { 1.0, 0.0, 0.0 } +}; + +/* material information */ +struct material_t { + GLfloat ambient[4]; + GLfloat diffuse[4]; + GLfloat specular[4]; + GLfloat emission[4]; + GLfloat shininess; +}; +struct material_t red_plastic = { + { 0.3, 0.0, 0.0, 1.0 }, + { 0.3, 0.0, 0.0, 1.0 }, + { 0.8, 0.6, 0.6, 1.0 }, + { 0.0, 0.0, 0.0, 1.0 }, + 32.0 +}; + + +void handle_event(struct wiimote_t* wm); +void display(); +void update_light(GLenum l, struct light_t* lptr); +void set_material(struct material_t* mptr); +void resize_window(GLint new_width, GLint new_height); + +void handle_event(struct wiimote_t* wm) { + if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_PLUS)) + wiiuse_motion_sensing(wm, 1); + if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_MINUS)) + wiiuse_motion_sensing(wm, 0); + + if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_UP)) + wiiuse_set_ir(wm, 1); + if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_DOWN)) + wiiuse_set_ir(wm, 0); + + if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_B)) + wiiuse_toggle_rumble(wm); + + if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_ONE)) { + int level; + WIIUSE_GET_IR_SENSITIVITY(wm, &level); + wiiuse_set_ir_sensitivity(wm, level+1); + } + if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_TWO)) { + int level; + WIIUSE_GET_IR_SENSITIVITY(wm, &level); + wiiuse_set_ir_sensitivity(wm, level-1); + } + + #if 0 + if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_A)) { + if (render_mode == IR) + render_mode = TEAPOT; + else + render_mode = IR; + resize_window(width, height); + } + #endif +} + +#define DRAW_TRIANGLE(x, y, z, s) do { \ + glVertex3f(x, y-s, z); \ + glVertex3f(x+s, y+s, z); \ + glVertex3f(x-s, y+s, z); \ + } while (0) + +int can_render() { + /* quick fps limit to ~60fps -- not too fancy, could be better */ + #ifdef WIN32 + if (GetTickCount() < (last_render + 16)) + return 0; + last_render = GetTickCount(); + return 1; + #else + struct timeval now; + long elapsed_usec = 0; + + gettimeofday(&now, NULL); + + if (now.tv_usec > 1000000) { + now.tv_usec -= 1000000; + ++now.tv_sec; + } + + if (now.tv_sec > last_render.tv_sec) + elapsed_usec = ((now.tv_sec - last_render.tv_sec) * 1000000); + + if (now.tv_usec > last_render.tv_usec) + elapsed_usec += now.tv_usec - last_render.tv_usec; + else + elapsed_usec += last_render.tv_usec - now.tv_usec; + + if (time(NULL) > last_sec) { + printf("fps: %i\n", fps); + fps = 0; + last_sec = time(NULL); + } + + if (elapsed_usec < 16000) + return 0; + + last_render = now; + ++fps; + + return 1; + #endif +} + +void display() { + int i, wm; + float size = 5; + + if (!can_render()) + return; + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + if (render_mode == IR) { + /* draw the IR stuff */ + + glDisable(GL_LIGHTING); + + glBegin(GL_TRIANGLES); + /* green center */ + glColor3f(0.0, 1.0, 0.0); + DRAW_TRIANGLE(width/2, height/2, 0, size); + glEnd(); + + for (wm = 0; wm < MAX_WIIMOTES; ++wm) { + glBegin(GL_TRIANGLES); + /* red ir */ + glColor3f(1.0, 0.0, 0.0); + for (i = 0; i < 4; ++i) { + if (wiimotes[wm]->ir.dot[i].visible) + DRAW_TRIANGLE(wiimotes[wm]->ir.dot[i].rx, wiimotes[wm]->ir.dot[i].ry, 0, size); + } + + /* yellow corrected ir */ + glColor3f(1.0, 1.0, 0.0); + for (i = 0; i < 4; ++i) { + if (wiimotes[wm]->ir.dot[i].visible) + DRAW_TRIANGLE(wiimotes[wm]->ir.dot[i].x, wiimotes[wm]->ir.dot[i].y, 0, size); + } + + /* blue cursor */ + glColor3f(0.0, 0.0, 1.0); + DRAW_TRIANGLE(wiimotes[wm]->ir.x, wiimotes[wm]->ir.y-size, 0, size); + glEnd(); + } + } else { + /* draw the teapot */ + gluLookAt(0.0, 0.0, -5.0, + 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0); + + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + update_light(GL_LIGHT0, &light); + set_material(&red_plastic); + + glRotatef(wiimotes[0]->orient.roll, 0.0f, 0.0f, 1.0f); + glRotatef(wiimotes[0]->orient.pitch, 1.0f, 0.0f, 0.0f); + + + glutSolidTeapot(1); + } + + SDL_GL_SwapBuffers(); +} + + +void update_light(GLenum l, struct light_t* lptr) { + glLightfv(l, GL_POSITION, lptr->position); + glLightfv(l, GL_DIFFUSE, lptr->diffuse); + glLightfv(l, GL_SPECULAR, lptr->specular); + glLightfv(l, GL_AMBIENT, lptr->ambient); + glLightfv(l, GL_SPOT_DIRECTION, lptr->spotDirection); + glLightf(l, GL_SPOT_CUTOFF, lptr->spotCutoff); + glLightf(l, GL_SPOT_EXPONENT, lptr->spotExponent); + glLightf(l, GL_CONSTANT_ATTENUATION, lptr->spotAttenuation[0]); + glLightf(l, GL_LINEAR_ATTENUATION, lptr->spotAttenuation[1]); + glLightf(l, GL_QUADRATIC_ATTENUATION, lptr->spotAttenuation[2]); +} + + +void set_material(struct material_t* mptr) { + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mptr->ambient); + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mptr->diffuse); + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mptr->specular); + glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, mptr->shininess); + glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, mptr->emission); +} + + +void resize_window(GLint new_width, GLint new_height) { + int wm; + + width = new_width; + height = new_height; + + if (new_height == 0) + new_height = 1; + + SDL_SetVideoMode(width, height, 16, SDL_RESIZABLE | SDL_OPENGL); + + glViewport(0, 0, new_width, new_height); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + if (render_mode == IR) + gluOrtho2D(0, width, height, 0); + else + gluPerspective(60.0f, (float)new_width/(float)new_height, 0.1f, 100.0f); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + width = new_width; + height = new_height; + + for (wm = 0; wm < MAX_WIIMOTES; ++wm) + wiiuse_set_ir_vres(wiimotes[wm], width, height); +} + +#ifndef WIN32 +int main(int argc, char** argv) { +#else +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { +#endif + int found, connected; + int wm; + + //printf("wiiuse version = %s\n", wiiuse_version()); + + wiimotes = wiiuse_init(MAX_WIIMOTES); + found = wiiuse_find(wiimotes, MAX_WIIMOTES, 5); + if (!found) + return 0; + connected = wiiuse_connect(wiimotes, MAX_WIIMOTES); + if (connected) + printf("Connected to %i wiimotes (of %i found).\n", connected, found); + else { + printf("Failed to connect to any wiimote.\n"); + return 0; + } + wiiuse_set_leds(wiimotes[0], WIIMOTE_LED_1 | WIIMOTE_LED_4); + wiiuse_set_leds(wiimotes[1], WIIMOTE_LED_2 | WIIMOTE_LED_4); + wiiuse_rumble(wiimotes[0], 1); + + #ifndef WIN32 + usleep(200000); + #else + Sleep(200); + #endif + + wiiuse_rumble(wiimotes[0], 0); + + /* enable IR and motion sensing for all wiimotes */ + for (wm = 0; wm < MAX_WIIMOTES; ++wm) { + wiiuse_motion_sensing(wiimotes[wm], 1); + wiiuse_set_ir(wiimotes[wm], 1); + } + + if (SDL_Init(SDL_INIT_VIDEO) < 0) { + printf("Failed to initialize SDL: %s\n", SDL_GetError()); + return 0; + } + + SDL_WM_SetCaption("wiiuse SDL IR Example", "wiiuse SDL IR Example"); + + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); + + /* set window size */ + width = wiimotes[0]->ir.vres[0]; + height = wiimotes[0]->ir.vres[1]; + SDL_SetVideoMode(width, height, 16, SDL_RESIZABLE | SDL_OPENGL); + + for (wm = 0; wm < MAX_WIIMOTES; ++wm) + wiiuse_set_ir_vres(wiimotes[wm], width, height); + + /* set OpenGL stuff */ + glEnable(GL_DEPTH_TEST); + glEnable(GL_LIGHTING); + glEnable(GL_NORMALIZE); + glEnable(GL_BLEND); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDepthFunc(GL_LEQUAL); + glClearColor(0, 0, 0, 0); + + /* set the size of the window */ + resize_window(width, height); + + display(); + + #ifdef WIN32 + last_render = GetTickCount(); + #endif + + while (1) { + SDL_Event event; + + if (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_VIDEORESIZE: + { + /* resize the window */ + resize_window(event.resize.w, event.resize.h); + break; + } + case SDL_QUIT: + { + /* shutdown */ + SDL_Quit(); + wiiuse_cleanup(wiimotes, MAX_WIIMOTES); + return 0; + } + default: + { + } + } + } + + if (wiiuse_poll(wiimotes, MAX_WIIMOTES)) { + /* + * This happens if something happened on any wiimote. + * So go through each one and check if anything happened. + */ + int i = 0; + for (; i < MAX_WIIMOTES; ++i) { + switch (wiimotes[i]->event) { + case WIIUSE_EVENT: + /* a generic event occured */ + handle_event(wiimotes[i]); + break; + + default: + break; + } + } + } + + display(); + } +} diff --git a/example/Makefile b/example/Makefile new file mode 100644 index 0000000..41b5cd1 --- /dev/null +++ b/example/Makefile @@ -0,0 +1,84 @@ +# +# 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 = -L../src/$(OBJ_DIR) -lm -lwiiuse + +# +# Target binaries (always created as BIN) +# +BIN = ./$(OBJ_DIR)/wiiuse-example + +# +# Inclusion paths. +# +INCLUDES = -I../src/ + +# +# Generate a list of object files +# +OBJS = $(OBJ_DIR)/example.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/bin ; \ + fi + + +$(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 + +run: all + LD_LIBRARY_PATH=`pwd`/../src/$(OBJ_DIR):$(LD_LIBRARY_PATH) $(BIN) + diff --git a/example/example.c b/example/example.c new file mode 100644 index 0000000..9fee161 --- /dev/null +++ b/example/example.c @@ -0,0 +1,437 @@ +/* + * 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 Example using the wiiuse API. + * + * This file is an example of how to use the wiiuse library. + */ + +#include +#include + +#ifndef WIN32 + #include +#endif + +#include "wiiuse.h" + + +#define MAX_WIIMOTES 4 + + +/** + * @brief Callback that handles an event. + * + * @param wm Pointer to a wiimote_t structure. + * + * This function is called automatically by the wiiuse library when an + * event occurs on the specified wiimote. + */ +void handle_event(struct wiimote_t* wm) { + printf("\n\n--- EVENT [id %i] ---\n", wm->unid); + + /* if a button is pressed, report it */ + if (IS_PRESSED(wm, WIIMOTE_BUTTON_A)) printf("A pressed\n"); + if (IS_PRESSED(wm, WIIMOTE_BUTTON_B)) printf("B pressed\n"); + if (IS_PRESSED(wm, WIIMOTE_BUTTON_UP)) printf("UP pressed\n"); + if (IS_PRESSED(wm, WIIMOTE_BUTTON_DOWN)) printf("DOWN pressed\n"); + if (IS_PRESSED(wm, WIIMOTE_BUTTON_LEFT)) printf("LEFT pressed\n"); + if (IS_PRESSED(wm, WIIMOTE_BUTTON_RIGHT)) printf("RIGHT pressed\n"); + if (IS_PRESSED(wm, WIIMOTE_BUTTON_MINUS)) printf("MINUS pressed\n"); + if (IS_PRESSED(wm, WIIMOTE_BUTTON_PLUS)) printf("PLUS pressed\n"); + if (IS_PRESSED(wm, WIIMOTE_BUTTON_ONE)) printf("ONE pressed\n"); + if (IS_PRESSED(wm, WIIMOTE_BUTTON_TWO)) printf("TWO pressed\n"); + if (IS_PRESSED(wm, WIIMOTE_BUTTON_HOME)) printf("HOME pressed\n"); + + /* + * Pressing minus will tell the wiimote we are no longer interested in movement. + * This is useful because it saves battery power. + */ + if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_MINUS)) + wiiuse_motion_sensing(wm, 0); + + /* + * Pressing plus will tell the wiimote we are interested in movement. + */ + if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_PLUS)) + wiiuse_motion_sensing(wm, 1); + + /* + * Pressing B will toggle the rumble + * + * if B is pressed but is not held, toggle the rumble + */ + if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_B)) + wiiuse_toggle_rumble(wm); + + if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_UP)) + wiiuse_set_ir(wm, 1); + if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_DOWN)) + wiiuse_set_ir(wm, 0); + + /* if the accelerometer is turned on then print angles */ + if (WIIUSE_USING_ACC(wm)) { + printf("wiimote roll = %f [%f]\n", wm->orient.roll, wm->orient.a_roll); + printf("wiimote pitch = %f [%f]\n", wm->orient.pitch, wm->orient.a_pitch); + printf("wiimote yaw = %f\n", wm->orient.yaw); + } + + /* + * If IR tracking is enabled then print the coordinates + * on the virtual screen that the wiimote is pointing to. + * + * Also make sure that we see at least 1 dot. + */ + if (WIIUSE_USING_IR(wm)) { + int i = 0; + + /* go through each of the 4 possible IR sources */ + for (; i < 4; ++i) { + /* check if the source is visible */ + if (wm->ir.dot[i].visible) + printf("IR source %i: (%u, %u)\n", i, wm->ir.dot[i].x, wm->ir.dot[i].y); + } + + printf("IR cursor: (%u, %u)\n", wm->ir.x, wm->ir.y); + printf("IR z distance: %f\n", wm->ir.z); + } + + /* show events specific to supported expansions */ + if (wm->exp.type == EXP_NUNCHUK) { + /* nunchuk */ + struct nunchuk_t* nc = (nunchuk_t*)&wm->exp.nunchuk; + + if (IS_PRESSED(nc, NUNCHUK_BUTTON_C)) printf("Nunchuk: C pressed\n"); + if (IS_PRESSED(nc, NUNCHUK_BUTTON_Z)) printf("Nunchuk: Z pressed\n"); + + printf("nunchuk roll = %f\n", nc->orient.roll); + printf("nunchuk pitch = %f\n", nc->orient.pitch); + printf("nunchuk yaw = %f\n", nc->orient.yaw); + + printf("nunchuk joystick angle: %f\n", nc->js.ang); + printf("nunchuk joystick magnitude: %f\n", nc->js.mag); + } else if (wm->exp.type == EXP_CLASSIC) { + /* classic controller */ + struct classic_ctrl_t* cc = (classic_ctrl_t*)&wm->exp.classic; + + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_ZL)) printf("Classic: ZL pressed\n"); + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_B)) printf("Classic: B pressed\n"); + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_Y)) printf("Classic: Y pressed\n"); + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_A)) printf("Classic: A pressed\n"); + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_X)) printf("Classic: X pressed\n"); + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_ZR)) printf("Classic: ZR pressed\n"); + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_LEFT)) printf("Classic: LEFT pressed\n"); + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_UP)) printf("Classic: UP pressed\n"); + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_RIGHT)) printf("Classic: RIGHT pressed\n"); + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_DOWN)) printf("Classic: DOWN pressed\n"); + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_FULL_L)) printf("Classic: FULL L pressed\n"); + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_MINUS)) printf("Classic: MINUS pressed\n"); + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_HOME)) printf("Classic: HOME pressed\n"); + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_PLUS)) printf("Classic: PLUS pressed\n"); + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_FULL_R)) printf("Classic: FULL R pressed\n"); + + printf("classic L button pressed: %f\n", cc->l_shoulder); + printf("classic R button pressed: %f\n", cc->r_shoulder); + printf("classic left joystick angle: %f\n", cc->ljs.ang); + printf("classic left joystick magnitude: %f\n", cc->ljs.mag); + printf("classic right joystick angle: %f\n", cc->rjs.ang); + printf("classic right joystick magnitude: %f\n", cc->rjs.mag); + } else if (wm->exp.type == EXP_GUITAR_HERO_3) { + /* guitar hero 3 guitar */ + struct guitar_hero_3_t* gh3 = (guitar_hero_3_t*)&wm->exp.gh3; + + if (IS_PRESSED(gh3, GUITAR_HERO_3_BUTTON_STRUM_UP)) printf("Guitar: Strum Up pressed\n"); + if (IS_PRESSED(gh3, GUITAR_HERO_3_BUTTON_STRUM_DOWN)) printf("Guitar: Strum Down pressed\n"); + if (IS_PRESSED(gh3, GUITAR_HERO_3_BUTTON_YELLOW)) printf("Guitar: Yellow pressed\n"); + if (IS_PRESSED(gh3, GUITAR_HERO_3_BUTTON_GREEN)) printf("Guitar: Green pressed\n"); + if (IS_PRESSED(gh3, GUITAR_HERO_3_BUTTON_BLUE)) printf("Guitar: Blue pressed\n"); + if (IS_PRESSED(gh3, GUITAR_HERO_3_BUTTON_RED)) printf("Guitar: Red pressed\n"); + if (IS_PRESSED(gh3, GUITAR_HERO_3_BUTTON_ORANGE)) printf("Guitar: Orange pressed\n"); + if (IS_PRESSED(gh3, GUITAR_HERO_3_BUTTON_PLUS)) printf("Guitar: Plus pressed\n"); + if (IS_PRESSED(gh3, GUITAR_HERO_3_BUTTON_MINUS)) printf("Guitar: Minus pressed\n"); + + printf("Guitar whammy bar: %f\n", gh3->whammy_bar); + printf("Guitar joystick angle: %f\n", gh3->js.ang); + printf("Guitar joystick magnitude: %f\n", gh3->js.mag); + } +} + + +/** + * @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. + * + * This function is called automatically by the wiiuse library when + * the wiimote has returned the full data requested by a previous + * call to wiiuse_read_data(). + * + * You can read data on the wiimote, such as Mii data, if + * you know the offset address and the length. + * + * The \a data pointer was specified on the call to wiiuse_read_data(). + * At the time of this function being called, it is not safe to deallocate + * this buffer. + */ +void handle_read(struct wiimote_t* wm, byte* data, unsigned short len) { + int i = 0; + + printf("\n\n--- DATA READ [wiimote id %i] ---\n", wm->unid); + printf("finished read of size %i\n", len); + for (; i < len; ++i) { + if (!(i%16)) + printf("\n"); + printf("%x ", data[i]); + } + printf("\n\n"); +} + + +/** + * @brief Callback that handles a controller status event. + * + * @param wm Pointer to a wiimote_t structure. + * @param attachment Is there an attachment? (1 for yes, 0 for no) + * @param speaker Is the speaker enabled? (1 for yes, 0 for no) + * @param ir Is the IR support enabled? (1 for yes, 0 for no) + * @param led What LEDs are lit. + * @param battery_level Battery level, between 0.0 (0%) and 1.0 (100%). + * + * This occurs when either the controller status changed + * or the controller status was requested explicitly by + * wiiuse_status(). + * + * One reason the status can change is if the nunchuk was + * inserted or removed from the expansion port. + */ +void handle_ctrl_status(struct wiimote_t* wm) { + printf("\n\n--- CONTROLLER STATUS [wiimote id %i] ---\n", wm->unid); + + printf("attachment: %i\n", wm->exp.type); + printf("speaker: %i\n", WIIUSE_USING_SPEAKER(wm)); + printf("ir: %i\n", WIIUSE_USING_IR(wm)); + printf("leds: %i %i %i %i\n", WIIUSE_IS_LED_SET(wm, 1), WIIUSE_IS_LED_SET(wm, 2), WIIUSE_IS_LED_SET(wm, 3), WIIUSE_IS_LED_SET(wm, 4)); + printf("battery: %f %%\n", wm->battery_level); +} + + +/** + * @brief Callback that handles a disconnection event. + * + * @param wm Pointer to a wiimote_t structure. + * + * This can happen if the POWER button is pressed, or + * if the connection is interrupted. + */ +void handle_disconnect(wiimote* wm) { + printf("\n\n--- DISCONNECTED [wiimote id %i] ---\n", wm->unid); +} + + +void test(struct wiimote_t* wm, byte* data, unsigned short len) { + printf("test: %i [%x %x %x %x]\n", len, data[0], data[1], data[2], data[3]); +} + + + +/** + * @brief main() + * + * Connect to up to two wiimotes and print any events + * that occur on either device. + */ +int main(int argc, char** argv) { + wiimote** wiimotes; + int found, connected; + + /* + * Initialize an array of wiimote objects. + * + * The parameter is the number of wiimotes I want to create. + */ + wiimotes = wiiuse_init(MAX_WIIMOTES); + + /* + * Find wiimote devices + * + * Now we need to find some wiimotes. + * Give the function the wiimote array we created, and tell it there + * are MAX_WIIMOTES wiimotes we are interested in. + * + * Set the timeout to be 5 seconds. + * + * This will return the number of actual wiimotes that are in discovery mode. + */ + found = wiiuse_find(wiimotes, MAX_WIIMOTES, 5); + if (!found) { + printf ("No wiimotes found."); + return 0; + } + + /* + * Connect to the wiimotes + * + * Now that we found some wiimotes, connect to them. + * Give the function the wiimote array and the number + * of wiimote devices we found. + * + * This will return the number of established connections to the found wiimotes. + */ + connected = wiiuse_connect(wiimotes, MAX_WIIMOTES); + if (connected) + printf("Connected to %i wiimotes (of %i found).\n", connected, found); + else { + printf("Failed to connect to any wiimote.\n"); + return 0; + } + + /* + * Now set the LEDs and rumble for a second so it's easy + * to tell which wiimotes are connected (just like the wii does). + */ + wiiuse_set_leds(wiimotes[0], WIIMOTE_LED_1); + wiiuse_set_leds(wiimotes[1], WIIMOTE_LED_2); + wiiuse_set_leds(wiimotes[2], WIIMOTE_LED_3); + wiiuse_set_leds(wiimotes[3], WIIMOTE_LED_4); + wiiuse_rumble(wiimotes[0], 1); + wiiuse_rumble(wiimotes[1], 1); + + #ifndef WIN32 + usleep(200000); + #else + Sleep(200); + #endif + + wiiuse_rumble(wiimotes[0], 0); + wiiuse_rumble(wiimotes[1], 0); + + /* + * Maybe I'm interested in the battery power of the 0th + * wiimote. This should be WIIMOTE_ID_1 but to be sure + * you can get the wiimote assoicated with WIIMOTE_ID_1 + * using the wiiuse_get_by_id() function. + * + * A status request will return other things too, like + * if any expansions are plugged into the wiimote or + * what LEDs are lit. + */ + //wiiuse_status(wiimotes[0]); + + /* + * This is the main loop + * + * wiiuse_poll() needs to be called with the wiimote array + * and the number of wiimote structures in that array + * (it doesn't matter if some of those wiimotes are not used + * or are not connected). + * + * This function will set the event flag for each wiimote + * when the wiimote has things to report. + */ + while (1) { + if (wiiuse_poll(wiimotes, MAX_WIIMOTES)) { + /* + * This happens if something happened on any wiimote. + * So go through each one and check if anything happened. + */ + int i = 0; + for (; i < MAX_WIIMOTES; ++i) { + switch (wiimotes[i]->event) { + case WIIUSE_EVENT: + /* a generic event occured */ + handle_event(wiimotes[i]); + break; + + case WIIUSE_STATUS: + /* a status event occured */ + handle_ctrl_status(wiimotes[i]); + break; + + case WIIUSE_DISCONNECT: + case WIIUSE_UNEXPECTED_DISCONNECT: + /* the wiimote disconnected */ + handle_disconnect(wiimotes[i]); + break; + + case WIIUSE_READ_DATA: + /* + * Data we requested to read was returned. + * Take a look at wiimotes[i]->read_req + * for the data. + */ + break; + + case WIIUSE_NUNCHUK_INSERTED: + /* + * a nunchuk was inserted + * This is a good place to set any nunchuk specific + * threshold values. By default they are the same + * as the wiimote. + */ + //wiiuse_set_nunchuk_orient_threshold((struct nunchuk_t*)&wiimotes[i]->exp.nunchuk, 90.0f); + //wiiuse_set_nunchuk_accel_threshold((struct nunchuk_t*)&wiimotes[i]->exp.nunchuk, 100); + printf("Nunchuk inserted.\n"); + break; + + case WIIUSE_CLASSIC_CTRL_INSERTED: + printf("Classic controller inserted.\n"); + break; + + case WIIUSE_GUITAR_HERO_3_CTRL_INSERTED: + /* some expansion was inserted */ + handle_ctrl_status(wiimotes[i]); + printf("Guitar Hero 3 controller inserted.\n"); + break; + + case WIIUSE_NUNCHUK_REMOVED: + case WIIUSE_CLASSIC_CTRL_REMOVED: + case WIIUSE_GUITAR_HERO_3_CTRL_REMOVED: + /* some expansion was removed */ + handle_ctrl_status(wiimotes[i]); + printf("An expansion was removed.\n"); + break; + + default: + break; + } + } + } + } + + /* + * Disconnect the wiimotes + */ + wiiuse_cleanup(wiimotes, MAX_WIIMOTES); + + return 0; +} diff --git a/example/msvc/wiiuseexample.dsp b/example/msvc/wiiuseexample.dsp new file mode 100644 index 0000000..9e9b34f --- /dev/null +++ b/example/msvc/wiiuseexample.dsp @@ -0,0 +1,106 @@ +# Microsoft Developer Studio Project File - Name="wiiuseexample" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=wiiuseexample - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "wiiuseexample.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "wiiuseexample.mak" CFG="wiiuseexample - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "wiiuseexample - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "wiiuseexample - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "wiiuseexample - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\..\src" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib wiiuse.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "wiiuseexample - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\src" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "wiiuseexample - Win32 Release" +# Name "wiiuseexample - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\example.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\src\wiiuse.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/example/msvc/wiiuseexample.dsw b/example/msvc/wiiuseexample.dsw new file mode 100644 index 0000000..e31f8f5 --- /dev/null +++ b/example/msvc/wiiuseexample.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "wiiuseexample"=".\wiiuseexample.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/example/msvc/wiiuseexample.ncb b/example/msvc/wiiuseexample.ncb new file mode 100644 index 0000000000000000000000000000000000000000..d943e18bec7fa8d21f55deb8395e535d6437cc50 GIT binary patch literal 58368 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 AyZ`_I literal 0 HcmV?d00001 diff --git a/example/msvc/wiiuseexample.opt b/example/msvc/wiiuseexample.opt new file mode 100644 index 0000000000000000000000000000000000000000..fe837f89e234c5220eb3fb941ec44928f332e83c GIT binary patch literal 48640 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 ^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/src/classic.c b/src/classic.c new file mode 100644 index 0000000..1d2c3ab --- /dev/null +++ b/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/src/classic.h b/src/classic.h new file mode 100644 index 0000000..356f6a4 --- /dev/null +++ b/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/src/definitions.h b/src/definitions.h new file mode 100644 index 0000000..5a8da85 --- /dev/null +++ b/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/src/dynamics.c b/src/dynamics.c new file mode 100644 index 0000000..53612a6 --- /dev/null +++ b/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/src/dynamics.h b/src/dynamics.h new file mode 100644 index 0000000..2a8f965 --- /dev/null +++ b/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/src/events.c b/src/events.c new file mode 100644 index 0000000..6668eda --- /dev/null +++ b/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/src/events.h b/src/events.h new file mode 100644 index 0000000..5e9b955 --- /dev/null +++ b/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/src/guitar_hero_3.c b/src/guitar_hero_3.c new file mode 100644 index 0000000..5837dc0 --- /dev/null +++ b/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/src/guitar_hero_3.h b/src/guitar_hero_3.h new file mode 100644 index 0000000..024d603 --- /dev/null +++ b/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/src/io.c b/src/io.c new file mode 100644 index 0000000..ae420b9 --- /dev/null +++ b/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/src/io.h b/src/io.h new file mode 100644 index 0000000..7a683e4 --- /dev/null +++ b/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/src/io_nix.c b/src/io_nix.c new file mode 100644 index 0000000..ec4e0e1 --- /dev/null +++ b/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/src/io_win.c b/src/io_win.c new file mode 100644 index 0000000..17fac36 --- /dev/null +++ b/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/src/ir.c b/src/ir.c new file mode 100644 index 0000000..7a9bb68 --- /dev/null +++ b/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/src/ir.h b/src/ir.h new file mode 100644 index 0000000..9082492 --- /dev/null +++ b/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/src/msvc/wiiuse.dsp b/src/msvc/wiiuse.dsp new file mode 100644 index 0000000..dd66ae7 --- /dev/null +++ b/src/msvc/wiiuse.dsp @@ -0,0 +1,191 @@ +# Microsoft Developer Studio Project File - Name="wiiuse" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=wiiuse - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "wiiuse.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "wiiuse.mak" CFG="wiiuse - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "wiiuse - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "wiiuse - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "wiiuse - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WIIUSE_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WIIUSE_EXPORTS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Ws2_32.lib hid.lib setupapi.lib /nologo /dll /machine:I386 + +!ELSEIF "$(CFG)" == "wiiuse - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WIIUSE_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WIIUSE_EXPORTS" /D "WITH_WIIUSE_DEBUG" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Ws2_32.lib hid.lib setupapi.lib /nologo /dll /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "wiiuse - Win32 Release" +# Name "wiiuse - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\classic.c +# End Source File +# Begin Source File + +SOURCE=..\dynamics.c +# End Source File +# Begin Source File + +SOURCE=..\events.c +# End Source File +# Begin Source File + +SOURCE=..\guitar_hero_3.c +# End Source File +# Begin Source File + +SOURCE=..\io.c +# End Source File +# Begin Source File + +SOURCE=..\io_nix.c +# End Source File +# Begin Source File + +SOURCE=..\io_win.c +# End Source File +# Begin Source File + +SOURCE=..\ir.c +# End Source File +# Begin Source File + +SOURCE=..\nunchuk.c +# End Source File +# Begin Source File + +SOURCE=..\wiiuse.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\classic.h +# End Source File +# Begin Source File + +SOURCE=..\definitions.h +# End Source File +# Begin Source File + +SOURCE=..\dynamics.h +# End Source File +# Begin Source File + +SOURCE=..\events.h +# End Source File +# Begin Source File + +SOURCE=..\guitar_hero_3.h +# End Source File +# Begin Source File + +SOURCE=..\io.h +# End Source File +# Begin Source File + +SOURCE=..\ir.h +# End Source File +# Begin Source File + +SOURCE=..\nunchuk.h +# End Source File +# Begin Source File + +SOURCE=..\os.h +# End Source File +# Begin Source File + +SOURCE=..\wiiuse.h +# End Source File +# Begin Source File + +SOURCE=..\wiiuse_internal.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=..\..\CHANGELOG +# End Source File +# End Group +# End Target +# End Project diff --git a/src/msvc/wiiuse.dsw b/src/msvc/wiiuse.dsw new file mode 100644 index 0000000..5d662bf --- /dev/null +++ b/src/msvc/wiiuse.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "wiiuse"=".\wiiuse.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/src/msvc/wiiuse.ncb b/src/msvc/wiiuse.ncb new file mode 100644 index 0000000000000000000000000000000000000000..80073e4863f90716b48bf29474bf78eebf9dd8a8 GIT binary patch literal 115712 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 literal 0 HcmV?d00001 diff --git a/src/msvc/wiiuse.opt b/src/msvc/wiiuse.opt new file mode 100644 index 0000000000000000000000000000000000000000..b6ebe4c479239c2ec58ee8c9e4382f397e1a8c44 GIT binary patch literal 52736 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 CA%+qF literal 0 HcmV?d00001 diff --git a/src/nunchuk.c b/src/nunchuk.c new file mode 100644 index 0000000..48dbe6a --- /dev/null +++ b/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/src/nunchuk.h b/src/nunchuk.h new file mode 100644 index 0000000..f036073 --- /dev/null +++ b/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/src/os.h b/src/os.h new file mode 100644 index 0000000..53b80f5 --- /dev/null +++ b/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/src/wiiuse.c b/src/wiiuse.c new file mode 100644 index 0000000..8d4b763 --- /dev/null +++ b/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/src/wiiuse.h b/src/wiiuse.h new file mode 100644 index 0000000..9dff81c --- /dev/null +++ b/src/wiiuse.h @@ -0,0 +1,653 @@ +/* + * 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); + + +#ifdef __cplusplus +} +#endif + + +#endif /* WIIUSE_H_INCLUDED */ + diff --git a/src/wiiuse_internal.h b/src/wiiuse_internal.h new file mode 100644 index 0000000..1b2f423 --- /dev/null +++ b/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/wiiuse.cbp b/wiiuse.cbp new file mode 100644 index 0000000..a71d3a0 --- /dev/null +++ b/wiiuse.cbp @@ -0,0 +1,86 @@ + + + + + + diff --git a/wiiuse.layout b/wiiuse.layout new file mode 100644 index 0000000..5b74afe --- /dev/null +++ b/wiiuse.layout @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +