├── .gitignore ├── .travis.yml ├── AUTHORS ├── COPYING ├── ChangeLog ├── Makefile.in ├── NEWS ├── README.md ├── common └── include │ ├── .gitignore │ ├── app.mak │ ├── config.h.in │ ├── dep.mak │ ├── lib.mak.in │ └── plugin.mak ├── configure.ac ├── defs.mak.in ├── libcwiid ├── Makefile.in ├── bluetooth.c ├── command.c ├── connect.c ├── cwiid.h ├── cwiid.pc.in ├── cwiid_internal.h ├── interface.c ├── process.c ├── state.c ├── thread.c └── util.c └── python ├── Makefile.in ├── Wiimote.c ├── cwiidmodule.c └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.d 2 | *.o 3 | *.a 4 | *.pc 5 | *.so 6 | *.so.* 7 | Makefile 8 | aclocal.m4 9 | autom4te.cache 10 | config.* 11 | configure 12 | defs.mak 13 | python/installed_files.txt 14 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | before_install: 4 | - sudo apt-get -qq update 5 | - sudo apt-get install -y libbluetooth-dev 6 | 7 | python: 8 | - "3.2" 9 | - "3.3" 10 | - "3.4" 11 | - "3.5" 12 | - "3.5-dev" 13 | - "3.6" 14 | - "3.6-dev" 15 | - "3.7-dev" 16 | - "nightly" 17 | 18 | script: 19 | - | 20 | aclocal 21 | autoconf 22 | ./configure 23 | make 24 | cd libcwiid/ 25 | sudo make install 26 | cd ../python/ 27 | python setup.py install 28 | python -c 'import cwiid' 29 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | L. Donnie Smith 2 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 2007-08-26 L. Donnie Smith 2 | docs 3 | * updated wminput man page 4 | 5 | 2007-08-23 L. Donnie Smith 6 | python 7 | * fixed libdir install bug 8 | 9 | 2007-08-14 L. Donnie Smith 10 | libcwiid 11 | * make cwiid_err_default public 12 | 13 | wminput 14 | * added {c,py}_wiimote_deinit functions 15 | * added daemon, quiet, and reconnect options 16 | 17 | 2007-07-29 L. Donnie Smith 18 | wminput 19 | * fixed wait forever logic 20 | 21 | 2007-07-28 L. Donnie Smith 22 | configure.ac 23 | * added config.h header 24 | * added with-python argument and associated logic 25 | 26 | lswm 27 | * added config.h include for sources requiring defs 28 | 29 | wmgui 30 | * added config.h include for sources requiring defs 31 | 32 | wminput 33 | * added config.h include for sources requiring defs 34 | * added HAVE_PYTHON tests around all python code 35 | 36 | 2007-06-28 L. Donnie Smith 37 | libcwiid 38 | * changed version 39 | 40 | python 41 | * implemented uninstall 42 | 43 | wminput 44 | * rewrote ir_ptr plugin 45 | * supress error for nonexistent python plugins 46 | 47 | 2007-06-18 L. Donnie Smith 48 | wminput 49 | * revised error messages 50 | 51 | python 52 | * revised error messages and doc strings 53 | 54 | 2007-06-14 L. Donnie Smith 55 | libcwiid 56 | * added sleep after cwiid_find_wiimote call 57 | 58 | python 59 | * added --prefix option to install script 60 | 61 | 2007-06-05 L. Donnie Smith 62 | python 63 | * removed Wiimote_FromC function 64 | * added bdaddr argument to Wiimote.init 65 | * overloaded Wiimote.init to accept CObject (existing wiimote), 66 | and logic to avoid closing it on dealloc 67 | 68 | wminput 69 | * refactored to isolate plugin logic 70 | * now imports python plugins without changing directories 71 | 72 | 2007-06-01 Nick 73 | lswm 74 | * reworked command-line options (added standard options, long options) 75 | 76 | wminput 77 | * reworked command-line options (added standard options, long options) 78 | 79 | 2007-06-01 L. Donnie Smith 80 | python 81 | * added Wiimote_FromC 82 | * exported Wiimote_FromC and ConvertMesgArray as CObjects 83 | * added get_acc_cal 84 | 85 | wminput 86 | * added pyplugin.c, pyplugin.h 87 | * changed wmplugin_exec prototype (&mesg->mesg) 88 | * changed param format (pass pointers) 89 | * added python plugin support (experimental) 90 | 91 | 2007-05-30 L. Donnie Smith 92 | configure.ac 93 | * added python/Makefile and PYTHON_VERSION variable 94 | 95 | build system 96 | * added ROOTDIR (massaged DESTDIR) 97 | 98 | python 99 | * added directory 100 | 101 | 2007-05-27 Arthur Peters 102 | python 103 | * removed set_mesg_callback from methods table 104 | 105 | 2007-05-16 L. Donnie Smith 106 | libcwiid 107 | * removed error_pipe 108 | * fixed error message reporting 109 | * changed cwiid_connect, cwiid_disconnect to cwiid_open, cwiid_close 110 | (added macros for backward compatibility) 111 | * split cwiid_command into cwiid_request_status, cwiid_set_led, 112 | cwiid_set_rumble, cwiid_set_rpt_mode (kept cwiid_command for backward 113 | compatibility) 114 | 115 | wmdemo 116 | * updated for function name changes 117 | 118 | wmgui 119 | * updated for function name changes 120 | 121 | wminput 122 | * updated for function name changes 123 | 124 | 2007-05-14 L. Donnie Smith 125 | libcwiid 126 | * added timestamp to message interfaces 127 | * added cwiid_get_acc_cal 128 | 129 | wmdemo 130 | * updated for timestamp addition 131 | 132 | wmgui 133 | * updated for timestamp addition 134 | * use cwiid_get_acc_cal to get acc calibration values 135 | 136 | wminput 137 | * updated for timestamp addition 138 | * use cwiid_get_acc_cal to get acc calibration values (acc plugins) 139 | 140 | 2007-04-24 L. Donnie Smith 141 | libcwiid 142 | * rewrite (API overhaul) 143 | 144 | wmdemo 145 | * updated for API overhaul 146 | 147 | wmgui 148 | * updated for API overhaul 149 | 150 | wminput 151 | * updated for API overhaul 152 | 153 | 2007-04-15 154 | wminput 155 | * fixed classic controller configuration bug 156 | 157 | 2007-04-12 L. Donnie Smith 158 | libcwiid 159 | * streamlined wiimote filter 160 | 161 | 2007-04-12 Petter Reinholdtsen 162 | wmdemo 163 | * added command-line WIIMOTE_BDADDR 164 | 165 | 2007-04-09 L. Donnie Smith 166 | libcwiid 167 | * renamed from libwiimote 168 | * renamed external data structures 169 | 170 | lswm 171 | * updated for libcwiid rename 172 | 173 | wmdemo 174 | * updated for libcwiid rename 175 | 176 | wmgui 177 | * updated for libcwiid rename 178 | 179 | wminput 180 | * updated for libcwiid rename 181 | 182 | 2007-04-08 Arthur Peters 183 | wminput 184 | * added debounce and low-pass filter to ir_ptr plugin 185 | * added low-pass filter to acc plugin 186 | 187 | 2007-04-08 L. Donnie Smith 188 | defs.mak 189 | * added DEBUGFLAGS variable 190 | 191 | wiimote 192 | * fixed incompatible pointer warning in process_error 193 | 194 | wmgui 195 | * fixed signed/unsigned comparison warning in btnRead_clicked 196 | 197 | wminput 198 | * fixed signed/unsigned comparison warning in uinput_open and get_plugin 199 | * copied acc low-pass filter to nunchuk_acc 200 | * removed path from default config symlink target 201 | * added plugins parameters (added lex and parse rules, conf functions, 202 | wmplugin_param_info struct, updated README) 203 | * initialized param info in ir_ptr, nunchuk_acc, and acc plugins 204 | * created Scale params in nunchuk_acc and acc plugins 205 | * set Scale params for neverball config 206 | 207 | 2007-04-08 Petter Reinholdtsen 208 | defs.mak 209 | * created WARNFLAGS variable 210 | * added -W to WARNFLAGS 211 | 212 | wiimote 213 | * fixed signed/unsigned comparison warning in int_listen, send_report, and 214 | exec_write_seq 215 | 216 | 2007-04-07 L. Donnie Smith 217 | wiimote 218 | * changed wiimote_info.class to btclass 219 | 220 | 2007-04-03 L. Donnie Smith 221 | configure.ac 222 | * removed --noyywrap from lex 223 | 224 | wiimote 225 | * added queue_flush 226 | * reimplemented queue_queue with queue_flush 227 | * added wiimote_mesg_error message type 228 | * moved RW error state to separate wiimote member 229 | * updated wiimote_read and wiimote_write to trigger and detect rw_error 230 | * cancel rw operations from wiimote_disconnect 231 | * implemented process_error to handle socket read errors 232 | * added rw_status triggers to read and write handlers 233 | 234 | wmdemo 235 | * made wiimote handle global 236 | * disconnect and exit on wiimote_mesg_error 237 | 238 | wmgui 239 | * disconnect on wiimote_mesg_error 240 | 241 | wminput 242 | * exit on wiimote_mesg_error 243 | 244 | 2007-04-03 L. Donnie Smith 245 | wiimote 246 | * fixed wiimote_find_wiimote seg fault 247 | 248 | wmgui 249 | * commented custom wiimote_err (causing Xlib errors) 250 | 251 | wminput 252 | * added stdio.h include to conf.h 253 | 254 | 2007-04-02 L. Donnie Smith 255 | wiimote 256 | * fixed exception handling bugs in bluetooth.c 257 | 258 | wminput 259 | * added wait option 260 | 261 | 2007-04-01 L. Donnie Smith 262 | * Moved defs.mak.in to top level directory 263 | * Added directories to defs.mak.in 264 | * Moved CFLAGS directories from defs.mak to Makefiles 265 | * simplified make install deps 266 | 267 | lswm 268 | * created app 269 | 270 | wmdemo 271 | * renamed main.c to wmdemo.c 272 | * updated for wiimote_connect change 273 | * clarified status output menu item, added status request 274 | 275 | wmgui 276 | * updated for wiimote_connect change 277 | 278 | wminput 279 | * updated for wiimote_connect change 280 | 281 | wiimote 282 | * created bluetooth.c 283 | * moved wiimote_findfirst to bluetooth.c, renamed to wiimote_find_wiimote, 284 | added timeout argument 285 | * defined struct wiimote_info 286 | * wrote wiimote_get_info_array 287 | * wiimote_connect now takes a pointer to bdaddr_t 288 | 289 | 2007-03-27 L. Donnie Smith 290 | * Added DESTDIR variable to make system 291 | 292 | 2007-03-23 L. Donnie Smith 293 | * Corrected installation directory creation logic 294 | * Added .NOTPARALLEL to top level Makefile 295 | 296 | 2007-03-19 L. Donnie Smith 297 | * Added --disable-ldconfig option to configure 298 | * Makefiles - append to rather than set compiler options 299 | 300 | 2007-03-15 L. Donnie Smith 301 | wminput 302 | * action_enum.awk - explicitly call awk rather than #! /usr/bin/awk 303 | 304 | 2007-03-14 L. Donnie Smith 305 | wiimote 306 | * audited error checking (coda and error handler sections) 307 | * updated comments 308 | * event.c - moved int_listen read/write code to process_read and 309 | process_write, reorganized file 310 | * wiimote_read - changed to obey decode flag only for register read 311 | * wiimote_connect - changed memcpy to bacmp 312 | 313 | 2007-03-08 L. Donnie Smith 314 | * added explicit creation of installation directories to prevent 315 | installation errors 316 | 317 | wiimote 318 | * created wiimote_err_t function type 319 | * created wiimote_set_err function 320 | * added wiimote parameter to wiimote_err calls 321 | 322 | wmdemo 323 | * added implementation of wiimote_err_t, wiimote_set_err 324 | 325 | 2007-03-05 L. Donnie Smith 326 | * Type audit - boolean ints, const strings where appropriate, stdint.h 327 | wiimote types 328 | * Changed email addresses to donnie.smith@gatech.edu 329 | * Added file ChangeLogs 330 | * Fixed GTK_{CFLAGS,LIBS} in configure.ac and wmgui/Makefile.in 331 | 332 | 2007-03-01 L. Donnie Smith 333 | * configure.ac - check for stdint.h 334 | 335 | 2007-02-26 L. Donnie Smith 336 | * Changed installation directories to comply with FHS standard 337 | * Added check for yypop_buffer_state in flex 338 | * Various minor documentation changes 339 | * Lowercased "cwiid" in filenames 340 | 341 | wiimote 342 | * added 'static' to local function declarations 343 | 344 | wminput 345 | * added filenames and correct location tracking to parser error messages 346 | * added 'static' to local function declarations (plugins) 347 | 348 | 2007-02-21 Romain Beauxis 349 | wminput 350 | * fixed help message 351 | 352 | 2007-02-18 L. Donnie Smith 353 | wiimote 354 | * fixed wiimote_status_mesg allocation size 355 | * changed wiimote_log to wiimote_err with format string and args 356 | * reworked event/callback system to pass arrays of (simultaneous) messages 357 | * added extern "C" declaration to wiimote.h for c++ programs 358 | * added wiimote_t * to wiimote_mesg_t callback prototype (to facilitate 359 | using the same callback for multiple wiimotes) 360 | 361 | wmdemo 362 | * added 363 | 364 | wmgui 365 | * Added parent argument to message function 366 | 367 | wminput 368 | * rewrite: new configuration syntax, plugin architecture 369 | 370 | 2007-01-25 L. Donnie Smith 371 | wiimote 372 | * added rpt_mode_flag lock to prevent race condition 373 | * extended write sequences to simplify multi-part operations 374 | 375 | wmgui 376 | * added status request at connect to populate status boxes 377 | 378 | 2007-01-24 L. Donnie Smith 379 | Added uninstall make target 380 | 381 | wiimote 382 | * macros renamed (should be last rename of public macros) 383 | * added status, nunchuk, and classic controller messages 384 | * added intelligent report mode selection 385 | 386 | wmgui 387 | * changed button widgets 388 | * added nunchuk and classic controller support 389 | 390 | wminput 391 | * fixed command-line bug 392 | * updated for wiimote updates 393 | * changes to plugin architecture - gives greater access to plugin 394 | * added LED indicators to default (IR) tracking 395 | 396 | 2007-01-16 L. Donnie Smith 397 | wminput 398 | * fixed build error in plugins directory 399 | 400 | 2007-01-15 L. Donnie Smith 401 | reworked build system, now using autoconf 402 | 403 | wiimote 404 | * fixed bug in IR report data extraction 405 | * created acc_ir client message 406 | * make install now installs library and header to /usr/local 407 | 408 | wmif 409 | * removed 410 | 411 | wmgui 412 | * reworked GUI 413 | * added force, roll and pitch displays 414 | * removed AutoMake 415 | * split wiimote_callback into separate functions 416 | * rewrote command-line parsing 417 | * added WIIMOTE_BDADDR environment variable lookup 418 | 419 | wminput 420 | * split wiimote_callback into separate functions 421 | * cleaned up cursor tracking 422 | * renamed wminput.c to main.c 423 | * rewrote command-line parsing 424 | * added WIIMOTE_BDADDR environment variable lookup 425 | * created plugin architecture and acc plugin 426 | 427 | 2007-01-09 L. Donnie Smith 428 | reworked top-level Makefile 429 | bins install to /usr/local/bin on make install 430 | wiimote 431 | * Changes to message dispatch thread to isolate main thread from dispatch 432 | timing issues (especially GTK apps) 433 | 434 | wmif 435 | * fixed --help bug 436 | 437 | wmgui 438 | * fixed --help bug 439 | * added g_thread_support test before g_thread_init 440 | 441 | wminput 442 | * fixed --help bug 443 | * added #ifdef tests around KEY_ macros in key_enum.{c,awk} 444 | 445 | 2007-01-04 L. Donnie Smith 446 | wiimote 447 | * put mesg callback data in a union 448 | * fixed write flood error (wait for ACK after each packet) 449 | * added IR reporting (mode 0x33 only) 450 | * moved internal definitions from wiimote.h into wiimote_internal.h 451 | (struct wiimote is now opaque) 452 | * wiimote_connect now returns a wiimote_t * 453 | * sends button message only when button status changes 454 | 455 | wmif 456 | * updated for wiimote changes 457 | 458 | wmgui 459 | * updated for wiimote changes 460 | * enabled IR widgets 461 | 462 | wminput 463 | * added to package 464 | 465 | 2006-12-31 L. Donnie Smith 466 | wiimote 467 | * changed various macro names and parameter types (mostly signed to unsigned) 468 | * cleaned up LED & RUMBLE command logic 469 | * added ACC reporting 470 | * added data read/write 471 | * created dispatch thread (isolates bluetooth read from app callbacks) 472 | * reset report mode after receive status report 473 | 474 | wmif 475 | * updated for wiimote changes 476 | * added EEPROM read menu option 477 | 478 | wmgui 479 | * updated for wiimote changes 480 | * added ACC output 481 | * added data read/write 482 | * added IR data widgets (not yet enabled) 483 | 484 | 2006-12-28 L. Donnie Smith 485 | Initial release 486 | -------------------------------------------------------------------------------- /Makefile.in: -------------------------------------------------------------------------------- 1 | #Copyright (C) 2007 L. Donnie Smith 2 | 3 | include @top_builddir@/defs.mak 4 | 5 | LIB_DIRS = libcwiid 6 | ifdef PYTHON 7 | BIND_DIRS = python 8 | endif 9 | 10 | SUB_DIRS = $(LIB_DIRS) $(BIND_DIRS) 11 | 12 | all install clean distclean uninstall: TARGET += $(MAKECMDGOALS) 13 | 14 | all install clean distclean uninstall: $(LIB_DIRS) $(BIND_DIRS) 15 | 16 | ifneq ($(MAKECMDGOALS),clean) 17 | ifneq ($(MAKECMDGOALS),distclean) 18 | $(BIND_DIRS): $(LIB_DIRS) 19 | endif 20 | endif 21 | 22 | $(SUB_DIRS): 23 | $(MAKE) $(TARGET) -C $@ 24 | 25 | distclean: 26 | rm -rf Makefile config.log config.status autom4te.cache \ 27 | defs.mak $(COMMON)/include/lib.mak $(COMMON)/include/config.h 28 | 29 | .PHONY: all install clean distclean uninstall uninstall_config $(SUB_DIRS) 30 | 31 | .NOTPARALLEL: 32 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | 0.6.00 2 | - renamed libwiimote to libcwiid to avoid naming conflict with other projects 3 | - rewrite of libcwiid architecture 4 | - Python libcwiid interface 5 | - Python wminput plugins 6 | - rewrite of ir_ptr plugin 7 | 8 | 0.5.03 9 | - Bugfixes, lswm utility, disconnect messages, wminput infinite wait 10 | 11 | 0.5.02 12 | - Bugfixes, configure --disable-ldconfig 13 | 14 | 0.5.01 15 | - Bugfixes 16 | 17 | 0.5.00 18 | - Overhauled wminput configuration 19 | - wmdemo test application 20 | 21 | 0.4.01 22 | - Bugfixes 23 | 24 | 0.4.00 25 | - Status, Nunchuk, Classic Controller support 26 | 27 | 0.3.51 28 | - Bugfixes 29 | 30 | 0.3.50 31 | - Created plugin architecture 32 | - Acc calculations and plugin 33 | 34 | 0.3.01 35 | - Bugfixes 36 | 37 | 0.3.00 38 | - IR Reporting 39 | - wminput Event driver 40 | 41 | 0.2.00 42 | - ACC Reporting 43 | - Memory Read/Write 44 | 45 | 0.1.00 46 | - Initial Release 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CWiid Wiimote Interface 2 | 3 | [![Build Status](https://travis-ci.org/azzra/python3-wiimote.svg?branch=master)](https://travis-ci.org/azzra/python3-wiimote) 4 | 5 | ## DESCRIPTION 6 | 7 | The CWiid package contains the following parts: 8 | 1. libcwiid - wiimote API 9 | 2. cwiid module - python interface to libcwiid 10 | 11 | ## REQUIREMENTS 12 | 13 | awk, bison, flex, bluez-libs, python 3.5 or greater, python dev for python module, kernel sources 14 | 15 | ## INSTALLATION 16 | 17 | First of all, you need to prepare the environment: 18 | 19 | ```sh 20 | aclocal 21 | autoconf 22 | ./configure 23 | make 24 | ``` 25 | 26 | ### Only extension 27 | 28 | Install the library with package manger & the extension from the sources 29 | 30 | ```sh 31 | apt-get install libcwiid1 32 | cd python 33 | sudo make install 34 | ``` 35 | 36 | ### Library & extension 37 | 38 | Use extension & library from sources 39 | 40 | ```sh 41 | sudo make install 42 | ``` 43 | 44 | ## Credits 45 | 46 | Original libcwiid & Python module author: L. Donnie Smith . 47 | You can fin the original source here: https://github.com/abstrakraft/cwiid 48 | 49 | I just made the Python extension working for Python 3. 50 | -------------------------------------------------------------------------------- /common/include/.gitignore: -------------------------------------------------------------------------------- 1 | lib.mak 2 | -------------------------------------------------------------------------------- /common/include/app.mak: -------------------------------------------------------------------------------- 1 | #Copyright (C) 2007 L. Donnie Smith 2 | 3 | OBJECTS = $(SOURCES:.c=.o) 4 | DEPS = $(SOURCES:.c=.d) 5 | 6 | INST_DIR ?= /usr/local/bin 7 | 8 | DEST_INST_DIR = $(ROOTDIR)$(INST_DIR) 9 | 10 | all: $(APP_NAME) 11 | 12 | $(APP_NAME): $(OBJECTS) 13 | $(CC) $(LDFLAGS) -o $@ $(OBJECTS) $(LDLIBS) 14 | 15 | install: $(APP_NAME) 16 | install -D $(APP_NAME) $(DEST_INST_DIR)/$(APP_NAME) 17 | 18 | clean: 19 | rm -f $(APP_NAME) $(OBJECTS) $(DEPS) 20 | 21 | uninstall: 22 | rm -f $(DEST_INST_DIR)/$(APP_NAME) 23 | 24 | ifneq ($(MAKECMDGOALS),clean) 25 | ifneq ($(MAKECMDGOALS),distclean) 26 | include $(COMMON)/include/dep.mak 27 | -include $(DEPS) 28 | endif 29 | endif 30 | 31 | .PHONY: all install uninstall clean 32 | -------------------------------------------------------------------------------- /common/include/config.h.in: -------------------------------------------------------------------------------- 1 | /* common/include/config.h.in. Generated from configure.ac by autoheader. */ 2 | 3 | /* Define to 1 if you have the header file. */ 4 | #undef HAVE_BLUETOOTH_HCI_H 5 | 6 | /* Define to 1 if you have the header file. */ 7 | #undef HAVE_BLUETOOTH_L2CAP_H 8 | 9 | /* Define to 1 if you have the header file. */ 10 | #undef HAVE_INTTYPES_H 11 | 12 | /* Define to 1 if you have the `bluetooth' library (-lbluetooth). */ 13 | #undef HAVE_LIBBLUETOOTH 14 | 15 | /* Define to 1 if you have the `dl' library (-ldl). */ 16 | #undef HAVE_LIBDL 17 | 18 | /* Define to 1 if you have the `pthread' library (-lpthread). */ 19 | #undef HAVE_LIBPTHREAD 20 | 21 | /* Define to 1 if you have the header file. */ 22 | #undef HAVE_MEMORY_H 23 | 24 | /* Define to 1 if python support is enabled */ 25 | #undef HAVE_PYTHON 26 | 27 | /* Define to 1 if you have the header file. */ 28 | #undef HAVE_STDINT_H 29 | 30 | /* Define to 1 if you have the header file. */ 31 | #undef HAVE_STDLIB_H 32 | 33 | /* Define to 1 if you have the header file. */ 34 | #undef HAVE_STRINGS_H 35 | 36 | /* Define to 1 if you have the header file. */ 37 | #undef HAVE_STRING_H 38 | 39 | /* Define to 1 if you have the header file. */ 40 | #undef HAVE_SYS_STAT_H 41 | 42 | /* Define to 1 if you have the header file. */ 43 | #undef HAVE_SYS_TYPES_H 44 | 45 | /* Define to 1 if you have the header file. */ 46 | #undef HAVE_UNISTD_H 47 | 48 | /* Define to the address where bug reports for this package should be sent. */ 49 | #undef PACKAGE_BUGREPORT 50 | 51 | /* Define to the full name of this package. */ 52 | #undef PACKAGE_NAME 53 | 54 | /* Define to the full name and version of this package. */ 55 | #undef PACKAGE_STRING 56 | 57 | /* Define to the one symbol short name of this package. */ 58 | #undef PACKAGE_TARNAME 59 | 60 | /* Define to the version of this package. */ 61 | #undef PACKAGE_VERSION 62 | 63 | /* Define to 1 if you have the ANSI C header files. */ 64 | #undef STDC_HEADERS 65 | 66 | /* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a 67 | `char[]'. */ 68 | #undef YYTEXT_POINTER 69 | -------------------------------------------------------------------------------- /common/include/dep.mak: -------------------------------------------------------------------------------- 1 | %.d: %.c 2 | @$(CC) -M $(CFLAGS) $< > $@.$$$$; \ 3 | sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ 4 | rm -f $@.$$$$ 5 | 6 | -------------------------------------------------------------------------------- /common/include/lib.mak.in: -------------------------------------------------------------------------------- 1 | #Copyright (C) 2007 L. Donnie Smith 2 | 3 | LDCONFIG = @LDCONFIG@ 4 | 5 | HEADER = $(LIB_NAME).h 6 | STATIC_LIB = lib$(LIB_NAME).a 7 | LINK_NAME = lib$(LIB_NAME).so 8 | SO_NAME = $(LINK_NAME).$(MAJOR_VER) 9 | SHARED_LIB = $(SO_NAME).$(MINOR_VER) 10 | DEST_INC_INST_DIR = $(ROOTDIR)$(INC_INST_DIR) 11 | DEST_LIB_INST_DIR = $(ROOTDIR)$(LIB_INST_DIR) 12 | 13 | OBJECTS = $(SOURCES:.c=.o) 14 | DEPS = $(SOURCES:.c=.d) 15 | 16 | CFLAGS += -fpic 17 | 18 | all: static shared 19 | 20 | static: $(STATIC_LIB) 21 | 22 | shared: $(SHARED_LIB) 23 | 24 | $(STATIC_LIB): $(OBJECTS) 25 | ar rcs $(STATIC_LIB) $(OBJECTS) 26 | 27 | $(SHARED_LIB): $(OBJECTS) 28 | $(CC) -shared -Wl,-soname,$(SO_NAME) $(LDFLAGS) -o $(SHARED_LIB) \ 29 | $(OBJECTS) $(LDLIBS) 30 | 31 | install: install_header install_static install_shared 32 | 33 | install_header: 34 | install -D $(LIB_NAME).h $(DEST_INC_INST_DIR)/$(LIB_NAME).h 35 | 36 | install_static: static 37 | install -D $(STATIC_LIB) $(DEST_LIB_INST_DIR)/$(STATIC_LIB) 38 | 39 | install_shared: shared 40 | install -D $(SHARED_LIB) $(DEST_LIB_INST_DIR)/$(SHARED_LIB) 41 | ln -sf $(SHARED_LIB) $(DEST_LIB_INST_DIR)/$(SO_NAME) 42 | ln -sf $(SO_NAME) $(DEST_LIB_INST_DIR)/$(LINK_NAME) 43 | $(LDCONFIG) 44 | 45 | clean: 46 | rm -f $(STATIC_LIB) $(SHARED_LIB) $(OBJECTS) $(DEPS) 47 | 48 | uninstall: 49 | rm -f $(DEST_INC_INST_DIR)/$(LIB_NAME).h \ 50 | $(DEST_LIB_INST_DIR)/$(STATIC_LIB) \ 51 | $(DEST_LIB_INST_DIR)/$(LINK_NAME)* 52 | 53 | ifneq ($(MAKECMDGOALS),clean) 54 | ifneq ($(MAKECMDGOALS),distclean) 55 | include $(COMMON)/include/dep.mak 56 | -include $(DEPS) 57 | endif 58 | endif 59 | 60 | .PHONY: all static shared install install_header install_static install_shared clean uninstall 61 | -------------------------------------------------------------------------------- /common/include/plugin.mak: -------------------------------------------------------------------------------- 1 | #Copyright (C) 2007 L. Donnie Smith 2 | 3 | LIB_NAME = $(PLUGIN_NAME).so 4 | 5 | OBJECTS = $(SOURCES:.c=.o) 6 | DEPS = $(SOURCES:.c=.d) 7 | 8 | CFLAGS += -fpic 9 | 10 | #TODO:unify the way ROOTDIR is handled 11 | #Currently, defs.mak adds ROOTDIR to the plugin INST_DIR, 12 | #so we don't do it here 13 | #DEST_INST_DIR = $(ROOTDIR)/$(INST_DIR) 14 | DEST_INST_DIR = $(INST_DIR) 15 | 16 | all: $(LIB_NAME) 17 | 18 | $(LIB_NAME): $(OBJECTS) 19 | $(CC) -shared $(LDFLAGS) -o $(LIB_NAME) $(OBJECTS) $(LDLIBS) 20 | 21 | install: $(LIB_NAME) 22 | install -D $(LIB_NAME) $(DEST_INST_DIR)/$(LIB_NAME) 23 | 24 | clean: 25 | rm -f $(LIB_NAME) $(OBJECTS) $(DEPS) 26 | 27 | uninstall: 28 | rm -f $(INST_DIR)/$(LIB_NAME) 29 | 30 | ifneq ($(MAKECMDGOALS),clean) 31 | ifneq ($(MAKECMDGOALS),distclean) 32 | include $(COMMON)/include/dep.mak 33 | -include $(DEPS) 34 | endif 35 | endif 36 | 37 | .PHONY: all install clean uninstall 38 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT(CWiid,3.0.0,https://github.com/azzra/python3-wiimote/issues) 2 | AC_CONFIG_HEADER(common/include/config.h) 3 | 4 | AC_PROG_CC 5 | AC_PROG_AWK 6 | AC_PROG_LEX 7 | if test "$LEX" != "flex"; then 8 | AC_MSG_ERROR([flex not found]) 9 | fi 10 | if test -z "`echo %%|$LEX -t|grep yypop_buffer_state`"; then 11 | AC_MSG_ERROR([flex missing yypop_buffer_state - upgrade to version 2.5.33 or later]) 12 | fi 13 | AC_PROG_YACC 14 | if test "$YACC" != "bison -y"; then 15 | AC_MSG_ERROR([bison not found]) 16 | fi 17 | 18 | AC_ARG_WITH( 19 | [python], 20 | [AS_HELP_STRING([--without-python],[compile without python support])], 21 | [case $withval in 22 | yes) 23 | REQUIRE_PYTHON=1 24 | PYTHON_NAME=python3 25 | ;; 26 | no) 27 | REQUIRE_PYTHON= 28 | PYTHON_NAME= 29 | ;; 30 | *) 31 | REQUIRE_PYTHON=1 32 | PYTHON_NAME=$withval 33 | ;; 34 | esac], 35 | [REQUIRE_PYTHON=1; PYTHON_NAME=python3]) 36 | if test $REQUIRE_PYTHON; then 37 | AC_CHECK_PROGS([PYTHON],$PYTHON_NAME) 38 | if test $REQUIRE_PYTHON -a ! $PYTHON; then 39 | AC_MSG_ERROR([$PYTHON_NAME not found]) 40 | fi 41 | fi 42 | AC_SUBST(PYTHON) 43 | if test $PYTHON; then 44 | PYTHON_VERSION=[`$PYTHON -c 'import sys; print(sys.version[:3])'`] 45 | AC_SUBST(PYTHON_VERSION) 46 | AC_DEFINE([HAVE_PYTHON],1,[Define to 1 if python support is enabled]) 47 | fi 48 | 49 | AC_CHECK_LIB([pthread], [pthread_create],, 50 | AC_MSG_ERROR([pthread library not found])) 51 | AC_CHECK_LIB([bluetooth], [hci_devid],, 52 | AC_MSG_ERROR([bluetooth library not found])) 53 | AC_CHECK_LIB([dl], [dlopen],, 54 | AC_MSG_ERROR([dl lib not found])) 55 | #AC_CHECK_LIB([rt], [clock_gettime],, 56 | # AC_MSG_ERROR([rt lib not found])) 57 | 58 | AC_HEADER_STDC 59 | AC_CHECK_HEADER([stdint.h],, 60 | AC_MSG_ERROR([stdint.h not found])) 61 | AC_CHECK_HEADER([bluetooth/bluetooth.h],, 62 | AC_MSG_ERROR([bluetooth/bluetooth.h not found])) 63 | AC_CHECK_HEADERS([bluetooth/l2cap.h bluetooth/hci.h],, 64 | AC_MSG_ERROR([bluetooth headers not found]), 65 | [#include ]) 66 | AC_CHECK_HEADER([linux/input.h],, 67 | AC_MSG_ERROR([linux/input.h not found])) 68 | AC_CHECK_HEADER([linux/uinput.h],, 69 | AC_MSG_ERROR([linux/uinput.h]), 70 | [#include ]) 71 | 72 | AC_ISC_POSIX 73 | 74 | AC_ARG_WITH(ldconfig,AC_HELP_STRING([--disable-ldconfig], 75 | [don't execute ldconfig after install])) 76 | if test "$enable_ldconfig" = "no"; then 77 | LDCONFIG="#ldconfig" 78 | else 79 | LDCONFIG="ldconfig" 80 | fi 81 | AC_SUBST(LDCONFIG) 82 | 83 | AC_OUTPUT( 84 | [Makefile] 85 | [defs.mak] 86 | [common/include/lib.mak] 87 | [libcwiid/Makefile] 88 | [libcwiid/cwiid.pc] 89 | [python/Makefile] 90 | ) 91 | 92 | -------------------------------------------------------------------------------- /defs.mak.in: -------------------------------------------------------------------------------- 1 | #Copyright (C) 2007 L. Donnie Smith 2 | 3 | PACKAGE_NAME = @PACKAGE_NAME@ 4 | PACKAGE_TARNAME = @PACKAGE_TARNAME@ 5 | PACKAGE_VERSION = @PACKAGE_VERSION@ 6 | PACKAGE_STRING = @PACKAGE_STRING@ 7 | PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ 8 | 9 | prefix = @prefix@ 10 | exec_prefix = @exec_prefix@ 11 | 12 | sysconfdir = @sysconfdir@ 13 | libdir = @libdir@ 14 | 15 | datarootdir = @datarootdir@ 16 | mandir = @mandir@ 17 | docdir = @docdir@ 18 | 19 | CC = @CC@ 20 | AWK = @AWK@ 21 | LEX = @LEX@ 22 | YACC = @YACC@ 23 | PYTHON = @PYTHON@ 24 | 25 | COMMON = @abs_top_builddir@/common 26 | 27 | ifdef DESTDIR 28 | ROOTDIR = $(DESTDIR:%/=%) 29 | endif 30 | 31 | DEBUGFLAGS = -g 32 | WARNFLAGS = -Wall -W 33 | CFLAGS = $(DEBUGFLAGS) $(WARNFLAGS) @DEFS@ -I$(COMMON)/include 34 | -------------------------------------------------------------------------------- /libcwiid/Makefile.in: -------------------------------------------------------------------------------- 1 | #Copyright (C) 2006 L. Donnie Smith 2 | 3 | include @top_builddir@/defs.mak 4 | 5 | LIB_NAME = cwiid 6 | MAJOR_VER = 1 7 | MINOR_VER = 0 8 | SOURCES = bluetooth.c command.c connect.c interface.c process.c state.c \ 9 | thread.c util.c 10 | LDLIBS += -lbluetooth -lpthread -lrt 11 | LIB_INST_DIR = @libdir@ 12 | INC_INST_DIR = @includedir@ 13 | DEST_PKG_CONFIG_INST_DIR = $(ROOTDIR)@libdir@/pkgconfig 14 | 15 | include $(COMMON)/include/lib.mak 16 | 17 | $(SHARED_LIB): $(SO_NAME) $(LINK_NAME) 18 | 19 | $(SO_NAME): 20 | ln -sf $(SHARED_LIB) $(SO_NAME) 21 | 22 | $(LINK_NAME): 23 | ln -sf $(SO_NAME) $(LINK_NAME) 24 | 25 | install: install_pkgconfig 26 | 27 | uninstall: uninstall_pkgconfig 28 | 29 | install_pkgconfig: 30 | install -D -m 644 cwiid.pc $(DEST_PKG_CONFIG_INST_DIR)/cwiid.pc 31 | 32 | uninstall_pkgconfig: 33 | rm -f $(DEST_PKG_CONFIG_INST_DIR)/cwiid.pc 34 | 35 | clean: remove_links 36 | 37 | remove_links: 38 | rm -f $(SO_NAME) $(LINK_NAME) 39 | 40 | distclean: clean 41 | rm Makefile cwiid.pc 42 | 43 | .PHONY: distclean clean make_links remove_links 44 | -------------------------------------------------------------------------------- /libcwiid/bluetooth.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2007 L. Donnie Smith 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; either version 2 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 16 | * 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include "cwiid_internal.h" 25 | 26 | /* When filtering wiimotes, in order to avoid having to store the 27 | * remote names before the blue_dev array is malloced (because we don't 28 | * yet know how many wiimotes there are, we'll assume there are no more 29 | * than dev_count, and realloc to the actual number afterwards, since 30 | * reallocing to a smaller chunk should be fast. */ 31 | #define BT_MAX_INQUIRY 256 32 | /* timeout in 2 second units */ 33 | int cwiid_get_bdinfo_array(int dev_id, unsigned int timeout, int max_bdinfo, 34 | struct cwiid_bdinfo **bdinfo, uint8_t flags) 35 | { 36 | inquiry_info *dev_list = NULL; 37 | int max_inquiry; 38 | int dev_count; 39 | int sock = -1; 40 | int bdinfo_count; 41 | int i, j; 42 | int err = 0; 43 | int ret; 44 | 45 | /* NULLify for the benefit of error handling */ 46 | *bdinfo = NULL; 47 | 48 | /* If not given (=-1), get the first available Bluetooth interface */ 49 | if (dev_id == -1) { 50 | if ((dev_id = hci_get_route(NULL)) == -1) { 51 | cwiid_err(NULL, "No Bluetooth interface found"); 52 | return -1; 53 | } 54 | } 55 | 56 | /* Get Bluetooth Device List */ 57 | if ((flags & BT_NO_WIIMOTE_FILTER) && (max_bdinfo != -1)) { 58 | max_inquiry = max_bdinfo; 59 | } 60 | else { 61 | max_inquiry = BT_MAX_INQUIRY; 62 | } 63 | if ((dev_count = hci_inquiry(dev_id, timeout, max_inquiry, NULL, 64 | &dev_list, IREQ_CACHE_FLUSH)) == -1) { 65 | cwiid_err(NULL, "Bluetooth device inquiry error"); 66 | err = 1; 67 | goto CODA; 68 | } 69 | 70 | if (dev_count == 0) { 71 | bdinfo_count = 0; 72 | goto CODA; 73 | } 74 | 75 | /* Open connection to Bluetooth Interface */ 76 | if ((sock = hci_open_dev(dev_id)) == -1) { 77 | cwiid_err(NULL, "Bluetooth interface open error"); 78 | err = 1; 79 | goto CODA; 80 | } 81 | 82 | /* Allocate info list */ 83 | if (max_bdinfo == -1) { 84 | max_bdinfo = dev_count; 85 | } 86 | if ((*bdinfo = malloc(max_bdinfo * sizeof **bdinfo)) == NULL) { 87 | cwiid_err(NULL, "Memory allocation error (bdinfo array)"); 88 | err = 1; 89 | goto CODA; 90 | } 91 | 92 | /* Copy dev_list to bdinfo */ 93 | for (bdinfo_count=i=0; (i < dev_count) && (bdinfo_count < max_bdinfo); 94 | i++) { 95 | /* Filter by class */ 96 | if (!(flags & BT_NO_WIIMOTE_FILTER) && 97 | ((dev_list[i].dev_class[0] != WIIMOTE_CLASS_0) || 98 | (dev_list[i].dev_class[1] != WIIMOTE_CLASS_1) || 99 | (dev_list[i].dev_class[2] != WIIMOTE_CLASS_2))) { 100 | continue; 101 | } 102 | 103 | /* timeout (10000) in milliseconds */ 104 | if (hci_read_remote_name(sock, &dev_list[i].bdaddr, BT_NAME_LEN, 105 | (*bdinfo)[bdinfo_count].name, 10000)) { 106 | cwiid_err(NULL, "Bluetooth name read error"); 107 | err = 1; 108 | goto CODA; 109 | } 110 | 111 | /* Filter by name */ 112 | if (!(flags & BT_NO_WIIMOTE_FILTER) && 113 | strncmp((*bdinfo)[bdinfo_count].name, WIIMOTE_NAME, BT_NAME_LEN) && 114 | strncmp((*bdinfo)[bdinfo_count].name, WIIBALANCE_NAME, BT_NAME_LEN)) { 115 | continue; 116 | } 117 | 118 | /* Passed filter, add to bdinfo */ 119 | bacpy(&(*bdinfo)[bdinfo_count].bdaddr, &dev_list[i].bdaddr); 120 | for (j=0; j<3; j++) { 121 | (*bdinfo)[bdinfo_count].btclass[j] = 122 | dev_list[i].dev_class[j]; 123 | } 124 | bdinfo_count++; 125 | } 126 | 127 | if (bdinfo_count == 0) { 128 | free(*bdinfo); 129 | } 130 | else if (bdinfo_count < max_bdinfo) { 131 | if ((*bdinfo = realloc(*bdinfo, bdinfo_count * sizeof **bdinfo)) 132 | == NULL) { 133 | cwiid_err(NULL, "Memory reallocation error (bdinfo array)"); 134 | err = 1; 135 | goto CODA; 136 | } 137 | } 138 | 139 | CODA: 140 | if (dev_list) free(dev_list); 141 | if (sock != -1) hci_close_dev(sock); 142 | if (err) { 143 | if (*bdinfo) free(*bdinfo); 144 | ret = -1; 145 | } 146 | else { 147 | ret = bdinfo_count; 148 | } 149 | return ret; 150 | } 151 | 152 | int cwiid_find_wiimote(bdaddr_t *bdaddr, int timeout) 153 | { 154 | struct cwiid_bdinfo *bdinfo; 155 | int bdinfo_count; 156 | 157 | if (timeout == -1) { 158 | while ((bdinfo_count = cwiid_get_bdinfo_array(-1, 2, 1, &bdinfo, 0)) 159 | == 0); 160 | if (bdinfo_count == -1) { 161 | return -1; 162 | } 163 | } 164 | else { 165 | bdinfo_count = cwiid_get_bdinfo_array(-1, timeout, 1, &bdinfo, 0); 166 | if (bdinfo_count == -1) { 167 | return -1; 168 | } 169 | else if (bdinfo_count == 0) { 170 | cwiid_err(NULL, "No wiimotes found"); 171 | return -1; 172 | } 173 | } 174 | 175 | bacpy(bdaddr, &bdinfo[0].bdaddr); 176 | free(bdinfo); 177 | return 0; 178 | } 179 | -------------------------------------------------------------------------------- /libcwiid/command.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2007 L. Donnie Smith 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; either version 2 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 16 | * 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include "cwiid_internal.h" 25 | 26 | int cwiid_command(cwiid_wiimote_t *wiimote, enum cwiid_command command, 27 | int flags) { 28 | int ret; 29 | 30 | switch (command) { 31 | case CWIID_CMD_STATUS: 32 | ret = cwiid_request_status(wiimote); 33 | break; 34 | case CWIID_CMD_LED: 35 | ret = cwiid_set_led(wiimote, flags); 36 | break; 37 | case CWIID_CMD_RUMBLE: 38 | ret = cwiid_set_rumble(wiimote, flags); 39 | break; 40 | case CWIID_CMD_RPT_MODE: 41 | ret = cwiid_set_rpt_mode(wiimote, flags); 42 | break; 43 | default: 44 | ret = -1; 45 | break; 46 | } 47 | 48 | return ret; 49 | } 50 | 51 | /* TODO: fix error reporting - this is public now and 52 | * should report its own errors */ 53 | int cwiid_send_rpt(cwiid_wiimote_t *wiimote, uint8_t flags, uint8_t report, 54 | size_t len, const void *data) 55 | { 56 | unsigned char *buf; 57 | 58 | if ((buf = malloc((len*2) * sizeof *buf)) == NULL) { 59 | cwiid_err(wiimote, "Memory allocation error (mesg array)"); 60 | return -1; 61 | } 62 | 63 | buf[0] = BT_TRANS_SET_REPORT | BT_PARAM_OUTPUT; 64 | buf[1] = report; 65 | memcpy(buf+2, data, len); 66 | if (!(flags & CWIID_SEND_RPT_NO_RUMBLE)) { 67 | buf[2] |= wiimote->state.rumble; 68 | } 69 | 70 | if (write(wiimote->ctl_socket, buf, len+2) != (ssize_t)(len+2)) { 71 | free(buf); 72 | return -1; 73 | } 74 | else if (verify_handshake(wiimote)) { 75 | free(buf); 76 | return -1; 77 | } 78 | 79 | return 0; 80 | } 81 | 82 | int cwiid_request_status(cwiid_wiimote_t *wiimote) 83 | { 84 | unsigned char data; 85 | 86 | data = 0; 87 | if (cwiid_send_rpt(wiimote, 0, RPT_STATUS_REQ, 1, &data)) { 88 | cwiid_err(wiimote, "Status request error"); 89 | return -1; 90 | } 91 | 92 | return 0; 93 | } 94 | 95 | int cwiid_set_led(cwiid_wiimote_t *wiimote, uint8_t led) 96 | { 97 | unsigned char data; 98 | 99 | /* TODO: assumption: char assignments are atomic, no mutex lock needed */ 100 | wiimote->state.led = led & 0x0F; 101 | data = wiimote->state.led << 4; 102 | if (cwiid_send_rpt(wiimote, 0, RPT_LED_RUMBLE, 1, &data)) { 103 | cwiid_err(wiimote, "Report send error (led)"); 104 | return -1; 105 | } 106 | 107 | return 0; 108 | } 109 | 110 | int cwiid_set_rumble(cwiid_wiimote_t *wiimote, uint8_t rumble) 111 | { 112 | unsigned char data; 113 | 114 | /* TODO: assumption: char assignments are atomic, no mutex lock needed */ 115 | wiimote->state.rumble = rumble ? 1 : 0; 116 | data = wiimote->state.led << 4; 117 | if (cwiid_send_rpt(wiimote, 0, RPT_LED_RUMBLE, 1, &data)) { 118 | cwiid_err(wiimote, "Report send error (led)"); 119 | return -1; 120 | } 121 | 122 | return 0; 123 | } 124 | 125 | int cwiid_set_rpt_mode(cwiid_wiimote_t *wiimote, uint8_t rpt_mode) 126 | { 127 | return update_rpt_mode(wiimote, rpt_mode); 128 | } 129 | 130 | #define RPT_READ_REQ_LEN 6 131 | int cwiid_read(cwiid_wiimote_t *wiimote, uint8_t flags, uint32_t offset, 132 | uint16_t len, void *data) 133 | { 134 | unsigned char buf[RPT_READ_REQ_LEN]; 135 | struct rw_mesg mesg; 136 | unsigned char *cursor; 137 | int ret = 0; 138 | 139 | /* Compose read request packet */ 140 | buf[0]=flags & (CWIID_RW_EEPROM | CWIID_RW_REG); 141 | buf[1]=(unsigned char)((offset>>16) & 0xFF); 142 | buf[2]=(unsigned char)((offset>>8) & 0xFF); 143 | buf[3]=(unsigned char)(offset & 0xFF); 144 | buf[4]=(unsigned char)((len>>8) & 0xFF); 145 | buf[5]=(unsigned char)(len & 0xFF); 146 | 147 | /* Lock wiimote rw access */ 148 | if (pthread_mutex_lock(&wiimote->rw_mutex)) { 149 | cwiid_err(wiimote, "Mutex lock error (rw_mutex)"); 150 | return -1; 151 | } 152 | 153 | /* Setup read info */ 154 | wiimote->rw_status = RW_READ; 155 | 156 | /* TODO: Document: user is responsible for ensuring that read/write 157 | * operations are not in flight while disconnecting. Nothing serious, 158 | * just accesses to freed memory */ 159 | /* Send read request packet */ 160 | if (cwiid_send_rpt(wiimote, 0, RPT_READ_REQ, RPT_READ_REQ_LEN, buf)) { 161 | cwiid_err(wiimote, "Report send error (read)"); 162 | ret = -1; 163 | goto CODA; 164 | } 165 | 166 | /* TODO:Better sanity checks (offset) */ 167 | /* Read packets */ 168 | for (cursor = data; cursor - (unsigned char *)data < len; 169 | cursor += mesg.len) { 170 | if (full_read(wiimote->rw_pipe[0], &mesg, sizeof mesg)) { 171 | cwiid_err(wiimote, "Pipe read error (rw pipe)"); 172 | ret = -1; 173 | goto CODA; 174 | } 175 | 176 | if (mesg.type == RW_CANCEL) { 177 | ret = -1; 178 | goto CODA; 179 | } 180 | else if (mesg.type != RW_READ) { 181 | cwiid_err(wiimote, "Unexpected write message"); 182 | ret = -1; 183 | goto CODA; 184 | } 185 | 186 | if (mesg.error) { 187 | cwiid_err(wiimote, "Wiimote read error"); 188 | ret = -1; 189 | goto CODA; 190 | } 191 | 192 | memcpy(cursor, &mesg.data, mesg.len); 193 | } 194 | 195 | CODA: 196 | /* Clear rw_status */ 197 | wiimote->rw_status = RW_IDLE; 198 | 199 | /* Unlock rw_mutex */ 200 | if (pthread_mutex_unlock(&wiimote->rw_mutex)) { 201 | cwiid_err(wiimote, "Mutex unlock error (rw_mutex) - deadlock warning"); 202 | } 203 | 204 | return ret; 205 | } 206 | 207 | #define RPT_WRITE_LEN 21 208 | int cwiid_write(cwiid_wiimote_t *wiimote, uint8_t flags, uint32_t offset, 209 | uint16_t len, const void *data) 210 | { 211 | unsigned char buf[RPT_WRITE_LEN]; 212 | uint16_t sent=0; 213 | struct rw_mesg mesg; 214 | int ret = 0; 215 | 216 | /* Compose write packet header */ 217 | buf[0]=flags; 218 | 219 | /* Lock wiimote rw access */ 220 | if (pthread_mutex_lock(&wiimote->rw_mutex)) { 221 | cwiid_err(wiimote, "Mutex lock error (rw mutex)"); 222 | return -1; 223 | } 224 | 225 | /* Send packets */ 226 | wiimote->rw_status = RW_WRITE; 227 | while (sent>16) & 0xFF); 230 | buf[2]=(unsigned char)(((offset+sent)>>8) & 0xFF); 231 | buf[3]=(unsigned char)((offset+sent) & 0xFF); 232 | if (len-sent >= 0x10) { 233 | buf[4]=(unsigned char)0x10; 234 | } 235 | else { 236 | buf[4]=(unsigned char)(len-sent); 237 | } 238 | memcpy(buf+5, data+sent, buf[4]); 239 | 240 | if (cwiid_send_rpt(wiimote, 0, RPT_WRITE, RPT_WRITE_LEN, buf)) { 241 | cwiid_err(wiimote, "Report send error (write)"); 242 | ret = -1; 243 | goto CODA; 244 | } 245 | 246 | /* Read packets from pipe */ 247 | if (read(wiimote->rw_pipe[0], &mesg, sizeof mesg) != sizeof mesg) { 248 | cwiid_err(wiimote, "Pipe read error (rw pipe)"); 249 | ret = -1; 250 | goto CODA; 251 | } 252 | 253 | if (mesg.type == RW_CANCEL) { 254 | ret = -1; 255 | goto CODA; 256 | } 257 | else if (mesg.type != RW_WRITE) { 258 | cwiid_err(wiimote, "Unexpected read message"); 259 | ret = -1; 260 | goto CODA; 261 | } 262 | 263 | if (mesg.error) { 264 | cwiid_err(wiimote, "Wiimote write error"); 265 | ret = -1; 266 | goto CODA; 267 | }; 268 | 269 | sent+=buf[4]; 270 | } 271 | 272 | CODA: 273 | /* Clear rw_status */ 274 | wiimote->rw_status = RW_IDLE; 275 | 276 | /* Unlock rw_mutex */ 277 | if (pthread_mutex_unlock(&wiimote->rw_mutex)) { 278 | cwiid_err(wiimote, "Mutex unlock error (rw_mutex) - deadlock warning"); 279 | } 280 | 281 | return ret; 282 | } 283 | 284 | 285 | struct write_seq speaker_enable_seq[] = { 286 | {WRITE_SEQ_RPT, RPT_SPEAKER_ENABLE, (const void *)"\x04", 1, 0}, 287 | {WRITE_SEQ_RPT, RPT_SPEAKER_MUTE, (const void *)"\x04", 1, 0}, 288 | {WRITE_SEQ_MEM, 0xA20009, (const void *)"\x01", 1, CWIID_RW_REG}, 289 | {WRITE_SEQ_MEM, 0xA20001, (const void *)"\x08", 1, CWIID_RW_REG}, 290 | {WRITE_SEQ_MEM, 0xA20001, (const void *)"\x00\x00\x00\x0C\x40\x00\x00", 291 | 7, CWIID_RW_REG}, 292 | {WRITE_SEQ_MEM, 0xA20008, (const void *)"\x01", 1, CWIID_RW_REG}, 293 | {WRITE_SEQ_RPT, RPT_SPEAKER_MUTE, (const void *)"\x00", 1, 0} 294 | }; 295 | 296 | struct write_seq speaker_disable_seq[] = { 297 | {WRITE_SEQ_RPT, RPT_SPEAKER_MUTE, (const void *)"\x04", 1, 0}, 298 | {WRITE_SEQ_RPT, RPT_SPEAKER_ENABLE, (const void *)"\x00", 1, 0} 299 | }; 300 | 301 | #define SOUND_BUF_LEN 21 302 | int cwiid_beep(cwiid_wiimote_t *wiimote) 303 | { 304 | /* unsigned char buf[SOUND_BUF_LEN] = { 0xA0, 0xCC, 0x33, 0xCC, 0x33, 305 | 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 306 | 0xCC, 0x33, 0xCC, 0x33}; */ 307 | unsigned char buf[SOUND_BUF_LEN] = { 0xA0, 0xC3, 0xC3, 0xC3, 0xC3, 308 | 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 309 | 0xC3, 0xC3, 0xC3, 0xC3}; 310 | int i; 311 | int ret = 0; 312 | pthread_mutex_t timer_mutex = PTHREAD_MUTEX_INITIALIZER; 313 | pthread_cond_t timer_cond = PTHREAD_COND_INITIALIZER; 314 | struct timespec t; 315 | 316 | if (exec_write_seq(wiimote, SEQ_LEN(speaker_enable_seq), 317 | speaker_enable_seq)) { 318 | cwiid_err(wiimote, "Speaker enable error"); 319 | ret = -1; 320 | } 321 | 322 | pthread_mutex_lock(&timer_mutex); 323 | 324 | for (i=0; i<100; i++) { 325 | clock_gettime(CLOCK_REALTIME, &t); 326 | t.tv_nsec += 10204081; 327 | /* t.tv_nsec += 7000000; */ 328 | if (cwiid_send_rpt(wiimote, 0, RPT_SPEAKER_DATA, SOUND_BUF_LEN, buf)) { 329 | printf("%d\n", i); 330 | cwiid_err(wiimote, "Report send error (speaker data)"); 331 | ret = -1; 332 | break; 333 | } 334 | /* TODO: I should be shot for this, but hey, it works. 335 | * longterm - find a better wait */ 336 | pthread_cond_timedwait(&timer_cond, &timer_mutex, &t); 337 | } 338 | 339 | pthread_mutex_unlock(&timer_mutex); 340 | 341 | if (exec_write_seq(wiimote, SEQ_LEN(speaker_disable_seq), 342 | speaker_disable_seq)) { 343 | cwiid_err(wiimote, "Speaker disable error"); 344 | ret = -1; 345 | } 346 | 347 | return ret; 348 | } 349 | -------------------------------------------------------------------------------- /libcwiid/connect.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2007 L. Donnie Smith 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; either version 2 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 16 | * 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "cwiid_internal.h" 29 | 30 | pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER; 31 | static int wiimote_id = 0; 32 | 33 | /* TODO: Turn this onto a macro on next major so version */ 34 | cwiid_wiimote_t *cwiid_open(bdaddr_t *bdaddr, int flags) 35 | { 36 | return cwiid_open_timeout(bdaddr, flags, DEFAULT_TIMEOUT); 37 | } 38 | 39 | cwiid_wiimote_t *cwiid_open_timeout(bdaddr_t *bdaddr, int flags, int timeout) 40 | { 41 | struct sockaddr_l2 remote_addr; 42 | int ctl_socket = -1, int_socket = -1; 43 | struct wiimote *wiimote = NULL; 44 | 45 | /* If BDADDR_ANY is given, find available wiimote */ 46 | if (bacmp(bdaddr, BDADDR_ANY) == 0) { 47 | if (cwiid_find_wiimote(bdaddr, timeout)) { 48 | goto ERR_HND; 49 | } 50 | sleep(1); 51 | } 52 | 53 | /* Connect to Wiimote */ 54 | /* Control Channel */ 55 | memset(&remote_addr, 0, sizeof remote_addr); 56 | remote_addr.l2_family = AF_BLUETOOTH; 57 | remote_addr.l2_bdaddr = *bdaddr; 58 | remote_addr.l2_psm = htobs(CTL_PSM); 59 | if ((ctl_socket = 60 | socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1) { 61 | cwiid_err(NULL, "Socket creation error (control socket)"); 62 | goto ERR_HND; 63 | } 64 | if (connect(ctl_socket, (struct sockaddr *)&remote_addr, 65 | sizeof remote_addr)) { 66 | cwiid_err(NULL, "Socket connect error (control socket)"); 67 | goto ERR_HND; 68 | } 69 | 70 | /* Interrupt Channel */ 71 | remote_addr.l2_psm = htobs(INT_PSM); 72 | if ((int_socket = 73 | socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1) { 74 | cwiid_err(NULL, "Socket creation error (interrupt socket)"); 75 | goto ERR_HND; 76 | } 77 | if (connect(int_socket, (struct sockaddr *)&remote_addr, 78 | sizeof remote_addr)) { 79 | cwiid_err(NULL, "Socket connect error (interrupt socket)"); 80 | goto ERR_HND; 81 | } 82 | 83 | if ((wiimote = cwiid_new(ctl_socket, int_socket, flags)) == NULL) { 84 | /* Raises its own error */ 85 | goto ERR_HND; 86 | } 87 | 88 | return wiimote; 89 | 90 | ERR_HND: 91 | /* Close Sockets */ 92 | if (ctl_socket != -1) { 93 | if (close(ctl_socket)) { 94 | cwiid_err(NULL, "Socket close error (control socket)"); 95 | } 96 | } 97 | if (int_socket != -1) { 98 | if (close(int_socket)) { 99 | cwiid_err(NULL, "Socket close error (interrupt socket)"); 100 | } 101 | } 102 | return NULL; 103 | } 104 | 105 | cwiid_wiimote_t *cwiid_listen(int flags) 106 | { 107 | struct sockaddr_l2 local_addr; 108 | struct sockaddr_l2 remote_addr; 109 | socklen_t socklen; 110 | int ctl_server_socket = -1, int_server_socket = -1, 111 | ctl_socket = -1, int_socket = -1; 112 | struct wiimote *wiimote = NULL; 113 | 114 | /* Connect to Wiimote */ 115 | /* Control Channel */ 116 | memset(&local_addr, 0, sizeof local_addr); 117 | local_addr.l2_family = AF_BLUETOOTH; 118 | local_addr.l2_bdaddr = *BDADDR_ANY; 119 | local_addr.l2_psm = htobs(CTL_PSM); 120 | if ((ctl_server_socket = 121 | socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1) { 122 | cwiid_err(NULL, "Socket creation error (control socket)"); 123 | goto ERR_HND; 124 | } 125 | if (bind(ctl_server_socket, (struct sockaddr *)&local_addr, 126 | sizeof local_addr)) { 127 | cwiid_err(NULL, "Socket bind error (control socket)"); 128 | goto ERR_HND; 129 | } 130 | if (listen(ctl_server_socket, 1)) { 131 | cwiid_err(NULL, "Socket listen error (control socket)"); 132 | goto ERR_HND; 133 | } 134 | 135 | /* Interrupt Channel */ 136 | local_addr.l2_psm = htobs(INT_PSM); 137 | if ((int_server_socket = 138 | socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1) { 139 | cwiid_err(NULL, "Socket creation error (interrupt socket)"); 140 | goto ERR_HND; 141 | } 142 | if (bind(int_server_socket, (struct sockaddr *)&local_addr, 143 | sizeof local_addr)) { 144 | cwiid_err(NULL, "Socket bind error (interrupt socket)"); 145 | goto ERR_HND; 146 | } 147 | if (listen(int_server_socket, 1)) { 148 | cwiid_err(NULL, "Socket listen error (interrupt socket)"); 149 | goto ERR_HND; 150 | } 151 | 152 | /* Block for Connections */ 153 | if ((ctl_socket = accept(ctl_server_socket, (struct sockaddr *)&remote_addr, &socklen)) < 0) { 154 | cwiid_err(NULL, "Socket accept error (control socket)"); 155 | goto ERR_HND; 156 | } 157 | if ((int_socket = accept(int_server_socket, (struct sockaddr *)&remote_addr, &socklen)) < 0) { 158 | cwiid_err(NULL, "Socket accept error (interrupt socket)"); 159 | goto ERR_HND; 160 | } 161 | 162 | /* Close server sockets */ 163 | if (close(ctl_server_socket)) { 164 | cwiid_err(NULL, "Socket close error (control socket)"); 165 | } 166 | if (close(int_server_socket)) { 167 | cwiid_err(NULL, "Socket close error (interrupt socket)"); 168 | } 169 | 170 | if ((wiimote = cwiid_new(ctl_socket, int_socket, flags)) == NULL) { 171 | /* Raises its own error */ 172 | goto ERR_HND; 173 | } 174 | 175 | return wiimote; 176 | 177 | ERR_HND: 178 | /* Close Sockets */ 179 | if (ctl_server_socket != -1) { 180 | if (close(ctl_server_socket)) { 181 | cwiid_err(NULL, "Socket close error (control server socket)"); 182 | } 183 | } 184 | if (int_server_socket != -1) { 185 | if (close(int_server_socket)) { 186 | cwiid_err(NULL, "Socket close error (interrupt server socket)"); 187 | } 188 | } 189 | if (ctl_socket != -1) { 190 | if (close(ctl_socket)) { 191 | cwiid_err(NULL, "Socket close error (control socket)"); 192 | } 193 | } 194 | if (int_socket != -1) { 195 | if (close(int_socket)) { 196 | cwiid_err(NULL, "Socket close error (interrupt socket)"); 197 | } 198 | } 199 | 200 | return NULL; 201 | } 202 | 203 | cwiid_wiimote_t *cwiid_new(int ctl_socket, int int_socket, int flags) 204 | { 205 | struct wiimote *wiimote = NULL; 206 | char mesg_pipe_init = 0, status_pipe_init = 0, rw_pipe_init = 0, 207 | state_mutex_init = 0, rw_mutex_init = 0, rpt_mutex_init = 0, 208 | router_thread_init = 0, status_thread_init = 0; 209 | void *pthread_ret; 210 | 211 | /* Allocate wiimote */ 212 | if ((wiimote = malloc(sizeof *wiimote)) == NULL) { 213 | cwiid_err(NULL, "Memory allocation error (cwiid_wiimote_t)"); 214 | goto ERR_HND; 215 | } 216 | 217 | /* set sockets and flags */ 218 | wiimote->ctl_socket = ctl_socket; 219 | wiimote->int_socket = int_socket; 220 | wiimote->flags = flags; 221 | 222 | /* Global Lock, Store and Increment wiimote_id */ 223 | if (pthread_mutex_lock(&global_mutex)) { 224 | cwiid_err(NULL, "Mutex lock error (global mutex)"); 225 | goto ERR_HND; 226 | } 227 | wiimote->id = wiimote_id++; 228 | if (pthread_mutex_unlock(&global_mutex)) { 229 | cwiid_err(wiimote, "Mutex unlock error (global mutex) - " 230 | "deadlock warning"); 231 | goto ERR_HND; 232 | } 233 | 234 | /* Create pipes */ 235 | if (pipe(wiimote->mesg_pipe)) { 236 | cwiid_err(wiimote, "Pipe creation error (mesg pipe)"); 237 | goto ERR_HND; 238 | } 239 | mesg_pipe_init = 1; 240 | if (pipe(wiimote->status_pipe)) { 241 | cwiid_err(wiimote, "Pipe creation error (status pipe)"); 242 | goto ERR_HND; 243 | } 244 | status_pipe_init = 1; 245 | if (pipe(wiimote->rw_pipe)) { 246 | cwiid_err(wiimote, "Pipe creation error (rw pipe)"); 247 | goto ERR_HND; 248 | } 249 | rw_pipe_init = 1; 250 | 251 | /* Setup blocking */ 252 | if (fcntl(wiimote->mesg_pipe[1], F_SETFL, O_NONBLOCK)) { 253 | cwiid_err(wiimote, "File control error (mesg write pipe)"); 254 | goto ERR_HND; 255 | } 256 | if (wiimote->flags & CWIID_FLAG_NONBLOCK) { 257 | if (fcntl(wiimote->mesg_pipe[0], F_SETFL, O_NONBLOCK)) { 258 | cwiid_err(wiimote, "File control error (mesg read pipe)"); 259 | goto ERR_HND; 260 | } 261 | } 262 | 263 | /* Init mutexes */ 264 | if (pthread_mutex_init(&wiimote->state_mutex, NULL)) { 265 | cwiid_err(wiimote, "Mutex initialization error (state mutex)"); 266 | goto ERR_HND; 267 | } 268 | state_mutex_init = 1; 269 | if (pthread_mutex_init(&wiimote->rw_mutex, NULL)) { 270 | cwiid_err(wiimote, "Mutex initialization error (rw mutex)"); 271 | goto ERR_HND; 272 | } 273 | rw_mutex_init = 1; 274 | if (pthread_mutex_init(&wiimote->rpt_mutex, NULL)) { 275 | cwiid_err(wiimote, "Mutex initialization error (rpt mutex)"); 276 | goto ERR_HND; 277 | } 278 | rpt_mutex_init = 1; 279 | 280 | /* Set rw_status before starting router thread */ 281 | wiimote->rw_status = RW_IDLE; 282 | 283 | /* Launch interrupt socket listener and dispatch threads */ 284 | if (pthread_create(&wiimote->router_thread, NULL, 285 | (void *(*)(void *))&router_thread, wiimote)) { 286 | cwiid_err(wiimote, "Thread creation error (router thread)"); 287 | goto ERR_HND; 288 | } 289 | router_thread_init = 1; 290 | if (pthread_create(&wiimote->status_thread, NULL, 291 | (void *(*)(void *))&status_thread, wiimote)) { 292 | cwiid_err(wiimote, "Thread creation error (status thread)"); 293 | goto ERR_HND; 294 | } 295 | status_thread_init = 1; 296 | 297 | /* Success! Update state */ 298 | memset(&wiimote->state, 0, sizeof wiimote->state); 299 | wiimote->mesg_callback = NULL; 300 | cwiid_set_led(wiimote, 0); 301 | cwiid_request_status(wiimote); 302 | 303 | return wiimote; 304 | 305 | ERR_HND: 306 | if (wiimote) { 307 | /* Close threads */ 308 | if (router_thread_init) { 309 | pthread_cancel(wiimote->router_thread); 310 | if (pthread_join(wiimote->router_thread, &pthread_ret)) { 311 | cwiid_err(wiimote, "Thread join error (router thread)"); 312 | } 313 | else if (!((pthread_ret == PTHREAD_CANCELED) && 314 | (pthread_ret == NULL))) { 315 | cwiid_err(wiimote, "Bad return value from router thread"); 316 | } 317 | } 318 | 319 | if (status_thread_init) { 320 | pthread_cancel(wiimote->status_thread); 321 | if (pthread_join(wiimote->status_thread, &pthread_ret)) { 322 | cwiid_err(wiimote, "Thread join error (status thread)"); 323 | } 324 | else if (!((pthread_ret == PTHREAD_CANCELED) && (pthread_ret == NULL))) { 325 | cwiid_err(wiimote, "Bad return value from status thread"); 326 | } 327 | } 328 | 329 | /* Close Pipes */ 330 | if (mesg_pipe_init) { 331 | if (close(wiimote->mesg_pipe[0]) || close(wiimote->mesg_pipe[1])) { 332 | cwiid_err(wiimote, "Pipe close error (mesg pipe)"); 333 | } 334 | } 335 | if (status_pipe_init) { 336 | if (close(wiimote->status_pipe[0]) || 337 | close(wiimote->status_pipe[1])) { 338 | cwiid_err(wiimote, "Pipe close error (status pipe)"); 339 | } 340 | } 341 | if (rw_pipe_init) { 342 | if (close(wiimote->rw_pipe[0]) || close(wiimote->rw_pipe[1])) { 343 | cwiid_err(wiimote, "Pipe close error (rw pipe)"); 344 | } 345 | } 346 | /* Destroy Mutexes */ 347 | if (state_mutex_init) { 348 | if (pthread_mutex_destroy(&wiimote->state_mutex)) { 349 | cwiid_err(wiimote, "Mutex destroy error (state mutex)"); 350 | } 351 | } 352 | if (rw_mutex_init) { 353 | if (pthread_mutex_destroy(&wiimote->rw_mutex)) { 354 | cwiid_err(wiimote, "Mutex destroy error (rw mutex)"); 355 | } 356 | } 357 | if (rpt_mutex_init) { 358 | if (pthread_mutex_destroy(&wiimote->rpt_mutex)) { 359 | cwiid_err(wiimote, "Mutex destroy error (rpt mutex)"); 360 | } 361 | } 362 | free(wiimote); 363 | } 364 | return NULL; 365 | } 366 | 367 | int cwiid_close(cwiid_wiimote_t *wiimote) 368 | { 369 | void *pthread_ret; 370 | 371 | /* Stop rumbling, otherwise wiimote continues to rumble for 372 | few seconds after closing the connection! There should be no 373 | need to check if stopping fails: we are closing the connection 374 | in any case. */ 375 | if (wiimote->state.rumble) { 376 | cwiid_set_rumble(wiimote, 0); 377 | } 378 | 379 | /* Cancel and join router_thread and status_thread */ 380 | if (pthread_cancel(wiimote->router_thread)) { 381 | /* if thread quit abnormally, would have printed it's own error */ 382 | } 383 | if (pthread_join(wiimote->router_thread, &pthread_ret)) { 384 | cwiid_err(wiimote, "Thread join error (router thread)"); 385 | } 386 | else if (!((pthread_ret == PTHREAD_CANCELED) || (pthread_ret == NULL))) { 387 | cwiid_err(wiimote, "Bad return value from router thread"); 388 | } 389 | 390 | if (pthread_cancel(wiimote->status_thread)) { 391 | /* if thread quit abnormally, would have printed it's own error */ 392 | } 393 | if (pthread_join(wiimote->status_thread, &pthread_ret)) { 394 | cwiid_err(wiimote, "Thread join error (status thread)"); 395 | } 396 | else if (!((pthread_ret == PTHREAD_CANCELED) || (pthread_ret == NULL))) { 397 | cwiid_err(wiimote, "Bad return value from status thread"); 398 | } 399 | 400 | if (wiimote->mesg_callback) { 401 | if (cancel_mesg_callback(wiimote)) { 402 | /* prints it's own errors */ 403 | } 404 | } 405 | 406 | if (cancel_rw(wiimote)) { 407 | /* prints it's own errors */ 408 | } 409 | 410 | /* Close sockets */ 411 | if (close(wiimote->int_socket)) { 412 | cwiid_err(wiimote, "Socket close error (interrupt socket)"); 413 | } 414 | if (close(wiimote->ctl_socket)) { 415 | cwiid_err(wiimote, "Socket close error (control socket)"); 416 | } 417 | /* Close Pipes */ 418 | if (close(wiimote->mesg_pipe[0]) || close(wiimote->mesg_pipe[1])) { 419 | cwiid_err(wiimote, "Pipe close error (mesg pipe)"); 420 | } 421 | if (close(wiimote->status_pipe[0]) || close(wiimote->status_pipe[1])) { 422 | cwiid_err(wiimote, "Pipe close error (status pipe)"); 423 | } 424 | if (close(wiimote->rw_pipe[0]) || close(wiimote->rw_pipe[1])) { 425 | cwiid_err(wiimote, "Pipe close error (rw pipe)"); 426 | } 427 | /* Destroy mutexes */ 428 | if (pthread_mutex_destroy(&wiimote->state_mutex)) { 429 | cwiid_err(wiimote, "Mutex destroy error (state)"); 430 | } 431 | if (pthread_mutex_destroy(&wiimote->rw_mutex)) { 432 | cwiid_err(wiimote, "Mutex destroy error (rw)"); 433 | } 434 | if (pthread_mutex_destroy(&wiimote->rpt_mutex)) { 435 | cwiid_err(wiimote, "Mutex destroy error (rpt)"); 436 | } 437 | 438 | free(wiimote); 439 | 440 | return 0; 441 | } 442 | -------------------------------------------------------------------------------- /libcwiid/cwiid.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2007 L. Donnie Smith 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; either version 2 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 16 | * 17 | */ 18 | 19 | #ifndef CWIID_H 20 | #define CWIID_H 21 | 22 | #include 23 | #include 24 | #include 25 | #include /* bdaddr_t */ 26 | 27 | /* Flags */ 28 | #define CWIID_FLAG_MESG_IFC 0x01 29 | #define CWIID_FLAG_CONTINUOUS 0x02 30 | #define CWIID_FLAG_REPEAT_BTN 0x04 31 | #define CWIID_FLAG_NONBLOCK 0x08 32 | #define CWIID_FLAG_MOTIONPLUS 0x10 33 | 34 | /* Report Mode Flags */ 35 | #define CWIID_RPT_STATUS 0x01 36 | #define CWIID_RPT_BTN 0x02 37 | #define CWIID_RPT_ACC 0x04 38 | #define CWIID_RPT_IR 0x08 39 | #define CWIID_RPT_NUNCHUK 0x10 40 | #define CWIID_RPT_CLASSIC 0x20 41 | #define CWIID_RPT_BALANCE 0x40 42 | #define CWIID_RPT_MOTIONPLUS 0x80 43 | #define CWIID_RPT_EXT (CWIID_RPT_NUNCHUK | CWIID_RPT_CLASSIC | \ 44 | CWIID_RPT_BALANCE | CWIID_RPT_MOTIONPLUS) 45 | 46 | /* LED flags */ 47 | #define CWIID_LED1_ON 0x01 48 | #define CWIID_LED2_ON 0x02 49 | #define CWIID_LED3_ON 0x04 50 | #define CWIID_LED4_ON 0x08 51 | 52 | /* Button flags */ 53 | #define CWIID_BTN_2 0x0001 54 | #define CWIID_BTN_1 0x0002 55 | #define CWIID_BTN_B 0x0004 56 | #define CWIID_BTN_A 0x0008 57 | #define CWIID_BTN_MINUS 0x0010 58 | #define CWIID_BTN_HOME 0x0080 59 | #define CWIID_BTN_LEFT 0x0100 60 | #define CWIID_BTN_RIGHT 0x0200 61 | #define CWIID_BTN_DOWN 0x0400 62 | #define CWIID_BTN_UP 0x0800 63 | #define CWIID_BTN_PLUS 0x1000 64 | 65 | #define CWIID_NUNCHUK_BTN_Z 0x01 66 | #define CWIID_NUNCHUK_BTN_C 0x02 67 | 68 | #define CWIID_CLASSIC_BTN_UP 0x0001 69 | #define CWIID_CLASSIC_BTN_LEFT 0x0002 70 | #define CWIID_CLASSIC_BTN_ZR 0x0004 71 | #define CWIID_CLASSIC_BTN_X 0x0008 72 | #define CWIID_CLASSIC_BTN_A 0x0010 73 | #define CWIID_CLASSIC_BTN_Y 0x0020 74 | #define CWIID_CLASSIC_BTN_B 0x0040 75 | #define CWIID_CLASSIC_BTN_ZL 0x0080 76 | #define CWIID_CLASSIC_BTN_R 0x0200 77 | #define CWIID_CLASSIC_BTN_PLUS 0x0400 78 | #define CWIID_CLASSIC_BTN_HOME 0x0800 79 | #define CWIID_CLASSIC_BTN_MINUS 0x1000 80 | #define CWIID_CLASSIC_BTN_L 0x2000 81 | #define CWIID_CLASSIC_BTN_DOWN 0x4000 82 | #define CWIID_CLASSIC_BTN_RIGHT 0x8000 83 | 84 | /* Send Report flags */ 85 | #define CWIID_SEND_RPT_NO_RUMBLE 0x01 86 | 87 | /* Data Read/Write flags */ 88 | #define CWIID_RW_EEPROM 0x00 89 | #define CWIID_RW_REG 0x04 90 | #define CWIID_RW_DECODE 0x00 91 | 92 | /* Maximum Data Read Length */ 93 | #define CWIID_MAX_READ_LEN 0xFFFF 94 | 95 | /* Array Index Defs */ 96 | #define CWIID_X 0 97 | #define CWIID_Y 1 98 | #define CWIID_Z 2 99 | #define CWIID_PHI 0 100 | #define CWIID_THETA 1 101 | #define CWIID_PSI 2 102 | 103 | /* Acc Defs */ 104 | #define CWIID_ACC_MAX 0xFF 105 | 106 | /* IR Defs */ 107 | #define CWIID_IR_SRC_COUNT 4 108 | #define CWIID_IR_X_MAX 1024 109 | #define CWIID_IR_Y_MAX 768 110 | 111 | /* Battery */ 112 | #define CWIID_BATTERY_MAX 0xD0 113 | 114 | /* Classic Controller Maxes */ 115 | #define CWIID_CLASSIC_L_STICK_MAX 0x3F 116 | #define CWIID_CLASSIC_R_STICK_MAX 0x1F 117 | #define CWIID_CLASSIC_LR_MAX 0x1F 118 | 119 | /* Environment Variables */ 120 | #define WIIMOTE_BDADDR "WIIMOTE_BDADDR" 121 | 122 | /* Callback Maximum Message Count */ 123 | #define CWIID_MAX_MESG_COUNT 5 124 | 125 | /* Enumerations */ 126 | enum cwiid_command { 127 | CWIID_CMD_STATUS, 128 | CWIID_CMD_LED, 129 | CWIID_CMD_RUMBLE, 130 | CWIID_CMD_RPT_MODE 131 | }; 132 | 133 | enum cwiid_mesg_type { 134 | CWIID_MESG_STATUS, 135 | CWIID_MESG_BTN, 136 | CWIID_MESG_ACC, 137 | CWIID_MESG_IR, 138 | CWIID_MESG_NUNCHUK, 139 | CWIID_MESG_CLASSIC, 140 | CWIID_MESG_BALANCE, 141 | CWIID_MESG_MOTIONPLUS, 142 | CWIID_MESG_ERROR, 143 | CWIID_MESG_UNKNOWN 144 | }; 145 | 146 | enum cwiid_ext_type { 147 | CWIID_EXT_NONE, 148 | CWIID_EXT_NUNCHUK, 149 | CWIID_EXT_CLASSIC, 150 | CWIID_EXT_BALANCE, 151 | CWIID_EXT_MOTIONPLUS, 152 | CWIID_EXT_UNKNOWN 153 | }; 154 | 155 | enum cwiid_error { 156 | CWIID_ERROR_NONE, 157 | CWIID_ERROR_DISCONNECT, 158 | CWIID_ERROR_COMM 159 | }; 160 | 161 | struct acc_cal { 162 | uint8_t zero[3]; 163 | uint8_t one[3]; 164 | }; 165 | 166 | struct balance_cal { 167 | uint16_t right_top[3]; 168 | uint16_t right_bottom[3]; 169 | uint16_t left_top[3]; 170 | uint16_t left_bottom[3]; 171 | }; 172 | 173 | /* Message Structs */ 174 | struct cwiid_status_mesg { 175 | enum cwiid_mesg_type type; 176 | uint8_t battery; 177 | enum cwiid_ext_type ext_type; 178 | }; 179 | 180 | struct cwiid_btn_mesg { 181 | enum cwiid_mesg_type type; 182 | uint16_t buttons; 183 | }; 184 | 185 | struct cwiid_acc_mesg { 186 | enum cwiid_mesg_type type; 187 | uint8_t acc[3]; 188 | }; 189 | 190 | struct cwiid_ir_src { 191 | char valid; 192 | uint16_t pos[2]; 193 | int8_t size; 194 | }; 195 | 196 | struct cwiid_ir_mesg { 197 | enum cwiid_mesg_type type; 198 | struct cwiid_ir_src src[CWIID_IR_SRC_COUNT]; 199 | }; 200 | 201 | struct cwiid_nunchuk_mesg { 202 | enum cwiid_mesg_type type; 203 | uint8_t stick[2]; 204 | uint8_t acc[3]; 205 | uint8_t buttons; 206 | }; 207 | 208 | struct cwiid_classic_mesg { 209 | enum cwiid_mesg_type type; 210 | uint8_t l_stick[2]; 211 | uint8_t r_stick[2]; 212 | uint8_t l; 213 | uint8_t r; 214 | uint16_t buttons; 215 | }; 216 | 217 | struct cwiid_balance_mesg { 218 | enum cwiid_mesg_type type; 219 | uint16_t right_top; 220 | uint16_t right_bottom; 221 | uint16_t left_top; 222 | uint16_t left_bottom; 223 | }; 224 | 225 | struct cwiid_motionplus_mesg { 226 | enum cwiid_mesg_type type; 227 | uint16_t angle_rate[3]; 228 | uint8_t low_speed[3]; 229 | }; 230 | 231 | struct cwiid_error_mesg { 232 | enum cwiid_mesg_type type; 233 | enum cwiid_error error; 234 | }; 235 | 236 | union cwiid_mesg { 237 | enum cwiid_mesg_type type; 238 | struct cwiid_status_mesg status_mesg; 239 | struct cwiid_btn_mesg btn_mesg; 240 | struct cwiid_acc_mesg acc_mesg; 241 | struct cwiid_ir_mesg ir_mesg; 242 | struct cwiid_nunchuk_mesg nunchuk_mesg; 243 | struct cwiid_classic_mesg classic_mesg; 244 | struct cwiid_balance_mesg balance_mesg; 245 | struct cwiid_motionplus_mesg motionplus_mesg; 246 | struct cwiid_error_mesg error_mesg; 247 | }; 248 | 249 | /* State Structs */ 250 | struct nunchuk_state { 251 | uint8_t stick[2]; 252 | uint8_t acc[3]; 253 | uint8_t buttons; 254 | }; 255 | 256 | struct classic_state { 257 | uint8_t l_stick[2]; 258 | uint8_t r_stick[2]; 259 | uint8_t l; 260 | uint8_t r; 261 | uint16_t buttons; 262 | }; 263 | 264 | struct balance_state { 265 | uint16_t right_top; 266 | uint16_t right_bottom; 267 | uint16_t left_top; 268 | uint16_t left_bottom; 269 | }; 270 | 271 | struct motionplus_state { 272 | uint16_t angle_rate[3]; 273 | uint8_t low_speed[3]; 274 | }; 275 | 276 | union ext_state { 277 | struct nunchuk_state nunchuk; 278 | struct classic_state classic; 279 | struct balance_state balance; 280 | struct motionplus_state motionplus; 281 | }; 282 | 283 | struct cwiid_state { 284 | uint8_t rpt_mode; 285 | uint8_t led; 286 | uint8_t rumble; 287 | uint8_t battery; 288 | uint16_t buttons; 289 | uint8_t acc[3]; 290 | struct cwiid_ir_src ir_src[CWIID_IR_SRC_COUNT]; 291 | enum cwiid_ext_type ext_type; 292 | union ext_state ext; 293 | enum cwiid_error error; 294 | }; 295 | 296 | /* Typedefs */ 297 | typedef struct wiimote cwiid_wiimote_t; 298 | 299 | typedef void cwiid_mesg_callback_t(cwiid_wiimote_t *, int, 300 | union cwiid_mesg [], struct timespec *); 301 | typedef void cwiid_err_t(cwiid_wiimote_t *, const char *, va_list ap); 302 | 303 | /* get_bdinfo */ 304 | #define BT_NO_WIIMOTE_FILTER 0x01 305 | #define BT_NAME_LEN 32 306 | 307 | struct cwiid_bdinfo { 308 | bdaddr_t bdaddr; 309 | uint8_t btclass[3]; 310 | char name[BT_NAME_LEN]; 311 | }; 312 | 313 | #ifdef __cplusplus 314 | extern "C" { 315 | #endif 316 | 317 | /* Error reporting (library wide) */ 318 | int cwiid_set_err(cwiid_err_t *err); 319 | void cwiid_err_default(struct wiimote *wiimote, const char *str, va_list ap); 320 | 321 | /* Connection */ 322 | #define cwiid_connect cwiid_open 323 | #define cwiid_disconnect cwiid_close 324 | cwiid_wiimote_t *cwiid_open(bdaddr_t *bdaddr, int flags); 325 | cwiid_wiimote_t *cwiid_open_timeout(bdaddr_t *bdaddr, int flags, int timeout); 326 | cwiid_wiimote_t *cwiid_listen(int flags); 327 | int cwiid_close(cwiid_wiimote_t *wiimote); 328 | 329 | int cwiid_get_id(cwiid_wiimote_t *wiimote); 330 | int cwiid_set_data(cwiid_wiimote_t *wiimote, const void *data); 331 | const void *cwiid_get_data(cwiid_wiimote_t *wiimote); 332 | int cwiid_enable(cwiid_wiimote_t *wiimote, int flags); 333 | int cwiid_disable(cwiid_wiimote_t *wiimote, int flags); 334 | 335 | /* Interfaces */ 336 | int cwiid_set_mesg_callback(cwiid_wiimote_t *wiimote, 337 | cwiid_mesg_callback_t *callback); 338 | int cwiid_get_mesg(cwiid_wiimote_t *wiimote, int *mesg_count, 339 | union cwiid_mesg *mesg[], struct timespec *timestamp); 340 | int cwiid_get_state(cwiid_wiimote_t *wiimote, struct cwiid_state *state); 341 | int cwiid_get_acc_cal(struct wiimote *wiimote, enum cwiid_ext_type ext_type, 342 | struct acc_cal *acc_cal); 343 | int cwiid_get_balance_cal(struct wiimote *wiimote, 344 | struct balance_cal *balance_cal); 345 | 346 | /* Operations */ 347 | int cwiid_command(cwiid_wiimote_t *wiimote, enum cwiid_command command, 348 | int flags); 349 | int cwiid_send_rpt(cwiid_wiimote_t *wiimote, uint8_t flags, uint8_t report, 350 | size_t len, const void *data); 351 | int cwiid_request_status(cwiid_wiimote_t *wiimote); 352 | int cwiid_set_led(cwiid_wiimote_t *wiimote, uint8_t led); 353 | int cwiid_set_rumble(cwiid_wiimote_t *wiimote, uint8_t rumble); 354 | int cwiid_set_rpt_mode(cwiid_wiimote_t *wiimote, uint8_t rpt_mode); 355 | int cwiid_read(cwiid_wiimote_t *wiimote, uint8_t flags, uint32_t offset, 356 | uint16_t len, void *data); 357 | int cwiid_write(cwiid_wiimote_t *wiimote, uint8_t flags, uint32_t offset, 358 | uint16_t len, const void *data); 359 | /* int cwiid_beep(cwiid_wiimote_t *wiimote); */ 360 | 361 | /* HCI functions */ 362 | int cwiid_get_bdinfo_array(int dev_id, unsigned int timeout, int max_bdinfo, 363 | struct cwiid_bdinfo **bdinfo, uint8_t flags); 364 | int cwiid_find_wiimote(bdaddr_t *bdaddr, int timeout); 365 | 366 | #ifdef __cplusplus 367 | } 368 | #endif 369 | 370 | #endif 371 | -------------------------------------------------------------------------------- /libcwiid/cwiid.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | sysconfdir=@sysconfdir@ 6 | 7 | Name: CWiid 8 | Description: CWiid Wiimote Interface 9 | Version: @PACKAGE_VERSION@ 10 | Requires: bluez 11 | Libs: -L${libdir} -lcwiid 12 | Cflags: -I${includedir} 13 | -------------------------------------------------------------------------------- /libcwiid/cwiid_internal.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2007 L. Donnie Smith 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; either version 2 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 16 | * 17 | */ 18 | 19 | #ifndef CWIID_INTERNAL_H 20 | #define CWIID_INTERNAL_H 21 | 22 | #include 23 | #include 24 | #include /* ssize_t */ 25 | #include "cwiid.h" 26 | 27 | #define DEFAULT_TIMEOUT 5 28 | 29 | /* Bluetooth magic numbers */ 30 | #define BT_TRANS_MASK 0xF0 31 | #define BT_TRANS_HANDSHAKE 0x00 32 | #define BT_TRANS_SET_REPORT 0x50 33 | #define BT_TRANS_DATA 0xA0 34 | #define BT_TRANS_DATAC 0xB0 35 | 36 | #define BT_PARAM_MASK 0x0F 37 | /* HANDSHAKE params */ 38 | #define BT_PARAM_SUCCESSFUL 0x00 39 | #define BT_PARAM_NOT_READY 0x01 40 | #define BT_PARAM_ERR_INVALID_REPORT_ID 0x02 41 | #define BT_PARAM_ERR_UNSUPPORTED_REQUEST 0x03 42 | #define BT_PARAM_ERR_INVALID_PARAMETER 0x04 43 | #define BT_PARAM_ERR_UNKNOWN 0x0E 44 | #define BT_PARAM_ERR_FATAL 0x0F 45 | /* SET_REPORT, DATA, DATAC params */ 46 | #define BT_PARAM_INPUT 0x01 47 | #define BT_PARAM_OUTPUT 0x02 48 | #define BT_PARAM_FEATURE 0x03 49 | 50 | /* Wiimote specific magic numbers */ 51 | #define WIIMOTE_NAME "Nintendo RVL-CNT-01" 52 | #define WIIBALANCE_NAME "Nintendo RVL-WBC-01" 53 | #define WIIMOTE_CLASS_0 0x04 54 | #define WIIMOTE_CLASS_1 0x25 55 | #define WIIMOTE_CLASS_2 0x00 56 | 57 | /* Wiimote port/channel/PSMs */ 58 | #define CTL_PSM 17 59 | #define INT_PSM 19 60 | 61 | /* Report numbers */ 62 | #define RPT_LED_RUMBLE 0x11 63 | #define RPT_RPT_MODE 0x12 64 | #define RPT_IR_ENABLE1 0x13 65 | #define RPT_SPEAKER_ENABLE 0x14 66 | #define RPT_STATUS_REQ 0x15 67 | #define RPT_WRITE 0x16 68 | #define RPT_READ_REQ 0x17 69 | #define RPT_SPEAKER_DATA 0x18 70 | #define RPT_SPEAKER_MUTE 0x19 71 | #define RPT_IR_ENABLE2 0x1A 72 | #define RPT_STATUS 0x20 73 | #define RPT_READ_DATA 0x21 74 | #define RPT_WRITE_ACK 0x22 75 | #define RPT_BTN 0x30 76 | #define RPT_BTN_ACC 0x31 77 | #define RPT_BTN_EXT8 0x32 78 | #define RPT_BTN_ACC_IR12 0x33 79 | #define RPT_BTN_EXT19 0x34 80 | #define RPT_BTN_ACC_EXT16 0x35 81 | #define RPT_BTN_IR10_EXT9 0x36 82 | #define RPT_BTN_ACC_IR10_EXT6 0x37 83 | #define RPT_EXT21 0x3D 84 | #define RPT_BTN_ACC_IR36_1 0x3E 85 | #define RPT_BTN_ACC_IR36_2 0x3F 86 | 87 | /* Button Mask (masks unknown bits in button bytes) */ 88 | #define BTN_MASK_0 0x1F 89 | #define BTN_MASK_1 0x9F 90 | #define NUNCHUK_BTN_MASK 0x03 91 | 92 | /* Extension Values */ 93 | #define EXT_NONE 0x2E2E 94 | #define EXT_PARTIAL 0xFFFF 95 | #define EXT_NUNCHUK 0x0000 96 | #define EXT_CLASSIC 0x0101 97 | #define EXT_BALANCE 0x0402 98 | #define EXT_MOTIONPLUS 0x0405 99 | 100 | /* IR Enable blocks */ 101 | #define MARCAN_IR_BLOCK_1 "\x00\x00\x00\x00\x00\x00\x90\x00\xC0" 102 | #define MARCAN_IR_BLOCK_2 "\x40\x00" 103 | #define CLIFF_IR_BLOCK_1 "\x02\x00\x00\x71\x01\x00\xAA\x00\x64" 104 | #define CLIFF_IR_BLOCK_2 "\x63\x03" 105 | #define MAX_SENSITIVITY_IR_BLOCK_1 "\x00\x00\x00\x00\x00\x00\x90\x00\x41" 106 | #define MAX_SENSITIVITY_IR_BLOCK_2 "\x40\x00" 107 | #define WII_L1_IR_BLOCK_1 "\x02\x00\x00\x71\x01\x00\x64\x00\xFE" 108 | #define WII_L1_IR_BLOCK_2 "\xFD\x05" 109 | #define WII_L2_IR_BLOCK_1 "\x02\x00\x00\x71\x01\x00\x96\x00\xB4" 110 | #define WII_L2_IR_BLOCK_2 "\xB3\x04" 111 | #define WII_L3_IR_BLOCK_1 "\x02\x00\x00\x71\x01\x00\xAA\x00\x64" 112 | #define WII_L3_IR_BLOCK_2 "\x63\x03" 113 | #define WII_L4_IR_BLOCK_1 "\x02\x00\x00\x71\x01\x00\xC8\x00\x36" 114 | #define WII_L4_IR_BLOCK_2 "\x35\x03" 115 | #define WII_L5_IR_BLOCK_1 "\x02\x00\x00\x71\x01\x00\x72\x00\x20" 116 | #define WII_L5_IR_BLOCK_2 "\x1F\x03" 117 | 118 | /* Write Sequences */ 119 | enum write_seq_type { 120 | WRITE_SEQ_RPT, 121 | WRITE_SEQ_MEM 122 | }; 123 | 124 | struct write_seq { 125 | enum write_seq_type type; 126 | uint32_t report_offset; 127 | const void *data; 128 | uint16_t len; 129 | uint8_t flags; 130 | }; 131 | 132 | #define SEQ_LEN(seq) (sizeof(seq)/sizeof(struct write_seq)) 133 | 134 | /* Message arrays */ 135 | struct mesg_array { 136 | uint8_t count; 137 | struct timespec timestamp; 138 | union cwiid_mesg array[CWIID_MAX_MESG_COUNT]; 139 | }; 140 | 141 | /* RW State/Mesg */ 142 | enum rw_status { 143 | RW_IDLE, 144 | RW_READ, 145 | RW_WRITE, 146 | RW_CANCEL 147 | }; 148 | 149 | struct rw_mesg { 150 | enum rw_status type; 151 | uint8_t error; 152 | uint32_t offset; 153 | uint8_t len; 154 | char data[16]; 155 | }; 156 | 157 | /* Wiimote struct */ 158 | struct wiimote { 159 | int flags; 160 | int ctl_socket; 161 | int int_socket; 162 | pthread_t router_thread; 163 | pthread_t status_thread; 164 | pthread_t mesg_callback_thread; 165 | int mesg_pipe[2]; 166 | int status_pipe[2]; 167 | int rw_pipe[2]; 168 | struct cwiid_state state; 169 | enum rw_status rw_status; 170 | cwiid_mesg_callback_t *mesg_callback; 171 | pthread_mutex_t state_mutex; 172 | pthread_mutex_t rw_mutex; 173 | pthread_mutex_t rpt_mutex; 174 | int id; 175 | const void *data; 176 | }; 177 | 178 | /* prototypes */ 179 | cwiid_wiimote_t *cwiid_new(int ctl_socket, int int_socket, int flags); 180 | 181 | /* thread.c */ 182 | void *router_thread(struct wiimote *wiimote); 183 | void *status_thread(struct wiimote *wiimote); 184 | void *mesg_callback_thread(struct wiimote *wiimote); 185 | 186 | /* util.c */ 187 | void cwiid_err(struct wiimote *wiimote, const char *str, ...); 188 | int verify_handshake(struct wiimote *wiimote); 189 | int exec_write_seq(struct wiimote *wiimote, unsigned int len, 190 | struct write_seq *seq); 191 | int full_read(int fd, void *buf, size_t len); 192 | int write_mesg_array(struct wiimote *wiimote, struct mesg_array *ma); 193 | int read_mesg_array(int fd, struct mesg_array *ma); 194 | int cancel_rw(struct wiimote *wiimote); 195 | int cancel_mesg_callback(struct wiimote *wiimote); 196 | 197 | /* process.c */ 198 | int process_error(struct wiimote *, ssize_t, struct mesg_array *); 199 | int process_status(struct wiimote *, const unsigned char *, 200 | struct mesg_array *); 201 | int process_btn(struct wiimote *, const unsigned char *, struct mesg_array *); 202 | int process_acc(struct wiimote *, const unsigned char *, struct mesg_array *); 203 | int process_ir10(struct wiimote *, const unsigned char *, struct mesg_array *); 204 | int process_ir12(struct wiimote *, const unsigned char *, struct mesg_array *); 205 | int process_ext(struct wiimote *, unsigned char *, unsigned char, 206 | struct mesg_array *); 207 | int process_read(struct wiimote *, unsigned char *); 208 | int process_write(struct wiimote *, unsigned char *); 209 | 210 | /* state.c */ 211 | int update_state(struct wiimote *wiimote, struct mesg_array *ma); 212 | int update_rpt_mode(struct wiimote *wiimote, int8_t rpt_mode); 213 | 214 | #endif 215 | -------------------------------------------------------------------------------- /libcwiid/interface.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2007 L. Donnie Smith 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; either version 2 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 16 | * 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "cwiid_internal.h" 26 | 27 | int cwiid_get_id(cwiid_wiimote_t *wiimote) 28 | { 29 | return wiimote->id; 30 | } 31 | 32 | int cwiid_set_data(cwiid_wiimote_t *wiimote, const void *data) 33 | { 34 | wiimote->data = data; 35 | return 0; 36 | } 37 | 38 | const void *cwiid_get_data(cwiid_wiimote_t *wiimote) 39 | { 40 | return wiimote->data; 41 | } 42 | 43 | int cwiid_enable(cwiid_wiimote_t *wiimote, int flags) 44 | { 45 | unsigned char data; 46 | 47 | if ((flags & CWIID_FLAG_NONBLOCK) && 48 | !(wiimote->flags & CWIID_FLAG_NONBLOCK)) { 49 | if (fcntl(wiimote->mesg_pipe[0], F_SETFL, O_NONBLOCK)) { 50 | cwiid_err(wiimote, "File control error (mesg pipe)"); 51 | return -1; 52 | } 53 | } 54 | if (flags & CWIID_FLAG_MOTIONPLUS) { 55 | data = 0x04; 56 | cwiid_write(wiimote, CWIID_RW_REG, 0xA600FE, 1, &data); 57 | cwiid_request_status(wiimote); 58 | } 59 | wiimote->flags |= flags; 60 | return 0; 61 | } 62 | 63 | int cwiid_disable(cwiid_wiimote_t *wiimote, int flags) 64 | { 65 | unsigned char data; 66 | 67 | if ((flags & CWIID_FLAG_NONBLOCK) && 68 | (wiimote->flags & CWIID_FLAG_NONBLOCK)) { 69 | if (fcntl(wiimote->mesg_pipe[0], F_SETFL, 0)) { 70 | cwiid_err(wiimote, "File control error (mesg pipe)"); 71 | return -1; 72 | } 73 | } 74 | if (flags & CWIID_FLAG_MOTIONPLUS) { 75 | data = 0x55; 76 | cwiid_write(wiimote, CWIID_RW_REG, 0xA400F0, 1, &data); 77 | data = 0x00; 78 | cwiid_write(wiimote, CWIID_RW_REG, 0xA400FB, 1, &data); 79 | cwiid_request_status(wiimote); 80 | } 81 | wiimote->flags &= ~flags; 82 | return 0; 83 | } 84 | 85 | int cwiid_set_mesg_callback(cwiid_wiimote_t *wiimote, 86 | cwiid_mesg_callback_t *callback) 87 | { 88 | if (wiimote->mesg_callback) { 89 | if (cancel_mesg_callback(wiimote)) { 90 | /* prints it's own errors */ 91 | return -1; 92 | } 93 | } 94 | 95 | wiimote->mesg_callback = callback; 96 | 97 | if (wiimote->mesg_callback) { 98 | if (pthread_create(&wiimote->mesg_callback_thread, NULL, 99 | (void *(*)(void *))&mesg_callback_thread, wiimote)) { 100 | cwiid_err(wiimote, "Thread creation error (callback thread)"); 101 | return -1; 102 | } 103 | } 104 | 105 | return 0; 106 | } 107 | 108 | int cwiid_get_mesg(cwiid_wiimote_t *wiimote, int *mesg_count, 109 | union cwiid_mesg *mesg[], struct timespec *timestamp) 110 | { 111 | struct mesg_array ma; 112 | 113 | if (read_mesg_array(wiimote->mesg_pipe[0], &ma)) { 114 | if (errno == EAGAIN) { 115 | return -1; 116 | } 117 | else { 118 | cwiid_err(wiimote, "Pipe read error (mesg_pipe)"); 119 | return -1; 120 | } 121 | } 122 | 123 | *mesg_count = ma.count; 124 | *timestamp = ma.timestamp; 125 | 126 | if ((*mesg = malloc(ma.count * sizeof ma.array[0])) == NULL) { 127 | cwiid_err(wiimote, "Memory allocation error (mesg array)"); 128 | return -1; 129 | } 130 | 131 | memcpy(*mesg, &ma.array, ma.count * sizeof (*mesg)[0]); 132 | 133 | return 0; 134 | } 135 | 136 | int cwiid_get_state(cwiid_wiimote_t *wiimote, struct cwiid_state *state) 137 | { 138 | if (pthread_mutex_lock(&wiimote->state_mutex)) { 139 | cwiid_err(wiimote, "Mutex lock error (state mutex)"); 140 | return -1; 141 | } 142 | 143 | memcpy(state, &wiimote->state, sizeof *state); 144 | 145 | if (pthread_mutex_unlock(&wiimote->state_mutex)) { 146 | cwiid_err(wiimote, "Mutex unlock error (state mutex) - " 147 | "deadlock warning"); 148 | return -1; 149 | } 150 | 151 | return 0; 152 | } 153 | 154 | int cwiid_get_acc_cal(cwiid_wiimote_t *wiimote, enum cwiid_ext_type ext_type, 155 | struct acc_cal *acc_cal) 156 | { 157 | uint8_t flags; 158 | uint32_t offset; 159 | unsigned char buf[7]; 160 | char *err_str; 161 | 162 | switch (ext_type) { 163 | case CWIID_EXT_NONE: 164 | flags = CWIID_RW_EEPROM; 165 | offset = 0x16; 166 | err_str = ""; 167 | break; 168 | case CWIID_EXT_NUNCHUK: 169 | flags = CWIID_RW_REG; 170 | offset = 0xA40020; 171 | err_str = "nunchuk "; 172 | break; 173 | default: 174 | cwiid_err(wiimote, "Unsupported calibration request"); 175 | return -1; 176 | } 177 | if (cwiid_read(wiimote, flags, offset, 7, buf)) { 178 | cwiid_err(wiimote, "Read error (%scal)", err_str); 179 | return -1; 180 | } 181 | 182 | acc_cal->zero[CWIID_X] = buf[0]; 183 | acc_cal->zero[CWIID_Y] = buf[1]; 184 | acc_cal->zero[CWIID_Z] = buf[2]; 185 | acc_cal->one[CWIID_X] = buf[4]; 186 | acc_cal->one[CWIID_Y] = buf[5]; 187 | acc_cal->one[CWIID_Z] = buf[6]; 188 | 189 | return 0; 190 | } 191 | 192 | int cwiid_get_balance_cal(cwiid_wiimote_t *wiimote, 193 | struct balance_cal *balance_cal) 194 | { 195 | unsigned char buf[24]; 196 | 197 | if (cwiid_read(wiimote, CWIID_RW_REG, 0xa40024, 24, buf)) { 198 | cwiid_err(wiimote, "Read error (balancecal)"); 199 | return -1; 200 | } 201 | balance_cal->right_top[0] = ((uint16_t)buf[0]<<8 | (uint16_t)buf[1]); 202 | balance_cal->right_bottom[0] = ((uint16_t)buf[2]<<8 | (uint16_t)buf[3]); 203 | balance_cal->left_top[0] = ((uint16_t)buf[4]<<8 | (uint16_t)buf[5]); 204 | balance_cal->left_bottom[0] = ((uint16_t)buf[6]<<8 | (uint16_t)buf[7]); 205 | balance_cal->right_top[1] = ((uint16_t)buf[8]<<8 | (uint16_t)buf[9]); 206 | balance_cal->right_bottom[1] = ((uint16_t)buf[10]<<8 | (uint16_t)buf[11]); 207 | balance_cal->left_top[1] = ((uint16_t)buf[12]<<8 | (uint16_t)buf[13]); 208 | balance_cal->left_bottom[1] = ((uint16_t)buf[14]<<8 | (uint16_t)buf[15]); 209 | balance_cal->right_top[2] = ((uint16_t)buf[16]<<8 | (uint16_t)buf[17]); 210 | balance_cal->right_bottom[2] = ((uint16_t)buf[18]<<8 | (uint16_t)buf[19]); 211 | balance_cal->left_top[2] = ((uint16_t)buf[20]<<8 | (uint16_t)buf[21]); 212 | balance_cal->left_bottom[2] = ((uint16_t)buf[22]<<8 | (uint16_t)buf[23]); 213 | 214 | return 0; 215 | } 216 | -------------------------------------------------------------------------------- /libcwiid/process.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2007 L. Donnie Smith 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; either version 2 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 16 | * 17 | */ 18 | 19 | #include 20 | #include "cwiid_internal.h" 21 | 22 | int process_error(struct wiimote *wiimote, ssize_t len, struct mesg_array *ma) 23 | { 24 | struct cwiid_error_mesg *error_mesg; 25 | 26 | error_mesg = &ma->array[ma->count++].error_mesg; 27 | error_mesg->type = CWIID_MESG_ERROR; 28 | if (len == 0) { 29 | error_mesg->error = CWIID_ERROR_DISCONNECT; 30 | } 31 | else { 32 | error_mesg->error = CWIID_ERROR_COMM; 33 | } 34 | 35 | if (cancel_rw(wiimote)) { 36 | cwiid_err(wiimote, "RW cancel error"); 37 | } 38 | 39 | return 0; 40 | } 41 | 42 | int process_status(struct wiimote *wiimote, const unsigned char *data, 43 | struct mesg_array *ma) 44 | { 45 | struct cwiid_status_mesg status_mesg; 46 | 47 | status_mesg.type = CWIID_MESG_STATUS; 48 | status_mesg.battery = data[5]; 49 | if (data[2] & 0x02) { 50 | /* status_thread will figure out what it is */ 51 | status_mesg.ext_type = CWIID_EXT_UNKNOWN; 52 | } 53 | else { 54 | status_mesg.ext_type = CWIID_EXT_NONE; 55 | } 56 | 57 | if (write(wiimote->status_pipe[1], &status_mesg, sizeof status_mesg) 58 | != sizeof status_mesg) { 59 | cwiid_err(wiimote, "Status pipe write error"); 60 | return -1; 61 | } 62 | 63 | return 0; 64 | } 65 | 66 | int process_btn(struct wiimote *wiimote, const unsigned char *data, 67 | struct mesg_array *ma) 68 | { 69 | struct cwiid_btn_mesg *btn_mesg; 70 | uint16_t buttons; 71 | 72 | buttons = (data[0] & BTN_MASK_0)<<8 | 73 | (data[1] & BTN_MASK_1); 74 | if (wiimote->state.rpt_mode & CWIID_RPT_BTN) { 75 | if ((wiimote->state.buttons != buttons) || 76 | (wiimote->flags & CWIID_FLAG_REPEAT_BTN)) { 77 | btn_mesg = &ma->array[ma->count++].btn_mesg; 78 | btn_mesg->type = CWIID_MESG_BTN; 79 | btn_mesg->buttons = buttons; 80 | } 81 | } 82 | 83 | return 0; 84 | } 85 | 86 | int process_acc(struct wiimote *wiimote, const unsigned char *data, 87 | struct mesg_array *ma) 88 | { 89 | struct cwiid_acc_mesg *acc_mesg; 90 | 91 | if (wiimote->state.rpt_mode & CWIID_RPT_ACC) { 92 | acc_mesg = &ma->array[ma->count++].acc_mesg; 93 | acc_mesg->type = CWIID_MESG_ACC; 94 | acc_mesg->acc[CWIID_X] = data[0]; 95 | acc_mesg->acc[CWIID_Y] = data[1]; 96 | acc_mesg->acc[CWIID_Z] = data[2]; 97 | } 98 | 99 | return 0; 100 | } 101 | 102 | int process_ir10(struct wiimote *wiimote, const unsigned char *data, 103 | struct mesg_array *ma) 104 | { 105 | struct cwiid_ir_mesg *ir_mesg; 106 | int i; 107 | const unsigned char *block; 108 | 109 | if (wiimote->state.rpt_mode & CWIID_RPT_IR) { 110 | ir_mesg = &ma->array[ma->count++].ir_mesg; 111 | ir_mesg->type = CWIID_MESG_IR; 112 | 113 | for (i=0, block=data; i < CWIID_IR_SRC_COUNT; i+=2, block+=5) { 114 | if (block[0] == 0xFF) { 115 | ir_mesg->src[i].valid = 0; 116 | } 117 | else { 118 | ir_mesg->src[i].valid = 1; 119 | ir_mesg->src[i].pos[CWIID_X] = ((uint16_t)block[2] & 0x30)<<4 | 120 | (uint16_t)block[0]; 121 | ir_mesg->src[i].pos[CWIID_Y] = ((uint16_t)block[2] & 0xC0)<<2 | 122 | (uint16_t)block[1]; 123 | ir_mesg->src[i].size = -1; 124 | } 125 | 126 | if (block[3] == 0xFF) { 127 | ir_mesg->src[i+1].valid = 0; 128 | } 129 | else { 130 | ir_mesg->src[i+1].valid = 1; 131 | ir_mesg->src[i+1].pos[CWIID_X] = 132 | ((uint16_t)block[2] & 0x03)<<8 | 133 | (uint16_t)block[3]; 134 | ir_mesg->src[i+1].pos[CWIID_Y] = 135 | ((uint16_t)block[2] & 0x0C)<<6 | 136 | (uint16_t)block[4]; 137 | ir_mesg->src[i+1].size = -1; 138 | } 139 | } 140 | } 141 | 142 | return 0; 143 | } 144 | 145 | int process_ir12(struct wiimote *wiimote, const unsigned char *data, 146 | struct mesg_array *ma) 147 | { 148 | struct cwiid_ir_mesg *ir_mesg; 149 | int i; 150 | const unsigned char *block; 151 | 152 | if (wiimote->state.rpt_mode & CWIID_RPT_IR) { 153 | ir_mesg = &ma->array[ma->count++].ir_mesg; 154 | ir_mesg->type = CWIID_MESG_IR; 155 | 156 | for (i=0, block=data; i < CWIID_IR_SRC_COUNT; i++, block+=3) { 157 | if (block[0] == 0xFF) { 158 | ir_mesg->src[i].valid = 0; 159 | } 160 | else { 161 | ir_mesg->src[i].valid = 1; 162 | ir_mesg->src[i].pos[CWIID_X] = ((uint16_t)block[2] & 0x30)<<4 | 163 | (uint16_t)block[0]; 164 | ir_mesg->src[i].pos[CWIID_Y] = ((uint16_t)block[2] & 0xC0)<<2 | 165 | (uint16_t)block[1]; 166 | ir_mesg->src[i].size = block[2] & 0x0F; 167 | } 168 | } 169 | } 170 | 171 | return 0; 172 | } 173 | 174 | int process_ext(struct wiimote *wiimote, unsigned char *data, 175 | unsigned char len, struct mesg_array *ma) 176 | { 177 | struct cwiid_nunchuk_mesg *nunchuk_mesg; 178 | struct cwiid_classic_mesg *classic_mesg; 179 | struct cwiid_balance_mesg *balance_mesg; 180 | struct cwiid_motionplus_mesg *motionplus_mesg; 181 | int i; 182 | 183 | switch (wiimote->state.ext_type) { 184 | case CWIID_EXT_NONE: 185 | cwiid_err(wiimote, "Received unexpected extension report"); 186 | break; 187 | case CWIID_EXT_UNKNOWN: 188 | break; 189 | case CWIID_EXT_NUNCHUK: 190 | if (wiimote->state.rpt_mode & CWIID_RPT_NUNCHUK) { 191 | nunchuk_mesg = &ma->array[ma->count++].nunchuk_mesg; 192 | nunchuk_mesg->type = CWIID_MESG_NUNCHUK; 193 | nunchuk_mesg->stick[CWIID_X] = data[0]; 194 | nunchuk_mesg->stick[CWIID_Y] = data[1]; 195 | nunchuk_mesg->acc[CWIID_X] = data[2]; 196 | nunchuk_mesg->acc[CWIID_Y] = data[3]; 197 | nunchuk_mesg->acc[CWIID_Z] = data[4]; 198 | nunchuk_mesg->buttons = ~data[5] & NUNCHUK_BTN_MASK; 199 | } 200 | break; 201 | case CWIID_EXT_CLASSIC: 202 | if (wiimote->state.rpt_mode & CWIID_RPT_CLASSIC) { 203 | classic_mesg = &ma->array[ma->count++].classic_mesg; 204 | classic_mesg->type = CWIID_MESG_CLASSIC; 205 | 206 | for (i=0; i < 6; i++) { 207 | data[i] = data[i]; 208 | } 209 | 210 | classic_mesg->l_stick[CWIID_X] = data[0] & 0x3F; 211 | classic_mesg->l_stick[CWIID_Y] = data[1] & 0x3F; 212 | classic_mesg->r_stick[CWIID_X] = (data[0] & 0xC0)>>3 | 213 | (data[1] & 0xC0)>>5 | 214 | (data[2] & 0x80)>>7; 215 | classic_mesg->r_stick[CWIID_Y] = data[2] & 0x1F; 216 | classic_mesg->l = (data[2] & 0x60)>>2 | 217 | (data[3] & 0xE0)>>5; 218 | classic_mesg->r = data[3] & 0x1F; 219 | classic_mesg->buttons = ~((uint16_t)data[4]<<8 | 220 | (uint16_t)data[5]); 221 | } 222 | break; 223 | case CWIID_EXT_BALANCE: 224 | if (wiimote->state.rpt_mode & CWIID_RPT_BALANCE) { 225 | balance_mesg = &ma->array[ma->count++].balance_mesg; 226 | balance_mesg->type = CWIID_MESG_BALANCE; 227 | balance_mesg->right_top = ((uint16_t)data[0]<<8 | 228 | (uint16_t)data[1]); 229 | balance_mesg->right_bottom = ((uint16_t)data[2]<<8 | 230 | (uint16_t)data[3]); 231 | balance_mesg->left_top = ((uint16_t)data[4]<<8 | 232 | (uint16_t)data[5]); 233 | balance_mesg->left_bottom = ((uint16_t)data[6]<<8 | 234 | (uint16_t)data[7]); 235 | } 236 | break; 237 | case CWIID_EXT_MOTIONPLUS: 238 | if (wiimote->state.rpt_mode & CWIID_RPT_MOTIONPLUS) { 239 | motionplus_mesg = &ma->array[ma->count++].motionplus_mesg; 240 | motionplus_mesg->type = CWIID_MESG_MOTIONPLUS; 241 | motionplus_mesg->angle_rate[CWIID_PHI] = ((uint16_t)data[5] & 0xFC)<<6 | 242 | (uint16_t)data[2]; 243 | motionplus_mesg->angle_rate[CWIID_THETA] = ((uint16_t)data[4] & 0xFC)<<6 | 244 | (uint16_t)data[1]; 245 | motionplus_mesg->angle_rate[CWIID_PSI] = ((uint16_t)data[3] & 0xFC)<<6 | 246 | (uint16_t)data[0]; 247 | motionplus_mesg->low_speed[CWIID_PHI] = ((uint8_t)data[3] & 0x01); 248 | motionplus_mesg->low_speed[CWIID_THETA] = ((uint8_t)data[4] & 0x02)>>1; 249 | motionplus_mesg->low_speed[CWIID_PSI] = ((uint8_t)data[3] & 0x02)>>1; 250 | } 251 | break; 252 | } 253 | 254 | return 0; 255 | } 256 | 257 | int process_read(struct wiimote *wiimote, unsigned char *data) 258 | { 259 | struct rw_mesg rw_mesg; 260 | 261 | if (wiimote->rw_status != RW_READ) { 262 | cwiid_err(wiimote, "Received unexpected read report"); 263 | return -1; 264 | } 265 | 266 | rw_mesg.type = RW_READ; 267 | rw_mesg.len = (data[0]>>4)+1; 268 | rw_mesg.error = data[0] & 0x0F; 269 | memcpy(&rw_mesg.data, data+3, rw_mesg.len); 270 | 271 | if (write(wiimote->rw_pipe[1], &rw_mesg, sizeof rw_mesg) != 272 | sizeof rw_mesg) { 273 | cwiid_err(wiimote, "RW pipe write error"); 274 | return -1; 275 | } 276 | 277 | return 0; 278 | } 279 | 280 | int process_write(struct wiimote *wiimote, unsigned char *data) 281 | { 282 | struct rw_mesg rw_mesg; 283 | 284 | if (wiimote->rw_status != RW_WRITE) { 285 | cwiid_err(wiimote, "Received unexpected write report"); 286 | return -1; 287 | } 288 | 289 | rw_mesg.type = RW_WRITE; 290 | rw_mesg.error = data[0]; 291 | 292 | if (write(wiimote->rw_pipe[1], &rw_mesg, sizeof rw_mesg) != 293 | sizeof rw_mesg) { 294 | cwiid_err(wiimote, "RW pipe write error"); 295 | return -1; 296 | } 297 | 298 | return 0; 299 | } 300 | -------------------------------------------------------------------------------- /libcwiid/state.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2007 L. Donnie Smith 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; either version 2 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 16 | * 17 | */ 18 | 19 | #include 20 | #include 21 | #include "cwiid_internal.h" 22 | 23 | int update_state(struct wiimote *wiimote, struct mesg_array *ma) 24 | { 25 | int i; 26 | union cwiid_mesg *mesg; 27 | 28 | if (pthread_mutex_lock(&wiimote->state_mutex)) { 29 | cwiid_err(wiimote, "Mutex lock error (state mutex)"); 30 | return -1; 31 | } 32 | 33 | for (i=0; i < ma->count; i++) { 34 | mesg = &ma->array[i]; 35 | 36 | switch (mesg->type) { 37 | case CWIID_MESG_STATUS: 38 | wiimote->state.battery = mesg->status_mesg.battery; 39 | if (wiimote->state.ext_type != mesg->status_mesg.ext_type) { 40 | memset(&wiimote->state.ext, 0, sizeof wiimote->state.ext); 41 | wiimote->state.ext_type = mesg->status_mesg.ext_type; 42 | } 43 | break; 44 | case CWIID_MESG_BTN: 45 | wiimote->state.buttons = mesg->btn_mesg.buttons; 46 | break; 47 | case CWIID_MESG_ACC: 48 | memcpy(wiimote->state.acc, mesg->acc_mesg.acc, 49 | sizeof wiimote->state.acc); 50 | break; 51 | case CWIID_MESG_IR: 52 | memcpy(wiimote->state.ir_src, mesg->ir_mesg.src, 53 | sizeof wiimote->state.ir_src); 54 | break; 55 | case CWIID_MESG_NUNCHUK: 56 | memcpy(wiimote->state.ext.nunchuk.stick, 57 | mesg->nunchuk_mesg.stick, 58 | sizeof wiimote->state.ext.nunchuk.stick); 59 | memcpy(wiimote->state.ext.nunchuk.acc, 60 | mesg->nunchuk_mesg.acc, 61 | sizeof wiimote->state.ext.nunchuk.acc); 62 | wiimote->state.ext.nunchuk.buttons = mesg->nunchuk_mesg.buttons; 63 | break; 64 | case CWIID_MESG_CLASSIC: 65 | memcpy(wiimote->state.ext.classic.l_stick, 66 | mesg->classic_mesg.l_stick, 67 | sizeof wiimote->state.ext.classic.l_stick); 68 | memcpy(wiimote->state.ext.classic.r_stick, 69 | mesg->classic_mesg.r_stick, 70 | sizeof wiimote->state.ext.classic.r_stick); 71 | wiimote->state.ext.classic.l = mesg->classic_mesg.l; 72 | wiimote->state.ext.classic.r = mesg->classic_mesg.r; 73 | wiimote->state.ext.classic.buttons = mesg->classic_mesg.buttons; 74 | break; 75 | case CWIID_MESG_BALANCE: 76 | wiimote->state.ext.balance.right_top = mesg->balance_mesg.right_top; 77 | wiimote->state.ext.balance.right_bottom = mesg->balance_mesg.right_bottom; 78 | wiimote->state.ext.balance.left_top = mesg->balance_mesg.left_top; 79 | wiimote->state.ext.balance.left_bottom = mesg->balance_mesg.left_bottom; 80 | break; 81 | case CWIID_MESG_MOTIONPLUS: 82 | memcpy(wiimote->state.ext.motionplus.angle_rate, 83 | mesg->motionplus_mesg.angle_rate, 84 | sizeof wiimote->state.ext.motionplus.angle_rate); 85 | memcpy(wiimote->state.ext.motionplus.low_speed, 86 | mesg->motionplus_mesg.low_speed, 87 | sizeof wiimote->state.ext.motionplus.low_speed); 88 | break; 89 | case CWIID_MESG_ERROR: 90 | wiimote->state.error = mesg->error_mesg.error; 91 | break; 92 | case CWIID_MESG_UNKNOWN: 93 | /* do nothing, error has already been printed */ 94 | break; 95 | } 96 | } 97 | 98 | if (pthread_mutex_unlock(&wiimote->state_mutex)) { 99 | cwiid_err(wiimote, "Mutex unlock error (state mutex) - " 100 | "deadlock warning"); 101 | return -1; 102 | } 103 | 104 | return 0; 105 | } 106 | 107 | /* IR Sensitivity Block */ 108 | unsigned char ir_block1[] = MAX_SENSITIVITY_IR_BLOCK_1; 109 | unsigned char ir_block2[] = MAX_SENSITIVITY_IR_BLOCK_2; 110 | 111 | struct write_seq ir_enable10_seq[] = { 112 | {WRITE_SEQ_RPT, RPT_IR_ENABLE1, (const void *)"\x04", 1, 0}, 113 | {WRITE_SEQ_RPT, RPT_IR_ENABLE2, (const void *)"\x04", 1, 0}, 114 | {WRITE_SEQ_MEM, 0xB00030, (const void *)"\x08", 1, CWIID_RW_REG}, 115 | {WRITE_SEQ_MEM, 0xB00000, ir_block1, sizeof(ir_block1)-1, CWIID_RW_REG}, 116 | {WRITE_SEQ_MEM, 0xB0001A, ir_block2, sizeof(ir_block2)-1, CWIID_RW_REG}, 117 | {WRITE_SEQ_MEM, 0xB00033, (const void *)"\x01", 1, CWIID_RW_REG} 118 | }; 119 | 120 | struct write_seq ir_enable12_seq[] = { 121 | {WRITE_SEQ_RPT, RPT_IR_ENABLE1, (const void *)"\x04", 1, 0}, 122 | {WRITE_SEQ_RPT, RPT_IR_ENABLE2, (const void *)"\x04", 1, 0}, 123 | {WRITE_SEQ_MEM, 0xB00030, (const void *)"\x08", 1, CWIID_RW_REG}, 124 | {WRITE_SEQ_MEM, 0xB00000, ir_block1, sizeof(ir_block1)-1, CWIID_RW_REG}, 125 | {WRITE_SEQ_MEM, 0xB0001A, ir_block2, sizeof(ir_block2)-1, CWIID_RW_REG}, 126 | {WRITE_SEQ_MEM, 0xB00033, (const void *)"\x03", 1, CWIID_RW_REG} 127 | }; 128 | 129 | struct write_seq ir_disable_seq[] = { 130 | {WRITE_SEQ_RPT, RPT_IR_ENABLE1, (const void *)"\x00", 1, 0}, 131 | {WRITE_SEQ_RPT, RPT_IR_ENABLE2, (const void *)"\x00", 1, 0} 132 | }; 133 | 134 | #define RPT_MODE_BUF_LEN 2 135 | int update_rpt_mode(struct wiimote *wiimote, int8_t rpt_mode) 136 | { 137 | unsigned char buf[RPT_MODE_BUF_LEN]; 138 | uint8_t rpt_type; 139 | struct write_seq *ir_enable_seq; 140 | int seq_len; 141 | 142 | /* rpt_mode = bitmask of requested report types */ 143 | /* rpt_type = report id sent to the wiimote */ 144 | if (pthread_mutex_lock(&wiimote->rpt_mutex)) { 145 | cwiid_err(wiimote, "Mutex lock error (rpt mutex)"); 146 | return -1; 147 | } 148 | 149 | /* -1 updates the reporting mode using old rpt_mode 150 | * (reporting type may change if extensions are 151 | * plugged in/unplugged */ 152 | if (rpt_mode == -1) { 153 | rpt_mode = wiimote->state.rpt_mode; 154 | } 155 | 156 | /* Pick a report mode based on report flags */ 157 | if ((rpt_mode & CWIID_RPT_EXT) && 158 | ((wiimote->state.ext_type == CWIID_EXT_NUNCHUK) || 159 | (wiimote->state.ext_type == CWIID_EXT_CLASSIC) || 160 | (wiimote->state.ext_type == CWIID_EXT_MOTIONPLUS))) { 161 | if ((rpt_mode & CWIID_RPT_IR) && (rpt_mode & CWIID_RPT_ACC)) { 162 | rpt_type = RPT_BTN_ACC_IR10_EXT6; 163 | ir_enable_seq = ir_enable10_seq; 164 | seq_len = SEQ_LEN(ir_enable10_seq); 165 | } 166 | else if (rpt_mode & CWIID_RPT_IR) { 167 | rpt_type = RPT_BTN_IR10_EXT9; 168 | ir_enable_seq = ir_enable10_seq; 169 | seq_len = SEQ_LEN(ir_enable10_seq); 170 | } 171 | else if (rpt_mode & CWIID_RPT_ACC) { 172 | rpt_type = RPT_BTN_ACC_EXT16; 173 | } 174 | else if (rpt_mode & CWIID_RPT_BTN) { 175 | rpt_type = RPT_BTN_EXT8; 176 | } 177 | else { 178 | rpt_type = RPT_EXT21; 179 | } 180 | } 181 | else if ((rpt_mode & CWIID_RPT_EXT) && 182 | wiimote->state.ext_type == CWIID_EXT_BALANCE) { 183 | rpt_type = RPT_BTN_EXT8; 184 | } 185 | else { 186 | if (rpt_mode & CWIID_RPT_IR) { 187 | rpt_type = RPT_BTN_ACC_IR12; 188 | ir_enable_seq = ir_enable12_seq; 189 | seq_len = SEQ_LEN(ir_enable12_seq); 190 | } 191 | else if (rpt_mode & CWIID_RPT_ACC) { 192 | rpt_type = RPT_BTN_ACC; 193 | } 194 | else { 195 | rpt_type = RPT_BTN; 196 | } 197 | } 198 | 199 | /* Enable IR */ 200 | /* TODO: only do this when necessary (record old IR mode) */ 201 | if ((rpt_mode & CWIID_RPT_IR)) { 202 | if (exec_write_seq(wiimote, seq_len, ir_enable_seq)) { 203 | cwiid_err(wiimote, "IR enable error"); 204 | return -1; 205 | } 206 | } 207 | /* Disable IR */ 208 | else if ((wiimote->state.rpt_mode & CWIID_RPT_IR) && 209 | !(rpt_mode & CWIID_RPT_IR)) { 210 | if (exec_write_seq(wiimote, SEQ_LEN(ir_disable_seq), ir_disable_seq)) { 211 | cwiid_err(wiimote, "IR disable error"); 212 | return -1; 213 | } 214 | } 215 | 216 | /* Send SET_REPORT */ 217 | buf[0] = (wiimote->flags & CWIID_FLAG_CONTINUOUS) ? 0x04 : 0; 218 | buf[1] = rpt_type; 219 | if (cwiid_send_rpt(wiimote, 0, RPT_RPT_MODE, RPT_MODE_BUF_LEN, buf)) { 220 | cwiid_err(wiimote, "Send report error (report mode)"); 221 | return -1; 222 | } 223 | 224 | /* clear state for unreported data */ 225 | if (CWIID_RPT_BTN & ~rpt_mode & wiimote->state.rpt_mode) { 226 | wiimote->state.buttons = 0; 227 | } 228 | if (CWIID_RPT_ACC & ~rpt_mode & wiimote->state.rpt_mode) { 229 | memset(wiimote->state.acc, 0, sizeof wiimote->state.acc); 230 | } 231 | if (CWIID_RPT_IR & ~rpt_mode & wiimote->state.rpt_mode) { 232 | memset(wiimote->state.ir_src, 0, sizeof wiimote->state.ir_src); 233 | } 234 | if ((wiimote->state.ext_type == CWIID_EXT_NUNCHUK) && 235 | (CWIID_RPT_NUNCHUK & ~rpt_mode & wiimote->state.rpt_mode)) { 236 | memset(&wiimote->state.ext, 0, sizeof wiimote->state.ext); 237 | } 238 | else if ((wiimote->state.ext_type == CWIID_EXT_CLASSIC) && 239 | (CWIID_RPT_CLASSIC & ~rpt_mode & wiimote->state.rpt_mode)) { 240 | memset(&wiimote->state.ext, 0, sizeof wiimote->state.ext); 241 | } 242 | else if ((wiimote->state.ext_type == CWIID_EXT_BALANCE) && 243 | (CWIID_RPT_BALANCE & ~rpt_mode & wiimote->state.rpt_mode)) { 244 | memset(&wiimote->state.ext, 0, sizeof wiimote->state.ext); 245 | } 246 | else if ((wiimote->state.ext_type == CWIID_EXT_MOTIONPLUS) && 247 | (CWIID_RPT_MOTIONPLUS & ~rpt_mode & wiimote->state.rpt_mode)) { 248 | memset(&wiimote->state.ext, 0, sizeof wiimote->state.ext); 249 | } 250 | 251 | wiimote->state.rpt_mode = rpt_mode; 252 | 253 | if (pthread_mutex_unlock(&wiimote->rpt_mutex)) { 254 | cwiid_err(wiimote, "Mutex unlock error (rpt mutex) - " 255 | "deadlock warning"); 256 | return -1; 257 | } 258 | 259 | return 0; 260 | } 261 | -------------------------------------------------------------------------------- /libcwiid/thread.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2007 L. Donnie Smith 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; either version 2 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 16 | * 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "cwiid_internal.h" 26 | 27 | #define READ_BUF_LEN 23 28 | void *router_thread(struct wiimote *wiimote) 29 | { 30 | unsigned char buf[READ_BUF_LEN]; 31 | ssize_t len; 32 | struct mesg_array ma; 33 | char err, print_clock_err = 1; 34 | 35 | while (1) { 36 | /* Read packet */ 37 | len = read(wiimote->int_socket, buf, READ_BUF_LEN); 38 | ma.count = 0; 39 | if (clock_gettime(CLOCK_REALTIME, &ma.timestamp)) { 40 | if (print_clock_err) { 41 | cwiid_err(wiimote, "clock_gettime error"); 42 | print_clock_err = 0; 43 | } 44 | } 45 | err = 0; 46 | if ((len == -1) || (len == 0)) { 47 | process_error(wiimote, len, &ma); 48 | write_mesg_array(wiimote, &ma); 49 | /* Quit! */ 50 | break; 51 | } 52 | else { 53 | /* Verify first byte (DATA/INPUT) */ 54 | if (buf[0] != (BT_TRANS_DATA | BT_PARAM_INPUT)) { 55 | cwiid_err(wiimote, "Invalid packet type"); 56 | } 57 | 58 | /* Main switch */ 59 | /* printf("%.2X %.2X %.2X %.2X %.2X %.2X %.2X %.2X\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); 60 | printf("%.2X %.2X %.2X %.2X %.2X %.2X %.2X %.2X\n", buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]); 61 | printf("%.2X %.2X %.2X %.2X %.2X %.2X %.2X %.2X\n", buf[16], buf[17], buf[18], buf[19], buf[20], buf[21], buf[22], buf[23]); 62 | printf("\n"); */ 63 | switch (buf[1]) { 64 | case RPT_STATUS: 65 | err = process_status(wiimote, &buf[2], &ma); 66 | break; 67 | case RPT_BTN: 68 | err = process_btn(wiimote, &buf[2], &ma); 69 | break; 70 | case RPT_BTN_ACC: 71 | err = process_btn(wiimote, &buf[2], &ma) || 72 | process_acc(wiimote, &buf[4], &ma); 73 | break; 74 | case RPT_BTN_EXT8: 75 | err = process_btn(wiimote, &buf[2], &ma) || 76 | process_ext(wiimote, &buf[4], 8, &ma); 77 | break; 78 | case RPT_BTN_ACC_IR12: 79 | err = process_btn(wiimote, &buf[2], &ma) || 80 | process_acc(wiimote, &buf[4], &ma) || 81 | process_ir12(wiimote, &buf[7], &ma); 82 | break; 83 | case RPT_BTN_EXT19: 84 | err = process_btn(wiimote, &buf[2], &ma) || 85 | process_ext(wiimote, &buf[4], 19, &ma); 86 | break; 87 | case RPT_BTN_ACC_EXT16: 88 | err = process_btn(wiimote, &buf[2], &ma) || 89 | process_acc(wiimote, &buf[4], &ma) || 90 | process_ext(wiimote, &buf[7], 16, &ma); 91 | break; 92 | case RPT_BTN_IR10_EXT9: 93 | err = process_btn(wiimote, &buf[2], &ma) || 94 | process_ir10(wiimote, &buf[4], &ma) || 95 | process_ext(wiimote, &buf[14], 9, &ma); 96 | break; 97 | case RPT_BTN_ACC_IR10_EXT6: 98 | err = process_btn(wiimote, &buf[2], &ma) || 99 | process_acc(wiimote, &buf[4], &ma) || 100 | process_ir10(wiimote, &buf[7], &ma) || 101 | process_ext(wiimote, &buf[17], 6, &ma); 102 | break; 103 | case RPT_EXT21: 104 | err = process_ext(wiimote, &buf[2], 21, &ma); 105 | break; 106 | case RPT_BTN_ACC_IR36_1: 107 | case RPT_BTN_ACC_IR36_2: 108 | cwiid_err(wiimote, "Unsupported report type received " 109 | "(interleaved data)"); 110 | err = 1; 111 | break; 112 | case RPT_READ_DATA: 113 | err = process_read(wiimote, &buf[4]) || 114 | process_btn(wiimote, &buf[2], &ma); 115 | break; 116 | case RPT_WRITE_ACK: 117 | err = process_write(wiimote, &buf[2]); 118 | break; 119 | default: 120 | cwiid_err(wiimote, "Unknown message type"); 121 | err = 1; 122 | break; 123 | } 124 | 125 | if (!err && (ma.count > 0)) { 126 | if (update_state(wiimote, &ma)) { 127 | cwiid_err(wiimote, "State update error"); 128 | } 129 | if (wiimote->flags & CWIID_FLAG_MESG_IFC) { 130 | /* prints its own errors */ 131 | write_mesg_array(wiimote, &ma); 132 | } 133 | } 134 | } 135 | } 136 | 137 | return NULL; 138 | } 139 | 140 | void *status_thread(struct wiimote *wiimote) 141 | { 142 | struct mesg_array ma; 143 | struct cwiid_status_mesg *status_mesg; 144 | unsigned char buf[2]; 145 | 146 | ma.count = 1; 147 | status_mesg = &ma.array[0].status_mesg; 148 | 149 | while (1) { 150 | if (full_read(wiimote->status_pipe[0], status_mesg, 151 | sizeof *status_mesg)) { 152 | cwiid_err(wiimote, "Pipe read error (status)"); 153 | /* Quit! */ 154 | break; 155 | } 156 | 157 | if (status_mesg->type != CWIID_MESG_STATUS) { 158 | cwiid_err(wiimote, "Bad message on status pipe"); 159 | continue; 160 | } 161 | 162 | if (status_mesg->ext_type == CWIID_EXT_UNKNOWN) { 163 | /* Read extension ID */ 164 | if (cwiid_read(wiimote, CWIID_RW_REG, 0xA400FE, 2, &buf)) { 165 | cwiid_err(wiimote, "Read error (extension error)"); 166 | status_mesg->ext_type = CWIID_EXT_UNKNOWN; 167 | } 168 | /* If the extension didn't change, or if the extension is a 169 | * MotionPlus, no init necessary */ 170 | switch ((buf[0] << 8) | buf[1]) { 171 | case EXT_NONE: 172 | status_mesg->ext_type = CWIID_EXT_NONE; 173 | break; 174 | case EXT_NUNCHUK: 175 | status_mesg->ext_type = CWIID_EXT_NUNCHUK; 176 | break; 177 | case EXT_CLASSIC: 178 | status_mesg->ext_type = CWIID_EXT_CLASSIC; 179 | break; 180 | case EXT_BALANCE: 181 | status_mesg->ext_type = CWIID_EXT_BALANCE; 182 | break; 183 | case EXT_MOTIONPLUS: 184 | status_mesg->ext_type = CWIID_EXT_MOTIONPLUS; 185 | break; 186 | case EXT_PARTIAL: 187 | /* Everything (but MotionPlus) shows up as partial until initialized */ 188 | buf[0] = 0x55; 189 | buf[1] = 0x00; 190 | /* Initialize extension register space */ 191 | if (cwiid_write(wiimote, CWIID_RW_REG, 0xA400F0, 1, &buf[0])) { 192 | cwiid_err(wiimote, "Extension initialization error"); 193 | status_mesg->ext_type = CWIID_EXT_UNKNOWN; 194 | } 195 | else if (cwiid_write(wiimote, CWIID_RW_REG, 0xA400FB, 1, &buf[1])) { 196 | cwiid_err(wiimote, "Extension initialization error"); 197 | status_mesg->ext_type = CWIID_EXT_UNKNOWN; 198 | } 199 | /* Read extension ID */ 200 | else if (cwiid_read(wiimote, CWIID_RW_REG, 0xA400FE, 2, &buf)) { 201 | cwiid_err(wiimote, "Read error (extension error)"); 202 | status_mesg->ext_type = CWIID_EXT_UNKNOWN; 203 | } 204 | else { 205 | switch ((buf[0] << 8) | buf[1]) { 206 | case EXT_NONE: 207 | case EXT_PARTIAL: 208 | status_mesg->ext_type = CWIID_EXT_NONE; 209 | break; 210 | case EXT_NUNCHUK: 211 | status_mesg->ext_type = CWIID_EXT_NUNCHUK; 212 | break; 213 | case EXT_CLASSIC: 214 | status_mesg->ext_type = CWIID_EXT_CLASSIC; 215 | break; 216 | case EXT_BALANCE: 217 | status_mesg->ext_type = CWIID_EXT_BALANCE; 218 | break; 219 | default: 220 | status_mesg->ext_type = CWIID_EXT_UNKNOWN; 221 | break; 222 | } 223 | } 224 | break; 225 | } 226 | } 227 | 228 | if (update_state(wiimote, &ma)) { 229 | cwiid_err(wiimote, "State update error"); 230 | } 231 | if (update_rpt_mode(wiimote, -1)) { 232 | cwiid_err(wiimote, "Error reseting report mode"); 233 | } 234 | if ((wiimote->state.rpt_mode & CWIID_RPT_STATUS) && 235 | (wiimote->flags & CWIID_FLAG_MESG_IFC)) { 236 | if (write_mesg_array(wiimote, &ma)) { 237 | /* prints its own errors */ 238 | } 239 | } 240 | } 241 | 242 | return NULL; 243 | } 244 | 245 | void *mesg_callback_thread(struct wiimote *wiimote) 246 | { 247 | int mesg_pipe = wiimote->mesg_pipe[0]; 248 | cwiid_mesg_callback_t *callback = wiimote->mesg_callback; 249 | struct mesg_array ma; 250 | int cancelstate; 251 | 252 | while (1) { 253 | if (read_mesg_array(mesg_pipe, &ma)) { 254 | cwiid_err(wiimote, "Mesg pipe read error"); 255 | continue; 256 | } 257 | 258 | /* TODO: The callback can still be called once after disconnect, 259 | * although it's very unlikely. User must keep track and avoid 260 | * accessing the wiimote struct after disconnect. */ 261 | if (pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancelstate)) { 262 | cwiid_err(wiimote, "Cancel state disable error (callback thread)"); 263 | } 264 | callback(wiimote, ma.count, ma.array, &ma.timestamp); 265 | if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &cancelstate)) { 266 | cwiid_err(wiimote, "Cancel state restore error (callback thread)"); 267 | } 268 | } 269 | 270 | return NULL; 271 | } 272 | -------------------------------------------------------------------------------- /libcwiid/util.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2007 L. Donnie Smith 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; either version 2 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 16 | * 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include "cwiid_internal.h" 28 | 29 | cwiid_err_t cwiid_err_default; 30 | 31 | static cwiid_err_t *cwiid_err_func = &cwiid_err_default; 32 | 33 | int cwiid_set_err(cwiid_err_t *err) 34 | { 35 | /* TODO: assuming pointer assignment is atomic operation */ 36 | /* if it is, and the user doesn't care about race conditions, we don't 37 | * either */ 38 | cwiid_err_func = err; 39 | return 0; 40 | } 41 | 42 | void cwiid_err_default(struct wiimote *wiimote, const char *str, va_list ap) 43 | { 44 | vfprintf(stderr, str, ap); 45 | fprintf(stderr, "\n"); 46 | } 47 | 48 | void cwiid_err(struct wiimote *wiimote, const char *str, ...) 49 | { 50 | va_list ap; 51 | 52 | if (cwiid_err_func) { 53 | va_start(ap, str); 54 | (*cwiid_err_func)(wiimote, str, ap); 55 | va_end(ap); 56 | } 57 | } 58 | 59 | int verify_handshake(struct wiimote *wiimote) 60 | { 61 | unsigned char handshake; 62 | if (read(wiimote->ctl_socket, &handshake, 1) != 1) { 63 | cwiid_err(wiimote, "Socket read error (handshake)"); 64 | return -1; 65 | } 66 | else if ((handshake & BT_TRANS_MASK) != BT_TRANS_HANDSHAKE) { 67 | cwiid_err(wiimote, "Handshake expected, non-handshake received"); 68 | return -1; 69 | } 70 | else if ((handshake & BT_PARAM_MASK) != BT_PARAM_SUCCESSFUL) { 71 | cwiid_err(wiimote, "Non-successful handshake"); 72 | return -1; 73 | } 74 | 75 | return 0; 76 | } 77 | 78 | int exec_write_seq(struct wiimote *wiimote, unsigned int len, 79 | struct write_seq *seq) 80 | { 81 | unsigned int i; 82 | 83 | for (i=0; i < len; i++) { 84 | switch (seq[i].type) { 85 | case WRITE_SEQ_RPT: 86 | if (cwiid_send_rpt(wiimote, seq[i].flags, seq[i].report_offset, 87 | seq[i].len, seq[i].data)) { 88 | return -1; 89 | } 90 | break; 91 | case WRITE_SEQ_MEM: 92 | if (cwiid_write(wiimote, seq[i].flags, seq[i].report_offset, 93 | seq[i].len, seq[i].data)) { 94 | return -1; 95 | } 96 | break; 97 | } 98 | } 99 | 100 | return 0; 101 | } 102 | 103 | int full_read(int fd, void *buf, size_t len) 104 | { 105 | ssize_t last_len = 0; 106 | 107 | do { 108 | if ((last_len = read(fd, buf, len)) == -1) { 109 | return -1; 110 | } 111 | len -= last_len; 112 | buf += last_len; 113 | } while (len > 0); 114 | 115 | return 0; 116 | } 117 | 118 | int write_mesg_array(struct wiimote *wiimote, struct mesg_array *ma) 119 | { 120 | ssize_t len = (void *)&ma->array[ma->count] - (void *)ma; 121 | int ret = 0; 122 | 123 | /* This must remain a single write operation to ensure atomicity, 124 | * which is required to avoid mutexes and cancellation issues */ 125 | if (write(wiimote->mesg_pipe[1], ma, len) != len) { 126 | if (errno == EAGAIN) { 127 | cwiid_err(wiimote, "Mesg pipe overflow"); 128 | if (fcntl(wiimote->mesg_pipe[1], F_SETFL, 0)) { 129 | cwiid_err(wiimote, "File control error (mesg pipe)"); 130 | ret = -1; 131 | } 132 | else { 133 | if (write(wiimote->mesg_pipe[1], ma, len) != len) { 134 | cwiid_err(wiimote, "Pipe write error (mesg pipe)"); 135 | ret = -1; 136 | } 137 | if (fcntl(wiimote->mesg_pipe[1], F_SETFL, O_NONBLOCK)) { 138 | cwiid_err(wiimote, "File control error (mesg pipe"); 139 | } 140 | } 141 | } 142 | else { 143 | cwiid_err(wiimote, "Pipe write error (mesg pipe)"); 144 | ret = -1; 145 | } 146 | } 147 | 148 | return ret; 149 | } 150 | 151 | int read_mesg_array(int fd, struct mesg_array *ma) 152 | { 153 | ssize_t len; 154 | 155 | len = (void *)&ma->array[0] - (void *)ma; 156 | if (full_read(fd, ma, len)) { 157 | return -1; 158 | } 159 | 160 | len = ma->count * sizeof ma->array[0]; 161 | if (full_read(fd, &ma->array[0], len)) { 162 | return -1; 163 | } 164 | 165 | return 0; 166 | } 167 | 168 | int cancel_rw(struct wiimote *wiimote) 169 | { 170 | struct rw_mesg rw_mesg; 171 | 172 | rw_mesg.type = RW_CANCEL; 173 | 174 | if (write(wiimote->rw_pipe[1], &rw_mesg, sizeof rw_mesg) != 175 | sizeof rw_mesg) { 176 | cwiid_err(wiimote, "Pipe write error (rw)"); 177 | return -1; 178 | } 179 | 180 | return 0; 181 | } 182 | 183 | int cancel_mesg_callback(struct wiimote *wiimote) 184 | { 185 | int ret = 0; 186 | 187 | if (pthread_cancel(wiimote->mesg_callback_thread)) { 188 | cwiid_err(wiimote, "Thread cancel error (callback thread)"); 189 | ret = -1; 190 | } 191 | 192 | if (pthread_detach(wiimote->mesg_callback_thread)) { 193 | cwiid_err(wiimote, "Thread detach error (callback thread)"); 194 | ret = -1; 195 | } 196 | 197 | return ret; 198 | } 199 | -------------------------------------------------------------------------------- /python/Makefile.in: -------------------------------------------------------------------------------- 1 | #Copyright (C) 2007 Justin M. Tulloss 2 | 3 | include @top_builddir@/defs.mak 4 | 5 | ifdef ROOTDIR 6 | SET_ROOT_DIR = "--root=$(ROOTDIR)" 7 | endif 8 | 9 | all: 10 | $(PYTHON) setup.py build_ext $(DEBUGFLAGS) -I@top_builddir@/libcwiid -L@top_builddir@/libcwiid 11 | 12 | install: 13 | $(PYTHON) setup.py install --record installed_files.txt 14 | 15 | uninstall: 16 | cat installed_files.txt | xargs rm -rf 17 | 18 | clean: 19 | rm -rf build 20 | 21 | distclean: clean 22 | rm Makefile 23 | 24 | .PHONY: all install uninstall clean distclean 25 | -------------------------------------------------------------------------------- /python/Wiimote.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2007 Justin M. Tulloss , L. Donnie Smith 3 | * 4 | * Interface from Python to libcwiid 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 | * Boston, MA 02110-1301 USA 20 | * 21 | */ 22 | 23 | #include "Python.h" 24 | #include "structmember.h" 25 | #include 26 | #include 27 | #include 28 | 29 | typedef struct { 30 | PyObject_HEAD 31 | cwiid_wiimote_t *wiimote; 32 | PyObject *callback; 33 | char close_on_dealloc; 34 | } Wiimote; 35 | 36 | /* method prototypes */ 37 | static PyObject * 38 | Wiimote_new(PyTypeObject *type, PyObject *args, PyObject *kwds); 39 | static void Wiimote_dealloc(Wiimote *self); 40 | static int Wiimote_init(Wiimote *self, PyObject *args, PyObject *kwds); 41 | static PyObject *Wiimote_close(Wiimote *self); 42 | 43 | static PyObject *Wiimote_enable(Wiimote *self, PyObject *args, PyObject *kwds); 44 | static PyObject * 45 | Wiimote_disable(Wiimote *self, PyObject *args, PyObject *kwds); 46 | 47 | static int 48 | Wiimote_set_mesg_callback(Wiimote *self, PyObject *args, void *closure); 49 | static PyObject *Wiimote_get_mesg(Wiimote *self); 50 | static PyObject *Wiimote_get_state(Wiimote *self, void *closure); 51 | static PyObject *Wiimote_get_acc_cal(Wiimote *self, PyObject *args, 52 | PyObject *kwds); 53 | static PyObject *Wiimote_get_balance_cal(Wiimote *self); 54 | 55 | static PyObject *Wiimote_request_status(Wiimote *self); 56 | static int Wiimote_set_led(Wiimote *self, PyObject *PyLed, void *closure); 57 | static int 58 | Wiimote_set_rumble(Wiimote *self, PyObject *PyRumble, void *closure); 59 | static int 60 | Wiimote_set_rpt_mode(Wiimote *self, PyObject *PyRptMode, void *closure); 61 | 62 | static PyObject *Wiimote_send_rpt(Wiimote *self, PyObject *args, PyObject *kwds); 63 | static PyObject *Wiimote_read(Wiimote *self, PyObject *args, PyObject *kwds); 64 | static PyObject *Wiimote_write(Wiimote *self, PyObject *args, PyObject *kwds); 65 | 66 | /* helper prototypes */ 67 | static cwiid_mesg_callback_t CallbackBridge; 68 | PyObject *ConvertMesgArray(int mesg_count, union cwiid_mesg mesg[]); 69 | 70 | static PyMethodDef Wiimote_Methods[] = 71 | { 72 | {"close", (PyCFunction)Wiimote_close, METH_NOARGS, 73 | "close()\n\nClose the Wiimote connection"}, 74 | {"enable", (PyCFunction)Wiimote_enable, METH_VARARGS | METH_KEYWORDS, 75 | "enable(flags)\n\nenable Wiimote connection flags"}, 76 | {"disable", (PyCFunction)Wiimote_disable, METH_VARARGS | METH_KEYWORDS, 77 | "disable(flags)\n\ndisable Wiimote connection flags"}, 78 | {"get_mesg", (PyCFunction)Wiimote_get_mesg, METH_NOARGS, 79 | "get_mesg() -> message list\n\nretrieve message list from queue"}, 80 | {"get_acc_cal", (PyCFunction)Wiimote_get_acc_cal, 81 | METH_VARARGS | METH_KEYWORDS, 82 | "get_acc_cal(extension) -> calibration tuple\n\n" 83 | "retrieve accelerometer calibration information"}, 84 | {"get_balance_cal", (PyCFunction)Wiimote_get_balance_cal, METH_NOARGS, 85 | "get_balance_cal() -> calibration tuple\n\n" 86 | "retrieve Balance Board calibration information"}, 87 | {"request_status", (PyCFunction)Wiimote_request_status, METH_NOARGS, 88 | "request_status()\n\nrequest status message"}, 89 | {"read", (PyCFunction)Wiimote_read, METH_VARARGS | METH_KEYWORDS, 90 | "read(flags,offset,len) -> buffer\n\nread data from Wiimote"}, 91 | {"send_rpt", (PyCFunction)Wiimote_send_rpt, METH_VARARGS | METH_KEYWORDS, 92 | "send_rpt(flags,report,buffer)\n\nsend a report to Wiimote"}, 93 | {"write", (PyCFunction)Wiimote_write, METH_VARARGS | METH_KEYWORDS, 94 | "write(flags,offset,buffer)\n\nwrite data to Wiimote"}, 95 | {NULL, NULL, 0, NULL} 96 | }; 97 | 98 | static PyGetSetDef Wiimote_GetSet[] = { 99 | {"state", (getter)Wiimote_get_state, NULL, "Wiimote state", NULL}, 100 | {"mesg_callback", NULL, (setter)Wiimote_set_mesg_callback, 101 | "Wiimote message callback", NULL}, 102 | {"led", NULL, (setter)Wiimote_set_led, "Wiimote led state", NULL}, 103 | {"rumble", NULL, (setter)Wiimote_set_rumble, "Wiimote rumble state", NULL}, 104 | {"rpt_mode", NULL, (setter)Wiimote_set_rpt_mode, "Wiimote report mode", 105 | NULL}, 106 | {NULL, NULL, NULL, NULL, NULL} 107 | }; 108 | 109 | PyTypeObject Wiimote_Type = { 110 | PyVarObject_HEAD_INIT(NULL, 0) 111 | "cwiid.Wiimote", /* tp_name */ 112 | sizeof(Wiimote), /* tp_basicsize */ 113 | 0, /* tp_itemsize */ 114 | (destructor)Wiimote_dealloc, /* tp_dealloc */ 115 | 0, /* tp_print */ 116 | 0, /* tp_getattr */ 117 | 0, /* tp_setattr */ 118 | 0, /* tp_compare */ 119 | 0, /* tp_repr */ 120 | 0, /* tp_as_number */ 121 | 0, /* tp_as_sequence */ 122 | 0, /* tp_as_mapping */ 123 | 0, /* tp_hash */ 124 | 0, /* tp_call */ 125 | 0, /* tp_str */ 126 | 0, /* tp_getattro */ 127 | 0, /* tp_setattro */ 128 | 0, /* tp_as_buffer */ 129 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ 130 | "CWiid Wiimote connection object", /* tp_doc */ 131 | 0, /* tp_traverse */ 132 | 0, /* tp_clear */ 133 | 0, /* tp_richcompare */ 134 | 0, /* tp_weaklistoffset */ 135 | 0, /* tp_iter */ 136 | 0, /* tp_iternext */ 137 | Wiimote_Methods, /* tp_methods */ 138 | 0, /* tp_members */ 139 | Wiimote_GetSet, /* tp_getset */ 140 | 0, /* tp_base */ 141 | 0, /* tp_dict */ 142 | 0, /* tp_descr_get */ 143 | 0, /* tp_descr_set */ 144 | 0, /* tp_dictoffset */ 145 | (initproc)Wiimote_init, /* tp_init */ 146 | 0, /* tp_alloc */ 147 | Wiimote_new, /* tp_new */ 148 | }; 149 | 150 | /* Allocate and deallocate functions */ 151 | static PyObject * 152 | Wiimote_new(PyTypeObject *type, PyObject *args, PyObject *kwds) 153 | { 154 | Wiimote* self; 155 | 156 | if (!(self = (Wiimote *) type->tp_alloc(type, 0))) { 157 | return NULL; 158 | } 159 | 160 | self->wiimote = NULL; 161 | self->close_on_dealloc = 0; 162 | 163 | return (PyObject*) self; 164 | } 165 | 166 | static void Wiimote_dealloc(Wiimote *self) 167 | { 168 | if (self->close_on_dealloc && self->wiimote) { 169 | cwiid_close(self->wiimote); 170 | } 171 | Py_XDECREF(self->callback); 172 | //self->ob_type->tp_free((PyObject *)self); 173 | Py_TYPE(self)->tp_free((PyObject *)self); 174 | } 175 | 176 | static int Wiimote_init(Wiimote* self, PyObject* args, PyObject *kwds) 177 | { 178 | static char *kwlist[] = {"bdaddr", "flags", NULL}; 179 | PyObject *PyObj; 180 | cwiid_wiimote_t *wiimote = NULL; 181 | char *str_bdaddr = NULL; 182 | bdaddr_t bdaddr; 183 | int flags = 0; 184 | 185 | /* Overloaded function - if a single CObject is passed in, it's 186 | * an existing CObject. Otherwise, create a new one */ 187 | if (PyTuple_Size(args) == 1) { 188 | PyObj = PyTuple_GET_ITEM(args, 0); 189 | if (PyCapsule_CheckExact(PyObj)) { 190 | wiimote = PyCapsule_GetPointer(PyObj, "dynamr"); 191 | self->close_on_dealloc = 0; 192 | } 193 | } 194 | 195 | if (!wiimote) { 196 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "|si:cwiid.Wiimote.init", 197 | kwlist, &str_bdaddr, &flags)) { 198 | return -1; 199 | } 200 | 201 | if (str_bdaddr) { 202 | if (str2ba(str_bdaddr, &bdaddr)) { 203 | PyErr_SetString(PyExc_ValueError, "bad bdaddr"); 204 | return -1; 205 | } 206 | } 207 | else { 208 | bdaddr = *BDADDR_ANY; 209 | } 210 | 211 | if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION == 5) { 212 | PyEval_InitThreads(); 213 | } 214 | 215 | Py_BEGIN_ALLOW_THREADS 216 | wiimote = cwiid_open(&bdaddr, flags); 217 | Py_END_ALLOW_THREADS 218 | if (!wiimote) { 219 | PyErr_SetString(PyExc_RuntimeError, 220 | "Error opening wiimote connection"); 221 | return -1; 222 | } 223 | else { 224 | self->close_on_dealloc = 1; 225 | } 226 | } 227 | 228 | cwiid_set_data(wiimote, self); 229 | Py_INCREF(self->callback = Py_None); 230 | self->wiimote = wiimote; 231 | return 0; 232 | } 233 | 234 | #define SET_CLOSED_ERROR PyErr_SetString(PyExc_ValueError, "Wiimote is closed") 235 | 236 | static PyObject *Wiimote_close(Wiimote *self) 237 | { 238 | if (!self->wiimote) { 239 | SET_CLOSED_ERROR; 240 | return NULL; 241 | } 242 | 243 | if (cwiid_close(self->wiimote)) { 244 | PyErr_SetString(PyExc_RuntimeError, 245 | "Error closing wiimote connection"); 246 | self->wiimote = NULL; 247 | return NULL; 248 | } 249 | self->wiimote = NULL; 250 | 251 | Py_RETURN_NONE; 252 | } 253 | 254 | static PyObject *Wiimote_enable(Wiimote *self, PyObject *args, PyObject *kwds) 255 | { 256 | static char *kwlist[] = {"flags", NULL}; 257 | int flags; 258 | 259 | if (!self->wiimote) { 260 | SET_CLOSED_ERROR; 261 | return NULL; 262 | } 263 | 264 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:cwiid.Wiimote.enable", 265 | kwlist, &flags)) { 266 | return NULL; 267 | } 268 | 269 | if (cwiid_enable(self->wiimote, flags)) { 270 | PyErr_SetString(PyExc_RuntimeError, "Error enabling wiimote flags"); 271 | return NULL; 272 | } 273 | 274 | Py_RETURN_NONE; 275 | } 276 | 277 | static PyObject *Wiimote_disable(Wiimote *self, PyObject *args, PyObject *kwds) 278 | { 279 | static char *kwlist[] = {"flags", NULL}; 280 | int flags; 281 | 282 | if (!self->wiimote) { 283 | SET_CLOSED_ERROR; 284 | return NULL; 285 | } 286 | 287 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:cwiid.Wiimote.disable", 288 | kwlist, &flags)) { 289 | return NULL; 290 | } 291 | 292 | if (cwiid_disable(self->wiimote, flags)) { 293 | PyErr_SetString(PyExc_RuntimeError, "Error disabling wiimote flags"); 294 | return NULL; 295 | } 296 | 297 | Py_RETURN_NONE; 298 | } 299 | 300 | static int 301 | Wiimote_set_mesg_callback(Wiimote *self, PyObject *NewCallback, 302 | void *closure) 303 | { 304 | PyObject *OldCallback; 305 | 306 | if (!self->wiimote) { 307 | SET_CLOSED_ERROR; 308 | return -1; 309 | } 310 | 311 | if (!PyCallable_Check(NewCallback)) { 312 | PyErr_SetString(PyExc_TypeError, "callback must be callable!"); 313 | } 314 | OldCallback = self->callback; 315 | 316 | if ((OldCallback == Py_None) && (NewCallback != Py_None)) { 317 | if (cwiid_set_mesg_callback(self->wiimote, CallbackBridge)) { 318 | PyErr_SetString(PyExc_AttributeError, 319 | "Error setting wiimote callback"); 320 | return -1; 321 | } 322 | } 323 | else if ((OldCallback != Py_None) && (NewCallback == Py_None)) { 324 | if (cwiid_set_mesg_callback(self->wiimote, NULL)) { 325 | PyErr_SetString(PyExc_AttributeError, 326 | "Error clearing wiimote callback"); 327 | return -1; 328 | } 329 | } 330 | 331 | Py_INCREF(NewCallback); 332 | Py_DECREF(OldCallback); 333 | 334 | self->callback = NewCallback; 335 | 336 | return 0; 337 | } 338 | 339 | static PyObject *Wiimote_get_mesg(Wiimote *self) 340 | { 341 | union cwiid_mesg *mesg; 342 | int mesg_count; 343 | struct timespec t; 344 | PyObject *PyMesg; 345 | 346 | if (!self->wiimote) { 347 | SET_CLOSED_ERROR; 348 | return NULL; 349 | } 350 | 351 | if (cwiid_get_mesg(self->wiimote, &mesg_count, &mesg, &t)) { 352 | if (errno == EAGAIN) { 353 | Py_RETURN_NONE; 354 | } 355 | else { 356 | PyErr_SetString(PyExc_RuntimeError, 357 | "Error getting wiimote message list"); 358 | return NULL; 359 | } 360 | } 361 | 362 | PyMesg = ConvertMesgArray(mesg_count, mesg); 363 | 364 | free(mesg); 365 | 366 | return PyMesg; 367 | } 368 | 369 | static PyObject *Wiimote_get_state(Wiimote* self, void *closure) 370 | { 371 | struct cwiid_state state; 372 | PyObject *PyState; 373 | 374 | if (!self->wiimote) { 375 | SET_CLOSED_ERROR; 376 | return NULL; 377 | } 378 | 379 | if (cwiid_get_state(self->wiimote, &state)) { 380 | PyErr_SetString(PyExc_IOError, "get state error"); 381 | return NULL; 382 | } 383 | 384 | PyState = Py_BuildValue("{s:B,s:B,s:B,s:B,s:i,s:i}", 385 | "rpt_mode", state.rpt_mode, 386 | "led", state.led, 387 | "rumble", state.rumble, 388 | "battery", state.battery, 389 | "ext_type", state.ext_type, 390 | "error", state.error); 391 | 392 | if (state.rpt_mode & CWIID_RPT_BTN) { 393 | PyObject *PyBtn = Py_BuildValue("I", state.buttons); 394 | if (!PyBtn) { 395 | Py_DECREF(PyState); 396 | return NULL; 397 | } 398 | if (PyDict_SetItemString(PyState, "buttons", PyBtn)) { 399 | Py_DECREF(PyState); 400 | Py_DECREF(PyBtn); 401 | return NULL; 402 | } 403 | Py_DECREF(PyBtn); 404 | } 405 | 406 | if (state.rpt_mode & CWIID_RPT_ACC) { 407 | PyObject *PyAcc = Py_BuildValue("(B,B,B)", 408 | state.acc[CWIID_X], 409 | state.acc[CWIID_Y], 410 | state.acc[CWIID_Z]); 411 | if (!PyAcc) { 412 | Py_DECREF(PyState); 413 | return NULL; 414 | } 415 | if (PyDict_SetItemString(PyState, "acc", PyAcc)) { 416 | Py_DECREF(PyState); 417 | Py_DECREF(PyAcc); 418 | return NULL; 419 | } 420 | Py_DECREF(PyAcc); 421 | } 422 | 423 | if (state.rpt_mode & CWIID_RPT_IR) { 424 | int i; 425 | PyObject *PyIr = PyList_New(CWIID_IR_SRC_COUNT); 426 | 427 | if (!PyIr) { 428 | Py_DECREF(PyState); 429 | return NULL; 430 | } 431 | 432 | if (PyDict_SetItemString(PyState, "ir_src", PyIr)) { 433 | Py_DECREF(PyState); 434 | Py_DECREF(PyIr); 435 | return NULL; 436 | } 437 | 438 | Py_DECREF(PyIr); 439 | 440 | for (i=0; i < CWIID_IR_SRC_COUNT; i++) { 441 | PyObject *PyIrSrc; 442 | PyObject *PySize; 443 | 444 | if (state.ir_src[i].valid) { 445 | PyIrSrc = Py_BuildValue("{s:(I,I)}", 446 | "pos", 447 | state.ir_src[i].pos[CWIID_X], 448 | state.ir_src[i].pos[CWIID_Y]); 449 | if (!PyIrSrc) { 450 | Py_DECREF(PyState); 451 | return NULL; 452 | } 453 | 454 | if (state.ir_src[i].size != -1) { 455 | if (!(PySize = PyLong_FromLong( 456 | (long)state.ir_src[i].size))) { 457 | Py_DECREF(PyState); 458 | Py_DECREF(PyIrSrc); 459 | return NULL; 460 | } 461 | if (PyDict_SetItemString(PyIrSrc, "size", PySize)) { 462 | Py_DECREF(PyState); 463 | Py_DECREF(PyIrSrc); 464 | Py_DECREF(PySize); 465 | return NULL; 466 | } 467 | 468 | Py_DECREF(PySize); 469 | } 470 | } 471 | else { 472 | Py_INCREF(PyIrSrc = Py_None); 473 | } 474 | 475 | PyList_SET_ITEM(PyIr, i, PyIrSrc); 476 | } 477 | } 478 | 479 | switch (state.ext_type) { 480 | PyObject *PyExt; 481 | case CWIID_EXT_NUNCHUK: 482 | if (state.rpt_mode & CWIID_RPT_NUNCHUK) { 483 | PyExt = Py_BuildValue("{s:(B,B),s:(B,B,B),s:I}", 484 | "stick", 485 | state.ext.nunchuk.stick[CWIID_X], 486 | state.ext.nunchuk.stick[CWIID_Y], 487 | "acc", 488 | state.ext.nunchuk.acc[CWIID_X], 489 | state.ext.nunchuk.acc[CWIID_Y], 490 | state.ext.nunchuk.acc[CWIID_Z], 491 | "buttons", state.ext.nunchuk.buttons); 492 | 493 | if (!PyExt) { 494 | Py_DECREF(PyState); 495 | return NULL; 496 | } 497 | 498 | if (PyDict_SetItemString(PyState, "nunchuk", PyExt)) { 499 | Py_DECREF(PyState); 500 | Py_DECREF(PyExt); 501 | return NULL; 502 | } 503 | 504 | Py_DECREF(PyExt); 505 | } 506 | break; 507 | case CWIID_EXT_CLASSIC: 508 | if (state.rpt_mode & CWIID_RPT_CLASSIC) { 509 | PyExt = Py_BuildValue("{s:(B,B),s:(B,B),s:B,s:B,s:I}", 510 | "l_stick", 511 | state.ext.classic.l_stick[CWIID_X], 512 | state.ext.classic.l_stick[CWIID_Y], 513 | "r_stick", 514 | state.ext.classic.r_stick[CWIID_X], 515 | state.ext.classic.r_stick[CWIID_Y], 516 | "l", state.ext.classic.l, 517 | "r", state.ext.classic.r, 518 | "buttons", state.ext.classic.buttons); 519 | 520 | if (!PyExt) { 521 | Py_DECREF(PyState); 522 | return NULL; 523 | } 524 | 525 | if (PyDict_SetItemString(PyState, "classic", PyExt)) { 526 | Py_DECREF(PyState); 527 | Py_DECREF(PyExt); 528 | return NULL; 529 | } 530 | 531 | Py_DECREF(PyExt); 532 | } 533 | break; 534 | case CWIID_EXT_BALANCE: 535 | if (state.rpt_mode & CWIID_RPT_BALANCE) { 536 | PyExt = Py_BuildValue("{s:I,s:I,s:I,s:I}", 537 | "right_top", 538 | state.ext.balance.right_top, 539 | "right_bottom", 540 | state.ext.balance.right_bottom, 541 | "left_top", 542 | state.ext.balance.left_top, 543 | "left_bottom", 544 | state.ext.balance.left_bottom); 545 | 546 | if (!PyExt) { 547 | Py_DECREF(PyState); 548 | return NULL; 549 | } 550 | 551 | if (PyDict_SetItemString(PyState, "balance", PyExt)) { 552 | Py_DECREF(PyState); 553 | Py_DECREF(PyExt); 554 | return NULL; 555 | } 556 | 557 | Py_DECREF(PyExt); 558 | } 559 | break; 560 | case CWIID_EXT_MOTIONPLUS: 561 | if (state.rpt_mode & CWIID_RPT_MOTIONPLUS) { 562 | PyExt = Py_BuildValue("{s:(I,I,I),s:(I,I,I)}", 563 | "angle_rate", 564 | state.ext.motionplus.angle_rate[CWIID_PHI], 565 | state.ext.motionplus.angle_rate[CWIID_THETA], 566 | state.ext.motionplus.angle_rate[CWIID_PSI], 567 | "low_speed", 568 | state.ext.motionplus.low_speed[CWIID_PHI], 569 | state.ext.motionplus.low_speed[CWIID_THETA], 570 | state.ext.motionplus.low_speed[CWIID_PSI]); 571 | 572 | if (!PyExt) { 573 | Py_DECREF(PyState); 574 | return NULL; 575 | } 576 | 577 | if (PyDict_SetItemString(PyState, "motionplus", PyExt)) { 578 | Py_DECREF(PyState); 579 | Py_DECREF(PyExt); 580 | return NULL; 581 | } 582 | 583 | Py_DECREF(PyExt); 584 | } 585 | break; 586 | default: 587 | break; 588 | } 589 | 590 | return PyState; 591 | } 592 | 593 | static PyObject *Wiimote_get_acc_cal(Wiimote *self, PyObject *args, 594 | PyObject *kwds) 595 | { 596 | static char *kwlist[] = { "ext_type", NULL }; 597 | int ext_type; 598 | struct acc_cal acc_cal; 599 | PyObject *PyAccCal; 600 | 601 | if (!self->wiimote) { 602 | SET_CLOSED_ERROR; 603 | return NULL; 604 | } 605 | 606 | if (!PyArg_ParseTupleAndKeywords(args, kwds, 607 | "i:cwiid.Wiimote.get_acc_cal", kwlist, 608 | &ext_type)) { 609 | return NULL; 610 | } 611 | 612 | if (cwiid_get_acc_cal(self->wiimote, ext_type, &acc_cal)) { 613 | PyErr_SetString(PyExc_RuntimeError, 614 | "Error getting wiimote acc calibration"); 615 | return NULL; 616 | } 617 | 618 | if (!(PyAccCal = Py_BuildValue("([i,i,i],[i,i,i])", acc_cal.zero[0], 619 | acc_cal.zero[1], acc_cal.zero[2], 620 | acc_cal.one[0], acc_cal.one[1], 621 | acc_cal.one[2]))) { 622 | return NULL; 623 | } 624 | 625 | return PyAccCal; 626 | } 627 | 628 | static PyObject *Wiimote_get_balance_cal(Wiimote *self) 629 | { 630 | struct balance_cal balance_cal; 631 | PyObject *PyBalCal; 632 | 633 | if (cwiid_get_balance_cal(self->wiimote, &balance_cal)) { 634 | PyErr_SetString(PyExc_RuntimeError, 635 | "Error getting balance board calibration"); 636 | return NULL; 637 | } 638 | 639 | if (!(PyBalCal = Py_BuildValue("([i,i,i],[i,i,i],[i,i,i],[i,i,i])", 640 | balance_cal.right_top[0], 641 | balance_cal.right_top[1], 642 | balance_cal.right_top[2], 643 | balance_cal.right_bottom[0], 644 | balance_cal.right_bottom[1], 645 | balance_cal.right_bottom[2], 646 | balance_cal.left_top[0], 647 | balance_cal.left_top[1], 648 | balance_cal.left_top[2], 649 | balance_cal.left_bottom[0], 650 | balance_cal.left_bottom[1], 651 | balance_cal.left_bottom[2]))) { 652 | return NULL; 653 | } 654 | 655 | return PyBalCal; 656 | } 657 | 658 | static PyObject *Wiimote_request_status(Wiimote *self) 659 | { 660 | if (!self->wiimote) { 661 | SET_CLOSED_ERROR; 662 | return NULL; 663 | } 664 | 665 | if (cwiid_request_status(self->wiimote)) { 666 | PyErr_SetString(PyExc_RuntimeError, "Error requesting wiimote status"); 667 | return NULL; 668 | } 669 | 670 | Py_RETURN_NONE; 671 | } 672 | 673 | static int Wiimote_set_led(Wiimote *self, PyObject *PyLed, void *closure) 674 | { 675 | long led; 676 | 677 | if (!self->wiimote) { 678 | SET_CLOSED_ERROR; 679 | return -1; 680 | } 681 | 682 | if (((led = PyLong_AsLong(PyLed)) == -1) && PyErr_Occurred()) { 683 | return -1; 684 | } 685 | 686 | if (cwiid_set_led(self->wiimote, (uint8_t)led)) { 687 | PyErr_SetString(PyExc_AttributeError, 688 | "Error setting wiimote led state"); 689 | return -1; 690 | } 691 | 692 | return 0; 693 | } 694 | 695 | static int 696 | Wiimote_set_rumble(Wiimote *self, PyObject *PyRumble, void *closure) 697 | { 698 | long rumble; 699 | 700 | if (!self->wiimote) { 701 | SET_CLOSED_ERROR; 702 | return -1; 703 | } 704 | 705 | if (((rumble = PyLong_AsLong(PyRumble)) == -1) && PyErr_Occurred()) { 706 | return -1; 707 | } 708 | 709 | if (cwiid_set_rumble(self->wiimote, (uint8_t)rumble)) { 710 | PyErr_SetString(PyExc_AttributeError, 711 | "Error setting wiimote rumble state"); 712 | return -1; 713 | } 714 | 715 | return 0; 716 | } 717 | 718 | static int 719 | Wiimote_set_rpt_mode(Wiimote *self, PyObject *PyRptMode, void *closure) 720 | { 721 | long rpt_mode; 722 | 723 | if (!self->wiimote) { 724 | SET_CLOSED_ERROR; 725 | return -1; 726 | } 727 | 728 | if (((rpt_mode = PyLong_AsLong(PyRptMode)) == -1) && PyErr_Occurred()) { 729 | return -1; 730 | } 731 | 732 | if (cwiid_set_rpt_mode(self->wiimote, (uint8_t)rpt_mode)) { 733 | PyErr_SetString(PyExc_AttributeError, 734 | "Error setting wiimote report mode"); 735 | return -1; 736 | } 737 | 738 | return 0; 739 | } 740 | 741 | /* static PyObject *Wiimote_command(Wiimote *self, PyObject *args, PyObject *kwds) 742 | { 743 | static char *kwlist[] = { "command", "flags", NULL }; 744 | int command, flags; 745 | 746 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "ii", kwlist, &command, 747 | &flags)) { 748 | return NULL; 749 | } 750 | 751 | cwiid_command(self->wiimote, (enum cwiid_command)command, (uint8_t)flags); 752 | 753 | Py_RETURN_NONE; 754 | } 755 | */ 756 | 757 | static PyObject *Wiimote_send_rpt(Wiimote *self, PyObject *args, PyObject *kwds) 758 | { 759 | static char *kwlist[] = { "flags", "report", "buffer", NULL }; 760 | unsigned char flags, report; 761 | void *buf; 762 | int len; 763 | 764 | if (!self->wiimote) { 765 | SET_CLOSED_ERROR; 766 | return NULL; 767 | } 768 | 769 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "BBt#:cwiid.Wiimote.send_rpt", 770 | kwlist, &flags, &report, &buf, &len)) { 771 | return NULL; 772 | } 773 | 774 | if (cwiid_send_rpt(self->wiimote, flags, report, len, buf)) { 775 | PyErr_SetString(PyExc_RuntimeError, "Error sending report"); 776 | return NULL; 777 | } 778 | 779 | Py_RETURN_NONE; 780 | } 781 | 782 | static PyObject *Wiimote_read(Wiimote *self, PyObject *args, PyObject *kwds) 783 | { 784 | static char *kwlist[] = { "flags", "offset", "len", NULL }; 785 | unsigned char flags; 786 | unsigned int offset; 787 | Py_ssize_t len; 788 | void *buf; 789 | PyObject *pyRetBuf; 790 | 791 | if (!self->wiimote) { 792 | SET_CLOSED_ERROR; 793 | return NULL; 794 | } 795 | 796 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "BII:cwiid.Wiimote.read", 797 | kwlist, &flags, &offset, &len)) { 798 | return NULL; 799 | } 800 | 801 | if (!(pyRetBuf = malloc(len))) { 802 | return NULL; 803 | } 804 | if (PyObject_AsWriteBuffer(pyRetBuf, &buf, &len)) { 805 | Py_DECREF(pyRetBuf); 806 | return NULL; 807 | } 808 | if (cwiid_read(self->wiimote,flags,offset,len,buf)) { 809 | PyErr_SetString(PyExc_RuntimeError, "Error reading wiimote data"); 810 | Py_DECREF(pyRetBuf); 811 | return NULL; 812 | } 813 | 814 | return pyRetBuf; 815 | } 816 | 817 | static PyObject *Wiimote_write(Wiimote *self, PyObject *args, PyObject *kwds) 818 | { 819 | static char *kwlist[] = { "flags", "offset", "buffer", NULL }; 820 | unsigned char flags; 821 | unsigned int offset; 822 | void *buf; 823 | int len; 824 | 825 | if (!self->wiimote) { 826 | SET_CLOSED_ERROR; 827 | return NULL; 828 | } 829 | 830 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "BIt#:cwiid.Wiimote.write", 831 | kwlist, &flags, &offset, &buf, &len)) { 832 | return NULL; 833 | } 834 | 835 | if (cwiid_write(self->wiimote, flags, offset, len, buf)) { 836 | PyErr_SetString(PyExc_RuntimeError, "Error writing wiimote data"); 837 | return NULL; 838 | } 839 | 840 | Py_RETURN_NONE; 841 | } 842 | 843 | static void CallbackBridge(cwiid_wiimote_t *wiimote, int mesg_count, 844 | union cwiid_mesg mesg[], struct timespec *t) 845 | { 846 | PyObject *ArgTuple; 847 | PyObject *PySelf; 848 | PyGILState_STATE gstate; 849 | 850 | gstate = PyGILState_Ensure(); 851 | 852 | ArgTuple = ConvertMesgArray(mesg_count, mesg); 853 | 854 | /* Put id and the list of messages as the arguments to the callback */ 855 | PySelf = (PyObject *) cwiid_get_data(wiimote); 856 | if (!PyObject_CallFunction(((Wiimote *)PySelf)->callback, "(O, d)", 857 | ArgTuple, 858 | t->tv_sec + ((double) t->tv_nsec) * 1e-9)) { 859 | PyErr_Print(); 860 | } 861 | 862 | Py_XDECREF(ArgTuple); 863 | PyGILState_Release(gstate); 864 | } 865 | 866 | /* This is the function responsible for marshaling the cwiid messages from 867 | * C to python. It's rather complicated since it uses a complex C union 868 | * to store the data and multiple enumerations to figure out what data is 869 | * actually being sent. Neither of these common C types really translate 870 | * well into Python. I've done my best to translate it to python as follows: 871 | * 872 | * Python callback takes arg (mesgs). The mesgs is a list of 873 | * mesg tuples which contain the mesg type and a dict of the arguments. 874 | * 875 | * Ex: 876 | * mesgs =>[(cwiid.STATUS_MESG,{"battery":battery,"ext_type":ext_type}), 877 | * (cwiid.BTN_MESG,buttons), 878 | * (cwiid.ACC_MESG,(x,y,z)), 879 | * (cwiid.IR_MESG,[{"pos":(x,y),"size":size}, ...]), 880 | * (cwiid.NUNCHUK_MESG,{"stick":(x,y),"acc":(x,y,z), 881 | * "buttons":buttons}, 882 | * (cwiid.CLASSIC_MESG,{"l_stick":(x,y),"r_stick":(x,y),"l":l,"r":r, 883 | * "buttons":buttons}, 884 | * (cwiid.BALANCE_MESG,{"right_top":right_top, 885 | * "right_bottom":right_bottom, 886 | * "left_top":left_top, 887 | * "left_bottom":left_bottom}, 888 | * (cwiid.MOTIONPLUS_MESG,{"angle_rate":(psi,theta,phi), 889 | * "low_speed":(psi,theta,phi)}, 890 | * (cwiid.ERROR_MESG,error)] 891 | */ 892 | PyObject *ConvertMesgArray(int mesg_count, union cwiid_mesg mesg[]) 893 | { 894 | PyObject *mesglist; /* List of message tuples */ 895 | PyObject *amesg; /* A single message (type, [arguments]) */ 896 | PyObject *mesgVal; /* Dictionary of arguments for a message */ 897 | PyObject *PyIrList; 898 | int i, j; 899 | 900 | if (!(mesglist = PyList_New(mesg_count))) { 901 | return NULL; 902 | } 903 | 904 | for (i = 0; i < mesg_count; i++) { 905 | switch (mesg[i].type) { 906 | case CWIID_MESG_STATUS: 907 | mesgVal = Py_BuildValue("{s:B,s:i}", 908 | "battery", mesg[i].status_mesg.battery, 909 | "ext_type", mesg[i].status_mesg.ext_type); 910 | break; 911 | case CWIID_MESG_BTN: 912 | mesgVal = Py_BuildValue("I", mesg[i].btn_mesg.buttons); 913 | break; 914 | case CWIID_MESG_ACC: 915 | mesgVal = Py_BuildValue("(B,B,B)", mesg[i].acc_mesg.acc[CWIID_X], 916 | mesg[i].acc_mesg.acc[CWIID_Y], 917 | mesg[i].acc_mesg.acc[CWIID_Z]); 918 | break; 919 | case CWIID_MESG_IR: 920 | mesgVal = NULL; 921 | 922 | if (!(PyIrList = PyList_New(CWIID_IR_SRC_COUNT))) { 923 | break; 924 | } 925 | 926 | for (j=0; j < CWIID_IR_SRC_COUNT; j++) { 927 | PyObject *PyIrSrc; 928 | PyObject *PySize; 929 | 930 | if (mesg[i].ir_mesg.src[j].valid) { 931 | PyIrSrc = Py_BuildValue("{s:(I,I)}", 932 | "pos", 933 | mesg[i].ir_mesg.src[j].pos[CWIID_X], 934 | mesg[i].ir_mesg.src[j].pos[CWIID_Y]); 935 | 936 | if (!PyIrSrc) { 937 | Py_DECREF(PyIrList); 938 | PyIrList = NULL; 939 | break; 940 | } 941 | 942 | if (mesg[i].ir_mesg.src[j].size != -1) { 943 | if (!(PySize = PyLong_FromLong( 944 | (long)mesg[i].ir_mesg.src[j].size))) { 945 | Py_DECREF(PyIrList); 946 | Py_DECREF(PyIrSrc); 947 | PyIrList = NULL; 948 | break; 949 | } 950 | if (PyDict_SetItemString(PyIrSrc, "size", PySize)) { 951 | Py_DECREF(PyIrList); 952 | Py_DECREF(PyIrSrc); 953 | Py_DECREF(PySize); 954 | PyIrList = NULL; 955 | break; 956 | } 957 | 958 | Py_DECREF(PySize); 959 | } 960 | } 961 | else { 962 | Py_INCREF(PyIrSrc = Py_None); 963 | } 964 | PyList_SET_ITEM(PyIrList, j, PyIrSrc); 965 | } 966 | 967 | if (!PyIrList) { 968 | break; 969 | } 970 | 971 | mesgVal = PyIrList; 972 | break; 973 | case CWIID_MESG_NUNCHUK: 974 | mesgVal = Py_BuildValue("{s:(B,B),s:(B,B,B),s:I}", 975 | "stick", 976 | mesg[i].nunchuk_mesg.stick[CWIID_X], 977 | mesg[i].nunchuk_mesg.stick[CWIID_Y], 978 | "acc", 979 | mesg[i].nunchuk_mesg.acc[CWIID_X], 980 | mesg[i].nunchuk_mesg.acc[CWIID_Y], 981 | mesg[i].nunchuk_mesg.acc[CWIID_Z], 982 | "buttons", mesg[i].nunchuk_mesg.buttons); 983 | break; 984 | case CWIID_MESG_CLASSIC: 985 | mesgVal = Py_BuildValue("{s:(B,B),s:(B,B),s:B,s:B,s:I}", 986 | "l_stick", 987 | mesg[i].classic_mesg.l_stick[CWIID_X], 988 | mesg[i].classic_mesg.l_stick[CWIID_Y], 989 | "r_stick", 990 | mesg[i].classic_mesg.r_stick[CWIID_X], 991 | mesg[i].classic_mesg.r_stick[CWIID_Y], 992 | "l", mesg[i].classic_mesg.l, 993 | "r", mesg[i].classic_mesg.r, 994 | "buttons", mesg[i].classic_mesg.buttons); 995 | break; 996 | case CWIID_MESG_BALANCE: 997 | mesgVal = Py_BuildValue("{s:I,s:I,s:I,s:I}", 998 | "right_top", 999 | mesg[i].balance_mesg.right_top, 1000 | "right_bottom", 1001 | mesg[i].balance_mesg.right_bottom, 1002 | "left_top", 1003 | mesg[i].balance_mesg.left_top, 1004 | "left_bottom", 1005 | mesg[i].balance_mesg.left_bottom); 1006 | break; 1007 | case CWIID_MESG_MOTIONPLUS: 1008 | mesgVal = Py_BuildValue("{s:(I,I,I),s:(I,I,I)}", 1009 | "angle_rate", 1010 | mesg[i].motionplus_mesg.angle_rate[CWIID_PHI], 1011 | mesg[i].motionplus_mesg.angle_rate[CWIID_THETA], 1012 | mesg[i].motionplus_mesg.angle_rate[CWIID_PSI], 1013 | "low_speed", 1014 | mesg[i].motionplus_mesg.low_speed[CWIID_PHI], 1015 | mesg[i].motionplus_mesg.low_speed[CWIID_THETA], 1016 | mesg[i].motionplus_mesg.low_speed[CWIID_PSI]); 1017 | 1018 | break; 1019 | case CWIID_MESG_ERROR: 1020 | mesgVal = Py_BuildValue("i", mesg[i].error_mesg.error); 1021 | break; 1022 | default: 1023 | Py_INCREF(mesgVal = Py_None); 1024 | break; 1025 | } 1026 | 1027 | if (!mesgVal) { 1028 | return NULL; 1029 | } 1030 | 1031 | /* Finally Put the type next to the message in a tuple and 1032 | * append them to the list of messages */ 1033 | if (!(amesg = Py_BuildValue("(iO)", mesg[i].type, mesgVal))) { 1034 | Py_DECREF(mesgVal); 1035 | return NULL; 1036 | } 1037 | Py_DECREF(mesgVal); 1038 | PyList_SET_ITEM(mesglist, i, amesg); 1039 | } 1040 | 1041 | return mesglist; 1042 | } 1043 | -------------------------------------------------------------------------------- /python/cwiidmodule.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2007 Justin M. Tulloss , L. Donnie Smith 3 | * 4 | * Interface from Python to libcwiid 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 | * Boston, MA 02110-1301 USA 20 | * 21 | */ 22 | 23 | #include "Python.h" 24 | 25 | #include 26 | 27 | #include 28 | #include "structmember.h" 29 | 30 | /* externally defined types */ 31 | extern PyTypeObject Wiimote_Type; 32 | extern PyObject *ConvertMesgArray(int, union cwiid_mesg []); 33 | 34 | /* cwiid module initializer */ 35 | PyMODINIT_FUNC PyInit_cwiid(void); 36 | 37 | /* constants, enumerations */ 38 | #define CWIID_CONST_MACRO(a) {#a, CWIID_##a} 39 | static struct { 40 | char *name; 41 | int value; 42 | } cwiid_constants[] = { 43 | CWIID_CONST_MACRO(FLAG_MESG_IFC), 44 | CWIID_CONST_MACRO(FLAG_CONTINUOUS), 45 | CWIID_CONST_MACRO(FLAG_REPEAT_BTN), 46 | CWIID_CONST_MACRO(FLAG_NONBLOCK), 47 | CWIID_CONST_MACRO(FLAG_MOTIONPLUS), 48 | CWIID_CONST_MACRO(RPT_STATUS), 49 | CWIID_CONST_MACRO(RPT_BTN), 50 | CWIID_CONST_MACRO(RPT_ACC), 51 | CWIID_CONST_MACRO(RPT_IR), 52 | CWIID_CONST_MACRO(RPT_NUNCHUK), 53 | CWIID_CONST_MACRO(RPT_CLASSIC), 54 | CWIID_CONST_MACRO(RPT_BALANCE), 55 | CWIID_CONST_MACRO(RPT_MOTIONPLUS), 56 | CWIID_CONST_MACRO(RPT_EXT), 57 | CWIID_CONST_MACRO(LED1_ON), 58 | CWIID_CONST_MACRO(LED2_ON), 59 | CWIID_CONST_MACRO(LED3_ON), 60 | CWIID_CONST_MACRO(LED4_ON), 61 | CWIID_CONST_MACRO(BTN_2), 62 | CWIID_CONST_MACRO(BTN_1), 63 | CWIID_CONST_MACRO(BTN_B), 64 | CWIID_CONST_MACRO(BTN_A), 65 | CWIID_CONST_MACRO(BTN_MINUS), 66 | CWIID_CONST_MACRO(BTN_HOME), 67 | CWIID_CONST_MACRO(BTN_LEFT), 68 | CWIID_CONST_MACRO(BTN_RIGHT), 69 | CWIID_CONST_MACRO(BTN_DOWN), 70 | CWIID_CONST_MACRO(BTN_UP), 71 | CWIID_CONST_MACRO(BTN_PLUS), 72 | CWIID_CONST_MACRO(NUNCHUK_BTN_Z), 73 | CWIID_CONST_MACRO(NUNCHUK_BTN_C), 74 | CWIID_CONST_MACRO(CLASSIC_BTN_UP), 75 | CWIID_CONST_MACRO(CLASSIC_BTN_LEFT), 76 | CWIID_CONST_MACRO(CLASSIC_BTN_ZR), 77 | CWIID_CONST_MACRO(CLASSIC_BTN_X), 78 | CWIID_CONST_MACRO(CLASSIC_BTN_A), 79 | CWIID_CONST_MACRO(CLASSIC_BTN_Y), 80 | CWIID_CONST_MACRO(CLASSIC_BTN_B), 81 | CWIID_CONST_MACRO(CLASSIC_BTN_ZL), 82 | CWIID_CONST_MACRO(CLASSIC_BTN_R), 83 | CWIID_CONST_MACRO(CLASSIC_BTN_PLUS), 84 | CWIID_CONST_MACRO(CLASSIC_BTN_HOME), 85 | CWIID_CONST_MACRO(CLASSIC_BTN_MINUS), 86 | CWIID_CONST_MACRO(CLASSIC_BTN_L), 87 | CWIID_CONST_MACRO(CLASSIC_BTN_DOWN), 88 | CWIID_CONST_MACRO(CLASSIC_BTN_RIGHT), 89 | CWIID_CONST_MACRO(SEND_RPT_NO_RUMBLE), 90 | CWIID_CONST_MACRO(RW_EEPROM), 91 | CWIID_CONST_MACRO(RW_REG), 92 | CWIID_CONST_MACRO(RW_DECODE), 93 | CWIID_CONST_MACRO(MAX_READ_LEN), 94 | CWIID_CONST_MACRO(X), 95 | CWIID_CONST_MACRO(Y), 96 | CWIID_CONST_MACRO(Z), 97 | CWIID_CONST_MACRO(PHI), 98 | CWIID_CONST_MACRO(THETA), 99 | CWIID_CONST_MACRO(PSI), 100 | CWIID_CONST_MACRO(IR_SRC_COUNT), 101 | CWIID_CONST_MACRO(IR_X_MAX), 102 | CWIID_CONST_MACRO(IR_Y_MAX), 103 | CWIID_CONST_MACRO(BATTERY_MAX), 104 | CWIID_CONST_MACRO(CLASSIC_L_STICK_MAX), 105 | CWIID_CONST_MACRO(CLASSIC_R_STICK_MAX), 106 | CWIID_CONST_MACRO(CLASSIC_LR_MAX), 107 | CWIID_CONST_MACRO(CMD_STATUS), 108 | CWIID_CONST_MACRO(CMD_LED), 109 | CWIID_CONST_MACRO(CMD_RUMBLE), 110 | CWIID_CONST_MACRO(CMD_RPT_MODE), 111 | CWIID_CONST_MACRO(MESG_STATUS), 112 | CWIID_CONST_MACRO(MESG_BTN), 113 | CWIID_CONST_MACRO(MESG_ACC), 114 | CWIID_CONST_MACRO(MESG_IR), 115 | CWIID_CONST_MACRO(MESG_NUNCHUK), 116 | CWIID_CONST_MACRO(MESG_CLASSIC), 117 | CWIID_CONST_MACRO(MESG_BALANCE), 118 | CWIID_CONST_MACRO(MESG_MOTIONPLUS), 119 | CWIID_CONST_MACRO(MESG_ERROR), 120 | CWIID_CONST_MACRO(MESG_UNKNOWN), 121 | CWIID_CONST_MACRO(EXT_NONE), 122 | CWIID_CONST_MACRO(EXT_NUNCHUK), 123 | CWIID_CONST_MACRO(EXT_CLASSIC), 124 | CWIID_CONST_MACRO(EXT_BALANCE), 125 | CWIID_CONST_MACRO(EXT_MOTIONPLUS), 126 | CWIID_CONST_MACRO(EXT_UNKNOWN), 127 | CWIID_CONST_MACRO(ERROR_DISCONNECT), 128 | CWIID_CONST_MACRO(ERROR_COMM), 129 | {NULL, 0} 130 | }; 131 | 132 | /* Associates cwiid functions with python ones */ 133 | static PyMethodDef Module_Methods[] = 134 | { 135 | {NULL, NULL, 0, NULL} 136 | }; 137 | 138 | static struct PyModuleDef moduledef = { 139 | PyModuleDef_HEAD_INIT, 140 | "cwiid", /* m_name */ 141 | "Cwiid FFS!", /* m_doc */ 142 | -1, /* m_size */ 143 | Module_Methods, /* m_methods */ 144 | NULL, /* m_reload */ 145 | NULL, /* m_traverse */ 146 | NULL, /* m_clear */ 147 | NULL, /* m_free */ 148 | }; 149 | 150 | PyMODINIT_FUNC PyInit_cwiid(void) 151 | { 152 | PyObject *Module; 153 | PyObject *CCapsule; 154 | int i; 155 | 156 | if (!(Module = PyModule_Create(&moduledef))) { 157 | return NULL; 158 | } 159 | 160 | Wiimote_Type.tp_new = PyType_GenericNew; 161 | if (PyType_Ready(&Wiimote_Type) < 0) { 162 | return NULL; 163 | } 164 | 165 | Py_INCREF(&Wiimote_Type); 166 | PyModule_AddObject(Module, "Wiimote", (PyObject *)&Wiimote_Type); 167 | 168 | for (i = 0; cwiid_constants[i].name; i++) { 169 | /* No way to report errors from here, so just ignore them and hope 170 | * for segfault */ 171 | PyModule_AddIntConstant(Module, cwiid_constants[i].name, 172 | cwiid_constants[i].value); 173 | } 174 | 175 | if (!(CCapsule = PyCapsule_New(ConvertMesgArray, "dynamr", NULL))) { 176 | return NULL; 177 | } 178 | PyModule_AddObject(Module, "ConvertMesgArray", CCapsule); 179 | 180 | return Module; 181 | } 182 | -------------------------------------------------------------------------------- /python/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup, Extension 2 | 3 | setup( 4 | name='cwiid', 5 | version='3.0.0', 6 | description='Python3 module for libcwiid', 7 | author='Azzra', 8 | author_email='azzra@users.noreply.github.com', 9 | ext_modules=[Extension('cwiid', ['cwiidmodule.c', 'Wiimote.c'], libraries=['cwiid', 'bluetooth'])] 10 | ) 11 | --------------------------------------------------------------------------------